r_draw.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 1997-2001 Id Software, Inc.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 /* console font */
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 /* chars are batched per frame so that they are drawn in one shot */
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) == ' ')     /* space */
00074         return;
00075 
00076     if (y <= -con_fontHeight)
00077         return;                 /* totally off screen */
00078 
00079     if (char_index >= MAX_CHARS * 8)
00080         return;
00081 
00082     row = (int) num >> 4;
00083     col = (int) num & 15;
00084 
00085     /* 0.0625 => 16 cols (conchars images) */
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     /* alter the array pointers */
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     /* and restore them */
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     /* scan the texture for any non-255 alpha */
00151     c = scaledWidth * scaledHeight;
00152     /* set scan to the first alpha byte */
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) {  /* whereas others need to be scaled */
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         /* Reallocate the texture */
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     /* alter the array pointers */
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     /* and restore them */
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     /* scale it */
00348     radius *= viddef.rx;
00349     thickness *= viddef.rx;
00350 
00351     /* store the matrix - we are using glTranslate */
00352     glPushMatrix();
00353 
00354     /* translate the position */
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     /* Create a vertex at the exact position specified by the start angle. */
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         /* When filling we're drawing triangles so we need to
00420          * create a vertex in the middle of the vertex to fill
00421          * the entire pie slice/circle. */
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     /* fit it on screen */
00441     if (points > MAX_LINEVERTS * 2)
00442         points = MAX_LINEVERTS * 2;
00443 
00444     /* set vertex array pointer */
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     /* we want to overwrite depth buffer not to have his constraints */
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     /* compute a full bounding box */
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     /* Draw top and sides */
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     /* Draw bottom */
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 }

Generated by  doxygen 1.6.2