From 641fcc25158dc30f45a7b2faaab165ec61ebb54b Mon Sep 17 00:00:00 2001 From: biezhihua Date: Mon, 22 Jan 2018 21:09:42 +0800 Subject: [PATCH] Upgrade Grade & Lesson ndk implements (#11) * Upgrade Grade & Lesson two ndk implement * Lesson three ndk implement * Lesson four ndk implement * Lesson five ndk implements * Lesson six ndk implement * Lesson seven ndk implement * Lesson eight ndk implement --- .../app/CMakeLists.txt | 75 +- .../app/build.gradle | 14 +- .../app/src/main/AndroidManifest.xml | 36 +- .../per_pixel_fragment_shader_no_tex.glsl | 38 + .../per_pixel_vertex_shader_no_tex.glsl | 27 + .../app/src/main/cpp/graphics/GLUtils.cpp | 2 +- .../app/src/main/cpp/graphics/Matrix.cpp | 4 + .../app/src/main/cpp/graphics/Matrix.h | 12 + .../src/main/cpp/lesson2/Native2Lesson.cpp | 587 +++++++++++++++ .../app/src/main/cpp/lesson2/Native2Lesson.h | 58 ++ .../src/main/cpp/lesson3/Native3Lesson.cpp | 567 +++++++++++++++ .../app/src/main/cpp/lesson3/Native3Lesson.h | 55 ++ .../src/main/cpp/lesson4/Native4Lesson.cpp | 607 ++++++++++++++++ .../app/src/main/cpp/lesson4/Native4Lesson.h | 59 ++ .../src/main/cpp/lesson5/Native5Lesson.cpp | 315 ++++++++ .../app/src/main/cpp/lesson5/Native5Lesson.h | 58 ++ .../src/main/cpp/lesson6/Native6Lesson.cpp | 673 ++++++++++++++++++ .../app/src/main/cpp/lesson6/Native6Lesson.h | 87 +++ .../app/src/main/cpp/lesson7/Cubes.cpp | 95 +++ .../app/src/main/cpp/lesson7/Cubes.h | 79 ++ .../src/main/cpp/lesson7/CubesClientSide.cpp | 32 + .../src/main/cpp/lesson7/CubesClientSide.h | 30 + .../cpp/lesson7/CubesClientSideWithStride.cpp | 35 + .../cpp/lesson7/CubesClientSideWithStride.h | 33 + .../app/src/main/cpp/lesson7/CubesWithVbo.cpp | 37 + .../app/src/main/cpp/lesson7/CubesWithVbo.h | 72 ++ .../cpp/lesson7/CubesWithVboWithStride.cpp | 40 ++ .../main/cpp/lesson7/CubesWithVboWithStride.h | 47 ++ .../app/src/main/cpp/lesson7/GenData.cpp | 331 +++++++++ .../app/src/main/cpp/lesson7/GenData.h | 70 ++ .../src/main/cpp/lesson7/Native7Lesson.cpp | 432 +++++++++++ .../app/src/main/cpp/lesson7/Native7Lesson.h | 71 ++ .../app/src/main/cpp/lesson8/HeightMap.cpp | 193 +++++ .../app/src/main/cpp/lesson8/HeightMap.h | 69 ++ .../src/main/cpp/lesson8/Native8Lesson.cpp | 261 +++++++ .../app/src/main/cpp/lesson8/Native8Lesson.h | 118 +++ .../android/TableOfContents.java | 71 ++ .../java/com/learnopengles/android/Utils.java | 278 ++++++++ .../lesson1/LessonOneNativeRenderer.java | 2 + .../android/lesson2/LessonTwoActivity.java | 55 ++ .../lesson2/LessonTwoNativeRenderer.java | 35 + .../android/lesson3/LessonThreeActivity.java | 54 ++ .../lesson3/LessonThreeNativeRenderer.java | 35 + .../android/lesson4/LessonFourActivity.java | 54 ++ .../lesson4/LessonFourNativeRenderer.java | 44 ++ .../android/lesson5/BlendingMode.java | 5 + .../android/lesson5/LessonFiveActivity.java | 92 +++ .../lesson5/LessonFiveNativeRenderer.java | 50 ++ .../learnopengles/android/lesson6/Action.java | 9 + .../android/lesson6/LessonSixActivity.java | 195 +++++ .../lesson6/LessonSixGLSurfaceView.java | 50 ++ .../lesson6/LessonSixNativeRenderer.java | 66 ++ .../learnopengles/android/lesson7/Action.java | 11 + .../android/lesson7/LessonSevenActivity.java | 162 +++++ .../lesson7/LessonSevenGLSurfaceView.java | 57 ++ .../lesson7/LessonSevenNativeRenderer.java | 102 +++ .../learnopengles/android/lesson8/Action.java | 5 + .../android/lesson8/LessonEightActivity.java | 61 ++ .../lesson8/LessonEightGLSurfaceView.java | 57 ++ .../lesson8/LessonEightNativeRenderer.java | 49 ++ .../app/src/main/res/layout/lesson_seven.xml | 41 ++ .../app/src/main/res/layout/lesson_six.xml | 27 + .../AndroidOpenGLESLessonsCpp/build.gradle | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- 64 files changed, 6966 insertions(+), 28 deletions(-) create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/assets/fragment/per_pixel_fragment_shader_no_tex.glsl create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/assets/vertex/per_pixel_vertex_shader_no_tex.glsl create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson2/Native2Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson3/Native3Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson4/Native4Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson5/Native5Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson6/Native6Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Cubes.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSide.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesClientSideWithStride.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVbo.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/CubesWithVboWithStride.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/GenData.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson7/Native7Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/HeightMap.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.cpp create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/cpp/lesson8/Native8Lesson.h create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/Utils.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson2/LessonTwoNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson3/LessonThreeNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson4/LessonFourNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/BlendingMode.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson5/LessonFiveNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/Action.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixGLSurfaceView.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson6/LessonSixNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/Action.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenGLSurfaceView.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson7/LessonSevenNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/Action.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightActivity.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightGLSurfaceView.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/java/com/learnopengles/android/lesson8/LessonEightNativeRenderer.java create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_seven.xml create mode 100644 android/AndroidOpenGLESLessonsCpp/app/src/main/res/layout/lesson_six.xml 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 @@ + + + + +