• Skip to main content
  • Skip to primary sidebar

Anastasios Chondrogiannis

Software developer with a focus on iOS

Android OpenGL ES – Part 7: Textures

March 13, 2020 by Anastasios Chondrogiannis Leave a Comment

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;
}

8. References

  • https://www.pexels.com/search/texture/
  • https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html

Filed Under: Android Development

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

Let’s connect!

  • Facebook
  • Instagram
  • LinkedIn
  • Twitter

Recent Posts

  • Android OpenGL ES – Part 10: Specular lighting
  • Android OpenGL ES – Part 9: Diffuse lighting
  • Android OpenGL ES – Part 8: Ambient Lighting
  • Android OpenGL ES – Part 7: Textures
  • Android OpenGL ES – Part 6: Camera View

Archives

  • March 2020
  • February 2020
  • November 2019
  • October 2019
  • July 2019

Categories

  • Android Development
  • Machine Learning

Copyright © 2025 · Genesis Sample on Genesis Framework · WordPress · Log in