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