Crossfire Client, Branch
R11627
|
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