From f7979501e5e4cbc90f9420bb1373207bcd470e6c Mon Sep 17 00:00:00 2001 From: vortex Date: Sun, 4 Oct 2009 22:38:47 +0000 Subject: [PATCH] -added game Blood Omnicide -added r_shadow_gloss2exponent (gloss exponent for forced gloss surfaces), this don't work for Dot3 pieline however, i'm used this to make "wet surfaces when rain falls" in Blood Omnicide -added DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET, DP_CSQC_ENTITYNOCULL, DP_CSQC_SPAWNPARTICLE. Definitions are here: http://darkmaster.quakedev.com/work/csqc_new_ext.qc git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9304 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 2 +- client.h | 3 + clvm_cmds.c | 458 ++++++++++++++++++++++++++++++++++++++++++++++++- common.c | 3 + common.h | 1 + csprogs.c | 6 + csprogs.h | 2 + gl_rmain.c | 9 +- progsvm.h | 1 + protocol.h | 2 + prvm_edict.c | 1 + r_shadow.c | 2 + r_shadow.h | 1 + svvm_cmds.c | 3 + 14 files changed, 484 insertions(+), 10 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index ae5aa388..9a4472b7 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -519,7 +519,7 @@ void CL_Particles_Shutdown (void) // orientation - one of the PARTICLE_ values // staincolor1, staincolor2: minimum and maximum ranges of stain color, randomly interpolated to decide particle color (-1 to use none) // staintex: any of the tex_ values such as tex_smoke[rand()&7] or tex_particle (-1 to use none) -static particle_t *CL_NewParticle(unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex) +particle_t *CL_NewParticle(unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex) { int l1, l2, r, g, b; particle_t *part; diff --git a/client.h b/client.h index 5ac54832..c6a347fa 100644 --- a/client.h +++ b/client.h @@ -271,6 +271,8 @@ typedef struct entity_render_s float alpha; // size the model is shown float scale; + // transparent sorting offset + float transparent_offset; // NULL = no model dp_model_t *model; @@ -1341,6 +1343,7 @@ extern cvar_t cl_decals_fadetime; void CL_Particles_Clear(void); void CL_Particles_Init(void); void CL_Particles_Shutdown(void); +particle_t *CL_NewParticle(unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex); typedef enum effectnameindex_s { diff --git a/clvm_cmds.c b/clvm_cmds.c index c317b452..077b926d 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -2455,6 +2455,448 @@ void VM_CL_gettaginfo (void) //============================================================================ +//==================== +// DP_CSQC_SPAWNPARTICLE +// a QC hook to engine's CL_NewParticle +//==================== + +// particle theme struct +typedef struct vmparticletheme_s +{ + unsigned short typeindex; + qboolean initialized; + pblend_t blendmode; + porientation_t orientation; + int color1; + int color2; + int tex; + float size; + float sizeincrease; + int alpha; + int alphafade; + float gravity; + float bounce; + float airfriction; + float liquidfriction; + float originjitter; + float velocityjitter; + qboolean qualityreduction; + float lifetime; + float stretch; + int staincolor1; + int staincolor2; + int staintex; + float delayspawn; + float delaycollision; +}vmparticletheme_t; + +// particle spawner +typedef struct vmparticlespawner_s +{ + mempool_t *pool; + qboolean initialized; + qboolean verified; + vmparticletheme_t *themes; + int max_themes; + // global addresses + float *particle_type; + float *particle_blendmode; + float *particle_orientation; + float *particle_color1; + float *particle_color2; + float *particle_tex; + float *particle_size; + float *particle_sizeincrease; + float *particle_alpha; + float *particle_alphafade; + float *particle_time; + float *particle_gravity; + float *particle_bounce; + float *particle_airfriction; + float *particle_liquidfriction; + float *particle_originjitter; + float *particle_velocityjitter; + float *particle_qualityreduction; + float *particle_stretch; + float *particle_staincolor1; + float *particle_staincolor2; + float *particle_staintex; + float *particle_delayspawn; + float *particle_delaycollision; +}vmparticlespawner_t; + +vmparticlespawner_t vmpartspawner; + +// TODO: automatic max_themes grow +static void VM_InitParticleSpawner (int maxthemes) +{ + prvm_eval_t *val; + + // bound max themes to not be an insane value + if (maxthemes < 4) + maxthemes = 4; + if (maxthemes > 2048) + maxthemes = 2048; + // allocate and set up structure + if (vmpartspawner.initialized) // reallocate + { + Mem_FreePool(&vmpartspawner.pool); + memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t)); + } + vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL); + vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes); + vmpartspawner.max_themes = maxthemes; + vmpartspawner.initialized = true; + vmpartspawner.verified = true; + // get field addresses for fast querying (we can do 1000 calls of spawnparticle in a frame) + #define getglobal(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = &val->_float; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; } + #define getglobalvector(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = (float *)val->vector; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; } + getglobal(particle_type, "particle_type"); + getglobal(particle_blendmode, "particle_blendmode"); + getglobal(particle_orientation, "particle_orientation"); + getglobalvector(particle_color1, "particle_color1"); + getglobalvector(particle_color2, "particle_color2"); + getglobal(particle_tex, "particle_tex"); + getglobal(particle_size, "particle_size"); + getglobal(particle_sizeincrease, "particle_sizeincrease"); + getglobal(particle_alpha, "particle_alpha"); + getglobal(particle_alphafade, "particle_alphafade"); + getglobal(particle_time, "particle_time"); + getglobal(particle_gravity, "particle_gravity"); + getglobal(particle_bounce, "particle_bounce"); + getglobal(particle_airfriction, "particle_airfriction"); + getglobal(particle_liquidfriction, "particle_liquidfriction"); + getglobal(particle_originjitter, "particle_originjitter"); + getglobal(particle_velocityjitter, "particle_velocityjitter"); + getglobal(particle_qualityreduction, "particle_qualityreduction"); + getglobal(particle_stretch, "particle_stretch"); + getglobalvector(particle_staincolor1, "particle_staincolor1"); + getglobalvector(particle_staincolor2, "particle_staincolor2"); + getglobal(particle_staintex, "particle_staintex"); + getglobal(particle_delayspawn, "particle_delayspawn"); + getglobal(particle_delaycollision, "particle_delaycollision"); + #undef getglobal + #undef getglobalvector +} + +// reset particle theme to default values +static void VM_ResetParticleTheme (vmparticletheme_t *theme) +{ + theme->initialized = true; + theme->typeindex = pt_static; + theme->blendmode = PBLEND_ADD; + theme->orientation = PARTICLE_BILLBOARD; + theme->color1 = 0x808080; + theme->color2 = 0xFFFFFF; + theme->tex = 63; + theme->size = 2; + theme->sizeincrease = 0; + theme->alpha = 256; + theme->alphafade = 512; + theme->gravity = 0.0f; + theme->bounce = 0.0f; + theme->airfriction = 1.0f; + theme->liquidfriction = 4.0f; + theme->originjitter = 0.0f; + theme->velocityjitter = 0.0f; + theme->qualityreduction = false; + theme->lifetime = 4; + theme->stretch = 1; + theme->staincolor1 = -1; + theme->staincolor2 = -1; + theme->staintex = -1; + theme->delayspawn = 0.0f; + theme->delaycollision = 0.0f; +} + +// particle theme -> QC globals +void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme) +{ + *vmpartspawner.particle_type = theme->typeindex; + *vmpartspawner.particle_blendmode = theme->blendmode; + *vmpartspawner.particle_orientation = theme->orientation; + vmpartspawner.particle_color1[0] = (theme->color1 >> 16) & 0xFF; // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375... + vmpartspawner.particle_color1[1] = (theme->color1 >> 8) & 0xFF; + vmpartspawner.particle_color1[2] = (theme->color1 >> 0) & 0xFF; + vmpartspawner.particle_color2[0] = (theme->color2 >> 16) & 0xFF; + vmpartspawner.particle_color2[1] = (theme->color2 >> 8) & 0xFF; + vmpartspawner.particle_color2[2] = (theme->color2 >> 0) & 0xFF; + *vmpartspawner.particle_tex = (float)theme->tex; + *vmpartspawner.particle_size = theme->size; + *vmpartspawner.particle_sizeincrease = theme->sizeincrease; + *vmpartspawner.particle_alpha = (float)theme->alpha/256; + *vmpartspawner.particle_alphafade = (float)theme->alphafade/256; + *vmpartspawner.particle_time = theme->lifetime; + *vmpartspawner.particle_gravity = theme->gravity; + *vmpartspawner.particle_bounce = theme->bounce; + *vmpartspawner.particle_airfriction = theme->airfriction; + *vmpartspawner.particle_liquidfriction = theme->liquidfriction; + *vmpartspawner.particle_originjitter = theme->originjitter; + *vmpartspawner.particle_velocityjitter = theme->velocityjitter; + *vmpartspawner.particle_qualityreduction = theme->qualityreduction; + *vmpartspawner.particle_stretch = theme->stretch; + vmpartspawner.particle_staincolor1[0] = (theme->staincolor1 >> 16) & 0xFF; + vmpartspawner.particle_staincolor1[1] = (theme->staincolor1 >> 8) & 0xFF; + vmpartspawner.particle_staincolor1[2] = (theme->staincolor1 >> 0) & 0xFF; + vmpartspawner.particle_staincolor2[0] = (theme->staincolor2 >> 16) & 0xFF; + vmpartspawner.particle_staincolor2[1] = (theme->staincolor2 >> 8) & 0xFF; + vmpartspawner.particle_staincolor2[2] = (theme->staincolor2 >> 0) & 0xFF; + *vmpartspawner.particle_staintex = (float)theme->staintex; + *vmpartspawner.particle_delayspawn = theme->delayspawn; + *vmpartspawner.particle_delaycollision = theme->delaycollision; +} + +// QC globals -> particle theme +void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme) +{ + theme->typeindex = (unsigned short)*vmpartspawner.particle_type; + theme->blendmode = (pblend_t)*vmpartspawner.particle_blendmode; + theme->orientation = (porientation_t)*vmpartspawner.particle_orientation; + theme->color1 = ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]); + theme->color2 = ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]); + theme->tex = (int)*vmpartspawner.particle_tex; + theme->size = *vmpartspawner.particle_size; + theme->sizeincrease = *vmpartspawner.particle_sizeincrease; + theme->alpha = (int)(*vmpartspawner.particle_alpha*256); + theme->alphafade = (int)(*vmpartspawner.particle_alphafade*256); + theme->lifetime = *vmpartspawner.particle_time; + theme->gravity = *vmpartspawner.particle_gravity; + theme->bounce = *vmpartspawner.particle_bounce; + theme->airfriction = *vmpartspawner.particle_airfriction; + theme->liquidfriction = *vmpartspawner.particle_liquidfriction; + theme->originjitter = *vmpartspawner.particle_originjitter; + theme->velocityjitter = *vmpartspawner.particle_velocityjitter; + theme->qualityreduction = (*vmpartspawner.particle_qualityreduction) ? true : false; + theme->stretch = *vmpartspawner.particle_stretch; + theme->staincolor1 = vmpartspawner.particle_staincolor1[0]*65536 + vmpartspawner.particle_staincolor1[1]*256 + vmpartspawner.particle_staincolor1[2]; + theme->staincolor2 = vmpartspawner.particle_staincolor2[0]*65536 + vmpartspawner.particle_staincolor2[1]*256 + vmpartspawner.particle_staincolor2[2]; + theme->staintex =(int)*vmpartspawner.particle_staintex; + theme->delayspawn = *vmpartspawner.particle_delayspawn; + theme->delaycollision = *vmpartspawner.particle_delaycollision; +} + +// init particle spawner interface +// # float(float max_themes) initparticlespawner +void VM_CL_InitParticleSpawner (void) +{ + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner); + VM_InitParticleSpawner((int)PRVM_G_FLOAT(OFS_PARM0)); + vmpartspawner.themes[0].initialized = true; + VM_ResetParticleTheme(&vmpartspawner.themes[0]); + PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0; +} + +// void() resetparticle +void VM_CL_ResetParticle (void) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_ResetParticle: particle spawner not initialized\n"); + return; + } + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]); +} + +// void(float themenum) particletheme +void VM_CL_ParticleTheme (void) +{ + int themenum; + + VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_ParticleTheme: particle spawner not initialized\n"); + return; + } + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (themenum < 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning("VM_CL_ParticleTheme: bad theme number %i\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]); + return; + } + if (vmpartspawner.themes[themenum].initialized = false) + { + VM_Warning("VM_CL_ParticleTheme: theme #%i not exists\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]); + return; + } + // load particle theme into globals + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum]); +} + +// float() saveparticletheme +// void(float themenum) updateparticletheme +void VM_CL_ParticleThemeSave (void) +{ + int themenum; + + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_ParticleThemeSave: particle spawner not initialized\n"); + return; + } + // allocate new theme, save it and return + if (prog->argc < 1) + { + for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++) + if (vmpartspawner.themes[themenum].initialized == false) + break; + if (themenum >= vmpartspawner.max_themes) + { + if (vmpartspawner.max_themes == 2048) + VM_Warning("VM_CL_ParticleThemeSave: no free theme slots\n"); + else + VM_Warning("VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n"); + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + vmpartspawner.themes[themenum].initialized = true; + VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]); + PRVM_G_FLOAT(OFS_RETURN) = themenum; + return; + } + // update existing theme + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (themenum < 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning("VM_CL_ParticleThemeSave: bad theme number %i\n", themenum); + return; + } + vmpartspawner.themes[themenum].initialized = true; + VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]); +} + +// void(float themenum) freeparticletheme +void VM_CL_ParticleThemeFree (void) +{ + int themenum; + + VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_ParticleThemeFree: particle spawner not initialized\n"); + return; + } + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + // check parms + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning("VM_CL_ParticleThemeFree: bad theme number %i\n", themenum); + return; + } + if (vmpartspawner.themes[themenum].initialized = false) + { + VM_Warning("VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]); + return; + } + // free theme + VM_ResetParticleTheme(&vmpartspawner.themes[themenum]); + vmpartspawner.themes[themenum].initialized = false; +} + +// float(vector org, vector dir, [float theme]) particle +// returns 0 if failed, 1 if succesful +void VM_CL_SpawnParticle (void) +{ + float *org, *dir; + vmparticletheme_t *theme; + particle_t *part; + int themenum; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n"); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + org = PRVM_G_VECTOR(OFS_PARM0); + dir = PRVM_G_VECTOR(OFS_PARM1); + + if (prog->argc < 3) // global-set particle + { + part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex); + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + if (*vmpartspawner.particle_delayspawn) + part->delayedspawn = cl.time + *vmpartspawner.particle_delayspawn; + if (*vmpartspawner.particle_delaycollision) + part->delayedcollisions = cl.time + *vmpartspawner.particle_delaycollision; + } + else // quick themed particle + { + themenum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + theme = &vmpartspawner.themes[themenum]; + part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex); + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + if (theme->delayspawn) + part->delayedspawn = cl.time + theme->delayspawn; + if (theme->delaycollision) + part->delayedcollisions = cl.time + theme->delaycollision; + } + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +// float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle +// returns 0 if failed, 1 if success +void VM_CL_SpawnParticleDelayed (void) +{ + float *org, *dir; + vmparticletheme_t *theme; + particle_t *part; + int themenum; + + VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2); + if (vmpartspawner.verified == false) + { + VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n"); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + org = PRVM_G_VECTOR(OFS_PARM0); + dir = PRVM_G_VECTOR(OFS_PARM1); + if (prog->argc < 5) // global-set particle + part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex); + else // themed particle + { + themenum = (int)PRVM_G_FLOAT(OFS_PARM4); + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + theme = &vmpartspawner.themes[themenum]; + part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex); + } + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2); + part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3); + PRVM_G_FLOAT(OFS_RETURN) = 0; +} + +// //==================== //QC POLYGON functions //==================== @@ -3709,14 +4151,14 @@ VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION) VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME) VM_keynumtostring, // #520 string keynumtostring(float keynum) -VM_findkeysforcommand, // #521 string findkeysforcommand(string command) -NULL, // #522 -NULL, // #523 -NULL, // #524 -NULL, // #525 -NULL, // #526 -NULL, // #527 -NULL, // #528 +VM_findkeysforcommand, // #521 string findkeysforcommand(string command) +VM_CL_InitParticleSpawner, // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE) +VM_CL_ResetParticle, // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleTheme, // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleThemeSave, // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleThemeFree, // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE) +VM_CL_SpawnParticle, // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE) +VM_CL_SpawnParticleDelayed, // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE) NULL, // #529 NULL, // #530 NULL, // #531 diff --git a/common.c b/common.c index e29a00ab..9fa09688 100644 --- a/common.c +++ b/common.c @@ -1492,6 +1492,9 @@ static const gamemode_info_t gamemode_info [GAME_COUNT] = // GAME_PROPHECY // COMMANDLINEOPTION: Game: -prophecy runs the game Quake (default) { "prophecy", "-prophecy", "Prophecy", "data", NULL, "prophecy", "prophecy" }, +// GAME_BLOODOMNICIDE +// COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide +{ "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" }, }; void COM_InitGameType (void) diff --git a/common.h b/common.h index 40634807..cc5029ea 100644 --- a/common.h +++ b/common.h @@ -302,6 +302,7 @@ typedef enum gamemode_e GAME_EDU2P, GAME_BLADEMASTER, GAME_PROPHECY, + GAME_BLOODOMNICIDE, GAME_COUNT } gamemode_t; diff --git a/csprogs.c b/csprogs.c index 58d631ef..1929838f 100644 --- a/csprogs.c +++ b/csprogs.c @@ -244,12 +244,18 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) // concat the matrices to make the entity relative to its tag Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2); + // transparent offset + if ((renderflags & RF_USETRANSPARENTOFFSET) && (val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.transparent_offset))) + entrender->transparent_offset = val->_float; + if(renderflags) { if(renderflags & RF_VIEWMODEL) entrender->flags |= RENDER_VIEWMODEL; if(renderflags & RF_EXTERNALMODEL)entrender->flags |= RENDER_EXTERIORMODEL; + if(renderflags & RF_NOCULL) entrender->flags |= RENDER_NOCULL; if(renderflags & RF_DEPTHHACK) entrender->effects |= EF_NODEPTHTEST; if(renderflags & RF_ADDITIVE) entrender->effects |= EF_ADDITIVE; + } c = (int)ed->fields.client->colormap; diff --git a/csprogs.h b/csprogs.h index 03944584..e4a3e897 100644 --- a/csprogs.h +++ b/csprogs.h @@ -48,6 +48,8 @@ #define RF_USEAXIS 16 // When set, the entity will use the v_forward, v_right and v_up globals instead of it's angles field for orientation. Angles will be ignored compleatly. // Note that to use this properly, you'll NEED to use the predraw function to set the globals. //#define RF_DOUBLESIDED 32 +#define RF_USETRANSPARENTOFFSET 64 // Allows QC to customize origin used for transparent sorting via transparent_origin global, helps to fix transparent sorting bugs on a very large entities +#define RF_NOCULL 128 // do not cull this entity using r_cullentities, for large outdoor entities (asteroids on the sky. etc) extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; diff --git a/gl_rmain.c b/gl_rmain.c index d811bfd4..5794e317 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -3295,7 +3295,7 @@ static void R_View_UpdateEntityVisible (void) for (i = 0;i < r_refdef.scene.numentities;i++) { ent = r_refdef.scene.entities[i]; - if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*'))) + if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & (RENDER_VIEWMODEL + RENDER_NOCULL)) && !(ent->model && (ent->model->name[0] == '*'))) { if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.scene.worldmodel, r_refdef.view.origin, ent->mins, ent->maxs)) ent->last_trace_visibility = realtime; @@ -5505,6 +5505,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->glosstexture = r_texture_white; t->backgroundglosstexture = r_texture_white; t->specularscale = r_shadow_gloss2intensity.value; + t->specularpower = r_shadow_gloss2exponent.value; } } @@ -7575,6 +7576,12 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); + if (queueentity->transparent_offset) // transparent offset + { + center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset; + center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset; + center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset; + } R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight); } } diff --git a/progsvm.h b/progsvm.h index 97660c28..b175a7b1 100644 --- a/progsvm.h +++ b/progsvm.h @@ -278,6 +278,7 @@ typedef struct prvm_prog_globaloffsets_s int gettaginfo_forward; // ssqc / csqc int gettaginfo_right; // ssqc / csqc int gettaginfo_up; // ssqc / csqc + int transparent_offset; // csqc } prvm_prog_globaloffsets_t; diff --git a/protocol.h b/protocol.h index 78697e7c..9fdd636b 100644 --- a/protocol.h +++ b/protocol.h @@ -332,6 +332,8 @@ void Protocol_Names(char *buffer, size_t buffersize); #define RENDER_EXTERIORMODEL 8 #define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth #define RENDER_COLORMAPPED 32 +#define RENDER_NOCULL 64 // do not cull this entity with r_cullentities + #define RENDER_SHADOW 65536 // cast shadow #define RENDER_LIGHT 131072 // receive light #define RENDER_NOSELFSHADOW 262144 // render lighting on this entity before its own shadow is added to the scene diff --git a/prvm_edict.c b/prvm_edict.c index f29b50c4..92e53f9a 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -1675,6 +1675,7 @@ void PRVM_FindOffsets(void) prog->globaloffsets.gettaginfo_parent = PRVM_ED_FindGlobalOffset("gettaginfo_parent"); prog->globaloffsets.gettaginfo_right = PRVM_ED_FindGlobalOffset("gettaginfo_right"); prog->globaloffsets.gettaginfo_up = PRVM_ED_FindGlobalOffset("gettaginfo_up"); + prog->globaloffsets.transparent_offset = PRVM_ED_FindGlobalOffset("transparent_offset"); prog->globaloffsets.intermission = PRVM_ED_FindGlobalOffset("intermission"); prog->globaloffsets.require_spawnfunc_prefix = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix"); prog->globaloffsets.sb_showscores = PRVM_ED_FindGlobalOffset("sb_showscores"); diff --git a/r_shadow.c b/r_shadow.c index c7dc780f..fa3ad8f7 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -253,6 +253,7 @@ cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (sp cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"}; cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"}; cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"}; +cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"}; cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"}; cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"}; cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"}; @@ -636,6 +637,7 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_gloss2intensity); Cvar_RegisterVariable(&r_shadow_glossintensity); Cvar_RegisterVariable(&r_shadow_glossexponent); + Cvar_RegisterVariable(&r_shadow_gloss2exponent); Cvar_RegisterVariable(&r_shadow_glossexact); Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias); Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale); diff --git a/r_shadow.h b/r_shadow.h index a2bd45a3..b1347201 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -9,6 +9,7 @@ extern cvar_t r_shadow_gloss; extern cvar_t r_shadow_gloss2intensity; extern cvar_t r_shadow_glossintensity; extern cvar_t r_shadow_glossexponent; +extern cvar_t r_shadow_gloss2exponent; extern cvar_t r_shadow_glossexact; extern cvar_t r_shadow_lightattenuationpower; extern cvar_t r_shadow_lightattenuationscale; diff --git a/svvm_cmds.c b/svvm_cmds.c index ede31ff3..a4a2d143 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -180,6 +180,9 @@ char *vm_sv_extensions = "TENEBRAE_GFX_DLIGHTS " "TW_SV_STEPCONTROL " "ZQ_PAUSE " +"DP_CSQC_SPAWNPARTICLE " +"DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET " +"DP_CSQC_ENTITYNOCULL " //"EXT_CSQC " // not ready yet ; -- 2.39.2