1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
14 /**
15  * @file
16  * Implements an opengl version of the map renderer.  I've tried to keep this
17  * platform generic, but there are just some things that must be tied to the
18  * window system is is using, namely, window creation and flipping the data
19  * buffers.  For that, on X, we use to use glx - MSW 2005-03-12
20  */
21 
22 #include "client.h"
23 
24 #ifdef HAVE_OPENGL
25 
26 #include <errno.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtk.h>
29 
30 #ifndef WIN32
31 #include <gdk/gdkx.h>
32 #else
33 #include <windows.h>
34 #include <gdk/gdkwin32.h>
35 #endif
36 
37 #include "image.h"
38 #include "main.h"
39 #include "mapdata.h"
40 #include "gtk2proto.h"
41 
42 /* Start of Open GL includes */
43 #include <GL/gl.h>
44 #include <GL/glu.h>
45 #ifndef WIN32
46 #include <GL/glx.h>
47 #endif
48 
49 #ifndef WIN32
50 static Display  *display;       /* X display & window for glx buffer swapping */
51 static Window   window;
52 #else
53 static HDC devicecontext;       /* Windows device context for windows buffer swapping */
54 #endif
55 static int      width=1, height=1;
56 
57 /**
58  * This function does the generic initialization for opengl and does not use
59  * any machine specific calls.
60  */
init_opengl_common(void)61 static void init_opengl_common(void)
62 {
63     GLint texSize;
64 
65     /* Need to enable texture mapping */
66     glEnable(GL_TEXTURE_2D);
67     glShadeModel(GL_SMOOTH);
68 
69     /* Need to enable alpha blending */
70     glEnable(GL_BLEND);
71     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
72 
73     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
74     glClearDepth(1.0f);
75 
76 #ifndef WIN32
77     glViewport(0, 0, (float)width, (float)height);
78 #else
79     /*
80      * There is a bug somewhere that causes the viewport to be shifted up by
81      * 25-MAPHEIGHT tiles when run in Windows.  Don't know yet what causes
82      * this, but this is a bad hack to fix it.
83      */
84     glViewport(0, (use_config[CONFIG_MAPHEIGHT]-25)*32, (float)width, (float)height);
85 #endif
86 
87     glMatrixMode(GL_PROJECTION);
88     glLoadIdentity();
89 
90     /* Make the upper left 0,0 coordinate */
91     glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f);
92     glMatrixMode(GL_MODELVIEW);
93     glLoadIdentity();
94 
95     glFlush();
96 
97     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
98     LOG(LOG_INFO,"gtk-v2::opengl_common", "Maximum texture size is %d\n", texSize);
99 }
100 
101 #ifndef WIN32
102 /**
103  * GLX (X-Windows) specific OpenGL init
104  *
105  * @param drawingarea
106  */
init_glx_opengl(GtkWidget * drawingarea)107 void init_glx_opengl(GtkWidget* drawingarea)
108 {
109     GLXContext  ctx;
110     XVisualInfo *vi;
111     int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
112                           GLX_RED_SIZE, 4,
113                           GLX_GREEN_SIZE, 4,
114                           GLX_BLUE_SIZE, 4,
115                           GLX_ALPHA_SIZE, 4,
116                           GLX_DEPTH_SIZE, 16,
117                           None
118                         };
119     XSetWindowAttributes attr;
120 
121     /* Need to tuck these away, because they are needed for glXSwappBuffers() */
122     display = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(drawingarea));
123     vi = glXChooseVisual(display,
124                          gdk_x11_get_default_screen (), attrListDbl);
125 
126     width = drawingarea->allocation.width;
127     height = drawingarea->allocation.height;
128 
129     /*
130      * On many systems, the default visual used by the display doesn't have the
131      * features we need (alpha channel, etc).  The only way around this is to
132      * create a subwindow with the ideal visual.  As an oddity, we need to
133      * create a colormap if using a different visual or we get a BadMatch
134      * error.
135      */
136     DefaultVisual(display, gdk_x11_get_default_screen ());
137     attr.colormap= XCreateColormap(display, GDK_WINDOW_XID(gtk_widget_get_window(drawingarea)),
138                                    vi->visual, AllocNone);
139 
140     window = XCreateWindow(display, GDK_WINDOW_XID(gtk_widget_get_window(drawingarea)),
141                            0, 0, width, height, 0,
142                            vi->depth,
143                            InputOutput,
144                            vi->visual,
145                            CWColormap, &attr);
146 
147     XMapWindow(display,window);
148 
149     if (!vi) {
150         LOG(LOG_WARNING,"gtk-v2::init_glx_opengl", "Could not get double buffered screen!\n");
151     }
152 
153     ctx = glXCreateContext(display, vi, 0, GL_TRUE);
154 
155     if (!glXMakeCurrent(display, window, ctx)) {
156         LOG(LOG_ERROR,"gtk-v2::init_glx_opengl", "Could not set opengl context!\n");
157         exit(1);
158     }
159     if (glXIsDirect(display, ctx)) {
160         LOG(LOG_INFO,"gtk-v2::init_glx_opengl", "Direct rendering is available!\n");
161     } else {
162         LOG(LOG_INFO,"gtk-v2::init_glx_opengl", "Direct rendering is not available!\n");
163     }
164 
165 }
166 #endif /* #ifndef WIN32 */
167 
168 #ifdef WIN32
169 /**
170  * WGL (MS Windows) specific OpenGL init
171  *
172  * @param drawingarea
173  */
init_wgl_opengl(GtkWidget * drawingarea)174 void init_wgl_opengl(GtkWidget* drawingarea)
175 {
176     HGLRC glctx;
177     HDC dctx;
178     int pixelformat;
179     PIXELFORMATDESCRIPTOR pfd = {
180         sizeof(PIXELFORMATDESCRIPTOR),          //size of structure
181         1,                                      //default version
182         PFD_DRAW_TO_WINDOW |                    //window drawing support
183         PFD_SUPPORT_OPENGL |                    //opengl support
184         PFD_DOUBLEBUFFER,                       //double buffering support
185         PFD_TYPE_RGBA,                          //RGBA color mode
186         16,                                     //16 bit color mode
187         0, 0, 0, 0, 0, 0,                       //ignore color bits
188         4,                                      //4 bits alpha buffer
189         0,                                      //ignore shift bit
190         0,                                      //no accumulation buffer
191         0, 0, 0, 0,                             //ignore accumulation bits
192         16,                                     //16 bit z-buffer size
193         0,                                      //no stencil buffer
194         0,                                      //no aux buffer
195         PFD_MAIN_PLANE,                         //main drawing plane
196         0,                                      //reserved
197         0, 0, 0                                 //layer masks ignored
198     };
199 
200     width = drawingarea->allocation.width;
201     height = drawingarea->allocation.height;
202 
203     dctx = GetDC(GDK_WINDOW_HWND(gtk_widget_get_window(drawingarea)));
204     devicecontext = dctx;
205 
206     /* Get the closest matching pixel format to what we specified and set it */
207     pixelformat = ChoosePixelFormat(dctx, &pfd);
208     SetPixelFormat(dctx, pixelformat, &pfd);
209 
210     glctx = wglCreateContext(dctx);
211     wglMakeCurrent(dctx, glctx);
212 }
213 #endif /* #ifdef WIN32 */
214 
215 /**
216  * Takes te GtkWindow to draw on - this should always be 'drawingarea'
217  * Calls the correct platform-specific initialization code, then the generic.
218  *
219  * @param drawingarea
220  */
init_opengl(GtkWidget * drawingarea)221 void init_opengl(GtkWidget* drawingarea)
222 {
223 
224 #ifndef WIN32
225     init_glx_opengl(drawingarea);
226 #else
227     init_wgl_opengl(drawingarea);
228 #endif
229     init_opengl_common();
230 }
231 
232 /*
233  * We set up a table of darkness - when opengl draws the first layer, it fills
234  * this in - in this way, we have a table of all the darkness values that we
235  * should use - this makes dealing with darkness much faster, as we don't have
236  * to see if the space is has valid darkness, etc.  We add 2 to the value to
237  * take into acount the padding of an extra space (thus, don't need special
238  * logic for final row/column).  That is +1 value.  but the last row also has
239  * the right/bottom side vertices, and that is where the other +1 comes from
240  */
241 static guint16 map_darkness[(MAP_MAX_SIZE+2)*2][(MAP_MAX_SIZE+2)*2];
242 
243 /*
244  * This is darkness to use if we have no darkness information.  0 makes sense
245  * for standard behaviour, but I find setting this to 255 makes for some
246  * interesting smoothing effects relative to the edge of the screen and blocked
247  * spaces.  I'm not sure if anything other than 0 and 255 would be useful.
248  */
249 #define DEFAULT_DARKNESS    0
250 
251 /**
252  * This lights a space in opengl mode.  It is effectively the same quality as
253  * the sdl per pixel lighting, but opengl makes the work much easier.
254  * Basically, divide the space into 4 smaller subspaces.  We then draw these
255  * 4 squares, setting the color of the different vertices on a average of our
256  * space lightness and that of the neighboring space for the outside vertices.
257  * For the inside (middle) one, we just use our value.  Note that this code
258  * uses the light info of all 8 neighboring spaces.
259  *
260  * I draw all the squares starting in the upper left position and then going to
261  * upper right, bottom right, bottom left
262  *
263  * As a note, for GlColor4ub, 255 is full opaque, 0 fully transparent
264  *
265  * @param x
266  * @param y
267  * @param mx
268  * @param my
269  */
opengl_light_space(int x,int y,int mx,int my)270 static void opengl_light_space(int x, int y, int mx, int my)
271 {
272     if (use_config[CONFIG_DARKNESS] == CFG_LT_TILE) {
273         /* If we don't have darkness, or it isn't dark, don't do anything */
274         if (!mapdata_cell(mx, my)->have_darkness || mapdata_cell(mx, my)->darkness==0) {
275             return;
276         }
277 
278         glColor4ub(0, 0, 0,  mapdata_cell(mx, my)->darkness);
279         glBegin(GL_QUADS);
280         glVertex3i(x * map_image_size, y * map_image_size, 0);
281         glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
282         glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
283         glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
284         glEnd();
285     }
286 
287     /* Do the upper left area */
288     glBegin(GL_QUADS);
289 
290     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2]);
291     glVertex3i(x * map_image_size, y * map_image_size, 0);
292 
293     glColor4ub(0, 0, 0,   map_darkness[x*2 + 1][y*2]);
294     glVertex3i(x * map_image_size + map_image_half_size, y * map_image_size, 0);
295 
296     glColor4ub(0, 0, 0,   map_darkness[x*2 + 1][y*2 + 1]);
297     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
298 
299     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+1]);
300     glVertex3i(x * map_image_size, y * map_image_size + map_image_half_size, 0);
301 
302     glEnd();
303 
304     /* Repeat for upper right area */
305     glBegin(GL_QUADS);
306 
307     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2]);
308     glVertex3i(x * map_image_size + map_image_half_size, y * map_image_size, 0);
309 
310     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2]);
311     glVertex3i((x +1 ) * map_image_size, y * map_image_size, 0);
312 
313     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+1]);
314     glVertex3i((x+1) * map_image_size, y * map_image_size + map_image_half_size, 0);
315 
316     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
317     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
318 
319     glEnd();
320 
321     /* Repeat for lower left area */
322     glBegin(GL_QUADS);
323 
324     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+1]);
325     glVertex3i(x * map_image_size, y * map_image_size + map_image_half_size, 0);
326 
327     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
328     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
329 
330     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+2]);
331     glVertex3i(x * map_image_size + map_image_half_size, (y + 1) * map_image_size, 0);
332 
333     glColor4ub(0, 0, 0,  map_darkness[x*2][y*2+2]);
334     glVertex3i( x * map_image_size, (y +1)* map_image_size, 0);
335 
336     glEnd();
337 
338     /* Repeat for lower right area */
339     glBegin(GL_QUADS);
340 
341     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+1]);
342     glVertex3i( x * map_image_size + map_image_half_size, y * map_image_size + map_image_half_size, 0);
343 
344     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+1]);
345     glVertex3i((x+1) * map_image_size, y * map_image_size + map_image_half_size, 0);
346 
347     glColor4ub(0, 0, 0,  map_darkness[x*2+2][y*2+2]);
348     glVertex3i((x+1) * map_image_size, (y +1)* map_image_size, 0);
349 
350     glColor4ub(0, 0, 0,  map_darkness[x*2+1][y*2+2]);
351     glVertex3i(x * map_image_size + map_image_half_size, (y + 1) * map_image_size, 0);
352 
353     glEnd();
354 }
355 
356 /*
357  * Some basics.  dx, dy are coordinate pairs for offsets. bweights and cweights
358  * are bitmasks that determine the face to draw (or'd together)
359  */
360 static int dx[8]= {0,1,1,1,0,-1,-1,-1};
361 static int dy[8]= {-1,-1,0,1,1,1,0,-1};
362 
363 static int bweights[8]= {2,0,4,0,8,0,1,0};
364 static int cweights[8]= {0,2,0,4,0,8,0,1};
365 static int bc_exclude[8]= {
366     1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
367     0,
368     2+4,/*east exclude northeast and southeast*/
369     0,
370     4+8,/*and so on*/
371     0,
372     8+1,
373     0
374 };
375 
376 /*
377  * Vertices are floats.  This sets the value appropriately for us to multiply
378  * the x coordinate by.
379  */
380 #define     TEXTURE_OFFSET  1.0/16.0
381 
382 /**
383  * Draw anything in adjacent squares that could smooth on given square You
384  * should not call this function to smooth on a 'completely black' square.
385  * (simply for visual result).
386  *
387  * @param x
388  * @param y
389  * @param mx Coordinate of square to smooth on.
390  * @param my Coordinate of square to smooth on.
391  * @param layer Layer to examine (we smooth only one layer at a time).
392  */
drawsmooth_opengl(int x,int y,int mx,int my,int layer)393 static void drawsmooth_opengl (int x, int y, int mx, int my, int layer)
394 {
395     int partdone[8]= {0,0,0,0,0,0,0,0}, slevels[8], sfaces[8], i,
396                      weight,weightC, emx,emy, smoothface, dosmooth, lowest, havesmooth;
397 
398     dosmooth=0;
399     for (i=0; i<8; i++) {
400         emx=mx+dx[i];
401         emy=my+dy[i];
402 
403         if (!mapdata_contains(emx, emy)) {
404             slevels[i]=0;
405             sfaces[i]=0; /*black picture*/
406         } else if (mapdata_cell(emx, emy)->smooth[layer]<=mapdata_cell(mx, my)->smooth[layer] ||
407                    mapdata_cell(emx, emy)->heads[layer].face == 0) {
408             slevels[i]=0;
409             sfaces[i]=0; /*black picture*/
410         } else {
411             slevels[i]=mapdata_cell(emx, emy)->smooth[layer];
412             sfaces[i]=pixmaps[mapdata_cell(emx, emy)->heads[layer].face]->smooth_face;
413             dosmooth++;
414         }
415     }
416 
417     /*
418      * slevels[] & sfaces[] contain the smooth level.  dosmooth is the number
419      * if spaces that need to be smoothed.  lowlevel is the lowest level to
420      * smooth.
421      *
422      * havesmooth is how many faces we have smoothed
423      */
424     havesmooth=0;
425 
426     while (havesmooth < dosmooth) {
427         lowest=-1;
428         for (i=0; i<8; i++) {
429             if ( (slevels[i]>0) && (!partdone[i]) && ((lowest<0) || (slevels[i]<slevels[lowest]))) {
430                 lowest=i;
431             }
432         }
433         if (lowest<0) {
434             break;    /*no more smooth to do on this square*/
435         }
436 
437         /* The weight values is a bitmask that determines what image we draw */
438         weight=0;
439         weightC=15; /*works in backward. remove where there is nothing*/
440 
441         for (i=0; i<8; i++) { /*check all nearby squares*/
442             if (slevels[i]==slevels[lowest] && sfaces[i] == sfaces[lowest]) {
443                 partdone[i]=1;
444                 weight=weight+bweights[i];
445                 weightC&=~bc_exclude[i];
446                 havesmooth++;
447             } else {
448                 /*must rmove the weight of a corner if not in smoothing*/
449                 weightC&=~cweights[i];
450             }
451         }
452 
453         smoothface=sfaces[lowest];
454         if (smoothface<=0) {
455             continue;  /*picture for smoothing not yet available*/
456         }
457 
458         /*
459          * Now, it's quite easy. We must draw using a 32x32 part of the picture
460          * smoothface.
461          * This part is located using the 2 weights calculated: (32*weight,0)
462          * and (32*weightC,32)
463          */
464 
465         if ( (!pixmaps[smoothface]->map_texture) || (pixmaps[smoothface] == pixmaps[0])) {
466             continue;    /*don't have the picture associated*/
467         }
468 
469         if (mapdata_cell(mx, my)->cleared) {
470             glBindTexture(GL_TEXTURE_2D, pixmaps[smoothface]->fog_texture);
471         } else {
472             glBindTexture(GL_TEXTURE_2D, pixmaps[smoothface]->map_texture);
473         }
474 
475         /*
476          * The values of 0.0f and 0.5f are hardcoded, but as of now, it is a
477          * known fact that there are 2 rows of data in the smoothing images, so
478          * that should be OK.
479          */
480         if (weight) {
481             glBegin(GL_QUADS);
482 
483             glTexCoord2f(TEXTURE_OFFSET * weight, 0.0f);
484             glVertex3i(x * map_image_size, y * map_image_size, 0);
485 
486             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.0f);
487             glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
488 
489             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.5f);
490             glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
491 
492             glTexCoord2f(TEXTURE_OFFSET * weight, 0.5f);
493             glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
494 
495             glEnd();
496         }
497         if (weightC) {
498             glBegin(GL_QUADS);
499 
500             glTexCoord2f(TEXTURE_OFFSET * weight, 0.5f);
501             glVertex3i(x * map_image_size, y * map_image_size, 0);
502 
503             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 0.5f);
504             glVertex3i((x+1) * map_image_size, y * map_image_size, 0);
505 
506             glTexCoord2f(TEXTURE_OFFSET * (weight+1), 1.0f);
507             glVertex3i((x+1) * map_image_size, (y+1) * map_image_size, 0);
508 
509             glTexCoord2f(TEXTURE_OFFSET * weight, 1.0f);
510             glVertex3i(x * map_image_size, (y+1) * map_image_size, 0);
511 
512             glEnd();
513         }
514     } /* While there's some smooth to do */
515 }
516 
517 /**
518  *
519  * @param layer
520  */
draw_smoothing(int layer)521 static void draw_smoothing(int layer)
522 {
523     int x, y, mx, my;
524 
525     for(y = use_config[CONFIG_MAPHEIGHT]+MAX_MAP_OFFSET; y>=0; y--) {
526         for(x = use_config[CONFIG_MAPWIDTH]+MAX_MAP_OFFSET; x>=0; x--) {
527 
528             mx = x + pl_pos.x;
529             my = y + pl_pos.y;
530 
531             if (mapdata_can_smooth(mx, my,layer)) {
532                 drawsmooth_opengl(x, y, mx, my, layer);
533             }
534         }
535     }
536 }
537 
538 /**
539  * Generates a map in Opengl mode and is based loosely on the SDL code.  We
540  * re-draw the entire map every time this is called
541  *
542  * Note that at current time, most of the options are not available.  On my
543  * system, opengl is blindingly fast compared to other drawing methods - for
544  * the 25x25 map, sdl/pixmap took almost 100% of cpu time (athlon mp 2000).  On
545  * opengl, cpu time is less than 10%.  And that is with redrawing the entire
546  * map each time.  As such, the more complex drawing options should still be
547  * easily handled on any system that does have opengl.
548  * (For reference, glxgears gets about 380 fps on my system)
549  * MSW 2005-03-14a
550  *
551  * @param redraw
552  */
opengl_gen_map(int redraw)553 void opengl_gen_map(int redraw) {
554     int mx,my, layer,x,y, d1, d2, d3, num_dark, got_smooth, face, t1, t2;
555     glClear(GL_COLOR_BUFFER_BIT);
556 
557     /*
558      * Need to set this, as the darkness logic could have reset this.  since
559      * darkness is done after all other drawing, we can do it just once here.
560      */
561     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
562 
563     /* We draw every space every time this is called.  We draw from bottom
564      * right to top left - this makes stacking of big images work as expected.
565      * we also draw all of one layer before doing the next layer.  This really
566      * shouldn't effect performance all that much - all that is being changed
567      * is the order of the loops we add MAX_MAP_OFFSET so that big objects off
568      * the edge of the map are drawn.
569      */
570 
571     got_smooth=0; /*smooth marker. Once we have a face and "can_smooth" on a layer, this layer and all above draw smooth */
572 
573     for (layer=0; layer<=MAXLAYERS; layer++) {
574 
575 
576         if (layer == MAXLAYERS) {
577             /*
578              * The top layer is the darkness processing - turn off the texture
579              * pattern so darkness works as expected.
580              */
581             glBindTexture(GL_TEXTURE_2D, 0);
582         }
583         for(y = use_config[CONFIG_MAPHEIGHT]+MAX_MAP_OFFSET; y>=0; y--) {
584             for(x = use_config[CONFIG_MAPWIDTH]+MAX_MAP_OFFSET; x>=0; x--) {
585                 /*
586                  * mx,my represent the spaces on the 'virtual' map (ie, the_map
587                  * structure).  x and y (from the for loop) represent the
588                  * visible screen.
589                  */
590                 mx = x + pl_pos.x;
591                 my = y + pl_pos.y;
592                 /*
593                  * If we get here, this denotes a special/top layer.  This is
594                  * the time to do lighting, smoothing, etc.
595                  */
596                 if (layer == MAXLAYERS) {
597                     /*
598                      * If off the map, don't need to do anything, because the
599                      * code here doesn't do anything that would extend onto the
600                      * map.
601                      */
602                     if (x >= use_config[CONFIG_MAPWIDTH] || y >= use_config[CONFIG_MAPHEIGHT]) {
603                         continue;
604                     }
605                     /*
606                      * One could make the case it doesn't make sense to light
607                      * fog of war spaces, but I find visually it looks a lot
608                      * nicer if you do - otherwise, they are too bright
609                      * relative to the spaces around.  them.
610                      */
611                     if (use_config[CONFIG_DARKNESS]) {
612                         opengl_light_space(x, y, mx, my);
613                     }
614 
615                 } else {
616                     /*
617                      * Only do this in the better lighting modes.  Fortunately,
618                      * the CFG_LT_.. values are ordered from worst to best, to
619                      * are >= check works just fine, right now.
620                      */
621                     if (layer == 0 && use_config[CONFIG_DARKNESS] >= CFG_LT_PIXEL &&
622                             ~                       x <= use_config[CONFIG_MAPWIDTH] && y <= use_config[CONFIG_MAPHEIGHT]) {
623                         /*
624                          * The darkness code is similar to the per pixel SDL
625                          * code.  As such, each square we process needs to know
626                          * the values for the intersection points - there is a
627                          * lot of redundant calculation in this if done a
628                          * square at a time, so instead, we can calculate the
629                          * darkness point of all the vertices here.  We
630                          * calculate the upper/left 4 vertices.
631                          *
632                          * SDL actually gets better results I think - perhaps
633                          * because the per pixel lighting uses a different
634                          * algorithm - we basically let opengl do the blending.
635                          * But the results we use here, while perhaps not as
636                          * nice, certainly look better than per tile lighting.
637                          */
638                         if (mapdata_cell(mx, my)->have_darkness) {
639                             map_darkness[x*2 + 1][y*2 + 1] = mapdata_cell(mx, my)->darkness;
640                         } else {
641                             map_darkness[x*2 + 1][y*2 + 1] = DEFAULT_DARKNESS;
642                         }
643 
644                         d1 = DEFAULT_DARKNESS;  /* square to left */
645                         d2 = DEFAULT_DARKNESS;  /* square to upper left */
646                         d3 = DEFAULT_DARKNESS;  /* square above */
647                         num_dark=1; /* Number of adjoining spaces w/darkness */
648 
649                         if (x>0 && mapdata_cell(mx-1, my)->have_darkness) {
650                             d1 = mapdata_cell(mx-1, my)->darkness;
651                             num_dark++;
652                         }
653 
654                         if (x>0 && y>0 && mapdata_cell(mx-1, my-1)->have_darkness) {
655                             d2 = mapdata_cell(mx-1, my-1)->darkness;
656                             num_dark++;
657                         }
658 
659                         if (y>0 && mapdata_cell(mx, my-1)->have_darkness) {
660                             d3 = mapdata_cell(mx, my-1)->darkness;
661                             num_dark++;
662                         }
663 #if 0
664                         /*
665                          * If we don't have darkness, we want to use our value
666                          * and not average.  That is because the value we
667                          * average against is 0 - this results in lighter bands
668                          * next to areas we won't have darkness info for.
669                          */
670                         map_darkness[x*2][y*2] = (d1 + d2 +d3 + map_darkness[x*2 + 1][y*2 + 1]) / num_dark;
671 
672                         if (d1) {
673                             map_darkness[x*2][y*2 + 1] = (d1 + map_darkness[x*2 + 1][y*2 + 1]) / 2;
674                         } else {
675                             map_darkness[x*2][y*2 + 1] = map_darkness[x*2 + 1][y*2 + 1];
676                         }
677 
678                         if (d3) {
679                             map_darkness[x*2 +1 ][y*2] = (d3 + map_darkness[x*2 + 1][y*2 + 1]) / 2;
680                         } else {
681                             map_darkness[x*2 + 1][y*2] = map_darkness[x*2 + 1][y*2 + 1];
682                         }
683 #else
684                         /*
685                          * This block does a 'max' darkness - I think it gives
686                          * the best results, which is why by default it is the
687                          * one used.
688                          */
689                         map_darkness[x*2][y*2] = MAX( MAX(d1, d2), MAX(d3, map_darkness[x*2 + 1][y*2 + 1]));
690                         map_darkness[x*2][y*2 + 1] = MAX(d1, map_darkness[x*2 + 1][y*2 + 1]);
691                         map_darkness[x*2 + 1][y*2] = MAX(d3, map_darkness[x*2 + 1][y*2 + 1]);
692 #endif
693                     }
694 
695                     if (mapdata_cell(mx, my)->heads[layer].face) {
696                         if (pixmaps[mapdata_cell(mx, my)->heads[layer].face]->map_texture) {
697                             int nx, ny;
698 
699                             /*
700                              * nx, ny are the location of the top/left side of
701                              * the image to draw.
702                              */
703                             nx = (x+1) * map_image_size - pixmaps[mapdata_cell(mx, my)->heads[layer].face]->map_width;
704                             ny = (y+1) * map_image_size - pixmaps[mapdata_cell(mx, my)->heads[layer].face]->map_height;
705                             /*
706                              * If both nx and ny are outside visible area,
707                              * don't need to do anything more
708                              */
709                             if (nx > width && ny > height) {
710                                 continue;
711                             }
712                             /*
713                              * There are some issues with this - it is really
714                              * the head of the object that is determining fog
715                              * of war logic.  I don't have good solution to
716                              * that, other than to live with it.
717                              */
718                             if (mapdata_cell(mx, my)->cleared) {
719                                 glBindTexture(GL_TEXTURE_2D, pixmaps[mapdata_cell(mx, my)->heads[layer].face]->fog_texture);
720                             } else {
721                                 glBindTexture(GL_TEXTURE_2D, pixmaps[mapdata_cell(mx, my)->heads[layer].face]->map_texture);
722                             }
723 
724                             glBegin(GL_QUADS);
725 
726                             glTexCoord2f(0.0f, 0.0f);
727                             glVertex3i(nx, ny, 0);
728 
729                             glTexCoord2f(1.0f, 0.0f);
730                             glVertex3i( (x+1) * map_image_size, ny, 0);
731 
732                             glTexCoord2f(1.0f, 1.0f);
733                             glVertex3i( (x+1) * map_image_size, (y+1) * map_image_size, 0);
734 
735                             glTexCoord2f(0.0f, 1.0f);
736                             glVertex3i(nx, (y+1) * map_image_size, 0);
737 
738                             glEnd();
739                         }
740                         if (use_config[CONFIG_SMOOTH] && mapdata_can_smooth(mx, my, layer) &&
741                                 mapdata_cell(mx, my)->heads[layer].face !=0) {
742 
743                             got_smooth=1;
744                         }
745                     }
746                     if ((face=mapdata_bigface_head(x, y, layer, &t1, &t2))!=0) {
747                         if (pixmaps[face]->map_texture) {
748                             int nx, ny;
749 
750                             /*
751                              * nx, ny are the location of the top/left side of
752                              * the image to draw.
753                              */
754                             nx = (x+1) * map_image_size - pixmaps[face]->map_width;
755                             ny = (y+1) * map_image_size - pixmaps[face]->map_height;
756                             /*
757                              * If both nx and ny are outside visible area,
758                              * don't need to do anything more
759                              */
760                             if (nx > width && ny > height) {
761                                 continue;
762                             }
763                             /*
764                              * There are some issues with this - it is really
765                              * the head of the object that is determining fog
766                              * of war logic.  I don't have good solution to
767                              * that, other than to live with it.
768                              */
769                             if (mapdata_cell(mx, my)->cleared) {
770                                 glBindTexture(GL_TEXTURE_2D, pixmaps[face]->fog_texture);
771                             } else {
772                                 glBindTexture(GL_TEXTURE_2D, pixmaps[face]->map_texture);
773                             }
774 
775                             glBegin(GL_QUADS);
776 
777                             glTexCoord2f(0.0f, 0.0f);
778                             glVertex3i(nx, ny, 0);
779 
780                             glTexCoord2f(1.0f, 0.0f);
781                             glVertex3i( (x+1) * map_image_size, ny, 0);
782 
783                             glTexCoord2f(1.0f, 1.0f);
784                             glVertex3i( (x+1) * map_image_size, (y+1) * map_image_size, 0);
785 
786                             glTexCoord2f(0.0f, 1.0f);
787                             glVertex3i(nx, (y+1) * map_image_size, 0);
788 
789                             glEnd();
790                         }
791                     } /* If this space has a valid face */
792                 } /* If last layer/else not last layer */
793             } /* for x loop */
794         } /* for y loop */
795 
796         /*
797          * Because of our handling with big images, we can't easily draw this
798          * when drawing the space - we may want to smooth onto another space in
799          * which the ground hasn't been drawn yet, so we have to do smoothing
800          * at the end of each layer.
801          *
802          * We use the got_smooth variable to know if there is in fact any
803          * smoothing to do - for many layers, this is not likely to be set, so
804          * we can save work by not doing this.
805          */
806         if (got_smooth) {
807             draw_smoothing(layer);
808         }
809     }
810 
811 #ifndef WIN32
812     glXSwapBuffers(display, window);
813 #else
814     SwapBuffers(devicecontext);
815 #endif
816 }
817 
818 /**
819  * Rather than put a bunch of opengl code in the image.c file, it instead calls
820  * these routines for the image creation logic.
821  *
822  * @param data
823  * @param pi
824  */
create_opengl_map_image(guint8 * data,PixmapInfo * pi)825 void create_opengl_map_image(guint8 *data, PixmapInfo *pi)
826 {
827     static guint8 *newdata;
828     static int size=0;
829     int nwidth, nheight, numshifts, i;
830     guint8 *data_to_use = data, *l;
831     guint32 g, *p;
832 
833     /*
834      * The width and height of textures has to be a power of 2.  so 32x32 and
835      * 64x64 images work, but 96x96 does not.  The logic below basically
836      * figures out if the width we have is in fact a power of two or not, and
837      * if not, the next power of 2 up that is.
838      */
839     for (nwidth = pi->map_width, numshifts=0; nwidth >1; nwidth >>=1, numshifts++) ;
840     nwidth <<= numshifts;
841     if (nwidth != pi->map_width) {
842         nwidth <<=1;
843     }
844 
845     for (nheight = pi->map_height, numshifts=0; nheight >1; nheight >>=1, numshifts++) ;
846     nheight <<= numshifts;
847     if (nheight != pi->map_height) {
848         nheight <<=1;
849     }
850     /*
851      * Below deals with cases where the pixmap is not a power of 2.  The
852      * 'proper' opengl way of dealing with such textures is to make a mipmap -
853      * this is basically a resized version up/down to the nearest power of two,
854      * which is then rescaled when it is used to actually texture something -
855      * this means it is scaled up once, then scaled down again.  For most
856      * opengl apps, this probably isn't a big deal, because the surface the
857      * texture being applied applied to is going to cause distortion.  However,
858      * in this client, we are doing a 1:1 paste operation, so that scaling will
859      * certainly cause some distortion.  instead, I take the approach make a
860      * bigger image, but fill the extra bits with transparent alpha bits.  This
861      * way, we have no loss of quality.
862      */
863     if (pi->map_width != nwidth || pi->map_height != nheight) {
864         int y;
865         guint8   *datastart;
866 
867         /*
868          * Use a static buffer to hold image data, so we don't have to keep
869          * allocating/deallocating, but need to make sure it is big enough.
870          */
871         if (nwidth * nheight * 4 > size) {
872             size = nwidth * nheight * 4;
873             newdata = g_realloc(newdata, size);
874 
875             if (newdata == NULL) {
876                 LOG(LOG_ERROR, "create_opengl_map_image",
877                         "Could not allocate memory: %s", strerror(errno));
878                 exit(EXIT_FAILURE);
879             }
880         }
881         /*
882          * Fill the top portion of the image with empty/transparent data.
883          * Also, set up datastart to point to where we should start filling in
884          * the rest of the data.
885          */
886         if (nheight > pi->map_height) {
887             memset(newdata, 0, (nheight - pi->map_height) * nwidth * 4);
888             datastart = newdata + (nheight - pi->map_height) * nwidth * 4;
889         } else {
890             datastart = newdata;
891         }
892 
893         for (y =0; y < pi->map_height; y++) {
894             memset(datastart + y * nwidth * 4, 0, (nwidth - pi->map_width) * 4);
895             memcpy(datastart + y * nwidth * 4 + (nwidth - pi->map_width) * 4,
896                    data + y * pi->map_width * 4, pi->map_width * 4);
897         }
898         data_to_use = newdata;
899         pi->map_width = nwidth;
900         pi->map_height = nheight;
901     }
902 
903     glGenTextures(1, &pi->map_texture);
904     glBindTexture(GL_TEXTURE_2D, pi->map_texture);
905     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
906     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
907 
908     glTexImage2D(GL_TEXTURE_2D, 0, 4, pi->map_width, pi->map_height,
909                  0, GL_RGBA, GL_UNSIGNED_BYTE, data_to_use);
910 
911     /*
912      * Generate a fog image.  This isn't 100% efficient, because we copy data
913      * we may need to modify, but makes the code simpler in in the case above
914      * where we've had to change the size of the image.
915      */
916 
917     if (pi->map_width * pi->map_height * 4 > size) {
918         size = pi->map_width * pi->map_height * 4;
919         newdata = g_realloc(newdata, size);
920     }
921 
922     /* In this case, newdata does not contain a copy of the data - make one */
923     if (data_to_use != newdata) {
924         memcpy(newdata, data, pi->map_height *  pi->map_width * 4);
925     }
926 
927     for (i=0; i < pi->map_width * pi->map_height; i++) {
928         l = (guint8 *) (newdata + i*4);
929         g = MAX(*l, *(l+1));
930         g = MAX(g, *(l+2));
931         p = (guint32*) newdata + i;
932         *p = g | (g << 8) | (g << 16) | (*(l + 3) << 24);
933     }
934 
935     glGenTextures(1, &pi->fog_texture);
936     glBindTexture(GL_TEXTURE_2D, pi->fog_texture);
937     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
938     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
939 
940     glTexImage2D(GL_TEXTURE_2D, 0, 4, pi->map_width, pi->map_height,
941                  0, GL_RGBA, GL_UNSIGNED_BYTE, newdata);
942 }
943 
944 /**
945  *
946  * @param pi
947  */
opengl_free_pixmap(PixmapInfo * pi)948 void opengl_free_pixmap(PixmapInfo *pi)
949 {
950     if (pi->map_texture) {
951         glDeleteTextures(1, &pi->map_texture);
952         pi->map_texture=0;
953     }
954     if (pi->fog_texture) {
955         glDeleteTextures(1, &pi->fog_texture);
956         pi->fog_texture=0;
957     }
958 }
959 
960 #include "../../pixmaps/question.111"
961 
962 /**
963  * Create question mark to display in OpenGL mode when an image is not cached.
964  * When image caching is enabled, if a needed image is not yet in the cache, a
965  * question mark image is displayed instead.  The image displayed is unique to
966  * the display mode.  This function creates the image to use when OpenGL mode
967  * is in effect.
968  */
create_opengl_question_mark(void)969 void create_opengl_question_mark(void)
970 {
971     GLubyte question[question_height][question_width][4];
972     int xb, x, y, offset=0;
973 
974     /*
975      * We want data in rgba format.  So convert the question bits to an rgba
976      * format.  We only need to do this once
977      */
978     for (y=0; y<question_height; y++) {
979         for (xb=0; xb<question_width/8; xb++) {
980             for (x=0; x<8; x++) {
981                 if (question_bits[offset] & (1 << x)) {
982                     question[y][xb * 8 + x][0] = 255;
983                     question[y][xb * 8 + x][1] = 255;
984                     question[y][xb * 8 + x][2] = 255;
985                     question[y][xb * 8 + x][3] = 255;
986                 } else {
987                     question[y][xb * 8 + x][0] = 0;
988                     question[y][xb * 8 + x][1] = 0;
989                     question[y][xb * 8 + x][2] = 0;
990                     question[y][xb * 8 + x][3] = 0;
991                 }
992             }
993             offset++;
994         }
995     }
996 
997     glGenTextures(1, &pixmaps[0]->map_texture);
998     glBindTexture(GL_TEXTURE_2D, pixmaps[0]->map_texture);
999     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1000     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1001 
1002     glTexImage2D(GL_TEXTURE_2D, 0, 4, question_width, question_height,
1003                  0, GL_RGBA, GL_UNSIGNED_BYTE, &question[0][0][0]);
1004 
1005     glGenTextures(1, &pixmaps[0]->fog_texture);
1006     glBindTexture(GL_TEXTURE_2D, pixmaps[0]->fog_texture);
1007     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1008     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1009 
1010     glTexImage2D(GL_TEXTURE_2D, 0, 4, question_width, question_height,
1011                  0, GL_RGBA, GL_UNSIGNED_BYTE, &question[0][0][0]);
1012 }
1013 
1014 #endif
1015