/* * * * * * * Copyright (C) 2016 ChillingVan * * * * * * 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. * * * */ package com.chillingvan.canvasgl; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.opengl.GLES20; import android.opengl.Matrix; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.chillingvan.canvasgl.glcanvas.BasicTexture; import com.chillingvan.canvasgl.glcanvas.BitmapTexture; import com.chillingvan.canvasgl.glcanvas.GLCanvas; import com.chillingvan.canvasgl.glcanvas.GLES20Canvas; import com.chillingvan.canvasgl.glcanvas.GLPaint; import com.chillingvan.canvasgl.glcanvas.RawTexture; import com.chillingvan.canvasgl.matrix.BaseBitmapMatrix; import com.chillingvan.canvasgl.matrix.IBitmapMatrix; import com.chillingvan.canvasgl.textureFilter.TextureFilter; /** * Created by Matthew on 2016/9/26. */ public interface ICanvasGL { BitmapTexture bindBitmapToTexture(int whichTexture, Bitmap bitmap); void bindRawTexture(int whichTexture, RawTexture texture); void beginRenderTarget(RawTexture texture); void endRenderTarget(); GLCanvas getGlCanvas(); void drawSurfaceTexture(BasicTexture texture, @Nullable SurfaceTexture surfaceTexture, int left, int top, int right, int bottom); void drawSurfaceTexture(BasicTexture texture, @Nullable SurfaceTexture surfaceTexture, int left, int top, int right, int bottom, TextureFilter textureFilter); void drawSurfaceTexture(BasicTexture texture, @Nullable SurfaceTexture surfaceTexture, @NonNull IBitmapMatrix matrix); void drawSurfaceTexture(BasicTexture texture, @Nullable SurfaceTexture surfaceTexture, @NonNull IBitmapMatrix matrix, @NonNull TextureFilter textureFilter); void drawSurfaceTexture(BasicTexture texture, SurfaceTexture surfaceTexture, int left, int top, int right, int bottom, @NonNull IBitmapMatrix matrix, TextureFilter textureFilter); void drawBitmap(Bitmap bitmap, @NonNull IBitmapMatrix matrix); void drawBitmap(Bitmap bitmap, IBitmapMatrix matrix, @NonNull TextureFilter textureFilter); void drawBitmap(Bitmap bitmap, Rect src, RectF dst); void drawBitmap(Bitmap bitmap, int left, int top); void drawBitmap(Bitmap bitmap, int left, int top, @NonNull TextureFilter textureFilter); void drawBitmap(Bitmap bitmap, Rect src, Rect dst); void drawBitmap(Bitmap bitmap, RectF src, RectF dst, @NonNull TextureFilter textureFilter); void drawBitmap(Bitmap bitmap, int left, int top, int width, int height); void drawBitmap(Bitmap bitmap, int left, int top, int width, int height, @NonNull TextureFilter textureFilter); void invalidateTextureContent(Bitmap bitmap); void drawCircle(float x, float y, float radius, GLPaint paint); void drawLine(float startX, float startY, float stopX, float stopY, GLPaint paint); void drawRect(@NonNull RectF rect, @NonNull GLPaint paint); void drawRect(@NonNull Rect r, @NonNull GLPaint paint); void drawRect(float left, float top, float right, float bottom, GLPaint paint); void save(); void save(int saveFlags); void restore(); void rotate(float degrees); void rotate(float degrees, float px, float py); void scale(float sx, float sy); void scale(float sx, float sy, float px, float py); void translate(float dx, float dy); void clearBuffer(); void clearBuffer(int color); void setSize(int width, int height); int getWidth(); int getHeight(); void resume(); void pause(); /** * If used in a texture view, make sure the setOpaque(false) is called. * * @param alpha alpha value */ void setAlpha(@IntRange(from = 0, to = 255) int alpha); /** * Default bitmap matrix. It uses perspective projection type. So it can have 3D feel. As a result, rotate around X, rotate around Y, rotate around Z are supported. */ class BitmapMatrix extends BaseBitmapMatrix { private final int maxViewPortInt; public BitmapMatrix() { reset(); int[] maxViewPort = new int[1]; GLES20.glGetIntegerv(GLES20.GL_MAX_VIEWPORT_DIMS, maxViewPort, 0); maxViewPortInt = maxViewPort[0]; } public void translate(float dx, float dy) { transform[TRANSLATE_X] += dx; transform[TRANSLATE_Y] += dy; } /** * Should not be larger than 2 * GLES20.GL_MAX_VIEWPORT_DIMS * @param sx * @param sy */ public void scale(float sx, float sy) { transform[SCALE_X] *= sx; transform[SCALE_Y] *= sy; } public void rotateX(float degrees) { transform[ROTATE_X] += degrees; } public void rotateY(float degrees) { transform[ROTATE_Y] += degrees; } public void rotateZ(float degrees) { transform[ROTATE_Z] += degrees; } @Override public float[] obtainResultMatrix(int viewportW, int viewportH, float x, float y, float drawW, float drawH) { transform[TRANSLATE_X] += x; transform[TRANSLATE_Y] += y; // The ratio is used to make sure the openGL view port contain the origin view port, so that the picture won't be cropped. // double viewport size is enough to include the origin view port int viewPortRatio = 2; // Move view port to make sure the picture in the center of the view port. final float absTransX = Math.abs(transform[TRANSLATE_X]); // Make sure viewportX + realViewportW includes viewportW final float absTransY = Math.abs(transform[TRANSLATE_Y]); // Make sure realViewportH - viewportY includes viewportH int realViewportW = (int) (viewPortRatio * viewportW + 2*absTransX); int realViewportH = (int) (viewPortRatio * viewportH + 2*absTransY); realViewportW = Math.max(realViewportW, maxViewPortInt); realViewportH = Math.min(realViewportH, maxViewPortInt); int viewportX = (int) (drawW / 2 - realViewportW / 2 + transform[TRANSLATE_X]); int viewportY = (int) (-drawH / 2 - transform[TRANSLATE_Y] - realViewportH / 2 + viewportH); GLES20.glViewport(viewportX, viewportY, realViewportW, realViewportH); float ratio = (float) realViewportW / realViewportH; Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, NEAR, FAR); Matrix.setLookAtM(mViewMatrix, 0, 0, 0, EYEZ, 0, 0, 0, 0, 1, 0); Matrix.multiplyMM(viewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); // reverse Y Matrix.scaleM(mModelMatrix, 0, 1, -1, 1); GLES20Canvas.printMatrix("model init:", mModelMatrix, 0); Matrix.rotateM(mModelMatrix, 0, transform[ROTATE_X], 1f, 0, 0); Matrix.rotateM(mModelMatrix, 0, transform[ROTATE_Y], 0, 1f, 0); Matrix.rotateM(mModelMatrix, 0, transform[ROTATE_Z], 0, 0, 1f); GLES20Canvas.printMatrix("model rotated:", mModelMatrix, 0); // Translate to the middleZ of the projection // realW,realH are the w,h in the middleZ of the projection float realW = (2 * ratio) * drawW / realViewportW * Z_RATIO; float realH = 2 * drawH / realViewportH * Z_RATIO; // Need to make X, Y to the middleZ of the plane, too. The middleZ of the plane is (0, 0, -Z_RATIO + EYEZ) Matrix.translateM(tempMultiplyMatrix4, 0, mModelMatrix, 0, -realW/2, -realH/2, -Z_RATIO + EYEZ); GLES20Canvas.printMatrix("model translated:", tempMultiplyMatrix4, 0); Matrix.scaleM(tempMultiplyMatrix4, 0, transform[SCALE_X] * realW, transform[SCALE_Y] * realH, 1); GLES20Canvas.printMatrix("model scaled:", tempMultiplyMatrix4, 0); Matrix.multiplyMM(mvp, 0, viewProjectionMatrix, 0, tempMultiplyMatrix4, 0); GLES20Canvas.printMatrix("ultra matrix:", mvp, 0); return mvp; } } /** * Orthographic bitmap matrix. It uses orthographic projection type. So it only support rotate around Z */ class OrthoBitmapMatrix extends BaseBitmapMatrix { public OrthoBitmapMatrix() { reset(); } public void translate(float dx, float dy) { transform[TRANSLATE_X] += dx; transform[TRANSLATE_Y] += dy; } public void scale(float sx, float sy) { transform[SCALE_X] *= sx; transform[SCALE_Y] *= sy; } /** * The center x, y is the center of the view port * @param degrees */ public void rotateZ(float degrees) { transform[ROTATE_Z] += degrees; } @Override public float[] obtainResultMatrix(int viewportW, int viewportH, float x, float y, float drawW, float drawH) { float ratio = (float) viewportW / viewportH; transform[TRANSLATE_X] += x; transform[TRANSLATE_Y] += y; GLES20.glViewport(0, 0, viewportW, viewportH); Matrix.orthoM(mProjectionMatrix, 0, 0, ratio, 0, 1, -1, 1); Matrix.multiplyMM(viewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); Matrix.scaleM(mModelMatrix, 0, 1, -1, 1); GLES20Canvas.printMatrix("model init:", mModelMatrix, 0); Matrix.rotateM(mModelMatrix, 0, transform[ROTATE_Z], 0, 0, 1f); GLES20Canvas.printMatrix("model rotated:", mModelMatrix, 0); final float transX = transform[TRANSLATE_X] / viewportW; final float transY = transform[TRANSLATE_Y] / viewportH -1; Matrix.translateM(tempMultiplyMatrix4, 0, mModelMatrix, 0, transX, transY, 0); GLES20Canvas.printMatrix("model translated:", tempMultiplyMatrix4, 0); Matrix.scaleM(tempMultiplyMatrix4, 0, transform[SCALE_X] * drawW/viewportW * ratio, transform[SCALE_Y] * drawH/viewportH, 1); GLES20Canvas.printMatrix("model scaled:", tempMultiplyMatrix4, 0); Matrix.multiplyMM(mvp, 0, viewProjectionMatrix, 0, tempMultiplyMatrix4, 0); GLES20Canvas.printMatrix("ultra matrix:", mvp, 0); return mvp; } } }