#include "quakedef.h"
#include "r_shadow.h"
+#include "polygon.h"
// used for dlight push checking and other things
int r_framecount;
-mplane_t frustum[4];
+mplane_t frustum[5];
matrix4x4_t r_identitymatrix;
cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
+
+cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
+
rtexturepool_t *r_main_texturepool;
rtexture_t *r_bloom_texture_screen;
rtexture_t *r_bloom_texture_bloom;
+rtexture_t *r_texture_blanknormalmap;
+rtexture_t *r_texture_white;
+rtexture_t *r_texture_black;
+rtexture_t *r_texture_notexture;
+rtexture_t *r_texture_whitecube;
+rtexture_t *r_texture_normalizationcube;
+rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES];
+rtexture_t *r_texture_distorttexture[64];
void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
{
}
}
+static void R_BuildDetailTextures (void)
+{
+ int i, x, y, light;
+ float vc[3], vx[3], vy[3], vn[3], lightdir[3];
+#define DETAILRESOLUTION 256
+ qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
+ lightdir[0] = 0.5;
+ lightdir[1] = 1;
+ lightdir[2] = -0.25;
+ VectorNormalize(lightdir);
+ for (i = 0;i < NUM_DETAILTEXTURES;i++)
+ {
+ fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
+ for (y = 0;y < DETAILRESOLUTION;y++)
+ {
+ for (x = 0;x < DETAILRESOLUTION;x++)
+ {
+ vc[0] = x;
+ vc[1] = y;
+ vc[2] = noise[y][x] * (1.0f / 32.0f);
+ vx[0] = x + 1;
+ vx[1] = y;
+ vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
+ vy[0] = x;
+ vy[1] = y + 1;
+ vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
+ VectorSubtract(vx, vc, vx);
+ VectorSubtract(vy, vc, vy);
+ CrossProduct(vx, vy, vn);
+ VectorNormalize(vn);
+ light = 128 - DotProduct(vn, lightdir) * 128;
+ light = bound(0, light, 255);
+ data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
+ data[y][x][3] = 255;
+ }
+ }
+ r_texture_detailtextures[i] = R_LoadTexture2D(r_main_texturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
+ }
+}
+
+static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
+{
+ int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
+ ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
+ ((y2 - y0) * morph) +
+ (y1));
+ return (qbyte)bound(0, m, 255);
+}
+
+static void R_BuildDistortTexture (void)
+{
+ int x, y, i, j;
+#define DISTORTRESOLUTION 32
+ qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
+
+ for (i=0; i<4; i++)
+ {
+ for (y=0; y<DISTORTRESOLUTION; y++)
+ {
+ for (x=0; x<DISTORTRESOLUTION; x++)
+ {
+ data[i][y][x][0] = rand () & 255;
+ data[i][y][x][1] = rand () & 255;
+ }
+ }
+ }
+
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<16; j++)
+ {
+ r_texture_distorttexture[i*16+j] = NULL;
+ if (gl_textureshader)
+ {
+ for (y=0; y<DISTORTRESOLUTION; y++)
+ {
+ for (x=0; x<DISTORTRESOLUTION; x++)
+ {
+ data[4][y][x][0] = R_MorphDistortTexture (data[(i-1)&3][y][x][0], data[i][y][x][0], data[(i+1)&3][y][x][0], data[(i+2)&3][y][x][0], 0.0625*j);
+ data[4][y][x][1] = R_MorphDistortTexture (data[(i-1)&3][y][x][1], data[i][y][x][1], data[(i+1)&3][y][x][1], data[(i+2)&3][y][x][1], 0.0625*j);
+ }
+ }
+ r_texture_distorttexture[i*16+j] = R_LoadTexture2D(r_main_texturepool, va("distorttexture%i", i*16+j), DISTORTRESOLUTION, DISTORTRESOLUTION, &data[4][0][0][0], TEXTYPE_DSDT, TEXF_PRECACHE, NULL);
+ }
+ }
+ }
+}
+
+static void R_BuildBlankTextures(void)
+{
+ qbyte data[4];
+ data[0] = 128; // normal X
+ data[1] = 128; // normal Y
+ data[2] = 255; // normal Z
+ data[3] = 128; // height
+ r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 255;
+ data[1] = 255;
+ data[2] = 255;
+ data[3] = 255;
+ r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 255;
+ r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+}
+
+static void R_BuildNoTexture(void)
+{
+ int x, y;
+ qbyte pix[16][16][4];
+ // this makes a light grey/dark grey checkerboard texture
+ for (y = 0;y < 16;y++)
+ {
+ for (x = 0;x < 16;x++)
+ {
+ if ((y < 8) ^ (x < 8))
+ {
+ pix[y][x][0] = 128;
+ pix[y][x][1] = 128;
+ pix[y][x][2] = 128;
+ pix[y][x][3] = 255;
+ }
+ else
+ {
+ pix[y][x][0] = 64;
+ pix[y][x][1] = 64;
+ pix[y][x][2] = 64;
+ pix[y][x][3] = 255;
+ }
+ }
+ }
+ r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
+}
+
+static void R_BuildWhiteCube(void)
+{
+ qbyte data[6*1*1*4];
+ data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
+ data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
+ data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
+ data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
+ data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
+ data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
+ r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
+}
+
+static void R_BuildNormalizationCube(void)
+{
+ int x, y, side;
+ vec3_t v;
+ vec_t s, t, intensity;
+#define NORMSIZE 64
+ qbyte data[6][NORMSIZE][NORMSIZE][4];
+ for (side = 0;side < 6;side++)
+ {
+ for (y = 0;y < NORMSIZE;y++)
+ {
+ for (x = 0;x < NORMSIZE;x++)
+ {
+ s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
+ t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
+ switch(side)
+ {
+ case 0:
+ v[0] = 1;
+ v[1] = -t;
+ v[2] = -s;
+ break;
+ case 1:
+ v[0] = -1;
+ v[1] = -t;
+ v[2] = s;
+ break;
+ case 2:
+ v[0] = s;
+ v[1] = 1;
+ v[2] = t;
+ break;
+ case 3:
+ v[0] = s;
+ v[1] = -1;
+ v[2] = -t;
+ break;
+ case 4:
+ v[0] = s;
+ v[1] = -t;
+ v[2] = 1;
+ break;
+ case 5:
+ v[0] = -s;
+ v[1] = -t;
+ v[2] = -1;
+ break;
+ }
+ intensity = 127.0f / sqrt(DotProduct(v, v));
+ data[side][y][x][0] = 128.0f + intensity * v[0];
+ data[side][y][x][1] = 128.0f + intensity * v[1];
+ data[side][y][x][2] = 128.0f + intensity * v[2];
+ data[side][y][x][3] = 255;
+ }
+ }
+ }
+ r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
+}
+
void gl_main_start(void)
{
r_main_texturepool = R_AllocTexturePool();
r_bloom_texture_screen = NULL;
r_bloom_texture_bloom = NULL;
+ R_BuildBlankTextures();
+ R_BuildNoTexture();
+ R_BuildDetailTextures();
+ R_BuildDistortTexture();
+ if (gl_texturecubemap)
+ {
+ R_BuildWhiteCube();
+ R_BuildNormalizationCube();
+ }
}
void gl_main_shutdown(void)
R_FreeTexturePool(&r_main_texturepool);
r_bloom_texture_screen = NULL;
r_bloom_texture_bloom = NULL;
+ r_texture_blanknormalmap = NULL;
+ r_texture_white = NULL;
+ r_texture_black = NULL;
+ r_texture_whitecube = NULL;
+ r_texture_normalizationcube = NULL;
}
extern void CL_ParseEntityLump(char *entitystring);
Cvar_RegisterVariable(&r_bloom_blur);
Cvar_RegisterVariable(&r_bloom_resolution);
Cvar_RegisterVariable(&r_bloom_power);
+ Cvar_RegisterVariable(&developer_texturelogging);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
}
extern void R_Textures_Init(void);
-extern void Mod_RenderInit(void);
extern void GL_Draw_Init(void);
extern void GL_Main_Init(void);
extern void R_Shadow_Init(void);
-extern void GL_Models_Init(void);
extern void R_Sky_Init(void);
extern void GL_Surf_Init(void);
extern void R_Crosshairs_Init(void);
extern void R_Light_Init(void);
extern void R_Particles_Init(void);
extern void R_Explosion_Init(void);
-extern void ui_init(void);
extern void gl_backend_init(void);
extern void Sbar_Init(void);
extern void R_LightningBeams_Init(void);
+extern void Mod_RenderInit(void);
void Render_Init(void)
{
+ gl_backend_init();
R_Textures_Init();
Mod_RenderInit();
- gl_backend_init();
R_MeshQueue_Init();
- GL_Draw_Init();
GL_Main_Init();
+ GL_Draw_Init();
R_Shadow_Init();
- GL_Models_Init();
R_Sky_Init();
GL_Surf_Init();
R_Crosshairs_Init();
R_Light_Init();
R_Particles_Init();
R_Explosion_Init();
- //ui_init();
UI_Init();
Sbar_Init();
R_LightningBeams_Init();
if (!r_drawentities.integer)
return;
+ r_refdef.worldentity->visframe = r_framecount;
renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
{
RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
PlaneClassify(&frustum[3]);
+
+ // nearclip plane
+ VectorCopy(r_viewforward, frustum[4].normal);
+ frustum[4].dist = DotProduct (r_vieworigin, frustum[4].normal) + 1.0f;
+ PlaneClassify(&frustum[4]);
}
static void R_BlendView(void)
GL_DepthMask(true);
GL_DepthTest(false);
R_Mesh_Matrix(&r_identitymatrix);
+ // vertex coordinates for a quad that covers the screen exactly
varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
float xoffset, yoffset, r;
c_bloom++;
+ // set the (poorly named) screenwidth and screenheight variables to
+ // a power of 2 at least as large as the screen, these will define the
+ // size of the texture to allocate
for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+ // allocate textures as needed
+ if (!r_bloom_texture_screen)
+ r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ if (!r_bloom_texture_bloom)
+ r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ // set bloomwidth and bloomheight to the bloom resolution that will be
+ // used (often less than the screen resolution for faster rendering)
bloomwidth = min(r_view_width, r_bloom_resolution.integer);
bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
+ // set up a texcoord array for the full resolution screen image
+ // (we have to keep this around to copy back during final render)
varray_texcoord2f[0][0] = 0;
varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
varray_texcoord2f[0][5] = 0;
varray_texcoord2f[0][6] = 0;
varray_texcoord2f[0][7] = 0;
+ // set up a texcoord array for the reduced resolution bloom image
+ // (which will be additive blended over the screen image)
varray_texcoord2f[1][0] = 0;
varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
varray_texcoord2f[1][5] = 0;
varray_texcoord2f[1][6] = 0;
varray_texcoord2f[1][7] = 0;
- if (!r_bloom_texture_screen)
- r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
- if (!r_bloom_texture_bloom)
- r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
memset(&m, 0, sizeof(m));
m.pointer_vertex = varray_vertex3f;
m.pointer_texcoord[0] = varray_texcoord2f[0];
m.tex[0] = R_GetTexture(r_bloom_texture_screen);
R_Mesh_State(&m);
- // copy view to a texture
+ // copy view into the full resolution screen image texture
GL_ActiveTexture(0);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
c_bloomcopies++;
c_bloomcopypixels += r_view_width * r_view_height;
// now scale it down to the bloom size and raise to a power of itself
- qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ // to darken it (this leaves the really bright stuff bright, and
+ // everything else becomes very dark)
// TODO: optimize with multitexture or GLSL
+ qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_Color(1, 1, 1, 1);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += bloomwidth * bloomheight;
+ // render multiple times with a multiply blendfunc to raise to a power
GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
for (x = 1;x < r_bloom_power.integer;x++)
{
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += bloomwidth * bloomheight;
}
- // copy the bloom view to a texture
+ // we now have a darkened bloom image in the framebuffer, copy it into
+ // the bloom image texture for more processing
memset(&m, 0, sizeof(m));
m.pointer_vertex = varray_vertex3f;
m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
c_bloomcopies++;
c_bloomcopypixels += bloomwidth * bloomheight;
- // blend on at multiple offsets vertically
+ // blend on at multiple vertical offsets to achieve a vertical blur
// TODO: do offset blends using GLSL
range = r_bloom_blur.integer * bloomwidth / 320;
GL_BlendFunc(GL_ONE, GL_ZERO);
{
xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
varray_texcoord2f[2][0] = xoffset+0;
varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
varray_texcoord2f[2][5] = yoffset+0;
varray_texcoord2f[2][6] = xoffset+0;
varray_texcoord2f[2][7] = yoffset+0;
- r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
if (r < 0.01f)
continue;
GL_Color(r, r, r, 1);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += bloomwidth * bloomheight;
GL_BlendFunc(GL_ONE, GL_ONE);
}
- // copy the blurred bloom view to a texture
+ // copy the vertically blurred bloom view to a texture
GL_ActiveTexture(0);
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
c_bloomcopies++;
c_bloomcopypixels += bloomwidth * bloomheight;
- // blend on at multiple offsets horizontally
+ // blend the vertically blurred image at multiple offsets horizontally
+ // to finish the blur effect
// TODO: do offset blends using GLSL
range = r_bloom_blur.integer * bloomwidth / 320;
GL_BlendFunc(GL_ONE, GL_ZERO);
{
xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
varray_texcoord2f[2][0] = xoffset+0;
varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
varray_texcoord2f[2][5] = yoffset+0;
varray_texcoord2f[2][6] = xoffset+0;
varray_texcoord2f[2][7] = yoffset+0;
- r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
if (r < 0.01f)
continue;
GL_Color(r, r, r, 1);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += bloomwidth * bloomheight;
GL_BlendFunc(GL_ONE, GL_ONE);
c_bloomcopypixels += bloomwidth * bloomheight;
// go back to full view area
qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
- // put the original view back in place
+ // put the original screen image back in place and blend the bloom
+ // texture on it
memset(&m, 0, sizeof(m));
m.pointer_vertex = varray_vertex3f;
m.tex[0] = R_GetTexture(r_bloom_texture_screen);
R_Mesh_State(&m);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_Color(1,1,1,1);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += r_view_width * r_view_height;
// now blend on the bloom texture if multipass
R_Mesh_State(&m);
GL_BlendFunc(GL_ONE, GL_ONE);
GL_Color(1,1,1,1);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
c_bloomdraws++;
c_bloomdrawpixels += r_view_width * r_view_height;
}
R_Mesh_State(&m);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
}
}
R_MeshQueue_Render();
R_MeshQueue_EndScene();
- if (r_shadow_visiblevolumes.integer && !r_showtrispass)
+ if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
{
R_ShadowVolumeLighting(true);
- R_TimeReport("shadowvolume");
+ R_TimeReport("visiblevolume");
}
GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
else
m.pointer_color = nomodelcolor4f;
R_Mesh_State(&m);
- R_Mesh_Draw(6, 8, nomodelelements);
+ R_Mesh_Draw(0, 6, 8, nomodelelements);
}
void R_DrawNoModel(entity_render_t *ent)
m.pointer_vertex = varray_vertex3f;
R_Mesh_State(&m);
GL_Color(cr, cg, cb, ca);
- R_Mesh_Draw(4, 2, polygonelements);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+}
+
+int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v)
+{
+ int i;
+ float *vertex3f;
+ for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
+ if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
+ break;
+ if (i == mesh->numvertices)
+ {
+ if (mesh->numvertices < mesh->maxvertices)
+ {
+ VectorCopy(v, vertex3f);
+ mesh->numvertices++;
+ }
+ return mesh->numvertices;
+ }
+ else
+ return i;
+}
+
+void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
+{
+ int i;
+ int *e, element[3];
+ element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
+ element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
+ e = mesh->element3i + mesh->numtriangles * 3;
+ for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
+ {
+ element[2] = R_Mesh_AddVertex3f(mesh, vertex3f);
+ if (mesh->numtriangles < mesh->maxtriangles)
+ {
+ *e++ = element[0];
+ *e++ = element[1];
+ *e++ = element[2];
+ mesh->numtriangles++;
+ }
+ element[1] = element[2];
+ }
}
+void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
+{
+ int planenum, planenum2;
+ int w;
+ int tempnumpoints;
+ mplane_t *plane, *plane2;
+ float temppoints[2][256*3];
+ for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
+ {
+ w = 0;
+ tempnumpoints = 4;
+ PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0);
+ for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
+ {
+ if (planenum2 == planenum)
+ continue;
+ PolygonF_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, 1.0/32.0, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints);
+ w = !w;
+ }
+ if (tempnumpoints < 3)
+ continue;
+ // generate elements forming a triangle fan for this polygon
+ R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]);
+ }
+}
+
+