X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=8525e1d2bfdda26afe90c6d98a04aecc3384b7cf;hb=aa33d8f8642530f7f266d6cde1422f95aa74b2be;hp=0527c171ef753124d64fd0a3d5d158211f4c7b09;hpb=af0dcabc0e2b5e187cc9182015b612d5ae4efb0b;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 0527c171..8525e1d2 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -97,7 +97,6 @@ cvar_t r_textureunits = {0, "r_textureunits", "32"}; cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"}; cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"}; cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"}; -cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"}; cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"}; cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"}; @@ -105,7 +104,13 @@ 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"}; +cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1"}; + +cvar_t developer_texturelogging = {0, "developer_texturelogging", "0"}; + +cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"}; + +cvar_t r_test = {0, "r_test", "0"}; // used for testing renderer code changes, otherwise does nothing rtexturepool_t *r_main_texturepool; rtexture_t *r_bloom_texture_screen; @@ -116,8 +121,6 @@ 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) { @@ -217,94 +220,6 @@ void FOG_registercvars(void) } } -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; yname, sizeof(entname)); - l = strlen(entname) - 4; + l = (int)strlen(entname) - 4; if (l >= 0 && !strcmp(entname + l, ".bsp")) { strcpy(entname + l, ".ent"); - if ((entities = FS_LoadFile(entname, tempmempool, true))) + if ((entities = (char *)FS_LoadFile(entname, tempmempool, true))) { CL_ParseEntityLump(entities); Mem_Free(entities); @@ -495,14 +409,16 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_lerpsprites); Cvar_RegisterVariable(&r_lerpmodels); Cvar_RegisterVariable(&r_waterscroll); - Cvar_RegisterVariable(&r_watershader); Cvar_RegisterVariable(&r_drawcollisionbrushes); Cvar_RegisterVariable(&r_bloom); Cvar_RegisterVariable(&r_bloom_intensity); Cvar_RegisterVariable(&r_bloom_blur); Cvar_RegisterVariable(&r_bloom_resolution); Cvar_RegisterVariable(&r_bloom_power); + Cvar_RegisterVariable(&r_smoothnormals_areaweighting); Cvar_RegisterVariable(&developer_texturelogging); + Cvar_RegisterVariable(&gl_lightmaps); + Cvar_RegisterVariable(&r_test); 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); @@ -567,7 +483,6 @@ void Render_Init(void) { gl_backend_init(); R_Textures_Init(); - Mod_RenderInit(); R_MeshQueue_Init(); GL_Main_Init(); GL_Draw_Init(); @@ -581,6 +496,7 @@ void Render_Init(void) UI_Init(); Sbar_Init(); R_LightningBeams_Init(); + Mod_RenderInit(); } /* @@ -594,7 +510,7 @@ void GL_Init (void) VID_CheckExtensions(); // LordHavoc: report supported extensions - Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS); + Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions ); // clear to black (loading plaque will be seen over this) qglClearColor(0,0,0,1); @@ -802,8 +718,8 @@ static void R_BlendView(void) // 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); + for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2); + for (screenheight = 1;screenheight < vid.height;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); @@ -840,14 +756,14 @@ static void R_BlendView(void) R_Mesh_State(&m); // 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); + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (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 // 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); + qglViewport(r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight); GL_BlendFunc(GL_ONE, GL_ZERO); GL_Color(1, 1, 1, 1); R_Mesh_Draw(0, 4, 2, polygonelements); @@ -869,7 +785,7 @@ static void R_BlendView(void) m.pointer_texcoord[0] = varray_texcoord2f[2]; R_Mesh_State(&m); GL_ActiveTexture(0); - qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight); + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight); c_bloomcopies++; c_bloomcopypixels += bloomwidth * bloomheight; // blend on at multiple vertical offsets to achieve a vertical blur @@ -903,7 +819,7 @@ static void R_BlendView(void) } // 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); + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight); c_bloomcopies++; c_bloomcopypixels += bloomwidth * bloomheight; // blend the vertically blurred image at multiple offsets horizontally @@ -938,11 +854,11 @@ static void R_BlendView(void) } // copy the 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); + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight); c_bloomcopies++; 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); + qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height); // put the original screen image back in place and blend the bloom // texture on it memset(&m, 0, sizeof(m)); @@ -998,6 +914,8 @@ static void R_BlendView(void) void R_RenderScene(void); +matrix4x4_t r_waterscrollmatrix; + /* ================ R_RenderView @@ -1008,11 +926,11 @@ void R_RenderView(void) if (!r_refdef.entities/* || !r_refdef.worldmodel*/) return; //Host_Error ("R_RenderView: NULL worldmodel"); - r_view_width = bound(0, r_refdef.width, vid.realwidth); - r_view_height = bound(0, r_refdef.height, vid.realheight); + r_view_width = bound(0, r_refdef.width, vid.width); + r_view_height = bound(0, r_refdef.height, vid.height); r_view_depth = 1; - r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width); - r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height); + r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width); + r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height); r_view_z = 0; r_view_fov_x = bound(1, r_refdef.fov_x, 170); r_view_fov_y = bound(1, r_refdef.fov_y, 170); @@ -1025,7 +943,7 @@ void R_RenderView(void) r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1; // GL is weird because it's bottom to top, r_view_y is top to bottom - qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height); + qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height); GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height); GL_ScissorTest(true); GL_DepthMask(true); @@ -1047,7 +965,7 @@ void R_RenderView(void) R_BlendView(); R_TimeReport("blendview"); - GL_Scissor(0, 0, vid.realwidth, vid.realheight); + GL_Scissor(0, 0, vid.width, vid.height); GL_ScissorTest(false); } @@ -1074,6 +992,8 @@ void R_RenderScene(void) GL_SetupView_Orientation_FromEntity(&r_view_matrix); + Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); + R_SkyStartFrame(); R_WorldVisibility(); @@ -1236,7 +1156,7 @@ float nomodelcolor4f[6*4] = void R_DrawNoModelCallback(const void *calldata1, int calldata2) { - const entity_render_t *ent = calldata1; + const entity_render_t *ent = (entity_render_t *)calldata1; int i; float f1, f2, *c, diff[3]; float color4f[6*4]; @@ -1435,4 +1355,802 @@ void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *plane } } +void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, matrix4x4_t *matrix, float r, float g, float b, float a) +{ + texturelayer_t *layer; + layer = t->currentlayers + t->currentnumlayers++; + layer->type = type; + layer->depthmask = depthmask; + layer->blendfunc1 = blendfunc1; + layer->blendfunc2 = blendfunc2; + layer->texture = texture; + layer->texmatrix = *matrix; + layer->color[0] = r; + layer->color[1] = g; + layer->color[2] = b; + layer->color[3] = a; +} + +void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) +{ + // FIXME: identify models using a better check than ent->model->brush.shadowmesh + //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2; + float currentalpha; + + { + texture_t *texture = t; + model_t *model = ent->model; + int s = ent->skinnum; + if ((unsigned int)s >= (unsigned int)model->numskins) + s = 0; + if (s >= 1) + c_models++; + if (model->skinscenes) + { + if (model->skinscenes[s].framecount > 1) + s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount; + else + s = model->skinscenes[s].firstframe; + } + if (s > 0) + t = t + s * model->num_surfaces; + if (t->animated) + t = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0]; + texture->currentframe = t; + } + + t->currentmaterialflags = t->basematerialflags; + currentalpha = ent->alpha; + if (t->basematerialflags & MATERIALFLAG_WATERALPHA) + currentalpha *= r_wateralpha.value; + if (!(ent->flags & RENDER_LIGHT)) + t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; + if (ent->effects & EF_ADDITIVE) + t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT; + else if (currentalpha < 1) + t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT; + if (ent->effects & EF_NODEPTHTEST) + t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST; + if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0) + t->currenttexmatrix = r_waterscrollmatrix; + else + t->currenttexmatrix = r_identitymatrix; + t->currentnumlayers = 0; + if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + if (gl_lightmaps.integer) + R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS, r_texture_white, &r_identitymatrix, 1, 1, 1, 1); + else if (t->currentmaterialflags & MATERIALFLAG_SKY) + { + // transparent sky would be ridiculous + if (!(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_SKY, r_texture_white, &r_identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], 1); + } + else + { + int blendfunc1, blendfunc2, depthmask; + if (t->currentmaterialflags & MATERIALFLAG_ADD) + { + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE; + depthmask = false; + } + else if (t->currentmaterialflags & MATERIALFLAG_ALPHA) + { + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE_MINUS_SRC_ALPHA; + depthmask = false; + } + else + { + blendfunc1 = GL_ONE; + blendfunc2 = GL_ZERO; + depthmask = true; + } + if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL)) + { + rtexture_t *currentbasetexture; + int layerflags = 0; + if (fogenabled && (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + layerflags |= TEXTURELAYERFLAG_FOGDARKEN; + currentbasetexture = (ent->colormap < 0 && t->skin.merged) ? t->skin.merged : t->skin.base; + if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], currentalpha); + if (ent->colormap >= 0 && t->skin.pants) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2], currentalpha); + if (ent->colormap >= 0 && t->skin.shirt) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2], currentalpha); + } + else + { + float colorscale; + colorscale = 2; + // q3bsp has no lightmap updates, so the lightstylevalue that + // would normally be baked into the lightmaptexture must be + // applied to the color + if (ent->model->type == mod_brushq3) + colorscale *= d_lightstylevalue[0] * (1.0f / 256.0f); + // transparent and fullbright are not affected by r_lightmapintensity + if (!(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + colorscale *= r_lightmapintensity; + if (r_textureunits.integer >= 2 && gl_combine.integer) + R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_COMBINE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, currentalpha); + else if ((t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) == 0) + R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale * 0.5f, ent->colormod[1] * colorscale * 0.5f, ent->colormod[2] * colorscale * 0.5f, currentalpha); + else + R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, currentalpha); + if (r_ambient.value >= (1.0f/64.0f)) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), currentalpha); + if (ent->colormap >= 0 && t->skin.pants) + { + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * colorscale, ent->colormap_pantscolor[1] * colorscale, ent->colormap_pantscolor[2] * colorscale, currentalpha); + if (r_ambient.value >= (1.0f/64.0f)) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * r_ambient.value * (1.0f / 64.0f), currentalpha); + } + if (ent->colormap >= 0 && t->skin.shirt) + { + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * colorscale, ent->colormap_shirtcolor[1] * colorscale, ent->colormap_shirtcolor[2] * colorscale, currentalpha); + if (r_ambient.value >= (1.0f/64.0f)) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * r_ambient.value * (1.0f / 64.0f), currentalpha); + } + } + if (t->skin.glow != NULL) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, 1, 1, 1, currentalpha); + if (fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD)) + { + // if this is opaque use alpha blend which will darken the earlier + // passes cheaply. + // + // if this is an alpha blended material, all the earlier passes + // were darkened by fog already, so we only need to add the fog + // color ontop through the fog mask texture + // + // if this is an additive blended material, all the earlier passes + // were darkened by fog already, and we should not add fog color + // (because the background was not darkened, there is no fog color + // that was lost behind it). + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &r_identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha); + } + } + } + } +} + +void R_UpdateAllTextureInfo(entity_render_t *ent) +{ + int i; + if (ent->model) + for (i = 0;i < ent->model->num_textures;i++) + R_UpdateTextureInfo(ent, ent->model->data_textures + i); +} + +float *rsurface_vertex3f; +float *rsurface_svector3f; +float *rsurface_tvector3f; +float *rsurface_normal3f; +float *rsurface_lightmapcolor4f; + +void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg) +{ + int i, j; + float center[3], forward[3], right[3], up[3], v[4][3]; + matrix4x4_t matrix1, imatrix1; + if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights)) + { + rsurface_vertex3f = varray_vertex3f; + rsurface_svector3f = NULL; + rsurface_tvector3f = NULL; + rsurface_normal3f = NULL; + Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f); + } + else + { + rsurface_vertex3f = surface->groupmesh->data_vertex3f; + rsurface_svector3f = surface->groupmesh->data_svector3f; + rsurface_tvector3f = surface->groupmesh->data_tvector3f; + rsurface_normal3f = surface->groupmesh->data_normal3f; + } + if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2) + { + if (!rsurface_svector3f) + { + rsurface_svector3f = varray_svector3f; + rsurface_tvector3f = varray_tvector3f; + rsurface_normal3f = varray_normal3f; + Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer); + } + // a single autosprite surface can contain multiple sprites... + VectorClear(forward); + VectorClear(right); + VectorSet(up, 0, 0, 1); + for (j = 0;j < surface->num_vertices - 3;j += 4) + { + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); + VectorScale(center, 0.25f, center); + // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out? + Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center); + Matrix4x4_Invert_Simple(&imatrix1, &matrix1); + for (i = 0;i < 4;i++) + Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]); + forward[0] = modelorg[0] - center[0]; + forward[1] = modelorg[1] - center[1]; + VectorNormalize(forward); + right[0] = forward[1]; + right[1] = -forward[0]; + for (i = 0;i < 4;i++) + VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3); + } + rsurface_vertex3f = varray_vertex3f; + rsurface_svector3f = NULL; + rsurface_tvector3f = NULL; + rsurface_normal3f = NULL; + } + else if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE) + { + if (!rsurface_svector3f) + { + rsurface_svector3f = varray_svector3f; + rsurface_tvector3f = varray_tvector3f; + rsurface_normal3f = varray_normal3f; + Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer); + } + Matrix4x4_Transform(&ent->inversematrix, r_viewforward, forward); + Matrix4x4_Transform(&ent->inversematrix, r_viewright, right); + Matrix4x4_Transform(&ent->inversematrix, r_viewup, up); + // a single autosprite surface can contain multiple sprites... + for (j = 0;j < surface->num_vertices - 3;j += 4) + { + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); + VectorScale(center, 0.25f, center); + // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out? + Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center); + Matrix4x4_Invert_Simple(&imatrix1, &matrix1); + for (i = 0;i < 4;i++) + Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]); + for (i = 0;i < 4;i++) + VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3); + } + rsurface_vertex3f = varray_vertex3f; + rsurface_svector3f = NULL; + rsurface_tvector3f = NULL; + rsurface_normal3f = NULL; + } + R_Mesh_VertexPointer(rsurface_vertex3f); +} + +void RSurf_SetColorPointer(const entity_render_t *ent, const msurface_t *surface, const vec3_t modelorg, float r, float g, float b, float a, int lightmode, qboolean applycolor, qboolean applyfog) +{ + int i; + float f; + float *v, *c, *c2; + vec3_t diff; + if (lightmode >= 2) + { + // model lighting + vec4_t ambientcolor4f; + vec3_t diffusecolor; + vec3_t diffusenormal; + if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, r*0.5f, g*0.5f, b*0.5f, a, false)) + { + rsurface_lightmapcolor4f = varray_color4f; + if (rsurface_normal3f == NULL) + { + rsurface_normal3f = varray_normal3f; + Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f, r_smoothnormals_areaweighting.integer); + } + R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, surface->groupmesh->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, rsurface_lightmapcolor4f + 4 * surface->num_firstvertex); + r = 1; + g = 1; + b = 1; + a = 1; + applycolor = false; + } + else + { + r = ambientcolor4f[0]; + g = ambientcolor4f[1]; + b = ambientcolor4f[2]; + a = ambientcolor4f[3]; + rsurface_lightmapcolor4f = NULL; + } + } + else if (lightmode >= 1) + { + if (surface->lightmapinfo) + { + for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4) + { + const qbyte *lm = surface->lightmapinfo->samples + (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i]; + if (lm) + { + float scale = d_lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f); + VectorScale(lm, scale, c); + if (surface->lightmapinfo->styles[1] != 255) + { + int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3; + lm += size3; + scale = d_lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[2] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[3] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + } + } + } + } + else + VectorClear(c); + } + rsurface_lightmapcolor4f = varray_color4f; + } + else + rsurface_lightmapcolor4f = surface->groupmesh->data_lightmapcolor4f; + } + else + rsurface_lightmapcolor4f = NULL; + if (applyfog) + { + if (rsurface_lightmapcolor4f) + { + for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c2[0] = c[0] * f; + c2[1] = c[1] * f; + c2[2] = c[2] * f; + c2[3] = c[3]; + } + } + else + { + for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c2[0] = f; + c2[1] = f; + c2[2] = f; + c2[3] = 1; + } + } + rsurface_lightmapcolor4f = varray_color4f; + } + if (applycolor && rsurface_lightmapcolor4f) + { + for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4) + { + c2[0] = c[0] * r; + c2[1] = c[1] * g; + c2[2] = c[2] * b; + c2[3] = c[3] * a; + } + rsurface_lightmapcolor4f = varray_color4f; + } + R_Mesh_ColorPointer(rsurface_lightmapcolor4f); + GL_Color(r, g, b, a); +} + + +static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg) +{ + int texturesurfaceindex; + int lightmode; + const msurface_t *surface; + qboolean applycolor; + rmeshstate_t m; + if (texture->currentmaterialflags & MATERIALFLAG_NODRAW) + return; + c_faces += texturenumsurfaces; + // FIXME: identify models using a better check than ent->model->brush.shadowmesh + lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2; + GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglDisable(GL_CULL_FACE); + if (texture->currentnumlayers) + { + int layerindex; + texturelayer_t *layer; + for (layerindex = 0, layer = texture->currentlayers;layerindex < texture->currentnumlayers;layerindex++, layer++) + { + vec4_t layercolor; + int layertexrgbscale; + GL_DepthMask(layer->depthmask); + GL_BlendFunc(layer->blendfunc1, layer->blendfunc2); + if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask)) + { + layertexrgbscale = 4; + VectorScale(layer->color, 0.25f, layercolor); + } + else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask)) + { + layertexrgbscale = 2; + VectorScale(layer->color, 0.5f, layercolor); + } + else + { + layertexrgbscale = 1; + VectorScale(layer->color, 1.0f, layercolor); + } + layercolor[3] = layer->color[3]; + GL_Color(layercolor[0], layercolor[1], layercolor[2], layercolor[3]); + applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1; + switch (layer->type) + { + case TEXTURELAYERTYPE_SKY: + if (skyrendernow) + { + skyrendernow = false; + if (skyrendermasked) + { + R_Sky(); + // restore entity matrix and GL_Color + R_Mesh_Matrix(&ent->matrix); + GL_Color(layercolor[0], layercolor[1], layercolor[2], layercolor[3]); + } + } + // LordHavoc: HalfLife maps have freaky skypolys... + //if (!ent->model->brush.ishlbsp) + { + if (skyrendermasked) + { + // depth-only (masking) + GL_ColorMask(0,0,0,0); + // just to make sure that braindead drivers don't draw anything + // despite that colormask... + GL_BlendFunc(GL_ZERO, GL_ONE); + } + else + { + // fog sky + GL_BlendFunc(GL_ONE, GL_ZERO); + } + memset(&m, 0, sizeof(m)); + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + if (skyrendermasked) + GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1); + } + break; + case TEXTURELAYERTYPE_LITTEXTURE_COMBINE: + memset(&m, 0, sizeof(m)); + m.tex[1] = R_GetTexture(layer->texture); + m.texmatrix[1] = layer->texmatrix; + m.texrgbscale[1] = layertexrgbscale; + m.pointer_color = varray_color4f; + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f); + R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f); + if (lightmode == 2) + { + R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 2, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + } + else if (surface->lightmaptexture) + { + R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture)); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + } + else + { + R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 1, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + } + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + break; + case TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS: + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(layer->texture); + m.texmatrix[0] = layer->texmatrix; + m.pointer_color = varray_color4f; + m.texrgbscale[0] = layertexrgbscale; + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f); + if (lightmode == 2) + { + R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); + RSurf_SetColorPointer(ent, surface, modelorg, 1, 1, 1, 1, 2, false, false); + } + else if (surface->lightmaptexture) + { + R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture)); + R_Mesh_ColorPointer(NULL); + } + else + { + R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); + RSurf_SetColorPointer(ent, surface, modelorg, 1, 1, 1, 1, 1, false, false); + } + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(layer->texture); + m.texmatrix[0] = layer->texmatrix; + m.pointer_color = varray_color4f; + m.texrgbscale[0] = layertexrgbscale; + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + break; + case TEXTURELAYERTYPE_LITTEXTURE_VERTEX: + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(layer->texture); + m.texmatrix[0] = layer->texmatrix; + m.texrgbscale[0] = layertexrgbscale; + m.pointer_color = varray_color4f; + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], lightmode ? lightmode : 1, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + break; + case TEXTURELAYERTYPE_TEXTURE: + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(layer->texture); + m.texmatrix[0] = layer->texmatrix; + m.pointer_color = varray_color4f; + m.texrgbscale[0] = layertexrgbscale; + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f); + RSurf_SetColorPointer(ent, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, layer->flags & TEXTURELAYERFLAG_FOGDARKEN); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + break; + case TEXTURELAYERTYPE_FOG: + memset(&m, 0, sizeof(m)); + if (layer->texture) + { + m.tex[0] = R_GetTexture(layer->texture); + m.texmatrix[0] = layer->texmatrix; + } + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + int i; + float diff[3]; + float f, *v, *c; + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + if (layer->texture) + R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f); + R_Mesh_ColorPointer(varray_color4f); + for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = exp(fogdensity/DotProduct(diff, diff)); + c[0] = layercolor[0]; + c[1] = layercolor[1]; + c[2] = layercolor[2]; + c[3] = f * layercolor[3]; + } + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + break; + default: + Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type); + } + // if trying to do overbright on first pass of an opaque surface + // when combine is not supported, brighten as a post process + if (layertexrgbscale > 1 && !gl_combine.integer && layer->depthmask) + { + int scale; + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + GL_Color(1, 1, 1, 1); + memset(&m, 0, sizeof(m)); + R_Mesh_State(&m); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + for (scale = 1;scale < layertexrgbscale;scale <<= 1) + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); + GL_LockArrays(0, 0); + } + } + } + } + if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglEnable(GL_CULL_FACE); +} + +static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2) +{ + const entity_render_t *ent = (entity_render_t *)calldata1; + const msurface_t *surface = ent->model->data_surfaces + calldata2; + vec3_t modelorg; + texture_t *texture; + + texture = surface->texture; + if (texture->basematerialflags & MATERIALFLAG_SKY) + return; // transparent sky is too difficult + R_UpdateTextureInfo(ent, texture); + + R_Mesh_Matrix(&ent->matrix); + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + R_DrawTextureSurfaceList(ent, texture->currentframe, 1, &surface, modelorg); +} + +void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg) +{ + int texturesurfaceindex; + const msurface_t *surface; + vec3_t tempcenter, center; + if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + { + // drawing sky transparently would be too difficult + if (!(texture->currentmaterialflags & MATERIALFLAG_SKY)) + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + Matrix4x4_Transform(&ent->matrix, tempcenter, center); + R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->data_surfaces); + } + } + } + else + R_DrawTextureSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg); +} + +extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); +void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) +{ + int i, j, f, flagsmask; + msurface_t *surface, **surfacechain; + texture_t *t, *texture; + model_t *model = ent->model; + vec3_t modelorg; + const int maxsurfacelist = 1024; + int numsurfacelist = 0; + const msurface_t *surfacelist[1024]; + if (model == NULL) + return; + R_Mesh_Matrix(&ent->matrix); + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + + // update light styles + if (!skysurfaces && model->brushq1.light_styleupdatechains) + { + for (i = 0;i < model->brushq1.light_styles;i++) + { + if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]]) + { + model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]]; + if ((surfacechain = model->brushq1.light_styleupdatechains[i])) + for (;(surface = *surfacechain);surfacechain++) + surface->cached_dlight = true; + } + } + } + + R_UpdateAllTextureInfo(ent); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL); + f = 0; + t = NULL; + texture = NULL; + numsurfacelist = 0; + if (ent == r_refdef.worldentity) + { + for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + { + if (!r_worldsurfacevisible[j]) + continue; + if (t != surface->texture) + { + if (numsurfacelist) + { + R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); + numsurfacelist = 0; + } + t = surface->texture; + texture = t->currentframe; + f = texture->currentmaterialflags & flagsmask; + } + if (f && surface->num_triangles) + { + // if lightmap parameters changed, rebuild lightmap texture + if (surface->cached_dlight && surface->lightmapinfo->samples) + R_BuildLightMap(ent, surface); + // add face to draw list + surfacelist[numsurfacelist++] = surface; + if (numsurfacelist >= maxsurfacelist) + { + R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); + numsurfacelist = 0; + } + } + } + } + else + { + for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + { + if (t != surface->texture) + { + if (numsurfacelist) + { + R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); + numsurfacelist = 0; + } + t = surface->texture; + texture = t->currentframe; + f = texture->currentmaterialflags & flagsmask; + } + if (f && surface->num_triangles) + { + // if lightmap parameters changed, rebuild lightmap texture + if (surface->cached_dlight && surface->lightmapinfo->samples) + R_BuildLightMap(ent, surface); + // add face to draw list + surfacelist[numsurfacelist++] = surface; + if (numsurfacelist >= maxsurfacelist) + { + R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); + numsurfacelist = 0; + } + } + } + } + if (numsurfacelist) + R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); +}