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