Crossfire Client, Trunk  R19307
opengl.c
Go to the documentation of this file.
00001 /*
00002  * Crossfire -- cooperative multi-player graphical RPG and adventure game
00003  *
00004  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
00005  * Copyright (c) 1992 Frank Tore Johansen
00006  *
00007  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
00008  * welcome to redistribute it under certain conditions. For details, see the
00009  * 'LICENSE' and 'COPYING' files.
00010  *
00011  * The authors can be reached via e-mail to crossfire-devel@real-time.com
00012  */
00013 
00027 #include <config.h>
00028 
00029 #ifdef HAVE_OPENGL
00030 
00031 #include <client-types.h>
00032 
00033 #include <errno.h>
00034 #include <gdk/gdkkeysyms.h>
00035 #include <gtk/gtk.h>
00036 
00037 #ifndef WIN32
00038 #include <gdk/gdkx.h>
00039 #else
00040 #include <windows.h>
00041 #include <gdk/gdkwin32.h>
00042 #endif
00043 
00044 #include <client.h>
00045 #include "main.h"
00046 #include "image.h"
00047 #include "mapdata.h"
00048 
00049 #include "gtk2proto.h"
00050 
00051 /* Start of Open GL includes */
00052 #include <GL/gl.h>
00053 #include <GL/glu.h>
00054 #ifndef WIN32
00055 #include <GL/glx.h>
00056 #endif
00057 
00058 extern int time_map_redraw;
00059 
00060 #ifndef WIN32
00061 static Display  *display;       /* X display & window for glx buffer swapping */
00062 static Window   window;
00063 #else
00064 static HDC devicecontext;       /* Windows device context for windows buffer swapping */
00065 #endif
00066 static int      width=1, height=1;
00067 
00072 static void init_opengl_common(void)
00073 {
00074     GLint texSize;
00075 
00076     /* Need to enable texture mapping */
00077     glEnable(GL_TEXTURE_2D);
00078     glShadeModel(GL_SMOOTH);
00079 
00080     /* Need to enable alpha blending */
00081     glEnable(GL_BLEND);
00082     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00083 
00084     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00085     glClearDepth(1.0f);
00086 
00087 #ifndef WIN32
00088     glViewport(0, 0, (float)width, (float)height);
00089 #else
00090     /*
00091      * There is a bug somewhere that causes the viewport to be shifted up by
00092      * 25-MAPHEIGHT tiles when run in Windows.  Don't know yet what causes
00093      * this, but this is a bad hack to fix it.
00094      */
00095     glViewport(0, (use_config[CONFIG_MAPHEIGHT]-25)*32, (float)width, (float)height);
00096 #endif
00097 
00098     glMatrixMode(GL_PROJECTION);
00099     glLoadIdentity();
00100 
00101     /* Make the upper left 0,0 coordinate */
00102     glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f);
00103     glMatrixMode(GL_MODELVIEW);
00104     glLoadIdentity();
00105 
00106     glFlush();
00107 
00108     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
00109     LOG(LOG_INFO,"gtk-v2::opengl_common", "Maximum texture size is %d\n", texSize);
00110 }
00111 
00112 #ifndef WIN32
00113 
00118 void init_glx_opengl(GtkWidget* drawingarea)
00119 {
00120     GLXContext  ctx;
00121     XVisualInfo *vi;
00122     int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
00123                           GLX_RED_SIZE, 4,
00124                           GLX_GREEN_SIZE, 4,
00125                           GLX_BLUE_SIZE, 4,
00126                           GLX_ALPHA_SIZE, 4,
00127                           GLX_DEPTH_SIZE, 16,
00128                           None
00129                         };
00130     XSetWindowAttributes attr;
00131 
00132     /* Need to tuck these away, because they are needed for glXSwappBuffers() */
00133     display = GDK_WINDOW_XDISPLAY(drawingarea->window);
00134     vi = glXChooseVisual(display,
00135                          gdk_x11_get_default_screen (), attrListDbl);
00136 
00137     width = drawingarea->allocation.width;
00138     height = drawingarea->allocation.height;
00139 
00140     /*
00141      * On many systems, the default visual used by the display doesn't have the
00142      * features we need (alpha channel, etc).  The only way around this is to
00143      * create a subwindow with the ideal visual.  As an oddity, we need to
00144      * create a colormap if using a different visual or we get a BadMatch
00145      * error.
00146      */
00147     DefaultVisual(display, gdk_x11_get_default_screen ());
00148     attr.colormap= XCreateColormap(display, GDK_WINDOW_XID(drawingarea->window),
00149                                    vi->visual, AllocNone);
00150 
00151     window = XCreateWindow(display, GDK_WINDOW_XID(drawingarea->window),
00152                            0, 0, width, height, 0,
00153                            vi->depth,
00154                            InputOutput,
00155                            vi->visual,
00156                            CWColormap, &attr);
00157 
00158     XMapWindow(display,window);
00159 
00160     if (!vi) {
00161         LOG(LOG_WARNING,"gtk-v2::init_glx_opengl", "Could not get double buffered screen!\n");
00162     }
00163 
00164     ctx = glXCreateContext(display, vi, 0, GL_TRUE);
00165 
00166     if (!glXMakeCurrent(display, window, ctx)) {
00167         LOG(LOG_ERROR,"gtk-v2::init_glx_opengl", "Could not set opengl context!\n");
00168         exit(1);
00169     }
00170     if (glXIsDirect(display, ctx)) {
00171         LOG(LOG_INFO,"gtk-v2::init_glx_opengl", "Direct rendering is available!\n");
00172     } else {
00173         LOG(LOG_INFO,"gtk-v2::init_glx_opengl", "Direct rendering is not available!\n");
00174     }
00175 
00176 }
00177 #endif /* #ifndef WIN32 */
00178 
00179 #ifdef WIN32
00180 
00185 void init_wgl_opengl(GtkWidget* drawingarea)
00186 {
00187     HGLRC glctx;
00188     HDC dctx;
00189     int pixelformat;
00190     PIXELFORMATDESCRIPTOR pfd = {
00191         sizeof(PIXELFORMATDESCRIPTOR),          //size of structure
00192         1,                                      //default version
00193         PFD_DRAW_TO_WINDOW |                    //window drawing support
00194         PFD_SUPPORT_OPENGL |                    //opengl support
00195         PFD_DOUBLEBUFFER,                       //double buffering support
00196         PFD_TYPE_RGBA,                          //RGBA color mode
00197         16,                                     //16 bit color mode
00198         0, 0, 0, 0, 0, 0,                       //ignore color bits
00199         4,                                      //4 bits alpha buffer
00200         0,                                      //ignore shift bit
00201         0,                                      //no accumulation buffer
00202         0, 0, 0, 0,                             //ignore accumulation bits
00203         16,                                     //16 bit z-buffer size
00204         0,                                      //no stencil buffer
00205         0,                                      //no aux buffer
00206         PFD_MAIN_PLANE,                         //main drawing plane
00207         0,                                      //reserved
00208         0, 0, 0                                 //layer masks ignored
00209     };
00210 
00211     width = drawingarea->allocation.width;
00212     height = drawingarea->allocation.height;
00213 
00214     dctx = GetDC(GDK_WINDOW_HWND(drawingarea->window));
00215     devicecontext = dctx;
00216 
00217     /* Get the closest matching pixel format to what we specified and set it */
00218     pixelformat = ChoosePixelFormat(dctx, &pfd);
00219     SetPixelFormat(dctx, pixelformat, &pfd);
00220 
00221     glctx = wglCreateContext(dctx);
00222     wglMakeCurrent(dctx, glctx);
00223 }
00224 #endif /* #ifdef WIN32 */
00225 
00232 void init_opengl(GtkWidget* drawingarea)
00233 {
00234 
00235 #ifndef WIN32
00236     init_glx_opengl(drawingarea);
00237 #else
00238     init_wgl_opengl(drawingarea);
00239 #endif
00240     init_opengl_common();
00241 }
00242 
00243 /*
00244  * We set up a table of darkness - when opengl draws the first layer, it fills
00245  * this in - in this way, we have a table of all the darkness values that we
00246  * should use - this makes dealing with darkness much faster, as we don't have
00247  * to see if the space is has valid darkness, etc.  We add 2 to the value to
00248  * take into acount the padding of an extra space (thus, don't need special
00249  * logic for final row/column).  That is +1 value.  but the last row also has
00250  * the right/bottom side vertices, and that is where the other +1 comes from
00251  */
00252 static uint16 map_darkness[(MAP_MAX_SIZE+2)*2][(MAP_MAX_SIZE+2)*2];
00253 
00254 /*
00255  * This is darkness to use if we have no darkness information.  0 makes sense
00256  * for standard behaviour, but I find setting this to 255 makes for some
00257  * interesting smoothing effects relative to the edge of the screen and blocked
00258  * spaces.  I'm not sure if anything other than 0 and 255 would be useful.
00259  */
00260 #define DEFAULT_DARKNESS    0
00261 
00281 static void opengl_light_space(int x, int y, int mx, int my)
00282 {
00283     if (use_config[CONFIG_DARKNESS] == CFG_LT_TILE) {
00284         /* If we don't have darkness, or it isn't dark, don't do anything */
00285         if (!the_map.cells[mx][my].have_darkness || the_map.cells[mx][my].darkness==0) {
00286             return;
00287         }
00288 
00289         glColor4ub(0, 0, 0,  the_map.cells[mx][my].darkness);
00290         glBegin(GL_QUADS);
00291         glVertex3i(x * map_image_size, y * map_image_size, 0);
00292         glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
00293         glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
00294         glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
00295         glEnd();
00296     }
00297 
00298     /* Do the upper left area */
00299     glBegin(GL_QUADS);
00300 
00301     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2]);
00302     glVertex3i(x * map_image_size, y * map_image_size, 0);
00303 
00304     glColor4ub(0, 0, 0,   map_darkness[x*2 + 1][y*2]);
00305     glVertex3i(x * map_image_size + map_image_half_size, y * map_image_size, 0);
00306 
00307     glColor4ub(0, 0, 0,   map_darkness[x*2 + 1][y*2 + 1]);
00308     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
00309 
00310     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+1]);
00311     glVertex3i(x * map_image_size, y * map_image_size + map_image_half_size, 0);
00312 
00313     glEnd();
00314 
00315     /* Repeat for upper right area */
00316     glBegin(GL_QUADS);
00317 
00318     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2]);
00319     glVertex3i(x * map_image_size + map_image_half_size, y * map_image_size, 0);
00320 
00321     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2]);
00322     glVertex3i((x +1 ) * map_image_size, y * map_image_size, 0);
00323 
00324     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+1]);
00325     glVertex3i((x+1) * map_image_size, y * map_image_size + map_image_half_size, 0);
00326 
00327     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
00328     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
00329 
00330     glEnd();
00331 
00332     /* Repeat for lower left area */
00333     glBegin(GL_QUADS);
00334 
00335     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+1]);
00336     glVertex3i(x * map_image_size, y * map_image_size + map_image_half_size, 0);
00337 
00338     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
00339     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
00340 
00341     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+2]);
00342     glVertex3i(x * map_image_size + map_image_half_size, (y + 1) * map_image_size, 0);
00343 
00344     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+2]);
00345     glVertex3i( x * map_image_size, (y +1)* map_image_size, 0);
00346 
00347     glEnd();
00348 
00349     /* Repeat for lower right area */
00350     glBegin(GL_QUADS);
00351 
00352     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
00353     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
00354 
00355     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+1]);
00356     glVertex3i((x+1) * map_image_size, y * map_image_size + map_image_half_size, 0);
00357 
00358     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+2]);
00359     glVertex3i((x+1) * map_image_size, (y +1)* map_image_size, 0);
00360 
00361     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+2]);
00362     glVertex3i(x * map_image_size + map_image_half_size, (y + 1) * map_image_size, 0);
00363 
00364     glEnd();
00365 }
00366 
00367 /*
00368  * Some basics.  dx, dy are coordinate pairs for offsets. bweights and cweights
00369  * are bitmasks that determine the face to draw (or'd together)
00370  */
00371 static int dx[8]= {0,1,1,1,0,-1,-1,-1};
00372 static int dy[8]= {-1,-1,0,1,1,1,0,-1};
00373 
00374 static int bweights[8]= {2,0,4,0,8,0,1,0};
00375 static int cweights[8]= {0,2,0,4,0,8,0,1};
00376 static int bc_exclude[8]= {
00377     1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
00378     0,
00379     2+4,/*east exclude northeast and southeast*/
00380     0,
00381     4+8,/*and so on*/
00382     0,
00383     8+1,
00384     0
00385 };
00386 
00387 /*
00388  * Vertices are floats.  This sets the value appropriately for us to multiply
00389  * the x coordinate by.
00390  */
00391 #define     TEXTURE_OFFSET  1.0/16.0
00392 
00404 static void drawsmooth_opengl (int x, int y, int mx, int my, int layer)
00405 {
00406     int partdone[8]= {0,0,0,0,0,0,0,0}, slevels[8], sfaces[8], i,
00407                      weight,weightC, emx,emy, smoothface, dosmooth, lowest, havesmooth;
00408 
00409     dosmooth=0;
00410     for (i=0; i<8; i++) {
00411         emx=mx+dx[i];
00412         emy=my+dy[i];
00413 
00414         if ( (emx<0) || (emy<0) || (emx >= the_map.x) || (emy >= the_map.y)) {
00415             slevels[i]=0;
00416             sfaces[i]=0; /*black picture*/
00417         } else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer] ||
00418                    the_map.cells[emx][emy].heads[layer].face == 0) {
00419             slevels[i]=0;
00420             sfaces[i]=0; /*black picture*/
00421         } else {
00422             slevels[i]=the_map.cells[emx][emy].smooth[layer];
00423             sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
00424             dosmooth++;
00425         }
00426     }
00427 
00428     /*
00429      * slevels[] & sfaces[] contain the smooth level.  dosmooth is the number
00430      * if spaces that need to be smoothed.  lowlevel is the lowest level to
00431      * smooth.
00432      *
00433      * havesmooth is how many faces we have smoothed
00434      */
00435     havesmooth=0;
00436 
00437     while (havesmooth < dosmooth) {
00438         lowest=-1;
00439         for (i=0; i<8; i++) {
00440             if ( (slevels[i]>0) && (!partdone[i]) && ((lowest<0) || (slevels[i]<slevels[lowest]))) {
00441                 lowest=i;
00442             }
00443         }
00444         if (lowest<0) {
00445             break;    /*no more smooth to do on this square*/
00446         }
00447 
00448         /* The weight values is a bitmask that determines what image we draw */
00449         weight=0;
00450         weightC=15; /*works in backward. remove where there is nothing*/
00451 
00452         for (i=0; i<8; i++) { /*check all nearby squares*/
00453             if (slevels[i]==slevels[lowest] && sfaces[i] == sfaces[lowest]) {
00454                 partdone[i]=1;
00455                 weight=weight+bweights[i];
00456                 weightC&=~bc_exclude[i];
00457                 havesmooth++;
00458             } else {
00459                 /*must rmove the weight of a corner if not in smoothing*/
00460                 weightC&=~cweights[i];
00461             }
00462         }
00463 
00464         smoothface=sfaces[lowest];
00465         if (smoothface<=0) {
00466             continue;  /*picture for smoothing not yet available*/
00467         }
00468 
00469         /*
00470          * Now, it's quite easy. We must draw using a 32x32 part of the picture
00471          * smoothface.
00472          * This part is located using the 2 weights calculated: (32*weight,0)
00473          * and (32*weightC,32)
00474          */
00475 
00476         if ( (!pixmaps[smoothface]->map_texture) || (pixmaps[smoothface] == pixmaps[0])) {
00477             continue;    /*don't have the picture associated*/
00478         }
00479 
00480         if (the_map.cells[mx][my].cleared) {
00481             glBindTexture(GL_TEXTURE_2D, pixmaps[smoothface]->fog_texture);
00482         } else {
00483             glBindTexture(GL_TEXTURE_2D, pixmaps[smoothface]->map_texture);
00484         }
00485 
00486         /*
00487          * The values of 0.0f and 0.5f are hardcoded, but as of now, it is a
00488          * known fact that there are 2 rows of data in the smoothing images, so
00489          * that should be OK.
00490          */
00491         if (weight) {
00492             glBegin(GL_QUADS);
00493 
00494             glTexCoord2f(TEXTURE_OFFSET * weight, 0.0f);
00495             glVertex3i(x * map_image_size, y * map_image_size, 0);
00496 
00497             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.0f);
00498             glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
00499 
00500             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.5f);
00501             glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
00502 
00503             glTexCoord2f(TEXTURE_OFFSET * weight, 0.5f);
00504             glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
00505 
00506             glEnd();
00507         }
00508         if (weightC) {
00509             glBegin(GL_QUADS);
00510 
00511             glTexCoord2f(TEXTURE_OFFSET * weight, 0.5f);
00512             glVertex3i(x * map_image_size, y * map_image_size, 0);
00513 
00514             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.5f);
00515             glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
00516 
00517             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 1.0f);
00518             glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
00519 
00520             glTexCoord2f(TEXTURE_OFFSET * weight, 1.0f);
00521             glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
00522 
00523             glEnd();
00524         }
00525     } /* While there's some smooth to do */
00526 }
00527 
00532 static void draw_smoothing(int layer)
00533 {
00534     int x, y, mx, my;
00535 
00536     for(y = use_config[CONFIG_MAPHEIGHT]+MAX_MAP_OFFSET; y>=0; y--) {
00537         for(x = use_config[CONFIG_MAPWIDTH]+MAX_MAP_OFFSET; x>=0; x--) {
00538 
00539             mx = x + pl_pos.x;
00540             my = y + pl_pos.y;
00541 
00542             if (CAN_SMOOTH(the_map.cells[mx][my],layer)) {
00543                 drawsmooth_opengl(x, y, mx, my, layer);
00544             }
00545         }
00546     }
00547 }
00548 
00564 void opengl_gen_map(int redraw)
00565 {
00566     long elapsed1, elapsed2;
00567     struct timeval tv1, tv2,tv3;
00568     int mx,my, layer,x,y, d1, d2, d3, num_dark, got_smooth, face, t1, t2;
00569 
00570     if (time_map_redraw) {
00571         gettimeofday(&tv1, NULL);
00572     }
00573 
00574     glClear(GL_COLOR_BUFFER_BIT);
00575 
00576     /*
00577      * Need to set this, as the darkness logic could have reset this.  since
00578      * darkness is done after all other drawing, we can do it just once here.
00579      */
00580     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00581 
00582     /* We draw every space every time this is called.  We draw from bottom
00583      * right to top left - this makes stacking of big images work as expected.
00584      * we also draw all of one layer before doing the next layer.  This really
00585      * shouldn't effect performance all that much - all that is being changed
00586      * is the order of the loops we add MAX_MAP_OFFSET so that big objects off
00587      * the edge of the map are drawn.
00588      */
00589 
00590     got_smooth=0; /*smooth marker. Once we have a face and "can_smooth" on a layer, this layer and all above draw smooth */
00591 
00592     for (layer=0; layer<=MAXLAYERS; layer++) {
00593 
00594 
00595         if (layer == MAXLAYERS) {
00596             /*
00597              * The top layer is the darkness processing - turn off the texture
00598              * pattern so darkness works as expected.
00599              */
00600             glBindTexture(GL_TEXTURE_2D, 0);
00601         }
00602         for(y = use_config[CONFIG_MAPHEIGHT]+MAX_MAP_OFFSET; y>=0; y--) {
00603             for(x = use_config[CONFIG_MAPWIDTH]+MAX_MAP_OFFSET; x>=0; x--) {
00604                 /*
00605                  * mx,my represent the spaces on the 'virtual' map (ie, the_map
00606                  * structure).  x and y (from the for loop) represent the
00607                  * visible screen.
00608                  */
00609                 mx = x + pl_pos.x;
00610                 my = y + pl_pos.y;
00611                 /*
00612                  * If we get here, this denotes a special/top layer.  This is
00613                  * the time to do lighting, smoothing, etc.
00614                  */
00615                 if (layer == MAXLAYERS) {
00616                     /*
00617                      * If off the map, don't need to do anything, because the
00618                      * code here doesn't do anything that would extend onto the
00619                      * map.
00620                      */
00621                     if (x >= use_config[CONFIG_MAPWIDTH] || y >= use_config[CONFIG_MAPHEIGHT]) {
00622                         continue;
00623                     }
00624                     /*
00625                      * One could make the case it doesn't make sense to light
00626                      * fog of war spaces, but I find visually it looks a lot
00627                      * nicer if you do - otherwise, they are too bright
00628                      * relative to the spaces around.  them.
00629                      */
00630                     if (use_config[CONFIG_DARKNESS]) {
00631                         opengl_light_space(x, y, mx, my);
00632                     }
00633 
00634                 } else {
00635                     /*
00636                      * Only do this in the better lighting modes.  Fortunately,
00637                      * the CFG_LT_.. values are ordered from worst to best, to
00638                      * are >= check works just fine, right now.
00639                      */
00640                     if (layer == 0 && use_config[CONFIG_DARKNESS] >= CFG_LT_PIXEL &&
00641                             ~                       x <= use_config[CONFIG_MAPWIDTH] && y <= use_config[CONFIG_MAPHEIGHT]) {
00642                         /*
00643                          * The darkness code is similar to the per pixel SDL
00644                          * code.  As such, each square we process needs to know
00645                          * the values for the intersection points - there is a
00646                          * lot of redundant calculation in this if done a
00647                          * square at a time, so instead, we can calculate the
00648                          * darkness point of all the vertices here.  We
00649                          * calculate the upper/left 4 vertices.
00650                          *
00651                          * SDL actually gets better results I think - perhaps
00652                          * because the per pixel lighting uses a different
00653                          * algorithm - we basically let opengl do the blending.
00654                          * But the results we use here, while perhaps not as
00655                          * nice, certainly look better than per tile lighting.
00656                          */
00657                         if (the_map.cells[mx][my].have_darkness) {
00658                             map_darkness[x*2 + 1][y*2 + 1] = the_map.cells[mx][my].darkness;
00659                         } else {
00660                             map_darkness[x*2 + 1][y*2 + 1] = DEFAULT_DARKNESS;
00661                         }
00662 
00663                         d1 = DEFAULT_DARKNESS;  /* square to left */
00664                         d2 = DEFAULT_DARKNESS;  /* square to upper left */
00665                         d3 = DEFAULT_DARKNESS;  /* square above */
00666                         num_dark=1; /* Number of adjoining spaces w/darkness */
00667 
00668                         if (x>0 && the_map.cells[mx-1][my].have_darkness) {
00669                             d1 = the_map.cells[mx-1][my].darkness;
00670                             num_dark++;
00671                         }
00672 
00673                         if (x>0 && y>0 && the_map.cells[mx-1][my-1].have_darkness) {
00674                             d2 = the_map.cells[mx-1][my-1].darkness;
00675                             num_dark++;
00676                         }
00677 
00678                         if (y>0 && the_map.cells[mx][my-1].have_darkness) {
00679                             d3 = the_map.cells[mx][my-1].darkness;
00680                             num_dark++;
00681                         }
00682 #if 0
00683                         /*
00684                          * If we don't have darkness, we want to use our value
00685                          * and not average.  That is because the value we
00686                          * average against is 0 - this results in lighter bands
00687                          * next to areas we won't have darkness info for.
00688                          */
00689                         map_darkness[x*2][y*2] = (d1 + d2 +d3 + map_darkness[x*2 + 1][y*2 + 1]) / num_dark;
00690 
00691                         if (d1) {
00692                             map_darkness[x*2][y*2 + 1] = (d1 + map_darkness[x*2 + 1][y*2 + 1]) / 2;
00693                         } else {
00694                             map_darkness[x*2][y*2 + 1] = map_darkness[x*2 + 1][y*2 + 1];
00695                         }
00696 
00697                         if (d3) {
00698                             map_darkness[x*2 +1 ][y*2] = (d3 + map_darkness[x*2 + 1][y*2 + 1]) / 2;
00699                         } else {
00700                             map_darkness[x*2 + 1][y*2] = map_darkness[x*2 + 1][y*2 + 1];
00701                         }
00702 #else
00703                         /*
00704                          * This block does a 'max' darkness - I think it gives
00705                          * the best results, which is why by default it is the
00706                          * one used.
00707                          */
00708                         map_darkness[x*2][y*2] = MAX( MAX(d1, d2), MAX(d3, map_darkness[x*2 + 1][y*2 + 1]));
00709                         map_darkness[x*2][y*2 + 1] = MAX(d1, map_darkness[x*2 + 1][y*2 + 1]);
00710                         map_darkness[x*2 + 1][y*2] = MAX(d3, map_darkness[x*2 + 1][y*2 + 1]);
00711 #endif
00712                     }
00713 
00714                     if (the_map.cells[mx][my].heads[layer].face) {
00715                         if (pixmaps[the_map.cells[mx][my].heads[layer].face]->map_texture) {
00716                             int nx, ny;
00717 
00718                             /*
00719                              * nx, ny are the location of the top/left side of
00720                              * the image to draw.
00721                              */
00722                             nx = (x+1) * map_image_size - pixmaps[the_map.cells[mx][my].heads[layer].face]->map_width;
00723                             ny = (y+1) * map_image_size - pixmaps[the_map.cells[mx][my].heads[layer].face]->map_height;
00724                             /*
00725                              * If both nx and ny are outside visible area,
00726                              * don't need to do anything more
00727                              */
00728                             if (nx > width && ny > height) {
00729                                 continue;
00730                             }
00731                             /*
00732                              * There are some issues with this - it is really
00733                              * the head of the object that is determining fog
00734                              * of war logic.  I don't have good solution to
00735                              * that, other than to live with it.
00736                              */
00737                             if (the_map.cells[mx][my].cleared) {
00738                                 glBindTexture(GL_TEXTURE_2D, pixmaps[the_map.cells[mx][my].heads[layer].face]->fog_texture);
00739                             } else {
00740                                 glBindTexture(GL_TEXTURE_2D, pixmaps[the_map.cells[mx][my].heads[layer].face]->map_texture);
00741                             }
00742 
00743                             glBegin(GL_QUADS);
00744 
00745                             glTexCoord2f(0.0f, 0.0f);
00746                             glVertex3i(nx, ny, 0);
00747 
00748                             glTexCoord2f(1.0f, 0.0f);
00749                             glVertex3i( (x+1) * map_image_size, ny, 0);
00750 
00751                             glTexCoord2f(1.0f, 1.0f);
00752                             glVertex3i( (x+1) * map_image_size, (y+1) * map_image_size, 0);
00753 
00754                             glTexCoord2f(0.0f, 1.0f);
00755                             glVertex3i(nx, (y+1) * map_image_size, 0);
00756 
00757                             glEnd();
00758                         }
00759                         if (use_config[CONFIG_SMOOTH] && CAN_SMOOTH(the_map.cells[mx][my],layer) &&
00760                                 the_map.cells[mx][my].heads[layer].face !=0) {
00761 
00762                             got_smooth=1;
00763                         }
00764                     }
00765                     if ((face=mapdata_bigface_head(x, y, layer, &t1, &t2))!=0) {
00766                         if (pixmaps[face]->map_texture) {
00767                             int nx, ny;
00768 
00769                             /*
00770                              * nx, ny are the location of the top/left side of
00771                              * the image to draw.
00772                              */
00773                             nx = (x+1) * map_image_size - pixmaps[face]->map_width;
00774                             ny = (y+1) * map_image_size - pixmaps[face]->map_height;
00775                             /*
00776                              * If both nx and ny are outside visible area,
00777                              * don't need to do anything more
00778                              */
00779                             if (nx > width && ny > height) {
00780                                 continue;
00781                             }
00782                             /*
00783                              * There are some issues with this - it is really
00784                              * the head of the object that is determining fog
00785                              * of war logic.  I don't have good solution to
00786                              * that, other than to live with it.
00787                              */
00788                             if (the_map.cells[mx][my].cleared) {
00789                                 glBindTexture(GL_TEXTURE_2D, pixmaps[face]->fog_texture);
00790                             } else {
00791                                 glBindTexture(GL_TEXTURE_2D, pixmaps[face]->map_texture);
00792                             }
00793 
00794                             glBegin(GL_QUADS);
00795 
00796                             glTexCoord2f(0.0f, 0.0f);
00797                             glVertex3i(nx, ny, 0);
00798 
00799                             glTexCoord2f(1.0f, 0.0f);
00800                             glVertex3i( (x+1) * map_image_size, ny, 0);
00801 
00802                             glTexCoord2f(1.0f, 1.0f);
00803                             glVertex3i( (x+1) * map_image_size, (y+1) * map_image_size, 0);
00804 
00805                             glTexCoord2f(0.0f, 1.0f);
00806                             glVertex3i(nx, (y+1) * map_image_size, 0);
00807 
00808                             glEnd();
00809                         }
00810                     } /* If this space has a valid face */
00811                 } /* If last layer/else not last layer */
00812             } /* for x loop */
00813         } /* for y loop */
00814 
00815         /*
00816          * Because of our handling with big images, we can't easily draw this
00817          * when drawing the space - we may want to smooth onto another space in
00818          * which the ground hasn't been drawn yet, so we have to do smoothing
00819          * at the end of each layer.
00820          *
00821          * We use the got_smooth variable to know if there is in fact any
00822          * smoothing to do - for many layers, this is not likely to be set, so
00823          * we can save work by not doing this.
00824          */
00825         if (got_smooth) {
00826             draw_smoothing(layer);
00827         }
00828     }
00829 
00830     if (time_map_redraw) {
00831         gettimeofday(&tv2, NULL);
00832     }
00833 
00834 #ifndef WIN32
00835     glXSwapBuffers(display, window);
00836 #else
00837     SwapBuffers(devicecontext);
00838 #endif
00839 
00840     if (time_map_redraw) {
00841         gettimeofday(&tv3, NULL);
00842         elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
00843         elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
00844         /*
00845          * I care about performance for 'long' updates, so put the check in to
00846          * make these a little more noticable
00847          */
00848         if ((elapsed1 + elapsed2)>10000)
00849             LOG(LOG_INFO,"gtk-v2::opengl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
00850                 elapsed1, elapsed2, elapsed1 + elapsed2);
00851     }
00852 } /* opengl_gen_map function */
00853 
00861 void create_opengl_map_image(uint8 *data, PixmapInfo *pi)
00862 {
00863     static uint8 *newdata;
00864     static int size=0;
00865     int nwidth, nheight, numshifts, i;
00866     uint8 *data_to_use = data, *l;
00867     uint32 g, *p;
00868 
00869     /*
00870      * The width and height of textures has to be a power of 2.  so 32x32 and
00871      * 64x64 images work, but 96x96 does not.  The logic below basically
00872      * figures out if the width we have is in fact a power of two or not, and
00873      * if not, the next power of 2 up that is.
00874      */
00875     for (nwidth = pi->map_width, numshifts=0; nwidth >1; nwidth >>=1, numshifts++) ;
00876     nwidth <<= numshifts;
00877     if (nwidth != pi->map_width) {
00878         nwidth <<=1;
00879     }
00880 
00881     for (nheight = pi->map_height, numshifts=0; nheight >1; nheight >>=1, numshifts++) ;
00882     nheight <<= numshifts;
00883     if (nheight != pi->map_height) {
00884         nheight <<=1;
00885     }
00886     /*
00887      * Below deals with cases where the pixmap is not a power of 2.  The
00888      * 'proper' opengl way of dealing with such textures is to make a mipmap -
00889      * this is basically a resized version up/down to the nearest power of two,
00890      * which is then rescaled when it is used to actually texture something -
00891      * this means it is scaled up once, then scaled down again.  For most
00892      * opengl apps, this probably isn't a big deal, because the surface the
00893      * texture being applied applied to is going to cause distortion.  However,
00894      * in this client, we are doing a 1:1 paste operation, so that scaling will
00895      * certainly cause some distortion.  instead, I take the approach make a
00896      * bigger image, but fill the extra bits with transparent alpha bits.  This
00897      * way, we have no loss of quality.
00898      */
00899     if (pi->map_width != nwidth || pi->map_height != nheight) {
00900         int y;
00901         uint8   *datastart;
00902 
00903         /*
00904          * Use a static buffer to hold image data, so we don't have to keep
00905          * allocating/deallocating, but need to make sure it is big enough.
00906          */
00907         if (nwidth * nheight * 4 > size) {
00908             size = nwidth * nheight * 4;
00909             newdata = realloc(newdata, size);
00910 
00911             if (newdata == NULL) {
00912                 LOG(LOG_ERROR, "create_opengl_map_image",
00913                         "Could not allocate memory: %s", strerror(errno));
00914                 exit(EXIT_FAILURE);
00915             }
00916         }
00917         /*
00918          * Fill the top portion of the image with empty/transparent data.
00919          * Also, set up datastart to point to where we should start filling in
00920          * the rest of the data.
00921          */
00922         if (nheight > pi->map_height) {
00923             memset(newdata, 0, (nheight - pi->map_height) * nwidth * 4);
00924             datastart = newdata + (nheight - pi->map_height) * nwidth * 4;
00925         } else {
00926             datastart = newdata;
00927         }
00928 
00929         for (y =0; y < pi->map_height; y++) {
00930             memset(datastart + y * nwidth * 4, 0, (nwidth - pi->map_width) * 4);
00931             memcpy(datastart + y * nwidth * 4 + (nwidth - pi->map_width) * 4,
00932                    data + y * pi->map_width * 4, pi->map_width * 4);
00933         }
00934         data_to_use = newdata;
00935         pi->map_width = nwidth;
00936         pi->map_height = nheight;
00937     }
00938 
00939     glGenTextures(1, &pi->map_texture);
00940     glBindTexture(GL_TEXTURE_2D, pi->map_texture);
00941     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00942     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00943 
00944     glTexImage2D(GL_TEXTURE_2D, 0, 4, pi->map_width, pi->map_height,
00945                  0, GL_RGBA, GL_UNSIGNED_BYTE, data_to_use);
00946 
00947     /*
00948      * Generate a fog image.  This isn't 100% efficient, because we copy data
00949      * we may need to modify, but makes the code simpler in in the case above
00950      * where we've had to change the size of the image.
00951      */
00952 
00953     if (pi->map_width * pi->map_height * 4 > size) {
00954         size = pi->map_width * pi->map_height * 4;
00955         newdata = realloc(newdata, size);
00956     }
00957 
00958     /* In this case, newdata does not contain a copy of the data - make one */
00959     if (data_to_use != newdata) {
00960         memcpy(newdata, data, pi->map_height *  pi->map_width * 4);
00961     }
00962 
00963     for (i=0; i < pi->map_width * pi->map_height; i++) {
00964         l = (uint8 *) (newdata + i*4);
00965         g = MAX(*l, *(l+1));
00966         g = MAX(g, *(l+2));
00967         p = (uint32*) newdata + i;
00968         *p = g | (g << 8) | (g << 16) | (*(l + 3) << 24);
00969     }
00970 
00971     glGenTextures(1, &pi->fog_texture);
00972     glBindTexture(GL_TEXTURE_2D, pi->fog_texture);
00973     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00974     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00975 
00976     glTexImage2D(GL_TEXTURE_2D, 0, 4, pi->map_width, pi->map_height,
00977                  0, GL_RGBA, GL_UNSIGNED_BYTE, newdata);
00978 }
00979 
00984 void opengl_free_pixmap(PixmapInfo *pi)
00985 {
00986     if (pi->map_texture) {
00987         glDeleteTextures(1, &pi->map_texture);
00988         pi->map_texture=0;
00989     }
00990     if (pi->fog_texture) {
00991         glDeleteTextures(1, &pi->fog_texture);
00992         pi->fog_texture=0;
00993     }
00994 }
00995 
00996 #include "../../pixmaps/question.111"
00997 
01005 void create_opengl_question_mark(void)
01006 {
01007     GLubyte question[question_height][question_width][4];
01008     int xb, x, y, offset=0;
01009 
01010     /*
01011      * We want data in rgba format.  So convert the question bits to an rgba
01012      * format.  We only need to do this once
01013      */
01014     for (y=0; y<question_height; y++) {
01015         for (xb=0; xb<question_width/8; xb++) {
01016             for (x=0; x<8; x++) {
01017                 if (question_bits[offset] & (1 << x)) {
01018                     question[y][xb * 8 + x][0] = 255;
01019                     question[y][xb * 8 + x][1] = 255;
01020                     question[y][xb * 8 + x][2] = 255;
01021                     question[y][xb * 8 + x][3] = 255;
01022                 } else {
01023                     question[y][xb * 8 + x][0] = 0;
01024                     question[y][xb * 8 + x][1] = 0;
01025                     question[y][xb * 8 + x][2] = 0;
01026                     question[y][xb * 8 + x][3] = 0;
01027                 }
01028             }
01029             offset++;
01030         }
01031     }
01032 
01033     glGenTextures(1, &pixmaps[0]->map_texture);
01034     glBindTexture(GL_TEXTURE_2D, pixmaps[0]->map_texture);
01035     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01036     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01037 
01038     glTexImage2D(GL_TEXTURE_2D, 0, 4, question_width, question_height,
01039                  0, GL_RGBA, GL_UNSIGNED_BYTE, &question[0][0][0]);
01040 
01041     glGenTextures(1, &pixmaps[0]->fog_texture);
01042     glBindTexture(GL_TEXTURE_2D, pixmaps[0]->fog_texture);
01043     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01044     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01045 
01046     glTexImage2D(GL_TEXTURE_2D, 0, 4, question_width, question_height,
01047                  0, GL_RGBA, GL_UNSIGNED_BYTE, &question[0][0][0]);
01048 }
01049 
01050 #endif