Crossfire Client, Trunk
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 
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 
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 
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 
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 
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 
270 static void opengl_light_space(int x, int y, int mx, int my)
271 {
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]);
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]);
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]);
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]);
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 
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 
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 
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  */
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  */
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 &&
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 
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 
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 
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
mapdata_cell
struct MapCell * mapdata_cell(const int x, const int y)
Definition: mapdata.c:127
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:439
redraw
static gboolean redraw(gpointer data)
Definition: main.c:126
init_glx_opengl
void init_glx_opengl(GtkWidget *drawingarea)
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:440
PlayerPosition::x
int x
Definition: client.h:530
CFG_LT_PIXEL
#define CFG_LT_PIXEL
Definition: client.h:233
MapCell::cleared
guint8 cleared
Definition: mapdata.h:64
pixmaps
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:38
height
static int height
Definition: mapdata.c:90
mapdata_can_smooth
bool mapdata_can_smooth(int x, int y, int layer)
Definition: mapdata.c:142
PlayerPosition::y
int y
Definition: client.h:531
CFG_LT_TILE
#define CFG_LT_TILE
Definition: client.h:232
mapdata.h
map_image_half_size
int map_image_half_size
Definition: main.h:34
PixmapInfo::map_height
guint16 map_height
Definition: image.h:60
MAX_MAP_OFFSET
#define MAX_MAP_OFFSET
Definition: client.h:487
MapCellLayer::face
gint16 face
Definition: mapdata.h:19
PixmapInfo::map_width
guint16 map_width
Definition: image.h:60
MapCell::heads
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:57
init_opengl
void init_opengl(GtkWidget *drawingarea)
gtk2proto.h
MapCell::smooth
guint8 smooth[MAXLAYERS]
Definition: mapdata.h:59
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
mapdata_bigface_head
gint16 mapdata_bigface_head(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:1168
width
static int width
Definition: mapdata.c:89
PixmapInfo::smooth_face
guint16 smooth_face
Definition: image.h:62
MAP_MAX_SIZE
#define MAP_MAX_SIZE
Definition: client.h:471
MapCell::darkness
guint8 darkness
Definition: mapdata.h:60
image.h
opengl_gen_map
void opengl_gen_map(int redraw)
create_opengl_question_mark
void create_opengl_question_mark(void)
mapdata_contains
bool mapdata_contains(int x, int y)
Definition: mapdata.c:134
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:441
main.h
CONFIG_MAPWIDTH
#define CONFIG_MAPWIDTH
Definition: client.h:208
opengl_free_pixmap
void opengl_free_pixmap(PixmapInfo *pi)
CONFIG_SMOOTH
#define CONFIG_SMOOTH
Definition: client.h:215
pl_pos
PlayerPosition pl_pos
Definition: map.c:37
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:247
create_opengl_map_image
void create_opengl_map_image(guint8 *data, PixmapInfo *pi)
MAXLAYERS
#define MAXLAYERS
Definition: mapdata.h:6
PixmapInfo
Definition: image.h:47
CONFIG_MAPHEIGHT
#define CONFIG_MAPHEIGHT
Definition: client.h:209
map_image_size
int map_image_size
Definition: map.c:41
CONFIG_DARKNESS
#define CONFIG_DARKNESS
Definition: client.h:211
client.h