C++
Файл texture_buffer_shader.cpp
bool ShaderOpenGL::Create()
{
...
const char* fragmentShaderStr = R"(
precision mediump float;
varying vec2 TexCoord;
uniform sampler2D textureGood;
void main()
{
gl_FragColor = texture2D(textureGood, TexCoord);
if ( (gl_FragColor.x > 0.95 && gl_FragColor.x<=1.0) && (gl_FragColor.y > 0.95 && gl_FragColor.y<=1.0) && (gl_FragColor.z > 0.95 && gl_FragColor.z<=1.0) )
{
gl_FragColor.a = 0.0; // fully transparent
}
}
)";
...
}
C++
Файл my_game.cpp
bool MyGame::InitGraphic_OpenGL(ANativeWindow* pWindow)
{
// init Display
m_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(m_Display, nullptr, nullptr);
// init Surface
CreateSurfaceFromWindow_OpenGL(pWindow);
// init Context
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,EGL_NONE };
m_Context = eglCreateContext(m_Display, m_configOpenGL, NULL, contextAttribs);
if (!MakeCurrent_Display_Surface_Context_OpenGL())
return false;
EGLint w, h;
eglQuerySurface(m_Display, m_Surface, EGL_WIDTH, &w);
eglQuerySurface(m_Display, m_Surface, EGL_HEIGHT, &h);
m_Width = w;
m_Height = h;
// Open GL states
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// for alpha color (transparency)
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// create shader (for drawing vertex very fast)
m_ShaderOpenGL.Create();
...
}
C++
Файл texture_buffer_shader.cpp
#include <android/native_window.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <android/asset_manager.h>
#include "texture_buffer_shader.h"
#include <string>
#include "texture_buffer_shader.h"
#include <unistd.h>
bool WaitOpenGlStatus(int goodOpenGlStatus, int waitSeonds)
{
timespec timeNow1;
clock_gettime(CLOCK_MONOTONIC, &timeNow1);
while (true)
{
if (glGetError()==goodOpenGlStatus)
return true;
sleep(1); // sleep 1 second
timespec timeNow2;
clock_gettime(CLOCK_MONOTONIC, &timeNow2);
if ((timeNow2.tv_sec- timeNow1.tv_sec)>waitSeonds)
return false;
};
}
/////////// class TextureImageOpenGL //////////////
TextureImageOpenGL::TextureImageOpenGL()
{
m_TextureId = 0;
}
TextureImageOpenGL::~TextureImageOpenGL()
{
}
bool TextureImageOpenGL::Create(AAssetManager* pAssetManager, const char* filename, GLuint imgFormat)
{
m_TextureId = 0;
int fileSize = 0;
void* pFileData = LoadImageFromAssets(pAssetManager, filename, &fileSize);
int width = 0;
int height = 0;
int dataOffset = 0;
GetBmpWidthHeight(pFileData, fileSize, &width, &height, &dataOffset);
void* pColorData = (char*)pFileData + dataOffset;
Swap24BitColors(pColorData, fileSize-dataOffset);
Bmp24BitUpDownLines(pColorData, width, height);
GLuint textureID = 0;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, imgFormat, width, height, 0, imgFormat, GL_UNSIGNED_BYTE, pColorData);
if (WaitOpenGlStatus(GL_NO_ERROR, 5 /*seconds to finish wait*/))
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
}
else // error
{
textureID = 0;
return false;
}
if (pFileData!= nullptr)
delete[] ((char*)pFileData);
glBindTexture(GL_TEXTURE_2D, 0);
m_TextureId = textureID;
return true;
}
int32_t TextureImageOpenGL::GetTextureId()
{
return m_TextureId;
}
void* TextureImageOpenGL::LoadImageFromAssets(AAssetManager* pAssetManager, const char* filename, int* pFileSize)
{
*pFileSize = 0;
int readBytesCount = 0;
char* buffer = nullptr;
// open file
AAsset* pAsset = AAssetManager_open(pAssetManager, filename, AASSET_MODE_UNKNOWN);
if (pAsset== nullptr)
return nullptr;
int fileSize = AAsset_getLength64(pAsset);
if (fileSize==0)
return nullptr;
*pFileSize = fileSize;
buffer = new char [fileSize];
if (buffer== nullptr)
return nullptr;
// read file
readBytesCount = AAsset_read(pAsset, buffer, fileSize);
AAsset_close(pAsset);
if (readBytesCount==fileSize) // good
return buffer;
delete[] buffer;
return nullptr;
}
void TextureImageOpenGL::Swap24BitColors(void* pColorData, int count)
{
unsigned char* pBuffer = (unsigned char*)pColorData;
for (int i=0; i<(count-2); i+=3)
std::swap(pBuffer[i], pBuffer[i+2]);
}
void TextureImageOpenGL::Bmp24BitUpDownLines(void* pColorData, int width, int height)
{
int bytesCountPerColor = 3;
const int bytesCountFor1Line = width * bytesCountPerColor;
char* pData =(char*) pColorData;
char* pLine = new char[bytesCountFor1Line];
int iBottom = 0;
for (int iTop=0; iTop< height / 2; iTop++)
{
iBottom = height-1 - iTop;
memcpy(pLine, pData+(iTop*bytesCountFor1Line), bytesCountFor1Line);
memcpy(pData+(iTop*bytesCountFor1Line), pData+(iBottom*bytesCountFor1Line), bytesCountFor1Line);
memcpy(pData+(iBottom*bytesCountFor1Line), pLine, bytesCountFor1Line);
}
delete[] pLine;
}
void TextureImageOpenGL::GetBmpWidthHeight(void* pFileData, int count, int* pWidth, int* pHeight, int* pDataOffset)
{
const int DATA_OFFSET_OFFSET = 0x000A;
const int WIDTH_OFFSET = 0x0012;
const int HEIGHT_OFFSET = 0x0016;
*pWidth = *(int*)((char*)pFileData + WIDTH_OFFSET);
*pHeight = *(int*)((char*)pFileData + HEIGHT_OFFSET);
*pDataOffset = *(int*)((char*)pFileData + DATA_OFFSET_OFFSET);
}
//////////// class BufferPointsOpenGL to create 3d points in video card buffer ///////////////
BufferPointsOpenGL::BufferPointsOpenGL()
{
m_BufferId = 0;
m_PointsCount = 0;
m_PointsModeHowToDraw = 0;
}
BufferPointsOpenGL::~BufferPointsOpenGL()
{
}
bool BufferPointsOpenGL::Create(PosXYZ_TextureXY* pBuffer, int itemsCount, GLuint pointsModeHowToDraw)
{
m_BufferId = 0;
m_PointsCount = itemsCount;
m_PointsModeHowToDraw = pointsModeHowToDraw;
glGenBuffers(1, &m_BufferId);
glBindBuffer(GL_ARRAY_BUFFER, m_BufferId);
glBufferData(GL_ARRAY_BUFFER, sizeof(PosXYZ_TextureXY)*itemsCount, pBuffer, GL_STATIC_DRAW);
return true;
}
int32_t BufferPointsOpenGL::GetBufferId()
{
return m_BufferId;
}
GLuint BufferPointsOpenGL::GetPointsModeHowToDraw()
{
return m_PointsModeHowToDraw;
}
GLuint BufferPointsOpenGL::GetPointsCount()
{
return m_PointsCount;
}
//////////////////// class ShaderOpenGL ///////////////
ShaderOpenGL::ShaderOpenGL()
{
m_ShaderId = 0;
m_SHADER_TEXTURE_parameter_position_index = 0;
m_SHADER_TEXTURE_parameter_texture_index = 0;
}
ShaderOpenGL::~ShaderOpenGL()
{
Close();
}
bool ShaderOpenGL::Create()
{
m_ShaderId = 0;
const char* vertexShaderStr = R"(
attribute vec3 aPos;
attribute vec2 aTexCoord;
varying vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
gl_Position.x = gl_Position.x * 2.0 - 1.0; // I use x from [0, 1] in my files. This line converts x from [0, 1] -> openGL standard [-1, 1]
gl_Position.y = -(gl_Position.y * 2.0 - 1.0); // I use y from [0, 1] in my files. This line converts y from [0, 1] -> openGL standard [1, -1]
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
)";
const char* fragmentShaderStr = R"(
precision mediump float;
varying vec2 TexCoord;
uniform sampler2D textureGood;
void main()
{
gl_FragColor = texture2D(textureGood, TexCoord);
if ( (gl_FragColor.x > 0.95 && gl_FragColor.x<=1.0) && (gl_FragColor.y > 0.95 && gl_FragColor.y<=1.0) && (gl_FragColor.z > 0.95 && gl_FragColor.z<=1.0) )
{
gl_FragColor.a = 0.0; // fully transparent
}
}
)";
GLuint vertexShader;
GLuint fragmentShader;
GLint linked;
// Load the vertex/fragment shaders
vertexShader = LoadShader(vertexShaderStr, GL_VERTEX_SHADER);
fragmentShader = LoadShader(fragmentShaderStr, GL_FRAGMENT_SHADER);
// Create the program object
int32_t myGraphicObject = glCreateProgram();
if(myGraphicObject == 0)
{
return false;
}
// Attach shaders to program
glAttachShader(myGraphicObject, vertexShader);
glAttachShader(myGraphicObject, fragmentShader);
// Link the program
glLinkProgram(myGraphicObject);
m_SHADER_TEXTURE_parameter_position_index = glGetAttribLocation(myGraphicObject, "aPos");
m_SHADER_TEXTURE_parameter_texture_index = glGetAttribLocation(myGraphicObject, "aTexCoord");
// Check the link status
glGetProgramiv(myGraphicObject, GL_LINK_STATUS, &linked);
if(!linked)
{
GLint infoLen = 0;
glGetProgramiv(myGraphicObject, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = new char[infoLen];
glGetProgramInfoLog(myGraphicObject, infoLen, NULL, infoLog);
//LOG_WARN("Error linking program:\n%s\n", infoLog);
delete[] infoLog;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteProgram(myGraphicObject);
return false;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
m_ShaderId = myGraphicObject;
return true;
}
void ShaderOpenGL::Close()
{
if (m_ShaderId!=0)
{
glDeleteProgram(m_ShaderId);
m_ShaderId = 0;
}
}
GLuint ShaderOpenGL::LoadShader(const char *shaderSrc, GLenum type)
{
GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader(type);
if(shader != 0)
{
// Load the shader source
glShaderSource(shader, 1, &shaderSrc, NULL);
// Compile the shader
glCompileShader(shader);
// Check the compile status
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = new char[infoLen];
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
//LOG_WARN("Error compiling shader:\n%s\n", infoLog);
delete[] infoLog;
}
glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
void ShaderOpenGL::MakeActive()
{
// Use the program object
glUseProgram(m_ShaderId);
glEnableVertexAttribArray(m_SHADER_TEXTURE_parameter_position_index);
glEnableVertexAttribArray(m_SHADER_TEXTURE_parameter_texture_index);
}
void ShaderOpenGL::Disable()
{
glDisableVertexAttribArray(m_SHADER_TEXTURE_parameter_position_index);
glDisableVertexAttribArray(m_SHADER_TEXTURE_parameter_texture_index);
glUseProgram(0);
}
void ShaderOpenGL::Draw(TextureImageOpenGL& rTextureImageOpenGL, BufferPointsOpenGL& rBufferPointsOpenGL)
{
glBindTexture(GL_TEXTURE_2D, rTextureImageOpenGL.GetTextureId());
// data
glBindBuffer(GL_ARRAY_BUFFER, rBufferPointsOpenGL.GetBufferId());
// vertex pos and texture coord
glVertexAttribPointer(m_SHADER_TEXTURE_parameter_position_index,
3 /*fields with type float*/, // x,y,z
GL_FLOAT,
GL_FALSE,
sizeof(PosXYZ_TextureXY),
(GLvoid*)0
);
// texture
glVertexAttribPointer(m_SHADER_TEXTURE_parameter_texture_index,
2 /*fields with type float*/, // texture_x, texture_y
GL_FLOAT,
GL_FALSE,
sizeof(PosXYZ_TextureXY),
(GLvoid*)( sizeof(PosXYZ_TextureXY::x) + sizeof(PosXYZ_TextureXY::y) + sizeof(PosXYZ_TextureXY::z) )
);
// draw
glDrawArrays(rBufferPointsOpenGL.GetPointsModeHowToDraw(), 0, rBufferPointsOpenGL.GetPointsCount());
}
C++
Файл my_game.cpp
#include <android/native_window.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include "my_game.h"
MyGame::MyGame(AAssetManager* pAssetManager)
{
m_Width = 0;
m_Height = 0;
m_pAssetManager = pAssetManager;
}
void MyGame::OnActiveFocus()
{
}
void MyGame::OnLostFocus()
{
}
bool MyGame::OnHandleTouch(AInputEvent* pEvent)
{
return false; // event not handled
}
void MyGame::OnNextTick()
{
}
// open GL
void MyGame::DrawGraphic_OpenGL()
{
if (m_Display == EGL_NO_DISPLAY || m_Surface == EGL_NO_SURFACE || m_Context == EGL_NO_CONTEXT)
return;
// green color
glClearColor(0.72f, 0.87f, 0.55f, 1);
glClear(GL_COLOR_BUFFER_BIT);
m_ShaderOpenGL.MakeActive();
m_ShaderOpenGL.Draw(m_TextureImage_Hero, m_BufferPoints_Hero);
m_ShaderOpenGL.Draw(m_TextureImage_Ghost, m_BufferPoints_Ghost1);
m_ShaderOpenGL.Draw(m_TextureImage_Ghost, m_BufferPoints_Ghost2);
m_ShaderOpenGL.Disable();
eglSwapBuffers(m_Display, m_Surface);
}
void MyGame::CreateSurfaceFromWindow_OpenGL(ANativeWindow* pWindow)
{
const EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE};
EGLint format;
EGLint numConfigs;
eglChooseConfig(m_Display, attribs, &m_configOpenGL, 1, &numConfigs);
eglGetConfigAttrib(m_Display, m_configOpenGL, EGL_NATIVE_VISUAL_ID, &format);
m_Surface = eglCreateWindowSurface(m_Display, m_configOpenGL, pWindow, NULL);
}
void MyGame::KillSurface_OpenGL()
{
eglMakeCurrent(m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_Surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_Display, m_Surface);
m_Surface = EGL_NO_SURFACE;
}
}
bool MyGame::MakeCurrent_Display_Surface_Context_OpenGL()
{
if (eglMakeCurrent(m_Display, m_Surface, m_Surface, m_Context) == EGL_FALSE)
return false;
return true;
}
bool MyGame::InitGraphic_OpenGL(ANativeWindow* pWindow)
{
// init Display
m_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(m_Display, nullptr, nullptr);
// init Surface
CreateSurfaceFromWindow_OpenGL(pWindow);
// init Context
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,EGL_NONE };
m_Context = eglCreateContext(m_Display, m_configOpenGL, NULL, contextAttribs);
if (!MakeCurrent_Display_Surface_Context_OpenGL())
return false;
EGLint w, h;
eglQuerySurface(m_Display, m_Surface, EGL_WIDTH, &w);
eglQuerySurface(m_Display, m_Surface, EGL_HEIGHT, &h);
m_Width = w;
m_Height = h;
// Open GL states
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// for alpha color (transparency)
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// create shader (for drawing vertex very fast)
m_ShaderOpenGL.Create();
// load textures
m_TextureImage_Hero.Create(m_pAssetManager, "hero.bmp", GL_RGB); // my file from assets folder
m_TextureImage_Ghost.Create(m_pAssetManager, "ghost.bmp", GL_RGB); // my file from assets folder
// create display points and texture points
float z = 0;
PosXYZ_TextureXY* pBuffer = nullptr;
pBuffer = new PosXYZ_TextureXY[]{
{.x=0.0, .y=0.5, .z=z, .texture_x=0, .texture_y=0}, // left top
{.x=0.4, .y=0.5, .z=z, .texture_x=1, .texture_y=0}, // right top
{.x=0.0, .y=0.9, .z=z, .texture_x=0, .texture_y=1}, // left bottom
{.x=0.4, .y=0.9, .z=z, .texture_x=1, .texture_y=1} // right bottom
};
m_BufferPoints_Hero.Create(pBuffer, 4,GL_TRIANGLE_STRIP);
delete[] pBuffer;
pBuffer = new PosXYZ_TextureXY[]{
{.x=0.5, .y=0.2, .z=z, .texture_x=0, .texture_y=0}, // left top
{.x=0.7, .y=0.2, .z=z, .texture_x=1, .texture_y=0}, // right top
{.x=0.5, .y=0.4, .z=z, .texture_x=0, .texture_y=1}, // left bottom
{.x=0.7, .y=0.4, .z=z, .texture_x=1, .texture_y=1} // right bottom
};
m_BufferPoints_Ghost1.Create(pBuffer, 4,GL_TRIANGLE_STRIP);
delete[] pBuffer;
pBuffer = new PosXYZ_TextureXY[]{
{.x=0.8, .y=0.6, .z=z, .texture_x=0, .texture_y=0}, // left top
{.x=1, .y=0.6, .z=z, .texture_x=1, .texture_y=0}, // right top
{.x=0.8, .y=0.8, .z=z, .texture_x=0, .texture_y=1}, // left bottom
{.x=1, .y=0.8, .z=z, .texture_x=1, .texture_y=1} // right bottom
};
m_BufferPoints_Ghost2.Create(pBuffer, 4,GL_TRIANGLE_STRIP);
delete[] pBuffer;
return true;
}
void MyGame::CloseGraphic_OpenGL()
{
if (m_Display != EGL_NO_DISPLAY)
{
eglMakeCurrent(m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_Context != EGL_NO_CONTEXT) {
eglDestroyContext(m_Display, m_Context);
}
if (m_Surface != EGL_NO_SURFACE) {
eglDestroySurface(m_Display, m_Surface);
}
eglTerminate(m_Display);
}
m_Display = EGL_NO_DISPLAY;
m_Context = EGL_NO_CONTEXT;
m_Surface = EGL_NO_SURFACE;
m_ShaderOpenGL.Close();
}