From cebb5fae9e40526f6d2abe8bf250807f9fb1a306 Mon Sep 17 00:00:00 2001 From: briangr Date: Mon, 7 Dec 2009 02:26:08 +0000 Subject: [PATCH] Added Jean-Phillipe image padding patch with minor fix git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@1951 30fe4595-0a0c-4342-8851-515496e4dcbd Former-commit-id: ec72f4d59380f7fdd7874e31093c7838e98dfa0a Former-commit-id: ce601058bc096c8174ea5a37c7e3bd78ffebb076 --- src/libs/client/splash.cpp | 2 +- src/libs/tgfclient/gui.cpp | 81 ++++++++++++++++++------- src/libs/tgfclient/gui.h | 3 +- src/libs/tgfclient/img.cpp | 64 +++++++++++++------ src/libs/tgfclient/tgfclient.h | 2 +- src/modules/graphic/ssggraph/grutil.cpp | 2 +- src/tools/trackgen/elevation.cpp | 2 +- src/tools/trackgen/objects.cpp | 2 +- 8 files changed, 110 insertions(+), 48 deletions(-) diff --git a/src/libs/client/splash.cpp b/src/libs/client/splash.cpp index b3d360b5..62d954ec 100644 --- a/src/libs/client/splash.cpp +++ b/src/libs/client/splash.cpp @@ -214,7 +214,7 @@ int SplashScreen(void) sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); - GLbyte *tex = (GLbyte*)GfImgReadPng(filename, &s_imgWidth, &s_imgHeight, screen_gamma); + GLbyte *tex = (GLbyte*)GfImgReadPng(filename, &s_imgWidth, &s_imgHeight, screen_gamma, 0, 0); if (!tex) { GfParmReleaseHandle(handle); diff --git a/src/libs/tgfclient/gui.cpp b/src/libs/tgfclient/gui.cpp index efda7fa7..b133da64 100644 --- a/src/libs/tgfclient/gui.cpp +++ b/src/libs/tgfclient/gui.cpp @@ -172,47 +172,74 @@ GfuiDisplay(void) if (GfuiScreen->bgColor.alpha != 0.0) { glClearColor(GfuiScreen->bgColor.red, - GfuiScreen->bgColor.green, - GfuiScreen->bgColor.blue, - GfuiScreen->bgColor.alpha); + GfuiScreen->bgColor.green, + GfuiScreen->bgColor.blue, + GfuiScreen->bgColor.alpha); glClear(GL_COLOR_BUFFER_BIT); } - if (GfuiScreen->bgImage != 0) { - GLfloat tx1 = 0.0f, tx2 = 1.0f, ty1 = 0.0f, ty2 = 1.0f; - - // All background images are 16:10 images which are stored as quadratic images. - // Compute texture coordinates to ensure proper unskewed/unstretched display of - // image content. - tdble rfactor = (16.0f*ViewH)/(10.0f*ViewW); + // Display backround image if any. + if (GfuiScreen->bgImage) { + + // Prepare texture display. + glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(GfuiColor[GFUI_BASECOLORBGIMAGE][0], + GfuiColor[GFUI_BASECOLORBGIMAGE][1], + GfuiColor[GFUI_BASECOLORBGIMAGE][2]); + glBindTexture(GL_TEXTURE_2D, GfuiScreen->bgImage); + + // Get real 2^N x 2^P texture size (may have been 0 padded at load time + // if the original image was not 2^N x 2^P) + // This 2^N x 2^P stuff is needed by some low-end OpenGL hardware/drivers. + int bgQuadWidth = 1, bgQuadHeight = 1; + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &bgQuadWidth); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &bgQuadHeight); + + // Compute the initial width of the right area and the height of the bottom area + // of the texture that will not be displayed + // (We display only the top left rectangle of the quad texture + // that corresponds to the original image). + GLfloat tx1 = 0.0f; + GLfloat tx2 = GfuiScreen->bgWidth / (GLfloat)bgQuadWidth; + + GLfloat ty1 = 1.0f-(GfuiScreen->bgHeight / (GLfloat)bgQuadHeight); + GLfloat ty2 = 1.0; + + // Compute the width/height of the symetrical left/right / top/bottom + // areas of original image that will need to be clipped + // in order to keep its aspect ratio. + const GLfloat rfactor = GfuiScreen->bgWidth * (GLfloat)ViewH + / GfuiScreen->bgHeight / (GLfloat)ViewW; + if (rfactor >= 1.0f) { - // Aspect ratio of view is smaller than 16:10, "cut off" sides - tdble tdx = (1.0f-1.0f/rfactor)/2.0f; + // If aspect ratio of view is smaller than image's one, "cut off" sides. + GLfloat tdx = (1.0f - 1.0f / rfactor) / 2.0f; tx1 += tdx; tx2 -= tdx; } else { - // Aspect ratio of view is larger than 16:10, "cut off" top and bottom - tdble tdy = (1.0f-rfactor)/2.0f; + // If aspect ratio of view is larger than image's one, + // "cut off" top and bottom. + GLfloat tdy = (1.0f - rfactor) / 2.0f; ty1 += tdy; ty2 -= tdy; } - glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glColor3f(GfuiColor[GFUI_BASECOLORBGIMAGE][0],GfuiColor[GFUI_BASECOLORBGIMAGE][1],GfuiColor[GFUI_BASECOLORBGIMAGE][2]); - glBindTexture(GL_TEXTURE_2D, GfuiScreen->bgImage); + // Display texture. glBegin(GL_QUADS); glTexCoord2f(tx1, ty1); glVertex3f(0.0, 0.0, 0.0); glTexCoord2f(tx1, ty2); glVertex3f(0.0, GfuiScreen->height, 0.0); glTexCoord2f(tx2, ty2); glVertex3f(GfuiScreen->width, GfuiScreen->height, 0.0); glTexCoord2f(tx2, ty1); glVertex3f(GfuiScreen->width, 0.0, 0.0); + glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); } + // Display other screen objects curObj = GfuiScreen->objects; if (curObj) { do { @@ -221,6 +248,7 @@ GfuiDisplay(void) } while (curObj != GfuiScreen->objects); } + // Display mouse cursor if needed/specified if (!GfuiMouseHW && GfuiMouseVisible && GfuiScreen->mouseAllowed) { GfuiDrawCursor(); } @@ -983,7 +1011,7 @@ GfuiScreenAddBgImg(void *scr, const char *filename) void *handle; float screen_gamma; GLbyte *tex; - int w,h; + int qw, qh; if (screen->bgImage != 0) { glDeleteTextures(1, &screen->bgImage); @@ -992,14 +1020,23 @@ GfuiScreenAddBgImg(void *scr, const char *filename) sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); handle = GfParmReadFile(buf, GFPARM_RMODE_STD); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); - tex = (GLbyte*)GfImgReadPng(filename, &w, &h, screen_gamma); + // Note: Here, we save the original image size (may be not 2^n x 2^p) + // in order to be able to hide padding pixels added in texture to enforce 2^n x 2^p. + tex = (GLbyte*)GfImgReadPng(filename, &screen->bgWidth, &screen->bgHeight, + screen_gamma, &qw, &qh); + if (!tex) { GfParmReleaseHandle(handle); return; } //Force Background image to power of 2 - GfScaleImagePowerof2((unsigned char*)tex,w,h,GL_RGBA,screen->bgImage); +// GfScaleImagePowerof2((unsigned char*)tex,w,h,GL_RGBA,screen->bgImage); + glGenTextures(1, &screen->bgImage); + glBindTexture(GL_TEXTURE_2D, screen->bgImage); + 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_RGBA, qw, qh, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)(tex)); free(tex); GfParmReleaseHandle(handle); diff --git a/src/libs/tgfclient/gui.h b/src/libs/tgfclient/gui.h index 667d8944..1b9ed2e3 100644 --- a/src/libs/tgfclient/gui.h +++ b/src/libs/tgfclient/gui.h @@ -239,7 +239,8 @@ typedef struct { float width, height; Color bgColor; /* RGBA */ - GLuint bgImage; + GLuint bgImage; /* Should always be 2^n x 2^p */ + int bgWidth, bgHeight; /* Original bg image size (may be not 2^n x 2^p) */ /* sub-objects */ tGfuiObject *objects; diff --git a/src/libs/tgfclient/img.cpp b/src/libs/tgfclient/img.cpp index 62f7dc31..1543f822 100644 --- a/src/libs/tgfclient/img.cpp +++ b/src/libs/tgfclient/img.cpp @@ -101,29 +101,32 @@ GfScaleImagePowerof2(unsigned char *pSrcImg,int srcW,int srcH,GLenum format,GLui } /** Load an image from disk to a buffer in RGBA mode. - @ingroup img +=======/** Load an image from disk to a buffer in RGBA mode (if specified, enforce 2^N x 2^P size for the target buffer, to suit with low-end OpenGL hardwares/drivers poor texture support). +>>>>>>> .theirs @ingroup img @param filename name of the image to load - @param widthp width of the read image - @param heightp height of the read image + @param widthp original width of the read image (left aligned in target buffer) + @param heightp original height of the read image (top aligned in target buffer) @param screen_gamma gamma correction value + @param quad_widthp if not 0, pointer to 2^N width of the target image buffer + @param quad_heightp if not 0, pointer to 2^N height of the target image buffer @return Pointer on the buffer containing the image
NULL Error */ unsigned char * -GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma) +GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma, int *quad_widthp, int *quad_heightp) { unsigned char buf[PNG_BYTES_TO_CHECK]; FILE *fp; - png_structp png_ptr; + png_structp png_ptr; png_infop info_ptr; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; + png_uint_32 src_width, src_height; + png_uint_32 tgt_width, tgt_height; + int bit_depth, color_type, interlace_type; - /* png_color_16p image_background; */ double gamma; png_bytep *row_pointers; unsigned char *image_ptr, *cur_ptr; - png_uint_32 rowbytes; + png_uint_32 src_rowbytes, tgt_rowbytes; png_uint_32 i; if ((fp = fopen(filename, "rb")) == NULL) { @@ -169,10 +172,28 @@ GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); - *widthp = (int)width; - *heightp = (int)height; + png_get_IHDR(png_ptr, info_ptr, &src_width, &src_height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + *widthp = (int)src_width; + *heightp = (int)src_height; + // Compute target quad image buffer size if specified. + // Note: This 2^N x 2^P stuff is needed by some low-end OpenGL hardware/drivers + // that don't support non 2^N x 2^P textures (or at extremely low frame rates). + if (quad_widthp && quad_heightp) { + tgt_width = 2; + tgt_height = 2; + while(tgt_width < src_width) + tgt_width *= 2; + //tgt_height = tgt_width; + while(tgt_height < src_height) + tgt_height *= 2; + *quad_widthp = (int)tgt_width; + *quad_heightp = (int)tgt_height; + } else { + tgt_width = (int)src_width; + tgt_height = (int)src_height; + } + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) png_set_invert_mono(png_ptr); if (bit_depth == 16) { png_set_swap(png_ptr); @@ -210,35 +231,39 @@ GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma } png_read_update_info(png_ptr, info_ptr); - rowbytes = png_get_rowbytes(png_ptr, info_ptr); + src_rowbytes = png_get_rowbytes(png_ptr, info_ptr); + tgt_rowbytes = src_rowbytes; + if (quad_widthp && quad_heightp) + tgt_rowbytes = tgt_width * src_rowbytes / src_width; // RGBA expected. - if (rowbytes != (4 * width)) { - GfTrace("%s bad byte count... %lu instead of %lu\n", filename, (unsigned long)rowbytes, (unsigned long)(4 * width)); + if (src_rowbytes != (4 * src_width)) { + GfTrace("%s bad byte count... %lu instead of %lu\n", filename, (unsigned long)src_rowbytes, (unsigned long)(4 * src_width)); fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } - row_pointers = (png_bytep*)malloc(height * sizeof(png_bytep)); + row_pointers = (png_bytep*)malloc(tgt_height * sizeof(png_bytep)); if (row_pointers == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } - image_ptr = (unsigned char *)malloc(height * rowbytes); + image_ptr = (unsigned char *)malloc(tgt_height * tgt_rowbytes); if (image_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } - for (i = 0, cur_ptr = image_ptr + (height - 1) * rowbytes ; i < height; i++, cur_ptr -= rowbytes) { + for (i = 0, cur_ptr = image_ptr + (tgt_height - 1) * tgt_rowbytes ; i < tgt_height; i++, cur_ptr -= tgt_rowbytes) { row_pointers[i] = cur_ptr; } png_read_image(png_ptr, row_pointers); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(row_pointers); @@ -246,7 +271,6 @@ GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma return image_ptr; } - /** Write a buffer to a png image on disk. @ingroup img @param img image data (RGB) @@ -366,7 +390,7 @@ GfImgReadTex(const char *filename, int &width, int &height) sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); - tex = (GLbyte*)GfImgReadPng(filename, &width, &height, screen_gamma); + tex = (GLbyte*)GfImgReadPng(filename, &width, &height, screen_gamma, 0, 0); if (!tex) { GfParmReleaseHandle(handle); diff --git a/src/libs/tgfclient/tgfclient.h b/src/libs/tgfclient/tgfclient.h index 3658cbe3..9da35bd7 100644 --- a/src/libs/tgfclient/tgfclient.h +++ b/src/libs/tgfclient/tgfclient.h @@ -44,7 +44,7 @@ public: * Screen Interface * ********************/ -extern unsigned char *GfImgReadPng(const char *filename, int *widthp, int *heightp, float gamma); +extern unsigned char *GfImgReadPng(const char *filename, int *widthp, int *heightp, float gamma, int *quad_widthp, int *quad_heightp); extern int GfImgWritePng(unsigned char *img, const char *filename, int width, int height); extern void GfImgFreeTex(GLuint tex); extern GLuint GfImgReadTex(const char *filename); diff --git a/src/modules/graphic/ssggraph/grutil.cpp b/src/modules/graphic/ssggraph/grutil.cpp index d07cefd0..b9e75f6e 100644 --- a/src/modules/graphic/ssggraph/grutil.cpp +++ b/src/modules/graphic/ssggraph/grutil.cpp @@ -91,7 +91,7 @@ bool grLoadPngTexture (const char *fname, ssgTextureInfo* info) TRACE_GL("Load: grLoadPngTexture start"); - tex = (GLubyte*)GfImgReadPng(fname, &w, &h, 2.0); + tex = (GLubyte*)GfImgReadPng(fname, &w, &h, 2.0, 0, 0); if (!tex) { return false; } diff --git a/src/tools/trackgen/elevation.cpp b/src/tools/trackgen/elevation.cpp index ab6bf888..6d4bb752 100644 --- a/src/tools/trackgen/elevation.cpp +++ b/src/tools/trackgen/elevation.cpp @@ -56,7 +56,7 @@ void LoadElevation(tTrack *track, void *TrackHandle, char *imgFile) tdble zmin, zmax; tdble xmin, xmax, ymin, ymax; - ElvImage = GfImgReadPng(imgFile, &width, &height, 2.0); + ElvImage = GfImgReadPng(imgFile, &width, &height, 2.0, 0, 0); if (!ElvImage) { return; } diff --git a/src/tools/trackgen/objects.cpp b/src/tools/trackgen/objects.cpp index 5448b14d..0dd8b557 100644 --- a/src/tools/trackgen/objects.cpp +++ b/src/tools/trackgen/objects.cpp @@ -459,7 +459,7 @@ GenerateObjects(tTrack *track, void *TrackHandle, void *CfgHandle, FILE *save_fd sprintf(buf, "tracks/%s/%s/%s", track->category, track->internalname, map); printf("Processing object map %s\n", buf); - MapImage = GfImgReadPng(buf, &width, &height, 2.0); + MapImage = GfImgReadPng(buf, &width, &height, 2.0, 0, 0); if (!MapImage) { return; }