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