Add support for drawLines(), with anti-aliasing
Change-Id: I16c0593c5671490909dec13a85df601e1428a1a6
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
new file mode 100644
index 0000000..48e18eb
--- /dev/null
+++ b/libs/hwui/Line.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_LINE_H
+#define ANDROID_UI_LINE_H
+
+#include <GLES2/gl2.h>
+
+#include <cmath>
+
+#include <sys/types.h>
+
+#include "Patch.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Globals
+///////////////////////////////////////////////////////////////////////////////
+
+// Alpha8 texture used to perform texture anti-aliasing
+static const uint8_t gLineTexture[] = {
+ 0, 0, 0, 0, 0,
+ 0, 255, 255, 255, 0,
+ 0, 255, 255, 255, 0,
+ 0, 255, 255, 255, 0,
+ 0, 0, 0, 0, 0
+};
+static const GLsizei gLineTextureWidth = 5;
+static const GLsizei gLineTextureHeight = 5;
+static const float gLineAABias = 1.0f;
+
+///////////////////////////////////////////////////////////////////////////////
+// Line
+///////////////////////////////////////////////////////////////////////////////
+
+class Line {
+public:
+ Line(): mXDivsCount(2), mYDivsCount(2) {
+ mPatch = new Patch(mXDivsCount, mYDivsCount);
+ mXDivs = new int32_t[mXDivsCount];
+ mYDivs = new int32_t[mYDivsCount];
+
+ mXDivs[0] = mYDivs[0] = 2;
+ mXDivs[1] = mYDivs[1] = 3;
+
+ glGenTextures(1, &mTexture);
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gLineTextureWidth, gLineTextureHeight, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, gLineTexture);
+ }
+
+ ~Line() {
+ delete mPatch;
+ delete mXDivs;
+ delete mYDivs;
+
+ glDeleteTextures(1, &mTexture);
+ }
+
+ void update(float x1, float y1, float x2, float y2, float lineWidth, float& tx, float& ty) {
+ const float length = sqrtf((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
+ const float half = lineWidth * 0.5f;
+
+ mPatch->updateVertices(gLineTextureWidth, gLineTextureHeight,
+ -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias,
+ mXDivs, mYDivs, mXDivsCount, mYDivsCount);
+
+ tx = -gLineAABias;
+ ty = -half - gLineAABias;
+ }
+
+ inline GLvoid* getVertices() const {
+ return &mPatch->vertices[0].position[0];
+ }
+
+ inline GLvoid* getTexCoords() const {
+ return &mPatch->vertices[0].texture[0];
+ }
+
+ inline GLsizei getElementsCount() const {
+ return mPatch->verticesCount;
+ }
+
+ inline GLuint getTexture() const {
+ return mTexture;
+ }
+
+private:
+ uint32_t mXDivsCount;
+ uint32_t mYDivsCount;
+
+ int32_t* mXDivs;
+ int32_t* mYDivs;
+
+ Patch* mPatch;
+
+ GLuint mTexture;
+}; // class Line
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_LINE_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d6c0053..ecc02fa 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -39,6 +39,9 @@
// Generates simple and textured vertices
#define FV(x, y, u, v) { { x, y }, { u, v } }
+#define RAD_TO_DEG (180.0f / 3.14159265f)
+#define MIN_ANGLE 0.001f
+
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
@@ -588,7 +591,7 @@
getAlphaAndMode(paint, &alpha, &mode);
Patch* mesh = mCaches.patchCache.get(patch);
- mesh->updateVertices(bitmap, left, top, right, bottom,
+ mesh->updateVertices(bitmap->width(), bitmap->height(),left, top, right, bottom,
&patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
// Specify right and bottom as +1.0f from left/top to prevent scaling since the
@@ -598,6 +601,50 @@
&mesh->vertices[0].texture[0], GL_TRIANGLES, mesh->verticesCount);
}
+void OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+ int alpha;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &alpha, &mode);
+
+ uint32_t color = paint->getColor();
+ const GLfloat a = alpha / 255.0f;
+ const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
+ const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
+ const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
+
+ GLuint textureUnit = 0;
+ setupTextureAlpha8(mLine.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a,
+ mode, false, true, mLine.getVertices(), mLine.getTexCoords());
+
+ for (int i = 0; i < count; i += 4) {
+ float tx = 0.0f;
+ float ty = 0.0f;
+
+ mLine.update(points[i], points[i + 1], points[i + 2], points[i + 3],
+ paint->getStrokeWidth(), tx, ty);
+
+ const float dx = points[i + 2] - points[i];
+ const float dy = points[i + 3] - points[i + 1];
+ const float mag = sqrtf(dx * dx + dy * dy);
+ const float angle = acos(dx / mag);
+
+ mModelView.loadTranslate(points[i], points[i + 1], 0.0f);
+ if (angle > MIN_ANGLE || angle < -MIN_ANGLE) {
+ mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f);
+ }
+ mModelView.translate(tx, ty, 0.0f);
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+
+ if (mShader) {
+ mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
+ }
+
+ glDrawArrays(GL_TRIANGLES, 0, mLine.getElementsCount());
+ }
+
+ glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
+}
+
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
const Rect& clip = *mSnapshot->clipRect;
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
@@ -793,12 +840,22 @@
float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
bool transforms, bool applyFilters) {
setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit,
- x, y, r, g, b, a, mode, transforms, applyFilters);
+ x, y, r, g, b, a, mode, transforms, applyFilters,
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
}
void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
SkXfermode::Mode mode, bool transforms, bool applyFilters) {
+ setupTextureAlpha8(texture, width, height, textureUnit,
+ x, y, r, g, b, a, mode, transforms, applyFilters,
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
+}
+
+void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
+ GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
+ SkXfermode::Mode mode, bool transforms, bool applyFilters,
+ GLvoid* vertices, GLvoid* texCoords) {
// Describe the required shaders
ProgramDescription description;
description.hasTexture = true;
@@ -827,9 +884,9 @@
// Setup attributes
glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, &mMeshVertices[0].position[0]);
+ gMeshStride, vertices);
glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, &mMeshVertices[0].texture[0]);
+ gMeshStride, texCoords);
// Setup uniforms
if (transforms) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 387fb12..cd7963f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -40,6 +40,7 @@
#include "SkiaShader.h"
#include "SkiaColorFilter.h"
#include "Caches.h"
+#include "Line.h"
namespace android {
namespace uirenderer {
@@ -99,6 +100,7 @@
void drawColor(int color, SkXfermode::Mode mode);
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
void drawPath(SkPath* path, SkPaint* paint);
+ void drawLines(float* points, int count, const SkPaint* paint);
void resetShader();
void setupShader(SkiaShader* shader);
@@ -297,6 +299,15 @@
SkXfermode::Mode mode, bool transforms, bool applyFilters);
/**
+ * Same as above setupTextureAlpha8() but specifies the mesh's vertices
+ * and texCoords pointers.
+ */
+ void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
+ GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
+ SkXfermode::Mode mode, bool transforms, bool applyFilters,
+ GLvoid* vertices, GLvoid* texCoords);
+
+ /**
* Draws text underline and strike-through if needed.
*
* @param text The text to decor
@@ -403,6 +414,10 @@
// List of rectangles to clear due to calls to saveLayer()
Vector<Rect*> mLayers;
+ // Single object used to draw lines
+ Line mLine;
+
+ // Misc
GLint mMaxTextureSize;
}; // class OpenGLRenderer
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index a660730..0a6eca3 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -16,11 +16,8 @@
#define LOG_TAG "OpenGLRenderer"
-#include <cstring>
#include <cmath>
-#include <utils/Log.h>
-
#include "Patch.h"
namespace android {
@@ -34,7 +31,6 @@
// 2 triangles per patch, 3 vertices per triangle
verticesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
vertices = new TextureVertex[verticesCount];
- memset(vertices, 0, sizeof(TextureVertex) * verticesCount);
}
Patch::~Patch() {
@@ -45,9 +41,9 @@
// Vertices management
///////////////////////////////////////////////////////////////////////////////
-void Patch::updateVertices(const SkBitmap* bitmap, float left, float top, float right,
- float bottom, const int32_t* xDivs, const int32_t* yDivs, const uint32_t width,
- const uint32_t height) {
+void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
+ float left, float top, float right, float bottom,
+ const int32_t* xDivs, const int32_t* yDivs, const uint32_t width, const uint32_t height) {
const uint32_t xStretchCount = (width + 1) >> 1;
const uint32_t yStretchCount = (height + 1) >> 1;
@@ -56,9 +52,6 @@
const float meshWidth = right - left;
- const float bitmapWidth = float(bitmap->width());
- const float bitmapHeight = float(bitmap->height());
-
if (xStretchCount > 0) {
uint32_t stretchSize = 0;
for (uint32_t i = 1; i < width; i += 2) {
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index f712455..1d08c64 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -19,8 +19,6 @@
#include <sys/types.h>
-#include <SkBitmap.h>
-
#include "Vertex.h"
namespace android {
@@ -59,8 +57,9 @@
Patch(const uint32_t xCount, const uint32_t yCount);
~Patch();
- void updateVertices(const SkBitmap* bitmap, float left, float top, float right, float bottom,
- const int32_t* xDivs, const int32_t* yDivs,
+ void updateVertices(const float bitmapWidth, const float bitmapHeight,
+ float left, float top, float right, float bottom,
+ const int32_t* xDivs, const int32_t* yDivs,
const uint32_t width, const uint32_t height);
TextureVertex* vertices;
@@ -70,7 +69,8 @@
static inline void generateRow(TextureVertex*& vertex, float y1, float y2,
float v1, float v2, const int32_t xDivs[], uint32_t xCount,
float stretchX, float width, float bitmapWidth);
- static inline void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+ static inline void generateQuad(TextureVertex*& vertex,
+ float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2);
}; // struct Patch
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 5166ee9..f03a602 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -164,4 +164,4 @@
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_RECT_H
+#endif // ANDROID_UI_RECT_H
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index a5e0f78..946cc4b 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -128,6 +128,22 @@
glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
}
+void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
+ const Snapshot& snapshot) {
+ mat4 textureTransform;
+ if (mMatrix) {
+ SkMatrix inverse;
+ mMatrix->invert(&inverse);
+ textureTransform.load(inverse);
+ textureTransform.multiply(modelView);
+ } else {
+ textureTransform.load(modelView);
+ }
+
+ glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+ GL_FALSE, &textureTransform.data[0]);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Linear gradient shader
///////////////////////////////////////////////////////////////////////////////
@@ -185,6 +201,13 @@
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
+void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
+ const Snapshot& snapshot) {
+ mat4 screenSpace(*snapshot.transform);
+ screenSpace.multiply(modelView);
+ glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Compose shader
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index d95e3b0..cc94ae6 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -73,6 +73,10 @@
mGradientCache = gradientCache;
}
+ virtual void updateTransforms(Program* program, const mat4& modelView,
+ const Snapshot& snapshot) {
+ }
+
void setMatrix(SkMatrix* matrix) {
mMatrix = matrix;
}
@@ -106,6 +110,7 @@
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
+ void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
private:
/**
@@ -130,6 +135,7 @@
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
+ void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
private:
float* mBounds;