]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Reworked VM_CL_PolygonBegin/Vertex/End functions to do the commit to the mesh in...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 25 May 2020 04:18:02 +0000 (04:18 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 25 May 2020 04:18:02 +0000 (04:18 +0000)
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

cl_main.c
cl_screen.c
client.h
clvm_cmds.c
gl_draw.c
host.c
model_shared.c
model_shared.h
progsvm.h
r_lightning.c

index 5932212e7e8fc1c75e89ad38bbae94bcf67d1bb8..210d35f5babcfd59e1558ae136a3186f3e613161 100644 (file)
--- 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);
        }
 }
 
index 82fbc8ce00ba09098235383e744d1065c34d345d..9ce2f5773906283bb62a39b02099a845d105d903 100644 (file)
@@ -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);
                }
index 06031c9409588bac7596d25c7d526e71c270f876..45312d96fcd95d53f97f7fbf5a4754823af9d423 100644 (file)
--- 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);
index eb2976804639de1230ecfe83ce99029e13350724..efbae27c981b292a522f20872399f766b05bc7aa 100644 (file)
@@ -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;
 }
 
 /*
index 21871af5a01852aa12842a1d76690ea0532e6b84..cdd5b766172ec63d233cf438d8ddb58448af165c 100644 (file)
--- 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 7a813b6db86b341e3a3134d10af91c979522cb32..a73cd73c1a19e9fe3ea60d11cd586645766487b4 100644 (file)
--- 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)
index 811b26cb794e68cfa8f32dc5fe397ee125215052..b650c44813258709aa0a47adfc0e64b4d9400290 100644 (file)
@@ -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:
index 64c3c7d7995f6a22b0a58c9808181099de169c3a..db71e4b112dae04b3210def3ec60f47c5f308714 100644 (file)
@@ -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;
 
index 392d8465ff4ca0696f77a1e16ce43e93a4d54916..676aa67e606d40436c0a39571688cf220013eb26 100644 (file)
--- 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;
index acdaec4dfbaefddd9bcbec09b13656f45ac2a6ec..b0299a40602cca2eb56a370efb8af209d4be454a 100644 (file)
@@ -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);