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