diff --git a/android/AndroidOpenGLESLessonsCpp/app/CMakeLists.txt b/android/AndroidOpenGLESLessonsCpp/app/CMakeLists.txt
index ac862c1..7f03899 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/CMakeLists.txt
+++ b/android/AndroidOpenGLESLessonsCpp/app/CMakeLists.txt
@@ -14,22 +14,65 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions -Wall")
-add_library( # Sets the name of the library.
- lesson-lib
-
- # Sets the library as a shared library.
- SHARED
-
- # graphics
- src/main/cpp/graphics/GLUtils.h
- src/main/cpp/graphics/GLUtils.cpp
- src/main/cpp/graphics/Matrix.h
- src/main/cpp/graphics/Matrix.cpp
-
- # Provides a relative path to your source file(s).
- # lesson1
- src/main/cpp/lesson1/Native1Lesson.cpp
- src/main/cpp/lesson1/Native1Lesson.h
+add_library(
+ # Sets the name of the library.
+ lesson-lib
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # graphics
+ src/main/cpp/graphics/GLUtils.h
+ src/main/cpp/graphics/GLUtils.cpp
+ src/main/cpp/graphics/Matrix.h
+ src/main/cpp/graphics/Matrix.cpp
+
+ # Provides a relative path to your source file(s).
+ # lesson1
+ src/main/cpp/lesson1/Native1Lesson.cpp
+ src/main/cpp/lesson1/Native1Lesson.h
+
+ # lesson2
+ src/main/cpp/lesson2/Native2Lesson.cpp
+ src/main/cpp/lesson2/Native2Lesson.h
+
+ # lesson3
+ src/main/cpp/lesson3/Native3Lesson.cpp
+ src/main/cpp/lesson3/Native3Lesson.h
+
+ # lesson4
+ src/main/cpp/lesson4/Native4Lesson.cpp
+ src/main/cpp/lesson4/Native4Lesson.h
+
+ # lesson5
+ src/main/cpp/lesson5/Native5Lesson.cpp
+ src/main/cpp/lesson5/Native5Lesson.h
+
+ # lesson6
+ src/main/cpp/lesson6/Native6Lesson.cpp
+ src/main/cpp/lesson6/Native6Lesson.h
+
+ # lesson7
+ src/main/cpp/lesson7/Native7Lesson.cpp
+ src/main/cpp/lesson7/Native7Lesson.h
+ src/main/cpp/lesson7/Cubes.cpp
+ src/main/cpp/lesson7/Cubes.h
+ src/main/cpp/lesson7/CubesClientSide.cpp
+ src/main/cpp/lesson7/CubesClientSide.h
+ src/main/cpp/lesson7/CubesClientSideWithStride.cpp
+ src/main/cpp/lesson7/CubesClientSideWithStride.h
+ src/main/cpp/lesson7/CubesWithVbo.cpp
+ src/main/cpp/lesson7/CubesWithVbo.h
+ src/main/cpp/lesson7/CubesWithVboWithStride.cpp
+ src/main/cpp/lesson7/CubesWithVboWithStride.h
+ src/main/cpp/lesson7/GenData.cpp
+ src/main/cpp/lesson7/GenData.h
+
+ # lesson8
+ src/main/cpp/lesson8/Native8Lesson.cpp
+ src/main/cpp/lesson8/Native8Lesson.h
+ src/main/cpp/lesson8/HeightMap.cpp
+ src/main/cpp/lesson8/HeightMap.h
)
include_directories(src/main/cpp/)
diff --git a/android/AndroidOpenGLESLessonsCpp/app/build.gradle b/android/AndroidOpenGLESLessonsCpp/app/build.gradle
index 8490dd9..25e1c8c 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/build.gradle
+++ b/android/AndroidOpenGLESLessonsCpp/app/build.gradle
@@ -3,13 +3,12 @@ apply plugin: 'com.android.application'
def platformVersion = 18 //openGLES 3 min Version
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion 27
defaultConfig {
- applicationId "com.learnopengles.android"
- minSdkVersion 9
- targetSdkVersion 25
+ applicationId "com.learnopengles.android.cpp"
+ minSdkVersion 21
+ targetSdkVersion 27
externalNativeBuild {
cmake {
@@ -26,3 +25,8 @@ android {
}
}
}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:27.0.2'
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/AndroidManifest.xml b/android/AndroidOpenGLESLessonsCpp/app/src/main/AndroidManifest.xml
index ae40268..5d32d38 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/AndroidManifest.xml
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
@@ -13,16 +13,46 @@
android:icon="@drawable/icon"
android:label="@string/app_name">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/fragment/per_pixel_fragment_shader_no_tex.glsl b/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/fragment/per_pixel_fragment_shader_no_tex.glsl
new file mode 100644
index 0000000..c13eca8
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/fragment/per_pixel_fragment_shader_no_tex.glsl
@@ -0,0 +1,38 @@
+precision mediump float; // Set the default precision to medium. We don't need as high of a
+ // precision in the fragment shader.
+uniform vec3 u_LightPos; // The position of the light in eye space.
+
+varying vec3 v_Position; // Interpolated position for this fragment.
+varying vec4 v_Color; // This is the color from the vertex shader interpolated across the
+ // triangle per fragment.
+varying vec3 v_Normal; // Interpolated normal for this fragment.
+
+// The entry point for our fragment shader.
+void main()
+{
+ // Will be used for attenuation.
+ float distance = length(u_LightPos - v_Position);
+
+ // Get a lighting direction vector from the light to the vertex.
+ vec3 lightVector = normalize(u_LightPos - v_Position);
+
+ // Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
+ // pointing in the same direction then it will get max illumination.
+ float diffuse;
+
+ if (gl_FrontFacing) {
+ diffuse = max(dot(v_Normal, lightVector), 0.0);
+ } else {
+ diffuse = max(dot(-v_Normal, lightVector), 0.0);
+ }
+
+ // Add attenuation.
+ diffuse = diffuse * (1.0 / (1.0 + (0.10 * distance)));
+
+ // Add ambient lighting
+ diffuse = diffuse + 0.3;
+
+ // Multiply the color by the diffuse illumination level to get final output color.
+ gl_FragColor = (v_Color * diffuse);
+}
+
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/vertex/per_pixel_vertex_shader_no_tex.glsl b/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/vertex/per_pixel_vertex_shader_no_tex.glsl
new file mode 100644
index 0000000..bb92053
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/assets/vertex/per_pixel_vertex_shader_no_tex.glsl
@@ -0,0 +1,27 @@
+uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.
+uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix.
+
+attribute vec4 a_Position; // Per-vertex position information we will pass in.
+attribute vec4 a_Color; // Per-vertex color information we will pass in.
+attribute vec3 a_Normal; // Per-vertex normal information we will pass in.
+
+varying vec3 v_Position; // This will be passed into the fragment shader.
+varying vec4 v_Color; // This will be passed into the fragment shader.
+varying vec3 v_Normal; // This will be passed into the fragment shader.
+
+// The entry point for our vertex shader.
+void main()
+{
+ // Transform the vertex into eye space.
+ v_Position = vec3(u_MVMatrix * a_Position);
+
+ // Pass through the color.
+ v_Color = a_Color;
+
+ // Transform the normal's orientation into eye space.
+ v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));
+
+ // gl_Position is a special variable used to store the final position.
+ // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
+ gl_Position = u_MVPMatrix * a_Position;
+}
\ No newline at end of file
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/GLUtils.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/GLUtils.cpp
index 28444a7..2ed207d 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/GLUtils.cpp
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/GLUtils.cpp
@@ -97,7 +97,7 @@ long GLUtils::currentTimeMillis() {
GLuint GLUtils::loadTexture(const char *path) {
GLuint textureId = 0;
- jclass utilsClass = sEnv->FindClass("com/bzh/gl/Utils");
+ jclass utilsClass = sEnv->FindClass("com/learnopengles/android/Utils");
if (utilsClass == NULL) {
LOGE("Couldn't find utils class");
return (GLuint) -1;
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.cpp
index 8b70fef..70b6636 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.cpp
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.cpp
@@ -344,3 +344,7 @@ void mx4transform(float x, float y, float z, float w, const float *pM, float *pD
void Matrix::multiplyMV(float *r, const float *lhs, const float *rhs) {
mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
}
+
+float Matrix::length(float x, float y, float z) {
+ return (float) sqrt(x * x + y * y + z * z);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.h
index 82e2799..9953b5d 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.h
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/graphics/Matrix.h
@@ -16,7 +16,9 @@
class Matrix {
public:
+
static const int MATRIX_SIZE = 16;
+
float mData[MATRIX_SIZE];
Matrix();
@@ -68,6 +70,16 @@ class Matrix {
const float *rhs);
static void multiplyMV(float *r, const float *lhs, const float *rhs);
+
+ /**
+ * Computes the length of a vector.
+ *
+ * @param x x coordinate of a vector
+ * @param y y coordinate of a vector
+ * @param z z coordinate of a vector
+ * @return the length of a vector
+ */
+ static float length(float x, float y, float z);
};
#endif
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.cpp
new file mode 100644
index 0000000..7ef3ead
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.cpp
@@ -0,0 +1,587 @@
+//
+// Created by biezhihua on 2017/7/8.
+//
+
+#include "Native2Lesson.h"
+#include "../graphics/GLUtils.h"
+
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+static GLint POSITION_DATA_SIZE = 3;
+static GLint COLOR_DATA_SIZE = 4;
+static GLint NORMAL_DATA_SIZE = 3;
+
+static const char *POINT_VERTEX_SHADER_CODE =
+ "uniform mat4 u_MVPMatrix; \n"
+ "attribute vec4 a_Position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_MVPMatrix \n"
+ " * a_Position; \n"
+ " gl_PointSize = 5.0; \n"
+ "} \n";
+
+static const char *POINT_FRAGMENT_SHADER_CODE =
+ "precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(1.0, \n"
+ " 1.0, 1.0, 1.0); \n"
+ "} \n";
+
+static const char *VERTEX_SHADER_CODE =
+ "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "uniform mat4 u_MVMatrix; \n" // A constant representing the combined model/view matrix.
+ "uniform vec3 u_LightPos; \n" // The position of the light in eye space.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "attribute vec3 a_Normal; \n" // Per-vertex normal information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ // Transform the vertex into eye space.
+ " vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); \n"
+ // Transform the normal's orientation into eye space.
+ " vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0)); \n"
+ // Will be used for attenuation.
+ " float distance = length(u_LightPos - modelViewVertex); \n"
+ // Get a lighting direction vector from the light to the vertex.
+ " vec3 lightVector = normalize(u_LightPos - modelViewVertex); \n"
+ // Calculate the dot product of the light vector and vertex normal.
+ // If the normal and light vector are
+ // pointing in the same direction then it will get max illumination.
+ " float diffuse = max(dot(modelViewNormal, lightVector), 0.1); \n"
+ // Attenuate the light based on distance.
+ " diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance))); \n"
+ // Multiply the color by the illumination level. It will be interpolated across the triangle.
+ " v_Color = a_Color * diffuse; \n"
+ // gl_Position is a special variable used to store the final position.
+ // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
+ " gl_Position = u_MVPMatrix * a_Position; \n"
+ "}";
+
+static const char *FRAGMENT_SHADER_CODE =
+ // Set the default precision to medium. We don't need as high of a
+ // precision in the fragment shader.
+ "precision mediump float; \n"
+ // This is the color from the vertex shader interpolated across the
+ // triangle per fragment.
+ "varying vec4 v_Color; \n"
+ // The entry point for our fragment shader.
+ "void main() \n"
+ "{ \n"
+ // Pass the color directly through the pipeline.
+ " gl_FragColor = v_Color; \n"
+ "} \n";
+
+
+const static GLfloat CUBE_POSITION_DATA[] = {
+ // Front face
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+
+ // Right face
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Back face
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ // Left face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+
+ // Top face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Bottom face
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+};
+
+static const GLfloat CUBE_COLOR_DATA[] = {
+ // R, G, B, A
+
+ // Front face (red)
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+
+ // Right face (green)
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+
+ // Back face (blue)
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+
+ // Left face (yellow)
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+
+ // Top face (cyan)
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+
+ // Bottom face (magenta)
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f
+};
+
+// X, Y, Z
+// The normal is used in light calculations and is a vector which points
+// orthogonal to the plane of the surface. For a cube model, the normals
+// should be orthogonal to the points of each face.
+static const GLfloat CUBE_NORMAL_DATA[] = {
+ // Front face
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+
+ // Right face
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+
+ // Left face
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+
+ // Top face
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f
+};
+
+
+Native2Lesson::Native2Lesson() {
+
+ mWidth = 0;
+ mHeight = 0;
+
+ mViewMatrix = NULL;
+ mModelMatrix = NULL;
+ mProjectionMatrix = NULL;
+ mMVPMatrix = NULL;
+ mLightModelMatrix = NULL;
+
+ mMVPMatrixHandle = 0;
+ mMVMatrixHandle = 0;
+ mLightPosHandle = 0;
+ mPositionHandle = 0;
+ mColorHandle = 0;
+ mNormalHandle = 0;
+
+ mPerVertexProgramHandle = 0;
+ mPointProgramHandle = 0;
+
+ mLightPosInModelSpace[0] = 0.0f;
+ mLightPosInModelSpace[1] = 0.0f;
+ mLightPosInModelSpace[2] = 0.0f;
+ mLightPosInModelSpace[3] = 1.0f;
+
+ mLightPosInWorldSpace[0] = 0.0f;
+ mLightPosInWorldSpace[1] = 0.0f;
+ mLightPosInWorldSpace[2] = 0.0f;
+ mLightPosInWorldSpace[3] = 0.0f;
+
+ mLightPosInEyeSpace[0] = 0.0f;
+ mLightPosInEyeSpace[1] = 0.0f;
+ mLightPosInEyeSpace[2] = 0.0f;
+ mLightPosInEyeSpace[3] = 0.0f;
+
+ LOGD("Create Native2Lesson instance successful");
+}
+
+void Native2Lesson::create() {
+ LOGD("Native2Lesson create");
+
+ // Use culling to remove back face.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Set program handles
+ mPerVertexProgramHandle = GLUtils::createProgram(&VERTEX_SHADER_CODE, &FRAGMENT_SHADER_CODE);
+ if (!mPerVertexProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Set Point program handle
+ mPointProgramHandle = GLUtils::createProgram(&POINT_VERTEX_SHADER_CODE,
+ &POINT_FRAGMENT_SHADER_CODE);
+ if (!mPointProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ mLightModelMatrix = new Matrix();
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = 1.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+}
+
+void Native2Lesson::change(int width, int height) {
+ LOGD("Native2Lesson change");
+
+ mWidth = width;
+ mHeight = height;
+
+ glViewport(0, 0, mWidth, mHeight);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+}
+
+void Native2Lesson::draw() {
+ // Set the OpenGL viewport to same size as the surface.
+
+ glClearColor(0, 0, 0, 1);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
+
+ // Set out pre-vertex lighting program.
+ glUseProgram(mPerVertexProgramHandle);
+
+ // Set program handle for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVPMatrix");
+ mMVMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVMatrix");
+ mLightPosHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_LightPos");
+ mPositionHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Position");
+ mColorHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Color");
+ mNormalHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Normal");
+
+ // Calculate position of the light
+ // Rotate and then push into the distance.
+ mLightModelMatrix->identity();
+ mLightModelMatrix->translate(0, 0, -5);
+ mLightModelMatrix->rotate(angleInDegrees, 0, 1, 0);
+ mLightModelMatrix->translate(0, 0, 2);
+
+ Matrix::multiplyMV(mLightPosInWorldSpace, mLightModelMatrix->mData, mLightPosInModelSpace);
+ Matrix::multiplyMV(mLightPosInEyeSpace, mViewMatrix->mData, mLightPosInWorldSpace);
+
+ // right
+ mModelMatrix->identity();
+ mModelMatrix->translate(4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 0.0f, 0.0f);
+ drawCube();
+
+ // left
+ mModelMatrix->identity();
+ mModelMatrix->translate(-4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // top
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // bottom
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, -4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // center
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.0f, -5.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 1.0f, 1.0f);
+ drawCube();
+
+ // Draw a pint to indicate the light
+ glUseProgram(mPointProgramHandle);
+ drawLight();
+}
+
+void Native2Lesson::destroy() {
+ delete mModelMatrix;
+ mModelMatrix = NULL;
+ delete mViewMatrix;
+ mViewMatrix = NULL;
+ delete mProjectionMatrix;
+ mProjectionMatrix = NULL;
+ delete mLightModelMatrix;
+ mLightModelMatrix = NULL;
+}
+
+Native2Lesson::~Native2Lesson() {
+ destroy();
+}
+
+void Native2Lesson::drawCube() {
+
+ // Pass in the position info
+ glVertexAttribPointer(
+ mPositionHandle,
+ POSITION_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_POSITION_DATA
+ );
+ glEnableVertexAttribArray(mPositionHandle);
+
+ // Pass in the color info
+ glVertexAttribPointer(
+ mColorHandle,
+ COLOR_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_COLOR_DATA
+ );
+ glEnableVertexAttribArray(mColorHandle);
+
+ // Pass in the normal information
+ glVertexAttribPointer(
+ mNormalHandle,
+ NORMAL_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_NORMAL_DATA
+ );
+ glEnableVertexAttribArray(mNormalHandle);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // Pass in the model view matrix
+ glUniformMatrix4fv(
+ mMVMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Pass in the light position in eye space
+ glUniform3f(mLightPosHandle,
+ mLightPosInEyeSpace[0],
+ mLightPosInEyeSpace[1],
+ mLightPosInEyeSpace[2]
+ );
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Native2Lesson::drawLight() {
+
+ GLint pointMVPMatrixHandle = glGetUniformLocation(mPointProgramHandle, "u_MVPMatrix");
+ GLint pointPositionHandle = glGetAttribLocation(mPointProgramHandle, "a_Position");
+
+ // Pass in the position
+ glVertexAttrib3f(
+ pointPositionHandle,
+ mLightPosInModelSpace[0],
+ mLightPosInModelSpace[1],
+ mLightPosInModelSpace[2]);
+
+ // Since we are not using a buffer object,
+ // disable vertex arrays for the attribute
+ glDisableVertexAttribArray(pointPositionHandle);
+
+ // Pass in the transformation matrix.
+ mMVPMatrix->identity();
+ mMVPMatrix->multiply(*mViewMatrix, *mLightModelMatrix);
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ glUniformMatrix4fv(
+ pointMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ glDrawArrays(GL_POINTS, 0, 1);
+}
+
+
+///=======
+
+static Native2Lesson *native2Lesson;
+
+static void printGLString(const char *name, GLenum s) {
+ const char *v = (const char *) glGetString(s);
+ LOGI("GL %s = %s \n", name, v);
+}
+
+static void checkGlError(const char *op) {
+ for (GLint error = glGetError(); error; error = glGetError()) {
+ LOGI("after %s() glError (0x%x)\n", op, error);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson2_LessonTwoNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jclass type) {
+ if (native2Lesson) {
+ delete native2Lesson;
+ native2Lesson = NULL;
+ }
+
+ // Print some OpenGL info
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ native2Lesson = new Native2Lesson();
+ native2Lesson->create();
+
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson2_LessonTwoNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jclass type,
+ jint width,
+ jint height) {
+ if (native2Lesson) {
+ native2Lesson->change(width, height);
+ }
+
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson2_LessonTwoNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jclass type) {
+ if (native2Lesson) {
+ native2Lesson->draw();
+ }
+}
\ No newline at end of file
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.h
new file mode 100644
index 0000000..cad1bb1
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.h
@@ -0,0 +1,58 @@
+//
+// Created by biezhihua on 2017/7/8.
+//
+
+#ifndef OPENGLLESSON_NATIVE2LESSON_H
+#define OPENGLLESSON_NATIVE2LESSON_H
+
+
+#include
+#include "../graphics/Matrix.h"
+
+class Native2Lesson {
+
+public:
+
+ Native2Lesson();
+
+ ~Native2Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+ void destroy();
+
+private:
+
+ GLsizei mWidth;
+ GLsizei mHeight;
+
+ Matrix *mViewMatrix;
+ Matrix *mModelMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+ Matrix *mLightModelMatrix;
+
+ GLuint mMVPMatrixHandle;
+ GLuint mMVMatrixHandle;
+ GLuint mLightPosHandle;
+ GLuint mPositionHandle;
+ GLuint mColorHandle;
+ GLuint mNormalHandle;
+
+ GLuint mPerVertexProgramHandle;
+ GLuint mPointProgramHandle;
+
+ float mLightPosInModelSpace[4];
+ float mLightPosInWorldSpace[4];
+ float mLightPosInEyeSpace[4];
+
+ void drawCube();
+
+ void drawLight();
+};
+
+#endif //OPENGLLESSON_NATIVE2LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.cpp
new file mode 100644
index 0000000..89c9a82
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.cpp
@@ -0,0 +1,567 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#include
+#include "Native3Lesson.h"
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+static GLint POSITION_DATA_SIZE = 3;
+static GLint COLOR_DATA_SIZE = 4;
+static GLint NORMAL_DATA_SIZE = 3;
+
+static const char *POINT_VERTEX_SHADER_CODE =
+ "uniform mat4 u_MVPMatrix; \n"
+ "attribute vec4 a_Position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_MVPMatrix \n"
+ " * a_Position; \n"
+ " gl_PointSize = 5.0; \n"
+ "} \n";
+
+static const char *POINT_FRAGMENT_SHADER_CODE =
+ "precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(1.0, \n"
+ " 1.0, 1.0, 1.0); \n"
+ "} \n";
+
+static const char *VERTEX_SHADER_CODE =
+ "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "uniform mat4 u_MVMatrix; \n" // A constant representing the combined model/view matrix.
+
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "attribute vec3 a_Normal; \n" // Per-vertex normal information we will pass in.
+
+ "varying vec3 v_Position; \n" // This will be passed into the fragment shader.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "varying vec3 v_Normal; \n" // This will be passed into the fragment shader.
+
+ // The entry point for our vertex shader.
+ "void main() \n"
+ "{ \n"
+ // Transform the vertex into eye space.
+ " v_Position = vec3(u_MVMatrix * a_Position); \n"
+ // Pass through the color.
+ " v_Color = a_Color; \n"
+ // Transform the normal's orientation into eye space.
+ " v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0)); \n"
+ // gl_Position is a special variable used to store the final position.
+ // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
+ " gl_Position = u_MVPMatrix * a_Position; \n"
+ "}";
+
+static const char *FRAGMENT_SHADER_CODE =
+ "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
+ // precision in the fragment shader.
+ "uniform vec3 u_LightPos; \n" // The position of the light in eye space.
+
+ "varying vec3 v_Position; \n" // Interpolated position for this fragment.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
+ // triangle per fragment.
+ "varying vec3 v_Normal; \n" // Interpolated normal for this fragment.
+
+ // The entry point for our fragment shader.
+ "void main() \n"
+ "{ \n"
+ // Will be used for attenuation.
+ " float distance = length(u_LightPos - v_Position); \n"
+ // Get a lighting direction vector from the light to the vertex.
+ " vec3 lightVector = normalize(u_LightPos - v_Position); \n"
+ // Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
+ // pointing in the same direction then it will get max illumination.
+ " float diffuse = max(dot(v_Normal, lightVector), 0.1); \n"
+ // Add attenuation.
+ " diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance))); \n"
+ // Multiply the color by the diffuse illumination level to get final output color.
+ " gl_FragColor = v_Color * diffuse; \n"
+ "} \n";
+
+
+const static GLfloat CUBE_POSITION_DATA[] = {
+ // Front face
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+
+ // Right face
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Back face
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ // Left face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+
+ // Top face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Bottom face
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+};
+
+static const GLfloat CUBE_COLOR_DATA[] = {
+ // R, G, B, A
+
+ // Front face (red)
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+
+ // Right face (green)
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+
+ // Back face (blue)
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+
+ // Left face (yellow)
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+
+ // Top face (cyan)
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+
+ // Bottom face (magenta)
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f
+};
+
+// X, Y, Z
+// The normal is used in light calculations and is a vector which points
+// orthogonal to the plane of the surface. For a cube model, the normals
+// should be orthogonal to the points of each face.
+static const GLfloat CUBE_NORMAL_DATA[] = {
+ // Front face
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+
+ // Right face
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+
+ // Left face
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+
+ // Top face
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f
+};
+
+Native3Lesson::Native3Lesson() {
+ mWidth = 0;
+ mHeight = 0;
+
+ mViewMatrix = NULL;
+ mModelMatrix = NULL;
+ mProjectionMatrix = NULL;
+ mMVPMatrix = NULL;
+ mLightModelMatrix = NULL;
+
+ mMVPMatrixHandle = 0;
+ mMVMatrixHandle = 0;
+ mLightPosHandle = 0;
+ mPositionHandle = 0;
+ mColorHandle = 0;
+ mNormalHandle = 0;
+
+ mPerVertexProgramHandle = 0;
+ mPointProgramHandle = 0;
+
+ mLightPosInModelSpace[0] = 0.0f;
+ mLightPosInModelSpace[1] = 0.0f;
+ mLightPosInModelSpace[2] = 0.0f;
+ mLightPosInModelSpace[3] = 1.0f;
+
+ mLightPosInWorldSpace[0] = 0.0f;
+ mLightPosInWorldSpace[1] = 0.0f;
+ mLightPosInWorldSpace[2] = 0.0f;
+ mLightPosInWorldSpace[3] = 0.0f;
+
+ mLightPosInEyeSpace[0] = 0.0f;
+ mLightPosInEyeSpace[1] = 0.0f;
+ mLightPosInEyeSpace[2] = 0.0f;
+ mLightPosInEyeSpace[3] = 0.0f;
+}
+
+Native3Lesson::~Native3Lesson() {
+ delete mModelMatrix;
+ mModelMatrix = NULL;
+ delete mViewMatrix;
+ mViewMatrix = NULL;
+ delete mProjectionMatrix;
+ mProjectionMatrix = NULL;
+ delete mLightModelMatrix;
+ mLightModelMatrix = NULL;
+}
+
+void Native3Lesson::create() {
+ LOGD("Native3Lesson create");
+
+ // Use culling to remove back face.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Set program handles
+ mPerVertexProgramHandle = GLUtils::createProgram(&VERTEX_SHADER_CODE, &FRAGMENT_SHADER_CODE);
+ if (!mPerVertexProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Set Point program handle
+ mPointProgramHandle = GLUtils::createProgram(&POINT_VERTEX_SHADER_CODE,
+ &POINT_FRAGMENT_SHADER_CODE);
+ if (!mPointProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ mLightModelMatrix = new Matrix();
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = 1.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+}
+
+void Native3Lesson::change(int width, int height) {
+
+ mWidth = width;
+ mHeight = height;
+
+ glViewport(0, 0, mWidth, mHeight);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+}
+
+void Native3Lesson::draw() {
+// Set the OpenGL viewport to same size as the surface.
+
+ glClearColor(0, 0, 0, 1);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
+
+ // Set out pre-vertex lighting program.
+ glUseProgram(mPerVertexProgramHandle);
+
+ // Set program handle for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVPMatrix");
+ mMVMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVMatrix");
+ mLightPosHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_LightPos");
+ mPositionHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Position");
+ mColorHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Color");
+ mNormalHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Normal");
+
+ // Calculate position of the light
+ // Rotate and then push into the distance.
+ mLightModelMatrix->identity();
+ mLightModelMatrix->translate(0, 0, -5);
+ mLightModelMatrix->rotate(angleInDegrees, 0, 1, 0);
+ mLightModelMatrix->translate(0, 0, 2);
+
+ Matrix::multiplyMV(mLightPosInWorldSpace, mLightModelMatrix->mData, mLightPosInModelSpace);
+ Matrix::multiplyMV(mLightPosInEyeSpace, mViewMatrix->mData, mLightPosInWorldSpace);
+
+ // right
+ mModelMatrix->identity();
+ mModelMatrix->translate(4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 0.0f, 0.0f);
+ drawCube();
+
+ // left
+ mModelMatrix->identity();
+ mModelMatrix->translate(-4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // top
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // bottom
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, -4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // center
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.0f, -5.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 1.0f, 1.0f);
+ drawCube();
+
+ // Draw a pint to indicate the light
+ glUseProgram(mPointProgramHandle);
+ drawLight();
+}
+
+void Native3Lesson::drawCube() {
+
+ // Pass in the position info
+ glVertexAttribPointer(
+ mPositionHandle,
+ POSITION_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_POSITION_DATA
+ );
+ glEnableVertexAttribArray(mPositionHandle);
+
+ // Pass in the color info
+ glVertexAttribPointer(
+ mColorHandle,
+ COLOR_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_COLOR_DATA
+ );
+ glEnableVertexAttribArray(mColorHandle);
+
+ // Pass in the normal information
+ glVertexAttribPointer(
+ mNormalHandle,
+ NORMAL_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_NORMAL_DATA
+ );
+ glEnableVertexAttribArray(mNormalHandle);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // Pass in the model view matrix
+ glUniformMatrix4fv(
+ mMVMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Pass in the light position in eye space
+ glUniform3f(mLightPosHandle,
+ mLightPosInEyeSpace[0],
+ mLightPosInEyeSpace[1],
+ mLightPosInEyeSpace[2]
+ );
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Native3Lesson::drawLight() {
+
+ GLint pointMVPMatrixHandle = glGetUniformLocation(mPointProgramHandle, "u_MVPMatrix");
+ GLint pointPositionHandle = glGetAttribLocation(mPointProgramHandle, "a_Position");
+
+ // Pass in the position
+ glVertexAttrib3f(
+ pointPositionHandle,
+ mLightPosInModelSpace[0],
+ mLightPosInModelSpace[1],
+ mLightPosInModelSpace[2]);
+
+ // Since we are not using a buffer object,
+ // disable vertex arrays for the attribute
+ glDisableVertexAttribArray(pointPositionHandle);
+
+ // Pass in the transformation matrix.
+ mMVPMatrix->identity();
+ mMVPMatrix->multiply(*mViewMatrix, *mLightModelMatrix);
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ glUniformMatrix4fv(
+ pointMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ glDrawArrays(GL_POINTS, 0, 1);
+}
+
+
+//////////////////////
+
+
+Native3Lesson *lesson3;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson3_LessonThreeNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jclass type) {
+
+ if (lesson3) {
+ delete lesson3;
+ lesson3 = NULL;
+ }
+ lesson3 = new Native3Lesson();
+ lesson3->create();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson3_LessonThreeNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jclass type,
+ jint width,
+ jint height) {
+ if (lesson3) {
+ lesson3->change(width, height);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson3_LessonThreeNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jclass type) {
+
+ if (lesson3) {
+ lesson3->draw();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.h
new file mode 100644
index 0000000..0ddaf39
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.h
@@ -0,0 +1,55 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#ifndef OPENGLLESSON_NATIVE3LESSON_H
+#define OPENGLLESSON_NATIVE3LESSON_H
+
+#include
+#include "../graphics/Matrix.h"
+
+class Native3Lesson {
+
+public:
+
+ Native3Lesson();
+
+ ~Native3Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+private:
+
+ GLsizei mWidth;
+ GLsizei mHeight;
+
+ Matrix *mViewMatrix;
+ Matrix *mModelMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+ Matrix *mLightModelMatrix;
+
+ GLuint mMVPMatrixHandle;
+ GLuint mMVMatrixHandle;
+ GLuint mLightPosHandle;
+ GLuint mPositionHandle;
+ GLuint mColorHandle;
+ GLuint mNormalHandle;
+
+ GLuint mPerVertexProgramHandle;
+ GLuint mPointProgramHandle;
+
+ float mLightPosInModelSpace[4];
+ float mLightPosInWorldSpace[4];
+ float mLightPosInEyeSpace[4];
+
+ void drawCube();
+
+ void drawLight();
+};
+
+#endif //OPENGLLESSON_NATIVE3LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.cpp
new file mode 100644
index 0000000..4904ddf
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.cpp
@@ -0,0 +1,607 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#include
+#include "Native4Lesson.h"
+#include
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+static GLint POSITION_DATA_SIZE = 3;
+static GLint COLOR_DATA_SIZE = 4;
+static GLint NORMAL_DATA_SIZE = 3;
+
+static const char *POINT_VERTEX_SHADER_CODE =
+ "uniform mat4 u_MVPMatrix; \n"
+ "attribute vec4 a_Position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_MVPMatrix \n"
+ " * a_Position; \n"
+ " gl_PointSize = 5.0; \n"
+ "} \n";
+
+static const char *POINT_FRAGMENT_SHADER_CODE =
+ "precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(1.0, \n"
+ " 1.0, 1.0, 1.0); \n"
+ "} \n";
+
+const static GLfloat CUBE_POSITION_DATA[] = {
+ // Front face
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+
+ // Right face
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Back face
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ // Left face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+
+ // Top face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Bottom face
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+};
+
+static const GLfloat CUBE_COLOR_DATA[] = {
+ // R, G, B, A
+
+ // Front face (red)
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+
+ // Right face (green)
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+
+ // Back face (blue)
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+
+ // Left face (yellow)
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+
+ // Top face (cyan)
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+
+ // Bottom face (magenta)
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f
+};
+
+// X, Y, Z
+// The normal is used in light calculations and is a vector which points
+// orthogonal to the plane of the surface. For a cube model, the normals
+// should be orthogonal to the points of each face.
+static const GLfloat CUBE_NORMAL_DATA[] = {
+ // Front face
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+
+ // Right face
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+
+ // Left face
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+
+ // Top face
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f
+};
+
+/**
+ * S,T (X,Y)
+ * Texture coordinate data.
+ * Because images have a Y axis pointing downward,
+ * while OpenGL has a Y axis pointing upward, we adjust for
+ * that here by flipping the Y axis.
+ * What's more is that the texture coordinates are the same for every face.
+ */
+static const GLfloat CUBE_TEXTURE_COORDINATE_DATA[] =
+ {
+ // Front face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Right face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Left face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Top face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+ };
+
+Native4Lesson::Native4Lesson() {
+ mWidth = 0;
+ mHeight = 0;
+
+ mViewMatrix = NULL;
+ mModelMatrix = NULL;
+ mProjectionMatrix = NULL;
+ mMVPMatrix = NULL;
+ mLightModelMatrix = NULL;
+
+ mMVPMatrixHandle = 0;
+ mMVMatrixHandle = 0;
+ mLightPosHandle = 0;
+ mPositionHandle = 0;
+ mColorHandle = 0;
+ mNormalHandle = 0;
+
+ mPerVertexProgramHandle = 0;
+ mPointProgramHandle = 0;
+
+ mLightPosInModelSpace[0] = 0.0f;
+ mLightPosInModelSpace[1] = 0.0f;
+ mLightPosInModelSpace[2] = 0.0f;
+ mLightPosInModelSpace[3] = 1.0f;
+
+ mLightPosInWorldSpace[0] = 0.0f;
+ mLightPosInWorldSpace[1] = 0.0f;
+ mLightPosInWorldSpace[2] = 0.0f;
+ mLightPosInWorldSpace[3] = 0.0f;
+
+ mLightPosInEyeSpace[0] = 0.0f;
+ mLightPosInEyeSpace[1] = 0.0f;
+ mLightPosInEyeSpace[2] = 0.0f;
+ mLightPosInEyeSpace[3] = 0.0f;
+}
+
+Native4Lesson::~Native4Lesson() {
+ delete mModelMatrix;
+ mModelMatrix = NULL;
+ delete mViewMatrix;
+ mViewMatrix = NULL;
+ delete mProjectionMatrix;
+ mProjectionMatrix = NULL;
+ delete mLightModelMatrix;
+ mLightModelMatrix = NULL;
+}
+
+void Native4Lesson::create() {
+ LOGD("Native4Lesson create");
+
+ // Use culling to remove back face.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Main Program
+ const char *vertex = GLUtils::openTextFile("vertex/per_pixel_vertex_shader.glsl");
+ const char *fragment = GLUtils::openTextFile("fragment/per_pixel_fragment_shader.glsl");
+
+ // Set program handles
+ mPerVertexProgramHandle = GLUtils::createProgram(&vertex, &fragment);
+ if (!mPerVertexProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Set Point program handle
+ mPointProgramHandle = GLUtils::createProgram(&POINT_VERTEX_SHADER_CODE,
+ &POINT_FRAGMENT_SHADER_CODE);
+ if (!mPointProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ mTextureDataHandle = GLUtils::loadTexture("texture/bumpy_bricks_public_domain.jpg");
+
+ mLightModelMatrix = new Matrix();
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = 1.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+}
+
+void Native4Lesson::change(int width, int height) {
+
+ mWidth = width;
+ mHeight = height;
+
+ glViewport(0, 0, mWidth, mHeight);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+}
+
+void Native4Lesson::draw() {
+// Set the OpenGL viewport to same size as the surface.
+
+ glClearColor(0, 0, 0, 1);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
+
+ // Set out pre-vertex lighting program.
+ glUseProgram(mPerVertexProgramHandle);
+
+ // Set program handle for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVPMatrix");
+ mMVMatrixHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_MVMatrix");
+ mLightPosHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_LightPos");
+ mPositionHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Position");
+ mColorHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Color");
+ mNormalHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle, "a_Normal");
+ mTextureUniformHandle = (GLuint) glGetUniformLocation(mPerVertexProgramHandle, "u_Texture");
+ mTextureCoordinateHandle = (GLuint) glGetAttribLocation(mPerVertexProgramHandle,
+ "a_TexCoordinate");
+
+ // Set the active texture unit to texture unit 0.
+ glActiveTexture(GL_TEXTURE0);
+
+ // Bind the texture to this unit
+ glBindTexture(GL_TEXTURE_2D, mTextureDataHandle);
+
+ // Tell the texture uniform sampler to use the texture
+ // in the shader by binding to texture unit 0.
+ glUniform1i(mTextureUniformHandle, 0);
+
+
+ // Calculate position of the light
+ // Rotate and then push into the distance.
+ mLightModelMatrix->identity();
+ mLightModelMatrix->translate(0, 0, -5);
+ mLightModelMatrix->rotate(angleInDegrees, 0, 1, 0);
+ mLightModelMatrix->translate(0, 0, 2);
+
+ Matrix::multiplyMV(mLightPosInWorldSpace, mLightModelMatrix->mData, mLightPosInModelSpace);
+ Matrix::multiplyMV(mLightPosInEyeSpace, mViewMatrix->mData, mLightPosInWorldSpace);
+
+ // right
+ mModelMatrix->identity();
+ mModelMatrix->translate(4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 0.0f, 0.0f);
+ drawCube();
+
+ // left
+ mModelMatrix->identity();
+ mModelMatrix->translate(-4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // top
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // bottom
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, -4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // center
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.0f, -5.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 1.0f, 1.0f);
+ drawCube();
+
+ // Draw a pint to indicate the light
+ glUseProgram(mPointProgramHandle);
+ drawLight();
+}
+
+void Native4Lesson::drawCube() {
+
+ // Pass in the position info
+ glVertexAttribPointer(
+ mPositionHandle,
+ POSITION_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_POSITION_DATA
+ );
+ glEnableVertexAttribArray(mPositionHandle);
+
+ // Pass in the color info
+ glVertexAttribPointer(
+ mColorHandle,
+ COLOR_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_COLOR_DATA
+ );
+ glEnableVertexAttribArray(mColorHandle);
+
+ // Pass in the normal information
+ glVertexAttribPointer(
+ mNormalHandle,
+ NORMAL_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_NORMAL_DATA
+ );
+ glEnableVertexAttribArray(mNormalHandle);
+
+ // Pass in the texture coordinate information
+ glVertexAttribPointer(
+ mTextureCoordinateHandle,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_TEXTURE_COORDINATE_DATA
+ );
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // Pass in the model view matrix
+ glUniformMatrix4fv(
+ mMVMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Pass in the light position in eye space
+ glUniform3f(mLightPosHandle,
+ mLightPosInEyeSpace[0],
+ mLightPosInEyeSpace[1],
+ mLightPosInEyeSpace[2]
+ );
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Native4Lesson::drawLight() {
+
+ GLint pointMVPMatrixHandle = glGetUniformLocation(mPointProgramHandle, "u_MVPMatrix");
+ GLint pointPositionHandle = glGetAttribLocation(mPointProgramHandle, "a_Position");
+
+ // Pass in the position
+ glVertexAttrib3f(
+ pointPositionHandle,
+ mLightPosInModelSpace[0],
+ mLightPosInModelSpace[1],
+ mLightPosInModelSpace[2]);
+
+ // Since we are not using a buffer object,
+ // disable vertex arrays for the attribute
+ glDisableVertexAttribArray(pointPositionHandle);
+
+ // Pass in the transformation matrix.
+ mMVPMatrix->identity();
+ mMVPMatrix->multiply(*mViewMatrix, *mLightModelMatrix);
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ glUniformMatrix4fv(
+ pointMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ glDrawArrays(GL_POINTS, 0, 1);
+}
+
+////////////////////////////
+
+Native4Lesson *lesson4;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson4_LessonFourNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jclass type,
+ jobject assetManager) {
+ GLUtils::setEnvAndAssetManager(env, assetManager);
+ if (lesson4) {
+ delete lesson4;
+ lesson4 = NULL;
+ }
+ lesson4 = new Native4Lesson();
+ lesson4->create();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson4_LessonFourNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jclass type,
+ jint width,
+ jint height) {
+ if (lesson4) {
+ lesson4->change(width, height);
+ }
+
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson4_LessonFourNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jclass type) {
+
+ if (lesson4) {
+ lesson4->draw();
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.h
new file mode 100644
index 0000000..521c7aa
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.h
@@ -0,0 +1,59 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#ifndef OPENGLLESSON_NATIVEFOURLESSON_H
+#define OPENGLLESSON_NATIVEFOURLESSON_H
+
+#include
+#include
+
+class Native4Lesson {
+
+public:
+
+ Native4Lesson();
+
+ ~Native4Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+private:
+
+ GLsizei mWidth;
+ GLsizei mHeight;
+
+ Matrix *mViewMatrix;
+ Matrix *mModelMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+ Matrix *mLightModelMatrix;
+
+ GLuint mMVPMatrixHandle;
+ GLuint mMVMatrixHandle;
+ GLuint mLightPosHandle;
+ GLuint mPositionHandle;
+ GLuint mColorHandle;
+ GLuint mNormalHandle;
+ GLuint mTextureUniformHandle;
+ GLuint mTextureCoordinateHandle;
+
+ GLuint mTextureDataHandle;
+
+ GLuint mPerVertexProgramHandle;
+ GLuint mPointProgramHandle;
+
+ float mLightPosInModelSpace[4];
+ float mLightPosInWorldSpace[4];
+ float mLightPosInEyeSpace[4];
+
+ void drawCube();
+
+ void drawLight();
+};
+
+#endif //OPENGLLESSON_NATIVEFOURLESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.cpp
new file mode 100644
index 0000000..c68896a
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.cpp
@@ -0,0 +1,315 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#include
+#include
+#include "Native5Lesson.h"
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+
+Native5Lesson::Native5Lesson() :
+ mWidth(0), mHeight(0),
+ mModelMatrix(NULL), mViewMatrix(NULL), mProjectionMatrix(NULL), mMVPMatrix(NULL),
+ mMVPMatrixHandle(0), mPositionHandle(0), mColorHandle(0),
+ mProgramHandle(0), mBending(true) {
+
+}
+
+Native5Lesson::~Native5Lesson() {
+ delete mModelMatrix;
+ mModelMatrix = NULL;
+ delete mViewMatrix;
+ mViewMatrix = NULL;
+ delete mProjectionMatrix;
+ mProjectionMatrix = NULL;
+ delete mMVPMatrix;
+ mMVPMatrix = NULL;
+}
+
+void Native5Lesson::create() {
+
+ // Set the background clear color to black
+ glClearColor(0, 0, 0, 0);
+
+ // Use culling the remove back face
+ glDisable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glDisable(GL_DEPTH_TEST);
+
+ // Enable blending
+ glEnable(GL_BLEND);
+
+ // Interpolative blending
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // Main Program
+ const char *vertex = GLUtils::openTextFile("vertex/color_vertex_shader.glsl");
+ const char *fragment = GLUtils::openTextFile("fragment/color_fragment_shader.glsl");
+
+ // Set program handles
+ mProgramHandle = GLUtils::createProgram(&vertex, &fragment);
+ if (!mProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // create Cube data
+ createCubeData();
+
+ //
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = 1.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+}
+
+void Native5Lesson::change(int width, int height) {
+
+ mWidth = width;
+ mHeight = height;
+
+ glViewport(0, 0, mWidth, mHeight);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+}
+
+void Native5Lesson::draw() {
+
+ if (mBending) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ } else {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
+
+ // Set out pre-vertex lighting program.
+ glUseProgram(mProgramHandle);
+
+ // Set program handle for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+ mPositionHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Position");
+ mColorHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Color");
+
+ // draw mCubes
+
+ // right
+ mModelMatrix->identity();
+ mModelMatrix->translate(4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 0.0f, 0.0f);
+ drawCube();
+
+ // left
+ mModelMatrix->identity();
+ mModelMatrix->translate(-4.0f, 0.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // top
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // bottom
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, -4.0f, -7.0f);
+ mModelMatrix->rotate(angleInDegrees, 0.0f, 1.0f, 0.0f);
+ drawCube();
+
+ // center
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.0f, -5.0f);
+ mModelMatrix->rotate(angleInDegrees, 1.0f, 1.0f, 1.0f);
+ drawCube();
+}
+
+void Native5Lesson::drawCube() {
+
+ // Pass in the position info
+ glVertexAttribPointer(
+ mPositionHandle,
+ 3,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ mCubePositionData
+ );
+ glEnableVertexAttribArray(mPositionHandle);
+
+ // Pass in the color info
+ glVertexAttribPointer(
+ mColorHandle,
+ 4,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ mCubeColorData
+ );
+ glEnableVertexAttribArray(mColorHandle);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Native5Lesson::createCubeData() {
+
+ // Define points for a cube.
+ // X, Y, Z
+ float p1p[] = {-1.0f, 1.0f, 1.0f};
+ float p2p[] = {1.0f, 1.0f, 1.0f};
+ float p3p[] = {-1.0f, -1.0f, 1.0f};
+ float p4p[] = {1.0f, -1.0f, 1.0f};
+ float p5p[] = {-1.0f, 1.0f, -1.0f};
+ float p6p[] = {1.0f, 1.0f, -1.0f};
+ float p7p[] = {-1.0f, -1.0f, -1.0f};
+ float p8p[] = {1.0f, -1.0f, -1.0f};
+
+ mCubePositionData = GLUtils::generateCubeData(p1p, p2p, p3p, p4p, p5p, p6p, p7p, p8p,
+ (sizeof(p1p) / sizeof(*p1p)));
+
+ // Points of the cube: color information
+ // R, G, B, A
+ float p1c[] = {1.0f, 0.0f, 0.0f, 1.0f}; // red
+ float p2c[] = {1.0f, 0.0f, 1.0f, 1.0f}; // magenta
+ float p3c[] = {0.0f, 0.0f, 0.0f, 1.0f}; // black
+ float p4c[] = {0.0f, 0.0f, 1.0f, 1.0f}; // blue
+ float p5c[] = {1.0f, 1.0f, 0.0f, 1.0f}; // yellow
+ float p6c[] = {1.0f, 1.0f, 1.0f, 1.0f}; // white
+ float p7c[] = {0.0f, 1.0f, 0.0f, 1.0f}; // green
+ float p8c[] = {0.0f, 1.0f, 1.0f, 1.0f}; // cyan
+
+ mCubeColorData = GLUtils::generateCubeData(p1c, p2c, p3c, p4c, p5c, p6c, p7c, p8c,
+ (sizeof(p1c) / sizeof(*p1c)));
+}
+
+void Native5Lesson::switchMode() {
+ mBending = !mBending;
+
+ if (mBending) {
+ // No culling of back faces
+ glDisable(GL_CULL_FACE);
+
+ // No depth testing
+ glDisable(GL_DEPTH_TEST);
+
+ // Enable blending
+ glEnable(GL_BLEND);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ } else {
+ // Culling back faces.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Disable blending
+ glDisable(GL_BLEND);
+ }
+}
+
+
+///////////////
+
+Native5Lesson *lesson5;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson5_LessonFiveNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jclass type,
+ jobject assetManager) {
+
+ GLUtils::setEnvAndAssetManager(env, assetManager);
+ if (lesson5) {
+ delete lesson5;
+ lesson5 = NULL;
+ }
+ lesson5 = new Native5Lesson();
+ lesson5->create();
+
+ lesson5->switchMode();
+
+}extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson5_LessonFiveNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jclass type,
+ jint width,
+ jint height) {
+
+ if (lesson5) {
+ lesson5->change(width, height);
+ }
+
+}extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson5_LessonFiveNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jclass type) {
+
+ if (lesson5) {
+ lesson5->draw();
+ }
+
+}extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson5_LessonFiveNativeRenderer_nativeSwitchMode(JNIEnv *env,
+ jclass type) {
+
+ if (lesson5) {
+ lesson5->switchMode();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.h
new file mode 100644
index 0000000..3292c00
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.h
@@ -0,0 +1,58 @@
+//
+// Created by biezhihua on 2017/7/15.
+//
+
+#ifndef OPENGLLESSON_NATIVE5LESSON_H
+#define OPENGLLESSON_NATIVE5LESSON_H
+
+
+#include
+
+class Native5Lesson {
+
+public:
+
+ Native5Lesson();
+
+ ~Native5Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+ void switchMode();
+
+private:
+
+ //
+ float *mCubePositionData;
+ float *mCubeColorData;
+
+ //
+ GLsizei mWidth;
+ GLsizei mHeight;
+
+ // Matrix
+ Matrix *mModelMatrix;
+ Matrix *mViewMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+
+ // Handle
+ GLuint mMVPMatrixHandle;
+ GLuint mPositionHandle;
+ GLuint mColorHandle;
+
+ GLuint mProgramHandle;
+
+ bool mBending;
+
+ void drawCube();
+
+ void createCubeData();
+};
+
+
+#endif //OPENGLLESSON_NATIVE5LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.cpp
new file mode 100644
index 0000000..2d5ff9e
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.cpp
@@ -0,0 +1,673 @@
+//
+// Created by biezhihua on 2017/7/16.
+//
+
+#include
+#include "Native6Lesson.h"
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+const static GLfloat CUBE_POSITION_DATA[] = {
+ // Front face
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+
+ // Right face
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Back face
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ // Left face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+
+ // Top face
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+
+ // Bottom face
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+};
+
+static const GLfloat CUBE_COLOR_DATA[] = {
+ // R, G, B, A
+
+ // Front face (red)
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+
+ // Right face (green)
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+
+ // Back face (blue)
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+
+ // Left face (yellow)
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+
+ // Top face (cyan)
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 1.0f, 1.0f,
+
+ // Bottom face (magenta)
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 0.0f, 1.0f, 1.0f
+};
+
+// X, Y, Z
+// The normal is used in light calculations and is a vector which points
+// orthogonal to the plane of the surface. For a cube model, the normals
+// should be orthogonal to the points of each face.
+static const GLfloat CUBE_NORMAL_DATA[] = {
+ // Front face
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+
+ // Right face
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+
+ // Left face
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+
+ // Top face
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f
+};
+
+/**
+ * S,T (X,Y)
+ * Texture coordinate data.
+ * Because images have a Y axis pointing downward,
+ * while OpenGL has a Y axis pointing upward, we adjust for
+ * that here by flipping the Y axis.
+ * What's more is that the texture coordinates are the same for every face.
+ */
+static const GLfloat CUBE_TEXTURE_COORDINATE_DATA[] =
+ {
+ // Front face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Right face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Left face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Top face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+ };
+
+
+// S, T (or X, Y)
+// Texture coordinate data.
+// Because images have a Y axis pointing downward (values increase as you move down the image) while
+// OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
+// What's more is that the texture coordinates are the same for every face.
+static const GLfloat CUBE_TEXTURE_COORDINATE_DATA_FOR_PLANE[] =
+ {
+ // Front face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f,
+
+ // Right face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f,
+
+ // Left face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f,
+
+ // Top face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 0.0f,
+ 0.0f, 25.0f,
+ 25.0f, 25.0f,
+ 25.0f, 0.0f
+ };
+
+Native6Lesson::Native6Lesson() {
+
+}
+
+Native6Lesson::~Native6Lesson() {
+
+}
+
+void Native6Lesson::create() {
+ // Use culling to remove back face.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Main Program
+ const char *vertex = GLUtils::openTextFile("vertex/per_pixel_vertex_shader_tex_and_light.glsl");
+ const char *fragment = GLUtils::openTextFile(
+ "fragment/per_pixel_fragment_shader_tex_and_light.glsl");
+
+ // Set program handles
+ mProgramHandle = GLUtils::createProgram(&vertex, &fragment);
+ if (!mProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Main Program
+ const char *pointVertex = GLUtils::openTextFile(
+ "vertex/point_vertex_shader.glsl");
+ const char *pointFragment = GLUtils::openTextFile(
+ "fragment/point_fragment_shader.glsl");
+
+ // Set program handles
+ mPointProgramHandle = GLUtils::createProgram(&pointVertex, &pointFragment);
+ if (!mPointProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Load the texture
+ mBrickDataHandle = GLUtils::loadTexture("texture/stone_wall_public_domain.png");
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ mGrassDataHandle = GLUtils::loadTexture("texture/noisy_grass_public_domain.png");
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ mLightModelMatrix = new Matrix();
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+ mCurrentRotationMatrix = new Matrix();
+ mAccumulatedRotationMatrix = new Matrix();
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = 1.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+
+ if (mQueuedMinFilter != 0) {
+ setMinFilter(mQueuedMinFilter);
+ }
+
+ if (mQueuedMagFilter != 0) {
+ setMagFilter(mQueuedMagFilter);
+ }
+}
+
+void Native6Lesson::change(int width, int height) {
+
+ mWidth = width;
+ mHeight = height;
+
+ glViewport(0, 0, mWidth, mHeight);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+
+}
+
+void Native6Lesson::draw() {
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ long slowTime = GLUtils::currentTimeMillis() % 100000L;
+ float angleInDegrees = (180.0f / 100000.0f) * ((int) time);
+ float slowAngleInDegrees = (180.0f / 1000000.0f) * ((int) slowTime);
+
+ // Set out pre-vertex lighting program.
+ glUseProgram(mProgramHandle);
+
+ // Set program handles for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+ mMVMatrixHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+ mLightPosHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_LightPos");
+ mTextureUniformHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_Texture");
+ mPositionHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Position");
+ mNormalHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Normal");
+ mTextureCoordinateHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
+
+ // Calculate position of the light
+ // Rotate and then push into the distance.
+ mLightModelMatrix->identity();
+ mLightModelMatrix->translate(0, 0, -2);
+ mLightModelMatrix->rotate(angleInDegrees, 0, 1, 0);
+ mLightModelMatrix->translate(0, 0, 3.5);
+
+ Matrix::multiplyMV(mLightPosInWorldSpace, mLightModelMatrix->mData, mLightPosInModelSpace);
+ Matrix::multiplyMV(mLightPosInEyeSpace, mViewMatrix->mData, mLightPosInWorldSpace);
+
+ // Draw a cube.
+ // Translate the cube into the screen.
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.8f, -3.5f);
+// mModelMatrix->rotate(angleInDegrees, 1.0f, 1.0f, 1.0f);
+
+ // Set a matrix that contains the current rotation.
+ mCurrentRotationMatrix->identity();
+ mCurrentRotationMatrix->rotate(mDeltaX, 0.0f, 1.0f, 0.0f);
+ mCurrentRotationMatrix->rotate(mDeltaY, 1.0f, 0.0f, 0.0f);
+ mDeltaX = 0.0f;
+ mDeltaY = 0.0f;
+
+ Matrix tempMatrix;
+
+ // Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
+ tempMatrix.identity();
+ tempMatrix.multiply(*mCurrentRotationMatrix, *mAccumulatedRotationMatrix);
+ mAccumulatedRotationMatrix->loadWith(tempMatrix);
+
+ // Rotate the cube taking the overall rotation into account.
+ tempMatrix.identity();
+ tempMatrix.multiply(*mModelMatrix, *mAccumulatedRotationMatrix);
+ mModelMatrix->loadWith(tempMatrix);
+
+ // Set the active texture unit to texture unit 0.
+ glActiveTexture(GL_TEXTURE0);
+
+ // Bind the texture to this unit.
+ glBindTexture(GL_TEXTURE_2D, mBrickDataHandle);
+
+ // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
+ glUniform1i(mTextureUniformHandle, 0);
+
+ drawCube();
+
+ // Draw a plane
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, -2.0f, -5.0f);
+ mModelMatrix->scale(25.0f, 1.0f, 25.0f);
+ mModelMatrix->rotate(slowAngleInDegrees, 0.0f, 1.0f, 0.0f);
+
+ // Set the active texture unit to texture unit 0.
+ glActiveTexture(GL_TEXTURE0);
+
+ // Bind the texture to this unit.
+ glBindTexture(GL_TEXTURE_2D, mGrassDataHandle);
+
+ // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
+ glUniform1i(mTextureUniformHandle, 0);
+
+ drawCube();
+
+ // Draw a point to indicate the light
+ glUseProgram(mPointProgramHandle);
+ drawLight();
+}
+
+void Native6Lesson::setMinFilter(int filter) {
+ if (mBrickDataHandle != 0 && mGrassDataHandle != 0) {
+ glBindTexture(GL_TEXTURE_2D, mBrickDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glBindTexture(GL_TEXTURE_2D, mGrassDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ } else {
+ mQueuedMinFilter = filter;
+ }
+}
+
+void Native6Lesson::setMagFilter(int filter) {
+ if (mBrickDataHandle != 0 && mGrassDataHandle != 0) {
+ glBindTexture(GL_TEXTURE_2D, mBrickDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+ glBindTexture(GL_TEXTURE_2D, mGrassDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+ } else {
+ mQueuedMagFilter = filter;
+ }
+}
+
+void Native6Lesson::drawCube() {
+
+ // Pass in the position info
+ glVertexAttribPointer(
+ mPositionHandle,
+ POSITION_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_POSITION_DATA
+ );
+ glEnableVertexAttribArray(mPositionHandle);
+
+ // Pass in the texture coordinate information
+ glVertexAttribPointer(
+ mTextureCoordinateHandle,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_TEXTURE_COORDINATE_DATA
+ );
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+
+ // Pass in the normal information
+ glVertexAttribPointer(
+ mNormalHandle,
+ NORMAL_DATA_SIZE,
+ GL_FLOAT,
+ GL_FALSE,
+ 0,
+ CUBE_NORMAL_DATA
+ );
+ glEnableVertexAttribArray(mNormalHandle);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // Pass in the model view matrix
+ glUniformMatrix4fv(
+ mMVMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Pass in the light position in eye space
+ glUniform3f(mLightPosHandle,
+ mLightPosInEyeSpace[0],
+ mLightPosInEyeSpace[1],
+ mLightPosInEyeSpace[2]
+ );
+
+ // Draw the cube
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Native6Lesson::drawLight() {
+
+ GLint pointMVPMatrixHandle = glGetUniformLocation(mPointProgramHandle, "u_MVPMatrix");
+ GLint pointPositionHandle = glGetAttribLocation(mPointProgramHandle, "a_Position");
+
+ // Pass in the position
+ glVertexAttrib3f(
+ pointPositionHandle,
+ mLightPosInModelSpace[0],
+ mLightPosInModelSpace[1],
+ mLightPosInModelSpace[2]);
+
+ // Since we are not using a buffer object,
+ // disable vertex arrays for the attribute
+ glDisableVertexAttribArray(pointPositionHandle);
+
+ // Pass in the transformation matrix.
+ mMVPMatrix->identity();
+ mMVPMatrix->multiply(*mViewMatrix, *mLightModelMatrix);
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ glUniformMatrix4fv(
+ pointMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ glDrawArrays(GL_POINTS, 0, 1);
+}
+
+void Native6Lesson::setDelta(float x, float y) {
+ mDeltaX += x;
+ mDeltaY += y;
+}
+
+//////////////////////
+
+Native6Lesson *lesson6;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jclass type,
+ jobject assetManager) {
+ GLUtils::setEnvAndAssetManager(env, assetManager);
+ if (lesson6) {
+ delete lesson6;
+ lesson6 = NULL;
+ }
+ lesson6 = new Native6Lesson();
+ lesson6->create();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jclass type,
+ jint width,
+ jint height) {
+ if (lesson6) {
+ lesson6->change(width, height);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jclass type) {
+ if (lesson6) {
+ lesson6->draw();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeSetDelta(JNIEnv *env,
+ jclass type, jfloat x,
+ jfloat y) {
+ if (lesson6) {
+ lesson6->setDelta(x, y);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeSetMinFilter(JNIEnv *env,
+ jclass type,
+ jint filter) {
+ if (lesson6) {
+ lesson6->setMagFilter(filter);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson6_LessonSixNativeRenderer_nativeSetMagFilter(JNIEnv *env,
+ jclass type,
+ jint filter) {
+ if (lesson6) {
+ lesson6->setMinFilter(filter);
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.h
new file mode 100644
index 0000000..d56b91b
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.h
@@ -0,0 +1,87 @@
+//
+// Created by biezhihua on 2017/7/16.
+//
+
+#ifndef OPENGLLESSON_NATIVE6LESSON_H
+#define OPENGLLESSON_NATIVE6LESSON_H
+
+
+#include
+#include
+
+class Native6Lesson {
+
+public:
+ Native6Lesson();
+
+ ~Native6Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+ void setDelta(float x, float y);
+
+ void setMinFilter(int filter);
+
+ void setMagFilter(int filter);
+
+private:
+
+ //
+ const int BYTES_PER_FLOAT = 4;
+ const int POSITION_DATA_SIZE = 3;
+ const int NORMAL_DATA_SIZE = 3;
+ const int TEXTURE_COORDINATE_DATA_SIZE = 2;
+
+ //
+ GLsizei mWidth;
+ GLsizei mHeight;
+
+ // model/view/projection matrix
+ Matrix *mModelMatrix;
+ Matrix *mViewMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+
+ //
+ Matrix *mAccumulatedRotationMatrix;
+ Matrix *mCurrentRotationMatrix;
+
+ //
+ Matrix *mLightModelMatrix;
+
+ //
+ GLuint mMVPMatrixHandle;
+ GLuint mMVMatrixHandle;
+ GLuint mLightPosHandle;
+ GLuint mTextureUniformHandle;
+ GLuint mPositionHandle;
+ GLuint mNormalHandle;
+ GLuint mTextureCoordinateHandle;
+
+ GLuint mProgramHandle;
+ GLuint mPointProgramHandle;
+
+ GLuint mBrickDataHandle;
+ GLuint mGrassDataHandle;
+
+ GLint mQueuedMinFilter;
+ GLint mQueuedMagFilter;
+
+ float mLightPosInModelSpace[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float mLightPosInWorldSpace[4];
+ float mLightPosInEyeSpace[4];
+
+ float mDeltaX;
+ float mDeltaY;
+
+ void drawCube();
+
+ void drawLight();
+};
+
+
+#endif //OPENGLLESSON_NATIVE6LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.cpp
new file mode 100644
index 0000000..79cf487
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.cpp
@@ -0,0 +1,95 @@
+//
+// Created by biezhihua on 2017/7/21.
+//
+
+#include "Cubes.h"
+
+int Cubes::POSITION_DATA_SIZE = 3;
+
+int Cubes::NORMAL_DATA_SIZE = 3;
+
+int Cubes::TEXTURE_COORDINATE_DATA_SIZE = 2;
+
+int Cubes::BYTES_PER_FLOAT = 4;
+
+vector *> Cubes::getBuffers(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates,
+ int generatedCubeFactor) {
+
+ mActualCubeFactor = generatedCubeFactor;
+
+ vector *cubeNormalsBuffer = new vector();
+ for (int i = 0;
+ i < (generatedCubeFactor * generatedCubeFactor * generatedCubeFactor); i++) {
+ cubeNormalsBuffer->insert(cubeNormalsBuffer->end(), cubeNormals->begin(),
+ cubeNormals->end());
+ }
+
+ vector *cubeTextureCoordinatesBuffer = new vector();
+ for (int i = 0;
+ i < (generatedCubeFactor * generatedCubeFactor * generatedCubeFactor); i++) {
+ cubeTextureCoordinatesBuffer->insert(cubeTextureCoordinatesBuffer->end(),
+ cubeTextureCoordinates->begin(),
+ cubeTextureCoordinates->end());
+ }
+
+ vector *> results;
+ results.push_back(cubePositions);
+ results.push_back(cubeNormalsBuffer);
+ results.push_back(cubeTextureCoordinatesBuffer);
+
+ return results;
+}
+
+vector *Cubes::getInterleavedBuffer(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates,
+ int generatedCubeFactor) {
+
+ mActualCubeFactor = generatedCubeFactor;
+
+ int cubePositionOffset = 0;
+ int cubeNormalOffset = 0;
+ int cubeTextureOffset = 0;
+
+ vector *cubeBuffer = new vector();
+
+ for (int i = 0; i < generatedCubeFactor * generatedCubeFactor * generatedCubeFactor; i++) {
+ for (int v = 0; v < 36; v++) {
+ cubeBuffer->insert(cubeBuffer->end(), cubePositions->begin() + cubePositionOffset,
+ cubePositions->begin() + cubePositionOffset + POSITION_DATA_SIZE);
+ cubePositionOffset += POSITION_DATA_SIZE;
+
+ cubeBuffer->insert(cubeBuffer->end(), cubeNormals->begin() + cubeNormalOffset,
+ cubeNormals->begin() + cubeNormalOffset + NORMAL_DATA_SIZE);
+ cubeNormalOffset += NORMAL_DATA_SIZE;
+
+ cubeBuffer->insert(cubeBuffer->end(),
+ cubeTextureCoordinates->begin() + cubeTextureOffset,
+ cubeTextureCoordinates->begin() + cubeTextureOffset +
+ TEXTURE_COORDINATE_DATA_SIZE);
+ cubeTextureOffset += TEXTURE_COORDINATE_DATA_SIZE;
+ }
+
+ // The normal and texture data is repeated for each cube.
+ cubeNormalOffset = 0;
+ cubeTextureOffset = 0;
+ }
+
+ return cubeBuffer;
+}
+
+
+void Cubes::setPositionHandle(GLuint positionHandle) {
+ Cubes::mPositionHandle = positionHandle;
+}
+
+void Cubes::setNormalHandle(GLuint normalHandle) {
+ Cubes::mNormalHandle = normalHandle;
+}
+
+void Cubes::setTextureCoordinateHandle(GLuint textureCoordinateHandle) {
+ Cubes::mTextureCoordinateHandle = textureCoordinateHandle;
+}
+
+
+
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.h
new file mode 100644
index 0000000..e5037be
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.h
@@ -0,0 +1,79 @@
+//
+// Created by biezhihua on 2017/7/21.
+//
+
+#ifndef OPENGLLESSON_CUBES_H
+#define OPENGLLESSON_CUBES_H
+
+#include
+#include
+
+using namespace std;
+
+class Cubes {
+
+protected:
+
+ /**
+ * This will be used to pass in model position information.
+ */
+ GLuint mPositionHandle = 0;
+
+ /**
+ * This will be used to pass in model normal information.
+ */
+ GLuint mNormalHandle = 0;
+
+ /**
+ * This will be used to pass in model texture coordinate information.
+ */
+ GLuint mTextureCoordinateHandle = 0;
+
+ int mActualCubeFactor = 0;
+
+public:
+ void setPositionHandle(GLuint positionHandle);
+
+ void setNormalHandle(GLuint normalHandle);
+
+ void setTextureCoordinateHandle(GLuint textureCoordinateHandle);
+
+
+public:
+ vector *> getBuffers(vector *cubePositions,
+ vector *cubeNormals,
+ vector *cubeTextureCoordinates,
+ int generatedCubeFactor);
+
+ vector *getInterleavedBuffer(vector *cubePositions,
+ vector *cubeNormals,
+ vector *cubeTextureCoordinates,
+ int generatedCubeFactor);
+
+ virtual void renderer()= 0;
+
+ virtual void release()= 0;
+
+ /**
+ * Size of the position data in elements.
+ */
+ static int POSITION_DATA_SIZE;
+
+ /**
+ * Size of the normal data in elements.
+ */
+ static int NORMAL_DATA_SIZE;
+
+ /**
+ * Size of the texture coordinate data in elements.
+ */
+ static int TEXTURE_COORDINATE_DATA_SIZE;
+
+ /**
+ * How many bytes per float.
+ */
+ static int BYTES_PER_FLOAT;
+};
+
+
+#endif //OPENGLLESSON_CUBES_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.cpp
new file mode 100644
index 0000000..77cec3b
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.cpp
@@ -0,0 +1,32 @@
+#include "CubesClientSide.h"
+
+void CubesClientSide::renderer() {
+
+ // Pass in the position information
+ glEnableVertexAttribArray(mPositionHandle);
+ glVertexAttribPointer(mPositionHandle, Cubes::POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, 0,
+ mCubePositions->data());
+
+
+ // Pass in the normal information
+ glEnableVertexAttribArray(mNormalHandle);
+ glVertexAttribPointer(mNormalHandle, Cubes::NORMAL_DATA_SIZE, GL_FLOAT, GL_FALSE, 0,
+ mCubeNormals->data());
+
+ // Pass in the texture information
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+ glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, GL_FLOAT,
+ GL_FALSE,
+ 0, mCubeTextureCoordinates->data());
+
+ // Draw the mCubes.
+ glDrawArrays(GL_TRIANGLES, 0, mActualCubeFactor * mActualCubeFactor * mActualCubeFactor * 36);
+}
+
+void CubesClientSide::release() {
+ if (mCubeTextureCoordinates != nullptr) {
+ mCubeTextureCoordinates->clear();
+ vector().swap(*mCubeTextureCoordinates);
+ mCubeTextureCoordinates = nullptr;
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.h
new file mode 100644
index 0000000..e3ddddc
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.h
@@ -0,0 +1,30 @@
+#ifndef OPENGLLESSON_CUBESCLIENTSIDE_H
+#define OPENGLLESSON_CUBESCLIENTSIDE_H
+
+#include
+#include "Cubes.h"
+
+class CubesClientSide : public Cubes {
+
+public:
+ vector *mCubePositions = nullptr;
+ vector *mCubeNormals = nullptr;
+ vector *mCubeTextureCoordinates = nullptr;
+
+public:
+ CubesClientSide(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates, int generatedCubeFactor) {
+ vector *> buffers = getBuffers(cubePositions, cubeNormals,
+ cubeTextureCoordinates, generatedCubeFactor);
+ CubesClientSide::mCubePositions = buffers.at(0);
+ CubesClientSide::mCubeNormals = buffers.at(1);
+ CubesClientSide::mCubeTextureCoordinates = buffers.at(2);
+ }
+
+ virtual void renderer() override;
+
+ virtual void release() override;
+};
+
+
+#endif //INC_21CPLUSPLUS_CUBESCLIENTSIDE_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.cpp
new file mode 100644
index 0000000..7f7d30b
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.cpp
@@ -0,0 +1,35 @@
+#include "CubesClientSideWithStride.h"
+
+void CubesClientSideWithStride::renderer() {
+ int stride = (POSITION_DATA_SIZE + NORMAL_DATA_SIZE + TEXTURE_COORDINATE_DATA_SIZE) *
+ BYTES_PER_FLOAT;
+
+ // Pass in the position information
+ glEnableVertexAttribArray(mPositionHandle);
+ glVertexAttribPointer(mPositionHandle, Cubes::POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, stride,
+ mCubeBuffer->data());
+
+
+ // Pass in the normal information
+ glEnableVertexAttribArray(mNormalHandle);
+ glVertexAttribPointer(mNormalHandle, Cubes::NORMAL_DATA_SIZE, GL_FLOAT, GL_FALSE, stride,
+ mCubeBuffer->data() + Cubes::POSITION_DATA_SIZE);
+
+ // Pass in the texture information
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+ glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, GL_FLOAT,
+ GL_FALSE,
+ stride, mCubeBuffer->data() + Cubes::POSITION_DATA_SIZE +
+ Cubes::NORMAL_DATA_SIZE);
+
+ // Draw the mCubes.
+ glDrawArrays(GL_TRIANGLES, 0, mActualCubeFactor * mActualCubeFactor * mActualCubeFactor * 36);
+
+}
+
+void CubesClientSideWithStride::release() {
+ if (mCubeBuffer != nullptr) {
+ mCubeBuffer->clear();
+ vector().swap(*mCubeBuffer);
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.h
new file mode 100644
index 0000000..6a0561f
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.h
@@ -0,0 +1,33 @@
+//
+// Created by biezhihua on 2017/7/23.
+//
+
+#ifndef OPENGLLESSON_CUBESCLIENTSIDEWITHSTRIDE_H
+#define OPENGLLESSON_CUBESCLIENTSIDEWITHSTRIDE_H
+
+
+#include "Cubes.h"
+
+class CubesClientSideWithStride : public Cubes {
+
+private :
+ vector *mCubeBuffer;
+public:
+
+ CubesClientSideWithStride(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates, int generatedCubeFactor) {
+ mCubeBuffer = getInterleavedBuffer(cubePositions, cubeNormals, cubeTextureCoordinates,
+ generatedCubeFactor);
+ }
+
+ ~CubesClientSideWithStride() {
+
+ }
+
+ virtual void renderer() override;
+
+ virtual void release() override;
+};
+
+
+#endif //OPENGLLESSON_CUBESCLIENTSIDEWITHSTRIDE_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.cpp
new file mode 100644
index 0000000..4cb9cd0
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.cpp
@@ -0,0 +1,37 @@
+//
+// Created by biezhihua on 2017/7/23.
+//
+
+#include "CubesWithVbo.h"
+
+void CubesWithVbo::renderer() {
+ // Pass in the position information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubePositionsBufferIdx);
+ glEnableVertexAttribArray(mPositionHandle);
+ glVertexAttribPointer(mPositionHandle, Cubes::POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, 0);
+
+ // Pass in the normal information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubeNormalsBufferIdx);
+ glEnableVertexAttribArray(mNormalHandle);
+ glVertexAttribPointer(mNormalHandle, Cubes::NORMAL_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, 0);
+
+ // Pass in the texture information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubeTexCoordsBufferIdx);
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+ glVertexAttribPointer(mTextureCoordinateHandle, Cubes::TEXTURE_COORDINATE_DATA_SIZE, GL_FLOAT,
+ GL_FALSE,
+ 0, 0);
+
+ // Clear the currently bound buffer (so future OpenGL calls do not use this buffer).
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // Draw the mCubes.
+ glDrawArrays(GL_TRIANGLES, 0, mActualCubeFactor * mActualCubeFactor * mActualCubeFactor * 36);
+
+}
+
+void CubesWithVbo::release() {
+ GLuint buffersToDelete[] = {mCubePositionsBufferIdx, mCubeNormalsBufferIdx,
+ mCubeTexCoordsBufferIdx};
+ glDeleteBuffers(3, buffersToDelete);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.h
new file mode 100644
index 0000000..d99431f
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.h
@@ -0,0 +1,72 @@
+//
+// Created by biezhihua on 2017/7/23.
+//
+
+#ifndef OPENGLLESSON_CUBESWITHVBO_H
+#define OPENGLLESSON_CUBESWITHVBO_H
+
+
+#include "Cubes.h"
+
+class CubesWithVbo : public Cubes {
+
+private:
+ GLuint mCubePositionsBufferIdx;
+ GLuint mCubeNormalsBufferIdx;
+ GLuint mCubeTexCoordsBufferIdx;
+public:
+
+ CubesWithVbo(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates, int generatedCubeFactor) {
+
+ vector *> floatBuffers = getBuffers(cubePositions, cubeNormals,
+ cubeTextureCoordinates,
+ generatedCubeFactor);
+
+ vector *mCubePositions = floatBuffers.at(0);
+ vector *mCubeNormals = floatBuffers.at(1);
+ vector *mCubeTextureCoordinates = floatBuffers.at(2);
+
+ // First, generate as many buffers as we need.
+ // This will give us the OpenGL handles for these buffers.
+ GLuint buffers[3];
+ glGenBuffers(3, buffers);
+
+ // Bind to the buffer. Future commands will affect this buffer specifically.
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+ // Transfer data from client memory to the buffer.
+ // We can release the client memory after this call.
+ glBufferData(GL_ARRAY_BUFFER, mCubePositions->size() * BYTES_PER_FLOAT,
+ mCubePositions->data(),
+ GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+ glBufferData(GL_ARRAY_BUFFER, mCubeNormals->size() * BYTES_PER_FLOAT, mCubeNormals->data(),
+ GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
+ glBufferData(GL_ARRAY_BUFFER, mCubeTextureCoordinates->size() * BYTES_PER_FLOAT,
+ mCubeTextureCoordinates->data(),
+ GL_STATIC_DRAW);
+
+ // IMPORTANT: Unbind from the buffer when we're done with it.
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ mCubePositionsBufferIdx = buffers[0];
+ mCubeNormalsBufferIdx = buffers[1];
+ mCubeTexCoordsBufferIdx = buffers[2];
+
+ delete (mCubeNormals);
+ mCubeNormals = nullptr;
+
+ delete (mCubeTextureCoordinates);
+ mCubeTextureCoordinates = nullptr;
+ }
+
+ virtual void renderer() override;
+
+ virtual void release() override;
+};
+
+
+#endif //OPENGLLESSON_CUBESWITHVBO_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.cpp
new file mode 100644
index 0000000..b7d034b
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.cpp
@@ -0,0 +1,40 @@
+//
+// Created by biezhihua on 2017/7/23.
+//
+
+#include "CubesWithVboWithStride.h"
+
+void CubesWithVboWithStride::renderer() {
+ int stride = (POSITION_DATA_SIZE + NORMAL_DATA_SIZE + TEXTURE_COORDINATE_DATA_SIZE) *
+ BYTES_PER_FLOAT;
+
+ // Pass in the position information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubeBufferIdx);
+ glEnableVertexAttribArray(mPositionHandle);
+ glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, stride, 0);
+
+ // Pass in the normal information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubeBufferIdx);
+ glEnableVertexAttribArray(mNormalHandle);
+ glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GL_FLOAT, GL_FALSE, stride,
+ (const GLvoid *) (POSITION_DATA_SIZE * BYTES_PER_FLOAT));
+
+ // Pass in the texture information
+ glBindBuffer(GL_ARRAY_BUFFER, mCubeBufferIdx);
+ glEnableVertexAttribArray(mTextureCoordinateHandle);
+ glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, GL_FLOAT,
+ GL_FALSE,
+ stride, (const GLvoid *) ((POSITION_DATA_SIZE + NORMAL_DATA_SIZE) *
+ BYTES_PER_FLOAT));
+
+ // Clear the currently bound buffer (so future OpenGL calls do not use this buffer).
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // Draw the mCubes.
+ glDrawArrays(GL_TRIANGLES, 0, mActualCubeFactor * mActualCubeFactor * mActualCubeFactor * 36);
+}
+
+void CubesWithVboWithStride::release() {
+ GLuint buffersToDelete[] = {mCubeBufferIdx};
+ glDeleteBuffers(1, buffersToDelete);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.h
new file mode 100644
index 0000000..77ae1e5
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.h
@@ -0,0 +1,47 @@
+//
+// Created by biezhihua on 2017/7/23.
+//
+
+#ifndef OPENGLLESSON_CUBESWITHVBOWITHSTRIDE_H
+#define OPENGLLESSON_CUBESWITHVBOWITHSTRIDE_H
+
+
+#include "Cubes.h"
+
+class CubesWithVboWithStride : public Cubes {
+
+private:
+ GLuint mCubeBufferIdx;
+public:
+
+ CubesWithVboWithStride(vector *cubePositions, vector *cubeNormals,
+ vector *cubeTextureCoordinates, int generatedCubeFactor) {
+ vector *cubeBuffer = getInterleavedBuffer(cubePositions, cubeNormals,
+ cubeTextureCoordinates,
+ generatedCubeFactor);
+
+ // Second, copy these buffers into OpenGL's memory. After, we don't need to keep the client-side buffers around.
+ GLuint buffers[1];
+ glGenBuffers(1, buffers);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, cubeBuffer->size() * BYTES_PER_FLOAT, cubeBuffer->data(),
+ GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ mCubeBufferIdx = buffers[0];
+
+ delete (cubeBuffer);
+ cubeBuffer = nullptr;
+ }
+
+ virtual void renderer() override;
+
+ virtual void release() override;
+
+
+};
+
+
+#endif //OPENGLLESSON_CUBESWITHVBOWITHSTRIDE_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.cpp
new file mode 100644
index 0000000..e351e98
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.cpp
@@ -0,0 +1,331 @@
+//
+// Created by biezhihua on 2017/7/22.
+//
+
+#include "GenData.h"
+#include "CubesClientSideWithStride.h"
+#include "CubesWithVbo.h"
+#include "CubesWithVboWithStride.h"
+#include "CubesClientSide.h"
+
+vector GenData::CUBE_TEXTURE_COORDINATE_DATA = {
+ // Front face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Right face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Left face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Top face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+};
+
+
+vector GenData::CUBE_NORMAL_DATA = {
+ // Front face
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+
+ // Right face
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+
+ // Back face
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+
+ // Left face
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+
+ // Top face
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+
+ // Bottom face
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f
+};
+
+
+vector *
+GenData::generatorCubeData(int requestedCubeFactor) {
+
+ vector *cubePositionData = new vector();
+
+ int cubePositionDataOffset = 0;
+
+ int segments = requestedCubeFactor + (requestedCubeFactor - 1);
+ float minPosition = -1.0f;
+ float maxPosition = 1.0f;
+ float positionRange = maxPosition - minPosition;
+
+ for (int x = 0; x < requestedCubeFactor; x++) {
+ for (int y = 0; y < requestedCubeFactor; y++) {
+ for (int z = 0; z < requestedCubeFactor; z++) {
+
+ float x1 = minPosition + ((positionRange / segments) * (x * 2));
+ float x2 = minPosition + ((positionRange / segments) * ((x * 2) + 1));
+
+ float y1 = minPosition + ((positionRange / segments) * (y * 2));
+ float y2 = minPosition + ((positionRange / segments) * ((y * 2) + 1));
+
+ float z1 = minPosition + ((positionRange / segments) * (z * 2));
+ float z2 = minPosition + ((positionRange / segments) * ((z * 2) + 1));
+
+ // Define points for a cube.
+ // X, Y, Z
+ float p1p[] = {x1, y2, z2};
+ float p2p[] = {x2, y2, z2};
+ float p3p[] = {x1, y1, z2};
+ float p4p[] = {x2, y1, z2};
+ float p5p[] = {x1, y2, z1};
+ float p6p[] = {x2, y2, z1};
+ float p7p[] = {x1, y1, z1};
+ float p8p[] = {x2, y1, z1};
+
+ vector *thisCubePositionData = generateCubeData(p1p, p2p, p3p, p4p, p5p, p6p,
+ p7p, p8p,
+ (sizeof(p1p) /
+ sizeof(*p1p)));
+
+ cubePositionData->insert(cubePositionData->end(), thisCubePositionData->begin(),
+ thisCubePositionData->end());
+ cubePositionDataOffset += thisCubePositionData->size();
+ }
+ }
+ }
+
+ return cubePositionData;
+}
+
+vector *GenData::generateCubeData(float *point1,
+ float *point2,
+ float *point3,
+ float *point4,
+ float *point5,
+ float *point6,
+ float *point7,
+ float *point8,
+ int elementsPerPoint) {
+
+ // Given a cube with the points define as follows:
+ // front left top, front right top, front left bottom,front right bottom
+ // back left top, back right top, back left bottom, front right bottom
+ // return an array of 6 sides, 2 triangles per side, 3 vertices per cube.
+
+ int FRONT = 0;
+ int RIGHT = 1;
+ int BACK = 2;
+ int LEFT = 3;
+ int TOP = 4;
+ int BOTTOM = 5;
+
+ int size = elementsPerPoint * 6 * 6;
+
+ vector *cubeData = new vector();
+
+ for (int face = 0; face < 6; face++) {
+ // Relative to the side,
+ // p1 = top left
+ // p2 = top right
+ // p3 = bottom left
+ // p4 = bottom right
+ float *p1, *p2, *p3, *p4;
+
+ // Select the points for this face
+ if (face == FRONT) {
+ p1 = point1;
+ p2 = point2;
+ p3 = point3;
+ p4 = point4;
+ } else if (face == RIGHT) {
+ p1 = point2;
+ p2 = point6;
+ p3 = point4;
+ p4 = point8;
+ } else if (face == BACK) {
+ p1 = point6;
+ p2 = point5;
+ p3 = point8;
+ p4 = point7;
+ } else if (face == LEFT) {
+ p1 = point5;
+ p2 = point1;
+ p3 = point7;
+ p4 = point3;
+ } else if (face == TOP) {
+ p1 = point5;
+ p2 = point6;
+ p3 = point1;
+ p4 = point2;
+ } else // if (face == BOTTOM)
+ {
+ p1 = point8;
+ p2 = point7;
+ p3 = point4;
+ p4 = point3;
+ }
+
+ // In OpenGL counter-clockwise winding is default.
+ // This means that when we look at a triangle,
+ // if the points are counter-clockwise we are looking at the "front".
+ // If not we are looking at the back.
+ // OpenGL has an optimization where all back-facing triangles are culled, since they
+ // usually represent the backside of an object and aren't visible anyways.
+
+ // Build the triangles
+ // 1---3,6
+ // | / |
+ // 2,4--5
+ int offset = face * elementsPerPoint * 6;
+
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p1[i]);
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p3[i]);
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p2[i]);
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p3[i]);
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p4[i]);
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ offset++;
+ cubeData->push_back(p2[i]);
+ }
+ }
+ return cubeData;
+}
+
+void GenData::genCube(int requestedCubeFactor, bool toggleVbos, bool toggleStride) {
+
+ if (mCubes != nullptr) {
+ mCubes->release();
+ delete (mCubes);
+ mCubes = nullptr;
+ }
+
+ GenData::mLastRequestedCubeFactor = requestedCubeFactor;
+
+ vector *cubePositionData = generatorCubeData(requestedCubeFactor);
+
+ bool useVBOs = mUseVBOs;
+ bool useStride = mUseStride;
+
+ if (toggleVbos) {
+ useVBOs = !useVBOs;
+ }
+
+ if (toggleStride) {
+ useStride = !useStride;
+ }
+
+ if (useStride) {
+ if (useVBOs) {
+ mCubes = new CubesWithVboWithStride(cubePositionData, &GenData::CUBE_NORMAL_DATA,
+ &GenData::CUBE_TEXTURE_COORDINATE_DATA,
+ requestedCubeFactor);
+ } else {
+ mCubes = new CubesClientSideWithStride(cubePositionData, &GenData::CUBE_NORMAL_DATA,
+ &GenData::CUBE_TEXTURE_COORDINATE_DATA,
+ requestedCubeFactor);
+ }
+ } else {
+ if (useVBOs) {
+ mCubes = new CubesWithVbo(cubePositionData, &GenData::CUBE_NORMAL_DATA,
+ &GenData::CUBE_TEXTURE_COORDINATE_DATA,
+ requestedCubeFactor);
+ } else {
+ mCubes = new CubesClientSide(cubePositionData, &GenData::CUBE_NORMAL_DATA,
+ &GenData::CUBE_TEXTURE_COORDINATE_DATA,
+ requestedCubeFactor);
+ }
+ }
+
+ mUseVBOs = useVBOs;
+ mUseStride = useStride;
+
+ if (lesson7 != nullptr) {
+ lesson7->updateVboStatus(mUseVBOs);
+ lesson7->updateStrideStatus(mUseStride);
+ }
+}
+
+Cubes *GenData::getCubes() const {
+ return mCubes;
+}
+
+
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.h
new file mode 100644
index 0000000..d848925
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.h
@@ -0,0 +1,70 @@
+//
+// Created by biezhihua on 2017/7/22.
+//
+
+#ifndef OPENGLLESSON_GENDATA_H
+#define OPENGLLESSON_GENDATA_H
+
+#include
+#include
+#include "Cubes.h"
+#include "Native7Lesson.h"
+
+using namespace std;
+
+class GenData {
+
+public:
+
+ int mLastRequestedCubeFactor = 3;
+
+ bool mUseVBOs = false;
+
+ bool mUseStride = false;
+
+private:
+
+ Native7Lesson *lesson7;
+
+ Cubes *mCubes;
+
+ // X, Y, Z
+ // The normal is used in light calculations and is a vector which points
+ // orthogonal to the plane of the surface. For a cube model, the normals
+ // should be orthogonal to the points of each face.
+ static vector CUBE_NORMAL_DATA;
+
+ // S, T (or X, Y)
+ // Texture coordinate data.
+ // Because images have a Y axis pointing downward (values increase as you move down the image) while
+ // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
+ // What's more is that the texture coordinates are the same for every face.
+ static vector CUBE_TEXTURE_COORDINATE_DATA;
+
+ vector *
+ generateCubeData(float *point1, float *point2, float *point3, float *point4, float *point5,
+ float *point6, float *point7, float *point8, int elementsPerPoint);
+
+ vector *generatorCubeData(int requestedCubeFactor);
+
+public:
+ GenData(Native7Lesson *pLesson) : lesson7(pLesson) {
+ mCubes = nullptr;
+ }
+
+ ~GenData() {
+ lesson7 = nullptr;
+ if (mCubes != nullptr) {
+ mCubes->release();
+ delete (mCubes);
+ mCubes = nullptr;
+ }
+ }
+
+ Cubes *getCubes() const;
+
+ void genCube(int requestedCubeFactor, bool toggleVbos, bool toggleStride);
+};
+
+
+#endif //INC_21CPLUSPLUS_GENDATARUNNABLE_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.cpp
new file mode 100644
index 0000000..d55921c
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.cpp
@@ -0,0 +1,432 @@
+//
+// Created by biezhihua on 2017/7/22.
+//
+
+#include
+#include "Native7Lesson.h"
+#include "GenData.h"
+#include
+#include
+
+#define LOG_TAG "Lesson"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+// processing callback to handler class
+typedef struct context {
+ JavaVM *javaVM;
+ jclass nativeRendererClz;
+ jobject nativeRendererObj;
+} Context;
+
+static Native7Lesson *lesson7;
+static GenData *genData;
+static Context g_ctx;
+
+Native7Lesson::Native7Lesson() {
+
+ mViewMatrix = nullptr;
+ mModelMatrix = nullptr;
+ mProjectionMatrix = nullptr;
+ mMVPMatrix = nullptr;
+ mLightModelMatrix = nullptr;
+
+ mMVPMatrixHandle = 0;
+ mMVMatrixHandle = 0;
+ mLightPosHandle = 0;
+ mPointProgramHandle = 0;
+
+ mLightPosInModelSpace[0] = 0.0f;
+ mLightPosInModelSpace[1] = 0.0f;
+ mLightPosInModelSpace[2] = 0.0f;
+ mLightPosInModelSpace[3] = 1.0f;
+
+ mLightPosInWorldSpace[0] = 0.0f;
+ mLightPosInWorldSpace[1] = 0.0f;
+ mLightPosInWorldSpace[2] = 0.0f;
+ mLightPosInWorldSpace[3] = 0.0f;
+
+ mLightPosInEyeSpace[0] = 0.0f;
+ mLightPosInEyeSpace[1] = 0.0f;
+ mLightPosInEyeSpace[2] = 0.0f;
+ mLightPosInEyeSpace[3] = 0.0f;
+}
+
+Native7Lesson::~Native7Lesson() {
+ delete genData;
+ genData = nullptr;
+ delete mModelMatrix;
+ mModelMatrix = nullptr;
+ delete mViewMatrix;
+ mViewMatrix = nullptr;
+ delete mProjectionMatrix;
+ mProjectionMatrix = nullptr;
+ delete mMVPMatrix;
+ mMVPMatrix = nullptr;
+}
+
+void Native7Lesson::create() {
+
+// genData->setNative7Lesson(this);
+
+ genData->genCube(3, false, false);
+
+ // Set the background clear color to black
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ // Use culling to remove back face.
+ glEnable(GL_CULL_FACE);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = -0.5f;
+
+ // We are looking at the origin
+ float centerX = 0.0f;
+ float centerY = 0.0f;
+ float centerZ = -5.0f;
+
+ // Set our up vector.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix.
+ mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+
+ // Main Program
+ const char *vertex = GLUtils::openTextFile("vertex/lesson_seven_vertex_shader.glsl");
+ const char *fragment = GLUtils::openTextFile(
+ "fragment/lesson_seven_fragment_shader.glsl");
+
+ // Set program handles
+ mProgramHandle = GLUtils::createProgram(&vertex, &fragment);
+ if (!mProgramHandle) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Load the texture
+ mAndroidDataHandle = GLUtils::loadTexture("texture/usb_android.png");
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, mAndroidDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glBindTexture(GL_TEXTURE_2D, mAndroidDataHandle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ mModelMatrix = new Matrix();
+ mMVPMatrix = new Matrix();
+ mViewMatrix = new Matrix();
+ mProjectionMatrix = new Matrix();
+ mCurrentRotationMatrix = new Matrix();
+ mAccumulatedRotationMatrix = new Matrix();
+ mLightModelMatrix = new Matrix();
+}
+
+void Native7Lesson::change(int width, int height) {
+
+ glViewport(0, 0, width, height);
+
+ // Create a new perspective projection matrix. The height will stay the same
+ // while the width will vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 10.0f;
+
+ mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+}
+
+void Native7Lesson::draw() {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Do a compile rotation every 10 seconds;
+ long time = GLUtils::currentTimeMillis() % 10000L;
+ float angleInDegrees = (360.0f / 100000.0f) * ((int) time);
+
+ // Set our per-vertex lighting program.
+ glUseProgram(mProgramHandle);
+
+ // Set program handles for cube drawing.
+ mMVPMatrixHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+ mMVMatrixHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+ mLightPosHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_LightPos");
+ mTextureUniformHandle = (GLuint) glGetUniformLocation(mProgramHandle, "u_Texture");
+ GLuint positionHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Position");
+ GLuint normalHandle = (GLuint) glGetAttribLocation(mProgramHandle, "a_Normal");
+ GLuint textureCoordinateHandle = (GLuint) glGetAttribLocation(mProgramHandle,
+ "a_TexCoordinate");
+
+ if (genData != nullptr && genData->getCubes() != nullptr) {
+ genData->getCubes()->setNormalHandle(normalHandle);
+ genData->getCubes()->setPositionHandle(positionHandle);
+ genData->getCubes()->setTextureCoordinateHandle(textureCoordinateHandle);
+ }
+
+ // Calculate position of the light
+ // Rotate and then push into the distance.
+ mLightModelMatrix->identity();
+ mLightModelMatrix->translate(0, 0, -1);
+
+ Matrix::multiplyMV(mLightPosInWorldSpace, mLightModelMatrix->mData, mLightPosInModelSpace);
+ Matrix::multiplyMV(mLightPosInEyeSpace, mViewMatrix->mData, mLightPosInWorldSpace);
+
+ // Draw a cube.
+ // Translate the cube into the screen.
+ mModelMatrix->identity();
+ mModelMatrix->translate(0.0f, 0.0f, -3.5f);
+ mModelMatrix->rotate(angleInDegrees, 1, 1, 1);
+
+ // Set a matrix that contains the current rotation.
+ mCurrentRotationMatrix->identity();
+ mCurrentRotationMatrix->rotate(mDeltaX, 0.0f, 1.0f, 0.0f);
+ mCurrentRotationMatrix->rotate(mDeltaY, 1.0f, 0.0f, 0.0f);
+ mDeltaX = 0.0f;
+ mDeltaY = 0.0f;
+
+ Matrix tempMatrix;
+
+ // Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
+ tempMatrix.identity();
+ tempMatrix.multiply(*mCurrentRotationMatrix, *mAccumulatedRotationMatrix);
+ mAccumulatedRotationMatrix->loadWith(tempMatrix);
+
+ // Rotate the cube taking the overall rotation into account.
+ tempMatrix.identity();
+ tempMatrix.multiply(*mModelMatrix, *mAccumulatedRotationMatrix);
+ mModelMatrix->loadWith(tempMatrix);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mMVPMatrix->multiply(*mViewMatrix, *mModelMatrix);
+
+ // Pass in the model view matrix
+ glUniformMatrix4fv(
+ mMVMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // This multiplies the model view matrix by the projection matrix
+ // and stores the result in the MVP matrix.
+ // which no contains model * view * projection
+ mMVPMatrix->multiply(*mProjectionMatrix, *mMVPMatrix);
+
+ // Pass in the model view projection matrix
+ glUniformMatrix4fv(
+ mMVPMatrixHandle,
+ 1,
+ GL_FALSE,
+ mMVPMatrix->mData
+ );
+
+ // Pass in the light position in eye space
+ glUniform3f(mLightPosHandle,
+ mLightPosInEyeSpace[0],
+ mLightPosInEyeSpace[1],
+ mLightPosInEyeSpace[2]
+ );
+
+ // Set the active texture unit to texture unit 0.
+ glActiveTexture(GL_TEXTURE0);
+
+ // Bind the texture to this unit.
+ glBindTexture(GL_TEXTURE_2D, mAndroidDataHandle);
+
+ // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
+ glUniform1i(mTextureUniformHandle, 0);
+
+ if (genData != nullptr && genData->getCubes() != nullptr) {
+ genData->getCubes()->renderer();
+ }
+}
+
+void Native7Lesson::decreaseCubeCount() {
+ if (genData != nullptr && genData->mLastRequestedCubeFactor > 1) {
+ genData->genCube(--genData->mLastRequestedCubeFactor, false, false);
+ }
+}
+
+void Native7Lesson::increaseCubeCount() {
+ if (genData != nullptr && genData->mLastRequestedCubeFactor < 16) {
+ genData->genCube(++genData->mLastRequestedCubeFactor, false, false);
+ }
+}
+
+void Native7Lesson::setDelta(float x, float y) {
+ mDeltaX += x;
+ mDeltaY += y;
+}
+
+void Native7Lesson::toggleStride() {
+ genData->genCube(genData->mLastRequestedCubeFactor, false, true);
+}
+
+void Native7Lesson::toggleVBOs() {
+ genData->genCube(genData->mLastRequestedCubeFactor, true, false);
+}
+
+void Native7Lesson::updateVboStatus(bool useVbos) {
+ LOGD("updateVboStatus %d", useVbos);
+ Context *pctx = &g_ctx;
+ JavaVM *javaVM = pctx->javaVM;
+ JNIEnv *env;
+ jint res = javaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
+ if (JNI_OK != res) {
+ LOGE("Failed to Get env, ErrorCode = %d", res);
+ return;
+ }
+ jmethodID statusId = env->GetMethodID(pctx->nativeRendererClz, "updateVboStatus", "(Z)V");
+ env->CallVoidMethod(pctx->nativeRendererObj, statusId, useVbos);
+}
+
+void Native7Lesson::updateStrideStatus(bool useStride) {
+ LOGD("updateStrideStatus %d", useStride);
+ Context *pctx = &g_ctx;
+ JavaVM *javaVM = pctx->javaVM;
+ JNIEnv *env;
+ jint res = javaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
+ if (JNI_OK != res) {
+ LOGE("Failed to Get env, ErrorCode = %d", res);
+ return;
+ }
+ jmethodID statusId = env->GetMethodID(pctx->nativeRendererClz, "updateStrideStatus", "(Z)V");
+ env->CallVoidMethod(pctx->nativeRendererObj, statusId, useStride);
+}
+
+// ----------------------------------------------------------
+
+extern "C"
+JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+ JNIEnv *env;
+ memset(&g_ctx, 0, sizeof(g_ctx));
+
+ g_ctx.javaVM = vm;
+ if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
+ return JNI_ERR; // JNI version not supported.
+ }
+ g_ctx.nativeRendererObj = NULL;
+ return JNI_VERSION_1_6;
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeToggleStride(JNIEnv *env,
+ jobject instance) {
+ if (lesson7 != nullptr) {
+ lesson7->toggleStride();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeToggleVBOs(JNIEnv *env,
+ jobject instance) {
+ if (lesson7 != nullptr) {
+ lesson7->toggleVBOs();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeIncreaseCubeCount(
+ JNIEnv *env, jobject instance) {
+ if (lesson7 != nullptr) {
+ lesson7->increaseCubeCount();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeDecreaseCubeCount(
+ JNIEnv *env, jobject instance) {
+ if (lesson7 != nullptr) {
+ lesson7->decreaseCubeCount();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeSetDelta(JNIEnv *env,
+ jobject instance,
+ jfloat x,
+ jfloat y) {
+ if (lesson7 != nullptr) {
+ lesson7->setDelta(x, y);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jobject instance) {
+ if (lesson7 != nullptr) {
+ lesson7->draw();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jobject instance,
+ jint width,
+ jint height) {
+ if (lesson7 != nullptr) {
+ lesson7->change(width, height);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jobject instance,
+ jobject assetManager) {
+
+ GLUtils::setEnvAndAssetManager(env, assetManager);
+ lesson7 = new Native7Lesson();
+ genData = new GenData(lesson7);
+ if (lesson7 != nullptr) {
+ lesson7->create();
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeDestroy(JNIEnv *env,
+ jobject instance) {
+ env->DeleteGlobalRef(g_ctx.nativeRendererClz);
+ env->DeleteGlobalRef(g_ctx.nativeRendererObj);
+ g_ctx.nativeRendererClz = NULL;
+ g_ctx.nativeRendererObj = NULL;
+
+ if (lesson7 != nullptr) {
+ delete (lesson7);
+ lesson7 = NULL;
+ }
+ if (genData != nullptr) {
+ delete (genData);
+ genData = NULL;
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson7_LessonSevenNativeRenderer_nativeInit(JNIEnv *env,
+ jobject instance) {
+ jclass clz = env->GetObjectClass(instance);
+ g_ctx.nativeRendererClz = (jclass) env->NewGlobalRef(clz);
+ g_ctx.nativeRendererObj = env->NewGlobalRef(instance);
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.h
new file mode 100644
index 0000000..6c220f4
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.h
@@ -0,0 +1,71 @@
+//
+// Created by biezhihua on 2017/7/22.
+//
+
+#ifndef OPENGLLESSON_NATIVE7LESSON_H
+#define OPENGLLESSON_NATIVE7LESSON_H
+
+
+#include
+#include
+
+class Native7Lesson {
+public:
+ Native7Lesson();
+
+ ~Native7Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+ void decreaseCubeCount();
+
+ void increaseCubeCount();
+
+ void setDelta(float x, float y);
+
+ void toggleStride();
+
+ void toggleVBOs();
+
+ void updateVboStatus(bool useVbos);
+
+ void updateStrideStatus(bool useStride);
+
+private:
+
+ // model/view/projection matrix
+ Matrix *mModelMatrix;
+ Matrix *mViewMatrix;
+ Matrix *mProjectionMatrix;
+ Matrix *mMVPMatrix;
+
+ //
+ Matrix *mAccumulatedRotationMatrix;
+ Matrix *mCurrentRotationMatrix;
+ Matrix *mLightModelMatrix;
+
+ //
+ GLuint mMVPMatrixHandle;
+ GLuint mMVMatrixHandle;
+ GLuint mLightPosHandle;
+ GLuint mTextureUniformHandle;
+
+ GLuint mProgramHandle;
+ GLuint mPointProgramHandle;
+
+ GLuint mAndroidDataHandle;
+
+ float mLightPosInModelSpace[4];
+ float mLightPosInWorldSpace[4];
+ float mLightPosInEyeSpace[4];
+
+ float mDeltaX;
+ float mDeltaY;
+};
+
+
+#endif //OPENGLLESSON_NATIVE7LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.cpp
new file mode 100644
index 0000000..c9c164d
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.cpp
@@ -0,0 +1,193 @@
+//
+// Created by biezhihua on 2017/7/30.
+//
+
+#include
+#include "HeightMap.h"
+#include "graphics/Matrix.h"
+
+#define LOG_TAG "Lesson8"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+const float HeightMap::MIN_POSITION = -5.0f;
+const float HeightMap::POSITION_RANGE = 10.0f;
+
+HeightMap::HeightMap() : heightMapVertexData(nullptr), heightMapIndexData(nullptr) {
+// try {
+//
+ const int floatsPerVertex = POSITION_DATA_SIZE_IN_ELEMENTS + NORMAL_DATA_SIZE_IN_ELEMENTS
+ + COLOR_DATA_SIZE_IN_ELEMENTS;
+
+ const int xLength = SIZE_PER_SIZE;
+ const int yLength = SIZE_PER_SIZE;
+
+ heightMapVertexData = new vector();
+
+ // First, build the data for the vertex buffer.
+ for (int y = 0; y < yLength; y++) {
+ for (int x = 0; x < xLength; x++) {
+ // Build our heightmap from the top down,
+ // so that triangles are counter-clockwise.
+ float xRatio = x / (float) (xLength - 1);
+ float yRatio = 1.0f - (y / (float) (yLength - 1));
+
+ float xPosition = MIN_POSITION + (xRatio * POSITION_RANGE);
+ float yPosition = MIN_POSITION + (yRatio * POSITION_RANGE);;
+ float zPosition = ((xPosition * xPosition) + (yPosition * yPosition)) / 10.0f;
+
+ // Position
+ heightMapVertexData->push_back(xPosition);
+ heightMapVertexData->push_back(yPosition);
+ heightMapVertexData->push_back(zPosition);
+
+ // Cheap normal using a derivative of the function.
+ // The slope for X will be 2X, for Y will be 2Y.
+ // Divide by 10 since the position's Z is also divided by 10.
+ float xSlope = (2 * xPosition) / 10.0f;
+ float ySlope = (2 * yPosition) / 10.0f;
+
+ // Calculate the normal using the cross product of the slopes.
+ float planeVectorX[3] = {1.0f, 0.0f, xSlope};
+ float planeVectorY[3] = {0.0f, 1.0, ySlope};
+ float normalVector[3] = {
+ (planeVectorX[1] * planeVectorY[2]) - (planeVectorX[2] * planeVectorY[1]),
+ (planeVectorX[2] * planeVectorY[0]) - (planeVectorX[0] * planeVectorY[2]),
+ (planeVectorX[0] * planeVectorY[1]) - (planeVectorX[1] * planeVectorY[0])};
+
+ // Normalize the normal
+ float length = Matrix::length(normalVector[0], normalVector[1], normalVector[2]);
+
+ heightMapVertexData->push_back(normalVector[0] / length);
+ heightMapVertexData->push_back(normalVector[1] / length);
+ heightMapVertexData->push_back(normalVector[2] / length);
+
+ // Add some fancy colors.
+ heightMapVertexData->push_back(xRatio);
+ heightMapVertexData->push_back(yRatio);
+ heightMapVertexData->push_back(0.5f);
+ heightMapVertexData->push_back(1.0f);
+ }
+ }
+
+ // Now, build the index data.
+ int numStripsRequired = yLength - 1;
+ int numDegensRequired = 2 * (numStripsRequired - 1);
+ int verticesPerStrip = 2 * xLength;
+
+ heightMapIndexData = new vector();
+
+ for (int y = 0; y < yLength - 1; y++) {
+ if (y > 0) {
+ // Degenerate begin: repeat first vertex
+ heightMapIndexData->push_back((short) (y * yLength));
+ }
+
+ for (int x = 0; x < xLength; x++) {
+ // One part of the strip
+ heightMapIndexData->push_back((short) ((y * yLength) + x));
+ heightMapIndexData->push_back((short) (((y + 1) * yLength) + x));
+ }
+
+ if (y < yLength - 2) {
+ // Degenerate end: repeat last vertex
+ heightMapIndexData->push_back((short) (((y + 1) * yLength) + (xLength - 1)));
+ }
+ }
+
+ indexCount = (GLsizei) heightMapIndexData->size();
+
+ glGenBuffers(1, vbo);
+ glGenBuffers(1, ibo);
+
+ if (vbo[0] > 0 && ibo[0] > 0) {
+ glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
+ glBufferData(GL_ARRAY_BUFFER, heightMapVertexData->size() * BYTES_PER_FLOAT,
+ heightMapVertexData->data(), GL_STATIC_DRAW);
+
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, heightMapIndexData->size()
+ * BYTES_PER_SHORT,
+ heightMapIndexData->data(), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+// } catch (const std::exception &exception) {
+// LOGE("Exception %s", exception.what());
+// }
+}
+
+HeightMap::~HeightMap() {
+ heightMapVertexData->clear();
+ vector().swap(*heightMapVertexData);
+
+ heightMapIndexData->clear();
+ vector().swap(*heightMapIndexData);
+
+ delete[] heightMapVertexData;
+ delete[] heightMapIndexData;
+ heightMapVertexData = nullptr;
+ heightMapIndexData = nullptr;
+}
+
+void HeightMap::render() {
+ if (vbo[0] > 0 && ibo[0] > 0) {
+ glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
+
+ // Bind attributes
+ glVertexAttribPointer(positionAttribute,
+ POSITION_DATA_SIZE_IN_ELEMENTS, GL_FLOAT, GL_FALSE, STRIDE, 0
+ );
+ glEnableVertexAttribArray(positionAttribute);
+
+ glVertexAttribPointer(normalAttribute,
+ NORMAL_DATA_SIZE_IN_ELEMENTS,
+ GL_FLOAT, GL_FALSE, STRIDE,
+ (const void *) (POSITION_DATA_SIZE_IN_ELEMENTS * BYTES_PER_FLOAT)
+ );
+ glEnableVertexAttribArray(normalAttribute);
+
+ glVertexAttribPointer(colorAttribute, COLOR_DATA_SIZE_IN_ELEMENTS, GL_FLOAT, GL_FALSE,
+ STRIDE,
+ (const void *) (
+ (POSITION_DATA_SIZE_IN_ELEMENTS +
+ NORMAL_DATA_SIZE_IN_ELEMENTS) *
+ BYTES_PER_FLOAT)
+ );
+ glEnableVertexAttribArray(colorAttribute);
+
+ // Draw
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
+ glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_SHORT, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+}
+
+void HeightMap::release() {
+ if (vbo[0] > 0) {
+ glDeleteBuffers(1, vbo);
+ vbo[0] = 0;
+ }
+ if (ibo[0] > 0) {
+ glDeleteBuffers(1, ibo);
+ ibo[0] = 0;
+ }
+}
+
+void HeightMap::setPositionAttribute(GLuint positionAttribute) {
+ HeightMap::positionAttribute = positionAttribute;
+}
+
+void HeightMap::setNormalAttribute(GLuint normalAttribute) {
+ HeightMap::normalAttribute = normalAttribute;
+}
+
+void HeightMap::setColorAttribute(GLuint colorAttribute) {
+ HeightMap::colorAttribute = colorAttribute;
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.h
new file mode 100644
index 0000000..9ff4e9b
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.h
@@ -0,0 +1,69 @@
+//
+// Created by biezhihua on 2017/7/30.
+//
+
+#ifndef OPENGLLESSON_HEIGHTMAP_H
+#define OPENGLLESSON_HEIGHTMAP_H
+
+#include
+#include
+#include "graphics/Matrix.h"
+
+using namespace std;
+
+class HeightMap {
+
+private:
+ /**
+ * Additional constants.
+ */
+ static const int POSITION_DATA_SIZE_IN_ELEMENTS = 3;
+ static const int NORMAL_DATA_SIZE_IN_ELEMENTS = 3;
+ static const int COLOR_DATA_SIZE_IN_ELEMENTS = 4;
+
+ static const int BYTES_PER_FLOAT = 4;
+ static const int BYTES_PER_SHORT = 2;
+
+ static const int STRIDE = (POSITION_DATA_SIZE_IN_ELEMENTS + NORMAL_DATA_SIZE_IN_ELEMENTS +
+ COLOR_DATA_SIZE_IN_ELEMENTS) * BYTES_PER_FLOAT;
+
+
+ static const int SIZE_PER_SIZE = 32;
+ static const float MIN_POSITION;
+ static const float POSITION_RANGE;
+
+ GLuint vbo[1] = {0};
+ GLuint ibo[1] = {0};
+
+ GLsizei indexCount = 0;
+
+ vector *heightMapVertexData;
+
+ vector *heightMapIndexData;
+
+ /**
+ * OpenGL handles to our program attributes.
+ */
+ GLuint positionAttribute;
+ GLuint normalAttribute;
+ GLuint colorAttribute;
+
+public:
+
+ HeightMap();
+
+ ~HeightMap();
+
+ void render();
+
+ void release();
+
+ void setPositionAttribute(GLuint positionAttribute);
+
+ void setNormalAttribute(GLuint normalAttribute);
+
+ void setColorAttribute(GLuint colorAttribute);
+};
+
+
+#endif //OPENGLLESSON_HEIGHTMAP_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.cpp b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.cpp
new file mode 100644
index 0000000..498d6dd
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.cpp
@@ -0,0 +1,261 @@
+//
+// Created by biezhihua on 2017/7/30.
+//
+
+#include
+#include "Native8Lesson.h"
+#include
+#include "graphics/GLUtils.h"
+
+#define LOG_TAG "Lesson8"
+#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
+#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
+#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
+
+const string Native8Lesson::MVP_MATRIX_UNIFORM = "u_MVPMatrix";
+const string Native8Lesson::MV_MATRIX_UNIFORM = "u_MVMatrix";
+const string Native8Lesson::LIGHT_POSITION_UNIFORM = "u_LightPos";
+
+const string Native8Lesson::POSITION_ATTRIBUTE = "a_Position";
+const string Native8Lesson::NORMAL_ATTRIBUTE = "a_Normal";
+const string Native8Lesson::COLOR_ATTRIBUTE = "a_Color";
+
+Native8Lesson::Native8Lesson() : modelMatrix(nullptr),
+ viewMatrix(nullptr),
+ projectionMatrix(nullptr),
+ mvpMatrix(nullptr),
+ accumulatedRotation(nullptr),
+ currentRotaion(nullptr),
+ lightModelMatrix(nullptr),
+ heightMap(nullptr) {
+ LOGD("Native8Lesson");
+
+ lightPosInModelSpace[0] = 0.0f;
+ lightPosInModelSpace[1] = 0.0f;
+ lightPosInModelSpace[2] = 0.0f;
+ lightPosInModelSpace[3] = 1.0f;
+
+ lightPosInWorldSpace[0] = 0.0f;
+ lightPosInWorldSpace[1] = 0.0f;
+ lightPosInWorldSpace[2] = 0.0f;
+ lightPosInWorldSpace[3] = 0.0f;
+
+ lightPosInEyeSpace[0] = 0.0f;
+ lightPosInEyeSpace[1] = 0.0f;
+ lightPosInEyeSpace[2] = 0.0f;
+ lightPosInEyeSpace[3] = 0.0f;
+
+}
+
+Native8Lesson::~Native8Lesson() {
+
+ delete (modelMatrix);
+ delete (viewMatrix);
+ delete (projectionMatrix);
+ delete (mvpMatrix);
+ delete (accumulatedRotation);
+ delete (currentRotaion);
+ delete (lightModelMatrix);
+
+ modelMatrix = nullptr;
+ viewMatrix = nullptr;
+ projectionMatrix = nullptr;
+ mvpMatrix = nullptr;
+ accumulatedRotation = nullptr;
+ currentRotaion = nullptr;
+ lightModelMatrix = nullptr;
+
+ heightMap->release();
+ delete (heightMap);
+ heightMap = nullptr;
+
+ LOGD("~Native8Lesson");
+}
+
+void Native8Lesson::create() {
+ heightMap = new HeightMap();
+
+ // Set the background clear color th black.
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ // Enable depth testing
+ glEnable(GL_DEPTH_TEST);
+
+ // Position the eye in front of the origin.
+ float eyeX = 0.0f;
+ float eyeY = 0.0f;
+ float eyeZ = -0.5f;
+
+ // We are looking toward the distance
+ float lookX = 0.0f;
+ float lookY = 0.0f;
+ float lookZ = -5.0f;
+
+ // Set our up vector. This is where our head would be pointing were we
+ // holding the camera.
+ float upX = 0.0f;
+ float upY = 1.0f;
+ float upZ = 0.0f;
+
+ // Set the view matrix. This matrix can be said to represent the camera
+ // position.
+ // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination
+ // of a model and view matrix. In OpenGL 2, we can keep track of these
+ // matrices separately if we choose.
+ viewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
+
+ // Main Program
+ const char *vertex = GLUtils::openTextFile("vertex/per_pixel_vertex_shader_no_tex.glsl");
+ const char *fragment = GLUtils::openTextFile("fragment/per_pixel_fragment_shader_no_tex.glsl");
+
+ // Set the program.
+ program = GLUtils::createProgram(&vertex, &fragment);
+ if (!program) {
+ LOGD("Could not create program");
+ return;
+ }
+
+ // Init matrix
+ modelMatrix = new Matrix();
+ mvpMatrix = new Matrix();
+ accumulatedRotation = new Matrix();
+ currentRotaion = new Matrix();
+ lightModelMatrix = new Matrix();
+
+ LOGD("create");
+}
+
+void Native8Lesson::change(int width, int height) {
+ // Set the OpenGL viewport to the same size as the surface.
+ glViewport(0, 0, width, height);
+
+ // Create a new perspective projection matrix.
+ // The height wil stay the same while the width
+ // vary as per aspect ratio.
+ float ratio = (float) width / height;
+ float left = -ratio;
+ float right = ratio;
+ float bottom = -1.0f;
+ float top = 1.0f;
+ float near = 1.0f;
+ float far = 1000.0f;
+
+ projectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
+
+ LOGD("change");
+}
+
+void Native8Lesson::draw() {
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Set our per-vertex lighting program.
+ glUseProgram(program);
+ mvpMatrixUniform = glGetUniformLocation(program, MVP_MATRIX_UNIFORM.c_str());
+ mvMatrixUniform = glGetUniformLocation(program, MV_MATRIX_UNIFORM.c_str());
+ lightPosUniform = glGetAttribLocation(program, LIGHT_POSITION_UNIFORM.c_str());
+
+ GLint positionAttribute = glGetAttribLocation(program, POSITION_ATTRIBUTE.c_str());
+ GLint normalAttribute = glGetAttribLocation(program, NORMAL_ATTRIBUTE.c_str());
+ GLint colorAttribute = glGetAttribLocation(program, COLOR_ATTRIBUTE.c_str());
+
+ if (heightMap != nullptr) {
+ heightMap->setPositionAttribute((GLuint) positionAttribute);
+ heightMap->setNormalAttribute((GLuint) normalAttribute);
+ heightMap->setColorAttribute((GLuint) colorAttribute);
+ }
+
+ // Calculate position of the light. Push into the distance.
+ lightModelMatrix->identity();
+ lightModelMatrix->translate(0.0f, 7.5f, -8.0f);
+
+ Matrix::multiplyMV(lightPosInWorldSpace, lightModelMatrix->mData, lightPosInModelSpace);
+ Matrix::multiplyMV(lightPosInEyeSpace, viewMatrix->mData, lightPosInWorldSpace);
+
+ // Draw the heightmap
+ // Translate the heightmap into the screen.
+ modelMatrix->identity();
+ modelMatrix->translate(0.0f, 0.0f, -12.0f);
+
+ // Set a matrix that contains the current rotation.
+ currentRotaion->identity();
+ currentRotaion->rotate(deltaX, 0.0f, 1.0f, 0.0f);
+ currentRotaion->rotate(deltaY, 1.0f, 0.0f, 0.0f);
+ deltaX = 0;
+ deltaY = 0;
+
+ Matrix tempMatrix;
+
+ // Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
+ tempMatrix.identity();
+ tempMatrix.multiply(*currentRotaion, *accumulatedRotation);
+ accumulatedRotation->loadWith(tempMatrix);
+
+ // Rotate the cube taking the overall rotation into account.
+ tempMatrix.identity();
+ tempMatrix.multiply(*modelMatrix, *accumulatedRotation);
+ modelMatrix->loadWith(tempMatrix);
+
+ // This multiplies the view by the model matrix
+ // and stores the result the MVP matrix.
+ // which currently contains model * view
+ mvpMatrix->multiply(*viewMatrix, *modelMatrix);
+ glUniformMatrix4fv(mvMatrixUniform, 1, GL_FALSE, mvpMatrix->mData);
+
+ // Pass in the combined matrix.
+ mvpMatrix->multiply(*projectionMatrix, *mvpMatrix);
+ glUniformMatrix4fv(mvpMatrixUniform, 1, GL_FALSE, mvpMatrix->mData);
+
+ glUniform3f(lightPosUniform, lightPosInEyeSpace[0], lightPosInEyeSpace[1],
+ lightPosInEyeSpace[2]);
+
+ // Renderer the heightmap;
+ heightMap->render();
+}
+
+void Native8Lesson::setDelta(float x, float y) {
+ deltaX += x;
+ deltaY += y;
+}
+
+
+// ------------------------------------------------------------------
+
+Native8Lesson native8Lesson;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson8_LessonEightNativeRenderer_nativeSurfaceCreate(JNIEnv *env,
+ jobject instance,
+ jobject assetManager) {
+
+ GLUtils::setEnvAndAssetManager(env, assetManager);
+ native8Lesson.create();
+}
+
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson8_LessonEightNativeRenderer_nativeSurfaceChange(JNIEnv *env,
+ jobject instance,
+ jint width,
+ jint height) {
+
+ native8Lesson.change(width, height);
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson8_LessonEightNativeRenderer_nativeDrawFrame(JNIEnv *env,
+ jobject instance) {
+ native8Lesson.draw();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_learnopengles_android_lesson8_LessonEightNativeRenderer_nativeSetDelta(JNIEnv *env,
+ jobject instance,
+ jfloat x,
+ jfloat y) {
+ native8Lesson.setDelta(x, y);
+}
\ No newline at end of file
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.h b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.h
new file mode 100644
index 0000000..ff3dbf0
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.h
@@ -0,0 +1,118 @@
+#ifndef OPENGLLESSON_NATIVE8LESSON_H
+#define OPENGLLESSON_NATIVE8LESSON_H
+
+
+#include
+#include
+#include "HeightMap.h"
+#include "graphics/Matrix.h"
+
+using namespace std;
+
+class Native8Lesson {
+
+public :
+
+ Native8Lesson();
+
+ ~Native8Lesson();
+
+ void create();
+
+ void change(int width, int height);
+
+ void draw();
+
+ void setDelta(float x, float y);
+
+private:
+ /**
+ * Identifiers for our uniforms and attributes inside the shaders.
+ */
+ static const string MVP_MATRIX_UNIFORM;
+ static const string MV_MATRIX_UNIFORM;
+ static const string LIGHT_POSITION_UNIFORM;
+
+ static const string POSITION_ATTRIBUTE;
+ static const string NORMAL_ATTRIBUTE;
+ static const string COLOR_ATTRIBUTE;
+
+ /**
+ * Used to hold a light centered on the origin in model space.
+ * We need a 4th coordinate so we can get translations to
+ * work when we multiply this by our transformation matrices.
+ */
+ float lightPosInModelSpace[4];
+
+ /**
+ * Used to hold the current position of the light in world space
+ * (after transformation via model matrix).
+ */
+ float lightPosInWorldSpace[4];
+
+ /**
+ * Used to hold the transformed position of the light in eye space
+ * (after transformation via modelview matrix).
+ */
+ float lightPosInEyeSpace[4];
+
+ /**
+ * Store the model matrix.
+ * This matrix is used to move models from
+ * object space (where each model can be tought of
+ * being located at the center of the universe)
+ * to world space.
+ */
+ Matrix *modelMatrix;
+
+ /**
+ * Store the view matrix.
+ * This can be tought of as our camera.
+ * This matrix transforms world space to eye space.
+ * it positions things relative to our eye.
+ */
+ Matrix *viewMatrix;
+
+ /**
+ * Store the projection matrix.
+ * This is used to projet the scene onto a 2D viewport.
+ */
+ Matrix *projectionMatrix;
+
+ /**
+ * Allocate storage for the final combined matrix.
+ * This will be passed into the shader program.
+ */
+ Matrix *mvpMatrix;
+
+ Matrix *accumulatedRotation;
+ Matrix *currentRotaion;
+ Matrix *lightModelMatrix;
+
+ /**
+ * OpenGL handles to our program uniforms
+ */
+ GLint mvpMatrixUniform;
+ GLint mvMatrixUniform;
+ GLint lightPosUniform;
+
+
+ /**
+ * This is a handle to our cube shading program.
+ */
+ GLuint program;
+
+ /**
+ * Retaion the most recent delta for touch events.
+ */
+ volatile float deltaX;
+ volatile float deltaY;
+
+
+ /**
+ * The current heightmap object.
+ */
+ HeightMap *heightMap;
+};
+
+#endif //OPENGLLESSON_NATIVE8LESSON_H
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/TableOfContents.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/TableOfContents.java
index 7173014..025e999 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/TableOfContents.java
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/TableOfContents.java
@@ -10,7 +10,15 @@
import android.widget.AdapterView.OnItemClickListener;
import android.widget.SimpleAdapter;
+import com.learnopengles.android.cpp.R;
import com.learnopengles.android.lesson1.LessonOneActivity;
+import com.learnopengles.android.lesson2.LessonTwoActivity;
+import com.learnopengles.android.lesson3.LessonThreeActivity;
+import com.learnopengles.android.lesson4.LessonFourActivity;
+import com.learnopengles.android.lesson5.LessonFiveActivity;
+import com.learnopengles.android.lesson6.LessonSixActivity;
+import com.learnopengles.android.lesson7.LessonSevenActivity;
+import com.learnopengles.android.lesson8.LessonEightActivity;
import java.util.ArrayList;
import java.util.HashMap;
@@ -43,6 +51,69 @@ public void onCreate(Bundle savedInstanceState) {
activityMapping.put(i++, LessonOneActivity.class);
}
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_two);
+ item.put(ITEM_TITLE, getText(R.string.lesson_two));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_two_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonTwoActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_three);
+ item.put(ITEM_TITLE, getText(R.string.lesson_three));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_three_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonThreeActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_four);
+ item.put(ITEM_TITLE, getText(R.string.lesson_four));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_four_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonFourActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_five);
+ item.put(ITEM_TITLE, getText(R.string.lesson_five));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_five_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonFiveActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_six);
+ item.put(ITEM_TITLE, getText(R.string.lesson_six));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_six_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonSixActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_seven);
+ item.put(ITEM_TITLE, getText(R.string.lesson_seven));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_seven_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonSevenActivity.class);
+ }
+
+ {
+ final Map item = new HashMap();
+ item.put(ITEM_IMAGE, R.drawable.ic_lesson_eight);
+ item.put(ITEM_TITLE, getText(R.string.lesson_eight));
+ item.put(ITEM_SUBTITLE, getText(R.string.lesson_eight_subtitle));
+ data.add(item);
+ activityMapping.put(i++, LessonEightActivity.class);
+ }
+
final SimpleAdapter dataAdapter = new SimpleAdapter(this, data, R.layout.toc_item, new String[]{ITEM_IMAGE, ITEM_TITLE, ITEM_SUBTITLE}, new int[]{R.id.Image, R.id.Title, R.id.SubTitle});
setListAdapter(dataAdapter);
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/Utils.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/Utils.java
new file mode 100644
index 0000000..d33bc35
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/Utils.java
@@ -0,0 +1,278 @@
+package com.learnopengles.android;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Utils {
+
+ private static final String TAG = "Utils";
+
+ /**
+ * type:
+ * create a vertex shader type {@link GLES20.GL_VERTEX_SHADER}
+ * or a fragment shader type {@link GLES20.GL_FRAGMENT_SHADER}
+ */
+ @SuppressWarnings("JavadocReference")
+ public static int compileShader(int type, String shaderCode) {
+
+ // Load in the shader
+ int shader = GLES20.glCreateShader(type);
+
+ if (shader != 0) {
+ // Pass in the shader source
+ GLES20.glShaderSource(shader, shaderCode);
+
+ // Compile the shader
+ GLES20.glCompileShader(shader);
+
+ // Get the compilation status.
+ final int[] compileStatus = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
+
+ // If the compilation failed, delete the shader.
+ if (compileStatus[0] == 0) {
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+
+ if (shader == 0) {
+ GLES20.glGetShaderInfoLog(shader);
+ throw new RuntimeException("Error creating vertex shader.");
+ }
+
+ return shader;
+ }
+
+ /**
+ * Helper function to compile and link a program.
+ */
+ public static int createAndLinkProgram(final int vertexShaderHandle,
+ final int fragmentShaderHandle,
+ final String[] attributes) {
+
+ int programHandle = GLES20.glCreateProgram();
+
+ if (programHandle != 0) {
+
+ // Bind the vertex shader to the program
+ GLES20.glAttachShader(programHandle, vertexShaderHandle);
+
+ // Bind the fragment shader to the program.
+ GLES20.glAttachShader(programHandle, fragmentShaderHandle);
+
+ // Bind attribuets
+ if (attributes != null) {
+ final int size = attributes.length;
+ for (int i = 0; i < size; i++) {
+ GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
+ }
+ }
+
+ // Link the two shader together into a program.
+ GLES20.glLinkProgram(programHandle);
+
+
+ // Get the link status.
+ final int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
+
+ // If the link failed, delete the program.
+ if (linkStatus[0] == 0) {
+ Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
+ GLES20.glDeleteProgram(programHandle);
+ programHandle = 0;
+ }
+ }
+
+ if (programHandle == 0) {
+ throw new RuntimeException("Error creating program.");
+ }
+
+ return programHandle;
+ }
+
+ public static int loadTexture(final Context context,
+ final int resourceId) {
+ final int[] textureHandle = new int[1];
+
+ GLES20.glGenTextures(1, textureHandle, 0);
+
+ if (textureHandle[0] != 0) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inScaled = false; // No pre-scaling
+
+ // Read in the resource
+ final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
+
+ // Bind to the texture in OpenGL
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
+
+ // Set filtering
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+ GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_NEAREST);
+
+ // Load the bitmap into the bound texture
+ GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+
+ // Recycle the bitmap, since its data has been loaded into OpenGL
+ bitmap.recycle();
+ }
+
+ if (textureHandle[0] == 0) {
+ throw new RuntimeException("Error loading texture.");
+ }
+
+ return textureHandle[0];
+ }
+
+ public static int loadTexture(final AssetManager manager, final String path) {
+ InputStream in = null;
+ try {
+ in = manager.open(path);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ BitmapFactory.Options op = new BitmapFactory.Options();
+ op.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ Bitmap bmp = BitmapFactory.decodeStream(in, null, op);
+
+ // generate textureID
+ int[] textures = new int[1];
+ GLES20.glGenTextures(1, textures, 0);
+ int textureID = textures[0];
+
+ // create texture
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
+ GLES20.glTexParameteri(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
+ GLES20.glTexParameteri(
+ GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
+ GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
+
+ // clean up
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ bmp.recycle();
+ }
+ return textureID;
+ }
+
+ public static float[] generateCubeData(float[] point1,
+ float[] point2,
+ float[] point3,
+ float[] point4,
+ float[] point5,
+ float[] point6,
+ float[] point7,
+ float[] point8,
+ int elementsPerPoint) {
+
+ // Given a cube with the points define as follows:
+ // front left top, front right top, front left bottom,front right bottom
+ // back left top, back right top, back left bottom, front right bottom
+ // return an array of 6 sides, 2 triangles per side, 3 vertices per cube.
+
+ final int FRONT = 0;
+ final int RIGHT = 1;
+ final int BACK = 2;
+ final int LEFT = 3;
+ final int TOP = 4;
+ final int BOTTOM = 5;
+
+ final int size = elementsPerPoint * 6 * 6;
+ final float[] cubeData = new float[size];
+
+ for (int face = 0; face < 6; face++) {
+ // Relative to the side,
+ // p1 = top left
+ // p2 = top right
+ // p3 = bottom left
+ // p4 = bottom right
+ final float[] p1, p2, p3, p4;
+
+ // Select the points for this face
+ if (face == FRONT) {
+ p1 = point1;
+ p2 = point2;
+ p3 = point3;
+ p4 = point4;
+ } else if (face == RIGHT) {
+ p1 = point2;
+ p2 = point6;
+ p3 = point4;
+ p4 = point8;
+ } else if (face == BACK) {
+ p1 = point6;
+ p2 = point5;
+ p3 = point8;
+ p4 = point7;
+ } else if (face == LEFT) {
+ p1 = point5;
+ p2 = point1;
+ p3 = point7;
+ p4 = point3;
+ } else if (face == TOP) {
+ p1 = point5;
+ p2 = point6;
+ p3 = point1;
+ p4 = point2;
+ } else // if (face == BOTTOM)
+ {
+ p1 = point8;
+ p2 = point7;
+ p3 = point4;
+ p4 = point3;
+ }
+
+ // In OpenGL counter-clockwise winding is default.
+ // This means that when we look at a triangle,
+ // if the points are counter-clockwise we are looking at the "front".
+ // If not we are looking at the back.
+ // OpenGL has an optimization where all back-facing triangles are culled, since they
+ // usually represent the backside of an object and aren't visible anyways.
+
+ // Build the triangles
+ // 1---3,6
+ // | / |
+ // 2,4--5
+ int offset = face * elementsPerPoint * 6;
+
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p1[i];
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p3[i];
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p2[i];
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p3[i];
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p4[i];
+ }
+ for (int i = 0; i < elementsPerPoint; i++) {
+ cubeData[offset++] = p2[i];
+ }
+ }
+ return cubeData;
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson1/LessonOneNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson1/LessonOneNativeRenderer.java
index e608bce..12c5f6b 100644
--- a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson1/LessonOneNativeRenderer.java
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson1/LessonOneNativeRenderer.java
@@ -1,6 +1,8 @@
package com.learnopengles.android.lesson1;
+import android.annotation.TargetApi;
import android.opengl.GLSurfaceView;
+import android.os.Build;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoActivity.java
new file mode 100644
index 0000000..466442e
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoActivity.java
@@ -0,0 +1,55 @@
+package com.learnopengles.android.lesson2;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+
+public class LessonTwoActivity extends Activity {
+
+ /**
+ * Hold a reference to our GLSurfaceView
+ */
+ private GLSurfaceView mGLSurfaceView;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGLSurfaceView = new GLSurfaceView(this);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGLSurfaceView.setEGLContextClientVersion(2);
+
+ // Set the renderer to out demo renderer, define below
+ mGLSurfaceView.setRenderer(new LessonTwoNativeRenderer());
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+ setContentView(mGLSurfaceView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLSurfaceView.onPause();
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoNativeRenderer.java
new file mode 100644
index 0000000..0b9122c
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoNativeRenderer.java
@@ -0,0 +1,35 @@
+package com.learnopengles.android.lesson2;
+
+import android.opengl.GLSurfaceView;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonTwoNativeRenderer implements GLSurfaceView.Renderer {
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public static native void nativeSurfaceCreate();
+
+ public static native void nativeSurfaceChange(int width, int height);
+
+ public static native void nativeDrawFrame();
+
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeActivity.java
new file mode 100644
index 0000000..2437f5f
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeActivity.java
@@ -0,0 +1,54 @@
+package com.learnopengles.android.lesson3;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+
+public class LessonThreeActivity extends Activity {
+
+ /**
+ * Hold a reference to our GLSurfaceView
+ */
+ private GLSurfaceView mGLSurfaceView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGLSurfaceView = new GLSurfaceView(this);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGLSurfaceView.setEGLContextClientVersion(2);
+
+ // Set the renderer to out demo renderer, define below
+ mGLSurfaceView.setRenderer(new LessonThreeNativeRenderer());
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+ setContentView(mGLSurfaceView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLSurfaceView.onPause();
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeNativeRenderer.java
new file mode 100644
index 0000000..3ae5dee
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeNativeRenderer.java
@@ -0,0 +1,35 @@
+package com.learnopengles.android.lesson3;
+
+import android.opengl.GLSurfaceView;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonThreeNativeRenderer implements GLSurfaceView.Renderer {
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public static native void nativeSurfaceCreate();
+
+ public static native void nativeSurfaceChange(int width, int height);
+
+ public static native void nativeDrawFrame();
+
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourActivity.java
new file mode 100644
index 0000000..4631502
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourActivity.java
@@ -0,0 +1,54 @@
+package com.learnopengles.android.lesson4;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+
+public class LessonFourActivity extends Activity {
+
+ /**
+ * Hold a reference to our GLSurfaceView
+ */
+ private GLSurfaceView mGLSurfaceView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGLSurfaceView = new GLSurfaceView(this);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGLSurfaceView.setEGLContextClientVersion(2);
+
+ // Set the renderer to out demo renderer, define below
+ mGLSurfaceView.setRenderer(new LessonFourNativeRenderer(this));
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+ setContentView(mGLSurfaceView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLSurfaceView.onPause();
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourNativeRenderer.java
new file mode 100644
index 0000000..9fd0c4d
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourNativeRenderer.java
@@ -0,0 +1,44 @@
+package com.learnopengles.android.lesson4;
+
+import android.app.Activity;
+import android.content.res.AssetManager;
+import android.opengl.GLSurfaceView;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonFourNativeRenderer implements GLSurfaceView.Renderer {
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ private Activity mActivity;
+
+ public LessonFourNativeRenderer(Activity activity) {
+ mActivity = activity;
+ }
+
+
+ public static native void nativeSurfaceCreate(AssetManager assetManager);
+
+ public static native void nativeSurfaceChange(int width, int height);
+
+ public static native void nativeDrawFrame();
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ AssetManager assetManager = mActivity.getAssets();
+ nativeSurfaceCreate(assetManager);
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/BlendingMode.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/BlendingMode.java
new file mode 100644
index 0000000..96110e0
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/BlendingMode.java
@@ -0,0 +1,5 @@
+package com.learnopengles.android.lesson5;
+
+interface BlendingMode {
+ void switchMode();
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveActivity.java
new file mode 100644
index 0000000..c4464c2
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveActivity.java
@@ -0,0 +1,92 @@
+package com.learnopengles.android.lesson5;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+public class LessonFiveActivity extends Activity {
+
+ /**
+ * Hold a reference to our GLSurfaceView
+ */
+ private LessonFiveGLSurfaceView mGLSurfaceView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mGLSurfaceView = new LessonFiveGLSurfaceView(this);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGLSurfaceView.setEGLContextClientVersion(2);
+
+ // Set the renderer to out demo renderer, define below
+ mGLSurfaceView.setRenderer(new LessonFiveNativeRenderer(this));
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+ setContentView(mGLSurfaceView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLSurfaceView.onPause();
+ }
+
+ class LessonFiveGLSurfaceView extends GLSurfaceView {
+ private BlendingMode mRenderer;
+
+ public LessonFiveGLSurfaceView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event != null) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mRenderer != null) {
+ // Ensure we call switchMode() on the OpenGL thread.
+ // queueEvent() is a method of GLSurfaceView that will do this for us.
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ mRenderer.switchMode();
+ }
+ });
+
+ return true;
+ }
+ }
+ }
+
+ return super.onTouchEvent(event);
+ }
+
+ // Hides superclass method.
+ public void setRenderer(Renderer renderer) {
+ if (renderer instanceof BlendingMode) {
+ mRenderer = (BlendingMode) renderer;
+ }
+ super.setRenderer(renderer);
+ }
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveNativeRenderer.java
new file mode 100644
index 0000000..e3c3696
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveNativeRenderer.java
@@ -0,0 +1,50 @@
+package com.learnopengles.android.lesson5;
+
+import android.app.Activity;
+import android.content.res.AssetManager;
+import android.opengl.GLSurfaceView;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonFiveNativeRenderer implements GLSurfaceView.Renderer, BlendingMode {
+
+ private Activity mActivity;
+
+ public LessonFiveNativeRenderer(Activity activity) {
+ mActivity = activity;
+ }
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public static native void nativeSurfaceCreate(AssetManager assetManager);
+
+ public static native void nativeSurfaceChange(int width, int height);
+
+ public static native void nativeDrawFrame();
+
+ public static native void nativeSwitchMode();
+
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate(mActivity.getAssets());
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+
+ @Override
+ public void switchMode() {
+ nativeSwitchMode();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/Action.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/Action.java
new file mode 100644
index 0000000..db4e629
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/Action.java
@@ -0,0 +1,9 @@
+package com.learnopengles.android.lesson6;
+
+interface Action {
+ void setMinFilter(int filter);
+
+ void setMagFilter(int filter);
+
+ void setDelta(float deltaX, float deltaY);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixActivity.java
new file mode 100644
index 0000000..649d044
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixActivity.java
@@ -0,0 +1,195 @@
+package com.learnopengles.android.lesson6;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import com.learnopengles.android.cpp.R;
+
+public class LessonSixActivity extends Activity {
+
+ private LessonSixGLSurfaceView mGLSurfaceView;
+ private Action mRenderer;
+
+ private static final int MIN_DIALOG = 1;
+ private static final int MAG_DIALOG = 2;
+
+ private int mMinSetting = -1;
+ private int mMagSetting = -1;
+
+ private static final String MIN_SETTING = "min_setting";
+ private static final String MAG_SETTING = "mag_setting";
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.lesson_six);
+
+ mGLSurfaceView = (LessonSixGLSurfaceView) findViewById(R.id.gl_surface_view);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGLSurfaceView.setEGLContextClientVersion(2);
+
+ final DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+
+ // Set the renderer to out demo renderer, define below
+ mRenderer = new LessonSixNativeRenderer(this);
+
+ mGLSurfaceView.setRenderer((GLSurfaceView.Renderer) mRenderer, displayMetrics.density);
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+
+ findViewById(R.id.button_set_min_filter).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(MIN_DIALOG);
+ }
+ });
+
+ findViewById(R.id.button_set_mag_filter).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(MAG_DIALOG);
+ }
+ });
+
+ // Restore previous settings
+ if (savedInstanceState != null) {
+ mMinSetting = savedInstanceState.getInt(MIN_SETTING, -1);
+ mMagSetting = savedInstanceState.getInt(MAG_SETTING, -1);
+
+ if (mMinSetting != -1) {
+ setMinSetting(mMinSetting);
+ }
+ if (mMagSetting != -1) {
+ setMagSetting(mMagSetting);
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLSurfaceView.onPause();
+ }
+
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ outState.putInt(MIN_SETTING, mMinSetting);
+ outState.putInt(MAG_SETTING, mMagSetting);
+ }
+
+ private void setMinSetting(final int item) {
+ mMinSetting = item;
+
+ mGLSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ final int filter;
+
+ if (item == 0) {
+ filter = GLES20.GL_NEAREST;
+ } else if (item == 1) {
+ filter = GLES20.GL_LINEAR;
+ } else if (item == 2) {
+ filter = GLES20.GL_NEAREST_MIPMAP_NEAREST;
+ } else if (item == 3) {
+ filter = GLES20.GL_NEAREST_MIPMAP_LINEAR;
+ } else if (item == 4) {
+ filter = GLES20.GL_LINEAR_MIPMAP_NEAREST;
+ } else // if (item == 5)
+ {
+ filter = GLES20.GL_LINEAR_MIPMAP_LINEAR;
+ }
+
+ mRenderer.setMinFilter(filter);
+ }
+ });
+ }
+
+ private void setMagSetting(final int item) {
+ mMagSetting = item;
+
+ mGLSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ final int filter;
+
+ if (item == 0) {
+ filter = GLES20.GL_NEAREST;
+ } else // if (item == 1)
+ {
+ filter = GLES20.GL_LINEAR;
+ }
+
+ mRenderer.setMagFilter(filter);
+ }
+ });
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ Dialog dialog = null;
+
+ switch (id) {
+ case MIN_DIALOG: {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getText(R.string.lesson_six_set_min_filter_message));
+ builder.setItems(getResources().getStringArray(R.array.lesson_six_min_filter_types), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int item) {
+ setMinSetting(item);
+ }
+ });
+
+ dialog = builder.create();
+ }
+ break;
+ case MAG_DIALOG: {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getText(R.string.lesson_six_set_mag_filter_message));
+ builder.setItems(getResources().getStringArray(R.array.lesson_six_mag_filter_types), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int item) {
+ setMagSetting(item);
+ }
+ });
+
+ dialog = builder.create();
+ }
+ break;
+ default:
+ dialog = null;
+ }
+
+ return dialog;
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixGLSurfaceView.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixGLSurfaceView.java
new file mode 100644
index 0000000..81a7de4
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixGLSurfaceView.java
@@ -0,0 +1,50 @@
+package com.learnopengles.android.lesson6;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class LessonSixGLSurfaceView extends GLSurfaceView {
+
+ private Action mRenderer;
+
+ private float mPreviousX;
+ private float mPreviousY;
+ private float mDensity;
+
+ public LessonSixGLSurfaceView(Context context) {
+ super(context);
+ }
+
+ public LessonSixGLSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event != null) {
+ float x = event.getX();
+ float y = event.getY();
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (mRenderer != null) {
+ float deltaX = (x - mPreviousX) / mDensity / 2;
+ float deltaY = (y - mPreviousY) / mDensity / 2;
+ mRenderer.setDelta(deltaX, deltaY);
+ }
+ }
+ mPreviousX = x;
+ mPreviousY = y;
+ return true;
+ }
+
+ return super.onTouchEvent(event);
+ }
+
+ // Hides superclass method.
+ public void setRenderer(GLSurfaceView.Renderer renderer, float density) {
+ mRenderer = (Action) renderer;
+ mDensity = density;
+ super.setRenderer(renderer);
+ }
+}
\ No newline at end of file
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixNativeRenderer.java
new file mode 100644
index 0000000..e0974a1
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixNativeRenderer.java
@@ -0,0 +1,66 @@
+package com.learnopengles.android.lesson6;
+
+import android.app.Activity;
+import android.content.res.AssetManager;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+@RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
+public class LessonSixNativeRenderer implements GLSurfaceView.Renderer, Action {
+
+ private Activity mActivity;
+
+ public LessonSixNativeRenderer(Activity activity) {
+ mActivity = activity;
+ }
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public static native void nativeSurfaceCreate(AssetManager assetManager);
+
+ public static native void nativeSurfaceChange(int width, int height);
+
+ public static native void nativeDrawFrame();
+
+ public static native void nativeSetDelta(float x, float y);
+
+ public static native void nativeSetMinFilter(int filter);
+
+ public static native void nativeSetMagFilter(int filter);
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate(mActivity.getAssets());
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+
+ @Override
+ public void setMinFilter(int filter) {
+ nativeSetMinFilter(filter);
+ }
+
+ @Override
+ public void setMagFilter(int filter) {
+ nativeSetMagFilter(filter);
+ }
+
+ @Override
+ public void setDelta(float deltaX, float deltaY) {
+ nativeSetDelta(deltaX, deltaY);
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/Action.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/Action.java
new file mode 100644
index 0000000..09a7f76
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/Action.java
@@ -0,0 +1,11 @@
+package com.learnopengles.android.lesson7;
+
+interface Action {
+ void init();
+ void destroy();
+ void setDelta(float deltaX, float deltaY);
+ void decreaseCubeCount();
+ void increaseCubeCount();
+ void toggleVBOs();
+ void toggleStride();
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenActivity.java
new file mode 100644
index 0000000..831af07
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenActivity.java
@@ -0,0 +1,162 @@
+package com.learnopengles.android.lesson7;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.widget.Button;
+
+import com.learnopengles.android.cpp.R;
+
+
+public class LessonSevenActivity extends Activity {
+
+ private LessonSevenGLSurfaceView mGlSurfaceView;
+ private Action mRender;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.lesson_seven);
+
+ mGlSurfaceView = (LessonSevenGLSurfaceView) findViewById(R.id.gl_surface_view);
+
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context
+ mGlSurfaceView.setEGLContextClientVersion(2);
+
+ final DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+
+ // Set the renderer to out demo renderer, define now
+ mRender = new LessonSevenNativeRenderer(this, mGlSurfaceView);
+ mRender.init();
+ mGlSurfaceView.setRenderer((GLSurfaceView.Renderer) mRender, displayMetrics.density);
+ } else {
+ return;
+ }
+
+ findViewById(R.id.button_decrease_num_cubes).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ decreaseCubeCount();
+ }
+ });
+
+ findViewById(R.id.button_increase_num_cubes).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ increaseCubeCount();
+ }
+ });
+
+ findViewById(R.id.button_switch_VBOs).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleVBOs();
+ }
+ });
+
+ findViewById(R.id.button_switch_stride).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleStride();
+ }
+ });
+ }
+
+ @Override
+ protected void onResume() {
+ // The activity must call the GL surface view's onResume() on activity
+ // onResume().
+ super.onResume();
+ mGlSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // The activity must call the GL surface view's onPause() on activity
+ // onPause().
+ super.onPause();
+ mGlSurfaceView.onPause();
+ }
+
+ private void decreaseCubeCount() {
+ mGlSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ mRender.decreaseCubeCount();
+ }
+ });
+ }
+
+ private void increaseCubeCount() {
+ mGlSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ mRender.increaseCubeCount();
+ }
+ });
+ }
+
+ private void toggleVBOs() {
+ mGlSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ mRender.toggleVBOs();
+ }
+ });
+ }
+
+ protected void toggleStride() {
+ mGlSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ mRender.toggleStride();
+ }
+ });
+ }
+
+ public void updateVboStatus(final boolean usingVbos) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (usingVbos) {
+ ((Button) findViewById(R.id.button_switch_VBOs)).setText(R.string.lesson_seven_using_VBOs);
+ } else {
+ ((Button) findViewById(R.id.button_switch_VBOs)).setText(R.string.lesson_seven_not_using_VBOs);
+ }
+ }
+ });
+ }
+
+ public void updateStrideStatus(final boolean useStride) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (useStride) {
+ ((Button) findViewById(R.id.button_switch_stride)).setText(R.string.lesson_seven_using_stride);
+ } else {
+ ((Button) findViewById(R.id.button_switch_stride)).setText(R.string.lesson_seven_not_using_stride);
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mRender.destroy();
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenGLSurfaceView.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenGLSurfaceView.java
new file mode 100644
index 0000000..6d711b5
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenGLSurfaceView.java
@@ -0,0 +1,57 @@
+package com.learnopengles.android.lesson7;
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class LessonSevenGLSurfaceView extends GLSurfaceView {
+
+ private Action mRender;
+
+ // Offsets for touch events
+ private float mPreviousX;
+ private float mPreviousY;
+
+ private float mDensity;
+
+ public LessonSevenGLSurfaceView(Context context) {
+ super(context);
+ }
+
+ public LessonSevenGLSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event != null) {
+ float x = event.getX();
+ float y = event.getY();
+
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (mRender != null) {
+ float deltaX = (x - mPreviousX) / mDensity / 2f;
+ float deltaY = (y - mPreviousY) / mDensity / 2f;
+ mRender.setDelta(deltaX, deltaY);
+
+ }
+ }
+
+ mPreviousX = x;
+ mPreviousY = y;
+
+ return true;
+ } else {
+ return super.onTouchEvent(event);
+ }
+ }
+
+ // Hides superclass method.
+ public void setRenderer(Renderer renderer, float density) {
+ mRender = (Action) renderer;
+ mDensity = density;
+ super.setRenderer(renderer);
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenNativeRenderer.java
new file mode 100644
index 0000000..fbc9678
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenNativeRenderer.java
@@ -0,0 +1,102 @@
+package com.learnopengles.android.lesson7;
+
+import android.content.res.AssetManager;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonSevenNativeRenderer implements GLSurfaceView.Renderer, Action {
+
+ private LessonSevenActivity mActivity;
+ private GLSurfaceView mGlSurfaceView;
+
+ public LessonSevenNativeRenderer(LessonSevenActivity activity, GLSurfaceView glSurfaceView) {
+ mActivity = activity;
+ mGlSurfaceView = glSurfaceView;
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate(mActivity.getAssets());
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+
+ @Override
+ public void init() {
+ nativeInit();
+ }
+
+ @Override
+ public void destroy() {
+ nativeDestroy();
+ }
+
+ @Override
+ public void setDelta(float deltaX, float deltaY) {
+ nativeSetDelta(deltaX, deltaY);
+ }
+
+ @Override
+ public void decreaseCubeCount() {
+ nativeDecreaseCubeCount();
+ }
+
+ @Override
+ public void increaseCubeCount() {
+ nativeIncreaseCubeCount();
+ }
+
+ @Override
+ public void toggleVBOs() {
+ nativeToggleVBOs();
+ }
+
+ @Override
+ public void toggleStride() {
+ nativeToggleStride();
+ }
+
+ {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public void updateVboStatus(boolean useVbos) {
+ mActivity.updateVboStatus(useVbos);
+ }
+
+ public void updateStrideStatus(boolean useStride) {
+ mActivity.updateStrideStatus(useStride);
+ }
+
+ public native void nativeInit();
+
+ public native void nativeDestroy();
+
+ public native void nativeSurfaceCreate(AssetManager assetManager);
+
+ public native void nativeSurfaceChange(int width, int height);
+
+ public native void nativeDrawFrame();
+
+ public native void nativeSetDelta(float x, float y);
+
+ public native void nativeDecreaseCubeCount();
+
+ public native void nativeIncreaseCubeCount();
+
+ public native void nativeToggleVBOs();
+
+ public native void nativeToggleStride();
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/Action.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/Action.java
new file mode 100644
index 0000000..9be7df8
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/Action.java
@@ -0,0 +1,5 @@
+package com.learnopengles.android.lesson8;
+
+interface Action {
+ void setDelta(float deltaX, float deltaY);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightActivity.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightActivity.java
new file mode 100644
index 0000000..f534a86
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightActivity.java
@@ -0,0 +1,61 @@
+package com.learnopengles.android.lesson8;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.DisplayMetrics;
+
+public class LessonEightActivity extends Activity {
+
+ private LessonEightGLSurfaceView mGlSurfaceView;
+ private Action mRender;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mGlSurfaceView = new LessonEightGLSurfaceView(this);
+ setContentView(mGlSurfaceView);
+ // Check if the system support OpenGL ES 2.0
+ final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
+
+ if (supportsEs2) {
+ // Request an OpenGL ES 2.0 compatible context.
+ mGlSurfaceView.setEGLContextClientVersion(2);
+
+ final DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+
+ // Set the renderer to our demo renderer, defined below.
+ mRender = (Action) new LessonEightNativeRenderer(this);
+ mGlSurfaceView.setRenderer((GLSurfaceView.Renderer) mRender, displayMetrics.density);
+ } else {
+ // This is where you could create an OpenGL ES 1.x compatible
+ // renderer if you wanted to support both ES 1 and ES 2
+ return;
+ }
+
+ }
+
+ @Override
+ protected void onResume() {
+ // The activity must call the GL surface view's onResume() on activity
+ // onResume().
+ super.onResume();
+ mGlSurfaceView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // The activity must call the GL surface view's onPause() on activity
+ // onPause().
+ super.onPause();
+ mGlSurfaceView.onPause();
+ }
+
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightGLSurfaceView.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightGLSurfaceView.java
new file mode 100644
index 0000000..b825725
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightGLSurfaceView.java
@@ -0,0 +1,57 @@
+package com.learnopengles.android.lesson8;
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class LessonEightGLSurfaceView extends GLSurfaceView {
+
+ private Action mRender;
+
+ // Offsets for touch events
+ private float mPreviousX;
+ private float mPreviousY;
+
+ private float mDensity;
+
+ public LessonEightGLSurfaceView(Context context) {
+ super(context);
+ }
+
+ public LessonEightGLSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event != null) {
+ float x = event.getX();
+ float y = event.getY();
+
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (mRender != null) {
+ float deltaX = (x - mPreviousX) / mDensity / 2f;
+ float deltaY = (y - mPreviousY) / mDensity / 2f;
+ mRender.setDelta(deltaX, deltaY);
+
+ }
+ }
+
+ mPreviousX = x;
+ mPreviousY = y;
+
+ return true;
+ } else {
+ return super.onTouchEvent(event);
+ }
+ }
+
+ // Hides superclass method.
+ public void setRenderer(Renderer renderer, float density) {
+ mRender = (Action) renderer;
+ mDensity = density;
+ super.setRenderer(renderer);
+ }
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightNativeRenderer.java b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightNativeRenderer.java
new file mode 100644
index 0000000..e931671
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightNativeRenderer.java
@@ -0,0 +1,49 @@
+package com.learnopengles.android.lesson8;
+
+import android.app.Activity;
+import android.content.res.AssetManager;
+import android.opengl.GLSurfaceView;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class LessonEightNativeRenderer implements GLSurfaceView.Renderer, Action {
+
+ private Activity mActivity;
+
+ static {
+ System.loadLibrary("lesson-lib");
+ }
+
+ public LessonEightNativeRenderer(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeSurfaceCreate(mActivity.getAssets());
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ nativeSurfaceChange(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ nativeDrawFrame();
+ }
+
+ @Override
+ public void setDelta(float deltaX, float deltaY) {
+ nativeSetDelta(deltaX, deltaY);
+ }
+
+ public native void nativeSurfaceCreate(AssetManager assetManager);
+
+ public native void nativeSurfaceChange(int width, int height);
+
+ public native void nativeDrawFrame();
+
+ public native void nativeSetDelta(float x, float y);
+}
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_seven.xml b/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_seven.xml
new file mode 100644
index 0000000..efef8e7
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_seven.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_six.xml b/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_six.xml
new file mode 100644
index 0000000..2a059e8
--- /dev/null
+++ b/android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_six.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/AndroidOpenGLESLessonsCpp/build.gradle b/android/AndroidOpenGLESLessonsCpp/build.gradle
index 97e8b8e..97d43c4 100644
--- a/android/AndroidOpenGLESLessonsCpp/build.gradle
+++ b/android/AndroidOpenGLESLessonsCpp/build.gradle
@@ -2,14 +2,16 @@
buildscript {
repositories {
jcenter()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.0'
+ classpath 'com.android.tools.build:gradle:3.0.1'
}
}
allprojects {
repositories {
jcenter()
+ google()
}
}
diff --git a/android/AndroidOpenGLESLessonsCpp/gradle/wrapper/gradle-wrapper.properties b/android/AndroidOpenGLESLessonsCpp/gradle/wrapper/gradle-wrapper.properties
index 8ff3745..4c6ddfa 100644
--- a/android/AndroidOpenGLESLessonsCpp/gradle/wrapper/gradle-wrapper.properties
+++ b/android/AndroidOpenGLESLessonsCpp/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Mar 12 15:47:53 EET 2017
+#Fri Jan 19 18:54:49 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip