void atInitialize_02_cube(void** ppAppData, const char* const args) { GLuint texture = 0; GLenum target; GLenum glerror; GLboolean isMipmapped; GLuint gnDecalFs, gnVs; GLsizeiptr offset; KTX_error_code ktxerror; CubeTextured* pData = (CubeTextured*)atMalloc(sizeof(CubeTextured), 0); atAssert(pData); atAssert(ppAppData); *ppAppData = pData; pData->bInitialized = GL_FALSE; pData->gnTexture = 0; ktxerror = ktxLoadTextureN(args, &texture, &target, NULL, &isMipmapped, &glerror, 0, NULL); if (KTX_SUCCESS == ktxerror) { if (target != GL_TEXTURE_2D) { /* Can only draw 2D textures */ glDeleteTextures(1, &texture); return; } if (isMipmapped) /* Enable bilinear mipmapping */ /* TO DO: application can consider inserting a key,value pair in the KTX * file that indicates what type of filtering to use. */ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); else glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); atAssert(GL_NO_ERROR == glGetError()); } else { char message[1024]; int maxchars = sizeof(message)/sizeof(char); int nchars; nchars = snprintf(message, maxchars, "Load of texture \"%s\" failed: %s.", args, ktxErrorString(ktxerror)); if (ktxerror == KTX_GL_ERROR) { maxchars -= nchars; nchars += snprintf(&message[nchars], maxchars, " GL error is %#x.", glerror); } atMessageBox(message, "Texture load failed", AT_MB_OK|AT_MB_ICONERROR); } /* By default dithering is enabled. Dithering does not provide visual improvement * in this sample so disable it to improve performance. */ glDisable(GL_DITHER); glEnable(GL_CULL_FACE); glClearColor(0.2f,0.3f,0.4f,1.0f); // Create a VAO and bind it. glGenVertexArrays(1, &pData->gnVao); glBindVertexArray(pData->gnVao); // Must have vertex data in buffer objects to use VAO's on ES3/GL Core glGenBuffers(1, &pData->gnVbo); glBindBuffer(GL_ARRAY_BUFFER, pData->gnVbo); // Must be done after the VAO is bound // Use the same buffer for vertex attributes and element indices. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pData->gnVbo); // Create the buffer data store. glBufferData(GL_ARRAY_BUFFER, sizeof(cube_face) + sizeof(cube_color) + sizeof(cube_texture) + sizeof(cube_normal) + sizeof(cube_index_buffer), NULL, GL_STATIC_DRAW); // Interleave data copying and attrib pointer setup so offset is only computed once. glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cube_face), cube_face); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(cube_face); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cube_color), cube_color); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(cube_color); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cube_texture), cube_texture); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(cube_texture); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cube_normal), cube_normal); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(cube_normal); pData->iIndicesOffset = offset; // Either of the following can be used to buffer the data. glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cube_index_buffer), cube_index_buffer); //glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, sizeof(cube_index_buffer), cube_index_buffer); if (makeShader(GL_VERTEX_SHADER, pszVs, &gnVs)) { if (makeShader(GL_FRAGMENT_SHADER, pszDecalFs, &gnDecalFs)) { if (makeProgram(gnVs, gnDecalFs, &pData->gnTexProg)) { pData->gulMvMatrixLocTP = glGetUniformLocation(pData->gnTexProg, "mvmatrix"); pData->gulPMatrixLocTP = glGetUniformLocation(pData->gnTexProg, "pmatrix"); pData->gulSamplerLocTP = glGetUniformLocation(pData->gnTexProg, "sampler"); glUseProgram(pData->gnTexProg); // We're using the default texture unit 0 glUniform1i(pData->gulSamplerLocTP, 0); } } glDeleteShader(gnVs); glDeleteShader(gnDecalFs); } atAssert(GL_NO_ERROR == glGetError()); pData->bInitialized = GL_TRUE; }
void atInitialize_01_draw_texture(void** ppAppData, const char* const szArgs, const char* const szBasePath) { GLint iCropRect[4] = {0, 0, 0, 0}; const GLchar* szExtensions = (const GLchar*)glGetString(GL_EXTENSIONS); const char* filename; GLuint texture = 0; GLenum target; GLboolean isMipmapped; GLboolean npotTexture; GLenum glerror; GLubyte* pKvData; GLuint kvDataLen; KTX_dimensions dimensions; KTX_error_code ktxerror; KTX_hash_table kvtable; GLint sign_s = 1, sign_t = 1; DrawTexture* pData = (DrawTexture*)atMalloc(sizeof(DrawTexture), 0); atAssert(pData); atAssert(ppAppData); *ppAppData = pData; pData->bInitialized = GL_FALSE; pData->gnTexture = 0; if (strstr(szExtensions, "OES_draw_texture") != NULL) { pData->glDrawTexsOES = (PFNGLDRAWTEXSOESPROC)SDL_GL_GetProcAddress("glDrawTexsOES"); pData->glDrawTexiOES = (PFNGLDRAWTEXIOESPROC)SDL_GL_GetProcAddress("glDrawTexiOES"); pData->glDrawTexxOES = (PFNGLDRAWTEXXOESPROC)SDL_GL_GetProcAddress("glDrawTexxOES"); pData->glDrawTexfOES = (PFNGLDRAWTEXFOESPROC)SDL_GL_GetProcAddress("glDrawTexfOES"); pData->glDrawTexsvOES = (PFNGLDRAWTEXSVOESPROC)SDL_GL_GetProcAddress("glDrawTexsvOES"); pData->glDrawTexivOES = (PFNGLDRAWTEXIVOESPROC)SDL_GL_GetProcAddress("glDrawTexivOES"); pData->glDrawTexxvOES = (PFNGLDRAWTEXXVOESPROC)SDL_GL_GetProcAddress("glDrawTexxvOES"); pData->glDrawTexfvOES = (PFNGLDRAWTEXFVOESPROC)SDL_GL_GetProcAddress("glDrawTexfvOES"); } else { /* Can't do anything */ atMessageBox("This OpenGL ES implementation does not support " "OES_draw_texture.", "Can't Run Test", AT_MB_OK|AT_MB_ICONERROR); return; } if (strstr(szExtensions, "OES_texture_npot") != NULL) pData->bNpotSupported = GL_TRUE; else pData->bNpotSupported = GL_FALSE; if ((filename = strchr(szArgs, ' ')) != NULL) { if (!strncmp(szArgs, "--npot ", 7)) { npotTexture = GL_TRUE; #if defined(DEBUG) } else { assert(0); /* Unknown argument in sampleInvocations */ #endif } } else { filename = szArgs; npotTexture = GL_FALSE; } if (npotTexture && !pData->bNpotSupported) { /* Load error texture. */ filename = "testimages/no-npot.ktx"; } filename = atStrCat(szBasePath, filename); if (filename != NULL) { ktxerror = ktxLoadTextureN(filename, &pData->gnTexture, &target, &dimensions, &isMipmapped, &glerror, &kvDataLen, &pKvData); if (KTX_SUCCESS == ktxerror) { if (target != GL_TEXTURE_2D) { /* Can only draw 2D textures */ glDeleteTextures(1, &pData->gnTexture); return; } ktxerror = ktxHashTable_Deserialize(kvDataLen, pKvData, &kvtable); if (KTX_SUCCESS == ktxerror) { GLchar* pValue; GLuint valueLen; if (KTX_SUCCESS == ktxHashTable_FindValue(kvtable, KTX_ORIENTATION_KEY, &valueLen, (void*)&pValue)) { char s, t; if (sscanf(pValue, /*valueLen,*/ KTX_ORIENTATION2_FMT, &s, &t) == 2) { if (s == 'l') sign_s = -1; if (t == 'd') sign_t = -1; } } ktxHashTable_Destroy(kvtable); free(pKvData); } iCropRect[2] = pData->iTexWidth = dimensions.width; iCropRect[3] = pData->iTexHeight = dimensions.height; iCropRect[2] *= sign_s; iCropRect[3] *= sign_t; glEnable(target); if (isMipmapped) /* Enable bilinear mipmapping */ /* TO DO: application can consider inserting a key,value pair in the KTX * that indicates what type of filtering to use. */ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); else glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexParameteriv(target, GL_TEXTURE_CROP_RECT_OES, iCropRect); /* Check for any errors */ glerror = glGetError(); } else { char message[1024]; int maxchars = sizeof(message)/sizeof(char); int nchars; nchars = snprintf(message, maxchars, "Load of texture \"%s\" failed: ", filename); maxchars -= nchars; if (ktxerror == KTX_GL_ERROR) { nchars += snprintf(&message[nchars], maxchars, "GL error %#x occurred.", glerror); } else { nchars += snprintf(&message[nchars], maxchars, "%s.", ktxErrorString(ktxerror)); } atMessageBox(message, "Texture load failed", AT_MB_OK | AT_MB_ICONERROR); pData->iTexWidth = pData->iTexHeight = 50; pData->gnTexture = 0; } atFree((void*)filename, NULL); } /* else Out of memory. In which case, a message box is unlikely to work. */ glClearColor(0.4f, 0.4f, 0.5f, 1.0f); glColor4f(1.0f, 1.0f, 0.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_BYTE, 0, (GLvoid *)frame_position); pData->bInitialized = GL_TRUE; }
void atInitialize_01_draw_texture(void** ppAppData, const char* const szArgs, const char* const szBasePath) { const char* filename; GLfloat* pfQuadTexCoords = quad_texture; GLfloat fTmpTexCoords[sizeof(quad_texture)/sizeof(GLfloat)]; GLuint texture = 0; GLenum target; GLboolean isMipmapped; GLenum glerror; GLubyte* pKvData; GLuint kvDataLen; GLint sign_s = 1, sign_t = 1; GLint i; GLuint gnColorFs, gnDecalFs, gnVs; GLsizeiptr offset; KTX_dimensions dimensions; KTX_error_code ktxerror; KTX_hash_table kvtable; DrawTexture* pData = (DrawTexture*)atMalloc(sizeof(DrawTexture), 0); atAssert(pData); atAssert(ppAppData); *ppAppData = pData; pData->bInitialized = GL_FALSE; pData->gnTexture = 0; filename = atStrCat(szBasePath, szArgs); if (filename != NULL) { ktxerror = ktxLoadTextureN(filename, &pData->gnTexture, &target, &dimensions, &isMipmapped, &glerror, &kvDataLen, &pKvData); if (KTX_SUCCESS == ktxerror) { ktxerror = ktxHashTable_Deserialize(kvDataLen, pKvData, &kvtable); if (KTX_SUCCESS == ktxerror) { GLchar* pValue; GLuint valueLen; if (KTX_SUCCESS == ktxHashTable_FindValue(kvtable, KTX_ORIENTATION_KEY, &valueLen, (void**)&pValue)) { char s, t; if (sscanf(pValue, /*valueLen,*/ KTX_ORIENTATION2_FMT, &s, &t) == 2) { if (s == 'l') sign_s = -1; if (t == 'd') sign_t = -1; } } ktxHashTable_Destroy(kvtable); free(pKvData); } if (sign_s < 0 || sign_t < 0) { // Transform the texture coordinates to get correct image orientation. int iNumCoords = sizeof(quad_texture) / sizeof(float); for (i = 0; i < iNumCoords; i++) { fTmpTexCoords[i] = quad_texture[i]; if (i & 1) { // odd, i.e. a y coordinate if (sign_t < 1) { fTmpTexCoords[i] = fTmpTexCoords[i] * -1 + 1; } } else { // an x coordinate if (sign_s < 1) { fTmpTexCoords[i] = fTmpTexCoords[i] * -1 + 1; } } } pfQuadTexCoords = fTmpTexCoords; } pData->iTexWidth = dimensions.width; pData->iTexHeight = dimensions.height; if (isMipmapped) /* Enable bilinear mipmapping */ /* TO DO: application can consider inserting a key,value pair in the KTX * that indicates what type of filtering to use. */ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); else glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); atAssert(GL_NO_ERROR == glGetError()); } else { char message[1024]; int maxchars = sizeof(message)/sizeof(char); int nchars; nchars = snprintf(message, maxchars, "Load of texture \"%s\" failed: ", filename); maxchars -= nchars; if (ktxerror == KTX_GL_ERROR) { nchars += snprintf(&message[nchars], maxchars, "GL error %#x occurred.", glerror); } else { nchars += snprintf(&message[nchars], maxchars, "%s.", ktxErrorString(ktxerror)); } atMessageBox(message, "Texture load failed", AT_MB_OK|AT_MB_ICONERROR); pData->iTexWidth = pData->iTexHeight = 50; pData->gnTexture = 0; } atFree((void*)filename, NULL); } /* else Out of memory. In which case, a message box is unlikely to work. */ glClearColor(0.4f, 0.4f, 0.5f, 1.0f); // Must have vertex data in buffer objects to use VAO's on ES3/GL Core glGenBuffers(1, &pData->gnVbo); glBindBuffer(GL_ARRAY_BUFFER, pData->gnVbo); // Create the buffer data store glBufferData(GL_ARRAY_BUFFER, sizeof(frame_position) + sizeof(frame_color) + sizeof(quad_position) + sizeof(quad_color) + sizeof(quad_texture), NULL, GL_STATIC_DRAW); glGenVertexArrays(2, pData->gnVaos); // Interleave data copying and attrib pointer setup so offset is only computed once. // Setup VAO and buffer the data for frame glBindVertexArray(pData->gnVaos[FRAME]); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(frame_position), frame_position); glVertexAttribPointer(0, 3, GL_BYTE, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(frame_position); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(frame_color), frame_color); glVertexAttribPointer(1, 3, GL_BYTE, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(frame_color); // Setup VAO for quad glBindVertexArray(pData->gnVaos[QUAD]); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(quad_position), quad_position); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(quad_position); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(quad_color), quad_color); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); offset += sizeof(quad_color); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(quad_texture), pfQuadTexCoords); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); glBindVertexArray(0); if (makeShader(GL_VERTEX_SHADER, pszVs, &gnVs)) { if (makeShader(GL_FRAGMENT_SHADER, pszColorFs, &gnColorFs)) { if (makeProgram(gnVs, gnColorFs, &pData->gnColProg)) { pData->gulMvMatrixLocCP = glGetUniformLocation(pData->gnColProg, "mvmatrix"); pData->gulPMatrixLocCP = glGetUniformLocation(pData->gnColProg, "pmatrix"); } } if (makeShader(GL_FRAGMENT_SHADER, pszDecalFs, &gnDecalFs)) { if (makeProgram(gnVs, gnDecalFs, &pData->gnTexProg)) { pData->gulMvMatrixLocTP = glGetUniformLocation(pData->gnTexProg, "mvmatrix"); pData->gulPMatrixLocTP = glGetUniformLocation(pData->gnTexProg, "pmatrix"); pData->gulSamplerLocTP = glGetUniformLocation(pData->gnTexProg, "sampler"); glUseProgram(pData->gnTexProg); // We're using the default texture unit 0 glUniform1i(pData->gulSamplerLocTP, 0); } } glDeleteShader(gnVs); glDeleteShader(gnColorFs); glDeleteShader(gnDecalFs); } // Set the quad's mv matrix to scale by the texture size. // With the pixel-mapping ortho projection set below, the texture will // be rendered at actual size just like DrawTex*OES. for (i = 0; i < 16; i++) { pData->fQuadMvMatrix[i] = atIdentity[i]; pData->fFrameMvMatrix[i] = atIdentity[i]; } pData->fQuadMvMatrix[0*4 + 0] = (float)pData->iTexWidth / 2; pData->fQuadMvMatrix[1*4 + 1] = (float)pData->iTexHeight / 2; atAssert(GL_NO_ERROR == glGetError()); pData->bInitialized = GL_TRUE; }