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/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