// OpenGL + libpng sample. PNG image is in memory // // PNGファイルをOpenGLで扱う話 // https://proken.mydns.jp/index.php?plugin=attach&refer=pg_koneta%2FPNGInOpenGL&openfile=PNGInOpenGL.html // // 008 PNGテクスチャの読み込み [stepism] // https://stepism.sakura.ne.jp/wiki/doku.php?id=wiki:opengl:tips:008 #include #include #include #include // png image binary #include "texture.h" GLuint texture; int offset = 0; // Callback function for reading data in libpng void ReadEndProcess(png_structp _pPng, png_bytep _buf, png_size_t _size) { unsigned char* p = (unsigned char*)png_get_io_ptr(_pPng); memcpy(_buf, p + offset, _size); offset += _size; } /** * Load texture from png image on memory * * @param[in] _pngData png binary on memory * return GLuint OpenGL texture ID. if 0, process fails */ GLuint createTextureFromPngInMemory(const unsigned char* _pngData) { GLuint texture; png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int width, height; int depth, colorType, interlaceType; int rowSize; unsigned char *data; // PNG file ? if (png_sig_cmp(_pngData, 0, 8) != 0) { fprintf(stderr, "createTextureFromPngInMemory() : Not png file binary"); return 0; } // create png read struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { return 0; } // create png information struct info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // set read data callback function png_set_read_fn(png_ptr, (png_voidp)_pngData, ReadEndProcess); offset = 8; // If error, jump here if (setjmp(png_jmpbuf(png_ptr))) { // Release allocated memory png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 0; } // Skip identification area (8 bytes) in png files png_set_sig_bytes(png_ptr, 8); // Load image information // get width, height, bit depth, color type, interlace mode png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &depth, &colorType, &interlaceType, NULL, NULL); // support RGB/RGBA only if (colorType != PNG_COLOR_TYPE_RGB && colorType != PNG_COLOR_TYPE_RGBA) { fprintf(stderr, "createTextureFromPngInMemory() : Supprted color type are RGB/RGBA only."); png_destroy_info_struct(png_ptr, &info_ptr); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // not support interlace if (interlaceType != PNG_INTERLACE_NONE) { fprintf(stderr, "createTextureFromPngInMemory() : Interlace image is not supprted."); png_destroy_info_struct(png_ptr, &info_ptr); png_destroy_read_struct(&png_ptr, NULL, NULL); return 0; } // calc memory size rowSize = png_get_rowbytes(png_ptr, info_ptr); data = malloc(rowSize * height); // read pixel for (int i = 0; i < height; i++) { png_read_row(png_ptr, &data[i * rowSize], NULL); } png_read_end(png_ptr, info_ptr); // create OpenGL texture glGenTextures(1, &texture); // select texture glBindTexture(GL_TEXTURE_2D, texture); // set texture from PNG image glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // Release allocated all memory free(data); png_destroy_info_struct(png_ptr, &info_ptr); png_destroy_read_struct(&png_ptr, NULL, NULL); return texture; } // draw OpenGL void display() { glClear(GL_COLOR_BUFFER_BIT); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // enable texture glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); // draw polygon glBegin(GL_QUADS); GLfloat v = 0.85f; glTexCoord2f(0.0, 0.0); // set texture u, v glVertex2f(-v, v); glTexCoord2f(0.0, 1.0); glVertex2f(-v, -v); glTexCoord2f(1.0, 1.0); glVertex2f(v, -v); glTexCoord2f(1.0, 0.0); glVertex2f(v, v); glEnd(); // disable texture glDisable(GL_TEXTURE_2D); glFlush(); } // Keyboard callback function void keyboard(unsigned char key, int x, int y) { switch (key) { case '\x1B': case 'q': // Exit on escape or 'q' key press glutLeaveMainLoop(); // exit(EXIT_SUCCESS); break; } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutInitWindowSize(1280, 720); glutCreateWindow("OpenGL Texture Example"); // create OpenGL texture from PNG image texture = createTextureFromPngInMemory((void *)&texture_png); if (!texture) { fprintf(stderr, "Failed create texture\n"); exit(1); } glClearColor(0.2f, 0.4f, 0.8f, 1.0f); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glutKeyboardFunc(keyboard); glutDisplayFunc(display); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); glutMainLoop(); return EXIT_SUCCESS; }