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