Add support for transformations.
This change adds partial support for the following transforms:
- scale()
- translate()
- rotate()
- setMatrix()
- getMatrix()
The transform is stored in a snapshot and saved/restored as needed.
The transform is currently not applied to the clip rect and is not
mapped to the vertex shader.
Change-Id: Id48993453311200804149917d0c126a4d0471226
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index fbfea95..8df2e86 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -212,8 +212,10 @@
@Override
public void translate(float dx, float dy) {
- // TODO: Implement
+ nTranslate(mRenderer, dx, dy);
}
+
+ private native void nTranslate(int renderer, float dx, float dy);
@Override
public void skew(float sx, float sy) {
@@ -222,30 +224,39 @@
@Override
public void rotate(float degrees) {
- // TODO: Implement
+ nRotate(mRenderer, degrees);
}
+
+ private native void nRotate(int renderer, float degrees);
@Override
public void scale(float sx, float sy) {
- // TODO: Implement
+ nScale(mRenderer, sx, sy);
}
-
+ private native void nScale(int renderer, float sx, float sy);
+
@Override
public void setMatrix(Matrix matrix) {
- // TODO: Implement
+ nSetMatrix(mRenderer, matrix.native_instance);
}
+
+ private native void nSetMatrix(int renderer, int matrix);
@Override
- public void getMatrix(Matrix ctm) {
- // TODO: Implement
+ public void getMatrix(Matrix matrix) {
+ nGetMatrix(mRenderer, matrix.native_instance);
}
+
+ private native void nGetMatrix(int renderer, int matrix);
@Override
public void concat(Matrix matrix) {
- // TODO: Implement
+ nConcatMatrix(mRenderer, matrix.native_instance);
}
+ private native void nConcatMatrix(int renderer, int matrix);
+
///////////////////////////////////////////////////////////////////////////
// State management
///////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 8c2a04c..1ca172d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -18,12 +18,11 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <SkMatrix.h>
#include <SkXfermode.h>
#include <OpenGLRenderer.h>
-#define UI ((OpenGLRenderer*) renderer)
-
namespace android {
// ----------------------------------------------------------------------------
@@ -34,73 +33,104 @@
return new OpenGLRenderer;
}
-static void android_view_GLES20Renderer_destroyRenderer(JNIEnv* env, jobject canvas, jint renderer) {
- delete UI;
+static void android_view_GLES20Renderer_destroyRenderer(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer) {
+ delete renderer;
}
// ----------------------------------------------------------------------------
// Setup
// ----------------------------------------------------------------------------
-static void android_view_GLES20Renderer_setViewport(JNIEnv* env, jobject canvas, jint renderer,
- jint width, jint height) {
-
- UI->setViewport(width, height);
+static void android_view_GLES20Renderer_setViewport(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jint width, jint height) {
+ renderer->setViewport(width, height);
}
-static void android_view_GLES20Renderer_prepare(JNIEnv* env, jobject canvas, jint renderer) {
-
- UI->prepare();
+static void android_view_GLES20Renderer_prepare(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer) {
+ renderer->prepare();
}
// ----------------------------------------------------------------------------
// State
// ----------------------------------------------------------------------------
-static jint android_view_GLES20Renderer_save(JNIEnv* env, jobject canvas, jint renderer,
+static jint android_view_GLES20Renderer_save(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer,
jint flags) {
-
- return UI->save(flags);
+ return renderer->save(flags);
}
-static jint android_view_GLES20Renderer_getSaveCount(JNIEnv* env, jobject canvas, jint renderer) {
- return UI->getSaveCount();
+static jint android_view_GLES20Renderer_getSaveCount(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer) {
+ return renderer->getSaveCount();
}
-static void android_view_GLES20Renderer_restore(JNIEnv* env, jobject canvas, jint renderer) {
- UI->restore();
+static void android_view_GLES20Renderer_restore(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer) {
+ renderer->restore();
}
-static void android_view_GLES20Renderer_restoreToCount(JNIEnv* env, jobject canvas, jint renderer,
- jint saveCount) {
-
- UI->restoreToCount(saveCount);
+static void android_view_GLES20Renderer_restoreToCount(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jint saveCount) {
+ renderer->restoreToCount(saveCount);
}
// ----------------------------------------------------------------------------
// Clipping
// ----------------------------------------------------------------------------
-static bool android_view_GLES20Renderer_clipRectF(JNIEnv* env, jobject canvas, jint renderer,
- jfloat left, jfloat top, jfloat right, jfloat bottom) {
-
- return UI->clipRect(left, top, right, bottom);
+static bool android_view_GLES20Renderer_clipRectF(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
+ return renderer->clipRect(left, top, right, bottom);
}
-static bool android_view_GLES20Renderer_clipRect(JNIEnv* env, jobject canvas, jint renderer,
- jint left, jint top, jint right, jint bottom) {
+static bool android_view_GLES20Renderer_clipRect(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom) {
+ return renderer->clipRect(float(left), float(top), float(right), float(bottom));
+}
- return UI->clipRect(float(left), float(top), float(right), float(bottom));
+// ----------------------------------------------------------------------------
+// Transforms
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20Renderer_translate(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat dx, jfloat dy) {
+ renderer->translate(dx, dy);
+}
+
+static void android_view_GLES20Renderer_rotate(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat degrees) {
+ renderer->rotate(degrees);
+}
+
+static void android_view_GLES20Renderer_scale(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat sx, jfloat sy) {
+ renderer->scale(sx, sy);
+}
+
+static void android_view_GLES20Renderer_setMatrix(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, SkMatrix* matrix) {
+ renderer->setMatrix(matrix);
+}
+
+static void android_view_GLES20Renderer_getMatrix(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, SkMatrix* matrix) {
+ renderer->getMatrix(matrix);
+}
+
+static void android_view_GLES20Renderer_concatMatrix(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, SkMatrix* matrix) {
+ renderer->concatMatrix(matrix);
}
// ----------------------------------------------------------------------------
// Drawing
// ----------------------------------------------------------------------------
-static void android_view_GLES20Renderer_drawColor(JNIEnv* env, jobject canvas, jint renderer,
- jint color, jint mode) {
-
- UI->drawColor(color, (SkXfermode::Mode) mode);
+static void android_view_GLES20Renderer_drawColor(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jint color, jint mode) {
+ renderer->drawColor(color, (SkXfermode::Mode) mode);
}
// ----------------------------------------------------------------------------
@@ -123,6 +153,14 @@
{ "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF },
{ "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect },
+ { "nTranslate", "(IFF)V", (void*) android_view_GLES20Renderer_translate },
+ { "nRotate", "(IF)V", (void*) android_view_GLES20Renderer_rotate },
+ { "nScale", "(IFF)V", (void*) android_view_GLES20Renderer_scale },
+
+ { "nSetMatrix", "(II)V", (void*) android_view_GLES20Renderer_setMatrix },
+ { "nGetMatrix", "(II)V", (void*) android_view_GLES20Renderer_getMatrix },
+ { "nConcatMatrix", "(II)V", (void*) android_view_GLES20Renderer_concatMatrix },
+
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor },
};
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index f549900..b336995 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -37,7 +37,10 @@
public static final int MPERSP_1 = 7; //!< use with getValues/setValues
public static final int MPERSP_2 = 8; //!< use with getValues/setValues
- /* package */ int native_instance;
+ /**
+ * @hide
+ */
+ public int native_instance;
/**
* Create an identity matrix
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 638c1b8..cbbce382f2 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -22,30 +22,32 @@
#include <utils/Log.h>
+#include <SkMatrix.h>
+
#include "Matrix.h"
namespace android {
void Matrix4::loadIdentity() {
- mMat[0] = 1;
- mMat[1] = 0;
- mMat[2] = 0;
- mMat[3] = 0;
+ mMat[0] = 1.0f;
+ mMat[1] = 0.0f;
+ mMat[2] = 0.0f;
+ mMat[3] = 0.0f;
- mMat[4] = 0;
- mMat[5] = 1;
- mMat[6] = 0;
- mMat[7] = 0;
+ mMat[4] = 0.0f;
+ mMat[5] = 1.0f;
+ mMat[6] = 0.0f;
+ mMat[7] = 0.0f;
- mMat[8] = 0;
- mMat[9] = 0;
- mMat[10] = 1;
- mMat[11] = 0;
+ mMat[8] = 0.0f;
+ mMat[9] = 0.0f;
+ mMat[10] = 1.0f;
+ mMat[11] = 0.0f;
- mMat[12] = 0;
- mMat[13] = 0;
- mMat[14] = 0;
- mMat[15] = 1;
+ mMat[12] = 0.0f;
+ mMat[13] = 0.0f;
+ mMat[14] = 0.0f;
+ mMat[15] = 1.0f;
}
void Matrix4::load(const float* v) {
@@ -56,6 +58,40 @@
memcpy(mMat, v.mMat, sizeof(mMat));
}
+void Matrix4::load(const SkMatrix& v) {
+ memset(mMat, 0, sizeof(mMat));
+
+ mMat[0] = v[SkMatrix::kMScaleX];
+ mMat[4] = v[SkMatrix::kMSkewX];
+ mMat[12] = v[SkMatrix::kMTransX];
+
+ mMat[1] = v[SkMatrix::kMSkewY];
+ mMat[5] = v[SkMatrix::kMScaleY];
+ mMat[13] = v[SkMatrix::kMTransY];
+
+ mMat[3] = v[SkMatrix::kMPersp0];
+ mMat[7] = v[SkMatrix::kMPersp1];
+ mMat[15] = v[SkMatrix::kMPersp2];
+
+ mMat[10] = 1.0f;
+}
+
+void Matrix4::copyTo(SkMatrix& v) const {
+ v.reset();
+
+ v.set(SkMatrix::kMScaleX, mMat[0]);
+ v.set(SkMatrix::kMSkewX, mMat[4]);
+ v.set(SkMatrix::kMTransX, mMat[12]);
+
+ v.set(SkMatrix::kMSkewY, mMat[1]);
+ v.set(SkMatrix::kMScaleY, mMat[5]);
+ v.set(SkMatrix::kMTransY, mMat[13]);
+
+ v.set(SkMatrix::kMPersp0, mMat[3]);
+ v.set(SkMatrix::kMPersp1, mMat[7]);
+ v.set(SkMatrix::kMPersp2, mMat[15]);
+}
+
void Matrix4::copyTo(float* v) const {
memcpy(v, mMat, sizeof(mMat));
}
@@ -75,13 +111,13 @@
}
void Matrix4::loadRotate(float angle, float x, float y, float z) {
- mMat[3] = 0;
- mMat[7] = 0;
- mMat[11] = 0;
- mMat[12] = 0;
- mMat[13] = 0;
- mMat[14] = 0;
- mMat[15] = 1;
+ mMat[3] = 0.0f;
+ mMat[7] = 0.0f;
+ mMat[11] = 0.0f;
+ mMat[12] = 0.0f;
+ mMat[13] = 0.0f;
+ mMat[14] = 0.0f;
+ mMat[15] = 1.0f;
angle *= float(M_PI / 180.0f);
float c = cosf(angle);
@@ -131,9 +167,9 @@
void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
loadIdentity();
- mMat[0] = 2 / (right - left);
- mMat[5] = 2 / (top - bottom);
- mMat[10] = -2 / (far - near);
+ mMat[0] = 2.0f / (right - left);
+ mMat[5] = 2.0f / (top - bottom);
+ mMat[10] = -2.0f / (far - near);
mMat[12] = -(right + left) / (right - left);
mMat[13] = -(top + bottom) / (top - bottom);
mMat[14] = -(far + near) / (far - near);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 51014a9..80f3fd6 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_MATRIX_H
#define ANDROID_MATRIX_H
+#include <SkMatrix.h>
+
namespace android {
///////////////////////////////////////////////////////////////////////////////
@@ -37,10 +39,15 @@
load(v);
}
+ Matrix4(const SkMatrix& v) {
+ load(v);
+ }
+
void loadIdentity();
void load(const float* v);
void load(const Matrix4& v);
+ void load(const SkMatrix& v);
void loadTranslate(float x, float y, float z);
void loadScale(float sx, float sy, float sz);
@@ -74,10 +81,11 @@
}
void copyTo(float* v) const;
+ void copyTo(SkMatrix& v) const;
void dump() const;
-//private:
+private:
inline float get(int i, int j) const {
return mMat[i * 4 + j];
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1416ce1..e19795e7 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -33,17 +33,22 @@
namespace android {
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
OpenGLRenderer::OpenGLRenderer() {
LOGD("Create OpenGLRenderer");
-
- mSnapshot = new Snapshot;
- mSaveCount = 0;
}
OpenGLRenderer::~OpenGLRenderer() {
LOGD("Destroy OpenGLRenderer");
}
+///////////////////////////////////////////////////////////////////////////////
+// Setup
+///////////////////////////////////////////////////////////////////////////////
+
void OpenGLRenderer::setViewport(int width, int height) {
glViewport(0, 0, width, height);
@@ -56,15 +61,23 @@
}
void OpenGLRenderer::prepare() {
+ mSnapshot = &mFirstSnapshot;
+ mSaveCount = 0;
+
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
+
mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight);
}
+///////////////////////////////////////////////////////////////////////////////
+// State management
+///////////////////////////////////////////////////////////////////////////////
+
int OpenGLRenderer::getSaveCount() const {
return mSaveCount;
}
@@ -97,8 +110,7 @@
int OpenGLRenderer::saveSnapshot() {
mSnapshot = new Snapshot(mSnapshot);
- mSaveCount++;
- return mSaveCount;
+ return ++mSaveCount;
}
bool OpenGLRenderer::restoreSnapshot() {
@@ -106,14 +118,50 @@
bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
mSaveCount--;
- mSnapshot = mSnapshot->previous;
+
+ // Do not merge these two lines!
+ sp<Snapshot> previous = mSnapshot->previous;
+ mSnapshot = previous;
return restoreClip;
}
+///////////////////////////////////////////////////////////////////////////////
+// Transforms
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::translate(float dx, float dy) {
+ mSnapshot->transform.translate(dx, dy, 0.0f);
+}
+
+void OpenGLRenderer::rotate(float degrees) {
+ mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f);
+}
+
+void OpenGLRenderer::scale(float sx, float sy) {
+ mSnapshot->transform.scale(sx, sy, 1.0f);
+}
+
+void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
+ mSnapshot->transform.load(*matrix);
+}
+
+void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
+ mSnapshot->transform.copyTo(*matrix);
+}
+
+void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
+ mat4 m(*matrix);
+ mSnapshot->transform.multiply(m);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clipping
+///////////////////////////////////////////////////////////////////////////////
+
void OpenGLRenderer::setScissorFromClip() {
- Rect clip = mSnapshot->clipRect;
- glScissor(clip.left, clip.top, clip.getWidth(), clip.getHeight());
+ Rect* clip = &(mSnapshot->clipRect);
+ glScissor(clip->left, clip->top, clip->getWidth(), clip->getHeight());
}
bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) {
@@ -126,6 +174,10 @@
return clipped;
}
+///////////////////////////////////////////////////////////////////////////////
+// Drawing
+///////////////////////////////////////////////////////////////////////////////
+
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
LOGD("Drawing color");
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 8a541fc..595768c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -17,24 +17,36 @@
#ifndef ANDROID_OPENGL_RENDERER_H
#define ANDROID_OPENGL_RENDERER_H
+#include <SkMatrix.h>
#include <SkXfermode.h>
#include <utils/RefBase.h>
+#include "Matrix.h"
#include "Rect.h"
namespace android {
+///////////////////////////////////////////////////////////////////////////////
+// Support
+///////////////////////////////////////////////////////////////////////////////
+
class Snapshot: public LightRefBase<Snapshot> {
public:
- Snapshot() { }
+ Snapshot() {
+ }
- Snapshot(const sp<Snapshot> s): clipRect(s->clipRect), flags(0), previous(s) { }
+ Snapshot(const sp<Snapshot> s): transform(s->transform), clipRect(s->clipRect),
+ flags(0), previous(s) {
+ }
enum Flags {
kFlagClipSet = 0x1,
};
+ // Local transformations
+ mat4 transform;
+
// Clipping rectangle at the time of this snapshot
Rect clipRect;
@@ -45,6 +57,10 @@
sp<Snapshot> previous;
}; // struct Snapshot
+///////////////////////////////////////////////////////////////////////////////
+// Renderer
+///////////////////////////////////////////////////////////////////////////////
+
class OpenGLRenderer {
public:
OpenGLRenderer();
@@ -58,6 +74,14 @@
void restore();
void restoreToCount(int saveCount);
+ void translate(float dx, float dy);
+ void rotate(float degrees);
+ void scale(float sx, float sy);
+
+ void setMatrix(SkMatrix* matrix);
+ void getMatrix(SkMatrix* matrix);
+ void concatMatrix(SkMatrix* matrix);
+
bool clipRect(float left, float top, float right, float bottom);
void drawColor(int color, SkXfermode::Mode mode);
@@ -76,6 +100,8 @@
// Number of saved states
int mSaveCount;
+ // Base state
+ Snapshot mFirstSnapshot;
// Current state
sp<Snapshot> mSnapshot;
}; // class OpenGLRenderer