1. Add the texture image file
- Download this image.
- Open the Project pane from the left side of the IDE.
- Select the Project view.
- Navigate to app->src->main.
- Right click the main folder and select New->Directory.
- Name it assets and click OK.
- Drag and drop the image to the newly created assets directory and click OK.
- Return to the Android view.
2. Extract the texture image file
- Open the MainActivity.kt file.
- Add the following function:
private fun extractFiles() {
val fileNames = arrayOf("texture-wood.jpg")
val filesDir = filesDir.absolutePath
val assetManager = assets
for (fileName in fileNames) {
val file = File(filesDir, fileName)
if (!file.exists()) {
val bytes = assetManager.open(fileName).readBytes()
file.writeBytes(bytes)
}
}
}
- You will also need to add the following import statement:
import java.io.File
- Modify the onCreate function as follows:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
customGLSurfaceView = findViewById(R.id.customGLSurfaceView)
extractFiles()
}
3. Add the image loading library
- Download this file.
- Open the Project pane from the left side of the IDE.
- Select the Project view.
- Navigate to app->src->main.
- Drag and drop the stb_image.h file onto the cpp folder and click OK.
- Return to the Android view.
4. Load the texture image
- Open the main.cpp file.
- Add the following code at the top of the file:
#define STB_IMAGE_IMPLEMENTATION #import "stb_image.h" #include <string> #include <jni.h> #include <GLES3/gl31.h> /* code */
- Add the following global variables:
/* code */ glm::mat4 projectionMatrix; unsigned char *texture_image_data; int texture_image_width; int texture_image_height; int texture_image_depth; float currentAngle = 0.0f; /* code */
- Add the following function:
extern "C" JNIEXPORT void JNICALL Java_dev_anastasioscho_glestriangle_NativeLibrary_loadTextureImageFile(JNIEnv * env, jobject obj, jstring aFilesDir) {
const char *files_dir_UTF_chars = env->GetStringUTFChars(aFilesDir, NULL);
std::string files_dir(files_dir_UTF_chars);
env->ReleaseStringUTFChars(aFilesDir, files_dir_UTF_chars);
std::string texture_image_file_path = files_dir + "/texture-wood.jpg";
texture_image_data = stbi_load(texture_image_file_path.c_str(), &texture_image_width, &texture_image_height, &texture_image_depth, 0);
if (!texture_image_data) {
LOGE("Failed to load texture image file: %s", texture_image_file_path.c_str());
}
return;
}
- Open the NativeLibrary.kt file.
- Add the following lines of code:
/* code */ external fun nOnSurfaceChanged(width: Int, height: Int) external fun nOnDrawFrame() external fun loadTextureImageFile(aFilesDir: String) /* code */
- Open the MainActivity.kt file.
- Add the following property:
/* code */
class MainActivity: AppCompatActivity() {
private val nativeLibrary = NativeLibrary()
private lateinit var customGLSurfaceView: CustomGLSurfaceView
/* code */
}
- Modify the onCreate function as follows:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
customGLSurfaceView = findViewById(R.id.customGLSurfaceView)
extractFiles()
nativeLibrary.loadTextureImageFile(filesDir.absolutePath)
}
5. Create the texture
- Open the main.cpp file.
- Declare the following global variable:
/* code */ GLuint program, triangleVAO, triangleVBO, triangleIBO, texture; GLint uniformModel, uniformProjection, uniformView; glm::mat4 projectionMatrix; /* code */
- Modify the Java_dev_anastasioscho_glestriangle_NativeLibrary_nOnSurfaceCreated function as follows:
extern "C" JNIEXPORT void JNICALL Java_dev_anastasioscho_glestriangle_NativeLibrary_nOnSurfaceCreated(JNIEnv * env, jobject obj) {
glClearColor(0.0, 1.0, 0.0, 1.0);
glEnable(GL_DEPTH_TEST);
createProgram();
createTriangle();
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture_image_width, texture_image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image_data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(texture_image_data);
return;
}
6. Add the texture coordinates
- Modify the createTriangle function as follows:
void createTriangle() {
/* code */
GLfloat vertices[] = {
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.5f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f,
1.0f, -1.0f, -1.0f, 0.5f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.5f, 0.5f
};
/* code */
glGenBuffers(1, &triangleVBO);
glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
glBufferData(GL_ARRAY_BUFFER, 25 * sizeof(GL_FLOAT), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, (void*)(sizeof(GL_FLOAT) * 3));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* code */
}
7. Draw the texture
7.1. Modify the vertex shader
- Modify the vertex shader source code as follows:
static const GLchar vertexShaderSource[] =
"#version 310 es\n"
"layout (location = 0) in vec3 pos;\n"
"layout (location = 1) in vec2 texCoords;\n"
"out vec4 vColor;\n"
"out vec2 vTexCoords;\n"
"uniform mat4 model;\n"
"uniform mat4 projection;\n"
"uniform mat4 view;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(pos, 1.0);\n"
"vColor = vec4(clamp(pos, 0.0, 1.0), 1.0);\n"
"vTexCoords = texCoords;\n"
"}\n";
7.2 Modify the fragment shader
- Modify the fragment shader source code:
static const GLchar fragmentShaderSource[] =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 vColor;\n"
"in vec2 vTexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D textureSampler;\n"
"void main()\n"
"{\n"
"color = texture(textureSampler, vTexCoords);\n"
"}\n";
Info
You don’t need to set a value to the uniform variable because it already has a default value of 0. This means that the sampler will work with the GL_TEXTURE0 texture unit.
If for example you intend to use the GL_TEXTURE1 texture unit then you should set the uniform variable to 1.
7.3 Activate the texture
- Modify the Java_dev_anastasioscho_glestriangle_NativeLibrary_nOnDrawFrame function as follows:
extern "C" JNIEXPORT void JNICALL Java_dev_anastasioscho_glestriangle_NativeLibrary_nOnDrawFrame(JNIEnv * env, jobject obj) {
/* code */
glm::mat4 viewMatrix = glm::lookAt(cameraPosition, cameraTarget, worldUp);
glUniformMatrix4fv(uniformView, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
/* code */
return;
}
Leave a Reply