2020-08-31 18:50:41 +02:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
2020-09-01 14:57:29 +02:00
|
|
|
int i;
|
2020-08-31 18:50:41 +02:00
|
|
|
// find the free sound slot
|
2020-09-01 14:57:29 +02:00
|
|
|
for( i = 0; mat->impact_parts[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
|
2020-08-31 18:50:41 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-09-01 14:57:29 +02:00
|
|
|
int i;
|
2020-08-31 18:50:41 +02:00
|
|
|
// find the free sound slot
|
2020-09-01 14:57:29 +02:00
|
|
|
for( i = 0; mat->impact_sounds[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
|
2020-08-31 18:50:41 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-09-01 14:57:29 +02:00
|
|
|
int i;
|
2020-08-31 18:50:41 +02:00
|
|
|
// find the free sound slot
|
2020-09-01 14:57:29 +02:00
|
|
|
for( i = 0; mat->step_sounds[i] != NULL && i < MAX_MAT_SOUNDS; i++ );
|
2020-08-31 18:50:41 +02:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2020-08-31 00:15:53 +02:00
|
|
|
}
|