00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <stdlib.h>
00010 #include <math.h>
00011
00012 #include <imagergba.h>
00013
00014 #include "framewk.h"
00015
00016
00018
00022 typedef struct
00023 {
00024 int width;
00025 int height;
00026
00027 int bytesPerPixel;
00028
00029 void *data;
00030 } Image;
00031
00032 static const Image *displayImage = NULL;
00033
00034 static GLdouble displayZoom = 1.0;
00035
00036 static GLint displayHotSpotX = 0;
00037 static GLint displayHotSpotY = 0;
00038
00039 static GLdouble displayRasterX = 0;
00040 static GLdouble displayRasterY = 0;
00041
00042 static bool displayChanged = true;
00043
00044 static int glutWindowId = -1;
00045
00046
00048
00050
00052
00053
00055 static void fwkWindowToImageCoordinates(int x, int y, float *ix, float *iy);
00056
00058 static void fwkSetDisplayHotSpot(int x, int y);
00059
00061
00063
00064 #include <iostream.h>
00065
00066 #define HAVE_GLCOPYTEXSUBIMAGE2D
00067
00068 static bool fwkUpdateRasterPos(void)
00069
00070 {
00071 GLdouble oldRasterX = displayRasterX;
00072 GLdouble oldRasterY = displayRasterY;
00073
00074 {
00075 GLdouble displayWidth = displayZoom * displayImage->width;
00076 GLdouble displayHeight = displayZoom * displayImage->height;
00077 GLint vp[4];
00078
00079 glGetIntegerv(GL_VIEWPORT, vp);
00080
00081 if (vp[2] >= displayWidth)
00082 displayRasterX = (vp[2] - displayWidth) / 2;
00083 else
00084 {
00085 #ifdef HAVE_GLCOPYTEXSUBIMAGE2D
00086 displayRasterX = displayHotSpotX - displayWidth * displayHotSpotX / (float)vp[2];
00087 #else
00088 displayRasterX = 0;
00089 #endif
00090 }
00091
00092 if (vp[3] >= displayHeight)
00093 displayRasterY = (vp[3] - displayHeight) / 2;
00094 else
00095 {
00096 #ifdef HAVE_GLCOPYTEXSUBIMAGE2D
00097 displayRasterY = displayHotSpotY - displayHeight * displayHotSpotY / (float)vp[3];
00098 #else
00099 displayRasterY = 0;
00100 #endif
00101 }
00102 }
00103
00104 return displayRasterX != oldRasterX || displayRasterY != oldRasterY;
00105 }
00106
00107 void fwkWindowToImageCoordinates(int x, int y, float *ix, float *iy)
00119 {
00120 *ix = (float)((x+0.5-displayRasterX) / displayZoom);
00121 *iy = (float)((y+0.5-displayRasterY) / displayZoom);
00122 }
00123
00125
00127
00128 #ifdef HAVE_GLCOPYTEXSUBIMAGE2D
00129 GLuint imageTexID = 0;
00130 #endif
00131 static unsigned nextPowerOfTwo(unsigned x)
00132 {
00133 int n;
00134 unsigned m = x;
00135 for (n=0; m; m>>=1, n++);
00136 if (x == (1u << (n-1)))
00137 return (1u << (n-1));
00138 else
00139 return (1u << n);
00140 }
00141
00142 #ifdef HAVE_GLCOPYTEXSUBIMAGE2D
00143 unsigned texWidth = 0;
00144 unsigned texHeight = 0;
00145 GLenum texId = 0;
00146 #endif
00147
00148 static void fwkRedrawCB(void)
00149
00150
00151
00152
00153
00154
00155
00156 {
00157 if (displayImage)
00158 {
00159 GLint vp[4];
00160
00161 glGetIntegerv(GL_VIEWPORT, vp);
00162
00163 fwkUpdateRasterPos();
00164
00165
00166 glMatrixMode(GL_PROJECTION);
00167 glLoadIdentity();
00168 glOrtho(0, vp[2], vp[3], 0, -1, 1);
00169 glMatrixMode(GL_MODELVIEW);
00170 glLoadIdentity();
00171
00172
00173 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00174 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00175
00176
00177 glClearColor(0.2f,0.2f,0.4f,1.0f);
00178 glClear(GL_COLOR_BUFFER_BIT);
00179
00180 #ifdef HAVE_GLCOPYTEXSUBIMAGE2D
00181 {
00182 if (texId==0 || displayChanged)
00183 {
00184 unsigned w2p = nextPowerOfTwo((unsigned)displayImage->width);
00185 unsigned h2p = nextPowerOfTwo((unsigned)displayImage->width);
00186 if (texId > 0 && (w2p != texWidth || h2p != texHeight))
00187 {
00188 glDeleteTextures(1, &texId);
00189 texId = 0;
00190 }
00191 if (texId == 0)
00192 {
00193 glGenTextures(1, &texId);
00194 glBindTexture(GL_TEXTURE_2D, texId);
00195
00196 texWidth = w2p;
00197 texHeight = h2p;
00198
00199 glTexImage2D(GL_TEXTURE_2D, 0,
00200 displayImage->bytesPerPixel,
00201 texWidth, texHeight, 0,
00202 displayImage->bytesPerPixel == 4 ? GL_RGBA : GL_LUMINANCE,
00203 GL_UNSIGNED_BYTE,
00204 NULL);
00205 }
00206 else
00207 glBindTexture(GL_TEXTURE_2D, texId);
00208
00209 glTexSubImage2D(GL_TEXTURE_2D, 0,
00210 0, 0, displayImage->width, displayImage->height,
00211 displayImage->bytesPerPixel == 4 ? GL_RGBA : GL_LUMINANCE,
00212 GL_UNSIGNED_BYTE,
00213 displayImage->data);
00214 }
00215 else
00216 glBindTexture(GL_TEXTURE_2D, texId);
00217
00218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00222
00223 glEnable(GL_TEXTURE_2D);
00224 glDisable(GL_DEPTH_TEST);
00225 glDisable(GL_LIGHTING);
00226 glBegin(GL_QUADS);
00227 {
00228 GLfloat displayWidth = displayZoom * displayImage->width;
00229 GLfloat displayHeight = displayZoom * displayImage->height;
00230
00231 GLfloat maxS = (GLfloat)displayImage->width / texWidth;
00232 GLfloat maxT = (GLfloat)displayImage->height / texHeight;
00233
00234 glTexCoord2f(0, 0);
00235 glVertex2f(displayRasterX, displayRasterY);
00236
00237 glTexCoord2f(maxS, 0);
00238 glVertex2f(displayRasterX+displayWidth, displayRasterY);
00239
00240 glTexCoord2f(maxS, maxT);
00241 glVertex2f(displayRasterX+displayWidth, displayRasterY+displayHeight);
00242
00243 glTexCoord2f(0, maxT);
00244 glVertex2f(displayRasterX, displayRasterY+displayHeight);
00245 }
00246 glEnd();
00247 glEnable(GL_DEPTH_TEST);
00248 glDisable(GL_TEXTURE_2D);
00249 }
00250 #else
00251 {
00252 glRasterPos2d(displayRasterX, displayRasterY);
00253 glPixelZoom(displayZoom, -displayZoom);
00254 if (displayImage->bytesPerPixel == 4)
00255 {
00256 glDrawPixels(displayImage->width, displayImage->height,
00257 GL_RGBA,
00258 GL_UNSIGNED_BYTE,
00259 displayImage->data);
00260 }
00261 else
00262 {
00263 glDrawPixels(displayImage->width, displayImage->height,
00264 GL_LUMINANCE,
00265 GL_UNSIGNED_BYTE,
00266 displayImage->data);
00267 }
00268 }
00269 #endif
00270 }
00271 else
00272
00273 glClear(GL_COLOR_BUFFER_BIT);
00274
00275
00276 glutSwapBuffers();
00277
00278 displayChanged = false;
00279 }
00280
00281 static void fwkKeyboardCB(unsigned char key, int x, int y)
00282 {
00283 float imageX;
00284 float imageY;
00285
00286 fwkSetDisplayHotSpot(x, y);
00287 fwkWindowToImageCoordinates(x, y, &imageX, &imageY);
00288
00289 keyboardCB(key, imageX, imageY);
00290 }
00291
00292 static void fwkSpecialCB(int key, int x, int y)
00293 {
00294 float imageX;
00295 float imageY;
00296
00297 fwkSetDisplayHotSpot(x, y);
00298 fwkWindowToImageCoordinates(x, y, &imageX, &imageY);
00299
00300 specialCB(key, imageX, imageY);
00301 }
00302
00303 static void fwkMouseCB(int button, int state, int x, int y)
00304 {
00305 float imageX;
00306 float imageY;
00307
00308 fwkSetDisplayHotSpot(x, y);
00309 fwkWindowToImageCoordinates(x, y, &imageX, &imageY);
00310
00311 mouseCB(button, state, imageX, imageY);
00312 }
00313
00314 static void fwkMotionCB(int x, int y)
00315 {
00316 float imageX;
00317 float imageY;
00318
00319 fwkSetDisplayHotSpot(x, y);
00320 fwkWindowToImageCoordinates(x, y, &imageX, &imageY);
00321
00322 motionCB(imageX, imageY);
00323 }
00324
00325 static void fwkPassiveMotionCB(int x, int y)
00334 {
00335 fwkSetDisplayHotSpot(x, y);
00336 }
00337
00339
00341
00342 void fwkInit(int *argc, const char *argv[])
00349 {
00350
00351 {
00352 if (argc && *argc >= 1 && argv)
00353 glutInit(argc, (char **)argv);
00354 else
00355 {
00356 int fake_argc = 1;
00357 char *fake_argv[] = {"painter"};
00358 glutInit(&fake_argc, fake_argv);
00359 }
00360 }
00361
00362
00363 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
00364
00365
00366 glutInitWindowSize(512, 512);
00367 glutWindowId = glutCreateWindow("Paint Application");
00368
00369
00370 glutDisplayFunc(fwkRedrawCB);
00371 glutKeyboardFunc(fwkKeyboardCB);
00372 glutSpecialFunc(fwkSpecialCB);
00373 glutMouseFunc(fwkMouseCB);
00374 glutMotionFunc(fwkMotionCB);
00375 glutPassiveMotionFunc(fwkPassiveMotionCB);
00376 glutIdleFunc(idleCB);
00377 }
00378
00379 void fwkMainLoop(void)
00384 {
00385 glutMainLoop();
00386 }
00387
00389
00390 void fwkSetDisplayImage(const void *img)
00397 {
00398 assert(((const Image *)img)->bytesPerPixel == 1 ||
00399 ((const Image *)img)->bytesPerPixel == 4);
00400
00401 if (displayImage != img && glutWindowId >= 0)
00402 {
00403 displayImage = (const Image *)img;
00404 glutPostRedisplay();
00405 }
00406 else
00407 displayImage = (const Image *)img;
00408 }
00409
00410 float fwkGetDisplayZoom(void)
00411 {
00412 return (float)displayZoom;
00413 }
00414
00415 void fwkSetDisplayZoom(float zoom)
00416 {
00417 if (displayZoom != zoom)
00418 {
00419 displayZoom = zoom;
00420 fwkPostRedisplayNoChange();
00421 }
00422 }
00423
00424 void fwkSetDisplayHotSpot(int x, int y)
00428 {
00429 if (displayHotSpotX != x || displayHotSpotY != y)
00430 {
00431 GLint vp[4];
00432
00433 glGetIntegerv(GL_VIEWPORT, vp);
00434
00435 if (x >= vp[0] && x-vp[0] < vp[2])
00436 displayHotSpotX = x;
00437
00438 if(y >= vp[1] && y-vp[1] < vp[3])
00439 displayHotSpotY = y;
00440
00441 if (fwkUpdateRasterPos())
00442 fwkPostRedisplayNoChange();
00443 }
00444 }
00445
00446 void fwkPostRedisplay(void)
00452 {
00453 displayChanged = true;
00454 glutPostRedisplay();
00455 }
00456
00457 void fwkPostRedisplayNoChange(void)
00464 {
00465 glutPostRedisplay();
00466 }
00467