====================
StudioSetupShadows
====================
*/
void CStudioModelRenderer::StudioSetupShadows ( void )
{
StudioSetExtraData();
if ( !m_pShadowHeader->submodels.size() )
return;
m_fShadowType = false;
if ( m_pCvarShadowsDynamic->value <= 1 )
StudioSwapLights();
mstudiobodyparts_t *bp = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex);
int baseindex = 0;
for (int i = 0; i < m_pStudioHeader->numbodyparts; i++)
{
int index = m_pCurrentEntity->curstate.body / bp[i].base;
index = index % bp[i].nummodels;
StudioDrawShadow( m_pShadowHeader->submodels[index + baseindex] );
baseindex += bp[i].nummodels;
}
}
/*
====================
SwapLights Я говорил про эту
Go through each light within the array, see if it's
closer than 512 units, see wich one of these lights
is the closest to our model, and select that as the
light position.
====================
*/
void CStudioModelRenderer::StudioSwapLights ( void )
{
int m_iDist;
vec3_t m_vEntOrigin;
int m_iLightDistArray[1024];
int m_iLightIDArray[1024];
int m_iLightNum = 0;
int m_iLastLowestDist = -1;
int m_iLastLowestDistID = -1;
if( m_iNumRenderEnts && m_pCvarShadowsDynamic->value >= 1 )
{
for( int i = 0; i < m_iNumRenderEnts; i++ )
{
if ( m_pRenderEnts[i]->model->type == mod_brush )
continue;
m_vEntOrigin.x = m_pCurrentEntity->curstate.origin.x;
m_vEntOrigin.y = m_pCurrentEntity->curstate.origin.y;
m_vEntOrigin.z = m_pCurrentEntity->curstate.origin.z + 128;
m_iDist = (m_pRenderEnts[i]->curstate.origin - m_vEntOrigin).Length();
if( m_iDist < 512 )
{
m_iLightDistArray[m_iLightNum] = m_iDist;
m_iLightIDArray[m_iLightNum] = i;
m_iLightNum++;
}
}
if( m_iLightNum )
{
m_iLastLowestDist = -1;
m_iLastLowestDistID = -1;
for ( int j = 0; j < m_iLightNum; j++ )
{
if ( m_iLastLowestDist >= m_iLightDistArray[j]
|| m_iLastLowestDist == -1
&& m_iLastLowestDistID == -1 )
{
m_iLastLowestDist = m_iLightDistArray[j];
m_iLastLowestDistID = m_iLightIDArray[j];
}
}
m_vLightPosition = m_pRenderEnts[m_iLastLowestDistID]->curstate.origin;
m_fShadowType = true;
return;
}
}
m_vShadowAngle[0] = 0.5;
m_vShadowAngle[1] = 1;
m_vShadowAngle[2] = 1.5;
return;
}
/*
====================
DrawShadowVolume
====================
*/
void CStudioModelRenderer::StudioDrawShadow( shadowsubmodel_t &submodel )
{
if ((submodel.faces.size() == 0) || (submodel.faces.size() > MAXSTUDIOTRIANGLES))
return;
vec3_t d;
int i, j;
int neighborIndex;
if ( m_fShadowType == false )
{
VectorScale(m_vShadowAngle, INFINITY, d);
for (i = 0, j = 0; i < submodel.numverts; i++, j+=2)
{
VectorTransform(submodel.vertices[i], (*m_pshadowbonetransform)[submodel.boneindexes[i]], vertexdata[j]);
VectorSubtract(vertexdata[j], d, vertexdata[j+1]);
}
}
else
{
for (i = 0, j = 0; i < submodel.numverts; i++, j+=2)
{
VectorTransform(submodel.vertices[i], (*m_pshadowbonetransform)[submodel.boneindexes[i]], vertexdata[j]);
VectorScale( vertexdata[j]-m_vLightPosition, INFINITY, vertexdata[j+1]);
}
}
for (int j = 0; j < submodel.faces.size(); j++)
{
facelight[j] = StudioFacingLight( submodel.faces[j] );
}
g_Lock.Lock(submodel.numverts * 2);
int trianglecount = 0;
GLushort *inddata = indexdata;
for (int i = 0; i < submodel.faces.size(); i++)
{
Face &triangle = submodel.faces[i];
if ( facelight[i] )
{
inddata[0] = triangle.vertexIndexes[0];
inddata[1] = triangle.vertexIndexes[2];
inddata[2] = triangle.vertexIndexes[1];
inddata[3] = triangle.vertexIndexes[0] + 1;
inddata[4] = triangle.vertexIndexes[1] + 1;
inddata[5] = triangle.vertexIndexes[2] + 1;
inddata += 6;
trianglecount += 2;
for ( int j = 0; j < 3; j++ )
{
neighborIndex = triangle.neighborIndexes[j];
if ( neighborIndex == 65535 || !facelight[neighborIndex] )
{
inddata[0] = triangle.vertexIndexes[j];
inddata[1] = triangle.vertexIndexes[( j+1 )%3];
inddata[2] = inddata[0] + 1;
inddata[3] = inddata[2];
inddata[4] = inddata[1];
inddata[5] = inddata[1] + 1;
inddata += 6;
trianglecount += 2;
}
}
}
}
// We only need one pass.
glDrawElements(GL_TRIANGLES, trianglecount * 3, GL_UNSIGNED_SHORT, indexdata);
g_Lock.Unlock();
g_shadowpolycounter += trianglecount * 2;
}
/*
====================
TriangleFacingLight
See if the given triangle is facing the light origin or vector.
====================
*/
bool CStudioModelRenderer :: StudioFacingLight( Face &triangle )
{
vec_t *v1;
vec_t *v2;
vec_t *v3;
float side;
float planeEq[4];
if ( m_fShadowType == true )
{
v1 = vertexdata[triangle.vertexIndexes[0]];
v2 = vertexdata[triangle.vertexIndexes[1]];
v3 = vertexdata[triangle.vertexIndexes[2]];
planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]);
planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]);
planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]);
planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) +
v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) +
v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) );
side = planeEq[0]*m_vLightPosition[0]+
planeEq[1]*m_vLightPosition[1]+
planeEq[2]*m_vLightPosition[2]+
planeEq[3];
if ( side > 0 )
{
return 1;
}
return 0;
}
else
{
vec3_t v1, v2, norm;
VectorSubtract(vertexdata[triangle.vertexIndexes[1]], vertexdata[triangle.vertexIndexes[0]], v1);
VectorSubtract(vertexdata[triangle.vertexIndexes[2]], vertexdata[triangle.vertexIndexes[1]], v2);
CrossProduct(v2, v1, norm);
if ( DotProduct(norm, m_vShadowAngle) > 0 )
{
return 0;
}
return 1;
}
}
void CStudioModelRenderer::StudioShadowForEntity( cl_entity_t *pEntity )
{
m_pCurrentEntity = pEntity;
m_pRenderModel = m_pCurrentEntity->model;
m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel);
IEngineStudio.StudioSetHeader( m_pStudioHeader );
IEngineStudio.SetRenderModel( m_pRenderModel );
if (m_pStudioHeader->numbodyparts == 0)
return;
m_pshadowbonetransform = (float (*)[MAXSTUDIOBONES][3][4])m_psavedbonetransform[m_pCurrentEntity->index];
StudioSetupShadows();
}
void CStudioModelRenderer::StudioRenderingCheck ( void )
{
if (!IEngineStudio.IsHardware())
{
gEngfuncs.pfnClientCmd("escape\n");
MessageBox(NULL, "VIDEO ERROR: Attempting to run in Software mode!\n\nRaven City does not support the software renderer.\nChange to OpenGL mode\n\nPress Ok to quit the game.\n", "ERROR", MB_OK);
gEngfuncs.Con_Printf("VidInit: Error! Attempting to run in Software mode!\n");
exit( -1 );
}
if ( IEngineStudio.IsHardware() == 2 )
{
gEngfuncs.pfnClientCmd("escape\n");
MessageBox(NULL, "VIDEO ERROR: Attempting to run in Direct3D mode!\n\nRaven City does not support DirectX.\nPlease change to OpenGL mode.\n\nPress Ok to quit the game.\n", "ERROR", MB_OK);
gEngfuncs.Con_Printf("VidInit: Error! Attempting to run in Direct3D mode!\n");
exit( -1 );
}
m_hOpenGL32Dll = LoadLibrary("opengl32.dll");
if (m_hOpenGL32Dll)
{
// check hacked opengl library
if (!StudioCheckExtension("RAVEN_HACKS_V1"))
{
gEngfuncs.pfnClientCmd("escape\n");
MessageBox(NULL, "VIDEO ERROR: Raven City's hacked OpenGL32.dll is missing!\n\nRaven City can't run without the library.\nCopy OpenGL32.dll from raven/sdk/ to the Half-Life folder.\n\nPress Ok to quit the game.\n", "ERROR", MB_OK);
gEngfuncs.Con_Printf("VidInit: Error! Raven City's hacked opengl32.dll is missing!\n");
FreeLibrary( m_hOpenGL32Dll );
m_hOpenGL32Dll = NULL;
exit( -1 );
}
}
}
BOOL CStudioModelRenderer::StudioCheckExtension(const char *ext)
{
const char * extensions = (const char *)glGetString ( GL_EXTENSIONS );
const char * start = extensions;
const char * ptr;
while ( ( ptr = strstr ( start, ext ) ) != NULL )
{
// we've found, ensure name is exactly ext
const char * end = ptr + strlen ( ext );
if ( isspace ( *end ) || *end == '\0' )
return TRUE;
start = end;
}
return FALSE;
}