Merge "Line endcaps for AA lines are now antialiased."
This commit is contained in:
@ -62,8 +62,10 @@ static const TextureVertex gMeshVertices[] = {
|
||||
static const GLsizei gMeshStride = sizeof(TextureVertex);
|
||||
static const GLsizei gVertexStride = sizeof(Vertex);
|
||||
static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
|
||||
static const GLsizei gAAVertexStride = sizeof(AAVertex);
|
||||
static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
|
||||
static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
|
||||
static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
|
||||
static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
|
||||
static const GLsizei gMeshCount = 4;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -915,7 +915,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() {
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setupDrawAALine() {
|
||||
mDescription.hasWidth = true;
|
||||
mDescription.isAA = true;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setupDrawPoint(float pointSize) {
|
||||
@ -1121,25 +1121,30 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
|
||||
|
||||
/**
|
||||
* Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
|
||||
* outer boundary that fades out to 0. The variables set in the shader define the width of the
|
||||
* core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The
|
||||
* "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment
|
||||
* shader where the fragment is in relation to the line width overall; this value is then used
|
||||
* to compute the proper color, based on whether the fragment lies in the fading AA region of
|
||||
* the line.
|
||||
* outer boundary that fades out to 0. The variables set in the shader define the proportion of
|
||||
* the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
|
||||
* attributes (one per vertex) are values from zero to one that tells the fragment
|
||||
* shader where the fragment is in relation to the line width/length overall; these values are
|
||||
* then used to compute the proper color, based on whether the fragment lies in the fading AA
|
||||
* region of the line.
|
||||
* Note that we only pass down the width values in this setup function. The length coordinates
|
||||
* are set up for each individual segment.
|
||||
*/
|
||||
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
|
||||
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
|
||||
GLvoid* lengthCoords, float strokeWidth) {
|
||||
mCaches.unbindMeshBuffer();
|
||||
glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gAlphaVertexStride, vertices);
|
||||
int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance");
|
||||
glEnableVertexAttribArray(distanceSlot);
|
||||
glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords);
|
||||
int widthSlot = mCaches.currentProgram->getUniform("width");
|
||||
gAAVertexStride, vertices);
|
||||
int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
|
||||
glEnableVertexAttribArray(widthSlot);
|
||||
glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
|
||||
int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
|
||||
glEnableVertexAttribArray(lengthSlot);
|
||||
glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
|
||||
int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
|
||||
// Setting the inverse value saves computations per-fragment in the shader
|
||||
int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
|
||||
float boundaryWidth = (1 - strokeWidth) / 2;
|
||||
glUniform1f(widthSlot, strokeWidth);
|
||||
glUniform1f(boundaryWidthSlot, boundaryWidth);
|
||||
glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
|
||||
}
|
||||
@ -1480,20 +1485,21 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
|
||||
}
|
||||
Vertex lines[verticesCount];
|
||||
Vertex* vertices = &lines[0];
|
||||
AlphaVertex wLines[verticesCount];
|
||||
AlphaVertex* aaVertices = &wLines[0];
|
||||
AAVertex wLines[verticesCount];
|
||||
AAVertex* aaVertices = &wLines[0];
|
||||
if (!isAA) {
|
||||
setupDrawVertices(vertices);
|
||||
} else {
|
||||
void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset;
|
||||
void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
|
||||
void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
|
||||
// innerProportion is the ratio of the inner (non-AA) port of the line to the total
|
||||
// AA stroke width (the base stroke width expanded by a half pixel on either side).
|
||||
// This value is used in the fragment shader to determine how to fill fragments.
|
||||
float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f);
|
||||
setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion);
|
||||
setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion);
|
||||
}
|
||||
|
||||
AlphaVertex *prevAAVertex = NULL;
|
||||
AAVertex *prevAAVertex = NULL;
|
||||
Vertex *prevVertex = NULL;
|
||||
float inverseScaleX = 1.0f;
|
||||
float inverseScaleY = 1.0f;
|
||||
@ -1516,15 +1522,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
|
||||
}
|
||||
}
|
||||
|
||||
int boundaryLengthSlot = -1;
|
||||
int inverseBoundaryLengthSlot = -1;
|
||||
for (int i = 0; i < count; i += 4) {
|
||||
// a = start point, b = end point
|
||||
vec2 a(points[i], points[i + 1]);
|
||||
vec2 b(points[i + 2], points[i + 3]);
|
||||
float length = 0;
|
||||
|
||||
// Find the normal to the line
|
||||
vec2 n = (b - a).copyNormalized() * strokeWidth;
|
||||
if (isHairLine) {
|
||||
n *= inverseScaleX;
|
||||
if (isAA) {
|
||||
float wideningFactor;
|
||||
if (fabs(n.x) >= fabs(n.y)) {
|
||||
@ -1534,27 +1542,35 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
|
||||
}
|
||||
n *= wideningFactor;
|
||||
}
|
||||
n.x *= inverseScaleX;
|
||||
n.y *= inverseScaleY;
|
||||
}
|
||||
float x = n.x;
|
||||
n.x = -n.y;
|
||||
n.y = x;
|
||||
|
||||
// aa lines expand the endpoint vertices to encompass the AA boundary
|
||||
if (isAA) {
|
||||
vec2 abVector = (b - a);
|
||||
length = abVector.length();
|
||||
abVector.normalize();
|
||||
a -= abVector;
|
||||
b += abVector;
|
||||
}
|
||||
|
||||
// Four corners of the rectangle defining a thick line
|
||||
vec2 p1 = a - n;
|
||||
vec2 p2 = a + n;
|
||||
vec2 p3 = b + n;
|
||||
vec2 p4 = b - n;
|
||||
|
||||
|
||||
const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
|
||||
const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
|
||||
const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
|
||||
const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
|
||||
|
||||
if (!quickReject(left, top, right, bottom)) {
|
||||
// Draw the line as 2 triangles, could be optimized
|
||||
// by using only 4 vertices and the correct indices
|
||||
// Also we should probably used non textured vertices
|
||||
// when line AA is disabled to save on bandwidth
|
||||
if (!isAA) {
|
||||
if (prevVertex != NULL) {
|
||||
// Issue two repeat vertices to create degenerate triangles to bridge
|
||||
@ -1572,24 +1588,36 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
|
||||
prevVertex = vertices - 1;
|
||||
generatedVerticesCount += 4;
|
||||
} else {
|
||||
if (boundaryLengthSlot < 0) {
|
||||
boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
|
||||
inverseBoundaryLengthSlot =
|
||||
mCaches.currentProgram->getUniform("inverseBoundaryLength");
|
||||
}
|
||||
float innerProportion = (length) / (length + 2);
|
||||
float boundaryLength = (1 - innerProportion) / 2;
|
||||
glUniform1f(boundaryLengthSlot, boundaryLength);
|
||||
glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength));
|
||||
|
||||
if (prevAAVertex != NULL) {
|
||||
// Issue two repeat vertices to create degenerate triangles to bridge
|
||||
// between the previous line and the new one. This is necessary because
|
||||
// we are creating a single triangle_strip which will contain
|
||||
// potentially discontinuous line segments.
|
||||
AlphaVertex::set(aaVertices++,prevAAVertex->position[0],
|
||||
prevAAVertex->position[1], prevAAVertex->alpha);
|
||||
AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
|
||||
AAVertex::set(aaVertices++,prevAAVertex->position[0],
|
||||
prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
|
||||
AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
|
||||
generatedVerticesCount += 2;
|
||||
}
|
||||
AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
|
||||
AlphaVertex::set(aaVertices++, p1.x, p1.y, 1);
|
||||
AlphaVertex::set(aaVertices++, p3.x, p3.y, 0);
|
||||
AlphaVertex::set(aaVertices++, p2.x, p2.y, 0);
|
||||
AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
|
||||
AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
|
||||
AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
|
||||
AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
|
||||
prevAAVertex = aaVertices - 1;
|
||||
generatedVerticesCount += 4;
|
||||
}
|
||||
dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
|
||||
dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
|
||||
a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
|
||||
*mSnapshot->transform);
|
||||
}
|
||||
}
|
||||
if (generatedVerticesCount > 0) {
|
||||
|
@ -468,7 +468,8 @@ private:
|
||||
void setupDrawTextureTransform(mat4& transform);
|
||||
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
|
||||
void setupDrawVertices(GLvoid* vertices);
|
||||
void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
|
||||
void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
|
||||
float strokeWidth);
|
||||
void finishDrawTexture();
|
||||
|
||||
void drawRegionRects(const Region& region);
|
||||
|
@ -39,8 +39,9 @@ const char* gVS_Header_Attributes =
|
||||
"attribute vec4 position;\n";
|
||||
const char* gVS_Header_Attributes_TexCoords =
|
||||
"attribute vec2 texCoords;\n";
|
||||
const char* gVS_Header_Attributes_Distance =
|
||||
"attribute float vtxDistance;\n";
|
||||
const char* gVS_Header_Attributes_AAParameters =
|
||||
"attribute float vtxWidth;\n"
|
||||
"attribute float vtxLength;\n";
|
||||
const char* gVS_Header_Uniforms_TextureTransform =
|
||||
"uniform mat4 mainTextureTransform;\n";
|
||||
const char* gVS_Header_Uniforms =
|
||||
@ -60,8 +61,9 @@ const char* gVS_Header_Uniforms_HasBitmap =
|
||||
"uniform mediump vec2 textureDimension;\n";
|
||||
const char* gVS_Header_Varyings_HasTexture =
|
||||
"varying vec2 outTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_HasWidth =
|
||||
"varying float distance;\n";
|
||||
const char* gVS_Header_Varyings_IsAA =
|
||||
"varying float widthProportion;\n"
|
||||
"varying float lengthProportion;\n";
|
||||
const char* gVS_Header_Varyings_HasBitmap =
|
||||
"varying vec2 outBitmapTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_PointHasBitmap =
|
||||
@ -96,8 +98,9 @@ const char* gVS_Main_Position =
|
||||
" gl_Position = transform * position;\n";
|
||||
const char* gVS_Main_PointSize =
|
||||
" gl_PointSize = pointSize;\n";
|
||||
const char* gVS_Main_Width =
|
||||
" distance = vtxDistance;\n";
|
||||
const char* gVS_Main_AA =
|
||||
" widthProportion = vtxWidth;\n"
|
||||
" lengthProportion = vtxLength;\n";
|
||||
const char* gVS_Footer =
|
||||
"}\n\n";
|
||||
|
||||
@ -113,10 +116,11 @@ const char* gFS_Header =
|
||||
"precision mediump float;\n\n";
|
||||
const char* gFS_Uniforms_Color =
|
||||
"uniform vec4 color;\n";
|
||||
const char* gFS_Uniforms_Width =
|
||||
"uniform float width;\n"
|
||||
const char* gFS_Uniforms_AA =
|
||||
"uniform float boundaryWidth;\n"
|
||||
"uniform float inverseBoundaryWidth;\n";
|
||||
"uniform float inverseBoundaryWidth;\n"
|
||||
"uniform float boundaryLength;\n"
|
||||
"uniform float inverseBoundaryLength;\n";
|
||||
const char* gFS_Header_Uniforms_PointHasBitmap =
|
||||
"uniform vec2 textureDimension;\n"
|
||||
"uniform float pointSize;\n";
|
||||
@ -189,11 +193,16 @@ const char* gFS_Main_FetchColor =
|
||||
" fragColor = color;\n";
|
||||
const char* gFS_Main_ModulateColor =
|
||||
" fragColor *= color.a;\n";
|
||||
const char* gFS_Main_AccountForWidth =
|
||||
" if (distance < boundaryWidth) {\n"
|
||||
" fragColor *= (distance * inverseBoundaryWidth);\n"
|
||||
" } else if (distance > (1.0 - boundaryWidth)) {\n"
|
||||
" fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n"
|
||||
const char* gFS_Main_AccountForAA =
|
||||
" if (widthProportion < boundaryWidth) {\n"
|
||||
" fragColor *= (widthProportion * inverseBoundaryWidth);\n"
|
||||
" } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
|
||||
" fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
|
||||
" }\n"
|
||||
" if (lengthProportion < boundaryLength) {\n"
|
||||
" fragColor *= (lengthProportion * inverseBoundaryLength);\n"
|
||||
" } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
|
||||
" fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
|
||||
" }\n";
|
||||
const char* gFS_Main_FetchTexture[2] = {
|
||||
// Don't modulate
|
||||
@ -380,8 +389,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
|
||||
if (description.hasTexture || description.hasExternalTexture) {
|
||||
shader.append(gVS_Header_Attributes_TexCoords);
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gVS_Header_Attributes_Distance);
|
||||
if (description.isAA) {
|
||||
shader.append(gVS_Header_Attributes_AAParameters);
|
||||
}
|
||||
// Uniforms
|
||||
shader.append(gVS_Header_Uniforms);
|
||||
@ -401,8 +410,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
|
||||
if (description.hasTexture || description.hasExternalTexture) {
|
||||
shader.append(gVS_Header_Varyings_HasTexture);
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gVS_Header_Varyings_HasWidth);
|
||||
if (description.isAA) {
|
||||
shader.append(gVS_Header_Varyings_IsAA);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
|
||||
@ -421,8 +430,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
|
||||
if (description.hasExternalTexture) {
|
||||
shader.append(gVS_Main_OutTransformedTexCoords);
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gVS_Main_Width);
|
||||
if (description.isAA) {
|
||||
shader.append(gVS_Main_AA);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gVS_Main_OutGradient[description.gradientType]);
|
||||
@ -464,8 +473,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
if (description.hasTexture || description.hasExternalTexture) {
|
||||
shader.append(gVS_Header_Varyings_HasTexture);
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gVS_Header_Varyings_HasWidth);
|
||||
if (description.isAA) {
|
||||
shader.append(gVS_Header_Varyings_IsAA);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
|
||||
@ -491,8 +500,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
if (description.hasExternalTexture) {
|
||||
shader.append(gFS_Uniforms_ExternalTextureSampler);
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gFS_Uniforms_Width);
|
||||
if (description.isAA) {
|
||||
shader.append(gFS_Uniforms_AA);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
|
||||
@ -502,7 +511,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
}
|
||||
|
||||
// Optimization for common cases
|
||||
if (!description.hasWidth && !blendFramebuffer &&
|
||||
if (!description.isAA && !blendFramebuffer &&
|
||||
description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
|
||||
bool fast = false;
|
||||
|
||||
@ -587,8 +596,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
shader.append(gFS_Main_FetchColor);
|
||||
}
|
||||
}
|
||||
if (description.hasWidth) {
|
||||
shader.append(gFS_Main_AccountForWidth);
|
||||
if (description.isAA) {
|
||||
shader.append(gFS_Main_AccountForAA);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gFS_Main_FetchGradient[description.gradientType]);
|
||||
|
@ -75,7 +75,7 @@ namespace uirenderer {
|
||||
|
||||
#define PROGRAM_IS_POINT_SHIFT 36
|
||||
|
||||
#define PROGRAM_HAS_WIDTH_SHIFT 37
|
||||
#define PROGRAM_HAS_AA_SHIFT 37
|
||||
|
||||
#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
|
||||
|
||||
@ -124,7 +124,7 @@ struct ProgramDescription {
|
||||
bool hasBitmap;
|
||||
bool isBitmapNpot;
|
||||
|
||||
bool hasWidth;
|
||||
bool isAA;
|
||||
|
||||
bool hasGradient;
|
||||
Gradient gradientType;
|
||||
@ -156,7 +156,7 @@ struct ProgramDescription {
|
||||
hasAlpha8Texture = false;
|
||||
hasExternalTexture = false;
|
||||
|
||||
hasWidth = false;
|
||||
isAA = false;
|
||||
|
||||
modulate = false;
|
||||
|
||||
@ -243,7 +243,7 @@ struct ProgramDescription {
|
||||
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
|
||||
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
|
||||
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
|
||||
if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
|
||||
if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
|
||||
if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
|
||||
return key;
|
||||
}
|
||||
|
@ -68,6 +68,25 @@ struct AlphaVertex : Vertex {
|
||||
}
|
||||
}; // struct AlphaVertex
|
||||
|
||||
/**
|
||||
* Simple structure to describe a vertex with a position and an alpha value.
|
||||
*/
|
||||
struct AAVertex : Vertex {
|
||||
float width;
|
||||
float length;
|
||||
|
||||
static inline void set(AAVertex* vertex, float x, float y, float width, float length) {
|
||||
Vertex::set(vertex, x, y);
|
||||
vertex[0].width = width;
|
||||
vertex[0].length = length;
|
||||
}
|
||||
|
||||
static inline void setColor(AAVertex* vertex, float width, float length) {
|
||||
vertex[0].width = width;
|
||||
vertex[0].length = length;
|
||||
}
|
||||
}; // struct AlphaVertex
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
|
@ -86,6 +86,14 @@ public class Lines2Activity extends Activity {
|
||||
canvas.drawLines(copyPoints, 0, 12, p);
|
||||
}
|
||||
|
||||
private void drawVerticalLine(Canvas canvas, Paint p, float length, float x, float y) {
|
||||
canvas.drawLine(x, y, x, y + length, p);
|
||||
}
|
||||
|
||||
private void drawDiagonalLine(Canvas canvas, Paint p, float length, float x, float y) {
|
||||
canvas.drawLine(x, y, x + length, y + length, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
@ -145,6 +153,99 @@ public class Lines2Activity extends Activity {
|
||||
canvas.translate(60, 0);
|
||||
drawLines(canvas, p, mOffset/2, yOffset/2);
|
||||
canvas.restore();
|
||||
|
||||
yOffset += 100;
|
||||
canvas.save();
|
||||
p.setStrokeWidth(1);
|
||||
float x = 10 + mOffset;
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
drawVerticalLine(canvas, p, length, x, yOffset);
|
||||
x += 5;
|
||||
p.setAntiAlias(true);
|
||||
drawVerticalLine(canvas, p, length, x, yOffset);
|
||||
x += 5;
|
||||
}
|
||||
p.setStrokeWidth(5);
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
drawVerticalLine(canvas, p, length, x, yOffset);
|
||||
x += 10;
|
||||
p.setAntiAlias(true);
|
||||
drawVerticalLine(canvas, p, length, x, yOffset);
|
||||
x += 10;
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
yOffset += 20;
|
||||
canvas.save();
|
||||
p.setStrokeWidth(1);
|
||||
x = 10 + mOffset;
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
drawDiagonalLine(canvas, p, length, x, yOffset);
|
||||
x += 5;
|
||||
p.setAntiAlias(true);
|
||||
drawDiagonalLine(canvas, p, length, x, yOffset);
|
||||
x += 5;
|
||||
}
|
||||
p.setStrokeWidth(2);
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
drawDiagonalLine(canvas, p, length, x, yOffset);
|
||||
x += 10;
|
||||
p.setAntiAlias(true);
|
||||
drawDiagonalLine(canvas, p, length, x, yOffset);
|
||||
x += 10;
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
yOffset += 20;
|
||||
canvas.save();
|
||||
p.setStrokeWidth(1);
|
||||
x = 10 + mOffset;
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
|
||||
x += 5;
|
||||
p.setAntiAlias(true);
|
||||
canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
|
||||
x += 5;
|
||||
}
|
||||
p.setStrokeWidth(2);
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
|
||||
x += 10;
|
||||
p.setAntiAlias(true);
|
||||
canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
|
||||
x += 10;
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
yOffset += 20;
|
||||
canvas.save();
|
||||
p.setStrokeWidth(1);
|
||||
x = 10 + mOffset;
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
|
||||
x += 5;
|
||||
p.setAntiAlias(true);
|
||||
canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
|
||||
x += 5;
|
||||
}
|
||||
p.setStrokeWidth(2);
|
||||
for (float length = 1; length <= 10; length +=1 ) {
|
||||
p.setAntiAlias(false);
|
||||
canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
|
||||
x += 10;
|
||||
p.setAntiAlias(true);
|
||||
canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
|
||||
x += 10;
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user