Paranoia2/game_shared/material.cpp

345 lines
7.9 KiB
C++

/*
material.cpp - material description for both client and server
Copyright (C) 2015 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef CLIENT_DLL
#include"extdll.h"
#include "util.h"
#else
#include "hud.h"
#include "cl_util.h"
#endif
#include "material.h"
#include "stringlib.h"
#include "com_model.h"
static matdef_t *com_matdef; // pointer to global materials array
static int com_matcount;
static matdef_t *com_defmat;
char *_COM_CopyString( const char *s, const char *file, const int line )
{
if( !s ) return NULL;
char *b = (char *)_Mem_Alloc( Q_strlen( s ) + 1, file, line );
Q_strcpy( b, s );
return b;
}
matdef_t *COM_CreateDefaultMatdef( void )
{
static matdef_t mat;
if( mat.name[0] )
return &mat; // already created
Q_strcpy( mat.name, "default" );
mat.detailName[0] = '\0';
mat.impact_decal = COM_CopyString( "shot" ); // default Paranoia decal
mat.impact_sounds[0] = COM_CopyString( "debris/concrete1.wav" );
mat.impact_sounds[1] = COM_CopyString( "debris/concrete2.wav" );
mat.impact_sounds[0] = COM_CopyString( "debris/concrete3.wav" );
mat.impact_sounds[1] = COM_CopyString( "debris/concrete4.wav" );
mat.step_sounds[0] = COM_CopyString( "player/pl_beton1.wav" );
mat.step_sounds[1] = COM_CopyString( "player/pl_beton2.wav" );
mat.step_sounds[2] = COM_CopyString( "player/pl_beton3.wav" );
mat.step_sounds[3] = COM_CopyString( "player/pl_beton4.wav" );
return &mat;
}
/*
==================
COM_FindMatdef
This function never failed
==================
*/
matdef_t *COM_FindMatdef( const char *name )
{
for( int i = 0; i < com_matcount; i++ )
{
if( !Q_stricmp( name, com_matdef[i].name ))
return &com_matdef[i];
}
ALERT( at_error, "material specific '%s' not found. forcing to defualt\n", name );
return com_defmat;
}
/*
==================
GetLayerIndexForPoint
this function came from q3map2
==================
*/
static char COM_GetLayerIndexForPoint( mfaceinfo_t *land, const Vector &point )
{
Vector size;
if( !land || !land->heightmap )
return -1;
for( int i = 0; i < 3; i++ )
size[i] = ( land->maxs[i] - land->mins[i] );
float s = ( point[0] - land->mins[0] ) / size[0];
float t = ( land->maxs[1] - point[1] ) / size[1];
int x = s * land->heightmap_width;
int y = t * land->heightmap_height;
x = bound( 0, x, ( land->heightmap_width - 1 ));
y = bound( 0, y, ( land->heightmap_height - 1 ));
return land->heightmap[y * land->heightmap_width + x];
}
/*
=================
COM_MatDefFromSurface
safe version to get matdef_t
=================
*/
matdef_t *COM_MatDefFromSurface( msurface_t *surf, const Vector &vecPoint )
{
if( !surf || !surf->texinfo )
return NULL;
mtexinfo_t *tx = surf->texinfo;
int layerNum = COM_GetLayerIndexForPoint( tx->faceinfo, vecPoint );
if( layerNum != -1 && layerNum < MAX_LANDSCAPE_LAYERS )
{
// landscape support
return tx->faceinfo->effects[layerNum];
}
if( !tx->texture )
return NULL;
return surf->texinfo->texture->effects; // epic chain!
}
matdef_t *COM_DefaultMatdef( void )
{
return com_defmat;
}
void COM_InitMatdef( void )
{
ALERT( at_aiconsole, "loading materials.def\n" );
char *afile = (char *)LOAD_FILE( "scripts/materials.def", NULL );
if( !afile )
{
ALERT( at_error, "Cannot open file \"scripts/materials.def\"\n" );
return;
}
char *pfile = afile;
char token[256];
int depth = 0;
com_matcount = 0;
// count materials
while( pfile != NULL )
{
pfile = COM_ParseFile( pfile, token );
if( !pfile ) break;
if( Q_strlen( token ) > 1 )
continue;
if( token[0] == '{' )
{
depth++;
}
else if( token[0] == '}' )
{
com_matcount++;
depth--;
}
}
if( depth > 0 ) ALERT( at_warning, "materials.def: EOF reached without closing brace\n" );
if( depth < 0 ) ALERT( at_warning, "materials.def: EOF reached without opening brace\n" );
com_matdef = (matdef_t *)Mem_Alloc( sizeof( matdef_t ) * com_matcount );
pfile = afile; // start real parsing
int current = 0;
while( pfile != NULL )
{
pfile = COM_ParseFile( pfile, token );
if( !pfile ) break;
if( current >= com_matcount )
{
ALERT ( at_error, "material parse is overrun %d > %d\n", current, com_matcount );
break;
}
matdef_t *mat = &com_matdef[current];
// read the material name
Q_strncpy( mat->name, token, sizeof( mat->name ));
// detail scale default values
mat->detailScale[0] = 10.0f;
mat->detailScale[1] = 10.0f;
// read opening brace
pfile = COM_ParseFile( pfile, token );
if( !pfile ) break;
if( token[0] != '{' )
{
ALERT( at_error, "found %s when expecting {\n", token );
break;
}
while( pfile != NULL )
{
pfile = COM_ParseFile( pfile, token );
if( !pfile )
{
ALERT( at_error, "EOF without closing brace\n" );
goto getout;
}
// description end goto next material
if( token[0] == '}' )
{
current++;
break;
}
else if( !Q_stricmp( token, "impact_decal" ))
{
pfile = COM_ParseFile( pfile, token );
if( !pfile )
{
ALERT( at_error, "hit EOF while parsing 'impact_decal'\n" );
goto getout;
}
mat->impact_decal = COM_CopyString( token );
}
else if( !Q_stricmp( token, "impact_parts" ))
{
while(( pfile = COM_ParseLine( pfile, token )) != NULL )
{
if( !Q_strlen( token )) break; // end of line
int i;
// find the free sound slot
for( i = 0; mat->impact_parts[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
if( i < MAX_MAT_SOUNDS )
{
mat->impact_parts[i] = COM_CopyString( token );
}
}
}
else if( !Q_stricmp( token, "impact_sound" ))
{
while(( pfile = COM_ParseLine( pfile, token )) != NULL )
{
if( !Q_strlen( token )) break; // end of line
int i;
// find the free sound slot
for( i = 0; mat->impact_sounds[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
if( i < MAX_MAT_SOUNDS )
{
mat->impact_sounds[i] = COM_CopyString( token );
}
}
}
else if( !Q_stricmp( token, "step_sound" ))
{
while(( pfile = COM_ParseLine( pfile, token )) != NULL )
{
if( !Q_strlen( token )) break; // end of line
int i;
// find the free sound slot
for( i = 0; mat->step_sounds[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
if( i < MAX_MAT_SOUNDS )
{
mat->step_sounds[i] = COM_CopyString( token );
}
}
}
else if( !Q_stricmp( token, "detailScale" ))
{
pfile = COM_ParseFile( pfile, token );
if( !pfile )
{
ALERT( at_error, "hit EOF while parsing 'detailScale'\n" );
goto getout;
}
Q_atov( mat->detailScale, token, 2 );
mat->detailScale[0] = bound( 0.01f, mat->detailScale[0], 100.0f );
mat->detailScale[1] = bound( 0.01f, mat->detailScale[0], 100.0f );
}
else if( !Q_stricmp( token, "detailmap" ))
{
pfile = COM_ParseFile( pfile, token );
if( !pfile )
{
ALERT( at_error, "hit EOF while parsing 'detailmap'\n" );
goto getout;
}
COM_FixSlashes( token );
Q_strncpy( mat->detailName, token, sizeof( mat->detailName ));
}
else ALERT( at_warning, "Unknown material token %s\n", token );
}
}
getout:
FREE_FILE( afile );
ALERT( at_aiconsole, "%d matdefs parsed\n", current );
com_defmat = NULL;
// search for default material
for( int i = 0; i < com_matcount; i++ )
{
if( !Q_stricmp( "default", com_matdef[i].name ))
{
com_defmat = &com_matdef[i];
break;
}
}
// if default material was not specified by mod-maker - create internal
if( !com_defmat )
{
ALERT( at_warning, "Default material was not specified. Create internal\n" );
com_defmat = COM_CreateDefaultMatdef();
}
}