Add colored rectangles implementation in OpenGLRenderer.

Drawing two rectangles one after the other discards the second one because of
Z buffering issues. This will be fixed in another changelist.

Change-Id: Ida1b3cde8a78e60cacc07e477abc44def527ff67
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index cbbce382f2..c097d7f 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "UIMatrix"
+#define LOG_TAG "Matrix"
 
 #include <math.h>
 #include <stdlib.h>
@@ -27,6 +27,7 @@
 #include "Matrix.h"
 
 namespace android {
+namespace uirenderer {
 
 void Matrix4::loadIdentity() {
 	mMat[0]  = 1.0f;
@@ -175,6 +176,21 @@
     mMat[14] = -(far + near) / (far - near);
 }
 
+#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c)
+
+void Matrix4::mapRect(Rect& r) const {
+	const float sx = mMat[0];
+	const float sy = mMat[5];
+
+	const float tx = mMat[12];
+	const float ty = mMat[13];
+
+	MUL_ADD_STORE(r.left, sx, tx);
+	MUL_ADD_STORE(r.right, sx, tx);
+	MUL_ADD_STORE(r.top, sy, ty);
+	MUL_ADD_STORE(r.bottom, sy, ty);
+}
+
 void Matrix4::dump() const {
 	LOGD("Matrix4[");
 	LOGD("  %f %f %f %f", mMat[0], mMat[4], mMat[ 8], mMat[12]);
@@ -184,4 +200,5 @@
 	LOGD("]");
 }
 
-};
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 80f3fd6..9bd289f 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MATRIX_H
-#define ANDROID_MATRIX_H
+#ifndef ANDROID_UI_MATRIX_H
+#define ANDROID_UI_MATRIX_H
 
 #include <SkMatrix.h>
 
+#include "Rect.h"
+
 namespace android {
+namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Classes
@@ -83,6 +86,8 @@
 	void copyTo(float* v) const;
 	void copyTo(SkMatrix& v) const;
 
+	void mapRect(Rect& r) const;
+
 	void dump() const;
 
 private:
@@ -103,6 +108,7 @@
 
 typedef Matrix4 mat4;
 
+}; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_MATRIX_H
+#endif // ANDROID_UI_MATRIX_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e19795e7..575bc20 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/Log.h>
 
 #include <GLES2/gl2.h>
@@ -32,6 +33,129 @@
 #include "Matrix.h"
 
 namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define SOLID_WHITE { 1.0f, 1.0f, 1.0f, 1.0f }
+
+#define P(x, y) { x, y }
+
+///////////////////////////////////////////////////////////////////////////////
+// Globals
+///////////////////////////////////////////////////////////////////////////////
+
+const Vertex gDrawColorVertices[] = {
+		{ P(0.0f, 0.0f), SOLID_WHITE },
+		{ P(1.0f, 0.0f), SOLID_WHITE },
+		{ P(0.0f, 1.0f), SOLID_WHITE },
+		{ P(1.0f, 1.0f), SOLID_WHITE }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Shaders
+///////////////////////////////////////////////////////////////////////////////
+
+#define SHADER_SOURCE(name, source) const char* name = #source
+
+#include "shaders/drawColor.vert"
+#include "shaders/drawColor.frag"
+
+Program::Program(const char* vertex, const char* fragment) {
+	vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+	fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+
+	id = glCreateProgram();
+	glAttachShader(id, vertexShader);
+	glAttachShader(id, fragmentShader);
+	glLinkProgram(id);
+
+	GLint status;
+	glGetProgramiv(id, GL_LINK_STATUS, &status);
+	if (status != GL_TRUE) {
+		GLint infoLen = 0;
+		glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+		if (infoLen > 1) {
+			char* log = (char*) malloc(sizeof(char) * infoLen);
+			glGetProgramInfoLog(id, infoLen, 0, log);
+			LOGE("Error while linking shaders: %s", log);
+			delete log;
+		}
+		glDeleteProgram(id);
+	}
+}
+
+Program::~Program() {
+	glDeleteShader(vertexShader);
+	glDeleteShader(fragmentShader);
+	glDeleteProgram(id);
+}
+
+void Program::use() {
+	glUseProgram(id);
+}
+
+int Program::addAttrib(const char* name) {
+	int slot = glGetAttribLocation(id, name);
+	attributes.add(name, slot);
+	return slot;
+}
+
+int Program::getAttrib(const char* name) {
+	return attributes.valueFor(name);
+}
+
+int Program::addUniform(const char* name) {
+	int slot = glGetUniformLocation(id, name);
+	uniforms.add(name, slot);
+	return slot;
+}
+
+int Program::getUniform(const char* name) {
+	return uniforms.valueFor(name);
+}
+
+GLuint Program::buildShader(const char* source, GLenum type) {
+	GLuint shader = glCreateShader(type);
+	glShaderSource(shader, 1, &source, 0);
+	glCompileShader(shader);
+
+	GLint status;
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+	if (status != GL_TRUE) {
+		// Some drivers return wrong values for GL_INFO_LOG_LENGTH
+		// use a fixed size instead
+		GLchar log[512];
+		glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
+		LOGE("Error while compiling shader: %s", log);
+		glDeleteShader(shader);
+	}
+
+	return shader;
+}
+
+DrawColorProgram::DrawColorProgram():
+		Program(gDrawColorVertexShader, gDrawColorFragmentShader) {
+	position = addAttrib("position");
+	color = addAttrib("color");
+	projection = addUniform("projection");
+	modelView = addUniform("modelView");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Support
+///////////////////////////////////////////////////////////////////////////////
+
+const Rect& Snapshot::getMappedClip() {
+	if (flags & kFlagDirtyTransform) {
+		flags &= ~kFlagDirtyTransform;
+		mappedClip.set(clipRect);
+		transform.mapRect(mappedClip);
+	}
+	return mappedClip;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
@@ -39,6 +163,8 @@
 
 OpenGLRenderer::OpenGLRenderer() {
     LOGD("Create OpenGLRenderer");
+
+    mDrawColorShader = new DrawColorProgram;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -114,7 +240,6 @@
 }
 
 bool OpenGLRenderer::restoreSnapshot() {
-	// TODO: handle local transformations
 	bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
 
 	mSaveCount--;
@@ -132,18 +257,22 @@
 
 void OpenGLRenderer::translate(float dx, float dy) {
 	mSnapshot->transform.translate(dx, dy, 0.0f);
+	mSnapshot->flags |= Snapshot::kFlagDirtyTransform;
 }
 
 void OpenGLRenderer::rotate(float degrees) {
 	mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f);
+	mSnapshot->flags |= Snapshot::kFlagDirtyTransform;
 }
 
 void OpenGLRenderer::scale(float sx, float sy) {
 	mSnapshot->transform.scale(sx, sy, 1.0f);
+	mSnapshot->flags |= Snapshot::kFlagDirtyTransform;
 }
 
 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
 	mSnapshot->transform.load(*matrix);
+	mSnapshot->flags |= Snapshot::kFlagDirtyTransform;
 }
 
 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
@@ -153,6 +282,7 @@
 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
 	mat4 m(*matrix);
 	mSnapshot->transform.multiply(m);
+	mSnapshot->flags |= Snapshot::kFlagDirtyTransform;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -160,12 +290,15 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setScissorFromClip() {
-	Rect* clip = &(mSnapshot->clipRect);
-	glScissor(clip->left, clip->top, clip->getWidth(), clip->getHeight());
+	const Rect& clip = mSnapshot->getMappedClip();
+	glScissor(clip.left, clip.top, clip.getWidth(), clip.getHeight());
+}
+
+const Rect& OpenGLRenderer::getClipBounds() {
+	return mSnapshot->clipRect;
 }
 
 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) {
-	// TODO: take local translate transform into account
 	bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom);
 	if (clipped) {
 		mSnapshot->flags |= Snapshot::kFlagClipSet;
@@ -179,7 +312,41 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
-	LOGD("Drawing color");
+	GLfloat a = ((color >> 24) & 0xFF) / 255.0f;
+	GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
+	GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
+	GLfloat b = ((color      ) & 0xFF) / 255.0f;
+
+	// TODO Optimize this section
+	const Rect& clip = mSnapshot->getMappedClip();
+
+	mat4 modelView;
+	modelView.loadScale(clip.getWidth(), clip.getHeight(), 1.0f);
+	modelView.translate(clip.left, clip.top, 0.0f);
+
+	float matrix[16];
+	modelView.copyTo(matrix);
+	// TODO Optimize this section
+
+	mDrawColorShader->use();
+
+	glUniformMatrix4fv(mDrawColorShader->projection, 1, GL_FALSE, &mOrthoMatrix[0]);
+	glUniformMatrix4fv(mDrawColorShader->modelView, 1, GL_FALSE, &matrix[0]);
+
+	glEnableVertexAttribArray(mDrawColorShader->position);
+
+	GLsizei stride = sizeof(Vertex);
+	const GLvoid* p = &gDrawColorVertices[0].position[0];
+
+	glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, stride, p);
+	glVertexAttrib4f(mDrawColorShader->color, r, g, b, a);
+
+	GLsizei vertexCount = sizeof(gDrawColorVertices) / sizeof(Vertex);
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
+
+	glDisableVertexAttribArray(mDrawColorShader->position);
+	glDisableVertexAttribArray(mDrawColorShader->color);
 }
 
+}; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 595768c..88cbc1c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -14,18 +14,23 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_OPENGL_RENDERER_H
-#define ANDROID_OPENGL_RENDERER_H
+#ifndef ANDROID_UI_OPENGL_RENDERER_H
+#define ANDROID_UI_OPENGL_RENDERER_H
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 #include <SkMatrix.h>
 #include <SkXfermode.h>
 
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 
 #include "Matrix.h"
 #include "Rect.h"
 
 namespace android {
+namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Support
@@ -36,14 +41,20 @@
 	Snapshot() {
 	}
 
-	Snapshot(const sp<Snapshot> s): transform(s->transform), clipRect(s->clipRect),
-				flags(0), previous(s) {
+	Snapshot(const sp<Snapshot> s):
+			transform(s->transform),
+			clipRect(s->clipRect),
+			flags(kFlagDirtyTransform),
+			previous(s) {
 	}
 
 	enum Flags {
 		kFlagClipSet = 0x1,
+		kFlagDirtyTransform = 0x2,
 	};
 
+	const Rect& getMappedClip();
+
 	// Local transformations
 	mat4 transform;
 
@@ -55,7 +66,58 @@
 
 	// Previous snapshot in the frames stack
 	sp<Snapshot> previous;
-}; // struct Snapshot
+
+private:
+	// Clipping rectangle mapped with the transform
+	Rect mappedClip;
+}; // class Snapshot
+
+struct Vertex {
+	float position[2];
+	float color[4];
+}; // struct Vertex
+
+typedef char* shader;
+
+class Program: public LightRefBase<Program> {
+public:
+	Program(const char* vertex, const char* fragment);
+	~Program();
+
+	void use();
+
+protected:
+	int addAttrib(const char* name);
+	int getAttrib(const char* name);
+
+	int addUniform(const char* name);
+	int getUniform(const char* name);
+
+private:
+	GLuint buildShader(const char* source, GLenum type);
+
+	// Handle of the OpenGL program
+	GLuint id;
+
+	// Handles of the shaders
+	GLuint vertexShader;
+	GLuint fragmentShader;
+
+	// Keeps track of attributes and uniforms slots
+	KeyedVector<const char*, int> attributes;
+	KeyedVector<const char*, int> uniforms;
+}; // class Program
+
+class DrawColorProgram: public Program {
+public:
+	DrawColorProgram();
+
+	int position;
+	int color;
+
+	int projection;
+	int modelView;
+};
 
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
@@ -82,6 +144,7 @@
     void getMatrix(SkMatrix* matrix);
     void concatMatrix(SkMatrix* matrix);
 
+    const Rect& getClipBounds();
     bool clipRect(float left, float top, float right, float bottom);
 
     void drawColor(int color, SkXfermode::Mode mode);
@@ -104,8 +167,12 @@
     Snapshot mFirstSnapshot;
     // Current state
     sp<Snapshot> mSnapshot;
+
+    // Shaders
+    sp<DrawColorProgram> mDrawColorShader;
 }; // class OpenGLRenderer
 
+}; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_OPENGL_RENDERER_H
+#endif // ANDROID_UI_OPENGL_RENDERER_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 724bd1a..fcf11e9 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_RECT_H
-#define ANDROID_RECT_H
+#ifndef ANDROID_UI_RECT_H
+#define ANDROID_UI_RECT_H
 
 namespace android {
+namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Structs
@@ -29,7 +30,19 @@
 	float right;
 	float bottom;
 
-	Rect(): left(0), top(0), right(0), bottom(0) { }
+	Rect():
+			left(0),
+			top(0),
+			right(0),
+			bottom(0) {
+	}
+
+	Rect(float left, float top, float right, float bottom):
+			left(left),
+			top(top),
+			right(right),
+			bottom(bottom) {
+	}
 
 	Rect(const Rect& r) {
 		set(r);
@@ -120,6 +133,7 @@
 
 }; // struct Rect
 
+}; // namespace uirenderer
 }; // namespace android
 
 #endif // ANDROID_RECT_H
diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag
new file mode 100644
index 0000000..f753abb
--- /dev/null
+++ b/libs/hwui/shaders/drawColor.frag
@@ -0,0 +1,11 @@
+SHADER_SOURCE(gDrawColorFragmentShader,
+
+precision mediump float;
+
+varying vec4 outColor;
+
+void main(void) {
+    gl_FragColor = outColor;
+}
+
+);
diff --git a/libs/hwui/shaders/drawColor.vert b/libs/hwui/shaders/drawColor.vert
new file mode 100644
index 0000000..fd3cb45
--- /dev/null
+++ b/libs/hwui/shaders/drawColor.vert
@@ -0,0 +1,16 @@
+SHADER_SOURCE(gDrawColorVertexShader,
+
+attribute vec4 position;
+attribute vec4 color;
+
+uniform mat4 projection;
+uniform mat4 modelView;
+
+varying vec4 outColor;
+
+void main(void) {
+	outColor = color;
+	gl_Position = projection * modelView * position;
+}
+
+);