00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "r_local.h"
00026 #include "r_sphere.h"
00027 #include "r_error.h"
00028 #include "r_draw.h"
00029 #include "r_mesh.h"
00030 #include "r_framebuffer.h"
00031 #include "r_program.h"
00032 #include "../cl_console.h"
00033
00034 image_t *shadow;
00035
00036
00037 static image_t *draw_chars;
00038
00043 void R_DrawInitLocal (void)
00044 {
00045 shadow = R_FindImage("pics/sfx/shadow", it_effect);
00046 if (shadow == r_noTexture)
00047 Com_Printf("Could not find shadow image in game pics/sfx directory!\n");
00048
00049 draw_chars = R_FindImage("pics/conchars", it_chars);
00050 if (draw_chars == r_noTexture)
00051 Com_Error(ERR_FATAL, "Could not find conchars image in game pics directory!");
00052 }
00053
00054 #define MAX_CHARS 8192
00055
00056
00057 static float char_texcoords[MAX_CHARS * 4 * 2];
00058 static short char_verts[MAX_CHARS * 4 * 2];
00059 static int char_index = 0;
00060
00066 void R_DrawChar (int x, int y, int num)
00067 {
00068 int row, col;
00069 float frow, fcol;
00070
00071 num &= 255;
00072
00073 if ((num & 127) == ' ')
00074 return;
00075
00076 if (y <= -con_fontHeight)
00077 return;
00078
00079 if (char_index >= MAX_CHARS * 8)
00080 return;
00081
00082 row = (int) num >> 4;
00083 col = (int) num & 15;
00084
00085
00086 frow = row * 0.0625;
00087 fcol = col * 0.0625;
00088
00089 char_texcoords[char_index + 0] = fcol;
00090 char_texcoords[char_index + 1] = frow;
00091 char_texcoords[char_index + 2] = fcol + 0.0625;
00092 char_texcoords[char_index + 3] = frow;
00093 char_texcoords[char_index + 4] = fcol + 0.0625;
00094 char_texcoords[char_index + 5] = frow + 0.0625;
00095 char_texcoords[char_index + 6] = fcol;
00096 char_texcoords[char_index + 7] = frow + 0.0625;
00097
00098 char_verts[char_index + 0] = x;
00099 char_verts[char_index + 1] = y;
00100 char_verts[char_index + 2] = x + con_fontWidth;
00101 char_verts[char_index + 3] = y;
00102 char_verts[char_index + 4] = x + con_fontWidth;
00103 char_verts[char_index + 5] = y + con_fontHeight;
00104 char_verts[char_index + 6] = x;
00105 char_verts[char_index + 7] = y + con_fontHeight;
00106
00107 char_index += 8;
00108 }
00109
00110 void R_DrawChars (void)
00111 {
00112 R_BindTexture(draw_chars->texnum);
00113
00114
00115 glVertexPointer(2, GL_SHORT, 0, char_verts);
00116 glTexCoordPointer(2, GL_FLOAT, 0, char_texcoords);
00117
00118 glDrawArrays(GL_QUADS, 0, char_index / 2);
00119
00120 char_index = 0;
00121
00122
00123 R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
00124 R_BindDefaultArray(GL_VERTEX_ARRAY);
00125 }
00126
00135 int R_UploadData (const char *name, byte *frame, int width, int height)
00136 {
00137 image_t *img;
00138 unsigned *scaled;
00139 int scaledWidth, scaledHeight;
00140 int samples = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format;
00141 int i, c;
00142 byte *scan;
00143
00144 R_GetScaledTextureSize(width, height, &scaledWidth, &scaledHeight);
00145
00146 img = R_FindImage(name, it_pic);
00147 if (img == r_noTexture)
00148 Com_Error(ERR_FATAL, "Could not find the searched image: %s", name);
00149
00150
00151 c = scaledWidth * scaledHeight;
00152
00153 for (i = 0, scan = ((byte *) frame) + 3; i < c; i++, scan += 4) {
00154 if (*scan != 255) {
00155 samples = r_config.gl_compressed_alpha_format ? r_config.gl_compressed_alpha_format : r_config.gl_alpha_format;
00156 break;
00157 }
00158 }
00159
00160 if (scaledWidth != width || scaledHeight != height) {
00161 scaled = (unsigned *)Mem_PoolAllocExt(scaledWidth * scaledHeight * sizeof(unsigned), qfalse, vid_imagePool, 0);
00162 R_ScaleTexture((unsigned *)frame, width, height, scaled, scaledWidth, scaledHeight);
00163 } else {
00164 scaled = (unsigned *)frame;
00165 }
00166
00167 R_BindTexture(img->texnum);
00168 if (img->upload_width == scaledWidth && img->upload_height == scaledHeight) {
00169 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, scaledWidth, scaledHeight, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
00170 } else {
00171
00172 img->width = width;
00173 img->height = height;
00174 img->upload_width = scaledWidth;
00175 img->upload_height = scaledHeight;
00176 glTexImage2D(GL_TEXTURE_2D, 0, samples, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
00177 }
00178 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00179 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00180 R_CheckError();
00181
00182 if (scaled != (unsigned *)frame)
00183 Mem_Free(scaled);
00184
00185 return img->texnum;
00186 }
00187
00195 const image_t *R_RegisterImage (const char *name)
00196 {
00197 const image_t *image = R_FindImage(va("pics/%s", name), it_pic);
00198 if (image == r_noTexture)
00199 return NULL;
00200 return image;
00201 }
00202
00211 void R_DrawTexture (int texnum, int x, int y, int w, int h)
00212 {
00213 const vec2_t vertexes[4] = {{x, y}, {x + w, y}, {x + w, y + h}, {x, y + h}};
00214
00215 R_BindTexture(texnum);
00216 R_DrawImageArray(default_texcoords, vertexes, NULL);
00217 }
00218
00224 void R_DrawImage (float x, float y, const image_t *image)
00225 {
00226 if (!image)
00227 return;
00228
00229 R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, image->width * viddef.rx, image->height * viddef.ry);
00230 }
00231
00232 void R_DrawStretchImage (float x, float y, int w, int h, const image_t *image)
00233 {
00234 if (!image)
00235 return;
00236
00237 R_DrawTexture(image->texnum, x * viddef.rx, y * viddef.ry, w * viddef.rx, h * viddef.ry);
00238 }
00239
00240 const image_t *R_DrawImageArray (const vec2_t texcoords[4], const vec2_t verts[4], const image_t *image)
00241 {
00242
00243 glVertexPointer(2, GL_FLOAT, 0, verts);
00244 R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoords);
00245
00246 if (image != NULL)
00247 R_BindTexture(image->texnum);
00248
00249 glDrawArrays(GL_QUADS, 0, 4);
00250
00251
00252 R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY);
00253 R_BindDefaultArray(GL_VERTEX_ARRAY);
00254
00255 return image;
00256 }
00257
00261 void R_DrawFill (int x, int y, int w, int h, const vec4_t color)
00262 {
00263 const float nx = x * viddef.rx;
00264 const float ny = y * viddef.ry;
00265 const float nw = w * viddef.rx;
00266 const float nh = h * viddef.ry;
00267
00268 R_Color(color);
00269
00270 glDisable(GL_TEXTURE_2D);
00271
00272 glBegin(GL_QUADS);
00273 glVertex2f(nx, ny);
00274 glVertex2f(nx + nw, ny);
00275 glVertex2f(nx + nw, ny + nh);
00276 glVertex2f(nx, ny + nh);
00277 glEnd();
00278
00279 glEnable(GL_TEXTURE_2D);
00280
00281 R_Color(NULL);
00282 }
00283
00298 void R_DrawRect (int x, int y, int w, int h, const vec4_t color, float lineWidth, int pattern)
00299 {
00300 const float nx = x * viddef.rx;
00301 const float ny = y * viddef.ry;
00302 const float nw = w * viddef.rx;
00303 const float nh = h * viddef.ry;
00304
00305 R_Color(color);
00306
00307 glDisable(GL_TEXTURE_2D);
00308 glLineWidth(lineWidth);
00309 glLineStipple(2, pattern);
00310 glEnable(GL_LINE_STIPPLE);
00311
00312 glBegin(GL_LINE_LOOP);
00313 glVertex2f(nx, ny);
00314 glVertex2f(nx + nw, ny);
00315 glVertex2f(nx + nw, ny + nh);
00316 glVertex2f(nx, ny + nh);
00317 glEnd();
00318
00319 glEnable(GL_TEXTURE_2D);
00320 glLineWidth(1.0f);
00321 glDisable(GL_LINE_STIPPLE);
00322
00323 R_Color(NULL);
00324 }
00325
00334 void R_DrawCircle (vec3_t mid, float radius, const vec4_t color, int thickness)
00335 {
00336 float theta;
00337 const float accuracy = 5.0;
00338 const float step = M_PI / radius * accuracy;
00339
00340 glDisable(GL_TEXTURE_2D);
00341 glEnable(GL_LINE_SMOOTH);
00342
00343 R_Color(color);
00344
00345 assert(radius > thickness);
00346
00347
00348 radius *= viddef.rx;
00349 thickness *= viddef.rx;
00350
00351
00352 glPushMatrix();
00353
00354
00355 glTranslated(mid[0], mid[1], mid[2]);
00356
00357 if (thickness <= 1) {
00358 glBegin(GL_LINE_STRIP);
00359 for (theta = 0.0; theta <= 2.0 * M_PI; theta += step) {
00360 glVertex3f(radius * cos(theta), radius * sin(theta), 0.0);
00361 }
00362 glEnd();
00363 } else {
00364 glBegin(GL_TRIANGLE_STRIP);
00365 for (theta = 0.0; theta <= 2.0 * M_PI; theta += step) {
00366 glVertex3f(radius * cos(theta), radius * sin(theta), 0.0);
00367 glVertex3f(radius * cos(theta - step), radius * sin(theta - step), 0.0);
00368 glVertex3f((radius - thickness) * cos(theta - step), (radius - thickness) * sin(theta - step), 0.0);
00369 glVertex3f((radius - thickness) * cos(theta), (radius - thickness) * sin(theta), 0.0);
00370 }
00371 glEnd();
00372 }
00373
00374 glPopMatrix();
00375
00376 R_Color(NULL);
00377
00378 glDisable(GL_LINE_SMOOTH);
00379 glEnable(GL_TEXTURE_2D);
00380 }
00381
00382 #define CIRCLE_LINE_COUNT 40
00383
00395 void R_DrawCircle2D (int x, int y, float radius, qboolean fill, const vec4_t color, float thickness)
00396 {
00397 int i;
00398
00399 glPushAttrib(GL_ALL_ATTRIB_BITS);
00400
00401 glDisable(GL_TEXTURE_2D);
00402 R_Color(color);
00403
00404 if (thickness > 0.0)
00405 glLineWidth(thickness);
00406
00407 if (fill)
00408 glBegin(GL_TRIANGLE_STRIP);
00409 else
00410 glBegin(GL_LINE_LOOP);
00411
00412
00413 glVertex2f(x + radius, y);
00414
00415 for (i = 0; i < CIRCLE_LINE_COUNT; i++) {
00416 const float angle = (2.0 * M_PI / CIRCLE_LINE_COUNT) * i;
00417 glVertex2f(x + radius * cos(angle), y - radius * sin(angle));
00418
00419
00420
00421
00422 if (fill)
00423 glVertex2f(x, y);
00424 }
00425
00426 glVertex2f(x + radius, y);
00427 glEnd();
00428 glEnable(GL_TEXTURE_2D);
00429 R_Color(NULL);
00430
00431 glPopAttrib();
00432 }
00433
00434 #define MAX_LINEVERTS 256
00435
00436 static inline void R_Draw2DArray (int points, int *verts, GLenum mode)
00437 {
00438 int i;
00439
00440
00441 if (points > MAX_LINEVERTS * 2)
00442 points = MAX_LINEVERTS * 2;
00443
00444
00445 glVertexPointer(2, GL_SHORT, 0, r_state.vertex_array_2d);
00446
00447 for (i = 0; i < points * 2; i += 2) {
00448 r_state.vertex_array_2d[i] = verts[i] * viddef.rx;
00449 r_state.vertex_array_2d[i + 1] = verts[i + 1] * viddef.ry;
00450 }
00451
00452 glDisable(GL_TEXTURE_2D);
00453 glDrawArrays(mode, 0, points);
00454 glEnable(GL_TEXTURE_2D);
00455 glVertexPointer(3, GL_FLOAT, 0, r_state.vertex_array_3d);
00456 }
00457
00463 void R_DrawLineStrip (int points, int *verts)
00464 {
00465 R_Draw2DArray(points, verts, GL_LINE_STRIP);
00466 }
00467
00472 void R_DrawLineLoop (int points, int *verts)
00473 {
00474 R_Draw2DArray(points, verts, GL_LINE_LOOP);
00475 }
00476
00482 void R_DrawLine (int *verts, float thickness)
00483 {
00484 if (thickness > 0.0)
00485 glLineWidth(thickness);
00486
00487 R_Draw2DArray(2, verts, GL_LINES);
00488
00489 if (thickness > 0.0)
00490 glLineWidth(1.0);
00491 }
00492
00498 void R_DrawPolygon (int points, int *verts)
00499 {
00500 R_Draw2DArray(points, verts, GL_POLYGON);
00501 }
00502
00503 typedef struct {
00504 int x;
00505 int y;
00506 int width;
00507 int height;
00508 } rect_t;
00509
00510 #define MAX_CLIPRECT 16
00511
00512 static rect_t clipRect[MAX_CLIPRECT];
00513
00514 static int currentClipRect = 0;
00515
00522 static void R_RectIntersection (const rect_t* a, const rect_t* b, rect_t* out)
00523 {
00524 out->x = (a->x > b->x) ? a->x : b->x;
00525 out->y = (a->y > b->y) ? a->y : b->y;
00526 out->width = ((a->x + a->width < b->x + b->width) ? a->x + a->width : b->x + b->width) - out->x;
00527 out->height = ((a->y + a->height < b->y + b->height) ? a->y + a->height : b->y + b->height) - out->y;
00528 if (out->width < 0)
00529 out->width = 0;
00530 if (out->height < 0)
00531 out->height = 0;
00532 }
00533
00539 void R_PushClipRect (int x, int y, int width, int height)
00540 {
00541 const int depth = currentClipRect;
00542 assert(depth < MAX_CLIPRECT);
00543
00544 if (depth == 0) {
00545 clipRect[depth].x = x * viddef.rx;
00546 clipRect[depth].y = (viddef.virtualHeight - (y + height)) * viddef.ry;
00547 clipRect[depth].width = width * viddef.rx;
00548 clipRect[depth].height = height * viddef.ry;
00549 } else {
00550 rect_t rect;
00551 rect.x = x * viddef.rx;
00552 rect.y = (viddef.virtualHeight - (y + height)) * viddef.ry;
00553 rect.width = width * viddef.rx;
00554 rect.height = height * viddef.ry;
00555 R_RectIntersection(&clipRect[depth - 1], &rect, &clipRect[depth]);
00556 }
00557
00558 glScissor(clipRect[depth].x, clipRect[depth].y, clipRect[depth].width, clipRect[depth].height);
00559
00560 if (currentClipRect == 0)
00561 glEnable(GL_SCISSOR_TEST);
00562 currentClipRect++;
00563 }
00564
00568 void R_PopClipRect (void)
00569 {
00570 assert(currentClipRect > 0);
00571 currentClipRect--;
00572 if (currentClipRect == 0)
00573 glDisable(GL_SCISSOR_TEST);
00574 else {
00575 const int depth = currentClipRect - 1;
00576 glScissor(clipRect[depth].x, clipRect[depth].y, clipRect[depth].width, clipRect[depth].height);
00577 }
00578 }
00579
00585 void R_CleanupDepthBuffer (int x, int y, int width, int height)
00586 {
00587 const int nx = x * viddef.rx;
00588 const int ny = y * viddef.ry;
00589 const int nwidth = width * viddef.rx;
00590 const int nheight = height * viddef.ry;
00591 const GLboolean hasDepthTest = glIsEnabled(GL_DEPTH_TEST);
00592 const GLdouble bigZ = 2000;
00593 GLint depthFunc;
00594 glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
00595
00596
00597 glEnable(GL_DEPTH_TEST);
00598 glDepthFunc(GL_ALWAYS);
00599 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00600
00601 glBegin(GL_QUADS);
00602 glVertex3d(nx, ny, bigZ);
00603 glVertex3d(nx + nwidth, ny, bigZ);
00604 glVertex3d(nx + nwidth, ny + nheight, bigZ);
00605 glVertex3d(nx, ny + nheight, bigZ);
00606 glEnd();
00607
00608 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00609 if (!hasDepthTest)
00610 glDisable(GL_DEPTH_TEST);
00611 glDepthFunc(depthFunc);
00612 }
00613
00618 static void R_ComputeBoundingBox (const vec3_t mins, const vec3_t maxs, vec3_t bbox[8])
00619 {
00620 int i;
00621
00622
00623 for (i = 0; i < 8; i++) {
00624 bbox[i][0] = (i & 1) ? mins[0] : maxs[0];
00625 bbox[i][1] = (i & 2) ? mins[1] : maxs[1];
00626 bbox[i][2] = (i & 4) ? mins[2] : maxs[2];
00627 }
00628 }
00629
00634 void R_DrawBoundingBox (const vec3_t mins, const vec3_t maxs)
00635 {
00636 vec3_t bbox[8];
00637
00638 R_ComputeBoundingBox(mins, maxs, bbox);
00639
00640 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00641
00642
00643 glBegin(GL_TRIANGLE_STRIP);
00644 glVertex3fv(bbox[2]);
00645 glVertex3fv(bbox[1]);
00646 glVertex3fv(bbox[0]);
00647 glVertex3fv(bbox[1]);
00648 glVertex3fv(bbox[4]);
00649 glVertex3fv(bbox[5]);
00650 glVertex3fv(bbox[1]);
00651 glVertex3fv(bbox[7]);
00652 glVertex3fv(bbox[3]);
00653 glVertex3fv(bbox[2]);
00654 glVertex3fv(bbox[7]);
00655 glVertex3fv(bbox[6]);
00656 glVertex3fv(bbox[2]);
00657 glVertex3fv(bbox[4]);
00658 glVertex3fv(bbox[0]);
00659 glEnd();
00660
00661
00662 glBegin(GL_TRIANGLE_STRIP);
00663 glVertex3fv(bbox[4]);
00664 glVertex3fv(bbox[6]);
00665 glVertex3fv(bbox[7]);
00666 glEnd();
00667
00668 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00669 }