diff --git a/UI/Triangle/README_zh.md b/UI/Triangle/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..4e8cf98221a0b888b88efc74022571f21c453b4a
--- /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 0000000000000000000000000000000000000000..65c90323f5b81b1f7427d57785e9121d2e598537
--- /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 6
+ defaultConfig {
+ compatibleSdkVersion 6
+ }
+}
+
+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 0000000000000000000000000000000000000000..517434f3eb381e298cda2efd84135d9b43285fdb
--- /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 6
+ defaultConfig {
+ compatibleSdkVersion 6
+ }
+ 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 0000000000000000000000000000000000000000..db5409b1edd997a4ed7e10ea9ca4c1f2dee380c0
--- /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:app_name",
+ "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 0000000000000000000000000000000000000000..c1857bfc6fc698581cbab56183e3350b4acb515a
--- /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 0000000000000000000000000000000000000000..da3a73b912dd7a3badedc2361aa4133121e90e4e
--- /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 0000000000000000000000000000000000000000..12aee41e138b013dd92e39a45a24718213cd4cf1
--- /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 0000000000000000000000000000000000000000..f0d2de4f91d021aee77e8ced4e0e5356abb68541
--- /dev/null
+++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Matrix.java
@@ -0,0 +1,265 @@
+package ohos.samples.triangle.slice;
+
+public class Matrix {
+
+ /**
+ * multiplyMM Multiplication matrix operation
+ *
+ * @param result float[]
+ * @param resultOffset int
+ * @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];
+ 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);
+ }
+
+ /**
+ * setRotateM Create a new matrix
+ *
+ * @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;
+
+ 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;
+ }
+ }
+
+ /**
+ * 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;
+ rm[1] = ss;
+ rm[4] = -ss;
+ rm[2] = 0;
+ rm[6] = 0;
+ rm[8] = 0;
+ rm[9] = 0;
+ 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;
+ rm[8] = ss;
+ rm[2] = -ss;
+ rm[1] = 0;
+ rm[4] = 0;
+ rm[6] = 0;
+ rm[9] = 0;
+ 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;
+ rm[6] = ss;
+ rm[9] = -ss;
+ rm[1] = 0;
+ rm[2] = 0;
+ rm[4] = 0;
+ rm[8] = 0;
+ 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 Calculate the perspective projection matrix
+ *
+ * @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);
+ 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;
+ }
+
+ /**
+ * 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 Defining the camera View
+ *
+ * @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;
+ 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);
+ }
+
+ /**
+ * translateM Translation matrix
+ *
+ * @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;
+ 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 0000000000000000000000000000000000000000..9b62664301a05f6868d410508feeb8418d3aa143
--- /dev/null
+++ b/UI/Triangle/entry/src/main/java/ohos/samples/triangle/slice/Triangle.java
@@ -0,0 +1,458 @@
+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;
+
+ //三角形的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,
+ 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);
+ //将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");
+ 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);
+
+ }
+
+ /**
+ * checkParameter
+ *
+ * @param program int
+ */
+ 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);
+ }
+
+ /**
+ * 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) {
+ 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;
+ }
+
+ /**
+ * 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();
+ GLES20.glGetShaderInfoLog(shader, max, null,shaderInfoLog);
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ 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());
+ ShortBuffer sb = buffer.asShortBuffer();
+ sb.put(arr).position(0);
+ 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());
+ 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 0000000000000000000000000000000000000000..6e532c6b419e85665655857636cef6d6f48429aa
--- /dev/null
+++ b/UI/Triangle/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,12 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "Triangle"
+ },
+ {
+ "name": "mainability_description",
+ "value": "Draw triangles using OpenGL ES"
+ }
+ ]
+}
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 0000000000000000000000000000000000000000..c0c0a3df480fa387a452b9c40ca191cc918a3fc0
--- /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 0000000000000000000000000000000000000000..655091e796db6c34063919bf381b2f1ad4e5d2f1
--- /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
Binary files /dev/null and b/UI/Triangle/entry/src/main/resources/base/media/icon.png differ
diff --git a/UI/Triangle/entry/src/main/resources/en/element/string.json b/UI/Triangle/entry/src/main/resources/en/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..6e532c6b419e85665655857636cef6d6f48429aa
--- /dev/null
+++ b/UI/Triangle/entry/src/main/resources/en/element/string.json
@@ -0,0 +1,12 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "Triangle"
+ },
+ {
+ "name": "mainability_description",
+ "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
new file mode 100644
index 0000000000000000000000000000000000000000..139a142d9777c3cd306465a9f65558dea461a310
--- /dev/null
+++ b/UI/Triangle/entry/src/main/resources/zh/element/string.json
@@ -0,0 +1,12 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "三角形"
+ },
+ {
+ "name": "mainability_description",
+ "value": "使用 OpenGL_ES 绘制三角形"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/UI/Triangle/screenshots/device/screen.png b/UI/Triangle/screenshots/device/screen.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a0edcdf43d4db7ecbfb40782c4357aa4df087fb
Binary files /dev/null and b/UI/Triangle/screenshots/device/screen.png differ
diff --git a/UI/Triangle/settings.gradle b/UI/Triangle/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..4773db73233a570c2d0c01a22e75321acfbf7a07
--- /dev/null
+++ b/UI/Triangle/settings.gradle
@@ -0,0 +1 @@
+include ':entry'