From a00f3732473b10f3257befd271f2f80b8b1c04f0 Mon Sep 17 00:00:00 2001 From: g-cont Date: Sun, 1 Feb 2009 00:00:00 +0300 Subject: [PATCH] 01 Feb 2009 --- backup.lst | 2 + common/basetypes.h | 6 - engine/client/cl_effects.c | 21 +- engine/client/client.h | 2 +- engine/host.c | 2 +- history.log | 4 + launch/imagelib/imagelib.h | 5 + public/launch_api.h | 2 + public/matrix_lib.h | 24 + public/render_api.h | 10 +- release.bat | 2 +- render/gl_backend.c | 39 +- render/r_backend.c | 2 +- render/r_backend.h | 11 +- render/r_backend2.c | 174 ++- render/r_draw.c | 12 +- render/r_fragment.c | 2 +- render/r_image.c | 35 +- render/r_light.c | 42 +- render/r_local.h | 38 +- render/r_main.c | 41 +- render/r_model.c | 4 +- render/r_model.h | 13 +- render/r_opengl.c | 247 +++- render/r_opengl.h | 5 +- render/r_program.c | 2 + render/r_shader.c | 5 +- render/r_shader.h | 4 +- render/r_sprite.c | 92 +- render/r_studio.c | 380 ++++--- render/r_studio.c.old | 2200 ++++++++++++++++++++++++++++++++++++ render/r_surface.c | 10 +- server/global/client.cpp | 4 +- todo.log | 9 +- xtools/mdllib.h | 11 - 35 files changed, 3069 insertions(+), 393 deletions(-) create mode 100644 history.log create mode 100644 render/r_studio.c.old diff --git a/backup.lst b/backup.lst index 70f7eb76..c3ebd5c5 100644 --- a/backup.lst +++ b/backup.lst @@ -10,6 +10,7 @@ backup.lst backup.bat release.bat launchers.bat +history.log todo.log baserc\ @@ -41,6 +42,7 @@ server\global\ server\monsters\ vprogs\ vsound\ +uimenu\ xtools\ xtools\bsplib xtools\ripper \ No newline at end of file diff --git a/common/basetypes.h b/common/basetypes.h index af833238..1fd26b14 100644 --- a/common/basetypes.h +++ b/common/basetypes.h @@ -23,12 +23,6 @@ typedef struct cl_priv_s cl_priv_t; typedef struct sv_priv_s sv_priv_t; typedef float vec_t; -// color packs -typedef struct { uint b:5; uint g:6; uint r:5; } color16; -typedef struct { byte r:8; byte g:8; byte b:8; } color24; -typedef struct { byte r; byte g; byte b; byte a; } color32; - - #define DLLEXPORT __declspec( dllexport ) #ifndef NULL diff --git a/engine/client/cl_effects.c b/engine/client/cl_effects.c index fedc9fdd..9b1d6feb 100644 --- a/engine/client/cl_effects.c +++ b/engine/client/cl_effects.c @@ -245,7 +245,7 @@ typedef struct cdecal_s { struct cdecal_s *prev, *next; int time; - vec4_t modulate; + rgba_t modulate; bool alphaFade; shader_t shader; int numVerts; @@ -326,7 +326,7 @@ CL_AddDecal called from render after clipping ================= */ -void CL_AddDecal( vec3_t org, matrix3x3 m, shader_t s, vec4_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ) +void CL_AddDecal( vec3_t org, matrix3x3 m, shader_t s, rgba_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ) { cdecal_t *decal; vec3_t delta; @@ -382,7 +382,7 @@ void CL_AddDecals( void ) if( time < fadeTime ) { - c = 1.0 - ((float)time / fadeTime); + c = 255 - ((float)time / fadeTime); for( i = 0; i < decal->numVerts; i++ ) { @@ -428,11 +428,17 @@ pfnAddDecal void pfnAddDecal( float *org, float *dir, float *rgba, float rot, float rad, HSPRITE hSpr, int flags ) { bool fade, temp; + rgba_t color; fade = (flags & DECAL_FADE) ? true : false; temp = (flags & DECAL_TEMPORARY) ? true : false; - re->ImpactMark( org, dir, rot, rad, rgba, fade, hSpr, temp ); + color[0] = 255 * rgba[0]; + color[1] = 255 * rgba[1]; + color[2] = 255 * rgba[2]; + color[3] = 255 * rgba[3]; + + re->ImpactMark( org, dir, rot, rad, color, fade, hSpr, temp ); } /* @@ -544,7 +550,7 @@ void CL_AddParticles( void ) { cparticle_t *p, *next; cparticle_t *active = NULL, *tail = NULL; - dword modulate; + rgba_t modulate; vec3_t origin, oldorigin, velocity, color; vec3_t ambientLight; float alpha, radius, length; @@ -721,7 +727,10 @@ void CL_AddParticles( void ) } // bound color and alpha and convert to byte - modulate = PackRGBA( color[0], color[1], color[2], alpha ); + modulate[0] = bound( 0, 255 * color[0], 255 ); + modulate[1] = bound( 0, 255 * color[1], 255 ); + modulate[2] = bound( 0, 255 * color[2], 255 ); + modulate[3] = bound( 0, 255 * alpha, 255 ); if( p->flags & PARTICLE_INSTANT ) { diff --git a/engine/client/client.h b/engine/client/client.h index 052015f0..e85c66de 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -583,7 +583,7 @@ void CL_ClearEffects( void ); void CL_TestLights( void ); void CL_TestEntities( void ); void CL_StudioEvent( dstudioevent_t *event, edict_t *ent ); -void CL_AddDecal( vec3_t org, matrix3x3 m, shader_t s, vec4_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ); +void CL_AddDecal( vec3_t org, matrix3x3 m, shader_t s, rgba_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ); edict_t *CL_GetEdictByIndex( int index ); edict_t *CL_GetLocalPlayer( void ); bool pfnAddParticle( cparticle_t *src, HSPRITE shader, int flags ); diff --git a/engine/host.c b/engine/host.c index 9eaac80d..64110ed9 100644 --- a/engine/host.c +++ b/engine/host.c @@ -96,7 +96,7 @@ void Host_InitRender( void ) } // video system not started, run dedicated server - if( !result ) Sys_NewInstance( va("#%s", GI->title), "Host_InitRender: fallback to dedicated mode\n" ); + if( !result ) Sys_NewInstance( va("#%s", GI->gamedir ), "Host_InitRender: fallback to dedicated mode\n" ); } void Host_FreeRender( void ) diff --git a/history.log b/history.log new file mode 100644 index 00000000..ef02ca52 --- /dev/null +++ b/history.log @@ -0,0 +1,4 @@ +Xash 0.56 alpha + +Xash 0.56 pre-alpha +- initial release \ No newline at end of file diff --git a/launch/imagelib/imagelib.h b/launch/imagelib/imagelib.h index 61ec126c..27229810 100644 --- a/launch/imagelib/imagelib.h +++ b/launch/imagelib/imagelib.h @@ -11,6 +11,11 @@ // skyorder_q2[6] = { 2, 3, 1, 0, 4, 5, }; // Quake, Half-Life skybox ordering // skyorder_ms[6] = { 4, 5, 1, 0, 2, 3 }; // Microsoft DDS ordering (reverse) +// color packs +typedef struct { uint b:5; uint g:6; uint r:5; } color16; +typedef struct { byte r:8; byte g:8; byte b:8; } color24; +typedef struct { byte r; byte g; byte b; byte a; } color32; + // cubemap hints typedef enum { diff --git a/public/launch_api.h b/public/launch_api.h index 051aff60..453539c8 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -28,6 +28,8 @@ typedef vec_t vec2_t[2]; typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; +typedef byte rgba_t[4]; // unsigned byte colorpack +typedef byte rgb_t[3]; // unsigned byte colorpack typedef vec_t matrix3x3[3][3]; typedef vec_t matrix4x4[4][4]; typedef char string[MAX_STRING]; diff --git a/public/matrix_lib.h b/public/matrix_lib.h index f01f0c63..028fb2de 100644 --- a/public/matrix_lib.h +++ b/public/matrix_lib.h @@ -867,6 +867,30 @@ _inline bool Matrix4x4_CompareRotateOnly( const matrix4x4 mat1, const matrix4x4 return true; } +_inline bool Matrix4x4_Compare( const matrix4x4 mat1, const matrix4x4 mat2 ) +{ +#ifdef OPENGL_STYLE + if( mat1[0][0] != mat2[0][0] || mat1[0][1] != mat2[0][1] || mat1[0][2] != mat2[0][2] ) + return false; + if( mat1[1][0] != mat2[1][0] || mat1[1][1] != mat2[1][1] || mat1[1][2] != mat2[1][2] ) + return false; + if( mat1[2][0] != mat2[2][0] || mat1[2][1] != mat2[2][1] || mat1[2][2] != mat2[2][2] ) + return false; + if( mat1[3][0] != mat2[3][0] || mat1[3][1] != mat2[3][1] || mat1[3][2] != mat2[3][2] ) + return false; +#else + if( mat1[0][0] != mat2[0][0] || mat1[1][0] != mat2[1][0] || mat1[2][0] != mat2[2][0] ) + return false; + if( mat1[0][1] != mat2[0][1] || mat1[1][1] != mat2[1][1] || mat1[2][1] != mat2[2][1] ) + return false; + if( mat1[0][2] != mat2[0][2] || mat1[1][2] != mat2[1][2] || mat1[2][2] != mat2[2][2] ) + return false; + if( mat1[0][3] != mat2[0][3] || mat1[1][3] != mat2[1][3] || mat1[2][3] != mat2[2][3] ) + return false; +#endif + return true; +} + _inline void Matrix4x4_FromVectors( matrix4x4 out, const float vx[3], const float vy[3], const float vz[3], const float t[3]) { #ifdef OPENGL_STYLE diff --git a/public/render_api.h b/public/render_api.h index cd20dbd6..9dd8abf0 100644 --- a/public/render_api.h +++ b/public/render_api.h @@ -16,7 +16,7 @@ typedef struct { vec3_t point; - vec4_t modulate; + rgba_t modulate; vec2_t st; } polyVert_t; @@ -49,7 +49,7 @@ typedef struct render_exp_s // prepare frame to rendering bool (*AddRefEntity)( edict_t *pRefEntity, int ed_type, float lerp ); bool (*AddDynLight)( vec3_t org, vec3_t color, float intensity ); - bool (*AddParticle)( shader_t shader, const vec3_t p1, const vec3_t p2, float rad, float len, float rot, int col ); + bool (*AddParticle)( shader_t shader, const vec3_t p1, const vec3_t p2, float rad, float len, float rot, rgba_t col ); bool (*AddPolygon)( shader_t shader, int numVerts, const polyVert_t *verts ); bool (*AddLightStyle)( int stylenum, vec3_t color ); void (*ClearScene)( void ); @@ -59,7 +59,7 @@ typedef struct render_exp_s void (*EndFrame)( void ); // misc utilities - void (*SetColor)( const float *rgba ); + void (*SetColor)( const void *color ); void (*SetParms)( shader_t handle, kRenderMode_t rendermode, int frame ); void (*GetParms)( int *w, int *h, int *frames, int frame, shader_t shader ); bool (*ScrShot)( const char *filename, int shot_type ); // write screenshot with same name @@ -68,7 +68,7 @@ typedef struct render_exp_s 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 ); - void (*ImpactMark)( vec3_t org, vec3_t dir, float rot, float radius, vec4_t mod, bool fade, shader_t s, bool tmp ); + void (*ImpactMark)( vec3_t org, vec3_t dir, float rot, float radius, rgba_t mod, bool fade, shader_t s, bool tmp ); } render_exp_t; @@ -80,7 +80,7 @@ typedef struct render_imp_s // client fundamental callbacks void (*UpdateScreen)( void ); // update screen while loading void (*StudioEvent)( dstudioevent_t *event, edict_t *ent ); - void (*AddDecal)( vec3_t org, matrix3x3 m, shader_t s, vec4_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ); + void (*AddDecal)( vec3_t org, matrix3x3 m, shader_t s, rgba_t rgba, bool fade, decalFragment_t *df, const vec3_t *v ); void (*ShowCollision)( cmdraw_t callback ); // debug long (*WndProc)( void *hWnd, uint uMsg, uint wParam, long lParam ); edict_t *(*GetClientEdict)( int index ); diff --git a/release.bat b/release.bat index 8f5d5c1c..663a785d 100644 --- a/release.bat +++ b/release.bat @@ -71,5 +71,5 @@ if exist xtools\xtools.plg del /f /q xtools\xtools.plg echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -quake.exe -game xash -dev 3 -log +map dm_qstyle +xash.exe -dev 3 -log +map dm_qstyle :done \ No newline at end of file diff --git a/render/gl_backend.c b/render/gl_backend.c index fd7cbcc1..16b7b5c3 100644 --- a/render/gl_backend.c +++ b/render/gl_backend.c @@ -41,6 +41,7 @@ static dllfunc_t opengl_110funcs[] = {"glDepthFunc", (void **) &pglDepthFunc}, {"glDepthMask", (void **) &pglDepthMask}, {"glDepthRange", (void **) &pglDepthRange}, + {"glFrontFace", (void **) &pglFrontFace}, {"glDrawElements", (void **) &pglDrawElements}, {"glColorMask", (void **) &pglColorMask}, {"glIndexPointer", (void **) &pglIndexPointer}, @@ -64,6 +65,8 @@ static dllfunc_t opengl_110funcs[] = {"glVertex2f", (void **) &pglVertex2f}, {"glVertex3f", (void **) &pglVertex3f}, {"glVertex3fv", (void **) &pglVertex3fv}, + {"glNormal3f", (void **) &pglNormal3f}, + {"glNormal3fv", (void **) &pglNormal3fv}, {"glBegin", (void **) &pglBegin}, {"glEnd", (void **) &pglEnd}, {"glLineWidth", (void**) &pglLineWidth}, @@ -329,6 +332,9 @@ void GL_InitCommands( void ) r_width = Cvar_Get("width", "640", CVAR_READ_ONLY, "screen width" ); r_height = Cvar_Get("height", "480", CVAR_READ_ONLY, "screen height" ); r_mode = Cvar_Get( "r_mode", "0", CVAR_ARCHIVE, "display resolution mode" ); + r_stencilbits = Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE|CVAR_LATCH, "pixelformat stencil bits (0 - auto)" ); + r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE|CVAR_LATCH, "pixelformat color bits (0 - auto)" ); + r_depthbits = Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE|CVAR_LATCH, "pixelformat depth bits (0 - auto)" ); r_check_errors = Cvar_Get("r_check_errors", "1", CVAR_ARCHIVE, "ignore video engine errors" ); r_lefthand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE, "viewmodel handedness" ); @@ -374,6 +380,7 @@ void GL_InitCommands( void ) r_showtris = Cvar_Get( "r_showtris", "0", 0, "show mesh triangles" ); r_lockpvs = Cvar_Get( "r_lockpvs", "0", 0, "lockpvs area at current point (pvs test)" ); r_fullscreen = Cvar_Get( "fullscreen", "0", CVAR_ARCHIVE, "set in 1 to enable fullscreen mode" ); + r_allow_software = Cvar_Get( "gl_software", "0", CVAR_ARCHIVE, "allow software gl acceleration" ); r_nobind = Cvar_Get( "r_nobind", "0", CVAR_CHEAT, "disable all textures (perfomance test)" ); r_drawparticles = Cvar_Get( "r_drawparticles", "1", CVAR_CHEAT, "disable particles (perfomance test)" ); @@ -496,9 +503,6 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv MsgDev( D_NOTE, "GL_CheckExtension: %s ", name ); - for( func = funcs; func && func->name; func++ ) - *func->func = NULL; - if( cvarname ) { // system config disable extensions @@ -518,6 +522,10 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv return; } + // clear exports + for( func = funcs; func && func->name; func++ ) + *func->func = NULL; + GL_SetExtension( r_ext, true ); // predict extension state for( func = funcs; func && func->name != NULL; func++ ) { @@ -676,6 +684,7 @@ void GL_InitExtensions( void ) flags |= IL_USE_LERPING; Image_Init( NULL, flags ); + glw_state.initialized = true; } /* @@ -916,11 +925,17 @@ void GL_SetColor( const void *data ) if( color ) { - Vector4Set( gl_state.draw_color, color[0], color[1], color[2], color[3] ); + gl_state.draw_color[0] = 255 * color[0]; + gl_state.draw_color[1] = 255 * color[1]; + gl_state.draw_color[2] = 255 * color[2]; + gl_state.draw_color[3] = 255 * color[3]; } else { - Vector4Set( gl_state.draw_color, 1.0f, 1.0f, 1.0f, 1.0f ); + gl_state.draw_color[0] = 255; + gl_state.draw_color[1] = 255; + gl_state.draw_color[2] = 255; + gl_state.draw_color[3] = 255; } } @@ -928,6 +943,12 @@ void GL_LoadMatrix( matrix4x4 source ) { gl_matrix dest; +#if 0 + if( Matrix4x4_Compare( source, gl_state.matrix )) + return; // ident + + Matrix4x4_Copy( gl_state.matrix, source ); +#endif Matrix4x4_ToArrayFloatGL( source, dest ); pglLoadMatrixf( dest ); } @@ -1026,9 +1047,13 @@ void GL_SetDefaultState( void ) if(GL_Support( R_TEXTURECUBEMAP_EXT )) pglDisable( GL_TEXTURE_CUBE_MAP_ARB ); + Matrix4x4_LoadIdentity( gl_state.matrix ); pglDisable( GL_TEXTURE_2D ); - Vector4Set( gl_state.draw_color, 1.0f, 1.0f, 1.0f, 1.0f ); - + gl_state.draw_color[0] = 255; + gl_state.draw_color[1] = 255; + gl_state.draw_color[2] = 255; + gl_state.draw_color[3] = 255; + GL_UpdateSwapInterval(); } diff --git a/render/r_backend.c b/render/r_backend.c index 014ca313..69d2a3c8 100644 --- a/render/r_backend.c +++ b/render/r_backend.c @@ -97,7 +97,7 @@ void RB_InitVertexBuffers( void ) int i; ref.vertexBuffer = RB_AllocVertexBuffer( MAX_VERTEXES * sizeof(vec3_t), GL_STREAM_DRAW_ARB ); - ref.colorBuffer = RB_AllocVertexBuffer( MAX_VERTEXES * sizeof(vec4_t), GL_STREAM_DRAW_ARB ); + ref.colorBuffer = RB_AllocVertexBuffer( MAX_VERTEXES * sizeof(rgba_t), GL_STREAM_DRAW_ARB ); ref.normalBuffer = RB_AllocVertexBuffer( MAX_VERTEXES * sizeof(vec3_t), GL_STREAM_DRAW_ARB ); for( i = 0; i < MAX_TEXTURE_UNITS; i++ ) ref.texCoordBuffer[i] = RB_AllocVertexBuffer( MAX_VERTEXES * sizeof(vec3_t), GL_STREAM_DRAW_ARB ); diff --git a/render/r_backend.h b/render/r_backend.h index 4e196dfc..1381d800 100644 --- a/render/r_backend.h +++ b/render/r_backend.h @@ -55,7 +55,7 @@ typedef struct glstate_s word stateRamp[768]; // original gamma ramp uint screenTexture; - vec4_t draw_color; // current color + rgba_t draw_color; // current color int texNum[MAX_TEXTURE_UNITS]; int texEnv[MAX_TEXTURE_UNITS]; uint activeTMU; @@ -70,6 +70,7 @@ typedef struct glstate_s bool blend; // OpenGL current state + matrix4x4 matrix; GLenum cullMode; GLfloat offsetFactor; GLfloat offsetUnits; @@ -106,6 +107,10 @@ typedef struct glconfig_s GLfloat max_lodbias; GLint texRectangle; + int color_bits; + int depth_bits; + int stencil_bits; + bool deviceSupportsGamma; bool fullscreen; int prev_mode; @@ -125,8 +130,6 @@ BACKEND #define MAX_VERTEXES 4096 #define MAX_ELEMENTS MAX_VERTEXES * 6 -typedef uint elem_t; - typedef struct ref_buffer_s { byte *pointer; @@ -169,7 +172,7 @@ typedef struct // vbo source buffers elem_t indexArray[MAX_ELEMENTS]; - vec4_t colorArray[MAX_VERTEXES]; + rgba_t colorArray[MAX_VERTEXES]; vec3_t vertexArray[MAX_VERTEXES]; vec3_t normalArray[MAX_VERTEXES]; vec3_t texCoordArray[MAX_TEXTURE_UNITS][MAX_VERTEXES]; diff --git a/render/r_backend2.c b/render/r_backend2.c index 584081b8..f8089868 100644 --- a/render/r_backend2.c +++ b/render/r_backend2.c @@ -148,10 +148,10 @@ static void RB_SetTexCoord( GLfloat s, GLfloat t, GLfloat ls, GLfloat lt ) static void RB_SetColor( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) { - ref.colorArray[ref.numVertex][0] = r; - ref.colorArray[ref.numVertex][1] = g; - ref.colorArray[ref.numVertex][2] = b; - ref.colorArray[ref.numVertex][3] = a; + ref.colorArray[ref.numVertex][0] = 255 * r; + ref.colorArray[ref.numVertex][1] = 255 * g; + ref.colorArray[ref.numVertex][2] = 255 * b; + ref.colorArray[ref.numVertex][3] = 255 * a; } static void RB_SetNormal( GLfloat x, GLfloat y, GLfloat z ) @@ -267,12 +267,18 @@ void GL_Color4fv( const GLfloat *v ) void GL_Color4ub( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) { - GL_Color4fv(UnpackRGBA(MakeRGBA( red, green, blue, alpha ))); + ref.colorArray[ref.numVertex][0] = red; + ref.colorArray[ref.numVertex][1] = green; + ref.colorArray[ref.numVertex][2] = blue; + ref.colorArray[ref.numVertex][3] = alpha; } void GL_Color4ubv( const GLubyte *v ) { - GL_Color4fv(UnpackRGBA(BuffLittleLong( v ))); + ref.colorArray[ref.numVertex][0] = v[0]; + ref.colorArray[ref.numVertex][1] = v[1]; + ref.colorArray[ref.numVertex][2] = v[2]; + ref.colorArray[ref.numVertex][3] = v[3]; } /* @@ -576,15 +582,15 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) case RGBGEN_IDENTITY: for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = 1.0f; - ref.colorArray[i][1] = 1.0f; - ref.colorArray[i][2] = 1.0f; + ref.colorArray[i][0] = 255; + ref.colorArray[i][1] = 255; + ref.colorArray[i][2] = 255; } break; case RGBGEN_IDENTITYLIGHTING: if( gl_config.deviceSupportsGamma ) - r = g = b = 1>>r_overbrightbits->integer; - else r = g = b = 1.0f; + r = g = b = 255 >> r_overbrightbits->integer; + else r = g = b = 255; for( i = 0; i < ref.numVertex; i++ ) { @@ -600,9 +606,9 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) f = bound( 0.0, f, 1.0 ); - r = 1.0f * f; - g = 1.0f * f; - b = 1.0f * f; + r = 255 * f; + g = 255 * f; + b = 255 * f; for( i = 0; i < ref.numVertex; i++ ) { @@ -618,9 +624,9 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) f = bound(0.0, f, 1.0); - r = 1.0f * (rgbGen->params[0] * f); - g = 1.0f * (rgbGen->params[1] * f); - b = 1.0f * (rgbGen->params[2] * f); + r = 255 * (rgbGen->params[0] * f); + g = 255 * (rgbGen->params[1] * f); + b = 255 * (rgbGen->params[2] * f); for( i = 0; i < ref.numVertex; i++ ) { @@ -634,9 +640,9 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) case RGBGEN_ONEMINUSVERTEX: for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = 1.0f - ref.colorArray[i][0]; - ref.colorArray[i][1] = 1.0f - ref.colorArray[i][1]; - ref.colorArray[i][2] = 1.0f - ref.colorArray[i][2]; + ref.colorArray[i][0] = 255 - ref.colorArray[i][0]; + ref.colorArray[i][1] = 255 - ref.colorArray[i][1]; + ref.colorArray[i][2] = 255 - ref.colorArray[i][2]; } break; case RGBGEN_ENTITY: @@ -661,9 +667,9 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) case RGBGEN_ONEMINUSENTITY: for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = 1.0f - m_pCurrentEntity->rendercolor[0]; - ref.colorArray[i][1] = 1.0f - m_pCurrentEntity->rendercolor[1]; - ref.colorArray[i][2] = 1.0f - m_pCurrentEntity->rendercolor[2]; + ref.colorArray[i][0] = 255 - m_pCurrentEntity->rendercolor[0]; + ref.colorArray[i][1] = 255 - m_pCurrentEntity->rendercolor[1]; + ref.colorArray[i][2] = 255 - m_pCurrentEntity->rendercolor[2]; } break; case RGBGEN_LIGHTINGAMBIENT: @@ -673,9 +679,9 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) R_LightingDiffuse(); break; case RGBGEN_CONST: - r = 1.0f * rgbGen->params[0]; - g = 1.0f * rgbGen->params[1]; - b = 1.0f * rgbGen->params[2]; + r = 255 * rgbGen->params[0]; + g = 255 * rgbGen->params[1]; + b = 255 * rgbGen->params[2]; for( i = 0; i < ref.numVertex; i++ ) { @@ -692,14 +698,14 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) { case ALPHAGEN_IDENTITY: for( i = 0; i < ref.numVertex; i++ ) - ref.colorArray[i][3] = 1.0f; + ref.colorArray[i][3] = 255; break; case ALPHAGEN_WAVE: table = RB_TableForFunc(&alphaGen->func); now = alphaGen->func.params[2] + alphaGen->func.params[3] * m_fShaderTime; f = table[((int)(now * TABLE_SIZE)) & TABLE_MASK] * alphaGen->func.params[1] + alphaGen->func.params[0]; f = bound( 0.0, f, 1.0 ); - a = 1.0f * f; + a = 255 * f; for( i = 0; i < ref.numVertex; i++ ) ref.colorArray[i][3] = a; @@ -709,7 +715,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) now = alphaGen->func.params[2] + alphaGen->func.params[3] * m_fShaderTime; f = table[((int)(now * TABLE_SIZE)) & TABLE_MASK] * alphaGen->func.params[1] + alphaGen->func.params[0]; f = bound( 0.0, f, 1.0 ); - a = 1.0f * (alphaGen->params[0] * f); + a = 255 * (alphaGen->params[0] * f); for( i = 0; i < ref.numVertex; i++ ) ref.colorArray[i][3] = a; @@ -718,7 +724,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) break; case ALPHAGEN_ONEMINUSVERTEX: for( i = 0; i < ref.numVertex; i++ ) - ref.colorArray[i][3] = 1.0f - ref.colorArray[i][3]; + ref.colorArray[i][3] = 255 - ref.colorArray[i][3]; break; case ALPHAGEN_ENTITY: switch( m_pCurrentEntity->rendermode ) @@ -739,7 +745,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) break; case ALPHAGEN_ONEMINUSENTITY: for( i = 0; i < ref.numVertex; i++ ) - ref.colorArray[i][3] = 1.0f - m_pCurrentEntity->renderamt; + ref.colorArray[i][3] = 255 - m_pCurrentEntity->renderamt; break; case ALPHAGEN_DOT: if( !Matrix3x3_Compare( m_pCurrentEntity->matrix, matrix3x3_identity )) @@ -750,7 +756,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) { f = DotProduct(vec, ref.normalArray[i] ); if( f < 0 ) f = -f; - ref.colorArray[i][3] = 1.0f * bound( alphaGen->params[0], f, alphaGen->params[1] ); + ref.colorArray[i][3] = 255 * bound( alphaGen->params[0], f, alphaGen->params[1] ); } break; case ALPHAGEN_ONEMINUSDOT: @@ -762,7 +768,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) { f = DotProduct(vec, ref.normalArray[i] ); if( f < 0 ) f = -f; - ref.colorArray[i][3] = bound( alphaGen->params[0], 1.0 - f, alphaGen->params[1]); + ref.colorArray[i][3] = bound( alphaGen->params[0], 255 - f, alphaGen->params[1]); } break; case ALPHAGEN_FADE: @@ -784,7 +790,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) f = bound( alphaGen->params[0], f, alphaGen->params[1] ) - alphaGen->params[0]; f = f * alphaGen->params[2]; - ref.colorArray[i][3] = bound( 0.0, 1.0 - f, 1.0 ); + ref.colorArray[i][3] = 255 * bound( 0.0, 1.0 - f, 1.0 ); } break; case ALPHAGEN_LIGHTINGSPECULAR: @@ -802,11 +808,11 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) f = DotProduct( dir, ref.normalArray[i] ); f = pow( f, alphaGen->params[0] ); - ref.colorArray[i][3] = 1.0f * bound( 0.0, f, 1.0 ); + ref.colorArray[i][3] = 255 * bound( 0.0, f, 1.0 ); } break; case ALPHAGEN_CONST: - a = 1.0f * alphaGen->params[0]; + a = 255 * alphaGen->params[0]; for( i = 0; i < ref.numVertex; i++ ) ref.colorArray[i][3] = a; @@ -1351,9 +1357,9 @@ static void RB_RenderShaderARB( void ) RB_SetShaderStageState( stage ); RB_CalcVertexColors( stage ); - RB_UpdateVertexBuffer( ref.colorBuffer, ref.colorArray, ref.numVertex * sizeof( vec4_t )); + RB_UpdateVertexBuffer( ref.colorBuffer, ref.colorArray, ref.numVertex * sizeof( rgba_t )); pglEnableClientState( GL_COLOR_ARRAY ); - pglColorPointer( 4, GL_FLOAT, 0, ref.colorBuffer->pointer ); + pglColorPointer( 4, GL_UNSIGNED_BYTE, 0, ref.colorBuffer->pointer ); for( j = 0; j < stage->numBundles; j++ ) { @@ -1388,6 +1394,73 @@ static void RB_RenderShaderARB( void ) pglUnlockArraysEXT(); } +/* +================= +RB_RenderShader +================= +*/ +static void RB_RenderShader( void ) +{ + shaderStage_t *stage; + stageBundle_t *bundle; + int i, j, k, l; + + pglDisableClientState( GL_VERTEX_ARRAY ); + pglDisableClientState( GL_NORMAL_ARRAY ); + pglDisableClientState( GL_COLOR_ARRAY ); + pglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + + RB_SetShaderState(); + RB_DeformVertexes(); + + for( i = 0; i < m_pCurrentShader->numStages; i++ ) + { + stage = m_pCurrentShader->stages[i]; + + RB_SetShaderStageState( stage ); + RB_CalcVertexColors( stage ); + + for( j = 0; j < stage->numBundles; j++ ) + { + bundle = stage->bundles[j]; + + RB_SetupTextureUnit( bundle, j ); + RB_CalcTextureCoords( bundle, j ); + } + + for( k = 0; k < ref.numIndex; k += 3 ) + { + pglBegin( GL_TRIANGLES ); + + l = ref.indexArray[k+0]; + pglTexCoord2f( ref.texCoordArray[0][l][0], ref.texCoordArray[0][l][1] ); + pglNormal3fv( ref.normalArray[l]); + pglColor4ubv( ref.colorArray[l] ); + pglVertex3fv( ref.vertexArray[l] ); + + l = ref.indexArray[k+1]; + pglTexCoord2f( ref.texCoordArray[0][l][0], ref.texCoordArray[0][l][1] ); + pglNormal3fv( ref.normalArray[l]); + pglColor4ubv( ref.colorArray[l] ); + pglVertex3fv( ref.vertexArray[l] ); + + l = ref.indexArray[k+2]; + pglTexCoord2f( ref.texCoordArray[0][l][0], ref.texCoordArray[0][l][1] ); + pglNormal3fv( ref.normalArray[l]); + pglColor4ubv( ref.colorArray[l] ); + pglVertex3fv( ref.vertexArray[l] ); + + pglEnd(); + } + + for( j = stage->numBundles - 1; j >= 0; j-- ) + { + bundle = stage->bundles[j]; + RB_CleanupTextureUnit( bundle, j ); + } + } +} + /* ================= RB_DrawTris @@ -1560,7 +1633,7 @@ static void RB_DrawLine( int color, int numpoints, const float *points, const in VectorSet( p1, points[i*3+0], points[i*3+1], points[i*3+2] ); if( r_physbdebug->integer == 1 ) ConvertPositionToGame( p1 ); - pglColor4fv(UnpackRGBA( color )); + pglColor4ubv( (byte *)color ); pglVertex3fv( p0 ); pglVertex3fv( p1 ); @@ -1650,8 +1723,11 @@ void RB_RenderMesh( void ) r_stats.numIndices += ref.numIndex; r_stats.totalIndices += ref.numIndex * m_pCurrentShader->numStages; - // render the shader - RB_RenderShaderARB(); + // NOTE: too small models uses glBegin\glEnd for perfomance reason +// if( ref.numVertex < 512 ) + if( glw_state.software ) + RB_RenderShader(); + else RB_RenderShaderARB(); // draw debug tools if( r_showtris->integer || r_physbdebug->integer || r_shownormals->integer || r_showtangentspace->integer || r_showmodelbounds->integer ) @@ -1673,7 +1749,7 @@ void RB_RenderMeshes( mesh_t *meshes, int numMeshes ) { int i; mesh_t *mesh; - ref_shader_t *shader; + ref_shader_t *shader; ref_entity_t *entity; int infoKey; uint sortKey = 0; @@ -1700,8 +1776,8 @@ void RB_RenderMeshes( mesh_t *meshes, int numMeshes ) sortKey = mesh->sortKey; // unpack sort key - shader = &r_shaders[(sortKey>>18) & (MAX_SHADERS - 1)]; - entity = &r_entities[(sortKey >> 8) & MAX_ENTITIES-1]; + shader = &r_shaders[(sortKey>>20) & (MAX_SHADERS - 1)]; + entity = &r_entities[(sortKey>>8) & MAX_ENTITIES-1]; infoKey = sortKey & 255; Com_Assert( shader == NULL ); @@ -1805,19 +1881,19 @@ void RB_DrawStretchPic( float x, float y, float w, float h, float sl, float tl, RB_CheckMeshOverflow( 6, 4 ); GL_Begin( GL_QUADS ); - GL_Color4fv( gl_state.draw_color ); + GL_Color4ubv( gl_state.draw_color ); GL_TexCoord2f( sl, tl ); GL_Vertex2f( x, y ); - GL_Color4fv( gl_state.draw_color ); + GL_Color4ubv( gl_state.draw_color ); GL_TexCoord2f( sh, tl ); GL_Vertex2f( x + w, y ); - GL_Color4fv( gl_state.draw_color ); + GL_Color4ubv( gl_state.draw_color ); GL_TexCoord2f( sh, th ); GL_Vertex2f( x + w, y + h ); - GL_Color4fv( gl_state.draw_color ); + GL_Color4ubv( gl_state.draw_color ); GL_TexCoord2f( sl, th ); GL_Vertex2f( x, y + h ); GL_End(); @@ -1858,6 +1934,8 @@ void RB_ShutdownBackend( void ) { int i; + if( !glw_state.initialized ) return; + // disable arrays if( GL_Support( R_ARB_MULTITEXTURE )) { diff --git a/render/r_draw.c b/render/r_draw.c index 91be8557..67f76f8a 100644 --- a/render/r_draw.c +++ b/render/r_draw.c @@ -7,7 +7,7 @@ /* ================= -R_GetPicSize +R_DrawGetParms this is needed by some client drawing functions ================= @@ -147,7 +147,9 @@ void R_DrawStretchRaw( int x, int y, int w, int h, int rawWidth, int rawHeight, GL_BindTexture( r_rawTexture ); if( rawWidth == r_rawTexture->width && rawHeight == r_rawTexture->height ) + { pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, rawWidth, rawHeight, GL_RGBA, GL_UNSIGNED_BYTE, raw ); + } else { r_rawTexture->width = rawWidth; @@ -172,7 +174,7 @@ void R_DrawStretchRaw( int x, int y, int w, int h, int rawWidth, int rawHeight, pglEnable( GL_TEXTURE_2D ); // draw it - pglColor4fv( gl_state.draw_color ); + pglColor4ubv( gl_state.draw_color ); pglBegin( GL_QUADS ); pglTexCoord2f( 0, 0 ); @@ -244,7 +246,7 @@ void R_DrawScreenRect( float x, float y, float w, float h ) // draw it pglBindTexture( gl_config.texRectangle, gl_state.screenTexture ); - pglColor4fv( gl_state.draw_color ); + pglColor4ubv( gl_state.draw_color ); pglBegin( GL_QUADS ); pglTexCoord2f( 0, h ); @@ -271,9 +273,9 @@ fills a box of pixels with a single color void R_DrawFill( float x, float y, float w, float h ) { pglDisable( GL_TEXTURE_2D ); - pglColor4fv( gl_state.draw_color ); + pglColor4ubv( gl_state.draw_color ); GL_Enable( GL_BLEND ); - if(gl_state.draw_color[3] != 1.0f ) + if( gl_state.draw_color[3] != 255 ) GL_BlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); else GL_BlendFunc( GL_ONE, GL_ZERO ); diff --git a/render/r_fragment.c b/render/r_fragment.c index 33eb808b..bbf211d0 100644 --- a/render/r_fragment.c +++ b/render/r_fragment.c @@ -271,7 +271,7 @@ R_ImpactMark temporary marks will be inmediately passed to the renderer ================= */ -void R_ImpactMark( vec3_t org, vec3_t dir, float rot, float radius, vec4_t rgba, bool fade, shader_t shader, bool temp ) +void R_ImpactMark( vec3_t org, vec3_t dir, float rot, float radius, rgba_t rgba, bool fade, shader_t shader, bool temp ) { int i, j; vec3_t delta; diff --git a/render/r_image.c b/render/r_image.c index 425ee7b5..41c0eae0 100644 --- a/render/r_image.c +++ b/render/r_image.c @@ -2877,7 +2877,7 @@ void RB_ShowTextures( void ) { texture_t *image; float x, y, w, h; - int i, j; + int i, j, base_w, base_h; if( !gl_state.orthogonal ) { @@ -2887,31 +2887,32 @@ void RB_ShowTextures( void ) pglClear( GL_COLOR_BUFFER_BIT ); pglFinish(); pglEnable( GL_TEXTURE_2D ); - + + if( r_showtextures->integer == 1 ) + { + base_w = 32; + base_h = 24; + } + else + { + base_w = 16; + base_h = 12; + } + for( i = j = 0, image = r_textures; i < r_numTextures; i++, image++ ) { if( !image->texnum ) continue; // FIXME: make cases for system, 2d, bsp, sprite and model textures - if( r_showtextures->integer == 1 && image->flags & TF_STATIC ) continue; if( r_showtextures->integer == 2 && !(image->flags & TF_STATIC )) continue; - if( r_showtextures->integer == 3 && !(image->flags & TF_LIGHTMAP )) - continue; - w = r_width->integer / 10; - h = r_height->integer / 8; - x = j % 10 * w; - y = j / 10 * h; - - // show in proportional size in mode 2 - /*if( r_showtextures->integer == 2 ) - { - w *= image->width / 512.0f; - h *= image->height / 512.0f; - }*/ + w = r_width->integer / base_w; + h = r_height->integer / base_h; + x = j % base_w * w; + y = j / base_w * h; pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_BindTexture( image ); @@ -3119,6 +3120,8 @@ void R_ShutdownTextures( void ) int i; texture_t *image; + if( !glw_state.initialized ) return; + for( i = MAX_TEXTURE_UNITS - 1; i >= 0; i-- ) { if( GL_Support( R_FRAGMENT_PROGRAM_EXT )) diff --git a/render/r_light.c b/render/r_light.c index b9a08b78..9633b92f 100644 --- a/render/r_light.c +++ b/render/r_light.c @@ -13,7 +13,7 @@ R_LightNormalizeColor ================= */ -void R_LightNormalizeColor( vec3_t in, vec4_t out ) +void R_LightNormalizeColor( vec3_t in, rgba_t out ) { float max; @@ -29,9 +29,9 @@ void R_LightNormalizeColor( vec3_t in, vec4_t out ) // rescale all the color components if the intensity of the greatest // channel exceeds 1.0 - if( max > 255.0f ) + if( max > 1.0f ) { - max = (1.0f / max); + max = 255 * (1.0f / max); out[0] = in[0] * max; out[1] = in[1] * max; @@ -39,11 +39,11 @@ void R_LightNormalizeColor( vec3_t in, vec4_t out ) } else { - out[0] = in[0] / 255; - out[1] = in[1] / 255; - out[2] = in[2] / 255; + out[0] = in[0] * 255; + out[1] = in[1] * 255; + out[2] = in[2] * 255; } - out[3] = 1.0f; + out[3] = 255; } /* @@ -269,7 +269,7 @@ void R_LightForPoint( const vec3_t point, vec3_t ambientLight ) if( !dist || dist > dl->intensity ) continue; - add = (dl->intensity - dist); + add = (dl->intensity - dist) * (1.0/255); VectorMA( ambientLight, add, dl->color, ambientLight ); } } @@ -377,22 +377,23 @@ void R_LightingAmbient( void ) float add, dist, radius; int i, l; vec4_t ambientLight; + rgba_t color; // Set to full bright if no light data if( r_refdef.onlyClientDraw || !r_worldModel->lightData || !m_pCurrentEntity ) { for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = 1.0f; - ref.colorArray[i][1] = 1.0f; - ref.colorArray[i][2] = 1.0f; - ref.colorArray[i][3] = 1.0f; + ref.colorArray[i][0] = 255; + ref.colorArray[i][1] = 255; + ref.colorArray[i][2] = 255; + ref.colorArray[i][3] = 255; } return; } // Get lighting at this point - VectorSet( end, m_pCurrentEntity->origin[0], m_pCurrentEntity->origin[1], m_pCurrentEntity->origin[2] - MAX_WORLD_COORD ); + VectorSet( end, m_pCurrentEntity->origin[0], m_pCurrentEntity->origin[1], m_pCurrentEntity->origin[2] - WORLD_SIZE ); VectorSet( r_pointColor, 1, 1, 1 ); R_RecursiveLightPoint( r_worldModel->nodes, m_pCurrentEntity->origin, end ); @@ -429,14 +430,11 @@ void R_LightingAmbient( void ) } // normalize - R_LightNormalizeColor( ambientLight, ambientLight ); + R_LightNormalizeColor( ambientLight, color ); for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = ambientLight[0]; - ref.colorArray[i][1] = ambientLight[1]; - ref.colorArray[i][2] = ambientLight[2]; - ref.colorArray[i][3] = 1.0f; + Vector4Copy( ambientLight, ref.colorArray[i] ); } } @@ -458,10 +456,10 @@ void R_LightingDiffuse( void ) { for( i = 0; i < ref.numVertex; i++ ) { - ref.colorArray[i][0] = 1.0f; - ref.colorArray[i][1] = 1.0f; - ref.colorArray[i][2] = 1.0f; - ref.colorArray[i][3] = 1.0f; + ref.colorArray[i][0] = 255; + ref.colorArray[i][1] = 255; + ref.colorArray[i][2] = 255; + ref.colorArray[i][3] = 255; } return; } diff --git a/render/r_local.h b/render/r_local.h index 05c1f472..d7692c01 100644 --- a/render/r_local.h +++ b/render/r_local.h @@ -21,11 +21,13 @@ extern render_imp_t ri; extern byte *r_temppool; #define Host_Error com.error +typedef uint elem_t; + // limits #define MAX_TEXTURE_UNITS 8 #define MAX_LIGHTMAPS 128 #define MAX_PROGRAMS 512 -#define MAX_ENTITIES 1024 +#define MAX_ENTITIES 4096 #define MAX_VERTEX_BUFFERS 2048 #define MAX_POLYS 4096 #define MAX_POLY_VERTS 16384 @@ -172,7 +174,7 @@ BRUSH MODELS #define SURF_LAVACAUSTICS 8 #define CONTENTS_NODE -1 -#define SKY_SIZE 8 +#define SKY_SIZE 16 #define SKY_INDICES (SKY_SIZE * SKY_SIZE * 6) #define SKY_VERTICES ((SKY_SIZE+1) * (SKY_SIZE+1)) @@ -201,7 +203,7 @@ typedef struct particle_s float radius; float length; float rotation; - vec4_t modulate; + rgba_t modulate; } particle_t; typedef struct @@ -209,7 +211,7 @@ typedef struct vec3_t xyz; vec2_t st; vec2_t lm; - vec4_t color; + rgba_t color; } surfPolyVert_t; typedef struct surfPoly_s @@ -484,6 +486,9 @@ typedef struct rmodel_s dstudiohdr_t *phdr; dstudiohdr_t *thdr; mstudiosurface_t *studiofaces; + int nummeshes; // num alloceed meshes + int numnorms; + int numverts; void *extradata; // model buffer @@ -546,8 +551,8 @@ typedef struct ref_entity_s // misc float backlerp; // 0.0 = current, 1.0 = old - vec3_t rendercolor; // hl1 rendercolor - float renderamt; // hl1 alphavalues + rgb_t rendercolor; // hl1 rendercolor + byte renderamt; // hl1 alphavalues int rendermode; // hl1 rendermode int renderfx; // server will be translate hl1 values into flags int colormap; // q1 and hl1 model colormap (can applied for sprites) @@ -562,6 +567,15 @@ typedef struct ref_entity_s float gaitframe; // client->frame + yaw float gaityaw; // local value + mstudiomesh_t *meshes; // studio meshes + vec3_t *points; // global arrays + vec3_t *normals; + vec2_t *chrome; + mstudiomesh_t *weaponmeshes; // studio meshes + vec3_t *weaponpoints; // global arrays + vec3_t *weaponnormals; + vec2_t *weaponchrome; + // shader information ref_shader_t *shader; float shaderTime; // subtracted from refdef time to control effect start times @@ -579,6 +593,7 @@ bool R_StudioComputeBBox( vec3_t bbox[8] ); // for drawing bounds void R_StudioResetSequenceInfo( ref_entity_t *ent, dstudiohdr_t *hdr ); float R_StudioFrameAdvance( ref_entity_t *ent, float flInterval ); void R_StudioSetupModel( int body, int bodypart ); +void R_StudioClearMeshes( void ); void R_InitModels( void ); void R_ShutdownModels( void ); rmodel_t *Mod_ForName( const char *name, bool crash ); @@ -598,7 +613,7 @@ DOOM1 STYLE AUTOMAP typedef struct radar_ent_s { - vec4_t color; + rgba_t color; vec3_t origin; vec3_t angles; } radar_ent_t; @@ -657,7 +672,6 @@ void RB_CheckForErrors( const char *filename, const int fileline ); void R_EndFrame( void ); bool R_Init_OpenGL( void ); void R_Free_OpenGL( void ); - #define R_CheckForErrors() RB_CheckForErrors( __FILE__, __LINE__ ) /* @@ -682,7 +696,7 @@ typedef enum typedef struct { - uint sortKey; + qword sortKey; meshType_t meshType; void *mesh; } mesh_t; @@ -792,7 +806,7 @@ bool R_CullSphere( const vec3_t origin, float radius, int clipFlags ); void R_RotateForEntity( ref_entity_t *entity ); void R_AddMeshToList( meshType_t meshType, void *mesh, ref_shader_t *shader, ref_entity_t *entity, int infoKey ); bool R_AddPolyToScene( shader_t shader, int numVerts, const polyVert_t *verts ); -void R_ImpactMark( vec3_t org, vec3_t dir, float rot, float radius, vec4_t rgba, bool fade, shader_t shader, bool temp ); +void R_ImpactMark( vec3_t org, vec3_t dir, float rot, float radius, rgba_t rgba, bool fade, shader_t shader, bool temp ); void R_DrawSprite( void ); void R_DrawBeam( void ); void R_DrawParticle( void ); @@ -848,6 +862,7 @@ extern cvar_t *r_lockpvs; extern cvar_t *r_frontbuffer; extern cvar_t *r_showcluster; extern cvar_t *r_showtris; +extern cvar_t *r_allow_software; extern cvar_t *r_shownormals; extern cvar_t *r_showtextures; extern cvar_t *r_showtangentspace; @@ -864,6 +879,9 @@ extern cvar_t *r_skipbackend; extern cvar_t *r_skipfrontend; extern cvar_t *r_swapInterval; extern cvar_t *r_mode; +extern cvar_t *r_stencilbits; +extern cvar_t *r_colorbits; +extern cvar_t *r_depthbits; extern cvar_t *r_testmode; extern cvar_t *r_fullscreen; extern cvar_t *r_caustics; diff --git a/render/r_main.c b/render/r_main.c index b79ff44d..656c36ab 100644 --- a/render/r_main.c +++ b/render/r_main.c @@ -67,6 +67,7 @@ cvar_t *r_lockpvs; cvar_t *r_frontbuffer; cvar_t *r_showcluster; cvar_t *r_showtris; +cvar_t *r_allow_software; cvar_t *r_shownormals; cvar_t *r_showtangentspace; cvar_t *r_showmodelbounds; @@ -83,6 +84,9 @@ cvar_t *r_skipfrontend; cvar_t *r_swapInterval; cvar_t *r_vertexbuffers; cvar_t *r_mode; +cvar_t *r_stencilbits; +cvar_t *r_colorbits; +cvar_t *r_depthbits; cvar_t *r_testmode; cvar_t *r_fullscreen; cvar_t *r_caustics; @@ -330,7 +334,6 @@ static void R_AddEntitiesToList( void ) switch( model->type ) { - case mod_world: case mod_brush: R_AddBrushModelToList( entity ); break; @@ -616,10 +619,10 @@ R_QSortMeshes static void R_QSortMeshes( mesh_t *meshes, int numMeshes ) { static mesh_t tmp; - static int stack[4096]; + static int64 stack[4096]; int depth = 0; - int L, R, l, r, median; - uint pivot; + int64 L, R, l, r, median; + qword pivot; if( !numMeshes ) return; @@ -709,6 +712,17 @@ static void R_ISortMeshes( mesh_t *meshes, int numMeshes ) } } +void R_ClearMeshes( void ) +{ + int i; + + for( i = 0; i < r_numEntities; i++ ) + { + m_pCurrentEntity = &r_entities[i]; + R_StudioClearMeshes(); + } +} + /* ================= R_AddMeshToList @@ -734,7 +748,7 @@ void R_AddMeshToList( meshType_t meshType, void *mesh, ref_shader_t *shader, ref m = &r_transMeshes[r_numTransMeshes++]; } - m->sortKey = (shader->sort<<28) | (shader->shadernum<<18) | ((entity - r_entities)<<8) | (infoKey); + m->sortKey = (shader->sort<<36) | (shader->shadernum<<20) | ((entity - r_entities)<<8) | (infoKey); m->meshType = meshType; m->mesh = mesh; } @@ -908,6 +922,8 @@ void R_RenderView( const ref_params_t *fd ) R_DrawNullModels(); RB_DebugGraphics(); + R_ClearMeshes(); + R_BloomBlend( fd ); } @@ -1044,20 +1060,20 @@ static bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type, float lerpfrac refent->index = pRefEntity->serialnumber; refent->ent_type = ed_type; refent->backlerp = 1.0f - lerpfrac; - refent->renderamt = pRefEntity->v.renderamt / 255.0f; + refent->renderamt = pRefEntity->v.renderamt; refent->rendermode = pRefEntity->v.rendermode; refent->body = pRefEntity->v.body; refent->scale = pRefEntity->v.scale; refent->colormap = pRefEntity->v.colormap; refent->effects = pRefEntity->v.effects; if( VectorIsNull( pRefEntity->v.rendercolor )) - VectorSet( refent->rendercolor, 1.0f, 1.0f, 1.0f ); - else VectorDivide( pRefEntity->v.rendercolor, 255.0f, refent->rendercolor ); + VectorSet( refent->rendercolor, 255, 255, 255 ); + else VectorCopy( pRefEntity->v.rendercolor, refent->rendercolor ); refent->model = cl_models[pRefEntity->v.modelindex]; refent->movetype = pRefEntity->v.movetype; refent->framerate = pRefEntity->v.framerate; refent->prev.sequencetime = refent->animtime - refent->prev.animtime; - + // check model if( !refent->model ) return false; switch( refent->model->type ) @@ -1152,6 +1168,9 @@ static bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type, float lerpfrac Matrix3x3_FromAngles( refent->angles, refent->matrix ); + if(( refent->ent_type == ED_VIEWMODEL ) && ( r_lefthand->integer == 1 )) + VectorNegate( refent->matrix[1], refent->matrix[1] ); + // copy controllers for( i = 0; i < MAXSTUDIOCONTROLLERS; i++ ) { @@ -1220,7 +1239,7 @@ static bool R_AddDynamicLight( vec3_t org, vec3_t color, float intensity ) R_AddParticleToScene ================= */ -bool R_AddParticleToScene( shader_t shader, const vec3_t org1, const vec3_t org2, float radius, float length, float rotate, int color ) +bool R_AddParticleToScene( shader_t shader, const vec3_t org1, const vec3_t org2, float radius, float length, float rotate, rgba_t color ) { particle_t *p; @@ -1238,7 +1257,7 @@ bool R_AddParticleToScene( shader_t shader, const vec3_t org1, const vec3_t org2 p->radius = radius; p->length = length; p->rotation = rotate; - Vector4Copy( UnpackRGBA( color ), p->modulate ); + Vector4Copy( color, p->modulate ); r_numParticles++; return true; diff --git a/render/r_model.c b/render/r_model.c index 19c7c521..ba793334 100644 --- a/render/r_model.c +++ b/render/r_model.c @@ -1357,8 +1357,8 @@ void R_InitModels( void ) r_worldEntity->ent_type = ED_NORMAL; r_worldEntity->model = r_worldModel; Matrix3x3_LoadIdentity( r_worldEntity->matrix ); - VectorSet( r_worldEntity->rendercolor, 1.0f, 1.0f, 1.0f ); - r_worldEntity->renderamt = 1.0f; // i'm hope we don't want to see semisolid world :) + VectorSet( r_worldEntity->rendercolor, 255, 255, 255 ); + r_worldEntity->renderamt = 255; // i'm hope we don't want to see semisolid world :) R_StudioInit(); } diff --git a/render/r_model.h b/render/r_model.h index 5c229f0d..e7975a64 100644 --- a/render/r_model.h +++ b/render/r_model.h @@ -20,7 +20,7 @@ typedef struct { vec3_t point; vec2_t st; - vec4_t color; + rgba_t color; } mstudiopoint_t; typedef struct mstudiosurface_s @@ -36,9 +36,14 @@ typedef struct mstudiosurface_s typedef struct mstudiomesh_s { - mstudiosurface_t *surfaces; - int numSurfaces; - ref_shader_t *shader; + float s; + float t; + int flags; // alternative texcoords, etc + vec3_t *verts; // pointer to globals vertices array + vec2_t *chrome; // pointer to global chrome coords array + short *tricmds; // triangle commands + int numVerts; // to avoid overflow + int numTris; } mstudiomesh_t; #endif//R_MODEL_H \ No newline at end of file diff --git a/render/r_opengl.c b/render/r_opengl.c index 469f6a63..7e185a4b 100644 --- a/render/r_opengl.c +++ b/render/r_opengl.c @@ -7,8 +7,10 @@ glwstate_t glw_state; +#define MAX_PFDS 256 #define num_vidmodes ((int)(sizeof(vidmode) / sizeof(vidmode[0])) - 1) #define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE) +#define GL_DRIVER_OPENGL "OpenGL32" typedef enum { @@ -57,7 +59,7 @@ static dllfunc_t wgl_funcs[] = { {"wglChoosePixelFormat", (void **) &pwglChoosePixelFormat}, {"wglDescribePixelFormat", (void **) &pwglDescribePixelFormat}, - {"wglGetPixelFormat", (void **) &pwglGetPixelFormat}, +// {"wglGetPixelFormat", (void **) &pwglGetPixelFormat}, {"wglSetPixelFormat", (void **) &pwglSetPixelFormat}, {"wglSwapBuffers", (void **) &pwglSwapBuffers}, {"wglCreateContext", (void **) &pwglCreateContext}, @@ -86,63 +88,234 @@ bool R_DeleteContext( void ) return false; } +/* +================= +R_ChoosePFD +================= +*/ +static int R_ChoosePFD( int colorBits, int depthBits, int stencilBits ) +{ + PIXELFORMATDESCRIPTOR PFDs[MAX_PFDS], *current, *selected; + int i, numPFDs, pixelFormat = 0; + uint flags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER; + + MsgDev( D_NOTE, "R_ChoosePFD( %i, %i, %i )\n", colorBits, depthBits, stencilBits); + + // Count PFDs + if( glw_state.minidriver ) + numPFDs = pwglDescribePixelFormat( glw_state.hDC, 0, 0, NULL ); + else numPFDs = DescribePixelFormat( glw_state.hDC, 0, 0, NULL ); + + if( numPFDs > MAX_PFDS ) + { + MsgDev( D_NOTE, "too many PFDs returned (%i > %i), reduce it\n", numPFDs, MAX_PFDS ); + numPFDs = MAX_PFDS; + } + else if( numPFDs < 1 ) + { + MsgDev( D_ERROR, "R_ChoosePFD failed\n" ); + return 0; + } + + MsgDev( D_NOTE, "R_ChoosePFD: %i PFDs found\n", numPFDs ); + + // run through all the PFDs, looking for the best match + for( i = 1, current = PFDs; i <= numPFDs; i++, current++ ) + { + if( glw_state.minidriver ) + pwglDescribePixelFormat( glw_state.hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), current ); + else DescribePixelFormat( glw_state.hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), current ); + + // check acceleration + if(( current->dwFlags & PFD_GENERIC_FORMAT ) && !r_allow_software->integer ) + { + MsgDev( D_NOTE, "PFD %i rejected, software acceleration\n", i ); + continue; + } + + // check flags + if(( current->dwFlags & flags ) != flags ) + { + MsgDev( D_NOTE, "PFD %i rejected, improper flags (0x%x instead of 0x%x)\n", i, current->dwFlags, flags ); + continue; + } + + // Check pixel type + if( current->iPixelType != PFD_TYPE_RGBA ) + { + MsgDev( D_NOTE, "PFD %i rejected, not RGBA\n", i ); + continue; + } + + // check color bits + if( current->cColorBits < colorBits ) + { + MsgDev( D_NOTE, "PFD %i rejected, insufficient color bits (%i < %i)\n", i, current->cColorBits, colorBits ); + continue; + } + + // check depth bits + if( current->cDepthBits < depthBits ) + { + MsgDev( D_NOTE, "PFD %i rejected, insufficient depth bits (%i < %i)\n", i, current->cDepthBits, depthBits ); + continue; + } + + // check stencil bits + if( current->cStencilBits < stencilBits ) + { + MsgDev( D_NOTE, "PFD %i rejected, insufficient stencil bits (%i < %i)\n", i, current->cStencilBits, stencilBits ); + continue; + } + + // if we don't have a selected PFD yet, then use it + if( !pixelFormat ) + { + selected = current; + pixelFormat = i; + continue; + } + + if( colorBits != selected->cColorBits ) + { + if( colorBits == current->cColorBits || current->cColorBits > selected->cColorBits ) + { + selected = current; + pixelFormat = i; + continue; + } + } + + if( depthBits != selected->cDepthBits ) + { + if( depthBits == current->cDepthBits || current->cDepthBits > selected->cDepthBits ) + { + selected = current; + pixelFormat = i; + continue; + } + } + + if( stencilBits != selected->cStencilBits ) + { + if( stencilBits == current->cStencilBits || current->cStencilBits > selected->cStencilBits ) + { + selected = current; + pixelFormat = i; + continue; + } + } + } + + if( !pixelFormat ) + { + MsgDev( D_ERROR, "R_ChoosePFD: no hardware acceleration found\n" ); + return 0; + } + + if( selected->dwFlags & PFD_GENERIC_FORMAT ) + { + if( selected->dwFlags & PFD_GENERIC_ACCELERATED ) + { + MsgDev( D_NOTE, "R_ChoosePFD:: MCD acceleration found\n" ); + glw_state.software = false; + } + else + { + MsgDev( D_NOTE, "R_ChoosePFD: using software emulation\n" ); + glw_state.software = true; + } + } + else + { + MsgDev( D_NOTE, "using hardware acceleration\n"); + glw_state.software = false; + } + MsgDev( D_LOAD, "R_ChoosePFD: PIXELFORMAT %i selected\n", pixelFormat ); + + return pixelFormat; +} + bool R_SetPixelformat( void ) { - long flags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_GENERIC_ACCELERATED|PFD_DOUBLEBUFFER; - int pixelformat; + PIXELFORMATDESCRIPTOR PFD; + int colorBits, depthBits, stencilBits; + int pixelFormat; size_t gamma_size; byte *savedGamma; - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR),// size of this pfd - 1, // version number - flags, // support window|OpenGL|generic accel|double buffer - PFD_TYPE_RGBA, // RGBA type - 32, // 32-bit color depth - 0, 0, 0, 0, 0, 0, // color bits ignored - 0, 0, // no alpha buffer - 0, // no accumulation buffer - 0, 0, 0, 0, // accum bits ignored - 24, // 24-bit z-buffer - 8, // 8-bit stencil buffer - 0, // no auxiliary buffer - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0 // layer masks ignored - }; - Sys_LoadLibrary( &opengl_dll ); // load opengl32.dll if( !opengl_dll.link ) return false; - if(( glw_state.hDC = GetDC( glw_state.hWnd )) == NULL ) - return false; + glw_state.minidriver = false; // FIXME - glw_state.minidriver = false; if( glw_state.minidriver ) { - if(!(pixelformat = pwglChoosePixelFormat( glw_state.hDC, &pfd))) + if(( glw_state.hDC = pwglGetCurrentDC()) == NULL ) return false; - if(!(pwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd))) - return false; - pwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); } else { - if(!( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd ))) + if(( glw_state.hDC = GetDC( glw_state.hWnd )) == NULL ) return false; - if(!(SetPixelFormat( glw_state.hDC, pixelformat, &pfd ))) - return false; - DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); } + // set color/depth/stencil + colorBits = (r_colorbits->integer) ? r_colorbits->integer : 32; + depthBits = (r_depthbits->integer) ? r_depthbits->integer : 24; + stencilBits = (r_stencilbits->integer) ? r_stencilbits->integer : 0; + + // choose a pixel format + pixelFormat = R_ChoosePFD( colorBits, depthBits, stencilBits ); + if( !pixelFormat ) + { + // try again with default color/depth/stencil + if( colorBits > 16 || depthBits > 16 || stencilBits > 0 ) + pixelFormat = R_ChoosePFD( 16, 16, 0 ); + else pixelFormat = R_ChoosePFD( 32, 24, 0 ); + + if( !pixelFormat ) + { + MsgDev( D_ERROR, "R_SetPixelformat: failed to find an appropriate PIXELFORMAT\n" ); + ReleaseDC( glw_state.hWnd, glw_state.hDC ); + glw_state.hDC = NULL; + return false; + } + } + + // set the pixel format + if( glw_state.minidriver ) + { + pwglDescribePixelFormat( glw_state.hDC, pixelFormat, sizeof( PIXELFORMATDESCRIPTOR ), &PFD ); + + if( !pwglSetPixelFormat( glw_state.hDC, pixelFormat, &PFD )) + { + MsgDev( D_ERROR, "R_SetPixelformat: wglSetPixelFormat failed\n" ); + return R_DeleteContext(); + } + } + else + { + DescribePixelFormat( glw_state.hDC, pixelFormat, sizeof( PIXELFORMATDESCRIPTOR ), &PFD ); + + if( !SetPixelFormat( glw_state.hDC, pixelFormat, &PFD )) + { + MsgDev( D_ERROR, "R_SetPixelformat: failed\n" ); + return R_DeleteContext(); + } + } + + gl_config.color_bits = PFD.cColorBits; + gl_config.depth_bits = PFD.cDepthBits; + gl_config.stencil_bits = PFD.cStencilBits; + if(!(glw_state.hGLRC = pwglCreateContext( glw_state.hDC ))) return R_DeleteContext(); if(!(pwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ))) return R_DeleteContext(); // print out PFD specifics - MsgDev(D_NOTE, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int )pfd.cColorBits, ( int )pfd.cDepthBits ); + MsgDev( D_NOTE, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int )PFD.cColorBits, ( int )PFD.cDepthBits ); // init gamma ramp ZeroMemory( gl_state.stateRamp, sizeof(gl_state.stateRamp)); @@ -241,6 +414,7 @@ void R_Free_OpenGL( void ) // now all extensions are disabled Mem_Set( gl_config.extension, 0, sizeof( gl_config.extension[0] ) * R_EXTCOUNT ); + glw_state.initialized = false; } void R_SaveVideoMode( int vid_mode ) @@ -320,6 +494,11 @@ bool R_CreateWindow( int width, int height, bool fullscreen ) // init all the gl stuff for the window if( !R_SetPixelformat( )) { + ShowWindow( glw_state.hWnd, SW_HIDE ); + DestroyWindow( glw_state.hWnd ); + glw_state.hWnd = NULL; + + UnregisterClass( "Xash Window", glw_state.hInst ); MsgDev( D_ERROR, "OpenGL driver not installed\n" ); return false; } diff --git a/render/r_opengl.h b/render/r_opengl.h index c56e8083..91f1b32c 100644 --- a/render/r_opengl.h +++ b/render/r_opengl.h @@ -45,7 +45,8 @@ typedef uint GLhandleARB; #define GL_DEPTH_TEST 0x0B71 #define GL_CULL_FACE 0x0B44 - +#define GL_CW 0x0900 +#define GL_CCW 0x0901 #define GL_BLEND 0x0BE2 #define GL_ALPHA_TEST 0x0BC0 @@ -1057,6 +1058,8 @@ typedef struct HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library + bool software; // software emulation uses RB_RenderShader() + bool initialized; // OpenGL subsystem started bool minidriver; int developer; // engine developer level; diff --git a/render/r_program.c b/render/r_program.c index 5781aeb3..0705108b 100644 --- a/render/r_program.c +++ b/render/r_program.c @@ -219,6 +219,8 @@ void R_ShutdownPrograms( void ) program_t *program; int i; + if( !glw_state.initialized ) return; + for( i = 0; i < r_numPrograms; i++ ) { program = r_programs[i]; diff --git a/render/r_shader.c b/render/r_shader.c index 2c06e4ad..c20d31a2 100644 --- a/render/r_shader.c +++ b/render/r_shader.c @@ -3919,10 +3919,9 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui else if( shader->surfaceParm & SURF_ALPHA ) { shader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; - shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - shader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; shader->stages[0]->alphaFunc.func = GL_GREATER; shader->stages[0]->alphaFunc.ref = 0.666; + shader->surfaceParm |= SURF_NOLIGHTMAP; shader->sort = SORT_SEETHROUGH; } if( shader->surfaceParm & SURF_WARP ) @@ -3980,7 +3979,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui { shader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; shader->stages[0]->alphaFunc.func = GL_GREATER; - shader->stages[0]->alphaFunc.ref = 0.9; // FIXME + shader->stages[0]->alphaFunc.ref = 0.666; // FIXME shader->sort = SORT_SEETHROUGH; } shader->stages[0]->bundles[0]->numTextures++; diff --git a/render/r_shader.h b/render/r_shader.h index 5e75d31a..b236818e 100644 --- a/render/r_shader.h +++ b/render/r_shader.h @@ -24,8 +24,8 @@ #define SHADER_STUDIO 5 // studio skins #define SHADER_SPRITE 6 // sprite frames -#define MAX_SHADERS 1024 -#define SHADERS_HASH_SIZE 256 +#define MAX_SHADERS 4096 +#define SHADERS_HASH_SIZE 1024 #define MAX_EXPRESSION_OPS 4096 #define MAX_EXPRESSION_REGISTERS 4096 #define MAX_PROGRAM_PARMS 16 diff --git a/render/r_sprite.c b/render/r_sprite.c index 140321ad..901311d5 100644 --- a/render/r_sprite.c +++ b/render/r_sprite.c @@ -279,6 +279,49 @@ mspriteframe_t *R_GetSpriteFrame( ref_entity_t *ent ) return pspriteframe; } +void R_SpriteSetRenderMode( ref_shader_t *m_pFrameShader ) +{ + if( m_pFrameShader->stages[0]->renderMode != m_pCurrentEntity->rendermode ) + { + switch( m_pCurrentEntity->rendermode ) + { + case kRenderNormal: + m_pFrameShader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + break; + case kRenderTransColor: + m_pFrameShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pFrameShader->stages[0]->blendFunc.src = GL_SRC_COLOR; + m_pFrameShader->stages[0]->blendFunc.dst = GL_ZERO; + break; + case kRenderTransTexture: + m_pFrameShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pFrameShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pFrameShader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case kRenderGlow: + m_pFrameShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pFrameShader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; + m_pFrameShader->stages[0]->blendFunc.dst = GL_ONE; +// FIXME: write flareOcclusionTest +// m_pFrameShader->stages[0]->flags &= ~SHADERSTAGE_DEPTHFUNC; + m_pFrameShader->stages[0]->depthFunc.func = 0; + break; + case kRenderTransAlpha: + m_pFrameShader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; + m_pFrameShader->stages[0]->alphaFunc.func = GL_GREATER; + m_pFrameShader->stages[0]->alphaFunc.ref = 0.666; + m_pFrameShader->sort = SORT_SEETHROUGH; + break; + case kRenderTransAdd: + m_pFrameShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pFrameShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pFrameShader->stages[0]->blendFunc.dst = GL_ONE; + break; + } + m_pFrameShader->stages[0]->renderMode = m_pCurrentEntity->rendermode; + } +} + /* ================= R_AddSpriteModelToList @@ -296,10 +339,13 @@ void R_AddSpriteModelToList( ref_entity_t *entity ) return; // copy frame params + m_pCurrentEntity = entity; entity->radius = frame->radius; entity->rotation = 0; entity->shader = &r_shaders[frame->shader]; + R_SpriteSetRenderMode( entity->shader ); + // add it R_AddMeshToList( MESH_SPRITE, NULL, entity->shader, entity, 0 ); } @@ -314,7 +360,7 @@ void R_DrawSpriteModel( void ) mspriteframe_t *frame; msprite_t *psprite; vec3_t forward, right, up; - float angle, sr, cr; + float angle, sr, cr, alpha; vec3_t point; ref_entity_t *e; int i; @@ -363,52 +409,12 @@ void R_DrawSpriteModel( void ) break; } - // HACKHACK: manually set rendermode for sprites - if( m_pCurrentShader->stages[0]->renderMode != m_pCurrentEntity->rendermode ) - { - switch( m_pCurrentEntity->rendermode ) - { - case kRenderNormal: - m_pCurrentShader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); - break; - case kRenderTransColor: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_COLOR; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ZERO; - break; - case kRenderTransTexture: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - break; - case kRenderGlow: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; -// FIXME: write flareOcclusionTest -// m_pCurrentShader->stages[0]->flags &= ~SHADERSTAGE_DEPTHFUNC; - m_pCurrentShader->stages[0]->depthFunc.func = 0; - break; - case kRenderTransAlpha: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; - m_pCurrentShader->stages[0]->alphaFunc.func = GL_GREATER; - m_pCurrentShader->stages[0]->alphaFunc.ref = 0.666; - m_pCurrentShader->sort = SORT_SEETHROUGH; - break; - case kRenderTransAdd: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; - break; - } - m_pCurrentShader->stages[0]->renderMode = m_pCurrentEntity->rendermode; - } - if((m_pCurrentEntity->rendermode == kRenderGlow) || (m_pCurrentShader->surfaceParm & SURF_GLOW)) { float dist = VectorDistance( m_pCurrentEntity->origin, r_refdef.vieworg ); e->scale = bound( 1.0, dist * 0.005f, 10.0f ); - e->renderamt = bound( 0.0f, dist / 1000, 1.0f ); + alpha = bound( 0, dist / 1000, 1.0f ); + e->renderamt = 255 * alpha; } // draw it diff --git a/render/r_studio.c b/render/r_studio.c index 0ace4f1b..2d4c30b5 100644 --- a/render/r_studio.c +++ b/render/r_studio.c @@ -29,14 +29,13 @@ vec3_t m_pshadevector; // shadow vector // lighting stuff vec3_t *m_pxformverts; vec3_t *m_pxformnorms; +vec2_t *m_pxformchrome; vec3_t *m_pvlightvalues; +mstudiomesh_t *m_pxmesh; vec3_t m_blightvec [MAXSTUDIOBONES]; -vec3_t g_xformverts[MAXSTUDIOVERTS]; -vec3_t g_xformnorms[MAXSTUDIOVERTS]; vec3_t g_lightvalues[MAXSTUDIOVERTS]; // chrome stuff -float g_chrome[MAXSTUDIOVERTS][2]; // texture coords for surface normals int g_chromeage[MAXSTUDIOBONES]; // last time chrome vectors were updated vec3_t g_chromeup[MAXSTUDIOBONES]; // chrome vector "up" in bone reference frames vec3_t g_chromeright[MAXSTUDIOBONES]; // chrome vector "right" in bone reference frames @@ -45,6 +44,7 @@ int m_fDoInterp; int m_pStudioModelCount; int m_nTopColor; // palette substition for top and bottom of model int m_nBottomColor; +int m_iCurrentMesh; rmodel_t *m_pRenderModel; ref_entity_t *m_pCurrentEntity; dstudiomodel_t *m_pSubModel; @@ -215,6 +215,35 @@ dstudiohdr_t *R_StudioLoadHeader( rmodel_t *mod, const uint *buffer ) return (dstudiohdr_t *)buffer; } +void R_StudioSetupVertexes( void ) +{ + int i, j; + int numverts = 0; + int numnorms = 0; + int nummesh = 0; + + // set global pointers + m_pStudioHeader = m_pLoadModel->phdr; + m_pTextureHeader = m_pLoadModel->thdr; + + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) + { + m_pBodyPart = (dstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + i; + + for( j = 0; j < m_pBodyPart->nummodels; j++ ) + { + m_pSubModel = (dstudiomodel_t *)((byte *)m_pStudioHeader + m_pBodyPart->modelindex) + j; + numverts += m_pSubModel->numverts; + numnorms += m_pSubModel->numnorms; + nummesh += m_pSubModel->nummesh; + } + } + + m_pLoadModel->numnorms = numnorms; + m_pLoadModel->numverts = numverts; + m_pLoadModel->nummeshes = nummesh; +} + void R_StudioLoadModel( rmodel_t *mod, const void *buffer ) { dstudiohdr_t *phdr = R_StudioLoadHeader( mod, buffer ); @@ -240,6 +269,8 @@ void R_StudioLoadModel( rmodel_t *mod, const void *buffer ) R_StudioExtractBbox( phdr, 0, mod->mins, mod->maxs ); mod->registration_sequence = registration_sequence; + + R_StudioSetupVertexes(); } // extract bbox from animation @@ -779,11 +810,20 @@ void R_StudioSetUpTransform( void ) // don't rotate player model, only aim angles[PITCH] = 0; } + else if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + { + // stupid quake bug + if( r_lefthand->integer == 1 ) + angles[YAW] = -angles[YAW]; + } else if( m_pCurrentEntity->movetype != MOVETYPE_NONE ) { VectorCopy( m_pCurrentEntity->angles, angles ); } Matrix4x4_CreateFromEntity( m_protationmatrix, modelpos[0], modelpos[1], modelpos[2], angles[PITCH], angles[YAW], angles[ROLL], m_pCurrentEntity->scale ); + + if(( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) && ( r_lefthand->integer == 1 )) + VectorNegate( m_protationmatrix[1], m_protationmatrix[1] ); } @@ -1196,67 +1236,53 @@ void R_StudioCalcAttachments( void ) bool R_StudioComputeBBox( vec3_t bbox[8] ) { - vec3_t vectors[3]; - ref_entity_t *e = m_pCurrentEntity; - vec3_t mins, maxs, tmp, angles; - int i, seq = m_pCurrentEntity->sequence; + ref_entity_t *e = m_pCurrentEntity; + int i, seq = m_pCurrentEntity->sequence; + vec3_t mins, maxs, tmp; if(!R_ExtractBbox( seq, mins, maxs )) return false; // compute a full bounding box - for ( i = 0; i < 8; i++ ) + for( i = 0; i < 8; i++ ) { - if ( i & 1 ) tmp[0] = mins[0]; - else tmp[0] = maxs[0]; - if ( i & 2 ) tmp[1] = mins[1]; - else tmp[1] = maxs[1]; - if ( i & 4 ) tmp[2] = mins[2]; - else tmp[2] = maxs[2]; - VectorCopy( tmp, bbox[i] ); - } + tmp[0] = (i & 1) ? mins[0] : maxs[0]; + tmp[1] = (i & 2) ? mins[1] : maxs[1]; + tmp[2] = (i & 4) ? mins[2] : maxs[2]; - // rotate the bounding box - VectorScale( e->angles, -1, angles ); - AngleVectorsFLU( angles, vectors[0], vectors[1], vectors[2] ); - - for ( i = 0; i < 8; i++ ) - { - VectorCopy( bbox[i], tmp ); - bbox[i][0] = DotProduct( vectors[0], tmp ); - bbox[i][1] = DotProduct( vectors[1], tmp ); - bbox[i][2] = DotProduct( vectors[2], tmp ); - VectorAdd( e->origin, bbox[i], bbox[i] ); + // rotate and translate + Matrix3x3_Transform( e->matrix, tmp, bbox[i] ); + VectorAdd( bbox[i], e->origin, bbox[i] ); } return true; } -static bool R_StudioCheckBBox( void ) +static bool R_StudioCullModel( void ) { - int i, j; - vec3_t bbox[8]; - - int aggregatemask = ~0; + int i, j; + cplane_t *plane; + vec3_t bbox[8]; + int aggregatemask = ~0; if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) - return true; + return false; if(!R_StudioComputeBBox( bbox )) - return false; + return true; for ( i = 0; i < 8; i++ ) { int mask = 0; - for ( j = 0; j < 4; j++ ) + for( j = 0, plane = r_frustum; j < 4; j++, plane++ ) { - float dp = DotProduct( r_frustum[j].normal, bbox[i] ); - if ( ( dp - r_frustum[j].dist ) < 0 ) mask |= ( 1 << j ); + if( DotProduct( bbox[i], plane->normal ) - plane->dist < 0 ) + mask |= (1<stages[0]->renderMode != m_pCurrentEntity->rendermode ) + if( m_pSkinShader->stages[0]->renderMode != m_pCurrentEntity->rendermode ) { switch( m_pCurrentEntity->rendermode ) { case kRenderNormal: - m_pCurrentShader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + m_pSkinShader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); break; case kRenderTransColor: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_COLOR; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ZERO; + m_pSkinShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pSkinShader->stages[0]->blendFunc.src = GL_SRC_COLOR; + m_pSkinShader->stages[0]->blendFunc.dst = GL_ZERO; break; case kRenderTransTexture: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + m_pSkinShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pSkinShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pSkinShader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; break; case kRenderGlow: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; - m_pCurrentShader->stages[0]->flags &= ~SHADERSTAGE_DEPTHWRITE; + m_pSkinShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pSkinShader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; + m_pSkinShader->stages[0]->blendFunc.dst = GL_ONE; + m_pSkinShader->stages[0]->flags &= ~SHADERSTAGE_DEPTHWRITE; break; case kRenderTransAlpha: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; - m_pCurrentShader->stages[0]->alphaFunc.func = GL_GREATER; - m_pCurrentShader->stages[0]->alphaFunc.ref = 0.666; - m_pCurrentShader->sort = SORT_SEETHROUGH; + m_pSkinShader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; + m_pSkinShader->stages[0]->alphaFunc.func = GL_GREATER; + m_pSkinShader->stages[0]->alphaFunc.ref = 0.666; + m_pSkinShader->sort = SORT_SEETHROUGH; break; case kRenderTransAdd: - m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; + m_pSkinShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pSkinShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pSkinShader->stages[0]->blendFunc.dst = GL_ONE; break; } - m_pCurrentShader->stages[0]->renderMode = m_pCurrentEntity->rendermode; + m_pSkinShader->stages[0]->renderMode = m_pCurrentEntity->rendermode; } } void R_StudioDrawMeshes( dstudiotexture_t * ptexture, short *pskinref ) { int i, j; - float *av, *lv; + float *lv; float lv_tmp; vec3_t fbright = { 0.95f, 0.95f, 0.95f }; vec3_t irgoggles = { 0.95f, 0.0f, 0.0f }; // predefined lightcolor - int flags; + int flags, numverts; dstudiomesh_t *pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex); byte *pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex); vec3_t *pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); lv = (float *)m_pvlightvalues; - for (j = 0; j < m_pSubModel->nummesh; j++) + for( j = 0; j < m_pSubModel->nummesh; j++ ) { flags = ptexture[pskinref[pmesh[j].skinref]].flags; @@ -1434,57 +1460,42 @@ void R_StudioDrawMeshes( dstudiotexture_t * ptexture, short *pskinref ) // FIXME: move this check out of the inner loop if( flags & STUDIO_NF_CHROME ) - R_StudioSetupChrome( g_chrome[(float (*)[3])lv - m_pvlightvalues], *pnormbone, (float *)pstudionorms ); - VectorScale(m_plightcolor, lv_tmp, lv ); + R_StudioSetupChrome( m_pxformchrome[(float (*)[3])lv - m_pvlightvalues], *pnormbone, (float *)pstudionorms ); + VectorScale( m_plightcolor, lv_tmp, lv ); } } - + for( j = 0; j < m_pSubModel->nummesh; j++ ) { - float s, t; + ref_shader_t *pshader; + mstudiomesh_t *m_pMesh; short *ptricmds; - ref_shader_t *m_pSkinShader; + m_pMesh = m_pxmesh++; pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; - ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); - - flags = ptexture[pskinref[pmesh->skinref]].flags; - s = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].width; - t = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].height; - m_pSkinShader = &r_shaders[ptexture[pskinref[pmesh->skinref]].shader]; - - if( m_pCurrentShader != m_pSkinShader ) - RB_RenderMesh(); - - m_pCurrentShader = m_pSkinShader; - R_StudioSetRenderMode(); + m_pMesh->tricmds = ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + numverts = 0; + // calc vertexcount while( i = *(ptricmds++)) { - if( i < 0 ) - { - GL_Begin( GL_TRIANGLE_FAN ); - i = -i; - } - else - { - GL_Begin( GL_TRIANGLE_STRIP ); - } - - for( ; i > 0; i--, ptricmds += 4 ) - { - if( flags & STUDIO_NF_CHROME ) - GL_TexCoord2f( g_chrome[ptricmds[1]][0] * s, g_chrome[ptricmds[1]][1] * t ); - else GL_TexCoord2f( ptricmds[2] * s, ptricmds[3] * t ); - - lv = m_pvlightvalues[ptricmds[1]]; - - GL_Normal3fv( vec3_origin ); // FIXME: apply normals - av = m_pxformverts[ptricmds[0]]; // verts - GL_Vertex3f( av[0], av[1], av[2] ); - } - GL_End(); + if( i < 0 ) i = -i; + for( ; i > 0; i--, ptricmds += 4, numverts++ ); } + + m_pMesh->flags = ptexture[pskinref[pmesh->skinref]].flags; + m_pMesh->s = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].width; + m_pMesh->t = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].height; + pshader = &r_shaders[ptexture[pskinref[pmesh->skinref]].shader]; + m_pMesh->verts = m_pxformverts; + m_pMesh->chrome = m_pxformchrome; + m_pMesh->numTris = pmesh->numtris; + m_pMesh->numVerts = numverts; + + R_StudioSetRenderMode( pshader ); // merge rendermode if needs + + R_AddMeshToList( MESH_STUDIO, m_pMesh, pshader, m_pCurrentEntity, 0 ); + m_iCurrentMesh++; } } @@ -1518,19 +1529,15 @@ void R_StudioDrawPoints ( void ) Matrix4x4_Transform( m_pbonestransform[pnormbone[i]], pstudionorms[i], m_pxformnorms[i]); } - // hack the depth range to prevent view model from poking into walls - if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) pglDepthRange( 0.0, 0.3 ); - if(( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) && ( r_lefthand->value == 1.0F )) - VectorNegate( m_pCurrentEntity->matrix[1], m_pCurrentEntity->matrix[1] ); R_StudioDrawMeshes( ptexture, pskinref ); - // hack the depth range to prevent view model from poking into walls - if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) pglDepthRange( 0.0, 1.0 ); + // move pointers + m_pxformverts += m_pSubModel->numverts; + m_pxformchrome += m_pSubModel->numverts; } void R_StudioDrawBones( void ) { - dstudiobone_t *pbones = (dstudiobone_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); vec3_t point; int i; @@ -1749,6 +1756,8 @@ void R_StudioRenderModel( void ) { int i; + m_iCurrentMesh = 0; + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) { R_StudioSetupModel( m_pCurrentEntity->body, i ); @@ -1779,16 +1788,40 @@ void R_StudioRenderModel( void ) } } -void R_StudioSetupRender( void ) +void R_StudioSetupRender( rmodel_t *model, bool weaponmodel ) { // set global pointers - m_pRenderModel = m_pCurrentEntity->model; + m_pRenderModel = model; m_pStudioHeader = m_pRenderModel->phdr; m_pTextureHeader = m_pRenderModel->thdr; - // set intermediate vertex buffers - m_pxformverts = &g_xformverts[0]; - m_pxformnorms = &g_xformnorms[0]; + // allocate meshes + if( weaponmodel ) + { + m_pCurrentEntity->weaponmeshes = Mem_Alloc( r_temppool, sizeof( mstudiomesh_t ) * m_pRenderModel->nummeshes ); + m_pCurrentEntity->weaponpoints = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); + m_pCurrentEntity->weaponnormals = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numnorms ); + m_pCurrentEntity->weaponchrome = Mem_Alloc( r_temppool, sizeof( vec2_t ) * m_pRenderModel->numverts ); + + // set intermediate vertex buffers + m_pxmesh = m_pCurrentEntity->weaponmeshes; + m_pxformverts = m_pCurrentEntity->weaponpoints; + m_pxformnorms = m_pCurrentEntity->weaponnormals; + m_pxformchrome = m_pCurrentEntity->weaponchrome; + } + else + { + m_pCurrentEntity->meshes = Mem_Alloc( r_temppool, sizeof( mstudiomesh_t ) * m_pRenderModel->nummeshes ); + m_pCurrentEntity->points = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); + m_pCurrentEntity->normals = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numnorms ); + m_pCurrentEntity->chrome = Mem_Alloc( r_temppool, sizeof( vec2_t ) * m_pRenderModel->numverts ); + + // set intermediate vertex buffers + m_pxmesh = m_pCurrentEntity->meshes; + m_pxformverts = m_pCurrentEntity->points; + m_pxformnorms = m_pCurrentEntity->normals; + m_pxformchrome = m_pCurrentEntity->chrome; + } m_pvlightvalues = &g_lightvalues[0]; // misc info @@ -1812,13 +1845,13 @@ bool R_StudioDrawModel( int flags ) flags |= STUDIO_EVENTS; } - R_StudioSetupRender (); + R_StudioSetupRender( m_pCurrentEntity->model, false ); R_StudioSetUpTransform (); if( flags & STUDIO_RENDER ) { // see if the bounding box lets us trivially reject, also sets - if( !R_StudioCheckBBox( )) return 0; + if( R_StudioCullModel( )) return 0; m_pStudioModelCount++; // render data cache cookie @@ -1873,17 +1906,17 @@ bool R_StudioDrawModel( int flags ) // draw weaponmodel for monsters if( m_pCurrentEntity->weaponmodel ) { - ref_entity_t saveent = *m_pCurrentEntity; - rmodel_t *pweaponmodel = m_pCurrentEntity->weaponmodel; + ref_entity_t saveent; + + R_StudioSetupRender( m_pCurrentEntity->weaponmodel, true ); + saveent = *m_pCurrentEntity; // get remap colors m_nTopColor = m_pCurrentEntity->colormap & 0xFF; m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - m_pStudioHeader = pweaponmodel->phdr; - m_pTextureHeader = pweaponmodel->thdr; - R_StudioMergeBones( pweaponmodel ); + R_StudioMergeBones( m_pCurrentEntity->weaponmodel ); R_StudioSetupLighting( ); R_StudioRenderModel( ); @@ -2064,7 +2097,7 @@ int R_StudioDrawPlayer( int flags ) } pplayer = ri.GetClientEdict( m_pCurrentEntity->index ); - R_StudioSetupRender(); + R_StudioSetupRender( m_pCurrentEntity->model, false ); // MsgDev( D_INFO, "DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); // MsgDev( D_INFO, "DrawPlayer %d %d (%d)\n", r_framecount, pplayer->serialnumber, m_pCurrentEntity->sequence ); @@ -2101,8 +2134,7 @@ int R_StudioDrawPlayer( int flags ) if( flags & STUDIO_RENDER ) { // see if the bounding box lets us trivially reject, also sets - if(!R_StudioCheckBBox()) - return 0; + if( R_StudioCullModel()) return 0; m_pStudioModelCount++; // render data cache cookie @@ -2156,16 +2188,17 @@ int R_StudioDrawPlayer( int flags ) if( m_pCurrentEntity->weaponmodel ) { - ref_entity_t saveent = *m_pCurrentEntity; - rmodel_t *pweaponmodel = m_pCurrentEntity->weaponmodel; + ref_entity_t saveent; + + R_StudioSetupRender( m_pCurrentEntity->weaponmodel, true ); + saveent = *m_pCurrentEntity; + // get remap colors m_nTopColor = m_pCurrentEntity->colormap & 0xFF; m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); - m_pStudioHeader = pweaponmodel->phdr; - m_pTextureHeader = pweaponmodel->thdr; - R_StudioMergeBones( pweaponmodel ); + R_StudioMergeBones( m_pCurrentEntity->weaponmodel ); R_StudioSetupLighting( ); R_StudioRenderModel( ); @@ -2177,6 +2210,65 @@ int R_StudioDrawPlayer( int flags ) } void R_DrawStudioModel( void ) +{ + mstudiomesh_t *surf = m_pRenderMesh->mesh; + short *ptricmds = surf->tricmds; + float s, t, *av; + int i; + + s = surf->s; + t = surf->t; + + // draw it + RB_CheckMeshOverflow( surf->numTris * 3, surf->numVerts ); + + m_pxformverts = surf->verts; + m_pxformchrome = surf->chrome; + while( i = *(ptricmds++)) + { + if( i < 0 ) + { + GL_Begin( GL_TRIANGLE_FAN ); + i = -i; + } + else + { + GL_Begin( GL_TRIANGLE_STRIP ); + } + for( ; i > 0; i--, ptricmds += 4 ) + { + if( surf->flags & STUDIO_NF_CHROME ) + GL_TexCoord2f( m_pxformchrome[ptricmds[1]][0] * s, m_pxformchrome[ptricmds[1]][1] * t ); + else GL_TexCoord2f( ptricmds[2] * s, ptricmds[3] * t ); + + GL_Normal3fv( vec3_origin ); // FIXME: apply normals + av = m_pxformverts[ptricmds[0]]; + GL_Vertex3f( av[0], av[1], av[2] ); + } + GL_End(); + } + + // hack the depth range to prevent view model from poking into walls + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + { + if( r_lefthand->integer == 1 ) + pglFrontFace( GL_CW ); + pglDepthRange( 0.0, 0.3 ); + } + + // flush + RB_RenderMesh(); + + // hack the depth range to prevent view model from poking into walls + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + { + if( r_lefthand->integer == 1 ) + pglFrontFace( GL_CCW ); + pglDepthRange( 0, 1 ); + } +} + +void R_AddStudioModelToList( ref_entity_t *entity ) { if( m_pCurrentEntity->ent_type == ED_CLIENT ) R_StudioDrawPlayer( STUDIO_RENDER ); @@ -2185,12 +2277,26 @@ void R_DrawStudioModel( void ) R_StudioAddEntityToRadar( ); } -void R_AddStudioModelToList( ref_entity_t *entity ) +void R_StudioClearMeshes( void ) { - R_StudioSetupRender(); - if( !R_StudioCheckBBox( )) return; - if( !entity->shader ) return; + if( !m_pCurrentEntity ) return; - // add it - R_AddMeshToList( MESH_STUDIO, NULL, entity->shader, entity, 0 ); -} + // clear old studio mdl meshes + if( m_pCurrentEntity->meshes ) Mem_Free( m_pCurrentEntity->meshes ); + if( m_pCurrentEntity->points ) Mem_Free( m_pCurrentEntity->points ); + if( m_pCurrentEntity->normals ) Mem_Free( m_pCurrentEntity->normals ); + if( m_pCurrentEntity->chrome ) Mem_Free( m_pCurrentEntity->chrome ); + if( m_pCurrentEntity->weaponmeshes ) Mem_Free( m_pCurrentEntity->weaponmeshes ); + if( m_pCurrentEntity->weaponpoints ) Mem_Free( m_pCurrentEntity->weaponpoints ); + if( m_pCurrentEntity->weaponnormals ) Mem_Free( m_pCurrentEntity->weaponnormals ); + if( m_pCurrentEntity->weaponchrome ) Mem_Free( m_pCurrentEntity->weaponchrome ); + + m_pCurrentEntity->meshes = NULL; + m_pCurrentEntity->points = NULL; + m_pCurrentEntity->normals = NULL; + m_pCurrentEntity->chrome = NULL; + m_pCurrentEntity->weaponmeshes = NULL; + m_pCurrentEntity->weaponpoints = NULL; + m_pCurrentEntity->weaponnormals = NULL; + m_pCurrentEntity->weaponchrome = NULL; +} \ No newline at end of file diff --git a/render/r_studio.c.old b/render/r_studio.c.old new file mode 100644 index 00000000..2e3b24ea --- /dev/null +++ b/render/r_studio.c.old @@ -0,0 +1,2200 @@ +//======================================================================= +// Copyright XashXT Group 2007 © +// r_studio.c - render studio models +//======================================================================= + +#include "r_local.h" +#include "byteorder.h" +#include "mathlib.h" +#include "matrix_lib.h" +#include "const.h" + +/* +============================================================= + + STUDIO MODELS + +============================================================= +*/ + +#define STUDIO_API_VERSION 0.2 + +matrix4x4 m_pbonestransform [MAXSTUDIOBONES]; +matrix4x4 m_plighttransform [MAXSTUDIOBONES]; +matrix4x4 m_protationmatrix; +vec3_t m_plightcolor; // ambient light color +vec3_t m_plightvec; // ambleint light vector +vec3_t m_pshadevector; // shadow vector + +// lighting stuff +vec3_t *m_pxformverts; +vec3_t *m_pxformnorms; +vec3_t *m_pvlightvalues; +vec3_t m_blightvec [MAXSTUDIOBONES]; +vec3_t g_xformverts[MAXSTUDIOVERTS]; +vec3_t g_xformnorms[MAXSTUDIOVERTS]; +vec3_t g_lightvalues[MAXSTUDIOVERTS]; + +// chrome stuff +float g_chrome[MAXSTUDIOVERTS][2]; // texture coords for surface normals +int g_chromeage[MAXSTUDIOBONES]; // last time chrome vectors were updated +vec3_t g_chromeup[MAXSTUDIOBONES]; // chrome vector "up" in bone reference frames +vec3_t g_chromeright[MAXSTUDIOBONES]; // chrome vector "right" in bone reference frames + +int m_fDoInterp; +int m_pStudioModelCount; +int m_nTopColor; // palette substition for top and bottom of model +int m_nBottomColor; +rmodel_t *m_pRenderModel; +ref_entity_t *m_pCurrentEntity; +dstudiomodel_t *m_pSubModel; +dstudiohdr_t *m_pStudioHeader; +dstudiohdr_t *m_pTextureHeader; +dstudiobodyparts_t *m_pBodyPart; + +int m_nCachedBones; // number of bones in cache +char m_nCachedBoneNames[MAXSTUDIOBONES][32]; +matrix4x4 m_rgCachedBonesTransform [MAXSTUDIOBONES]; +matrix4x4 m_rgCachedLightTransform [MAXSTUDIOBONES]; + +// sprite model used for drawing studio model chrome +rmodel_t *m_pChromeSprite; + +// player gait sequence stuff +int m_fGaitEstimation; +float m_flGaitMovement; + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + m_pBodyPart = NULL; + m_pRenderModel = NULL; + m_pStudioHeader = NULL; + m_pCurrentEntity = NULL; + m_flGaitMovement = 1; +} + +void R_StudioShutdown( void ) +{ +} + +/* +==================== +MISC STUDIO UTILS +==================== +*/ +// extract texture filename from modelname +char *R_ExtName( rmodel_t *mod ) +{ + static string texname; + + com.strncpy( texname, mod->name, MAX_STRING ); + FS_StripExtension( texname ); + com.strncat( texname, "T.mdl", MAX_STRING ); + return texname; +} + +int R_StudioExtractBbox( dstudiohdr_t *phdr, int sequence, float *mins, float *maxs ) +{ + dstudioseqdesc_t *pseqdesc; + pseqdesc = (dstudioseqdesc_t *)((byte *)phdr + phdr->seqindex); + + if( sequence == -1 ) return 0; + + VectorCopy( pseqdesc[sequence].bbmin, mins ); + VectorCopy( pseqdesc[sequence].bbmax, maxs ); + + return 1; +} + +/* +================= +R_FindTriangleWithEdge +================= +*/ +static int R_FindTriangleWithEdge( int numtris, mstudiotriangle_t *triangles, uint start, uint end, int ignore ) +{ + mstudiotriangle_t *tri; + int i, count = 0; + int match = -1; + + for( i = 0, tri = triangles; i < numtris; i++, tri++ ) + { + if((tri->index[0] == start && tri->index[1] == end) || (tri->index[1] == start && tri->index[2] == end) || (tri->index[2] == start && tri->index[0] == end)) + { + if( i != ignore ) + match = i; + count++; + } + else if((tri->index[1] == start && tri->index[0] == end) || (tri->index[2] == start && tri->index[1] == end) || (tri->index[0] == start && tri->index[2] == end)) + count++; + } + + // detect edges shared by three triangles and make them seams + if( count > 2 ) match = -1; + + return match; +} + +/* +================= +R_StudioBuildNeighbors +================= +*/ +static void R_StudioBuildNeighbors( int numtris, mstudiotriangle_t *triangles, mstudioneighbor_t *neighbors ) +{ + mstudioneighbor_t *neighbor; + mstudiotriangle_t *tri; + int i; + + for( i = 0, tri = triangles, neighbor = neighbors; i < numtris; i++, tri++, neighbor++ ) + { + neighbor->index[0] = R_FindTriangleWithEdge( numtris, triangles, tri->index[1], tri->index[0], i ); + neighbor->index[1] = R_FindTriangleWithEdge( numtris, triangles, tri->index[2], tri->index[1], i ); + neighbor->index[2] = R_FindTriangleWithEdge( numtris, triangles, tri->index[0], tri->index[2], i ); + } +} + +/* +==================== +Studio model loader +==================== +*/ +uint R_StudioSurfaceParm( dstudiotexture_t *tex ) +{ + uint surfaceParm = 0; + + if( tex->flags & STUDIO_NF_TRANSPARENT ) + surfaceParm |= SURF_ALPHA; + else if( tex->flags & STUDIO_NF_ADDITIVE ) + surfaceParm |= SURF_ADDITIVE; + else if( tex->flags & STUDIO_NF_BLENDED ) + surfaceParm |= SURF_BLEND; + + return surfaceParm; +} + +dstudiohdr_t *R_StudioLoadHeader( rmodel_t *mod, const uint *buffer ) +{ + int i; + byte *pin; + dstudiohdr_t *phdr; + dstudiotexture_t *ptexture; + string shadername; + uint surfaceParm; + + pin = (byte *)buffer; + phdr = (dstudiohdr_t *)pin; + + if( phdr->version != STUDIO_VERSION ) + { + Msg("%s has wrong version number (%i should be %i)\n", phdr->name, phdr->version, STUDIO_VERSION); + return NULL; + } + + ptexture = (dstudiotexture_t *)(pin + phdr->textureindex); + if( phdr->textureindex > 0 && phdr->numtextures <= MAXSTUDIOSKINS ) + { + mod->numShaders = phdr->numtextures; + mod->shaders = Mem_Alloc( mod->mempool, sizeof( shader_t* ) * mod->numShaders ); + + for( i = 0; i < phdr->numtextures; i++ ) + { + surfaceParm = R_StudioSurfaceParm( &ptexture[i] ); + com.snprintf( shadername, MAX_STRING, "%s/%s", mod->name, ptexture[i].name ); + FS_StripExtension( shadername ); // doesn't produce shaders with .ext + ptexture[i].shader = R_FindShader( shadername, SHADER_STUDIO, surfaceParm )->shadernum; + mod->shaders[i] = &r_shaders[ptexture[i].shader]; + } + } + return (dstudiohdr_t *)buffer; +} + +void R_StudioLoadModel( rmodel_t *mod, const void *buffer ) +{ + dstudiohdr_t *phdr = R_StudioLoadHeader( mod, buffer ); + dstudiohdr_t *thdr; + void *texbuf; + + if( !phdr ) return; // there were problems + mod->phdr = (dstudiohdr_t *)Mem_Alloc(mod->mempool, LittleLong(phdr->length)); + Mem_Copy( mod->phdr, buffer, LittleLong( phdr->length )); + + if( phdr->numtextures == 0 ) + { + texbuf = FS_LoadFile( R_ExtName( mod ), NULL ); // use buffer again + if( texbuf ) thdr = R_StudioLoadHeader( mod, texbuf ); + else MsgDev( D_WARN, "textures for %s not found!\n", mod->name ); + + if( !thdr ) return; // there were problems + mod->thdr = (dstudiohdr_t *)Mem_Alloc( mod->mempool, LittleLong( thdr->length )); + Mem_Copy( mod->thdr, texbuf, LittleLong( thdr->length )); + if( texbuf ) Mem_Free( texbuf ); + } + else mod->thdr = mod->phdr; // just make link + + R_StudioExtractBbox( phdr, 0, mod->mins, mod->maxs ); + mod->registration_sequence = registration_sequence; +} + +// extract bbox from animation +int R_ExtractBbox( int sequence, float *mins, float *maxs ) +{ + return R_StudioExtractBbox( m_pStudioHeader, sequence, mins, maxs ); +} + +void SetBodygroup( int iGroup, int iValue ) +{ + int iCurrent; + dstudiobodyparts_t *m_pBodyPart; + + if( iGroup > m_pStudioHeader->numbodyparts ) + return; + + m_pBodyPart = (dstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + iGroup; + + if (iValue >= m_pBodyPart->nummodels) + return; + + iCurrent = (m_pCurrentEntity->body / m_pBodyPart->base) % m_pBodyPart->nummodels; + m_pCurrentEntity->body = (m_pCurrentEntity->body - (iCurrent * m_pBodyPart->base) + (iValue * m_pBodyPart->base)); +} + +int R_StudioGetBodygroup( int iGroup ) +{ + dstudiobodyparts_t *m_pBodyPart; + + if (iGroup > m_pStudioHeader->numbodyparts) + return 0; + + m_pBodyPart = (dstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + iGroup; + + if (m_pBodyPart->nummodels <= 1) + return 0; + + return (m_pCurrentEntity->body / m_pBodyPart->base) % m_pBodyPart->nummodels; +} + +void R_StudioAddEntityToRadar( void ) +{ + if( r_minimap->value < 2 ) return; + + if( numRadarEnts >= MAX_RADAR_ENTS ) return; + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) return; + + if( m_pCurrentEntity->ent_type == ED_MONSTER ) + { + Vector4Set(RadarEnts[numRadarEnts].color, 1.0f, 0.0f, 2.0f, 1.0f ); + } + else + { + Vector4Set(RadarEnts[numRadarEnts].color, 0.0f, 1.0f, 1.0f, 0.5f ); + } + VectorCopy( m_pCurrentEntity->origin, RadarEnts[numRadarEnts].origin ); + VectorCopy( m_pCurrentEntity->angles, RadarEnts[numRadarEnts].angles ); + numRadarEnts++; +} + +/* +==================== +R_StudioGetSequenceInfo + +used for client animation +==================== +*/ +float R_StudioSequenceDuration( dstudiohdr_t *hdr, ref_entity_t *ent ) +{ + dstudioseqdesc_t *pseqdesc; + + if( !hdr || ent->sequence >= hdr->numseq ) + return 0.0f; + + pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + ent->sequence; + return pseqdesc->numframes / pseqdesc->fps; +} + +int R_StudioGetSequenceFlags( dstudiohdr_t *hdr, ref_entity_t *ent ) +{ + dstudioseqdesc_t *pseqdesc; + + if( !hdr || ent->sequence >= hdr->numseq ) + return 0; + + pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + (int)ent->sequence; + return pseqdesc->flags; +} + +float R_StudioFrameAdvance( ref_entity_t *ent, float flInterval ) +{ + if( flInterval == 0.0 ) + { + flInterval = ( r_refdef.time - ent->animtime ); + if( flInterval <= 0.001 ) + { + ent->animtime = r_refdef.time; + return 0.0; + } + } + if( !ent->animtime ) flInterval = 0.0; + + ent->frame += flInterval * ent->framerate; + //ent->animtime = r_refdef.time; + + if( ent->frame < 0.0 || ent->frame >= 256.0 ) + { + if( ent->m_fSequenceLoops ) + ent->frame -= (int)(ent->frame / 256.0) * 256.0; + else ent->frame = (ent->frame < 0.0) ? 0 : 255; + ent->m_fSequenceFinished = true; + } + return flInterval; +} + +void R_StudioResetSequenceInfo( ref_entity_t *ent, dstudiohdr_t *hdr ) +{ + if( !ent || !hdr ) return; + + ent->m_fSequenceLoops = ((R_StudioGetSequenceFlags( hdr, ent ) & STUDIO_LOOPING) != 0 ); + + // calc anim time + if( !ent->animtime ) ent->animtime = r_refdef.time; + ent->prev.animtime = ent->animtime; + ent->animtime = r_refdef.time + R_StudioSequenceDuration( hdr, ent ); + ent->m_fSequenceFinished = FALSE; +} + +int R_StudioGetEvent( dstudioevent_t *pcurrent, float flStart, float flEnd, int index ) +{ + dstudioseqdesc_t *pseqdesc; + dstudioevent_t *pevent; + int events = 0; + + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->sequence; + pevent = (dstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex); + + if( pseqdesc->numevents == 0 || index > pseqdesc->numevents ) + return 0; + + if( pseqdesc->numframes == 1 ) + { + flStart = 0; + flEnd = 1.0; + } + + for( ; index < pseqdesc->numevents; index++ ) + { + // don't send server-side events to the client effects + if( pevent[index].event < EVENT_CLIENT ) + continue; + + if(( pevent[index].frame >= flStart && pevent[index].frame < flEnd ) + || ((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1 )) + { + Mem_Copy( pcurrent, &pevent[index], sizeof( *pcurrent )); + return index + 1; + } + } + return 0; +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +void R_StudioCalcBoneAdj( float dadt, float *adj, const float *pcontroller1, const float *pcontroller2, byte mouthopen ) +{ + int i, j; + float value; + dstudiobonecontroller_t *pbonecontroller; + + pbonecontroller = (dstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + + if( i == STUDIO_MOUTH ) + { + // mouth hardcoded at controller 4 + value = mouthopen / 64.0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Msg("%d %f\n", mouthopen, value ); + } + else if( i <= MAXSTUDIOCONTROLLERS ) + { + // check for 360% wrapping + if( pbonecontroller[j].type & STUDIO_RLOOP ) + { + if(abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + float a, b; + a = fmod((pcontroller1[j] + 128), 256 ); + b = fmod((pcontroller2[j] + 128), 256 ); + value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + // Msg("%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + + switch( pbonecontroller[j].type & STUDIO_TYPES ) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = value * (M_PI / 180.0); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + +/* +==================== +StudioCalcBoneQuaterion + +==================== +*/ +void R_StudioCalcBoneQuaterion( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *q ) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + dstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j+3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j+3]; // default; + } + else + { + panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + k = frame; + + // debug + if (panimvalue->num.total < panimvalue->num.valid) k = 0; + + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k+1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k+2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid+2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + } + + if (pbone->bonecontroller[j+3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j+3]]; + angle2[j] += adj[pbone->bonecontroller[j+3]]; + } + } + + if (!VectorCompare( angle1, angle2 )) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q ); + } + else + { + AngleQuaternion( angle1, q ); + } +} + +/* +==================== +StudioCalcBonePosition + +==================== +*/ +void R_StudioCalcBonePosition( int frame, float s, dstudiobone_t *pbone, dstudioanim_t *panim, float *adj, float *pos ) +{ + int j, k; + dstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + + //if (j == 0) Msg("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + k = frame; + + // debug + if (panimvalue->num.total < panimvalue->num.valid) k = 0; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if ( pbone->bonecontroller[j] != -1 && adj ) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* +==================== +StudioSlerpBones + +==================== +*/ +void R_StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) +{ + int i; + vec4_t q3; + float s1; + + if( s < 0 ) s = 0; + else if( s > 1.0 ) s = 1.0; + + s1 = 1.0 - s; + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* +==================== +StudioGetAnim + +==================== +*/ +dstudioanim_t *R_StudioGetAnim( rmodel_t *m_pSubModel, dstudioseqdesc_t *pseqdesc ) +{ + dstudioseqgroup_t *pseqgroup; + byte *paSequences; + size_t filesize; + byte *buf; + + pseqgroup = (dstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + if( pseqdesc->seqgroup == 0 ) + return (dstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); + paSequences = (void *)m_pSubModel->submodels; + + if( paSequences == NULL ) + { + MsgDev( D_INFO, "loading %s\n", pseqgroup->name ); + buf = FS_LoadFile (pseqgroup->name, &filesize); + if( !buf || !filesize ) + { + MsgDev( D_ERROR, "R_StudioGetAnim: %s not found", pseqgroup->name ); + Mem_Set( pseqgroup->name, 0, sizeof(pseqgroup->name)); + return NULL; + } + if( IDSEQGRPHEADER == LittleLong(*(uint *)buf)) //it's sequence group + { + byte *pin = (byte *)buf; + dstudioseqgroup_t *pseqhdr = (dstudioseqgroup_t *)pin; + + paSequences = (byte *)Mem_Alloc( m_pSubModel->mempool, filesize ); + m_pSubModel->submodels = (submodel_t *)paSequences; // just a container + Mem_Copy( &paSequences[pseqdesc->seqgroup], buf, filesize ); + Mem_Free( buf ); + } + } + return (dstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup] + pseqdesc->animindex ); +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +void R_StudioPlayerBlend( dstudioseqdesc_t *pseqdesc, float *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3); + + if( *pBlend < pseqdesc->blendstart[0] ) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0; + *pBlend = 0; + } + else if( *pBlend > pseqdesc->blendend[0] ) + { + *pPitch -= pseqdesc->blendend[0] / 3.0; + *pBlend = 255; + } + else + { + if( pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1f ) // catch qc error + *pBlend = 127; + else *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0; + } +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void R_StudioSetUpTransform( void ) +{ + int i; + vec3_t angles, modelpos; + + VectorCopy( m_pCurrentEntity->origin, modelpos ); + VectorCopy( m_pCurrentEntity->angles, angles ); + + // TODO: should really be stored with the entity instead of being reconstructed + // TODO: should use a look-up table + // TODO: could cache lazily, stored in the entity + if( m_pCurrentEntity->movetype == MOVETYPE_STEP ) + { + float d, f = 0; + + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + if(( r_refdef.time < m_pCurrentEntity->animtime + 1.0f ) && ( m_pCurrentEntity->animtime != m_pCurrentEntity->prev.animtime ) ) + { + f = (r_refdef.time - m_pCurrentEntity->animtime) / (m_pCurrentEntity->animtime - m_pCurrentEntity->prev.animtime); + Msg( "%4.2f %.2f %.2f\n", f, m_pCurrentEntity->animtime, r_refdef.time ); + } + + // calculate frontlerp value + if( m_fDoInterp ) f = 1.0 - m_pCurrentEntity->backlerp; + else f = 0; + + for( i = 0; i < 3; i++ ) + modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->prev.origin[i]) * f; + + for( i = 0; i < 3; i++ ) + { + float ang1, ang2; + + ang1 = m_pCurrentEntity->angles[i]; + ang2 = m_pCurrentEntity->prev.angles[i]; + + d = ang1 - ang2; + if( d > 180 ) d -= 360; + else if( d < -180 ) d += 360; + angles[i] += d * f; + } + } + else if( m_pCurrentEntity->ent_type == ED_CLIENT ) + { + // don't rotate player model, only aim + angles[PITCH] = 0; + } + else if( m_pCurrentEntity->movetype != MOVETYPE_NONE ) + { + VectorCopy( m_pCurrentEntity->angles, angles ); + } + Matrix4x4_CreateFromEntity( m_protationmatrix, modelpos[0], modelpos[1], modelpos[2], angles[PITCH], angles[YAW], angles[ROLL], m_pCurrentEntity->scale ); +} + + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float R_StudioEstimateInterpolant( void ) +{ + float dadt = 1.0; + + if ( m_fDoInterp && ( m_pCurrentEntity->animtime >= m_pCurrentEntity->prev.animtime + 0.01 ) ) + { + dadt = (r_refdef.time - m_pCurrentEntity->animtime) / 0.1; + if( dadt > 2.0 ) dadt = 2.0; + } + return dadt; +} + + +/* +==================== +StudioCalcRotations + +==================== +*/ +void R_StudioCalcRotations( float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdesc, dstudioanim_t *panim, float f ) +{ + int i; + int frame; + dstudiobone_t *pbone; + + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; + + if( f > pseqdesc->numframes - 1 ) f = 0; // bah, fix this bug with changing sequences too fast + else if ( f < -0.01f ) + { + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + MsgDev( D_ERROR, "f = %g\n", f ); + f = -0.01f; + } + + frame = (int)f; + + // Msg("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + // Msg( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); + // Msg("frame %d %d\n", frame1, frame2 ); + + dadt = R_StudioEstimateInterpolant(); + s = (f - frame); + + // add in programtic controllers + pbone = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + R_StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->controller, m_pCurrentEntity->prev.controller, m_pCurrentEntity->mouth.open ); + + for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + { + R_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); + R_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + // if (0 && i == 0) Msg("%d %d %d %d\n", m_pCurrentEntity->sequence, frame, j, k ); + } + + if (pseqdesc->motiontype & STUDIO_X) pos[pseqdesc->motionbone][0] = 0.0; + if (pseqdesc->motiontype & STUDIO_Y) pos[pseqdesc->motionbone][1] = 0.0; + if (pseqdesc->motiontype & STUDIO_Z) pos[pseqdesc->motionbone][2] = 0.0; + + s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->framerate; + + if (pseqdesc->motiontype & STUDIO_LX) pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; + if (pseqdesc->motiontype & STUDIO_LY) pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; + if (pseqdesc->motiontype & STUDIO_LZ) pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void R_StudioFxTransform( ref_entity_t *ent, matrix4x4 transform ) +{ + if( ent->renderfx == kRenderFxHologram ) + { + if(!Com_RandomLong( 0, 49 )) + { + int axis = Com_RandomLong( 0, 1 ); + if( axis == 1 ) axis = 2; // choose between x & z + VectorScale( transform[axis], Com_RandomFloat( 1, 1.484 ), transform[axis] ); + } + else if(!Com_RandomLong( 0, 49 )) + { + float offset; + int axis = Com_RandomLong( 0, 1 ); + if( axis == 1 ) axis = 2; // choose between x & z + offset = Com_RandomFloat( -10, 10 ); + transform[Com_RandomLong( 0, 2 )][3] += offset; + } + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float R_StudioEstimateFrame( dstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if( m_fDoInterp ) + { + if( r_refdef.time < m_pCurrentEntity->animtime ) dfdt = 0; + else dfdt = (r_refdef.time - m_pCurrentEntity->animtime) * m_pCurrentEntity->framerate * pseqdesc->fps; + } + else dfdt = 0; + + if( pseqdesc->numframes <= 1 ) f = 0; + else f = (m_pCurrentEntity->frame * (pseqdesc->numframes - 1)) / 256.0; + + f += dfdt; + + if( pseqdesc->flags & STUDIO_LOOPING ) + { + if( pseqdesc->numframes > 1 ) f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + if( f < 0 ) f += (pseqdesc->numframes - 1); + } + else + { + if( f >= pseqdesc->numframes - 1.001 ) f = pseqdesc->numframes - 1.001; + if( f < 0.0 ) f = 0.0; + } + return f; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +float R_StudioSetupBones( void ) +{ + int i; + double f; + + dstudiobone_t *pbones; + dstudioseqdesc_t *pseqdesc; + dstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + matrix4x4 bonematrix; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + if( m_pCurrentEntity->sequence >= m_pStudioHeader->numseq ) m_pCurrentEntity->sequence = 0; + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->sequence; + + f = R_StudioEstimateFrame( pseqdesc ); + + if( m_pCurrentEntity->prev.frame > f ) + { + // Msg( "%f %f\n", m_pCurrentEntity->prev.frame, f ); + } + + panim = R_StudioGetAnim( m_pRenderModel, pseqdesc ); + R_StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + if( pseqdesc->numblends > 1 ) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + dadt = R_StudioEstimateInterpolant(); + s = (m_pCurrentEntity->blending[0] * dadt + m_pCurrentEntity->prev.blending[0] * (1.0 - dadt)) / 255.0; + + R_StudioSlerpBones( q, pos, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); + + s = (m_pCurrentEntity->blending[0] * dadt + m_pCurrentEntity->prev.blending[0] * (1.0 - dadt)) / 255.0; + R_StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->blending[1] * dadt + m_pCurrentEntity->prev.blending[1] * (1.0 - dadt)) / 255.0; + R_StudioSlerpBones( q, pos, q3, pos3, s ); + } + } + + if( m_fDoInterp && m_pCurrentEntity->prev.sequencetime && ( m_pCurrentEntity->prev.sequencetime + 0.2 > r_refdef.time) && ( m_pCurrentEntity->prev.sequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->prev.sequence; + panim = R_StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + R_StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->prev.frame ); + + if( pseqdesc->numblends > 1 ) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->prev.frame ); + + s = (m_pCurrentEntity->prev.seqblending[0]) / 255.0; + R_StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + + if( pseqdesc->numblends == 4 ) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->prev.frame ); + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->prev.frame ); + + s = (m_pCurrentEntity->prev.seqblending[0]) / 255.0; + R_StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->prev.seqblending[1]) / 255.0; + R_StudioSlerpBones( q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0 - (r_refdef.time - m_pCurrentEntity->prev.sequencetime) / 0.2; + R_StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + // MsgDev( D_INFO, "prevframe = %4.2f\n", f ); + m_pCurrentEntity->prev.frame = f; + } + + pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if( m_pCurrentEntity->gaitsequence != 0 ) + { + if( m_pCurrentEntity->gaitsequence >= m_pStudioHeader->numseq ) + m_pCurrentEntity->gaitsequence = 0; + + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->gaitsequence; + + panim = R_StudioGetAnim( m_pRenderModel, pseqdesc ); + R_StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->gaitframe ); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + // g-cont. hey, what a hell ? + if( !com.strcmp( pbones[i].name, "Bip01 Spine" )) + break; + Mem_Copy( pos[i], pos2[i], sizeof( pos[i] )); + Mem_Copy( q[i], q2[i], sizeof( q[i] )); + } + } + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + Matrix4x4_FromOriginQuat( bonematrix, pos[i][0], pos[i][1], pos[i][2], q[i][0], q[i][1], q[i][2], q[i][3] ); + if( pbones[i].parent == -1 ) + { + Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_protationmatrix, bonematrix ); + Matrix4x4_Copy( m_plighttransform[i], m_pbonestransform[i] ); + + // apply client-side effects to the transformation matrix + R_StudioFxTransform( m_pCurrentEntity, m_pbonestransform[i] ); + } + else + { + Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_pbonestransform[pbones[i].parent], bonematrix ); + Matrix4x4_ConcatTransforms( m_plighttransform[i], m_plighttransform[pbones[i].parent], bonematrix ); + } + } + return (float)f; +} + +/* +==================== +StudioSaveBones + +==================== +*/ +void R_StudioSaveBones( void ) +{ + int i; + dstudiobone_t *pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + m_nCachedBones = m_pStudioHeader->numbones; + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + com.strncpy( m_nCachedBoneNames[i], pbones[i].name, 32 ); + Matrix4x4_Copy( m_rgCachedBonesTransform[i], m_pbonestransform[i] ); + Matrix4x4_Copy( m_rgCachedLightTransform[i], m_plighttransform[i] ); + } +} + +/* +==================== +StudioMergeBones + +==================== +*/ +float R_StudioMergeBones ( rmodel_t *m_pSubModel ) +{ + int i, j; + double f; + int do_hunt = true; + + dstudiobone_t *pbones; + dstudioseqdesc_t *pseqdesc; + dstudioanim_t *panim; + matrix4x4 bonematrix; + + static vec4_t q[MAXSTUDIOBONES]; + static float pos[MAXSTUDIOBONES][3]; + + if( m_pCurrentEntity->sequence >= m_pStudioHeader->numseq ) m_pCurrentEntity->sequence = 0; + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->sequence; + + f = R_StudioEstimateFrame( pseqdesc ); + + if( m_pCurrentEntity->prev.frame > f ) + { + // Msg("%f %f\n", m_pCurrentEntity->prev.frame, f ); + } + + panim = R_StudioGetAnim( m_pSubModel, pseqdesc ); + R_StudioCalcRotations( pos, q, pseqdesc, panim, f ); + pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + for( j = 0; j < m_nCachedBones; j++ ) + { + if( !com.stricmp( pbones[i].name, m_nCachedBoneNames[j] )) + { + Matrix4x4_Copy( m_pbonestransform[i], m_rgCachedBonesTransform[j] ); + Matrix4x4_Copy( m_plighttransform[i], m_rgCachedLightTransform[j] ); + break; + } + } + if( j >= m_nCachedBones ) + { + Matrix4x4_FromOriginQuat( bonematrix, pos[i][0], pos[i][1], pos[i][2], q[i][0], q[i][1], q[i][2], q[i][3] ); + if( pbones[i].parent == -1 ) + { + Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_protationmatrix, bonematrix ); + Matrix4x4_Copy( m_plighttransform[i], m_pbonestransform[i] ); + + // apply client-side effects to the transformation matrix + R_StudioFxTransform( m_pCurrentEntity, m_pbonestransform[i] ); + } + else + { + Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_pbonestransform[pbones[i].parent], bonematrix ); + Matrix4x4_ConcatTransforms( m_plighttransform[i], m_plighttransform[pbones[i].parent], bonematrix ); + } + } + } + return (float)f; +} + + +/* +==================== +StudioCalcAttachments + +==================== +*/ +void R_StudioCalcAttachments( void ) +{ + int i; + dstudioattachment_t *pattachment; + + if( m_pStudioHeader->numattachments > MAXSTUDIOATTACHMENTS ) + { + MsgDev( D_WARN, "Too many attachments on %s\n", m_pCurrentEntity->model->name ); + m_pStudioHeader->numattachments = MAXSTUDIOATTACHMENTS; // reduce it + } + + // calculate attachment points + pattachment = (dstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + for( i = 0; i < m_pStudioHeader->numattachments; i++ ) + { + Matrix4x4_Transform( m_plighttransform[pattachment[i].bone], pattachment[i].org, m_pCurrentEntity->attachment[i] ); + } +} + +bool R_StudioComputeBBox( vec3_t bbox[8] ) +{ + vec3_t vectors[3]; + ref_entity_t *e = m_pCurrentEntity; + vec3_t mins, maxs, tmp, angles; + int i, seq = m_pCurrentEntity->sequence; + + if(!R_ExtractBbox( seq, mins, maxs )) + return false; + + // compute a full bounding box + for ( i = 0; i < 8; i++ ) + { + if ( i & 1 ) tmp[0] = mins[0]; + else tmp[0] = maxs[0]; + if ( i & 2 ) tmp[1] = mins[1]; + else tmp[1] = maxs[1]; + if ( i & 4 ) tmp[2] = mins[2]; + else tmp[2] = maxs[2]; + VectorCopy( tmp, bbox[i] ); + } + + // rotate the bounding box + VectorScale( e->angles, -1, angles ); + AngleVectorsFLU( angles, vectors[0], vectors[1], vectors[2] ); + + for ( i = 0; i < 8; i++ ) + { + VectorCopy( bbox[i], tmp ); + bbox[i][0] = DotProduct( vectors[0], tmp ); + bbox[i][1] = DotProduct( vectors[1], tmp ); + bbox[i][2] = DotProduct( vectors[2], tmp ); + VectorAdd( e->origin, bbox[i], bbox[i] ); + } + return true; +} + +static bool R_StudioCheckBBox( void ) +{ + int i, j; + vec3_t bbox[8]; + + int aggregatemask = ~0; + + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + return true; + if(!R_StudioComputeBBox( bbox )) + return false; + + for ( i = 0; i < 8; i++ ) + { + int mask = 0; + for ( j = 0; j < 4; j++ ) + { + float dp = DotProduct( r_frustum[j].normal, bbox[i] ); + if ( ( dp - r_frustum[j].dist ) < 0 ) mask |= ( 1 << j ); + } + aggregatemask &= mask; + } + + if ( aggregatemask ) + return false; + return true; +} + +/* +==================== +StudioSetupModel + +==================== +*/ +void R_StudioSetupModel( int body, int bodypart ) +{ + int index; + + if( bodypart > m_pStudioHeader->numbodyparts ) bodypart = 0; + m_pBodyPart = (dstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + bodypart; + + index = body / m_pBodyPart->base; + index = index % m_pBodyPart->nummodels; + + m_pSubModel = (dstudiomodel_t *)((byte *)m_pStudioHeader + m_pBodyPart->modelindex) + index; +} + +void R_StudioSetupLighting( void ) +{ + int i; + dstudiobone_t *pbone; + + // get light from floor or ceil + m_plightvec[0] = 0.0f; + m_plightvec[1] = 0.0f; + m_plightvec[2] = (m_pCurrentEntity->effects & EF_INVLIGHT) ? 1.0f : -1.0f; + + { + vec3_t light_org; + VectorCopy( m_pCurrentEntity->origin, light_org ); + light_org[2] += 3; // make sure what lightpoint is off the ground + R_LightForPoint( light_org, m_plightcolor ); + if ( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + r_lightlevel->value = bound(0, VectorLength(m_plightcolor) * 75.0f, 255); + + } + + // TODO: only do it for bones that actually have textures + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + pbone = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex + i); + //if(pbone->flags & STUDIO_HAS_CHROME) + { + Matrix4x4_Rotate3x3( m_pbonestransform[i], m_plightvec, m_blightvec[i] ); + } + } +} + +void R_StudioLighting( float *lv, int bone, int flags, vec3_t normal ) +{ + float lightcos; + + float shadelight = 192.0f; + float illum = 32.0f;//RF_MINLIGHT & RF_FULLBRIGHT + + if( flags & STUDIO_NF_FLATSHADE ) + { + illum += shadelight * 0.8f; + } + else + { + lightcos = DotProduct (normal, m_blightvec[bone]);// -1 colinear, 1 opposite + if (lightcos > 1.0) lightcos = 1; + + illum += shadelight; + lightcos = (lightcos + 0.5f) / 1.5f;// do modified hemispherical lighting + if (lightcos > 0.0) illum -= shadelight * lightcos; + } + illum = bound( 0, illum, 255); + + *lv = illum / 255.0; // Light from 0 to 1.0 +} + +void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal ) +{ + float n; + + if( g_chromeage[bone] != m_pStudioModelCount ) + { + // calculate vectors from the viewer to the bone. This roughly adjusts for position + vec3_t chromeupvec; // g_chrome t vector in world reference frame + vec3_t chromerightvec; // g_chrome s vector in world reference frame + vec3_t tmp, tmp2; // vector pointing at bone in world reference frame + + VectorScale( m_pCurrentEntity->origin, -1, tmp ); + Matrix4x4_OriginFromMatrix( m_pbonestransform[bone], tmp2 ); + VectorAdd( tmp, tmp2, tmp ); + + VectorNormalize( tmp ); + CrossProduct( tmp, r_right, chromeupvec ); + VectorNormalize( chromeupvec ); + CrossProduct( tmp, chromeupvec, chromerightvec ); + VectorNormalize( chromerightvec ); + + Matrix4x4_Rotate3x3( m_pbonestransform[bone], chromeupvec, g_chromeup[bone] ); + Matrix4x4_Rotate3x3( m_pbonestransform[bone], chromerightvec, g_chromeright[bone] ); + g_chromeage[bone] = m_pStudioModelCount; + } + + // calc s coord + n = DotProduct( normal, g_chromeright[bone] ); + pchrome[0] = (n + 1.0) * 32.0f; + + // calc t coord + n = DotProduct( normal, g_chromeup[bone] ); + pchrome[1] = (n + 1.0) * 32.0f; +} + +void R_StudioSetRenderMode( void ) +{ + if( m_pCurrentShader->stages[0]->renderMode != m_pCurrentEntity->rendermode ) + { + switch( m_pCurrentEntity->rendermode ) + { + case kRenderNormal: + m_pCurrentShader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + break; + case kRenderTransColor: + m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_COLOR; + m_pCurrentShader->stages[0]->blendFunc.dst = GL_ZERO; + break; + case kRenderTransTexture: + m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case kRenderGlow: + m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pCurrentShader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; + m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; + m_pCurrentShader->stages[0]->flags &= ~SHADERSTAGE_DEPTHWRITE; + break; + case kRenderTransAlpha: + m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; + m_pCurrentShader->stages[0]->alphaFunc.func = GL_GREATER; + m_pCurrentShader->stages[0]->alphaFunc.ref = 0.666; + m_pCurrentShader->sort = SORT_SEETHROUGH; + break; + case kRenderTransAdd: + m_pCurrentShader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; + m_pCurrentShader->stages[0]->blendFunc.src = GL_SRC_ALPHA; + m_pCurrentShader->stages[0]->blendFunc.dst = GL_ONE; + break; + } + m_pCurrentShader->stages[0]->renderMode = m_pCurrentEntity->rendermode; + } +} + +void R_StudioDrawMeshes( dstudiotexture_t * ptexture, short *pskinref ) +{ + int i, j; + float *av, *lv; + float lv_tmp; + vec3_t fbright = { 0.95f, 0.95f, 0.95f }; + vec3_t irgoggles = { 0.95f, 0.0f, 0.0f }; // predefined lightcolor + int flags; + + dstudiomesh_t *pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex); + byte *pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex); + vec3_t *pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); + + lv = (float *)m_pvlightvalues; + for (j = 0; j < m_pSubModel->nummesh; j++) + { + flags = ptexture[pskinref[pmesh[j].skinref]].flags; + + for (i = 0; i < pmesh[j].numnorms; i++, lv += 3, pstudionorms++, pnormbone++) + { + R_StudioLighting (&lv_tmp, *pnormbone, flags, (float *)pstudionorms); + + // FIXME: move this check out of the inner loop + if( flags & STUDIO_NF_CHROME ) + R_StudioSetupChrome( g_chrome[(float (*)[3])lv - m_pvlightvalues], *pnormbone, (float *)pstudionorms ); + VectorScale(m_plightcolor, lv_tmp, lv ); + } + } + + for( j = 0; j < m_pSubModel->nummesh; j++ ) + { + float s, t; + short *ptricmds; + ref_shader_t *m_pSkinShader; + + pmesh = (dstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; + ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + + flags = ptexture[pskinref[pmesh->skinref]].flags; + s = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].width; + t = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].height; + m_pSkinShader = &r_shaders[ptexture[pskinref[pmesh->skinref]].shader]; + + if( m_pCurrentShader != m_pSkinShader ) + RB_RenderMesh(); + + m_pCurrentShader = m_pSkinShader; + R_StudioSetRenderMode(); + + while( i = *(ptricmds++)) + { + if( i < 0 ) + { + GL_Begin( GL_TRIANGLE_FAN ); + i = -i; + } + else + { + GL_Begin( GL_TRIANGLE_STRIP ); + } + + for( ; i > 0; i--, ptricmds += 4 ) + { + if( flags & STUDIO_NF_CHROME ) + GL_TexCoord2f( g_chrome[ptricmds[1]][0] * s, g_chrome[ptricmds[1]][1] * t ); + else GL_TexCoord2f( ptricmds[2] * s, ptricmds[3] * t ); + + lv = m_pvlightvalues[ptricmds[1]]; + + GL_Normal3fv( vec3_origin ); // FIXME: apply normals + av = m_pxformverts[ptricmds[0]]; // verts + GL_Vertex3f( av[0], av[1], av[2] ); + } + GL_End(); + } + } +} + +void R_StudioDrawPoints ( void ) +{ + int i, m_skinnum = m_pCurrentEntity->skin; + byte *pvertbone; + byte *pnormbone; + vec3_t *pstudioverts; + vec3_t *pstudionorms; + dstudiotexture_t *ptexture; + short *pskinref; + + pvertbone = ((byte *)m_pStudioHeader + m_pSubModel->vertinfoindex); + pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex); + ptexture = (dstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex); + + pstudioverts = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->vertindex); + pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); + + pskinref = (short *)((byte *)m_pTextureHeader + m_pTextureHeader->skinindex); + if( m_skinnum != 0 && m_skinnum < m_pTextureHeader->numskinfamilies ) + pskinref += (m_skinnum * m_pTextureHeader->numskinref); + + for( i = 0; i < m_pSubModel->numverts; i++ ) + { + Matrix4x4_Transform( m_pbonestransform[pvertbone[i]], pstudioverts[i], m_pxformverts[i]); + } + for( i = 0; i < m_pSubModel->numnorms; i++ ) + { + Matrix4x4_Transform( m_pbonestransform[pnormbone[i]], pstudionorms[i], m_pxformnorms[i]); + } + + // hack the depth range to prevent view model from poking into walls + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) pglDepthRange( 0.0, 0.3 ); + if(( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) && ( r_lefthand->value == 1.0F )) + VectorNegate( m_pCurrentEntity->matrix[1], m_pCurrentEntity->matrix[1] ); + R_StudioDrawMeshes( ptexture, pskinref ); + + // hack the depth range to prevent view model from poking into walls + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) pglDepthRange( 0.0, 1.0 ); +} + +void R_StudioDrawBones( void ) +{ + + dstudiobone_t *pbones = (dstudiobone_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + vec3_t point; + int i; + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + if( pbones[i].parent >= 0 ) + { + pglPointSize( 3.0f ); + pglColor3f( 1, 0.7f, 0 ); + pglBegin( GL_LINES ); + + Matrix4x4_OriginFromMatrix( m_pbonestransform[pbones[i].parent], point ); + pglVertex3fv( point ); + Matrix4x4_OriginFromMatrix( m_pbonestransform[i], point ); + pglVertex3fv( point ); + + pglEnd(); + + pglColor3f( 0, 0, 0.8f ); + pglBegin( GL_POINTS ); + if( pbones[pbones[i].parent].parent != -1 ) + { + Matrix4x4_OriginFromMatrix( m_pbonestransform[pbones[i].parent], point ); + pglVertex3fv( point ); + } + Matrix4x4_OriginFromMatrix( m_pbonestransform[i], point ); + pglVertex3fv( point ); + pglEnd(); + } + else + { + // draw parent bone node + pglPointSize( 5.0f ); + pglColor3f( 0.8f, 0, 0 ); + pglBegin( GL_POINTS ); + Matrix4x4_OriginFromMatrix( m_pbonestransform[i], point ); + pglVertex3fv( point ); + pglEnd(); + } + } + pglPointSize( 1.0f ); +} + +void R_StudioDrawHitboxes( void ) +{ + int i, j; + + pglColor4f (1, 0, 0, 0.5f); + pglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + for (i = 0; i < m_pStudioHeader->numhitboxes; i++) + { + dstudiobbox_t *pbboxes = (dstudiobbox_t *) ((byte *) m_pStudioHeader + m_pStudioHeader->hitboxindex); + vec3_t v[8], v2[8], bbmin, bbmax; + + VectorCopy (pbboxes[i].bbmin, bbmin); + VectorCopy (pbboxes[i].bbmax, bbmax); + + v[0][0] = bbmin[0]; + v[0][1] = bbmax[1]; + v[0][2] = bbmin[2]; + + v[1][0] = bbmin[0]; + v[1][1] = bbmin[1]; + v[1][2] = bbmin[2]; + + v[2][0] = bbmax[0]; + v[2][1] = bbmax[1]; + v[2][2] = bbmin[2]; + + v[3][0] = bbmax[0]; + v[3][1] = bbmin[1]; + v[3][2] = bbmin[2]; + + v[4][0] = bbmax[0]; + v[4][1] = bbmax[1]; + v[4][2] = bbmax[2]; + + v[5][0] = bbmax[0]; + v[5][1] = bbmin[1]; + v[5][2] = bbmax[2]; + + v[6][0] = bbmin[0]; + v[6][1] = bbmax[1]; + v[6][2] = bbmax[2]; + + v[7][0] = bbmin[0]; + v[7][1] = bbmin[1]; + v[7][2] = bbmax[2]; + + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[0], v2[0]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[1], v2[1]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[2], v2[2]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[3], v2[3]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[4], v2[4]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[5], v2[5]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[6], v2[6]); + Matrix4x4_Transform (m_pbonestransform[pbboxes[i].bone], v[7], v2[7]); + + pglBegin( GL_QUAD_STRIP ); + for (j = 0; j < 10; j++) pglVertex3fv (v2[j & 7]); + pglEnd( ); + + pglBegin( GL_QUAD_STRIP ); + pglVertex3fv (v2[6]); + pglVertex3fv (v2[0]); + pglVertex3fv (v2[4]); + pglVertex3fv (v2[2]); + pglEnd( ); + + pglBegin( GL_QUAD_STRIP ); + pglVertex3fv (v2[1]); + pglVertex3fv (v2[7]); + pglVertex3fv (v2[3]); + pglVertex3fv (v2[5]); + pglEnd( ); + } + + pglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); +} + +void R_StudioDrawAttachments( void ) +{ + int i; + + for (i = 0; i < m_pStudioHeader->numattachments; i++) + { + dstudioattachment_t *pattachments = (dstudioattachment_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + vec3_t v[4]; + + Matrix4x4_Transform (m_pbonestransform[pattachments[i].bone], pattachments[i].org, v[0]); + Matrix4x4_Transform (m_pbonestransform[pattachments[i].bone], pattachments[i].vectors[0], v[1]); + Matrix4x4_Transform (m_pbonestransform[pattachments[i].bone], pattachments[i].vectors[1], v[2]); + Matrix4x4_Transform (m_pbonestransform[pattachments[i].bone], pattachments[i].vectors[2], v[3]); + + pglBegin (GL_LINES); + pglColor3f (1, 0, 0); + pglVertex3fv (v[0]); + pglColor3f (1, 1, 1); + pglVertex3fv (v[1]); + pglColor3f (1, 0, 0); + pglVertex3fv (v[0]); + pglColor3f (1, 1, 1); + pglVertex3fv (v[2]); + pglColor3f (1, 0, 0); + pglVertex3fv (v[0]); + pglColor3f (1, 1, 1); + pglVertex3fv (v[3]); + pglEnd (); + + pglPointSize (5.0f); + pglColor3f (0, 1, 0); + pglBegin (GL_POINTS); + pglVertex3fv (v[0]); + pglEnd (); + pglPointSize (1.0f); + } +} + +void R_StudioDrawHulls ( void ) +{ + int i; + vec3_t bbox[8]; + + // we already have code for drawing hulls + // make this go away + + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + return; + + if(!R_StudioComputeBBox( bbox )) return; + + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + pglBegin( GL_LINES ); + for( i = 0; i < 2; i += 1 ) + { + pglVertex3fv(bbox[i+0]); + pglVertex3fv(bbox[i+2]); + pglVertex3fv(bbox[i+4]); + pglVertex3fv(bbox[i+6]); + pglVertex3fv(bbox[i+0]); + pglVertex3fv(bbox[i+4]); + pglVertex3fv(bbox[i+2]); + pglVertex3fv(bbox[i+6]); + pglVertex3fv(bbox[i*2+0]); + pglVertex3fv(bbox[i*2+1]); + pglVertex3fv(bbox[i*2+4]); + pglVertex3fv(bbox[i*2+5]); + } + pglEnd(); +} + +void R_StudioDrawShadow ( void ) +{ + float an = m_pCurrentEntity->angles[1] / 180 * M_PI; + + m_pshadevector[0] = cos(-an); + m_pshadevector[1] = sin(-an); + m_pshadevector[2] = 1; + VectorNormalize( m_pshadevector ); +} + +void R_StudioSetRemapColors( int m_topColor, int m_bottomColor ) +{ + // FIXME: get some code from q1 +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void R_StudioRenderModel( void ) +{ + int i; + + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) + { + R_StudioSetupModel( m_pCurrentEntity->body, i ); + R_StudioDrawPoints(); + } + + if( !r_refdef.onlyClientDraw ) + { + if( r_drawentities->integer < 2 ) + return; + + GL_Disable( GL_VERTEX_PROGRAM_ARB ); + GL_Disable( GL_FRAGMENT_PROGRAM_ARB ); + GL_Disable( GL_ALPHA_TEST ); + GL_Disable( GL_BLEND ); + GL_DepthFunc( GL_LEQUAL ); + GL_DepthMask( GL_TRUE ); + + pglDepthRange( 0, 0 ); + switch( r_drawentities->integer ) + { + case 2: R_StudioDrawBones(); break; + case 3: R_StudioDrawHitboxes(); break; + case 4: R_StudioDrawAttachments(); break; + case 5: R_StudioDrawHulls(); break; + } + pglDepthRange( 0, 1 ); + } +} + +void R_StudioSetupRender( void ) +{ + // set global pointers + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = m_pRenderModel->phdr; + m_pTextureHeader = m_pRenderModel->thdr; + + // set intermediate vertex buffers + m_pxformverts = &g_xformverts[0]; + m_pxformnorms = &g_xformnorms[0]; + m_pvlightvalues = &g_lightvalues[0]; + + // misc info + m_fDoInterp = (m_pCurrentEntity->effects & EF_NOINTERP) ? false : true; +} + +/* +==================== +StudioDrawModel + +==================== +*/ +bool R_StudioDrawModel( int flags ) +{ + float curframe = 0.0f; + + if( m_pCurrentEntity->ent_type == ED_VIEWMODEL ) + { + if( /*mirror_render ||*/ r_lefthand->value == 2 ) + return 0; + flags |= STUDIO_EVENTS; + } + + R_StudioSetupRender (); + R_StudioSetUpTransform (); + + if( flags & STUDIO_RENDER ) + { + // see if the bounding box lets us trivially reject, also sets + if( !R_StudioCheckBBox( )) return 0; + + m_pStudioModelCount++; // render data cache cookie + + // nothing to draw + if( m_pStudioHeader->numbodyparts == 0 ) + return 1; + } + + if( m_pCurrentEntity->movetype == MOVETYPE_FOLLOW ) + { + curframe = R_StudioMergeBones( m_pRenderModel ); + } + else + { + curframe = R_StudioSetupBones(); + } + R_StudioSaveBones(); + + //////// AFTER THIS POINT GO STUDIO MODEL DRAW /////// + //////// SAVE BONES INTO LOCAL ARRAY ///////////////// + + if( flags & STUDIO_EVENTS ) + { + edict_t *ent = ri.GetClientEdict( m_pCurrentEntity->index ); + float flStart = curframe + m_pCurrentEntity->framerate; + float flEnd = flStart + 0.4f; + dstudioevent_t event; + int index = 0; + + R_StudioCalcAttachments(); + Mem_Set( &event, 0, sizeof( event )); + + // copy attachments back to client entity + Mem_Copy( ent->v.attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * MAXSTUDIOATTACHMENTS ); + while(( index = R_StudioGetEvent( &event, flStart, flEnd, index )) != 0 ) + { + ri.StudioEvent( &event, ent ); + } + } + + if( flags & STUDIO_RENDER ) + { + R_StudioSetupLighting( ); + + // get remap colors + m_nTopColor = m_pCurrentEntity->colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; + + R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + R_StudioRenderModel( ); + + // draw weaponmodel for monsters + if( m_pCurrentEntity->weaponmodel ) + { + ref_entity_t saveent = *m_pCurrentEntity; + rmodel_t *pweaponmodel = m_pCurrentEntity->weaponmodel; + + // get remap colors + m_nTopColor = m_pCurrentEntity->colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; + R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + m_pStudioHeader = pweaponmodel->phdr; + m_pTextureHeader = pweaponmodel->thdr; + R_StudioMergeBones( pweaponmodel ); + R_StudioSetupLighting( ); + + R_StudioRenderModel( ); + R_StudioCalcAttachments( ); + *m_pCurrentEntity = saveent; + } + } + return 1; +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void R_StudioEstimateGait( edict_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = ( r_refdef.time - r_refdef.oldtime ); + if( dt < 0 ) dt = 0.0f; + else if ( dt > 1.0 ) dt = 1.0f; + + if( dt == 0 || m_pCurrentEntity->renderframe == r_frameCount ) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->v.velocity, pplayer->v.prediction_error, est_velocity ); + if( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pCurrentEntity->prev.gaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pCurrentEntity->prev.gaitorigin ); + + m_flGaitMovement = VectorLength( est_velocity ); + if( dt <= 0 || m_flGaitMovement / dt < 5 ) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->v.velocity, est_velocity ); + m_flGaitMovement = VectorLength( est_velocity ) * dt; + } + + if( est_velocity[1] == 0 && est_velocity[0] == 0 ) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pCurrentEntity->gaityaw; + + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if( flYawDiff > 180 ) flYawDiff -= 360; + if( flYawDiff < -180 ) flYawDiff += 360; + + if( dt < 0.25 ) flYawDiff *= dt * 4; + else flYawDiff *= dt; + + m_pCurrentEntity->gaityaw += flYawDiff; + m_pCurrentEntity->gaityaw = m_pCurrentEntity->gaityaw - (int)(m_pCurrentEntity->gaityaw / 360) * 360; + m_flGaitMovement = 0; + } + else + { + m_pCurrentEntity->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if( m_pCurrentEntity->gaityaw > 180 ) m_pCurrentEntity->gaityaw = 180; + if( m_pCurrentEntity->gaityaw < -180 ) m_pCurrentEntity->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void R_StudioProcessGait( edict_t *pplayer ) +{ + dstudioseqdesc_t *pseqdesc; + float dt, flYaw; // view direction relative to movement + float fBlend; + + if( m_pCurrentEntity->sequence >= m_pStudioHeader->numseq ) + m_pCurrentEntity->sequence = 0; + + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->sequence; + R_StudioPlayerBlend( pseqdesc, &fBlend, &m_pCurrentEntity->angles[PITCH] ); + + m_pCurrentEntity->prev.angles[PITCH] = m_pCurrentEntity->angles[PITCH]; + m_pCurrentEntity->blending[0] = fBlend; + m_pCurrentEntity->prev.blending[0] = m_pCurrentEntity->blending[0]; + m_pCurrentEntity->prev.seqblending[0] = m_pCurrentEntity->blending[0]; + + // MsgDev( D_INFO, "%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + + dt = (r_refdef.time - r_refdef.oldtime); + if( dt < 0 ) dt = 0.0f; + else if( dt > 1.0 ) dt = 1.0f; + + R_StudioEstimateGait( pplayer ); + + // MsgDev( D_INFO, "%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pCurrentEntity->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if( flYaw < -180 ) flYaw = flYaw + 360; + if( flYaw > 180 ) flYaw = flYaw - 360; + + if( flYaw > 120 ) + { + m_pCurrentEntity->gaityaw = m_pCurrentEntity->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if( flYaw < -120 ) + { + m_pCurrentEntity->gaityaw = m_pCurrentEntity->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + // adjust torso + m_pCurrentEntity->controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->prev.controller[0] = m_pCurrentEntity->controller[0]; + m_pCurrentEntity->prev.controller[1] = m_pCurrentEntity->controller[1]; + m_pCurrentEntity->prev.controller[2] = m_pCurrentEntity->controller[2]; + m_pCurrentEntity->prev.controller[3] = m_pCurrentEntity->controller[3]; + + m_pCurrentEntity->angles[YAW] = m_pCurrentEntity->gaityaw; + if( m_pCurrentEntity->angles[YAW] < -0 ) m_pCurrentEntity->angles[YAW] += 360; + m_pCurrentEntity->prev.angles[YAW] = m_pCurrentEntity->angles[YAW]; + + if( pplayer->v.gaitsequence >= m_pStudioHeader->numseq ) + pplayer->v.gaitsequence = 0; + + pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->v.gaitsequence; + + // calc gait frame + if( pseqdesc->linearmovement[0] > 0 ) + { + m_pCurrentEntity->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pCurrentEntity->gaitframe += pseqdesc->fps * dt; + } + + // do modulo + m_pCurrentEntity->gaitframe = m_pCurrentEntity->gaitframe - (int)(m_pCurrentEntity->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if( m_pCurrentEntity->gaitframe < 0 ) m_pCurrentEntity->gaitframe += pseqdesc->numframes; +} + +/* +==================== +StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags ) +{ + edict_t *pplayer; + + if( !r_refdef.thirdperson ) + return 0; + + if( !( flags & STUDIO_MIRROR )) + { + //m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + } + + pplayer = ri.GetClientEdict( m_pCurrentEntity->index ); + R_StudioSetupRender(); + + // MsgDev( D_INFO, "DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + // MsgDev( D_INFO, "DrawPlayer %d %d (%d)\n", r_framecount, pplayer->serialnumber, m_pCurrentEntity->sequence ); + // MsgDev( D_INFO, "Player %.2f %.2f %.2f\n", pplayer->v.velocity[0], pplayer->v.velocity[1], pplayer->v.velocity[2] ); + + if( pplayer->serialnumber < 0 || pplayer->serialnumber > ri.GetMaxClients()) + return 0; + + if( pplayer->v.gaitsequence ) + { + vec3_t orig_angles; + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + R_StudioProcessGait( pplayer ); + + m_pCurrentEntity->gaitsequence = pplayer->v.gaitsequence; + R_StudioSetUpTransform( ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->controller[0] = 127; + m_pCurrentEntity->controller[1] = 127; + m_pCurrentEntity->controller[2] = 127; + m_pCurrentEntity->controller[3] = 127; + m_pCurrentEntity->prev.controller[0] = m_pCurrentEntity->controller[0]; + m_pCurrentEntity->prev.controller[1] = m_pCurrentEntity->controller[1]; + m_pCurrentEntity->prev.controller[2] = m_pCurrentEntity->controller[2]; + m_pCurrentEntity->prev.controller[3] = m_pCurrentEntity->controller[3]; + m_pCurrentEntity->gaitsequence = 0; + R_StudioSetUpTransform( ); + } + + if( flags & STUDIO_RENDER ) + { + // see if the bounding box lets us trivially reject, also sets + if(!R_StudioCheckBBox()) + return 0; + + m_pStudioModelCount++; // render data cache cookie + + // nothing to draw + if( m_pStudioHeader->numbodyparts == 0 ) + return 1; + } + + R_StudioSetupBones( ); + R_StudioSaveBones( ); + m_pCurrentEntity->renderframe = r_frameCount; + + if( flags & STUDIO_EVENTS ) + { + R_StudioCalcAttachments( ); + + //FIXME: + //ri.StudioEvent( dstudioevent_t *event, ent ); + + if( m_pCurrentEntity->index > 0 ) + { + // copy attachments into global entity array + edict_t *ent = ri.GetClientEdict( m_pCurrentEntity->index ); + Mem_Copy( ent->v.attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * MAXSTUDIOATTACHMENTS ); + } + } + + if( flags & STUDIO_RENDER ) + { + // show highest resolution multiplayer model + if( r_himodels->integer && m_pRenderModel != m_pCurrentEntity->model ) + m_pCurrentEntity->body = 255; + + if(!(glw_state.developer == 0 && ri.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model )) + m_pCurrentEntity->body = 1; // force helmet + + R_StudioSetupLighting( ); + + // get remap colors + m_nTopColor = m_pCurrentEntity->colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; + + if( m_nTopColor < 0 ) m_nTopColor = 0; + if( m_nTopColor > 360 ) m_nTopColor = 360; + if( m_nBottomColor < 0 ) m_nBottomColor = 0; + if( m_nBottomColor > 360 ) m_nBottomColor = 360; + + R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + R_StudioRenderModel( ); + + if( m_pCurrentEntity->weaponmodel ) + { + ref_entity_t saveent = *m_pCurrentEntity; + rmodel_t *pweaponmodel = m_pCurrentEntity->weaponmodel; + // get remap colors + m_nTopColor = m_pCurrentEntity->colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->colormap & 0xFF00)>>8; + R_StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + m_pStudioHeader = pweaponmodel->phdr; + m_pTextureHeader = pweaponmodel->thdr; + R_StudioMergeBones( pweaponmodel ); + R_StudioSetupLighting( ); + + R_StudioRenderModel( ); + R_StudioCalcAttachments( ); + *m_pCurrentEntity = saveent; + } + } + return 1; +} + +void R_DrawStudioModel( void ) +{ + if( m_pCurrentEntity->ent_type == ED_CLIENT ) + R_StudioDrawPlayer( STUDIO_RENDER ); + else R_StudioDrawModel( STUDIO_RENDER ); + + R_StudioAddEntityToRadar( ); +} + +void R_AddStudioModelToList( ref_entity_t *entity ) +{ + R_StudioSetupRender(); + if( !R_StudioCheckBBox( )) return; + if( !entity->shader ) return; + + // add it + R_AddMeshToList( MESH_STUDIO, NULL, entity->shader, entity, 0 ); +} + +void R_StudioClearMeshes( void ) +{ +} \ No newline at end of file diff --git a/render/r_surface.c b/render/r_surface.c index 1245c7a6..e90f9bcb 100644 --- a/render/r_surface.c +++ b/render/r_surface.c @@ -89,7 +89,7 @@ void R_DrawSurface( void ) GL_Binormal3fv( surf->binormal ); GL_Tangent3fv( surf->tangent ); GL_Normal3fv( surf->normal ); - GL_Color4fv( v->color ); + GL_Color4ubv( v->color ); GL_Vertex3fv( v->xyz ); } GL_End(); @@ -186,7 +186,10 @@ static void R_AddSurfaceToList( surface_t *surf, ref_entity_t *entity ) // check for lightmap modification if( r_dynamiclights->integer && (shader->flags & SHADER_HASLIGHTMAP)) { - if( surf->dlightFrame == r_frameCount ) lmNum = 255; + if( surf->dlightFrame == r_frameCount ) + { + lmNum = 255; + } else { for( map = 0; map < surf->numStyles; map++ ) @@ -506,9 +509,6 @@ void R_AddWorldToList( void ) // bump frame count r_frameCount++; - // auto cycle the world frame for texture animation - r_worldEntity->frame = (int)(r_refdef.time * 2); - // clear world mins/maxs ClearBounds( r_worldMins, r_worldMaxs ); diff --git a/server/global/client.cpp b/server/global/client.cpp index fc5bca88..75234b90 100644 --- a/server/global/client.cpp +++ b/server/global/client.cpp @@ -1137,13 +1137,13 @@ const char *GetGameDescription( void ) { char token[256]; char szbuffer[128]; - char *pfile = (char *)LOAD_FILE( "liblist.gam", NULL ); + char *pfile = (char *)LOAD_FILE( "gameinfo.txt", NULL ); if( pfile ) { while( pfile ) { - if( !stricmp( token, "game" )) + if( !stricmp( token, "title" )) { pfile = COM_ParseFile(pfile, token); sprintf( szbuffer, "%s ", token ); diff --git a/todo.log b/todo.log index 2c88ae25..5a8fc9bf 100644 --- a/todo.log +++ b/todo.log @@ -54,9 +54,7 @@ Beta 13.12.08 23.first implement efxapi_t OK 24.ed_fields flags OK 25.install ALL missing models & sounds! OK -26.fixangle doesn't working correctly -1. testing NET_ANGLE protocol OK -2. setup viewangles and angles on a server +26.fixangle doesn't working correctly OK 27.fixup viewmodel drawing OK 28.fixing r_pause_effect OK 29.dm_knot wrong entities OK @@ -75,7 +73,10 @@ Beta 13.12.08 42. fixup sky rendering OK 43. fixup sowtware mip-map generator OK 44. fixup sky rendering -45. make color as unsigned_byte(4) +45. make color as unsigned_byte(4) OK +46. RB_RenderShader() OK +47. fixup slowly rendering +48. building uimenu.dll Список доступных рендереров: Что в них интересного diff --git a/xtools/mdllib.h b/xtools/mdllib.h index b8e11b55..c5461cb5 100644 --- a/xtools/mdllib.h +++ b/xtools/mdllib.h @@ -190,17 +190,6 @@ typedef struct char name[64]; } s_sequencegroup_t; - -typedef struct -{ - byte r, g, b; -} rgb_t; - -typedef struct -{ - byte b, g, r, x; -} rgb2_t; - typedef struct { char name[64];