1 /*
2 *
3 * Copyright (c) 2010 Arthur Huillet
4 * Copyright (c) 2003 Johannes Prix
5 *
6 *
7 * This file is part of Freedroid
8 *
9 * Freedroid is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * Freedroid is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Freedroid; see the file COPYING. If not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 *
24 */
25
26 /**
27 * This file contains function relevant for OpenGL based graphics output.
28 */
29
30 #define _open_gl_c
31
32 #include <math.h>
33 #include "system.h"
34
35 #include "defs.h"
36 #include "struct.h"
37 #include "global.h"
38 #include "proto.h"
39
40 // 28 degress is the magic angle for our iso view
41 #define COS_28 0.88294759
42 #define SIN_28 0.46947156
43
44 int gl_max_texture_size;
45
46 /**
47 * This is a wrapper for the SDL_Flip function, that will use either the
48 * OpenGL buffer-swapping or the classic SDL flipper, depending on the
49 * current output method, like OpenGL or not.
50 */
our_SDL_flip_wrapper()51 int our_SDL_flip_wrapper()
52 {
53 #ifdef DEBUG_QUAD_BORDER
54 debug_quad_border_seed = 0;
55 #endif
56
57 if (use_open_gl)
58 SDL_GL_SwapBuffers();
59 else
60 return (SDL_Flip(Screen));
61
62 return (0);
63 }; // int our_SDL_flip_wrapper ( SDL_Surface *screen )
64
65 /**
66 *
67 *
68 */
our_SDL_update_rect_wrapper(SDL_Surface * screen,Sint32 x,Sint32 y,Sint32 w,Sint32 h)69 void our_SDL_update_rect_wrapper(SDL_Surface * screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
70 {
71 if (use_open_gl) {
72 our_SDL_flip_wrapper();
73 } else {
74 SDL_UpdateRect(screen, x, y, w, h);
75 }
76 }; // void our_SDL_update_rect_wrapper ( SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h )
77
78 /**
79 * Simon N.: ISO functions. these draw quads in the 3D planes
80 */
drawISOXYQuad(int x,int y,int z,int w,int h)81 void drawISOXYQuad(int x, int y, int z, int w, int h)
82 {
83 #ifdef HAVE_LIBGL
84 glVertex3f(x, y - h, z);
85 glVertex3f(x, y, z);
86 glVertex3f(x + w * COS_28, y + w * SIN_28, z);
87 glVertex3f(x + w * COS_28, y - h + w * SIN_28, z);
88 #endif
89 }
90
drawISOXZQuad(int x,int y,int z,int w,int d)91 void drawISOXZQuad(int x, int y, int z, int w, int d)
92 {
93 #ifdef HAVE_LIBGL
94 glVertex3f(x + d * COS_28, y - d * SIN_28, z);
95 glVertex3f(x, y, z);
96 glVertex3f(x + w * COS_28, y + w * SIN_28, z);
97 glVertex3f(x + w * COS_28 + d * COS_28, y + w * SIN_28 - d * SIN_28, z);
98 #endif
99 }
100
drawISOYZQuad(int x,int y,int z,int h,int d)101 void drawISOYZQuad(int x, int y, int z, int h, int d)
102 {
103 #ifdef HAVE_LIBGL
104 glVertex3f(x, y - h, z);
105 glVertex3f(x, y, z);
106 glVertex3f(x + d * COS_28, y - d * SIN_28, z);
107 glVertex3f(x + d * COS_28, y - h - d * SIN_28, z);
108 #endif
109 }
110
111 /**
112 * Simon N.: Draws an isometric energy bar.
113 * x,y,z : the position of the lower left hand corner
114 * h : the height of the energy bar, as if viewed in the X direction
115 * d : the depth of the energy bar, as if viewed in the X direction
116 * fill : the percentage the energy bar is filled
117 * c1 : the fill color
118 * c1 : the background color
119 */
drawIsoEnergyBar(int x,int y,int z,int h,int d,int length,float fill,myColor * c1,myColor * c2)120 void drawIsoEnergyBar(int x, int y, int z, int h, int d, int length, float fill, myColor * c1, myColor * c2)
121 {
122 #ifdef HAVE_LIBGL
123 int l = (int)(fill * length);
124 int l2 = (int)length * (1.0 - fill);
125 int lcos, lsin, l2cos, l2sin;
126 glColor4ub(c1->r, c1->g, c1->b, c1->a);
127 glDisable(GL_TEXTURE_2D);
128 glBegin(GL_QUADS);
129
130 lcos = (int)rint(l * COS_28);
131 lsin = (int)rint(l * SIN_28);
132 // think of this a dcos, same reason above
133 l2cos = (int)rint(d * COS_28);
134 l2sin = (int)rint(d * SIN_28);
135 drawISOXYQuad(x, y, z, d, h);
136 drawISOYZQuad(x + l2cos, y + l2sin, z, h, l);
137 drawISOXZQuad(x, y - h, z, d, l);
138
139 glColor4ub(c2->r, c2->g, c2->b, c2->a);
140 drawISOYZQuad(x + l2cos + lcos, y + l2sin - lsin, z, h, l2);
141 drawISOXZQuad(x + lcos, y - lsin - h, z, d, l2);
142
143 glEnd();
144 glEnable(GL_TEXTURE_2D);
145 glColor4ub(255, 255, 255, 255);
146 #endif
147 }; // void drawIsoEnergyBar(int dir, int x, int y, int z, int h, int d, int length, float fill, myColor *c1, myColor *c2 )
148
149 /**
150 * This function flips a given SDL_Surface.
151 *
152 * This is particularly necessary, since OpenGL has a different native
153 * coordinate system than SDL and therefore images often appear flipped
154 * around if one doesn't counter this effect with OpenGL by flipping the
155 * images just once more in the same fashion. That is what this function
156 * does.
157 */
flip_image_vertically(SDL_Surface * tmp1)158 void flip_image_vertically(SDL_Surface * tmp1)
159 {
160 SDL_LockSurface(tmp1);
161
162 int nHH = tmp1->h >> 1;
163 int nPitch = tmp1->pitch;
164
165 unsigned char pBuf[nPitch + 1];
166 unsigned char *pSrc = (unsigned char *)tmp1->pixels;
167 unsigned char *pDst = (unsigned char *)tmp1->pixels + nPitch * (tmp1->h - 1);
168
169 while (nHH--) {
170 memcpy(pBuf, pSrc, nPitch);
171 memcpy(pSrc, pDst, nPitch);
172 memcpy(pDst, pBuf, nPitch);
173
174 pSrc += nPitch;
175 pDst -= nPitch;
176 }
177
178 SDL_UnlockSurface(tmp1);
179
180 }; // void flip_image_vertically ( SDL_Surface* tmp1 )
181
182 /**
183 *
184 *
185 */
our_IMG_load_wrapper(const char * file)186 SDL_Surface *our_IMG_load_wrapper(const char *file)
187 {
188 SDL_Surface *surf;
189
190 surf = IMG_Load(file);
191
192 if (surf == NULL) {
193 error_message(__FUNCTION__, "IMG_Load returned NULL. IMG_GetError() : %s.", PLEASE_INFORM, IMG_GetError());
194 return (NULL);
195 }
196
197 if (use_open_gl) {
198 // flip_image_vertically(surf);
199 }
200
201 return surf;
202 }
203
204 /**
205 * There is need to do some padding, cause OpenGL textures need to have
206 * a format: width and length both each a power of two. Therefore some
207 * extra alpha to the sides must be inserted. This is what this function
208 * is supposed to do: manually adding the proper amount of padding to
209 * the surface, so that the dimensions will reach the next biggest power
210 * of two in both directions, width and length.
211 */
212 #ifdef HAVE_LIBGL
pad_image_for_texture(SDL_Surface * our_surface)213 static SDL_Surface *pad_image_for_texture(SDL_Surface * our_surface)
214 {
215 int x = 1;
216 int y = 1;
217 SDL_Surface *padded_surf;
218 SDL_Rect dest;
219
220 while (x < our_surface->w)
221 x <<= 1;
222 while (y < our_surface->h)
223 y <<= 1;
224
225 padded_surf = SDL_CreateRGBSurface(0, x, y, 32, rmask, gmask, bmask, amask);
226
227 SDL_SetAlpha(our_surface, SDL_RLEACCEL, 0);
228 dest.x = 0;
229 dest.y = y - our_surface->h;
230 dest.w = our_surface->w;
231 dest.h = our_surface->h;
232
233 SDL_BlitSurface(our_surface, NULL, padded_surf, &dest);
234
235 return padded_surf;
236 }
237 #endif
238
239 /**
240 * If OpenGL is in use, we need to make textured quads out of our normal
241 * SDL surfaces.
242 */
243 #ifdef HAVE_LIBGL
do_make_texture_out_of_surface(struct image * our_image,int txw,int txh,void * data)244 static void do_make_texture_out_of_surface(struct image * our_image, int txw, int txh, void *data)
245 {
246 // Stop any image batch being constructed, if relevant
247 end_image_batch();
248
249 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
250
251 if (!our_image->texture) {
252 glGenTextures(1, &our_image->texture);
253 }
254
255 our_image->texture_type = TEXTURE_CREATED;
256 DebugPrintf(1, "Using texture %d\n", our_image->texture);
257
258 glBindTexture(GL_TEXTURE_2D, (our_image->texture));
259
260 // We tend to scale those textures a lot, so we use linear filtering otherwise
261 // the result is not so good.
262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
264
265 // Generate The Texture
266 glTexImage2D(GL_TEXTURE_2D, 0, 4, txw, txh, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
267
268 our_image->tex_x0 = 0;
269 our_image->tex_y0 = 1.0 - (float)our_image->h / (float)our_image->tex_h;
270 our_image->tex_x1 = (float)our_image->w / (float)our_image->tex_w;
271 our_image->tex_y1 = 1.0;
272
273 open_gl_check_error_status(__FUNCTION__);
274 }
275 #endif
276
277
make_texture_out_of_surface(struct image * our_image)278 void make_texture_out_of_surface(struct image * our_image)
279 {
280 #ifdef HAVE_LIBGL
281
282 SDL_Surface *right_sized_image;
283
284 // This fills up the image with transparent material, and makes
285 // it have powers of 2 as the dimensions, which is a requirement
286 // for textures on most OpenGL capable cards.
287 //
288 right_sized_image = pad_image_for_texture(our_image->surface);
289 our_image->tex_w = right_sized_image->w;
290 our_image->tex_h = right_sized_image->h;
291 our_image->w = our_image->surface->w;
292 our_image->h = our_image->surface->h;
293
294 // Having prepared the raw image it's now time to create the real
295 // textures.
296 //
297 do_make_texture_out_of_surface(our_image, right_sized_image->w, right_sized_image->h, right_sized_image->pixels);
298 SDL_FreeSurface(right_sized_image);
299
300 // Now that the texture has been created, we assume that the image is
301 // not needed any more and can be freed now!
302 SDL_FreeSurface(our_image->surface);
303 our_image->surface = NULL;
304
305 #endif
306 }
307
308 /**
309 * This function does the first part of the OpenGL parameter
310 * initialization. We've made this chunk of code into a separate function
311 * such that the frequent issues with OpenGL drivers can be attributed to
312 * a particular spot in the code more easily.
313 */
safely_set_open_gl_viewport_and_matrix_mode(void)314 void safely_set_open_gl_viewport_and_matrix_mode(void)
315 {
316 #ifdef HAVE_LIBGL
317
318 glViewport(0, 0, GameConfig.screen_width, GameConfig.screen_height);
319 glMatrixMode(GL_PROJECTION);
320 glLoadIdentity();
321 glOrtho(0.0f, GameConfig.screen_width, GameConfig.screen_height, 0.0f, -1.0f, 1.0f);
322 glMatrixMode(GL_MODELVIEW);
323
324 open_gl_check_error_status(__FUNCTION__);
325
326 #endif
327 }
328
329 /**
330 * This function does the second part of the OpenGL parameter
331 * initialization. We've made this chunk of code into a separate function
332 * such that the frequent issues with OpenGL drivers can be attributed to
333 * a particular spot in the code more easily.
334 */
safely_set_some_open_gl_flags_and_shade_model(void)335 void safely_set_some_open_gl_flags_and_shade_model(void)
336 {
337 #ifdef HAVE_LIBGL
338
339 glClearColor(0.0, 0.0, 0.0, 1.0);
340
341 glEnable(GL_TEXTURE_2D);
342
343 glShadeModel(GL_FLAT);
344
345 glEnable(GL_BLEND);
346 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
347
348 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
349
350 glEnableClientState(GL_VERTEX_ARRAY);
351 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
352
353 open_gl_check_error_status(__FUNCTION__);
354
355 #endif
356 }
357
358 /**
359 * Initialize the OpenGL interface.
360 */
safely_initialize_our_default_open_gl_parameters(void)361 int safely_initialize_our_default_open_gl_parameters(void)
362 {
363 #ifdef HAVE_LIBGL
364 init_opengl_debug();
365 safely_set_open_gl_viewport_and_matrix_mode();
366 safely_set_some_open_gl_flags_and_shade_model();
367 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
368 open_gl_check_error_status(__FUNCTION__);
369
370 #endif
371
372 return TRUE;
373 }
374
375 /**
376 * This function restores the menu background, that must have been stored
377 * before using the function of similar name.
378 */
RestoreMenuBackground(int backup_slot)379 void RestoreMenuBackground(int backup_slot)
380 {
381 if (use_open_gl) {
382 #ifdef HAVE_LIBGL
383 int h = GameConfig.screen_height;
384 int w = GameConfig.screen_width;
385
386 // Stop any image batch being constructed,
387 // so that struct image does not get confused.
388 end_image_batch();
389
390 glDisable(GL_TEXTURE_2D);
391 glEnable(GL_TEXTURE_RECTANGLE_ARB);
392 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, (StoredMenuBackgroundTex[backup_slot]));
393
394 glBegin(GL_QUADS);
395 glTexCoord2i(0, h);
396 glVertex2i(0, 0);
397 glTexCoord2i(0, 0);
398 glVertex2i(0, h);
399 glTexCoord2i(w, 0);
400 glVertex2i(w, h);
401 glTexCoord2i(w, h);
402 glVertex2i(w, 0);
403 glEnd();
404
405 glEnable(GL_TEXTURE_2D);
406 glDisable(GL_TEXTURE_RECTANGLE_ARB);
407
408 #endif
409 } else {
410 SDL_BlitSurface(StoredMenuBackground[backup_slot], NULL, Screen, NULL);
411 }
412 }
413
414 /**
415 * This function stores the current background as the background for a
416 * menu, so that it can be refreshed much faster than by reassembling it
417 * every frame.
418 */
StoreMenuBackground(int backup_slot)419 void StoreMenuBackground(int backup_slot)
420 {
421 static int first_call = TRUE;
422
423 if (first_call) {
424 StoredMenuBackground[0] = NULL;
425 StoredMenuBackground[1] = NULL;
426 first_call = FALSE;
427 }
428
429 if (use_open_gl) {
430 #ifdef HAVE_LIBGL
431 // Stop any image batch being constructed,
432 // so that struct image does not get confused.
433 end_image_batch();
434
435 glFlush();
436
437 if (StoredMenuBackgroundTex[backup_slot] == 0) {
438 glGenTextures(1, &StoredMenuBackgroundTex[backup_slot]);
439 }
440
441 glDisable(GL_TEXTURE_2D);
442 glEnable(GL_TEXTURE_RECTANGLE_ARB);
443 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, StoredMenuBackgroundTex[backup_slot]);
444 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
445 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
446
447 glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, GameConfig.screen_width, GameConfig.screen_height, 0);
448 open_gl_check_error_status(__FUNCTION__);
449
450 glEnable(GL_TEXTURE_2D);
451 glDisable(GL_TEXTURE_RECTANGLE_ARB);
452
453 #endif
454 } else {
455 // If the memory was not yet allocated, we need to do that now...
456 //
457 // otherwise we free the old surface and create a new copy of the
458 // current screen content...
459 //
460 if (StoredMenuBackground[backup_slot] == NULL) {
461 StoredMenuBackground[backup_slot] = SDL_DisplayFormat(Screen);
462 } else {
463 SDL_FreeSurface(StoredMenuBackground[backup_slot]);
464 StoredMenuBackground[backup_slot] = SDL_DisplayFormat(Screen);
465 }
466 }
467
468 }; // void StoreMenuBackground ( int backup_slot )
469
470 /**
471 * Following a suggestion from Simon, we're now implementing one single
472 * small texture (to be modified with pixel operations every frame) that
473 * can be stretched out over the whole screen via OpenGL.
474 * This function is here to set up the texture in the first place.
475 */
set_up_stretched_texture_for_light_radius(void)476 void set_up_stretched_texture_for_light_radius(void)
477 {
478 #ifdef HAVE_LIBGL
479
480 static int texture_is_set_up_already = FALSE;
481
482 // In the non-open-gl case, this function shouldn't be called ever....
483 //
484 if (!use_open_gl)
485 return;
486
487 // Stop any image batch being constructed,
488 // so that struct image does not get confused.
489 end_image_batch();
490
491 // Some protection against creating this texture twice...
492 //
493 if (texture_is_set_up_already)
494 return;
495 texture_is_set_up_already = TRUE;
496
497 // We create an SDL surface, so that we can make the texture for the
498 // stretched-texture method light radius from it...
499 //
500 light_radius_stretch_surface =
501 SDL_CreateRGBSurface(SDL_SWSURFACE, LightRadiusConfig.texture_w, LightRadiusConfig.texture_h, 32, rmask, gmask, bmask, amask);
502
503 // Having prepared the raw image it's now time to create the real
504 // textures.
505 //
506 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
507
508 glGenTextures(1, &light_radius_stretch_texture);
509
510 glBindTexture(GL_TEXTURE_2D, (light_radius_stretch_texture));
511
512 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
513 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
515 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
516
517 // Generate The Texture
518 glTexImage2D(GL_TEXTURE_2D, 0, 4, light_radius_stretch_surface->w,
519 light_radius_stretch_surface->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, light_radius_stretch_surface->pixels);
520
521 #endif
522
523 }; // void set_up_stretched_texture_for_light_radius ( void )
524
525 /**
526 * This function updated the automap texture, such that all info from the
527 * current square is on the automap.
528 */
light_radius_update_stretched_texture(void)529 void light_radius_update_stretched_texture(void)
530 {
531 #ifdef HAVE_LIBGL
532 int x, y;
533 int red = 0;
534 int blue = 0;
535 int green = 0;
536 int alpha = 0;
537 int light_strength;
538 static float alpha_factor = 255.0 / (float)NUMBER_OF_SHADOW_IMAGES;
539 // Now it's time to edit the automap texture.
540 //
541 for (y = 0; y < LightRadiusConfig.cells_h; y++) {
542 for (x = 0; x < LightRadiusConfig.cells_w; x++) {
543 light_strength = get_light_strength_cell(x, y);
544
545 alpha = 255 - (alpha_factor) * ((float)light_strength);
546
547 sdl_put_pixel(light_radius_stretch_surface, x, y, red, green, blue, alpha);
548
549 }
550 }
551
552 // Stop any image batch being constructed,
553 // so that struct image does not get confused.
554 end_image_batch();
555
556 glBindTexture(GL_TEXTURE_2D, light_radius_stretch_texture);
557 glTexSubImage2D(GL_TEXTURE_2D, 0,
558 0, 0,
559 LightRadiusConfig.texture_w,
560 LightRadiusConfig.texture_h, GL_RGBA, GL_UNSIGNED_BYTE, light_radius_stretch_surface->pixels);
561
562 open_gl_check_error_status(__FUNCTION__);
563
564 #endif
565
566 }; // void light_radius_update_stretched_texture ( void )
567
568 /**
569 * Following a suggestion from Simon, we're now implementing one single
570 * small texture (to be modified with pixel operations every frame) that
571 * can be stretched out over the whole screen via OpenGL.
572 * This function is here to set up the texture in the first place.
573 *
574 * decay_x and decay_y does translate the textured rectangle to avoid
575 * darkness flickering. See flicker-free code's note in set_up_light_strength_buffer()
576 */
blit_open_gl_stretched_texture_light_radius(int decay_x,int decay_y)577 void blit_open_gl_stretched_texture_light_radius(int decay_x, int decay_y)
578 {
579 #ifdef HAVE_LIBGL
580 struct image local_iso_image;
581
582 // We make sure, that there is one single texture created before
583 // doing any of our texture-blitting or texture-modification stuff
584 // with it.
585 //
586 set_up_stretched_texture_for_light_radius();
587
588 light_radius_update_stretched_texture();
589
590 // Now we blit the current automap texture to the screen. We use standard
591 // texture blitting code for this, so we need to embed the automap texture
592 // in a surrounding 'iso_image', but that shouldn't be costly or anything...
593 //
594 local_iso_image.texture = light_radius_stretch_texture;
595 local_iso_image.tex_w = LightRadiusConfig.texture_w;
596 local_iso_image.tex_h = LightRadiusConfig.texture_h;
597 local_iso_image.w = LightRadiusConfig.texture_w;
598 local_iso_image.h = LightRadiusConfig.texture_h;
599 local_iso_image.texture_type = TEXTURE_CREATED | IS_SUBTEXTURE;
600 local_iso_image.offset_x = 0;
601 local_iso_image.offset_y = 0;
602 local_iso_image.tex_x0 = 0.0;
603 local_iso_image.tex_y0 = 0.0;
604 local_iso_image.tex_x1 = 1.0;
605 local_iso_image.tex_y1 = 1.0;
606
607 display_image_on_screen(&local_iso_image, decay_x, decay_y, IMAGE_SCALE_TRANSFO(LightRadiusConfig.scale_factor));
608
609 #endif
610
611 }; // void blit_open_gl_stretched_texture_light_radius ( void )
612
613 /**
614 * Draw a colored rectangle on screen in OpenGL.
615 *
616 * @param rect The rectangular area.
617 * @param r The red color value.
618 * @param g The green color value.
619 * @param b The blue color value.
620 * @param a The alpha color value.
621 */
gl_draw_rectangle(SDL_Rect * rect,int r,int g,int b,int a)622 void gl_draw_rectangle(SDL_Rect *rect, int r, int g, int b, int a)
623 {
624 #ifdef HAVE_LIBGL
625 glDisable(GL_TEXTURE_2D);
626
627 glColor4ub(r, g, b, a);
628
629 glBegin(GL_QUADS);
630 glVertex2i(rect->x, rect->y);
631 glVertex2i(rect->x, rect->y + rect->h);
632 glVertex2i(rect->x + rect->w, rect->y + rect->h);
633 glVertex2i(rect->x + rect->w, rect->y);
634 glEnd();
635
636 glColor4ub(255, 255, 255, 255);
637
638 glEnable(GL_TEXTURE_2D);
639 #endif
640 }
641
642 static struct background {
643 const char *filename;
644 struct image img;
645 int x;
646 int y;
647 int must_scale;
648 } backgrounds[] = {
649 {"inventory.png", EMPTY_IMAGE, 0, 0, FALSE },
650 {"character.png", EMPTY_IMAGE, -320, 0, FALSE },
651 {"SkillScreen.png", EMPTY_IMAGE, -320, 0, FALSE },
652 {"SkillExplanationScreen.png", EMPTY_IMAGE, 0, 0, FALSE },
653 {"title.jpg", EMPTY_IMAGE, 0, 0, TRUE },
654 {"credits.jpg", EMPTY_IMAGE, 0, 0, TRUE },
655 {"shoppe.jpg", EMPTY_IMAGE, 0, 0, TRUE },
656 {"takeover_browser.png", EMPTY_IMAGE, 0, 0, TRUE },
657 {"item_browser_shop.png", EMPTY_IMAGE, 0, 0,TRUE },
658 {"startup1.jpg", EMPTY_IMAGE, 0, 0, TRUE },
659 {"conversation.png", EMPTY_IMAGE, 0, 0, TRUE },
660 {"transfer.jpg", EMPTY_IMAGE, 0, 0, TRUE },
661 {"number_selector.png", EMPTY_IMAGE, 0, 0, TRUE },
662 {"item_upgrade.png", EMPTY_IMAGE, ITEM_UPGRADE_RECT_X, ITEM_UPGRADE_RECT_Y, FALSE },
663 {"item_upgrade_crafting.png", EMPTY_IMAGE, ADDON_CRAFTING_RECT_X, ADDON_CRAFTING_RECT_Y, FALSE },
664 {"console_bg1.jpg", EMPTY_IMAGE, 0, 0, TRUE },
665 };
666
667 /**
668 * This function displays a background (or UI element) at a given position in the game.
669 */
blit_background(const char * background)670 void blit_background(const char *background)
671 {
672 int i;
673
674 // Search the specified background in the list
675 struct background *bg = NULL;
676
677 for (i = 0; i < sizeof(backgrounds)/sizeof(backgrounds[0]); i++) {
678 if (!strcmp(backgrounds[i].filename, background)) {
679 bg = &backgrounds[i];
680 break;
681 }
682 }
683
684 if (!bg) {
685 error_message(__FUNCTION__, "Received a request to display background %s which is unknown. Doing nothing.", PLEASE_INFORM, background);
686 return;
687 }
688
689 // Load the background
690 if (!image_loaded(&bg->img)) {
691 char path[2048];
692 sprintf(path, "backgrounds/%s", bg->filename);
693 load_image(&bg->img, path, USE_WIDE);
694 }
695
696
697 // Compute coordinates and display
698 int x = bg->x;
699 int y = bg->y;
700
701 float scalex = 1.0, scaley = 1.0;
702 if (bg->must_scale) {
703 scalex = (float)GameConfig.screen_width / bg->img.w;
704 scaley = (float)GameConfig.screen_height / bg->img.h;
705 }
706
707 x *= scalex;
708 y *= scaley;
709
710 if (x < 0)
711 x += GameConfig.screen_width;
712
713 if (y < 0)
714 y += GameConfig.screen_height;
715
716
717 display_image_on_screen(&bg->img, x, y, set_image_transformation(scalex, scaley, 1.0, 1.0, 1.0, 1.0, 0));
718 }
719
set_gl_clip_rect(const SDL_Rect * clip)720 void set_gl_clip_rect(const SDL_Rect *clip)
721 {
722 #ifdef HAVE_LIBGL
723 // Flush image batch. Scissor test shouldn't affect it.
724 end_image_batch();
725
726 if (use_open_gl) {
727 glScissor(clip->x, GameConfig.screen_height - (clip->y + clip->h), clip->w, clip->h);
728 glEnable(GL_SCISSOR_TEST);
729 }
730 #endif
731 }
732
unset_gl_clip_rect(void)733 void unset_gl_clip_rect(void)
734 {
735 #ifdef HAVE_LIBGL
736 if (use_open_gl) {
737 glDisable(GL_SCISSOR_TEST);
738 }
739 #endif
740 }
741
742
743 #undef _open_gl_c
744