X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=clvm_cmds.c;h=a216cf7ffbaad02da24a5d08d70472ec35cfef3a;hb=cf03adfc67295bfeff10abafc9505090f527ed48;hp=f15abe5dfeeef0888b04aad981b653bb6a6ecc37;hpb=4a6fac9f373f532d7d634b73af48e584571cffb4;p=xonotic%2Fdarkplaces.git diff --git a/clvm_cmds.c b/clvm_cmds.c index f15abe5d..a216cf7f 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -21,7 +21,6 @@ //4 feature darkplaces csqc: add builtins to clientside qc for gl calls extern cvar_t v_flipped; -extern cvar_t r_equalize_entities_fullbright; r_refdef_view_t csqc_original_r_refdef_view; r_refdef_view_t csqc_main_r_refdef_view; @@ -129,7 +128,7 @@ static void VM_CL_setmodel (prvm_prog_t *prog) if( mod ) { // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black] - // LordHavoc: erm you broke it by commenting this out - setmodel must do setsize or else the qc can't find out the model size, and ssqc does this by necessity, consistency. + // LadyHavoc: erm you broke it by commenting this out - setmodel must do setsize or else the qc can't find out the model size, and ssqc does this by necessity, consistency. SetMinMaxSize (prog, e, mod->normalmins, mod->normalmaxs); } else @@ -207,7 +206,7 @@ static void VM_CL_sound (prvm_prog_t *prog) flags = 0; else { - // LordHavoc: we only let the qc set certain flags, others are off-limits + // LadyHavoc: we only let the qc set certain flags, others are off-limits flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME); } @@ -220,8 +219,6 @@ static void VM_CL_sound (prvm_prog_t *prog) else startposition = 0; - channel = CHAN_USER2ENGINE(channel); - if (!IS_CHAN(channel)) { VM_Warning(prog, "VM_CL_sound: channel must be in range 0-127\n"); @@ -319,7 +316,7 @@ if the tryents flag is set. tracebox (vector1, vector mins, vector maxs, vector2, tryents) ================= */ -// LordHavoc: added this for my own use, VERY useful, similar to traceline +// LadyHavoc: added this for my own use, VERY useful, similar to traceline static void VM_CL_tracebox (prvm_prog_t *prog) { vec3_t v1, v2, m1, m2; @@ -369,7 +366,7 @@ static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edi gravity = 1.0f; gravity *= cl.movevars_gravity * 0.05; - for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds + for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds { PRVM_clientedictvector(tossent, velocity)[2] -= gravity; VectorMA (PRVM_clientedictvector(tossent, angles), 0.05, PRVM_clientedictvector(tossent, avelocity), PRVM_clientedictvector(tossent, angles)); @@ -500,7 +497,7 @@ static void VM_CL_findradius (prvm_prog_t *prog) // (note: this is the reason you can't blow up fallen zombies) if (PRVM_clientedictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer) continue; - // LordHavoc: compare against bounding box rather than center so it + // LadyHavoc: compare against bounding box rather than center so it // doesn't miss large objects, and use DotProduct instead of Length // for a major speedup VectorSubtract(org, PRVM_clientedictvector(ent, origin), eorg); @@ -662,7 +659,7 @@ static void VM_CL_pointcontents (prvm_prog_t *prog) vec3_t point; VM_SAFEPARMCOUNT(1, VM_CL_pointcontents); VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point); - PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(point)); + PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(CL_PointSuperContents(point)); } // #48 void(vector o, vector d, float color, float count) particle @@ -686,8 +683,8 @@ static void VM_CL_ambientsound (prvm_prog_t *prog) vec3_t f; sfx_t *s; VM_SAFEPARMCOUNT(4, VM_CL_ambientsound); - s = S_FindName(PRVM_G_STRING(OFS_PARM0)); - VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f); + s = S_FindName(PRVM_G_STRING(OFS_PARM1)); S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64); } @@ -696,17 +693,12 @@ static void VM_CL_getlight (prvm_prog_t *prog) { vec3_t ambientcolor, diffusecolor, diffusenormal; vec3_t p; + int flags = prog->argc >= 2 ? PRVM_G_FLOAT(OFS_PARM1) : LP_LIGHTMAP; VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getlight); VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p); - VectorClear(ambientcolor); - VectorClear(diffusecolor); - VectorClear(diffusenormal); - if (prog->argc >= 2) - R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, PRVM_G_FLOAT(OFS_PARM1)); - else if (cl.worldmodel && cl.worldmodel->brush.LightPoint) - cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal); + R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, flags, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity); VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN)); if (PRVM_clientglobalvector(getlight_ambient)) VectorCopy(ambientcolor, PRVM_clientglobalvector(getlight_ambient)); @@ -741,12 +733,16 @@ static void VM_CL_R_ClearScene (prvm_prog_t *prog) r_refdef.scene.numlights = 0; // restore the view settings to the values that VM_CL_UpdateView received from the client code r_refdef.view = csqc_original_r_refdef_view; + // polygonbegin without draw2d arg has to guess + prog->polygonbegin_guess2d = false; VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); cl.csqc_vidvars.drawworld = r_drawworld.integer != 0; 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) @@ -1418,10 +1414,13 @@ static void VM_CL_boxparticles (prvm_prog_t *prog) static void VM_CL_setpause(prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_CL_setpause); - if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0) - cl.csqc_paused = true; - else - cl.csqc_paused = false; + if(cl.islocalgame) + { + if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0) + host.paused = true; + else + host.paused = false; + } } //#343 void(float usecursor) setcursormode (DP_CSQC) @@ -1627,20 +1626,9 @@ static void VM_CL_setlistener (prvm_prog_t *prog) //#352 void(string cmdname) registercommand (EXT_CSQC) static void VM_CL_registercmd (prvm_prog_t *prog) { - char *t; VM_SAFEPARMCOUNT(1, VM_CL_registercmd); - if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0))) - { - size_t alloclen; - - alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1; - t = (char *)Z_Malloc(alloclen); - memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen); - Cmd_AddCommand(t, NULL, "console command created by QuakeC"); - } - else - Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); - + if(!Cmd_Exists(&cmd_client, PRVM_G_STRING(OFS_PARM0))) + Cmd_AddCommand(CMD_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); } //#360 float() readbyte (EXT_CSQC) @@ -1719,13 +1707,11 @@ static void VM_CL_ReadPicture (prvm_prog_t *prog) // if yes, it is used and the data is discarded // if not, the (low quality) data is used to build a new texture, whose name will get returned - pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT); + pic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_FAILONMISSING); if(size) { - if(pic->tex == r_texture_notexture) - pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic - if(pic->tex && !cl_readpicture_force.integer) + if (Draw_IsPicLoaded(pic) && !cl_readpicture_force.integer) { // texture found and loaded // skip over the jpeg as we don't need it @@ -1740,7 +1726,7 @@ static void VM_CL_ReadPicture (prvm_prog_t *prog) MSG_ReadBytes(&cl_message, size, buf); data = JPEG_LoadImage_BGRA(buf, size, NULL); Mem_Free(buf); - Draw_NewPic(name, image_width, image_height, false, data); + Draw_NewPic(name, image_width, image_height, data, TEXTYPE_BGRA, TEXF_CLAMP); Mem_Free(data); } } @@ -1816,8 +1802,6 @@ static void VM_CL_makestatic (prvm_prog_t *prog) { if (!(staticent->render.effects & EF_FULLBRIGHT)) staticent->render.flags |= RENDER_LIGHT; - else if(r_equalize_entities_fullbright.integer) - staticent->render.flags |= RENDER_LIGHT | RENDER_EQUALIZE; } // turn off shadows from transparent objects if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1)) @@ -1877,6 +1861,9 @@ static void VM_CL_copyentity (prvm_prog_t *prog) return; } memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t)); + + if (VectorCompare(PRVM_clientedictvector(out, absmin), PRVM_clientedictvector(out, absmax))) + return; CL_LinkEdict(out); } @@ -1885,14 +1872,16 @@ static void VM_CL_copyentity (prvm_prog_t *prog) // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT) static void VM_CL_effect (prvm_prog_t *prog) { -#if 1 - Con_Printf("WARNING: VM_CL_effect not implemented\n"); // FIXME: this needs to take modelname not modelindex, the csqc defs has it as string and so it shall be -#else + dp_model_t *model; vec3_t org; VM_SAFEPARMCOUNT(5, VM_CL_effect); VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); - CL_Effect(org, (int)PRVM_G_FLOAT(OFS_PARM1), (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4)); -#endif + + model = Mod_FindName(PRVM_G_STRING(OFS_PARM1), NULL); + if(model->loaded) + CL_Effect(org, model, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4)); + else + Con_Printf(CON_ERROR "VM_CL_effect: Could not load model '%s'\n", PRVM_G_STRING(OFS_PARM1)); } // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD) @@ -1939,7 +1928,7 @@ static void VM_CL_te_explosionrgb (prvm_prog_t *prog) CL_FindNonSolidLocation(pos, pos2, 10); CL_ParticleExplosion(pos2); Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); - CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE) @@ -2084,7 +2073,7 @@ static void VM_CL_te_customflash (prvm_prog_t *prog) VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); CL_FindNonSolidLocation(pos, pos2, 4); Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); - CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), NULL, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS) @@ -2235,7 +2224,7 @@ static void VM_CL_te_explosion2 (prvm_prog_t *prog) color[1] = tempcolor[1] * (2.0f / 255.0f); color[2] = tempcolor[2] * (2.0f / 255.0f); Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); - CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1); } @@ -2453,12 +2442,13 @@ static int CL_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int extern cvar_t cl_bob; extern cvar_t cl_bobcycle; extern cvar_t cl_bobup; -int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex) +int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex, prvm_vec_t *returnshadingorigin) { int ret; int attachloop; matrix4x4_t entitymatrix, tagmatrix, attachmatrix; dp_model_t *model; + vec3_t shadingorigin; *out = identitymatrix; // warnings and errors return identical matrix @@ -2509,9 +2499,9 @@ int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int if (PRVM_clientedictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value) { double bob, cycle; - // LordHavoc: this code is *weird*, but not replacable (I think it + // LadyHavoc: this code is *weird*, but not replacable (I think it // should be done in QC on the server, but oh well, quake is quake) - // LordHavoc: figured out bobup: the time at which the sin is at 180 + // LadyHavoc: figured out bobup: the time at which the sin is at 180 // degrees (which allows lengthening or squishing the peak or valley) cycle = cl.time/cl_bobcycle.value; cycle -= (int)cycle; @@ -2526,7 +2516,17 @@ int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4)); } */ + + // return the origin of the view + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, shadingorigin); + } + else + { + // return the origin of the root entity in the chain + Matrix4x4_OriginFromMatrix(out, shadingorigin); } + if (returnshadingorigin) + VectorCopy(shadingorigin, returnshadingorigin); return 0; } @@ -2582,7 +2582,7 @@ static void VM_CL_gettaginfo (prvm_prog_t *prog) e = PRVM_G_EDICT(OFS_PARM0); tagindex = (int)PRVM_G_FLOAT(OFS_PARM1); - returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex); + returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex, NULL); Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin); VectorCopy(forward, PRVM_clientglobalvector(v_forward)); VectorScale(left, -1, PRVM_clientglobalvector(v_right)); @@ -2927,7 +2927,7 @@ static void VM_CL_SpawnParticle (prvm_prog_t *prog) particle_t *part; int themenum; - VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2); + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle); if (vmpartspawner.verified == false) { VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n"); @@ -3049,10 +3049,10 @@ static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog) particle_t *part; int themenum; - VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2); + VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticleDelayed); if (vmpartspawner.verified == false) { - VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n"); + VM_Warning(prog, "VM_CL_SpawnParticleDelayed: particle spawner not initialized\n"); PRVM_G_FLOAT(OFS_RETURN) = 0; return; } @@ -3098,7 +3098,7 @@ static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog) themenum = (int)PRVM_G_FLOAT(OFS_PARM4); if (themenum <= 0 || themenum >= vmpartspawner.max_themes) { - VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum); + VM_Warning(prog, "VM_CL_SpawnParticleDelayed: bad theme number %i\n", themenum); PRVM_G_FLOAT(OFS_RETURN) = 0; return; } @@ -3160,7 +3160,7 @@ static void VM_CL_GetEntity (prvm_prog_t *prog) { int entnum, fieldnum; vec3_t forward, left, up, org; - VM_SAFEPARMCOUNT(2, VM_CL_GetEntityVec); + VM_SAFEPARMCOUNT(2, VM_CL_GetEntity); entnum = PRVM_G_FLOAT(OFS_PARM0); if (entnum < 0 || entnum >= cl.num_entities) @@ -3230,7 +3230,7 @@ static void VM_CL_GetEntity (prvm_prog_t *prog) VectorAdd(cl.entities[entnum].render.maxs, org, PRVM_G_VECTOR(OFS_RETURN)); break; case 16: // light - VectorMA(cl.entities[entnum].render.modellight_ambient, 0.5, cl.entities[entnum].render.modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN)); + VectorMA(cl.entities[entnum].render.render_modellight_ambient, 0.5, cl.entities[entnum].render.render_modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN)); break; default: PRVM_G_FLOAT(OFS_RETURN) = 0; @@ -3248,292 +3248,176 @@ static void VM_CL_GetEntity (prvm_prog_t *prog) // --blub static void VM_CL_R_RenderScene (prvm_prog_t *prog) { + qboolean ismain = r_refdef.view.ismain; double t = Sys_DirtyTime(); - vmpolygons_t *polys = &prog->vmpolygons; VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene); // update the views - if(r_refdef.view.ismain) + if(ismain) { // set the main view csqc_main_r_refdef_view = r_refdef.view; - - // clear the flags so no other view becomes "main" unless CSQC sets VF_MAINVIEW - r_refdef.view.ismain = false; - csqc_original_r_refdef_view.ismain = false; } + // 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_UpdateEntityShading(); // now draw stuff! - R_RenderView(); - - polys->num_vertices = polys->num_triangles = 0; + R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); // 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; -} - -static void VM_ResizePolygons(vmpolygons_t *polys) -{ - float *oldvertex3f = polys->data_vertex3f; - float *oldcolor4f = polys->data_color4f; - float *oldtexcoord2f = polys->data_texcoord2f; - vmpolygons_triangle_t *oldtriangles = polys->data_triangles; - unsigned short *oldsortedelement3s = polys->data_sortedelement3s; - polys->max_vertices = min(polys->max_triangles*3, 65536); - polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3])); - polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4])); - polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2])); - polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t)); - polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3])); - if (polys->num_vertices) - { - memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3])); - memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4])); - memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2])); - } - if (polys->num_triangles) - { - memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t)); - memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3])); - } - if (oldvertex3f) - Mem_Free(oldvertex3f); - if (oldcolor4f) - Mem_Free(oldcolor4f); - if (oldtexcoord2f) - Mem_Free(oldtexcoord2f); - if (oldtriangles) - Mem_Free(oldtriangles); - if (oldsortedelement3s) - Mem_Free(oldsortedelement3s); -} - -static void VM_InitPolygons (vmpolygons_t* polys) -{ - memset(polys, 0, sizeof(*polys)); - polys->pool = Mem_AllocPool("VMPOLY", 0, NULL); - polys->max_triangles = 1024; - VM_ResizePolygons(polys); - polys->initialized = true; -} - -static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) -{ - int surfacelistindex; - vmpolygons_t *polys = (vmpolygons_t *)ent; -// R_Mesh_ResetTextureState(); - R_EntityMatrix(&identitymatrix); - GL_CullFace(GL_NONE); - GL_DepthTest(true); // polys in 3D space shall always have depth test - GL_DepthRange(0, 1); - R_Mesh_PrepareVertices_Generic_Arrays(polys->num_vertices, polys->data_vertex3f, polys->data_color4f, polys->data_texcoord2f); - - for (surfacelistindex = 0;surfacelistindex < numsurfaces;) - { - int numtriangles = 0; - rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture; - int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag; - DrawQ_ProcessDrawFlag(drawflag, polys->data_triangles[surfacelist[surfacelistindex]].hasalpha); - R_SetupShader_Generic(tex, NULL, GL_MODULATE, 1, false, false, false); - numtriangles = 0; - for (;surfacelistindex < numsurfaces;surfacelistindex++) - { - if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag) - break; - VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles); - numtriangles++; - } - R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, NULL, 0, polys->data_sortedelement3s, NULL, 0); - } -} - -static void VMPolygons_Store(vmpolygons_t *polys) -{ - qboolean hasalpha; - int i; - - // detect if we have alpha - hasalpha = polys->begin_texture_hasalpha; - for(i = 0; !hasalpha && (i < polys->begin_vertices); ++i) - if(polys->begin_color[i][3] < 1) - hasalpha = true; - - if (polys->begin_draw2d) - { - // draw the polygon as 2D immediately - drawqueuemesh_t mesh; - mesh.texture = polys->begin_texture; - mesh.num_vertices = polys->begin_vertices; - mesh.num_triangles = polys->begin_vertices-2; - mesh.data_element3i = polygonelement3i; - mesh.data_element3s = polygonelement3s; - mesh.data_vertex3f = polys->begin_vertex[0]; - mesh.data_color4f = polys->begin_color[0]; - mesh.data_texcoord2f = polys->begin_texcoord[0]; - DrawQ_Mesh(&mesh, polys->begin_drawflag, hasalpha); - } - else - { - // queue the polygon as 3D for sorted transparent rendering later - if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2) - { - while (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2) - polys->max_triangles *= 2; - VM_ResizePolygons(polys); - } - if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices) - { - // needle in a haystack! - // polys->num_vertices was used for copying where we actually want to copy begin_vertices - // that also caused it to not render the first polygon that is added - // --blub - memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3])); - memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4])); - memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2])); - for (i = 0;i < polys->begin_vertices-2;i++) - { - polys->data_triangles[polys->num_triangles].texture = polys->begin_texture; - polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag; - polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices; - polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1; - polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2; - polys->data_triangles[polys->num_triangles].hasalpha = hasalpha; - polys->num_triangles++; - } - polys->num_vertices += polys->begin_vertices; - } - } - polys->begin_active = false; -} - -// TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black] -// LordHavoc: agreed, this is a mess -void VM_CL_AddPolygonsToMeshQueue (prvm_prog_t *prog) -{ - int i; - vmpolygons_t *polys = &prog->vmpolygons; - vec3_t center; - - // only add polygons of the currently active prog to the queue - if there is none, we're done - if( !prog ) - return; - if (!polys->num_triangles) - return; + // polygonbegin without draw2d arg has to guess + prog->polygonbegin_guess2d = false; - for (i = 0;i < polys->num_triangles;i++) + // update the views + if (ismain) { - VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[2], center); - R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, VM_DrawPolygonCallback, (entity_render_t *)polys, i, NULL); + // clear the flags so no other view becomes "main" unless CSQC sets VF_MAINVIEW + r_refdef.view.ismain = false; + csqc_original_r_refdef_view.ismain = false; } - - /*polys->num_triangles = 0; // now done after rendering the scene, - polys->num_vertices = 0; // otherwise it's not rendered at all and prints an error message --blub */ } //void(string texturename, float flag[, float is2d]) R_BeginPolygon static void VM_CL_R_PolygonBegin (prvm_prog_t *prog) { - const char *picname; - skinframe_t *sf; - vmpolygons_t *polys = &prog->vmpolygons; - int tf; - - // TODO instead of using skinframes here (which provides the benefit of - // better management of flags, and is more suited for 3D rendering), what - // about supporting Q3 shaders? + const char *texname; + int drawflags; + qboolean draw2d; + dp_model_t *mod; VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_PolygonBegin); - if (!polys->initialized) - VM_InitPolygons(polys); - if (polys->begin_active) - { - VM_Warning(prog, "VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n"); - return; - } - picname = PRVM_G_STRING(OFS_PARM0); - - sf = NULL; - if(*picname) + texname = PRVM_G_STRING(OFS_PARM0); + drawflags = (int)PRVM_G_FLOAT(OFS_PARM1); + if (prog->argc >= 3) + draw2d = PRVM_G_FLOAT(OFS_PARM2) != 0; + else { - tf = TEXF_ALPHA; - if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP) - tf |= TEXF_MIPMAP; - - do - { - sf = R_SkinFrame_FindNextByName(sf, picname); - } - while(sf && sf->textureflags != tf); - - if(!sf || !sf->base) - sf = R_SkinFrame_LoadExternal(picname, tf, true); - - if(sf) - R_SkinFrame_MarkUsed(sf); + // weird hacky way to figure out if this is a 2D HUD polygon or a scene + // polygon, for compatibility with mods aimed at old darkplaces versions + // - polygonbegin_guess2d is 0 if the most recent major call was + // clearscene, 1 if the most recent major call was drawpic (and similar) + // or renderscene + draw2d = prog->polygonbegin_guess2d; } - polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white; - polys->begin_texture_hasalpha = (sf && sf->base) ? sf->hasalpha : false; - polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK; - polys->begin_vertices = 0; - polys->begin_active = true; - polys->begin_draw2d = (prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : r_refdef.draw2dstage); + // we need to remember whether this is a 2D or 3D mesh we're adding to + mod = draw2d ? CL_Mesh_UI() : CL_Mesh_Scene(); + prog->polygonbegin_model = mod; + if (texname == NULL || texname[0] == 0) + texname = "$whiteimage"; + 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 static void VM_CL_R_PolygonVertex (prvm_prog_t *prog) { - vmpolygons_t *polys = &prog->vmpolygons; + const prvm_vec_t *v = PRVM_G_VECTOR(OFS_PARM0); + 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; VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex); - if (!polys->begin_active) + if (!mod) { VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n"); return; } - if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS) + if (prog->polygonbegin_maxvertices <= prog->polygonbegin_numvertices) { - VM_Warning(prog, "VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS); - return; + 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; - polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0]; - polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1]; - polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2]; - polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0]; - polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1]; - polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0]; - polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1]; - polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2]; - polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3); - polys->begin_vertices++; + 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) { - vmpolygons_t *polys = &prog->vmpolygons; + 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; + texture_t *tex; + int materialflags; VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd); - if (!polys->begin_active) + if (!mod) { VM_Warning(prog, "VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n"); return; } - polys->begin_active = false; - if (polys->begin_vertices >= 3) - VMPolygons_Store(polys); - else - VM_Warning(prog, "VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices); + + // 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 + materialflags = MATERIALFLAG_WALL; + if (csqc_polygons_defaultmaterial_nocullface.integer) + materialflags |= MATERIALFLAG_NOCULLFACE; + if (hascolor) + materialflags |= MATERIALFLAG_VERTEXCOLOR; + if (hasalpha) + materialflags |= MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + tex = Mod_Mesh_GetTexture(mod, prog->polygonbegin_texname, prog->polygonbegin_drawflags, TEXF_ALPHA, materialflags); + surf = Mod_Mesh_AddSurface(mod, tex, 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; } /* @@ -3824,7 +3708,7 @@ static void VM_CL_checkpvs (prvm_prog_t *prog) unsigned char fatpvs[MAX_MAP_LEAFS/8]; #endif - VM_SAFEPARMCOUNT(2, VM_SV_checkpvs); + VM_SAFEPARMCOUNT(2, VM_CL_checkpvs); VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos); viewee = PRVM_G_EDICT(OFS_PARM1); @@ -4250,7 +4134,7 @@ static void VM_CL_V_CalcRefdef(prvm_prog_t *prog) flags = PRVM_G_FLOAT(OFS_PARM1); // use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad) - CL_GetTagMatrix(prog, &entrendermatrix, ent, 0); + CL_GetTagMatrix(prog, &entrendermatrix, ent, 0, NULL); VectorCopy(cl.csqc_viewangles, clviewangles); teleported = (flags & REFDEFFLAG_TELEPORTED) != 0; @@ -4324,7 +4208,7 @@ NULL, // #42 (QUAKE) VM_fabs, // #43 float(float f) fabs (QUAKE) NULL, // #44 vector(entity e, float speed) aim (QUAKE) VM_cvar, // #45 float(string s) cvar (QUAKE) -VM_localcmd, // #46 void(string s) localcmd (QUAKE) +VM_localcmd_client, // #46 void(string s) localcmd (QUAKE) VM_nextent, // #47 entity(entity e) nextent (QUAKE) VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE) VM_changeyaw, // #49 void() ChangeYaw (QUAKE) @@ -4681,7 +4565,7 @@ NULL, // #396 NULL, // #397 NULL, // #398 NULL, // #399 -// LordHavoc's range #400-#499 +// LadyHavoc's range #400-#499 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR) VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN) @@ -4930,27 +4814,17 @@ NULL const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); -void VM_Polygons_Reset(prvm_prog_t *prog) -{ - vmpolygons_t *polys = &prog->vmpolygons; - - // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system - if(polys->initialized) - { - Mem_FreePool(&polys->pool); - polys->initialized = false; - } -} - void CLVM_init_cmd(prvm_prog_t *prog) { VM_Cmd_Init(prog); - VM_Polygons_Reset(prog); + prog->polygonbegin_model = NULL; + prog->polygonbegin_guess2d = 0; } void CLVM_reset_cmd(prvm_prog_t *prog) { World_End(&cl.world); VM_Cmd_Reset(prog); - VM_Polygons_Reset(prog); + prog->polygonbegin_model = NULL; + prog->polygonbegin_guess2d = 0; }