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