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