From: havoc Date: Mon, 25 May 2020 04:18:02 +0000 (+0000) Subject: Reworked VM_CL_PolygonBegin/Vertex/End functions to do the commit to the mesh in... X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=df1cc2c4115be684d1e899643f4a47d40d073add Reworked VM_CL_PolygonBegin/Vertex/End functions to do the commit to the mesh in PolygonEnd, this allows it to examine if alpha is used on vertices and request different variants of a material according to such discoveries. Refactored CL_MeshEntities_AddToScene and CL_MeshEntities_Reset to be the more distinct stages of CL_MeshEntities_Scene_Clear (which is called in VM_CL_R_ClearScene), CL_MeshEntities_Scene_AddRenderEntity (which is called during VM_CL_R_AddEntities), and CL_MeshEntities_Scene_FinalizeRenderEntity (which is called during VM_CL_R_RenderScene) - this fixes issues with CSQC predraw functions adding polygons which were not subject to Finalize and thus not rendered. Fixed Mod_LoadTextureFromQ3Shader handling of texture name "" to properly set basematerialflags, this fixes invisible polygons in some games such as Xonotic. Refactored CL_Mesh_CSQC and CL_Mesh_Debug into CL_Mesh_Scene - not really a need for more than one mesh to overlay on the world. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12567 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_main.c b/cl_main.c index 5932212e..210d35f5 100644 --- a/cl_main.c +++ b/cl_main.c @@ -1873,6 +1873,8 @@ void CSQC_RelinkAllEntities (int drawmask) { // link stuff CL_RelinkWorld(); + // the scene mesh is added first for easier debugging (consistent spot in render entities list) + CL_MeshEntities_Scene_AddRenderEntity(); CL_RelinkStaticEntities(); CL_RelinkBeams(); CL_RelinkEffects(); @@ -1889,8 +1891,6 @@ void CSQC_RelinkAllEntities (int drawmask) // update view blend V_CalcViewBlend(); - - CL_MeshEntities_AddToScene(); } /* @@ -1941,7 +1941,12 @@ void CL_UpdateWorld(void) // when csqc is loaded, it will call this in CSQC_UpdateView if (!cl.csqc_loaded) + { + // clear the CL_Mesh_Scene() used for some engine effects + CL_MeshEntities_Scene_Clear(); + // add engine entities and effects CSQC_RelinkAllEntities(ENTMASK_ENGINE | ENTMASK_ENGINEVIEWMODELS); + } // decals, particles, and explosions will be updated during rneder } @@ -2370,9 +2375,7 @@ entity_t cl_meshentities[NUM_MESHENTITIES]; dp_model_t cl_meshentitymodels[NUM_MESHENTITIES]; const char *cl_meshentitynames[NUM_MESHENTITIES] = { - "MESH_DEBUG", - "MESH_CSQC_POLYGONS", - "MESH_PARTICLES", + "MESH_SCENE", "MESH_UI", }; @@ -2397,7 +2400,7 @@ static void CL_MeshEntities_Init(void) ent->state_current.active = true; ent->render.model = cl_meshentitymodels + i; Mod_Mesh_Create(ent->render.model, cl_meshentitynames[i]); - ent->render.alpha = 0.999999f; // not quite 1 so that MATERIALFLAG_ALPHA is always set. + ent->render.alpha = 1; ent->render.flags = RENDER_SHADOW | RENDER_LIGHT; ent->render.framegroupblend[0].lerp = 1; ent->render.frameblend[0].lerp = 1; @@ -2425,30 +2428,25 @@ static void CL_MeshEntities_Init(void) R_RegisterModule("cl_meshentities", CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart, CL_MeshEntities_Restart); } -void CL_MeshEntities_AddToScene(void) +void CL_MeshEntities_Scene_Clear(void) { - int i; - entity_t *ent; - for (i = 0; i < NUM_MESHENTITIES && r_refdef.scene.numentities < r_refdef.scene.maxentities; i++) - { - ent = cl_meshentities + i; - if (ent->render.model->num_surfaces == 0) - continue; - Mod_Mesh_Finalize(ent->render.model); - VectorCopy(ent->render.model->normalmins, ent->render.mins); - VectorCopy(ent->render.model->normalmaxs, ent->render.maxs); - r_refdef.scene.entities[r_refdef.scene.numentities++] = &ent->render; - } + Mod_Mesh_Reset(CL_Mesh_Scene()); } -void CL_MeshEntities_Reset(void) +void CL_MeshEntities_Scene_AddRenderEntity(void) { - int i; - entity_t *ent; - for (i = 0; i < NUM_MESHENTITIES && r_refdef.scene.numentities < r_refdef.scene.maxentities; i++) + entity_t* ent = &cl_meshentities[MESH_SCENE]; + r_refdef.scene.entities[r_refdef.scene.numentities++] = &ent->render; +} + +void CL_MeshEntities_Scene_FinalizeRenderEntity(void) +{ + entity_t *ent = &cl_meshentities[MESH_SCENE]; + if (ent->render.model->num_surfaces) { - ent = cl_meshentities + i; - Mod_Mesh_Reset(ent->render.model); + Mod_Mesh_Finalize(ent->render.model); + VectorCopy(ent->render.model->normalmins, ent->render.mins); + VectorCopy(ent->render.model->normalmaxs, ent->render.maxs); } } diff --git a/cl_screen.c b/cl_screen.c index 82fbc8ce..9ce2f577 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -2175,6 +2175,9 @@ static void SCR_DrawScreen (void) CL_VM_UpdateView(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime)); else { + // Prepare the scene mesh for rendering - this is lightning beams and other effects rendered as normal surfaces + CL_MeshEntities_Scene_FinalizeRenderEntity(); + CL_UpdateEntityShading(); R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); } diff --git a/client.h b/client.h index 06031c94..45312d96 100644 --- a/client.h +++ b/client.h @@ -2010,21 +2010,18 @@ void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s); void CL_RotateMoves(const matrix4x4_t *m); typedef enum meshname_e { - MESH_DEBUG, - MESH_CSQCPOLYGONS, - MESH_PARTICLES, + MESH_SCENE, // CSQC R_PolygonBegin, potentially also engine particles and debug stuff MESH_UI, NUM_MESHENTITIES, } meshname_t; extern entity_t cl_meshentities[NUM_MESHENTITIES]; extern dp_model_t cl_meshentitymodels[NUM_MESHENTITIES]; extern const char *cl_meshentitynames[NUM_MESHENTITIES]; -#define CL_Mesh_Debug() (&cl_meshentitymodels[MESH_DEBUG]) -#define CL_Mesh_CSQC() (&cl_meshentitymodels[MESH_CSQCPOLYGONS]) -#define CL_Mesh_Particles() (&cl_meshentitymodels[MESH_PARTICLES]) +#define CL_Mesh_Scene() (&cl_meshentitymodels[MESH_SCENE]) #define CL_Mesh_UI() (&cl_meshentitymodels[MESH_UI]) -void CL_MeshEntities_AddToScene(void); -void CL_MeshEntities_Reset(void); +void CL_MeshEntities_Scene_Clear(void); +void CL_MeshEntities_Scene_AddRenderEntity(void); +void CL_MeshEntities_Scene_FinalizeRenderEntity(void); void CL_UpdateEntityShading(void); void CL_NewFrameReceived(int num); diff --git a/clvm_cmds.c b/clvm_cmds.c index eb297680..efbae27c 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -743,6 +743,8 @@ static void VM_CL_R_ClearScene (prvm_prog_t *prog) cl.csqc_vidvars.drawenginesbar = false; cl.csqc_vidvars.drawcrosshair = false; CSQC_R_RecalcView(); + // clear the CL_Mesh_Scene() used for CSQC polygons and engine effects, they will be added by CSQC_RelinkAllEntities and manually created by CSQC + CL_MeshEntities_Scene_Clear(); } //#301 void(float mask) addentities (EXT_CSQC) @@ -3251,17 +3253,17 @@ static void VM_CL_R_RenderScene (prvm_prog_t *prog) csqc_main_r_refdef_view = r_refdef.view; } + // now after all of the predraw we know the geometry in the scene mesh and can finalize it for rendering + CL_MeshEntities_Scene_FinalizeRenderEntity(); + // we need to update any RENDER_VIEWMODEL entities at this point because // csqc supplies its own view matrix CL_UpdateViewEntities(); - CL_MeshEntities_AddToScene(); CL_UpdateEntityShading(); // now draw stuff! R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); - Mod_Mesh_Reset(CL_Mesh_CSQC()); - // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0; prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t; @@ -3303,9 +3305,11 @@ static void VM_CL_R_PolygonBegin (prvm_prog_t *prog) } // we need to remember whether this is a 2D or 3D mesh we're adding to - mod = draw2d ? CL_Mesh_UI() : CL_Mesh_CSQC(); + mod = draw2d ? CL_Mesh_UI() : CL_Mesh_Scene(); prog->polygonbegin_model = mod; - Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, texname, drawflags, TEXF_ALPHA, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), false); + strlcpy(prog->polygonbegin_texname, texname, sizeof(prog->polygonbegin_texname)); + prog->polygonbegin_drawflags = drawflags; + prog->polygonbegin_numvertices = 0; } //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex @@ -3315,47 +3319,87 @@ static void VM_CL_R_PolygonVertex (prvm_prog_t *prog) const prvm_vec_t *tc = PRVM_G_VECTOR(OFS_PARM1); const prvm_vec_t *c = PRVM_G_VECTOR(OFS_PARM2); const prvm_vec_t a = PRVM_G_FLOAT(OFS_PARM3); + float *o; dp_model_t *mod = prog->polygonbegin_model; - int e0, e1, e2; - msurface_t *surf; VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex); - if (!mod || mod->num_surfaces == 0) + if (!mod) { VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n"); return; } - surf = &mod->data_surfaces[mod->num_surfaces - 1]; - e2 = Mod_Mesh_IndexForVertex(mod, surf, v[0], v[1], v[2], 0, 0, 0, tc[0], tc[1], 0, 0, c[0], c[1], c[2], a); - if (surf->num_vertices >= 3) + if (prog->polygonbegin_maxvertices <= prog->polygonbegin_numvertices) { - // the first element is the start of the triangle fan - e0 = surf->num_firstvertex; - // the second element is the previous vertex - e1 = e0 + 1; - if (surf->num_triangles > 0) - e1 = mod->surfmesh.data_element3i[(surf->num_firsttriangle + surf->num_triangles) * 3 - 1]; - Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2); + prog->polygonbegin_maxvertices = max(16, prog->polygonbegin_maxvertices * 2); + prog->polygonbegin_vertexdata = (float *)Mem_Realloc(prog->progs_mempool, prog->polygonbegin_vertexdata, prog->polygonbegin_maxvertices * sizeof(float[10])); } + o = prog->polygonbegin_vertexdata + prog->polygonbegin_numvertices++ * 10; + + o[0] = v[0]; + o[1] = v[1]; + o[2] = v[2]; + o[3] = tc[0]; + o[4] = tc[1]; + o[5] = tc[2]; + o[6] = c[0]; + o[7] = c[1]; + o[8] = c[2]; + o[9] = a; } //void() R_EndPolygon static void VM_CL_R_PolygonEnd (prvm_prog_t *prog) { + int i; + qboolean hascolor; + qboolean hasalpha; + int e0 = 0, e1 = 0, e2 = 0; + float *o; dp_model_t *mod = prog->polygonbegin_model; msurface_t *surf; VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd); - if (!mod || mod->num_surfaces == 0) + if (!mod) { VM_Warning(prog, "VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n"); return; } - surf = &mod->data_surfaces[mod->num_surfaces - 1]; + + // determine if vertex alpha is being used so we can provide that hint to GetTexture... + hascolor = false; + hasalpha = false; + for (i = 0; i < prog->polygonbegin_numvertices; i++) + { + o = prog->polygonbegin_vertexdata + 10 * i; + if (o[6] != 1.0f || o[7] != 1.0f || o[8] != 1.0f) + hascolor = true; + if (o[9] != 1.0f) + hasalpha = true; + } + + // create the surface, looking up the best matching texture/shader + surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, prog->polygonbegin_texname, prog->polygonbegin_drawflags, TEXF_ALPHA, MATERIALFLAG_WALL | (hascolor ? MATERIALFLAG_VERTEXCOLOR : 0) | (hasalpha ? MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW : 0)), false); + // create triangle fan + for (i = 0; i < prog->polygonbegin_numvertices; i++) + { + o = prog->polygonbegin_vertexdata + 10 * i; + e2 = Mod_Mesh_IndexForVertex(mod, surf, o[0], o[1], o[2], 0, 0, 0, o[3], o[4], 0, 0, o[6], o[7], o[8], o[9]); + if (i >= 2) + Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2); + else if (i == 0) + e0 = e2; + e1 = e2; + } + // build normals (since they are not provided) Mod_BuildNormals(surf->num_firstvertex, surf->num_vertices, surf->num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_element3i + 3 * surf->num_firsttriangle, mod->surfmesh.data_normal3f, true); + + // reset state prog->polygonbegin_model = NULL; + prog->polygonbegin_texname[0] = 0; + prog->polygonbegin_drawflags = 0; + prog->polygonbegin_numvertices = 0; } /* diff --git a/gl_draw.c b/gl_draw.c index 21871af5..cdd5b766 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -1506,7 +1506,7 @@ void DrawQ_FlushUI(void) return; } - // TODO: render the mesh using R_Q1BSP_Draw or similar, for full material support. + // this is roughly equivalent to R_Q1BSP_Draw, so the UI can use full material feature set r_refdef.view.colorscale = 1; r_textureframe++; // used only by R_GetCurrentTexture GL_DepthMask(false); diff --git a/host.c b/host.c index 7a813b6d..a73cd73c 100644 --- a/host.c +++ b/host.c @@ -1036,7 +1036,6 @@ void Host_Main(void) R_TimeReport("client"); CL_UpdateScreen(); - CL_MeshEntities_Reset(); R_TimeReport("render"); if (host_speeds.integer) diff --git a/model_shared.c b/model_shared.c index 811b26cb..b650c448 100644 --- a/model_shared.c +++ b/model_shared.c @@ -2555,6 +2555,7 @@ nothing GL_ZERO GL_ONE { if (developer_extra.integer) Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name); + texture->basematerialflags = defaultmaterialflags; texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; } else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw")) @@ -4400,7 +4401,7 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra texture_t *t; int drawflag = defaultdrawflags & DRAWFLAG_MASK; for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++) - if (!strcmp(t->name, name) && t->drawflag == drawflag) + if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag && t->mesh_defaulttexflags == defaulttexflags && t->mesh_defaultmaterialflags == defaultmaterialflags) return t; if (mod->max_textures <= mod->num_textures) { @@ -4413,7 +4414,9 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra } t = &mod->data_textures[mod->num_textures++]; Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags); - t->drawflag = drawflag; + t->mesh_drawflag = drawflag; + t->mesh_defaulttexflags = defaulttexflags; + t->mesh_defaultmaterialflags = defaultmaterialflags; switch (defaultdrawflags & DRAWFLAG_MASK) { case DRAWFLAG_ADDITIVE: diff --git a/model_shared.h b/model_shared.h index 64c3c7d7..db71e4b1 100644 --- a/model_shared.h +++ b/model_shared.h @@ -632,8 +632,10 @@ typedef struct texture_s // diffuse and ambient float rtlightambient; - // used by Mod_Mesh_GetTexture for drawflag overrides, to disambiguate the same texture with different drawflags - int drawflag; + // used by Mod_Mesh_GetTexture for drawflag and materialflag overrides, to disambiguate the same texture with different hints + int mesh_drawflag; + int mesh_defaulttexflags; + int mesh_defaultmaterialflags; } texture_t; diff --git a/progsvm.h b/progsvm.h index 392d8465..676aa67e 100644 --- a/progsvm.h +++ b/progsvm.h @@ -626,8 +626,13 @@ typedef struct prvm_prog_s // buffer for storing all tempstrings created during one invocation of ExecuteProgram sizebuf_t tempstringsbuf; - // in csqc the polygonbegin,polygonvertex,polygonend sequencing is - // stateful, so this tracks the last polygonbegin's choice of + // polygonbegin, polygonvertex, polygonend state + // the polygon is buffered here until polygonend commits it to the relevant + // CL_Mesh entity, because important decisions depend on the vertex data + // provided (e.g. whether the polygon is transparent), we can't really do much + // with it until we have all of the data... + + // this tracks the last polygonbegin's choice of // CL_Mesh_CSQC or CL_Mesh_UI for this polygon dp_model_t *polygonbegin_model; // indicates if polygonbegin should be interpreted as 2d @@ -637,6 +642,13 @@ typedef struct prvm_prog_s // where the behavior is always 3D unless DRAWFLAG_2D is passed, but // DRAWFLAG_2D conflicts with our DRAWFLAG_SCREEN. qboolean polygonbegin_guess2d; + // the texture name and drawflags provided to polygonbegin + char polygonbegin_texname[MAX_QPATH]; + int polygonbegin_drawflags; + // the vertex data + int polygonbegin_numvertices; + int polygonbegin_maxvertices; + float *polygonbegin_vertexdata; // copies of some vars that were former read from sv int num_edicts; diff --git a/r_lightning.c b/r_lightning.c index acdaec4d..b0299a40 100644 --- a/r_lightning.c +++ b/r_lightning.c @@ -21,7 +21,7 @@ static void r_lightningbeams_start(void) static void CL_Beams_SetupExternalTexture(void) { - if (Mod_LoadTextureFromQ3Shader(r_main_mempool, "r_lightning.c", &cl_beams_externaltexture, "textures/particles/lightning", false, false, TEXF_ALPHA | TEXF_FORCELINEAR, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE)) + if (Mod_LoadTextureFromQ3Shader(r_main_mempool, "r_lightning.c", &cl_beams_externaltexture, "textures/particles/lightning", false, false, TEXF_ALPHA | TEXF_FORCELINEAR, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NOSHADOW | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX)) Cvar_SetValueQuick(&r_lightningbeam_qmbtexture, false); } @@ -75,7 +75,7 @@ static void CL_Beams_SetupBuiltinTexture(void) } skinframe = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, texwidth, texheight, 0, 0, 0, false); - Mod_LoadCustomMaterial(r_main_mempool, &cl_beams_builtintexture, "cl_beams_builtintexture", 0, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX, skinframe); + Mod_LoadCustomMaterial(r_main_mempool, &cl_beams_builtintexture, "cl_beams_builtintexture", 0, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NOSHADOW | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX, skinframe); Mem_Free(data); } @@ -180,7 +180,7 @@ void CL_Beam_AddPolygons(const beam_t *b) // (and realize that the whole polygon assembly orients itself to face // the viewer) - mod = &cl_meshentitymodels[MESH_PARTICLES]; + mod = CL_Mesh_Scene(); surf = Mod_Mesh_AddSurface(mod, r_lightningbeam_qmbtexture.integer ? &cl_beams_externaltexture : &cl_beams_builtintexture, false); // polygon 1 VectorM(r_lightningbeam_thickness.value, right, offset);