From c4a8b67e76a9589af89c3b1bdad6cd20f8258783 Mon Sep 17 00:00:00 2001 From: adslk Date: Tue, 7 Sep 2021 09:17:21 +0800 Subject: [PATCH 1/3] add sample for Triangle Signed-off-by: adslk --- UI/Triangle/README_zh.md | 16 + UI/Triangle/build.gradle | 36 ++ UI/Triangle/entry/build.gradle | 27 ++ UI/Triangle/entry/src/main/config.json | 45 ++ .../ohos/samples/triangle/MainAbility.java | 13 + .../ohos/samples/triangle/MyApplication.java | 10 + .../triangle/slice/MainAbilitySlice.java | 35 ++ .../ohos/samples/triangle/slice/Matrix.java | 184 ++++++++ .../ohos/samples/triangle/slice/Triangle.java | 394 ++++++++++++++++++ .../main/resources/base/element/string.json | 16 + .../base/graphic/background_ability_main.xml | 6 + .../resources/base/layout/ability_main.xml | 10 + .../src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes .../src/main/resources/en/element/string.json | 12 + .../src/main/resources/zh/element/string.json | 12 + UI/Triangle/screenshots/device/screen.png | Bin 0 -> 69575 bytes UI/Triangle/settings.gradle | 1 + 17 files changed, 817 insertions(+) create mode 100644 UI/Triangle/README_zh.md create mode 100644 UI/Triangle/build.gradle create mode 100644 UI/Triangle/entry/build.gradle create mode 100644 UI/Triangle/entry/src/main/config.json create mode 100644 UI/Triangle/entry/src/main/java/ohos/samples/triangle/MainAbility.java create mode 100644 UI/Triangle/entry/src/main/java/ohos/samples/triangle/MyApplication.java create mode 100644 UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/MainAbilitySlice.java create mode 100644 UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java create mode 100644 UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java create mode 100644 UI/Triangle/entry/src/main/resources/base/element/string.json create mode 100644 UI/Triangle/entry/src/main/resources/base/graphic/background_ability_main.xml create mode 100644 UI/Triangle/entry/src/main/resources/base/layout/ability_main.xml create mode 100644 UI/Triangle/entry/src/main/resources/base/media/icon.png create mode 100644 UI/Triangle/entry/src/main/resources/en/element/string.json create mode 100644 UI/Triangle/entry/src/main/resources/zh/element/string.json create mode 100644 UI/Triangle/screenshots/device/screen.png create mode 100644 UI/Triangle/settings.gradle diff --git a/UI/Triangle/README_zh.md b/UI/Triangle/README_zh.md new file mode 100644 index 0000000000..4e8cf98221 --- /dev/null +++ b/UI/Triangle/README_zh.md @@ -0,0 +1,16 @@ +# OpenGL绘制三角形 + +### 简介 + +OpenGL是一个跨平台的高性能3D渲染API,OpenGL ES是它的嵌入式平台版本。 + +本示例展示了OpenGL ES接口的使用,通过调用相关函数,在坐标系中绘制三角形,并实现逐帧旋转。 + +### 使用说明 + +点击应用,展示三角形以顶点为轴进行旋转。 + +### 约束与限制 + +本示例仅支持在大型系统上运行。 + diff --git a/UI/Triangle/build.gradle b/UI/Triangle/build.gradle new file mode 100644 index 0000000000..ffb7d0b240 --- /dev/null +++ b/UI/Triangle/build.gradle @@ -0,0 +1,36 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +apply plugin: 'com.huawei.ohos.app' + +//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 +ohos { + compileSdkVersion 5 + defaultConfig { + compatibleSdkVersion 5 + } +} + +buildscript { + repositories { + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + } + dependencies { + classpath 'com.huawei.ohos:hap:2.4.5.0' + classpath 'com.huawei.ohos:decctest:1.2.4.1' + } +} + +allprojects { + repositories { + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + } +} diff --git a/UI/Triangle/entry/build.gradle b/UI/Triangle/entry/build.gradle new file mode 100644 index 0000000000..8b7ec83125 --- /dev/null +++ b/UI/Triangle/entry/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.huawei.ohos.hap' +apply plugin: 'com.huawei.ohos.decctest' +//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 +ohos { + compileSdkVersion 5 + defaultConfig { + compatibleSdkVersion 5 + } + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + testImplementation 'junit:junit:4.13' + ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.200' +} +decc { + supportType = ['html','xml'] +} diff --git a/UI/Triangle/entry/src/main/config.json b/UI/Triangle/entry/src/main/config.json new file mode 100644 index 0000000000..d3c5b61631 --- /dev/null +++ b/UI/Triangle/entry/src/main/config.json @@ -0,0 +1,45 @@ +{ + "app": { + "bundleName": "ohos.samples.triangle", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "ohos.samples.triangle", + "name": ".MyApplication", + "mainAbility": "ohos.samples.triangle.MainAbility", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "name": "ohos.samples.triangle.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "$string:entry_MainAbility", + "type": "page", + "launchType": "standard" + } + ] + } +} \ No newline at end of file diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MainAbility.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MainAbility.java new file mode 100644 index 0000000000..c1857bfc6f --- /dev/null +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MainAbility.java @@ -0,0 +1,13 @@ +package ohos.samples.triangle; + +import ohos.samples.triangle.slice.MainAbilitySlice; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; + +public class MainAbility extends Ability { + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setMainRoute(MainAbilitySlice.class.getName()); + } +} diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MyApplication.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MyApplication.java new file mode 100644 index 0000000000..da3a73b912 --- /dev/null +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/MyApplication.java @@ -0,0 +1,10 @@ +package ohos.samples.triangle; + +import ohos.aafwk.ability.AbilityPackage; + +public class MyApplication extends AbilityPackage { + @Override + public void onInitialize() { + super.onInitialize(); + } +} diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/MainAbilitySlice.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/MainAbilitySlice.java new file mode 100644 index 0000000000..12aee41e13 --- /dev/null +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/MainAbilitySlice.java @@ -0,0 +1,35 @@ +package ohos.samples.triangle.slice; + +import ohos.agp.components.DirectionalLayout; +import ohos.agp.components.surfaceprovider.SurfaceProvider; +import ohos.samples.triangle.ResourceTable; +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; + +public class MainAbilitySlice extends AbilitySlice { + private DirectionalLayout layout; + private Triangle triangle; + private SurfaceProvider provider; + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_ability_main); + layout = (DirectionalLayout) findComponentById(ResourceTable.Id_surface_layout); + triangle = new Triangle(this); + provider = triangle.initSliceLayout(); + + layout.addComponent(provider); + triangle.startDraw(); + } + + @Override + public void onActive() { + super.onActive(); + } + + @Override + public void onForeground(Intent intent) { + super.onForeground(intent); + } +} diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java new file mode 100644 index 0000000000..94c646b02f --- /dev/null +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java @@ -0,0 +1,184 @@ +package ohos.samples.triangle.slice; + +public class Matrix { + + public static void multiplyMM(float[] result, int resultOffset, float[] lhs, float[] rhs) { + float[] result1 = new float[result.length - resultOffset]; + float[] lhs1 = new float[lhs.length]; + float[] rhs1 = new float[rhs.length]; + System.arraycopy(result, resultOffset, result1, 0, result1.length); + System.arraycopy(lhs, 0, lhs1, 0, lhs1.length); + System.arraycopy(rhs, 0, rhs1, 0, rhs1.length); + + for (int i=0; i<4; i++) { + float rhsl0 = rhs1[indexOf(i, 0)]; + float ri0 = lhs1[indexOf(0, 0)] * rhsl0; + float ri1 = lhs1[indexOf(0, 1)] * rhsl0; + float ri2 = lhs1[indexOf(0, 2)] * rhsl0; + float ri3 = lhs1[indexOf(0, 3)] * rhsl0; + for (int j=1; j<4; j++) { + float rhslj = rhs1[indexOf(i, j)]; + ri0 += lhs1[indexOf(j, 0)] * rhslj; + ri1 += lhs1[indexOf(j, 1)] * rhslj; + ri2 += lhs1[indexOf(j, 2)] * rhslj; + ri3 += lhs1[indexOf(j, 3)] * rhslj; + } + result1[indexOf(i, 0)] = ri0; + result1[indexOf(i, 1)] = ri1; + result1[indexOf(i, 2)] = ri2; + result1[indexOf(i, 3)] = ri3; + } + System.arraycopy(result1, 0, result, resultOffset, result1.length); + } + + public static void setRotateM(float[] rm, float angle, float xx, float yy, float zz) { + rm[3] = rm[7] = rm[11] = rm[12] = rm[13] = rm[14] = 0.0f; + rm[15] = 1.0f; + + float angleTemp = (float)(angle * Math.PI / 180.0f); + float ss = (float) Math.sin(angleTemp); + float cc = (float) Math.cos(angleTemp); + + if (xx == 1.0f && yy == 0.0f && zz == 0.0f) { + rmOne(rm, ss , cc); + } else if (xx == 0.0f && yy == 1.0f && zz == 0.0f) { + rmTwo(rm, ss , cc); + } else if (xx == 0.0f && yy == 0.0f && zz == 1.0f) { + rmThree(rm ,ss , cc); + } else { + float len = length(xx, yy, zz); + float xTemp = xx; + float yTemp = yy; + float zTemp = zz; + if (Math.abs(len -1) > 1e-6f) { + float recIpLen = 1 / len; + xTemp = xx * recIpLen; + yTemp = yy * recIpLen; + zTemp = zz * recIpLen; + } + float nc = 1 - cc; + rm[0] = xTemp * xTemp * nc +cc; + + float xy = xTemp * yTemp; + float zs = zTemp * ss; + rm[4] = xy * nc - zs; + float zx = zTemp * xTemp; + float ys = yTemp * ss; + rm[8] = zx * nc + ys; + rm[1] = xy * nc + zs; + rm[5] = yTemp * yTemp * nc + cc; + + float yz = yTemp * zTemp; + float xs = xTemp * ss; + rm[9] = yz * nc - xs; + rm[2] = zx * nc - ys; + rm[6] = yz * nc + xs; + rm[10] = zTemp * zTemp * nc + cc; + } + } + + private static void rmThree(float[] rm, float ss, float cc) { + rm[0] = cc; + rm[5] = cc; + rm[1] = ss; + rm[4] = -ss; + rm[2] = 0; + rm[6] = 0; + rm[8] = 0; + rm[9] = 0; + rm[10] = 1; + } + + private static void rmTwo(float[] rm, float ss, float cc) { + rm[0] = cc; + rm[10] = cc; + rm[8] = ss; + rm[2] = -ss; + rm[1] = 0; + rm[4] = 0; + rm[6] = 0; + rm[9] = 0; + rm[5] = 1; + } + + private static void rmOne(float[] rm, float ss, float cc) { + rm[5] = cc; + rm[10] = cc; + rm[6] = ss; + rm[9] = -ss; + rm[1] = 0; + rm[2] = 0; + rm[4] = 0; + rm[8] = 0; + rm[0] = 1; + } + + private static int indexOf(int i, int j) { + return j + 4 * i; + } + + public static void frustumM(float[] mm, float right, float top, float near, float far) { + final float rWidth = 1/(right * 2); + final float rHeight = 1/(top * 2); + mm[0] = 2.0f * (near * rWidth); + mm[5] = 2.0f * (near * rHeight); + mm[8] = 0; + mm[9] = 0; + final float rDepth = 1/(near - far); + mm[10] = (far + near) * rDepth; + mm[14] = 2.0f * (far * near * rDepth); + mm[11] = -1.0f; + mm[1] = 0.0f; + mm[2] = 0.0f; + mm[3] = 0.0f; + mm[4] = 0.0f; + mm[6] = 0.0f; + mm[7] = 0.0f; + mm[12] = 0.0f; + mm[13] = 0.0f; + mm[15] = 0.0f; + } + public static float length(float x, float y, float z) { + return (float) Math.sqrt(x * x + y * y + z * z); + } + + public static void setLookAtM(float[] rm, float eyeZ, float centerX, float centerY, float centerZ) { + float fx = centerX; + float fy = centerY; + float fz = centerZ - eyeZ; + float rlf = 1 / Matrix.length(fx, fy, fz); + fx *= rlf; + fy *= rlf; + fz *= rlf; + + float sx = -fz; + float sy = -fx; + float sz = fx; + float rls = 1 / Matrix.length(sx, sy, sz); + sx *= rls; + sy *= rls; + sz *= rls; + + rm[0] = sx; + rm[1] = sy * fz -sz * fy; + rm[2] = -fx; + rm[3] = 0.0f; + rm[4] = sy; + rm[5] = sz * fx -sx * fz; + rm[6] = -fy; + rm[7] = 0.0f; + rm[8] = sz; + rm[9] = sx * fy - sy * fx; + rm[10] = -fz; + rm[11] = rm[12] = rm[13] = rm[14] = 0.0f; + rm[15] = 1.0f; + translateM(rm, 0, 0, 0, -eyeZ); + } + + public static void translateM(float[] matrix, int offset, float x, float y, float z) { + for (int i = 0; i < 4; i++) { + int pos = offset + i; + matrix[12 + pos] += matrix[pos] * x + matrix[4 + pos] * y + matrix[8 + pos] * z; + } + } +} diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java new file mode 100644 index 0000000000..d4ff2beb06 --- /dev/null +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java @@ -0,0 +1,394 @@ +package ohos.samples.triangle.slice; + +import ohos.agp.components.surfaceprovider.SurfaceProvider; +import ohos.agp.graphics.SurfaceOps; +import ohos.agp.render.opengl.*; +import ohos.app.Context; +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +import java.nio.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class Triangle { + private SCallBacks callBacks; + private boolean stopRun = false; + private final Context mContext; + private SurfaceOps surfaceOps; + + public Triangle(Context context) { + this.mContext = context; + } + + public SurfaceProvider initSliceLayout() { + SurfaceProvider testSurfaceView = new SurfaceProvider(mContext); + if(testSurfaceView.getSurfaceOps().isPresent()){ + surfaceOps = testSurfaceView.getSurfaceOps().get(); + callBacks = new SCallBacks(); + surfaceOps.addCallback(callBacks); + surfaceOps.setKeepScreenOn(true); + } + testSurfaceView.setWidth(1080); + testSurfaceView.setHeight(2000); + + testSurfaceView.pinToZTop(true); + return testSurfaceView; + } + + public void startDraw() { + Runnable requestRunnable = () -> callBacks.onDrawFrame(); + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); + threadPoolExecutor.execute(() -> { + while (!stopRun) { + mContext.getUITaskDispatcher().asyncDispatch(requestRunnable); + } + }); + } + + public void stop() { + stopRun = true; + surfaceOps.removeCallback(callBacks); + } + + class SCallBacks implements SurfaceOps.Callback { + private final HiLogLabel LOG_TAG = new HiLogLabel(HiLog.LOG_APP, 0xD001400, "SCallBacks"); + private EGLDisplay eglDisplay; + private EGLSurface eglSurface; + + private EGLContext eglContext = null; + private EGLConfig eglConfig = null; + + private final float[] CubeCords = new float[]{ + 0f, 0.5f, 0f, + 0.5f, 0f, 0f, + -0.5f, 0f, 0f, + }; + + private final short[] indices = new short[]{ + 0, 1, 2 + }; + + private final float[] colors = { + 0f, 0f, 0f, 1f, + 0f, 0f, 0.8f, 1f, + 0f, 0.8f, 0f, 1f, + 0f, 0.8f, 0.8f, 1f, + 0.8f, 0f, 0f, 1f, + 0.8f, 0f, 0.8f, 1f, + 0.8f, 0.8f, 0f, 1f, + 0.8f, 0.8f, 0.8f, 1f, + 0.8f, 0f, 0f, 1f, + 0f, 0.8f, 0f, 1f, + 0f, 0f, 0.8f, 1f, + 0.8f, 0f, 0.8f, 1f, + }; + + private final float[] vPMatrix = new float[16]; + private final float[] projectionMatrix = new float[16]; + private final float[] viewMatrix = new float[16]; + private final float[] rotationMatrix = new float[16]; + private final float[] tempMatrix = new float[16]; + private int angle = 0; + private int disWidth = 0; + private int disHeight = 0; + + private int vertexShader = 0; + private int fragmentsShader = 0; + private final CharBuffer shaderCode = CharBuffer.allocate(100); + + @Override + public void surfaceCreated(SurfaceOps ops) { + eglDisplay = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL.EGL_NO_DISPLAY) { + return; + } + int[] version = new int[2]; + if (!EGL.eglInitialize(eglDisplay, version, version)) { + return; + } + + int alphaSize = 3; + int depthSize = 3; + int stencilSize = 3; + int renderType = 0x0004; + int[] attributes = new int[] { + EGL.EGL_RED_SIZE, 3, + EGL.EGL_GREEN_SIZE, 3, + EGL.EGL_ALPHA_SIZE, alphaSize, + EGL.EGL_DEPTH_SIZE, depthSize, + EGL.EGL_STENCIL_SIZE, stencilSize, + + EGL.EGL_RENDERABLE_TYPE, renderType, + EGL.EGL_NONE + }; + int[] configNum = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + if(!EGL.eglChooseConfig(eglDisplay, attributes, configs, 1, configNum)){ + return; + } + if (eglConfig == null) { + eglConfig = configs[0]; + } + int[] contextAttr = new int[] { + 0x3098, 2, EGL.EGL_NONE, + }; + eglContext = EGL.eglCreateContext(eglDisplay, eglConfig, EGL.EGL_NO_CONTEXT, contextAttr); + if (eglContext == EGL.EGL_NO_CONTEXT) { + return; + } + + String openVersion = GLES20.glGetString(GLES20.GL_VERSION); + HiLog.info(LOG_TAG, "OpenVersion: " + openVersion); + } + + @Override + public void surfaceChanged(SurfaceOps ops, int format, int width, int height) { + int[] contextAttr = new int[] { + EGL.EGL_NONE + }; + eglSurface = EGL.eglCreateWindowSurface(eglDisplay, eglConfig, ops.getSurface(),contextAttr); + + if (eglSurface == EGL.EGL_NO_SURFACE) { + return; + } + if (!EGL.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + return; + } + float ratio = (float) width/height; + + Matrix.frustumM(projectionMatrix, ratio, 1, 3, 7); + + Matrix.setLookAtM(viewMatrix, 4f, 0f, 0f, 0f); + + disWidth = width; + disHeight = height; + onDrawFrame(); + } + + @Override + public void surfaceDestroyed(SurfaceOps ops) { + EGL.eglMakeCurrent(eglDisplay, null, null, null); + EGL.eglDestroySurface(eglDisplay, eglSurface); + EGL.eglDestroyContext(eglDisplay, eglContext); + EGL.eglTerminate(eglDisplay); + stop(); + } + + public void onDrawFrame() { + GLES20.glEnable(GLES20.GL_DEPTH_TEST); + + GLES20.glViewport(0,0, disWidth, disHeight); + + GLES20.glClearColor(0.8f,0.8f,0.8f, 1.0f); + + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); + + String vertexShaderCode = "uniform mat4 uMatrix;" + + "attribute vec4 aPos;" + "attribute vec4 aColor;" + "attribute float aSize;" + + "varying vec4 ourColor;" + "void main() {" + + " gl_Position = uMatrix * aPos;" + "ourColor = aColor;" + + "}"; + + String fragmentShaderCode = "precision mediump float;" + "varying vec4 ourColor;" + + "void main() {" + "gl_FragColor = ourColor;" + + "}"; + + int program = createProgram(vertexShaderCode, fragmentShaderCode); + + GLES20.glUseProgram(program); + + int sizeHandle = GLES20.glGetAttribLocation(program, "aSize"); + GLES20.glVertexAttrib1f(sizeHandle, 1.0f); + + int positionHandle = GLES20.glGetAttribLocation(program, "aPos"); + + GLES20.glEnableVertexAttribArray(positionHandle); + FloatBuffer vertexBuffer = createFloatBuffer(CubeCords); + + GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false,3*4, vertexBuffer); + + int colorHandle = GLES20.glGetAttribLocation(program, "aColor"); + GLES20.glEnableVertexAttribArray(colorHandle); + FloatBuffer colorBuffer = createFloatBuffer(colors); + + GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false,4*4, colorBuffer); + + int matrixHandle = GLES20.glGetUniformLocation(program, "uMatrix"); + + Matrix.setRotateM(rotationMatrix, angle, 0, 1, 0); + + Matrix.multiplyMM(tempMatrix, 0, projectionMatrix, viewMatrix); + + Matrix.multiplyMM(vPMatrix, 0, tempMatrix, rotationMatrix); + + GLES20.glUniformMatrix4fv(matrixHandle, 1, false, vPMatrix); + + ShortBuffer indicesBuffer = createShortBuffer(indices); + GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, indices.length, GLES20.GL_UNSIGNED_SHORT, indicesBuffer); + + if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { + return; + } + + GLES20.glDisableVertexAttribArray(positionHandle); + GLES20.glDisableVertexAttribArray(colorHandle); + + GLES20.glDisable(GLES20.GL_DEPTH_TEST); + angle += 2; + checkParameter(program); + + } + + private void checkParameter(int program) { + int[] params = new int[1]; + + GLES20.glGetIntegerv(0x0B73, params); + HiLog.info(LOG_TAG, "glGetInteger: DEPTH_CLEAR = " + params[0]); + + boolean[] paramsb = new boolean[1]; + GLES20.glGetBooleanv(GLES20.GL_DEPTH_TEST, paramsb); + HiLog.info(LOG_TAG, "glGetInteger: DEPTH_CLEAR = " + (paramsb[0] ? "true":"false")); + + IntBuffer range = IntBuffer.allocate(2); + IntBuffer precision = IntBuffer.allocate(2); + GLES20.glGetShaderPrecisionFormat(GLES20.GL_VERTEX_SHADER, 0x8DF1, range, precision); + HiLog.info(LOG_TAG, "Range=[" + range.get(1) + "], precision=" + precision.get(0)); + + IntBuffer length = IntBuffer.allocate(4); + + GLES20.glGetShaderSource(GLES20.GL_FRAGMENT_SHADER, shaderCode.capacity(), length, shaderCode); + HiLog.info(LOG_TAG, "glGetShaderSource: length=" + length.get(0) + "shaderCode=" + shaderCode.toString()); + + int bufSize = 256; + int[] size = new int[1]; + int[] len = new int[1]; + int[] type = new int[1]; + byte[] name = new byte[bufSize]; + int[] counts = new int[1]; + + GLES20.glGetProgramiv(program, 0x8B86, counts); + if (counts[0] > 0) { + for (int idx = 0; idx < counts[0]; idx++) { + GLES20.glGetActiveUniform(program, idx, bufSize, len, size, type, name); + } + } + + GLES20.glGetProgramiv(program, 0x8B89, counts); + if (counts[0] > 0) { + for (int idx = 0; idx < counts[0]; idx++) { + GLES20.glGetActiveAttrib(program, idx, bufSize, len, size, type, name); + } + } + + float[] paramsf = new float[2]; + + GLES20.glGetFloatv(0x846E, paramsf); + HiLog.info(LOG_TAG, "glGetFloat: min = " + paramsf[0] + "max =" + paramsf[1]); + GLES20.glLineWidth(2.0f); + + GLES20.glFlush(); + GLES20.glFinish(); + + GLES20.glReleaseShaderCompiler(); + + GLES20.glDetachShader(program, vertexShader); + GLES20.glDetachShader(program, fragmentsShader); + } + + private int createProgram(String vertexSource, String fragmentSource) { + vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return 0; + } + boolean isShader = GLES20.glIsShader(vertexShader); + HiLog.info(LOG_TAG, "Is vertexShader" + (isShader ? "True" : "False")); + fragmentsShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); + if (fragmentsShader == 0) { + return 0; + } + isShader = GLES20.glIsShader(fragmentsShader); + HiLog.info(LOG_TAG, "Is fragmentsShader" + (isShader ? "True" : "False")); + int program = GLES20.glCreateProgram(); + + if (program == 0) { + HiLog.error(LOG_TAG, "Could not create program"); + return 0; + } + + boolean isProgram = GLES20.glIsProgram(program); + HiLog.info(LOG_TAG, "Is program" + (isProgram ? "True" : "False")); + + GLES20.glAttachShader(program, vertexShader); + + GLES20.glAttachShader(program, fragmentsShader); + + GLES20.glLinkProgram(program); + + GLES20.glDeleteShader(vertexShader); + + GLES20.glDeleteShader(fragmentsShader); + + final int[] compiled = new int[1]; + GLES20.glGetProgramiv(program,GLES20.GL_LINK_STATUS, compiled); + if (compiled[0] != GLES20.GL_TRUE) { + StringBuffer programInfo = new StringBuffer(); + + GLES20.glGetProgramInfoLog(program, 100, null, programInfo); + + HiLog.error(LOG_TAG, "Could not link program: " + programInfo.toString()); + + GLES20.glDeleteProgram(program); + return 0; + } + GLES20.glValidateProgram(program); + final int[] validateStatus = new int[1]; + + GLES20.glGetProgramiv(program, GLES20.GL_VALIDATE_STATUS, validateStatus); + if (validateStatus[0] != GLES20.GL_TRUE) { + StringBuffer programInfoLog = new StringBuffer(); + GLES20.glGetProgramInfoLog(program, 100, null, programInfoLog); + HiLog.error(LOG_TAG, "validate program failed: " + programInfoLog.toString()); + } + return program; + } + + private int loadShader(int type, String shaderCode) { + int shader = GLES20.glCreateShader(type); + HiLog.info(LOG_TAG, "loadShader: " + type + ", ret =" + shader); + String[] source = { shaderCode }; + IntBuffer length = IntBuffer.allocate(0); + + GLES20.glShaderSource(shader, 1, source, length); + + GLES20.glCompileShader(shader); + int[] compiled = new int[1]; + int max = 100; + + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled); + if (compiled[0] == 0) { + StringBuffer shaderInfoLog = new StringBuffer(); + GLES20.glGetShaderInfoLog(shader, max, null,shaderInfoLog); + GLES20.glDeleteShader(shader); + shader = 0; + } + return shader; + } + } + public static ShortBuffer createShortBuffer(short[] arr) { + ByteBuffer buffer = ByteBuffer.allocateDirect(arr.length * 2); + buffer.order(ByteOrder.nativeOrder()); + ShortBuffer sb = buffer.asShortBuffer(); + sb.put(arr).position(0); + return sb; + } + + public static FloatBuffer createFloatBuffer(float[] arr) { + ByteBuffer buffer = ByteBuffer.allocateDirect(arr.length * 4); + buffer.order(ByteOrder.nativeOrder()); + FloatBuffer fb = buffer.asFloatBuffer(); + fb.put(arr).position(0); + return fb; + } +} diff --git a/UI/Triangle/entry/src/main/resources/base/element/string.json b/UI/Triangle/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000..76d4e29e45 --- /dev/null +++ b/UI/Triangle/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_MainAbility", + "value": "Triangle" + }, + { + "name": "mainability_description", + "value": "Java_Empty Ability" + }, + { + "name": "mainability_HelloWorld", + "value": "Hello World" + } + ] +} \ No newline at end of file diff --git a/UI/Triangle/entry/src/main/resources/base/graphic/background_ability_main.xml b/UI/Triangle/entry/src/main/resources/base/graphic/background_ability_main.xml new file mode 100644 index 0000000000..c0c0a3df48 --- /dev/null +++ b/UI/Triangle/entry/src/main/resources/base/graphic/background_ability_main.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/UI/Triangle/entry/src/main/resources/base/layout/ability_main.xml b/UI/Triangle/entry/src/main/resources/base/layout/ability_main.xml new file mode 100644 index 0000000000..655091e796 --- /dev/null +++ b/UI/Triangle/entry/src/main/resources/base/layout/ability_main.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/UI/Triangle/entry/src/main/resources/base/media/icon.png b/UI/Triangle/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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

ZnHiC#P<);s*uglvPsl^s$5<~q@ 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 Date: Tue, 7 Sep 2021 15:16:14 +0800 Subject: [PATCH 2/3] add comments Signed-off-by: adslk --- UI/Triangle/build.gradle | 4 +- UI/Triangle/entry/build.gradle | 4 +- UI/Triangle/entry/src/main/config.json | 2 +- .../ohos/samples/triangle/slice/Matrix.java | 44 ++++++++++ .../ohos/samples/triangle/slice/Triangle.java | 86 ++++++++++++++++--- .../main/resources/base/element/string.json | 10 +-- .../src/main/resources/en/element/string.json | 4 +- .../src/main/resources/zh/element/string.json | 6 +- 8 files changed, 132 insertions(+), 28 deletions(-) diff --git a/UI/Triangle/build.gradle b/UI/Triangle/build.gradle index ffb7d0b240..65c90323f5 100644 --- a/UI/Triangle/build.gradle +++ b/UI/Triangle/build.gradle @@ -3,9 +3,9 @@ apply plugin: 'com.huawei.ohos.app' //For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 ohos { - compileSdkVersion 5 + compileSdkVersion 6 defaultConfig { - compatibleSdkVersion 5 + compatibleSdkVersion 6 } } diff --git a/UI/Triangle/entry/build.gradle b/UI/Triangle/entry/build.gradle index 8b7ec83125..517434f3eb 100644 --- a/UI/Triangle/entry/build.gradle +++ b/UI/Triangle/entry/build.gradle @@ -2,9 +2,9 @@ apply plugin: 'com.huawei.ohos.hap' apply plugin: 'com.huawei.ohos.decctest' //For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 ohos { - compileSdkVersion 5 + compileSdkVersion 6 defaultConfig { - compatibleSdkVersion 5 + compatibleSdkVersion 6 } buildTypes { release { diff --git a/UI/Triangle/entry/src/main/config.json b/UI/Triangle/entry/src/main/config.json index d3c5b61631..db5409b1ed 100644 --- a/UI/Triangle/entry/src/main/config.json +++ b/UI/Triangle/entry/src/main/config.json @@ -36,7 +36,7 @@ "name": "ohos.samples.triangle.MainAbility", "icon": "$media:icon", "description": "$string:mainability_description", - "label": "$string:entry_MainAbility", + "label": "$string:app_name", "type": "page", "launchType": "standard" } diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java index 94c646b02f..f80298e158 100644 --- a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java @@ -2,6 +2,14 @@ package ohos.samples.triangle.slice; public class Matrix { + /** + * multiplyMM 乘法矩阵运算 + * + * @param result float[] + * @param resultOffset float[] + * @param lhs float[] + * @param rhs float[] + */ public static void multiplyMM(float[] result, int resultOffset, float[] lhs, float[] rhs) { float[] result1 = new float[result.length - resultOffset]; float[] lhs1 = new float[lhs.length]; @@ -31,6 +39,15 @@ public class Matrix { System.arraycopy(result1, 0, result, resultOffset, result1.length); } + /** + * setRotateM 创建一个新矩阵 + * + * @param rm float[] + * @param angle float[] + * @param xx float + * @param yy float + * @param zz float + */ public static void setRotateM(float[] rm, float angle, float xx, float yy, float zz) { rm[3] = rm[7] = rm[11] = rm[12] = rm[13] = rm[14] = 0.0f; rm[15] = 1.0f; @@ -117,6 +134,15 @@ public class Matrix { return j + 4 * i; } + /** + * frustumM 计算透视投影矩阵:以六个裁剪平面定义投影矩阵。 + * + * @param mm float[] + * @param right float + * @param top float + * @param near float + * @param far float + */ public static void frustumM(float[] mm, float right, float top, float near, float far) { final float rWidth = 1/(right * 2); final float rHeight = 1/(top * 2); @@ -142,6 +168,15 @@ public class Matrix { return (float) Math.sqrt(x * x + y * y + z * z); } + /** + * setLookAtM 定义相机视图 + * + * @param rm float[] + * @param eyeZ float + * @param centerX float + * @param centerY float + * @param centerZ float + */ public static void setLookAtM(float[] rm, float eyeZ, float centerX, float centerY, float centerZ) { float fx = centerX; float fy = centerY; @@ -175,6 +210,15 @@ public class Matrix { translateM(rm, 0, 0, 0, -eyeZ); } + /** + * translateM 平移矩阵 + * + * @param matrix float[] + * @param offset int + * @param x float + * @param y float + * @param z float + */ public static void translateM(float[] matrix, int offset, float x, float y, float z) { for (int i = 0; i < 4; i++) { int pos = offset + i; diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java index d4ff2beb06..9b62664301 100644 --- a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java @@ -60,16 +60,19 @@ public class Triangle { private EGLContext eglContext = null; private EGLConfig eglConfig = null; + //三角形的3个顶点 private final float[] CubeCords = new float[]{ 0f, 0.5f, 0f, 0.5f, 0f, 0f, -0.5f, 0f, 0f, }; + private final short[] indices = new short[]{ 0, 1, 2 }; + //三角形的颜色 private final float[] colors = { 0f, 0f, 0f, 1f, 0f, 0f, 0.8f, 1f, @@ -85,16 +88,24 @@ public class Triangle { 0.8f, 0f, 0.8f, 1f, }; + //变换矩阵 private final float[] vPMatrix = new float[16]; + //投影矩阵 private final float[] projectionMatrix = new float[16]; + //相机矩阵 private final float[] viewMatrix = new float[16]; + //旋转矩阵 private final float[] rotationMatrix = new float[16]; + //临时矩阵,用于存放矩阵运算 private final float[] tempMatrix = new float[16]; + //旋转角度 private int angle = 0; private int disWidth = 0; private int disHeight = 0; + //顶点着色器 private int vertexShader = 0; + //片元着色器 private int fragmentsShader = 0; private final CharBuffer shaderCode = CharBuffer.allocate(100); @@ -158,8 +169,9 @@ public class Triangle { } float ratio = (float) width/height; + //设置投影矩阵 Matrix.frustumM(projectionMatrix, ratio, 1, 3, 7); - + //设置观察点 Matrix.setLookAtM(viewMatrix, 4f, 0f, 0f, 0f); disWidth = width; @@ -177,36 +189,37 @@ public class Triangle { } public void onDrawFrame() { + //启动深度测试 GLES20.glEnable(GLES20.GL_DEPTH_TEST); - + //设置显示范围 GLES20.glViewport(0,0, disWidth, disHeight); - + //设置背景,清除颜色 GLES20.glClearColor(0.8f,0.8f,0.8f, 1.0f); - + //执行背景清除 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); - + //将ourColor设置为我们输入的颜色 String vertexShaderCode = "uniform mat4 uMatrix;" + "attribute vec4 aPos;" + "attribute vec4 aColor;" + "attribute float aSize;" + "varying vec4 ourColor;" + "void main() {" + " gl_Position = uMatrix * aPos;" + "ourColor = aColor;" + "}"; - + // String fragmentShaderCode = "precision mediump float;" + "varying vec4 ourColor;" + "void main() {" + "gl_FragColor = ourColor;" + "}"; int program = createProgram(vertexShaderCode, fragmentShaderCode); - + //使用着色器程序 GLES20.glUseProgram(program); - + //获取属性变量位置 int sizeHandle = GLES20.glGetAttribLocation(program, "aSize"); GLES20.glVertexAttrib1f(sizeHandle, 1.0f); int positionHandle = GLES20.glGetAttribLocation(program, "aPos"); - + //启用通用顶点属性数据 GLES20.glEnableVertexAttribArray(positionHandle); FloatBuffer vertexBuffer = createFloatBuffer(CubeCords); - + //指定顶点的属性数据 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false,3*4, vertexBuffer); int colorHandle = GLES20.glGetAttribLocation(program, "aColor"); @@ -215,33 +228,46 @@ public class Triangle { GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false,4*4, colorBuffer); + //获取统一变量位置 int matrixHandle = GLES20.glGetUniformLocation(program, "uMatrix"); + //创建一个旋转矩阵 Matrix.setRotateM(rotationMatrix, angle, 0, 1, 0); + //矩阵计算 Matrix.multiplyMM(tempMatrix, 0, projectionMatrix, viewMatrix); Matrix.multiplyMM(vPMatrix, 0, tempMatrix, rotationMatrix); + //将视图转换器传递给着色器 GLES20.glUniformMatrix4fv(matrixHandle, 1, false, vPMatrix); + //索引法绘制三角形 ShortBuffer indicesBuffer = createShortBuffer(indices); GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, indices.length, GLES20.GL_UNSIGNED_SHORT, indicesBuffer); + //更新缓冲区显示到屏幕 if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { return; } - + //禁用通用顶点属性数组 GLES20.glDisableVertexAttribArray(positionHandle); GLES20.glDisableVertexAttribArray(colorHandle); + //禁用深度测试 GLES20.glDisable(GLES20.GL_DEPTH_TEST); angle += 2; checkParameter(program); } + /** + * checkParameter + * + * @param program int + */ private void checkParameter(int program) { + //获取清除深度缓冲区的值 int[] params = new int[1]; GLES20.glGetIntegerv(0x0B73, params); @@ -251,11 +277,13 @@ public class Triangle { GLES20.glGetBooleanv(GLES20.GL_DEPTH_TEST, paramsb); HiLog.info(LOG_TAG, "glGetInteger: DEPTH_CLEAR = " + (paramsb[0] ? "true":"false")); + //获取顶点着色器数字格式的范围和精度 IntBuffer range = IntBuffer.allocate(2); IntBuffer precision = IntBuffer.allocate(2); GLES20.glGetShaderPrecisionFormat(GLES20.GL_VERTEX_SHADER, 0x8DF1, range, precision); HiLog.info(LOG_TAG, "Range=[" + range.get(1) + "], precision=" + precision.get(0)); + //从着色器对象返回源代码字符串 IntBuffer length = IntBuffer.allocate(4); GLES20.glGetShaderSource(GLES20.GL_FRAGMENT_SHADER, shaderCode.capacity(), length, shaderCode); @@ -268,6 +296,7 @@ public class Triangle { byte[] name = new byte[bufSize]; int[] counts = new int[1]; + //从程序对象返回状态的统一变量 GLES20.glGetProgramiv(program, 0x8B86, counts); if (counts[0] > 0) { for (int idx = 0; idx < counts[0]; idx++) { @@ -275,6 +304,7 @@ public class Triangle { } } + //从程序对象返回活动状态的属性变化 GLES20.glGetProgramiv(program, 0x8B89, counts); if (counts[0] > 0) { for (int idx = 0; idx < counts[0]; idx++) { @@ -293,10 +323,18 @@ public class Triangle { GLES20.glReleaseShaderCompiler(); + //从程序对象中分离着色器对象 GLES20.glDetachShader(program, vertexShader); GLES20.glDetachShader(program, fragmentsShader); } + /** + * createProgram + * + * @param vertexSource String + * @param fragmentSource String + * @return int + */ private int createProgram(String vertexSource, String fragmentSource) { vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { @@ -310,6 +348,8 @@ public class Triangle { } isShader = GLES20.glIsShader(fragmentsShader); HiLog.info(LOG_TAG, "Is fragmentsShader" + (isShader ? "True" : "False")); + + //创建程序对象 int program = GLES20.glCreateProgram(); if (program == 0) { @@ -320,6 +360,7 @@ public class Triangle { boolean isProgram = GLES20.glIsProgram(program); HiLog.info(LOG_TAG, "Is program" + (isProgram ? "True" : "False")); + //将着色器对象附加到程序对象 GLES20.glAttachShader(program, vertexShader); GLES20.glAttachShader(program, fragmentsShader); @@ -354,18 +395,28 @@ public class Triangle { return program; } + /** + * loadShader + * + * @param type int + * @param shaderCode String + * @return int + */ private int loadShader(int type, String shaderCode) { int shader = GLES20.glCreateShader(type); HiLog.info(LOG_TAG, "loadShader: " + type + ", ret =" + shader); String[] source = { shaderCode }; IntBuffer length = IntBuffer.allocate(0); + //加载代码到着色器对象 GLES20.glShaderSource(shader, 1, source, length); + //编译着色器对象 GLES20.glCompileShader(shader); int[] compiled = new int[1]; int max = 100; + //从着色器对象获取编译状态信息 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled); if (compiled[0] == 0) { StringBuffer shaderInfoLog = new StringBuffer(); @@ -376,6 +427,13 @@ public class Triangle { return shader; } } + + /** + * createShortBuffer + * + * @param arr short[] + * @return ShortBuffer + */ public static ShortBuffer createShortBuffer(short[] arr) { ByteBuffer buffer = ByteBuffer.allocateDirect(arr.length * 2); buffer.order(ByteOrder.nativeOrder()); @@ -384,6 +442,12 @@ public class Triangle { return sb; } + /** + * createFloatBuffer + * + * @param arr float[] + * @return FloatBuffer + */ public static FloatBuffer createFloatBuffer(float[] arr) { ByteBuffer buffer = ByteBuffer.allocateDirect(arr.length * 4); buffer.order(ByteOrder.nativeOrder()); diff --git a/UI/Triangle/entry/src/main/resources/base/element/string.json b/UI/Triangle/entry/src/main/resources/base/element/string.json index 76d4e29e45..6e532c6b41 100644 --- a/UI/Triangle/entry/src/main/resources/base/element/string.json +++ b/UI/Triangle/entry/src/main/resources/base/element/string.json @@ -1,16 +1,12 @@ { "string": [ { - "name": "entry_MainAbility", + "name": "app_name", "value": "Triangle" }, { "name": "mainability_description", - "value": "Java_Empty Ability" - }, - { - "name": "mainability_HelloWorld", - "value": "Hello World" + "value": "Draw triangles using OpenGL ES" } ] -} \ No newline at end of file +} diff --git a/UI/Triangle/entry/src/main/resources/en/element/string.json b/UI/Triangle/entry/src/main/resources/en/element/string.json index 7a2471bec0..6e532c6b41 100644 --- a/UI/Triangle/entry/src/main/resources/en/element/string.json +++ b/UI/Triangle/entry/src/main/resources/en/element/string.json @@ -1,12 +1,12 @@ { "string": [ { - "name": "entry_MainAbility", + "name": "app_name", "value": "Triangle" }, { "name": "mainability_description", - "value": "Java_Empty Ability" + "value": "Draw triangles using OpenGL ES" } ] } diff --git a/UI/Triangle/entry/src/main/resources/zh/element/string.json b/UI/Triangle/entry/src/main/resources/zh/element/string.json index 0ab0ffe84d..139a142d97 100644 --- a/UI/Triangle/entry/src/main/resources/zh/element/string.json +++ b/UI/Triangle/entry/src/main/resources/zh/element/string.json @@ -1,12 +1,12 @@ { "string": [ { - "name": "entry_MainAbility", - "value": "Triangle" + "name": "app_name", + "value": "三角形" }, { "name": "mainability_description", - "value": "Java_Empty Ability" + "value": "使用 OpenGL_ES 绘制三角形" } ] } \ No newline at end of file -- Gitee From aa6c7712a35541c22f74e7ebce38d0be3910ae65 Mon Sep 17 00:00:00 2001 From: adslk Date: Tue, 7 Sep 2021 15:50:39 +0800 Subject: [PATCH 3/3] add comments Signed-off-by: adslk --- .../ohos/samples/triangle/slice/Matrix.java | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java index f80298e158..f0d2de4f91 100644 --- a/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java +++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java @@ -3,10 +3,10 @@ package ohos.samples.triangle.slice; public class Matrix { /** - * multiplyMM 乘法矩阵运算 + * multiplyMM Multiplication matrix operation * * @param result float[] - * @param resultOffset float[] + * @param resultOffset int * @param lhs float[] * @param rhs float[] */ @@ -40,7 +40,7 @@ public class Matrix { } /** - * setRotateM 创建一个新矩阵 + * setRotateM Create a new matrix * * @param rm float[] * @param angle float[] @@ -94,6 +94,13 @@ public class Matrix { } } + /** + * rmThree + * + * @param rm float[] + * @param ss float + * @param cc float + */ private static void rmThree(float[] rm, float ss, float cc) { rm[0] = cc; rm[5] = cc; @@ -106,6 +113,13 @@ public class Matrix { rm[10] = 1; } + /** + * rmTwo + * + * @param rm float[] + * @param ss float + * @param cc float + */ private static void rmTwo(float[] rm, float ss, float cc) { rm[0] = cc; rm[10] = cc; @@ -118,6 +132,13 @@ public class Matrix { rm[5] = 1; } + /** + * rmOne + * + * @param rm float[] + * @param ss float + * @param cc float + */ private static void rmOne(float[] rm, float ss, float cc) { rm[5] = cc; rm[10] = cc; @@ -130,12 +151,19 @@ public class Matrix { rm[0] = 1; } + /** + * indexOf + * + * @param i int + * @param j int + * @return int + */ private static int indexOf(int i, int j) { return j + 4 * i; } /** - * frustumM 计算透视投影矩阵:以六个裁剪平面定义投影矩阵。 + * frustumM Calculate the perspective projection matrix * * @param mm float[] * @param right float @@ -164,12 +192,21 @@ public class Matrix { mm[13] = 0.0f; mm[15] = 0.0f; } + + /** + * length + * + * @param x float + * @param y float + * @param z float + * @return float + */ public static float length(float x, float y, float z) { return (float) Math.sqrt(x * x + y * y + z * z); } /** - * setLookAtM 定义相机视图 + * setLookAtM Defining the camera View * * @param rm float[] * @param eyeZ float @@ -211,7 +248,7 @@ public class Matrix { } /** - * translateM 平移矩阵 + * translateM Translation matrix * * @param matrix float[] * @param offset int -- Gitee