package com.glview.hwui;
import com.glview.graphics.Bitmap;
import com.glview.graphics.Rect;
import com.glview.graphics.RectF;
import com.glview.graphics.drawable.ninepatch.NinePatch;
import com.glview.graphics.mesh.BasicMesh;
import com.glview.hwui.op.ClipRectOp;
import com.glview.hwui.op.DisplayListData;
import com.glview.hwui.op.DrawBitmapBatchRectOp;
import com.glview.hwui.op.DrawBitmapMeshOp;
import com.glview.hwui.op.DrawBitmapOp;
import com.glview.hwui.op.DrawBitmapRectFOp;
import com.glview.hwui.op.DrawBitmapRectOp;
import com.glview.hwui.op.DrawLineOp;
import com.glview.hwui.op.DrawMeshOp;
import com.glview.hwui.op.DrawOp;
import com.glview.hwui.op.DrawPatchOp;
import com.glview.hwui.op.DrawRectOp;
import com.glview.hwui.op.DrawTextOp;
import com.glview.hwui.op.RenderNodeOp;
import com.glview.hwui.op.RestoreOp;
import com.glview.hwui.op.RestoreToCountOp;
import com.glview.hwui.op.RotateOp;
import com.glview.hwui.op.SaveOp;
import com.glview.hwui.op.ScaleOp;
import com.glview.hwui.op.StateOp;
import com.glview.hwui.op.TranslateOp;
import com.glview.pool.Pool;
import com.glview.pool.Poolable;
/**
* This canvas is used to record our OpenGL operations,
* we will replay these operations in the {@link RenderThread}
* @see RenderNode#replay(GLCanvas)
*
* @author lijing.lj
*/
class GLRecordingCanvas extends AbsGLCanvas implements Poolable {
static Pool<GLRecordingCanvas> sPoll = new Pool<GLRecordingCanvas>(false);
DisplayListData mDisplayListData = null;
CanvasOp mLastCanvasNode = null;
float mTranslateX = 0, mTranslateY = 0, mTranslateZ = 0;
boolean mHasDeferredTranslate = false;
int mRestoreSaveCount = -1;
private GLRecordingCanvas() {}
static GLRecordingCanvas obtain(RenderNode renderNode) {
GLRecordingCanvas canvas = (GLRecordingCanvas) sPoll.poll(GLRecordingCanvas.class, false);
if (canvas == null) {
canvas = new GLRecordingCanvas();
}
return canvas;
}
void recycle() {
mDisplayListData = null;
mLastCanvasNode = null;
mTranslateX = mTranslateY = mTranslateZ = 0;
sPoll.push(this);
}
DisplayListData endRecording() {
flush();
return mDisplayListData;
}
void flush() {
flushRestoreToCount();
flushTranslate();
}
void ensureDisplayListData() {
if (mDisplayListData == null) {
mDisplayListData = DisplayListData.obtain();
}
}
/**
* Record the CanvasOp to display list
* @param op
*/
private void addOpAndUpdateChunk(CanvasOp op) {
ensureDisplayListData();
if (mDisplayListData.mCanvasOps == null) {
mDisplayListData.mCanvasOps = op;
}
if (mLastCanvasNode == null) {
mLastCanvasNode = op;
} else {
mLastCanvasNode.mNext = op;
mLastCanvasNode = op;
}
}
private void flushAndAddOp(CanvasOp op) {
flushRestoreToCount();
flushTranslate();
addOpAndUpdateChunk(op);
}
void addStateOp(StateOp op) {
flushAndAddOp(op);
}
void addDrawOp(DrawOp op) {
flushAndAddOp(op);
mDisplayListData.mHasDrawOp = true;
}
void addRenderNodeOp(RenderNodeOp op) {
addDrawOp(op);
}
void flushTranslate() {
if (mHasDeferredTranslate) {
if (mTranslateX != 0.0f || mTranslateY != 0.0f || mTranslateZ != 0.0f) {
addOpAndUpdateChunk(TranslateOp.obtain(mTranslateX, mTranslateY, mTranslateZ));
mTranslateX = mTranslateY = mTranslateZ = 0.0f;
}
mHasDeferredTranslate = false;
}
}
void flushRestoreToCount() {
if (mRestoreSaveCount >= 0) {
addOpAndUpdateChunk(RestoreToCountOp.obtain(mRestoreSaveCount));
mRestoreSaveCount = -1;
}
}
@Override
public void translate(float x, float y) {
translate(x, y, 0);
}
@Override
public void translate(float x, float y, float z) {
mHasDeferredTranslate = true;
mTranslateX += x;
mTranslateY += y;
mTranslateZ += z;
flushRestoreToCount();
}
@Override
public void scale(float sx, float sy, float sz) {
addStateOp(ScaleOp.obtain(sx, sy, sz));
}
@Override
public void rotate(float degrees, float x, float y, float z) {
addStateOp(RotateOp.obtain(degrees, x, y, z));
}
@Override
public void clipRect(Rect r) {
addStateOp(ClipRectOp.obtain(r));
}
@Override
public void clipRect(float left, float top, float right, float bottom) {
addStateOp(ClipRectOp.obtain(left, top, right, bottom));
}
@Override
public int save(int saveFlags) {
addStateOp(SaveOp.obtain(saveFlags));
return 0;
}
@Override
public void restore() {
addStateOp(RestoreOp.obtain());
}
@Override
public void restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
flushTranslate();
}
@Override
public void drawRenderNode(RenderNode renderNode) {
addRenderNodeOp(RenderNodeOp.obtain(renderNode));
}
@Override
public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
addDrawOp(DrawLineOp.obtain(x1, y1, x2, y2, paint));
}
@Override
public void drawRect(float left, float top, float right, float bottom,
GLPaint paint) {
addDrawOp(DrawRectOp.obtain(left, top, right, bottom, paint));
}
@Override
public void drawBitmap(Bitmap bitmap, float x, float y, GLPaint paint) {
addDrawOp(DrawBitmapOp.obtain(bitmap, x, y, paint));
}
@Override
public void drawBitmap(Bitmap bitmap, RectF source, RectF target,
GLPaint paint) {
addDrawOp(DrawBitmapRectFOp.obtain(bitmap, source, target, paint));
}
@Override
public void drawBitmap(Bitmap bitmap, Rect source, Rect target,
GLPaint paint) {
addDrawOp(DrawBitmapRectOp.obtain(bitmap, source, target, paint));
}
@Override
public void drawBitmapBatch(Bitmap bitmap, Rect source, Rect target,
GLPaint paint) {
addDrawOp(DrawBitmapBatchRectOp.obtain(bitmap, source, target, paint));
}
@Override
public void drawPatch(NinePatch patch, Rect rect, GLPaint paint) {
addDrawOp(DrawPatchOp.obtain(patch, rect, paint));
}
@Override
public void drawMesh(BasicMesh mesh, GLPaint paint) {
addDrawOp(DrawMeshOp.obtain(mesh, paint));
}
@Override
public void drawBitmapMesh(Bitmap bitmap, BasicMesh mesh, GLPaint paint) {
addDrawOp(DrawBitmapMeshOp.obtain(bitmap, mesh, paint));
}
@Override
public void drawText(CharSequence text, int start, int end, float x,
float y, GLPaint paint, boolean drawDefer) {
addDrawOp(DrawTextOp.obtain(text, start, end, x, y, paint, drawDefer));
}
}