1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #include "r_local.h"
26 #include "r_sphere.h"
27 #include "r_error.h"
28 #include "r_draw.h"
29 #include "r_mesh.h"
30 #include "r_framebuffer.h"
31 #include "r_program.h"
32 #include "r_misc.h"
33 #include "../cl_console.h"
34 
35 image_t* shadow;
36 
37 /* console font */
38 static image_t* draw_chars;
39 
40 #define MAX_CHARS 8192
41 
42 /** @brief Characters are batched per frame and drawn in one shot
43  * accumulate coordinates and colors as vertex arrays */
44 typedef struct char_arrays_s {
45 	GLfloat texcoords[MAX_CHARS * 4 * 2];
46 	int texcoord_index;
47 
48 	GLshort verts[MAX_CHARS * 4 * 2];
49 	int vert_index;
50 
51 	GLbyte colors[MAX_CHARS * 4 * 4];
52 	int color_index;
53 } char_arrays_t;
54 
55 static char_arrays_t r_char_arrays;
56 
57 #define MAX_BATCH_ENTRIES 512
58 
59 /** @brief array to store batched vertices and colors per frame */
60 typedef struct batch_arrays_s {
61 	GLshort verts[MAX_BATCH_ENTRIES * 4 * 2];
62 	int vert_index;
63 
64 	GLbyte colors[MAX_BATCH_ENTRIES * 4 * 4];
65 	int color_index;
66 } batch_arrays_t;
67 
68 static batch_arrays_t r_fill_arrays;
69 
70 #define MAX_BBOX_ENTRIES 256
71 
72 typedef struct bbox_arrays_s {
73 	float bboxes[3 * 8 * MAX_BBOX_ENTRIES];
74 	int bboxes_index;
75 } bbox_arrays_t;
76 
77 static bbox_arrays_t r_bbox_array;
78 
79 /**
80  * @brief Loads some textures and init the 3d globe
81  * @sa R_Init
82  */
R_DrawInitLocal(void)83 void R_DrawInitLocal (void)
84 {
85 	shadow = R_FindImage("pics/sfx/shadow", it_effect);
86 	if (shadow == r_noTexture)
87 		Com_Printf("Could not find shadow image in game pics/sfx directory!\n");
88 
89 	draw_chars = R_FindImage("pics/conchars", it_chars);
90 	if (draw_chars == r_noTexture)
91 		Com_Error(ERR_FATAL, "Could not find conchars image in game pics directory!");
92 }
93 
94 /**
95  * @brief Draws one 8*8 graphics character with 0 being transparent.
96  * It can be clipped to the top of the screen to allow the console to be
97  * smoothly scrolled off.
98  */
R_DrawChar(int x,int y,int num,uint32_t color)99 void R_DrawChar (int x, int y, int num, uint32_t color)
100 {
101 	num &= 255;
102 
103 	if ((num & 127) == ' ')		/* space */
104 		return;
105 
106 	if (y <= -con_fontHeight)
107 		return;					/* totally off screen */
108 
109 	if (r_char_arrays.vert_index >= lengthof(r_char_arrays.verts))
110 		return;
111 
112 	int row = (int) num >> 4;
113 	int col = (int) num & 15;
114 
115 	/* 0.0625 => 16 cols (conchars images) */
116 	float frow = row * 0.0625;
117 	float fcol = col * 0.0625;
118 
119 	memcpy(&r_char_arrays.colors[r_char_arrays.color_index +  0], &color, 4);
120 	memcpy(&r_char_arrays.colors[r_char_arrays.color_index +  4], &color, 4);
121 	memcpy(&r_char_arrays.colors[r_char_arrays.color_index +  8], &color, 4);
122 	memcpy(&r_char_arrays.colors[r_char_arrays.color_index + 12], &color, 4);
123 
124 	r_char_arrays.color_index += 16;
125 
126 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 0] = fcol;
127 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 1] = frow;
128 
129 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 2] = fcol + 0.0625;
130 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 3] = frow;
131 
132 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 4] = fcol + 0.0625;
133 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 5] = frow + 0.0625;
134 
135 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 6] = fcol;
136 	r_char_arrays.texcoords[r_char_arrays.texcoord_index + 7] = frow + 0.0625;
137 
138 	r_char_arrays.texcoord_index += 8;
139 
140 	r_char_arrays.verts[r_char_arrays.vert_index + 0] = x;
141 	r_char_arrays.verts[r_char_arrays.vert_index + 1] = y;
142 
143 	r_char_arrays.verts[r_char_arrays.vert_index + 2] = x + con_fontWidth;
144 	r_char_arrays.verts[r_char_arrays.vert_index + 3] = y;
145 
146 	r_char_arrays.verts[r_char_arrays.vert_index + 4] = x + con_fontWidth;
147 	r_char_arrays.verts[r_char_arrays.vert_index + 5] = y + con_fontHeight;
148 
149 	r_char_arrays.verts[r_char_arrays.vert_index + 6] = x;
150 	r_char_arrays.verts[r_char_arrays.vert_index + 7] = y + con_fontHeight;
151 
152 	r_char_arrays.vert_index += 8;
153 }
154 
R_DrawChars(void)155 void R_DrawChars (void)
156 {
157 	if (!r_char_arrays.vert_index)
158 		return;
159 
160 	R_BindTexture(draw_chars->texnum);
161 
162 	R_EnableColorArray(true);
163 
164 	/* alter the array pointers */
165 	R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_char_arrays.colors);
166 	R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, r_char_arrays.texcoords);
167 	glVertexPointer(2, GL_SHORT, 0, r_char_arrays.verts);
168 
169 	R_DrawArrays(0, r_char_arrays.vert_index / 2);
170 
171 	refdef.batchCount++;
172 
173 	r_char_arrays.color_index = 0;
174 	r_char_arrays.texcoord_index = 0;
175 	r_char_arrays.vert_index = 0;
176 
177 	/* and restore them */
178 	R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
179 	R_BindDefaultArray(GL_VERTEX_ARRAY);
180 	R_BindDefaultArray(GL_COLOR_ARRAY);
181 
182 	R_EnableColorArray(false);
183 }
184 
185 /**
186  * @brief Fills a box of pixels with a single color
187  */
R_DrawFill(int x,int y,int w,int h,const vec4_t color)188 void R_DrawFill (int x, int y, int w, int h, const vec4_t color)
189 {
190 	const float nx = x * viddef.rx;
191 	const float ny = y * viddef.ry;
192 	const float nw = w * viddef.rx;
193 	const float nh = h * viddef.ry;
194 	const int r = color[0] * 255.0;
195 	const int g = color[1] * 255.0;
196 	const int b = color[2] * 255.0;
197 	const int a = color[3] * 255.0;
198 	const uint32_t c = LittleLong((r << 0) + (g << 8) + (b << 16) + (a << 24));
199 
200 	if (r_fill_arrays.color_index >= lengthof(r_fill_arrays.colors))
201 		return;
202 
203 	/* duplicate color data to all 4 verts */
204 	memcpy(&r_fill_arrays.colors[r_fill_arrays.color_index +  0], &c, 4);
205 	memcpy(&r_fill_arrays.colors[r_fill_arrays.color_index +  4], &c, 4);
206 	memcpy(&r_fill_arrays.colors[r_fill_arrays.color_index +  8], &c, 4);
207 	memcpy(&r_fill_arrays.colors[r_fill_arrays.color_index + 12], &c, 4);
208 
209 	r_fill_arrays.color_index += 16;
210 
211 	/* populate verts */
212 	r_fill_arrays.verts[r_fill_arrays.vert_index + 0] = nx;
213 	r_fill_arrays.verts[r_fill_arrays.vert_index + 1] = ny;
214 
215 	r_fill_arrays.verts[r_fill_arrays.vert_index + 2] = nx + nw;
216 	r_fill_arrays.verts[r_fill_arrays.vert_index + 3] = ny;
217 
218 	r_fill_arrays.verts[r_fill_arrays.vert_index + 4] = nx + nw;
219 	r_fill_arrays.verts[r_fill_arrays.vert_index + 5] = ny + nh;
220 
221 	r_fill_arrays.verts[r_fill_arrays.vert_index + 6] = nx;
222 	r_fill_arrays.verts[r_fill_arrays.vert_index + 7] = ny + nh;
223 
224 	r_fill_arrays.vert_index += 8;
225 
226 	/** @todo this shouldn't be here, but only called once at the end of the frame
227 	 * but this is needed here because a) we don't want them to get rendered on top of the console
228 	 * and b) the ui stuff relies on the order of these renderings */
229 	R_DrawFills();
230 }
231 
R_DrawFills(void)232 void R_DrawFills (void)
233 {
234 	if (!r_fill_arrays.vert_index)
235 		return;
236 
237 	R_EnableTexture(&texunit_diffuse, false);
238 
239 	R_EnableColorArray(true);
240 
241 	/* alter the array pointers */
242 	R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_fill_arrays.colors);
243 	glVertexPointer(2, GL_SHORT, 0, r_fill_arrays.verts);
244 
245 	R_DrawArrays(0, r_fill_arrays.vert_index / 2);
246 
247 	refdef.batchCount++;
248 
249 	/* and restore them */
250 	R_BindDefaultArray(GL_VERTEX_ARRAY);
251 	R_BindDefaultArray(GL_COLOR_ARRAY);
252 
253 	R_EnableColorArray(false);
254 
255 	R_EnableTexture(&texunit_diffuse, true);
256 
257 	r_fill_arrays.vert_index = r_fill_arrays.color_index = 0;
258 
259 	R_Color(nullptr);
260 }
261 
262 /**
263  * @brief Uploads image data
264  * @param[in] name The name of the texture to use for this data
265  * @param[in] frame The frame data that is uploaded
266  * @param[in] width The width of the texture
267  * @param[in] height The height of the texture
268  * @return the texture number of the uploaded images
269  */
R_UploadData(const char * name,unsigned * frame,int width,int height)270 int R_UploadData (const char* name, unsigned *frame, int width, int height)
271 {
272 	image_t* img;
273 	unsigned *scaled;
274 	int scaledWidth, scaledHeight;
275 	int samples = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format;
276 #ifdef GL_VERSION_ES_CM_1_0
277 	samples = GL_RGBA;
278 #endif
279 
280 	R_GetScaledTextureSize(width, height, &scaledWidth, &scaledHeight);
281 
282 	img = R_FindImage(name, it_pic);
283 	if (img == r_noTexture)
284 		Com_Error(ERR_FATAL, "Could not find the searched image: %s", name);
285 
286 	/* scan the texture for any non-255 alpha */
287 	for (unsigned const* i = frame, * const end = i + scaledHeight * scaledWidth; i != end; ++i) {
288 		if ((*i & 0xFF000000U) != 0xFF000000U) {
289 			samples = r_config.gl_compressed_alpha_format ? r_config.gl_compressed_alpha_format : r_config.gl_alpha_format;
290 			break;
291 		}
292 	}
293 
294 	if (scaledWidth != width || scaledHeight != height) {  /* whereas others need to be scaled */
295 		scaled = Mem_PoolAllocTypeN(unsigned, scaledWidth * scaledHeight, vid_imagePool);
296 		R_ScaleTexture(frame, width, height, scaled, scaledWidth, scaledHeight);
297 	} else {
298 		scaled = frame;
299 	}
300 
301 	R_BindTexture(img->texnum);
302 	if (img->upload_width == scaledWidth && img->upload_height == scaledHeight) {
303 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, scaledWidth, scaledHeight, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
304 	} else {
305 		/* Reallocate the texture */
306 		img->width = width;
307 		img->height = height;
308 		img->upload_width = scaledWidth;
309 		img->upload_height = scaledHeight;
310 		glTexImage2D(GL_TEXTURE_2D, 0, samples, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
311 	}
312 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
313 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
314 	R_CheckError();
315 
316 	if (scaled != frame)
317 		Mem_Free(scaled);
318 
319 	return img->texnum;
320 }
321 
322 /**
323  * @brief Bind and draw a texture
324  * @param[in] texnum The texture id (already uploaded of course)
325  * @param[in] x normalized x value on the screen
326  * @param[in] y normalized y value on the screen
327  * @param[in] w normalized width value
328  * @param[in] h normalized height value
329  */
R_DrawTexture(int texnum,int x,int y,int w,int h)330 void R_DrawTexture (int texnum, int x, int y, int w, int h)
331 {
332 	const vec2_t vertexes[] = {Vector2FromInt(x, y), Vector2FromInt(x + w, y), Vector2FromInt(x + w, y + h), Vector2FromInt(x, y + h)};
333 
334 	R_BindTexture(texnum);
335 	R_DrawImageArray(default_texcoords, vertexes, nullptr);
336 }
337 
338 /**
339  * @brief Draws an image or parts of it
340  * @param x X position to draw the image to
341  * @param y Y position to draw the image to
342  * @param[in] image Pointer to the imlage to display
343  */
R_DrawImage(float x,float y,const image_t * image)344 void R_DrawImage (float x, float y, const image_t* image)
345 {
346 	if (!image)
347 		return;
348 
349 	R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, image->width * viddef.rx, image->height * viddef.ry);
350 }
351 
R_DrawStretchImage(float x,float y,int w,int h,const image_t * image)352 void R_DrawStretchImage (float x, float y, int w, int h, const image_t* image)
353 {
354 	if (!image)
355 		return;
356 
357 	R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, w * viddef.rx, h * viddef.ry);
358 }
359 
R_DrawImageArray(const vec2_t texcoords[4],const vec2_t verts[4],const image_t * image)360 const image_t* R_DrawImageArray (const vec2_t texcoords[4], const vec2_t verts[4], const image_t* image)
361 {
362 	/* alter the array pointers */
363 	glVertexPointer(2, GL_FLOAT, 0, verts);
364 	R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoords);
365 
366 	if (image != nullptr)
367 		R_BindTexture(image->texnum);
368 
369 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
370 
371 	refdef.batchCount++;
372 
373 	/* and restore them */
374 	R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
375 	R_BindDefaultArray(GL_VERTEX_ARRAY);
376 
377 	return image;
378 }
379 
380 /**
381  * @brief Draws a rect to the screen. Also has support for stippled rendering of the rect.
382  *
383  * @param[in] x X-position of the rect
384  * @param[in] y Y-position of the rect
385  * @param[in] w Width of the rect
386  * @param[in] h Height of the rect
387  * @param[in] color RGBA color of the rect
388  * @param[in] lineWidth Line strength in pixel of the rect
389  * @param[in] pattern Specifies a 16-bit integer whose bit pattern determines
390  * which fragments of a line will be drawn when the line is rasterized.
391  * Bit zero is used first; the default pattern is all 1's
392  * @note The stipple factor is @c 2 for this function
393  */
R_DrawRect(int x,int y,int w,int h,const vec4_t color,float lineWidth,int pattern)394 void R_DrawRect (int x, int y, int w, int h, const vec4_t color, float lineWidth, int pattern)
395 {
396 	const float nx = x * viddef.rx;
397 	const float ny = y * viddef.ry;
398 	const float nw = w * viddef.rx;
399 	const float nh = h * viddef.ry;
400 	const vec2_t points[] = { { nx, ny }, { nx + nw, ny }, { nx + nw, ny + nh }, { nx, ny + nh } };
401 
402 	R_Color(color);
403 
404 	glDisable(GL_TEXTURE_2D);
405 	glLineWidth(lineWidth);
406 #ifndef GL_VERSION_ES_CM_1_0
407 	glLineStipple(2, pattern);
408 	glEnable(GL_LINE_STIPPLE);
409 #endif
410 
411 	glVertexPointer(2, GL_FLOAT, 0, points);
412 	glDrawArrays(GL_LINE_LOOP, 0, 4);
413 	R_BindDefaultArray(GL_VERTEX_ARRAY);
414 
415 	refdef.batchCount++;
416 
417 	glEnable(GL_TEXTURE_2D);
418 	glLineWidth(1.0f);
419 #ifndef GL_VERSION_ES_CM_1_0
420 	glDisable(GL_LINE_STIPPLE);
421 #endif
422 
423 	R_Color(nullptr);
424 }
425 
R_DrawCircle(float radius,const vec4_t color,float thickness,const vec3_t shift)426 void R_DrawCircle (float radius, const vec4_t color, float thickness, const vec3_t shift)
427 {
428 	vec3_t points[16];
429 	const size_t steps = lengthof(points);
430 	unsigned int i;
431 
432 	glEnable(GL_LINE_SMOOTH);
433 	glLineWidth(thickness);
434 
435 	R_Color(color);
436 
437 	for (i = 0; i < steps; i++) {
438 		const float a = 2.0f * M_PI * (float) i / (float) steps;
439 		VectorSet(points[i], shift[0] + radius * cos(a), shift[1] + radius * sin(a), shift[2]);
440 	}
441 
442 	R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, points);
443 	glDrawArrays(GL_LINE_LOOP, 0, steps);
444 	R_BindDefaultArray(GL_VERTEX_ARRAY);
445 
446 	refdef.batchCount++;
447 
448 	R_Color(nullptr);
449 
450 	glLineWidth(1.0f);
451 	glDisable(GL_LINE_SMOOTH);
452 }
453 
454 #define MAX_LINEVERTS 256
455 
R_Draw2DArray(int points,int * verts,GLenum mode)456 static inline void R_Draw2DArray (int points, int* verts, GLenum mode)
457 {
458 	/* fit it on screen */
459 	if (points > MAX_LINEVERTS * 2)
460 		points = MAX_LINEVERTS * 2;
461 
462 	/* set vertex array pointer */
463 	glVertexPointer(2, GL_SHORT, 0, r_state.vertex_array_2d);
464 
465 	for (int i = 0; i < points * 2; i += 2) {
466 		r_state.vertex_array_2d[i] = verts[i] * viddef.rx;
467 		r_state.vertex_array_2d[i + 1] = verts[i + 1] * viddef.ry;
468 	}
469 
470 	glDisable(GL_TEXTURE_2D);
471 	glDrawArrays(mode, 0, points);
472 	glEnable(GL_TEXTURE_2D);
473 	glVertexPointer(3, GL_FLOAT, 0, r_state.vertex_array_3d);
474 
475 	refdef.batchCount++;
476 }
477 
478 /**
479  * @brief 2 dimensional line strip
480  * @sa R_DrawLineLoop
481  */
R_DrawLineStrip(int points,int * verts)482 void R_DrawLineStrip (int points, int* verts)
483 {
484 	R_Draw2DArray(points, verts, GL_LINE_STRIP);
485 }
486 
487 /**
488  * @sa R_DrawLineStrip
489  */
R_DrawLineLoop(int points,int * verts)490 void R_DrawLineLoop (int points, int* verts)
491 {
492 	R_Draw2DArray(points, verts, GL_LINE_LOOP);
493 }
494 
495 /**
496  * @brief Draws one line with only one start and one end point
497  * @sa R_DrawLineStrip
498  */
R_DrawLine(int * verts,float thickness)499 void R_DrawLine (int* verts, float thickness)
500 {
501 	if (thickness > 0.0)
502 		glLineWidth(thickness);
503 
504 	R_Draw2DArray(2, verts, GL_LINES);
505 
506 	if (thickness > 0.0)
507 		glLineWidth(1.0);
508 }
509 
510 /**
511  * @sa R_DrawLineStrip
512  * @sa R_DrawLineLoop
513  */
R_DrawPolygon(int points,int * verts)514 void R_DrawPolygon (int points, int* verts)
515 {
516 	R_Draw2DArray(points, verts, GL_TRIANGLE_FAN);
517 }
518 
519 typedef struct {
520 	int x;
521 	int y;
522 	int width;
523 	int height;
524 } rect_t;
525 
526 #define MAX_CLIPRECT 16
527 
528 static rect_t clipRect[MAX_CLIPRECT];
529 
530 static int currentClipRect = 0;
531 
532 /**
533  * @brief Compute the intersection of 2 rect
534  * @param[in] a A rect
535  * @param[in] b A rect
536  * @param[out] out The intersection rect
537  */
R_RectIntersection(const rect_t * a,const rect_t * b,rect_t * out)538 static void R_RectIntersection (const rect_t* a, const rect_t* b, rect_t* out)
539 {
540 	out->x = (a->x > b->x) ? a->x : b->x;
541 	out->y = (a->y > b->y) ? a->y : b->y;
542 	out->width = ((a->x + a->width < b->x + b->width) ? a->x + a->width : b->x + b->width) - out->x;
543 	out->height = ((a->y + a->height < b->y + b->height) ? a->y + a->height : b->y + b->height) - out->y;
544 	if (out->width < 0)
545 		out->width = 0;
546 	if (out->height < 0)
547 		out->height = 0;
548 }
549 
550 /**
551  * @brief Force to draw only on a rect
552  * @note Don't forget to call @c R_EndClipRect
553  * @sa R_PopClipRect
554  */
R_PushClipRect(int x,int y,int width,int height)555 void R_PushClipRect (int x, int y, int width, int height)
556 {
557 	const int depth = currentClipRect;
558 	assert(depth < MAX_CLIPRECT);
559 
560 	if (depth == 0) {
561 		clipRect[depth].x = x * viddef.rx;
562 		clipRect[depth].y = (viddef.virtualHeight - (y + height)) * viddef.ry;
563 		clipRect[depth].width = width * viddef.rx;
564 		clipRect[depth].height = height * viddef.ry;
565 	} else {
566 		rect_t rect;
567 		rect.x = x * viddef.rx;
568 		rect.y = (viddef.virtualHeight - (y + height)) * viddef.ry;
569 		rect.width = width * viddef.rx;
570 		rect.height = height * viddef.ry;
571 		R_RectIntersection(&clipRect[depth - 1], &rect, &clipRect[depth]);
572 	}
573 
574 	glScissor(clipRect[depth].x, clipRect[depth].y, clipRect[depth].width, clipRect[depth].height);
575 
576 	if (currentClipRect == 0)
577 		glEnable(GL_SCISSOR_TEST);
578 	currentClipRect++;
579 }
580 
581 /**
582  * @sa R_PushClipRect
583  */
R_PopClipRect(void)584 void R_PopClipRect (void)
585 {
586 	assert(currentClipRect > 0);
587 	currentClipRect--;
588 	if (currentClipRect == 0)
589 		glDisable(GL_SCISSOR_TEST);
590 	else {
591 		const int depth = currentClipRect - 1;
592 		glScissor(clipRect[depth].x, clipRect[depth].y, clipRect[depth].width, clipRect[depth].height);
593 	}
594 }
595 
596 /**
597  * @brief "Clean up" the depth buffer into a rect
598  * @note we use a big value (but not too big) to set the depth buffer, then it is not really a clean up
599  * @todo can we fix bigZ with a value come from glGet?
600  */
R_CleanupDepthBuffer(int x,int y,int width,int height)601 void R_CleanupDepthBuffer (int x, int y, int width, int height)
602 {
603 	const float nx = x * viddef.rx;
604 	const float ny = y * viddef.ry;
605 	const int nwidth = width * viddef.rx;
606 	const int nheight = height * viddef.ry;
607 	const GLboolean hasDepthTest = glIsEnabled(GL_DEPTH_TEST);
608 	const GLfloat bigZ = 2000.0f;
609 	const vec3_t points [] = { { nx, ny, bigZ }, { nx + nwidth, ny, bigZ }, { nx + nwidth, ny + nheight, bigZ }, { nx, ny + nheight, bigZ } };
610 
611 	GLint depthFunc;
612 	glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
613 
614 	/* we want to overwrite depth buffer not to have his constraints */
615 	glEnable(GL_DEPTH_TEST);
616 	glDepthFunc(GL_ALWAYS);
617 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
618 
619 	R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, points);
620 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
621 	R_BindDefaultArray(GL_VERTEX_ARRAY);
622 
623 	refdef.batchCount++;
624 
625 	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
626 	if (!hasDepthTest)
627 		glDisable(GL_DEPTH_TEST);
628 	glDepthFunc(depthFunc);
629 }
630 
631 /**
632  * @brief Compute the bounding box for an entity out of the mins, maxs
633  * @sa R_DrawBoundingBox
634  */
R_ComputeBoundingBox(const vec3_t mins,const vec3_t maxs,vec3_t bbox[8])635 static void R_ComputeBoundingBox (const vec3_t mins, const vec3_t maxs, vec3_t bbox[8])
636 {
637 	/* compute a full bounding box */
638 	for (int i = 0; i < 8; i++) {
639 		bbox[i][0] = (i & 1) ? mins[0] : maxs[0];
640 		bbox[i][1] = (i & 2) ? mins[1] : maxs[1];
641 		bbox[i][2] = (i & 4) ? mins[2] : maxs[2];
642 	}
643 }
644 
R_DrawBoundingBoxes(void)645 void R_DrawBoundingBoxes (void)
646 {
647 	const int step = 3 * 8;
648 	const int bboxes = r_bbox_array.bboxes_index / step;
649 	const GLushort indexes[] = { 2, 1, 0, 1, 4, 5, 1, 7, 3, 2, 7, 6, 2, 4, 0 };
650 	const GLushort indexes2[] = { 4, 6, 7 };
651 
652 	if (!r_bbox_array.bboxes_index)
653 		return;
654 
655 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
656 
657 	R_Color(nullptr);
658 
659 	for (int i = 0; i < bboxes; i++) {
660 		const float* bbox = &r_bbox_array.bboxes[i * step];
661 		R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, bbox);
662 		/* Draw top and sides */
663 		glDrawElements(GL_TRIANGLE_FAN, 15, GL_UNSIGNED_SHORT, indexes);
664 		/* Draw bottom */
665 		glDrawElements(GL_TRIANGLE_FAN, 3, GL_UNSIGNED_SHORT, indexes2);
666 	}
667 
668 	R_BindDefaultArray(GL_VERTEX_ARRAY);
669 
670 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
671 
672 	r_bbox_array.bboxes_index = 0;
673 }
674 
R_DrawBoundingBoxBatched(const vec3_t absmins,const vec3_t absmaxs)675 void R_DrawBoundingBoxBatched (const vec3_t absmins, const vec3_t absmaxs)
676 {
677 	vec3_t bbox[8];
678 	const size_t max = lengthof(r_bbox_array.bboxes);
679 
680 	if (r_bbox_array.bboxes_index >= max)
681 		return;
682 
683 	R_ComputeBoundingBox(absmins, absmaxs, bbox);
684 
685 	for (int i = 0; i < 8; i++) {
686 		VectorCopy(bbox[i], &r_bbox_array.bboxes[r_bbox_array.bboxes_index]);
687 		r_bbox_array.bboxes_index += 3;
688 	}
689 }
690 
691 /**
692  * @brief Draws the model bounding box
693  * @sa R_EntityComputeBoundingBox
694  */
R_DrawBoundingBox(const vec3_t absmins,const vec3_t absmaxs)695 void R_DrawBoundingBox (const vec3_t absmins, const vec3_t absmaxs)
696 {
697 	vec3_t bbox[8];
698 	const GLushort indexes[] = { 2, 1, 0, 1, 4, 5, 1, 7, 3, 2, 7, 6, 2, 4, 0 };
699 	const GLushort indexes2[] = { 4, 6, 7 };
700 
701 	R_ComputeBoundingBox(absmins, absmaxs, bbox);
702 
703 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
704 
705 	R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, bbox);
706 	/* Draw top and sides */
707 	glDrawElements(GL_TRIANGLE_STRIP, 15, GL_UNSIGNED_SHORT, indexes);
708 	/* Draw bottom */
709 	glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, indexes2);
710 	R_BindDefaultArray(GL_VERTEX_ARRAY);
711 
712 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
713 }
714 
715 /**
716  * @brief Draws the textured box, the caller should bind the texture
717  * @sa R_DrawBox
718  */
R_DrawTexturedBox(const vec3_t a0,const vec3_t a1)719 void R_DrawTexturedBox (const vec3_t a0, const vec3_t a1)
720 {
721 	const GLfloat texcoords[] = { 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, };
722 	const vec3_t bbox[] = {
723 					{ a0[0], a0[1], a0[2] }, { a0[0], a0[1], a1[2] }, { a1[0], a0[1], a1[2] }, { a1[0], a0[1], a0[2] },
724 					{ a1[0], a1[1], a0[2] }, { a1[0], a1[1], a1[2] }, { a0[0], a1[1], a1[2] }, { a0[0], a1[1], a0[2] },
725 					{ a0[0], a0[1], a0[2] }, { a0[0], a0[1], a1[2] }, { a1[0], a0[1], a1[2] }, { a1[0], a0[1], a0[2] },
726 					{ a1[0], a1[1], a0[2] }, { a1[0], a1[1], a1[2] }, { a0[0], a1[1], a1[2] }, { a0[0], a1[1], a0[2] } };
727 	const GLushort indexes[] = { 0, 1, 2, 1, 2, 3, 4, 5, 6, 6, 7, 4, 2 + 8, 3 + 8, 4 + 8, 2 + 8, 5 + 8, 4 + 8, 6 + 8, 7 + 8,
728 			0 + 8, 0 + 8, 1 + 8, 6 + 8, };
729 
730 	R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoords);
731 	R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, bbox);
732 
733 	/* Draw sides only */
734 	glDrawElements(GL_TRIANGLES, 8 * 3, GL_UNSIGNED_SHORT, indexes);
735 
736 	R_BindDefaultArray(GL_VERTEX_ARRAY);
737 	R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
738 }
739