From 4ae70b2e3eee94cacd931ad97d32d95741f90390 Mon Sep 17 00:00:00 2001 From: g-cont Date: Mon, 17 Nov 2008 00:00:00 +0300 Subject: [PATCH] 17 Nov 2008 --- common/bsplib/bspfile.c | 2 - common/bsplib/writebsp.c | 51 +++-- debug.bat | 2 +- engine/client/cl_fx.c | 446 +++++++++++++++++++++++++++++---------- engine/client/cl_main.c | 5 +- engine/client/cl_pred.c | 4 +- engine/client/cl_view.c | 2 +- engine/client/client.h | 24 +-- engine/host.c | 2 +- engine/server/sv_progs.c | 18 +- physic/cm_test.c | 2 +- public/matrixlib.h | 25 +++ public/render_api.h | 5 +- release.bat | 2 +- render/gl_backend.c | 1 + render/r_backend2.c | 279 +++++++++++++++++------- render/r_image.c | 2 +- render/r_main.c | 22 +- render/r_shader.h | 11 +- render/r_sky.c | 2 - render/r_studio.c | 5 +- todo.log | 12 +- 22 files changed, 641 insertions(+), 283 deletions(-) diff --git a/common/bsplib/bspfile.c b/common/bsplib/bspfile.c index 56d9428d..b59db7b9 100644 --- a/common/bsplib/bspfile.c +++ b/common/bsplib/bspfile.c @@ -343,8 +343,6 @@ void WriteBSPFile( void ) wadfile = FS_Open( va( "maps/%s.bsp", gs_filename ), "wb" ); FS_Write( wadfile, header, sizeof( dheader_t )); // overwritten later - Msg("add collision lump %i\n", dcollisiondatasize ); - AddLump( LUMP_ENTITIES, dentdata, entdatasize ); AddLump( LUMP_PLANES, dplanes, numplanes * sizeof( dplanes[0] )); AddLump( LUMP_VERTEXES, dvertexes, numvertexes * sizeof( dvertexes[0] )); diff --git a/common/bsplib/writebsp.c b/common/bsplib/writebsp.c index 00907458..ef15e83b 100644 --- a/common/bsplib/writebsp.c +++ b/common/bsplib/writebsp.c @@ -312,33 +312,32 @@ void SetLightStyles( void ) e = &entities[i]; t = ValueForKey( e, "classname" ); - if( !com.strncmp( t, "func_light", 10 )) - { - // may create func_light family - // e.g. func_light_fluoro, func_light_broken etc - k = com.atoi(ValueForKey( e, "spawnflags" )); - if( k & SF_START_ON ) t = "-2"; // initially on - else t = "-1"; // initially off - } - else t = ValueForKey( e, "style" ); - - switch( com.atoi( t )) - { - case 0: continue; // not a light, no style, generally pretty boring - case -1: // normal switchable texlight (start off) - SetKeyValue( e, "style", va( "%i", 32 + stylenum )); - stylenum++; - continue; - case -2: // backwards switchable texlight (start on) - SetKeyValue(e, "style", va( "%i", -(32 + stylenum ))); - stylenum++; - continue; - default: continue; // nothing to set - } - if( com.strncmp( t, "light", 5 )) - continue; - + { + if(!com.strncmp( t, "func_light", 10 )) + { + // may create func_light family + // e.g. func_light_fluoro, func_light_broken etc + k = com.atoi(ValueForKey( e, "spawnflags" )); + if( k & SF_START_ON ) t = "-2"; // initially on + else t = "-1"; // initially off + } + else t = ValueForKey( e, "style" ); + + switch( com.atoi( t )) + { + case 0: continue; // not a light, no style, generally pretty boring + case -1: // normal switchable texlight (start off) + SetKeyValue( e, "style", va( "%i", 32 + stylenum )); + stylenum++; + continue; + case -2: // backwards switchable texlight (start on) + SetKeyValue(e, "style", va( "%i", -(32 + stylenum ))); + stylenum++; + continue; + default: continue; // nothing to set + } + } t = ValueForKey( e, "targetname" ); if( !t[0] ) continue; diff --git a/debug.bat b/debug.bat index 2f471d7e..1d9b983e 100644 --- a/debug.bat +++ b/debug.bat @@ -67,5 +67,5 @@ if exist vsound\vsound.plg del /f /q vsound\vsound.plg echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -quake.exe -game tmpQuArK -log -debug -dev 3 +map qctest +quake.exe -game tmpQuArK -log -debug -dev 3 +map start :done \ No newline at end of file diff --git a/engine/client/cl_fx.c b/engine/client/cl_fx.c index a5ee8baf..b5a21bd4 100644 --- a/engine/client/cl_fx.c +++ b/engine/client/cl_fx.c @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "common.h" #include "client.h" +#include "const.h" /* ============================================================== @@ -245,10 +246,81 @@ PARTICLE MANAGEMENT ============================================================== */ -cparticle_t *active_particles, *free_particles; -cparticle_t particles[MAX_PARTICLES]; -int cl_numparticles = MAX_PARTICLES; +#define NUM_VERTEX_NORMALS 162 +#define PARTICLE_GRAVITY 40 +#define PARTICLE_BOUNCE 1 +#define PARTICLE_FRICTION 2 +#define PARTICLE_VERTEXLIGHT 4 +#define PARTICLE_STRETCH 8 +#define PARTICLE_UNDERWATER 16 +#define PARTICLE_INSTANT 32 + +typedef struct cparticle_s +{ + struct cparticle_s *next; + shader_t shader; + + int time; + int flags; + + vec3_t org; + vec3_t vel; + vec3_t accel; + vec3_t color; + vec3_t colorVel; + float alpha; + float alphaVel; + float radius; + float radiusVel; + float length; + float lengthVel; + float rotation; + float bounceFactor; + + vec3_t old_origin; +} cparticle_t; + +cparticle_t *cl_active_particles, *cl_free_particles; +static cparticle_t cl_particle_list[MAX_PARTICLES]; +static vec3_t cl_particle_velocities[NUM_VERTEX_NORMALS]; + +/* +================= +CL_FreeParticle +================= +*/ +static void CL_FreeParticle( cparticle_t *p ) +{ + p->next = cl_free_particles; + cl_free_particles = p; +} + +/* +================= +CL_AllocParticle +================= +*/ +static cparticle_t *CL_AllocParticle( void ) +{ + cparticle_t *p; + + if( !cl_free_particles ) + return NULL; + + if( cl_particlelod->integer > 1 ) + { + if(!(Com_RandomLong( 0, 1 ) % cl_particlelod->integer)) + return NULL; + } + + p = cl_free_particles; + cl_free_particles = p->next; + p->next = cl_active_particles; + cl_active_particles = p; + + return p; +} /* =============== @@ -259,14 +331,221 @@ void CL_ClearParticles( void ) { int i; - free_particles = &particles[0]; - active_particles = NULL; + cl_active_particles = NULL; + cl_free_particles = cl_particle_list; - for( i = 0; i < cl_numparticles; i++ ) - particles[i].next = &particles[i + 1]; - particles[cl_numparticles - 1].next = NULL; + for( i = 0; i < MAX_PARTICLES; i++ ) + cl_particle_list[i].next = &cl_particle_list[i+1]; + + cl_particle_list[MAX_PARTICLES-1].next = NULL; + + for( i = 0; i < NUM_VERTEX_NORMALS; i++ ) + { + cl_particle_velocities[i][0] = (rand() & 255) * 0.01; + cl_particle_velocities[i][1] = (rand() & 255) * 0.01; + cl_particle_velocities[i][2] = (rand() & 255) * 0.01; + } } +/* +=============== +CL_AddParticles +=============== +*/ +void CL_AddParticles( void ) +{ + cparticle_t *p, *next; + cparticle_t *active = NULL, *tail = NULL; + dword modulate; + vec3_t org, org2, vel, color; + vec3_t ambientLight; + float alpha, radius, length; + float time, time2, gravity, dot; + vec3_t mins, maxs; + int contents; + trace_t trace; + + if( !cl_particles->integer ) return; + + if( PRVM_EDICT_NUM( cl.frame.ps.number )->priv.cl->current.gravity != 0 ) + gravity = PRVM_EDICT_NUM( cl.frame.ps.number )->priv.cl->current.gravity / 800.0; + else gravity = 1.0f; + + for( p = cl_active_particles; p; p = next ) + { + // grab next now, so if the particle is freed we still have it + next = p->next; + + time = (cl.time - p->time) * 0.001; + time2 = time * time; + + alpha = p->alpha + p->alphaVel * time; + radius = p->radius + p->radiusVel * time; + length = p->length + p->lengthVel * time; + + if( alpha <= 0 || radius <= 0 || length <= 0 ) + { + // faded out + CL_FreeParticle( p ); + continue; + } + + color[0] = p->color[0] + p->colorVel[0] * time; + color[1] = p->color[1] + p->colorVel[1] * time; + color[2] = p->color[2] + p->colorVel[2] * time; + + org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2; + org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2; + org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2 * gravity; + + if( p->flags & PARTICLE_UNDERWATER ) + { + // underwater particle + VectorSet( org2, org[0], org[1], org[2] + radius ); + + if(!(CL_PointContents( org2 ) & MASK_WATER )) + { + // not underwater + CL_FreeParticle( p ); + continue; + } + } + + p->next = NULL; + if( !tail ) active = tail = p; + else + { + tail->next = p; + tail = p; + } + + if( p->flags & PARTICLE_FRICTION ) + { + // water friction affected particle + contents = CL_PointContents( org ); + if( contents & MASK_WATER ) + { + // add friction + if( contents & CONTENTS_WATER ) + { + VectorScale( p->vel, 0.25, p->vel ); + VectorScale( p->accel, 0.25, p->accel ); + } + if( contents & CONTENTS_SLIME ) + { + VectorScale( p->vel, 0.20, p->vel ); + VectorScale( p->accel, 0.20, p->accel ); + } + if( contents & CONTENTS_LAVA ) + { + VectorScale( p->vel, 0.10, p->vel ); + VectorScale( p->accel, 0.10, p->accel ); + } + + // don't add friction again + p->flags &= ~PARTICLE_FRICTION; + length = 1; + + // reset + p->time = cl.time; + VectorCopy( org, p->org ); + VectorCopy( color, p->color ); + p->alpha = alpha; + p->radius = radius; + + // don't stretch + p->flags &= ~PARTICLE_STRETCH; + p->length = length; + p->lengthVel = 0; + } + } + + if( p->flags & PARTICLE_BOUNCE ) + { + edict_t *clent = PRVM_EDICT_NUM( cl.frame.ps.number ); + + // bouncy particle + VectorSet(mins, -radius, -radius, -radius); + VectorSet(maxs, radius, radius, radius); + + trace = CL_Trace( p->old_origin, mins, maxs, org, MOVE_NORMAL, clent, MASK_SOLID ); + if( trace.fraction != 0.0 && trace.fraction != 1.0 ) + { + // reflect velocity + time = cl.time - (cls.frametime + cls.frametime * trace.fraction) * 1000; + time = (time - p->time) * 0.001; + + VectorSet( vel, p->vel[0], p->vel[1], p->vel[2]+p->accel[2]*gravity*time ); + VectorReflect( vel, 0, trace.plane.normal, p->vel ); + VectorScale( p->vel, p->bounceFactor, p->vel ); + + // check for stop or slide along the plane + if( trace.plane.normal[2] > 0 && p->vel[2] < 1 ) + { + if( trace.plane.normal[2] == 1 ) + { + VectorClear( p->vel ); + VectorClear( p->accel ); + p->flags &= ~PARTICLE_BOUNCE; + } + else + { + // FIXME: check for new plane or free fall + dot = DotProduct( p->vel, trace.plane.normal ); + VectorMA( p->vel, -dot, trace.plane.normal, p->vel ); + + dot = DotProduct( p->accel, trace.plane.normal ); + VectorMA( p->accel, -dot, trace.plane.normal, p->accel ); + } + } + + VectorCopy( trace.endpos, org ); + length = 1; + + // reset + p->time = cl.time; + VectorCopy( org, p->org ); + VectorCopy( color, p->color ); + p->alpha = alpha; + p->radius = radius; + + // don't stretch + p->flags &= ~PARTICLE_STRETCH; + p->length = length; + p->lengthVel = 0; + } + } + + // save current origin if needed + if( p->flags & (PARTICLE_BOUNCE|PARTICLE_STRETCH)) + { + VectorCopy( p->old_origin, org2 ); + VectorCopy( org, p->old_origin ); // FIXME: pause + } + + if( p->flags & PARTICLE_VERTEXLIGHT ) + { + // vertex lit particle + re->LightForPoint( org, ambientLight ); + VectorMultiply( color, ambientLight, color ); + } + + // bound color and alpha and convert to byte + modulate = PackRGBA( color[0], color[1], color[2], alpha ); + + if( p->flags & PARTICLE_INSTANT ) + { + // instant particle + p->alpha = 0; + p->alphaVel = 0; + } + + // send the particle to the renderer + re->AddParticle( p->shader, org, org2, radius, length, p->rotation, modulate ); + } + + cl_active_particles = active; +} /* =============== @@ -281,20 +560,16 @@ void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count) cparticle_t *p; float d; - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; + p = CL_AllocParticle(); + if( !p ) return; - p->time = cl.time * 0.001; - p->color = color + (rand()&7); + p->time = cl.time; + VectorCopy( UnpackRGBA( color ), p->color ); d = rand()&31; - for (j=0 ; j<3 ; j++) + for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j]; p->vel[j] = RANDOM_FLOAT( -1.0f, 1.0f ) * 20; @@ -303,8 +578,12 @@ void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count) p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; p->alpha = 1.0; - - p->alphavel = -1.0 / (0.5 + RANDOM_FLOAT(0, 1) * 0.3); + p->alphaVel = -1.0 / (0.5 + RANDOM_FLOAT(0, 1) * 0.3); + p->radius = 2; + p->radiusVel = 0; + p->length = 1; + p->lengthVel = 0; + p->rotation = 0; } } @@ -318,112 +597,61 @@ void CL_TeleportSplash( vec3_t org ) { int i, j, k; cparticle_t *p; - float vel; + shader_t teleShader; + float vel, color; vec3_t dir; + if( !cl_particles->integer ) + return; + + teleShader = re->RegisterShader( "particles/glow", SHADER_GENERIC ); + for( i = -16; i < 16; i += 4 ) { for( j = -16; j < 16; j += 4 ) { for( k = -24; k < 32; k += 4 ) { - if(!free_particles) return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; + p = CL_AllocParticle(); + if( !p ) return; - p->time = (cl.time * 0.001) + RANDOM_FLOAT( 0.02f, 0.2f ); - p->color = 0xdb; + VectorSet( dir, j*8, i*8, k*8 ); + VectorNormalizeFast( dir ); + + vel = 50 + (rand() & 63); + color = 0.1 + (0.2 * Com_RandomFloat( -1.0f, 1.0f )); + + p->shader = teleShader; + p->time = cl.time; + p->flags = 0; - dir[0] = j * 8; - dir[1] = i * 8; - dir[2] = k * 8; - - p->org[0] = org[0] + i + (rand()&3); - p->org[1] = org[1] + j + (rand()&3); - p->org[2] = org[2] + k + (rand()&3); - - p->accel[0] = p->accel[1] = 0; + p->org[0] = org[0] + i + (rand() & 3); + p->org[1] = org[1] + j + (rand() & 3); + p->org[2] = org[2] + k + (rand() & 3); + p->vel[0] = dir[0] * vel; + p->vel[1] = dir[1] * vel; + p->vel[2] = dir[2] * vel; + p->accel[0] = 0; + p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; - p->alphavel = -0.5; + p->color[0] = color; + p->color[1] = color; + p->color[2] = color; + p->colorVel[0] = 0; + p->colorVel[1] = 0; + p->colorVel[2] = 0; p->alpha = 1.0; - - VectorNormalize( dir ); - vel = 50 + (rand()&63); - VectorScale( dir, vel, p->vel ); + p->alphaVel = -1.0 / (0.3 + (rand() & 7) * 0.02); + p->radius = 2; + p->radiusVel = 0; + p->length = 1; + p->lengthVel = 0; + p->rotation = 0; } } } } -/* -=============== -CL_AddParticles -=============== -*/ -void CL_AddParticles (void) -{ - cparticle_t *p, *next; - float alpha; - float time, time2; - vec3_t org; - int color; - cparticle_t *active, *tail; - - active = NULL; - tail = NULL; - - for( p = active_particles; p; p = next ) - { - next = p->next; - - // PMM - added INSTANT_PARTICLE handling for heat beam - if( p->alphavel != INSTANT_PARTICLE ) - { - time = ( cl.time * 0.001 ) - p->time; - alpha = p->alpha + time * p->alphavel; - if( alpha <= 0 ) - { - // faded out - p->next = free_particles; - free_particles = p; - continue; - } - } - else - { - alpha = p->alpha; - } - - p->next = NULL; - if( !tail ) active = tail = p; - else - { - tail->next = p; - tail = p; - } - - if( alpha > 1.0 ) alpha = 1; - color = p->color; - - time2 = time*time; - - org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2; - org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2; - org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2; - - re->AddParticle( org, alpha, color ); - // PMM - if( p->alphavel == INSTANT_PARTICLE ) - { - p->alphavel = 0.0; - p->alpha = 0.0; - } - } - - active_particles = active; -} /* ============== diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 178f6500..64880061 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -37,6 +37,8 @@ cvar_t *cl_gun; cvar_t *cl_add_particles; cvar_t *cl_add_lights; cvar_t *cl_add_entities; +cvar_t *cl_particles; +cvar_t *cl_particlelod; cvar_t *cl_shownet; cvar_t *cl_showmiss; @@ -1075,8 +1077,9 @@ void CL_InitLocal (void) cl_gun = Cvar_Get ("cl_gun", "1", 0, "hide firstperson viewmodel" ); cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0, "disables player footsteps" ); cl_predict = Cvar_Get ("cl_predict", "1", CVAR_ARCHIVE, "disables client movement prediction" ); -// cl_minfps = Cvar_Get ("cl_minfps", "5", 0); cl_maxfps = Cvar_Get ("cl_maxfps", "1000", 0, "maximum client fps" ); + cl_particles = Cvar_Get( "cl_particles", "1", CVAR_ARCHIVE, "disables particle effects" ); + cl_particlelod = Cvar_Get( "cl_lod_particle", "0", CVAR_ARCHIVE, "enables particle LOD (1, 2, 3)" ); cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0, "client upspeed limit" ); cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0, "client forward speed limit" ); diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index b63b89cd..7b50b4ae 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -235,7 +235,7 @@ void CL_PMTrace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr *tr = CL_Trace( start, mins, maxs, end, MOVE_NORMAL, NULL, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY ); } -int CL_PMpointcontents( vec3_t point ) +int CL_PointContents( vec3_t point ) { // get world supercontents at this point if( cl.worldmodel && cl.worldmodel->PointContents ) @@ -289,7 +289,7 @@ void CL_PredictMovement (void) // copy current state to pmove memset (&pm, 0, sizeof(pm)); pm.trace = CL_PMTrace; - pm.pointcontents = CL_PMpointcontents; + pm.pointcontents = CL_PointContents; pm.ps = cl.frame.ps; // SCR_DebugGraph (current - ack - 1, COLOR_0); diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index b79de2e5..6b396fc7 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -94,7 +94,7 @@ void V_TestLights( void ) float f, r; cdlight_t dl; - memset( &dl, 0, sizeof(cdlight_t)); + Mem_Set( &dl, 0, sizeof( cdlight_t )); V_ClearScene(); for( i = 0; i < 32; i++ ) diff --git a/engine/client/client.h b/engine/client/client.h index 890b0c84..b444ec6a 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -300,6 +300,8 @@ extern cvar_t *cl_anglespeedkey; extern cvar_t *cl_showmiss; extern cvar_t *cl_showclamp; +extern cvar_t *cl_particles; +extern cvar_t *cl_particlelod; extern cvar_t *lookspring; extern cvar_t *lookstrafe; @@ -356,24 +358,6 @@ void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count); //================================================= - -// ======== -// PGM -typedef struct cparticle_s -{ - struct cparticle_s *next; - - float time; - - vec3_t org; - vec3_t vel; - vec3_t accel; - float color; - float colorvel; - float alpha; - float alphavel; -} cparticle_t; - // // cinematic.c // @@ -382,8 +366,6 @@ void CIN_DrawCinematic( void ); // draw current frame void CIN_RunCinematic( void ); // decompress next frame void CIN_StopCinematic( void ); // stop video playing -#define PARTICLE_GRAVITY 40 -#define INSTANT_PARTICLE -10000.0 void CL_TeleportSplash( vec3_t org ); int CL_ParseEntityBits( sizebuf_t *msg, uint *bits ); void CL_ParseFrame( sizebuf_t *msg ); @@ -546,6 +528,8 @@ float V_CalcFov( float fov_x, float width, float height ); void CL_InitPrediction (void); void CL_PredictMove (void); void CL_CheckPredictionError (void); +int CL_PointContents( vec3_t point ); +trace_t CL_Trace( const vec3_t s1, const vec3_t m1, const vec3_t m2, const vec3_t s2, int type, edict_t *ed, int mask ); // // cl_ents.c diff --git a/engine/host.c b/engine/host.c index bb1d0d1d..729487a8 100644 --- a/engine/host.c +++ b/engine/host.c @@ -139,7 +139,7 @@ void Host_InitSound( void ) // phys callback si.api_size = sizeof(vsound_imp_t); si.GetSoundSpatialization = CL_GetEntitySoundSpatialization; - si.PointContents = CL_PMpointcontents; + si.PointContents = CL_PointContents; si.AddLoopingSounds = CL_AddLoopingSounds; Sys_LoadLibrary( &vsound_dll ); diff --git a/engine/server/sv_progs.c b/engine/server/sv_progs.c index e43f144a..cc5f0307 100644 --- a/engine/server/sv_progs.c +++ b/engine/server/sv_progs.c @@ -608,23 +608,15 @@ void SV_FreeEdict( edict_t *ed ) { // unlink from world SV_UnlinkEdict( ed ); + pe->RemoveBody( ed->priv.sv->physbody ); - ed->priv.sv->s.ed_type = ED_SPAWNED; + Mem_Set( ed->priv.sv, 0, sizeof( sv_edict_t )); + Mem_Set( ed->progs.sv, 0, sizeof( sv_entvars_t )); + + // mark edict as freed ed->priv.sv->freetime = sv.time; ed->priv.sv->free = true; - - ed->progs.sv->model = 0; - ed->progs.sv->takedamage = 0; - ed->progs.sv->modelindex = 0; - ed->progs.sv->skin = 0; - ed->progs.sv->frame = 0; - ed->progs.sv->solid = 0; - - pe->RemoveBody( ed->priv.sv->physbody ); - VectorClear( ed->progs.sv->origin ); - VectorClear( ed->progs.sv->angles ); ed->progs.sv->nextthink = -1; - ed->priv.sv->physbody = NULL; } void SV_CountEdicts( void ) diff --git a/physic/cm_test.c b/physic/cm_test.c index d6d0c7c1..34207a0e 100644 --- a/physic/cm_test.c +++ b/physic/cm_test.c @@ -138,7 +138,7 @@ int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsiz ll.maxcount = listsize; ll.list = list; ll.storeleafs = CM_StoreLeafs; - ll.lastleaf = 0; + ll.lastleaf = -1; ll.overflowed = false; CM_BoxLeafnums_r( &ll, cm.nodes ); diff --git a/public/matrixlib.h b/public/matrixlib.h index a912a33a..f681a560 100644 --- a/public/matrixlib.h +++ b/public/matrixlib.h @@ -111,6 +111,31 @@ _inline void Matrix3x3_FromAngles( const vec3_t angles, matrix3x3 out ) out[2][2] = cr*cp; } +_inline void Matrix3x3_FromMatrix4x4( matrix3x3 out, const matrix4x4 in ) +{ +#ifdef OPENGL_STYLE + out[0][0] = in[0][0]; + out[1][0] = in[1][0]; + out[2][0] = in[2][0]; + out[0][1] = in[0][1]; + out[1][1] = in[1][1]; + out[2][1] = in[2][1]; + out[0][2] = in[0][2]; + out[1][2] = in[1][2]; + out[2][2] = in[2][2]; +#else + out[0][0] = in[0][0]; + out[1][0] = in[0][1]; + out[2][0] = in[0][2]; + out[0][1] = in[1][0]; + out[1][1] = in[1][1]; + out[2][1] = in[1][2]; + out[0][2] = in[2][0]; + out[1][2] = in[2][1]; + out[2][2] = in[2][2]; +#endif +} + _inline void Matrix3x3_ToAngles( const matrix3x3 matrix, vec3_t out ) { double pitch, cpitch, yaw, roll; diff --git a/public/render_api.h b/public/render_api.h index 0ac62892..feb5318e 100644 --- a/public/render_api.h +++ b/public/render_api.h @@ -9,6 +9,7 @@ #define SHADER_SKY 0 // sky box shader #define SHADER_FONT 1 // speical case for displayed fonts #define SHADER_NOMIP 2 // 2d images +#define SHADER_GENERIC 3 // generic shader typedef struct vrect_s { @@ -53,7 +54,7 @@ typedef struct render_exp_s // prepare frame to rendering bool (*AddRefEntity)( entity_state_t *s1, entity_state_t *s2, float lerp ); bool (*AddDynLight)( vec3_t org, vec3_t color, float intensity ); - bool (*AddParticle)( vec3_t org, float alpha, int color ); + bool (*AddParticle)( shader_t shader, const vec3_t p1, const vec3_t p2, float rad, float len, float rot, int col ); bool (*AddLightStyle)( int stylenum, vec3_t color ); void (*ClearScene)( void ); @@ -61,9 +62,11 @@ typedef struct render_exp_s void (*RenderFrame)( refdef_t *fd ); void (*EndFrame)( void ); + // misc utilities void (*SetColor)( const float *rgba ); bool (*ScrShot)( const char *filename, int shot_type ); // write screenshot with same name bool (*EnvShot)( const char *filename, uint size, bool skyshot ); // write envshot with same name + void (*LightForPoint)( const vec3_t point, vec3_t ambientLight ); void (*DrawFill)( float x, float y, float w, float h ); void (*DrawStretchRaw)( int x, int y, int w, int h, int cols, int rows, byte *data, bool redraw ); void (*DrawStretchPic)( float x, float y, float w, float h, float s1, float t1, float s2, float t2, shader_t shader ); diff --git a/release.bat b/release.bat index 54d7f02d..0139a6e4 100644 --- a/release.bat +++ b/release.bat @@ -67,5 +67,5 @@ if exist vsound\vsound.plg del /f /q vsound\vsound.plg echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -quake.exe -game tmpQuArK -dev 3 -log +map start +quake.exe -game tmpQuArK -dev 3 -log +map qctest :done \ No newline at end of file diff --git a/render/gl_backend.c b/render/gl_backend.c index 077d2de1..55ecc839 100644 --- a/render/gl_backend.c +++ b/render/gl_backend.c @@ -43,6 +43,7 @@ static dllfunc_t opengl_110funcs[] = {"glDepthRange", (void **) &pglDepthRange}, {"glDrawElements", (void **) &pglDrawElements}, {"glColorMask", (void **) &pglColorMask}, + {"glIndexPointer", (void **) &pglIndexPointer}, {"glVertexPointer", (void **) &pglVertexPointer}, {"glNormalPointer", (void **) &pglNormalPointer}, {"glColorPointer", (void **) &pglColorPointer}, diff --git a/render/r_backend2.c b/render/r_backend2.c index e7621427..a5f3563f 100644 --- a/render/r_backend2.c +++ b/render/r_backend2.c @@ -327,16 +327,20 @@ static float *RB_TableForFunc( const waveFunc_t *func ) } /* - ================= - RB_DeformVertexes - ================= +================= +RB_DeformVertexes +================= */ static void RB_DeformVertexes( void ) { deform_t *deformVertexes = m_pCurrentShader->deform; uint deformVertexesNum = m_pCurrentShader->numDeforms; + matrix3x3 mat1, mat2, mat3, matrix, invMatrix; + vec3_t vec, tmp, len, axis, rotCentre; + int index, longAxis, shortAxis; float *table, *v; float now, f, t; + float *quad[4]; int i, j; for( i = 0; i < deformVertexesNum; i++, deformVertexes++ ) @@ -376,8 +380,178 @@ static void RB_DeformVertexes( void ) VectorNormalizeFast( ref.normalArray[j] ); } break; - default: - Host_Error( "RB_DeformVertexes: unknown deformVertexes type %i in shader '%s'\n", deformVertexes->type, m_pCurrentShader->name); + case DEFORM_AUTOSPRITE: + if(( ref.numIndex % 6) || (ref.numVertex % 4 )) + { + MsgDev( D_WARN, "Shader '%s' has autoSprite but it's not a triangle quad\n", m_pCurrentShader->name ); + break; + } + + if( m_pCurrentEntity == r_worldEntity || !m_pCurrentEntity->model ) + Matrix3x3_FromMatrix4x4( invMatrix, r_worldMatrix ); + else Matrix3x3_FromMatrix4x4( invMatrix, r_entityMatrix ); + + for( index = 0; index < ref.numIndex; index += 6 ) + { + quad[0] = (float *)(ref.vertexArray + ref.indexArray[index+0]); + quad[1] = (float *)(ref.vertexArray + ref.indexArray[index+1]); + quad[2] = (float *)(ref.vertexArray + ref.indexArray[index+2]); + + for( j = 2; j >= 0; j-- ) + { + quad[3] = (float *)(ref.vertexArray + ref.indexArray[index+3+j]); + if( !VectorCompare( quad[3], quad[0] ) && !VectorCompare( quad[3], quad[1] ) && !VectorCompare( quad[3], quad[2] )) + break; + } + + VectorSubtract( quad[0], quad[1], mat1[0] ); + VectorSubtract( quad[2], quad[1], mat1[1] ); + CrossProduct( mat1[0], mat1[1], mat1[2] ); + VectorNormalizeFast( mat1[2] ); + VectorVectors( mat1[2], mat1[1], mat1[0] ); + + Matrix3x3_Concat( matrix, invMatrix, mat1 ); + + rotCentre[0] = (quad[0][0] + quad[1][0] + quad[2][0] + quad[3][0]) * 0.25; + rotCentre[1] = (quad[0][1] + quad[1][1] + quad[2][1] + quad[3][1]) * 0.25; + rotCentre[2] = (quad[0][2] + quad[1][2] + quad[2][2] + quad[3][2]) * 0.25; + + for( j = 0; j < 4; j++ ) + { + VectorSubtract(quad[j], rotCentre, vec); + Matrix3x3_Transform( matrix, vec, quad[j] ); + VectorAdd( quad[j], rotCentre, quad[j] ); + } + } + break; + case DEFORM_AUTOSPRITE2: + if(( ref.numIndex % 6) || (ref.numVertex % 4 )) + { + MsgDev( D_WARN, "Shader '%s' has autoSprite2 but it's not a triangle quad\n", m_pCurrentShader->name ); + break; + } + + for( index = 0; index < ref.numIndex; index += 6 ) + { + quad[0] = (float *)(ref.vertexArray + ref.indexArray[index+0]); + quad[1] = (float *)(ref.vertexArray + ref.indexArray[index+1]); + quad[2] = (float *)(ref.vertexArray + ref.indexArray[index+2]); + + for( j = 2; j >= 0; j-- ) + { + quad[3] = (float *)(ref.vertexArray + ref.indexArray[index+3+j]); + if( !VectorCompare( quad[3], quad[0] ) && !VectorCompare( quad[3], quad[1] ) && !VectorCompare( quad[3], quad[2] )) + break; + } + + VectorSubtract( quad[1], quad[0], mat1[0] ); + VectorSubtract( quad[2], quad[0], mat1[1] ); + VectorSubtract( quad[2], quad[1], mat1[2] ); + + len[0] = DotProduct( mat1[0], mat1[0] ); + len[1] = DotProduct( mat1[1], mat1[1] ); + len[2] = DotProduct( mat1[2], mat1[2] ); + + if( len[2] > len[1] && len[2] > len[0] ) + { + if( len[1] > len[0] ) + { + longAxis = 1; + shortAxis = 0; + } + else + { + longAxis = 0; + shortAxis = 1; + } + } + else if( len[1] > len[2] && len[1] > len[0] ) + { + if( len[2] > len[0] ) + { + longAxis = 2; + shortAxis = 0; + } + else + { + longAxis = 0; + shortAxis = 2; + } + } + else if( len[0] > len[1] && len[0] > len[2] ) + { + if( len[2] > len[1] ) + { + longAxis = 2; + shortAxis = 1; + } + else + { + longAxis = 1; + shortAxis = 2; + } + } + else + { + longAxis = 0; + shortAxis = 0; + } + + if( DotProduct( mat1[longAxis], mat1[shortAxis] )) + { + VectorNormalize2( mat1[longAxis], axis ); + VectorCopy(axis, mat1[1]); + + if( axis[0] || axis[1] ) + VectorVectors( mat1[1], mat1[0], mat1[2] ); + else VectorVectors( mat1[1], mat1[2], mat1[0] ); + } + else + { + VectorNormalize2( mat1[longAxis], axis ); + VectorNormalize2( mat1[shortAxis], mat1[0] ); + VectorCopy( axis, mat1[1] ); + CrossProduct( mat1[0], mat1[1], mat1[2] ); + } + + rotCentre[0] = (quad[0][0] + quad[1][0] + quad[2][0] + quad[3][0]) * 0.25; + rotCentre[1] = (quad[0][1] + quad[1][1] + quad[2][1] + quad[3][1]) * 0.25; + rotCentre[2] = (quad[0][2] + quad[1][2] + quad[2][2] + quad[3][2]) * 0.25; + + if( !Matrix3x3_Compare( m_pCurrentEntity->matrix, matrix3x3_identity )) + { + VectorAdd( rotCentre, m_pCurrentEntity->origin, vec ); + VectorSubtract( r_refdef.vieworg, vec, tmp ); + Matrix3x3_Transform( m_pCurrentEntity->matrix, tmp, vec ); + } + else + { + VectorAdd( rotCentre, m_pCurrentEntity->origin, vec ); + VectorSubtract( r_refdef.vieworg, vec, vec ); + } + + f = -DotProduct( vec, axis ); + + VectorMA( vec, f, axis, mat2[2] ); + VectorNormalizeFast( mat2[2] ); + VectorCopy( axis, mat2[1] ); + CrossProduct( mat2[1], mat2[2], mat2[0] ); + + VectorSet( mat3[0], mat2[0][0], mat2[1][0], mat2[2][0] ); + VectorSet( mat3[1], mat2[0][1], mat2[1][1], mat2[2][1] ); + VectorSet( mat3[2], mat2[0][2], mat2[1][2], mat2[2][2] ); + + Matrix3x3_Concat( matrix, mat3, mat1 ); + + for( j = 0; j < 4; j++ ) + { + VectorSubtract( quad[j], rotCentre, vec ); + Matrix3x3_Transform( matrix, vec, quad[j] ); + VectorAdd( quad[j], rotCentre, quad[j] ); + } + } + break; + default: Host_Error( "RB_DeformVertexes: unknown deformVertexes type %i in shader '%s'\n", deformVertexes->type, m_pCurrentShader->name); } } } @@ -1099,66 +1273,9 @@ static void RB_RenderShaderARB( void ) RB_UpdateVertexBuffer( ref.normalBuffer, ref.normalArray, ref.numVertex * sizeof( vec3_t )); pglEnableClientState( GL_NORMAL_ARRAY ); - pglNormalPointer( GL_FLOAT, 0, ref.vertexBuffer->pointer ); + pglNormalPointer( GL_FLOAT, 0, ref.normalBuffer->pointer ); - for( i = 0; i < m_pCurrentShader->numStages; i++ ) - { - stage = m_pCurrentShader->stages[i]; - - RB_SetShaderStageState( stage ); - RB_CalcVertexColors( stage ); - - RB_UpdateVertexBuffer( ref.colorBuffer, ref.colorArray, ref.numVertex * sizeof( vec4_t )); - pglEnableClientState( GL_COLOR_ARRAY ); - pglColorPointer( 4, GL_FLOAT, 0, ref.vertexBuffer->pointer ); - - for( j = 0; j < stage->numBundles; j++ ) - { - bundle = stage->bundles[j]; - - RB_SetupTextureUnit( bundle, j ); - RB_CalcTextureCoords( bundle, j ); - - RB_UpdateVertexBuffer( ref.texCoordBuffer[j], ref.texCoordArray[j], ref.numVertex * sizeof( vec3_t )); - pglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - pglTexCoordPointer( 3, GL_FLOAT, 0, ref.texCoordBuffer[j]->pointer ); - } - - RB_DrawElements(); - - for( j = stage->numBundles - 1; j >= 0; j-- ) - { - bundle = stage->bundles[j]; - - RB_CleanupTextureUnit( bundle, j ); - pglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - } - } -} - -/* -================= -RB_RenderShader -================= -*/ -static void RB_RenderShader( void ) -{ - shaderStage_t *stage; - stageBundle_t *bundle; - int i, j; - - RB_SetShaderState(); - RB_DeformVertexes(); - - RB_UpdateVertexBuffer( ref.vertexBuffer, ref.vertexArray, ref.numVertex * sizeof( vec3_t )); - pglEnableClientState( GL_VERTEX_ARRAY ); - pglVertexPointer( 3, GL_FLOAT, 0, ref.vertexBuffer->pointer ); - - RB_UpdateVertexBuffer( ref.normalBuffer, ref.normalArray, ref.numVertex * sizeof( vec3_t )); - pglEnableClientState( GL_NORMAL_ARRAY ); - pglNormalPointer( GL_FLOAT, 0, ref.vertexBuffer->pointer ); - - if( GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) + if( !GL_Support( R_ARB_VERTEX_BUFFER_OBJECT_EXT ) && GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) { if( m_pCurrentShader->numStages != 1 ) { @@ -1177,8 +1294,8 @@ static void RB_RenderShader( void ) RB_UpdateVertexBuffer( ref.colorBuffer, ref.colorArray, ref.numVertex * sizeof( vec4_t )); pglEnableClientState( GL_COLOR_ARRAY ); - pglColorPointer( 4, GL_FLOAT, 0, ref.vertexBuffer->pointer ); - + pglColorPointer( 4, GL_FLOAT, 0, ref.colorBuffer->pointer ); + for( j = 0; j < stage->numBundles; j++ ) { bundle = stage->bundles[j]; @@ -1191,7 +1308,7 @@ static void RB_RenderShader( void ) pglTexCoordPointer( 3, GL_FLOAT, 0, ref.texCoordBuffer[j]->pointer ); } - if(GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) + if(!GL_Support( R_ARB_VERTEX_BUFFER_OBJECT_EXT ) && GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) { if( m_pCurrentShader->numStages == 1 ) pglLockArraysEXT( 0, ref.numVertex ); @@ -1208,7 +1325,8 @@ static void RB_RenderShader( void ) } } - if( GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) pglUnlockArraysEXT(); + if(!GL_Support( R_ARB_VERTEX_BUFFER_OBJECT_EXT ) && GL_Support( R_CUSTOM_VERTEX_ARRAY_EXT )) + pglUnlockArraysEXT(); } /* @@ -1470,9 +1588,7 @@ void RB_RenderMesh( void ) r_stats.totalIndices += ref.numIndex * m_pCurrentShader->numStages; // render the shader - if( GL_Support( R_ARB_VERTEX_BUFFER_OBJECT_EXT )) - RB_RenderShaderARB(); - else RB_RenderShader(); + RB_RenderShaderARB(); // draw debug tools if( r_showtris->integer || r_physbdebug->integer || r_shownormals->integer || r_showtangentspace->integer || r_showmodelbounds->integer ) @@ -1546,16 +1662,17 @@ void RB_RenderMeshes( mesh_t *meshes, int numMeshes ) // check if the entity changed if( m_pCurrentEntity != entity ) { - if( entity == r_worldEntity ) - GL_LoadMatrix( r_worldMatrix ); - else if( entity->ent_type == ED_BSPBRUSH ) - R_RotateForEntity( entity ); - else if( entity->ent_type == ED_RIGIDBODY ) - R_RotateForEntity( entity ); - else if( entity->ent_type == ED_MOVER ) - R_RotateForEntity( entity ); - // sprites and studio models make transformation locally - + if( entity->model ) + { + switch( entity->model->type ) + { + case mod_brush: + R_RotateForEntity( entity ); + break; + default: break; + } + } + else GL_LoadMatrix( r_worldMatrix ); m_pCurrentEntity = entity; m_fShaderTime = r_refdef.time - entity->shaderTime; m_pRenderModel = m_pCurrentEntity->model; diff --git a/render/r_image.c b/render/r_image.c index 318f670a..2208384f 100644 --- a/render/r_image.c +++ b/render/r_image.c @@ -2225,7 +2225,7 @@ static void R_UploadTexture( rgbdata_t *pic, texture_t *tex ) default: dxtformat = false; break; } - tex->texnum = (tex - r_textures) + 1; + pglGenTextures( 1, &tex->texnum ); GL_BindTexture( tex ); // uploading texture into video memory diff --git a/render/r_main.c b/render/r_main.c index 16112d39..fd3571c2 100644 --- a/render/r_main.c +++ b/render/r_main.c @@ -1105,7 +1105,7 @@ static bool R_AddDynamicLight( vec3_t org, vec3_t color, float intensity ) R_AddParticleToScene ================= */ -bool R_AddParticleToScene( const vec3_t origin, float alpha, int color ) +bool R_AddParticleToScene( shader_t shader, const vec3_t org1, const vec3_t org2, float radius, float length, float rotate, int color ) { particle_t *p; @@ -1114,13 +1114,16 @@ bool R_AddParticleToScene( const vec3_t origin, float alpha, int color ) p = &r_particles[r_numParticles]; - p->shader = tr.particleShader; - VectorCopy( origin, p->origin ); - VectorCopy( origin, p->old_origin ); - p->radius = 5; - p->length = alpha; - p->rotation = 0; - Vector4Set( p->modulate, 1.0f, 1.0f, 1.0f, 1.0f ); + if( shader > 0 ) + p->shader = &r_shaders[shader]; + else p->shader = tr.particleShader; + + VectorCopy( org1, p->origin ); + VectorCopy( org2, p->old_origin ); + p->radius = radius; + p->length = length; + p->rotation = rotate; + Vector4Copy( UnpackRGBA( color ), p->modulate ); r_numParticles++; return true; @@ -1258,7 +1261,7 @@ shader_t Mod_RegisterShader( const char *name, int shaderType ) { shader_t shader = tr.defaultShader->shadernum; - if( shaderType >= SHADER_SKY && shaderType <= SHADER_NOMIP ) + if( shaderType >= SHADER_SKY && shaderType <= SHADER_GENERIC ) shader = R_FindShader( name, shaderType, 0 )->shadernum; else MsgDev( D_WARN, "Mod_RegisterShader: invalid shader type (%i)\n", shaderType ); if( shaderType == SHADER_SKY ) R_SetupSky( name, 0, vec3_origin ); @@ -1374,6 +1377,7 @@ render_exp_t DLLEXPORT *CreateAPI(stdlib_api_t *input, render_imp_t *engfuncs ) re.SetColor = GL_SetColor; re.ScrShot = VID_ScreenShot; re.EnvShot = VID_CubemapShot; + re.LightForPoint = R_LightForPoint; re.DrawFill = R_DrawFill; re.DrawStretchRaw = R_DrawStretchRaw; re.DrawStretchPic = R_DrawStretchPic; diff --git a/render/r_shader.h b/render/r_shader.h index a1e9cef9..f010162a 100644 --- a/render/r_shader.h +++ b/render/r_shader.h @@ -19,10 +19,10 @@ #define SHADER_SKY 0 // sky box shader #define SHADER_FONT 1 // speical case for displayed fonts #define SHADER_NOMIP 2 // 2d images -#define SHADER_TEXTURE 3 // bsp polygon -#define SHADER_STUDIO 4 // studio skins -#define SHADER_SPRITE 5 // sprite frames -#define SHADER_GENERIC 6 // generic shader +#define SHADER_GENERIC 3 // generic shader +#define SHADER_TEXTURE 4 // bsp polygon +#define SHADER_STUDIO 5 // studio skins +#define SHADER_SPRITE 6 // sprite frames #define MAX_SHADERS 1024 #define SHADERS_HASH_SIZE 256 @@ -180,7 +180,8 @@ typedef enum DEFORM_MOVE, DEFORM_NORMAL, DEFORM_AUTOSPRITE, - DEFORM_AUTOSPRITE2 + DEFORM_AUTOSPRITE2, + DEFORM_AUTOPARTICLE } deformType_t; typedef enum diff --git a/render/r_sky.c b/render/r_sky.c index de62bdff..2b1096bd 100644 --- a/render/r_sky.c +++ b/render/r_sky.c @@ -361,8 +361,6 @@ static void R_DrawSkyBox( texture_t *textures[6], bool blended ) if( GL_Support( R_ARB_VERTEX_BUFFER_OBJECT_EXT )) { - //pglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, rb_vbo.indexBuffer ); - //pglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, skySide->numIndices * sizeof(uint), skySide->indices, GL_STREAM_DRAW_ARB ); RB_UpdateVertexBuffer( sky->vbo[i], skySide->vertices, skySide->numVertices * sizeof(skySideVert_t)); pglEnableClientState( GL_VERTEX_ARRAY ); diff --git a/render/r_studio.c b/render/r_studio.c index 09787ab7..fdd3f0f4 100644 --- a/render/r_studio.c +++ b/render/r_studio.c @@ -1819,6 +1819,9 @@ bool R_StudioDrawModel( int pass, int flags ) } R_StudioSaveBones(); + //////// AFTER THIS POINT GO STUDIO MODEL DRAW /////// + //////// SAVE BONES INTO LOCAL ARRAY ///////////////// + if( flags & STUDIO_EVENTS ) { R_StudioCalcAttachments(); @@ -2159,8 +2162,6 @@ void R_DrawStudioModel( void ) void R_AddStudioModelToList( ref_entity_t *entity ) { - m_pCurrentEntity = entity; - R_StudioSetupRender( 0 ); if(!R_StudioCheckBBox()) return; diff --git a/todo.log b/todo.log index 36bc04d0..02e9b53c 100644 --- a/todo.log +++ b/todo.log @@ -22,9 +22,9 @@ GLOBAL: 0. Com_Filter убрать внутрь launch.dll ?? 1. имплементация нового формата карт OK 2. новый загрузчик моделей на рендере OK -3. SV_Frame на сервере +3. SV_Frame на сервере OK 4. переписать загрузчик BSP OK -5. отладить R_ImageFreeUnused +5. отладить R_ImageFreeUnused OK 6. дописать Image_ForceRGBA OK 7. SC_ALLOW_PATHNAMES2 - набор символов OK 8. упорядочить ресурсы OK @@ -39,8 +39,12 @@ GLOBAL: 17. наладить StudioModelRender 18. энумератор текстур OK 19. наладить удаление ключей из HashTable OK -20. CM_HeadnodeVisible -21. Matrix3x3_Compare crashed +20. CM_HeadnodeVisible OK +21. Matrix3x3_Compare crashed OK +22. SpriteCulling OK +23. LightSwitch OK +24. ParticleDrawing OK +25. CM_LeafCluster crashing операция "Полная отладка менеджера текстур" 0. анализ менеджера egl и q2e_068