diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
| commit | c068f22329d5cc722622a2183bbb22eef2093df7 (patch) | |
| tree | 12d56c1aede67988a55e241364606bfbb4dba933 /src/libparsec | |
| download | openparsec-main.tar.xz openparsec-main.zip | |
Diffstat (limited to 'src/libparsec')
118 files changed, 30690 insertions, 0 deletions
diff --git a/src/libparsec/con_arg.cpp b/src/libparsec/con_arg.cpp new file mode 100644 index 0000000..83d97d9 --- /dev/null +++ b/src/libparsec/con_arg.cpp @@ -0,0 +1,1083 @@ +/* + * PARSEC - Argument Parsing + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// local module header +#include "con_arg.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + #include "con_int_sv.h" + #include "con_main_sv.h" +#else // !PARSEC_SERVER + #include "con_int.h" + #include "con_main.h" +#endif // !PARSEC_SERVER + +#include "obj_clas.h" + + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + + +// string constants ----------------------------------------------------------- +// +static char value_missing[] = "value missing."; +static char unknown_key[] = "unknown key."; +static char invalid_value[] = "invalid value syntax."; +static char disallowed_key[] = "key not allowed."; +static char int_list_invalid[] = "int list invalid."; +static char int_list_too_long[] = "int list too long."; +static char int_list_too_short[] = "int list too short."; +static char float_list_invalid[] = "float list invalid."; +static char float_list_too_long[] = "float list too long."; +static char float_list_too_short[] = "float list too short."; +static char flag_value_invalid[] = "invalid flag specified."; +static char invalid_class[] = "invalid object class identifier."; +static char object_spec_needed[] = "object class must be specified."; +static char too_many_strings[] = "exactly one string must be supplied."; +static char string_arg_too_long[] = "string too long."; + + +// scan out all values to specified keys (key/value pairs) -------------------- +// +int ScanKeyValuePairs( key_value_s *table, char *kvstr ) +{ + ASSERT( table != NULL ); + + //NOTE: + // kvstr may be NULL to continue parsing with + // strtok( NULL, " " ). + + // reset all values + int keyno = 0; + for ( keyno = 0; table[ keyno ].key; keyno++ ) + table[ keyno ].value = NULL; + + // scan all supplied key/value pairs + char *key; + while ( ( key = strtok( kvstr, " " ) ) != NULL ) { + // continue in same string + kvstr = NULL; + // check all keys in table + for ( keyno = 0; table[ keyno ].key; keyno++ ) { + if ( strcmp( table[ keyno ].key, key ) == 0 ) { + if ( table[ keyno ].flags & KEYVALFLAG_DISALLOW ) { + CON_AddLine( disallowed_key ); + return FALSE; + } + char *value = strtok( NULL, " " ); + if ( value == NULL ) { + CON_AddLine( value_missing ); + return FALSE; + } + if ( table[ keyno ].flags & KEYVALFLAG_PARENTHESIZE ) { + value = GetParenthesizedName( value ); + if ( value == NULL ) { + CON_AddLine( invalid_value ); + return FALSE; + } + } + if ( table[ keyno ].flags & KEYVALFLAG_IGNORE ) { + sprintf( paste_str, "key %s ignored.", table[ keyno ].key ); + CON_AddLine( paste_str ); + } else { + table[ keyno ].value = value; + } + break; + } + } + if ( table[ keyno ].key == NULL ) { + CON_AddLine( unknown_key ); + return FALSE; + } + } + + // check for mandatory keys + for ( keyno = 0; table[ keyno ].key; keyno++ ) { + if ( table[ keyno ].flags & KEYVALFLAG_MANDATORY ) { + if ( table[ keyno ].value == NULL ) { + sprintf( paste_str, "mandatory key %s missing.", table[ keyno ].key ); + CON_AddLine( paste_str ); + return FALSE; + } + } + } + + return TRUE; +} + + +// convert integer value of key/value pair to int ----------------------------- +// +int ScanKeyValueInt( key_value_s *keyval, int *ival ) +{ + //NOTE: + // returns -1 if value was invalid. + // returns 0 if value was missing. + // returns 1 if value was ok. + + ASSERT( keyval != NULL ); + ASSERT( ival != NULL ); + + // missing value alters nothing + if ( keyval->value == NULL ) { + return 0; + } + + char *errpart; + int32 iparam = (int32) strtol( keyval->value, &errpart, 10 ); + + // invalid value returns error + if ( *errpart != 0 ) { + return -1; + } + + *ival = iparam; + + return 1; +} + + +// convert integer value list of key/value pair to int array ------------------ +// +int ScanKeyValueIntList( key_value_s *keyval, int *ilist, int minlen, int maxlen ) +{ + ASSERT( keyval != NULL ); + ASSERT( ilist != NULL ); + ASSERT( minlen > 0 ); + ASSERT( minlen <= maxlen ); + + char *liststr = keyval->value; + if ( liststr == NULL ) { + return 0; + } + + char *istr; + int cnt = 0; + for ( cnt = 0; (istr = strtok( liststr, " " )); cnt++ ) { + + liststr = NULL; + + if ( cnt >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + + char *errpart; + int iparam1 = -1; + + // check for range specification like "50-70" + char *checkstr = istr; + while ( ( *checkstr >= '0' ) && ( *checkstr <= '9' ) ) + checkstr++; + if ( ( *checkstr == '-' ) && ( checkstr != istr ) ) { + iparam1 = (int) strtol( istr, &errpart, 10 ); + if ( *errpart != '-' ) { + CON_AddLine( int_list_invalid ); + return 0; + } + istr = &checkstr[ 1 ]; + } + + int iparam2 = (int) strtol( istr, &errpart, 10 ); + if ( *errpart != 0 ) { + CON_AddLine( int_list_invalid ); + return 0; + } + + if ( iparam1 != -1 ) { + + // store specified range + if ( iparam1 <= iparam2 ) { + + if ( ( cnt + iparam2 - iparam1 ) >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + cnt += iparam2 - iparam1; + for ( ; iparam1 <= iparam2; iparam1++ ) { + *ilist++ = iparam1; + } + + } else { + + if ( ( cnt + iparam1 - iparam2 ) >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + cnt += iparam1 - iparam2; + for ( ; iparam1 >= iparam2; iparam1-- ) { + *ilist++ = iparam1; + } + } + + } else { + + // store single value + *ilist++ = iparam2; + } + } + + if ( cnt < minlen ) { + CON_AddLine( int_list_too_short ); + return 0; + } + + return cnt; +} + + +// convert bounded integer value list of key/value pair to int array ---------- +// +int ScanKeyValueIntListBounded( key_value_s *keyval, int *ilist, int minlen, int maxlen, int minval, int maxval ) +{ + ASSERT( keyval != NULL ); + ASSERT( ilist != NULL ); + ASSERT( minlen > 0 ); + ASSERT( minlen <= maxlen ); + ASSERT( minval <= maxval ); + + char *liststr = keyval->value; + if ( liststr == NULL ) { + return 0; + } + + char *istr; + int cnt = 0; + for ( cnt = 0; (istr = strtok( liststr, " " )); cnt++ ) { + + liststr = NULL; + + if ( cnt >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + + char *errpart; + int iparam1 = -1; + + // check for range specification like "50-70" + char *checkstr = istr; + while ( ( *checkstr >= '0' ) && ( *checkstr <= '9' ) ) + checkstr++; + if ( ( *checkstr == '-' ) && ( checkstr != istr ) ) { + iparam1 = (int) strtol( istr, &errpart, 10 ); + if ( *errpart != '-' ) { + CON_AddLine( int_list_invalid ); + return 0; + } + istr = &checkstr[ 1 ]; + } + + int iparam2 = (int) strtol( istr, &errpart, 10 ); + if ( *errpart != 0 ) { + CON_AddLine( int_list_invalid ); + return 0; + } + + if ( ( iparam2 < minval ) || ( iparam2 > maxval ) ) { + CON_AddLine( int_list_invalid ); + return 0; + } + + if ( iparam1 != -1 ) { + + if ( ( iparam1 < minval ) || ( iparam1 > maxval ) ) { + CON_AddLine( int_list_invalid ); + return 0; + } + + // store specified range + if ( iparam1 <= iparam2 ) { + + if ( ( cnt + iparam2 - iparam1 ) >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + cnt += iparam2 - iparam1; + for ( ; iparam1 <= iparam2; iparam1++ ) { + *ilist++ = iparam1; + } + + } else { + + if ( ( cnt + iparam1 - iparam2 ) >= maxlen ) { + CON_AddLine( int_list_too_long ); + return 0; + } + cnt += iparam1 - iparam2; + for ( ; iparam1 >= iparam2; iparam1-- ) { + *ilist++ = iparam1; + } + } + + } else { + + // store single value + *ilist++ = iparam2; + } + } + + if ( cnt < minlen ) { + CON_AddLine( int_list_too_short ); + return 0; + } + + return cnt; +} + + +// convert float value of key/value pair to float ----------------------------- +// +int ScanKeyValueFloat( key_value_s *keyval, float *fval ) +{ + //NOTE: + // returns -1 if value was invalid. + // returns 0 if value was missing. + // returns 1 if value was ok. + + ASSERT( keyval != NULL ); + ASSERT( fval != NULL ); + + // missing value alters nothing + if ( keyval->value == NULL ) { + return 0; + } + + char *errpart; + double fparam = strtod( keyval->value, &errpart ); + + // invalid value returns error + if ( *errpart != 0 ) { + return -1; + } + + *fval = (float)fparam; + + return 1; +} + + +// convert float value list of key/value pair to float array ------------------ +// +int ScanKeyValueFloatList( key_value_s *keyval, float *flist, int minlen, int maxlen ) +{ + ASSERT( keyval != NULL ); + ASSERT( flist != NULL ); + ASSERT( minlen > 0 ); + ASSERT( minlen <= maxlen ); + + char *liststr = keyval->value; + if ( liststr == NULL ) { + return 0; + } + + char *fstr; + int cnt = 0; + for ( cnt = 0; (fstr = strtok( liststr, " " )); cnt++ ) { + + liststr = NULL; + + if ( cnt >= maxlen ) { + CON_AddLine( float_list_too_long ); + return 0; + } + + char *errpart; + double fparam = strtod( fstr, &errpart ); + if ( *errpart != 0 ) { + CON_AddLine( float_list_invalid ); + return 0; + } + + *flist++ = (float)fparam; + } + + if ( cnt < minlen ) { + CON_AddLine( float_list_too_short ); + return 0; + } + + return cnt; +} + + +// convert bounded float value list of key/value pair to float array ---------- +// +int ScanKeyValueFloatListBounded( key_value_s *keyval, float *flist, int minlen, int maxlen, float minval, float maxval ) +{ + ASSERT( keyval != NULL ); + ASSERT( flist != NULL ); + ASSERT( minlen > 0 ); + ASSERT( minlen <= maxlen ); + ASSERT( minval <= maxval ); + + char *liststr = keyval->value; + if ( liststr == NULL ) { + return 0; + } + + char *fstr; + int cnt = 0; + for ( cnt = 0; (fstr = strtok( liststr, " " )); cnt++ ) { + + liststr = NULL; + + if ( cnt >= maxlen ) { + CON_AddLine( float_list_too_long ); + return 0; + } + + char *errpart; + double fparam = strtod( fstr, &errpart ); + if ( *errpart != 0 ) { + CON_AddLine( float_list_invalid ); + return 0; + } + + if ( ( fparam < minval ) || ( fparam > maxval ) ) { + CON_AddLine( float_list_invalid ); + return 0; + } + + *flist++ = (float)fparam; + } + + if ( cnt < minlen ) { + CON_AddLine( float_list_too_short ); + return 0; + } + + return cnt; +} + + +// convert flag value list of key/value pair to single flagword --------------- +// +int ScanKeyValueFlagList( key_value_s *keyval, dword *flagword, flag_map_s *flagmap ) +{ + ASSERT( keyval != NULL ); + ASSERT( flagword != NULL ); + ASSERT( flagmap != NULL ); + + char *liststr = keyval->value; + if ( liststr == NULL ) { + return 0; + } + + char *fstr; + int cnt = 0; + for ( cnt = 0; (fstr = strtok( liststr, " " )); cnt++ ) { + + liststr = NULL; + + // look for flag spec match + flag_map_s *map = NULL; + for ( map = flagmap; map->name != NULL; map++ ) { + if ( stricmp( fstr, map->name ) == 0 ) { + break; + } + } + if ( map->name == NULL ) { + CON_AddLine( flag_value_invalid ); + return 0; + } + + // set corresponding bit + *flagword |= map->value; + } + + return cnt; +} + + +// convert class spec (either class name or id) of key/value pair to id ------- +// +dword ScanKeyValueObjClass( key_value_s *keyval, int keyclass, int keyid ) +{ + ASSERT( keyval != NULL ); + + dword objclass = CLASS_ID_INVALID; + + // if name was specified try to get class id via name lookup + char *classname = keyval[ keyclass ].value; + if ( classname != NULL ) { + objclass = OBJ_FetchObjectClassId( classname ); + if ( objclass == CLASS_ID_INVALID ) { + CON_AddLine( invalid_class ); + return CLASS_ID_INVALID; + } + } + + // if the name was not found, try the id + if ( objclass == CLASS_ID_INVALID ) { + if ( ScanKeyValueInt( &keyval[ keyid ], (int*)&objclass ) < 0 ) { + CON_AddLine( invalid_class ); + return CLASS_ID_INVALID; + } + } + + // if neither name nor id was specified print error msg + if ( objclass == CLASS_ID_INVALID ) { + CON_AddLine( object_spec_needed ); + return CLASS_ID_INVALID; + } + + if ( objclass >= ( (dword)NumObjClasses ) ) { + CON_AddLine( invalid_class ); + return CLASS_ID_INVALID; + } + + return objclass; +} + + +// parse name that may be parenthesized to allow inclusion of whitespace ------ +// +char *GetParenthesizedName( char *name ) +{ + ASSERT( name != NULL ); + + if ( *name == '(' ) { + + // skip leftmost parenthesis + name++; + + int opened = 1; + int closed = 0; + + // concatenate fields + char *nextfield = name; + for ( ;; ) { + + // count enclosed parentheses + for ( ; *nextfield != 0; nextfield++ ) { + if ( *nextfield == '(' ) + opened++; + else if ( *nextfield == ')' ) + closed++; + } + // check for rightmost parenthesis + if ( *( nextfield - 1 ) == ')' ) { + if ( closed == opened ) { + // strip rightmost parenthesis + *( nextfield - 1 ) = 0; + return name; + } + } + + // replace '\0' by ' ' + *nextfield = ' '; + + // fetch next field + nextfield = strtok( NULL, " " ); + if ( nextfield == NULL ) + return NULL; + } + } + + return name; +} + + +// get int parameter from behind a command string ----------------------------- +// +int GetIntBehindCommand( char *cstr, int32 *iarg, int base, int paramoptional ) +{ + //NOTE: + // this function returns TRUE only if the int parameter + // could be parsed correctly. otherwise an error message + // will be displayed and FALSE returned. this implicates + // that quiet syntax error detection is not possible. + // (exception: missing parameter if it is optional. in + // this case paramoptional will be returned to the caller + // who must ensure to react correctly.) + + ASSERT( cstr != NULL ); + ASSERT( iarg != NULL ); + + // check if there is a space between command and argument + if ( ( *cstr != ' ' ) && ( *cstr != 0 ) ) { + CON_AddLine( unknown_command ); + return FALSE; + } + + // split off first token (int parameter) + char *istr = strtok( cstr, " " ); + + if ( istr == NULL ) { + if ( !paramoptional ) + CON_AddLine( arg_missing ); + return paramoptional; + } + + // check if more than one parameter + if ( strtok( NULL, " " ) != NULL ) { + CON_AddLine( too_many_args ); + return FALSE; + } + + // convert int parameter + char *errpart; + int32 iparam = (int32) strtol( istr, &errpart, base ); + + if ( *errpart != 0 ) { + CON_AddLine( invalid_arg ); + return FALSE; + } + + *iarg = iparam; + return TRUE; +} + + +// get argument string that has to be separated with at least one space ------- +// +const char *GetStringBehindCommand( char *scan, int paramoptional ) +{ + //NOTE: + // this function returns non-NULL only if the string parameter + // could be parsed correctly. otherwise an error message + // will be displayed and NULL returned. this implicates + // that quiet syntax error detection is not possible. + // (exception: missing parameter if it is optional.) + + //NOTE: + // if the parameter is optional this function + // will return an empty string (""). + + ASSERT( scan != NULL ); + + // check if there is a space between command and argument + if ( ( *scan != 0 ) && ( *scan != ' ' ) ) { + CON_AddLine( unknown_command ); + return NULL; + } + + // eat whitespace + while ( *scan == ' ' ) + scan++; + + // no argument found? + if ( *scan == 0 ) { + if ( paramoptional ) { + // return empty string + return ""; + } else { + // return error + CON_AddLine( arg_missing ); + return NULL; + } + } + + // cut off trailing whitespace + char *start = scan; + while ( *scan != 0 ) + scan++; + while ( *--scan == ' ' ) + {} + *( scan + 1 ) = 0; + + // return isolated part (may contain whitespace in the middle!) + return start; +} + + +// generic string set function ------------------------------------------------ +// +int SetSingleStringCommand( char *cstr, char *dst, int dstmaxlen ) +{ + ASSERT( cstr != NULL ); + ASSERT( dst != NULL ); + ASSERT( dstmaxlen > 0 ); + + // check if there is a space between command and argument + if ( ( *cstr != ' ' ) && ( *cstr != 0 ) ) { + CON_AddLine( unknown_command ); + return FALSE; + } + + char *name = strtok( cstr, " " ); + + if ( name == NULL ) { + CON_AddLine( dst ); + return FALSE; + } + + if ( strtok( NULL, " " ) != NULL ) { + CON_AddLine( too_many_strings ); + return FALSE; + } + + if ( ( (int)strlen( name ) ) > dstmaxlen ) { + CON_AddLine( string_arg_too_long ); + return FALSE; + } + + strcpy( dst, name ); + return TRUE; +} + + +// query/retrieve single int argument ----------------------------------------- +// +char *QueryIntArgument( const char *query, int *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( arg != NULL ); + + char *scan = strtok( NULL, " " ); + if ( scan != NULL ) { + if ( strtok( NULL, " " ) == NULL ) { + return scan; + } else { + CON_AddLine( too_many_args ); + } + } else if ( query != NULL ) { + sprintf( paste_str, query, *arg ); + CON_AddLine( paste_str ); + } else { + CON_AddLine( arg_missing ); + } + + return NULL; +} + + +// query/retrieve single int argument not using strtok( NULL, ... ) ----------- +// +char *QueryIntArgumentEx( char *params, const char *query, int *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( params != NULL ); + ASSERT( arg != NULL ); + + char *scan = strtok( params, " " ); + if ( scan != NULL ) { + if ( strtok( NULL, " " ) == NULL ) { + return scan; + } else { + CON_AddLine( too_many_args ); + } + } else if ( query != NULL ) { + sprintf( paste_str, query, *arg ); + CON_AddLine( paste_str ); + } else { + CON_AddLine( arg_missing ); + } + + return NULL; +} + + +// query/retrieve single float argument --------------------------------------- +// +char *QueryFltArgument( const char *query, float *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( arg != NULL ); + + char *scan = strtok( NULL, " " ); + if ( scan != NULL ) { + if ( strtok( NULL, " " ) == NULL ) { + return scan; + } else { + CON_AddLine( too_many_args ); + } + } else if ( query != NULL ) { + sprintf( paste_str, query, *arg ); + CON_AddLine( paste_str ); + } else { + CON_AddLine( arg_missing ); + } + + return NULL; +} + + +// query/retrieve single float argument not using strtok( NULL, ... ) --------- +// +char *QueryFltArgumentEx( char *params, const char *query, float *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( params != NULL ); + ASSERT( arg != NULL ); + + char *scan = strtok( params, " " ); + if ( scan != NULL ) { + if ( strtok( NULL, " " ) == NULL ) { + return scan; + } else { + CON_AddLine( too_many_args ); + } + } else if ( query != NULL ) { + sprintf( paste_str, query, *arg ); + CON_AddLine( paste_str ); + } else { + CON_AddLine( arg_missing ); + } + + return NULL; +} + + +// check command that alters an int value ------------------------------------- +// +int CheckSetIntArgument( const char *query, const char *scan, const char *command, int *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( scan != NULL ); + ASSERT( command != NULL ); + ASSERT( arg != NULL ); + + if ( strcmp( scan, command ) == 0 ) { + if ( (scan = QueryIntArgument( query, arg )) ) { + char *errpart; + int sval = (int) strtol( scan, &errpart, int_calc_base ); + if ( *errpart == 0 ) { + *arg = sval; + } else { + CON_AddLine( invalid_arg ); + } + } + return TRUE; + } else { + return FALSE; + } +} + + +// check command that alters a float value ------------------------------------ +// +int CheckSetFltArgument( const char *query, const char *scan, const char *command, float *arg ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( scan != NULL ); + ASSERT( command != NULL ); + ASSERT( arg != NULL ); + + if ( strcmp( scan, command ) == 0 ) { + if ( (scan = QueryFltArgument( query, arg )) ) { + char *errpart; + float sval = (float)strtod( scan, &errpart ); + if ( *errpart == 0 ) { + *arg = sval; + } else { + CON_AddLine( invalid_arg ); + } + } + return TRUE; + } else { + return FALSE; + } +} + + +// check command that alters an int value with guaranteed bounds -------------- +// +int CheckSetIntArgBounded( const char *query, const char *scan, char *command, int *arg, int bmin, int bmax, void (*func)() ) +{ + //NOTE: + // this function accepts delta arguments. instead of + // an absolute value ++val or --val may be supplied + // to specify a value that should be added to or + // subtracted from the current value, respectively. + + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( scan != NULL ); + ASSERT( command != NULL ); + ASSERT( arg != NULL ); + ASSERT( bmin <= bmax ); + + if ( strcmp( scan, command ) == 0 ) { + if ( (scan = QueryIntArgument( query, arg )) ) { + + // determine if delta modification (++/--) + int delta = 0; + if ( ( scan[ 0 ] == '+' ) && ( scan[ 1 ] == '+' ) ) + delta = 1; + else if ( ( scan[ 0 ] == '-' ) && ( scan[ 1 ] == '-' ) ) + delta = -1; + if ( delta != 0 ) + scan += 2; + + if ( *scan != 0 ) { + char *errpart; + int sval = (int) strtol( scan, &errpart, int_calc_base ); + if ( *errpart == 0 ) { + if ( delta != 0 ) + sval = *arg + sval * delta; + if ( sval >= bmin && sval <= bmax ) { + *arg = sval; + if ( func != NULL ) + (*func)(); + } else { + CON_AddLine( range_error ); + } + } else { + CON_AddLine( invalid_arg ); + } + } else { + CON_AddLine( invalid_arg ); + } + } + return TRUE; + } else { + return FALSE; + } +} + + +// check commands that manipulate int array contents -------------------------- +// +int CheckSetIntArray( const char *query, char *scan, char *comstub, int *array, int numelements ) +{ + //NOTE: + // query may be NULL, indicating that the variable + // may be queried by not supplying any argument. + + ASSERT( scan != NULL ); + ASSERT( comstub != NULL ); + ASSERT( array != NULL ); + ASSERT( numelements > 0 ); + + size_t cslen = strlen( comstub ); + + if ( strncmp( scan, comstub, cslen ) == 0 ) { + + int indx; + int ndig = 0; + + if ( ( strlen( scan ) == cslen + 2 ) && + isdigit( scan[ cslen + 0 ] ) && + isdigit( scan[ cslen + 1 ] ) ) { + ndig = 2; + indx = ( scan[ cslen ] - '0' ) * 10 + scan[ cslen + 1 ] - '0'; + } else if ( ( strlen( scan ) == cslen + 3 ) && + isdigit( scan[ cslen + 0 ] ) && + isdigit( scan[ cslen + 1 ] ) && + isdigit( scan[ cslen + 2 ] ) ) { + ndig = 3; + indx = ( scan[ cslen ] - '0' ) * 100 + ( scan[ cslen + 1 ] - '0' ) * 10 + scan[ cslen + 2 ] - '0'; + } + + if ( ndig > 0 ) { + if ( indx < numelements ) { + int *arg = array + indx; + if ( (scan = QueryIntArgument( query, arg )) ) { + char *errpart; + int sval = (int) strtol( scan, &errpart, int_calc_base ); + if ( *errpart == 0 ) { + *arg = sval; + } else { + CON_AddLine( invalid_arg ); + } + } + return TRUE; + } else { + return FALSE; + } + } else { + return FALSE; + } + } else { + return FALSE; + } +} + + +// check argument that alters a single string --------------------------------- +// +int CheckSetStrArgument( int query, char *scan, char *command, char *string, int maxlen ) +{ + ASSERT( ( query == FALSE ) || ( query == TRUE ) ); + ASSERT( scan != NULL ); + ASSERT( command != NULL ); + ASSERT( string != NULL ); + ASSERT( maxlen > 0 ); + + if ( strcmp( scan, command ) == 0 ) { + if ( (scan = strtok( NULL, " " )) ) { + if ( !strtok( NULL, " " ) ) { + strncpy( string, scan, maxlen ); + string[ maxlen ] = 0; + } else { + CON_AddLine( too_many_args ); + } + } else { + if ( query ) { + CON_AddLine( string ); + } else { + CON_AddLine( arg_missing ); + } + } + return TRUE; + } else { + return FALSE; + } +} + + + diff --git a/src/libparsec/con_tab.cpp b/src/libparsec/con_tab.cpp new file mode 100644 index 0000000..bb9309a --- /dev/null +++ b/src/libparsec/con_tab.cpp @@ -0,0 +1,312 @@ +/* + * PARSEC - Command Completion + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:40 $ + * + * Orginally written by: + * Copyright (c) Andreas Varga <sid@parsec.org> 1998-1999 + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#ifdef PARSEC_CLIENT + #include "aud_defs.h" +#endif // PARSEC_CLIENT + +// local module header +#include "con_tab.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + + #include "con_act_sv.h" + #include "con_aux_sv.h" + #include "con_com_sv.h" + #include "con_ext_sv.h" + #include "con_int_sv.h" + #include "con_main_sv.h" + #include "con_std_sv.h" + +#else // !PARSEC_SERVER + + #include "con_act.h" + #include "con_aux.h" + #include "con_com.h" + #include "con_conf.h" + #include "con_ext.h" + #include "con_int.h" + #include "con_main.h" + #include "con_std.h" + +#endif // PARSEC_SERVER + + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + +#if ( PASTE_STR_LEN < MAX_CONSOLE_LINE_LENGTH ) + #error "CON_TAB::paste_str too short!" +#endif + + +// maximum number of possible completions that will be shown ------------------ +// +#define MAX_COMPLETIONS 64 + + +// list of possible completions found ----------------------------------------- +// +static const char* found_names[ MAX_COMPLETIONS ]; +static int found_param[ MAX_COMPLETIONS ]; + + +// commands to check in current run ------------------------------------------- +// +enum { + + CHECK_STDCOMMS, + CHECK_USRCOMMS, + CHECK_INTCOMMS, + CHECK_EXTCOMMS, + CHECK_ACTCOMMS, +#ifdef PARSEC_CLIENT + CHECK_COLCOMMS, +#endif // PARSEC_CLIENT + + // must be last!! + CHECK_NUM_COMMS +}; + +static int num_commands[ CHECK_NUM_COMMS ]; + + +// <tab> key pressed in console ----------------------------------------------- +// +void CompleteCommand() +{ + // skip prompt + char* curinput = &con_lines[ con_bottom ][ PROMPT_SIZE ]; + int skiplen = PROMPT_SIZE; + + // only complete commands starting in first column + if ( ( curinput[ 0 ] == ' ' ) || ( curinput[ 0 ] == 0 ) ) + return; + +#ifdef PARSEC_CLIENT + + // handle talkmode + if ( con_in_talk_mode ) { + + // only complete commands + if ( curinput[ 0 ] != talk_escape_char ) { + + if ( !AUX_DISABLE_TALK_ESCAPE_ON_TAB ) { + int maxlen = MAX_CONSOLE_LINE_LENGTH - PROMPT_SIZE - 1; + strncpy( paste_str, curinput, maxlen ); + paste_str[ maxlen ] = 0; + curinput[ 0 ] = talk_escape_char; + strcpy( curinput + 1, paste_str ); + } else { + return; + } + } + + // skip command escape + curinput++; + skiplen++; + } + +#endif // PARSEC_CLIENT + + int inputlen = (int)strlen( curinput ); + + // fetch current numbers for all types + num_commands[ CHECK_STDCOMMS ] = num_std_commands; + num_commands[ CHECK_USRCOMMS ] = num_user_commands; + num_commands[ CHECK_INTCOMMS ] = num_int_commands; + num_commands[ CHECK_EXTCOMMS ] = num_external_commands; + num_commands[ CHECK_ACTCOMMS ] = ACM_NUM_COMMANDS; +#ifdef PARSEC_CLIENT + num_commands[ CHECK_COLCOMMS ] = num_col_commands; +#endif // PARSEC_CLIENT + + // check all command types + int numfound = 0; + for ( int cmdtyp = 0; cmdtyp < CHECK_NUM_COMMS; cmdtyp++ ) { + + // check all commands of current type + for ( int curcmd = 0; curcmd < num_commands[ cmdtyp ]; curcmd++ ) { + + if ( ( cmdtyp == CHECK_ACTCOMMS ) && !ACMCALLABLE( curcmd ) ) + continue; + + const char* name; + int para; + + switch ( cmdtyp ) { + + case CHECK_STDCOMMS: + name = CMSTR( curcmd ); + para = CMARG( curcmd ); + break; + + case CHECK_USRCOMMS: + name = USRSTR( curcmd ); + para = USRARG( curcmd ); + break; + + case CHECK_INTCOMMS: + name = ICMSTR( curcmd ); + para = 1; + break; + + case CHECK_EXTCOMMS: + name = ECMSTR( curcmd ); + para = 0; + break; + + case CHECK_ACTCOMMS: + name = ACMSTR( curcmd ); + para = 0; + break; +#ifdef PARSEC_CLIENT + case CHECK_COLCOMMS: + name = col_comms[ curcmd ].cmd; + para = -1; + break; +#endif // PARSEC_CLIENT + } + + // count number of equal chars + int cpos = 0; + for ( cpos = 0; cpos < inputlen; cpos++ ) + if ( curinput[ cpos ] != name[ cpos ] ) + break; + + if ( cpos == inputlen ) { + + // we either found a valid command or at least + // a partially complete one + + if ( numfound >= MAX_COMPLETIONS ) + break; + + found_names[ numfound ] = name; + found_param[ numfound ] = para; + numfound++; + } + } + } + + if ( numfound == 1 ) { + + // we've found just a single valid completion, so let's take it + strcpy( curinput, found_names[ 0 ] ); + + // special case for color commands + if ( found_param[ 0 ] == -1 ) { + int len = (int)strlen( curinput ); + curinput[ len - 2 ] = 0; + curinput[ len - 1 ] = 0; + found_param[ 0 ] = 0; + } + + // if command has parameters automatically append space + if ( found_param[ 0 ] > 0 ) { + strcat( curinput, " " ); + } + + } else { + +#ifdef PARSEC_CLIENT + // we beep if we have found multiple possible + // completions or none at all + AUD_Select2(); +#endif // PARSEC_CLIENT + + // list possible completions and print common prefix + if ( numfound > 1 ) { + + // save the original input line + strcpy( paste_str, con_lines[ con_bottom ] ); + + // overwrite old line in talkmode + if ( con_in_talk_mode ) { + con_bottom = con_talk_line; + CON_DisableLineFeed(); + } + + const char *common = found_names[ 0 ]; + int comlen = (int)strlen( common ); + + // print the list of completions + for ( int cnum = 0; cnum < numfound; cnum++ ) { + + const char *curname = found_names[ cnum ]; + + // maintain common prefix length + int cpos = 0; + for ( cpos = 0; cpos < comlen; cpos++ ) + if ( curname[ cpos ] != common[ cpos ] ) + break; + if ( cpos < comlen ) + comlen = cpos; + + CON_AddLine( curname ); + } +#ifdef PARSEC_CLIENT + // print the common prefix + strncpy( paste_str + skiplen, common, comlen ); + paste_str[ skiplen + comlen ] = 0; + CON_AddLine( paste_str ); +#elif PARSEC_SERVER + extern void EraseConLine( int line ); + // output supplied line + EraseConLine( con_bottom ); + strcpy( con_lines[ con_bottom ], paste_str ); +#endif // PARSEC_CLIENT + } + } + + // set cursor position to end of line + cursor_x = (int)strlen( con_lines[ con_bottom ] + PROMPT_SIZE ); +} + + + diff --git a/src/libparsec/con_vald.cpp b/src/libparsec/con_vald.cpp new file mode 100644 index 0000000..8b75233 --- /dev/null +++ b/src/libparsec/con_vald.cpp @@ -0,0 +1,94 @@ +/* + * PARSEC - Valid ASCII Characters + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:40 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1997-1998 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// local module header +#include "con_vald.h" + + +// table indicating if an ASCII character is valid in console ----------------- +// +int ConsoleASCIIValid[ CON_ASCII_TABLE_LEN ] = { + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 1, // ' ' + 1, // '!' + 1, // '"' + 1, // '#' + 1, // '$' + 1, // '%' + 0, // '&' + 1, // ''' + 1, // '(' + 1, // ')' + 1, // '*' + 1, // '+' + 1, // ',' + 1, // '-' + 1, // '.' + 1, // '/' + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' + + 1, // ':' + 1, // ';' + 1, // '<' + 1, // '=' + 1, // '>' + 1, // '?' + 1, // '@' + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'Z' + + 1, // '[' + 0, // '\' + 1, // ']' + 0, // '^' + 1, // '_' + 0, // '`' + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'z' + + 0, // '{' + 1, // '|' + 0, // '}' + 0, // '~' + 0 + +}; + + + diff --git a/src/libparsec/debug.cpp b/src/libparsec/debug.cpp new file mode 100644 index 0000000..856900d --- /dev/null +++ b/src/libparsec/debug.cpp @@ -0,0 +1,497 @@ +/* + * PARSEC - Debug Support Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:39 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +// global compilation options +#include "config.h" + +// for cleanup function +#include "gd_type.h" +#ifdef PARSEC_SERVER + #include "sys_err_sv.h" +#else + #include "sys_err.h" + #include "sys_glob.h" +#endif + + +// local module header +#include "debug.h" + + +// flags +//#define REGISTER_MCBDUMP_COMMAND +//#define WRITE_MALLOC_FREE_LOG + + + +// log file names ------------------------------------------------------------- +// +#ifdef WRITE_MALLOC_FREE_LOG + static char use_log_name[] = "memuse.log"; +#endif + +#ifdef REGISTER_MCBDUMP_COMMAND + static char mcb_log_name[] = "mcbdump.log"; +#endif + + +#ifdef USE_ALIGNED_MEMBLOCKS // ----------------------------------------------- + + +// alignment to enforce for all allocated memory blocks +#define MEMBLOCK_ALIGNMENT_VAL 0x1f // align to 32 byte boundary +#define MEMBLOCK_ALIGNMENT_MASK (~MEMBLOCK_ALIGNMENT_VAL) + + +// malloc wrapper that enforces a guaranteed block alignment ------------------ +// +void* _AlignedMalloc( size_t size ) +{ + void *temp = HEAP_ALLOC( size + ( MEMBLOCK_ALIGNMENT_VAL + 1 ) * 2 ); + + if ( temp == NULL ) + return NULL; + + size_t alignmentpadding = ( ( (size_t)temp + MEMBLOCK_ALIGNMENT_VAL ) & MEMBLOCK_ALIGNMENT_MASK ) - (size_t)temp; + + size_t *alignhead = (size_t *) ( (size_t)temp + alignmentpadding ); + *alignhead = (size_t)temp; + +#if defined( WRITE_MALLOC_FREE_LOG ) && !defined( LOG_MEMORY_BLOCKS ) + + refframe_t SYSs_GetRefFrameCount(); + refframe_t currefframe = SYSs_GetRefFrameCount(); + + FILE *fp = fopen( use_log_name, "a" ); + if ( fp != NULL ) { + fprintf( fp, "[%03d.%03d.%03d.%03d] A_ALLOC: 0x%08X (%d)\n", + ( ( currefframe >> 24 ) & 0xff ), + ( ( currefframe >> 16 ) & 0xff ), + ( ( currefframe >> 8 ) & 0xff ), + ( currefframe & 0xff ), + (size_t)alignhead + MEMBLOCK_ALIGNMENT_VAL + 1, size ); + fclose( fp ); + } + +#endif + + return (void*)( (size_t)alignhead + MEMBLOCK_ALIGNMENT_VAL + 1 ); +} + + +// free wrapper needed if aligned mallocs used -------------------------------- +// +void _AlignedFree( void *mem ) +{ + +#if defined( WRITE_MALLOC_FREE_LOG ) && !defined( LOG_MEMORY_BLOCKS ) + + refframe_t SYSs_GetRefFrameCount(); + refframe_t currefframe = SYSs_GetRefFrameCount(); + + FILE *fp = fopen( use_log_name, "a" ); + if ( fp != NULL ) { + fprintf( fp, "[%03d.%03d.%03d.%03d] A_FREE : 0x%08X\n", + ( ( currefframe >> 24 ) & 0xff ), + ( ( currefframe >> 16 ) & 0xff ), + ( ( currefframe >> 8 ) & 0xff ), + ( currefframe & 0xff ), + (size_t)mem ); + fclose( fp ); + } + +#endif + + HEAP_FREE( (void*) ( *(size_t*)( (size_t)mem - ( MEMBLOCK_ALIGNMENT_VAL + 1 ) ) ) ); +} + + +// redefine heap functions to enforce alignment ------------------------------- +// +#undef HEAP_ALLOC +#undef HEAP_FREE + +#define HEAP_ALLOC _AlignedMalloc +#define HEAP_FREE _AlignedFree + + +#endif // USE_ALIGNED_MEMBLOCKS ----------------------------------------------- + + + +// memory alloc/free/size counters + +unsigned int Num_Allocs = 0; +unsigned int Num_Frees = 0; +unsigned int Dyn_Mem_Size = 0; + + +// include system debugging functions ----------------------------------------- +// +#include "debugsys.h" + + + +#ifdef LOG_MEMORY_BLOCKS // --------------------------------------------------- + + +// structure for logging allocated memory blocks ------------------------------ +// +struct MCB_Log { + + MCB_Log* next; // next block in loglist + size_t size; // size of memblock (incl. signature) + void* address; // blockaddress (pointer to head-sig) + void* caller; // address of ALLOCMEM call (owner) +}; + +MCB_Log *McbLogList = NULL; + + +#define MCB_SIG_SIZE 32 +static char mcb_signature[] = "msh MCB BlockCheckerBoundarySig"; + + +// insert new log-block into list --------------------------------------------- +// +void InsertMcbLog( void *address, size_t size, void *caller ) +{ + MCB_Log *temp = (MCB_Log *) HEAP_ALLOC( sizeof( MCB_Log ) ); + ASSERT( temp != NULL ); + + temp->address = address; + temp->caller = caller; + temp->size = size; + temp->next = McbLogList; + McbLogList = temp; +} + + +// delete log-block from list ------------------------------------------------- +// +void DeleteMcbLog( void *address ) +{ + MCB_Log *prev = NULL; + + for ( MCB_Log *temp = McbLogList; temp; temp = temp->next ) { + + if ( temp->address == address ) { + if ( prev == NULL ) { + McbLogList = temp->next; + HEAP_FREE( temp ); + return; + } else { + prev->next = temp->next; + HEAP_FREE( temp ); + return; + } + } + + prev = temp; + } + + ASSERT( 0 ); +} + + +// get pointer to log-block --------------------------------------------------- +// +MCB_Log *GetMcbLog( void *address ) +{ + for ( MCB_Log *temp = McbLogList; temp; temp = temp->next ) { + + if ( temp->address == address ) + return temp; + } + +// ASSERT( 0 ); + return NULL; +} + + +#endif // LOG_MEMORY_BLOCKS -------------------------------------------------- + + + +#ifdef EXTENSIVE_MEMORY_CHECKS // --------------------------------------------- + + +#ifndef LOG_MEMORY_BLOCKS + #error "inconsistent debugging specs." +#endif + + +// check if ref is a valid base address of any heap block --------------------- +// +void _CheckHeapBaseRef( void *ref ) +{ + ref = (void *) ( (char*)ref - MCB_SIG_SIZE ); + ASSERT( GetMcbLog( ref ) != NULL ); +} + + +// check if ref is a valid pointer into any heap block ------------------------ +// +void _CheckHeapRef( void *ref ) +{ + for ( MCB_Log *temp = McbLogList; temp; temp = temp->next ) { + + if ( ( (unsigned)temp->address <= (unsigned)ref-MCB_SIG_SIZE ) && + ( ((unsigned)temp->address+temp->size-MCB_SIG_SIZE) > (unsigned)ref ) ) + return; + } + + ASSERT( 0 ); +} + + +// check integrity of all dynamically allocated memory blocks ----------------- +// +void _CheckMemIntegrity() +{ + int nummcbs = 0; + for ( MCB_Log *temp = McbLogList; temp; temp = temp->next, nummcbs++ ) { + + int corrupt1 = ( strcmp( (char*)temp->address, mcb_signature ) != 0 ); + int corrupt2 = ( strcmp( (char*)temp->address+temp->size-MCB_SIG_SIZE, mcb_signature ) != 0 ); + + // make breakpoint setting easy + if ( corrupt1 || corrupt2 ) { + ASSERT( 0 ); + } + } + + ASSERT( nummcbs == ( Num_Allocs - Num_Frees ) ); +} + + +#endif // EXTENSIVE_MEMORY_CHECKS --------------------------------------------- + + + +#ifdef LOG_MEMORY_BLOCKS // --------------------------------------------------- + + +// allocate memory block ------------------------------------------------------ +// +void* _LogAllocMem( size_t size ) +{ + // first thing: retrieve caller's address + void *caller; + GETCALLER( caller ) + + ASSERT( size > 0 ); + + size += MCB_SIG_SIZE * 2; + + void *temp = HEAP_ALLOC( size ); + ASSERT( temp != NULL ); + + Num_Allocs++; + Dyn_Mem_Size += size; + + // log mem allocation + InsertMcbLog( temp, size, caller ); + + unsigned *filldw = (unsigned *) temp; + size_t siz4 = size / 4; + while ( siz4-- > 0 ) + *filldw++ = 0xCCCCCCCC; + + unsigned char *fillb = (unsigned char *) filldw; + siz4 = size % 4; + while ( siz4-- > 0 ) + *fillb++ = 0xCC; + + strcpy( (char*)temp, mcb_signature ); + strcpy( (char*)temp + size - MCB_SIG_SIZE, mcb_signature ); + + return (void *) ( (char*)temp + MCB_SIG_SIZE ); +} + + +// free memory block ---------------------------------------------------------- +// +void _LogFreeMem( void *mem ) +{ + ASSERT( mem != NULL ); + +#ifdef CHECK_MEM_INTEGRITY_ON_FREE + +#ifndef EXTENSIVE_MEMORY_CHECKS + #error "inconsistent debugging specs." +#endif + + CHECKMEMINTEGRITY(); + +#endif + + mem = (void *) ( (char*)mem - MCB_SIG_SIZE ); + + MCB_Log *log = GetMcbLog( mem ); + ASSERT( log != NULL ); + + size_t size = log->size; + + DeleteMcbLog( mem ); + + unsigned *filldw = (unsigned *) mem; + size_t siz4 = size / 4; + while ( siz4-- > 0 ) + *filldw++ = 0xCCCCCCCC; + + unsigned char *fillb = (unsigned char *) filldw; + siz4 = size % 4; + while ( siz4-- > 0 ) + *fillb++ = 0xCC; + + HEAP_FREE( mem ); + + Num_Frees++; + Dyn_Mem_Size -= size; +} + + +#endif // LOG_MEMORY_BLOCKS --------------------------------------------------- + + + +#if defined( REGISTER_MCBDUMP_COMMAND ) && defined( LOG_MEMORY_BLOCKS ) // ---- + + +// user command registration +#include "con_com.h" +#include "gd_help.h" +#include "gd_type.h" + + +// command "mcbdump" for dumping the entire mcb list to a log file ------------ +// +PRIVATE +int Cmd_MCBDUMP( char *params ) +{ + ASSERT( params != NULL ); + void CON_AddLine( char *text ); + USERCOMMAND_NOPARAM( params ); + + refframe_t SYSs_GetRefFrameCount(); + refframe_t currefframe = SYSs_GetRefFrameCount(); + + FILE *fp = fopen( mcb_log_name, "a" ); + if ( fp != NULL ) { + + fprintf( fp, "\n[%03d.%03d.%03d.%03d] --------------\n", + ( ( currefframe >> 24 ) & 0xff ), + ( ( currefframe >> 16 ) & 0xff ), + ( ( currefframe >> 8 ) & 0xff ), + ( currefframe & 0xff ) ); + + int nummcbs = 0; + size_t mcbsum = 0; + + for ( MCB_Log *temp = McbLogList; temp; temp = temp->next, nummcbs++ ) { + + int corrupt1 = ( strcmp( (char*)temp->address, mcb_signature ) != 0 ); + int corrupt2 = ( strcmp( (char*)temp->address+temp->size-MCB_SIG_SIZE, mcb_signature ) != 0 ); + + mcbsum += temp->size; + + fprintf( fp, "[%d] adx=0x%08X own=0x%08X siz=%d", nummcbs, (size_t)temp->address, (size_t)temp->caller, temp->size ); + if ( corrupt1 ) + fprintf( fp, " **START CORRUPTED**" ); + if ( corrupt2 ) + fprintf( fp, " **END CORRUPTED**" ); + fprintf( fp, "\n" ); + } + fprintf( fp, "\n%d bytes in %d entries.\n", mcbsum, nummcbs ); + + fclose( fp ); + } + + return TRUE; +} + + +// register mcb dumping command ----------------------------------------------- +// +REGISTER_MODULE( DEBUG ) +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + regcom.command = "mcbdump"; + regcom.numparams = 0; + regcom.execute = Cmd_MCBDUMP; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); +} + + +#endif // REGISTER_MCBDUMP_COMMAND && LOG_MEMORY_BLOCKS ----------------------- + + + +// check assertion, abort if assertion failed --------------------------------- +// +#ifdef SYSTEM_LINUX_UNUSED + #define SYSABORT() exit( EXIT_FAILURE ) // abort() crashes +#else + #define SYSABORT() abort() +#endif + + +// check assertion, abort if assertion failed --------------------------------- +// +void _SysAssert( const char *file, unsigned line ) +{ + static int inSysAssert = FALSE; + + if ( !inSysAssert ) { + inSysAssert = TRUE; + +#if defined ( SYSTEM_TARGET_WINDOWS ) && !defined ( __MINGW32__ ) + __debugbreak(); +#endif // SYSTEM_WIN32_UNUSED + + SYSs_CriticalCleanUp(); + + fflush( NULL ); + fprintf( stderr, "\nAssertion failed: %s, line %u\n", file, line ); + fflush( stderr ); + + // system-dependent handling + SysAssertCallback( file, line ); + + // abort if callback returned + SYSABORT(); + } +} + + + diff --git a/src/libparsec/e_modulemanager.cpp b/src/libparsec/e_modulemanager.cpp new file mode 100644 index 0000000..efc19c1 --- /dev/null +++ b/src/libparsec/e_modulemanager.cpp @@ -0,0 +1,147 @@ +/* + * PARSEC - Modulemanager + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:39 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// proprietary headers +#include "con_arg.h" +#ifdef PARSEC_SERVER + #include "con_int_sv.h" + #include "con_com_sv.h" + #include "con_main_sv.h" +#else // !PARSEC_SERVER + #include "con_int.h" + #include "con_com.h" + #include "con_main.h" +#endif // !PARSEC_SERVER + +// standard ctor -------------------------------------------------------------- +// +E_Module::E_Module( const char* pszName ) +{ + strncpy( m_szName, pszName, 256 ); + m_szName[ 255 ] = 0; + TheModuleManager->RegisterModule( this ); +} + +// register a module ---------------------------------------------------------- +// +void E_ModuleManager::RegisterModule( E_Module* pModule ) +{ +#ifdef PARSEC_DEBUG + ASSERT( m_Modules.Find( pModule ) == NULL ); +#endif //PARSEC_DEBUG + m_Modules.AppendTail( pModule ); +} + +// unregister a module -------------------------------------------------------- +// +void E_ModuleManager::UnregisterModule( E_Module* pModule ) +{ +#ifdef PARSEC_DEBUG + ASSERT( m_Modules.Find( pModule ) != NULL ); +#endif //PARSEC_DEBUG + m_Modules.Remove( pModule ); +} + +// init all registered modules ( constructor ) -------------------------------- +// +void E_ModuleManager::InitAllModules() +{ + for( LE_Module* entry = m_Modules.GetHead(); entry != NULL; ) { + ASSERT( entry->m_data != NULL ); + entry->m_data->Init(); + entry = entry->m_pNext; + } +} + +// kill all registered modules ( destructor ) --------------------------------- +// +void E_ModuleManager::KillAllModules() +{ + for( LE_Module* entry = m_Modules.GetHead(); entry != NULL; ) { + ASSERT( entry->m_data != NULL ); + entry->m_data->Kill(); + entry = entry->m_pNext; + } +} + +// console command for listing all registered modules ------------------------- +// +PRIVATE +int Cmd_MODULES_LIST( char* dummystr ) +{ + ASSERT( dummystr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( dummystr ); + + TheModuleManager->ListAll(); + + return TRUE; +} + +// list all loaded modules in the console ------------------------------------- +// +void E_ModuleManager::ListAll() const +{ + MSGOUT( "# of registered modules: %d", m_Modules.GetNumEntries() ); + int nModule = 0; + for( LE_Module* entry = m_Modules.GetHead(); entry != NULL; ) { + ASSERT( entry->m_data != NULL ); + MSGOUT( "%d: %s", nModule, entry->m_data->GetName() ); + entry = entry->m_pNext; + nModule++; + } + +} + +// register the console commands for managing modules ------------------------- +// +void E_ModuleManager::_RegisterConsoleCommand() const +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "clbot.start" command + regcom.command = "modules.list"; + regcom.numparams = 0; + regcom.execute = Cmd_MODULES_LIST; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); +} + + diff --git a/src/libparsec/e_relist.cpp b/src/libparsec/e_relist.cpp new file mode 100644 index 0000000..14c0f37 --- /dev/null +++ b/src/libparsec/e_relist.cpp @@ -0,0 +1,1027 @@ +/* + * PARSEC - Remote Events handler + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:43 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001-2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" + +// mathematics header +#include "utl_math.h" + +#ifdef PARSEC_SERVER + + // server defs + #include "e_defs.h" + + // net game header + #include "net_game_sv.h" + + // proprietary module headers + #include "con_aux_sv.h" + #include "g_main_sv.h" + #include "obj_creg.h" + #include "e_simplayerinfo.h" + #include "e_simulator.h" + #include "e_gameserver.h" + #include "e_connmanager.h" + +#else + + #include "net_game.h" + +#endif // PARSEC_SERVER + +// local module header +#include "e_relist.h" + + +// table of remote event sizes ------------------------------------------------ +// +static size_t re_sizes[] = { + sizeof( RE_Header ), + sizeof( RE_Header ), + sizeof( RE_CreateObject ), + sizeof( RE_CreateLaser ), + sizeof( RE_CreateMissile ), + sizeof( RE_CreateExtra ), + sizeof( RE_KillObject ), + sizeof( RE_SendText ), + sizeof( RE_PlayerName ), + sizeof( RE_ParticleObject ), + sizeof( RE_PlayerList ), + sizeof( RE_ConnectQueue ), + sizeof( RE_WeaponState ), + sizeof( RE_StateSync ), + sizeof( RE_CreateSwarm ), + sizeof( RE_CreateEmp ), + sizeof( RE_OwnerSection ), + sizeof( RE_PlayerStatus ), + sizeof( RE_PlayerAndShipStatus ), + sizeof( RE_KillStats ), + sizeof( RE_GameState ), + sizeof( RE_CommandInfo ), + sizeof( RE_ClientInfo ), + sizeof( RE_CreateExtra2 ), + sizeof( RE_IPv4ServerInfo ), + sizeof( RE_ServerLinkInfo ), + sizeof( RE_MapObject ), + sizeof( RE_Stargate ), + sizeof( RE_CreateMine), +}; + +// table of remote event sizes ------------------------------------------------ +// +static const char* re_names[] = { + "RE_EMPTY", + "RE_DELETED", + "RE_CREATEOBJECT", + "RE_CREATELASER", + "RE_CREATEMISSILE", + "RE_CREATEEXTRA", + "RE_KILLOBJECT", + "RE_SENDTEXT", + "RE_PLAYERNAME", + "RE_PARTICLEOBJECT", + "RE_PLAYERLIST", + "RE_CONNECTQUEUE", + "RE_WEAPONSTATE", + "RE_STATESYNC", + "RE_CREATESWARM", + "RE_CREATEEMP", + "RE_OWNERSECTION", + "RE_PLAYERSTATUS", + "RE_PLAYERANDSHIPSTATUS", + "RE_KILLSTATS", + "RE_GAMESTATE", + "RE_COMMANDINFO", + "RE_CLIENTINFO", + "RE_CREATEEXTRA2", + "RE_IPV4SERVERINFO", + "RE_SERVERLINKINFO", + "RE_MAPOBJECT", + "RE_STARGATE", + "RE_CREATEMINE", + //FIXME: use NET_UTIL::PrInf_* functions and E_REList::Dump +}; + +// default ctor --------------------------------------------------------------- +// +E_REList::E_REList() +{ + m_data = NULL; + m_nMaxSize = 0; + m_nRefCount = 0; +} + +// ctor with init ------------------------------------------------------------- +// +E_REList::E_REList( size_t size ) +{ + m_data = NULL; + m_nMaxSize = 0; + m_nRefCount = 0; + + Init( size ); +} + +// standard dtor -------------------------------------------------------------- +// +E_REList::~E_REList() +{ + if ( m_data != NULL ) + delete []m_data; +} + +// init the remote event list ------------------------------------------------- +// +void E_REList::Init( size_t nMaxSize ) +{ + ASSERT( nMaxSize > 0 ); + + if ( m_data != NULL ) + delete []m_data; + + m_nMaxSize = nMaxSize; + + // allocate max. size of remote event list + m_data = new char[ nMaxSize ]; + + // initialize the list to empty + ( (RE_Header*) m_data)->RE_Type = RE_EMPTY; + + m_CurPos = m_data; + m_Avail = nMaxSize; + + ASSERT( m_Avail >= 0 ); +} + +// clear remote event list ---------------------------------------------------- +// +int E_REList::Clear() +{ + ASSERT( m_data != NULL ); + ASSERT( m_nMaxSize > 0 ); + + // initialize the list to empty + ( (RE_Header*) m_data)->RE_Type = RE_EMPTY; + + m_CurPos = m_data; + m_Avail = m_nMaxSize; + + ASSERT( m_Avail >= 0 ); + + return TRUE; +} + +// append a E_REList -------------------------------------------------------- +// +int E_REList::AppendList( E_REList* relist ) +{ + ASSERT( relist != NULL ); + return AppendList( (RE_Header*) relist->m_data ); +} + + +// append a remote event list ------------------------------------------------- +// +int E_REList::AppendList( RE_Header* relist ) +{ + ASSERT( m_data != NULL ); + + // do not append an empty list + if ( relist->RE_Type == RE_EMPTY ) + return TRUE; + + // determine the size of the list to append + size_t lsize = DetermineListSize( relist ); + + ASSERT( lsize <= m_Avail ); + if ( lsize <= m_Avail ) { + // append the list + memcpy( (void*)m_CurPos, (void*)relist, lsize ); + + m_CurPos += lsize; + m_Avail -= lsize; + + ASSERT( m_Avail >= 0 ); + + // ensure proper end for remote event list + ((RE_Header*) m_CurPos)->RE_Type = RE_EMPTY; + + return TRUE; + } else { + return FALSE; + } +} + +// append a remote event ------------------------------------------------------ +// +size_t E_REList::AppendEvent( RE_Header* re, size_t size ) +{ + ASSERT( re != NULL ); + ASSERT( RmEvGetSize( re ) == size ); + + // check whether enough space is left ( account for the trailing RE_EMPTY ) + if ( m_Avail >= ( size + sizeof( RE_Header ) ) ) { + + // copy over the event + memcpy( (void*)m_CurPos, (void*)re, size ); + + m_CurPos += size; + m_Avail -= size; + + ((RE_Header*)m_CurPos)->RE_Type = RE_EMPTY; + + return size; + + } else { + return 0; + } +} + + + + +// fill an external remote event list ----------------------------------------- +// +size_t E_REList::WriteTo( RE_Header* dst, size_t maxsize, int allow_truncate ) +{ + // determine size of remote event list ( include RE_EMPTY byte at end ) + size_t datasize = (size_t)( m_CurPos - m_data ); + + if ( datasize == 0 ) + return 0; + + // ensure we have enough space + if ( datasize > maxsize ) { + + if ( !allow_truncate ) { + ASSERT( FALSE ); + return 0; + } + + RE_Header* relist = (RE_Header*)m_data; + unsigned int filledsize = 0; + + // process remote event list + while ( ( relist->RE_Type != RE_EMPTY ) && ( filledsize < maxsize ) ) { + + size_t resize = RmEvGetSize( relist ); + + if ( ( resize + filledsize ) < maxsize ) { + memcpy( (void*)dst, (void*)relist, resize * sizeof( char ) ); + dst += resize; + + filledsize += resize; + } + + // advance to next event + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || + ( relist->RE_BlockSize == resize ) ); + relist = (RE_Header *) ( (char *) relist + resize ); + } + + return filledsize; + + + } else { + memcpy( (void*)dst, m_data, datasize * sizeof( char ) ); + return datasize; + } +} + +// determine size of remote event --------------------------------------------- +// +size_t E_REList::RmEvGetSize( RE_Header *relist ) +{ + ASSERT( relist != NULL ); + byte retype = relist->RE_Type; + + // use stored size for remote-events of variable size + if ( ( retype == RE_DELETED ) || ( retype == RE_SENDTEXT ) || ( retype == RE_COMMANDINFO ) ) { + ASSERT( relist->RE_BlockSize != RE_BLOCKSIZE_INVALID ); + return (size_t)relist->RE_BlockSize; + } + + ASSERT( retype > RE_DELETED ); + ASSERT( retype < RE_NUMEVENTS ); + + return re_sizes[ retype ]; +} + +// determine size of remote event --------------------------------------------- +// +size_t E_REList::RmEvGetSizeFromType( byte retype ) +{ + // use stored size for remote-events of variable size + if ( ( retype == RE_DELETED ) || ( retype == RE_SENDTEXT ) || ( retype == RE_COMMANDINFO ) ) { + return -1; + } + + ASSERT( retype > RE_DELETED ); + ASSERT( retype < RE_NUMEVENTS ); + + return re_sizes[ retype ]; +} + + +// check whether the remote event list is well formed ------------------------- +// +int E_REList::IsWellFormed( RE_Header *relist ) +{ + ASSERT( relist != NULL ); + + //FIXME: [1/30/2002] implement + //FIXME: check NET_RMEV::NET_RmEvList_IsWellFormed + + //RE_LIST_MAXAVAIL + + //ASSERT( FALSE ); + return TRUE; +} + +// return the max. size of the RE list that can fit in one external packet ---- +// +size_t E_REList::GetMaxSizeInPacket() +{ + return ( NET_UDP_DATA_LENGTH - sizeof( NetPacketExternal_GMSV ) ); +} + +// dump contents of RE list --------------------------------------------------- +// +void E_REList::Dump() +{ +#ifndef PARSEC_MASTER + + RE_Header* relist = (RE_Header*)m_data; + int nNumEvents = 0; + + // process remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + size_t resize = RmEvGetSize( relist ); + + if ( relist->RE_Type == RE_COMMANDINFO ) { + LOGOUT(( "%02d: %s size: %d command: %s", nNumEvents, re_names[ relist->RE_Type ], resize, ((RE_CommandInfo*)relist)->command )); + } else { + LOGOUT(( "%02d: %s size: %d", nNumEvents, re_names[ relist->RE_Type ], resize )); + } + + // advance to next event + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || + ( relist->RE_BlockSize == resize ) ); + relist = (RE_Header *) ( (char *) relist + resize ); + + nNumEvents++; + } + + LOGOUT(( "# of events: %d", nNumEvents )); + +#endif // !PARSEC_MASTER +} + +// validate the RE according to all bounds ------------------------------------ +// +int E_REList::ValidateRE( RE_Header* relist, size_t size ) +{ + switch( relist->RE_Type ) { + case RE_CLIENTINFO: + { + RE_ClientInfo* re_clientinfo = (RE_ClientInfo*)relist; + re_clientinfo->client_sendfreq = max( re_clientinfo->client_sendfreq, (byte) CLIENT_SEND_FREQUENCY_MIN ); + re_clientinfo->client_sendfreq = min( re_clientinfo->client_sendfreq, (byte) CLIENT_SEND_FREQUENCY_MAX ); + re_clientinfo->server_sendrate = max( re_clientinfo->server_sendrate, PACK_SERVERRATE( CLIENT_RECV_RATE_MIN ) ); + re_clientinfo->server_sendrate = min( re_clientinfo->server_sendrate, PACK_SERVERRATE( CLIENT_RECV_RATE_MAX ) ); + return TRUE; + } + default: + return TRUE; + } +} + + +// check if enough space in RE_List for specified remote event ---------------- +// +int E_REList::RmEvAllowed( int re_type ) +{ + ASSERT( re_type > RE_DELETED ); + ASSERT( re_type < RE_NUMEVENTS ); + ASSERT( re_type != RE_SENDTEXT ); + ASSERT( re_type != RE_PLAYERLIST ); + ASSERT( re_type != RE_CONNECTQUEUE ); + ASSERT( re_type != RE_OWNERSECTION ); + + return ( m_Avail < re_sizes[ re_type ] ); +} + +// insert state sync into RE_List --------------------------------------------- +// +int E_REList::RmEvStateSync( byte statekey, byte stateval ) +{ + //NOTE: + // calling E_REList::RmEvAllowed() is mandatory before calling this function. + + if ( m_Avail < sizeof( RE_StateSync ) ) { + ASSERT( 0 ); + return 0; + } + + RE_StateSync *re_statesync = (RE_StateSync *) m_CurPos; + re_statesync->RE_Type = RE_STATESYNC; + re_statesync->RE_BlockSize = sizeof( RE_StateSync ); + re_statesync->StateKey = statekey; + re_statesync->StateValue = stateval; + + re_statesync++; + re_statesync->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_statesync; + m_Avail -= sizeof( RE_StateSync ); + + return 1; +} + +// insert command info into remote event list --------------------------------- +// +int E_REList::NET_Append_RE_CommandInfo( const char* commandstring ) +{ + ASSERT( m_data != NULL ); + ASSERT( commandstring != NULL ); + + if ( m_Avail < sizeof( RE_CommandInfo ) ) { + return FALSE; + } + + size_t len = strlen( commandstring ); + if ( len > MAX_RE_COMMANDINFO_COMMAND_LEN ) { + len = MAX_RE_COMMANDINFO_COMMAND_LEN; + } + + RE_CommandInfo* re_commandinfo = (RE_CommandInfo*) m_CurPos; + re_commandinfo->RE_Type = RE_COMMANDINFO; + re_commandinfo->RE_BlockSize = len + 1/*string terminator '\0'*/ + 2/*header*/ + 1/*code*/; + strncpy( re_commandinfo->command , commandstring, MAX_RE_COMMANDINFO_COMMAND_LEN ); + re_commandinfo->command[ MAX_RE_COMMANDINFO_COMMAND_LEN ] = 0; + + m_CurPos += re_commandinfo->RE_BlockSize; + ((RE_Header*)m_CurPos)->RE_Type = RE_EMPTY; + + m_Avail -= sizeof( RE_CommandInfo ); + + ASSERT( m_Avail >= 0 ); + + return TRUE; +} + + +// insert owner section into remote event list -------------------------------- +// +int E_REList::NET_Append_RE_OwnerSection( int ownerid ) +{ + ASSERT( m_data != NULL ); + + if ( m_Avail < sizeof( RE_OwnerSection ) ) { + return FALSE; + } + + RE_OwnerSection* re_ownersection = (RE_OwnerSection*) m_CurPos; + re_ownersection->RE_Type = RE_OWNERSECTION; + re_ownersection->RE_BlockSize = sizeof( RE_OwnerSection ); + re_ownersection->owner = (byte) ownerid; + + re_ownersection++; + re_ownersection->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_ownersection; + m_Avail -= sizeof( RE_OwnerSection ); + + ASSERT( m_Avail >= 0 ); + + return TRUE; +} + +// append a RE_PlayerAndShipStatus event -------------------------------------- +// +int E_REList::NET_Append_RE_PlayerAndShipStatus( int nClientID, E_SimPlayerInfo* pSimPlayerInfo, E_SimShipState* pSimShipState, refframe_t CurRefFrame, bool_t bUpdatePropsOnly ) +{ +#ifdef PARSEC_SERVER + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + ASSERT( nClientID >= 0 && nClientID < MAX_NUM_CLIENTS ); + ASSERT( pSimShipState != NULL ); + + if ( m_Avail < sizeof( RE_PlayerAndShipStatus ) ) { + return FALSE; + } + + RE_PlayerAndShipStatus* re_pas_status = (RE_PlayerAndShipStatus*) m_CurPos; + ASSERT( re_pas_status->RE_Type == RE_EMPTY ); + + re_pas_status->RE_Type = RE_PLAYERANDSHIPSTATUS; + re_pas_status->RE_BlockSize = sizeof( RE_PlayerAndShipStatus ); + + // update all fields + re_pas_status->UpdateFlags = bUpdatePropsOnly ? UF_PROPERTIES : UF_ALL; + + //FIXME: redesign this !! + //FIXME: we should have flags indicating which fields are transmitted in this event + re_pas_status->player_status = pSimPlayerInfo->GetStatus(); + re_pas_status->params[ 0 ] = pSimPlayerInfo->IsPlayerConnected() ? TheGame->GetPlayerLastUnjoinFlag( nClientID ) : 0; + re_pas_status->params[ 1 ] = 0; + re_pas_status->params[ 2 ] = pSimPlayerInfo->IsPlayerConnected() ? ( TheGame->GetPlayerLastKiller( nClientID ) + KILLERID_BIAS ) : 0; + re_pas_status->params[ 3 ] = 0; + re_pas_status->senderid = nClientID; + //FIXME: is this the global object class id ? + re_pas_status->objectindex = ObjClassShipIndex[ pSimPlayerInfo->GetShipObjectClass() ]; + + // fill position and speed from sim-state + memcpy( &re_pas_status->ObjPosition, &pSimShipState->m_ObjPosition, sizeof( Xmatrx ) ); + re_pas_status->CurSpeed = pSimShipState->m_CurSpeed; + re_pas_status->CurYaw = pSimShipState->m_CurYaw; + re_pas_status->CurPitch = pSimShipState->m_CurPitch; + re_pas_status->CurRoll = pSimShipState->m_CurRoll; + re_pas_status->CurSlideHorz = pSimShipState->m_CurSlideHorz; + re_pas_status->CurSlideVert = pSimShipState->m_CurSlideVert; + + // get the properties directly from the ship object + ShipObject* pShipObject = pSimPlayerInfo->GetShipObject(); + if ( pShipObject != NULL ) { + re_pas_status->CurDamage = pShipObject->CurDamage; + re_pas_status->CurShield = pShipObject->CurShield; + re_pas_status->CurEnergy = pShipObject->CurEnergy; + re_pas_status->NumMissls = pShipObject->NumMissls; + re_pas_status->NumHomMissls = pShipObject->NumHomMissls; + re_pas_status->NumMines = pShipObject->NumMines; + re_pas_status->NumPartMissls = pShipObject->NumPartMissls; + } + + DBGTXT( MSGOUT( "sending RE_PlayerAndShipStatus: senderid: %d, status: %d, updateflags: %d", nClientID, pSimPlayerInfo->GetStatus(), re_pas_status->UpdateFlags ); ); + + re_pas_status->RefFrame = CurRefFrame; + + re_pas_status++; + re_pas_status->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_pas_status; + m_Avail -= sizeof( RE_PlayerAndShipStatus ); + + ASSERT( m_Avail >= 0 ); +#endif // PARSEC_SERVER + + return TRUE; +} + +// append a RE_GameState event ------------------------------------------------ +// +int E_REList::NET_Append_RE_GameState() +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + if ( m_Avail < sizeof( RE_GameState ) ) { + return FALSE; + } + + RE_GameState* re_gamestate = (RE_GameState*) m_CurPos; + re_gamestate->RE_Type = RE_GAMESTATE; + re_gamestate->RE_BlockSize = sizeof( RE_GameState ); + + // fill in the server gametime + re_gamestate->GameTime = TheGame->GetCurGameTime(); + + re_gamestate++; + re_gamestate->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_gamestate; + m_Avail -= sizeof( RE_GameState ); + + return TRUE; +#else + ASSERT( FALSE ); + return FALSE; +#endif // PARSEC_SERVER +} + +// insert particle object into RE_List ---------------------------------------- +// +int E_REList::NET_Append_RE_ParticleObject( int type, const Vertex3& origin ) +{ + if ( m_Avail < sizeof( RE_ParticleObject ) ) { + return FALSE; + } + + RE_ParticleObject *re_particleobject = (RE_ParticleObject *) m_CurPos; + re_particleobject->RE_Type = RE_PARTICLEOBJECT; + re_particleobject->RE_BlockSize = sizeof( RE_ParticleObject ); + re_particleobject->ObjectType = type; + re_particleobject->Origin = origin; + + re_particleobject++; + re_particleobject->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_particleobject; + m_Avail -= sizeof( RE_ParticleObject ); + + return TRUE; +} + + +// append a RE_CreateExtra2 event ---------------------------------------------- +// +int E_REList::NET_Append_RE_CreateExtra2( const ExtraObject *extrapo ) +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( extrapo != NULL ); + + if ( m_Avail < sizeof( RE_CreateExtra2 ) ) { + return FALSE; + } + + // translate from objectclass to extra index + int extraindex = ObjClassExtraIndex[ extrapo->ObjectClass ]; + ASSERT( extraindex != EXTRAINDEX_NO_EXTRA ); + + RE_CreateExtra2 *re_ce2 = (RE_CreateExtra2 *) m_CurPos; + re_ce2->RE_Type = RE_CREATEEXTRA2; + re_ce2->RE_BlockSize = sizeof( RE_CreateExtra2 ); + re_ce2->ExtraIndex = extraindex; + re_ce2->HostObjId = extrapo->HostObjNumber; + memcpy( &re_ce2->ObjPosition, &extrapo->ObjPosition, sizeof( Xmatrx ) ); + re_ce2->DriftVec.X = extrapo->DriftVec.X; + re_ce2->DriftVec.Y = extrapo->DriftVec.Y; + re_ce2->DriftVec.Z = extrapo->DriftVec.Z; + re_ce2->DriftTimeout = extrapo->DriftTimeout; + + re_ce2++; + re_ce2->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_ce2; + m_Avail -= sizeof( RE_CreateExtra2 ); + + return TRUE; +#else + ASSERT( FALSE ); + return FALSE; +#endif // PARSEC_SERVER +} + + +// append a RE_CreateLaser event ---------------------------------------------- +// +int E_REList::NET_Append_RE_CreateLaser( const LaserObject* laserpo ) +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + + //NOTE: + // calling NET_RmEvAllowed() is mandatory before calling this function. + + ASSERT( laserpo != NULL ); + + if ( m_Avail < sizeof( RE_CreateLaser ) ) { + return FALSE; + } + + RE_CreateLaser *re_createlaser = (RE_CreateLaser *) m_CurPos; + re_createlaser->RE_Type = RE_CREATELASER; + re_createlaser->RE_BlockSize = sizeof( RE_CreateLaser ); + //FIXME: objectclass is not synced between client and server + re_createlaser->ObjectClass = laserpo->ObjectClass; + re_createlaser->HostObjId = laserpo->HostObjNumber; + memcpy( &re_createlaser->ObjPosition, &laserpo->ObjPosition, sizeof( Xmatrx ) ); + re_createlaser->DirectionVec = laserpo->DirectionVec; + + re_createlaser++; + re_createlaser->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_createlaser; + m_Avail -= sizeof( RE_CreateLaser ); + + return TRUE; +#else + ASSERT( FALSE ); + return FALSE; +#endif // PARSEC_SERVER +} + +// insert missile into RE_List ------------------------------------------------ +// +int E_REList::NET_Append_RE_CreateMissile( const MissileObject *missilepo, dword targetobjid ) +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( missilepo != NULL ); + + + if ( m_Avail < sizeof( RE_CreateMissile ) ) { + return FALSE; + } + + RE_CreateMissile *re_createmissl = (RE_CreateMissile *) m_CurPos;; + re_createmissl->RE_Type = RE_CREATEMISSILE; + re_createmissl->RE_BlockSize = sizeof( RE_CreateMissile ); + re_createmissl->ObjectClass = missilepo->ObjectClass; + re_createmissl->HostObjId = missilepo->HostObjNumber; + re_createmissl->TargetHostObjId = targetobjid; + memcpy( &re_createmissl->ObjPosition, &missilepo->ObjPosition, sizeof( Xmatrx ) ); + re_createmissl->DirectionVec = missilepo->DirectionVec; + + re_createmissl++; + re_createmissl->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_createmissl; + m_Avail -= sizeof( RE_CreateMissile ); + + + return TRUE; +#else + return FALSE; +#endif //Parsec Server +} + +// append a RE_KillOjbect event ----------------------------------------------- +// +int E_REList::NET_Append_RE_KillObject( dword objectid, byte listno ) +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + +#ifdef NO_PROJECTILE_KILL_MESSAGES + + // for projectiles depend on local client lifetime expiration + if ( ( listno == LASER_LIST ) || ( listno == MISSL_LIST ) ) { + return 1; + } + ASSERT( listno == EXTRA_LIST ); + +#endif + + if ( m_Avail < sizeof( RE_KillObject ) ) { + return FALSE; + } + + RE_KillObject *re_killobject = (RE_KillObject *) m_CurPos; + re_killobject->RE_Type = RE_KILLOBJECT; + re_killobject->RE_BlockSize = sizeof( RE_KillObject ); + re_killobject->HostObjId = objectid; + re_killobject->ListId = listno; + + re_killobject++; + re_killobject->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_killobject; + m_Avail -= sizeof( RE_KillObject ); + + return TRUE; +#else + ASSERT( FALSE ); + return FALSE; +#endif // PARSEC_SERVER +} + + +// append a RE_KillStats event ------------------------------------------------ +// +int E_REList::NET_Append_RE_KillStats() +{ +#ifdef PARSEC_SERVER + + //FIXME: + //FIXME: + //FIXME: + //FIXME: this is GAMECODE !!! + //FIXME: + //FIXME: + //FIXME: + + if ( m_Avail < sizeof( RE_KillStats ) ) { + return FALSE; + } + + RE_KillStats* re_killstats = (RE_KillStats*) m_CurPos; + re_killstats->RE_Type = RE_KILLSTATS; + re_killstats->RE_BlockSize = sizeof( RE_KillStats ); + + // fill in the server gametime + for( int nClientID = 0; nClientID < MAX_NUM_CLIENTS; nClientID++ ) { + re_killstats->PlayerKills[ nClientID ] = TheGame->GetPlayerKills( nClientID ); + } + + re_killstats++; + re_killstats->RE_Type = RE_EMPTY; + + m_CurPos = (char*) re_killstats; + m_Avail -= sizeof( RE_KillStats ); + + return TRUE; +#else + ASSERT( FALSE ); + return FALSE; +#endif // PARSEC_SERVER +} + +// append a RE_IPv4ServerInfo event ------------------------------------------- +// +int E_REList::NET_Append_RE_IPv4ServerInfo( node_t* node, word nServerID, int xpos, int ypos, word flags ) +{ + + + ASSERT( node != NULL ); + + if ( m_Avail < sizeof( RE_IPv4ServerInfo ) ) { + return FALSE; + } + + RE_IPv4ServerInfo* re_ipv4serverinfo = (RE_IPv4ServerInfo*) m_CurPos; + re_ipv4serverinfo->RE_Type = RE_IPV4SERVERINFO; + re_ipv4serverinfo->RE_BlockSize = sizeof( RE_IPv4ServerInfo ); + + memcpy( re_ipv4serverinfo->node, node, NODE_ADR_LENGTH ); + + re_ipv4serverinfo->flags = flags; + re_ipv4serverinfo->serverid = nServerID; + re_ipv4serverinfo->xpos = xpos; + re_ipv4serverinfo->ypos = ypos; + + re_ipv4serverinfo++; + re_ipv4serverinfo->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_ipv4serverinfo; + m_Avail -= sizeof( RE_IPv4ServerInfo ); + + return TRUE; +} + +// append a RE_ServerLinkInfo event ------------------------------------------- +// +int E_REList::NET_Append_RE_ServerLinkInfo( word nServerID_1, word nServerID_2, word flags ) +{ + if ( m_Avail < sizeof( RE_ServerLinkInfo ) ) { + return FALSE; + } + + RE_ServerLinkInfo* re_sli = (RE_ServerLinkInfo*) m_CurPos; + re_sli->RE_Type = RE_SERVERLINKINFO; + re_sli->RE_BlockSize = sizeof( RE_ServerLinkInfo ); + + re_sli->flags = flags; + re_sli->serverid1 = nServerID_1; + re_sli->serverid2 = nServerID_2; + + re_sli++; + re_sli->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_sli; + m_Avail -= sizeof( RE_ServerLinkInfo ); + + return TRUE; +} + +// append a RE_MapObject ------------------------------------------------------ +// +int E_REList::NET_Append_RE_MapObject( int map_objectid, char* name, int xpos, int ypos, int w, int h, char* texname ) +{ + ASSERT( ( map_objectid >= 0 ) && ( map_objectid < MAX_MAP_OBJECTS ) ); + ASSERT( name != NULL ); + ASSERT( texname != NULL ); + + if ( m_Avail < sizeof( RE_MapObject ) ) { + return FALSE; + } + + RE_MapObject* re_mo = (RE_MapObject*) m_CurPos; + re_mo->RE_Type = RE_MAPOBJECT; + re_mo->RE_BlockSize = sizeof( RE_MapObject ); + + re_mo->map_objectid = map_objectid; + strncpy( re_mo->name, name, MAX_MAP_OBJ_NAME ); + re_mo->name[ MAX_MAP_OBJ_NAME ] = 0; + re_mo->xpos = xpos; + re_mo->ypos = ypos; + re_mo->w = w; + re_mo->h = h; + strncpy( re_mo->texname, texname, MAX_TEXNAME); + re_mo->texname[ MAX_TEXNAME ] = 0; + + re_mo++; + re_mo->RE_Type = RE_EMPTY; + + m_CurPos = (char *) re_mo; + m_Avail -= sizeof( RE_MapObject ); + + return TRUE; +} + +// allocate space for a specific RE ------------------------------------------- +// +RE_Header* E_REList::NET_Allocate( int retype ) +{ + ASSERT( ( retype >= RE_EMPTY ) && ( retype < RE_NUMEVENTS ) ); + ASSERT( ( retype != RE_DELETED ) && ( retype != RE_SENDTEXT ) && ( retype != RE_COMMANDINFO ) ); + + ssize_t size = RmEvGetSizeFromType( retype ); + ASSERT( size != -1 ); + + if( m_Avail < (size_t)size ) { + return NULL; + } + + RE_Header* pBegin = (RE_Header*)m_CurPos; + pBegin->RE_Type = retype; + pBegin->RE_BlockSize = size; + + m_CurPos += size; + m_Avail -= size; + + ((RE_Header*)m_CurPos)->RE_Type = RE_EMPTY; + + return pBegin; +} diff --git a/src/libparsec/g_emp.cpp b/src/libparsec/g_emp.cpp new file mode 100644 index 0000000..0a01c24 --- /dev/null +++ b/src/libparsec/g_emp.cpp @@ -0,0 +1,1443 @@ +/* + * PARSEC - Electromagnetic Impulse Weapon Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:36 $ + * + * Orginally written by: + * Copyright (c) Michael Woegerbauer <maiki@parsec.org> 2000-2001 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers + +#include "net_defs.h" + +#ifndef PARSEC_SERVER +// drawing subsystem +#include "d_iter.h" +#endif + +// mathematics header +#include "utl_math.h" + +// model header +//#include "utl_model.h" + +// local module header +#include "g_emp.h" +#include "con_arg.h" + + +#ifndef PARSEC_SERVER +// proprietary module headers +#include "aud_defs.h" + +#include "con_com.h" +#include "con_info.h" +#include "con_main.h" +#include "e_callbk.h" +#include "e_record.h" +#include "e_supp.h" +#include "h_supp.h" +#include "obj_expl.h" +#include "obj_ctrl.h" +#include "obj_game.h" +#else +#include "con_info_sv.h" +#include "con_main_sv.h" +#include "con_com_sv.h" +#endif + +#include "obj_cust.h" + + +// assigned type id for emp type ---------------------------------------------- +// +dword emp_type_id[ EMP_UPGRADES ]; + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + + +// string constants ----------------------------------------------------------- +// +static char emp_inval_lifetime_spec[] = "lifetime invalid"; +static char emp_inval_maxwidth_spec[] = "maxwidth invalid"; +static char emp_inval_lambda_spec[] = "lambda invalid"; +static char emp_inval_fadeout_spec[] = "fadeout invalid"; +static char emp_inval_waves_spec[] = "waves invalid"; +static char emp_inval_delay_spec[] = "delay invalid"; +static char emp_inval_energy_spec[] = "energy invalid"; +static char no_emp_str[] = "no emp device"; +static char low_energy_str[] = "low energy"; + + +// list of console-accessible properties -------------------------------------- +// + +// emp standard +PRIVATE +proplist_s Emp_PropList[] = { + + { "texname", OFS_TEXNAME, 0, EMP_MAX_TEX_NAME, PROPTYPE_STRING }, + { "lod", OFS_LOD, 2, 0xff, PROPTYPE_INT }, + { "lat", OFS_LAT, 0x0aaa, 0xffff, PROPTYPE_INT }, + { "rot", OFS_ROT, 0, 0xffff, PROPTYPE_INT }, + { "red", OFS_RED, 0, 0xff, PROPTYPE_INT }, + { "green", OFS_GREEN, 0, 0xff, PROPTYPE_INT }, + { "blue", OFS_BLUE, 0, 0xff, PROPTYPE_INT }, + { "alpha", OFS_ALPHA, 0, 0xff, PROPTYPE_INT }, + { "damage", OFS_DAMAGE, 0, 0xffff, PROPTYPE_INT }, + + { NULL, 0, 0, 0, 0 } +}; + + +// emp upgrade level 1 +PRIVATE +proplist_s EmpUp1_PropList[] = { + + { "texname", OFS_TEXNAME, 0, EMP_MAX_TEX_NAME, PROPTYPE_STRING }, + { "lod", OFS_LOD, 2, 0xff, PROPTYPE_INT }, + { "lat", OFS_LAT, 0x0aaa, 0xffff, PROPTYPE_INT }, + { "rot", OFS_ROT, 0, 0xffff, PROPTYPE_INT }, + { "red", OFS_RED, 0, 0xff, PROPTYPE_INT }, + { "green", OFS_GREEN, 0, 0xff, PROPTYPE_INT }, + { "blue", OFS_BLUE, 0, 0xff, PROPTYPE_INT }, + { "alpha", OFS_ALPHA, 0, 0xff, PROPTYPE_INT }, + { "damage", OFS_DAMAGE, 0, 0xffff, PROPTYPE_INT }, + + { NULL, 0, 0, 0, 0 } +}; + + +// emp upgrade level 2 +PRIVATE +proplist_s EmpUp2_PropList[] = { + + { "texname", OFS_TEXNAME, 0, EMP_MAX_TEX_NAME, PROPTYPE_STRING }, + { "lod", OFS_LOD, 2, 0xff, PROPTYPE_INT }, + { "lat", OFS_LAT, 0x0aaa, 0xffff, PROPTYPE_INT }, + { "rot", OFS_ROT, 0, 0xffff, PROPTYPE_INT }, + { "red", OFS_RED, 0, 0xff, PROPTYPE_INT }, + { "green", OFS_GREEN, 0, 0xff, PROPTYPE_INT }, + { "blue", OFS_BLUE, 0, 0xff, PROPTYPE_INT }, + { "alpha", OFS_ALPHA, 0, 0xff, PROPTYPE_INT }, + { "damage", OFS_DAMAGE, 0, 0xffff, PROPTYPE_INT }, + + { NULL, 0, 0, 0, 0 } +}; + + + + +// draw emp ------------------------------------------------------------------- +// +PRIVATE +int EmpDraw( void* param ) +{ +#ifndef PARSEC_SERVER + ASSERT( param != NULL ); + Emp *emp = (Emp *) param; + + ASSERT( emp->texmap != NULL ); + ASSERT( emp->alive < emp_lifetime[ emp->upgradelevel ] + emp->delay ); + + // setup transformation matrix (emps are defined + // in world-space, so transform is world->view) + D_LoadIterMatrix( ViewCamera ); + + // set vertex color + byte red = emp->red; + byte green = emp->green; + byte blue = emp->blue; + byte alpha = emp->alpha; + + int remaining = ( emp_lifetime[ emp->upgradelevel ] + emp->delay - emp->alive ); + if ( remaining <= emp_fadeout[ emp->upgradelevel ] ) { + alpha = emp->alpha - ( ( emp->alpha * ( emp_fadeout[ emp->upgradelevel ] - remaining ) ) + / emp_fadeout[ emp->upgradelevel ] ); + } + + COLOR_MUL( red, red, alpha ); + COLOR_MUL( green, green, alpha ); + COLOR_MUL( blue, blue, alpha ); + + // ( emp->lod * 2 ) segments + // plus the first segment extra + // two vertices per segment + int numverts = ( emp->lod * 2 + 1 ) * 2; + + IterTriStrip3 *itstrip = (IterTriStrip3 *) + ALLOCMEM( (size_t)&((IterTriStrip3*)0)->Vtxs[ numverts ] ); + + itstrip->flags = ITERFLAG_Z_DIV_XYZ | ITERFLAG_Z_DIV_UVW | ITERFLAG_Z_TO_DEPTH; + itstrip->NumVerts = numverts; + itstrip->itertype = iter_texrgba | iter_specularadd; + itstrip->raststate = rast_zcompare | rast_texwrap | rast_chromakeyoff; + itstrip->rastmask = rast_nomask; + itstrip->texmap = emp->texmap; + + geomv_t vtx_u; + geomv_t vtx_v; + geomv_t tex_w_delt = FLOAT_TO_GEOMV( (float)( 1L << emp->texmap->Width ) / (float)emp->lod ); + geomv_t tex_h_delt = FLOAT_TO_GEOMV( (float)( 1L << emp->texmap->Height ) / (float)emp->lod ); + + int latsegs = emp->lod; + int lonsegs = emp->lod * 2 + 1; + + // fill in the strip vertices + vtx_v = GEOMV_0; + for ( int lat = 0; lat < latsegs; lat++ ) { + + vtx_u = GEOMV_0; + for ( int lon = 0; lon < lonsegs; lon++ ) { + // fadeout bottom edge + if ( lat == 0 ) { + SET_ITER_VTX( &itstrip->Vtxs[ lon * 2 ], + &emp->WorldVtxs[ lat * lonsegs + lon ], + vtx_u, vtx_v, 0, 0, 0, alpha ); + } + else { + SET_ITER_VTX( &itstrip->Vtxs[ lon * 2 ], + &emp->WorldVtxs[ lat * lonsegs + lon ], + vtx_u, vtx_v, red, green, blue, alpha ); + + } + + // fadeout top edge + if ( lat == ( latsegs - 1 ) ) { + SET_ITER_VTX( &itstrip->Vtxs[ ( lon * 2 ) + 1 ], + &emp->WorldVtxs[ ( lat + 1 ) * lonsegs + lon ], + vtx_u, vtx_v + tex_h_delt, 0, 0, 0, alpha ); + } + else { + SET_ITER_VTX( &itstrip->Vtxs[ ( lon * 2 ) + 1 ], + &emp->WorldVtxs[ ( lat + 1 ) * lonsegs + lon ], + vtx_u, vtx_v + tex_h_delt, red, green, blue, alpha ); + } + vtx_u += tex_w_delt; + } + + // draw entire strip + D_DrawIterTriStrip3( itstrip, 0x3f ); + + vtx_v += tex_h_delt; + } + + FREEMEM( itstrip ); + itstrip = NULL; + + // restore identity transformation + D_LoadIterMatrix( NULL ); +#endif + return TRUE; +} + +#ifndef PARSEC_SERVER +// callback type and flags ---------------------------------------------------- +// +static int callback_type = CBTYPE_DRAW_CUSTOM_ITER | CBFLAG_REMOVE; +#else +static int callback_type = 0; +#endif + + +// ---------------------------------------------------------------------------- +// SINGLE EMP WAVE FUNCTIONS +// ---------------------------------------------------------------------------- + + +// single emp collision detection --------------------------------------------- +// +PRIVATE +int EmpShipCollision( Emp *emp, ShipObject* shippo ) +{ + ASSERT( shippo != NULL ); + + geomv_t empX = emp->WorldXmatrx[ 0 ][ 3 ]; + geomv_t empY = emp->WorldXmatrx[ 1 ][ 3 ]; + geomv_t empZ = emp->WorldXmatrx[ 2 ][ 3 ]; + + geomv_t bsphere = emp->BoundingSphere; + geomv_t bsphere2 = GEOMV_MUL( bsphere, bsphere ); + + geomv_t shipX = shippo->ObjPosition[ 0 ][ 3 ]; + geomv_t shipY = shippo->ObjPosition[ 1 ][ 3 ]; + geomv_t shipZ = shippo->ObjPosition[ 2 ][ 3 ]; + + if ( shipX < ( empX - bsphere ) ) return FALSE; + if ( shipX > ( empX + bsphere ) ) return FALSE; + if ( shipY < ( empY - bsphere ) ) return FALSE; + if ( shipY > ( empY + bsphere ) ) return FALSE; + if ( shipZ < ( empZ - bsphere ) ) return FALSE; + if ( shipZ > ( empZ + bsphere ) ) return FALSE; + + // do actual bounding sphere collision test + Vector3 vecdist; + vecdist.X = empX - shipX; + vecdist.Y = empY - shipY; + vecdist.Z = empZ - shipZ; + + geomv_t dist2 = DOT_PRODUCT( &vecdist, &vecdist ); + return( dist2 < bsphere2 ); +} + + +// emp collision detection ---------------------------------------------------- +// +PRIVATE +int CheckEmpCollision( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + +#ifndef PARSEC_SERVER + // check local ship + if ( ( emp->Owner != OWNER_LOCAL_PLAYER ) && NetJoined && + EmpShipCollision( emp, MyShip ) ) { + + OBJ_EventShipImpact( MyShip, TRUE ); + OBJ_ShipEmpDamage( MyShip, emp->Owner, emp->damage ); + } + + + // check shiplist + ShipObject *walkships = FetchFirstShip(); + for ( ; walkships; walkships = (ShipObject*) walkships->NextObj ) { + // prevent collision with owner of emp + if ( NetConnected && ( walkships->HostObjNumber == ShipHostObjId( emp->Owner ) ) ) + continue; + + if ( !EmpShipCollision( emp, walkships ) ) + continue; + OBJ_EventShipImpact( walkships, TRUE ); + OBJ_ShipEmpDamage( walkships, emp->Owner, emp->damage ); + + } +#endif + return TRUE; +} + + +// emp animation callback ----------------------------------------------------- +// +PRIVATE +int EmpAnimate( CustomObject *base ) +{ + + + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; +#ifndef PARSEC_SERVER + // remove emp if no texture found + if ( emp->texmap == NULL ) { + // returning FALSE deletes the object + return FALSE; + } + emp->alive += CurScreenRefFrames; +#else + emp->alive += 10; // approx to the client... //TheSimulator->GetThisFrameRefFrames(); +#endif + + // check emp expired + if ( emp->alive >= ( emp_lifetime[ emp->upgradelevel ] + emp->delay ) ) { + // returning FALSE deletes the object + MSGOUT("alive is %d, lifetime is %d, delay is %d, lifetime - delay is %d, delete object", + emp->alive, + emp_lifetime[emp->upgradelevel], + emp->delay, + ( emp_lifetime[ emp->upgradelevel ] + emp->delay )); + return FALSE; + } + + // check emp delay + if ( emp->alive < emp->delay ) { + MSGOUT("alive is %d, delay is %d, no show, return", emp->alive, emp->delay); + // do not show yet + return TRUE; + } +#ifndef PARSEC_SERVER + // register the drawing callback for drawing the emp + CALLBACK_RegisterCallback( callback_type, EmpDraw, (void*) base ); +#endif + + ASSERT( ( emp->alive - emp->delay ) < emp_lifetime[ emp->upgradelevel ] ); + + geomv_t sc = GEOMV_MUL( emp_max_width[ emp->upgradelevel ], + FLOAT_TO_GEOMV( emp_expansion_tab[ emp->upgradelevel ][ emp->alive - emp->delay ] ) ); + +#ifdef PARSEC_SERVER + + GenObject *ownerpo = TheWorld->FetchObject(emp->OwnerHostObjno); + if ( ownerpo != NULL ) { + memcpy( emp->WorldXmatrx, ownerpo->ObjPosition, sizeof( Xmatrx ) ); + } +#else // PARSEC_CLIENT + + // FIXME: known bug!!! + // FetchHostObject does not fetch anything if ( OwnerHostObjno == 0 ) and in + // ObjectCamera-Mode + + // try to get ownerpo in first place, since it could have been destroyd intermediatly + GenObject *ownerpo = FetchHostObject( emp->OwnerHostObjno ); + + if ( ownerpo != NULL ) { + memcpy( emp->WorldXmatrx, ownerpo->ObjPosition, sizeof( Xmatrx ) ); + } else if ( emp->ownerpo == MyShip ) { + memcpy( emp->WorldXmatrx, MyShip->ObjPosition, sizeof( Xmatrx ) ); + } else { + // owner-ship destroyed, emp does not change position any more + } +#endif + // animate emp object + Xmatrx curmatrx; + memcpy( curmatrx, emp->WorldXmatrx, sizeof( Xmatrx ) ); + + // rotate emp + ObjRotY( curmatrx, emp->rot * ( emp->alive - emp->delay ) ); + + // scale emp + Vertex3 instvtx; + for ( int curvtx = 0; curvtx < emp->vtxsnr; curvtx++ ) { + + instvtx.X = GEOMV_MUL( sc, emp->ObjVtxs[ curvtx ].X ); + instvtx.Y = GEOMV_MUL( sc, emp->ObjVtxs[ curvtx ].Y ); + instvtx.Z = GEOMV_MUL( sc, emp->ObjVtxs[ curvtx ].Z ); + + // transform vtxs into worldspace + MtxVctMUL( curmatrx, &instvtx, &emp->WorldVtxs[ curvtx ] ); + } + + emp->BoundingSphere = sc; + + return TRUE; +} + + +// create single emp wave object ---------------------------------------------- +// +PRIVATE +void CreateEmp( GenObject *ownerpo, int delay, int alive, int upgradelevel, int nClientID ) +{ + ASSERT( ownerpo != NULL ); + +#ifndef PARSEC_SERVER + // create emp object + Emp *emp = (Emp *) CreateVirtualObject( emp_type_id[ upgradelevel ] ); +#else + // FIXME: last arg is nClientID, need to figure out a way to pass that in or something. + Emp *emp = (Emp *) TheWorld->CreateVirtualObject( emp_type_id[ upgradelevel ], nClientID ); + +#endif + + ASSERT( emp != NULL ); + + if ( emp == NULL ) return; + +#ifndef PARSEC_SERVER + // get pointer to texture map + emp->texmap = FetchTextureMap( emp->texname ); + if ( emp->texmap == NULL ) { + MSGOUT( "emp texture '%s' invalid.", emp->texname ); + // emp will be deleted by animation callback + return; + } +#endif + // needed, since FetchHostObject( emp->OwnerHostObjno ) does not return MyShip + emp->ownerpo = ownerpo; + +#ifndef PARSEC_SERVER + // does GetObjectOwner return ownernumber of local ship ? + if ( ownerpo == MyShip ) { + emp->OwnerHostObjno = ( LocalPlayerId << 16 ); + emp->Owner = OWNER_LOCAL_PLAYER; + } + else { + emp->OwnerHostObjno = ownerpo->HostObjNumber; + emp->Owner = GetObjectOwner( ownerpo ); + } +#else + emp->OwnerHostObjno = ownerpo->HostObjNumber; + emp->Owner = nClientID; //GetObjectOwner( ownerpo ); +#endif + memcpy( emp->WorldXmatrx, ownerpo->ObjPosition, sizeof( Xmatrx ) ); + + // emp->lod = lod; + + // emp->lod latitude segments, first needs two rings of vertices + int numlatsegs = emp->lod + 1; + + // ( emp->lod * 2 ) longitude segments, first counts double + int numlonsegs = emp->lod * 2 + 1; + + emp->alive = alive; + emp->delay = delay; + emp->vtxsnr = numlonsegs * numlatsegs; + + // allocate emp object structure memory + emp->ObjVtxs = (Vertex3 *) ALLOCMEM( sizeof( Vertex3 ) * emp->vtxsnr * 2 ); + if ( emp->ObjVtxs == NULL ) { + OUTOFMEM( "no mem for emp." ); + } + emp->WorldVtxs = &emp->ObjVtxs[ emp->vtxsnr ]; + + // build emp object structure + for ( int latseg = 0; latseg < numlatsegs; latseg++ ) { + + bams_t lat = emp->lat - ( ( emp->lat * 2 * latseg ) / ( numlatsegs - 1 ) ); + + sincosval_s latirp; + GetSinCos( lat, &latirp ); + + for ( int lonseg = 0; lonseg < numlonsegs; lonseg++ ) { + + bams_t lon = ( BAMS_DEG360 * lonseg ) / ( numlonsegs - 1 ); + + sincosval_s longrp; + GetSinCos( lon, &longrp ); + + int curidx = latseg * numlonsegs + lonseg; + emp->ObjVtxs[ curidx ].X = GEOMV_MUL( longrp.cosval, latirp.cosval ); + emp->ObjVtxs[ curidx ].Y = latirp.sinval; + emp->ObjVtxs[ curidx ].Z = GEOMV_MUL( longrp.sinval, latirp.cosval ); + } + } + +// AUD_Emp( shippo ); +} + + +// template for default values of fields; may be altered from the console ----- +// +static Emp *emp_type_template[ EMP_UPGRADES ] = { + NULL, NULL, NULL, +}; + + +// init type fields with default values --------------------------------------- +// +PRIVATE +void EmpInitDefaults( Emp *emp, int upgradelevel ) +{ + ASSERT( emp != NULL ); + ASSERT( ( upgradelevel < EMP_UPGRADES ) && ( upgradelevel >= 0 ) ); + + emp->upgradelevel = upgradelevel; + + switch ( upgradelevel ) { + case 0: + strncpy( emp->texname, EMP_TEXNAME, EMP_MAX_TEX_NAME ); + emp->texname[ EMP_MAX_TEX_NAME ] = 0; + emp->lat = EMP_LAT; + emp->lod = EMP_LOD; + emp->rot = EMP_ROT; + emp->red = EMP_RED; + emp->green = EMP_GREEN; + emp->blue = EMP_BLUE; + emp->alpha = EMP_ALPHA; + emp->damage = EMP_DAMAGE; + break; + case 1: + strncpy( emp->texname, EMP_UP1_TEXNAME, EMP_MAX_TEX_NAME ); + emp->texname[ EMP_MAX_TEX_NAME ] = 0; + emp->lat = EMP_UP1_LAT; + emp->lod = EMP_UP1_LOD; + emp->rot = EMP_UP1_ROT; + emp->red = EMP_UP1_RED; + emp->green = EMP_UP1_GREEN; + emp->blue = EMP_UP1_BLUE; + emp->alpha = EMP_UP1_ALPHA; + emp->damage = EMP_UP1_DAMAGE; + break; + case 2: + strncpy( emp->texname, EMP_UP2_TEXNAME, EMP_MAX_TEX_NAME ); + emp->texname[ EMP_MAX_TEX_NAME ] = 0; + emp->lat = EMP_UP2_LAT; + emp->lod = EMP_UP2_LOD; + emp->rot = EMP_UP2_ROT; + emp->red = EMP_UP2_RED; + emp->green = EMP_UP2_GREEN; + emp->blue = EMP_UP2_BLUE; + emp->alpha = EMP_UP2_ALPHA; + emp->damage = EMP_UP2_DAMAGE; + break; + default: + ASSERT( 0 ); + } + + emp->ObjVtxs = NULL; + emp->WorldVtxs = NULL; + emp->BoundingSphere = GEOMV_0; +} + + +// type fields init function for emp ------------------------------------------ +// +PRIVATE +void EmpInitType( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + + // init either from template or default values + if ( !OBJ_InitFromCustomTypeTemplate( emp, emp_type_template[ 0 ] ) ) { + EmpInitDefaults( emp, 0 ); + } +} + + +PRIVATE +void EmpInitTypeUp1( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + + // init either from template or default values + if ( !OBJ_InitFromCustomTypeTemplate( emp, emp_type_template[ 1 ] ) ) { + EmpInitDefaults( emp, 1 ); + } +} + + +PRIVATE +void EmpInitTypeUp2( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + + // init either from template or default values + if ( !OBJ_InitFromCustomTypeTemplate( emp, emp_type_template[ 2 ] ) ) { + EmpInitDefaults( emp, 2 ); + } +} + + +// emp constructor (class instantiation) -------------------------------------- +// +PRIVATE +void EmpInstantiate( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + + // dynamic mem allocated in CreateEmp() + // (LOD is set there) +} + + +// emp destructor (instance destruction) -------------------------------------- +// +PRIVATE +void EmpDestroy( CustomObject *base ) +{ + ASSERT( base != NULL ); + Emp *emp = (Emp *) base; + +#ifndef PARSEC_SERVER + // ensure pending callbacks are destroyed to avoid + // calling them with invalid pointers + int numremoved = CALLBACK_DestroyCallback( callback_type, (void *) base ); + ASSERT( numremoved <= 1 ); +#endif + + // free object structure memory + FREEMEM( emp->ObjVtxs ); + emp->ObjVtxs = NULL; +} + + + +#ifndef PARSEC_SERVER +// ---------------------------------------------------------------------------- +// EMP DEVICE BEHAVIOUR +// ---------------------------------------------------------------------------- + + +// maintain emp of local ship ------------------------------------------------- +// +void WFX_CreateEmpWaves( ShipObject *shippo ) +{ + ASSERT( shippo != NULL ); + + shippo->EmpRefframesDelta += CurScreenRefFrames; + + int curwave; + + int curupgrade = 0; + if ( shippo->Specials & SPMASK_EMP_UPGRADE_2 ) { + curupgrade = 2; + } else if ( shippo->Specials & SPMASK_EMP_UPGRADE_1 ) { + curupgrade = 1; + } + + // try standard emp if low energy + if ( shippo->CurEnergy < emp_energy[ curupgrade ] ) { + curupgrade = 0; + } + + int numwaves = shippo->EmpRefframesDelta / emp_delay[ curupgrade ]; + int curalive = shippo->EmpRefframesDelta - emp_delay[ curupgrade ]; + dword energy_consumption = emp_energy[ curupgrade ]; + + // create waves (oldest first) + for ( curwave = ( numwaves - 1 ); curwave >= 0; curwave-- ) { + + // check if enough energy to create single wave + if ( (dword)shippo->CurEnergy >= energy_consumption ) { + + shippo->CurEnergy -= energy_consumption; + CreateEmp( shippo, 0, curalive, curupgrade ); + curalive -= emp_delay[ curupgrade ]; + } else { + + break; + } + } + + shippo->EmpRefframesDelta %= emp_delay[ curupgrade ]; +} + + +// activate emp of local ship ------------------------------------------------- +// +int WFX_ActivateEmp( ShipObject *shippo ) +{ + ASSERT( shippo != NULL ); + ASSERT( shippo == MyShip ); + ASSERT( ( shippo->WeaponsActive & WPMASK_DEVICE_EMP ) == 0 ); + + // check if enough space in RE_List + if ( !NET_RmEvAllowed( RE_WEAPONSTATE ) ) { + return FALSE; + } + + // check if emp available + if ( !OBJ_DeviceAvailable( shippo, WPMASK_DEVICE_EMP ) ) { + ShowMessage( no_emp_str ); + return FALSE; + } + + // create first emp-wave + int curupgrade = 0; + if ( shippo->Specials & SPMASK_EMP_UPGRADE_2 ) { + curupgrade = 2; + } else if ( shippo->Specials & SPMASK_EMP_UPGRADE_1 ) { + curupgrade = 1; + } + + shippo->EmpRefframesDelta = 0; + + // check if enough energy to shoot emp + if ( shippo->CurEnergy >= emp_energy[ curupgrade ] ) { + shippo->CurEnergy -= emp_energy[ curupgrade ]; + CreateEmp( shippo, 0, 0, curupgrade ); + } + // try standard emp + else if ( shippo->CurEnergy >= emp_energy[ 0 ] ) { + shippo->CurEnergy -= emp_energy[ 0 ]; + CreateEmp( shippo, 0, 0, 0 ); + } + else { + ShowMessage( low_energy_str ); + AUD_LowEnergy(); + return FALSE; + } + + // set active flag + shippo->WeaponsActive |= WPMASK_DEVICE_EMP; + + // send remote event to switch emp on + NET_RmEvWeaponState( WPMASK_DEVICE_EMP, WPSTATE_ON, shippo->CurEnergy, shippo->Specials ); + + // record activation event if recording active + Record_EmpActivation(); + + // play sound +// AUD_Emp( shippo ); + + return TRUE; +} + + +// deactivate emp of specified ship ------------------------------------------- +// +void WFX_DeactivateEmp( ShipObject *shippo ) +{ + ASSERT( shippo != NULL ); + ASSERT( shippo->WeaponsActive & WPMASK_DEVICE_EMP ); + + // local ship is special case + if ( shippo == MyShip ) { + + // check if enough space in RE_List + if ( !NET_RmEvAllowed( RE_WEAPONSTATE ) ) { + return; + } + + // send remote event to switch emp off + NET_RmEvWeaponState( WPMASK_DEVICE_EMP, WPSTATE_OFF, shippo->CurEnergy, shippo->Specials ); + + // record deactivation event if recording active + Record_EmpDeactivation(); + } + + // reset activation flag + shippo->WeaponsActive &= ~WPMASK_DEVICE_EMP; +} + + +// remote player activated emp ------------------------------------------------ +// +void WFX_RemoteActivateEmp( int playerid ) +{ + // fetch pointer to remote player's ship + ShipObject *shippo = NET_FetchOwnersShip( playerid ); + ASSERT( shippo != NULL ); + ASSERT( shippo != MyShip ); + + // make sure emp is active + if ( ( shippo->WeaponsActive & WPMASK_DEVICE_EMP) == 0 ) { + + // avoid additional stuff that would be done + // by WFX_ActivateEmp() + + // create first emp-wave + int curupgrade = 0; + if ( shippo->Specials & SPMASK_EMP_UPGRADE_2 ) { + curupgrade = 2; + } else if ( shippo->Specials & SPMASK_EMP_UPGRADE_1 ) { + curupgrade = 1; + } + + shippo->EmpRefframesDelta = 0; + + // check if enough energy to shoot emp + if ( shippo->CurEnergy >= emp_energy[ curupgrade ] ) { + shippo->CurEnergy -= emp_energy[ curupgrade ]; + CreateEmp( shippo, 0, 0, curupgrade ); + } + // try standard emp + else if ( shippo->CurEnergy >= emp_energy[ 0 ] ) { + shippo->CurEnergy -= emp_energy[ 0 ]; + CreateEmp( shippo, 0, 0, 0 ); + } + else { + return; + } + + shippo->WeaponsActive |= WPMASK_DEVICE_EMP; + } +} + + +// remote player deactivated emp ---------------------------------------------- +// +void WFX_RemoteDeactivateEmp( int playerid ) +{ + // fetch pointer to remote player's ship + ShipObject *shippo = NET_FetchOwnersShip( playerid ); + ASSERT( shippo != NULL ); + ASSERT( shippo != MyShip ); + + // make sure emp is inactive + if ( shippo->WeaponsActive & WPMASK_DEVICE_EMP) { + + // reset activation flag + shippo->WeaponsActive &= ~WPMASK_DEVICE_EMP; + } +} + + +// create emp blast ----------------------------------------------------------- +// +void WFX_EmpBlast( ShipObject *shippo ) +{ + ASSERT( shippo != NULL ); + + // check if enough space in RE_List + if ( !NET_RmEvAllowed( RE_CREATEEMP ) ) + return; + + if ( ( MyShip->Weapons & WPMASK_DEVICE_EMP ) == 0 ) { + ShowMessage( no_emp_str ); + return; + } + + int curdelay = 0; + + int curupgrade = 0; + if ( shippo->Specials & SPMASK_EMP_UPGRADE_2 ) { + curupgrade = 2; + } else if ( shippo->Specials & SPMASK_EMP_UPGRADE_1 ) { + curupgrade = 1; + } + int used_upgrade = curupgrade; + + int energy_consumption = emp_energy[ curupgrade ] * emp_waves[ curupgrade ]; + + // check if enough energy to shoot emp + if ( shippo->CurEnergy >= energy_consumption ) { + + shippo->CurEnergy -= energy_consumption; + + for ( int i = 0; i < emp_waves[ curupgrade ]; i++ ) { + CreateEmp( shippo, curdelay, 0, curupgrade ); + curdelay += emp_delay[ curupgrade ]; + } + } + // try standard emp + else if ( shippo->CurEnergy >= ( emp_energy[ 0 ] * emp_waves[ 0 ] ) ) { + + shippo->CurEnergy -= ( emp_energy[ 0 ] * emp_waves[ 0 ] ); + + for ( int i = 0; i < emp_waves[ 0 ]; i++ ) { + CreateEmp( shippo, curdelay, 0, 0 ); + curdelay += emp_delay[ 0 ]; + } + used_upgrade = 0; + } + else { + ShowMessage( low_energy_str ); + AUD_LowEnergy(); + return; + } + + // insert remote event + NET_RmEvCreateEmp( used_upgrade ); + + // record create event if recording active + Record_EmpCreation(); + + // play sound effect + AUD_EmpBlast( shippo, curupgrade ); +} + + +// create emp blast ----------------------------------------------------------- +// +void WFX_RemoteEmpBlast( ShipObject *shippo, int curupgrade ) +{ + ASSERT( shippo != NULL ); + + int curdelay = 0; + + for ( int i = 0; i < emp_waves[ curupgrade ]; i++ ) { + CreateEmp( shippo, curdelay, 0, curupgrade ); + curdelay += emp_delay[ curupgrade ]; + } + + // play sound effect + AUD_EmpBlast( shippo, curupgrade ); +} + +#endif + + +// ---------------------------------------------------------------------------- +// EMP REGISTRATION AND CONSOLE COMMANDS +// ---------------------------------------------------------------------------- + + +// register object types for emp ---------------------------------------------- +// +PRIVATE +void EmpRegisterCustomTypes() +{ + custom_type_info_s info; + memset( &info, 0, sizeof( info ) ); + + // always try to allocate templates + for ( int i = 0; i < EMP_UPGRADES; i++ ) { + emp_type_template[ i ] = (Emp *) ALLOCMEM( sizeof( Emp ) ); + if ( emp_type_template[ i ] != NULL ) { + memset( emp_type_template[ i ], 0, sizeof( Emp ) ); + EmpInitDefaults( emp_type_template[ i ], i ); + } + } + + info.type_name = "emp"; + info.type_id = 0x00000000; + info.type_size = sizeof( Emp ); + info.type_template = emp_type_template[ 0 ]; + info.type_flags = CUSTOM_TYPE_DEFAULT; + info.callback_init = EmpInitType; + info.callback_instant = EmpInstantiate; + info.callback_destroy = EmpDestroy; + info.callback_animate = EmpAnimate; + info.callback_collide = CheckEmpCollision; + info.callback_notify = NULL; + info.callback_persist = NULL; + + emp_type_id[ 0 ] = OBJ_RegisterCustomType( &info ); + CON_RegisterCustomType( info.type_id, Emp_PropList ); + + memset( &info, 0, sizeof( info ) ); + + info.type_name = "empup1"; + info.type_id = 0x00000000; + info.type_size = sizeof( Emp ); + info.type_template = emp_type_template[ 1 ]; + info.type_flags = CUSTOM_TYPE_DEFAULT; + info.callback_init = EmpInitTypeUp1; + info.callback_instant = EmpInstantiate; + info.callback_destroy = EmpDestroy; + info.callback_animate = EmpAnimate; + info.callback_collide = CheckEmpCollision; + info.callback_notify = NULL; + info.callback_persist = NULL; + + emp_type_id[ 1 ] = OBJ_RegisterCustomType( &info ); + CON_RegisterCustomType( info.type_id, EmpUp1_PropList ); + + memset( &info, 0, sizeof( info ) ); + + info.type_name = "empup2"; + info.type_id = 0x00000000; + info.type_size = sizeof( Emp ); + info.type_template = emp_type_template[ 2 ]; + info.type_flags = CUSTOM_TYPE_DEFAULT; + info.callback_init = EmpInitTypeUp2; + info.callback_instant = EmpInstantiate; + info.callback_destroy = EmpDestroy; + info.callback_animate = EmpAnimate; + info.callback_collide = CheckEmpCollision; + info.callback_notify = NULL; + info.callback_persist = NULL; + + emp_type_id[ 2 ] = OBJ_RegisterCustomType( &info ); + CON_RegisterCustomType( info.type_id, EmpUp2_PropList ); +} + + +// precalculate expansion table for given parameters -------------------------- +// +PRIVATE +void InitExpansionTableEmp( float **expansion_tab, int lifetime, float lambda ) +{ + ASSERT( ( lifetime >= EMP_MIN_LIFETIME ) && ( lifetime <= EMP_MAX_LIFETIME ) ); + ASSERT( lambda > 0.0 ); + + if ( *expansion_tab != NULL ) { + FREEMEM( *expansion_tab ); + *expansion_tab = NULL; + } + + *expansion_tab = (float *) ALLOCMEM( ( lifetime ) * sizeof( float ) ); + if ( *expansion_tab == NULL ) + OUTOFMEM( 0 ); + + // precalc full expansion curve in time resolution + // exactly as needed for emp expansion + float ref_factor = 1.0 / ( 1.0 - exp( -lambda ) ); + + for ( int i = 0; i < lifetime; i++ ) { + (*expansion_tab)[ i ] = ( 1.0 - exp( -lambda * ( (float) i / (float) lifetime) ) ) * ref_factor; + } +} + + +// key table for emp command -------------------------------------------- +// +key_value_s emp_key_value[] = { + + { "lifetime", NULL, KEYVALFLAG_NONE }, + { "maxwidth", NULL, KEYVALFLAG_NONE }, + { "lambda", NULL, KEYVALFLAG_NONE }, + { "fadeout", NULL, KEYVALFLAG_NONE }, + { "waves", NULL, KEYVALFLAG_NONE }, + { "delay", NULL, KEYVALFLAG_NONE }, + { "energy", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_EMP_LIFETIME, + KEY_EMP_MAXWIDTH, + KEY_EMP_LAMBDA, + KEY_EMP_FADEOUT, + KEY_EMP_WAVES, + KEY_EMP_DELAY, + KEY_EMP_ENERGY +}; + + +// customize emp -------------------------------------------------------------- +// +PRIVATE +int EMP_CONF( char *paramstr, int upgradelevel ) +{ + //NOTE: + //CONCOM: + // emp_conf_command ::= 'emp.conf' [<lifetime_spec>] [<maxwidth_spec>] + // [<lambda_spec>] [<fadeout_spec>] [<waves_spec>] + // [<delay_spec>] [<energy_spec>] + // lifetime_spec ::= 'lifetime' <int> + // maxwidth_spec ::= 'maxwidth' <float> + // lambda_spec ::= 'lambda' <float> + // fadeout_spec ::= 'fadeout' <int> + // waves_spec ::= 'waves' <int> + // delay_spec ::= 'delay' <int> + // energy_spec ::= 'energy' <int> + + ASSERT( paramstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( paramstr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( emp_key_value, paramstr ) ) + return TRUE; + + int alldefaults = TRUE; + int lifetime = emp_lifetime[ upgradelevel ]; + float max_width = GEOMV_TO_FLOAT( emp_max_width[ upgradelevel ] ); + float lambda = emp_lambda[ upgradelevel ]; + int fadeout = emp_fadeout[ upgradelevel ]; + int waves = emp_waves[ upgradelevel ]; + int delay = emp_delay[ upgradelevel ]; + int energy = emp_energy[ upgradelevel ]; + + // lifetime + if ( emp_key_value[ KEY_EMP_LIFETIME ].value != NULL ) { + + if ( ScanKeyValueInt( &emp_key_value[ KEY_EMP_LIFETIME ], &lifetime ) < 0 ) { + CON_AddLine( emp_inval_lifetime_spec ); + return TRUE; + } + if ( ( lifetime < EMP_MIN_LIFETIME ) || ( lifetime > EMP_MAX_LIFETIME ) ) { + CON_AddLine( emp_inval_lifetime_spec ); + return TRUE; + } + if ( lifetime < fadeout ) { + fadeout = lifetime; + } + alldefaults = FALSE; + } + + // max_width + if ( emp_key_value[ KEY_EMP_MAXWIDTH ].value != NULL ) { + + if ( ScanKeyValueFloat( &emp_key_value[ KEY_EMP_MAXWIDTH ], &max_width ) < 0 ) { + CON_AddLine( emp_inval_maxwidth_spec ); + return TRUE; + } + if ( max_width <= 0.0 ) { + CON_AddLine( emp_inval_maxwidth_spec ); + return TRUE; + } + alldefaults = FALSE; + } + + // lambda + if ( emp_key_value[ KEY_EMP_LAMBDA ].value != NULL ) { + + if ( ScanKeyValueFloat( &emp_key_value[ KEY_EMP_LAMBDA ], &lambda ) < 0 ) { + CON_AddLine( emp_inval_lambda_spec ); + return TRUE; + } + if ( lambda <= 0.0 ) { + CON_AddLine( emp_inval_maxwidth_spec ); + return TRUE; + } + alldefaults = FALSE; + } + + // fadeout + if ( emp_key_value[ KEY_EMP_FADEOUT ].value != NULL ) { + + if ( ScanKeyValueInt( &emp_key_value[ KEY_EMP_FADEOUT ], &fadeout ) < 0 ) { + CON_AddLine( emp_inval_fadeout_spec ); + return TRUE; + } + if ( ( fadeout < 0 ) || ( fadeout > EMP_MAX_LIFETIME ) ) { + CON_AddLine( emp_inval_fadeout_spec ); + return TRUE; + } + if ( fadeout > lifetime ) { + lifetime = fadeout; + } + alldefaults = FALSE; + } + + // waves + if ( emp_key_value[ KEY_EMP_WAVES ].value != NULL ) { + + if ( ScanKeyValueInt( &emp_key_value[ KEY_EMP_WAVES ], &waves ) < 0 ) { + CON_AddLine( emp_inval_waves_spec ); + return TRUE; + } + if ( ( waves < EMP_MIN_WAVES ) || ( waves > EMP_MAX_WAVES ) ) { + CON_AddLine( emp_inval_waves_spec ); + return TRUE; + } + alldefaults = FALSE; + } + + // delay + if ( emp_key_value[ KEY_EMP_DELAY ].value != NULL ) { + + if ( ScanKeyValueInt( &emp_key_value[ KEY_EMP_DELAY ], &delay ) < 0 ) { + CON_AddLine( emp_inval_delay_spec ); + return TRUE; + } + if ( ( waves < EMP_MIN_DELAY ) || ( waves > EMP_MAX_DELAY ) ) { + CON_AddLine( emp_inval_delay_spec ); + return TRUE; + } + alldefaults = FALSE; + } + + // energy + if ( emp_key_value[ KEY_EMP_ENERGY ].value != NULL ) { + + if ( ScanKeyValueInt( &emp_key_value[ KEY_EMP_ENERGY ], &energy ) < 0 ) { + CON_AddLine( emp_inval_energy_spec ); + return TRUE; + } + if ( ( energy < 0 ) ) { + CON_AddLine( emp_inval_energy_spec ); + return TRUE; + } + alldefaults = FALSE; + } + + if ( !alldefaults ) { + emp_max_width[ upgradelevel ] = FLOAT_TO_GEOMV( max_width ); + emp_fadeout[ upgradelevel ] = fadeout; + emp_waves[ upgradelevel ] = waves; + emp_delay[ upgradelevel ] = delay; + emp_energy[ upgradelevel ] = energy; + if ( ( lifetime != emp_lifetime[ upgradelevel ] ) || ( lambda != emp_lambda[ upgradelevel ] ) ) { + emp_lifetime[ upgradelevel ] = lifetime; + emp_lambda[ upgradelevel ] = lambda; + InitExpansionTableEmp( &emp_expansion_tab[ upgradelevel ], lifetime, lambda ); + } + } + else { + //FIXME: + // hack! + switch ( upgradelevel ) { + case 0: + sprintf( paste_str, "maxwidth: %f (%f)", max_width, EMP_MAX_WIDTH ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lifetime: %d (%d)", lifetime, EMP_LIFETIME ); + CON_AddLine( paste_str ); + sprintf( paste_str, "fadeout: %d (%d)", fadeout, EMP_FADEOUT ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lambda: %f (%f)", lambda, EMP_LAMBDA ); + CON_AddLine( paste_str ); + sprintf( paste_str, "delay: %d (%d)", delay, EMP_DELAY ); + CON_AddLine( paste_str ); + sprintf( paste_str, "waves: %d (%d)", waves, EMP_WAVES ); + CON_AddLine( paste_str ); + sprintf( paste_str, "energy: %d (%d)", energy, EMP_ENERGY ); + CON_AddLine( paste_str ); + break; + + case 1: + sprintf( paste_str, "maxwidth: %f (%f)", max_width, EMP_UP1_MAX_WIDTH ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lifetime: %d (%d)", lifetime, EMP_UP1_LIFETIME ); + CON_AddLine( paste_str ); + sprintf( paste_str, "fadeout: %d (%d)", fadeout, EMP_UP1_FADEOUT ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lambda: %f (%f)", lambda, EMP_UP1_LAMBDA ); + CON_AddLine( paste_str ); + sprintf( paste_str, "delay: %d (%d)", delay, EMP_UP1_DELAY ); + CON_AddLine( paste_str ); + sprintf( paste_str, "waves: %d (%d)", waves, EMP_UP1_WAVES ); + CON_AddLine( paste_str ); + sprintf( paste_str, "energy: %d (%d)", energy, EMP_UP1_ENERGY ); + CON_AddLine( paste_str ); + break; + + case 2: + sprintf( paste_str, "maxwidth: %f (%f)", max_width, EMP_UP2_MAX_WIDTH ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lifetime: %d (%d)", lifetime, EMP_UP2_LIFETIME ); + CON_AddLine( paste_str ); + sprintf( paste_str, "fadeout: %d (%d)", fadeout, EMP_UP2_FADEOUT ); + CON_AddLine( paste_str ); + sprintf( paste_str, "lambda: %f (%f)", lambda, EMP_UP2_LAMBDA ); + CON_AddLine( paste_str ); + sprintf( paste_str, "delay: %d (%d)", delay, EMP_UP2_DELAY ); + CON_AddLine( paste_str ); + sprintf( paste_str, "waves: %d (%d)", waves, EMP_UP2_WAVES ); + CON_AddLine( paste_str ); + sprintf( paste_str, "energy: %d (%d)", energy, EMP_UP2_ENERGY ); + CON_AddLine( paste_str ); + break; + + default: + ASSERT( 0 ); + } + } + + return TRUE; +} + + +PRIVATE +int Cmd_EMP_CONF( char *paramstr ) +{ + //NOTE: + //CONCOM: + // emp_conf_command ::= 'emp.conf' [<lifetime_spec>] [<maxwidth_spec>] + // [<lambda_spec>] [<fadeout_spec>] [<waves_spec>] + // [<delay_spec>] [<energy_spec>] + // lifetime_spec ::= 'lifetime' <int> + // maxwidth_spec ::= 'maxwidth' <float> + // lambda_spec ::= 'lambda' <float> + // fadeout_spec ::= 'fadeout' <int> + // waves_spec ::= 'waves' <int> + // delay_spec ::= 'delay' <int> + // energy_spec ::= 'energy' <int> + + return EMP_CONF( paramstr, 0 ); +} + + +PRIVATE +int Cmd_EMPUP1_CONF( char *paramstr ) +{ + //NOTE: + //CONCOM: + // emp_conf_command ::= 'empup1.conf' [<lifetime_spec>] [<maxwidth_spec>] + // [<lambda_spec>] [<fadeout_spec>] [<waves_spec>] + // [<delay_spec>] [<energy_spec>] + // lifetime_spec ::= 'lifetime' <int> + // maxwidth_spec ::= 'maxwidth' <float> + // lambda_spec ::= 'lambda' <float> + // fadeout_spec ::= 'fadeout' <int> + // waves_spec ::= 'waves' <int> + // delay_spec ::= 'delay' <int> + // energy_spec ::= 'energy' <int> + + return EMP_CONF( paramstr, 1 ); +} + + +PRIVATE +int Cmd_EMPUP2_CONF( char *paramstr ) +{ + //NOTE: + //CONCOM: + // emp_conf_command ::= 'empup2.conf' [<lifetime_spec>] [<maxwidth_spec>] + // [<lambda_spec>] [<fadeout_spec>] [<waves_spec>] + // [<delay_spec>] [<energy_spec>] + // lifetime_spec ::= 'lifetime' <int> + // maxwidth_spec ::= 'maxwidth' <float> + // lambda_spec ::= 'lambda' <float> + // fadeout_spec ::= 'fadeout' <int> + // waves_spec ::= 'waves' <int> + // delay_spec ::= 'delay' <int> + // energy_spec ::= 'energy' <int> + + return EMP_CONF( paramstr, 2 ); +} + + +// console command for activating the emp ------------------------------------- +// +PRIVATE +int Cmd_EMP( char *argstr ) +{ + //NOTE: + //CONCOM: + // emp_command ::= 'emp' + + ASSERT( argstr != NULL ); + HANDLE_COMMAND_DOMAIN( argstr ); +#ifndef PARSEC_SERVER + WFX_EmpBlast( MyShip ); +#endif + return TRUE; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( G_EMP ) +{ + // register type + EmpRegisterCustomTypes(); + + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "emp.conf" command + regcom.command = "emp.conf"; + regcom.numparams = 1; + regcom.execute = Cmd_EMP_CONF; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "empup1.conf" command + regcom.command = "empup1.conf"; + regcom.numparams = 1; + regcom.execute = Cmd_EMPUP1_CONF; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "empup2.conf" command + regcom.command = "empup2.conf"; + regcom.numparams = 1; + regcom.execute = Cmd_EMPUP2_CONF; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // register "emp" command + regcom.command = "emp"; + regcom.numparams = 0; + regcom.execute = Cmd_EMP; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // init default expansion tables + InitExpansionTableEmp( &emp_expansion_tab[ 0 ], EMP_LIFETIME, EMP_LAMBDA ); + InitExpansionTableEmp( &emp_expansion_tab[ 1 ], EMP_UP1_LIFETIME, EMP_UP1_LAMBDA ); + InitExpansionTableEmp( &emp_expansion_tab[ 2 ], EMP_UP2_LIFETIME, EMP_UP2_LAMBDA ); +} + + + diff --git a/src/libparsec/g_extra.cpp b/src/libparsec/g_extra.cpp new file mode 100644 index 0000000..c9b6057 --- /dev/null +++ b/src/libparsec/g_extra.cpp @@ -0,0 +1,1598 @@ +/* + * PARSEC - Extra management - SERVER + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:45 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem & headers +#include "net_defs.h" +//#include "e_defs.h" +#ifdef PARSEC_CLIENT + #include "aud_defs.h" +#endif // PARSEC_CLIENT + +// mathematics header +#include "utl_math.h" + +// utility headers +#include "utl_list.h" + +// local module header +#include "g_extra.h" + +#ifdef PARSEC_CLIENT + + // proprietary module headers + #include "con_aux.h" + #include "e_demo.h" + #include "g_supp.h" + //#include "net_game.h" + //#include "net_util.h" + #include "obj_clas.h" + #include "obj_creg.h" + #include "obj_ctrl.h" + #include "obj_game.h" + #include "obj_name.h" + #include "od_props.h" + #include "od_class.h" + #include "g_sfx.h" + //#include "e_connmanager.h" + //#include "e_simulator.h" + + #include "g_shipobject.h" + +#else // !PARSEC_CLIENT + + // proprietary module headers + #include "con_aux_sv.h" + #include "g_player.h" + #include "net_game_sv.h" + //#include "net_util.h" + #include "obj_clas.h" + #include "obj_creg.h" + #include "obj_name.h" + #include "od_props.h" + #include "od_class.h" + #include "g_main_sv.h" + #include "e_connmanager.h" + #include "e_simnetoutput.h" + #include "e_simulator.h" + #include "g_shipobject.h" + +#endif // !PARSEC_CLIENT + + +// number of refframes that extras should drift before they stop -------------- +// +#define DEFAULT_DRIFT_TIMEOUT 2000 + +// message strings ------------------------------------------------------------ +// +//FIXME: centralize ? +static char got_energy_str[] = "energy boosted"; +static char max_energy_str[] = "energy maxed out"; +static char no_decoy_str[] = "no holo decoy device"; +static char decoy_activated_str[] = "holo decoy activated"; +static char no_invisibility_str[] = "no invisibility device"; +static char invisibility_activated_str[] = "invisibility activated"; + +// strings for extra collections ---------------------------------------------- +// +//FIXME: centralize ? +static char got_dumb_str[] = "dumb missiles collected"; +static char max_dumb_str[] = "dumb missiles maxed out"; +static char got_homing_str[] = "guided missiles found"; +static char max_homing_str[] = "guided missiles maxed out"; +static char got_mines_str[] = "found proximity mines"; +static char max_mines_str[] = "mines maxed out"; +static char got_swarm_str[] = "swarm missiles found"; +static char max_swarm_str[] = "swarm missiles maxed out"; +static char got_helix_str[] = "got helix cannon"; +static char max_helix_str[] = "already got helix cannon"; +static char got_lightning_str[] = "got lightning device"; +static char max_lightning_str[] = "already got lightning device"; +static char got_photon_str[] = "got photon cannon"; +static char max_photon_str[] = "already got photon cannon"; +static char unknown_dev_str[] = "got unknown device"; +static char unknown_extra_str[] = "got unknown extra"; +static char no_damage_str[] = "no damage to repair"; +static char damage_repaired[] = "damage repaired"; +static char mine_killed_str[] = "killed by mine"; +static char mine_hit_str[] = "mine hit"; +static char got_afterburner_str[] = "got afterburner"; +static char max_afterburner_str[] = "already got afterburner"; +static char got_cloak_str[] = "got cloaking device"; +static char max_cloak_str[] = "cloak reactivated"; +static char got_megashield_str[] = "got invulnerability shield"; +static char max_megashield_str[] = "invulnerability reinforced"; +static char got_decoy_str[] = "got holo decoy device"; +static char max_decoy_str[] = "already got holo decoy device"; +static char got_laser_upgrade_1_str[] = "got laser upgrade 1"; +static char max_laser_upgrade_1_str[] = "already got laser upgrade 1"; +static char got_laser_upgrade_2_str[] = "got laser upgrade 2"; +static char max_laser_upgrade_2_str[] = "already got laser upgrade 2"; +static char need_laser_upgrade_1_str[] = "need laser upgrade 1 first"; +static char got_emp_str[] = "got emp device"; +static char max_emp_str[] = "already got emp device"; +static char got_emp_upgrade_1_str[] = "got emp upgrade 1"; +static char max_emp_upgrade_1_str[] = "already got emp upgrade 1"; +static char got_emp_upgrade_2_str[] = "got emp upgrade 2"; +static char max_emp_upgrade_2_str[] = "already got emp upgrade 2"; +static char need_emp_upgrade_1_str[] = "need emp upgrade 1 first"; + + +// flags ---------------------------------------------------------------------- +// +//#define TEST_EXTRA_CREATION_CODE +//#define TEST_EXTRA_CREATION_CODE_ON_SHIP_DOWNING + + +// standard ctor -------------------------------------------------------------- +// +G_ExtraManager::G_ExtraManager() +{ + ExtraProbability = EXTRA_PROBABILITY; + MaxExtraArea = MAX_EXTRA_AREA; + MinExtraDist = MIN_EXTRA_DIST; + + ProbHelixCannon = PROB_DAZZLE_LASER; + ProbLightningDevice = PROB_THIEF_LASER; + ProbPhotonCannon = 0; + + ProbProximityMine = PROB_PROXIMITY_MINE; + + ProbMissilePack = PROB_MISSILE_PACK; + ProbDumbMissPack = PROB_DUMB_MISS_PACK; + ProbHomMissPack = PROB_HOM_MISS_PACK; + ProbSwarmMissPack = 0; + + ProbRepairExtra = 0; + ProbAfterburner = 0; + ProbHoloDecoy = 0; + ProbInvisibility = 0; + ProbInvulnerability = 0; + ProbEnergyField = 0; + + ProbLaserUpgrade = 0; + ProbLaserUpgrade1 = 0; + ProbLaserUpgrade2 = 0; + + ProbEmpUpgrade1 = 0; + ProbEmpUpgrade2 = 0; +} + +// fill member variables of extras -------------------------------------------- +// +void G_ExtraManager::OBJ_FillExtraMemberVars( ExtraObject *extrapo ) +{ +#ifdef PARSEC_CLIENT + ASSERT( FALSE ); +#else // !PARSEC_CLIENT + + ASSERT( extrapo != NULL ); + ASSERT( OBJECT_TYPE_EXTRA( extrapo ) ); + + //NOTE: + // this function may be called for mines, but it need + // not be (and is indeed not called when the owner of + // the mine is set manually). + + // mine is a special extra + if ( extrapo->ObjectType == MINE1TYPE ) { + + // fallback for owner is the local player + // (just to be on the safe side, the basic type + // init sets the owner to the same value) + ((MineObject*)extrapo)->Owner = OWNER_LOCAL_PLAYER; + return; + } + + // default: no drifting + extrapo->DriftTimeout = 0; + + Extra1Obj *extra1po; + Extra2Obj *extra2po; + Extra3Obj *extra3po; + + switch ( extrapo->ObjectClass ) { + + case ENERGY_EXTRA_CLASS: + extra1po = (Extra1Obj *) extrapo; + extra1po->EnergyBoost = TheGame->EnergyExtraBoost; + break; + + case REPAIR_EXTRA_CLASS: + extra1po = (Extra1Obj *) extrapo; + extra1po->EnergyBoost = TheGame->RepairExtraBoost; + break; + + case DUMB_PACK_CLASS: + extra2po = (Extra2Obj *) extrapo; + extra2po->MissileType = MISSILE1TYPE; + extra2po->NumMissiles = TheGame->DumbPackNumMissls; + break; + + case GUIDE_PACK_CLASS: + extra2po = (Extra2Obj *) extrapo; + extra2po->MissileType = MISSILE4TYPE; + extra2po->NumMissiles = TheGame->HomPackNumMissls; + break; + + case SWARM_PACK_CLASS: + extra2po = (Extra2Obj *) extrapo; + extra2po->MissileType = MISSILE5TYPE; + extra2po->NumMissiles = TheGame->SwarmPackNumMissls; + break; + + case HELIX_DEVICE_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = HELIX_DEVICE; + break; + + case LIGHTNING_DEVICE_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = LIGHTNING_DEVICE; + break; + + case MINE_PACK_CLASS: + extra2po = (Extra2Obj *) extrapo; + extra2po->MissileType = MINE1TYPE; + extra2po->NumMissiles = TheGame->ProxPackNumMines; + break; + + case AFTERBURNER_DEVICE_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = AFTERBURNER_DEVICE; + break; + + case INVISIBILITY_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = INVISIBILITY_DEVICE; + break; + + case INVULNERABILITY_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = INVULNERABILITY_DEVICE; + break; + + case PHOTON_DEVICE_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = PHOTON_DEVICE; + break; + + case DECOY_DEVICE_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = DECOY_DEVICE; + break; + + case LASERUPGRADE1_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = LASER_UPGRADE_1_DEVICE; + break; + + case LASERUPGRADE2_CLASS: + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = LASER_UPGRADE_2_DEVICE; + break; + + default: + + //FIXME: ?????? + if ( extrapo->ObjectClass == ExtraClasses[ EXTRAINDX_EMPUPGRADE1 ] ) { + + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = EMP_UPGRADE_1_DEVICE; + + } else if ( extrapo->ObjectClass == ExtraClasses[ EXTRAINDX_EMPUPGRADE2 ] ) { + + extra3po = (Extra3Obj *) extrapo; + extra3po->DeviceType = EMP_UPGRADE_2_DEVICE; + } + + break; + + + MSGOUT( "OBJ_FillExtraMemberVars(): unknown extra class: %d.", extrapo->ObjectClass ); + } +#endif // !PARSEC_CLIENT +} + + +// kill extra that immediately follows passed node in list -------------------- +// +void G_ExtraManager::OBJ_KillExtra( ExtraObject* precnode, int collected ) +{ + ASSERT( precnode != NULL ); + + ExtraObject *extra = (ExtraObject *) precnode->NextObj; + ASSERT( extra != NULL ); + +#ifdef PARSEC_CLIENT + + // create vanishing animation if not collected + if ( !collected ) { + SFX_VanishExtra( extra ); + } + + #ifndef NO_EXTRA_KILL_MESSAGES + + // only transmit collection events, not lifetime expiration + if ( !NET_ConnectedGMSV() ) { + if ( collected ) { + NET_RmEvKillObject( extra->HostObjNumber, EXTRA_LIST ); + } + } + + #endif // NO_EXTRA_KILL_MESSAGES + + + // unlink from list + precnode->NextObj = extra->NextObj; + + // free extra + FreeObjectMem( extra ); + +#else // !PARSEC_CLIENT + + // release the E_Distributable ( distribute removal ) + //MSGOUT( "G_ExtraManager::OBJ_KillExtra() calls ReleaseDistributable()" ); + TheSimNetOutput->ReleaseDistributable( extra->pDist ); + + // unlink from list + precnode->NextObj = extra->NextObj; + + // free extra + TheWorld->FreeObjectMem( extra ); + +#endif // !PARSEC_CLIENT +} + + +// animate an extra ----------------------------------------------------------- +// +void G_ExtraManager::OBJ_AnimateExtra( ExtraObject *extrapo ) +{ +#ifdef PARSEC_CLIENT + + ASSERT( FALSE ); + +#else // !PARSEC_CLIENT + + ASSERT( extrapo != NULL ); + ASSERT( OBJECT_TYPE_EXTRA( extrapo ) ); + + // do self rotation + ObjRotX( extrapo->ObjPosition, extrapo->SelfRotX * TheSimulator->GetThisFrameRefFrames() ); + ObjRotY( extrapo->ObjPosition, extrapo->SelfRotY * TheSimulator->GetThisFrameRefFrames() ); + ObjRotZ( extrapo->ObjPosition, extrapo->SelfRotZ * TheSimulator->GetThisFrameRefFrames() ); + + // drift extras away from ship explosion center + if ( extrapo->DriftTimeout == 0 ) + return; + + extrapo->DriftTimeout -= TheSimulator->GetThisFrameRefFrames(); + if ( extrapo->DriftTimeout < 0 ) + extrapo->DriftTimeout = 0; + + extrapo->ObjPosition[ 0 ][ 3 ] += extrapo->DriftVec.X * TheSimulator->GetThisFrameRefFrames(); + extrapo->ObjPosition[ 1 ][ 3 ] += extrapo->DriftVec.Y * TheSimulator->GetThisFrameRefFrames(); + extrapo->ObjPosition[ 2 ][ 3 ] += extrapo->DriftVec.Z * TheSimulator->GetThisFrameRefFrames(); + +#endif // !PARSEC_CLIENT +} + + +// place extras in vicinity of local ship object ------------------------------ +// +void G_ExtraManager::OBJ_DoExtraPlacement() +{ +#ifdef PARSEC_CLIENT + ASSERT( FALSE ); +#else // !PARSEC_CLIENT + +#ifdef PARSEC_SERVER + + // check whether to autocreate extras + if ( !SV_GAME_EXTRAS_AUTOCREATE ) { + return; + } + + // determine upper bound to number of extras + int maxextras = SV_GAME_EXTRAS_MAXNUM * TheConnManager->GetNumConnected(); + +#else // !PARSEC_SERVER + + // no extra creation in GMSV mode + if ( NET_ConnectedGMSV() ) { + return; + } + + // don't create extras during demo replay + if ( !AUX_CREATE_EXTRAS_DURING_REPLAY && DEMO_ReplayActive() ) + return; + + // check if enough space in RE_List + ASSERT( sizeof( RE_CreateExtra ) >= sizeof( RE_ParticleObject ) ); + if ( !NET_RmEvAllowed( RE_CREATEEXTRA ) ) { + return; + } + + // determine upper bound to number of extras + ASSERT( ( NumRemPlayers >= 0 ) && ( NumRemPlayers <= MAX_NET_PROTO_PLAYERS ) ); + int maxextras = MaxNumExtras; + if ( NetConnected ) { + ASSERT( NumRemPlayers > 0 ); + maxextras *= NumRemPlayers; + } + +#endif // !PARSEC_CLIENT + + // create random extra object + if ( ( TheWorld->m_nCurrentNumExtras + TheWorld->m_nCurrentNumPrtExtras ) < maxextras ) { + + // check whether to create an extra in this turn + int r = RAND() % 100; + if ( r > ExtraProbability ) + return; + + Vector3 spawn_point; + +#ifdef PARSEC_SERVER + + // spawn position is either somewhere around a randomly selected ship + // or the origin + if ( TheGame->GetNumJoined() > 0 ) { + + // get a random ship object + int nRandomPlayer = RAND() % TheGame->GetNumJoined(); + + UTL_List<G_Player*>* pCurJoinedPlayerList = TheGame->GetCurJoinedPlayerList(); + ASSERT( pCurJoinedPlayerList != NULL ); + + UTL_listentry_s<G_Player*>* entry = pCurJoinedPlayerList->GetEntryAtIndex( nRandomPlayer ); + ASSERT( entry != NULL ); + + G_Player* pPlayer = (G_Player*)entry->m_data; + ASSERT( pPlayer != NULL ); + + ShipObject* pCurShip = pPlayer->GetShipObject(); + ASSERT( pCurShip != NULL ); + + FetchTVector( pCurShip->ObjPosition, &spawn_point ); + } else { + + // spawn around origin + spawn_point.X = spawn_point.Y = spawn_point.Z = GEOMV_0; + } + +#else // !PARSEC_SERVER + + FetchTVector( MyShip->ObjPosition, &spawn_point ); + +#endif // !PARSEC_SERVER + + Xmatrx startm; + MakeIdMatrx( startm ); + +#ifdef PARSEC_SERVER + + if ( SV_GAME_EXTRAS_TESTPLACE ) { + + static int nNumExtraCreated = 0; + + startm[ 0 ][ 3 ] = INT_TO_GEOMV( 0 ); + startm[ 1 ][ 3 ] = INT_TO_GEOMV( 0 ); + startm[ 2 ][ 3 ] = INT_TO_GEOMV( ( ( nNumExtraCreated % 20 ) + 1 ) * 100 ); + + nNumExtraCreated++; + + } else { + +#endif // PARSEC_SERVER + + // get random position around currently selected ship + int x = ( RAND() % MaxExtraArea ) - MaxExtraArea / 2; + int y = ( RAND() % MaxExtraArea ) - MaxExtraArea / 2; + int z = ( RAND() % MaxExtraArea ) - MaxExtraArea / 2; + + x += ( x < 0 ) ? -MinExtraDist : MinExtraDist; + y += ( y < 0 ) ? -MinExtraDist : MinExtraDist; + z += ( z < 0 ) ? -MinExtraDist : MinExtraDist; + + startm[ 0 ][ 3 ] = INT_TO_GEOMV( x ) + spawn_point.X; + startm[ 1 ][ 3 ] = INT_TO_GEOMV( y ) + spawn_point.Y; + startm[ 2 ][ 3 ] = INT_TO_GEOMV( z ) + spawn_point.Z; + +#ifdef PARSEC_SERVER + } +#endif // PARSEC_SERVER + + int probsum = 0; + int objclass = -1; + int dice = RAND() % 100; + + // energy field + if ( dice < ( probsum += ProbEnergyField ) ) { + +#ifdef PARSEC_SERVER + // create energy field particle object + Vertex3 origin; + FetchTVector( startm, &origin ); + TheWorld->SFX_CreateEnergyField( origin ); + + RE_ParticleObject re_particleobject; + memset( &re_particleobject , 0, sizeof ( RE_ParticleObject ) ); + re_particleobject.RE_Type = RE_PARTICLEOBJECT; + re_particleobject.RE_BlockSize = sizeof( RE_ParticleObject ); + re_particleobject.ObjectType = POBJ_ENERGYFIELD; + re_particleobject.Origin = origin; + + TheSimNetOutput->BufferForMulticastRE((RE_ParticleObject *) &re_particleobject, PLAYERID_ANONYMOUS, FALSE); + + +#else // !PARSEC_SERVER + + // create energy field particle object + Vertex3 origin; + FetchTVector( startm, &origin ); + SFX_CreateEnergyField( origin ); + + // insert remote event + NET_RmEvParticleObject( POBJ_ENERGYFIELD, origin ); + + // record create event if recording active + Record_EnergyFieldCreation( origin ); + +#endif // !PARSEC_SERVER + + return; + } + + // helix cannon + if ( dice < ( probsum += ProbHelixCannon ) ) { + objclass = HELIX_DEVICE_CLASS; + + // lightning device + } else if ( dice < ( probsum += ProbLightningDevice ) ) { + objclass = LIGHTNING_DEVICE_CLASS; + + // photon cannon + } else if ( dice < ( probsum += ProbPhotonCannon ) ) { + objclass = PHOTON_DEVICE_CLASS; + + // proximity mine pack + } else if ( dice < ( probsum += ProbProximityMine ) ) { + objclass = MINE_PACK_CLASS; + + // laser upgrade + } else if ( dice < ( probsum += ProbLaserUpgrade ) ) { + + probsum = 0; + int lasertype = RAND() % 100; + if ( lasertype < ( probsum += ProbLaserUpgrade1 ) ) { + objclass = LASERUPGRADE1_CLASS; + } else { // if ( lasertype < ( probsum += ProbLaserUpgrade2 ) ) + objclass = LASERUPGRADE2_CLASS; + } + + // missile pack + } else if ( dice < ( probsum += ProbMissilePack ) ) { + + probsum = 0; + int misstype = RAND() % 100; + if ( misstype < ( probsum += ProbDumbMissPack ) ) { + objclass = DUMB_PACK_CLASS; + } else if ( misstype < ( probsum += ProbHomMissPack ) ) { + objclass = GUIDE_PACK_CLASS; + } else { // if ( misstype < ( probsum += ProbSwarmMissPack ) ) + objclass = SWARM_PACK_CLASS; + } + + // repair extra + } else if ( dice < ( probsum += ProbRepairExtra ) ) { + objclass = REPAIR_EXTRA_CLASS; + + // afterburner + } else if ( dice < ( probsum += ProbAfterburner ) ) { + objclass = AFTERBURNER_DEVICE_CLASS; + + // holo decoy + } else if ( dice < ( probsum += ProbHoloDecoy ) ) { + objclass = DECOY_DEVICE_CLASS; + + // invisibility + } else if ( dice < ( probsum += ProbInvisibility ) ) { + objclass = INVISIBILITY_CLASS; + + // invulnerability + } else if ( dice < ( probsum += ProbInvulnerability ) ) { + objclass = INVULNERABILITY_CLASS; + + // emp upgrade 1 + } else if ( dice < ( probsum += ProbEmpUpgrade1 ) ) { + + if ( ExtraClasses[ EXTRAINDX_EMPUPGRADE1 ] == CLASS_ID_INVALID ) { + ExtraClasses[ EXTRAINDX_EMPUPGRADE1 ] = OBJ_FetchObjectClassId( OBJCLASSNAME_DEVICE_EMP_UPGRADE_1 ); + } + + objclass = ExtraClasses[ EXTRAINDX_EMPUPGRADE1 ]; + + // emp upgrade 2 + } else if ( dice < ( probsum += ProbEmpUpgrade2 ) ) { + + if ( ExtraClasses[ EXTRAINDX_EMPUPGRADE2 ] == CLASS_ID_INVALID ) { + ExtraClasses[ EXTRAINDX_EMPUPGRADE2 ] = OBJ_FetchObjectClassId( OBJCLASSNAME_DEVICE_EMP_UPGRADE_2 ); + } + + objclass = ExtraClasses[ EXTRAINDX_EMPUPGRADE2 ]; + + // energy extra + } else { + objclass = ENERGY_EXTRA_CLASS; + } + +#ifdef TEST_EXTRA_CREATION_CODE + + objclass = ENERGY_EXTRA_CLASS; + +#endif // !TEST_EXTRA_CREATION_CODE + + // create object + ExtraObject *extrapo = (ExtraObject *) TheWorld->CreateObject( objclass, startm, PLAYERID_SERVER ); + OBJ_FillExtraMemberVars( extrapo ); + + +#ifdef PARSEC_SERVER + + // attach the created E_Distributable for the engine object + extrapo->pDist = TheSimNetOutput->CreateDistributable( extrapo ); + + // record create event if recording active + //Record_ExtraCreation( extrapo ); + + +#else // !PARSEC_SERVER + + // insert remote event + NET_RmEvExtra( extrapo ); + + // record create event if recording active + Record_ExtraCreation( extrapo ); + +#endif // !PARSEC_SERVER + } +#endif // !PARSEC_CLIENT +} + + +// define area in which extras around ship will be placed --------------------- +// +#define EXPL_MAXEXTRAAREA 30 +#define EXPL_MINEXTRADIST 5 + +#define EXPL_DRIFTSPEED 0.0012f + + +// place extras after ship was shot down -------------------------------------- +// +void G_ExtraManager::_PlaceShipExtras( int num, int objclass, ShipObject *shippo ) +{ +#ifdef PARSEC_CLIENT + + ASSERT( FALSE ); + +#else // !PARSEC_CLIENT + + ASSERT( num >= 0 ); + ASSERT( objclass >= 0 ); + ASSERT( objclass < NumObjClasses ); + ASSERT( shippo != NULL ); + + for ( ; num > 0; num-- ) { + +#ifdef PARSEC_CLIENT + + if ( !NET_RmEvAllowed( RE_CREATEEXTRA ) ) + return; + +#endif // PARSEC_CLIENT + + // do random placement of extras in near vicinity of ship + int x = ( RAND() % EXPL_MAXEXTRAAREA ) - EXPL_MAXEXTRAAREA / 2; + int y = ( RAND() % EXPL_MAXEXTRAAREA ) - EXPL_MAXEXTRAAREA / 2; + int z = ( RAND() % EXPL_MAXEXTRAAREA ) - EXPL_MAXEXTRAAREA / 2; + + x += ( x < 0 ) ? -EXPL_MINEXTRADIST : EXPL_MINEXTRADIST; + y += ( y < 0 ) ? -EXPL_MINEXTRADIST : EXPL_MINEXTRADIST; + z += ( z < 0 ) ? -EXPL_MINEXTRADIST : EXPL_MINEXTRADIST; + +#ifdef TEST_EXTRA_CREATION_CODE_ON_SHIP_DOWNING + + static int numplaced = 0; + + Xmatrx startm; + MakeIdMatrx( startm ); + startm[ 0 ][ 3 ] = INT_TO_GEOMV( 0 ) + shippo->ObjPosition[ 0 ][ 3 ]; + startm[ 1 ][ 3 ] = INT_TO_GEOMV( ( numplaced % 10 ) * 20 ) + shippo->ObjPosition[ 1 ][ 3 ]; + startm[ 2 ][ 3 ] = INT_TO_GEOMV( 0 ) + shippo->ObjPosition[ 2 ][ 3 ]; + + numplaced++; + +#else // !TEST_EXTRA_CREATION_CODE_ON_SHIP_DOWNING + Xmatrx startm; + MakeIdMatrx( startm ); + startm[ 0 ][ 3 ] = INT_TO_GEOMV( x ) + shippo->ObjPosition[ 0 ][ 3 ]; + startm[ 1 ][ 3 ] = INT_TO_GEOMV( y ) + shippo->ObjPosition[ 1 ][ 3 ]; + startm[ 2 ][ 3 ] = INT_TO_GEOMV( z ) + shippo->ObjPosition[ 2 ][ 3 ]; +#endif // !TEST_EXTRA_CREATION_CODE_ON_SHIP_DOWNING + + // create object ( owner is ship ) + //NOTE: + // normal extras have PLAYERID_SERVER as owner, only extras placed after + // a player was shot down are owned by the player + int owner = GetOwnerFromHostOjbNumber( shippo->HostObjNumber ); + ExtraObject *extrapo = (ExtraObject *) TheWorld->CreateObject( objclass, startm, owner ); + OBJ_FillExtraMemberVars( extrapo ); + + // initialize drift timeout + extrapo->DriftTimeout = DEFAULT_DRIFT_TIMEOUT; + + // calculate drift direction vector + extrapo->DriftVec.X = FLOAT_TO_GEOMV( x * EXPL_DRIFTSPEED ); + extrapo->DriftVec.Y = FLOAT_TO_GEOMV( y * EXPL_DRIFTSPEED ); + extrapo->DriftVec.Z = FLOAT_TO_GEOMV( z * EXPL_DRIFTSPEED ); + + //TODO: + // randomly alter self rotation. + + ASSERT( extrapo->ObjectClass != MINE_CLASS_1 ); + ASSERT( extrapo->ObjectType != MINE1TYPE ); + +#ifdef PARSEC_SERVER + + // attach the created E_Distributable for the engine object + extrapo->pDist = TheSimNetOutput->CreateDistributable( extrapo, FALSE, TRUE ); + + // record create event if recording active + //Record_ExtraCreation( extrapo ); + +#else // !PARSEC_SERVER + + // insert remote event + NET_RmEvExtra( extrapo ); + + // record create event if recording active + Record_ExtraCreation( extrapo ); + +#endif // !PARSEC_SERVER + } +#endif // // !PARSEC_CLIENT +} + +// create extras after ship was shot down ------------------------------------- +// +void G_ExtraManager::OBJ_CreateShipExtras( ShipObject *shippo ) +{ + ASSERT( shippo != NULL ); + +#ifdef PARSEC_CLIENT + ASSERT( FALSE ); +#else // !PARSEC_CLIENT + + +#ifdef PARSEC_CLIENT + //NOTE: + // this is a helper function for functions + // in OBJ_COLL.C and for R_DrawWorld(). + + if ( !AUX_ENABLE_KILLED_SHIP_EXTRAS ) + return; + + // don't create extras during demo replay + if ( !AUX_CREATE_EXTRAS_DURING_REPLAY && DEMO_ReplayActive() ) + return; + + // in network game only for local ship because + // others will be received as remote events + if ( NetConnected && ( shippo != MyShip ) ) + return; + +//FIXME: +// if ( shippo != MyShip ) +// return; + +#endif // PARSEC_CLIENT + + +//#ifdef TEST_EXTRA_CREATION_CODE +// _PlaceShipExtras( 1, DUMB_PACK_CLASS, shippo ); +// return; +//#endif // TEST_EXTRA_CREATION_CODE + + + #define MAX_DUMBPACKS 2 + #define MAX_GUIDEPACKS 2 + #define MAX_MINEPACKS 1 + + // create dumb missile packs + if ( shippo->NumMissls > 0 ) { + if(TheGame->DumbPackNumMissls > 0) { + int num_missilepacks = ( shippo->NumMissls / TheGame->DumbPackNumMissls ); + if ( num_missilepacks > MAX_DUMBPACKS ) { + num_missilepacks = MAX_DUMBPACKS; + } + + _PlaceShipExtras( num_missilepacks, DUMB_PACK_CLASS, shippo ); + } + } + + // create guided missile packs + if ( shippo->NumHomMissls > 0 ) { + if(TheGame->HomPackNumMissls > 0) { + int num_guidedmissilepacks = ( shippo->NumHomMissls / TheGame->HomPackNumMissls ); + if ( num_guidedmissilepacks > MAX_GUIDEPACKS ) { + num_guidedmissilepacks = MAX_GUIDEPACKS; + } + + _PlaceShipExtras( num_guidedmissilepacks, GUIDE_PACK_CLASS, shippo ); + } + } + + // create proximity mine packs + if ( shippo->NumMines > 0 ) { + if(TheGame->ProxPackNumMines > 0) { + int num_minepacks = ( shippo->NumMines / TheGame->ProxPackNumMines ); + if ( num_minepacks > MAX_MINEPACKS ) { + num_minepacks = MAX_MINEPACKS; + } + + _PlaceShipExtras( num_minepacks, MINE_PACK_CLASS, shippo ); + } + } + + // create lightning device + if ( TheGame->OBJ_DeviceAvailable( shippo, WPMASK_CANNON_LIGHTNING ) ) { + + _PlaceShipExtras( 1, LIGHTNING_DEVICE_CLASS, shippo ); + } + + // create helix cannon + if ( TheGame->OBJ_DeviceAvailable( shippo, WPMASK_CANNON_HELIX ) ) { + + _PlaceShipExtras( 1, HELIX_DEVICE_CLASS, shippo ); + } + + // create photon cannon + if ( TheGame->OBJ_DeviceAvailable( shippo, WPMASK_CANNON_PHOTON ) ) { + + _PlaceShipExtras( 1, PHOTON_DEVICE_CLASS, shippo ); + } + + // create laser upgrade 1 + if ( shippo->Specials & SPMASK_LASER_UPGRADE_1 ) { + + _PlaceShipExtras( 1, LASERUPGRADE1_CLASS, shippo ); + } + + // create laser upgrade 2 + if ( shippo->Specials & SPMASK_LASER_UPGRADE_2 ) { + + _PlaceShipExtras( 1, LASERUPGRADE2_CLASS, shippo ); + } + + //FIXME: why do we not place the EMP upgrades ? + +/* + // create emp upgrade 1 + if ( shippo->Specials & SPMASK_EMP_UPGRADE_1 ) { + + _PlaceShipExtras( 1, EMPUPGRADE1_CLASS, shippo ); + } + + // create emp upgrade 2 + if ( shippo->Specials & SPMASK_EMP_UPGRADE_2 ) { + + _PlaceShipExtras( 1, EMPUPGRADE2_CLASS, shippo ); + } +*/ + // create energy extra if ship still has enough energy + if ( shippo->CurEnergy >= TheGame->EnergyExtraBoost ) { + + _PlaceShipExtras( 1, ENERGY_EXTRA_CLASS, shippo ); + } +#endif // !PARSEC_CLIENT +} + + + + +// boost extra collected: energy boost ---------------------------------------- +// +char* G_ExtraManager::_CollectBoostEnergy( ShipObject* cur_ship, Extra1Obj* extra1po ) +{ + ASSERT( extra1po != NULL ); + char* text = NULL; + + G_ShipObject* pShip = (G_ShipObject*)cur_ship; +#ifdef PARSEC_DEBUG + //MSGOUT( "G_ExtraManager::_CollectBoostEnergy() adds energy of %d", extra1po->EnergyBoost ); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !pShip->BoostEnergy( extra1po->EnergyBoost ) ) { + CLIENT_ONLY( AUD_MaxedOut( ENERGY_EXTRA_CLASS ); ); + text = max_energy_str; + } else { + CLIENT_ONLY( AUD_EnergyBoosted(); ); + CLIENT_ONLY( AUD_JimCommenting( JIM_COMMENT_ENERGY ); ); + text = got_energy_str; + } + + return text; +} + +// boost extra collected: energy boost ---------------------------------------- +// +char* G_ExtraManager::_CollectBoostEnergyField( ShipObject* cur_ship, int boost ) +{ + char* text = NULL; + + G_ShipObject* pShip = (G_ShipObject*)cur_ship; +#ifdef PARSEC_DEBUG + //MSGOUT( "G_ExtraManager::_CollectBoostEnergyField() adds energy of %d", boost ); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !pShip->BoostEnergy( boost ) ) { + CLIENT_ONLY( AUD_MaxedOut( ENERGY_EXTRA_CLASS ); ); + text = max_energy_str; + } else { + CLIENT_ONLY( AUD_EnergyBoosted(); ); + CLIENT_ONLY( AUD_JimCommenting( JIM_COMMENT_ENERGY ); ); + text = got_energy_str; + } + + return text; +} + +// boost extra collected: repair damage --------------------------------------- +// +char* G_ExtraManager::_CollectBoostRepair( ShipObject* cur_ship, Extra1Obj* extra1po ) +{ + ASSERT( extra1po != NULL ); + char *text = NULL; +#ifdef PARSEC_DEBUG + //MSGOUT( "G_ExtraManager::_CollectBoostRepair() adds energy of %d", extra1po->EnergyBoost ); +#endif // PARSEC_DEBUG + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !((G_ShipObject*)cur_ship)->BoostRepair( extra1po->EnergyBoost ) ) { + CLIENT_ONLY( AUD_MaxedOut( REPAIR_EXTRA_CLASS ); ); + text = no_damage_str; + } else { + CLIENT_ONLY( AUD_DamageRepaired(); ); + text = damage_repaired; + } + + return text; +} + + +// package extra collected: dumb missiles ------------------------------------- +// +char* G_ExtraManager::_CollectPackDumb( ShipObject* cur_ship, Extra2Obj *extra2po ) +{ + ASSERT( cur_ship != NULL ); + ASSERT( extra2po != NULL ); + char *text = NULL; + +#ifdef PARSEC_DEBUG + //MSGOUT( "G_ExtraManager::_CollectPackDumb() adds up to %d Missiles", extra2po->NumMissiles ); +#endif // PARSEC_DEBUG + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !((G_ShipObject*)cur_ship)->BoostMissiles( extra2po->NumMissiles ) ) { + CLIENT_ONLY( AUD_MaxedOut( MISSILE1TYPE ); ); + text = max_dumb_str; + } else { + CLIENT_ONLY( AUD_ExtraCollected( MISSILE1TYPE ); ); + text = got_dumb_str; + } + + return text; +} + + +// package extra collected: guided missiles ----------------------------------- +// + +char* G_ExtraManager::_CollectPackGuide( ShipObject* cur_ship, Extra2Obj *extra2po ) +{ + ASSERT( cur_ship != NULL ); + ASSERT( extra2po != NULL ); + char *text = NULL; + +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectPackGuide() adds up to %d Missiles", extra2po->NumMissiles ); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !((G_ShipObject*)cur_ship)->BoostHomMissiles( extra2po->NumMissiles ) ) { + text = max_homing_str; + CLIENT_ONLY( AUD_MaxedOut( MISSILE4TYPE ); ); + } else { + text = got_homing_str; + CLIENT_ONLY( AUD_ExtraCollected( MISSILE4TYPE ); ); + } + + return text; +} + + +// device extra collected: swarm missiles ------------------------------------- +// +char* G_ExtraManager::_CollectPackSwarm( ShipObject* cur_ship, Extra2Obj *extra2po ) +{ + ASSERT( cur_ship != NULL ); + ASSERT( extra2po != NULL ); + + char *text = NULL; + +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectPackSwarm() adds up to %d Missiles", extra2po->NumMissiles ); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !((G_ShipObject*)cur_ship)->BoostPartMissiles( extra2po->NumMissiles ) ) { + text = max_swarm_str; + CLIENT_ONLY( AUD_MaxedOut( MISSILE5TYPE ); ); + } else { + text = got_swarm_str; + CLIENT_ONLY( AUD_ExtraCollected( MISSILE5TYPE ); ); + } + + return text; +} + + +// package extra collected: proximity mines ----------------------------------- +// + +char* G_ExtraManager::_CollectPackMine( ShipObject* cur_ship, Extra2Obj *extra2po ) +{ + ASSERT( cur_ship != NULL ); + ASSERT( extra2po != NULL ); + char *text = NULL; + +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectPackMine() adds up to %d Mines", extra2po->NumMissiles ); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( !((G_ShipObject*)cur_ship)->BoostMines( extra2po->NumMissiles ) ) { + CLIENT_ONLY( AUD_MaxedOut( MINE1TYPE ); ); + text = max_mines_str; + } else { + CLIENT_ONLY( AUD_ExtraCollected( MINE1TYPE ); ); + text = got_mines_str; + } + + return text; +} + +// helper struct for defining paramters when collecting devices/specials ------ +// +struct collect_info_s { + int isDevice; + int mask; + char* success_string; + char* failure_string; +}; + + +collect_info_s collect_info[] = +{ + { FALSE, 0, NULL, NULL }, + { TRUE, WPMASK_CANNON_HELIX, got_helix_str, max_helix_str }, + { TRUE, WPMASK_CANNON_LIGHTNING, got_lightning_str, max_lightning_str }, + { FALSE, SPMASK_AFTERBURNER, got_afterburner_str, max_afterburner_str }, + { FALSE, SPMASK_INVISIBILITY, got_cloak_str, max_cloak_str }, + { TRUE, WPMASK_CANNON_PHOTON, got_photon_str, max_photon_str }, + { FALSE, SPMASK_DECOY, got_decoy_str, max_decoy_str }, + { FALSE, SPMASK_INVULNERABILITY, got_megashield_str, max_megashield_str }, + /*LASER_UPGRADE_1_DEVICE, // 8 + LASER_UPGRADE_2_DEVICE, // 9 + EMP_UPGRADE_1_DEVICE, // 10 + EMP_UPGRADE_2_DEVICE, // 11*/ +}; + + +// helper function when collecting devices ------------------------------------ +// +char* G_ExtraManager::_CollectDevice( int nDevice, ShipObject* cur_ship ) +{ + ASSERT( nDevice > UNKNOWN_DEVICE ); + ASSERT( nDevice <= EMP_UPGRADE_2_DEVICE ); + ASSERT( cur_ship != NULL ); + char *text = NULL; + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( ((G_ShipObject*)cur_ship)->CollectDevice( collect_info[ nDevice ].mask ) ) { + text = collect_info[ nDevice ].success_string; + CLIENT_ONLY( AUD_ExtraCollected( nDevice ); ); + } else { + text = collect_info[ nDevice ].failure_string; + CLIENT_ONLY( AUD_MaxedOut( nDevice ); ); + } + + return text; +} + +// helper function when collecting specials ----------------------------------- +// +char* G_ExtraManager::_CollectSpecial( int nSpecial, ShipObject* cur_ship ) +{ + ASSERT( nSpecial > UNKNOWN_DEVICE ); + ASSERT( nSpecial <= EMP_UPGRADE_2_DEVICE ); + ASSERT( cur_ship != NULL ); + char *text = NULL; + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( ((G_ShipObject*)cur_ship)->CollectSpecial( collect_info[ nSpecial ].mask ) ) { + text = collect_info[ nSpecial ].success_string; + } else { + text = collect_info[ nSpecial ].failure_string; + } + + // special is collected in any case + CLIENT_ONLY( AUD_ExtraCollected( nSpecial ); ); + + return text; +} + + +// device extra collected: helix cannon --------------------------------------- +// +char* G_ExtraManager::_CollectDeviceHelix( ShipObject* cur_ship ) +{ + return _CollectDevice( HELIX_DEVICE, cur_ship ); +} + + +// device extra collected: lightning device ----------------------------------- +// +char* G_ExtraManager::_CollectDeviceLightning( ShipObject* cur_ship ) +{ + return _CollectDevice( LIGHTNING_DEVICE, cur_ship ); +} + + +// device extra collected: photon cannon -------------------------------------- +// + +char* G_ExtraManager::_CollectDevicePhoton( ShipObject* cur_ship ) +{ + return _CollectDevice( PHOTON_DEVICE, cur_ship ); +} + + +// device extra collected: afterburner ---------------------------------------- +// +char* G_ExtraManager::_CollectDeviceAfterburner( ShipObject* cur_ship ) +{ +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectDeviceAfterburner() Item collected"); +#endif // PARSEC_DEBUG + return _CollectSpecial( AFTERBURNER_DEVICE, cur_ship ); +} + + +// device extra collected: invisibility --------------------------------------- +// +char* G_ExtraManager::_CollectDeviceInvisibility( ShipObject* cur_ship ) +{ +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectDeviceInvisibility() Item collected"); +#endif // PARSEC_DEBUG + return _CollectSpecial( INVISIBILITY_DEVICE, cur_ship ); +} + + +// device extra collected: invulnerability ------------------------------------ +// +char* G_ExtraManager::_CollectDeviceInvulnerability( ShipObject* cur_ship ) +{ +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectDeviceinvunerability() Item collected"); +#endif // PARSEC_DEBUG + return _CollectSpecial( INVULNERABILITY_DEVICE, cur_ship ); +} + + +// device extra collected: decoy ---------------------------------------------- +// +char* G_ExtraManager::_CollectDeviceDecoy( ShipObject* cur_ship ) +{ + return _CollectSpecial( DECOY_DEVICE, cur_ship ); +} + + +// device extra collected: laser upgrade 1 ------------------------------------ +// +char* G_ExtraManager::_CollectDeviceLaserUpgrade1( ShipObject* cur_ship ) +{ + ASSERT( cur_ship != NULL ); + + char *text = NULL; +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectDeviceLaserUpgrade1() Item collected"); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( cur_ship->Specials & SPMASK_LASER_UPGRADE_2 ) { + text = max_laser_upgrade_2_str; + CLIENT_ONLY( AUD_MaxedOut( LASER_UPGRADE_1_DEVICE ); ); + } else { + if ( ( cur_ship->Specials & SPMASK_LASER_UPGRADE_1 ) == 0 ) { + + text = got_laser_upgrade_1_str; + CLIENT_ONLY( AUD_ExtraCollected( LASER_UPGRADE_1_DEVICE ); ); + + ((G_ShipObject*)cur_ship)->EnableLaserUpgrade1(); + + } else { + + text = max_laser_upgrade_1_str; + CLIENT_ONLY( AUD_MaxedOut( LASER_UPGRADE_1_DEVICE ); ); + } + } + + return text; +} + + +// device extra collected: laser upgrade 2 ------------------------------------ +// + +char* G_ExtraManager::_CollectDeviceLaserUpgrade2( ShipObject* cur_ship ) +{ + ASSERT( cur_ship != NULL ); + + char *text = NULL; + +#ifdef PARSEC_DEBUG +// MSGOUT( "G_ExtraManager::_CollectDeviceLaserUpgrade2() Item collected"); +#endif // PARSEC_DEBUG + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( ( cur_ship->Specials & SPMASK_LASER_UPGRADE_1 ) == 0 ) { + text = need_laser_upgrade_1_str; + //FIXME: no audio feedback here ? + } else { + if ( ( cur_ship->Specials & SPMASK_LASER_UPGRADE_2 ) == 0 ) { + + text = got_laser_upgrade_2_str; + CLIENT_ONLY( AUD_ExtraCollected( LASER_UPGRADE_2_DEVICE ); ); + + ((G_ShipObject*)cur_ship)->EnableLaserUpgrade2(); + + } else { + + text = max_laser_upgrade_2_str; + CLIENT_ONLY( AUD_MaxedOut( LASER_UPGRADE_2_DEVICE ); ); + } + } + + return text; +} + + +// device extra collected: emp upgrade 1 -------------------------------------- +// + +char* G_ExtraManager::_CollectDeviceEmpUpgrade1( ShipObject* cur_ship ) +{ + ASSERT( cur_ship != NULL ); + + char *text = NULL; + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + // no emp1 upgrade if already got emp2 + if ( cur_ship->Specials & SPMASK_EMP_UPGRADE_2 ) { + text = max_emp_upgrade_2_str; + CLIENT_ONLY( AUD_MaxedOut( EMP_UPGRADE_1_DEVICE ); ); + } else { + if ( ( cur_ship->Specials & SPMASK_EMP_UPGRADE_1 ) == 0 ) { + text = got_emp_upgrade_1_str; + CLIENT_ONLY( AUD_ExtraCollected( EMP_UPGRADE_1_DEVICE ); ); + + ((G_ShipObject*)cur_ship)->EnableEmpUpgrade1(); + + } else { + text = max_emp_upgrade_1_str; + CLIENT_ONLY( AUD_MaxedOut( EMP_UPGRADE_1_DEVICE ); ); + } + } + + return text; +} + + +// device extra collected: emp upgrade 2 -------------------------------------- +// + +char* G_ExtraManager::_CollectDeviceEmpUpgrade2( ShipObject* cur_ship ) +{ + ASSERT( cur_ship != NULL ); + char *text = NULL; + + CLIENT_ONLY( ASSERT( cur_ship == MyShip ); ); + if ( ( cur_ship->Specials & SPMASK_EMP_UPGRADE_1 ) == 0 ) { + text = need_emp_upgrade_1_str; + //FIXME: no audio feedback here ? + } else { + if ( ( cur_ship->Specials & SPMASK_EMP_UPGRADE_2 ) == 0 ) { + + text = got_emp_upgrade_2_str; + CLIENT_ONLY( AUD_ExtraCollected( EMP_UPGRADE_2_DEVICE ); ); + + ((G_ShipObject*)cur_ship)->EnableEmpUpgrade2(); + + } else { + + text = max_emp_upgrade_2_str; + CLIENT_ONLY( AUD_MaxedOut( EMP_UPGRADE_2_DEVICE ); ); + } + } + + return text; +} + + +// local ship collided with proximity mine ------------------------------------ +// +char *G_ExtraManager::_CollisionProximityMine( Mine1Obj *minepo ) +{ + ASSERT( minepo != NULL ); + + //FIXME: implement server side.... + + char *text = NULL; + +#ifdef PARSEC_CLIENT + int hitpoints = minepo->HitPoints; + if ( ( hitpoints -= MyShip->MegaShieldAbsorption ) < 0 ) { + hitpoints = 0; + } + + if ( MyShip->CurDamage <= MyShip->MaxDamage ) { + + MyShip->CurDamage += hitpoints; + if ( MyShip->CurDamage > MyShip->MaxDamage ) { + + KillDurationWeapons( MyShip ); + OBJ_CreateShipExtras( MyShip ); + + // if mine is owned by remote player update kill state + if ( minepo->Owner != OWNER_LOCAL_PLAYER ) { + NET_SetPlayerKillStat( minepo->Owner, 1 ); + } + + text = mine_killed_str; + AUD_PlayerKilled(); + + } else { + + // detect hull impact + + OBJ_EventShipImpact( MyShip, TRUE ); + + text = mine_hit_str; + AUD_MineCollision(); + } + + } else { + + // occurs on mine hit when already killed + text = mine_hit_str; + } +#endif + return text; +} + + + +// perform action according to extra type and determine message to show ------- +// +char* G_ExtraManager::CollectExtra( ShipObject* cur_ship, ExtraObject* curextra ) +{ + ASSERT( cur_ship != NULL ); + ASSERT( curextra != NULL ); + + const char *text = NULL; + + /*MSGOUT( "G_ExtraManager::CollectExtra() %d at %.2f/%.2f/%.2f - ship at %.2f/%.2f/%.2f", + curextra->HostObjNumber, + + curextra->ObjPosition[ 0 ][ 3 ], + curextra->ObjPosition[ 1 ][ 3 ], + curextra->ObjPosition[ 2 ][ 3 ], + + cur_ship->ObjPosition[ 0 ][ 3 ], + cur_ship->ObjPosition[ 1 ][ 3 ], + cur_ship->ObjPosition[ 2 ][ 3 ] + ); +*/ + // extras of type 1 (boost extras) + if ( curextra->ObjectType == EXTRA1TYPE ) { + + Extra1Obj *extra1po = (Extra1Obj *) curextra; + + switch ( extra1po->ObjectClass ) { + + // energy boost extra + case ENERGY_EXTRA_CLASS: + text = _CollectBoostEnergy( cur_ship, extra1po ); + break; + + // damage repair extra + case REPAIR_EXTRA_CLASS: + text = _CollectBoostRepair( cur_ship, extra1po ); + break; + + // unrecognized class for this type + default: + MSGOUT( "G_ExtraManager::CollectExtra(): unknown boost extra: class1 %d.", extra1po->ObjectClass ); + text = unknown_extra_str; + } + + // extras of type 2 (package extras) + } else if ( curextra->ObjectType == EXTRA2TYPE ) { + + Extra2Obj *extra2po = (Extra2Obj *) curextra; + + switch ( extra2po->MissileType ) { + + // dumb missile package + case MISSILE1TYPE: + text = _CollectPackDumb( cur_ship, extra2po ); + break; + + // guide missile package + case MISSILE4TYPE: + text = _CollectPackGuide( cur_ship, extra2po ); + break; + + // swarm missiles package + case MISSILE5TYPE: + text = _CollectPackSwarm( cur_ship, extra2po ); + break; + + // proximity mine package + case MINE1TYPE: + text = _CollectPackMine( cur_ship, extra2po ); + break; + + // laser upgrade 1 + case LASER_UPGRADE_1_DEVICE: + text = _CollectDeviceLaserUpgrade1( cur_ship ); + break; + + // laser upgrade 2 + case LASER_UPGRADE_2_DEVICE: + text = _CollectDeviceLaserUpgrade2( cur_ship ); + break; + // unrecognized class for this type + default: + MSGOUT( "G_ExtraManager::CollectExtra(): unknown package extra: class2 %d.", extra2po->ObjectClass ); + text = unknown_extra_str; + } + + // extras of type 3 (device extras) + } else if ( curextra->ObjectType == EXTRA3TYPE ) { + + Extra3Obj *extra3po = (Extra3Obj *) curextra; + + switch ( extra3po->DeviceType ) { + + // helix cannon + case HELIX_DEVICE: + text = _CollectDeviceHelix( cur_ship ); + break; + + // lightning device + case LIGHTNING_DEVICE: + text = _CollectDeviceLightning( cur_ship ); + break; + + // afterburner device + case AFTERBURNER_DEVICE: + text = _CollectDeviceAfterburner( cur_ship ); + break; + + // cloaking (invisibility) device + case INVISIBILITY_DEVICE: + text = _CollectDeviceInvisibility( cur_ship ); + break; + + // photon cannon + case PHOTON_DEVICE: + text = _CollectDevicePhoton( cur_ship ); + break; + + // invulnerability device + case INVULNERABILITY_DEVICE: + text = _CollectDeviceInvulnerability( cur_ship ); + break; + + // decoy device + case DECOY_DEVICE: + text = _CollectDeviceDecoy( cur_ship ); + break; + + // laser upgrade 1 + case LASER_UPGRADE_1_DEVICE: + text = _CollectDeviceLaserUpgrade1( cur_ship ); + break; + + // laser upgrade 2 + case LASER_UPGRADE_2_DEVICE: + text = _CollectDeviceLaserUpgrade2( cur_ship ); + break; + + // emp upgrade 1 + case EMP_UPGRADE_1_DEVICE: + text = _CollectDeviceEmpUpgrade1( cur_ship ); + break; + + // emp upgrade 2 + case EMP_UPGRADE_2_DEVICE: + text = _CollectDeviceEmpUpgrade2( cur_ship ); + break; + + // unrecognized device type found + default: + MSGOUT( "G_ExtraManager::CollectExtra(): unknown device extra: class3 %d.", extra3po->ObjectClass ); + text = unknown_dev_str; + } + + // collision with proximity mine + } else if ( curextra->ObjectType == MINE1TYPE ) { + //MSGOUT( "G_ExtraManager::CollectExtra(): Mine Collision"); + text = "mine"; + } + + return (char *) text; +} + + + + diff --git a/src/libparsec/include/con_arg.h b/src/libparsec/include/con_arg.h new file mode 100644 index 0000000..24de1bb --- /dev/null +++ b/src/libparsec/include/con_arg.h @@ -0,0 +1,68 @@ +/* + * PARSEC HEADER: con_arg.h + */ + +#ifndef _CON_ARG_H_ +#define _CON_ARG_H_ + + +// structure for key/value pairs + +struct key_value_s { + + const char* key; + char* value; + + dword flags; + dword _padto_16; +}; + +#define KEYVALFLAG_NONE 0x0000 +#define KEYVALFLAG_DISALLOW 0x0001 +#define KEYVALFLAG_IGNORE 0x0002 +#define KEYVALFLAG_MANDATORY 0x0004 +#define KEYVALFLAG_PARENTHESIZE 0x0008 + + +// structure for flag mapping spec + +struct flag_map_s { + + const char* name; + dword value; + int group; + dword _pad16; +}; + + +// external functions + +int ScanKeyValuePairs( key_value_s *table, char *kvstr ); +int ScanKeyValueInt( key_value_s *keyval, int *ival ); +int ScanKeyValueIntList( key_value_s *keyval, int *ilist, int minlen, int maxlen ); +int ScanKeyValueIntListBounded( key_value_s *keyval, int *ilist, int minlen, int maxlen, int minval, int maxval ); +int ScanKeyValueFloat( key_value_s *keyval, float *fval ); +int ScanKeyValueFloatList( key_value_s *keyval, float *flist, int minlen, int maxlen ); +int ScanKeyValueFloatListBounded( key_value_s *keyval, float *flist, int minlen, int maxlen, float minval, float maxval ); +int ScanKeyValueFlagList( key_value_s *keyval, dword *flagword, flag_map_s *flagmap ); +dword ScanKeyValueObjClass( key_value_s *keyval, int keyclass, int keyid ); + +char* GetParenthesizedName( char *name ); +int GetIntBehindCommand( char *cstr, int32 *iarg, int base, int paramoptional ); +const char* GetStringBehindCommand( char *scan, int paramoptional ); +int SetSingleStringCommand( char *cstr, char *dst, int dstmaxlen ); + +char* QueryIntArgument( const char *query, int *arg ); +char* QueryFltArgument( const char *query, float *arg ); +char* QueryIntArgumentEx( char *params, const char *query, int *arg ); +char* QueryFltArgumentEx( char *params, const char *query, float *arg ); +int CheckSetIntArgument( const char *query, const char *scan, const char *command, int *arg ); +int CheckSetFltArgument( const char *query, const char *scan, const char *command, float *arg ); +int CheckSetIntArgBounded( const char *query, const char *scan, char *command, int *arg, int bmin, int bmax, void (*func)() ); +int CheckSetIntArray( const char *query, char *scan, char *comstub, int *array, int numelements ); +int CheckSetStrArgument( int query, char *scan, char *command, char *string, int maxlen ); + + +#endif // _CON_ARG_H_ + + diff --git a/src/libparsec/include/con_tab.h b/src/libparsec/include/con_tab.h new file mode 100644 index 0000000..6cd0821 --- /dev/null +++ b/src/libparsec/include/con_tab.h @@ -0,0 +1,16 @@ +/* + * PARSEC HEADER: con_tab.h + */ + +#ifndef _CON_TAB_H_ +#define _CON_TAB_H_ + + +// external functions + +void CompleteCommand(); + + +#endif + + diff --git a/src/libparsec/include/con_vald.h b/src/libparsec/include/con_vald.h new file mode 100644 index 0000000..5fc9dc8 --- /dev/null +++ b/src/libparsec/include/con_vald.h @@ -0,0 +1,20 @@ +/* + * PARSEC HEADER: con_vald.h + */ + +#ifndef _CON_VALD_H_ +#define _CON_VALD_H_ + + +#define CON_ASCII_TABLE_LEN 128 +#define CON_ASCII_MASK 0x7f + + +// external variables + +extern int ConsoleASCIIValid[]; + + +#endif + + diff --git a/src/libparsec/include/config.h b/src/libparsec/include/config.h new file mode 100644 index 0000000..c3685c6 --- /dev/null +++ b/src/libparsec/include/config.h @@ -0,0 +1,170 @@ +/* + * PARSEC HEADER: config.h + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + + +//----------------------------------------------------------------------------- +// PROJECT GLOBAL FLAGS FOR CONDITIONAL COMPILATION - +//----------------------------------------------------------------------------- + +#include "platform.h" + + +// determine if fractional depth buffer values should be used (depth_t) ------- +// +#define FRACTIONAL_DEPTH_VALUES + + +// determine if screen space coordinates should be subpixel accurate ---------- +// +#define SCREENVERTEX_SUBPIXEL_ACCURACY + + +// determine whether the refframe frequency can be changed from the console --- +// +#define VARIABLE_REFFRAME_FREQUENCY + + +// determine whether cheats are allowed --------------------------------------- +// +#define ENABLE_CHEAT_COMMANDS + + +// determine whether to enable the LOGOUT command ----------------------------- +// +//#define ENABLE_LOGOUT_COMMAND + + +// determine whether to build the self running demo --------------------------- +// +//#define CLIENT_BUILD_SELF_RUNNING_DEMO + +// determine whether to build the lan-only version ---------------------------- +// +//#define CLIENT_BUILD_LAN_ONLY_VERSION + +// define these at the project level for the corresponding builds ------------- +// +//#define PARSEC_CLIENT // client build +//#define PARSEC_SERVER // gameserver build +//#define PARSEC_MASTER // masterserver build + + +// define current build number ------------------------------------------------ +// +#define CLIENT_BUILD_NUMBER "0200 (ver. 0.2)" +#define SERVER_BUILD_NUMBER "0200" +#define MASTER_BUILD_NUMBER "0200" + + +// determine that this is an internal only ( testing ) version ---------------- +// +#define INTERNAL_VERSION + + +// enable/disable dynamic function binding ------------------------------------ +// +//#define NO_DBIND + +#if !defined( NO_DBIND ) && !defined( PARSEC_SERVER ) + #define DBIND_PROTOCOL +#endif // NO_DBIND + +// define this to use the CURSES library for the server ----------------------- +// +#define USE_CURSES + +// miscellaneous conditions --------------------------------------------------- +// +//#define SHOW_COMPILER // used only in this file + + +// automatic host cpu selection if not already set ---------------------------- +// TODO: fixme? +// +#if !( defined( SYSTEM_CPU_INTEL ) || defined( SYSTEM_CPU_POWERPC ) ) + #define SYSTEM_CPU_INTEL +#endif + + +// define endianness constants according to host cpu -------------------------- +// +#if defined( SYSTEM_CPU_INTEL ) + #define SYSTEM_LITTLE_ENDIAN +#elif defined( SYSTEM_CPU_POWERPC ) + #define SYSTEM_BIG_ENDIAN +#else + #error "endianness not defined!" +#endif + + +// legacy defines ------------------------------------------------------------- +// +#ifdef SERVER_GAMESERVER + #error "replace SERVER_GAMESERVER with PARSEC_SERVER" +#endif // SERVER_GAMESERVER + +#ifdef SERVER_MASTERSERVER + #error "replace SERVER_MASTERSERVER with PARSEC_MASTER" +#endif // SERVER_MASTERSERVER + + +// check for correct project level defines ------------------------------------ +// +#if !( defined( PARSEC_CLIENT ) || defined( PARSEC_SERVER ) || defined( PARSEC_MASTER ) ) + #error "missing project level define PARSEC_CLIENT, PARSEC_SERVER or PARSEC_MASTER" +#endif + +// conditional code generation macros +// +#if defined ( PARSEC_CLIENT ) + #define CLIENT_ONLY( x ) { x } + #define SERVER_ONLY( x ) { } + #define MASTER_ONLY( x ) { } +#elif defined ( PARSEC_SERVER ) + #define CLIENT_ONLY( x ) { } + #define SERVER_ONLY( x ) { x } + #define MASTER_ONLY( x ) { } +#elif defined ( PARSEC_MASTER ) + #define CLIENT_ONLY( x ) { } + #define SERVER_ONLY( x ) { } + #define MASTER_ONLY( x ) { x } +#endif + + +// compiler-specific definitions ---------------------------------------------- +// +#ifdef SHOW_COMPILER + #if defined( SYSTEM_COMPILER_MSVC ) + #pragma message( "Compiling with Visual C++" ) + #elif defined( SYSTEM_COMPILER_CLANG ) + #pragma message( "Compiling with Clang" ) + #elif defined( SYSTEM_COMPILER_LLVM_GCC ) + #pragma message( "Compiling with LLVM-GCC" ) + #elif defined( SYSTEM_COMPILER_GCC ) + #pragma message( "Compiling with GCC" ) + #endif +#endif // SHOW_COMPILER + +#ifdef SYSTEM_COMPILER_MSVC + #pragma warning ( disable : 4305 ) + #define PATH_MAX _MAX_PATH +// #define vsnprintf _vsnprintf + #define snprintf _snprintf +#endif // SYSTEM_COMPILER_MSVC + +#if defined(SYSTEM_COMPILER_GCC) || defined(SYSTEM_COMPILER_CLANG) || defined(SYSTEM_COMPILER_LLVM_GCC) + +#ifndef PATH_MAX + #define PATH_MAX 255 // not always defined +#endif + +#endif //defined(SYSTEM_COMPILER_GCC) || defined(SYSTEM_COMPILER_CLANG) || defined(SYSTEM_COMPILER_LLVM_GCC) + + +#endif // _CONFIG_H_ + + diff --git a/src/libparsec/include/debug.h b/src/libparsec/include/debug.h new file mode 100644 index 0000000..43a0967 --- /dev/null +++ b/src/libparsec/include/debug.h @@ -0,0 +1,227 @@ +/* + * PARSEC HEADER + * Debugging Support V1.20 + * + * Copyright (c) Markus Hadwiger 1996-1999 + * All Rights Reserved. + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + + +// debug control -------------------------------------------------------------- +// +#define PARSEC_DEBUG + + +// memory allocation control (also used in non-debug mode) -------------------- +// +#define USE_ALIGNED_MEMBLOCKS + + +// verbose assertions include the actual text of the evaluated expression ----- +// +//#define VERBOSE_ASSERTIONS + + +// debug control -------------------------------------------------------------- + +//NOTE: +// the following flags determine what checks are performed in debug mode. + +//#define LOG_MEMORY_BLOCKS +//#define EXTENSIVE_MEMORY_CHECKS +//#define CHECK_MEM_INTEGRITY_ON_FREE + + +// ---------------------------------------------------------------------------- + + + +#ifdef PARSEC_DEBUG + + // debug only statement encapsulation (pass through) + #define DBG(x) x + + // don't inline in debug build + #define INLINE + + // put private functions into global namespace + #define PRIVATE + #define PUBLIC + +#else // PARSEC_DEBUG + + // debug only statement encapsulation (eliminate) + #define DBG(x) + + // do inlining in release build + #define INLINE inline + + // declare private functions as static + #define PRIVATE static + #define PUBLIC + + // print warning message, when compiling RELEASE version + #ifdef ENABLE_CHEAT_COMMANDS + #ifdef SYSTEM_COMPILER_MSVC + #pragma message ( "WARNING: ENABLE_CHEAT_COMMANDS is defined in RELEASE build !" ) + #endif // SYSTEM_COMPILER_MSVC + #endif // ENABLE_CHEAT_COMMANDS + +#endif // PARSEC_DEBUG + + + +// define heap functions to use + +#define HEAP_ALLOC malloc // C runtime library malloc() +#define HEAP_FREE free // C runtime library free() + + +// used in function declarations to tell the compiler that the function won't return +#ifdef SYSTEM_COMPILER_MSVC + #define FUNCTION_NORETURN(x) __declspec(noreturn) x +#else + #define FUNCTION_NORETURN(x) x __attribute__((__noreturn__)) +#endif + + +// external functions + +void* _AlignedMalloc( size_t ); +void _AlignedFree( void* ); + +void _SysAssert( const char*, unsigned ); +void* _LogAllocMem( size_t ); +void _LogFreeMem( void* ); +void _CheckHeapBaseRef( void* ); +void _CheckHeapRef( void* ); +void _CheckMemIntegrity(); + + +// define function wrappers --------------------------------------------------- + +#ifdef PARSEC_DEBUG + + #include <assert.h> + #define ASSERT( f ) assert( f ) + + #ifdef LOG_MEMORY_BLOCKS + + #define ALLOCMEM( s ) _LogAllocMem( s ) + #define FREEMEM( m ) _LogFreeMem( m ) + + #else // LOG_MEMORY_BLOCKS + + #ifdef USE_ALIGNED_MEMBLOCKS + + #define ALLOCMEM( s ) _AlignedMalloc( s ) + #define FREEMEM( m ) _AlignedFree( m ) + + #else // USE_ALIGNED_MEMBLOCKS + + #define ALLOCMEM( s ) HEAP_ALLOC( s ) + #define FREEMEM( m ) HEAP_FREE( m ) + + #endif // USE_ALIGNED_MEMBLOCKS + + #endif // LOG_MEMORY_BLOCKS + + #ifdef EXTENSIVE_MEMORY_CHECKS + + #define CHECKHEAPBASEREF( r ) _CheckHeapBaseRef( r ) + #define CHECKHEAPREF( r ) _CheckHeapRef( r ) + #define CHECKMEMINTEGRITY() _CheckMemIntegrity() + + #else // EXTENSIVE_MEMORY_CHECKS + + #define CHECKHEAPBASEREF( r ) {} + #define CHECKHEAPREF( r ) {} + #define CHECKMEMINTEGRITY() {} + + #endif // EXTENSIVE_MEMORY_CHECKS + +#else // PARSEC_DEBUG + + #ifdef USE_ALIGNED_MEMBLOCKS + + #define ALLOCMEM( s ) _AlignedMalloc( s ) + #define FREEMEM( m ) _AlignedFree( m ) + + #else // USE_ALIGNED_MEMBLOCKS + + #define ALLOCMEM( s ) HEAP_ALLOC( s ) + #define FREEMEM( m ) HEAP_FREE( m ) + + #endif // USE_ALIGNED_MEMBLOCKS + + #define ASSERT( f ) {} + #define CHECKHEAPBASEREF( r ) {} + #define CHECKHEAPREF( r ) {} + #define CHECKMEMINTEGRITY() {} + +#endif // PARSEC_DEBUG + + + + + + +// message control ------------------------------------------------------------ +// + +//NOTE: the following flags determine, what messages get printed out by the +// various DBGTXT, UPDTXT, UPDTXT2, UPDTXT3, RMEVTXT, ADXTXT macros +// these flags were moved from NET_CONF.H as they prove generally useful + +#define DEBUG_TEXTS +#define SHOW_UPDATE_TEXT +#define RMEV_MESSAGES +#define PRINT_ADDRESSES + +#ifdef DEBUG_TEXTS + #define DBGTXT(x) { if ( AUX_ENABLE_CONSOLE_DEBUG_MESSAGES ) { x } else {} } +#else // !DEBUG_TEXTS + #define DBGTXT(x) +#endif // !DEBUG_TEXTS + +#ifdef SHOW_UPDATE_TEXT + #define UPDTXT(x) DBGTXT(x) +#else // !SHOW_UPDATE_TEXT + #define UPDTXT(x) +#endif // !SHOW_UPDATE_TEXT + +#ifdef SHOW_UPDATE_TEXT2 + #define UPDTXT2(x) DBGTXT(x) +#else // !SHOW_UPDATE_TEXT2 + #define UPDTXT2(x) +#endif // !SHOW_UPDATE_TEXT2 + +#ifdef SHOW_UPDATE_TEXT3 + #define UPDTXT3(x) DBGTXT(x) +#else // !SHOW_UPDATE_TEXT3 + #define UPDTXT3(x) +#endif // !SHOW_UPDATE_TEXT3 + +#ifdef RMEV_MESSAGES + #define RMEVTXT(x) DBGTXT(x) +#else // !RMEV_MESSAGES + #define RMEVTXT(x) +#endif // !RMEV_MESSAGES + +#ifdef PRINT_ADDRESSES + #define ADXTXT(x) DBGTXT(x) +#else // !PRINT_ADDRESSES + #define ADXTXT(x) +#endif // !PRINT_ADDRESSES + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + + +#endif // _DEBUG_H_ + + diff --git a/src/libparsec/include/debugsys.h b/src/libparsec/include/debugsys.h new file mode 100644 index 0000000..a9e9a26 --- /dev/null +++ b/src/libparsec/include/debugsys.h @@ -0,0 +1,57 @@ +/* + * PARSEC HEADER + * System Debugging Functions V1.15 + * + * Copyright (c) Markus Hadwiger 1998-2000 + * All Rights Reserved. + */ + +#ifndef _DEBUGSYS_H_ +#define _DEBUGSYS_H_ + + + +// _SysAssert() calls this prior to aborting ---------------------------------- +// +void SysAssertCallback( const char *file, unsigned line ) +{ + +#if defined( SYSTEM_MACOSX_UNUSED ) + + #ifdef PARSEC_CLIENT + static char str[ 256 ]; + sprintf( str, "Assertion failed: %s, line %u\n", file, line ); + + extern void SX_ReportErrorString( char *msg ); + SX_ReportErrorString( str ); + #endif // PARSEC_CLIENT + +#elif defined( SYSTEM_WIN32_UNUSED ) && defined( PARSEC_CLIENT ) + + const char *msg = ( *file == '"' ) ? "%s, line %u" : "file %s, line %u"; + + extern void SW_WinError( const char *caption, const char *content, ... ); + SW_WinError( "Assertion failed", msg, file, line ); + +#else + + // nothing here ( + +#endif + +} + + +// ascertain a function's caller ---------------------------------------------- +// +// not able to determine caller +#define GETCALLER(c) c=_SysGetCaller(); +void *_SysGetCaller() +{ + return NULL; +} + + +#endif // _DEBUGSYS_H_ + + diff --git a/src/libparsec/include/def_draw.h b/src/libparsec/include/def_draw.h new file mode 100644 index 0000000..82f2ddc --- /dev/null +++ b/src/libparsec/include/def_draw.h @@ -0,0 +1,4 @@ +/* + * PARSEC HEADER: def_draw.h + */ + diff --git a/src/libparsec/include/def_papi.h b/src/libparsec/include/def_papi.h new file mode 100644 index 0000000..9bc922a --- /dev/null +++ b/src/libparsec/include/def_papi.h @@ -0,0 +1,4 @@ +/* + * PARSEC HEADER: def_papi.h + */ + diff --git a/src/libparsec/include/def_prot.h b/src/libparsec/include/def_prot.h new file mode 100644 index 0000000..9ca7d93 --- /dev/null +++ b/src/libparsec/include/def_prot.h @@ -0,0 +1,26 @@ +/* + * PARSEC HEADER: def_prot.h + */ + +int PFX( Connect, () ); +int PFX( Disconnect, () ); +int PFX( Join, () ); +int PFX( Unjoin, ( byte flag ) ); +int PFX( UpdateName, () ); +void PFX( MaintainNet, () ); + +// protocol api - game functions + +size_t PFX( RmEvList_GetMaxSize, () ); +void PFX( UpdateKillStats, ( RE_KillStats* killstats ) ); + +// protocol api - packet handling functions + +size_t PFX( HandleOutPacket, ( const NetPacket* gamepacket, NetPacketExternal* ext_gamepacket ) ); +size_t PFX( HandleOutPacket_DEMO, ( const NetPacket* gamepacket, NetPacketExternal* ext_gamepacket ) ); +int PFX( HandleInPacket, ( const NetPacketExternal* ext_gamepacket, const int ext_pktlen, NetPacket* gamepacket ) ); +int PFX( HandleInPacket_DEMO, ( const NetPacketExternal* ext_gamepacket, NetPacket* gamepacket, size_t* psize_external ) ); +size_t PFX( NetPacketExternal_DEMO_GetSize,( const NetPacketExternal* ext_gamepacket ) ); +void PFX( StdGameHeader, ( byte command, NetPacket* pIntPkt ) ); +void PFX( WritePacketInfo, ( FILE *fp, NetPacketExternal* ext_gamepacket ) ); + diff --git a/src/libparsec/include/def_rend.h b/src/libparsec/include/def_rend.h new file mode 100644 index 0000000..e131d02 --- /dev/null +++ b/src/libparsec/include/def_rend.h @@ -0,0 +1,4 @@ +/* + * PARSEC HEADER: def_rend.h + */ + diff --git a/src/libparsec/include/def_vid.h b/src/libparsec/include/def_vid.h new file mode 100644 index 0000000..28fe7de --- /dev/null +++ b/src/libparsec/include/def_vid.h @@ -0,0 +1,4 @@ +/* + * PARSEC HEADER: def_vid.h + */ + diff --git a/src/libparsec/include/e_modulemanager.h b/src/libparsec/include/e_modulemanager.h new file mode 100644 index 0000000..40b1dbb --- /dev/null +++ b/src/libparsec/include/e_modulemanager.h @@ -0,0 +1,87 @@ +#ifndef E_MODULEMANAGER_H_ +#define E_MODULEMANAGER_H_ + +// ---------------------------------------------------------------------------- +// +#define TheModuleManager (E_ModuleManager::GetModuleManager()) + +// forward decls -------------------------------------------------------------- +// +class E_Module; + +// ---------------------------------------------------------------------------- +// +typedef UTL_listentry_s<E_Module*> LE_Module; + +// ---------------------------------------------------------------------------- +// +class E_ModuleManager { +protected: + UTL_List<E_Module*> m_Modules; + +protected: + // register the console commands for managing modules + void _RegisterConsoleCommand() const; + + E_ModuleManager() + { + _RegisterConsoleCommand(); + }; + ~E_ModuleManager() + { + KillAllModules(); + m_Modules.RemoveAll(); + }; + +public: + // SINGLETON access + static E_ModuleManager* GetModuleManager() + { + static E_ModuleManager _TheModuleManager; + return &_TheModuleManager; + } + + // register a module + void RegisterModule( E_Module* pModule ); + + // unregister a module + void UnregisterModule( E_Module* pModule ); + + // init all registered modules ( constructor ) + void InitAllModules(); + + // kill all registered modules ( destructor ) + void KillAllModules(); + + // list all loaded modules in the console + void ListAll() const; +}; + +// ---------------------------------------------------------------------------- +// +class E_Module +{ +protected: + char m_szName[ 256 ]; +public: + E_Module( const char* pszName ); + virtual void Init() = 0; + virtual void Kill() = 0; + const char* GetName() const { return m_szName; } +}; + +// module registration macros (automatic module-init/deinit on startup) ------- +// +#define REGISTER_MODULE( f ) class E_Module_##f : public E_Module \ + { public: E_Module_##f( const char* pszName ) : E_Module( pszName ) {}; void Init(); void Kill() {}; } \ + inst_##f( #f ); \ + void E_Module_##f::Init() + +#define REGISTER_MODULE_INIT( f ) class E_Module_##f : public E_Module \ + { public: E_Module_##f( const char* pszName ) : E_Module( pszName ) {}; void Init(); void Kill(); } \ + inst_##f( #f ); \ + void E_Module_##f::Init() + +#define REGISTER_MODULE_KILL(f) void E_Module_##f::Kill() + +#endif // E_MODULEMANAGER_H_ diff --git a/src/libparsec/include/e_relist.h b/src/libparsec/include/e_relist.h new file mode 100644 index 0000000..6f39e54 --- /dev/null +++ b/src/libparsec/include/e_relist.h @@ -0,0 +1,328 @@ +/* +* PARSEC HEADER: e_relist.h +*/ + +#ifndef _E_RELIST_H_ +#define _E_RELIST_H_ + +// forward decls -------------------------------------------------------------- +// +class E_SimShipState; +class E_SimPlayerInfo; + + +//FIXME: this should be merged with DEBUG.C + +// easy access to the singleton ----------------------------------------------- +// +#define TheMemoryManager UTL_MemoryManager::GetMemoryManager() + +// set these wisely +#define MEMMAN_HASH_TABLE_SIZE 1001 +#define HASH_POINTER_ADDRESS(x) ( ((size_t)(x)) % MEMMAN_HASH_TABLE_SIZE ) + +// struct defining a entry in the memory manager ------------------------------ +// +class UTL_MemEntry +{ +protected: + UTL_MemEntry* m_pNext; + void* m_p; + const char* m_descr1; + const char* m_descr2; +public: + UTL_MemEntry( void* p = NULL, const char* descr1 = NULL, const char* descr2 = NULL ) : + m_pNext( NULL ), + m_p( p ), + m_descr1( descr1 ), + m_descr2( descr2 ) + { + } + + friend class UTL_MemoryManager; +}; + +// memory manager ------------------------------------------------------------- +// +class UTL_MemoryManager +{ +protected: + + UTL_MemEntry* m_HashTable[ MEMMAN_HASH_TABLE_SIZE ]; + + UTL_MemoryManager() + { + for( int nEntry = 0; nEntry < MEMMAN_HASH_TABLE_SIZE; nEntry++ ) { + m_HashTable[ nEntry ] = NULL; + } + } + ~UTL_MemoryManager() + { + CheckLeaks(); + } +public: + // SINGLETON pattern + static UTL_MemoryManager* GetMemoryManager() + { + static UTL_MemoryManager _TheMemoryManager; + return &_TheMemoryManager; + } + + // add a pointer for tracking + int AddTracking( void* p, const char* descr1, const char* descr2 ) + { + //MSGOUT( "UTL_MemoryManager::AddTracking(): %x, %s, %s", p, descr1, descr2 ); + + // get hash key + size_t htid = HASH_POINTER_ADDRESS( p ); + + // search hash table for already existing entry + for ( UTL_MemEntry* scan = m_HashTable[ htid ]; scan != NULL; scan = scan->m_pNext ) { + if ( scan->m_p == p ) { + // issue warning + MSGOUT( "UTL_MemManager::AddTracking(): duplicate call for pointer %x (%s, %s).", p, descr1, descr2 ); + return FALSE; + } + } + + // create new entry & prepend to list + UTL_MemEntry* newentry = new UTL_MemEntry( p, descr1, descr2 ); + newentry->m_pNext = m_HashTable[ htid ]; + m_HashTable[ htid ] = newentry; + + return TRUE; + } + + // remove a pointer from tracking + int RemoveTracking( void* p ) + { + // get hash key + size_t htid = HASH_POINTER_ADDRESS( p ); + + UTL_MemEntry* scan = m_HashTable[ htid ]; + if ( scan != NULL ) { + // check for head removal + if ( scan->m_p == p ) { + m_HashTable[ htid ] = scan->m_pNext; + //MSGOUT( "UTL_MemoryManager::RemoveTracking(): %x, %s, %s", scan->m_p, scan->m_descr1, scan->m_descr2 ); + delete scan; + return TRUE; + } + + // setup iteration + UTL_MemEntry* prev = scan; + scan = scan->m_pNext; + + for ( ; scan != NULL; scan = scan->m_pNext ) { + + if ( scan->m_p == p ) { + + // unlink from list + prev->m_pNext = scan->m_pNext; + //MSGOUT( "UTL_MemoryManager::RemoveTracking(): %x, %s, %s", scan->m_p, scan->m_descr1, scan->m_descr2 ); + delete scan; + return TRUE; + } + } + } + + // issue warning + MSGOUT( "UTL_MemManager::RemoveTracking(): tracking entry for pointer %x not found.", p ); + return FALSE; + } + + // dump all pointers we still track + void CheckLeaks() + { + for( int nEntry = 0; nEntry < MEMMAN_HASH_TABLE_SIZE; nEntry++ ) { + + for( UTL_MemEntry* scan = m_HashTable[ nEntry ]; scan != NULL; scan = scan->m_pNext ) { + MSGOUT( "UTL_MemManager::CheckLeaks(): leaked pointer %x (%s, %s)", scan->m_p, scan->m_descr1, scan->m_descr2 ); + } + } + } +}; + +// class holding a remote event list ------------------------------------------ +// +class E_REList +{ +protected: + char* m_data; + char* m_CurPos; + size_t m_Avail; + size_t m_nMaxSize; + + // reference counting stuff + int m_nRefCount; + ~E_REList(); + E_REList(); + E_REList( size_t size ); +public: + + // reference counting stuff + static E_REList* CreateAndAddRef( size_t size ) + { + E_REList* relist = new E_REList; + relist->AddRef(); +#ifdef PARSEC_DEBUG + TheMemoryManager->AddTracking( (void*)relist, __FILE__, "E_REList::CreateAndAddRef()" ); +#endif // PARSEC_DEBUG + relist->Init( size ); + return relist; + } + + void AddRef() { m_nRefCount++; } + void Release() + { + m_nRefCount--; + if ( m_nRefCount == 0 ) { +#ifdef PARSEC_DEBUG + TheMemoryManager->RemoveTracking( (void*)this ); +#endif // PARSEC_DEBUG + delete this; + } + } + + // init the remote event list + void Init( size_t size ); + + // return the internal data of the remote event list + RE_Header* GetData() { return (RE_Header*)m_data; } + + // return the size of the RE list + size_t GetSize() { return (size_t)( m_CurPos - m_data ); } + + // clear remote event list + int Clear(); + + // append a remote event list + int AppendList( RE_Header* relist ); + + // append a E_REList + int AppendList( E_REList* relist ); + + // append a remote event + size_t AppendEvent( RE_Header* re, size_t size ); + + // check whether we have any remote events in the list + int HasEvents() + { + return ( ( (RE_Header*) m_data)->RE_Type != RE_EMPTY ); + } + + // write to an external remote event list + size_t WriteTo( RE_Header* dst, size_t maxsize, int allow_truncate ); + + // check if enough space in RE_List for specified remote event + int RmEvAllowed( int re_type ); + + // dump contents of RE list + void Dump(); + + // allocate space for a specific RE + RE_Header* NET_Allocate( int retype ); + + // insert state sync remote event + int RmEvStateSync( byte statekey, byte stateval ); + + // append a RE_OwnerSection event + int NET_Append_RE_OwnerSection( int ownerid ); + + // insert command info into remote event list + int NET_Append_RE_CommandInfo( const char* commandstring ); + + // append a RE_PlayerAndShipStatus event + //FIXME: GAMECODE + //FIXME: consolidate naming with RmEv<remote-event-name> + int NET_Append_RE_PlayerAndShipStatus( int nClientID, E_SimPlayerInfo* pSimPlayerInfo, E_SimShipState* pSimShipState, refframe_t CurRefFrame, bool_t bUpdatePropsOnly ); + + // append a RE_GameState + //FIXME: GAMECODE + int NET_Append_RE_GameState(); + + // append a RE_KillStats event + //FIXME: GAMECODE + int NET_Append_RE_KillStats(); + + // append a RE_CreateLaser event + //FIXME: GAMECODE + int NET_Append_RE_CreateLaser( const LaserObject* laserpo ); + + // append a RE_CreateMissile event + //FIXME: GAMECODE + int NET_Append_RE_CreateMissile( const MissileObject *missilepo, dword targetobjid ); + + // Append a RE_CreateExtra event + int NET_Append_RE_CreateExtra( const ExtraObject *extrapo ); + + // append a RE_KillOjbect event + //FIXME: GAMECODE + int NET_Append_RE_KillObject( dword objectid, byte listno ); + + // append a RE_CreateExtra2 event + //FIXME: GAMECODE + int NET_Append_RE_CreateExtra2( const ExtraObject *extrapo ); + + // append a RE_IPv4ServerInfo event + int NET_Append_RE_IPv4ServerInfo( node_t* node, word nServerID, int xpos, int ypos, word flags ); + + // append a RE_ServerLinkInfo event + int NET_Append_RE_ServerLinkInfo( word nServerID_1, word nServerID_2, word flags ); + + // append a RE_MapObject + int NET_Append_RE_MapObject( int map_objectid, char* name, int xpos, int ypos, int w, int h, char* texname ); + + //Append a Particle RE (energy fields, megashield...etc) + int NET_Append_RE_ParticleObject( int type, const Vertex3& origin ); + + // determine the size of a remote-event list + static size_t DetermineListSize( RE_Header* relist ) + { + ASSERT( relist != NULL ); + + size_t lsize = 0; + + // process remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + // sum up size of all remote events + size_t resize = RmEvGetSize( relist ); + lsize += resize; + + // advance to next event + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || + ( relist->RE_BlockSize == resize ) ); + relist = (RE_Header *) ( (char *) relist + resize ); + } + + // include size of RE list termination + lsize += sizeof( dword ); + + return lsize; + } + + // determine size of remote event + static size_t RmEvGetSize( RE_Header *relist ); + + // determine size of remote event from type + static size_t RmEvGetSizeFromType( byte retype ); + + // check whether the remote event list is well formed + static int IsWellFormed( RE_Header *relist ); + + // return the max. size of the RE list that can fit in one external packet + static size_t GetMaxSizeInPacket(); + + // validate the RE according to all bounds + static int ValidateRE( RE_Header* relist, size_t size ); + +protected: +}; + + +#define NET_RmEvList_GetSize E_REList::DetermineListSize +#define NET_RmEvList_IsWellFormed E_REList::IsWellFormed + + +#endif // _E_RELIST_H_ diff --git a/src/libparsec/include/g_emp.h b/src/libparsec/include/g_emp.h new file mode 100644 index 0000000..e0879a9 --- /dev/null +++ b/src/libparsec/include/g_emp.h @@ -0,0 +1,249 @@ +/* + * PARSEC HEADER: s_emp.h + */ + +#ifndef _S_EMP_H_ +#define _S_EMP_H_ + + + + +// use emp as duration weapon +#define EMP_FIRE_CONTINUOUSLY + + + + + +#define EMP_MAX_TEX_NAME 128 +// emp custom type structure -------------------------------------------------- +// +struct Emp : CustomObject { + + int upgradelevel; + Xmatrx WorldXmatrx; // object- to worldspace matrix + Vertex3* ObjVtxs; + Vertex3* WorldVtxs; // vertices in worldspace + TextureMap* texmap; + char texname[ EMP_MAX_TEX_NAME + 1 ]; + dword OwnerHostObjno; // needed for animation calculation + GenObject* ownerpo; + int Owner; + int vtxsnr; + int lod; + bams_t lat; + bams_t rot; + long alive; + int delay; + int red; + int green; + int blue; + int alpha; + dword damage; // hitpoints fractional per refframe +}; + +// number of upgrade levels --------------------------------------------------- +// +#define EMP_UPGRADES 3 + + +// preset emp type property values -------------------------------------------- +// +#define EMP_MAX_LIFETIME 6000 +#define EMP_MIN_LIFETIME 60 +#define EMP_MAX_WAVES 100 +#define EMP_MIN_WAVES 1 +#define EMP_MAX_DELAY 2400 +#define EMP_MIN_DELAY 0 + +// emp standard property values +#define EMP_TEXNAME "in01_00a.3df" +#define EMP_LOD 16 +#define EMP_MAX_WIDTH 200.0f +#define EMP_LAT 0x2000 // 45 deg +#define EMP_RED 220 +#define EMP_GREEN 220 +#define EMP_BLUE 220 +#define EMP_ALPHA 255 +#define EMP_LIFETIME 400 +#define EMP_FADEOUT 400 +#define EMP_LAMBDA 0.2 +#define EMP_ROT 32 +#define EMP_DELAY 200 +#define EMP_WAVES 1 +#define EMP_ENERGY 0 +#define EMP_DAMAGE 2000 + +// emp upgrade level 1 property values +#define EMP_UP1_TEXNAME "in01_00a.3df" +#define EMP_UP1_LOD 16 +#define EMP_UP1_MAX_WIDTH 200.0f +#define EMP_UP1_LAT 0x2000 // 45 deg +#define EMP_UP1_RED 220 +#define EMP_UP1_GREEN 220 +#define EMP_UP1_BLUE 220 +#define EMP_UP1_ALPHA 180 +#define EMP_UP1_LIFETIME 200 +#define EMP_UP1_FADEOUT 200 +#define EMP_UP1_LAMBDA 2.0 +#define EMP_UP1_ROT ( BAMS_DEG45 / 16 ) +#define EMP_UP1_DELAY 40 +#define EMP_UP1_WAVES 6 +#define EMP_UP1_ENERGY 6 +#define EMP_UP1_DAMAGE 1000 + +// emp upgrade level 2 property values +#define EMP_UP2_TEXNAME "in01_00a.3df" +#define EMP_UP2_LOD 16 +#define EMP_UP2_MAX_WIDTH 200.0f +#define EMP_UP2_LAT 0x2000 // 45 deg +#define EMP_UP2_RED 220 +#define EMP_UP2_GREEN 200 +#define EMP_UP2_BLUE 0 +#define EMP_UP2_ALPHA 90 +#define EMP_UP2_LIFETIME 800 +#define EMP_UP2_FADEOUT 800 +#define EMP_UP2_LAMBDA 4.0 +#define EMP_UP2_ROT 16 +#define EMP_UP2_DELAY 80 +#define EMP_UP2_WAVES 6 +#define EMP_UP2_ENERGY 40 +#define EMP_UP2_DAMAGE 2000 + + + +#define OFS_TEXNAME offsetof( Emp, texname ) +#define OFS_LOD offsetof( Emp, lod ) +#define OFS_LAT offsetof( Emp, lat ) +#define OFS_ROT offsetof( Emp, rot ) +#define OFS_RED offsetof( Emp, red ) +#define OFS_GREEN offsetof( Emp, green ) +#define OFS_BLUE offsetof( Emp, blue ) +#define OFS_ALPHA offsetof( Emp, alpha ) +#define OFS_DAMAGE offsetof( Emp, damage ) + + +// assigned type id for emp type ---------------------------------------------- +// +extern dword emp_type_id[ EMP_UPGRADES ]; + + +// full table for emp expansion ----------------------------------------------- +// +static float *emp_expansion_tab[ EMP_UPGRADES ] = { + NULL, NULL, NULL, +}; + + +// emp behaviour properties --------------------------------------------------- +// +static int emp_lifetime[ EMP_UPGRADES ] = { + EMP_LIFETIME, + EMP_UP1_LIFETIME, + EMP_UP2_LIFETIME, +}; +static geomv_t emp_max_width[ EMP_UPGRADES ] = { + FLOAT_TO_GEOMV( EMP_MAX_WIDTH ), + FLOAT_TO_GEOMV( EMP_UP1_MAX_WIDTH ), + FLOAT_TO_GEOMV( EMP_UP2_MAX_WIDTH ), +}; + +static float emp_lambda[ EMP_UPGRADES ] = { + EMP_LAMBDA, + EMP_UP1_LAMBDA, + EMP_UP2_LAMBDA, +}; + +static int emp_fadeout[ EMP_UPGRADES ] = { + EMP_FADEOUT, + EMP_UP1_FADEOUT, + EMP_UP2_FADEOUT, +}; + +static int emp_waves[ EMP_UPGRADES ] = { + EMP_WAVES, + EMP_UP1_WAVES, + EMP_UP2_WAVES, +}; + +static int emp_delay[ EMP_UPGRADES ] = { + EMP_DELAY, + EMP_UP1_DELAY, + EMP_UP2_DELAY, +}; + +static int emp_energy[ EMP_UPGRADES ] = { + EMP_ENERGY, + EMP_UP1_ENERGY, + EMP_UP2_ENERGY, +}; + + +// macro to set the properties of a itervertex -------------------------------- +// +#define SET_ITER_VTX( itvtx, vtx, u, v, r, g, b, a ) \ + (itvtx)->X = (vtx)->X; \ + (itvtx)->Y = (vtx)->Y; \ + (itvtx)->Z = (vtx)->Z; \ + (itvtx)->W = GEOMV_1; \ + (itvtx)->U = (u); \ + (itvtx)->V = (v); \ + (itvtx)->R = (r); \ + (itvtx)->G = (g); \ + (itvtx)->B = (b); \ + (itvtx)->A = (a); + + +// color combination macro ---------------------------------------------------- +// +#define COLOR_MUL(t,a,b) { \ + int tmp; \ + tmp = ( (int)(a) * (int)(b) ) / 255; \ + if ( tmp > 255 ) \ + tmp = 255; \ + (t) = tmp; \ +} + +#ifdef PARSEC_SERVER + +// mathematics header +#include "utl_math.h" + +// local module header +#include "e_gameserver.h" + +// proprietary module headers +#include "con_arg.h" +#include "con_aux_sv.h" +#include "con_com_sv.h" +#include "con_main_sv.h" +#include "e_colldet.h" +#include "g_extra.h" + +#include "obj_clas.h" +//#include "e_stats.h" +#include "g_main_sv.h" +#include "e_simulator.h" +#include "sys_refframe_sv.h" +#include "sys_util_sv.h" +#endif + +void CreateEmp( GenObject *ownerpo, int delay, int alive, int upgradelevel, int nClientID=0 ); +// external functions +#ifndef PARSEC_SERVER +void WFX_EmpBlast( ShipObject *shippo ); +void WFX_RemoteEmpBlast( ShipObject *shippo, int curupgrade ); +void WFX_CreateEmpWaves( ShipObject *shippo ); +int WFX_ActivateEmp( ShipObject *shippo ); +void WFX_DeactivateEmp( ShipObject *shippo ); +void WFX_RemoteActivateEmp( int playerid ); +void WFX_RemoteDeactivateEmp( int playerid ); +#else + +int EmpShipCollision( Emp *emp, ShipObject* shippo ); +int EmpAnimate( CustomObject *base ); +#endif + +#endif // _S_EMP_H_ + + diff --git a/src/libparsec/include/g_extra.h b/src/libparsec/include/g_extra.h new file mode 100644 index 0000000..e58be44 --- /dev/null +++ b/src/libparsec/include/g_extra.h @@ -0,0 +1,142 @@ +/* +* PARSEC HEADER: G_extra.h +*/ + +#ifndef _G_EXTRA_H_ +#define _G_EXTRA_H_ + +#ifdef PARSEC_CLIENT + //FIXME: move this into E_GLOBAL.H for the client + #define TheGameExtraManager (G_ExtraManager::GetExtraManager()) +#endif //PARSEC_CLIENT + +// class maintaining all EXTRA related stuff ---------------------------------- +// +class G_ExtraManager +{ +public: + + int ExtraProbability; + int MaxExtraArea; + int MinExtraDist; + int ProbHelixCannon; + int ProbLightningDevice; + int ProbPhotonCannon; + int ProbProximityMine; + int ProbMissilePack; + int ProbDumbMissPack; + int ProbHomMissPack; + int ProbSwarmMissPack; + int ProbRepairExtra; + int ProbAfterburner; + int ProbHoloDecoy; + int ProbInvisibility; + int ProbInvulnerability; + int ProbEnergyField; + int ProbLaserUpgrade; + int ProbLaserUpgrade1; + int ProbLaserUpgrade2; + int ProbEmpUpgrade1; + int ProbEmpUpgrade2; + +protected: + + G_ExtraManager(); + + // place extras after ship was shot down + void _PlaceShipExtras( int num, int objclass, ShipObject *shippo ); + + + // boost extra collected: energy boost + char* _CollectBoostEnergy( ShipObject* cur_ship, Extra1Obj* extra1po ); + + // boost extra collected: repair damage + char* _CollectBoostRepair( ShipObject* cur_ship, Extra1Obj* extra1po ); + + // package extra collected: dumb missiles + char* _CollectPackDumb( ShipObject* cur_ship, Extra2Obj* extra2po ); + + // package extra collected: guided missiles + char* _CollectPackGuide( ShipObject* cur_ship, Extra2Obj* extra2po ); + + // device extra collected: swarm missiles + char* _CollectPackSwarm( ShipObject* cur_ship, Extra2Obj* extra2po ); + + // package extra collected: proximity mines + char* _CollectPackMine( ShipObject* cur_ship, Extra2Obj* extra2po ); + + // device extra collected: helix cannon + char* _CollectDeviceHelix( ShipObject* cur_ship ); + + // device extra collected: lightning device + char* _CollectDeviceLightning( ShipObject* cur_ship ); + + // device extra collected: photon cannon + char* _CollectDevicePhoton( ShipObject* cur_ship ); + + // device extra collected: afterburner + char* _CollectDeviceAfterburner( ShipObject* cur_ship ); + + // device extra collected: invisibility + char* _CollectDeviceInvisibility( ShipObject* cur_ship ); + + // device extra collected: invulnerability + char* _CollectDeviceInvulnerability( ShipObject* cur_ship ); + + // device extra collected: decoy + char* _CollectDeviceDecoy( ShipObject* cur_ship ); + + // device extra collected: laser upgrade 1 + char* _CollectDeviceLaserUpgrade1( ShipObject* cur_ship ); + + // device extra collected: laser upgrade 2 + char* _CollectDeviceLaserUpgrade2( ShipObject* cur_ship ); + + // device extra collected: emp upgrade 1 + char* _CollectDeviceEmpUpgrade1( ShipObject* cur_ship ); + + // device extra collected: emp upgrade 2 + char* _CollectDeviceEmpUpgrade2( ShipObject* cur_ship ); + + // helper function when collecting devices + char* _CollectDevice( int nDevice, ShipObject* cur_ship ); + + // helper function when collecting specials + char* _CollectSpecial( int nSpecial, ShipObject* cur_ship ); + + // function when colliding with a mine + char* _CollisionProximityMine( Mine1Obj *minepo ); + +public: + + // SINGLETON pattern + static G_ExtraManager* GetExtraManager() + { + static G_ExtraManager _TheGameExtraManager; + return &_TheGameExtraManager; + } + + // place extras in vicinity of local ship object + void OBJ_DoExtraPlacement(); + + // create extras after ship was shot down + void OBJ_CreateShipExtras( ShipObject *shippo ); + + // fill member variables of extras + void OBJ_FillExtraMemberVars( ExtraObject* extrapo ); + + // kill extra that immediately follows passed node in list + void OBJ_KillExtra( ExtraObject* precnode, int collected ); + + // animate an extra + void OBJ_AnimateExtra( ExtraObject* extrapo ); + + + // perform action according to extra type and determine message to show + char* CollectExtra( ShipObject* cur_ship, ExtraObject* curextra ); + char* _CollectBoostEnergyField( ShipObject* cur_ship, int boost ); +}; + + + +#endif // _G_EXTRA_H_ diff --git a/src/libparsec/include/g_shipobject.h b/src/libparsec/include/g_shipobject.h new file mode 100644 index 0000000..f312914 --- /dev/null +++ b/src/libparsec/include/g_shipobject.h @@ -0,0 +1,214 @@ + + +class G_ShipObject : public ShipObject +{ +protected: +public: + + int BoostEnergy( int nEnergy ) + { + if ( CurEnergy == MaxEnergy ) { + return FALSE; + } else { + CurEnergy += nEnergy; + if ( CurEnergy > MaxEnergy ) { + CurEnergy = MaxEnergy; + } + return TRUE; + } + } + + int BoostRepair( int nRepair ) + { + if ( CurDamage == 0 ) { + return FALSE; + } else { + CurDamage -= nRepair; + if ( CurDamage < 0 ) { + CurDamage = 0; + } + return TRUE; + } + } + + int BoostMissiles( int nNumMissiles ) + { + if ( NumMissls == MaxNumMissls ) { + return FALSE; + } else { + NumMissls += nNumMissiles; + if ( NumMissls > MaxNumMissls ) { + NumMissls = MaxNumMissls; + } + return TRUE; + } + } + + int BoostHomMissiles( int nNumMissiles ) + { + if ( NumHomMissls == MaxNumHomMissls ) { + return FALSE; + } else { + NumHomMissls += nNumMissiles; + if ( NumHomMissls > MaxNumHomMissls ) { + NumHomMissls = MaxNumHomMissls; + } + return TRUE; + } + } + + int BoostPartMissiles( int nNumMissiles ) + { + if ( NumPartMissls == MaxNumPartMissls ) { + return FALSE; + } else { + NumPartMissls += nNumMissiles; + if ( NumPartMissls > MaxNumPartMissls ) { + NumPartMissls = MaxNumPartMissls; + } + return TRUE; + } + } + + int BoostMines( int nMines ) + { + if ( NumMines == MaxNumMines ) { + return FALSE; + } else { + NumMines += nMines; + if ( NumMines > MaxNumMines ) { + NumMines = MaxNumMines; + } + return TRUE; + } + } + + int CollectDevice( int mask ) + { + if ( ( Weapons & mask ) == 0 ) { + Weapons |= mask; + return TRUE; + } else { + return FALSE; + } + } + + // enable afterburner function ------------------------------------------------ + // + void EnableAfterBurner() + { + // set active flag + Specials |= SPMASK_AFTERBURNER; + afterburner_energy = AFTERBURNER_ENERGY; + } + + // enable invisibility function ----------------------------------------------- + // + void EnableInvisibility() + { + // set active flag + Specials |= SPMASK_INVISIBILITY; + + //TODO: + // well, nobody got around to implementing this :) + } + + + // enable invulnerability function -------------------------------------------- + // + void EnableInvulnerability() + { +#ifdef PARSEC_CLIENT + // create particle cluster visualizing invulnerability shield + if ( SFX_EnableInvulnerabilityShield( (ShipObject*)this ) ) { + + // set active flag + Specials |= SPMASK_INVULNERABILITY; + + // set shield strength + MegaShieldAbsorption = MegaShieldStrength; + } +#elif defined ( PARSEC_SERVER ) + + // set active flag + Specials |= SPMASK_INVULNERABILITY; + + // set shield strength + MegaShieldAbsorption = TheGame->MegaShieldStrength; +#endif + } + + // enable decoy device -------------------------------------------------------- + // + void EnableDecoy() + { + // set active flag + Specials |= SPMASK_DECOY; + } + + + // enable laser upgrade 1 ---------------------------------------------------- + // + void EnableLaserUpgrade1() + { + // set active flag + Specials |= SPMASK_LASER_UPGRADE_1; + } + + + // enable laser upgrade 2 ---------------------------------------------------- + // + void EnableLaserUpgrade2() + { + // set active flag + Specials |= SPMASK_LASER_UPGRADE_2; + } + + + // enable emp upgrade 1 ------------------------------------------------------ + // + void EnableEmpUpgrade1() + { + // set active flag + Specials |= SPMASK_EMP_UPGRADE_1; + } + + + // enable emp upgrade 2 ------------------------------------------------------ + // + void EnableEmpUpgrade2() + { + // set active flag + Specials |= SPMASK_EMP_UPGRADE_2; + } + + + int CollectSpecial( int mask ) + { + switch( mask ) { + case SPMASK_AFTERBURNER: + EnableAfterBurner(); + break; + case SPMASK_INVISIBILITY: + EnableInvisibility(); + break; + case SPMASK_INVULNERABILITY: + EnableInvulnerability(); + break; + case SPMASK_DECOY: + EnableDecoy(); + break; + default: + //NOTE: all other specials must be handled by directly calling the Enable* function + ASSERT( FALSE ); + break; + } + + if ( ( Specials & mask ) == 0 ) { + return TRUE; + } else { + return FALSE; + } + } +}; + diff --git a/src/libparsec/include/g_stgate.h b/src/libparsec/include/g_stgate.h new file mode 100644 index 0000000..2f838b2 --- /dev/null +++ b/src/libparsec/include/g_stgate.h @@ -0,0 +1,69 @@ +/* + * PARSEC HEADER: s_stgate.h + */ + +#ifndef _S_STGATE_H_ +#define _S_STGATE_H_ + + +// forward declaration +struct genobject_pcluster_s; + + +// stargate limits ------------------------------------------------------------ +// +#define STARGATE_MAX_DEST_IP 255 + + +// stargate custom type structure --------------------------------------------- +// +struct Stargate : CustomObject { + + // properties + bams_t rotspeed; + float radius; + geomv_t actdistance; + int dormant; + int active; + int autoactivate; + int numpartactive; + int actcyllen; + float partvel; + bams_t modulspeed; + float modulrad1; + float modulrad2; + float modulfade; + int acttime; + char flare_name [ MAX_TEXNAME + 1 ]; + char interior_name[ MAX_TEXNAME + 1 ]; + + // internal data + word serverid; + char destination_name[ MAX_SERVER_NAME + 1 ]; + //char destination_ip[ STARGATE_MAX_DEST_IP + 1 ]; + //word destination_port; + node_t destination_node; + bams_t modulate_bams; + int curactcyllen; + int activating; + int manually_activated; + float actring; + genobject_pcluster_s* pcluster; + Vertex3* interior_vtxlist; // vtxs in object space + Vertex3* interior_viewvtxs; // vtxs in view space + geomv_t* interior_u; // u texture coordinates + geomv_t* interior_v; // v texture coordinates + TextureMap* interior_texmap; + int ping; + refframe_t lastpinged; +}; + + +// external functions --------------------------------------------------------- +// +// (none) + + +#endif // _S_STGATE_H_ + + diff --git a/src/libparsec/include/gd_bmap.h b/src/libparsec/include/gd_bmap.h new file mode 100644 index 0000000..d48ead0 --- /dev/null +++ b/src/libparsec/include/gd_bmap.h @@ -0,0 +1,147 @@ +/* + * PARSEC HEADER: gd_bmap.h + */ + +#ifndef _GD_BMAP_H_ +#define _GD_BMAP_H_ + + +// ---------------------------------------------------------------------------- +// BITMAP INDEXES - +// ---------------------------------------------------------------------------- + + +// indexes of bitmaps in global bitmap table ---------------------------------- +// +#define BM_CROSSHAIR 0 +#define BM_RADAR 1 +#define BM_MSTAR1 2 +#define BM_MSTAR2 3 +#define BM_MSTAR3 4 +#define BM_MSTAR4 5 +#define BM_BIGPLANET1 6 +#define BM_SCLSTR1 7 +#define BM_SCLSTR2 8 +#define BM_MEDPLANET1 9 +#define BM_MINPLANET1 10 +#define BM_TARGET 11 + +#define BM_EXPLANIMBASE 12 // first frame of explosion animation +#define BM_NUMEXPLFRAMES 12 // number of frames for explosion + +#define BM_NEBULA 24 +#define BM_LOGO1 25 +#define BM_LOGO2 26 +#define BM_SHIP1_BLUEPRINT 27 +#define BM_SHIP2_BLUEPRINT 28 +#define BM_ROCKET1 29 +#define BM_ROCKET2 30 +#define BM_CROSSHAIR2 31 +#define BM_CROSSHAIR3 32 +#define BM_MINE 33 +#define BM_GUN1 34 +#define BM_GUN2 35 +#define BM_GUN3 36 +#define BM_OBJSLOGO 37 +#define BM_VIEWLOGO 38 +#define BM_LEFTARROW 39 +#define BM_RIGHTARROW 40 +#define BM_SELECT 41 +#define BM_SUN 42 +#define BM_LIGHTNING2 43 +#define BM_LIGHTNING1 44 +#define BM_FIREBALL1 45 +#define BM_FIREBALL2 46 +#define BM_SHIELD1 47 +#define BM_SHIELD2 48 +#define BM_PROPFUMES1 49 +#define BM_PROPFUMES2 50 +#define BM_PROPFUMES3 51 +#define BM_FIREBALL3 52 +#define BM_LENSFLARE1 53 +#define BM_LENSFLARE2 54 +#define BM_LENSFLARE3 55 +#define BM_LENSFLARE4 56 + +#define BM_CONTROLFILE_NUMBER 57 // number of bitmaps in control file + + +// names of default (control file-loaded) bitmaps ----------------------------- +// +#define BM_NAME_CROSSHAIR "crosshair" +#define BM_NAME_RADAR "radar" +#define BM_NAME_MSTAR1 "mstar1" +#define BM_NAME_MSTAR2 "mstar2" +#define BM_NAME_MSTAR3 "mstar3" +#define BM_NAME_MSTAR4 "mstar4" +#define BM_NAME_BIGPLANET1 "bigplanet1" +#define BM_NAME_SCLSTR1 "sclstr1" +#define BM_NAME_SCLSTR2 "sclstr2" +#define BM_NAME_MEDPLANET1 "medplanet1" +#define BM_NAME_MINPLANET1 "minplanet1" +#define BM_NAME_TARGET "target" +#define BM_NAME_EXPLANIM01 "explanim01" +#define BM_NAME_EXPLANIM02 "explanim02" +#define BM_NAME_EXPLANIM03 "explanim03" +#define BM_NAME_EXPLANIM04 "explanim04" +#define BM_NAME_EXPLANIM05 "explanim05" +#define BM_NAME_EXPLANIM06 "explanim06" +#define BM_NAME_EXPLANIM07 "explanim07" +#define BM_NAME_EXPLANIM08 "explanim08" +#define BM_NAME_EXPLANIM09 "explanim09" +#define BM_NAME_EXPLANIM10 "explanim10" +#define BM_NAME_EXPLANIM11 "explanim11" +#define BM_NAME_EXPLANIM12 "explanim12" +#define BM_NAME_NEBULA "nebula" +#define BM_NAME_LOGO1 "logo1" +#define BM_NAME_LOGO2 "logo2" +#define BM_NAME_SHIP1_BLUEPRINT "ship1_blueprint" +#define BM_NAME_SHIP2_BLUEPRINT "ship2_blueprint" +#define BM_NAME_ROCKET1 "rocket1" +#define BM_NAME_ROCKET2 "rocket2" +#define BM_NAME_CROSSHAIR2 "crosshair2" +#define BM_NAME_CROSSHAIR3 "crosshair3" +#define BM_NAME_MINE "mine" +#define BM_NAME_GUN1 "gun1" +#define BM_NAME_GUN2 "gun2" +#define BM_NAME_GUN3 "gun3" +#define BM_NAME_OBJSLOGO "objslogo" +#define BM_NAME_VIEWLOGO "viewlogo" +#define BM_NAME_LEFTARROW "leftarrow" +#define BM_NAME_RIGHTARRORW "rightarrow" +#define BM_NAME_SELECT "select" +#define BM_NAME_SUN "sun" +#define BM_NAME_LIGHTNING2 "lightning2" +#define BM_NAME_LIGHTNING1 "lightning1" +#define BM_NAME_FIREBALL1 "fireball1" +#define BM_NAME_FIREBALL2 "fireball2" +#define BM_NAME_SHIELD1 "shield1" +#define BM_NAME_SHIELD2 "shield2" +#define BM_NAME_PROPFUMES1 "propfumes1" +#define BM_NAME_PROPFUMES2 "propfumes2" +#define BM_NAME_PROPFUMES3 "propfumes3" +#define BM_NAME_FIREBALL3 "fireball3" +#define BM_NAME_LENSFLARE1 "lensflare1" +#define BM_NAME_LENSFLARE2 "lensflare2" +#define BM_NAME_LENSFLARE3 "lensflare3" +#define BM_NAME_LENSFLARE4 "lensflare4" + + +// names of non-default bitmaps (which have no predefined id) ----------------- +// +#define BM_NAME_RADAR2 "radar2" + + +// explosion animation definitions -------------------------------------------- +// +#define BM_EXPLVANISHFRAME 5 // the target vanishes in this frame +#define BM_EXPLNOTARGFRAME 3 // the target is lost in this frame +#define BM_EXPLPARTCLFRAME 3 // particle explosion starts in this frame + +#define EXPL_REF_SPEED 64 +#define MAX_EXPLOSION_COUNT ( BM_NUMEXPLFRAMES * EXPL_REF_SPEED - 1 ) + + +#endif // _GD_BMAP_H_ + + diff --git a/src/libparsec/include/gd_color.h b/src/libparsec/include/gd_color.h new file mode 100644 index 0000000..8ac73a6 --- /dev/null +++ b/src/libparsec/include/gd_color.h @@ -0,0 +1,57 @@ +/* + * PARSEC HEADER: gd_color.h + */ + +#ifndef _GD_COLOR_H_ +#define _GD_COLOR_H_ + + +// ---------------------------------------------------------------------------- +// COLOR TYPES - +// ---------------------------------------------------------------------------- + + +// RGB color triplet (mainly used for vga compatible palette entries) --------- +// +struct colrgb_s { + union { + struct { + byte R; + byte G; + byte B; + }; + byte index[3]; + }; +}; + + +// RGBA color specification with alpha component (standard color type) -------- +// +struct colrgba_s { + union { + struct { + byte R; + byte G; + byte B; + byte A; + }; + byte index[4]; + }; +}; + + +// color type for the currently active framebuffer color format --------------- +// +typedef dword visual_t; + + +// helper macros -------------------------------------------------------------- +// +#define SETRGBA( x, r,g,b,a ) { (x)->R = r; (x)->G = g; (x)->B = b; (x)->A = a; } +#define SETRGB ( x, r,g,b ) { (x)->R = r; (x)->G = g; (x)->B = b; } + + + +#endif // _GD_COLOR_H_ + + diff --git a/src/libparsec/include/gd_const.h b/src/libparsec/include/gd_const.h new file mode 100644 index 0000000..749c1be --- /dev/null +++ b/src/libparsec/include/gd_const.h @@ -0,0 +1,63 @@ +/* + * PARSEC HEADER: gd_const.h + */ + +#ifndef _GD_CONST_H_ +#define _GD_CONST_H_ + + +// ---------------------------------------------------------------------------- +// GLOBAL CONSTANTS - +// ---------------------------------------------------------------------------- + + +// frequency in hertz for ref-frames (number of ref-frames per second) -------- +// +#define DEFAULT_REFFRAME_FREQUENCY 600 + +#ifdef VARIABLE_REFFRAME_FREQUENCY + #define FRAME_MEASURE_TIMEBASE RefFrameFrequency +#else + #define FRAME_MEASURE_TIMEBASE DEFAULT_REFFRAME_FREQUENCY +#endif + + +// size of padding area appended to render segment ---------------------------- +// +#define RSEG_PADDING_SIZE (640*20) + + +// packet recv rates (bytes/sec) ---------------------------------------------- +// +#define CLIENT_RECV_RATE_MAX 100000 //FIXME: reasonable ? +#define CLIENT_RECV_RATE_1 8000 +#define CLIENT_RECV_RATE_2 4000 +#define CLIENT_RECV_RATE_3 2000 +#define CLIENT_RECV_RATE_MIN 10 //FIXME: reasonable ? + +// default rate (bytes/sec) for S->C traffic ---------------------------------- +// +#define DEFAULT_CLIENT_RECV_RATE CLIENT_RECV_RATE_1 + +// packet send frequencies ---------------------------------------------------- +// +#define CLIENT_SEND_FREQUENCY_MAX 100 //FIXME: reasonable ? +#define CLIENT_SEND_FREQUENCY_1 20 +#define CLIENT_SEND_FREQUENCY_2 15 +#define CLIENT_SEND_FREQUENCY_3 10 +#define CLIENT_SEND_FREQUENCY_MIN 1 + +// default frequency (packets/sec) for C->S traffic --------------------------- +// +#define DEFAULT_CLIENT_SEND_FREQUENCY CLIENT_SEND_FREQUENCY_1 + +// detail codes --------------------------------------------------------------- +// +#define DETAIL_LOW 0 +#define DETAIL_MEDIUM 1 +#define DETAIL_HIGH 2 + + +#endif // _GD_CONST_H_ + + diff --git a/src/libparsec/include/gd_font.h b/src/libparsec/include/gd_font.h new file mode 100644 index 0000000..3b11edf --- /dev/null +++ b/src/libparsec/include/gd_font.h @@ -0,0 +1,25 @@ +/* + * PARSEC HEADER: gd_font.h + */ + +#ifndef _GD_FONT_H_ +#define _GD_FONT_H_ + + +// ---------------------------------------------------------------------------- +// FONT INDEXES - +// ---------------------------------------------------------------------------- + + +// indexes of fonts in global charset table ----------------------------------- +// +#define MSG_CHARSETNO 0 // 16x16 font for four line message area +#define MIN_CHARSETNO 1 // 4x9 extremely small font; barely legible +#define HUD_CHARSETNO 2 // 8x8 font for console and most hud output +#define TGO_CHARSETNO 3 +#define GLD_CHARSETNO 4 // proportional font for 8bit menu + + +#endif // _GD_FONT_H_ + + diff --git a/src/libparsec/include/gd_heads.h b/src/libparsec/include/gd_heads.h new file mode 100644 index 0000000..b958294 --- /dev/null +++ b/src/libparsec/include/gd_heads.h @@ -0,0 +1,132 @@ +/* + * PARSEC HEADER: gd_heads.h + */ + +#ifndef _GD_HEADS_H_ +#define _GD_HEADS_H_ + + +// ---------------------------------------------------------------------------- +// DATA FILE HEADER DEFINITIONS - +// ---------------------------------------------------------------------------- + + +// filepack: structure of file package header --------------------------------- +// +struct packageheader_s { + + char signature[ 16 ]; + dword numitems; + dword headersize; + dword datasize; + dword packsize; +}; + + +// filepack: structure of single entry in info list in memory ----------------- +// +struct pfileinfo_s { + + char *file; + dword foffset; + dword flength; + FILE *fp; + dword fcurpos; +}; + + +// filepack: structure of single entry in info list on storage device --------- +// +struct pfileinfodisk_s { + + char file[ 16 ]; + dword foffset; + dword flength; + dword fp; // dword instead of FILE* because packed .dat file requires it to be 32 bits + dword fcurpos; +}; + + +// parpfg format (parsec font info files) ------------------------------------- +// +struct PfgHeader { + + char signature[7]; + byte version; + int srcwidth; + short width; + short height; +}; + +#define PFG_SIGNATURE "PARPFG" +#define REQUIRED_PFG_VERSION 0x01 + + +// parfnt format (parsec font files) ------------------------------------------ +// +struct FntHeader { + + char signature[7]; + byte version; + int width; + int height; +}; + +#define FNT_SIGNATURE "PARFNT" +#define REQUIRED_FNT_VERSION 0x01 +#define FONT_EXTENSION "fnt" + + +// partex format (parsec texture data files) ---------------------------------- +// +struct TexHeader { + + char signature[7]; + byte version; + int width; + int height; +}; + +#define TEX_SIGNATURE "PARTEX" +#define REQUIRED_TEX_VERSION 0x01 + + +// parbdt format (parsec bitmap data files) ----------------------------------- +// +struct BdtHeader { + + char signature[7]; + byte version; + int width; + int height; +}; + +#define BDT_SIGNATURE "PARBDT" +#define REQUIRED_BDT_VERSION 0x01 + + +// pardem format (parsec demo data files) -------------------------------------- +// +struct DemHeader { + + char signature[7]; + byte version; + dword headersize; +}; + +#define DEM_SIGNATURE "PARDEM" +#define REQUIRED_DEM_VERSION 0x01 + +enum { + + DEMO_KEY_TITLE = 0x01, + DEMO_KEY_DESCRIPTION = 0x02, + DEMO_KEY_AUTHOR = 0x03, + + NUM_DEMO_KEYS // must be last in list +}; + + +#endif // _GD_HEADS_H_ + + diff --git a/src/libparsec/include/gd_help.h b/src/libparsec/include/gd_help.h new file mode 100644 index 0000000..4185804 --- /dev/null +++ b/src/libparsec/include/gd_help.h @@ -0,0 +1,77 @@ +/* + * PARSEC HEADER: gd_help.h + */ + +#ifndef _GD_HELP_H_ +#define _GD_HELP_H_ + + +// ---------------------------------------------------------------------------- +// MISCELLANEOUS HELPER MACROS - +// ---------------------------------------------------------------------------- + + +// module registration macros (automatic module-init/deinit on startup) ------- +// +//#define REGISTER_MODULE(f) struct reg_##f {reg_##f();} inst_##f; reg_##f::reg_##f() +//#define REGISTER_MODULE_INIT(f) struct reg_##f {reg_##f(); ~reg_##f();} inst_##f; reg_##f::reg_##f() +//#define REGISTER_MODULE_KILL(f) reg_##f::~reg_##f() + +// for C++ min/max functions -------------------------------------------------- +// +#include <algorithm> + +// new module handling -------------------------------------------------------- +// +#include "e_modulemanager.h" + +// automatically calculate the number of entries of an arbitrary array -------- +// +#define CALC_NUM_ARRAY_ENTRIES(a) (sizeof(a)/sizeof((a)[0])) + + +// conversion macros for 5, 4, 3, and 2 digit values -------------------------- +// +#define DIG5_TO_STR( s, a ) (s)[0]=(((a)/10000)%10)+'0';\ + (s)[1]=(((a)/1000)%10)+'0';\ + (s)[2]=(((a)/100)%10)+'0';\ + (s)[3]=(((a)/10)%10)+'0';\ + (s)[4]=((a)%10)+'0';\ + (s)[5]='\0'; + +#define DIG4_TO_STR( s, a ) (s)[0]=(((a)/1000)%10)+'0';\ + (s)[1]=(((a)/100)%10)+'0';\ + (s)[2]=(((a)/10)%10)+'0';\ + (s)[3]=((a)%10)+'0';\ + (s)[4]='\0'; + +#define DIG3_TO_STR( s, a ) (s)[0]=(((a)/100)%10)+'0';\ + (s)[1]=(((a)/10)%10)+'0';\ + (s)[2]=((a)%10)+'0';\ + (s)[3]='\0'; + +#define DIG2_TO_STR( s, a ) (s)[0]=(((a)/10)%10)+'0';\ + (s)[1]=((a)%10)+'0';\ + (s)[2]='\0'; + + +// define wrapper around pseudo random number generator ----------------------- +// +#define RAND() rand() + + +// min/max functions ---------------------------------------------------------- +// +using std::min; +using std::max; + + +// safe string duplication ---------------------------------------------------- +// +#define SAFE_STR_DUPLICATE( dst, src, len ) char dst[ len + 1 ]; \ + strncpy( dst, src, len ); \ + dst[ len ] = 0; + +#endif // _GD_HELP_H_ + + diff --git a/src/libparsec/include/gd_host.h b/src/libparsec/include/gd_host.h new file mode 100644 index 0000000..96115bd --- /dev/null +++ b/src/libparsec/include/gd_host.h @@ -0,0 +1,79 @@ +/* + * PARSEC HEADER: gd_host.h + */ + +#ifndef _GD_HOST_H_ +#define _GD_HOST_H_ + + +// ---------------------------------------------------------------------------- +// HOST BYTE ORDER/WORD SIZE RELATED MACROS - +// ---------------------------------------------------------------------------- + + +// endianness conversion functions -------------------------------------------- +// +#define FORCESWAP_16(s) ( ((word)(s) >> 8) | ((word)(s) << 8) ) +#define FORCESWAP_32(l) ( ( ((dword)(l) ) << 24 ) | \ + ( ((dword)(l) ) >> 24 ) | \ + ( ((dword)(l) & 0x0000ff00) << 8 ) | \ + ( ((dword)(l) & 0x00ff0000) >> 8 ) ) + +#ifdef SYSTEM_BIG_ENDIAN + + // little endian to host (and vice versa) + #define SWAP_16(s) FORCESWAP_16(s) + #define SWAP_32(l) FORCESWAP_32(l) + + // big endian to host (and vice versa) + #define SWAP_16_BIG(s) (s) + #define SWAP_32_BIG(l) (l) + +#else + + // little endian to host (and vice versa) + #define SWAP_16(s) (s) + #define SWAP_32(l) (l) + + // big endian to host (and vice versa) + #define SWAP_16_BIG(s) FORCESWAP_16(s) + #define SWAP_32_BIG(l) FORCESWAP_32(l) + +#endif // SYSTEM_BIG_ENDIAN + + +// conversion from seg:ofs address to linear address (DOS32 only) ------------- +// +#define MK_LINEAR(seg,ofs) ((void*)((seg<<4)+ofs)) + + +// lo and hi byte and word functions (intentionally not named like in win32) -- +// +#ifndef LO_BYTE + #define LO_BYTE(w) ((byte)(w)) +#endif + +#ifndef HI_BYTE + #define HI_BYTE(w) ((byte)((w)>>8)) +#endif + +#ifndef LO_WORD + #define LO_WORD(l) ((word)(l)) +#endif + +#ifndef HI_WORD + #define HI_WORD(l) ((word)((l)>>16)) +#endif + +#ifndef MAKE_WORD + #define MAKE_WORD(l,h) (((byte)(l))|(((word)(byte)(h))<<8)) +#endif + +#ifndef MAKE_DWORD + #define MAKE_DWORD(l,h) (((word)(l))|(((dword)(word)(h))<<16)) +#endif + + +#endif // _GD_HOST_H_ + + diff --git a/src/libparsec/include/gd_limit.h b/src/libparsec/include/gd_limit.h new file mode 100644 index 0000000..0656032 --- /dev/null +++ b/src/libparsec/include/gd_limit.h @@ -0,0 +1,72 @@ +/* + * PARSEC HEADER: gd_limit.h + */ + +#ifndef _GD_LIMIT_H_ +#define _GD_LIMIT_H_ + + +// ---------------------------------------------------------------------------- +// ARBITRARY LIMITATIONS - +// ---------------------------------------------------------------------------- + + +// maximum numbers of object-types and object-classes ------------------------- +// +#define MAX_DISTINCT_OBJTYPES 32 +#define MAX_DISTINCT_OBJCLASSES 128 + + +// maximum numbers of data items ---------------------------------------------- +// +#define MAX_TEXTURES 1024 +#define MAX_TEXFONTS 16 +#define MAX_BITMAPS 128 +#define MAX_CHARSETS 16 +#define MAX_SAMPLES 96 +#define MAX_SONGS 16 + + +// maximum numbers of pseudo-stars and fixed-stars ---------------------------- +// +#define MAX_PSEUDO_STARS 512 +#define MAX_FIXED_STARS 120 + + +// maximum number of vertices of an iterpoly n-gon ---------------------------- +// +#define MAX_ITERPOLY_VERTICES 31 + + +// maximum number of vertices of an iterline line-strip ----------------------- +// +#define MAX_ITERLINE_VERTICES 128 + + +// message area limits -------------------------------------------------------- +// +#define MAX_MESSAGELEN 127 +#define MAX_SCREENMESSAGES 16 + + +// texfont message limits ----------------------------------------------------- +// +#define MAX_TEXFONT_MESSAGES 16 + + +// maximum name string lengths (excluding terminating zero) ------------------- +// +#define MAX_TEXNAME 31 +#define MAX_OBJNAME 31 +#define MAX_SAMNAME 31 +#define MAX_SNGNAME 31 + + +// maximum length of player name (network game) ------------------------------- +// +#define MAX_PLAYER_NAME 31 + + +#endif // _GD_LIMIT_H_ + + diff --git a/src/libparsec/include/gd_tabs.h b/src/libparsec/include/gd_tabs.h new file mode 100644 index 0000000..a405f21 --- /dev/null +++ b/src/libparsec/include/gd_tabs.h @@ -0,0 +1,134 @@ +/* + * PARSEC HEADER: gd_tabs.h + */ + +#ifndef _GD_TABS_H_ +#define _GD_TABS_H_ + + +// ---------------------------------------------------------------------------- +// GLOBAL DATA INFO TABLES - +// ---------------------------------------------------------------------------- + + +// object lod info ------------------------------------------------------------ +// +struct lodinfo_s { + + int numlods; + char** filetab; + geomv_t* lodmags; + geomv_t* lodmins; +}; + + +// object info table ---------------------------------------------------------- +// +struct objectinfo_s { + + dword type; // object type code + char* name; // object name (must be unique!) + char* file; // file object has been read from + lodinfo_s* lodinfo; // optional lod specification +}; + + +// texture info table --------------------------------------------------------- +// +struct textureinfo_s { + + TextureMap* texpointer; // pointer to actual texture struct + dword flags; // flagword + int width; // width in texels + int height; // height in texels + char* name; // texture name (must be unique!) + char* file; // file texture has been read from + char* standardbitmap; // texture bitmap in TEXFMT_STANDARD + char* loaderparams; // optional loading parameters +}; + +enum { + + TEXINFOFLAG_NONE = 0x00000000, + TEXINFOFLAG_USERPALETTE = 0x00000001, // don't touch texture palette + TEXINFOFLAG_PACKWASDISABLED = 0x00000100 // data was not read from pack +}; + + +// texfont info table --------------------------------------------------------- +// +struct texfontinfo_s { + + texfont_s* texfont; // pointer to actual texfont structure + dword flags; + int width; // width of single char in texels + int height; // height of single char in texels + char* name; // texfont name (must be unique!) + char* file; // file font has been read from + char* srcimage; // originally read data + int _mksiz32; +}; + + +// bitmap info table ---------------------------------------------------------- +// +struct bitmapinfo_s { + + char* bitmappointer; // pointer to current bitmap data + char* loadeddata; // pointer to original bitmap data + int width; // bitmap width + int height; // bitmap height + char* file; // file bitmap has been read from + char* name; // bitmap name (must be unique!) + int _mksiz32[2]; +}; + + +// charset info table --------------------------------------------------------- +// +struct charsetinfo_s { + + char* charsetpointer; // pointer to current font data + char* loadeddata; // pointer to original font data + dword* geompointer; // pointer to geometry table + int datasize; // size of actual font data in bytes + int width; // char width + int height; // char height + int srcwidth; // font bitmap width + dword flags; // flagword + char* file; // file font has been read from + TextureMap* fonttexture; // font converted to texture + int _mksiz64[6]; +}; + + +// sample info table ---------------------------------------------------------- +// +struct sampleinfo_s { + + char* name; + char* file; + char* samplepointer; + size_t size; + word flags; + short stereolevel; + int volume; + float samplefreq; + float stdfreq; +}; + + +// song info table ------------------------------------------------------------ +// +struct songinfo_s { + + char* songpointer; + char* name; + char* file; + int _mksiz16; +}; + + +#endif // _GD_TABS_H_ + + diff --git a/src/libparsec/include/gd_type.h b/src/libparsec/include/gd_type.h new file mode 100644 index 0000000..3ca42f4 --- /dev/null +++ b/src/libparsec/include/gd_type.h @@ -0,0 +1,60 @@ +/* + * PARSEC HEADER: gd_type.h + */ + +#ifndef _GD_TYPE_H_ +#define _GD_TYPE_H_ + +#include <stdint.h> + + +// ---------------------------------------------------------------------------- +// BASIC TYPE DEFINITIONS - +// ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- +// +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + + +// asm-style types ------------------------------------------------------------ +// +typedef uint8_t byte; +typedef uint16_t word; +typedef uint32_t dword; +typedef uint64_t qword; + + +// new types ------------------------------------------------------------------ +// +typedef bool bool_t; + + +// custom types --------------------------------------------------------------- +// +typedef int32 refframe_t; +#define REFFRAME_INVALID -1 + + +// boolean values ------------------------------------------------------------- +// +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + + +#endif // _GD_TYPE_H_ + + diff --git a/src/libparsec/include/general.h b/src/libparsec/include/general.h new file mode 100644 index 0000000..33e5853 --- /dev/null +++ b/src/libparsec/include/general.h @@ -0,0 +1,75 @@ +/* + * PARSEC HEADER: general.h + */ + +#ifndef _GENERAL_H_ +#define _GENERAL_H_ + + +// include type definitions --------------------------------------------------- +// +#include "gd_type.h" +#include "gd_color.h" + + +// include limits ------------------------------------------------------------- +// +#include "gd_limit.h" + + +// include global constants --------------------------------------------------- +// +#include "gd_const.h" +#ifdef PARSEC_CLIENT + #include "gd_bmap.h" + #include "gd_font.h" +#endif // PARSEC_CLIENT + + +// include host byte order macros --------------------------------------------- +// +#include "gd_host.h" + +// include general utility functions/classes ---------------------------------- +// +#include "utl_list.h" + + +// include helper functions --------------------------------------------------- +// +#include "gd_help.h" + + +// include message output functions ------------------------------------------- +// +#ifdef PARSEC_CLIENT + #include "sys_msg.h" +#elif defined ( PARSEC_SERVER ) // !PARSEC_CLIENT + #include "sys_msg_sv.h" +#endif // !PARSEC_CLIENT + + + +// include error functions and define exit function macros -------------------- +// +#ifdef PARSEC_CLIENT + #include "sys_err.h" +#elif defined ( PARSEC_SERVER ) // !PARSEC_CLIENT + #include "sys_err_sv.h" +#endif // !PARSEC_CLIENT + +#ifndef SYSTEM_TARGET_WINDOWS + // implemented in SL_MAIN.C + int stricmp( const char *s1, const char *s2 ); + int strnicmp( const char *s1, const char *s2, int len ); + char *strlwr( char *str ); + char *strupr( char *str ); +#elif !defined(__MINGW32__) +#include <BaseTsd.h> +#define ssize_t SSIZE_T +#define strtok_r strtok_s +#endif + +#endif // _GENERAL_H_ + + diff --git a/src/libparsec/include/globals.h b/src/libparsec/include/globals.h new file mode 100644 index 0000000..b818b06 --- /dev/null +++ b/src/libparsec/include/globals.h @@ -0,0 +1,53 @@ +/* + * PARSEC HEADER: globals.h + */ + +#ifndef _GLOBALS_H_ +#define _GLOBALS_H_ + +#ifdef PARSEC_SERVER + + // include subsystems globals ---------------------------- + + //#include "aud_glob.h" // AUDIO + //#include "inp_glob.h" // INPUT + //#include "net_glob.h" // NETWORKING + //#include "sys_glob.h" // SYSTEM + //#include "vid_glob.h" // VIDEO + + // include engine core globals --------------------------- + + #include "e_global_sv.h" // ENGINE CORE ( SERVER ) + + // include game code globals ----------------------------- + + #include "e_world.h" + +#else + + // include subsystems globals ---------------------------- + + #include "aud_glob.h" // AUDIO + #include "inp_glob.h" // INPUT + #include "net_glob.h" // NETWORKING + #include "sys_glob.h" // SYSTEM + #include "vid_glob.h" // VIDEO + + #include "d_glob.h" // DRAWING + #include "r_glob.h" // RENDERING + + // include engine core globals --------------------------- + + #include "e_global.h" // ENGINE CORE + + + // include game code globals ----------------------------- + + #include "g_global.h" // GAME CODE + #include "h_global.h" // GAME CODE/HUD + +#endif // PARSEC_SERVER + +#endif // _GLOBALS_H_ + + diff --git a/src/libparsec/include/keycodes.h b/src/libparsec/include/keycodes.h new file mode 100644 index 0000000..40442a4 --- /dev/null +++ b/src/libparsec/include/keycodes.h @@ -0,0 +1,28 @@ +/* + * PARSEC HEADER: keycodes.h + */ + +#ifndef _KEYCODES_H_ +#define _KEYCODES_H_ + + +//NOTE: +// this header is now just a wrapper for the +// file corresponding to the actual system + +//NOTE: +// only on the mac the actual keycodes are adapted to the system. +// all other systems (e.g., Linux, IRIX) map native key codes to +// parsec key codes in their keyboard handlers. that is, from +// there on, the same key codes as on a pc are used. + +#ifdef PARSEC_SERVER +#include "keys_server.h" +#else +#include "keys_sdl.h" +#endif + + +#endif // _KEYCODES_H_ + + diff --git a/src/libparsec/include/keys_sdl.h b/src/libparsec/include/keys_sdl.h new file mode 100755 index 0000000..399db1f --- /dev/null +++ b/src/libparsec/include/keys_sdl.h @@ -0,0 +1,449 @@ +/* + * keys_sdl.h + * + * Created on: Nov 3, 2012 + * Author: jasonw + */ + +#ifndef KEYS_SDL_H_ +#define KEYS_SDL_H_ + +#ifdef SYSTEM_TARGET_LINUX +#include <SDL/SDL.h> +#else +#include <SDL.h> +#endif + +// ---------------------------------------------------------------------------- +// SDL KEYBOARD KEYS - +// ---------------------------------------------------------------------------- + + + +// make codes for general keyboard handling ----------------------------------- +// +enum { + + MKC_MAKE_CODE = 0x00, +#if !SDL_VERSION_ATLEAST(2,0,0) + MKC_BREAK_CODE = SDLK_BREAK, +#endif + MKC_BASE_MASK = 0x00, + + MKC_EXT_MDIFR = 0x00, + MKC_PAUSE_MDIFR = SDLK_PAUSE, + + MKC_EXT_FLAG = 0x00, + MKC_SHIFT_FLAG = 0x10000, + + MKC_NIL = 0x00, + + MKC_ESCAPE = SDLK_ESCAPE, + MKC_SPACE = SDLK_SPACE, + MKC_ENTER = SDLK_RETURN, + MKC_CURSORUP = SDLK_UP, + MKC_CURSORDOWN = SDLK_DOWN, + MKC_CURSORLEFT = SDLK_LEFT, + MKC_CURSORRIGHT = SDLK_RIGHT, + MKC_BACKSPACE = SDLK_BACKSPACE, + MKC_INSERT = SDLK_INSERT, + MKC_DELETE = SDLK_DELETE, + MKC_HOME = SDLK_HOME, + MKC_END = SDLK_END, + MKC_PAGEUP = SDLK_PAGEUP, + MKC_PAGEDOWN = SDLK_PAGEDOWN, + MKC_CAPSLOCK = SDLK_CAPSLOCK, + MKC_TILDE = SDLK_BACKQUOTE, // U.S.: `~ german: ^ø + + MKC_MINUS = SDLK_MINUS, // U.S.: -_ german: á?bsl + MKC_EQUALS = SDLK_EQUALS, // U.S.: =+ german: ï` + MKC_TAB = SDLK_TAB, + MKC_LBRACKET = SDLK_LEFTBRACKET, // U.S.: [{ german: �š + MKC_RBRACKET = SDLK_RIGHTBRACKET, // U.S.: ]} german: +*~ + MKC_SEMICOLON = SDLK_SEMICOLON, // U.S.: ;: german: �™ + MKC_APOSTROPHE = SDLK_QUOTE, // U.S.: '" german: „Ž + MKC_GRAVE = SDLK_BACKQUOTE, // U.S.: `~ german: ^ø + + MKC_LSHIFT = SDLK_LSHIFT, + MKC_RSHIFT = SDLK_RSHIFT, + MKC_LCONTROL = SDLK_LCTRL, + MKC_RCONTROL = SDLK_RCTRL, + MKC_LALT = SDLK_LALT, + MKC_RALT = SDLK_RALT, + + MKC_COMMA = SDLK_COMMA, // U.S.: ,< german: ,; + MKC_PERIOD = SDLK_PERIOD, // U.S.: .> german: .: + MKC_SLASH = SDLK_PERIOD, // U.S.: /? german: -_ + + MKC_BACKSLASH = SDLK_BACKSLASH, // U.S.: bsl| german: #' + MKC_GERARROWS = 0x00, // german: <>| + + MKC_NUMPADSLASH = SDLK_KP_DIVIDE, // gray divide + MKC_NUMPADSTAR = SDLK_KP_MULTIPLY, // gray multiply + MKC_NUMPADMINUS = SDLK_KP_MINUS, // gray subtract + MKC_NUMPADPLUS = SDLK_KP_PLUS, // gray add + MKC_NUMPADPERIOD= SDLK_KP_PERIOD, // gray decimal (period/comma) + +#if SDL_VERSION_ATLEAST(2,0,0) + + MKC_NUMLOCK = SDLK_NUMLOCKCLEAR, + MKC_SCROLL = SDLK_SCROLLLOCK, + + MKC_NUMPAD0 = SDLK_KP_0, + MKC_NUMPAD1 = SDLK_KP_1, + MKC_NUMPAD2 = SDLK_KP_2, + MKC_NUMPAD3 = SDLK_KP_3, + MKC_NUMPAD4 = SDLK_KP_4, + MKC_NUMPAD5 = SDLK_KP_5, + MKC_NUMPAD6 = SDLK_KP_6, + MKC_NUMPAD7 = SDLK_KP_7, + MKC_NUMPAD8 = SDLK_KP_8, + MKC_NUMPAD9 = SDLK_KP_9, + + MKC_LWIN = SDLK_LGUI, // left windows/cmd key + MKC_RWIN = SDLK_RGUI, // right windows/cmd key + +#else // SDL_VERSION_ATLEAST(2,0,0) + + MKC_NUMLOCK = SDLK_NUMLOCK, + MKC_SCROLL = SDLK_SCROLLOCK, + + MKC_NUMPAD0 = SDLK_KP0, + MKC_NUMPAD1 = SDLK_KP1, + MKC_NUMPAD2 = SDLK_KP2, + MKC_NUMPAD3 = SDLK_KP3, + MKC_NUMPAD4 = SDLK_KP4, + MKC_NUMPAD5 = SDLK_KP5, + MKC_NUMPAD6 = SDLK_KP6, + MKC_NUMPAD7 = SDLK_KP7, + MKC_NUMPAD8 = SDLK_KP8, + MKC_NUMPAD9 = SDLK_KP9, + + MKC_LWIN = SDLK_LSUPER, // left windows key + MKC_RWIN = SDLK_RSUPER, // right windows key + +#endif // SDL_VERSION_ATLEAST(2,0,0) + + MKC_APPS = SDLK_MODE, // windows apps window key + + MKC_ENTER_GRAY = MKC_ENTER | MKC_EXT_FLAG, + MKC_CURSORUP_GRAY = MKC_CURSORUP | MKC_EXT_FLAG, + MKC_CURSORDOWN_GRAY = MKC_CURSORDOWN | MKC_EXT_FLAG, + MKC_CURSORLEFT_GRAY = MKC_CURSORLEFT | MKC_EXT_FLAG, + MKC_CURSORRIGHT_GRAY= MKC_CURSORRIGHT | MKC_EXT_FLAG, + MKC_BACKSPACE_GRAY = MKC_BACKSPACE | MKC_EXT_FLAG, + MKC_INSERT_GRAY = MKC_INSERT | MKC_EXT_FLAG, + MKC_DELETE_GRAY = MKC_DELETE | MKC_EXT_FLAG, + MKC_HOME_GRAY = MKC_HOME | MKC_EXT_FLAG, + MKC_END_GRAY = MKC_END | MKC_EXT_FLAG, + MKC_PAGEUP_GRAY = MKC_PAGEUP | MKC_EXT_FLAG, + MKC_PAGEDOWN_GRAY = MKC_PAGEDOWN | MKC_EXT_FLAG, + + MKC_A = SDLK_a, + MKC_B = SDLK_b, + MKC_C = SDLK_c, + MKC_D = SDLK_d, + MKC_E = SDLK_e, + MKC_F = SDLK_f, + MKC_G = SDLK_g, + MKC_H = SDLK_h, + MKC_I = SDLK_i, + MKC_J = SDLK_j, + MKC_K = SDLK_k, + MKC_L = SDLK_l, + MKC_M = SDLK_m, + MKC_N = SDLK_n, + MKC_O = SDLK_o, + MKC_P = SDLK_p, + MKC_Q = SDLK_q, + MKC_R = SDLK_r, + MKC_S = SDLK_s, + MKC_T = SDLK_t, + MKC_U = SDLK_u, + MKC_V = SDLK_v, + MKC_W = SDLK_w, + MKC_X = SDLK_x, + MKC_Y = SDLK_y, + MKC_Z = SDLK_z, + + MKC_0 = SDLK_0, + MKC_1 = SDLK_1, + MKC_2 = SDLK_2, + MKC_3 = SDLK_3, + MKC_4 = SDLK_4, + MKC_5 = SDLK_5, + MKC_6 = SDLK_6, + MKC_7 = SDLK_7, + MKC_8 = SDLK_8, + MKC_9 = SDLK_9, + + MKC_F1 = SDLK_F1, + MKC_F2 = SDLK_F2, + MKC_F3 = SDLK_F3, + MKC_F4 = SDLK_F4, + MKC_F5 = SDLK_F5, + MKC_F6 = SDLK_F6, + MKC_F7 = SDLK_F7, + MKC_F8 = SDLK_F8, + MKC_F9 = SDLK_F9, + MKC_F10 = SDLK_F10, + MKC_F11 = SDLK_F11, + MKC_F12 = SDLK_F12 +}; + + + +// key codes for console's keyboard buffer (only special codes/control keys) -- +// +enum { + + CKC_NIL = 0x000000, + CKC_ESCAPE = SDLK_ESCAPE, + CKC_SPACE = SDLK_SPACE, + CKC_ENTER = SDLK_RETURN, + CKC_CURSORUP = SDLK_UP, + CKC_CURSORDOWN = SDLK_DOWN, + CKC_CURSORLEFT = SDLK_LEFT, + CKC_CURSORRIGHT = SDLK_RIGHT, + CKC_BACKSPACE = SDLK_BACKSPACE, + CKC_INSERT = SDLK_INSERT, + CKC_DELETE = SDLK_DELETE, + CKC_HOME = SDLK_HOME, + CKC_END = SDLK_END, + CKC_PAGEUP = SDLK_PAGEUP, + CKC_PAGEDOWN = SDLK_PAGEDOWN, + CKC_TAB = SDLK_TAB, + CKC_CURSORUP_SHIFTED = SDLK_UP, + CKC_CURSORDOWN_SHIFTED = SDLK_DOWN, + CKC_CURSORLEFT_SHIFTED = SDLK_LEFT, + CKC_CURSORRIGHT_SHIFTED = SDLK_RIGHT, + + CKC_CTRL_MASK = 0x800000 +}; + + + +// key codes for flexible keyboard configuration (assignable keys) ------------ +// +enum { + + AKC_EXT_FLAG = 0x00000080, + AKC_JOY_FLAG = 0x10000000, // joystick buttons, no actual keyboard keys + AKC_SHIFT_FLAG = 0x00000000, + + AKC_ESCAPE = SDLK_ESCAPE, + AKC_SPACE = SDLK_SPACE, + AKC_ENTER = SDLK_RETURN, + AKC_CURSORUP = SDLK_UP, + AKC_CURSORDOWN = SDLK_DOWN, + AKC_CURSORLEFT = SDLK_LEFT, + AKC_CURSORRIGHT = SDLK_RIGHT, + AKC_BACKSPACE = SDLK_BACKSPACE, + AKC_INSERT = SDLK_INSERT, + AKC_DELETE = SDLK_DELETE, + AKC_HOME = SDLK_HOME, + AKC_END = SDLK_END, + AKC_PAGEUP = SDLK_PAGEUP, + AKC_PAGEDOWN = SDLK_PAGEDOWN, + AKC_CAPSLOCK = SDLK_CAPSLOCK, + AKC_TILDE = SDLK_BACKQUOTE, + + AKC_MINUS = SDLK_MINUS, + AKC_EQUALS = SDLK_EQUALS, + AKC_TAB = SDLK_TAB, + AKC_LBRACKET = SDLK_LEFTBRACKET, + AKC_RBRACKET = SDLK_RIGHTBRACKET, + AKC_SEMICOLON = SDLK_SEMICOLON, + AKC_APOSTROPHE = SDLK_QUOTE, + AKC_GRAVE = SDLK_BACKQUOTE, + + AKC_LSHIFT = SDLK_LSHIFT, + AKC_RSHIFT = SDLK_RSHIFT, + AKC_LCONTROL = SDLK_LCTRL, + AKC_RCONTROL = SDLK_RCTRL, + AKC_LALT = SDLK_LALT, + AKC_RALT = SDLK_RALT, + + AKC_COMMA = SDLK_COMMA, + AKC_PERIOD = SDLK_PERIOD, + AKC_SLASH = SDLK_SLASH, + + AKC_BACKSLASH = SDLK_BACKSLASH, + AKC_GERARROWS = 0X000000, + + AKC_NUMPADSLASH = SDLK_KP_DIVIDE, + AKC_NUMPADSTAR = SDLK_KP_MULTIPLY, + AKC_NUMPADMINUS = SDLK_KP_MINUS, + AKC_NUMPADPLUS = SDLK_KP_PLUS, + AKC_NUMPADPERIOD= SDLK_KP_PERIOD, + +#if SDL_VERSION_ATLEAST(2,0,0) + + AKC_NUMLOCK = SDLK_NUMLOCKCLEAR, + AKC_SCROLL = SDLK_SCROLLLOCK, + + AKC_NUMPAD0 = SDLK_KP_0, + AKC_NUMPAD1 = SDLK_KP_1, + AKC_NUMPAD2 = SDLK_KP_2, + AKC_NUMPAD3 = SDLK_KP_3, + AKC_NUMPAD4 = SDLK_KP_4, + AKC_NUMPAD5 = SDLK_KP_5, + AKC_NUMPAD6 = SDLK_KP_6, + AKC_NUMPAD7 = SDLK_KP_7, + AKC_NUMPAD8 = SDLK_KP_8, + AKC_NUMPAD9 = SDLK_KP_9, + + AKC_LWIN = SDLK_LGUI, // left windows/cmd key + AKC_RWIN = SDLK_RGUI, // right windows/cmd key + +#else // SDL_VERSION_ATLEAST(2,0,0) + + AKC_NUMLOCK = SDLK_NUMLOCK, + AKC_SCROLL = SDLK_SCROLLOCK, + + AKC_NUMPAD0 = SDLK_KP0, + AKC_NUMPAD1 = SDLK_KP1, + AKC_NUMPAD2 = SDLK_KP2, + AKC_NUMPAD3 = SDLK_KP3, + AKC_NUMPAD4 = SDLK_KP4, + AKC_NUMPAD5 = SDLK_KP5, + AKC_NUMPAD6 = SDLK_KP6, + AKC_NUMPAD7 = SDLK_KP7, + AKC_NUMPAD8 = SDLK_KP8, + AKC_NUMPAD9 = SDLK_KP9, + + AKC_LWIN = SDLK_LSUPER, + AKC_RWIN = SDLK_RSUPER, + +#endif // SDL_VERSION_ATLEAST(2,0,0) + + AKC_APPS = SDLK_MODE, + + AKC_ENTER_GRAY = AKC_ENTER | AKC_EXT_FLAG, + AKC_CURSORUP_GRAY = AKC_CURSORUP | AKC_EXT_FLAG, + AKC_CURSORDOWN_GRAY = AKC_CURSORDOWN | AKC_EXT_FLAG, + AKC_CURSORLEFT_GRAY = AKC_CURSORLEFT | AKC_EXT_FLAG, + AKC_CURSORRIGHT_GRAY= AKC_CURSORRIGHT | AKC_EXT_FLAG, + AKC_BACKSPACE_GRAY = AKC_BACKSPACE | AKC_EXT_FLAG, + AKC_INSERT_GRAY = AKC_INSERT | AKC_EXT_FLAG, + AKC_DELETE_GRAY = AKC_DELETE | AKC_EXT_FLAG, + AKC_HOME_GRAY = AKC_HOME | AKC_EXT_FLAG, + AKC_END_GRAY = AKC_END | AKC_EXT_FLAG, + AKC_PAGEUP_GRAY = AKC_PAGEUP | AKC_EXT_FLAG, + AKC_PAGEDOWN_GRAY = AKC_PAGEDOWN | AKC_EXT_FLAG, + + AKC_A = SDLK_a, + AKC_B = SDLK_b, + AKC_C = SDLK_c, + AKC_D = SDLK_d, + AKC_E = SDLK_e, + AKC_F = SDLK_f, + AKC_G = SDLK_g, + AKC_H = SDLK_h, + AKC_I = SDLK_i, + AKC_J = SDLK_j, + AKC_K = SDLK_k, + AKC_L = SDLK_l, + AKC_M = SDLK_m, + AKC_N = SDLK_n, + AKC_O = SDLK_o, + AKC_P = SDLK_p, + AKC_Q = SDLK_q, + AKC_R = SDLK_r, + AKC_S = SDLK_s, + AKC_T = SDLK_t, + AKC_U = SDLK_u, + AKC_V = SDLK_v, + AKC_W = SDLK_w, + AKC_X = SDLK_x, + AKC_Y = SDLK_y, + AKC_Z = SDLK_z, + + AKC_A_SHIFTED = AKC_A | AKC_SHIFT_FLAG, + AKC_B_SHIFTED = AKC_B | AKC_SHIFT_FLAG, + AKC_C_SHIFTED = AKC_C | AKC_SHIFT_FLAG, + AKC_D_SHIFTED = AKC_D | AKC_SHIFT_FLAG, + AKC_E_SHIFTED = AKC_E | AKC_SHIFT_FLAG, + AKC_F_SHIFTED = AKC_F | AKC_SHIFT_FLAG, + AKC_G_SHIFTED = AKC_G | AKC_SHIFT_FLAG, + AKC_H_SHIFTED = AKC_H | AKC_SHIFT_FLAG, + AKC_I_SHIFTED = AKC_I | AKC_SHIFT_FLAG, + AKC_J_SHIFTED = AKC_J | AKC_SHIFT_FLAG, + AKC_K_SHIFTED = AKC_K | AKC_SHIFT_FLAG, + AKC_L_SHIFTED = AKC_L | AKC_SHIFT_FLAG, + AKC_M_SHIFTED = AKC_M | AKC_SHIFT_FLAG, + AKC_N_SHIFTED = AKC_N | AKC_SHIFT_FLAG, + AKC_O_SHIFTED = AKC_O | AKC_SHIFT_FLAG, + AKC_P_SHIFTED = AKC_P | AKC_SHIFT_FLAG, + AKC_Q_SHIFTED = AKC_Q | AKC_SHIFT_FLAG, + AKC_R_SHIFTED = AKC_R | AKC_SHIFT_FLAG, + AKC_S_SHIFTED = AKC_S | AKC_SHIFT_FLAG, + AKC_T_SHIFTED = AKC_T | AKC_SHIFT_FLAG, + AKC_U_SHIFTED = AKC_U | AKC_SHIFT_FLAG, + AKC_V_SHIFTED = AKC_V | AKC_SHIFT_FLAG, + AKC_W_SHIFTED = AKC_W | AKC_SHIFT_FLAG, + AKC_X_SHIFTED = AKC_X | AKC_SHIFT_FLAG, + AKC_Y_SHIFTED = AKC_Y | AKC_SHIFT_FLAG, + AKC_Z_SHIFTED = AKC_Z | AKC_SHIFT_FLAG, + + AKC_0 = SDLK_0, + AKC_1 = SDLK_1, + AKC_2 = SDLK_2, + AKC_3 = SDLK_3, + AKC_4 = SDLK_4, + AKC_5 = SDLK_5, + AKC_6 = SDLK_6, + AKC_7 = SDLK_7, + AKC_8 = SDLK_8, + AKC_9 = SDLK_9, + + AKC_0_SHIFTED = SDLK_0 | MKC_SHIFT_FLAG, + AKC_1_SHIFTED = SDLK_1 | MKC_SHIFT_FLAG, + AKC_2_SHIFTED = SDLK_2 | MKC_SHIFT_FLAG, + AKC_3_SHIFTED = SDLK_3 | MKC_SHIFT_FLAG, + AKC_4_SHIFTED = SDLK_4 | MKC_SHIFT_FLAG, + AKC_5_SHIFTED = SDLK_5 | MKC_SHIFT_FLAG, + AKC_6_SHIFTED = SDLK_6 | MKC_SHIFT_FLAG, + AKC_7_SHIFTED = SDLK_7 | MKC_SHIFT_FLAG, + AKC_8_SHIFTED = SDLK_8 | MKC_SHIFT_FLAG, + AKC_9_SHIFTED = SDLK_9 | MKC_SHIFT_FLAG, + + AKC_F1 = SDLK_F1, + AKC_F2 = SDLK_F2, + AKC_F3 = SDLK_F3, + AKC_F4 = SDLK_F4, + AKC_F5 = SDLK_F5, + AKC_F6 = SDLK_F6, + AKC_F7 = SDLK_F7, + AKC_F8 = SDLK_F8, + AKC_F9 = SDLK_F9, + AKC_F10 = SDLK_F10, + AKC_F11 = SDLK_F11, + AKC_F12 = SDLK_F12, + + AKC_F1_SHIFTED = AKC_F1 | AKC_SHIFT_FLAG, + AKC_F2_SHIFTED = AKC_F2 | AKC_SHIFT_FLAG, + AKC_F3_SHIFTED = AKC_F3 | AKC_SHIFT_FLAG, + AKC_F4_SHIFTED = AKC_F4 | AKC_SHIFT_FLAG, + AKC_F5_SHIFTED = AKC_F5 | AKC_SHIFT_FLAG, + AKC_F6_SHIFTED = AKC_F6 | AKC_SHIFT_FLAG, + AKC_F7_SHIFTED = AKC_F7 | AKC_SHIFT_FLAG, + AKC_F8_SHIFTED = AKC_F8 | AKC_SHIFT_FLAG, + AKC_F9_SHIFTED = AKC_F9 | AKC_SHIFT_FLAG, + AKC_F10_SHIFTED = AKC_F10 | AKC_SHIFT_FLAG, + AKC_F11_SHIFTED = AKC_F11 | AKC_SHIFT_FLAG, + AKC_F12_SHIFTED = AKC_F12 | AKC_SHIFT_FLAG, + + // joystick buttons, no actual keyboard keys + AKC_JOY_BUTTON1 = 0x00000000 | AKC_JOY_FLAG, + AKC_JOY_BUTTON2 = 0x00000001 | AKC_JOY_FLAG, + AKC_JOY_BUTTON3 = 0x00000002 | AKC_JOY_FLAG, + AKC_JOY_BUTTON4 = 0x00000003 | AKC_JOY_FLAG, + AKC_JOY_BUTTON5 = 0x00000004 | AKC_JOY_FLAG, + AKC_JOY_BUTTON6 = 0x00000005 | AKC_JOY_FLAG, + AKC_JOY_BUTTON7 = 0x00000006 | AKC_JOY_FLAG, + AKC_JOY_BUTTON8 = 0x00000007 | AKC_JOY_FLAG +}; + + +#endif /* KEYS_SDL_H_ */ diff --git a/src/libparsec/include/keys_server.h b/src/libparsec/include/keys_server.h new file mode 100644 index 0000000..b74f033 --- /dev/null +++ b/src/libparsec/include/keys_server.h @@ -0,0 +1,392 @@ +/* + * PARSEC HEADER: keys_pc.h + */ + +#ifndef _KEYS_PC_H_ +#define _KEYS_PC_H_ + + + +// ---------------------------------------------------------------------------- +// INTEL PC KEYBOARD CODES - +// ---------------------------------------------------------------------------- + + + +// make codes for general keyboard handling ----------------------------------- +// +enum { + + MKC_MAKE_CODE = 0x00, + MKC_BREAK_CODE = 0x80, + MKC_BASE_MASK = 0x7f, + + MKC_EXT_MDIFR = 0xe0, + MKC_PAUSE_MDIFR = 0xe1, + + MKC_EXT_FLAG = 0x80, + MKC_SHIFT_FLAG = 0x80, + + MKC_NIL = 0x00, + + MKC_ESCAPE = 0x01, + MKC_SPACE = 0x39, + MKC_ENTER = 0x1c, + MKC_CURSORUP = 0x48, + MKC_CURSORDOWN = 0x50, + MKC_CURSORLEFT = 0x4b, + MKC_CURSORRIGHT = 0x4d, + MKC_BACKSPACE = 0x0e, + MKC_INSERT = 0x52, + MKC_DELETE = 0x53, + MKC_HOME = 0x47, + MKC_END = 0x4f, + MKC_PAGEUP = 0x49, + MKC_PAGEDOWN = 0x51, + MKC_CAPSLOCK = 0x3a, + MKC_TILDE = 0x29, // U.S.: `~ german: ^ø + + MKC_MINUS = 0x0c, // U.S.: -_ german: á?bsl + MKC_EQUALS = 0x0d, // U.S.: =+ german: ï` + MKC_TAB = 0x0f, + MKC_LBRACKET = 0x1a, // U.S.: [{ german: š + MKC_RBRACKET = 0x1b, // U.S.: ]} german: +*~ + MKC_SEMICOLON = 0x27, // U.S.: ;: german: ”™ + MKC_APOSTROPHE = 0x28, // U.S.: '" german: „Ž + MKC_GRAVE = 0x29, // U.S.: `~ german: ^ø + + MKC_LSHIFT = 0x2a, + MKC_RSHIFT = 0x36, + MKC_LCONTROL = 0x1d, + MKC_RCONTROL = 0x1d | MKC_EXT_FLAG, + MKC_LALT = 0x38, + MKC_RALT = 0x38 | MKC_EXT_FLAG, + + MKC_COMMA = 0x33, // U.S.: ,< german: ,; + MKC_PERIOD = 0x34, // U.S.: .> german: .: + MKC_SLASH = 0x35, // U.S.: /? german: -_ + + MKC_BACKSLASH = 0x2b, // U.S.: bsl| german: #' + MKC_GERARROWS = 0x56, // german: <>| + + MKC_NUMPADSLASH = 0x35 | MKC_EXT_FLAG, // gray divide + MKC_NUMPADSTAR = 0x37, // gray multiply + MKC_NUMPADMINUS = 0x4a, // gray subtract + MKC_NUMPADPLUS = 0x4e, // gray add + MKC_NUMPADPERIOD= MKC_DELETE, // gray decimal (period/comma) + MKC_NUMLOCK = 0x45, + MKC_SCROLL = 0x46, + + MKC_NUMPAD0 = MKC_INSERT, + MKC_NUMPAD1 = MKC_END, + MKC_NUMPAD2 = MKC_CURSORDOWN, + MKC_NUMPAD3 = MKC_PAGEDOWN, + MKC_NUMPAD4 = MKC_CURSORLEFT, + MKC_NUMPAD5 = 0x4c, + MKC_NUMPAD6 = MKC_CURSORRIGHT, + MKC_NUMPAD7 = MKC_HOME, + MKC_NUMPAD8 = MKC_CURSORUP, + MKC_NUMPAD9 = MKC_PAGEUP, + + MKC_LWIN = 0x5b | MKC_EXT_FLAG, // left windows key + MKC_RWIN = 0x5c | MKC_EXT_FLAG, // right windows key + MKC_APPS = 0x5d | MKC_EXT_FLAG, // windows apps window key + + MKC_ENTER_GRAY = MKC_ENTER | MKC_EXT_FLAG, + MKC_CURSORUP_GRAY = MKC_CURSORUP | MKC_EXT_FLAG, + MKC_CURSORDOWN_GRAY = MKC_CURSORDOWN | MKC_EXT_FLAG, + MKC_CURSORLEFT_GRAY = MKC_CURSORLEFT | MKC_EXT_FLAG, + MKC_CURSORRIGHT_GRAY= MKC_CURSORRIGHT | MKC_EXT_FLAG, + MKC_BACKSPACE_GRAY = MKC_BACKSPACE | MKC_EXT_FLAG, + MKC_INSERT_GRAY = MKC_INSERT | MKC_EXT_FLAG, + MKC_DELETE_GRAY = MKC_DELETE | MKC_EXT_FLAG, + MKC_HOME_GRAY = MKC_HOME | MKC_EXT_FLAG, + MKC_END_GRAY = MKC_END | MKC_EXT_FLAG, + MKC_PAGEUP_GRAY = MKC_PAGEUP | MKC_EXT_FLAG, + MKC_PAGEDOWN_GRAY = MKC_PAGEDOWN | MKC_EXT_FLAG, + + MKC_A = 0x1e, + MKC_B = 0x30, + MKC_C = 0x2e, + MKC_D = 0x20, + MKC_E = 0x12, + MKC_F = 0x21, + MKC_G = 0x22, + MKC_H = 0x23, + MKC_I = 0x17, + MKC_J = 0x24, + MKC_K = 0x25, + MKC_L = 0x26, + MKC_M = 0x32, + MKC_N = 0x31, + MKC_O = 0x18, + MKC_P = 0x19, + MKC_Q = 0x10, + MKC_R = 0x13, + MKC_S = 0x1f, + MKC_T = 0x14, + MKC_U = 0x16, + MKC_V = 0x2f, + MKC_W = 0x11, + MKC_X = 0x2d, + MKC_Y = 0x15, + MKC_Z = 0x2c, + + MKC_0 = 0x0b, + MKC_1 = 0x02, + MKC_2 = 0x03, + MKC_3 = 0x04, + MKC_4 = 0x05, + MKC_5 = 0x06, + MKC_6 = 0x07, + MKC_7 = 0x08, + MKC_8 = 0x09, + MKC_9 = 0x0a, + + MKC_F1 = 0x3b, + MKC_F2 = 0x3c, + MKC_F3 = 0x3d, + MKC_F4 = 0x3e, + MKC_F5 = 0x3f, + MKC_F6 = 0x40, + MKC_F7 = 0x41, + MKC_F8 = 0x42, + MKC_F9 = 0x43, + MKC_F10 = 0x44, + MKC_F11 = 0x57, + MKC_F12 = 0x58 +}; + + + +// key codes for console's keyboard buffer (only special codes/control keys) -- +// +enum { + + CKC_NIL = 0x800000, + CKC_ESCAPE = 0x800001, + CKC_SPACE = 0x000020, + CKC_ENTER = 0x800003, + CKC_CURSORUP = 0x800004, + CKC_CURSORDOWN = 0x800005, + CKC_CURSORLEFT = 0x800006, + CKC_CURSORRIGHT = 0x800007, + CKC_BACKSPACE = 0x800008, + CKC_INSERT = 0x800009, + CKC_DELETE = 0x80000A, + CKC_HOME = 0x80000B, + CKC_END = 0x80000C, + CKC_PAGEUP = 0x80000D, + CKC_PAGEDOWN = 0x80000E, + CKC_TAB = 0x80000F, + CKC_CURSORUP_SHIFTED = 0x800010, + CKC_CURSORDOWN_SHIFTED = 0x800011, + CKC_CURSORLEFT_SHIFTED = 0x800012, + CKC_CURSORRIGHT_SHIFTED = 0x800013, + + CKC_CTRL_MASK = 0x800000 +}; + + + +// key codes for flexible keyboard configuration (assignable keys) ------------ +// +enum { + + AKC_EXT_FLAG = 0x000080, + AKC_JOY_FLAG = 0x000100, // joystick buttons, no actual keyboard keys + AKC_SHIFT_FLAG = 0x010000, + + AKC_ESCAPE = 0x000001, + AKC_SPACE = 0x000039, + AKC_ENTER = 0x00001c, + AKC_CURSORUP = 0x000048, + AKC_CURSORDOWN = 0x000050, + AKC_CURSORLEFT = 0x00004b, + AKC_CURSORRIGHT = 0x00004d, + AKC_BACKSPACE = 0x00000e, + AKC_INSERT = 0x000052, + AKC_DELETE = 0x000053, + AKC_HOME = 0x000047, + AKC_END = 0x00004f, + AKC_PAGEUP = 0x000049, + AKC_PAGEDOWN = 0x000051, + AKC_CAPSLOCK = 0x00003a, + AKC_TILDE = 0x000029, + + AKC_MINUS = 0x00000c, + AKC_EQUALS = 0x00000d, + AKC_TAB = 0x00000f, + AKC_LBRACKET = 0x00001a, + AKC_RBRACKET = 0x00001b, + AKC_SEMICOLON = 0x000027, + AKC_APOSTROPHE = 0x000028, + AKC_GRAVE = 0x000029, + + AKC_LSHIFT = 0x00002a, + AKC_RSHIFT = 0x000036, + AKC_LCONTROL = 0x00001d, + AKC_RCONTROL = 0x00009d, + AKC_LALT = 0x000038 | AKC_EXT_FLAG, + AKC_RALT = 0x000038 | AKC_EXT_FLAG, + + AKC_COMMA = 0x000033, + AKC_PERIOD = 0x000034, + AKC_SLASH = 0x000035, + + AKC_BACKSLASH = 0x00002b, + AKC_GERARROWS = 0x000056, + + AKC_NUMPADSLASH = 0x000035 | AKC_EXT_FLAG, + AKC_NUMPADSTAR = 0x000037, + AKC_NUMPADMINUS = 0x00004a, + AKC_NUMPADPLUS = 0x00004e, + AKC_NUMPADPERIOD= AKC_DELETE, + AKC_NUMLOCK = 0x000045, + AKC_SCROLL = 0x000046, + + AKC_NUMPAD0 = AKC_INSERT, + AKC_NUMPAD1 = AKC_END, + AKC_NUMPAD2 = AKC_CURSORDOWN, + AKC_NUMPAD3 = AKC_PAGEDOWN, + AKC_NUMPAD4 = AKC_CURSORLEFT, + AKC_NUMPAD5 = 0x00004c, + AKC_NUMPAD6 = AKC_CURSORRIGHT, + AKC_NUMPAD7 = AKC_HOME, + AKC_NUMPAD8 = AKC_CURSORUP, + AKC_NUMPAD9 = AKC_PAGEUP, + + AKC_LWIN = 0x00005b | AKC_EXT_FLAG, + AKC_RWIN = 0x00005c | AKC_EXT_FLAG, + AKC_APPS = 0x00005d | AKC_EXT_FLAG, + + AKC_ENTER_GRAY = AKC_ENTER | AKC_EXT_FLAG, + AKC_CURSORUP_GRAY = AKC_CURSORUP | AKC_EXT_FLAG, + AKC_CURSORDOWN_GRAY = AKC_CURSORDOWN | AKC_EXT_FLAG, + AKC_CURSORLEFT_GRAY = AKC_CURSORLEFT | AKC_EXT_FLAG, + AKC_CURSORRIGHT_GRAY= AKC_CURSORRIGHT | AKC_EXT_FLAG, + AKC_BACKSPACE_GRAY = AKC_BACKSPACE | AKC_EXT_FLAG, + AKC_INSERT_GRAY = AKC_INSERT | AKC_EXT_FLAG, + AKC_DELETE_GRAY = AKC_DELETE | AKC_EXT_FLAG, + AKC_HOME_GRAY = AKC_HOME | AKC_EXT_FLAG, + AKC_END_GRAY = AKC_END | AKC_EXT_FLAG, + AKC_PAGEUP_GRAY = AKC_PAGEUP | AKC_EXT_FLAG, + AKC_PAGEDOWN_GRAY = AKC_PAGEDOWN | AKC_EXT_FLAG, + + AKC_A = 0x00001e, + AKC_B = 0x000030, + AKC_C = 0x00002e, + AKC_D = 0x000020, + AKC_E = 0x000012, + AKC_F = 0x000021, + AKC_G = 0x000022, + AKC_H = 0x000023, + AKC_I = 0x000017, + AKC_J = 0x000024, + AKC_K = 0x000025, + AKC_L = 0x000026, + AKC_M = 0x000032, + AKC_N = 0x000031, + AKC_O = 0x000018, + AKC_P = 0x000019, + AKC_Q = 0x000010, + AKC_R = 0x000013, + AKC_S = 0x00001f, + AKC_T = 0x000014, + AKC_U = 0x000016, + AKC_V = 0x00002f, + AKC_W = 0x000011, + AKC_X = 0x00002d, + AKC_Y = 0x000015, + AKC_Z = 0x00002c, + + AKC_A_SHIFTED = AKC_A | AKC_SHIFT_FLAG, + AKC_B_SHIFTED = AKC_B | AKC_SHIFT_FLAG, + AKC_C_SHIFTED = AKC_C | AKC_SHIFT_FLAG, + AKC_D_SHIFTED = AKC_D | AKC_SHIFT_FLAG, + AKC_E_SHIFTED = AKC_E | AKC_SHIFT_FLAG, + AKC_F_SHIFTED = AKC_F | AKC_SHIFT_FLAG, + AKC_G_SHIFTED = AKC_G | AKC_SHIFT_FLAG, + AKC_H_SHIFTED = AKC_H | AKC_SHIFT_FLAG, + AKC_I_SHIFTED = AKC_I | AKC_SHIFT_FLAG, + AKC_J_SHIFTED = AKC_J | AKC_SHIFT_FLAG, + AKC_K_SHIFTED = AKC_K | AKC_SHIFT_FLAG, + AKC_L_SHIFTED = AKC_L | AKC_SHIFT_FLAG, + AKC_M_SHIFTED = AKC_M | AKC_SHIFT_FLAG, + AKC_N_SHIFTED = AKC_N | AKC_SHIFT_FLAG, + AKC_O_SHIFTED = AKC_O | AKC_SHIFT_FLAG, + AKC_P_SHIFTED = AKC_P | AKC_SHIFT_FLAG, + AKC_Q_SHIFTED = AKC_Q | AKC_SHIFT_FLAG, + AKC_R_SHIFTED = AKC_R | AKC_SHIFT_FLAG, + AKC_S_SHIFTED = AKC_S | AKC_SHIFT_FLAG, + AKC_T_SHIFTED = AKC_T | AKC_SHIFT_FLAG, + AKC_U_SHIFTED = AKC_U | AKC_SHIFT_FLAG, + AKC_V_SHIFTED = AKC_V | AKC_SHIFT_FLAG, + AKC_W_SHIFTED = AKC_W | AKC_SHIFT_FLAG, + AKC_X_SHIFTED = AKC_X | AKC_SHIFT_FLAG, + AKC_Y_SHIFTED = AKC_Y | AKC_SHIFT_FLAG, + AKC_Z_SHIFTED = AKC_Z | AKC_SHIFT_FLAG, + + AKC_0 = 0x00000b, + AKC_1 = 0x000002, + AKC_2 = 0x000003, + AKC_3 = 0x000004, + AKC_4 = 0x000005, + AKC_5 = 0x000006, + AKC_6 = 0x000007, + AKC_7 = 0x000008, + AKC_8 = 0x000009, + AKC_9 = 0x00000a, + + AKC_0_SHIFTED = AKC_0 | AKC_SHIFT_FLAG, + AKC_1_SHIFTED = AKC_1 | AKC_SHIFT_FLAG, + AKC_2_SHIFTED = AKC_2 | AKC_SHIFT_FLAG, + AKC_3_SHIFTED = AKC_3 | AKC_SHIFT_FLAG, + AKC_4_SHIFTED = AKC_4 | AKC_SHIFT_FLAG, + AKC_5_SHIFTED = AKC_5 | AKC_SHIFT_FLAG, + AKC_6_SHIFTED = AKC_6 | AKC_SHIFT_FLAG, + AKC_7_SHIFTED = AKC_7 | AKC_SHIFT_FLAG, + AKC_8_SHIFTED = AKC_8 | AKC_SHIFT_FLAG, + AKC_9_SHIFTED = AKC_9 | AKC_SHIFT_FLAG, + + AKC_F1 = 0x00003b, + AKC_F2 = 0x00003c, + AKC_F3 = 0x00003d, + AKC_F4 = 0x00003e, + AKC_F5 = 0x00003f, + AKC_F6 = 0x000040, + AKC_F7 = 0x000041, + AKC_F8 = 0x000042, + AKC_F9 = 0x000043, + AKC_F10 = 0x000044, + AKC_F11 = 0x000057, + AKC_F12 = 0x000058, + + AKC_F1_SHIFTED = AKC_F1 | AKC_SHIFT_FLAG, + AKC_F2_SHIFTED = AKC_F2 | AKC_SHIFT_FLAG, + AKC_F3_SHIFTED = AKC_F3 | AKC_SHIFT_FLAG, + AKC_F4_SHIFTED = AKC_F4 | AKC_SHIFT_FLAG, + AKC_F5_SHIFTED = AKC_F5 | AKC_SHIFT_FLAG, + AKC_F6_SHIFTED = AKC_F6 | AKC_SHIFT_FLAG, + AKC_F7_SHIFTED = AKC_F7 | AKC_SHIFT_FLAG, + AKC_F8_SHIFTED = AKC_F8 | AKC_SHIFT_FLAG, + AKC_F9_SHIFTED = AKC_F9 | AKC_SHIFT_FLAG, + AKC_F10_SHIFTED = AKC_F10 | AKC_SHIFT_FLAG, + AKC_F11_SHIFTED = AKC_F11 | AKC_SHIFT_FLAG, + AKC_F12_SHIFTED = AKC_F12 | AKC_SHIFT_FLAG, + + // joystick buttons, no actual keyboard keys + AKC_JOY_BUTTON1 = 0x000000 | AKC_JOY_FLAG, + AKC_JOY_BUTTON2 = 0x000001 | AKC_JOY_FLAG, + AKC_JOY_BUTTON3 = 0x000002 | AKC_JOY_FLAG, + AKC_JOY_BUTTON4 = 0x000003 | AKC_JOY_FLAG, + AKC_JOY_BUTTON5 = 0x000004 | AKC_JOY_FLAG, + AKC_JOY_BUTTON6 = 0x000005 | AKC_JOY_FLAG, + AKC_JOY_BUTTON7 = 0x000006 | AKC_JOY_FLAG, + AKC_JOY_BUTTON8 = 0x000007 | AKC_JOY_FLAG +}; + + +#endif // _KEYS_PC_H_ + + diff --git a/src/libparsec/include/linkinfo.h b/src/libparsec/include/linkinfo.h new file mode 100644 index 0000000..205bd66 --- /dev/null +++ b/src/libparsec/include/linkinfo.h @@ -0,0 +1,33 @@ +/* + * PARSEC HEADER: linkinfo.h + */ + +#ifndef _LINKINFO_H_ +#define _LINKINFO_H_ + +// default bindings + +///* +#define BT_PROTOCOL_DEFAULT BT_PROTOCOL_GAMESERVER +//*/ + +/* +#define BT_PROTOCOL_DEFAULT BT_PROTOCOL_PEERTOPEER +*/ + + +// NULL NETWORKING subsystem linked (PROTOCOL) + +//#define NET_NULL + + +// linked PROTOCOL subsystems + +#define LINKED_PROTOCOL_PEERTOPEER +#define LINKED_PROTOCOL_GAMESERVER +//#define LINKED_PROTOCOL_DEMONULL + + +#endif // _LINKINFO_H_ + + diff --git a/src/libparsec/include/net_conf.h b/src/libparsec/include/net_conf.h new file mode 100644 index 0000000..1bdb37b --- /dev/null +++ b/src/libparsec/include/net_conf.h @@ -0,0 +1,48 @@ +/* + * PARSEC HEADER: net_conf.h + */ + +#ifndef _NET_CONF_H_ +#define _NET_CONF_H_ + +#ifdef PARSEC_SERVER + + // flags + #define INTERPOLATE_PLAYER_ACTIONS + #define SEND_KILL_MESSAGES + //#define NO_PROJECTILE_KILL_MESSAGES + //#define DONT_SEND_EXTRA_CREATES + #define ENABLE_PACKET_RECORDING + #define ENABLE_PACKET_SWAPPING + //#define ENABLE_PACKETDROP_TESTING + //#define ENCRYPT_PACKETS + + #ifdef DONT_SEND_EXTRA_CREATES + #define DSEXC(x) x + #else + #define DSEXC(x) + #endif + +#else // !PARSEC_SERVER + + // flags + #define INTERPOLATE_PLAYER_ACTIONS + #define SEND_KILL_MESSAGES + #define NO_PROJECTILE_KILL_MESSAGES + //#define DONT_SEND_EXTRA_CREATES + #define ENABLE_PACKET_RECORDING + #define ENABLE_PACKET_SWAPPING + #define ENABLE_PACKETDROP_TESTING + //#define ENCRYPT_PACKETS + + #ifdef DONT_SEND_EXTRA_CREATES + #define DSEXC(x) x + #else + #define DSEXC(x) + #endif + +#endif // !PARSEC_SERVER + +#endif // _NET_CONF_H_ + + diff --git a/src/libparsec/include/net_csdf.h b/src/libparsec/include/net_csdf.h new file mode 100644 index 0000000..b264643 --- /dev/null +++ b/src/libparsec/include/net_csdf.h @@ -0,0 +1,143 @@ +/* + * PARSEC HEADER: net_csdf.h + */ + +#ifndef _NET_CSDF_H_ +#define _NET_CSDF_H_ + + +// parsec client/server protocol version number ------------------------------- +// +#define CLSV_PROTOCOL_MAJOR 0 +#define CLSV_PROTOCOL_MINOR 20 + +#ifdef PARSEC_CLIENT + #include "net_udpdf.h" +#endif // PARSEC_CLIENT + +// client -> gameserver +//FIXME: use const char here and get rid of vars defined in sv_glob.h +#define GIVECHALLSTRING1 "givechallenge" +//#define CONNSTRING1 "connreq %d.%d n %s os %s" +#define CONNSTRING2 "c2 %02d.%02d ch %d n %s cr %d sr %d os %s" +#define RMVSTRING1 "rmvreq" +#define NAMESTRING1 "namereq %s" +#define PINGSTRING1 "p %d" +#define INFOSTRING1 "reqinfo %d" + +//FIXME: define these and use in RE_CommandInfo::code +/*#define PROT_GIVECHALLENGE_CODE 0 +#define PROT_CONNECTREQUEST_CODE 0 +#define PROT_GIVECHALLENGE_CODE 0 +#define PROT_GIVECHALLENGE_CODE 0 +#define PROT_GIVECHALLENGE_CODE 0 +*/ + +// gameserver -> client +#define RECVSTR_CHALLENGE "chall %d" +#define RECVSTR_ACCEPTED "acchost %s:%d slot %d max %d svid %d srv %s" +#define RECVSTR_SERVER_FULL "srvfull" +#define RECVSTR_REQUEST_INVALID "reqinval" +#define RECVSTR_REMOVE_OK "rmvok" +#define RECVSTR_NOT_CONNECTED "nconn" +#define RECVSTR_SERVER_INCOMP "srvincomp" +#define RECVSTR_CLIENT_BANNED "banned" +#define RECVSTR_NAME_OK "nameok" +#define RECVSTR_NAME_INVALID "nameinval" +#define RECVSTR_LINK_SERVER "linkserv %s:%d %d %d %d" +#define RECVSTR_CHALL_INVALID "challinv" +#define RECVSTR_PING_REPLY "p s %d r %d p %d/%d" +#define RECVSTR_INFO_REPLY "info s %d r %d p %d/%d v %d.%d n %s" +#define LISTSTR_ADDED_IN_SLOT "addslot %d nick %s" +#define LISTSTR_REMOVED_FROM_SLOT "rmvslot %d" +#define LISTSTR_NAME_UPDATED "updslot %d nick %s" + + +// gameserver -> masterserver +#define MASV_CHALLSTRING "c2 %02d.%02d ch %d n %s p %d/%d s %d os %s pt %d" + +// masterserver -> gameserver +#define MASV_RESPONSE_NEW_CHALL RECVSTR_CHALLENGE + +// client -> masterserver +#define MASV_LIST "list" +#define MASV_INFO "info %d" + + +// ---------------------------------------------------------------------------- +// +struct ipport_s { + + char ip[ MAX_IPADDR_LEN + 1 ]; // ip address + byte portlo; // low 8 bits of port + byte porthi; // high 8 bits of port + word _pad; +}; + + +// ---------------------------------------------------------------------------- +// +struct client_s { + + // data + int slot_free; + char client_name[ MAX_PLAYER_NAME + 1 ]; // the nickname of the player + + // methods + void Reset() + { + slot_free = TRUE; + memset( client_name, 0, ( MAX_PLAYER_NAME + 1 ) * sizeof( char ) ); + } +}; + + +// ---------------------------------------------------------------------------- +// +struct server_s { + + // data + char slot_free; + node_t node; + char server_name[ MAX_SERVER_NAME + 1 ]; // the name of the server + char server_os[ MAX_OSNAME_LEN + 1 ]; // the server's operating system + int number_of_players; // Number of clients joined at server + int max_players; // how many players the server can handle + char server_url[ MAX_CFG_LINE + 1 ]; + int xpos; // x position of server in starmap + int ypos; // y position of server in starmap + int serverid; // global universe id of server + int major_version; + int minor_version; + int ping_in_ms; // ping in ms +}; + + +// struct defining a link between 2 servers ----------------------------------- +// +struct link_s { + + // data + int serverid1; + int serverid2; + int flags; // see SERVERLINKINFO_BOTH etc. +}; + + +// struct defining a map object in the starmap -------------------------------- +// +struct mapobj_s { + + char name[ MAX_MAP_OBJ_NAME + 1 ]; + int xpos; + int ypos; + int w; + int h; + char* texname; + TextureMap* texmap; +}; + + +#endif // _NET_CSDF_H_ + + diff --git a/src/libparsec/include/net_defs.h b/src/libparsec/include/net_defs.h new file mode 100644 index 0000000..a2dbb4e --- /dev/null +++ b/src/libparsec/include/net_defs.h @@ -0,0 +1,1000 @@ +/* + * PARSEC HEADER: net_defs.h + */ + +#ifndef _NET_DEFS_H_ +#define _NET_DEFS_H_ + + +// ---------------------------------------------------------------------------- +// NETWORKING SUBSYSTEM (NET) related definitions - +// ---------------------------------------------------------------------------- + + +// possible values and masks of global NetworkGame ---------------------------- +// +#define NETWORK_GAME_OFF 0x00 +#define NETWORK_GAME_ON 0x01 +#define NETWORK_GAME_SIMULATED 0x02 + + +// game management constants (special values of global CurGameTime) ----------- +// +#define GAME_NOTSTARTEDYET -1 +#define GAME_FINISHED_TIME -2 +#define GAME_FINISHED_KILLS -3 +#define GAME_TERMINATED -4 +#define GAME_PEERTOPEER -5 + +#define GAME_RUNNING() ( CurGameTime >= 0 ) +#define GAME_OVER() ( ( CurGameTime == GAME_FINISHED_TIME ) || ( CurGameTime == GAME_FINISHED_KILLS ) ) +#define GAME_NO_SERVER() ( CurGameTime == GAME_PEERTOPEER ) + + +// identification of killer --------------------------------------------------- +// +#define KILLERID_UNKNOWN 0 // playerid of killer not known +#define KILLERID_BIAS 1 // playerid bias (additive) + +// number of allocated network slots (absolute maximum number of players) ----- +// +#define MAX_NET_ALLOC_SLOTS 16 + +// special player ids --------------------------------------------------------- +// +#define PLAYERID_SERVER 128 // packet destination is the server +#define PLAYERID_ANONYMOUS -2 // packet sender is not connected +#define PLAYERID_MASTERSERVER -3 // packet sender is masterserver +#define PLAYERID_INVALID -4 // invalid sender + +// maximum number of simultaneous network players in game-server mode --------- +// +#define MAX_NET_GMSV_PLAYERS MAX_NET_ALLOC_SLOTS + +// maximum number of simultaneous network players in peer-to-peer mode -------- +// +#define MAX_NET_UDP_PEER_PLAYERS 8 +#define MAX_NET_IPX_PEER_PLAYERS 4 + + +// current maximum number of network players, depending on active protocol ---- +// +#define MAX_NET_PROTO_PLAYERS CurMaxPlayers // declared in NET_GLOB.H + + +// node address compare results ----------------------------------------------- +// +#define NODECMP_LESSTHAN -1 +#define NODECMP_EQUAL 0 +#define NODECMP_GREATERTHAN 1 + + +// message id for connectionless datagrams ------------------------------------ +// +#define MSGID_DATAGRAM 0xFFFFFFFF + +// size of packet signature --------------------------------------------------- +// +#define PACKET_SIGNATURE_SIZE 8 + + +// maximum packet payload for ipx --------------------------------------------- +// +#define NET_IPX_DATA_LENGTH 546 + + +// maximum packet payload for udp --------------------------------------------- +// +#define NET_UDP_DATA_LENGTH 1400 + + +// current maximum packet payload --------------------------------------------- +// +#ifdef PARSEC_CLIENT + #define NET_MAX_DATA_LENGTH CurMaxDataLength +#else // !PARSEC_CLIENT + #define NET_MAX_DATA_LENGTH NET_UDP_DATA_LENGTH +#endif // !PARSEC_CLIENT + + +// max. length of internal packets -------------------------------------------- +// +#define NET_MAX_NETPACKET_INTERNAL_LEN 2 * NET_UDP_DATA_LENGTH + + +// size of statically allocated packets --------------------------------------- +// +#define NET_ALLOC_DATA_LENGTH NET_UDP_DATA_LENGTH + + +// size of remote packet stored into file (by recording it) ------------------- +// +#define RECORD_PACKET_SIZE NET_ALLOC_DATA_LENGTH + + +// maximum number of pending slot requests ------------------------------------ +// +#define MAX_SLOT_REQUESTS 8 + + +// maximum number of bytes in a remote address -------------------------------- +// (regardless of protocol; accommodates IPv6) +#define MAX_NODE_ADDRESS_BYTES 16 + + +// maximum number of specified masterservers ---------------------------------- +// +#define MAX_MASTERSERVERS 3 + + +// maximum number of servers (for serverlist and starmap) --------------------- +// +#define MAX_SERVERS 256 + + +// maximum # of links from one server ----------------------------------------- +// +#define MAX_NUM_LINKS 16 + + +// maximum # of map objects --------------------------------------------------- +// +#define MAX_MAP_OBJECTS 128 + +// max. length of map object names -------------------------------------------- +// +#define MAX_MAP_OBJ_NAME 31 + + +// various size constants ----------------------------------------------------- +// +#include "net_limits.h" + + +// encapsulate node address in portable manner -------------------------------- +// +struct node_t { + byte address[ MAX_NODE_ADDRESS_BYTES ]; +}; + + +// status of local ship that is transmitted to remote players ----------------- +// +struct ShipRemInfo { + + Xmatrx ObjPosition; // 12 * 4 = 48 + word CurDamage; // 2 + word CurShield; // 2 + fixed_t CurSpeed; // 4 + bams_t CurYaw; // 4 + bams_t CurPitch; // 4 + bams_t CurRoll; // 4 + geomv_t CurSlideHorz; // 4 + geomv_t CurSlideVert; // 4 + int NumMissls; // 4 + int NumHomMissls; // 4 + int NumMines; // 4 + int NumPartMissls; // 4 +}; + + + +// info about ship that should be created on remote host ---------------------- +// +struct ShipCreateInfo { + + dword ShipIndex; + Xmatrx ObjPosition; +}; + + +// server properties that are returned in ping packets ------------------------ +// +struct ServerInfo { + + char name[ 32 ]; + byte portlo; + byte porthi; + byte _padding[ 42 ]; +}; + +//NOTE: +// sizeof( ServerInfo ) must be <= sizeof( ShipRemInfo ) + + + +// ---------------------------------------------------------------------------- +// PEER protocol revisions: +// ---------------------------------------------------------------------------- +// +// 0.1 build 0190 NetGameData +// 0.2 build 0196 ( maxplayers set to 8 ) OldNetGameData = NetGameData from 0190 +// 0.3 build 0198 complete new packet handling ( NetPacket{External} ) +// 0.4 build 0198 CRC stored in packets + +// parsec peer-to-peer protocol version number -------------------------------- +// +#define P2P_PROTOCOL_MAJOR 0 +#define P2P_PROTOCOL_MINOR 4 + + +//NOTE: internal NetPackets are those that are used by all network/game functions +// except the ones actually sending and receiving packets over the wire + + +//NOTE: As we want to have only some fields in the structure inherited, we +// can not use standard C++ inheritance here. Instead we define the +// structures such, that they are compatible in the (shared) sections. +// The main reason for this is the variable sized remote event list + +//NOTE: if you change anything in the "shared" sections of NetPacket, be sure +// to do the same in NetPacket_GMSV and NetPacket_PEER + +// common base structure for internal ( in-memory ) packet structure ( protocol independent ) +// +struct NetPacket { + + //------------------------------------------------------------------------ + // header ( shared ) // = 128 + //------------------------------------------------------------------------ + int SendPlayerId; // 4 + dword MessageId; // 4 + + int Command; // 4 + int params[ 29 ]; // 116 + + //------------------------------------------------------------------------ + // payload ( differs ) // = 128 + //------------------------------------------------------------------------ + + byte payload_pad[ 128 ]; // 128 + + //------------------------------------------------------------------------ + // remote event list ( shared ) /// NET_MAX_DATA_LENGTH ( 1400 or 546 ) - 256 = 1144 or 290 + //------------------------------------------------------------------------ + //size_t RE_ListSize; // 4 + //dword RE_List; // 4 ( RE_Header + 2 ) + size_t test1; + dword test2; +}; + +// interal ( in-memory ) packet structure when using the gameserver protocol -- +// +struct NetPacket_GMSV { + + //------------------------------------------------------------------------ + // header ( shared ) // = 128 + //------------------------------------------------------------------------ + int SendPlayerId; // 4 + dword MessageId; // 4 + + int Command; // 4 +// int removeme_params[ 29 ]; // 116 //FIXME: not needed in GMSV protocol + + //------------------------------------------------------------------------ + // payload ( differs ) // = 128 + //------------------------------------------------------------------------ + dword ReliableMessageId; // 4 + dword AckMessageId; // 4 + dword AckReliableMessageId; // 4 + +// byte payload_pad[ 128 - 3 * sizeof( dword ) ]; // 112 //FIXME: get rid of this + + //------------------------------------------------------------------------ + // remote event list ( shared ) + //------------------------------------------------------------------------ + size_t RE_ListSize; // 4 + dword RE_List; // 4 ( RE_Header + 2 ) +}; + + +// interal ( in-memory ) packet structure when using the peer-to-peer protocol +// +struct NetPacket_PEER { + + //------------------------------------------------------------------------ + // header ( shared ) // = 128 + //------------------------------------------------------------------------ + int SendPlayerId; // 4 + dword MessageId; // 4 + + int Command; // 4 + int params[ 29 ]; // 116 + + //------------------------------------------------------------------------ + // payload ( differs ) // = 128 + //------------------------------------------------------------------------ + int DestPlayerId; // 4 + + byte Universe; // 1 + byte NumPlayers; // 1 + byte _padding1[ 2 ]; // 2 + byte PlayerKills[ MAX_NET_ALLOC_SLOTS ]; // 16 + + ShipRemInfo ShipInfo; // 76 + + int GameTime; // 4 + + byte payload_pad[ 128 - 104 ]; // 24 + + //------------------------------------------------------------------------ + // remote event list ( shared ) /// NET_MAX_DATA_LENGTH ( 1400 or 546 ) - 256 = 1144 or 290 + //------------------------------------------------------------------------ + size_t RE_ListSize; // 4 + dword RE_List; // 4 ( RE_Header + 2 ) +}; + +//NOTE: external NetPackets are those that are actually sent over the wire or +// stored in recorded demos + +// common base structure for external network packets ------------------------- +// +struct NetPacketExternal { + + // header ------------------------- + char Signature[ 1 ]; + +}; + +// external packet format for gameserver protocol ----------------------------- +// +struct NetPacketExternal_GMSV : NetPacketExternal { + + // header ------------------------- + char Signature2[ 3 ]; + word Protocol; + byte MajorVersion; + byte MinorVersion; + + dword crc32; + //FIXME: padding ????? + + // payload ------------------------ + int SendPlayerId; + + dword MessageId; + dword ReliableMessageId; + dword AckMessageId; + dword AckReliableMessageId; + + byte Command; +// signed char removeme_param1; // do we need these in gameserver protocol?? +// signed char removeme_param2; +// signed char removeme_param3; +// int removeme_param4; + + dword RE_List; +}; + + +// external DEMO packet format for gameserver protocol ------------------------ +// +typedef struct NetPacketExternal_GMSV NetPacketExternal_DEMO_GMSV; + + +// external packet format for peer-to-peer protocol --------------------------- +// +struct NetPacketExternal_PEER : NetPacketExternal { + + // header ------------------------- + char Signature2[ 3 ]; + word Protocol; + byte MajorVersion; + byte MinorVersion; + + dword crc32; + //FIXME: padding ????? + + // payload ------------------------ + dword MessageId; + + byte Command; + signed char param1; + signed char param2; + signed char param3; + int param4; + + byte Universe; + byte NumPlayers; + signed char SendPlayerId; + signed char DestPlayerId; + + byte PlayerKills[ MAX_NET_ALLOC_SLOTS ]; + + ShipRemInfo ShipInfo; + + int GameTime; + + dword RE_List; +}; + +// external DEMO packet format for peer-to-peer protocol ---------------------- +// +struct NetPacketExternal_DEMO_PEER : NetPacketExternal { + + // header ------------------------- + char Signature2[ 3 ]; + word Protocol; + byte MajorVersion; + byte MinorVersion; + + // additional header for DEMO ----- + size_t pktsize; + + dword crc32; // CRC over the whole packet + dword crc_header; // CRC over the header ( not including this field ) + + // payload ------------------------ + dword MessageId; + + byte Command; + signed char param1; + signed char param2; + signed char param3; + int param4; + + byte Universe; + byte NumPlayers; + signed char SendPlayerId; + signed char DestPlayerId; + + byte PlayerKills[ MAX_NET_ALLOC_SLOTS ]; + + ShipRemInfo ShipInfo; + + int GameTime; + + dword RE_List; +}; + +// external packet format for legacy recorded demos ( stored in demos <= 0190 ) ------- +// +struct NetPacketExternal_DEMO_PEER_0190 : NetPacketExternal { + + // header ------------------------- + char Signature2[ PACKET_SIGNATURE_SIZE - 1 ]; + + // payload ------------------------ + dword MessageId; + + byte Command; + signed char param1; + signed char param2; + signed char param3; + int param4; + + byte Universe; + byte NumPlayers; + signed char SendPlayerId; + signed char DestPlayerId; + + byte PlayerKills[ MAX_NET_IPX_PEER_PLAYERS ]; + + ShipRemInfo ShipInfo; + + int GameTime; + + dword RE_List; +}; + +//#define NETGAMEDATA_SIZE NET_MAX_DATA_LENGTH + +/* +#ifndef _NEW_NETPACKET + +// game data for network transfer --------------------------------------------- +// +struct NetGameData { + + char Signature[ PACKET_SIGNATURE_SIZE ]; + + dword MessageId; + + byte Command; + signed char param1; + signed char param2; + signed char param3; + int param4; + + byte Universe; + byte NumPlayers; + signed char SendPlayerId; + signed char DestPlayerId; + + byte PlayerKills[ MAX_NET_ALLOC_SLOTS ]; + + ShipRemInfo ShipInfo; + + int GameTime; + + dword RE_List; +}; + +// OLD game data for network transfer ----------------------------------------- +// +struct OldNetGameData { + + char Signature[ PACKET_SIGNATURE_SIZE ]; + + dword MessageId; + + byte Command; + signed char param1; + signed char param2; + signed char param3; + int param4; + + byte Universe; + byte NumPlayers; + signed char SendPlayerId; + signed char DestPlayerId; + + byte PlayerKills[ MAX_NET_IPX_PEER_PLAYERS ]; + + ShipRemInfo ShipInfo; + + int GameTime; + + dword RE_List; +}; + +#endif // !_NEW_NETPACKET +*/ + + +// maximum available space for remote event-list ------------------------------ +// +#define RE_LIST_MAXAVAIL ( NETs_RmEvList_GetMaxSize() ) +#define RE_LIST_ALLOC_SIZE ( NET_ALLOC_DATA_LENGTH + sizeof( RE_Header ) ) + + +// packet types (commands) ---------------------------------------------------- +// +#define PKTP_CONNECT 0x00 // initial request for connection (peer-to-peer only) +#define PKTP_CONNECT_REPLY 0x01 // reply to connect request (peer-to-peer only) +#define PKTP_DISCONNECT 0x02 // disconnect entirely (peer-to-peer only) +#define PKTP_SLOT_REQUEST 0x03 // slave requests slot (peer-to-peer only) +#define PKTP_SUBDUE_SLAVE 0x04 // make sure slave subjects himself (peer-to-peer only) + +#define PKTP_JOIN 0x05 // join game (connection already up) (peer-to-peer only) +#define PKTP_UNJOIN 0x06 // unjoin game (exit to entry-mode) (peer-to-peer only) +#define PKTP_GAME_STATE 0x07 // current game state update ( joined ) (peer-to-peer only) +#define PKTP_NODE_ALIVE 0x08 // prevent being kicked out ( unjoined ) (peer-to-peer only) +//#define PKTP_PING 0x09 // ping packet (peer-to-peer only) + +#define PKTP_COMMAND 0x20 // client/server command ( C <-> S ) +#define PKTP_STREAM 0x21 // client/server stream ( C <-> S ) + + +// object list identifiers ---------------------------------------------------- +// +#define SHIP_LIST 0x00 +#define LASER_LIST 0x01 +#define MISSL_LIST 0x02 +#define EXTRA_LIST 0x03 +#define CUSTM_LIST 0x04 + + +// particle object types ------------------------------------------------------ +// +#define POBJ_ENERGYFIELD 0x01 +#define POBJ_MEGASHIELD 0x02 +#define POBJ_SPREADFIRE 0x03 + + +// weapon status flags -------------------------------------------------------- +// +#define WPSTATE_OFF 0x00 +#define WPSTATE_ON 0x01 + + +// player connect/join status ------------------------------------------------- +// +#define PLAYER_INACTIVE 0x00 +#define PLAYER_CONNECTED 0x01 +#define PLAYER_JOINED 0x03 + + +// cause of return to entry-mode ---------------------------------------------- +// +#define USER_EXIT 0x00 +#define SHIP_DOWNED 0x01 + + +// remote event control blocks ------------------------------------------------ +// +enum re_events { + + RE_EMPTY, // 0x00 + RE_DELETED, // 0x01 + RE_CREATEOBJECT, // 0x02 + RE_CREATELASER, // 0x03 + RE_CREATEMISSILE, // 0x04 + RE_CREATEEXTRA, // 0x05 + RE_KILLOBJECT, // 0x06 + RE_SENDTEXT, // 0x07 + RE_PLAYERNAME, // 0x08 + RE_PARTICLEOBJECT, // 0x09 + RE_PLAYERLIST, // 0x0a + RE_CONNECTQUEUE, // 0x0b + RE_WEAPONSTATE, // 0x0c + RE_STATESYNC, // 0x0d + RE_CREATESWARM, // 0x0e + RE_CREATEEMP, // 0x0f + RE_OWNERSECTION, // 0x10 // 16 + RE_PLAYERSTATUS, // 0x11 // 17 + RE_PLAYERANDSHIPSTATUS, // 0x12 // 18 + RE_KILLSTATS, // 0x13 // 19 + RE_GAMESTATE, // 0x14 // 20 + RE_COMMANDINFO, // 0x15 // 21 + RE_CLIENTINFO, // 0x16 // 22 + RE_CREATEEXTRA2, // 0x17 // 23 + RE_IPV4SERVERINFO, // 0x18 // 24 + RE_SERVERLINKINFO, // 0x19 // 25 + RE_MAPOBJECT, // 0x1a // 26 + RE_STARGATE, // 0x1b // 27 + RE_CREATEMINE, + RE_NUMEVENTS +}; + +// used if remote event size > 255 +#define RE_BLOCKSIZE_INVALID 0x00 + +// header every block starts with +struct RE_Header { + + byte RE_Type; //1 + byte RE_BlockSize; //1 +}; //Size: 2 + +// generic object creation +struct RE_CreateObject : RE_Header { //2 + + word ObjectClass; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //48 + dword Flags; //4 +}; //Size: 60 + +// laser object creation +struct RE_CreateLaser : RE_Header { //2 + + word ObjectClass; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //48 + Vertex3 DirectionVec; //16 +}; //72 + +// missile object creation +struct RE_CreateMissile : RE_Header { //2 + + word ObjectClass; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //48 + Vertex3 DirectionVec; //16 + dword TargetHostObjId; //4 +}; //76 + +// extra object creation +struct RE_CreateExtra : RE_Header { //2 + + word ExtraIndex; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //28 +}; //36 + +// extra object creation +struct RE_CreateExtra2 : RE_Header { //2 + + word ExtraIndex; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //48 + Vector3 DriftVec; //16 + int DriftTimeout; //4 +}; //76 + +// Mine object creation +struct RE_CreateMine : RE_Header { //2 + word ExtraIndex; //2 + dword HostObjId; //4 + Xmatrx ObjPosition; //48 +}; //56 + +// object destruction +struct RE_KillObject : RE_Header { //2 + + byte ListId; //1 + byte Flags; //1 + dword HostObjId; //4 +}; //8 + +// arbitrary text +struct RE_SendText : RE_Header { //2 + + char TextStart[1]; +}; //3 - 257 + +// player name +struct RE_PlayerName : RE_Header { //2 + + char PlayerName[ MAX_PLAYER_NAME + 1 ]; //32 +}; //34 + +// particle object creation +struct RE_ParticleObject : RE_Header { //2 + + word ObjectType; //2 + Vertex3 Origin; //16 +}; //20 + +// list of all remote players +struct RE_PlayerList : RE_Header { //2 + + byte SyncValKillLimit; + byte SyncValNebulaId; + byte Status[ MAX_NET_IPX_PEER_PLAYERS ]; + node_t AddressTable[ MAX_NET_IPX_PEER_PLAYERS ]; + char NameTable[ MAX_NET_IPX_PEER_PLAYERS ][ MAX_PLAYER_NAME + 1 ]; + ShipCreateInfo ShipInfoTable[ MAX_NET_IPX_PEER_PLAYERS ]; +}; + +// list of remote players trying to connect +struct RE_ConnectQueue : RE_Header { + + short NumRequests; + node_t AddressTable[ MAX_SLOT_REQUESTS ]; + char NameTable[ MAX_SLOT_REQUESTS ][ MAX_PLAYER_NAME + 1 ]; +}; + +// weapon firing +struct RE_WeaponState : RE_Header { //2 + + byte State; //1 + byte _dummy; //1 + dword WeaponMask; //4 +// dword Specials; // would break demos + int CurEnergy; //4 + int SenderId; //4 +}; //16 + +// state synchroniziation +struct RE_StateSync : RE_Header { //2 + + byte StateKey; //1 + byte StateValue; //1 +}; //4 (was 8) + +// swarm missile creation +struct RE_CreateSwarm : RE_Header { //2 + Vertex3 Origin; //16 + dword TargetHostObjId; //4 + dword RandSeed; //4 + byte SenderId; //4 +}; //30 + +// emp creation +struct RE_CreateEmp : RE_Header { //2 + byte Upgradelevel; //1 + int SenderId; // 4 +}; //7 + +// owner section +struct RE_OwnerSection : RE_Header { //2 + + byte owner; //1 +}; //3 + +// playerstate +struct RE_PlayerStatus : RE_Header { //2 + + word player_status; //2 + signed char params[ 4 ]; //4 + int objectindex; //4 + byte senderid; //1 + refframe_t RefFrame; //4 + + // sizeof( RE_PlayerStatus ) = (2) + 2 + 4 + 4 + 4 = 17 +}; + + +#define UF_PROPERTIES 0x0001 +#define UF_SPEEDS 0x0002 +#define UF_RESYNCPOS 0x0004 +#define UF_STATUS 0x0008 +#define UF_ALL 0xFFFF + +// full ship & player state +struct RE_PlayerAndShipStatus : RE_PlayerStatus //20 +{ + Xmatrx ObjPosition; // 48 + word CurDamage; // 2 + word CurShield; // 2 + fixed_t CurSpeed; // 4 + bams_t CurYaw; // 4 + bams_t CurPitch; // 4 + bams_t CurRoll; // 4 + geomv_t CurSlideHorz; // 4 + geomv_t CurSlideVert; // 4 + int CurEnergy; // 4 + byte NumMissls; // 1 + byte NumHomMissls; // 1 + byte NumMines; // 1 + byte NumPartMissls; // 1 + byte UpdateFlags; // 1 + + // sizeof( RE_PlayerAndShipStatus ) = (17) + 85 = 102 +}; + + +// killstats +struct RE_KillStats : RE_Header { //2 + byte PlayerKills[ MAX_NET_ALLOC_SLOTS ]; //16 + // 18 +}; + +// gamestate +struct RE_GameState : RE_Header { //2 + int GameTime; //4 + // 6 +}; + +// max. length of a command --------------------------------------------------- +#define MAX_RE_COMMANDINFO_COMMAND_LEN 254 - 1 - 2 /*header*/ - 1 /*code*/ + +// command ( GMSV mode only ) +struct RE_CommandInfo : RE_Header { //2 + byte code; //1 + //char command[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + char command[1]; //? +}; //4 to 250 + +#define PACK_SERVERRATE( r ) ( (byte)(r / 100) ) +#define UNPACK_SERVERRATE( r ) ( (r) * 100 ) + +// clientinfo ( GMSV mode only ) +struct RE_ClientInfo : RE_Header { + byte client_sendfreq; // packets per sec. + byte server_sendrate; // bytes per sec. + // 4 +}; + + +// serverinfo about a IP4 server +struct RE_IPv4ServerInfo : RE_Header { + byte node[ 6 ]; + word flags; + word serverid; + int xpos; + int ypos; + + // sizeof( RE_IPv4ServerInfo ) = (2) + 6 + 2 + 2 + 4 + 4 = 20 +}; + +// serverlink info flags ------------------------------------------------------ +// +#define SERVERLINKINFO_1_TO_2 0x01 // link is 1 --> 2 +#define SERVERLINKINFO_2_TO_1 0x02 // link is 1 <-- 2 +#define SERVERLINKINFO_BOTH 0x03 // link is 1 <-> 2 + +// linkinfo between 2 servers ------------------------------------------------- +// +struct RE_ServerLinkInfo : RE_Header { + word flags; + word serverid1; + word serverid2; + + // sizeof( RE_ServerLinkInfo ) = (2) + 2 + 2 + 2 = 8 +}; + + +// map object ----------------------------------------------------------------- +// +struct RE_MapObject : RE_Header { + word map_objectid; + char name[ MAX_MAP_OBJ_NAME + 1 ]; + int xpos; + int ypos; + int w; + int h; + char texname[ MAX_TEXNAME + 1 ]; + + // sizeof( RE_MapObject ) = (2) + 2 + 32 + 4 + 4 + 4 + 4 + 32 = 84 +}; + +// stargate properties -------------------------------------------------------- +// +struct RE_Stargate : RE_Header { + word serverid; // 2 + float pos[ 3 ]; // 12 + float dir[ 3 ]; // 12 + bams_t rotspeed; // 4 + float radius; // 4 + float actdistance; // 4 + float partvel; // 4 + float modulrad1; // 4 + float modulrad2; // 4 + char flare_name [ MAX_TEXNAME + 1 ]; // 32 + char interior_name [ MAX_TEXNAME + 1 ]; // 32 + word numpartactive; // 2 + word actcyllen; // 2 + word modulspeed; // 2 + byte acttime; // 1 + byte autoactivate; // 1 + byte dormant; // 1 + byte active; // 1 + byte _mksz128[ 2 ]; // 2 + + // sizeof( RE_Stargate ) = 128 +}; + + +//NOTE: +// new remote event structures must ensure proper alignment +// after the two leading header bytes, which usually means +// using two single bytes or a word as first field. + + +// make object id unique in network game by appending local player's id ------- +// +#ifndef PARSEC_MASTER + + #ifdef PARSEC_SERVER + + inline dword CreateGlobalObjId( dword localobjid, dword dwOwner ) + { + ASSERT( ( ( dwOwner >= 0 ) && ( dwOwner < MAX_NET_ALLOC_SLOTS ) ) || ( dwOwner == PLAYERID_SERVER ) ); + return ( ( dwOwner << 16 ) | ( localobjid & 0xffff ) ); + } + + #else + + inline dword CreateGlobalObjId( dword localobjid ) + { + ASSERT( !NetConnected || ( ( LocalPlayerId >= 0 ) && ( LocalPlayerId < MAX_NET_ALLOC_SLOTS ) ) ); + return ( ( LocalPlayerId << 16 ) | ( localobjid & 0xffff ) ); + } + + #endif // PARSEC_SERVER + +#endif // PARSEC_MASTER + + +// calc host object-id for ship of remote player (ship object id is 0) -------- +// +//#define ShipHostObjId( playerid ) ( playerid << 16 ) +inline dword ShipHostObjId( dword playerid ) +{ + return ( playerid << 16 ); +} + + +// retrieve owner from HostOjbNumber ------------------------------------------ +// +inline dword GetOwnerFromHostOjbNumber( dword _HostObjNumber ) +{ + return _HostObjNumber >> 16; +} + +// determine owner of object (remote player id) ------------------------------- +// +inline dword GetObjectOwner( const GenObject *obj ) +{ + return GetOwnerFromHostOjbNumber( obj->HostObjNumber ); +} + +#ifdef PARSEC_CLIENT + + // include system-specific subsystem prototypes + #include "net_subh.h" + +#else // !PARSEC_CLIENT + + // include system-specific subsystem prototypes + #include "net_subh_sv.h" + +#endif // !PARSEC_CLIENT + + +#endif // _NET_DEFS_H_ + + diff --git a/src/libparsec/include/net_limits.h b/src/libparsec/include/net_limits.h new file mode 100644 index 0000000..503f599 --- /dev/null +++ b/src/libparsec/include/net_limits.h @@ -0,0 +1,20 @@ +/* + * PARSEC HEADER: net_limits.h + */ + +#ifndef _NET_LIMITS_H_ +#define _NET_LIMITS_H_ + +// various size constants ----------------------------------------------------- +// +#define MAX_IPADDR_LEN 15 // xxx.xxx.xxx.xxx = 15 +#define MAX_HOSTNAME_LEN 1024 +#define MAX_OSNAME_LEN 31 +#define MAX_FILENAME_LEN 255 +#define MAX_SERVER_NAME 31 +#define MAX_CFG_LINE 127 +#define IP_ADR_LENGTH 4 // four octet ip address +#define NODE_ADR_LENGTH 6 // ip address plus port number +#define MAX_STRLEN_IPADDR MAX_IPADDR_LEN + +#endif // _NET_LIMITS_H_ diff --git a/src/libparsec/include/net_pckt.h b/src/libparsec/include/net_pckt.h new file mode 100644 index 0000000..ec2efff --- /dev/null +++ b/src/libparsec/include/net_pckt.h @@ -0,0 +1,38 @@ +/* + * PARSEC HEADER: net_pckt.h + */ + +#ifndef _NET_PCKT_H_ +#define _NET_PCKT_H_ + +// net_pckt.c implements the following functions +// --------------------------------------------- + + +// external functions --------------------------------------------------------- +// + + +// protocol type -------------------------------------------------------------- +// +#define PROTOCOL_PEER2PEER 0x0100 +#define PROTOCOL_GAMESERVER 0x0200 +#define PROTOCOL_ENCRYPTED 0xF000 + +// protocol type signature ---------------------------------------------------- +// +extern const char net_game_signature[]; +extern const char net_cryp_signature[]; +extern const char net_packet_signature_gameserver[]; +extern const char net_packet_signature_peer2peer[]; + +// signature lengths ---------------------------------------------------------- +// +#define SIGNATRUE_LEN_OLD PACKET_SIGNATURE_SIZE +#define SIGNATURE_LEN_GAMESERVER 3 +#define SIGNATURE_LEN_PEER2PEER 3 + + +#endif // _NET_PCKT_H_ + + diff --git a/src/libparsec/include/net_pckt_gmsv.h b/src/libparsec/include/net_pckt_gmsv.h new file mode 100644 index 0000000..103c0b1 --- /dev/null +++ b/src/libparsec/include/net_pckt_gmsv.h @@ -0,0 +1,23 @@ +/* + * PARSEC HEADER: net_pckt_gmsv.h + */ + +#ifndef _NET_PCKT_GMSV_H_ +#define _NET_PCKT_GMSV_H_ + +// net_pckt_gmsv.c implements the following functions +// --------------------------------------------- +// size_t NETs_HandleOutPacket ( const NetPacket* int_gamepacket, NetPacketExternal* ext_gamepacket ); +// size_t NETs_HandleOutPacket_DEMO ( const NetPacket* int_gamepacket, NetPacketExternal* ext_gamepacket ); +// int NETs_HandleInPacket ( const NetPacketExternal* ext_gamepacket, const int ext_pktlen, NetPacket* int_gamepacket ) +// int NETs_HandleInPacket_DEMO ( const NetPacketExternal* ext_gamepacket, NetPacket* int_gamepacket, size_t& psize ); +// size_t NETs_NetPacketExternal_DEMO_GetSize ( const NetPacketExternal* ext_gamepacket ); +// void NETs_StdGameHeader ( byte command, NetPacket* gamepacket ); +// void NETs_WritePacketInfo ( FILE *fp, NetPacketExternal* ext_gamepacket ); + +// external functions + + +#endif // _NET_PCKT_GMSV_H_ + + diff --git a/src/libparsec/include/net_ports.h b/src/libparsec/include/net_ports.h new file mode 100644 index 0000000..7d99943 --- /dev/null +++ b/src/libparsec/include/net_ports.h @@ -0,0 +1,18 @@ +#ifndef _NET_PORTS_H_ +#define _NET_PORTS_H_ + +// port numbers --------------------------------------------------------------- +// +#define DEFAULT_MASTERSERVER_TCP_PORT 6580 +#define DEFAULT_MASTERSERVER_UDP_PORT 6580 +#define DEFAULT_PEERTOPEER_UDP_PORT 6581 +#define DEFAULT_GAMESERVER_UDP_PORT 6582 + +// /etc/services template ----------------------------------------------------- +// +// parsec-master 6580/tcp # Parsec Masterserver +// parsec-master 6580/udp # Parsec Masterserver +// parsec-peer 6581/udp # Parsec Peer-to-Peer +// parsec-game 6582/udp # Parsec Gameserver + +#endif // _NET_PORTS_H_ diff --git a/src/libparsec/include/net_stream.h b/src/libparsec/include/net_stream.h new file mode 100644 index 0000000..3b5bd3e --- /dev/null +++ b/src/libparsec/include/net_stream.h @@ -0,0 +1,148 @@ +/* + * PARSEC HEADER: net_stream.h + */ + +#ifndef _NET_STREAM_H_ +#define _NET_STREAM_H_ + +// forward decls -------------------------------------------------------------- +// +class E_REList; + +// history buffer for received message ids to filter out duplicates ----------- +// +#define MSGID_HISTORY_SIZE 64 + +// packet loss meter ---------------------------------------------------------- +// +#define PACKET_LOSS_METER_LENGTH 100 // horizontal size + +// flag to indicate that the packet does NOT include a reliable payload ------- +// +#define NO_RELIABLE 0 + +// max. # of reliable RE lists to buffer -------------------------------------- +// +#define MAX_NUM_RELIABLE_BACKLOG 256 + +// sructure of FIFO entries --------------------------------------------------- +// +struct StreamFIFOEntry_s { + E_REList* m_pREList; + refframe_t m_Timeout; + int m_nRetransmitCount; + + StreamFIFOEntry_s() : + m_pREList( NULL ) + { + Reset(); + } + + void Reset(); + void InitEntry( E_REList* pREList ); +}; + +// maintaining of message-ids ------------------------------------------------- +// +class NET_Stream { +protected: + + dword Out_MessageId; // next out message + dword Out_ReliableMessageId; // next reliable out message + + dword I_ACK_MessageId; // message I ACK from YOU + dword I_ACK_ReliableMessageId; // reliable message I ACK from YOU + + dword YOU_ACK_MessageId; // message YOU ACK from ME + dword YOU_ACK_ReliableMessageId; // reliable message YOU ACK from ME + + dword m_MessageId_ReliableWasSent; + + bool_t m_EnableReliable; + int m_nPeerID; + int m_nSenderID; + + bool_t m_bIsConnected; + + // FIXME: STATS + char packet_graph_recv[ PACKET_LOSS_METER_LENGTH ]; + char packet_graph_send[ PACKET_LOSS_METER_LENGTH ]; + + int message_id_history[ MSGID_HISTORY_SIZE ]; + + int m_nFIFO_WritePos; + int m_nFIFO_ReadPos; + StreamFIFOEntry_s m_FIFOEntries[ MAX_NUM_RELIABLE_BACKLOG ]; + + refframe_t m_ReliableRetransmit_Frames; // timeout to retransmit reliable packets ( based on RTT ( see Stevens ) ) + +protected: + int _FIFO_GetNextWritePos() { return ( m_nFIFO_WritePos + 1 ) % MAX_NUM_RELIABLE_BACKLOG; } + int _FIFO_GetNextReadPos() { return ( m_nFIFO_ReadPos + 1 ) % MAX_NUM_RELIABLE_BACKLOG; } + + // update the timeout for a specific FIFO entry + void _FIFO_UpdateTimeOut( StreamFIFOEntry_s* pEntry ); + +public: + + // default ctor + NET_Stream(); + + // set the peer ID this stream is connected to + void SetPeerID( int nPeerID ) { m_nPeerID = nPeerID; } + + // set the sender ID of this stream + void SetSenderID( int nSenderID ) { m_nSenderID = nSenderID; } + + // reset the stream to defaults + void Reset(); + + // set the stream to connected mode ( accepts non datagrams ) + void SetConnected(); + + // set whether we enable reliable for this stream + void SetEnableReliable( bool_t enable ) { m_EnableReliable = enable; } + + // check whether a reliable message was already ACK + bool_t IsReliableACK( dword dwMessage ) { return YOU_ACK_ReliableMessageId >= dwMessage; } + + // check whether a message was already ACK + bool_t IsACK( dword dwMessage ) { return YOU_ACK_MessageId >= dwMessage; } + + // return the last message id we got an ACK for + dword GetLastACKMessageId() { return YOU_ACK_MessageId; } + + // return the message# of the last packet received + dword GetLastInPacket() { return I_ACK_MessageId; } + + // check input packet for rejection and maintain ACKs correctly + int InPacket( NetPacket_GMSV* gamepacket_GMSV ); + + // fill in fields in outgoing packet + void OutPacket( NetPacket_GMSV* gamepacket_GMSV, int reliable = FALSE ); + + // check whether to filter out a duplicate packet + int FilterPacketDuplicate( int messageid ); + + // log packet loss statistics + void LogPacketLossStats( int numpackets, int packetok, int incoming ); + + // append a RE list to the FIFO + int AppendToReliableFIFO( E_REList* pREList ); + + // retrieve the next reliable RE list from FIFO to send + E_REList* GetNextReliableToSend(); + + // reset all reliable handling + void FlushReliableBuffer(); + + // return the next outgoing message id + dword GetNextOutMessageId() { return Out_MessageId; } + + friend class NET_PacketDriver; +}; + + +#endif // _NET_STREAM_H_ + + diff --git a/src/libparsec/include/net_swap.h b/src/libparsec/include/net_swap.h new file mode 100644 index 0000000..7a434b7 --- /dev/null +++ b/src/libparsec/include/net_swap.h @@ -0,0 +1,21 @@ +/* + * PARSEC HEADER: net_swap.h + */ + +#ifndef _NET_SWAP_H_ +#define _NET_SWAP_H_ + + +// external functions --------------------------------------------------------- +// +void NET_RmEvList_Swap( RE_Header* relist, int incoming ); +void SWAP_ShipRemInfo_in( ShipRemInfo *reminfo ); +void SWAP_ShipRemInfo_out( ShipRemInfo *reminfo ); + +// define low-level network byte-order swapping functions +#define NET_SWAP_16 SWAP_16 +#define NET_SWAP_32 SWAP_32 + +#endif + + diff --git a/src/libparsec/include/net_util.h b/src/libparsec/include/net_util.h new file mode 100644 index 0000000..5839192 --- /dev/null +++ b/src/libparsec/include/net_util.h @@ -0,0 +1,40 @@ +/* + * PARSEC HEADER: net_util.h + */ + +#ifndef _NET_UTIL_H_ +#define _NET_UTIL_H_ + + +// net_util.c implements the following functions +// --------------------------------------------- + + +// flag whether to include packet info writing code +#define PACKETINFO_WRITING_AVAILABLE + + +// external functions --------------------------------------------------------- +// +#ifdef PACKETINFO_WRITING_AVAILABLE + int NET_PacketInfo( const char *bstr, ... ); + void NET_RmEvList_WriteInfo( FILE* fp, RE_Header* relist ); +#endif // PACKETINFO_WRITING_AVAILABLE + +dword NET_CalcCRC( void* buf, size_t len ); +void NET_EncryptData( void* packet, size_t psize ); +void NET_DecryptData( void* packet, size_t psize ); + + +// include proper server/client specific header ------------------------------- +// +#ifdef PARSEC_CLIENT + #include "net_util_cl.h" +#else // !PARSEC_CLIENT + #include "net_util_sv.h" +#endif // !PARSEC_CLIENT + + +#endif // _NET_UTIL_H_ + + diff --git a/src/libparsec/include/net_wrap.h b/src/libparsec/include/net_wrap.h new file mode 100644 index 0000000..0861404 --- /dev/null +++ b/src/libparsec/include/net_wrap.h @@ -0,0 +1,114 @@ +/* + * PARSEC HEADER: net_wrap.h + */ + +#ifndef _NET_UNP_H_ +#define _NET_UNP_H_ + +#if defined( SYSTEM_TARGET_WINDOWS ) && ( _WIN32_WINNT >= _WIN32_WINNT_VISTA ) + #include <winsock2.h> + #include <ws2tcpip.h> + #include <io.h> +#else + #include <sys/types.h> + #include <sys/socket.h> + #include <sys/time.h> + #include <time.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <errno.h> + #include <fcntl.h> + #include <netdb.h> + #include <signal.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <sys/stat.h> + #include <sys/uio.h> + #include <unistd.h> + #include <sys/wait.h> + #include <net/if.h> + #include <sys/un.h> + #include <sys/ioctl.h> +#endif +/* +#elif defined( SYSTEM_MACOSX_UNUSED ) + #include <sys/types.h> + #include <sys/socket.h> + #include <sys/time.h> + #include <time.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <errno.h> + #include <fcntl.h> + #include <netdb.h> + #include <signal.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <sys/stat.h> + #include <sys/uio.h> + #include <unistd.h> + #include <sys/wait.h> + #include <net/if.h> + #include <sys/un.h> + #include <sys/sockio.h> + #include <sys/ioctl.h> + + #define socklen_t int +#endif +*/ + +// constants and macros used by the network code ------------------------------ +// +#define MAXLINE 4096 + +#define SA struct sockaddr + + +// windows uses closesocket, osx/linux use close +#ifdef SYSTEM_TARGET_WINDOWS +#define CLOSESOCKET closesocket +#else +#define CLOSESOCKET close +#endif + + +// define some macros to make error handling more readable -------------------- +// +#ifdef SYSTEM_TARGET_WINDOWS + #define ERRNO wsaerr + #define FETCH_ERRNO() int wsaerr = WSAGetLastError() + #define ERRNO_EWOULDBLOCK ( wsaerr == WSAEWOULDBLOCK ) + #define ERRNO_ECONNREFUSED ( wsaerr == WSAECONNREFUSED ) + #define ERRNO_ENETDOWN ( wsaerr == WSAENETDOWN ) + #define ERRNO_ECONNRESET ( wsaerr == WSAECONNRESET ) + //#define ERRNO_WSAEMSGSIZE ( wsaerr == WSAEMSGSIZE ) + + // UNP legacy stuff + #define ioctl( fd, request, arg ) ioctlsocket(fd, request, (unsigned long *) arg) + #define bzero(ptr,n) memset(ptr, 0, n) + + int inet_aton(const char *cp, struct in_addr *ap); + const char* hstrerror(int); +#if ( _WIN32_WINNT < _WIN32_WINNT_VISTA ) + const char* inet_ntop( int family, const void* addrptr, char* strptr, size_t len); +#endif +#else + #define ERRNO errno + #define FETCH_ERRNO() {} + #define ERRNO_EWOULDBLOCK ( errno == EWOULDBLOCK ) + #define ERRNO_ECONNREFUSED ( errno == ECONNREFUSED ) + #define ERRNO_ECONNRESET ( errno == ECONNRESET ) + #define ERRNO_ENETDOWN ( FALSE ) +#endif + + +#ifndef MAXHOSTNAMELEN + #define MAXHOSTNAMELEN 1024 +#endif + + +#endif // _NET_UNP_H_ + + diff --git a/src/libparsec/include/obj_clas.h b/src/libparsec/include/obj_clas.h new file mode 100644 index 0000000..735fd72 --- /dev/null +++ b/src/libparsec/include/obj_clas.h @@ -0,0 +1,20 @@ +/* + * PARSEC HEADER: obj_clas.h + */ + +#ifndef _OBJ_CLAS_H_ +#define _OBJ_CLAS_H_ + + +// external functions + +GenObject* OBJ_FetchObjectClass( const char *classname ); +dword OBJ_FetchObjectClassId( const char *classname ); +GenObject* OBJ_ReacquireObjectClass( dword *classid, const char *classname ); + +void OBJ_InitClass( dword classid ); + + +#endif // _OBJ_CLAS_H_ + + diff --git a/src/libparsec/include/obj_creg.h b/src/libparsec/include/obj_creg.h new file mode 100644 index 0000000..bada64d --- /dev/null +++ b/src/libparsec/include/obj_creg.h @@ -0,0 +1,46 @@ +/* + * PARSEC HEADER: obj_creg.h + */ + +#ifndef _OBJ_CREG_H_ +#define _OBJ_CREG_H_ + + +// maximum number of ship classes +#define MAX_SHIP_CLASSES 16 + +// maximum number of extra classes +#define MAX_EXTRA_CLASSES 64 + +// class is not a ship +#define SHIPINDEX_NO_SHIP -1 + +// class is not an extra +#define EXTRAINDEX_NO_EXTRA -1 + + +// function pointer type for class registration callback +typedef void (*classreg_fpt)( int numparams, int *params ); + + +// external variables + +extern int NumShipClasses; +extern dword ShipClasses[]; +extern int ObjClassShipIndex[]; + +extern int NumExtraClasses; +extern dword ExtraClasses[]; +extern int ObjClassExtraIndex[]; + + +// external functions + +int OBJ_RegisterClassRegistration( classreg_fpt regfunc ); +int OBJ_RegisterShipClass( dword classid ); +int OBJ_RegisterExtraClass( dword classid ); + + +#endif // _OBJ_CREG_H_ + + diff --git a/src/libparsec/include/obj_cust.h b/src/libparsec/include/obj_cust.h new file mode 100644 index 0000000..81fdf40 --- /dev/null +++ b/src/libparsec/include/obj_cust.h @@ -0,0 +1,77 @@ +/* + * PARSEC HEADER: obj_cust.h + */ + +#ifndef _OBJ_CUST_H_ +#define _OBJ_CUST_H_ + + +// maximum number of custom (additional) types -------------------------------- +// +#define MAX_NUM_CUSTOM_TYPES 64 + + +// custom type flags ---------------------------------------------------------- +// +#define CUSTOM_TYPE_DEFAULT 0x0000 +#define CUSTOM_TYPE_SUMMONABLE 0x0001 +#define CUSTOM_TYPE_NOT_PERSISTANT 0x0002 + + +// custom object notify events ------------------------------------------------ +// +enum { + + CUSTOM_NOTIFY_GENOBJECT_DELETE = 0 // GenObject will be deleted +}; + + +// structure for registration/maintenance of custom types --------------------- +// +struct custom_type_info_s { + + const char* type_name; + dword type_id; + size_t type_size; + CustomObject* type_template; + int type_flags; + + void (*callback_init)( CustomObject *base ); + + void (*callback_instant)( CustomObject *base ); + void (*callback_destroy)( CustomObject *base ); + + int (*callback_animate)( CustomObject *base ); + int (*callback_collide)( CustomObject *base ); + + void (*callback_notify)( CustomObject *base, GenObject *genobj, int event ); + int (*callback_persist)( CustomObject* base, int ToStream, void* relist ); + + dword _mksiz64[ 4 ]; +}; + + +// external functions + +dword OBJ_FetchCustomTypeId( const char *name ); +const char* OBJ_FetchCustomTypeName( dword objtypeid ); +size_t OBJ_FetchCustomTypeSize( dword objtypeid ); +CustomObject* OBJ_FetchCustomTypeTemplate( dword objtypeid ); +int OBJ_InitFromCustomTypeTemplate( CustomObject *obj, CustomObject *templ ); +void OBJ_InitCustomType( GenObject *classpo ); +dword OBJ_RegisterCustomType( custom_type_info_s *info ); +int OBJ_GetCustomTypeFlags( dword objtypeid ); +void OBJ_RegisterNotifyCustomObject( GenObject *genobj, CustomObject *customobj ); +int OBJ_UnregisterNotifyCustomObject( GenObject *genobj, CustomObject *customobj ); +void OBJ_NotifyCustomObjectsList( GenObject *genobj, int event ); + + +// external variables + +extern int num_custom_types; +extern custom_type_info_s custom_type_info[]; + + +#endif // _OBJ_CUST_H_ + + diff --git a/src/libparsec/include/obj_name.h b/src/libparsec/include/obj_name.h new file mode 100644 index 0000000..75abb01 --- /dev/null +++ b/src/libparsec/include/obj_name.h @@ -0,0 +1,53 @@ +/* + * PARSEC HEADER: obj_name.h + */ + +#ifndef _OBJ_NAME_H_ +#define _OBJ_NAME_H_ + + +// known object class names + +#define OBJCLASSNAME_SHIP_FIREBIRD "firebird" +#define OBJCLASSNAME_SHIP_BLUESPIRE "bluespire" +#define OBJCLASSNAME_SHIP_CORMORAN "cormoran" +#define OBJCLASSNAME_SHIP_STINGRAY "stingray" +#define OBJCLASSNAME_SHIP_CLAYMORE "claymore" +#define OBJCLASSNAME_SHIP_HURRICANE "hurricane" +#define OBJCLASSNAME_SHIP_NEEDLE "needle" + +#define OBJCLASSNAME_GUN_LEVEL0_A "laser_1a" +#define OBJCLASSNAME_GUN_LEVEL0_B "laser_1b" +#define OBJCLASSNAME_GUN_LEVEL1_DAZZLE "laser_2" +#define OBJCLASSNAME_GUN_LEVEL2_THIEF "laser_3" + +#define OBJCLASSNAME_MISSILE_DUMB "miss_dumb" +#define OBJCLASSNAME_MISSILE_GUIDE "miss_guide" + +#define OBJCLASSNAME_MISSILE_MINE "mine_proxy" + +#define OBJCLASSNAME_EXTRA_ENERGY "ex_energy" +#define OBJCLASSNAME_EXTRA_REPAIR "ex_repair" + +#define OBJCLASSNAME_EXTRA_GUN_HELIX "ex_helix" +#define OBJCLASSNAME_EXTRA_GUN_LIGHTNING "ex_light" +#define OBJCLASSNAME_EXTRA_GUN_PHOTON "ex_x2" +#define OBJCLASSNAME_EXTRA_GUN_UPGRADE_A "ex_laser2" +#define OBJCLASSNAME_EXTRA_GUN_UPGRADE_B "ex_laser3" + +#define OBJCLASSNAME_EXTRA_PACK_DUMB "ex_dumb" +#define OBJCLASSNAME_EXTRA_PACK_GUIDE "ex_guide" +#define OBJCLASSNAME_EXTRA_PACK_SWARM "ex_flare" +#define OBJCLASSNAME_EXTRA_PACK_MINES "ex_mine" + +#define OBJCLASSNAME_DEVICE_INVULNERABILITY "ex_invul" +#define OBJCLASSNAME_DEVICE_INVISIBILITY "ex_invis" +#define OBJCLASSNAME_DEVICE_AFTERBURNER "ex_aburn" +#define OBJCLASSNAME_DEVICE_DECOY "ex_x3" +#define OBJCLASSNAME_DEVICE_EMP_UPGRADE_1 "ex_emp" +#define OBJCLASSNAME_DEVICE_EMP_UPGRADE_2 "ex_emp2" + + +#endif // _OBJ_NAME_H_ + + diff --git a/src/libparsec/include/obj_odt.h b/src/libparsec/include/obj_odt.h new file mode 100644 index 0000000..3392b68 --- /dev/null +++ b/src/libparsec/include/obj_odt.h @@ -0,0 +1,65 @@ +/* + * PARSEC HEADER: obj_odt.h + */ + +#ifndef _OBJ_ODT_H_ +#define _OBJ_ODT_H_ + + + +// object class loading flags + +enum { + + OBJLOAD_NONE = 0x0000, // no additional info + OBJLOAD_DEFAULT = 0x8000, // use appropriate default settings + + OBJLOAD_WEDGENORMALS = 0x4001, // calculate WedgeNormals + OBJLOAD_WEDGECOLORS = 0x4002, // reserve storage for WedgeColors + OBJLOAD_WEDGETEXCOORDS = 0x4004, // store explicit WedgeTexCoords + OBJLOAD_WEDGELIGHTED = 0x4008, // reserve storage for WedgeLighted + OBJLOAD_WEDGESPECULAR = 0x4010, // reserve storage for WedgeSpecular + OBJLOAD_WEDGEFOGGED = 0x4020, // reserve storage for WedgeFogged + + OBJLOAD_WEDGE_INFO = 0x4000, // WedgeVertIndxs mandatory + + OBJLOAD_FACEANIMS = 0x0040, // FaceExtInfo and FaceAnimStates + OBJLOAD_VTXANIMS = 0x0080, // VtxAnimStates + + OBJLOAD_POLYCORNERCOLORS = 0x0100, // reserve corner colors in polys + OBJLOAD_POLYWEDGEINDEXES = 0x0200 // reserve wedge indexes in polys +}; + + +// maximum number of lods in an object + +#define MAX_OBJECT_LODS 16 + + +// additional configurable parameters for object loading + +struct odt_loading_params_s { + + int max_face_anim_states; + int max_vtx_anim_states; + geomv_t merge_normals_threshold; +}; + + +// forward declaration +struct shader_s; + + +// external functions + +int OBJ_LoadODT( dword classid, dword flags, shader_s *shader ); + + +// external variables + +extern odt_loading_params_s odt_loading_params; + + +#endif // _OBJ_ODT_H_ + + diff --git a/src/libparsec/include/obj_type.h b/src/libparsec/include/obj_type.h new file mode 100644 index 0000000..712acc9 --- /dev/null +++ b/src/libparsec/include/obj_type.h @@ -0,0 +1,24 @@ +/* + * PARSEC HEADER: obj_type.h + */ + +#ifndef _OBJ_TYPE_H_ +#define _OBJ_TYPE_H_ + + +// external variables + +extern const char* objtype_name[]; +extern dword objtype_id[]; + + +// external functions + +dword OBJ_FetchTypeIdFromName( const char *typestr ); +size_t OBJ_FetchTypeSize( dword objtypeid ); +void OBJ_InitDefaultTypeFields( GenObject *classpo ); + + +#endif // _OBJ_TYPE_H_ + + diff --git a/src/libparsec/include/objstruc.h b/src/libparsec/include/objstruc.h new file mode 100644 index 0000000..d556d0e --- /dev/null +++ b/src/libparsec/include/objstruc.h @@ -0,0 +1,47 @@ +/* + * PARSEC HEADER + * Object Structures and 3-D Datatypes V1.68 + * + * Copyright (c) Markus Hadwiger 1995-1998 + * All Rights Reserved. + */ + +#ifndef _OBJSTRUC_H_ +#define _OBJSTRUC_H_ + + +// include geometric type definitions +#include "od_geomv.h" + + +// include texture format specifications +#include "od_texdf.h" + + +// include ship weapons/specials masks +#include "od_masks.h" + + +// include transformation types +#include "od_trafo.h" + + +// include primitive types +#include "od_prim.h" + + +// include rasterization types +#include "od_rast.h" + + +// include generic object structures +#include "od_struc.h" + + +// include object type definitions +#include "od_types.h" + + +#endif // _OBJSTRUC_H_ + + diff --git a/src/libparsec/include/od_class.h b/src/libparsec/include/od_class.h new file mode 100644 index 0000000..ef5b0f3 --- /dev/null +++ b/src/libparsec/include/od_class.h @@ -0,0 +1,106 @@ +/* + * PARSEC HEADER (OBJECT) + * Class Codes V1.20 + * + * Copyright (c) Markus Hadwiger 1996-2000 + * All Rights Reserved. + */ + +#ifndef _OD_CLASS_H_ +#define _OD_CLASS_H_ + + +//NOTE: +// +// this lists the class ids of all object classes available. +// (actually: indexes into ObjClasses[] to retrieve class of certain id.) +// +// this *MUST* be consistent with the following information in other places: +// +// - list in control file (#objects); to ensure correct data<->class relation. +// - list in CON_INFO.C (ClassProperties[]); this provides textual class info. +// - version of remote player; class ids are part of some remote messages! +// + +enum enum_class_ids { + + SHIP_CLASS_1, // 0 + LASER0_CLASS_1, // 1 + LASER0_CLASS_2, // 2 + DUMB_CLASS_1, // 3 + GUIDE_CLASS_1, // 4 + SWARM_CLASS_1, // 5 + ENERGY_EXTRA_CLASS, // 6 + DUMB_PACK_CLASS, // 7 + SHIP_CLASS_2, // 8 + SHIP_CLASS_3, // 9 + GUIDE_PACK_CLASS, // 10 + HELIX_DEVICE_CLASS, // 11 + LIGHTNING_DEVICE_CLASS, // 12 + MINE_PACK_CLASS, // 13 + MINE_CLASS_1, // 14 + LASER1_CLASS_1, // 15 + LASER2_CLASS_1, // 16 + REPAIR_EXTRA_CLASS, // 17 + AFTERBURNER_DEVICE_CLASS, // 18 + SWARM_PACK_CLASS, // 19 + INVISIBILITY_CLASS, // 20 + PHOTON_DEVICE_CLASS, // 21 + DECOY_DEVICE_CLASS, // 22 + LASERUPGRADE1_CLASS, // 23 + LASERUPGRADE2_CLASS, // 24 + INVULNERABILITY_CLASS, // 25 +// EMPUPGRADE1_CLASS, // 26 +// EMPUPGRADE2_CLASS, // 27 + + NUM_ALTERABLE_CLASSES // must be last in list!! +}; + + +// indexes into OBJ_CREG::ExtraClasses[] for extras --------------------------- +// +enum { + + EXTRAINDX_ENERGY_EXTRA, // extra classindex 00: energy boost + EXTRAINDX_DUMB_PACK, // extra classindex 01: missile pack (dumb missiles) + EXTRAINDX_GUIDE_PACK, // extra classindex 02: missile pack (guided missiles) + EXTRAINDX_HELIX_DEVICE, // extra classindex 03: dazzling laser/helix cannon + EXTRAINDX_LIGHTNING_DEVICE, // extra classindex 04: thief laser/lightning device + EXTRAINDX_MINE_PACK, // extra classindex 05: mine pack (proximity mines) + EXTRAINDX_REPAIR_EXTRA, // extra classindex 06: repair damage + EXTRAINDX_AFTERBURNER_DEVICE, // extra classindex 07: afterburner + EXTRAINDX_SWARM_PACK, // extra classindex 08: missile pack (swarm missiles) + EXTRAINDX_INVISIBILITY, // extra classindex 09: invisibility (not used yet) + EXTRAINDX_PHOTON_DEVICE, // extra classindex 10: photon cannon + EXTRAINDX_DECOY_DEVICE, // extra classindex 11: decoy device + EXTRAINDX_LASERUPGRADE1, // extra classindex 12: laser upgrade 1 + EXTRAINDX_LASERUPGRADE2, // extra classindex 13: laser upgrade 2 + EXTRAINDX_INVULNERABILITY, // extra classindex 14: invulnerability + EXTRAINDX_MINE, // extra classindex 15: invulnerability + EXTRAINDX_EMPUPGRADE1, // extra classindex 16: emp upgrade 1 + EXTRAINDX_EMPUPGRADE2 // extra classindex 17: emp upgrade 2 +}; + + +// identifiers of collectable devices ----------------------------------------- +// +enum { + + UNKNOWN_DEVICE, // 0 + HELIX_DEVICE, // 1 + LIGHTNING_DEVICE, // 2 + AFTERBURNER_DEVICE, // 3 + INVISIBILITY_DEVICE, // 4 + PHOTON_DEVICE, // 5 + DECOY_DEVICE, // 6 + INVULNERABILITY_DEVICE, // 7 + LASER_UPGRADE_1_DEVICE, // 8 + LASER_UPGRADE_2_DEVICE, // 9 + EMP_UPGRADE_1_DEVICE, // 10 + EMP_UPGRADE_2_DEVICE // 11 +}; + + +#endif // _OD_CLASS_H_ + + diff --git a/src/libparsec/include/od_geomv.h b/src/libparsec/include/od_geomv.h new file mode 100644 index 0000000..9ccac5e --- /dev/null +++ b/src/libparsec/include/od_geomv.h @@ -0,0 +1,218 @@ +/* + * PARSEC HEADER (OBJECT) + * Types and Conversions for Geometry and Rasterization V1.22 + * + * Copyright (c) Markus Hadwiger 1997-1999 + * All Rights Reserved. + */ + +#ifndef _OD_GEOMV_H_ +#define _OD_GEOMV_H_ + + +//NOTE: +// basically, there are two important abstract types: +// *) GEOMV_T: for geometric calculations (view-space) +// *) RASTV_T: for rasterization calculations (screen-space) +// rastv_t should be identical to the primitive data type +// used by the underlying rasterization API. +// otherwise, time-consuming conversions will take place +// rather often. + + +// fixed and floating point types +typedef int32_t fixed_t; +typedef float psc_float_t; +typedef double hprec_t; + + +// type for binary angle measurement +typedef int32_t bams_t; + + +// fixed-point <-> floating-point conversions +#define FIXED_TO_FLOAT(x) ( (psc_float_t)( (fixed_t)(x) / 65536.0 ) ) +#define FLOAT_TO_FIXED(x) ( (fixed_t)( (hprec_t)(x) * 65536.0 ) ) + + +// define internal conversion macros +#define FIXED2FLOAT(x) ( (psc_float_t)( (fixed_t)(x) / 65536.0 ) ) +#define FLOAT2FIXED(x) ( (fixed_t)( (psc_float_t)(x) * 65536.0 ) ) +#define FIXED2INT(x) ( ( (fixed_t)(x) + 0x8000 ) >> 16 ) +#define INT2FIXED(x) ( (fixed_t)(x) << 16 ) +#define FLOAT2INT(x) ( (int)(psc_float_t)(x) ) +#define INT2FLOAT(x) ( (psc_float_t)(x) ) + + +// define coordinate conversion macros +#ifdef SCREENVERTEX_SUBPIXEL_ACCURACY + #define FLOAT2COORD(x) ( (psc_float_t)( (psc_float_t)(x) * D_Value ) ) + #define COORD2FLOAT(x) ((psc_float_t)(x)) // this doesn't account for D. +#else + #define FLOAT2COORD(x) ( (long)( (psc_float_t)(x) * D_Value ) ) + #define COORD2FLOAT(x) INT2FLOAT(x) // this doesn't account for D. +#endif + + +// pi and multiples +#define HPREC_PI ((hprec_t)3.14159265359) +#define HPREC_TWO_PI ((hprec_t)(2.0 * HPREC_PI)) +#define HPREC_HALF_PI ((hprec_t)(0.5 * HPREC_PI)) + +// some special angle values in bams +#define BAMS_DEG0 0x00000000 +#define BAMS_DEG45 0x00002000 +#define BAMS_DEG90 0x00004000 +#define BAMS_DEG180 0x00008000 +#define BAMS_DEG360 0x00010000 +#define BAMS_DEG720 0x00020000 + +// conversions between angle in degrees and angle in bams +#define DEG_TO_BAMS(x) ((bams_t)((65536.0/360.0) * (x))) +#define BAMS_TO_DEG(x) ((hprec_t)((360.0/65536.0) * (x))) + +// conversions between angle in radians and angle in bams +#define RAD_TO_BAMS(x) ((bams_t)((65536.0/HPREC_TWO_PI) * (x))) +#define BAMS_TO_RAD(x) ((hprec_t)((HPREC_TWO_PI/65536.0) * (x))) + +// conversions between angle in radians and angle in degrees +#define RAD_TO_DEG(x) ((hprec_t)((360.0/HPREC_TWO_PI) * (x))) +#define DEG_TO_RAD(x) ((hprec_t)((HPREC_TWO_PI/360.0) * (x))) + + +// access 32-bit quantity as dword +#define DW32(x) (*(dword*)&(x)) + + +// swap 32-bit quantity without intermediate temporary +#define SWAP_VALUES_32(a,b) { DW32(a)^=DW32(b); DW32(b)^=DW32(a); DW32(a)^=DW32(b); } + +// swap two geomv_t vars (works regardless of actual geomv_t) +#define SWAP_GEOMV(a,b) SWAP_VALUES_32((a),(b)) + + +// abs() macro for 32-bit quantity (only for lvalue!) +#define ABS32(x) { if ((x)<0) (x)=-(x); } + + +// abs() macros for fixed_t and float_t vars (only for lvalues!) +#define ABS_FIXED(x) ABS32(x) +#define ABS_FLOAT(x) { DW32(x)&=0x7fffffff; } + + +// comparison functions with zero for geomv_t that +// work for both fixed_t and float_t (only for lvalues!) + +// determine if geomv_t is zero +#define GEOMV_ZERO(x) (DW32(x) == 0) + +// determine if geomv_t is non-zero +#define GEOMV_NONZERO(x) (!GEOMV_ZERO(x)) + +// determine if geomv_t is negative +#define GEOMV_NEGATIVE(x) ( (DW32(x) & 0x80000000) != 0 ) +#define GEOMV_LTZERO(x) GEOMV_NEGATIVE(x) + +// determine if geomv_t is less than or equal zero +#define GEOMV_LEZERO(x) (GEOMV_ZERO(x) || GEOMV_NEGATIVE(x)) + +// determine if geomv_t is positive (in this context: non-negative) +#define GEOMV_POSITIVE(x) (!GEOMV_NEGATIVE(x)) +#define GEOMV_GEZERO(x) GEOMV_POSITIVE(x) + +// determine if geomv_t is greater than zero +#define GEOMV_GTZERO(x) (GEOMV_NONZERO(x) && GEOMV_POSITIVE(x)) + + + +// --------------------------------------------------------- +// define conversion macros depending on +// actual geomv_t and rastv_t types +// --------------------------------------------------------- + +// abs() macro for geomv_t +#define ABS_GEOMV(x) ABS_FLOAT(x) + + +// types for geometric values and rasterization values +typedef psc_float_t geomv_t; +typedef psc_float_t rastv_t; + + +// special values for geometric value type +#define GEOMV_0 ((geomv_t)0.0) +#define GEOMV_0_5 ((geomv_t)0.5) +#define GEOMV_1 ((geomv_t)1.0) +#define GEOMV_VANISHING ((geomv_t)1e-7) + + +// special values for rasterization value type +#define RASTV_0 ((rastv_t)0.0) +#define RASTV_1 ((rastv_t)1.0) +#define RASTV_VANISHING ((rastv_t)1e-7) + + +// geometric value conversion macros +#define GEOMV_TO_FIXED(x) FLOAT2FIXED (x) +#define FIXED_TO_GEOMV(x) FIXED2FLOAT (x) +#define GEOMV_TO_FLOAT(x) ((psc_float_t) (x)) +#define FLOAT_TO_GEOMV(x) ((geomv_t) (x)) +#define GEOMV_TO_COORD(x) FLOAT2COORD (x) +#define COORD_TO_GEOMV(x) COORD2FLOAT (x) +#define GEOMV_TO_INT(x) FLOAT2INT (x) +#define INT_TO_GEOMV(x) INT2FLOAT (x) +#define GEOMV_TO_RASTV(x) ((rastv_t) (x)) + + +// rasterization value conversion macros +#define RASTV_TO_FIXED(x) FLOAT2FIXED (x) +#define FIXED_TO_RASTV(x) FIXED2FLOAT (x) +#define RASTV_TO_FLOAT(x) ((psc_float_t) (x)) +#define FLOAT_TO_RASTV(x) ((rastv_t) (x)) +#define RASTV_TO_COORD(x) FLOAT2COORD (x) +#define COORD_TO_RASTV(x) COORD2FLOAT (x) +#define RASTV_TO_INT(x) FLOAT2INT (x) +#define INT_TO_RASTV(x) INT2FLOAT (x) +#define RASTV_TO_GEOMV(x) ((geomv_t) (x)) + + + +// ------------------------------------------------------ +// select type for depth values (integer or fractional) +// ------------------------------------------------------ + +#ifdef FRACTIONAL_DEPTH_VALUES + +typedef geomv_t depth_t; +#define DEPTH_TO_INTEGER(x) ((int32_t)GEOMV_TO_FIXED(x)) +#define DEPTH_TO_GEOMV(x) ((depth_t)(x)) +#define DEPTH_TO_RASTV(x) GEOMV_TO_RASTV(x) +#define DEPTH_TO_FLOAT(x) GEOMV_TO_FLOAT(x) +#define FIXED_TO_DEPTH(x) FIXED_TO_GEOMV(x) +#define FLOAT_TO_DEPTH(x) FLOAT_TO_GEOMV(x) + +#else + +typedef int32_t depth_t; +#define DEPTH_TO_INTEGER(x) ((depth_t)(x)) +#define DEPTH_TO_GEOMV(x) INT_TO_GEOMV(x) +#define DEPTH_TO_RASTV(x) INT_TO_RASTV(x) +#define DEPTH_TO_FLOAT(x) INT2FLOAT(x) +#define FIXED_TO_DEPTH(x) ((depth_t)(x)) +#define FLOAT_TO_DEPTH(x) FLOAT2FIXED(x) + +#endif + +//NOTE: +// there are TWO major differences between fractional and integer +// depth values: +// 1. trivially, integer depth values contain no fractional +// part whereas fractional depth values do. (regardless of +// whether they are of type float_t or fixed_t.) +// 2. the range of integer depth values is from 0 to 65535, +// whereas the range of fractional depth values is from 0.0 to 1.0. + + +#endif // _OD_GEOMV_H_ + + diff --git a/src/libparsec/include/od_masks.h b/src/libparsec/include/od_masks.h new file mode 100644 index 0000000..103342b --- /dev/null +++ b/src/libparsec/include/od_masks.h @@ -0,0 +1,64 @@ +/* + * PARSEC HEADER (OBJECT) + * Ship Weapons/Specials Masks V1.28 + * + * Copyright (c) Markus Hadwiger 1996-2000 + * All Rights Reserved. + */ + +#ifndef _OD_MASKS_H_ +#define _OD_MASKS_H_ + + +// masks for ShipObject::Weapons + +#define WPMASK_CANNON_LASER 0x00000001 +#define WPMASK_CANNON_HELIX 0x00000002 +#define WPMASK_CANNON_LIGHTNING 0x00000004 +#define WPMASK_CANNON_PHOTON 0x00000008 +#define WPMASK_LASER_BEAM 0x00000010 +#define WPMASK_LASER_AUX_6 0x00000020 +#define WPMASK_LASER_AUX_7 0x00000040 +#define WPMASK_LASER_AUX_8 0x00000080 +#define WPMASK_DEVICE_EMP 0x00000100 +#define WPMASK_DEVICE_AUX_2 0x00000200 +#define WPMASK_DEVICE_AUX_3 0x00000400 +#define WPMASK_DEVICE_AUX_4 0x00000800 +#define WPMASK_DEVICE_AUX_5 0x00001000 +#define WPMASK_DEVICE_AUX_6 0x00002000 +#define WPMASK_DEVICE_AUX_7 0x00004000 +#define WPMASK_DEVICE_AUX_8 0x00008000 +#define WPMASK_WEAPON_AUX_1 0x00010000 +#define WPMASK_WEAPON_AUX_2 0x00020000 +#define WPMASK_WEAPON_AUX_3 0x00040000 +#define WPMASK_WEAPON_AUX_4 0x00080000 +#define WPMASK_WEAPON_AUX_5 0x00100000 +#define WPMASK_WEAPON_AUX_6 0x00200000 +#define WPMASK_WEAPON_AUX_7 0x00400000 +#define WPMASK_WEAPON_AUX_8 0x00800000 + + +// mask aliases + +#define WPMASK_ALIAS_SPREADFIRE WPMASK_CANNON_HELIX + + +// masks for ShipObject::Specials + +#define SPMASK_INVISIBILITY 0x00000001 +#define SPMASK_INVULNERABILITY 0x00000002 +#define SPMASK_AUTOTARGETING 0x00000004 +#define SPMASK_AFTERBURNER 0x00000008 +#define SPMASK_LASER_UPGRADE_1 0x00001000 +#define SPMASK_LASER_UPGRADE_2 0x00002000 +#define SPMASK_DECOY 0x00004000 +#define SPMASK_FLARE_UPGRADE 0x00008000 +#define SPMASK_EMP_UPGRADE_1 0x00010000 +#define SPMASK_EMP_UPGRADE_2 0x00020000 +#define SPMASK_CAPABILITY_AUX_7 0x00040000 +#define SPMASK_CAPABILITY_AUX_8 0x00080000 + + +#endif // _OD_MASKS_H_ + + diff --git a/src/libparsec/include/od_odt.h b/src/libparsec/include/od_odt.h new file mode 100644 index 0000000..e8e5cf1 --- /dev/null +++ b/src/libparsec/include/od_odt.h @@ -0,0 +1,359 @@ +/* + * PARSEC HEADER (OBJECT) + * ODT/ODT2 Object File Format V1.70 + * + * Copyright (c) Markus Hadwiger 1995-1999 + * All Rights Reserved. + */ + +#ifndef _OD_ODT_H_ +#define _OD_ODT_H_ + + + +//----------------------------------------------------------------------------- +// ODT1 FORMAT (ODT) - +//----------------------------------------------------------------------------- + + +// generic transformation matrix +typedef fixed_t ODT_Xmatrx[ 3 ][ 4 ]; // [0 0 0 1] (line 4) omitted! + + +// 3-D vertex coordinates +struct ODT_Vertex3 { + + fixed_t X; + fixed_t Y; + fixed_t Z; + dword Flags; // padding to 16 bytes and flags +}; + + +// 2-D point in unsigned integer coordinates (always >= 0) +struct ODT_UPoint { + + dword X; // unsigned! + dword Y; // unsigned! +}; + + +// 2-D coordinates after projection; not yet converted to screen coordinates +struct ODT_ProjPoint { + + fixed_t X; + fixed_t Y; // 8 bytes +}; + + +// 2-D point in screen coordinates (used in vertex list for the edge tracer) +struct ODT_SPoint { + + long X; // signed! + long Y; // signed! +}; + + +// types for shading of faces +enum ODT_shadingtype_t { + + ODT_no_shad, // lighting independent ambient color (no shading!) + ODT_flat_shad, // flat shading + ODT_gouraud_shad, // gouraud shading + ODT_afftex_shad, // affine texture mapping + ODT_ipol1tex_shad, // first order interpolated texture mapping (lin) + ODT_ipol2tex_shad, // second order interpolated texture mapping (quad) + ODT_persptex_shad, // perspective correct texmapping w/o interpolation + ODT_material_shad, // shade using material specification + ODT_texmat_shad // composite texture and material specification +}; + + +// defines a single object-face (size is 128 bytes) +struct ODT_Face { + + char* TexMap; // pointer to texture name + ODT_UPoint* TexEqui; // (u,v) correspondences (texture placement) + dword ColorRGB; // RGB color for direct color display + dword ColorIndx; // colorindex for palette mapped display + dword FaceNormalIndx; // index of vertex which is the surface normal + ODT_Xmatrx TexXmatrx; // matrix for texture placement + dword _mtxscratch1; // scratchpad for matrix code + ODT_Xmatrx CurTexXmatrx; // current transformation screen -> texture + dword Shading; // shading type to apply to this face + dword _padto_128; +}; + + +// defines a single object-polygon (size is 16 bytes) +struct ODT_Poly { + + dword NumVerts; // number of vertices (no surface normal!) + dword FaceIndx; // index of face this polygon belongs to + dword* VertIndxs; // list of vertexindexes comprising the polygon + dword _padto_16; +}; + + +// list of indexes of currently visible polygons ( DetermineObjVisibility() ) +struct ODT_VisPolys { + + dword NumVisPolys; // number of polygon indexes in list + dword PolyIndxs[ 1 ]; // first element of polygon index list (array) +}; + + +// node structure for bsp tree nodes (size is 16 bytes) +struct ODT_BSPNode { + + dword Polygon; // index of polygon contained in this node + dword Contained; // index of first node in the same plane (list) + dword FrontTree; // index of root-node of front-subtree + dword BackTree; // index of root-node of back-subtree +}; + + +// structure of graphical object contained in ODT file ------------------------ +// +struct ODT_GenObject { + + ODT_GenObject* NextObj; // pointers to next and previous obj in + ODT_GenObject* PrevObj; // doubly linked objectinstance list + ODT_GenObject* NextVisObj; // pointer to next obj in visible list + dword ObjectNumber; // unique number of this objectinstance + dword HostObjNumber; // number this object has on its host + dword ObjectType; // type this object belongs to + dword ObjectClass; // class this object belongs to + dword InstanceSize; // size of instance of this object class + dword NumVerts; // number of vertices w/ normals + dword NumPolyVerts; // number of vertices w/o normals + dword NumNormals; // number of face normals + ODT_Vertex3* VertexList; // list of all vertices in object space + ODT_Vertex3* X_VertexList; // vertices transformed into view space + ODT_ProjPoint* P_VertexList; // vtxs projected onto view plane + ODT_SPoint* S_VertexList; // vtxs converted to screen coordinates + dword NumPolys; // number of polygons in this object + ODT_Poly* PolyList; // list of polygons in this object + dword NumFaces; // number of faces in this object + ODT_Face* FaceList; // list of all faces + ODT_VisPolys* VisPolyList; // indexes of currently visible polys + fixed_t FarthestZ; // currently farthest z of all vertices + fixed_t NearestZ; // currently nearest z of all vertices + fixed_t BoundingSphere; // radius of bounding sphere + fixed_t BoundingSphere2; // radius squared of bounding sphere + ODT_Vertex3 BoundingBox[8]; // vertices of bounding box in objectspace ??? + ODT_BSPNode* BSPTree; // pointer to root of bsp tree + ODT_Vertex3 LocalCameraLoc; // location of camera in object space + ODT_Vertex3 PyrNormals[4]; // normals of view pyramid in obj space + dword _mtxscratch1; // scratchpad for matrix code + ODT_Xmatrx ObjPosition; // location and orientation in worldsp. + dword _mtxscratch2; // scratchpad for matrix code + ODT_Xmatrx CurrentXmatrx; // current objspace -> viewspace xform + +}; + + + +//----------------------------------------------------------------------------- +// ODT2 FORMAT (OD2) - +//----------------------------------------------------------------------------- + + +// generic transformation matrix +typedef float OD2_Xmatrx[ 3 ][ 4 ]; // [0 0 0 1] (line 4) omitted! + + +// 3-D vertex coordinates +struct OD2_Vertex3 { + + float X; + float Y; + float Z; + dword Flags; // padding to 16 bytes and flags +}; + + +// types for shading of faces +enum OD2_shadingtype_t { + + OD2_shad_ambient = 0x1000, // fixed color (lighting independent ambient color) + OD2_shad_flat = 0x1001, // flat shading + OD2_shad_gouraud = 0x1002, // gouraud shading + OD2_shad_afftex = 0x2003, // affine texture mapping + OD2_shad_ipol1tex = 0x2004, // first order interpolated texture mapping (lin) + OD2_shad_ipol2tex = 0x2005, // second order interpolated texture mapping (quad) + OD2_shad_persptex = 0x2006, // perspective correct mapping without any interpolation + OD2_shad_material = 0x1007, // use material specification + OD2_shad_texmat = 0x3008, // textures modulated by material specification + + OD2_num_shadingtypes = 9, // MUST SET THIS MANUALLY!! + + OD2_shadmask_base = 0x00ff, // mask for basic shading type + OD2_shadmask_color = 0x1000, // mask to denote faces with attached color + OD2_shadmask_texmap = 0x2000 // mask to denote texture mapped faces +}; + + +// types for color specification +enum OD2_colormodel_t { + + OD2_col_none, // shading type has no associated color + OD2_col_indexed, // indexed color (color look up table index) + OD2_col_rgb, // color specified via separate R,G,B channels + OD2_col_rgba, // color specified via separate R,G,B,A channels + OD2_col_material, // use material specification + + OD2_num_colormodels +}; + + +// defines a single object-face +struct OD2_Face { + + char* TexMap; // pointer to texture name + dword ColorRGB; // RGB color for direct color display + dword ColorIndx; // colorindex for palette mapped display + dword FaceNormalIndx; // index of vertex which is the surface normal + OD2_Xmatrx TexXmatrx; // matrix for texture placement + dword Shading; // shading type to apply to this face + dword ColorModel; // type of color specification +}; + + +// defines a single object-polygon +struct OD2_Poly { + + dword NumVerts; // number of vertices (no surface normal!) + dword FaceIndx; // index of face this polygon belongs to + dword* VertIndxs; // list of vertexindexes comprising the polygon +}; + + +// 3-D plane +struct OD2_Plane { + + float X; // normal[0] + float Y; // normal[1] + float Z; // normal[2] + float D; // distance along normal +}; + + +// axial bounding box +struct OD2_CullBox { + + float mins[ 3 ]; // bounding box min-point + float maxs[ 3 ]; // bounding box max-point +}; + + +// node structure for bsp tree nodes +struct OD2_BSPNode { + + dword flags; // node/leaf/separator + + short frontpoly; // index of first front polygon + short numfront; // number of front polygons + + short backpoly; // index of first back polygon + short numback; // number of back polygons + + short fronttree; // front-subtree + short backtree; // back-subtree + + OD2_Plane plane; // separator plane + OD2_CullBox box; // tree bounding box +}; + + +// object node (part of node list attached to root or child in tree) ---------- +// +struct OD2_Node { + + dword NodeType; // node type + OD2_Node* NextNode; // next node in list + + dword flags; + dword flags2; + + dword InstanceSize; // size of instance of this object class +}; + + +// object node containing bsp tree -------------------------------------------- +// +struct OD2_Node_BSP : OD2_Node { + + dword NumVerts; // number of vertices w/ normals + dword NumPolyVerts; // number of vertices w/o normals + dword NumNormals; // number of face normals + OD2_Vertex3* VertexList; // list of all vertices in object space + + dword NumPolys; // number of polygons in this object + OD2_Poly* PolyList; // list of polygons in this object + + dword NumFaces; // number of faces in this object + OD2_Face* FaceList; // list of all faces + + OD2_BSPNode* BSPTree; // pointer to root of bsp tree + + OD2_Vertex3 BoundingCenter; // center of bounding sphere + float BoundingSphere; // radius of bounding sphere + OD2_CullBox BoundingBox; // axial bounding box +}; + + +// child (non-root) node in ODT2 object graph --------------------------------- +// +struct OD2_Child { + + dword childflags; + dword childflags2; + + OD2_Node* NodeList; // first node in attached list + OD2_Child* Children[ 2 ]; // child nodes in object graph + + ODT_Xmatrx NodeTrafo; // object-space transformation (relative) +}; + + +// ODT2 object's root node (includes file header) ----------------------------- +// +struct OD2_Root { + + char odt2[ 6 ]; // signature ("ODT2") + byte major; // major revision + byte minor; // minor revision + + dword rootflags; + dword rootflags2; + + OD2_Node* NodeList; // first node in attached list + OD2_Child* Children[ 2 ]; // child nodes in object graph + + dword ObjectType; // type this object belongs to + dword ObjectClass; // class this object belongs to + dword InstanceSize; // size of instance of this object class + + dword NumVerts; // number of vertices w/ normals + dword NumPolyVerts; // number of vertices w/o normals + dword NumNormals; // number of face normals + OD2_Vertex3* VertexList; // list of all vertices in object space + + dword NumPolys; // number of polygons in this object + OD2_Poly* PolyList; // list of polygons in this object + + dword NumFaces; // number of faces in this object + OD2_Face* FaceList; // list of all faces + + dword NumTextures; // number of textures + + OD2_Vertex3 BoundingCenter; // center of bounding sphere + float BoundingSphere; // radius of bounding sphere + OD2_CullBox BoundingBox; // axial bounding box +}; + + +#endif // _OD_ODT_H_ + + diff --git a/src/libparsec/include/od_prim.h b/src/libparsec/include/od_prim.h new file mode 100644 index 0000000..3bfbb98 --- /dev/null +++ b/src/libparsec/include/od_prim.h @@ -0,0 +1,676 @@ +/* + * PARSEC HEADER (OBJECT) + * Primitive Types V1.80 + * + * Copyright (c) Markus Hadwiger 1995-2001 + * All Rights Reserved. + */ + +#ifndef _OD_PRIM_H_ +#define _OD_PRIM_H_ + + +// homogeneous floating-point coordinates of point in 2-space ----------------- +// +struct Point2h_f { + + float X; + float Y; + float W; +}; + + +// homogeneous fixed-point coordinates of point in 2-space -------------------- +// +struct Point2h_x { + + fixed_t X; + fixed_t Y; + fixed_t W; +}; + + +// homogeneous floating-point coordinates of point in 3-space ----------------- +// +struct Point3h_f { + + float X; + float Y; + float Z; + float W; +}; + + +// homogeneous fixed-point coordinates of point in 3-space -------------------- +// +struct Point3h_x { + + fixed_t X; + fixed_t Y; + fixed_t Z; + fixed_t W; +}; + + +// general quaternion --------------------------------------------------------- +// +struct Quaternion { + + geomv_t W; // q = w + xi + yj + zk + geomv_t X; // q = ( w, (x,y,z) ) + geomv_t Y; // q = ( cos(theta/2), sin(theta/2)*(x,y,z) ) + geomv_t Z; +}; + + +// general quaternion with floating-point components -------------------------- +// +struct Quaternion_f { + + float W; // q = w + xi + yj + zk + float X; // q = ( w, (x,y,z) ) + float Y; // q = ( cos(theta/2), sin(theta/2)*(x,y,z) ) + float Z; +}; + + +// 2-D texture coordinates ---------------------------------------------------- +// +struct TexCoord2 { + + geomv_t U; + geomv_t V; +}; + + +// 3-D vertex coordinates (used by object structures) ------------------------- +// +struct Vertex3 { + + geomv_t X; + geomv_t Y; + geomv_t Z; + dword VisibleFrame; // ==CurVisibleFrame if vertex touched this frame +}; + + +// 3-D vector ----------------------------------------------------------------- +// +typedef Vertex3 Vector3; + + +// 2-D rectangle -------------------------------------------------------------- +// +struct Rectangle2 { + + rastv_t left; + rastv_t right; + rastv_t top; + rastv_t bottom; +}; + + +// 3-D plane ------------------------------------------------------------------ +// +struct Plane3 { + + geomv_t X; // normal[0] + geomv_t Y; // normal[1] + geomv_t Z; // normal[2] + geomv_t D; // distance along normal +}; +#if 0 +#define PLANE_NORMAL(p) ((p)->D, (Vector3*)(p)) // crude type check which will give an error if it fails and a warning otherwise.. +#else +#define PLANE_NORMAL(p) ((Vector3*)(p)) +#endif +#define PLANE_OFFSET(p) ((p)->D) +#define PLANE_AXIAL(p) (DW32((p)->X)==0xf800ff00) // signaling NaN +#define PLANE_CMPAXIS(p) (DW32((p)->Y)&0x03) // select coordinate +#define PLANE_AXISCOMP(p) ((p)->Z) // single component +#define PLANE_MAKEAXIAL(p,c,i) {DW32((p)->X)=0xf800ff00; DW32((p)->Y)=(i)&0x03; (p)->Z=(c);} + + +// 3-D sphere ----------------------------------------------------------------- +// +struct Sphere3 { + + geomv_t X; // origin[0] + geomv_t Y; // origin[1] + geomv_t Z; // origin[2] + geomv_t R; // radius or radius squared, depending on application +}; + + +// 2-D bounding rectangle ----------------------------------------------------- +// +struct CullBox2 { + + geomv_t minmax[ 4 ]; // [0 1]=[minx miny] [3 4]=[maxx maxy] +}; + + +// 3-D bounding box ----------------------------------------------------------- +// +struct CullBox3 { + + geomv_t minmax[ 6 ]; // [0 1 2]=[minx miny minz] [3 4 5]=[maxx maxy maxz] +}; + + +// 3-D test points for trivial reject and accept of a bounding box ------------ +// +struct ReAcPointBox3 { + + Vector3 reject; // in negative halfspace -> trivial reject + Vector3 accept; // in positive halfspace -> trivial accept +}; + + +// same as ReAcPointsBox3 but with coordinate indexes for a CullBox3 ---------- +// +struct ReAcIndexBox3 { + + int reject[ 3 ]; // reject coordinate indexes + int accept[ 3 ]; // accept coordinate indexes +}; + + +// 3-D cull plane (plane together with corresponding reject/accept indexes) --- +// +struct CullPlane3 { + + Plane3 plane; // the indexes of reject/accept points are an + ReAcIndexBox3 reacx; // invariant property of each plane! +}; + + +// bsp node including culling info -------------------------------------------- +// +struct CullBSPNode { + + short polygons[ 2 ]; // index of first front/back polygon + short numpolys[ 2 ]; // number of front/back polygons + + Plane3 plane; // separator plane + geomv_t minmax[ 6 ]; // tree bounding box + + dword flags; // node/leaf/separator + dword visframe; // visibility status (frame in which last visible) + dword subtrees[ 2 ]; // front- and back-subtree +}; + +#define NODE_FRONTPOLYGON(n) ((n)->polygons[1]) +#define NODE_BACKPOLYGON(n) ((n)->polygons[0]) +#define NODE_FRONTNUM(n) ((n)->numpolys[1]) +#define NODE_BACKNUM(n) ((n)->numpolys[0]) +#define NODE_FRONTSUBTREE(n) ((n)->subtrees[1]) +#define NODE_BACKSUBTREE(n) ((n)->subtrees[0]) +#define NODE_LEAF(n) ((n)->flags & 0x01) +#define NODE_SEPARATOR(n) ((n)->flags & 0x02) + + +// flags for iter vertices ---------------------------------------------------- +// +enum { + + ITERVTXFLAG_NONE = 0x00000000, // default + + ITERVTXFLAG_LAYERS_BASE = 0x00000000, + ITERVTXFLAG_LAYERS_1 = 0x00000002, // ITERVTXFLAG_LAYERS_xx specifies + ITERVTXFLAG_LAYERS_2 = 0x00000003, // the number of layers (stored in + ITERVTXFLAG_LAYERS_3 = 0x00000004, // IterLayer) apart from the base + ITERVTXFLAG_LAYERS_4 = 0x00000005, // layer (IterVertex). e.g., 2 + ITERVTXFLAG_LAYERS_5 = 0x00000006, // means there is one fully used + ITERVTXFLAG_LAYERS_6 = 0x00000007, // IterLayer, 1 that there is one + ITERVTXFLAG_LAYERS_7 = 0x00000008, // half used IterLayer + ITERVTXFLAG_LAYERS_8 = 0x00000009, // lowest bit is number of + ITERVTXFLAG_LAYERS_SLM = 0x00000001, // sublayers in last IterLayer - 1 + ITERVTXFLAG_LAYERS_MASK = 0x0000000f, + + ITERVTXFLAG_RESTART = 0x00000100 // restart strip (line/triangle) +}; + + +// 2-D vertex with iterative attributes --------------------------------------- +// +struct IterVertex2 { + + rastv_t X; // screenspace x + rastv_t Y; // screenspace y + rastv_t Z; // depth-buffer value + + geomv_t W; // homogeneous component + geomv_t U; // texture u + geomv_t V; // texture v + + byte R; // red component + byte G; // green component + byte B; // blue component + byte A; // alpha component + + dword flags; // ITERVTXFLAG_xx +}; + + +// 3-D vertex with iterative attributes --------------------------------------- +// +struct IterVertex3 { + + geomv_t X; // viewspace x + geomv_t Y; // viewspace y + geomv_t Z; // viewspace z + + geomv_t W; // homogeneous component + geomv_t U; // texture u + geomv_t V; // texture v + + byte R; // red component + byte G; // green component + byte B; // blue component + byte A; // alpha component + + dword flags; // ITERVTXFLAG_xx +}; + + +// 2-D vertex overlay with additional texture coordinates --------------------- +// +struct IterLayer2 { + + geomv_t U0; // texture u (layer 0) + geomv_t V0; // texture v (layer 0) + geomv_t W0; // homogeneous component + word mode0; // + word flags0; // + + geomv_t U1; // texture u (layer 1) + geomv_t V1; // texture v (layer 1) + geomv_t W1; // homogeneous component + word mode1; // + word flags1; // +}; + + +// 3-D vertex overlay with additional texture coordinates --------------------- +// +struct IterLayer3 { + + geomv_t U0; // texture u (layer 0) + geomv_t V0; // texture v (layer 0) + geomv_t W0; // homogeneous component + word mode0; // + word flags0; // + + geomv_t U1; // texture u (layer 1) + geomv_t V1; // texture v (layer 1) + geomv_t W1; // homogeneous component + word mode1; // + word flags1; // +}; + + +// type for specification of iteration/use of vertex attributes --------------- +// +enum itertype_t { + + iter_constrgb = 0x0000, // constant [rgb] attributes + iter_constrgba = 0x0001, // constant [rgba] attributes + iter_rgb = 0x0002, // iterated (rgb) attributes + iter_rgba = 0x0003, // iterated (rgba) attributes + iter_texonly = 0x0004, // apply texture without shading + iter_texconsta = 0x0005, // modulate texture with constant [a] + iter_texconstrgb = 0x0006, // modulate texture with constant [rgb] + iter_texconstrgba = 0x0007, // modulate texture with constant [rgba] + iter_texa = 0x0008, // modulate texture with iterated (a) + iter_texrgb = 0x0009, // modulate texture with iterated (rgb) + iter_texrgba = 0x000a, // modulate texture with iterated (rgba) + iter_constrgbtexa = 0x000b, // constant [rgb] with alpha-texture + iter_constrgbatexa = 0x000c, // constant [rgba] with alpha-texture + iter_rgbtexa = 0x000d, // iterated (rgb) with alpha-texture + iter_rgbatexa = 0x000e, // iterated (rgba) with alpha-texture + iter_texblendrgba = 0x000f, // blend texture with iterated (rgba) + iter_texspeca = 0x0010, // add (a) to texture (specular) + iter_texspecrgb = 0x0011, // add (rgb) to texture (specular) + iter_texconstaspecrgb = 0x0012, // add (rgb) to faded texture + iter_texconstrgbspeca = 0x0013, // add (a) to flat-shaded texture + iter_texaspecrgb = 0x0014, // add (rgb) to texture, modulate (a) + iter_texrgbspeca = 0x0015, // add (a) to texture, modulate (rgb) + iter_base_mask = 0x00ff, + + iter_overwrite = 0x0000, // overwrite destination + iter_alphablend = 0x0100, // alpha blend with destination + iter_modulate = 0x0200, // modulate destination (multiply) + iter_specularadd = 0x0300, // add to destination (emissive/specular) + iter_premulblend = 0x0400, // blend with premultiplied alpha + iter_additiveblend = 0x0500, // additively blend with destination + iter_compose_mask = 0xff00, + iter_compose_shift = 8 +}; + + +// type for specification of desired rasterizer state ------------------------- +// +enum raststate_t { + + rast_nozcompare = 0x0000, // no depth compare + rast_zcompare = 0x0001, // do depth compare + rast_mask_zcompare = 0x0001, // don't change depth compare + + rast_nozwrite = 0x0000, // no depth-buffer write + rast_zwrite = 0x0002, // do depth-buffer write + rast_mask_zwrite = 0x0002, // don't change depth-buffer write + + rast_nozbuffer = 0x0000, // no standard depth-buffering + rast_zbuffer = 0x0003, // do standard depth-buffering + rast_mask_zbuffer = 0x0003, // don't change depth-buffering + + rast_texwrap = 0x0000, // no texture coordinate clamping + rast_texclamp = 0x0004, // do texture coordinate clamping + rast_mask_texclamp = 0x0004, // don't change coordinate clamp/wrap mode + rast_mask_texwrap = 0x0004, // don't change coordinate clamp/wrap mode + + rast_chromakeyoff = 0x0000, // no chroma key compare + rast_chromakeyon = 0x0008, // do chroma key compare + rast_mask_chromakey = 0x0008, // don't change chroma keying + + rast_mask_mipmap = 0x0010, // don't change mip-mapping + rast_mask_texfilter = 0x0020, // don't change texture filtering + + rast_default = 0x0000, // nozbuffer/texwrap/chromakeyoff + rast_nomask = 0x0000, // don't mask anything + rast_maskall = 0xffff // mask everything +}; + + +// type for specification of texture combine function ------------------------- +// +enum texcombstate_t { + + texcomb_decal = 0x0000, // decal mapping (single texture) + texcomb_trifilter = 0x0001, // trilinearly filtered mip mapping + texcomb_modulate = 0x0002, // modulate texture with another texture + texcomb_specularadd = 0x0003, // add texture to another texture + texcomb_detail = 0x0004 // blend textures of two detail levels +}; + + +// flags for iter primitives -------------------------------------------------- +// +enum { + + ITERFLAG_NONE = 0x0000, // don't touch anything (draw as is) + ITERFLAG_BACKFACES = 0x0001, // draw backfaces instead of frontfaces + ITERFLAG_ONESIDED = 0x0002, // single-sided primitive + ITERFLAG_PLANESTRIP = 0x0004, // only one plane for entire strip + ITERFLAG_VERTEXREFS = 0x0008, // vertex pointers, no embedded vertices + + ITERFLAG_Z_DIV_XYZ = 0x0010, // divide xyz by z before rasterizing + ITERFLAG_Z_DIV_UVW = 0x0020, // divide uvw by z before rasterizing + ITERFLAG_Z_TO_DEPTH = 0x0040, // create depth buffer z (lerp-depth) + ITERFLAG_W_NOT_ONE = 0x0080, // w is not one (projective mapping) + + ITERFLAG_NONDESTRUCTIVE = 0x0100, // don't alter original vertex data + + ITERFLAG_PS_DEFAULT = 0x0000, // point style: default + ITERFLAG_PS_ANTIALIASED = 0x1000, // point style: antialiased + + ITERFLAG_LS_DEFAULT = 0x0000, // line style: default + ITERFLAG_LS_ANTIALIASED = 0x1000, // line style: antialiased + ITERFLAG_LS_THICK = 0x2000, // line style: thick + ITERFLAG_LS_STIPPLED = 0x4000, // line style: stippled + ITERFLAG_LS_CLOSE_STRIP = 0x8000 // line style: line-loop +}; + + +// forward declarations +struct TextureMap; +struct texfont_s; + + +// 2-D point (point-set) with iterative vertex attributes --------------------- +// +struct IterPoint2 { + + word flags; + short NumVerts; // number of points + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + float pointsize; // size in pixels + IterVertex2 Vtxs[ 1 ]; // alloc( (size_t)&((IterPoint2*)0)->Vtxs[ n ] ) +}; + + +// 3-D point (point-set) with iterative vertex attributes --------------------- +// +struct IterPoint3 { + + word flags; + short NumVerts; // number of points + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + float pointsize; // size in pixels + IterVertex3 Vtxs[ 1 ]; // alloc( (size_t)&((IterPoint3*)0)->Vtxs[ n ] ) +}; + + +// 2-D line (line-strip) with iterative vertex attributes --------------------- +// +struct IterLine2 { + + word flags; + short NumVerts; // number of lines + 1 + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 2 ]; // alloc( (size_t)&((IterLine2*)0)->Vtxs[ n ] ) +}; + + +// 3-D line (line-strip) with iterative vertex attributes --------------------- +// +struct IterLine3 { + + word flags; + short NumVerts; // number of lines + 1 + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 2 ]; // alloc( (size_t)&((IterLine3*)0)->Vtxs[ n ] ) +}; + + +// 2-D triangle with iterative vertex attributes ------------------------------ +// +struct IterTriangle2 { + + word flags; + short NumVerts; // need not be valid (implicitly 3) + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 3 ]; +}; + + +// 3-D triangle with iterative vertex attributes ------------------------------ +// +struct IterTriangle3 { + + word flags; + short NumVerts; // need not be valid (implicitly 3) + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 3 ]; +}; + + +// 2-D rectangle with iterative vertex attributes ----------------------------- +// +struct IterRectangle2 { + + word flags; + short NumVerts; // need not be valid (implicitly 4) + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 4 ]; +}; + + +// 3-D rectangle with iterative vertex attributes ----------------------------- +// +struct IterRectangle3 { + + word flags; + short NumVerts; // need not be valid (implicitly 4) + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 4 ]; +}; + + +// 2-D polygon (n-gon) with iterative vertex attributes ----------------------- +// +struct IterPolygon2 { + + word flags; + short NumVerts; + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 1 ]; // alloc( (size_t)&((IterPolygon2*)0)->Vtxs[ n ] ) +}; + + +// 3-D polygon (n-gon) with iterative vertex attributes ----------------------- +// +struct IterPolygon3 { + + word flags; + short NumVerts; + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 1 ]; // alloc( (size_t)&((IterPolygon3*)0)->Vtxs[ n ] ) +}; + + +// 2-D triangle strip with iterative vertex attributes ------------------------ +// +struct IterTriStrip2 { + + word flags; + short NumVerts; // number of triangles + 2 + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // array; need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 1 ]; // alloc( (size_t)&((IterTriStrip2*)0)->Vtxs[ n ] ) +}; + + +// 3-D triangle strip with iterative vertex attributes ------------------------ +// +struct IterTriStrip3 { + + word flags; + short NumVerts; // number of triangles + 2 + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + Plane3* plane; // array; need only be valid if ITERFLAG_ONESIDED + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 1 ]; // alloc( (size_t)&((IterTriStrip3*)0)->Vtxs[ n ] ) +}; + + +// flags for contents of iterated arrays -------------------------------------- +// +enum { + + ITERARRAY_USE_COLOR = 0x0001, + ITERARRAY_USE_TEXTURE = 0x0002, + ITERARRAY_GLOBAL_TEXTURE = 0x0100 +}; + + +// primitive types for iterated array drawing --------------------------------- +// +enum { + + ITERARRAY_MODE_TRIANGLES = 0x0000, + ITERARRAY_MODE_TRISTRIP = 0x0001, + ITERARRAY_MODE_TRIFAN = 0x0002, + ITERARRAY_MODE_QUADS = 0x0003, + ITERARRAY_MODE_QUADSTRIP = 0x0004, + + ITERARRAY_MODE_NUM_MODES // last! +}; + + +// 2-D vertex array with iterative vertex attributes -------------------------- +// +struct IterArray2 { + + word flags; + short NumVerts; // array size + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + dword arrayinfo; // flags for array content (ITERARRAY_xx) + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex2 Vtxs[ 1 ]; // alloc( (size_t)&((IterArray2*)0)->Vtxs[ n ] ) +}; + + +// 3-D vertex array with iterative vertex attributes -------------------------- +// +struct IterArray3 { + + word flags; + short NumVerts; // array size + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + dword arrayinfo; // flags for array content (ITERARRAY_xx) + TextureMap* texmap; // need only be valid if itertype >= iter_texonly + IterVertex3 Vtxs[ 1 ]; // alloc( (size_t)&((IterArray3*)0)->Vtxs[ n ] ) +}; + + +// descriptor for rendering with a texfont ------------------------------------ +// +struct IterTexfont { + + dword flags; + dword itertype; // itertype_t + word raststate; // raststate_t (state) + word rastmask; // raststate_t (mask) + texfont_s* texfont; // texfont (contains no rendering or color info) + IterVertex2 Vtxs[ 4 ]; // output location, color, and scale factors +}; + + +#endif // _OD_PRIM_H_ + + diff --git a/src/libparsec/include/od_props.h b/src/libparsec/include/od_props.h new file mode 100644 index 0000000..c5548e4 --- /dev/null +++ b/src/libparsec/include/od_props.h @@ -0,0 +1,248 @@ +/* + * PARSEC HEADER (OBJECT) + * Default Object Properties V1.35 + * + * Copyright (c) Markus Hadwiger 1996-2000 + * All Rights Reserved. + */ + +#ifndef _OD_PROPS_H_ +#define _OD_PROPS_H_ + + +// game control data ------------------------------------------------ +// +#define ENERGY_EXTRA_BOOST 50 +#define DUMB_PACK_NUMMISSLS 5 +#define HOM_PACK_NUMMISSLS 8 +#define PROX_PACK_NUMMINES 3 +#define SWARM_PACK_NUMMISSLS 2 + +#define MAX_EXTRA_AREA 700 +#define MIN_EXTRA_DIST 150 +#define EXTRA_PROBABILITY 4 + +#define PROB_DAZZLE_LASER 4 // remainder to 100% is prob of energy extras! +#define PROB_THIEF_LASER 4 +#define PROB_PROXIMITY_MINE 6 +#define PROB_MISSILE_PACK 22 + +#define PROB_DUMB_MISS_PACK 45 +#define PROB_HOM_MISS_PACK 55 + +#define MEGASHIELD_STRENGTH 20 + +#define LASER2_INTENSITY 20 + +#define FLASHTIME_LASER_STANDARD 2 +#define FLASHTIME_LASER_THIEF 8 +#define FLASHTIME_MISSILE 4 + + +// ship steering speeds and delays ---------------------------------- +// +#define SHIP_SPEED_INC_PER_REFFRAME ( 0x01200 / 8 /23) +#define SHIP_SPEED_DEC_PER_REFFRAME ( 0x01200 / 8 /23) +#define SHIP_YAW_PER_REFFRAME ( 0x068 / 8 ) +#define SHIP_PITCH_PER_REFFRAME ( 0x068 / 8 ) +#define SHIP_ROLL_PER_REFFRAME ( 0x05A / 3 ) +#define SHIP_SLIDE_PER_REFFRAME FIXED_TO_GEOMV( 0xb000 / 8 ) +#define SHIP_FIRE_REPEAT_DELAY ( 24 * 8 ) +#define SHIP_FIRE_DISABLE_DELAY ( 12 * 8 ) +#define SHIP_MISSILE_DISABLE_DELAY ( 36 * 8 ) + + +// object member variables init values ------------------------------ +// +#define PROP_FUME_FREQUENCY 220 +#define PROP_FUME_LIFETIME 11000 +#define PROP_FUME_SPEED -0x0080 + +#define PROP_FUME_START_X1 FIXED_TO_GEOMV( -0x35000 ) +#define PROP_FUME_START_X2 FIXED_TO_GEOMV( -0x35000 ) +#define PROP_FUME_START_X3 FIXED_TO_GEOMV( 0x35000 ) +#define PROP_FUME_START_X4 FIXED_TO_GEOMV( 0x35000 ) +#define PROP_FUME_START_Y FIXED_TO_GEOMV( 0x00000 ) +#define PROP_FUME_START_Z FIXED_TO_GEOMV( -0x125000 ) + +#define _2_PROP_FUME_START_X1 FIXED_TO_GEOMV( -0x35000 ) +#define _2_PROP_FUME_START_X2 FIXED_TO_GEOMV( -0x35000 ) +#define _2_PROP_FUME_START_X3 FIXED_TO_GEOMV( 0x35000 ) +#define _2_PROP_FUME_START_X4 FIXED_TO_GEOMV( 0x35000 ) +#define _2_PROP_FUME_START_Y FIXED_TO_GEOMV( 0x00000 ) +#define _2_PROP_FUME_START_Z FIXED_TO_GEOMV( -0x125000 ) + +#define SPREADFIRE_LIFETIME 1500 +#define SPREADFIRE_SPEED 0x10000 + +#define HELIX_LIFETIME 1500 +#define HELIX_SPEED 0x10000 + +#define PHOTON_LIFETIME 1500 +#define PHOTON_SPEED 0x80000 + +#define SHIP1_MAXDAMAGE 20 +#define SHIP1_MAXSHIELD 10 +#define SHIP1_NUM_MISSLS 05 +#define SHIP1_NUM_HOMMISSLS 10 +#define SHIP1_NUM_SWARMMISSLS 0 +#define SHIP1_NUM_MINES 3 +#define SHIP1_MAX_SPEED 0xbb80 +#define SHIP1_MAX_ENERGY 400 +#define SHIP1_MAX_FUEL 300 +#define SHIP1_WEAPONS 0x00070101 + +#define SHIP2_MAXDAMAGE 20 +#define SHIP2_MAXSHIELD 10 +#define SHIP2_NUM_MISSLS 10 +#define SHIP2_NUM_HOMMISSLS 15 +#define SHIP2_NUM_SWARMMISSLS 0 +#define SHIP2_NUM_MINES 5 +#define SHIP2_MAX_SPEED 0x9600 +#define SHIP2_MAX_ENERGY 800 +#define SHIP2_MAX_FUEL 950 +#define SHIP2_WEAPONS 0x00070101 + +#define ENERGYEXTRA_LIFETIME 10000 +#define MISSILEEXTRA_LIFETIME 20000 +#define DEVICEEXTRA_LIFETIME 25000 + +#define ENERGYEXTRA_SELFROTX 0x0025 +#define ENERGYEXTRA_SELFROTY 0x0055 +#define ENERGYEXTRA_SELFROTZ 0x0080 +#define MISSILEEXTRA_SELFROTX 0x0065 +#define MISSILEEXTRA_SELFROTY 0x0040 +#define MISSILEEXTRA_SELFROTZ 0x0015 +#define DEVICEEXTRA_SELFROTX 0x0025 +#define DEVICEEXTRA_SELFROTY 0x0055 +#define DEVICEEXTRA_SELFROTZ 0x0080 + +#define MINE1_HITPOINTS 15 +#define MINE1_LIFETIME 60000 +#define MINE1_SELFROTX 0x0065 +#define MINE1_SELFROTY 0x0040 +#define MINE1_SELFROTZ 0x0015 + +#define LASER1_LIFETIME 1680 +#define LASER1_SPEED 0x25000 +#define LASER1_HITPOINTS 1 +#define LASER1_ENERGY 5 + +#define LASER2_LIFETIME 1680 +#define LASER2_SPEED 0x25000 +#define LASER2_INTENSITY 20 +#define LASER2_ENERGY 2 + +#define LASER3_LIFETIME 1680 +#define LASER3_SPEED 0x25000 +#define LASER3_THEFTDAMAGE 50 +#define LASER3_ENERGY 10 + +#define MISSILE1_LIFETIME 3600 +#define MISSILE1_SPEED 0x1a000 +#define MISSILE1_HITPOINTS 10 + +#define HOMMISS1_LIFETIME 4800 +#define HOMMISS1_SPEED 0x20000 +#define HOMMISS1_HITPOINTS 5 + +#define HOMMISS1_LATENCY 60 +#define HOMMISS1_MAX_ROT 0x0100 + +#define LASER1_START_X_1 FIXED_TO_GEOMV( -0x0c000 ) +#define LASER1_START_X_2 FIXED_TO_GEOMV( -0x07000 ) +#define LASER1_START_X_3 FIXED_TO_GEOMV( 0x07000 ) +#define LASER1_START_X_4 FIXED_TO_GEOMV( 0x0c000 ) +#define LASER1_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define LASER1_START_Z FIXED_TO_GEOMV( 0x3e0000 ) + +#define _2_LASER1_START_X_1 FIXED_TO_GEOMV( -0x74000 ) +#define _2_LASER1_START_X_2 FIXED_TO_GEOMV( -0x66000 ) +#define _2_LASER1_START_X_3 FIXED_TO_GEOMV( 0x66000 ) +#define _2_LASER1_START_X_4 FIXED_TO_GEOMV( 0x74000 ) +#define _2_LASER1_START_Y FIXED_TO_GEOMV( 0x22000 ) +#define _2_LASER1_START_Z FIXED_TO_GEOMV( 0x370000 ) + +#define MISSILE1_START_X_1 FIXED_TO_GEOMV( -0x090000 ) +#define MISSILE1_START_X_2 FIXED_TO_GEOMV( -0x050000 ) +#define MISSILE1_START_X_3 FIXED_TO_GEOMV( 0x050000 ) +#define MISSILE1_START_X_4 FIXED_TO_GEOMV( 0x090000 ) +#define MISSILE1_START_Y FIXED_TO_GEOMV( 0x030000 ) +#define MISSILE1_START_Z FIXED_TO_GEOMV( 0x120000 ) + +#define _2_MISSILE1_START_X_1 FIXED_TO_GEOMV( -0xc5000 ) +#define _2_MISSILE1_START_X_2 FIXED_TO_GEOMV( -0x63000 ) +#define _2_MISSILE1_START_X_3 FIXED_TO_GEOMV( 0x63000 ) +#define _2_MISSILE1_START_X_4 FIXED_TO_GEOMV( 0xc5000 ) +#define _2_MISSILE1_START_Y FIXED_TO_GEOMV( 0x6c000 ) +#define _2_MISSILE1_START_Z FIXED_TO_GEOMV( -0x17000 ) + +#define MINE1_START_X FIXED_TO_GEOMV( 0x00000 ) +#define MINE1_START_Y FIXED_TO_GEOMV( 0x00000 ) +#define MINE1_START_Z FIXED_TO_GEOMV( -0x330000 ) + +#define _2_MINE1_START_X FIXED_TO_GEOMV( 0x00000 ) +#define _2_MINE1_START_Y FIXED_TO_GEOMV( 0x00000 ) +#define _2_MINE1_START_Z FIXED_TO_GEOMV( -0x360000 ) + +#define HOMMISS1_START_X_1 FIXED_TO_GEOMV( -0x060000 ) +#define HOMMISS1_START_X_2 FIXED_TO_GEOMV( -0x020000 ) +#define HOMMISS1_START_X_3 FIXED_TO_GEOMV( 0x020000 ) +#define HOMMISS1_START_X_4 FIXED_TO_GEOMV( 0x060000 ) +#define HOMMISS1_START_Y FIXED_TO_GEOMV( -0x010000 ) +#define HOMMISS1_START_Z FIXED_TO_GEOMV( 0x1f0000 ) + +#define SPREAD_START_X_1 FIXED_TO_GEOMV( -(0x0c000+0x45000) ) +#define SPREAD_START_X_2 FIXED_TO_GEOMV( -0x07000 ) +#define SPREAD_START_X_3 FIXED_TO_GEOMV( 0x07000 ) +#define SPREAD_START_X_4 FIXED_TO_GEOMV( (0x0c000+0x45000) ) +#define SPREAD_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define SPREAD_START_Z FIXED_TO_GEOMV( (0x3e0000 - 0x450000) ) + +#define _2_SPREAD_START_X_1 FIXED_TO_GEOMV( -(0x0c000+0x45000) ) +#define _2_SPREAD_START_X_2 FIXED_TO_GEOMV( -0x07000 ) +#define _2_SPREAD_START_X_3 FIXED_TO_GEOMV( 0x07000 ) +#define _2_SPREAD_START_X_4 FIXED_TO_GEOMV( (0x0c000+0x45000) ) +#define _2_SPREAD_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define _2_SPREAD_START_Z FIXED_TO_GEOMV( (0x3e0000 - 0x450000) ) + +#define HELIX_START_X FIXED_TO_GEOMV( -(0x0c000+0x45000) ) +#define HELIX_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define HELIX_START_Z FIXED_TO_GEOMV( (0x3e0000 - 0x450000) ) + +#define _2_HELIX_START_X FIXED_TO_GEOMV( -(0x0c000+0x45000) ) +#define _2_HELIX_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define _2_HELIX_START_Z FIXED_TO_GEOMV( (0x3e0000 - 0x450000) ) + +#define BEAM_START_X_1 FIXED_TO_GEOMV( -0x51000 ) +#define BEAM_START_X_2 FIXED_TO_GEOMV( -0x4a000 ) +#define BEAM_START_X_3 FIXED_TO_GEOMV( 0x4a000 ) +#define BEAM_START_X_4 FIXED_TO_GEOMV( 0x51000 ) +#define BEAM_START_Y FIXED_TO_GEOMV( 0x19000 ) +#define BEAM_START_Z FIXED_TO_GEOMV( 0x40000 ) + +#define _2_BEAM_START_X_1 FIXED_TO_GEOMV( -500000 ) +#define _2_BEAM_START_X_2 0 +#define _2_BEAM_START_X_3 0 +#define _2_BEAM_START_X_4 FIXED_TO_GEOMV( 400000 ) +#define _2_BEAM_START_Y 0 +#define _2_BEAM_START_Z FIXED_TO_GEOMV( -180000 ) + +#define SHIP1_OBJCAM_STARTPITCH ((bams_t) 0x0d00) +#define SHIP1_OBJCAM_STARTYAW ((bams_t)-0x0f00) +#define SHIP1_OBJCAM_STARTROLL ((bams_t) 0x0000) +#define SHIP1_OBJCAM_STARTDIST FIXED_TO_GEOMV( 0x600000 ) +#define SHIP1_OBJCAM_MINDISTANCE FIXED_TO_GEOMV( 0x300000 ) +#define SHIP1_OBJCAM_MAXDISTANCE FIXED_TO_GEOMV( 0xd00000 ) + +#define SHIP2_OBJCAM_STARTPITCH ((bams_t) 0x1000) +#define SHIP2_OBJCAM_STARTYAW ((bams_t)-0x1000) +#define SHIP2_OBJCAM_STARTROLL ((bams_t)-0x0500) +#define SHIP2_OBJCAM_STARTDIST FIXED_TO_GEOMV( 0x5c0000 ) +#define SHIP2_OBJCAM_MINDISTANCE FIXED_TO_GEOMV( 0x300000 ) +#define SHIP2_OBJCAM_MAXDISTANCE FIXED_TO_GEOMV( 0xc00000 ) + + +#endif // _OD_PROPS_H_ + + diff --git a/src/libparsec/include/od_rast.h b/src/libparsec/include/od_rast.h new file mode 100644 index 0000000..2d5e91b --- /dev/null +++ b/src/libparsec/include/od_rast.h @@ -0,0 +1,124 @@ +/* + * PARSEC HEADER (OBJECT) + * Rasterization Types V1.70 + * + * Copyright (c) Markus Hadwiger 1995-1999 + * All Rights Reserved. + */ + +#ifndef _OD_RAST_H_ +#define _OD_RAST_H_ + + +// coordinate on actual screen (integral component on the integer lattice) ---- +// +typedef dword ugrid_t; // unsigned! +typedef int32_t sgrid_t; // signed! +typedef rastv_t fgrid_t; + + +// 2-D point in unsigned integer coordinates (always >= 0) -------------------- +// +struct UPoint { + + ugrid_t X; // unsigned! + ugrid_t Y; // unsigned! +}; + + +// 2-D point in screen coordinates (used in vertex list for the edge tracer) -- +// +struct SPoint { + + sgrid_t X; // signed! + sgrid_t Y; // signed! +}; + + +// extended version of SPoint structure; contains z and color info ------------ +// +struct SPointEx { + + sgrid_t X; // signed! + sgrid_t Y; // signed! + depth_t View_Z; // Z coordinate in view space (for buffer fill) + dword RGBA; // RGBA color (8-bit channels) +}; + + +// 2-D point in screen coordinates with fractional part ----------------------- +// +struct FPoint { + + fgrid_t X; // 8 bytes + fgrid_t Y; +}; + + +// defines a polygon that should by rendered and drawn to the screen; --------- +// created after projection of 3-D polygon; scaled to screen coordinates; +// used only by edge tracer (must be filled from the object structure) +// +struct SVertexList { + + dword VCount; // number of vertices in list + SPoint Vertices[ 1 ]; // first element of vertex list (array) +}; + + +// list of extended SPoints --------------------------------------------------- +// +struct SVertexExList { + + dword VCount; // number of vertices in list + SPointEx Vertices[ 1 ]; // first element of vertex list (array) +}; + + +// defines single horizontal span; used for horizontal span list structure ---- +// the span starts at XLeft and ends at XRight (inclusively) +// +struct HSpan { + + ugrid_t XLeft; // size is 8 bytes + ugrid_t XRight; +}; + + +// extended version of HSpan structure; contains z and lighting info ---------- +// +struct HSpanEx { + + ugrid_t XLeft; // size is 16 bytes + ugrid_t XRight; + word ZLeft; + word ILeft; + word ZRight; + word IRight; +}; + + +// stores list of horizontal spans; created by polygon edge-tracer; ----------- +// used by low level polygon drawing/rendering functions +// +struct HSpanList { + + dword Height; // length of list (height of bounding rectangle) + ugrid_t TopY; // lowest y coordinate of polygon vertices + HSpan HSpans[ 1 ]; // first element of horizontal span list (array) +}; + + +// list of extended HSpans ---------------------------------------------------- +// +struct HSpanExList { + + dword Height; // length of list (height of bounding rectangle) + ugrid_t TopY; // lowest y coordinate of polygon vertices + HSpanEx HSpans[ 1 ]; // first element of horizontal span list (array) +}; + + +#endif // _OD_RAST_H_ + + diff --git a/src/libparsec/include/od_struc.h b/src/libparsec/include/od_struc.h new file mode 100644 index 0000000..397fd39 --- /dev/null +++ b/src/libparsec/include/od_struc.h @@ -0,0 +1,430 @@ +/* + * PARSEC HEADER (OBJECT) + * Generic Object Structures V1.80 + * + * Copyright (c) Markus Hadwiger 1995-2001 + * All Rights Reserved. + */ + +#ifndef _OD_STRUC_H_ +#define _OD_STRUC_H_ + +#ifdef PARSEC_SERVER + +// forward decls -------------------------------------------------------------- +// +class E_Distributable; + +#endif // PARSEC_SERVER + + +// defines a texture map (size is 32 bytes) ----------------------------------- +// +struct TextureMap { + + dword Geometry; // code for geometry of texture + word Width; // log2( width in pixels ) + word Height; // log2( height in pixels ) + word Flags; // flag word + byte LOD_small; // smallest LOD level (power of two) + byte LOD_large; // largest LOD level (power of two) + dword CompFormat; // impl.-dependent compressed format spec + char* BitMap; // pointer to bitmap (8 bit per texel) + word* TexPalette; // pointer to color look up table for texture + const char* TexMapName; // pointer to texture name + dword TexelFormat; // texel format +}; + + +// single texfont char (size is 8 bytes) -------------------------------------- +// +struct texchar_s { + + short tex_u; // u coordinate in texture + short tex_v; // v coordinate in texture + short tex_id; // id of texture (relative to texfont) + signed char tex_ulead; // u offset to first real column + signed char tex_ustep; // u advance after drawing this char +}; + + +// entire texfont descriptor (size is 16 bytes) ------------------------------- +// +struct texfont_s { + + dword flags; + byte height; // height of chars (must be equal for all) + byte numtextures; // may have been split up into several textures + short numtexchars; // number of chars in this font + texchar_s* texchars; // table of chars + TextureMap* texmap; // corresponding font textures (array) +}; + + +// single entry (frame) in table of textures ---------------------------------- +// +struct texfrm_s { + + int deltatime; // delta time to next entry (frame) + TextureMap* texmap; // texture map for this frame +}; + + +// single entry (frame) in table of 2-D (image) transformations --------------- +// +struct xfofrm_s { + + int deltatime; // delta time to next entry (frame) + imgtrafo_s* imgtrafo; // image transformation for this frame +}; + + +// texture animation descriptor (size is 32 bytes) ---------------------------- +// +struct texanim_s { + + texfrm_s* tex_table; // table of textures + dword tex_end; // end index + dword tex_start; // start index + dword tex_rep; // repeat index + + xfofrm_s* xfo_table; // table of 2-D (image) transformations + dword xfo_end; // end index + dword xfo_start; // start index + dword xfo_rep; // repeat index +}; + + +// single entry (frame) in color animation table (size is 8 bytes) ------------ +// +struct colfrm_s { + + int deltatime; // delta time to next entry (frame) + colrgba_s color; // color for this frame +}; + + +// how to combine the color sources in color animations ----------------------- +// +enum { + + COLANIM_SOURCENOCOMBINE = 0x0000, // no source color combination + COLANIM_SOURCEADD = 0x0001, // add source colors + COLANIM_SOURCEMUL = 0x0002, // multiply source colors + COLANIM_SOURCE_MASK = 0x0003 +}; + + +// color animation descriptor (size is 16 bytes) ------------------------------ +// +struct colanim_s { + + colfrm_s* col_table0; // color source 0 + colfrm_s* col_table1; // color source 1 + + word col_end0; // table 0 end index (length-1) + word col_end1; // table 1 end index (length-1) + + dword col_flags; // COLANIM_xx +}; + + +// how to combine the source color with the face color ------------------------ +// +enum { + + FACE_ANIM_BASEIGNORE = 0x0000, // ignore base (face) color + FACE_ANIM_BASEADD = 0x0001, // add anim to base color + FACE_ANIM_BASEMUL = 0x0002, // multiply base color by anim + FACE_ANIM_BASE_MASK = 0x0003 +}; + + +// instance data for current state of face animation (size is 32 bytes) ------- +// +struct FaceAnimState { + +// base info + + texanim_s* TexAnim; // texture animation + colanim_s* ColAnim; // color animation + dword ColFlags; // FACE_ANIM_xx + colrgba_s ColOutput; // animated output color + +// state info + + word tex_pos; // current position in texture table + short tex_time; // time left until next advance in table + word xfo_pos; // current position in trafo table + short xfo_time; // time left until next advance in table + + word col_pos0; // current position in color source 0 + short col_time0; // time left until next advance in table + word col_pos1; // current position in color source 1 + short col_time1; // time left until next advance in table +}; + + +// extended face info flags --------------------------------------------------- +// +enum { + + FACE_EXT_NONE = 0x0000, // no animations at all + FACE_EXT_ANIMATETEXTURES = 0x0001, // enable texture animation + FACE_EXT_TRANSFORMTEXTURES = 0x0002, // enable texture xfo animation + FACE_EXT_ANIMATECOLORS = 0x0004, // enable color animation + FACE_EXT_ONESHOT = 0x0010, // one-shot animation + FACE_EXT_ONESHOTRESTORE = 0x0020, // restore previous shader + FACE_EXT_DISABLED = 0x8000 // temporarily disabled +}; + + +// optional extended face information (size is 8 bytes) ----------------------- +// +struct FaceExtInfo { + + dword Flags; // FACE_EXT_xx + dword StateId; // index into GenObject::FaceAnimStates[] +}; + + +// face shading flags --------------------------------------------------------- +// +enum { + + FACE_SHADING_DEFAULT = 0x0000, + + FACE_SHADING_FACECOLOR = 0x0001, // use face color (direct/indexed) + FACE_SHADING_USECOLORINDEX = 0x0002, // indexed instead of direct color + FACE_SHADING_TEXIPOLATE = 0x0004, // texture may be interpolated + + FACE_SHADING_ENABLETEXTURE = 0x0010, // shader uses texture + FACE_SHADING_CONSTANTCOLOR = 0x0020, // shade with constant color + FACE_SHADING_NOVERTEXALPHA = 0x0040, // shader must ignore vertex alpha + + FACE_SHADING_NODEPTHCMP = 0x0100, // disable depth compare + FACE_SHADING_NODEPTHWRITE = 0x0200, // disable depth write + + FACE_SHADING_DRAW_SORTED = 0x0400, // draw in depth order + FACE_SHADING_DRAW_LAST = 0x0800, // draw last (overlay) + + FACE_SHADING_NOBACKCULLING = 0x1000, // turn off backface culling + FACE_SHADING_BACK_FIRST = 0x2000 // draw backfaces, then frontfaces +}; + + +// defines a single object-face (size is 128 bytes) --------------------------- +// +struct Face { + + TextureMap* TexMap; // pointer to texture description + FaceExtInfo* ExtInfo; // optional extended face info + dword ColorRGB; // RGB color for direct color display + dword ColorIndx; // colorindex for palette mapped display + dword FaceNormalIndx; // index of vertex which is the surface normal + Xmatrx TexXmatrx; // matrix for texture placement + dword _mtxscratch1; // scratchpad for matrix code + Xmatrx CurTexXmatrx; // current transformation screen -> texture + word ShadingIter; // shader to use for this face (iter_xx) + word ShadingFlags; // shading flags (FACE_SHADING_xx) + dword VisibleFrame; // ==CurVisibleFrame if face touched this frame +}; + + +// polygon flags -------------------------------------------------------------- +// +enum { + + POLYFLAG_DEFAULT = 0x0000, // vertex indexes only + POLYFLAG_CORNERCOLORS = 0x0001, // RGBA color array follows + POLYFLAG_WEDGEINDEXES = 0x0002 // wedge index array follows +}; + + +// defines a single object-polygon (size is 16 bytes) ------------------------- +// +struct Poly { + + dword NumVerts; // number of vertices (no surface normal!) + dword FaceIndx; // index of face this polygon belongs to + dword* VertIndxs; // list of vertexindexes comprising the polygon + dword Flags; // POLYFLAG_xx +}; + + +// node structure for bsp tree nodes (size is 16 bytes) ----------------------- +// +struct BSPNode { + + dword Polygon; // index of polygon contained in this node + dword Contained; // index of first node in the same plane (list) + dword FrontTree; // index of root-node of front-subtree + dword BackTree; // index of root-node of back-subtree +}; + + +// vertex animation callback function type ------------------------------------ +// +struct GenObject; +typedef int (*vtxanim_fpt)( GenObject *gobj, dword animid ); + + +// instance data for current state of vertex animation (size is 128 bytes) ---- +// +struct VtxAnimState { + +// base info + + dword NumVerts; // number of vertices with normals + dword NumPolyVerts; // number of vertices without normals + dword NumNormals; // number of face normals + dword VertexBase; // base index for vertex subarray + dword NumPolys; // number of polygons + dword PolyBase; // base index for polygon subarray + dword NumFaces; // number of faces + dword FaceBase; // base index for face subarray + dword NumWedges; // number of wedges + dword WedgeBase; // base index for wedge subarray + + vtxanim_fpt AnimCallback; // callback function + +// state info + + Xmatrx CurrentXmatrx; // current transformation matrix + dword StateInfo[ 9 ]; // custom animation state info +}; + + +// allow pointer to particle cluster to be declared --------------------------- +// +struct objectbase_pcluster_s; +typedef objectbase_pcluster_s ObjPartCluster; + + +// forward declaration -------------------------------------------------------- +// +struct CustomObject; + + +// wedge data flags ----------------------------------------------------------- +// +enum { + + WEDGEFLAG_ENABLE_TEXCOORDS = 0x0001 +}; + + +// structure of generic graphical object for specific lod --------------------- +// +struct GenLodObject { + + dword NumVerts; // number of vertices with normals + dword NumPolyVerts; // number of vertices without normals + dword NumNormals; // number of face normals + Vertex3* VertexList; // list of all vertices in object space + Vertex3* X_VertexList; // vertices transformed into view space + SPoint* S_VertexList; // vtxs converted to screen coordinates + dword NumPolys; // number of polygons in this object + Poly* PolyList; // list of polygons in this object + dword NumFaces; // number of faces in this object + Face* FaceList; // list of all faces + dword* VisPolyList; // indexes of currently visible polys + dword* SortedPolyList; // poly indexes sorted on attributes + void* AuxList; // ... + BSPNode* BSPTree; // pointer to root of bsp tree + CullBSPNode* AuxBSPTree; // auxiliary bsp tree + void* AuxObject; // object for api-optimized rendering + dword NumWedges; // wedges==subvertices on attributes + word NumLayers; // number of texcoordinates per wedge + word WedgeFlags; // WEDGEFLAG_xx + dword* WedgeVertIndxs; // vertices corresponding to wedges + Vector3* WedgeNormals; // vertex/wedge normals + colrgba_s* WedgeColors; // vertex/wedge colors + TexCoord2* WedgeTexCoords; // vertex/wedge texture coordinates + colrgba_s* WedgeLighted; // temp storage for lighted wedges + colrgba_s* WedgeSpecular; // temp storage for specular colors + colrgba_s* WedgeFogged; // temp storage for fogged wedges + word ActiveFaceAnims; // active face anim state subrange + word ActiveVtxAnims; // active vertex anim state subrange +}; + + +// object lod descriptor (size is 16 bytes) ----------------------------------- +// +struct GenLodInfo { + + dword Flags; + geomv_t MagTreshold; // switching thresholds with hysteresis + geomv_t MinTreshold; // (small->large, large->small) + GenLodObject* LodObject; // actual geometry for this lod +}; + + +// structure of generic graphical object -------------------------------------- +// +struct GenObject { + + GenObject* NextObj; // next object in list; _if_ the list + GenObject* PrevObj; // is doubly linked: previous object + GenObject* NextVisObj; // pointer to next obj in visible list + dword ObjectNumber; // unique number of this objectinstance + dword HostObjNumber; // number this object has on its host + dword ObjectType; // type this object belongs to + dword ObjectClass; // class this object belongs to + size_t InstanceSize; // size of instance of this object class + dword NumVerts; // number of vertices with normals + dword NumPolyVerts; // number of vertices without normals + dword NumNormals; // number of face normals + Vertex3* VertexList; // list of all vertices in object space + Vertex3* X_VertexList; // vertices transformed into view space + SPoint* S_VertexList; // vtxs converted to screen coordinates + dword NumPolys; // number of polygons in this object + Poly* PolyList; // list of polygons in this object + dword NumFaces; // number of faces in this object + Face* FaceList; // list of all faces + dword NumVisPolys; // number of polygon indexes in vislist + dword* VisPolyList; // indexes of currently visible polys + dword* SortedPolyList; // poly indexes sorted on attributes + void* AuxList; // ... + geomv_t BoundingSphere; // radius of bounding sphere + geomv_t BoundingSphere2; // radius squared of bounding sphere + Vertex3 BoundingBox[ 2 ]; // min-max vertices of bounding box + BSPNode* BSPTree; // pointer to root of bsp tree + ObjPartCluster* AttachedPClusters; // list of attached particle clusters + CustomObject* NotifyCustmObjects; // customobj list for callback_notify() + dword VisibleFrame; // ==CurVisibleFrame if object visible + CullBSPNode* AuxBSPTree; // auxiliary bsp tree + dword CullMask; // last cull mask set by culling code + void* AuxObject; // object for api-optimized rendering + dword NumWedges; // wedges==subvertices on attributes + word NumLayers; // number of texcoordinates per wedge + word WedgeFlags; // WEDGEFLAG_xx + dword* WedgeVertIndxs; // vertices corresponding to wedges + Vector3* WedgeNormals; // vertex/wedge normals + colrgba_s* WedgeColors; // vertex/wedge colors + TexCoord2* WedgeTexCoords; // vertex/wedge texture coordinates + colrgba_s* WedgeLighted; // temp storage for lighted wedges + colrgba_s* WedgeSpecular; // temp storage for specular colors + colrgba_s* WedgeFogged; // temp storage for fogged wedges + word CurrentLod; // currently active detail level + word NumLodObjects; // number of available detail levels + GenLodInfo* LodObjects; // detail level descriptors + word NumFaceAnims; // number of face anim states (maximum) + word ActiveFaceAnims; // active state subrange (from start) + FaceAnimState* FaceAnimStates; // face anim states (must be instanced!) + word NumVtxAnims; // number of vtx anim states (maximum) + word ActiveVtxAnims; // active state subrange (from start) + VtxAnimState* VtxAnimStates; // vtx anim states (must be instanced!) + dword _mtxscratch1; // scratchpad for matrix code + Xmatrx ObjPosition; // location and orientation in worldsp. + dword _mtxscratch2; // scratchpad for matrix code + Xmatrx CurrentXmatrx; // current objspace -> viewspace xform +#ifdef PARSEC_SERVER + E_Distributable* pDist; // pointer to the E_Distributable attached to this engine object +#endif // PARSEC_SERVER +}; + + +#endif // _OD_STRUC_H_ + + diff --git a/src/libparsec/include/od_texdf.h b/src/libparsec/include/od_texdf.h new file mode 100644 index 0000000..467d61e --- /dev/null +++ b/src/libparsec/include/od_texdf.h @@ -0,0 +1,146 @@ +/* + * PARSEC HEADER (OBJECT) + * Texture Format Specifications V1.15 + * + * Copyright (c) Markus Hadwiger 1998-2000 + * All Rights Reserved. + */ + +#ifndef _OD_TEXDF_H_ +#define _OD_TEXDF_H_ + + +// texture flags + +#define TEXFLG_NONE 0x0000 // no special flags +#define TEXFLG_EXT_GEOMETRY 0x0001 // extended geometry specification +#define TEXFLG_LODRANGE_VALID 0x0002 // lod range (small to large) valid +#define TEXFLG_GLIDE_TEXTURE 0x0004 // directly usable as glide texture +#define TEXFLG_IS_COMPRESSED 0x0010 // texture data is compressed +#define TEXFLG_DO_COMPRESSION 0x0020 // texture data should be compressed +#define TEXFLG_CACHE_MAY_FREE 0x0100 // cache may free texture data + + +// texture map formats + +#define TEXFMT_FORMATMASK 0x0000ffff // mask to extract actual format +#define TEXFMT_FLAGSMASK 0xffff0000 // mask to extract additional flags +#define TEXFMT_PALETTEDTEXTURE 0x00010000 // format needs texture palette +#define TEXFMT_GLIDEFORMAT 0x00020000 // format spec identical to glide + +#define TEXFMT_STANDARD 0x0000 // 8-bit indexes into global palette +#define TEXFMT_RGB_565 0x0001 // 16-bit direct color +#define TEXFMT_RGBA_1555 0x0002 // 16-bit direct color with alpha +#define TEXFMT_RGB_888 0x0003 // 24-bit direct color +#define TEXFMT_RGBA_8888 0x0004 // 32-bit direct color with alpha +#define TEXFMT_ALPHA_8 0x0005 // 8-bit alpha only +#define TEXFMT_INTENSITY_8 0x0006 // 8-bit intensity only +#define TEXFMT_LUMINANCE_8 0x0007 // 8-bit luminance only + +#define TEXFMT_GR_8BIT ( 0x0000 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_RGB_332 TEXFMT_GR_8BIT +#define TEXFMT_GR_YIQ_422 ( 0x0001 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ALPHA_8 ( 0x0002 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_INTENSITY_8 ( 0x0003 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ALPHA_INTENSITY_44 ( 0x0004 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_P_8 ( 0x0005 | TEXFMT_GLIDEFORMAT | TEXFMT_PALETTEDTEXTURE ) +#define TEXFMT_GR_RSVD0 ( 0x0006 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_RSVD1 ( 0x0007 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_16BIT ( 0x0008 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ARGB_8332 TEXFMT_GR_16BIT +#define TEXFMT_GR_AYIQ_8422 ( 0x0009 | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_RGB_565 ( 0x000a | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ARGB_1555 ( 0x000b | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ARGB_4444 ( 0x000c | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_ALPHA_INTENSITY_88 ( 0x000d | TEXFMT_GLIDEFORMAT ) +#define TEXFMT_GR_AP_88 ( 0x000e | TEXFMT_GLIDEFORMAT | TEXFMT_PALETTEDTEXTURE ) +#define TEXFMT_GR_RSVD2 ( 0x000f | TEXFMT_GLIDEFORMAT ) + + +// texture lod specification + +#define TEXLOD_1 0x0000 // lowest level: 1x1 +#define TEXLOD_2 0x0001 +#define TEXLOD_4 0x0002 +#define TEXLOD_8 0x0003 +#define TEXLOD_16 0x0004 +#define TEXLOD_32 0x0005 +#define TEXLOD_64 0x0006 +#define TEXLOD_128 0x0007 +#define TEXLOD_256 0x0008 +#define TEXLOD_512 0x0009 +#define TEXLOD_1024 0x000a +#define TEXLOD_2048 0x000b // highest level: 2048x2048 + + +// texture geometry codes (legacy geometry spec) + +#define TEXGEO_CODE_32x32 0x00000000 +#define TEXGEO_CODE_64x32 0x00000001 +#define TEXGEO_CODE_64x64 0x00000002 +#define TEXGEO_CODE_128x64 0x00000003 +#define TEXGEO_CODE_128x128 0x00000004 +#define TEXGEO_CODE_256x128 0x00000005 +#define TEXGEO_CODE_256x256 0x00000006 // currently not supported! + + +// texture extended geometry codes (scale, aspect ratio, flags) + +#define TEXGEO_NOTSPECIFIED 0x00000000 + +#define TEXGEO_GLIDEASPECT 0x00000100 // aspect ratio spec for glide +#define TEXGEO_EXTASPECT 0x00000200 // non-standard aspect ratio spec +#define TEXGEO_INVERSESCALE 0x00000400 // inverse scale factor stored +#define TEXGEO_ASPECTMASK 0x000000ff // mask to extract aspect ratio +#define TEXGEO_SCALEMASK 0x0fff0000 // mask to extract coordinate scale +#define TEXGEO_SCALESHIFT 16 // shift to get actual scale value +#define TEXGEO_SCALE2MASK 0xf0000000 // mask to extract log2 scale +#define TEXGEO_SCALE2SHIFT 28 // shift to get actual log2 scale +#define TEXGEO_FLAGSMASK 0x0000ff00 // mask to extract additional flags + +#define TEXGEO_SCALE_1 0x00010000 // scale factors by which texture +#define TEXGEO_SCALE_2 0x10020000 // coordinates need to be scaled +#define TEXGEO_SCALE_4 0x20040000 // up before they can be used for +#define TEXGEO_SCALE_8 0x30080000 // actual rendering (| their log2). +#define TEXGEO_SCALE_16 0x40100000 // this facility is used if texture +#define TEXGEO_SCALE_32 0x50200000 // coordinates have to be normalized +#define TEXGEO_SCALE_64 0x60400000 // to a reference texture size +#define TEXGEO_SCALE_128 0x70800000 // instead of the actual size of +#define TEXGEO_SCALE_256 0x81000000 // the texture. +#define TEXGEO_SCALE_512 0x92000000 +#define TEXGEO_SCALE_1024 0xa4000000 + +#define TEXGEO_ASPECT_1x1 0x00 // supported everywhere +#define TEXGEO_ASPECT_2x1 0x01 // supported everywhere +#define TEXGEO_ASPECT_4x1 ( 0x02 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_8x1 ( 0x03 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_16x1 ( 0x04 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_32x1 ( 0x05 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_64x1 ( 0x06 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_128x1 ( 0x07 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_256x1 ( 0x08 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_512x1 ( 0x09 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1024x1 ( 0x0a | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x2 ( 0x0b | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x4 ( 0x0c | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x8 ( 0x0d | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x16 ( 0x0e | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x32 ( 0x0f | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x64 ( 0x10 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x128 ( 0x11 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x256 ( 0x12 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x512 ( 0x13 | TEXGEO_EXTASPECT ) +#define TEXGEO_ASPECT_1x1024 ( 0x14 | TEXGEO_EXTASPECT ) + +#define TEXGEO_ASPECT_GR_8x1 ( 0x00 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_4x1 ( 0x01 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_2x1 ( 0x02 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_1x1 ( 0x03 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_1x2 ( 0x04 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_1x4 ( 0x05 | TEXGEO_GLIDEASPECT ) +#define TEXGEO_ASPECT_GR_1x8 ( 0x06 | TEXGEO_GLIDEASPECT ) + + +#endif // _OD_TEXDF_H_ + + diff --git a/src/libparsec/include/od_trafo.h b/src/libparsec/include/od_trafo.h new file mode 100644 index 0000000..044000d --- /dev/null +++ b/src/libparsec/include/od_trafo.h @@ -0,0 +1,62 @@ +/* + * PARSEC HEADER (OBJECT) + * Transformation Types V1.68 + * + * Copyright (c) Markus Hadwiger 1995-1998 + * All Rights Reserved. + */ + +#ifndef _OD_TRAFO_H_ +#define _OD_TRAFO_H_ + + +// generic transformation matrices -------------------------------------------- +// +typedef geomv_t Xmatrx[ 3 ][ 4 ]; // [0 0 0 1] (line 4) omitted! +typedef geomv_t dXmatrx[ 16 ]; // can be used as destination (ofs+4!!) +typedef geomv_t (*pXmatrx)[ 4 ]; // pointer to Xmatrx type +typedef geomv_t Camera[ 3 ][ 4 ]; // position and orientation of camera +typedef geomv_t (*pCamera)[ 4 ]; // pointer to Camera type + +typedef float fMatrx2h[ 3 ][ 3 ]; // float matrix for 2-D (homogeneous) +typedef float fMatrx3h[ 4 ][ 4 ]; // float matrix for 3-D (homogeneous) + + +// easily allocate destination matrix ----------------------------------------- +// +#define ALLOC_DESTXMATRX(x) \ + dXmatrx _##x; pXmatrx x = (pXmatrx) ( (char*)_##x + 4 ) + +//NOTE: +// must not be used like if (.) ALLOC_DESTXMATRX(x). this would make no sense +// and also doesn't work because the macro is not a single statement. + + +// image transformation ------------------------------------------------------- +// +struct imgtrafo_s { + + geomv_t A; + geomv_t B; + geomv_t C; + geomv_t D; + geomv_t E; + geomv_t F; + geomv_t G; + geomv_t H; + geomv_t I; +}; + + +// structure containing both the sine and cosine of a given angle ------------- +// +struct sincosval_s { + + geomv_t sinval; + geomv_t cosval; +}; + + +#endif // _OD_TRAFO_H_ + + diff --git a/src/libparsec/include/od_types.h b/src/libparsec/include/od_types.h new file mode 100644 index 0000000..a44891b --- /dev/null +++ b/src/libparsec/include/od_types.h @@ -0,0 +1,430 @@ +/* + * PARSEC HEADER (OBJECT) + * Object Type Definitions V1.72 + * + * Copyright (c) Markus Hadwiger 1996-2000 + * All Rights Reserved. + */ + +#ifndef _OD_TYPES_H_ +#define _OD_TYPES_H_ + + +//NOTE: +// different object type means different data structure and handling. +// there may be many objects of the same type. these are distinguished +// by their object class. there may also be many objects of the same +// class (object class instances). + + +// numbers of available object types (predefined) ----------------------------- +// +#define NUM_SHIP_TYPES 2 + +#define NUM_LASER_TYPES 3 +#define NUM_MISSILE_TYPES 5 + +#define NUM_PROJECTILE_TYPES (NUM_LASER_TYPES+NUM_MISSILE_TYPES) +#define NUM_TARGETMISSILE_TYPES 2 + +#define NUM_EXTRA_TYPES 4 +#define NUM_MINE_TYPES 1 + +#define NUM_DISTINCT_OBJTYPES (NUM_SHIP_TYPES+NUM_PROJECTILE_TYPES+NUM_EXTRA_TYPES) + + +// object type ids ------------------------------------------------------------ +// +#define SHIP1TYPE 0x00000000 +#define SHIP2TYPE 0x00000001 +#define LASER1TYPE 0x80008102 +#define LASER2TYPE 0x80008103 +#define LASER3TYPE 0x80008104 +#define MISSILE1TYPE 0x00000205 +#define MISSILE2TYPE 0x00000206 +#define MISSILE3TYPE 0x00000207 +#define MISSILE4TYPE 0x00010208 +#define MISSILE5TYPE 0x00020209 +#define EXTRA1TYPE 0x0000030A +#define EXTRA2TYPE 0x0000030B +#define EXTRA3TYPE 0x0000030C +#define MINE1TYPE 0x0000030D + +#define TYPENUMBERMASK 0x000000ff +#define TYPELISTMASK 0x00000f00 +#define TYPEFLAGSMASK 0x0000f000 +#define TYPECONTROLMASK 0x000f0000 + +#define TYPE_ID_INVALID 0xffffffff +#define CLASS_ID_INVALID 0xffffffff + +#define PSHIP_LIST_NO 0x00000000 +#define LASER_LIST_NO 0x00000100 +#define MISSL_LIST_NO 0x00000200 +#define EXTRA_LIST_NO 0x00000300 +#define CUSTM_LIST_NO 0x00000400 + +#define TYPEBACKFACEMASK 0x80008000 // no backfaceculling at all +#define TYPETWOSIDEDMASK 0x40004000 // some faces are two sided +#define TYPETRANSPARENTMASK 0x20002000 // some faces are transparent + +#define TYPEMISSILEISSTANDARD 0x00000000 +#define TYPEMISSILEISHOMING 0x00010000 +#define TYPEMISSILEISSWARM 0x00020000 + + +// type determination macros -------------------------------------------------- +// +#define TYPEID_TYPE_SHIP(i) ( ( (i) & TYPELISTMASK ) == PSHIP_LIST_NO ) +#define TYPEID_TYPE_LASER(i) ( ( (i) & TYPELISTMASK ) == LASER_LIST_NO ) +#define TYPEID_TYPE_MISSILE(i) ( ( (i) & TYPELISTMASK ) == MISSL_LIST_NO ) +#define TYPEID_TYPE_EXTRA(i) ( ( (i) & TYPELISTMASK ) == EXTRA_LIST_NO ) +#define TYPEID_TYPE_CUSTOM(i) ( ( (i) & TYPELISTMASK ) == CUSTM_LIST_NO ) + +#define OBJECT_TYPE_SHIP(o) ( ( (o)->ObjectType & TYPELISTMASK ) == PSHIP_LIST_NO ) +#define OBJECT_TYPE_LASER(o) ( ( (o)->ObjectType & TYPELISTMASK ) == LASER_LIST_NO ) +#define OBJECT_TYPE_MISSILE(o) ( ( (o)->ObjectType & TYPELISTMASK ) == MISSL_LIST_NO ) +#define OBJECT_TYPE_EXTRA(o) ( ( (o)->ObjectType & TYPELISTMASK ) == EXTRA_LIST_NO ) +#define OBJECT_TYPE_CUSTOM(o) ( ( (o)->ObjectType & TYPELISTMASK ) == CUSTM_LIST_NO ) + + +// owner id for local player -------------------------------------------------- +// +#define OWNER_LOCAL_PLAYER -1 + + +// special target identifiers ------------------------------------------------- +// +#define TARGETID_NO_TARGET ((dword)-1) + + +// generic ship object -------------------------------------------------------- +// +struct ShipObject : GenObject { + + int CurDamage; + int MaxDamage; + + // fractional part: 65536 == 1.0 + dword CurDamageFrac; + + int CurShield; + int MaxShield; + + int CurEnergy; + int MaxEnergy; + + // fractional part: 65536 == 1.0 + dword CurEnergyFrac; + + int CurFuel; + int MaxFuel; + + fixed_t CurSpeed; + fixed_t MaxSpeed; + + //NOTE: + // speeds are always fixed_t since they are too + // often used as such to become geomv_t now. + + Vertex3 DirectionVec; + + int BounceCount; + Vertex3 BounceVec; + + // counter for animation of explosion + int ExplosionCount; + + // used by particle system to start explosion + int DelayExplosion; + + // weapons availability state + dword Weapons; + + // weapons active state (same masks as Weapons) + dword WeaponsActive; + + // special device states (invulnerability, etc.) + dword Specials; + + // absorption factor of mega shield + int MegaShieldAbsorption; + + // downcounter for invisibility duration + int InvisibilityCount; + + int NumMissls; + int MaxNumMissls; + + int NumHomMissls; + int MaxNumHomMissls; + + int NumPartMissls; + int MaxNumPartMissls; + + int NumMines; + int MaxNumMines; + + // ship steering + bams_t YawPerRefFrame; + bams_t PitchPerRefFrame; + bams_t RollPerRefFrame; + + geomv_t XSlidePerRefFrame; + geomv_t YSlidePerRefFrame; + + int SpeedIncPerRefFrame; + int SpeedDecPerRefFrame; + + // firing control + int FireRepeatDelay; + int FireDisableDelay; + int MissileDisableDelay; + + // object camera control + geomv_t ObjCamMinDistance; + geomv_t ObjCamMaxDistance; + geomv_t ObjCamStartDist; + bams_t ObjCamStartPitch; + bams_t ObjCamStartYaw; + bams_t ObjCamStartRoll; + + // weapon info + dword Laser1_Class[ 4 ][ 4 ]; + geomv_t Laser1_X[ 4 ][ 4 ]; + geomv_t Laser1_Y[ 4 ][ 4 ]; + geomv_t Laser1_Z[ 4 ][ 4 ]; + + dword Missile1_Class[ 4 ]; + geomv_t Missile1_X[ 4 ]; + geomv_t Missile1_Y[ 4 ]; + geomv_t Missile1_Z[ 4 ]; + + dword Missile2_Class[ 4 ]; + geomv_t Missile2_X[ 4 ]; + geomv_t Missile2_Y[ 4 ]; + geomv_t Missile2_Z[ 4 ]; + + geomv_t Mine1_X; + geomv_t Mine1_Y; + geomv_t Mine1_Z; + + fixed_t SpreadSpeed; + int SpreadLifeTime; + + geomv_t Spread_X[ 4 ]; + geomv_t Spread_Y; + geomv_t Spread_Z; + + fixed_t HelixSpeed; + int HelixLifeTime; + bams_t HelixCurBams; + refframe_t helix_refframes_delta; + + geomv_t Helix_X; + geomv_t Helix_Y; + geomv_t Helix_Z; + + fixed_t PhotonSpeed; + int PhotonLifeTime; + + refframe_t EmpRefframesDelta; + + geomv_t Beam_X[ 4 ]; + geomv_t Beam_Y; + geomv_t Beam_Z; + + int FumeFreq; + fixed_t FumeSpeed; + int FumeLifeTime; + int FumeCount; + + geomv_t Fume_X[ 4 ]; + geomv_t Fume_Y; + geomv_t Fume_Z; + + GenObject* Orbit; + + // afterburner info per ship + int afterburner_previous_speed; + int afterburner_active; + refframe_t afterburner_energy; +}; + +// object type "Ship_1" (Objecttype #00) +struct Ship1Obj : ShipObject { + +}; + +// object type "Ship_2" (Objecttype #01) +struct Ship2Obj : ShipObject { + +}; + + +// generic projectile object -------------------------------------------------- +// +struct ProjectileObject : GenObject { + + int LifeTime; + int LifeTimeCount; + Vertex3 DirectionVec; + fixed_t Speed; + dword HitPoints; + int Owner; // OWNER_LOCAL_PLAYER means local player is owner + Vertex3 PrevPosition; + +}; + + +// generic laser object ------------------------------------------------------- +// +struct LaserObject : ProjectileObject { + + int EnergyNeeded; + +}; + +// object type "Laser_1" (Objecttype #02) +struct Laser1Obj : LaserObject { + +}; + +// object type "Laser_2" (Objecttype #03) +struct Laser2Obj : LaserObject { + +}; + +// object type "Laser_3" (Objecttype #04) +struct Laser3Obj : LaserObject { + +}; + + +// generic missile object ----------------------------------------------------- +// +struct MissileObject : ProjectileObject { + +}; + + +// object type "Missile_1" (Objecttype #05) +struct Missile1Obj : MissileObject { + +}; + +// object type "Missile_2" (Objecttype #06) +struct Missile2Obj : MissileObject { + +}; + +// object type "Missile_3" (Objecttype #07) +struct Missile3Obj : MissileObject { + +}; + + +// generic missile object with targeting -------------------------------------- +// +struct TargetMissileObject : MissileObject { + + dword TargetObjNumber; + GenObject* TargetObjPointer; + dword Latency; + bams_t MaxRotation; + +}; + +// object type "Missile_4" (Objecttype #08) +struct Missile4Obj : TargetMissileObject { + +}; + +// object type "Missile_5" (Objecttype #09) +struct Missile5Obj : TargetMissileObject { + +}; + + +// generic extra object ------------------------------------------------------- +// +struct ExtraObject : GenObject { + + int LifeTime; + int LifeTimeCount; + bams_t SelfRotX; + bams_t SelfRotY; + bams_t SelfRotZ; + int DriftTimeout; + Vector3 DriftVec; + refframe_t VisibleFrame_Reset_Frames; + +}; + +// object type "Extra_1" (Objecttype #0A) +struct Extra1Obj : ExtraObject { + + int EnergyBoost; + +}; + +// object type "Extra_2" (Objecttype #0B) +struct Extra2Obj : ExtraObject { + + int MissileType; + int NumMissiles; + +}; + +// object type "Extra_3" (Objecttype #0C) +struct Extra3Obj : ExtraObject { + + int DeviceType; + int DeviceSpecials1; + int DeviceSpecials2; + int DeviceSpecials3; + int DeviceSpecials4; + +}; + + +// generic mine object -------------------------------------------------------- +// +struct MineObject : ExtraObject { + + int HitPoints; + int Owner; // OWNER_LOCAL_PLAYER means local player is owner + +}; + +// object type "Mine_1" (Objecttype #0D) [counts as extra object!] +struct Mine1Obj : MineObject { + +}; + + +// custom (application specific object) --------------------------------------- +// +struct CustomObject : GenObject { + + void (*callback_instant)( CustomObject *base ); + void (*callback_destroy)( CustomObject *base ); + + int (*callback_animate)( CustomObject *base ); + int (*callback_collide)( CustomObject *base ); + + void (*callback_notify)( CustomObject *base, GenObject *genobj, int event ); + int (*callback_persist)( CustomObject* base, int ToStream, void* relist ); +}; + + +// planet object -------------------------------------------------------------- +// +struct PlanetObject : CustomObject { + +}; + + +#endif // _OD_TYPES_H_ + + diff --git a/src/libparsec/include/parttype.h b/src/libparsec/include/parttype.h new file mode 100644 index 0000000..c3d7c41 --- /dev/null +++ b/src/libparsec/include/parttype.h @@ -0,0 +1,432 @@ +/* + * PARSEC HEADER + * Particle System Types and Definitions V1.46 + * + * Copyright (c) Markus Hadwiger 1997-1999 + * All Rights Reserved. + */ + +#ifndef _PARTTYPE_H_ +#define _PARTTYPE_H_ + + +// lifetime for objects that don't destroy themselves +#define INFINITE_LIFETIME 2000000000 + +// number of lightning particles in beam +#define LIGHTNING_LENGTH 256 + + +// properties of generic sphere particles +#define SPHERE_BM_INDX BM_LIGHTNING1 +#define SPHERE_REF_Z 10.0f //9.0f // 30.0f // 150.0f +#define SPHERE_PARTICLE_COLOR 255 +#define SPHERE_PARTICLES 250 //512 //200 + +#define SPHERE_EXPLOSION_DURATION 250 //400 +#define SPHERE_EXPLOSION_SPEED FIXED_TO_GEOMV( 0x2800 ) //0x07000 + +#define SPHERE_EXPLOSION_BM_INDX BM_FIREBALL3 +#define SPHERE_EXPLOSION_COLOR 168 +#define SPHERE_EXPLOSION_REF_Z 20.0f + +#define SPHERE_EXPL_PARTICLES 150 + +// properties of contracting sphere +#define SPHERE_CONTRACT_SPEED FIXED_TO_GEOMV( 0x0c00 ) +#define CONTRACTING_SPHERE_LIFETIME 8000 +#define CONTRACTING_SPHERE_EXPANSION_TIME 800 + + +// sphere animation type identifiers +#define SAT_NO_ANIMATION 0x00000600 +#define SAT_ROTATING 0x00000601 +#define SAT_EXPLODING 0x00000402 +#define SAT_PULSATING 0x00000503 +#define SAT_CONTRACTING 0x00000404 +#define SAT_STOCHASTIC_MOTION 0x00000605 + +// anim type for lightning (no "real" sphere animtype) +#define SAT_LIGHTNING 0x00000006 + +// anim type for geometry particles (no "real" sphere animtype) +#define SAT_GENOBJECT 0x00000007 + +// anim type for photon particles (no "real" sphere animtype) +#define SAT_PHOTON 0x00000008 + +// types for differently shaped spheres +#define SAT_SPHERETYPE_NORMAL 0x00000000 +#define SAT_SPHERETYPE_DISC 0x00010000 +#define SAT_SPHERETYPE_DISCWITHCORE 0x00020000 + +// special sphere flags +#define SAT_RESET_MEGASHIELD_FLAG 0x00100000 +#define SAT_DECREMENT_EXTRA_COUNTER 0x00200000 +#define SAT_AUTO_DEPLETE_PARTICLES 0x00400000 + +// special sphere anim types (combined) +#define SAT_MEGASHIELD_SPHERE ( SAT_ROTATING | SAT_RESET_MEGASHIELD_FLAG | SAT_AUTO_DEPLETE_PARTICLES ) +#define SAT_ENERGYFIELD_SPHERE ( SAT_CONTRACTING | SAT_DECREMENT_EXTRA_COUNTER ) + +// sphere animation type identifier masks +#define SAT_NEEDS_REFCOORDS_MASK 0x00000100 +#define SAT_VALID_FOR_OBJECTCENTERED_SPHERE 0x00000200 +#define SAT_VALID_FOR_PSPHERE_OBJECT 0x00000400 +#define SAT_BASIC_ANIM_MASK 0x0000ffff +#define SAT_SPHERE_TYPE_MASK 0x000f0000 +#define SAT_SPECIAL_FLAGS_MASK 0xfff00000 + + +// cluster type identifiers (pcluster_s::type) +#define CT_CONSTANT_VELOCITY 0x00000000 +#define CT_LIGHTNING 0x00001201 +#define CT_OBJECTCENTERED_SPHERE 0x00000602 +#define CT_PARTICLE_SPHERE 0x00000103 +#define CT_CALLBACK_TRAJECTORY 0x00000004 +#define CT_CUSTOMDRAW 0x00000805 +#define CT_GENOBJECT_PARTICLES 0x00000606 +#define CT_PHOTON_SPHERE 0x00000207 + +// cluster type identifier flags/masks (pcluster_s::type) +#define CT_PARTICLE_OBJ_MASK 0x00000100 +#define CT_GENOBJECTRELATIVE_OBJ_MASK 0x00000200 +#define CT_DONT_DRAW_IN_COCKPIT_MASK 0x00000400 +#define CT_DONT_DRAW_AUTOMATICALLY 0x00000800 +#define CT_DONT_DRAW_IF_BASE_VISNEVER 0x00001000 +#define CT_EXTINFO_STORAGE 0x00010000 +#define CT_DONT_CULL_WITH_GENOBJECT 0x00020000 +#define CT_CLUSTER_GLOBAL_EXTINFO 0x00040000 +#define CT_HINT_PARTICLES_IDENTICAL 0x00100000 +#define CT_HINT_PARTICLES_HAVE_EXTINFO 0x00200000 +#define CT_HINT_NO_APPEARANCE_ANIMATION 0x00400000 +#define CT_HINT_NO_POSITIONAL_ANIMATION 0x00800000 +#define CT_HINT_CULL_APPEARANCE_ANIMATION 0x01000000 +#define CT_HINT_CULL_POSITIONAL_ANIMATION 0x02000000 +#define CT_TYPEMASK 0x0000ffff +#define CT_TYPEENUMERATIONMASK 0x000000ff + + +// particle flags (field particle_s::flags) +#define PARTICLE_ACTIVE 0x00000001 +#define PARTICLE_COLLISION 0x00000002 + +// linear particle distinguishing flags/masks +#define PARTICLE_IS_HELIX 0x00010000 +#define PARTICLE_IS_PHOTON 0x00020000 +#define PARTICLE_IS_MASK 0xffff0000 + + +// single texture anim registration info -------------------------------------- +// +struct ptexreg_s { + + int deltatime; // delta time to next entry (frame) + char* texname; // name of frame texture +}; + + +// single texture trafo registration info (currently same as ptrafo_s) -------- +// +struct pxforeg_s { + + int deltatime; // delta time to next entry (frame) + imgtrafo_s* imgtrafo; // image transformation for this frame +}; + + +// registration info for particle definition ---------------------------------- +// +struct pdefreg_s { + + ptexreg_s* texinfo; // info for texture table + dword textabsize; // number of texture table entries + dword texstart; // start index + dword texrep; // repeat index + dword texend; // end index + + pxforeg_s* xfoinfo; // info for trafo table + dword xfotabsize; // number of trafo table entries + dword xfostart; // start index + dword xfoend; // end index + dword xforep; // repeat index +}; + + +// particle definition (texture animation) ------------------------------------ +// +typedef texanim_s pdef_s; + + +// registered pdef as used by PART_API::ParticleDefinitions[] ----------------- +// +struct pdefref_s { + + char* defname; // unique name for particle definition + pdef_s* def; // actual definition +}; + + +// extended definition/state info (to fields in particle_s) ------------------- +// +struct pextinfo_s { + +// extended definition + + pdef_s* partdef; // particle definition (until particle dies) + pdef_s* partdef_dest; // particle definition (during destruction) + +// extended state info + + word tex_pos; // current position in texture table + short tex_time; // time left until next advance in table + word xfo_pos; // current position in trafo table + short xfo_time; // time left until next advance in table +}; + + +// generic particle structure (size is 64 bytes) ------------------------------ +// +struct particle_s { + + int owner; // particle's owner (used for identification in netgame) + dword flags; // miscellaneous flags + int lifetime; // lifetime after which automatic destruction commences + pextinfo_s* extinfo; // extended definition/state info (may be NULL) + int bitmap; // negative means single pixel; bitmapindex otherwise + int color; // color for pixel particle + int sizebound; // LOD threshold for switch between bitmap and pixel + float ref_z; // reference z (distance for original-size bitmap) + Vertex3 position; // current position in 3-space + Vector3 velocity; // velocity vector (or current tangent to trajectory) +}; + +//NOTE: +// if ( extinfo != NULL ) field particle_s::bitmap has +// nothing to do with a bitmap anymore, but rather contains +// the iteration-type (iter_xx) with which the particle +// should be rendered in the loword and additional rendering +// flags in the hiword. + +#define PART_REND_MASK_ITER 0x0000ffff +#define PART_REND_MASK_FLAGS 0xffff0000 + +#define PART_REND_NONE 0x00000000 +#define PART_REND_NODEPTHCMP 0x00010000 // disable depth compare +#define PART_REND_NODEPTHSCALE 0x00020000 // no scale with depth coordinate +#define PART_REND_POINTVIS 0x00040000 // check point visibility + +// flag to turn sizebound off (always use texture) +#define PRT_NO_SIZEBOUND -1 + + +// header for auxiliary memblock in cluster (normally accessed via userinfo) -- +// +struct pusrinfo_s { + + int infovalid; // flag if actually valid + size_t blocksize; // size of block in bytes +}; + + +// basic particle cluster (animation/culling/memory allocation efficiency) ---- +// +struct pcluster_s { + + pcluster_s* next; // [ THE SEQUENCE OF THE FIRST THREE FIELDS ] + pcluster_s* prec; // [ *MUST NOT* BE CHANGED!! ] + particle_s* rep; // particle storage + dword type; // type of cluster (CT_xx: anim/struct-type/flags) + int numel; // current number of contained particles + int maxnumel; // maximum number of contained particles + geomv_t bdsphere; // radius of bounding sphere (0 means none) + pusrinfo_s* userinfo; // arbitrary user-defined info pertaining to cluster +}; + + +// particle cluster for linear particles -------------------------------------- +// +struct linear_pcluster_s; +typedef void (*linear_pcluster_fpt)( linear_pcluster_s*, int ); +struct linear_pcluster_s : pcluster_s { + + linear_pcluster_fpt callback; +}; + + +// particle cluster with generic callback function for animation -------------- +// +struct callback_pcluster_s; +typedef void (*callback_pcluster_fpt)( callback_pcluster_s* ); +struct callback_pcluster_s : pcluster_s { + + callback_pcluster_fpt callback; +}; + + +// particle cluster for customdraw animation ---------------------------------- +// +struct customdraw_pcluster_s; +typedef void (*customdraw_pcluster_fpt)( customdraw_pcluster_s* ); +struct customdraw_pcluster_s : pcluster_s { + + const GenObject* baseobject; // owner object + customdraw_pcluster_fpt callback; +}; + + +// particle cluster containing genobject relative particles ------------------- +// +struct objectbase_pcluster_s : pcluster_s { + + GenObject* baseobject; // pointer to object that owns cluster + objectbase_pcluster_s* attachlist; // pointer to next attached cluster + int animtype; // animation type (SAT_xx) +}; + + +// particle cluster containing position-relative particles -------------------- +// +struct particleobj_pcluster_s : pcluster_s { + + Vertex3 origin; // origin of cluster as a whole + int animtype; // animation type (SAT_xx) +}; + + +// cluster of particles comprising a sphere around a genobject ---------------- +// +struct basesphere_pcluster_s : objectbase_pcluster_s { + + int lifetime; // current lifetime of entire sphere + int max_life; // initial lifetime of entire sphere + + union { + + struct { // SAT_ROTATING + bams_t pitch; + bams_t yaw; + bams_t roll; + } rot; + + struct { // SAT_STOCHASTIC_MOTION + geomv_t radius; + int speed; + int fcount; + } rand; + }; +}; + + +// particle cluster containing genobject relative photon particles ------------ +// +struct photon_sphere_pcluster_s : objectbase_pcluster_s { + + geomv_t contraction_speed; + int contraction_time; + int cur_contraction_time; + int max_loading_time; + int firing; + int numloads; + Vertex3 center; + int alive; // current lifetime of entire sphere + bams_t pitch; + bams_t yaw; + bams_t roll; +}; + + +// cluster of particles comprising a sphere at a specific position ------------ +// +struct sphereobj_pcluster_s : particleobj_pcluster_s { + + int lifetime; // current lifetime of entire sphere + int max_life; // initial lifetime of entire sphere + + union { + + struct { // SAT_ROTATING + bams_t pitch; + bams_t yaw; + bams_t roll; + } rot; + + struct { // SAT_EXPLODING + geomv_t speed; + } expl; + + struct { // SAT_PULSATING + geomv_t amplitude; + geomv_t midradius; + bams_t frequency; // actually: angle/timeunit (omega) + bams_t current_t; // actually: current angle (omega*t) + bams_t pitch; + bams_t yaw; + bams_t roll; + } puls; + + struct { // SAT_CONTRACTING + geomv_t speed; + int expandtime; + bams_t pitch; + bams_t yaw; + bams_t roll; + } cont; + }; +}; + + +// cluster of lightning particles --------------------------------------------- +// +struct lightning_pcluster_s : objectbase_pcluster_s { + + int sizzlespeed; + int framecount; + Vertex3 beamstart1; + Vertex3 beamstart2; +}; + + +// cluster of particles that are part of an object's geometry ----------------- +// +struct genobject_pcluster_s; +typedef void (*genobject_pcluster_fpt)( genobject_pcluster_s* ); +struct genobject_pcluster_s : objectbase_pcluster_s { + + genobject_pcluster_fpt callback; +}; + + +// info how a particle should be drawn ---------------------------------------- +// +struct pdrwinfo_s { + + int bmindx; // index of particle's bitmap + int pcolor; // particle's color if not drawn as bitmap + float ref_z; // reference z (scaling info) + int sizebnd; // LOD threshold for switch between bitmap and pixel + pextinfo_s* extinfo; // extended definition/state info (may be NULL) +}; + +//NOTE: +// this structure is used as argument to functions that create a whole cluster +// of particles instead of just a single particle. at the moment these are +// PRT_CreateObjectCenteredSphere() and PRT_CreateParticleSphereObject(). +// (functions creating a single particle take a particle_s directly.) + + +// list of particle clusters -------------------------------------------------- +// +extern pcluster_s *Particles; +extern pcluster_s *CurLinearCluster; +extern pcluster_s *CustomDrawCluster; + + +// typical lower boundary of particle bitmap size ----------------------------- +// +extern int partbitmap_size_bound; + + +#endif // _PARTTYPE_H_ + + diff --git a/src/libparsec/include/platform.h b/src/libparsec/include/platform.h new file mode 100644 index 0000000..309eb72 --- /dev/null +++ b/src/libparsec/include/platform.h @@ -0,0 +1,79 @@ +#ifndef _PLATFORM_H +#define _PLATFORM_H +// platform.h - platform dependent include selection should go here. + + +/* Sick of this junk, hard coding some stuff because there's no reason for the mass + system dependent code anymore */ + +#undef SYSTEM_WIN32_UNUSED +#undef SYSTEM_LINUX_UNUSED +#undef SYSTEM_MACOSX_UNUSED + +#define SYSTEM_SDL + + +// New defines for different systems + +#if defined(_WIN32) +# define SYSTEM_TARGET_WINDOWS +// support XP, for some reason... +#define _WIN32_WINNT _WIN32_WINNT_WS03 + +#elif defined(__APPLE__) // TODO: check for iOS using TargetConditionals.h +# define SYSTEM_TARGET_OSX +#elif defined(linux) || defined(__linux) +# define SYSTEM_TARGET_LINUX +#endif + + +// compiler specification (parsec constants) ---------------------------------- +// +#if defined(_MSC_VER) +# define SYSTEM_COMPILER_MSVC +#elif defined(__clang__) +# define SYSTEM_COMPILER_CLANG +#elif defined(__GNUC__) +# if defined(__llvm__) +# define SYSTEM_COMPILER_LLVM_GCC +# else +# define SYSTEM_COMPILER_GCC +# endif +#endif + +#include "platform_sdl.h" + +//PARSEC_SERVER Needs this: +#define CPU_VENDOR_OS "i386-pc-win32" + +#if ! defined ( PARSEC_CLIENT ) && ! defined ( PARSEC_SERVER ) +#error "Error: Building libparsec must be called from the client or server make files... for now..." +#endif + +// target system specification +// These should be defined by the compiler or by the +// building IDE +/* +#if defined ( __WIN32__ ) || defined (WIN32) || defined( __linux__) || defined(__CYGWIN__) || defined(__APPLE__) +// #define SYSTEM_WIN32_UNUSED +// #undef SYSTEM_LINUX_UNUSED +// #undef SYSTEM_MACOSX_UNUSED +// #define CPU_VENDOR_OS "i386-pc-win32" +//#elif defined( __linux__ ) + #undef SYSTEM_WIN32_UNUSED + #define SYSTEM_LINUX_UNUSED + #undef SYSTEM_MACOSX_UNUSED +#ifndef __CYGWIN__ + #define __CYGWIN__ // temporary, for SDL testing. +#endif + #define CPU_VENDOR_OS "i386-pc-linux-gnu" +#elif defined( __APPLE__ ) + #undef SYSTEM_WIN32_UNUSED + #define SYSTEM_LINUX_UNUSED + #undef SYSTEM_MACOSX_UNUSED + #define CPU_VENDOR_OS "i386-pc-linux-gnu" +#endif + + */ + +#endif //_PLATFORM_H diff --git a/src/libparsec/include/platform_sdl.h b/src/libparsec/include/platform_sdl.h new file mode 100755 index 0000000..8b3b29e --- /dev/null +++ b/src/libparsec/include/platform_sdl.h @@ -0,0 +1,21 @@ +#ifndef PLATFORM_SDL_H_ +#define PLATFORM_SDL_H_ + + +// host cpu specification (parsec constants) ---------------------------------- +// +#define SYSTEM_CPU_INTEL +//#define SYSTEM_CPU_POWERPC + +#ifdef SYSTEM_TARGET_WINDOWS +#define SIGIOT SIGABRT +#endif + +#ifdef SYSTEM_SDL +//#define DISABLE_JOYSTICK_CODE // No Joystick support in Cygwin port yet. +#endif + + +#endif // !PLATFORM_SDL_H_ + + diff --git a/src/libparsec/include/sl_path.h b/src/libparsec/include/sl_path.h new file mode 100644 index 0000000..604d605 --- /dev/null +++ b/src/libparsec/include/sl_path.h @@ -0,0 +1,20 @@ +/* + * PARSEC HEADER: sl_path.h + */ + +#ifndef _SL_PATH_H_ +#define _SL_PATH_H_ + + +// sl_path.c implements the following functions +// ------------------------------------------- +// char* SYSs_ProcessPathString( char *path ); +// char* SYSs_ScanToExtension( char *fname ); +// char* SYSs_StripPath( char *fname ); +// int SYSs_AcquireScriptPath( char *path, int comtype, char *prefix ); +// int SYSs_AcquireDemoPath( char *path, char *prefix ); + + +#endif // _SL_PATH_H_ + + diff --git a/src/libparsec/include/sl_timer.h b/src/libparsec/include/sl_timer.h new file mode 100644 index 0000000..1e738ad --- /dev/null +++ b/src/libparsec/include/sl_timer.h @@ -0,0 +1,30 @@ +/* + * PARSEC HEADER: sl_timer.h + */ + +#ifndef _SL_TIMER_H_ +#define _SL_TIMER_H_ + + +// sl_timer.c implements the following functions +// --------------------------------------------- +// void SYSs_InitRefFrameCount(); +// refframe_t SYSs_GetRefFrameCount(); +// void SYSs_PauseRefFrameCount(); +// void SYSs_ResumeRefFrameCount(); +// void SYSs_Wait( refframe_t refframes ); +// int SYSs_InitFrameTimer(); +// int SYSs_KillFrameTimer(); +// int SYSs_Yield(); + +// sl_timer.c implements the following variables +// --------------------------------------------- +// extern dword FrameRate; +// extern dword FrameCounter; +// extern dword RefTimeCount; +// extern dword RefFrameCount; + + +#endif // _SL_TIMER_H_ + + diff --git a/src/libparsec/include/sw_path.h b/src/libparsec/include/sw_path.h new file mode 100644 index 0000000..60095ff --- /dev/null +++ b/src/libparsec/include/sw_path.h @@ -0,0 +1,20 @@ +/* + * PARSEC HEADER: sw_path.h + */ + +#ifndef _SW_PATH_H_ +#define _SW_PATH_H_ + + +// sw_path.c implements the following functions +// ------------------------------------------- +// char* SYSs_ProcessPathString( char *path ); +// char* SYSs_ScanToExtension( char *fname ); +// char* SYSs_StripPath( char *fname ); +// int SYSs_AcquireScriptPath( char *path, int comtype, char *prefix ); +// int SYSs_AcquireDemoPath( char *path, char *prefix ); + + +#endif // _SW_PATH_H_ + + diff --git a/src/libparsec/include/sw_timer.h b/src/libparsec/include/sw_timer.h new file mode 100755 index 0000000..d1a21db --- /dev/null +++ b/src/libparsec/include/sw_timer.h @@ -0,0 +1,30 @@ +/* + * PARSEC HEADER: sw_timer.h + */ + +#ifndef _SW_TIMER_H_ +#define _SW_TIMER_H_ + + +// sw_timer.cpp implements the following functions +// --------------------------------------------- +// void SYSs_InitRefFrameCount(); +// refframe_t SYSs_GetRefFrameCount(); +// void SYSs_PauseRefFrameCount(); +// void SYSs_ResumeRefFrameCount(); +// void SYSs_Wait( refframe_t refframes ); +// int SYSs_InitFrameTimer(); +// int SYSs_KillFrameTimer(); +// int SYSs_Yield(); + +// sw_timer.cpp implements the following variables +// --------------------------------------------- +// dword FrameRate; +// dword FrameCounter; +// dword RefTimeCount; +// dword RefFrameCount; + + +#endif // _SW_TIMER_H_ + + diff --git a/src/libparsec/include/sys_date.h b/src/libparsec/include/sys_date.h new file mode 100644 index 0000000..e29d5e0 --- /dev/null +++ b/src/libparsec/include/sys_date.h @@ -0,0 +1,27 @@ +/* + * PARSEC HEADER: sys_date.h + */ + +#ifndef _SYS_DATE_H_ +#define _SYS_DATE_H_ + + +// external variables + +extern const char build_text[]; +extern const char build_date[]; +extern const char build_time[]; + +extern const char build_comp[]; +extern const char build_bind[]; +extern const char build_endn[]; + + +// external functions + +char * SYS_SystemTime(); + + +#endif // _SYS_DATE_H_ + + diff --git a/src/libparsec/include/sys_defs.h b/src/libparsec/include/sys_defs.h new file mode 100644 index 0000000..23c7959 --- /dev/null +++ b/src/libparsec/include/sys_defs.h @@ -0,0 +1,38 @@ +/* + * PARSEC HEADER: sys_defs.h + */ + +#ifndef _SYS_DEFS_H_ +#define _SYS_DEFS_H_ + + +// ---------------------------------------------------------------------------- +// SYSTEM SUBSYSTEM (SYS) related definitions - +// ---------------------------------------------------------------------------- + +#ifdef PARSEC_CLIENT + + // external variables + + extern volatile int FrameRate; + extern volatile int FrameCounter; + extern volatile int RefTimeCount; + extern volatile int RefFrameCount; + + + // include system-specific subsystem prototypes --------------------------- + // + #include "sys_subh.h" + +#else // !PARSEC_CLIENT + + #include "sys_refframe_sv.h" + #include "sys_util_sv.h" + //#include "sys_msg_sv.h" + +#endif // !PARSEC_CLIENT + + +#endif // _SYS_DEFS_H_ + + diff --git a/src/libparsec/include/sys_file.h b/src/libparsec/include/sys_file.h new file mode 100644 index 0000000..647f4cb --- /dev/null +++ b/src/libparsec/include/sys_file.h @@ -0,0 +1,44 @@ +/* + * PARSEC HEADER: sys_file.h + */ + +#ifndef _SYS_FILE_H_ +#define _SYS_FILE_H_ + + +// external variables + +extern int num_data_packages; +extern char* package_filename[]; + +#define PSCDATA_VERSION "011" // version to match in the embedded file to verify we are good to go. + + +// external functions + +int SYS_OverridePackage( const char* oldpackname, const char* newpackname ); +int SYS_RegisterPackage( const char *packname, size_t baseofs, char *prefix ); +int SYS_AcquirePackageScripts( int comtype ); +int SYS_AcquirePackageDemos(); +int SYS_CheckDataVersion(); + +// signature compatible system file function replacements + +long int SYS_GetFileLength( const char *filename ); +FILE* SYS_fopen( const char *filename, const char *mode ); +int SYS_fclose( FILE *fp ); +size_t SYS_fread( void *buf, size_t elsize, size_t nelem, FILE *fp ); +int SYS_fseek( FILE *fp, long int offset, int whence ); +long int SYS_ftell( FILE *fp ); +int SYS_feof( FILE *fp ); +char* SYS_fgets( char *string, int n, FILE *fp ); + +int SYS_open( const char *path, int access ); +int SYS_close( int handle ); +int SYS_read( int handle, char *buffer, int len ); +long SYS_filelength( int handle ); + + +#endif // _SYS_FILE_H_ + + diff --git a/src/libparsec/include/sys_io.h b/src/libparsec/include/sys_io.h new file mode 100644 index 0000000..0d066ee --- /dev/null +++ b/src/libparsec/include/sys_io.h @@ -0,0 +1,37 @@ +/* + * PARSEC HEADER: sys_io.h + */ + +#ifndef _SYS_IO_H_ +#define _SYS_IO_H_ + + +// include header containing I/O system calls --------------------------------- + +#if defined(SYSTEM_COMPILER_GCC) || defined(SYSTEM_COMPILER_CLANG) || defined(SYSTEM_COMPILER_LLVM_GCC) + + //NOTE: + // io.h need not be included (doesn't exist and + // prototypes are declared elsewhere). + + //NOTE: + // filelength() doesn't exist; + // SYS_FILE::SYS_filelength() must not be used. + + #define filelength(x) (PANIC(0),0) + +#else // SYSTEM_COMPILER_GCC + + // simply include correct header + #include <io.h> + + #ifndef SYSTEM_COMPILER_MSVC + #include <direct.h> + #endif + +#endif // SYSTEM_COMPILER_GCC + + +#endif // _SYS_IO_H_ + + diff --git a/src/libparsec/include/sys_path.h b/src/libparsec/include/sys_path.h new file mode 100644 index 0000000..b15eef3 --- /dev/null +++ b/src/libparsec/include/sys_path.h @@ -0,0 +1,22 @@ +/* + * PARSEC HEADER: sys_path.h + */ + +#ifndef _SYS_PATH_H_ +#define _SYS_PATH_H_ + + +// ---------------------------------------------------------------------------- +// SYSTEM SUBSYSTEM (SYS) PATH PROCESSING - +// ---------------------------------------------------------------------------- + +char* SYSs_ProcessPathString( char *path ); +char* SYSs_ScanToExtension( char *fname ); +char* SYSs_StripPath( char *fname ); +int SYSs_AcquireScriptPath( char *path, int comtype, char *prefix ); +int SYSs_AcquireDemoPath( char *path, char *prefix ); + + +#endif // _SYS_PATH_H_ + + diff --git a/src/libparsec/include/sys_swap.h b/src/libparsec/include/sys_swap.h new file mode 100644 index 0000000..9cd98e0 --- /dev/null +++ b/src/libparsec/include/sys_swap.h @@ -0,0 +1,26 @@ +/* + * PARSEC HEADER: sys_swap.h + */ + +#ifndef _SYS_SWAP_H_ +#define _SYS_SWAP_H_ + + +// external functions + +void SYS_SwapPackageHeader( packageheader_s *p ); +void SYS_SwapPFileInfo( pfileinfodisk_s *p ); + +void SYS_SwapBdtHeader( BdtHeader *b ); +void SYS_SwapFntHeader( FntHeader *f ); +void SYS_SwapTexHeader( TexHeader *t ); +void SYS_SwapDemHeader( DemHeader *d ); +void SYS_SwapPfgHeader( PfgHeader *p ); +void SYS_SwapPfgTable( int fixsize, dword *geomtab, size_t tabsize ); + +void SYS_SwapGenObject( GenObject *g ); + + +#endif // _SYS_SWAP_H_ + + diff --git a/src/libparsec/include/utl_bsp.h b/src/libparsec/include/utl_bsp.h new file mode 100644 index 0000000..8ef0611 --- /dev/null +++ b/src/libparsec/include/utl_bsp.h @@ -0,0 +1,16 @@ +/* + * PARSEC HEADER: xac_bsp.h + */ + +#ifndef _XAC_BSP_H_ +#define _XAC_BSP_H_ + + +// xac_bsp.c implements the following functions +// -------------------------------------------- +// int BSP_FindColliderLine( CullBSPNode *tree, Vertex3 *v0, Vertex3 *v1, dword *colnode, geomv_t *colt ); + + +#endif + + diff --git a/src/libparsec/include/utl_clip.h b/src/libparsec/include/utl_clip.h new file mode 100644 index 0000000..9065935 --- /dev/null +++ b/src/libparsec/include/utl_clip.h @@ -0,0 +1,35 @@ +/* + * PARSEC HEADER: xac_clip.h + */ + +#ifndef _XAC_CLIP_H_ +#define _XAC_CLIP_H_ + + +// xac_clip.c implements the following functions +// --------------------------------------------- +// IterPolygon3 *CLIP_VolumeIterTriangle3( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterRectangle3( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterPolygon3( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_VolumeIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +// IterPolygon3 *CLIP_PlaneIterTriangle3( IterTriangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterRectangle3( IterRectangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterPolygon3( IterPolygon3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *plane ); +// IterPolygon3 *CLIP_PlaneIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *plane ); +// IterLine2 *CLIP_RectangleIterLine2( IterLine2 *line, Rectangle2 *rect ); +// IterLine3 *CLIP_PlaneIterLine3( IterLine3 *line, Plane3 *plane ); + + +#endif // _XAC_CLIP_H_ + + diff --git a/src/libparsec/include/utl_clpo.h b/src/libparsec/include/utl_clpo.h new file mode 100644 index 0000000..5a8fdc9 --- /dev/null +++ b/src/libparsec/include/utl_clpo.h @@ -0,0 +1,17 @@ +/* + * PARSEC HEADER: xac_clpo.h + */ + +#ifndef _XAC_CLPO_H_ +#define _XAC_CLPO_H_ + + +// xac_clpo.c implements the following functions +// --------------------------------------------- +// GenObject *CLIP_VolumeGenObject( GenObject *clipobj, Plane3 *volume, dword cullmask ); +// GenObject *CLIP_PlaneGenObject( GenObject *clipobj, Plane3 *plane ); + + +#endif + + diff --git a/src/libparsec/include/utl_cull.h b/src/libparsec/include/utl_cull.h new file mode 100644 index 0000000..e888f8c --- /dev/null +++ b/src/libparsec/include/utl_cull.h @@ -0,0 +1,21 @@ +/* + * PARSEC HEADER: xac_cull.h + */ + +#ifndef _XAC_CULL_H_ +#define _XAC_CULL_H_ + + +// xac_cull.c implements the following functions +// --------------------------------------------- +// void CULL_ReAcPointBox3( ReAcPointBox3 *reac, CullBox3 *cullbox, Plane3 *plane ); +// void CULL_ReAcIndexBox3( ReAcIndexBox3 *reac, Plane3 *plane ); +// void CULL_MakeVolumeCullVolume( Plane3 *volume, CullPlane3 *cullvolume, dword cullmask ); +// int CULL_BoxAgainstCullVolume( CullBox3 *cullbox, CullPlane3 *volume, dword *cullmask ); +// int CULL_BoxAgainstVolume( CullBox3 *cullbox, Plane3 *volume, dword *cullmask ); +// int CULL_SphereAgainstVolume( Sphere3 *sphere, Plane3 *volume, dword *cullmask ); + + +#endif + + diff --git a/src/libparsec/include/utl_fcos.h b/src/libparsec/include/utl_fcos.h new file mode 100644 index 0000000..b671cbb --- /dev/null +++ b/src/libparsec/include/utl_fcos.h @@ -0,0 +1,261 @@ + + { + 1.0000000000,0.9999988235,0.9999952938,0.9999894111,0.9999811753,0.9999705864,0.9999576446,0.9999423497,0.9999247018,0.9999047011,0.9998823475,0.9998576410,0.9998305818,0.9998011699,0.9997694054,0.9997352883, + 0.9996988187,0.9996599967,0.9996188225,0.9995752960,0.9995294175,0.9994811870,0.9994306046,0.9993776704,0.9993223846,0.9992647473,0.9992047586,0.9991424187,0.9990777278,0.9990106859,0.9989412932,0.9988695499, + 0.9987954562,0.9987190122,0.9986402182,0.9985590742,0.9984755806,0.9983897374,0.9983015449,0.9982110034,0.9981181129,0.9980228738,0.9979252862,0.9978253504,0.9977230666,0.9976184351,0.9975114561,0.9974021299, + 0.9972904567,0.9971764367,0.9970600703,0.9969413578,0.9968202993,0.9966968952,0.9965711458,0.9964430514,0.9963126122,0.9961798286,0.9960447009,0.9959072294,0.9957674145,0.9956252564,0.9954807555,0.9953339121, + 0.9951847267,0.9950331994,0.9948793308,0.9947231211,0.9945645707,0.9944036801,0.9942404495,0.9940748793,0.9939069700,0.9937367219,0.9935641355,0.9933892111,0.9932119492,0.9930323502,0.9928504145,0.9926661424, + 0.9924795346,0.9922905913,0.9920993131,0.9919057004,0.9917097537,0.9915114733,0.9913108598,0.9911079137,0.9909026354,0.9906950254,0.9904850843,0.9902728124,0.9900582103,0.9898412785,0.9896220175,0.9894004278, + 0.9891765100,0.9889502645,0.9887216920,0.9884907929,0.9882575677,0.9880220171,0.9877841416,0.9875439418,0.9873014182,0.9870565713,0.9868094018,0.9865599103,0.9863080972,0.9860539633,0.9857975092,0.9855387353, + 0.9852776424,0.9850142310,0.9847485018,0.9844804554,0.9842100924,0.9839374134,0.9836624192,0.9833851103,0.9831054874,0.9828235512,0.9825393023,0.9822527414,0.9819638691,0.9816726862,0.9813791933,0.9810833912, + 0.9807852804,0.9804848618,0.9801821360,0.9798771037,0.9795697657,0.9792601226,0.9789481753,0.9786339244,0.9783173707,0.9779985149,0.9776773578,0.9773539001,0.9770281427,0.9767000861,0.9763697313,0.9760370790, + 0.9757021300,0.9753648851,0.9750253451,0.9746835107,0.9743393828,0.9739929622,0.9736442497,0.9732932461,0.9729399522,0.9725843689,0.9722264971,0.9718663375,0.9715038910,0.9711391584,0.9707721407,0.9704028387, + 0.9700312532,0.9696573851,0.9692812354,0.9689028048,0.9685220943,0.9681391047,0.9677538371,0.9673662922,0.9669764710,0.9665843745,0.9661900034,0.9657933589,0.9653944417,0.9649932529,0.9645897933,0.9641840640, + 0.9637760658,0.9633657998,0.9629532669,0.9625384680,0.9621214043,0.9617020765,0.9612804858,0.9608566331,0.9604305194,0.9600021457,0.9595715131,0.9591386225,0.9587034749,0.9582660714,0.9578264130,0.9573845008, + 0.9569403357,0.9564939189,0.9560452513,0.9555943341,0.9551411683,0.9546857549,0.9542280951,0.9537681899,0.9533060404,0.9528416476,0.9523750127,0.9519061368,0.9514350210,0.9509616663,0.9504860739,0.9500082450, + 0.9495281806,0.9490458819,0.9485613499,0.9480745859,0.9475855910,0.9470943664,0.9466009131,0.9461052324,0.9456073254,0.9451071933,0.9446048373,0.9441002585,0.9435934582,0.9430844375,0.9425731976,0.9420597398, + 0.9415440652,0.9410261751,0.9405060706,0.9399837530,0.9394592236,0.9389324835,0.9384035341,0.9378723764,0.9373390119,0.9368034417,0.9362656672,0.9357256895,0.9351835099,0.9346391298,0.9340925504,0.9335437730, + 0.9329927988,0.9324396293,0.9318842656,0.9313267091,0.9307669611,0.9302050229,0.9296408958,0.9290745813,0.9285060805,0.9279353948,0.9273625257,0.9267874743,0.9262102421,0.9256308305,0.9250492408,0.9244654743, + 0.9238795325,0.9232914167,0.9227011283,0.9221086687,0.9215140393,0.9209172415,0.9203182767,0.9197171463,0.9191138517,0.9185083943,0.9179007756,0.9172909970,0.9166790599,0.9160649658,0.9154487161,0.9148303122, + 0.9142097557,0.9135870479,0.9129621904,0.9123351846,0.9117060320,0.9110747341,0.9104412923,0.9098057081,0.9091679831,0.9085281187,0.9078861165,0.9072419779,0.9065957045,0.9059472978,0.9052967593,0.9046440906, + 0.9039892931,0.9033323685,0.9026733182,0.9020121439,0.9013488470,0.9006834292,0.9000158920,0.8993462370,0.8986744657,0.8980005797,0.8973245807,0.8966464702,0.8959662498,0.8952839210,0.8945994856,0.8939129451, + 0.8932243012,0.8925335554,0.8918407094,0.8911457648,0.8904487232,0.8897495864,0.8890483559,0.8883450333,0.8876396204,0.8869321188,0.8862225301,0.8855108561,0.8847970984,0.8840812587,0.8833633387,0.8826433400, + 0.8819212643,0.8811971135,0.8804708891,0.8797425928,0.8790122264,0.8782797917,0.8775452902,0.8768087238,0.8760700942,0.8753294031,0.8745866523,0.8738418435,0.8730949784,0.8723460589,0.8715950867,0.8708420635, + 0.8700869911,0.8693298713,0.8685707060,0.8678094968,0.8670462455,0.8662809540,0.8655136241,0.8647442575,0.8639728561,0.8631994217,0.8624239561,0.8616464611,0.8608669386,0.8600853904,0.8593018184,0.8585162243, + 0.8577286100,0.8569389774,0.8561473284,0.8553536647,0.8545579884,0.8537603011,0.8529606049,0.8521589016,0.8513551931,0.8505494813,0.8497417680,0.8489320552,0.8481203448,0.8473066387,0.8464909388,0.8456732470, + 0.8448535652,0.8440318955,0.8432082396,0.8423825996,0.8415549774,0.8407253750,0.8398937942,0.8390602371,0.8382247056,0.8373872016,0.8365477272,0.8357062844,0.8348628750,0.8340175011,0.8331701647,0.8323208678, + 0.8314696123,0.8306164003,0.8297612338,0.8289041148,0.8280450453,0.8271840273,0.8263210628,0.8254561540,0.8245893028,0.8237205112,0.8228497814,0.8219771153,0.8211025150,0.8202259826,0.8193475201,0.8184671296, + 0.8175848132,0.8167005729,0.8158144108,0.8149263291,0.8140363297,0.8131444148,0.8122505866,0.8113548470,0.8104571983,0.8095576424,0.8086561816,0.8077528179,0.8068475535,0.8059403906,0.8050313311,0.8041203774, + 0.8032075315,0.8022927955,0.8013761717,0.8004576622,0.7995372691,0.7986149946,0.7976908409,0.7967648102,0.7958369046,0.7949071263,0.7939754776,0.7930419605,0.7921065773,0.7911693302,0.7902302214,0.7892892532, + 0.7883464276,0.7874017470,0.7864552136,0.7855068296,0.7845565972,0.7836045186,0.7826505962,0.7816948321,0.7807372286,0.7797777879,0.7788165124,0.7778534042,0.7768884657,0.7759216990,0.7749531066,0.7739826906, + 0.7730104534,0.7720363972,0.7710605243,0.7700828370,0.7691033376,0.7681220285,0.7671389119,0.7661539902,0.7651672656,0.7641787405,0.7631884173,0.7621962981,0.7612023855,0.7602066817,0.7592091890,0.7582099098, + 0.7572088465,0.7562060014,0.7552013769,0.7541949753,0.7531867990,0.7521768504,0.7511651319,0.7501516458,0.7491363945,0.7481193805,0.7471006060,0.7460800735,0.7450577854,0.7440337442,0.7430079521,0.7419804117, + 0.7409511254,0.7399200955,0.7388873245,0.7378528148,0.7368165689,0.7357785892,0.7347388781,0.7336974381,0.7326542717,0.7316093812,0.7305627692,0.7295144381,0.7284643904,0.7274126286,0.7263591551,0.7253039724, + 0.7242470830,0.7231884893,0.7221281939,0.7210661993,0.7200025080,0.7189371224,0.7178700451,0.7168012785,0.7157308253,0.7146586879,0.7135848688,0.7125093706,0.7114321957,0.7103533469,0.7092728264,0.7081906370, + 0.7071067812,0.7060212614,0.7049340804,0.7038452405,0.7027547445,0.7016625947,0.7005687939,0.6994733446,0.6983762494,0.6972775108,0.6961771315,0.6950751140,0.6939714609,0.6928661748,0.6917592584,0.6906507141, + 0.6895405447,0.6884287528,0.6873153409,0.6862003117,0.6850836678,0.6839654118,0.6828455464,0.6817240742,0.6806009978,0.6794763199,0.6783500431,0.6772221701,0.6760927036,0.6749616461,0.6738290004,0.6726947691, + 0.6715589548,0.6704215604,0.6692825883,0.6681420414,0.6669999223,0.6658562337,0.6647109782,0.6635641586,0.6624157776,0.6612658378,0.6601143421,0.6589612930,0.6578066933,0.6566505457,0.6554928530,0.6543336178, + 0.6531728430,0.6520105311,0.6508466850,0.6496813074,0.6485144010,0.6473459686,0.6461760130,0.6450045368,0.6438315429,0.6426570340,0.6414810128,0.6403034822,0.6391244449,0.6379439036,0.6367618612,0.6355783205, + 0.6343932842,0.6332067551,0.6320187359,0.6308292296,0.6296382389,0.6284457666,0.6272518155,0.6260563884,0.6248594881,0.6236611175,0.6224612794,0.6212599765,0.6200572118,0.6188529880,0.6176473079,0.6164401745, + 0.6152315906,0.6140215589,0.6128100824,0.6115971639,0.6103828063,0.6091670123,0.6079497850,0.6067311270,0.6055110414,0.6042895309,0.6030665985,0.6018422471,0.6006164794,0.5993892984,0.5981607070,0.5969307081, + 0.5956993045,0.5944664992,0.5932322950,0.5919966950,0.5907597019,0.5895213186,0.5882815482,0.5870403935,0.5857978575,0.5845539430,0.5833086529,0.5820619903,0.5808139581,0.5795645591,0.5783137964,0.5770616729, + 0.5758081914,0.5745533550,0.5732971667,0.5720396293,0.5707807459,0.5695205193,0.5682589527,0.5669960488,0.5657318108,0.5644662415,0.5631993440,0.5619311212,0.5606615762,0.5593907119,0.5581185312,0.5568450373, + 0.5555702330,0.5542941215,0.5530167056,0.5517379884,0.5504579729,0.5491766622,0.5478940592,0.5466101669,0.5453249884,0.5440385267,0.5427507849,0.5414617659,0.5401714727,0.5388799085,0.5375870763,0.5362929791, + 0.5349976199,0.5337010018,0.5324031279,0.5311040012,0.5298036247,0.5285020015,0.5271991348,0.5258950275,0.5245896827,0.5232831035,0.5219752929,0.5206662541,0.5193559902,0.5180445041,0.5167317990,0.5154178780, + 0.5141027442,0.5127864006,0.5114688504,0.5101500967,0.5088301425,0.5075089911,0.5061866453,0.5048631085,0.5035383837,0.5022124740,0.5008853826,0.4995571125,0.4982276670,0.4968970490,0.4955652618,0.4942323085, + 0.4928981922,0.4915629161,0.4902264833,0.4888888969,0.4875501601,0.4862102761,0.4848692480,0.4835270789,0.4821837721,0.4808393306,0.4794937577,0.4781470564,0.4767992301,0.4754502817,0.4741002147,0.4727490320, + 0.4713967368,0.4700433325,0.4686888220,0.4673332087,0.4659764958,0.4646186863,0.4632597836,0.4618997907,0.4605387110,0.4591765475,0.4578133036,0.4564489824,0.4550835871,0.4537171210,0.4523495872,0.4509809890, + 0.4496113297,0.4482406123,0.4468688402,0.4454960165,0.4441221446,0.4427472276,0.4413712687,0.4399942713,0.4386162385,0.4372371737,0.4358570799,0.4344759606,0.4330938189,0.4317106580,0.4303264813,0.4289412921, + 0.4275550934,0.4261678887,0.4247796812,0.4233904741,0.4220002708,0.4206090744,0.4192168884,0.4178237158,0.4164295601,0.4150344245,0.4136383122,0.4122412267,0.4108431711,0.4094441487,0.4080441629,0.4066432169, + 0.4052413140,0.4038384576,0.4024346509,0.4010298972,0.3996241998,0.3982175622,0.3968099874,0.3954014789,0.3939920401,0.3925816741,0.3911703843,0.3897581741,0.3883450467,0.3869310055,0.3855160538,0.3841001950, + 0.3826834324,0.3812657692,0.3798472089,0.3784277548,0.3770074102,0.3755861785,0.3741640630,0.3727410670,0.3713171940,0.3698924471,0.3684668300,0.3670403457,0.3656129978,0.3641847896,0.3627557244,0.3613258056, + 0.3598950365,0.3584634206,0.3570309612,0.3555976617,0.3541635254,0.3527285558,0.3512927561,0.3498561298,0.3484186802,0.3469804108,0.3455413250,0.3441014260,0.3426607173,0.3412192023,0.3397768844,0.3383337670, + 0.3368898534,0.3354451471,0.3339996514,0.3325533699,0.3311063058,0.3296584625,0.3282098436,0.3267604523,0.3253102922,0.3238593665,0.3224076788,0.3209552324,0.3195020308,0.3180480774,0.3165933756,0.3151379288, + 0.3136817404,0.3122248139,0.3107671527,0.3093087603,0.3078496400,0.3063897954,0.3049292297,0.3034679466,0.3020059493,0.3005432414,0.2990798263,0.2976157074,0.2961508882,0.2946853722,0.2932191627,0.2917522632, + 0.2902846773,0.2888164082,0.2873474595,0.2858778347,0.2844075372,0.2829365705,0.2814649379,0.2799926431,0.2785196894,0.2770460803,0.2755718193,0.2740969099,0.2726213554,0.2711451595,0.2696683256,0.2681908571, + 0.2667127575,0.2652340303,0.2637546790,0.2622747070,0.2607941179,0.2593129151,0.2578311022,0.2563486825,0.2548656596,0.2533820370,0.2518978182,0.2504130066,0.2489276057,0.2474416192,0.2459550503,0.2444679027, + 0.2429801799,0.2414918853,0.2400030224,0.2385135948,0.2370236060,0.2355330594,0.2340419586,0.2325503070,0.2310581083,0.2295653658,0.2280720832,0.2265782638,0.2250839114,0.2235890292,0.2220936210,0.2205976901, + 0.2191012402,0.2176042746,0.2161067971,0.2146088110,0.2131103199,0.2116113274,0.2101118369,0.2086118520,0.2071113762,0.2056104131,0.2041089661,0.2026070388,0.2011046348,0.1996017576,0.1980984107,0.1965945977, + 0.1950903220,0.1935855873,0.1920803970,0.1905747548,0.1890686641,0.1875621286,0.1860551517,0.1845477369,0.1830398880,0.1815316083,0.1800229014,0.1785137709,0.1770042204,0.1754942534,0.1739838734,0.1724730840, + 0.1709618888,0.1694502912,0.1679382950,0.1664259035,0.1649131205,0.1633999494,0.1618863938,0.1603724572,0.1588581433,0.1573434556,0.1558283977,0.1543129730,0.1527971853,0.1512810380,0.1497645347,0.1482476790, + 0.1467304745,0.1452129247,0.1436950332,0.1421768035,0.1406582393,0.1391393442,0.1376201216,0.1361005752,0.1345807085,0.1330605252,0.1315400287,0.1300192227,0.1284981108,0.1269766965,0.1254549834,0.1239329751, + 0.1224106752,0.1208880872,0.1193652148,0.1178420615,0.1163186309,0.1147949266,0.1132709522,0.1117467112,0.1102222073,0.1086974440,0.1071724250,0.1056471537,0.1041216339,0.1025958690,0.1010698628,0.0995436187, + 0.0980171403,0.0964904314,0.0949634953,0.0934363358,0.0919089565,0.0903813609,0.0888535526,0.0873255352,0.0857973123,0.0842688876,0.0827402645,0.0812114468,0.0796824380,0.0781532416,0.0766238614,0.0750943008, + 0.0735645636,0.0720346532,0.0705045734,0.0689743276,0.0674439196,0.0659133528,0.0643826309,0.0628517576,0.0613207363,0.0597895707,0.0582582645,0.0567268212,0.0551952443,0.0536635377,0.0521317047,0.0505997490, + 0.0490676743,0.0475354842,0.0460031821,0.0444707719,0.0429382569,0.0414056410,0.0398729276,0.0383401204,0.0368072229,0.0352742389,0.0337411719,0.0322080254,0.0306748032,0.0291415088,0.0276081458,0.0260747178, + 0.0245412285,0.0230076815,0.0214740803,0.0199404286,0.0184067299,0.0168729879,0.0153392063,0.0138053885,0.0122715383,0.0107376592,0.0092037548,0.0076698287,0.0061358846,0.0046019261,0.0030679568,0.0015339802, + 0.0000000000,-0.0015339802,-0.0030679568,-0.0046019261,-0.0061358846,-0.0076698287,-0.0092037548,-0.0107376592,-0.0122715383,-0.0138053885,-0.0153392063,-0.0168729879,-0.0184067299,-0.0199404286,-0.0214740803,-0.0230076815, + -0.0245412285,-0.0260747178,-0.0276081458,-0.0291415088,-0.0306748032,-0.0322080254,-0.0337411719,-0.0352742389,-0.0368072229,-0.0383401204,-0.0398729276,-0.0414056410,-0.0429382569,-0.0444707719,-0.0460031821,-0.0475354842, + -0.0490676743,-0.0505997490,-0.0521317047,-0.0536635377,-0.0551952443,-0.0567268212,-0.0582582645,-0.0597895707,-0.0613207363,-0.0628517576,-0.0643826309,-0.0659133528,-0.0674439196,-0.0689743276,-0.0705045734,-0.0720346532, + -0.0735645636,-0.0750943008,-0.0766238614,-0.0781532416,-0.0796824380,-0.0812114468,-0.0827402645,-0.0842688876,-0.0857973123,-0.0873255352,-0.0888535526,-0.0903813609,-0.0919089565,-0.0934363358,-0.0949634953,-0.0964904314, + -0.0980171403,-0.0995436187,-0.1010698628,-0.1025958690,-0.1041216339,-0.1056471537,-0.1071724250,-0.1086974440,-0.1102222073,-0.1117467112,-0.1132709522,-0.1147949266,-0.1163186309,-0.1178420615,-0.1193652148,-0.1208880872, + -0.1224106752,-0.1239329751,-0.1254549834,-0.1269766965,-0.1284981108,-0.1300192227,-0.1315400287,-0.1330605252,-0.1345807085,-0.1361005752,-0.1376201216,-0.1391393442,-0.1406582393,-0.1421768035,-0.1436950332,-0.1452129247, + -0.1467304745,-0.1482476790,-0.1497645347,-0.1512810380,-0.1527971853,-0.1543129730,-0.1558283977,-0.1573434556,-0.1588581433,-0.1603724572,-0.1618863938,-0.1633999494,-0.1649131205,-0.1664259035,-0.1679382950,-0.1694502912, + -0.1709618888,-0.1724730840,-0.1739838734,-0.1754942534,-0.1770042204,-0.1785137709,-0.1800229014,-0.1815316083,-0.1830398880,-0.1845477369,-0.1860551517,-0.1875621286,-0.1890686641,-0.1905747548,-0.1920803970,-0.1935855873, + -0.1950903220,-0.1965945977,-0.1980984107,-0.1996017576,-0.2011046348,-0.2026070388,-0.2041089661,-0.2056104131,-0.2071113762,-0.2086118520,-0.2101118369,-0.2116113274,-0.2131103199,-0.2146088110,-0.2161067971,-0.2176042746, + -0.2191012402,-0.2205976901,-0.2220936210,-0.2235890292,-0.2250839114,-0.2265782638,-0.2280720832,-0.2295653658,-0.2310581083,-0.2325503070,-0.2340419586,-0.2355330594,-0.2370236060,-0.2385135948,-0.2400030224,-0.2414918853, + -0.2429801799,-0.2444679027,-0.2459550503,-0.2474416192,-0.2489276057,-0.2504130066,-0.2518978182,-0.2533820370,-0.2548656596,-0.2563486825,-0.2578311022,-0.2593129151,-0.2607941179,-0.2622747070,-0.2637546790,-0.2652340303, + -0.2667127575,-0.2681908571,-0.2696683256,-0.2711451595,-0.2726213554,-0.2740969099,-0.2755718193,-0.2770460803,-0.2785196894,-0.2799926431,-0.2814649379,-0.2829365705,-0.2844075372,-0.2858778347,-0.2873474595,-0.2888164082, + -0.2902846773,-0.2917522632,-0.2932191627,-0.2946853722,-0.2961508882,-0.2976157074,-0.2990798263,-0.3005432414,-0.3020059493,-0.3034679466,-0.3049292297,-0.3063897954,-0.3078496400,-0.3093087603,-0.3107671527,-0.3122248139, + -0.3136817404,-0.3151379288,-0.3165933756,-0.3180480774,-0.3195020308,-0.3209552324,-0.3224076788,-0.3238593665,-0.3253102922,-0.3267604523,-0.3282098436,-0.3296584625,-0.3311063058,-0.3325533699,-0.3339996514,-0.3354451471, + -0.3368898534,-0.3383337670,-0.3397768844,-0.3412192023,-0.3426607173,-0.3441014260,-0.3455413250,-0.3469804108,-0.3484186802,-0.3498561298,-0.3512927561,-0.3527285558,-0.3541635254,-0.3555976617,-0.3570309612,-0.3584634206, + -0.3598950365,-0.3613258056,-0.3627557244,-0.3641847896,-0.3656129978,-0.3670403457,-0.3684668300,-0.3698924471,-0.3713171940,-0.3727410670,-0.3741640630,-0.3755861785,-0.3770074102,-0.3784277548,-0.3798472089,-0.3812657692, + -0.3826834324,-0.3841001950,-0.3855160538,-0.3869310055,-0.3883450467,-0.3897581741,-0.3911703843,-0.3925816741,-0.3939920401,-0.3954014789,-0.3968099874,-0.3982175622,-0.3996241998,-0.4010298972,-0.4024346509,-0.4038384576, + -0.4052413140,-0.4066432169,-0.4080441629,-0.4094441487,-0.4108431711,-0.4122412267,-0.4136383122,-0.4150344245,-0.4164295601,-0.4178237158,-0.4192168884,-0.4206090744,-0.4220002708,-0.4233904741,-0.4247796812,-0.4261678887, + -0.4275550934,-0.4289412921,-0.4303264813,-0.4317106580,-0.4330938189,-0.4344759606,-0.4358570799,-0.4372371737,-0.4386162385,-0.4399942713,-0.4413712687,-0.4427472276,-0.4441221446,-0.4454960165,-0.4468688402,-0.4482406123, + -0.4496113297,-0.4509809890,-0.4523495872,-0.4537171210,-0.4550835871,-0.4564489824,-0.4578133036,-0.4591765475,-0.4605387110,-0.4618997907,-0.4632597836,-0.4646186863,-0.4659764958,-0.4673332087,-0.4686888220,-0.4700433325, + -0.4713967368,-0.4727490320,-0.4741002147,-0.4754502817,-0.4767992301,-0.4781470564,-0.4794937577,-0.4808393306,-0.4821837721,-0.4835270789,-0.4848692480,-0.4862102761,-0.4875501601,-0.4888888969,-0.4902264833,-0.4915629161, + -0.4928981922,-0.4942323085,-0.4955652618,-0.4968970490,-0.4982276670,-0.4995571125,-0.5008853826,-0.5022124740,-0.5035383837,-0.5048631085,-0.5061866453,-0.5075089911,-0.5088301425,-0.5101500967,-0.5114688504,-0.5127864006, + -0.5141027442,-0.5154178780,-0.5167317990,-0.5180445041,-0.5193559902,-0.5206662541,-0.5219752929,-0.5232831035,-0.5245896827,-0.5258950275,-0.5271991348,-0.5285020015,-0.5298036247,-0.5311040012,-0.5324031279,-0.5337010018, + -0.5349976199,-0.5362929791,-0.5375870763,-0.5388799085,-0.5401714727,-0.5414617659,-0.5427507849,-0.5440385267,-0.5453249884,-0.5466101669,-0.5478940592,-0.5491766622,-0.5504579729,-0.5517379884,-0.5530167056,-0.5542941215, + -0.5555702330,-0.5568450373,-0.5581185312,-0.5593907119,-0.5606615762,-0.5619311212,-0.5631993440,-0.5644662415,-0.5657318108,-0.5669960488,-0.5682589527,-0.5695205193,-0.5707807459,-0.5720396293,-0.5732971667,-0.5745533550, + -0.5758081914,-0.5770616729,-0.5783137964,-0.5795645591,-0.5808139581,-0.5820619903,-0.5833086529,-0.5845539430,-0.5857978575,-0.5870403935,-0.5882815482,-0.5895213186,-0.5907597019,-0.5919966950,-0.5932322950,-0.5944664992, + -0.5956993045,-0.5969307081,-0.5981607070,-0.5993892984,-0.6006164794,-0.6018422471,-0.6030665985,-0.6042895309,-0.6055110414,-0.6067311270,-0.6079497850,-0.6091670123,-0.6103828063,-0.6115971639,-0.6128100824,-0.6140215589, + -0.6152315906,-0.6164401745,-0.6176473079,-0.6188529880,-0.6200572118,-0.6212599765,-0.6224612794,-0.6236611175,-0.6248594881,-0.6260563884,-0.6272518155,-0.6284457666,-0.6296382389,-0.6308292296,-0.6320187359,-0.6332067551, + -0.6343932842,-0.6355783205,-0.6367618612,-0.6379439036,-0.6391244449,-0.6403034822,-0.6414810128,-0.6426570340,-0.6438315429,-0.6450045368,-0.6461760130,-0.6473459686,-0.6485144010,-0.6496813074,-0.6508466850,-0.6520105311, + -0.6531728430,-0.6543336178,-0.6554928530,-0.6566505457,-0.6578066933,-0.6589612930,-0.6601143421,-0.6612658378,-0.6624157776,-0.6635641586,-0.6647109782,-0.6658562337,-0.6669999223,-0.6681420414,-0.6692825883,-0.6704215604, + -0.6715589548,-0.6726947691,-0.6738290004,-0.6749616461,-0.6760927036,-0.6772221701,-0.6783500431,-0.6794763199,-0.6806009978,-0.6817240742,-0.6828455464,-0.6839654118,-0.6850836678,-0.6862003117,-0.6873153409,-0.6884287528, + -0.6895405447,-0.6906507141,-0.6917592584,-0.6928661748,-0.6939714609,-0.6950751140,-0.6961771315,-0.6972775108,-0.6983762494,-0.6994733446,-0.7005687939,-0.7016625947,-0.7027547445,-0.7038452405,-0.7049340804,-0.7060212614, + -0.7071067812,-0.7081906370,-0.7092728264,-0.7103533469,-0.7114321957,-0.7125093706,-0.7135848688,-0.7146586879,-0.7157308253,-0.7168012785,-0.7178700451,-0.7189371224,-0.7200025080,-0.7210661993,-0.7221281939,-0.7231884893, + -0.7242470830,-0.7253039724,-0.7263591551,-0.7274126286,-0.7284643904,-0.7295144381,-0.7305627692,-0.7316093812,-0.7326542717,-0.7336974381,-0.7347388781,-0.7357785892,-0.7368165689,-0.7378528148,-0.7388873245,-0.7399200955, + -0.7409511254,-0.7419804117,-0.7430079521,-0.7440337442,-0.7450577854,-0.7460800735,-0.7471006060,-0.7481193805,-0.7491363945,-0.7501516458,-0.7511651319,-0.7521768504,-0.7531867990,-0.7541949753,-0.7552013769,-0.7562060014, + -0.7572088465,-0.7582099098,-0.7592091890,-0.7602066817,-0.7612023855,-0.7621962981,-0.7631884173,-0.7641787405,-0.7651672656,-0.7661539902,-0.7671389119,-0.7681220285,-0.7691033376,-0.7700828370,-0.7710605243,-0.7720363972, + -0.7730104534,-0.7739826906,-0.7749531066,-0.7759216990,-0.7768884657,-0.7778534042,-0.7788165124,-0.7797777879,-0.7807372286,-0.7816948321,-0.7826505962,-0.7836045186,-0.7845565972,-0.7855068296,-0.7864552136,-0.7874017470, + -0.7883464276,-0.7892892532,-0.7902302214,-0.7911693302,-0.7921065773,-0.7930419605,-0.7939754776,-0.7949071263,-0.7958369046,-0.7967648102,-0.7976908409,-0.7986149946,-0.7995372691,-0.8004576622,-0.8013761717,-0.8022927955, + -0.8032075315,-0.8041203774,-0.8050313311,-0.8059403906,-0.8068475535,-0.8077528179,-0.8086561816,-0.8095576424,-0.8104571983,-0.8113548470,-0.8122505866,-0.8131444148,-0.8140363297,-0.8149263291,-0.8158144108,-0.8167005729, + -0.8175848132,-0.8184671296,-0.8193475201,-0.8202259826,-0.8211025150,-0.8219771153,-0.8228497814,-0.8237205112,-0.8245893028,-0.8254561540,-0.8263210628,-0.8271840273,-0.8280450453,-0.8289041148,-0.8297612338,-0.8306164003, + -0.8314696123,-0.8323208678,-0.8331701647,-0.8340175011,-0.8348628750,-0.8357062844,-0.8365477272,-0.8373872016,-0.8382247056,-0.8390602371,-0.8398937942,-0.8407253750,-0.8415549774,-0.8423825996,-0.8432082396,-0.8440318955, + -0.8448535652,-0.8456732470,-0.8464909388,-0.8473066387,-0.8481203448,-0.8489320552,-0.8497417680,-0.8505494813,-0.8513551931,-0.8521589016,-0.8529606049,-0.8537603011,-0.8545579884,-0.8553536647,-0.8561473284,-0.8569389774, + -0.8577286100,-0.8585162243,-0.8593018184,-0.8600853904,-0.8608669386,-0.8616464611,-0.8624239561,-0.8631994217,-0.8639728561,-0.8647442575,-0.8655136241,-0.8662809540,-0.8670462455,-0.8678094968,-0.8685707060,-0.8693298713, + -0.8700869911,-0.8708420635,-0.8715950867,-0.8723460589,-0.8730949784,-0.8738418435,-0.8745866523,-0.8753294031,-0.8760700942,-0.8768087238,-0.8775452902,-0.8782797917,-0.8790122264,-0.8797425928,-0.8804708891,-0.8811971135, + -0.8819212643,-0.8826433400,-0.8833633387,-0.8840812587,-0.8847970984,-0.8855108561,-0.8862225301,-0.8869321188,-0.8876396204,-0.8883450333,-0.8890483559,-0.8897495864,-0.8904487232,-0.8911457648,-0.8918407094,-0.8925335554, + -0.8932243012,-0.8939129451,-0.8945994856,-0.8952839210,-0.8959662498,-0.8966464702,-0.8973245807,-0.8980005797,-0.8986744657,-0.8993462370,-0.9000158920,-0.9006834292,-0.9013488470,-0.9020121439,-0.9026733182,-0.9033323685, + -0.9039892931,-0.9046440906,-0.9052967593,-0.9059472978,-0.9065957045,-0.9072419779,-0.9078861165,-0.9085281187,-0.9091679831,-0.9098057081,-0.9104412923,-0.9110747341,-0.9117060320,-0.9123351846,-0.9129621904,-0.9135870479, + -0.9142097557,-0.9148303122,-0.9154487161,-0.9160649658,-0.9166790599,-0.9172909970,-0.9179007756,-0.9185083943,-0.9191138517,-0.9197171463,-0.9203182767,-0.9209172415,-0.9215140393,-0.9221086687,-0.9227011283,-0.9232914167, + -0.9238795325,-0.9244654743,-0.9250492408,-0.9256308305,-0.9262102421,-0.9267874743,-0.9273625257,-0.9279353948,-0.9285060805,-0.9290745813,-0.9296408958,-0.9302050229,-0.9307669611,-0.9313267091,-0.9318842656,-0.9324396293, + -0.9329927988,-0.9335437730,-0.9340925504,-0.9346391298,-0.9351835099,-0.9357256895,-0.9362656672,-0.9368034417,-0.9373390119,-0.9378723764,-0.9384035341,-0.9389324835,-0.9394592236,-0.9399837530,-0.9405060706,-0.9410261751, + -0.9415440652,-0.9420597398,-0.9425731976,-0.9430844375,-0.9435934582,-0.9441002585,-0.9446048373,-0.9451071933,-0.9456073254,-0.9461052324,-0.9466009131,-0.9470943664,-0.9475855910,-0.9480745859,-0.9485613499,-0.9490458819, + -0.9495281806,-0.9500082450,-0.9504860739,-0.9509616663,-0.9514350210,-0.9519061368,-0.9523750127,-0.9528416476,-0.9533060404,-0.9537681899,-0.9542280951,-0.9546857549,-0.9551411683,-0.9555943341,-0.9560452514,-0.9564939189, + -0.9569403357,-0.9573845008,-0.9578264130,-0.9582660714,-0.9587034749,-0.9591386225,-0.9595715131,-0.9600021457,-0.9604305194,-0.9608566331,-0.9612804858,-0.9617020765,-0.9621214043,-0.9625384680,-0.9629532669,-0.9633657998, + -0.9637760658,-0.9641840640,-0.9645897933,-0.9649932529,-0.9653944417,-0.9657933589,-0.9661900034,-0.9665843745,-0.9669764710,-0.9673662922,-0.9677538371,-0.9681391047,-0.9685220943,-0.9689028048,-0.9692812354,-0.9696573851, + -0.9700312532,-0.9704028387,-0.9707721407,-0.9711391584,-0.9715038910,-0.9718663375,-0.9722264971,-0.9725843689,-0.9729399522,-0.9732932461,-0.9736442497,-0.9739929622,-0.9743393828,-0.9746835107,-0.9750253451,-0.9753648851, + -0.9757021300,-0.9760370790,-0.9763697313,-0.9767000861,-0.9770281427,-0.9773539001,-0.9776773578,-0.9779985149,-0.9783173707,-0.9786339244,-0.9789481753,-0.9792601226,-0.9795697657,-0.9798771037,-0.9801821360,-0.9804848618, + -0.9807852804,-0.9810833912,-0.9813791933,-0.9816726862,-0.9819638691,-0.9822527414,-0.9825393023,-0.9828235512,-0.9831054874,-0.9833851103,-0.9836624192,-0.9839374134,-0.9842100924,-0.9844804554,-0.9847485018,-0.9850142310, + -0.9852776424,-0.9855387353,-0.9857975092,-0.9860539633,-0.9863080972,-0.9865599103,-0.9868094018,-0.9870565713,-0.9873014182,-0.9875439418,-0.9877841416,-0.9880220171,-0.9882575677,-0.9884907929,-0.9887216920,-0.9889502645, + -0.9891765100,-0.9894004278,-0.9896220175,-0.9898412785,-0.9900582103,-0.9902728124,-0.9904850843,-0.9906950254,-0.9909026354,-0.9911079137,-0.9913108598,-0.9915114733,-0.9917097537,-0.9919057004,-0.9920993131,-0.9922905913, + -0.9924795346,-0.9926661424,-0.9928504145,-0.9930323502,-0.9932119492,-0.9933892111,-0.9935641355,-0.9937367219,-0.9939069700,-0.9940748793,-0.9942404495,-0.9944036801,-0.9945645707,-0.9947231211,-0.9948793308,-0.9950331994, + -0.9951847267,-0.9953339121,-0.9954807555,-0.9956252564,-0.9957674145,-0.9959072294,-0.9960447009,-0.9961798286,-0.9963126122,-0.9964430514,-0.9965711458,-0.9966968952,-0.9968202993,-0.9969413578,-0.9970600703,-0.9971764367, + -0.9972904567,-0.9974021299,-0.9975114561,-0.9976184351,-0.9977230666,-0.9978253504,-0.9979252862,-0.9980228738,-0.9981181129,-0.9982110034,-0.9983015449,-0.9983897374,-0.9984755806,-0.9985590742,-0.9986402182,-0.9987190122, + -0.9987954562,-0.9988695499,-0.9989412932,-0.9990106859,-0.9990777278,-0.9991424187,-0.9992047586,-0.9992647473,-0.9993223846,-0.9993776704,-0.9994306046,-0.9994811870,-0.9995294175,-0.9995752960,-0.9996188225,-0.9996599967, + -0.9996988187,-0.9997352883,-0.9997694054,-0.9998011699,-0.9998305818,-0.9998576410,-0.9998823475,-0.9999047011,-0.9999247018,-0.9999423497,-0.9999576446,-0.9999705864,-0.9999811753,-0.9999894111,-0.9999952938,-0.9999988235, + -1.0000000000,-0.9999988235,-0.9999952938,-0.9999894111,-0.9999811753,-0.9999705864,-0.9999576446,-0.9999423497,-0.9999247018,-0.9999047011,-0.9998823475,-0.9998576410,-0.9998305818,-0.9998011699,-0.9997694054,-0.9997352883, + -0.9996988187,-0.9996599967,-0.9996188225,-0.9995752960,-0.9995294175,-0.9994811870,-0.9994306046,-0.9993776704,-0.9993223846,-0.9992647473,-0.9992047586,-0.9991424187,-0.9990777278,-0.9990106859,-0.9989412932,-0.9988695499, + -0.9987954562,-0.9987190122,-0.9986402182,-0.9985590742,-0.9984755806,-0.9983897374,-0.9983015449,-0.9982110034,-0.9981181129,-0.9980228738,-0.9979252862,-0.9978253504,-0.9977230666,-0.9976184351,-0.9975114561,-0.9974021299, + -0.9972904567,-0.9971764367,-0.9970600703,-0.9969413578,-0.9968202993,-0.9966968952,-0.9965711458,-0.9964430514,-0.9963126122,-0.9961798286,-0.9960447009,-0.9959072294,-0.9957674145,-0.9956252564,-0.9954807555,-0.9953339121, + -0.9951847267,-0.9950331994,-0.9948793308,-0.9947231211,-0.9945645707,-0.9944036801,-0.9942404495,-0.9940748793,-0.9939069700,-0.9937367219,-0.9935641355,-0.9933892111,-0.9932119492,-0.9930323502,-0.9928504145,-0.9926661424, + -0.9924795346,-0.9922905913,-0.9920993131,-0.9919057004,-0.9917097537,-0.9915114733,-0.9913108598,-0.9911079137,-0.9909026354,-0.9906950254,-0.9904850843,-0.9902728124,-0.9900582103,-0.9898412785,-0.9896220175,-0.9894004278, + -0.9891765100,-0.9889502645,-0.9887216920,-0.9884907929,-0.9882575677,-0.9880220171,-0.9877841416,-0.9875439418,-0.9873014182,-0.9870565713,-0.9868094018,-0.9865599103,-0.9863080972,-0.9860539633,-0.9857975092,-0.9855387353, + -0.9852776424,-0.9850142310,-0.9847485018,-0.9844804554,-0.9842100924,-0.9839374134,-0.9836624192,-0.9833851103,-0.9831054874,-0.9828235512,-0.9825393023,-0.9822527414,-0.9819638691,-0.9816726862,-0.9813791933,-0.9810833912, + -0.9807852804,-0.9804848618,-0.9801821360,-0.9798771037,-0.9795697657,-0.9792601226,-0.9789481753,-0.9786339244,-0.9783173707,-0.9779985149,-0.9776773578,-0.9773539001,-0.9770281427,-0.9767000861,-0.9763697313,-0.9760370790, + -0.9757021300,-0.9753648851,-0.9750253451,-0.9746835107,-0.9743393828,-0.9739929622,-0.9736442497,-0.9732932461,-0.9729399522,-0.9725843689,-0.9722264971,-0.9718663375,-0.9715038910,-0.9711391584,-0.9707721407,-0.9704028387, + -0.9700312532,-0.9696573851,-0.9692812354,-0.9689028048,-0.9685220943,-0.9681391047,-0.9677538371,-0.9673662922,-0.9669764710,-0.9665843745,-0.9661900034,-0.9657933589,-0.9653944417,-0.9649932529,-0.9645897933,-0.9641840640, + -0.9637760658,-0.9633657998,-0.9629532669,-0.9625384680,-0.9621214043,-0.9617020765,-0.9612804858,-0.9608566331,-0.9604305194,-0.9600021457,-0.9595715131,-0.9591386225,-0.9587034749,-0.9582660714,-0.9578264130,-0.9573845008, + -0.9569403357,-0.9564939189,-0.9560452513,-0.9555943341,-0.9551411683,-0.9546857549,-0.9542280951,-0.9537681899,-0.9533060404,-0.9528416476,-0.9523750127,-0.9519061368,-0.9514350210,-0.9509616663,-0.9504860739,-0.9500082450, + -0.9495281806,-0.9490458819,-0.9485613499,-0.9480745859,-0.9475855910,-0.9470943664,-0.9466009131,-0.9461052324,-0.9456073254,-0.9451071933,-0.9446048373,-0.9441002585,-0.9435934582,-0.9430844375,-0.9425731976,-0.9420597398, + -0.9415440652,-0.9410261751,-0.9405060706,-0.9399837530,-0.9394592236,-0.9389324835,-0.9384035341,-0.9378723764,-0.9373390119,-0.9368034417,-0.9362656672,-0.9357256895,-0.9351835099,-0.9346391298,-0.9340925504,-0.9335437730, + -0.9329927988,-0.9324396293,-0.9318842656,-0.9313267091,-0.9307669611,-0.9302050229,-0.9296408958,-0.9290745813,-0.9285060805,-0.9279353948,-0.9273625257,-0.9267874743,-0.9262102421,-0.9256308305,-0.9250492408,-0.9244654743, + -0.9238795325,-0.9232914167,-0.9227011283,-0.9221086687,-0.9215140393,-0.9209172415,-0.9203182767,-0.9197171463,-0.9191138517,-0.9185083943,-0.9179007756,-0.9172909970,-0.9166790599,-0.9160649658,-0.9154487161,-0.9148303122, + -0.9142097557,-0.9135870479,-0.9129621904,-0.9123351846,-0.9117060320,-0.9110747341,-0.9104412923,-0.9098057081,-0.9091679831,-0.9085281187,-0.9078861165,-0.9072419779,-0.9065957045,-0.9059472978,-0.9052967593,-0.9046440906, + -0.9039892931,-0.9033323685,-0.9026733182,-0.9020121439,-0.9013488470,-0.9006834292,-0.9000158920,-0.8993462370,-0.8986744657,-0.8980005797,-0.8973245807,-0.8966464702,-0.8959662498,-0.8952839210,-0.8945994856,-0.8939129451, + -0.8932243012,-0.8925335554,-0.8918407094,-0.8911457648,-0.8904487232,-0.8897495864,-0.8890483559,-0.8883450333,-0.8876396204,-0.8869321188,-0.8862225301,-0.8855108561,-0.8847970984,-0.8840812587,-0.8833633387,-0.8826433400, + -0.8819212643,-0.8811971135,-0.8804708891,-0.8797425928,-0.8790122264,-0.8782797917,-0.8775452902,-0.8768087238,-0.8760700942,-0.8753294031,-0.8745866523,-0.8738418435,-0.8730949784,-0.8723460589,-0.8715950867,-0.8708420635, + -0.8700869911,-0.8693298713,-0.8685707060,-0.8678094968,-0.8670462455,-0.8662809540,-0.8655136241,-0.8647442575,-0.8639728561,-0.8631994217,-0.8624239561,-0.8616464611,-0.8608669386,-0.8600853904,-0.8593018184,-0.8585162243, + -0.8577286100,-0.8569389774,-0.8561473284,-0.8553536647,-0.8545579884,-0.8537603011,-0.8529606049,-0.8521589016,-0.8513551931,-0.8505494813,-0.8497417680,-0.8489320552,-0.8481203448,-0.8473066387,-0.8464909388,-0.8456732470, + -0.8448535652,-0.8440318955,-0.8432082396,-0.8423825996,-0.8415549774,-0.8407253750,-0.8398937942,-0.8390602371,-0.8382247056,-0.8373872016,-0.8365477272,-0.8357062844,-0.8348628750,-0.8340175011,-0.8331701647,-0.8323208678, + -0.8314696123,-0.8306164003,-0.8297612338,-0.8289041148,-0.8280450453,-0.8271840273,-0.8263210628,-0.8254561540,-0.8245893028,-0.8237205112,-0.8228497814,-0.8219771153,-0.8211025150,-0.8202259826,-0.8193475201,-0.8184671296, + -0.8175848132,-0.8167005729,-0.8158144108,-0.8149263291,-0.8140363297,-0.8131444148,-0.8122505866,-0.8113548470,-0.8104571983,-0.8095576424,-0.8086561816,-0.8077528179,-0.8068475535,-0.8059403906,-0.8050313311,-0.8041203774, + -0.8032075315,-0.8022927955,-0.8013761717,-0.8004576622,-0.7995372691,-0.7986149946,-0.7976908409,-0.7967648102,-0.7958369046,-0.7949071263,-0.7939754776,-0.7930419605,-0.7921065773,-0.7911693302,-0.7902302214,-0.7892892532, + -0.7883464276,-0.7874017470,-0.7864552136,-0.7855068296,-0.7845565972,-0.7836045186,-0.7826505962,-0.7816948321,-0.7807372286,-0.7797777879,-0.7788165124,-0.7778534042,-0.7768884657,-0.7759216990,-0.7749531066,-0.7739826906, + -0.7730104534,-0.7720363972,-0.7710605243,-0.7700828370,-0.7691033376,-0.7681220285,-0.7671389119,-0.7661539902,-0.7651672656,-0.7641787405,-0.7631884173,-0.7621962981,-0.7612023855,-0.7602066817,-0.7592091890,-0.7582099098, + -0.7572088465,-0.7562060014,-0.7552013769,-0.7541949753,-0.7531867990,-0.7521768504,-0.7511651319,-0.7501516458,-0.7491363945,-0.7481193805,-0.7471006060,-0.7460800735,-0.7450577854,-0.7440337442,-0.7430079521,-0.7419804117, + -0.7409511254,-0.7399200955,-0.7388873245,-0.7378528148,-0.7368165689,-0.7357785892,-0.7347388781,-0.7336974381,-0.7326542717,-0.7316093812,-0.7305627692,-0.7295144381,-0.7284643904,-0.7274126286,-0.7263591551,-0.7253039724, + -0.7242470830,-0.7231884893,-0.7221281939,-0.7210661993,-0.7200025080,-0.7189371224,-0.7178700451,-0.7168012785,-0.7157308253,-0.7146586879,-0.7135848688,-0.7125093706,-0.7114321957,-0.7103533469,-0.7092728264,-0.7081906370, + -0.7071067812,-0.7060212614,-0.7049340804,-0.7038452405,-0.7027547445,-0.7016625947,-0.7005687939,-0.6994733446,-0.6983762494,-0.6972775108,-0.6961771315,-0.6950751140,-0.6939714609,-0.6928661748,-0.6917592584,-0.6906507141, + -0.6895405447,-0.6884287528,-0.6873153409,-0.6862003117,-0.6850836678,-0.6839654118,-0.6828455464,-0.6817240742,-0.6806009978,-0.6794763199,-0.6783500431,-0.6772221701,-0.6760927036,-0.6749616461,-0.6738290004,-0.6726947691, + -0.6715589548,-0.6704215604,-0.6692825883,-0.6681420414,-0.6669999223,-0.6658562337,-0.6647109782,-0.6635641586,-0.6624157776,-0.6612658378,-0.6601143421,-0.6589612930,-0.6578066933,-0.6566505457,-0.6554928530,-0.6543336178, + -0.6531728430,-0.6520105311,-0.6508466850,-0.6496813074,-0.6485144010,-0.6473459686,-0.6461760130,-0.6450045368,-0.6438315429,-0.6426570340,-0.6414810128,-0.6403034822,-0.6391244449,-0.6379439036,-0.6367618612,-0.6355783205, + -0.6343932842,-0.6332067550,-0.6320187359,-0.6308292296,-0.6296382389,-0.6284457666,-0.6272518155,-0.6260563884,-0.6248594881,-0.6236611175,-0.6224612794,-0.6212599765,-0.6200572118,-0.6188529880,-0.6176473079,-0.6164401745, + -0.6152315906,-0.6140215589,-0.6128100824,-0.6115971639,-0.6103828063,-0.6091670123,-0.6079497850,-0.6067311270,-0.6055110414,-0.6042895309,-0.6030665985,-0.6018422471,-0.6006164794,-0.5993892984,-0.5981607070,-0.5969307081, + -0.5956993045,-0.5944664992,-0.5932322950,-0.5919966950,-0.5907597019,-0.5895213186,-0.5882815482,-0.5870403935,-0.5857978575,-0.5845539430,-0.5833086529,-0.5820619903,-0.5808139581,-0.5795645591,-0.5783137964,-0.5770616729, + -0.5758081914,-0.5745533550,-0.5732971667,-0.5720396293,-0.5707807459,-0.5695205193,-0.5682589527,-0.5669960488,-0.5657318108,-0.5644662415,-0.5631993440,-0.5619311212,-0.5606615762,-0.5593907119,-0.5581185312,-0.5568450373, + -0.5555702330,-0.5542941215,-0.5530167056,-0.5517379884,-0.5504579729,-0.5491766622,-0.5478940592,-0.5466101669,-0.5453249884,-0.5440385267,-0.5427507849,-0.5414617659,-0.5401714727,-0.5388799085,-0.5375870763,-0.5362929791, + -0.5349976199,-0.5337010018,-0.5324031279,-0.5311040012,-0.5298036247,-0.5285020015,-0.5271991348,-0.5258950275,-0.5245896827,-0.5232831035,-0.5219752929,-0.5206662541,-0.5193559902,-0.5180445041,-0.5167317990,-0.5154178780, + -0.5141027442,-0.5127864006,-0.5114688504,-0.5101500967,-0.5088301425,-0.5075089911,-0.5061866453,-0.5048631085,-0.5035383837,-0.5022124740,-0.5008853826,-0.4995571125,-0.4982276670,-0.4968970490,-0.4955652618,-0.4942323085, + -0.4928981922,-0.4915629161,-0.4902264833,-0.4888888969,-0.4875501601,-0.4862102761,-0.4848692480,-0.4835270789,-0.4821837721,-0.4808393306,-0.4794937577,-0.4781470564,-0.4767992301,-0.4754502817,-0.4741002147,-0.4727490320, + -0.4713967368,-0.4700433325,-0.4686888220,-0.4673332087,-0.4659764958,-0.4646186863,-0.4632597836,-0.4618997907,-0.4605387110,-0.4591765475,-0.4578133036,-0.4564489824,-0.4550835871,-0.4537171210,-0.4523495872,-0.4509809890, + -0.4496113297,-0.4482406123,-0.4468688402,-0.4454960165,-0.4441221446,-0.4427472276,-0.4413712687,-0.4399942713,-0.4386162385,-0.4372371737,-0.4358570799,-0.4344759606,-0.4330938189,-0.4317106580,-0.4303264813,-0.4289412921, + -0.4275550934,-0.4261678887,-0.4247796812,-0.4233904741,-0.4220002708,-0.4206090744,-0.4192168884,-0.4178237158,-0.4164295601,-0.4150344245,-0.4136383122,-0.4122412267,-0.4108431711,-0.4094441487,-0.4080441629,-0.4066432169, + -0.4052413140,-0.4038384576,-0.4024346509,-0.4010298972,-0.3996241998,-0.3982175622,-0.3968099874,-0.3954014789,-0.3939920401,-0.3925816741,-0.3911703843,-0.3897581741,-0.3883450467,-0.3869310055,-0.3855160538,-0.3841001950, + -0.3826834324,-0.3812657692,-0.3798472089,-0.3784277548,-0.3770074102,-0.3755861785,-0.3741640630,-0.3727410670,-0.3713171940,-0.3698924471,-0.3684668300,-0.3670403457,-0.3656129978,-0.3641847896,-0.3627557244,-0.3613258056, + -0.3598950365,-0.3584634206,-0.3570309612,-0.3555976617,-0.3541635254,-0.3527285558,-0.3512927561,-0.3498561298,-0.3484186802,-0.3469804108,-0.3455413250,-0.3441014260,-0.3426607173,-0.3412192023,-0.3397768844,-0.3383337670, + -0.3368898534,-0.3354451471,-0.3339996514,-0.3325533699,-0.3311063058,-0.3296584625,-0.3282098436,-0.3267604523,-0.3253102922,-0.3238593665,-0.3224076788,-0.3209552324,-0.3195020308,-0.3180480774,-0.3165933756,-0.3151379288, + -0.3136817404,-0.3122248139,-0.3107671527,-0.3093087603,-0.3078496400,-0.3063897954,-0.3049292297,-0.3034679466,-0.3020059493,-0.3005432414,-0.2990798263,-0.2976157074,-0.2961508882,-0.2946853722,-0.2932191627,-0.2917522632, + -0.2902846773,-0.2888164082,-0.2873474595,-0.2858778347,-0.2844075372,-0.2829365705,-0.2814649379,-0.2799926431,-0.2785196894,-0.2770460803,-0.2755718193,-0.2740969099,-0.2726213554,-0.2711451595,-0.2696683256,-0.2681908571, + -0.2667127575,-0.2652340303,-0.2637546790,-0.2622747070,-0.2607941179,-0.2593129151,-0.2578311022,-0.2563486825,-0.2548656596,-0.2533820370,-0.2518978182,-0.2504130066,-0.2489276057,-0.2474416192,-0.2459550503,-0.2444679027, + -0.2429801799,-0.2414918853,-0.2400030224,-0.2385135948,-0.2370236060,-0.2355330594,-0.2340419586,-0.2325503070,-0.2310581083,-0.2295653658,-0.2280720832,-0.2265782638,-0.2250839114,-0.2235890292,-0.2220936210,-0.2205976901, + -0.2191012402,-0.2176042746,-0.2161067971,-0.2146088110,-0.2131103199,-0.2116113274,-0.2101118369,-0.2086118520,-0.2071113762,-0.2056104131,-0.2041089661,-0.2026070388,-0.2011046348,-0.1996017576,-0.1980984107,-0.1965945977, + -0.1950903220,-0.1935855873,-0.1920803970,-0.1905747548,-0.1890686641,-0.1875621286,-0.1860551517,-0.1845477369,-0.1830398880,-0.1815316083,-0.1800229014,-0.1785137709,-0.1770042204,-0.1754942534,-0.1739838734,-0.1724730840, + -0.1709618888,-0.1694502912,-0.1679382950,-0.1664259035,-0.1649131205,-0.1633999494,-0.1618863938,-0.1603724572,-0.1588581433,-0.1573434556,-0.1558283977,-0.1543129730,-0.1527971853,-0.1512810380,-0.1497645347,-0.1482476790, + -0.1467304745,-0.1452129247,-0.1436950332,-0.1421768035,-0.1406582393,-0.1391393442,-0.1376201216,-0.1361005752,-0.1345807085,-0.1330605252,-0.1315400287,-0.1300192227,-0.1284981108,-0.1269766965,-0.1254549834,-0.1239329751, + -0.1224106752,-0.1208880872,-0.1193652148,-0.1178420615,-0.1163186309,-0.1147949266,-0.1132709522,-0.1117467112,-0.1102222073,-0.1086974440,-0.1071724250,-0.1056471537,-0.1041216339,-0.1025958690,-0.1010698628,-0.0995436187, + -0.0980171403,-0.0964904314,-0.0949634953,-0.0934363358,-0.0919089565,-0.0903813609,-0.0888535526,-0.0873255352,-0.0857973123,-0.0842688876,-0.0827402645,-0.0812114468,-0.0796824380,-0.0781532416,-0.0766238614,-0.0750943008, + -0.0735645636,-0.0720346532,-0.0705045734,-0.0689743276,-0.0674439196,-0.0659133528,-0.0643826309,-0.0628517576,-0.0613207363,-0.0597895707,-0.0582582645,-0.0567268212,-0.0551952443,-0.0536635377,-0.0521317047,-0.0505997490, + -0.0490676743,-0.0475354842,-0.0460031821,-0.0444707719,-0.0429382569,-0.0414056410,-0.0398729276,-0.0383401204,-0.0368072229,-0.0352742389,-0.0337411719,-0.0322080254,-0.0306748032,-0.0291415088,-0.0276081458,-0.0260747178, + -0.0245412285,-0.0230076815,-0.0214740803,-0.0199404286,-0.0184067299,-0.0168729879,-0.0153392063,-0.0138053885,-0.0122715383,-0.0107376592,-0.0092037548,-0.0076698287,-0.0061358846,-0.0046019261,-0.0030679568,-0.0015339802, + 0.0000000000,0.0015339802,0.0030679568,0.0046019261,0.0061358846,0.0076698287,0.0092037548,0.0107376592,0.0122715383,0.0138053885,0.0153392063,0.0168729879,0.0184067299,0.0199404286,0.0214740803,0.0230076815, + 0.0245412285,0.0260747178,0.0276081458,0.0291415088,0.0306748032,0.0322080254,0.0337411719,0.0352742389,0.0368072229,0.0383401204,0.0398729276,0.0414056410,0.0429382569,0.0444707719,0.0460031821,0.0475354842, + 0.0490676743,0.0505997490,0.0521317047,0.0536635377,0.0551952443,0.0567268212,0.0582582645,0.0597895707,0.0613207363,0.0628517576,0.0643826309,0.0659133528,0.0674439196,0.0689743276,0.0705045734,0.0720346532, + 0.0735645636,0.0750943008,0.0766238614,0.0781532416,0.0796824380,0.0812114468,0.0827402645,0.0842688876,0.0857973123,0.0873255352,0.0888535526,0.0903813609,0.0919089565,0.0934363358,0.0949634953,0.0964904314, + 0.0980171403,0.0995436187,0.1010698628,0.1025958690,0.1041216339,0.1056471537,0.1071724250,0.1086974440,0.1102222073,0.1117467112,0.1132709522,0.1147949266,0.1163186309,0.1178420615,0.1193652148,0.1208880872, + 0.1224106752,0.1239329751,0.1254549834,0.1269766965,0.1284981108,0.1300192227,0.1315400287,0.1330605252,0.1345807085,0.1361005752,0.1376201216,0.1391393442,0.1406582393,0.1421768035,0.1436950332,0.1452129247, + 0.1467304745,0.1482476790,0.1497645347,0.1512810380,0.1527971853,0.1543129730,0.1558283977,0.1573434556,0.1588581433,0.1603724572,0.1618863938,0.1633999494,0.1649131205,0.1664259035,0.1679382950,0.1694502912, + 0.1709618888,0.1724730840,0.1739838734,0.1754942534,0.1770042204,0.1785137709,0.1800229014,0.1815316083,0.1830398880,0.1845477369,0.1860551517,0.1875621286,0.1890686642,0.1905747548,0.1920803971,0.1935855873, + 0.1950903220,0.1965945977,0.1980984107,0.1996017576,0.2011046348,0.2026070388,0.2041089661,0.2056104131,0.2071113762,0.2086118520,0.2101118369,0.2116113274,0.2131103199,0.2146088110,0.2161067971,0.2176042746, + 0.2191012402,0.2205976901,0.2220936210,0.2235890292,0.2250839114,0.2265782638,0.2280720832,0.2295653658,0.2310581083,0.2325503070,0.2340419586,0.2355330594,0.2370236060,0.2385135948,0.2400030224,0.2414918853, + 0.2429801799,0.2444679027,0.2459550503,0.2474416192,0.2489276057,0.2504130066,0.2518978182,0.2533820370,0.2548656596,0.2563486825,0.2578311022,0.2593129151,0.2607941179,0.2622747070,0.2637546790,0.2652340303, + 0.2667127575,0.2681908571,0.2696683256,0.2711451595,0.2726213555,0.2740969099,0.2755718193,0.2770460803,0.2785196894,0.2799926431,0.2814649379,0.2829365705,0.2844075372,0.2858778347,0.2873474595,0.2888164082, + 0.2902846773,0.2917522632,0.2932191627,0.2946853722,0.2961508882,0.2976157074,0.2990798263,0.3005432414,0.3020059493,0.3034679466,0.3049292297,0.3063897954,0.3078496400,0.3093087603,0.3107671527,0.3122248139, + 0.3136817404,0.3151379288,0.3165933756,0.3180480774,0.3195020308,0.3209552324,0.3224076788,0.3238593665,0.3253102922,0.3267604523,0.3282098436,0.3296584625,0.3311063058,0.3325533699,0.3339996514,0.3354451471, + 0.3368898534,0.3383337670,0.3397768844,0.3412192023,0.3426607173,0.3441014260,0.3455413250,0.3469804108,0.3484186802,0.3498561298,0.3512927561,0.3527285558,0.3541635254,0.3555976617,0.3570309612,0.3584634206, + 0.3598950365,0.3613258056,0.3627557244,0.3641847896,0.3656129978,0.3670403457,0.3684668300,0.3698924471,0.3713171940,0.3727410670,0.3741640630,0.3755861785,0.3770074102,0.3784277548,0.3798472089,0.3812657692, + 0.3826834324,0.3841001950,0.3855160538,0.3869310055,0.3883450467,0.3897581741,0.3911703843,0.3925816741,0.3939920401,0.3954014789,0.3968099874,0.3982175622,0.3996241998,0.4010298972,0.4024346509,0.4038384576, + 0.4052413140,0.4066432169,0.4080441629,0.4094441487,0.4108431711,0.4122412267,0.4136383122,0.4150344245,0.4164295601,0.4178237158,0.4192168884,0.4206090744,0.4220002708,0.4233904741,0.4247796812,0.4261678887, + 0.4275550934,0.4289412921,0.4303264813,0.4317106580,0.4330938189,0.4344759606,0.4358570799,0.4372371737,0.4386162385,0.4399942713,0.4413712687,0.4427472276,0.4441221446,0.4454960165,0.4468688402,0.4482406123, + 0.4496113297,0.4509809890,0.4523495872,0.4537171210,0.4550835871,0.4564489824,0.4578133036,0.4591765475,0.4605387110,0.4618997907,0.4632597836,0.4646186863,0.4659764958,0.4673332087,0.4686888220,0.4700433325, + 0.4713967368,0.4727490320,0.4741002147,0.4754502817,0.4767992301,0.4781470564,0.4794937577,0.4808393306,0.4821837721,0.4835270789,0.4848692480,0.4862102761,0.4875501601,0.4888888969,0.4902264833,0.4915629161, + 0.4928981922,0.4942323085,0.4955652618,0.4968970490,0.4982276670,0.4995571125,0.5008853826,0.5022124740,0.5035383837,0.5048631085,0.5061866453,0.5075089911,0.5088301425,0.5101500967,0.5114688504,0.5127864006, + 0.5141027442,0.5154178780,0.5167317990,0.5180445041,0.5193559902,0.5206662541,0.5219752929,0.5232831035,0.5245896827,0.5258950275,0.5271991348,0.5285020015,0.5298036247,0.5311040012,0.5324031279,0.5337010018, + 0.5349976199,0.5362929791,0.5375870763,0.5388799085,0.5401714727,0.5414617659,0.5427507849,0.5440385267,0.5453249884,0.5466101669,0.5478940592,0.5491766622,0.5504579729,0.5517379884,0.5530167056,0.5542941215, + 0.5555702330,0.5568450373,0.5581185312,0.5593907119,0.5606615762,0.5619311212,0.5631993440,0.5644662415,0.5657318108,0.5669960488,0.5682589527,0.5695205193,0.5707807459,0.5720396293,0.5732971667,0.5745533550, + 0.5758081914,0.5770616729,0.5783137964,0.5795645591,0.5808139581,0.5820619903,0.5833086529,0.5845539430,0.5857978575,0.5870403935,0.5882815482,0.5895213186,0.5907597019,0.5919966950,0.5932322950,0.5944664992, + 0.5956993045,0.5969307081,0.5981607070,0.5993892984,0.6006164794,0.6018422471,0.6030665985,0.6042895309,0.6055110414,0.6067311270,0.6079497850,0.6091670123,0.6103828063,0.6115971639,0.6128100824,0.6140215589, + 0.6152315906,0.6164401745,0.6176473079,0.6188529880,0.6200572118,0.6212599765,0.6224612794,0.6236611175,0.6248594881,0.6260563884,0.6272518155,0.6284457666,0.6296382389,0.6308292296,0.6320187359,0.6332067551, + 0.6343932842,0.6355783205,0.6367618612,0.6379439036,0.6391244449,0.6403034822,0.6414810128,0.6426570340,0.6438315429,0.6450045368,0.6461760130,0.6473459686,0.6485144010,0.6496813074,0.6508466850,0.6520105311, + 0.6531728430,0.6543336178,0.6554928530,0.6566505457,0.6578066933,0.6589612930,0.6601143421,0.6612658378,0.6624157776,0.6635641586,0.6647109782,0.6658562337,0.6669999223,0.6681420414,0.6692825883,0.6704215604, + 0.6715589548,0.6726947691,0.6738290004,0.6749616461,0.6760927036,0.6772221701,0.6783500431,0.6794763199,0.6806009978,0.6817240742,0.6828455464,0.6839654118,0.6850836678,0.6862003117,0.6873153409,0.6884287528, + 0.6895405447,0.6906507141,0.6917592584,0.6928661748,0.6939714609,0.6950751140,0.6961771315,0.6972775108,0.6983762494,0.6994733446,0.7005687939,0.7016625947,0.7027547445,0.7038452405,0.7049340804,0.7060212614, + 0.7071067812,0.7081906370,0.7092728264,0.7103533469,0.7114321957,0.7125093706,0.7135848688,0.7146586879,0.7157308253,0.7168012785,0.7178700451,0.7189371224,0.7200025080,0.7210661993,0.7221281939,0.7231884893, + 0.7242470830,0.7253039724,0.7263591551,0.7274126286,0.7284643904,0.7295144381,0.7305627692,0.7316093812,0.7326542717,0.7336974381,0.7347388781,0.7357785892,0.7368165689,0.7378528148,0.7388873245,0.7399200955, + 0.7409511254,0.7419804117,0.7430079521,0.7440337442,0.7450577854,0.7460800735,0.7471006060,0.7481193805,0.7491363945,0.7501516458,0.7511651319,0.7521768504,0.7531867990,0.7541949753,0.7552013769,0.7562060014, + 0.7572088465,0.7582099098,0.7592091890,0.7602066817,0.7612023855,0.7621962981,0.7631884173,0.7641787405,0.7651672656,0.7661539902,0.7671389119,0.7681220285,0.7691033376,0.7700828370,0.7710605243,0.7720363972, + 0.7730104534,0.7739826906,0.7749531066,0.7759216990,0.7768884657,0.7778534042,0.7788165124,0.7797777879,0.7807372286,0.7816948321,0.7826505962,0.7836045186,0.7845565972,0.7855068296,0.7864552136,0.7874017470, + 0.7883464276,0.7892892532,0.7902302214,0.7911693302,0.7921065773,0.7930419605,0.7939754776,0.7949071263,0.7958369046,0.7967648102,0.7976908409,0.7986149946,0.7995372691,0.8004576622,0.8013761717,0.8022927955, + 0.8032075315,0.8041203774,0.8050313311,0.8059403906,0.8068475535,0.8077528179,0.8086561816,0.8095576424,0.8104571983,0.8113548470,0.8122505866,0.8131444148,0.8140363297,0.8149263291,0.8158144108,0.8167005729, + 0.8175848132,0.8184671296,0.8193475201,0.8202259826,0.8211025150,0.8219771153,0.8228497814,0.8237205112,0.8245893028,0.8254561540,0.8263210628,0.8271840273,0.8280450453,0.8289041148,0.8297612338,0.8306164003, + 0.8314696123,0.8323208678,0.8331701647,0.8340175011,0.8348628750,0.8357062844,0.8365477272,0.8373872016,0.8382247056,0.8390602371,0.8398937942,0.8407253750,0.8415549774,0.8423825996,0.8432082396,0.8440318955, + 0.8448535652,0.8456732470,0.8464909388,0.8473066387,0.8481203448,0.8489320552,0.8497417680,0.8505494813,0.8513551931,0.8521589016,0.8529606049,0.8537603011,0.8545579884,0.8553536647,0.8561473284,0.8569389774, + 0.8577286100,0.8585162243,0.8593018184,0.8600853904,0.8608669386,0.8616464611,0.8624239561,0.8631994217,0.8639728561,0.8647442575,0.8655136241,0.8662809540,0.8670462455,0.8678094968,0.8685707060,0.8693298713, + 0.8700869911,0.8708420635,0.8715950867,0.8723460589,0.8730949784,0.8738418435,0.8745866523,0.8753294031,0.8760700942,0.8768087238,0.8775452902,0.8782797917,0.8790122264,0.8797425928,0.8804708891,0.8811971135, + 0.8819212643,0.8826433400,0.8833633387,0.8840812587,0.8847970984,0.8855108561,0.8862225301,0.8869321188,0.8876396204,0.8883450333,0.8890483559,0.8897495864,0.8904487232,0.8911457648,0.8918407094,0.8925335554, + 0.8932243012,0.8939129451,0.8945994856,0.8952839210,0.8959662498,0.8966464702,0.8973245807,0.8980005797,0.8986744657,0.8993462370,0.9000158920,0.9006834292,0.9013488470,0.9020121439,0.9026733182,0.9033323685, + 0.9039892931,0.9046440906,0.9052967593,0.9059472978,0.9065957045,0.9072419779,0.9078861165,0.9085281187,0.9091679831,0.9098057081,0.9104412923,0.9110747341,0.9117060320,0.9123351846,0.9129621904,0.9135870479, + 0.9142097557,0.9148303122,0.9154487161,0.9160649658,0.9166790599,0.9172909970,0.9179007756,0.9185083943,0.9191138517,0.9197171463,0.9203182767,0.9209172415,0.9215140393,0.9221086687,0.9227011283,0.9232914167, + 0.9238795325,0.9244654743,0.9250492408,0.9256308305,0.9262102421,0.9267874743,0.9273625257,0.9279353948,0.9285060805,0.9290745813,0.9296408958,0.9302050229,0.9307669611,0.9313267091,0.9318842656,0.9324396293, + 0.9329927988,0.9335437730,0.9340925504,0.9346391298,0.9351835099,0.9357256895,0.9362656672,0.9368034417,0.9373390119,0.9378723764,0.9384035341,0.9389324835,0.9394592236,0.9399837530,0.9405060706,0.9410261751, + 0.9415440652,0.9420597398,0.9425731976,0.9430844375,0.9435934582,0.9441002585,0.9446048373,0.9451071933,0.9456073254,0.9461052324,0.9466009131,0.9470943664,0.9475855910,0.9480745859,0.9485613499,0.9490458819, + 0.9495281806,0.9500082450,0.9504860739,0.9509616663,0.9514350210,0.9519061368,0.9523750127,0.9528416476,0.9533060404,0.9537681899,0.9542280951,0.9546857549,0.9551411683,0.9555943341,0.9560452514,0.9564939189, + 0.9569403357,0.9573845008,0.9578264130,0.9582660714,0.9587034749,0.9591386225,0.9595715131,0.9600021457,0.9604305194,0.9608566331,0.9612804858,0.9617020765,0.9621214043,0.9625384680,0.9629532669,0.9633657998, + 0.9637760658,0.9641840640,0.9645897933,0.9649932529,0.9653944417,0.9657933589,0.9661900034,0.9665843745,0.9669764710,0.9673662922,0.9677538371,0.9681391047,0.9685220943,0.9689028048,0.9692812354,0.9696573851, + 0.9700312532,0.9704028387,0.9707721407,0.9711391584,0.9715038910,0.9718663375,0.9722264971,0.9725843689,0.9729399522,0.9732932461,0.9736442497,0.9739929622,0.9743393828,0.9746835107,0.9750253451,0.9753648851, + 0.9757021300,0.9760370790,0.9763697313,0.9767000861,0.9770281427,0.9773539001,0.9776773578,0.9779985149,0.9783173707,0.9786339244,0.9789481753,0.9792601226,0.9795697657,0.9798771037,0.9801821360,0.9804848618, + 0.9807852804,0.9810833912,0.9813791933,0.9816726862,0.9819638691,0.9822527414,0.9825393023,0.9828235512,0.9831054874,0.9833851103,0.9836624192,0.9839374134,0.9842100924,0.9844804554,0.9847485018,0.9850142310, + 0.9852776424,0.9855387353,0.9857975092,0.9860539633,0.9863080972,0.9865599103,0.9868094018,0.9870565713,0.9873014182,0.9875439418,0.9877841416,0.9880220171,0.9882575677,0.9884907929,0.9887216920,0.9889502645, + 0.9891765100,0.9894004278,0.9896220175,0.9898412785,0.9900582103,0.9902728124,0.9904850843,0.9906950254,0.9909026354,0.9911079137,0.9913108598,0.9915114733,0.9917097537,0.9919057004,0.9920993131,0.9922905913, + 0.9924795346,0.9926661424,0.9928504145,0.9930323502,0.9932119492,0.9933892111,0.9935641355,0.9937367219,0.9939069700,0.9940748793,0.9942404495,0.9944036801,0.9945645707,0.9947231211,0.9948793308,0.9950331994, + 0.9951847267,0.9953339121,0.9954807555,0.9956252564,0.9957674145,0.9959072294,0.9960447009,0.9961798286,0.9963126122,0.9964430514,0.9965711458,0.9966968952,0.9968202993,0.9969413578,0.9970600703,0.9971764367, + 0.9972904567,0.9974021299,0.9975114561,0.9976184351,0.9977230666,0.9978253504,0.9979252862,0.9980228738,0.9981181129,0.9982110034,0.9983015449,0.9983897374,0.9984755806,0.9985590742,0.9986402182,0.9987190122, + 0.9987954562,0.9988695499,0.9989412932,0.9990106859,0.9990777278,0.9991424187,0.9992047586,0.9992647473,0.9993223846,0.9993776704,0.9994306046,0.9994811870,0.9995294175,0.9995752960,0.9996188225,0.9996599967, + 0.9996988187,0.9997352883,0.9997694054,0.9998011699,0.9998305818,0.9998576410,0.9998823475,0.9999047011,0.9999247018,0.9999423497,0.9999576446,0.9999705864,0.9999811753,0.9999894111,0.9999952938,0.9999988235, + }; + + diff --git a/src/libparsec/include/utl_fsin.h b/src/libparsec/include/utl_fsin.h new file mode 100644 index 0000000..d907eb2 --- /dev/null +++ b/src/libparsec/include/utl_fsin.h @@ -0,0 +1,261 @@ + + { + 0.0000000000,0.0015339802,0.0030679568,0.0046019261,0.0061358846,0.0076698287,0.0092037548,0.0107376592,0.0122715383,0.0138053885,0.0153392063,0.0168729879,0.0184067299,0.0199404286,0.0214740803,0.0230076815, + 0.0245412285,0.0260747178,0.0276081458,0.0291415088,0.0306748032,0.0322080254,0.0337411719,0.0352742389,0.0368072229,0.0383401204,0.0398729276,0.0414056410,0.0429382569,0.0444707719,0.0460031821,0.0475354842, + 0.0490676743,0.0505997490,0.0521317047,0.0536635377,0.0551952443,0.0567268212,0.0582582645,0.0597895707,0.0613207363,0.0628517576,0.0643826309,0.0659133528,0.0674439196,0.0689743276,0.0705045734,0.0720346532, + 0.0735645636,0.0750943008,0.0766238614,0.0781532416,0.0796824380,0.0812114468,0.0827402645,0.0842688876,0.0857973123,0.0873255352,0.0888535526,0.0903813609,0.0919089565,0.0934363358,0.0949634953,0.0964904314, + 0.0980171403,0.0995436187,0.1010698628,0.1025958690,0.1041216339,0.1056471537,0.1071724250,0.1086974440,0.1102222073,0.1117467112,0.1132709522,0.1147949266,0.1163186309,0.1178420615,0.1193652148,0.1208880872, + 0.1224106752,0.1239329751,0.1254549834,0.1269766965,0.1284981108,0.1300192227,0.1315400287,0.1330605252,0.1345807085,0.1361005752,0.1376201216,0.1391393442,0.1406582393,0.1421768035,0.1436950332,0.1452129247, + 0.1467304745,0.1482476790,0.1497645347,0.1512810380,0.1527971853,0.1543129730,0.1558283977,0.1573434556,0.1588581433,0.1603724572,0.1618863938,0.1633999494,0.1649131205,0.1664259035,0.1679382950,0.1694502912, + 0.1709618888,0.1724730840,0.1739838734,0.1754942534,0.1770042204,0.1785137709,0.1800229014,0.1815316083,0.1830398880,0.1845477369,0.1860551517,0.1875621286,0.1890686641,0.1905747548,0.1920803970,0.1935855873, + 0.1950903220,0.1965945977,0.1980984107,0.1996017576,0.2011046348,0.2026070388,0.2041089661,0.2056104131,0.2071113762,0.2086118520,0.2101118369,0.2116113274,0.2131103199,0.2146088110,0.2161067971,0.2176042746, + 0.2191012402,0.2205976901,0.2220936210,0.2235890292,0.2250839114,0.2265782638,0.2280720832,0.2295653658,0.2310581083,0.2325503070,0.2340419586,0.2355330594,0.2370236060,0.2385135948,0.2400030224,0.2414918853, + 0.2429801799,0.2444679027,0.2459550503,0.2474416192,0.2489276057,0.2504130066,0.2518978182,0.2533820370,0.2548656596,0.2563486825,0.2578311022,0.2593129151,0.2607941179,0.2622747070,0.2637546790,0.2652340303, + 0.2667127575,0.2681908571,0.2696683256,0.2711451595,0.2726213554,0.2740969099,0.2755718193,0.2770460803,0.2785196894,0.2799926431,0.2814649379,0.2829365705,0.2844075372,0.2858778347,0.2873474595,0.2888164082, + 0.2902846773,0.2917522632,0.2932191627,0.2946853722,0.2961508882,0.2976157074,0.2990798263,0.3005432414,0.3020059493,0.3034679466,0.3049292297,0.3063897954,0.3078496400,0.3093087603,0.3107671527,0.3122248139, + 0.3136817404,0.3151379288,0.3165933756,0.3180480774,0.3195020308,0.3209552324,0.3224076788,0.3238593665,0.3253102922,0.3267604523,0.3282098436,0.3296584625,0.3311063058,0.3325533699,0.3339996514,0.3354451471, + 0.3368898534,0.3383337670,0.3397768844,0.3412192023,0.3426607173,0.3441014260,0.3455413250,0.3469804108,0.3484186802,0.3498561298,0.3512927561,0.3527285558,0.3541635254,0.3555976617,0.3570309612,0.3584634206, + 0.3598950365,0.3613258056,0.3627557244,0.3641847896,0.3656129978,0.3670403457,0.3684668300,0.3698924471,0.3713171940,0.3727410670,0.3741640630,0.3755861785,0.3770074102,0.3784277548,0.3798472089,0.3812657692, + 0.3826834324,0.3841001950,0.3855160538,0.3869310055,0.3883450467,0.3897581741,0.3911703843,0.3925816741,0.3939920401,0.3954014789,0.3968099874,0.3982175622,0.3996241998,0.4010298972,0.4024346509,0.4038384576, + 0.4052413140,0.4066432169,0.4080441629,0.4094441487,0.4108431711,0.4122412267,0.4136383122,0.4150344245,0.4164295601,0.4178237158,0.4192168884,0.4206090744,0.4220002708,0.4233904741,0.4247796812,0.4261678887, + 0.4275550934,0.4289412921,0.4303264813,0.4317106580,0.4330938189,0.4344759606,0.4358570799,0.4372371737,0.4386162385,0.4399942713,0.4413712687,0.4427472276,0.4441221446,0.4454960165,0.4468688402,0.4482406123, + 0.4496113297,0.4509809890,0.4523495872,0.4537171210,0.4550835871,0.4564489824,0.4578133036,0.4591765475,0.4605387110,0.4618997907,0.4632597836,0.4646186863,0.4659764958,0.4673332087,0.4686888220,0.4700433325, + 0.4713967368,0.4727490320,0.4741002147,0.4754502817,0.4767992301,0.4781470564,0.4794937577,0.4808393306,0.4821837721,0.4835270789,0.4848692480,0.4862102761,0.4875501601,0.4888888969,0.4902264833,0.4915629161, + 0.4928981922,0.4942323085,0.4955652618,0.4968970490,0.4982276670,0.4995571125,0.5008853826,0.5022124740,0.5035383837,0.5048631085,0.5061866453,0.5075089911,0.5088301425,0.5101500967,0.5114688504,0.5127864006, + 0.5141027442,0.5154178780,0.5167317990,0.5180445041,0.5193559902,0.5206662541,0.5219752929,0.5232831035,0.5245896827,0.5258950275,0.5271991348,0.5285020015,0.5298036247,0.5311040012,0.5324031279,0.5337010018, + 0.5349976199,0.5362929791,0.5375870763,0.5388799085,0.5401714727,0.5414617659,0.5427507849,0.5440385267,0.5453249884,0.5466101669,0.5478940592,0.5491766622,0.5504579729,0.5517379884,0.5530167056,0.5542941215, + 0.5555702330,0.5568450373,0.5581185312,0.5593907119,0.5606615762,0.5619311212,0.5631993440,0.5644662415,0.5657318108,0.5669960488,0.5682589527,0.5695205193,0.5707807459,0.5720396293,0.5732971667,0.5745533550, + 0.5758081914,0.5770616729,0.5783137964,0.5795645591,0.5808139581,0.5820619903,0.5833086529,0.5845539430,0.5857978575,0.5870403935,0.5882815482,0.5895213186,0.5907597019,0.5919966950,0.5932322950,0.5944664992, + 0.5956993045,0.5969307081,0.5981607070,0.5993892984,0.6006164794,0.6018422471,0.6030665985,0.6042895309,0.6055110414,0.6067311270,0.6079497850,0.6091670123,0.6103828063,0.6115971639,0.6128100824,0.6140215589, + 0.6152315906,0.6164401745,0.6176473079,0.6188529880,0.6200572118,0.6212599765,0.6224612794,0.6236611175,0.6248594881,0.6260563884,0.6272518155,0.6284457666,0.6296382389,0.6308292296,0.6320187359,0.6332067551, + 0.6343932842,0.6355783205,0.6367618612,0.6379439036,0.6391244449,0.6403034822,0.6414810128,0.6426570340,0.6438315429,0.6450045368,0.6461760130,0.6473459686,0.6485144010,0.6496813074,0.6508466850,0.6520105311, + 0.6531728430,0.6543336178,0.6554928530,0.6566505457,0.6578066933,0.6589612930,0.6601143421,0.6612658378,0.6624157776,0.6635641586,0.6647109782,0.6658562337,0.6669999223,0.6681420414,0.6692825883,0.6704215604, + 0.6715589548,0.6726947691,0.6738290004,0.6749616461,0.6760927036,0.6772221701,0.6783500431,0.6794763199,0.6806009978,0.6817240742,0.6828455464,0.6839654118,0.6850836678,0.6862003117,0.6873153409,0.6884287528, + 0.6895405447,0.6906507141,0.6917592584,0.6928661748,0.6939714609,0.6950751140,0.6961771315,0.6972775108,0.6983762494,0.6994733446,0.7005687939,0.7016625947,0.7027547445,0.7038452405,0.7049340804,0.7060212614, + 0.7071067812,0.7081906370,0.7092728264,0.7103533469,0.7114321957,0.7125093706,0.7135848688,0.7146586879,0.7157308253,0.7168012785,0.7178700451,0.7189371224,0.7200025080,0.7210661993,0.7221281939,0.7231884893, + 0.7242470830,0.7253039724,0.7263591551,0.7274126286,0.7284643904,0.7295144381,0.7305627692,0.7316093812,0.7326542717,0.7336974381,0.7347388781,0.7357785892,0.7368165689,0.7378528148,0.7388873245,0.7399200955, + 0.7409511254,0.7419804117,0.7430079521,0.7440337442,0.7450577854,0.7460800735,0.7471006060,0.7481193805,0.7491363945,0.7501516458,0.7511651319,0.7521768504,0.7531867990,0.7541949753,0.7552013769,0.7562060014, + 0.7572088465,0.7582099098,0.7592091890,0.7602066817,0.7612023855,0.7621962981,0.7631884173,0.7641787405,0.7651672656,0.7661539902,0.7671389119,0.7681220285,0.7691033376,0.7700828370,0.7710605243,0.7720363972, + 0.7730104534,0.7739826906,0.7749531066,0.7759216990,0.7768884657,0.7778534042,0.7788165124,0.7797777879,0.7807372286,0.7816948321,0.7826505962,0.7836045186,0.7845565972,0.7855068296,0.7864552136,0.7874017470, + 0.7883464276,0.7892892532,0.7902302214,0.7911693302,0.7921065773,0.7930419605,0.7939754776,0.7949071263,0.7958369046,0.7967648102,0.7976908409,0.7986149946,0.7995372691,0.8004576622,0.8013761717,0.8022927955, + 0.8032075315,0.8041203774,0.8050313311,0.8059403906,0.8068475535,0.8077528179,0.8086561816,0.8095576424,0.8104571983,0.8113548470,0.8122505866,0.8131444148,0.8140363297,0.8149263291,0.8158144108,0.8167005729, + 0.8175848132,0.8184671296,0.8193475201,0.8202259826,0.8211025150,0.8219771153,0.8228497814,0.8237205112,0.8245893028,0.8254561540,0.8263210628,0.8271840273,0.8280450453,0.8289041148,0.8297612338,0.8306164003, + 0.8314696123,0.8323208678,0.8331701647,0.8340175011,0.8348628750,0.8357062844,0.8365477272,0.8373872016,0.8382247056,0.8390602371,0.8398937942,0.8407253750,0.8415549774,0.8423825996,0.8432082396,0.8440318955, + 0.8448535652,0.8456732470,0.8464909388,0.8473066387,0.8481203448,0.8489320552,0.8497417680,0.8505494813,0.8513551931,0.8521589016,0.8529606049,0.8537603011,0.8545579884,0.8553536647,0.8561473284,0.8569389774, + 0.8577286100,0.8585162243,0.8593018184,0.8600853904,0.8608669386,0.8616464611,0.8624239561,0.8631994217,0.8639728561,0.8647442575,0.8655136241,0.8662809540,0.8670462455,0.8678094968,0.8685707060,0.8693298713, + 0.8700869911,0.8708420635,0.8715950867,0.8723460589,0.8730949784,0.8738418435,0.8745866523,0.8753294031,0.8760700942,0.8768087238,0.8775452902,0.8782797917,0.8790122264,0.8797425928,0.8804708891,0.8811971135, + 0.8819212643,0.8826433400,0.8833633387,0.8840812587,0.8847970984,0.8855108561,0.8862225301,0.8869321188,0.8876396204,0.8883450333,0.8890483559,0.8897495864,0.8904487232,0.8911457648,0.8918407094,0.8925335554, + 0.8932243012,0.8939129451,0.8945994856,0.8952839210,0.8959662498,0.8966464702,0.8973245807,0.8980005797,0.8986744657,0.8993462370,0.9000158920,0.9006834292,0.9013488470,0.9020121439,0.9026733182,0.9033323685, + 0.9039892931,0.9046440906,0.9052967593,0.9059472978,0.9065957045,0.9072419779,0.9078861165,0.9085281187,0.9091679831,0.9098057081,0.9104412923,0.9110747341,0.9117060320,0.9123351846,0.9129621904,0.9135870479, + 0.9142097557,0.9148303122,0.9154487161,0.9160649658,0.9166790599,0.9172909970,0.9179007756,0.9185083943,0.9191138517,0.9197171463,0.9203182767,0.9209172415,0.9215140393,0.9221086687,0.9227011283,0.9232914167, + 0.9238795325,0.9244654743,0.9250492408,0.9256308305,0.9262102421,0.9267874743,0.9273625257,0.9279353948,0.9285060805,0.9290745813,0.9296408958,0.9302050229,0.9307669611,0.9313267091,0.9318842656,0.9324396293, + 0.9329927988,0.9335437730,0.9340925504,0.9346391298,0.9351835099,0.9357256895,0.9362656672,0.9368034417,0.9373390119,0.9378723764,0.9384035341,0.9389324835,0.9394592236,0.9399837530,0.9405060706,0.9410261751, + 0.9415440652,0.9420597398,0.9425731976,0.9430844375,0.9435934582,0.9441002585,0.9446048373,0.9451071933,0.9456073254,0.9461052324,0.9466009131,0.9470943664,0.9475855910,0.9480745859,0.9485613499,0.9490458819, + 0.9495281806,0.9500082450,0.9504860739,0.9509616663,0.9514350210,0.9519061368,0.9523750127,0.9528416476,0.9533060404,0.9537681899,0.9542280951,0.9546857549,0.9551411683,0.9555943341,0.9560452513,0.9564939189, + 0.9569403357,0.9573845008,0.9578264130,0.9582660714,0.9587034749,0.9591386225,0.9595715131,0.9600021457,0.9604305194,0.9608566331,0.9612804858,0.9617020765,0.9621214043,0.9625384680,0.9629532669,0.9633657998, + 0.9637760658,0.9641840640,0.9645897933,0.9649932529,0.9653944417,0.9657933589,0.9661900034,0.9665843745,0.9669764710,0.9673662922,0.9677538371,0.9681391047,0.9685220943,0.9689028048,0.9692812354,0.9696573851, + 0.9700312532,0.9704028387,0.9707721407,0.9711391584,0.9715038910,0.9718663375,0.9722264971,0.9725843689,0.9729399522,0.9732932461,0.9736442497,0.9739929622,0.9743393828,0.9746835107,0.9750253451,0.9753648851, + 0.9757021300,0.9760370790,0.9763697313,0.9767000861,0.9770281427,0.9773539001,0.9776773578,0.9779985149,0.9783173707,0.9786339244,0.9789481753,0.9792601226,0.9795697657,0.9798771037,0.9801821360,0.9804848618, + 0.9807852804,0.9810833912,0.9813791933,0.9816726862,0.9819638691,0.9822527414,0.9825393023,0.9828235512,0.9831054874,0.9833851103,0.9836624192,0.9839374134,0.9842100924,0.9844804554,0.9847485018,0.9850142310, + 0.9852776424,0.9855387353,0.9857975092,0.9860539633,0.9863080972,0.9865599103,0.9868094018,0.9870565713,0.9873014182,0.9875439418,0.9877841416,0.9880220171,0.9882575677,0.9884907929,0.9887216920,0.9889502645, + 0.9891765100,0.9894004278,0.9896220175,0.9898412785,0.9900582103,0.9902728124,0.9904850843,0.9906950254,0.9909026354,0.9911079137,0.9913108598,0.9915114733,0.9917097537,0.9919057004,0.9920993131,0.9922905913, + 0.9924795346,0.9926661424,0.9928504145,0.9930323502,0.9932119492,0.9933892111,0.9935641355,0.9937367219,0.9939069700,0.9940748793,0.9942404495,0.9944036801,0.9945645707,0.9947231211,0.9948793308,0.9950331994, + 0.9951847267,0.9953339121,0.9954807555,0.9956252564,0.9957674145,0.9959072294,0.9960447009,0.9961798286,0.9963126122,0.9964430514,0.9965711458,0.9966968952,0.9968202993,0.9969413578,0.9970600703,0.9971764367, + 0.9972904567,0.9974021299,0.9975114561,0.9976184351,0.9977230666,0.9978253504,0.9979252862,0.9980228738,0.9981181129,0.9982110034,0.9983015449,0.9983897374,0.9984755806,0.9985590742,0.9986402182,0.9987190122, + 0.9987954562,0.9988695499,0.9989412932,0.9990106859,0.9990777278,0.9991424187,0.9992047586,0.9992647473,0.9993223846,0.9993776704,0.9994306046,0.9994811870,0.9995294175,0.9995752960,0.9996188225,0.9996599967, + 0.9996988187,0.9997352883,0.9997694054,0.9998011699,0.9998305818,0.9998576410,0.9998823475,0.9999047011,0.9999247018,0.9999423497,0.9999576446,0.9999705864,0.9999811753,0.9999894111,0.9999952938,0.9999988235, + 1.0000000000,0.9999988235,0.9999952938,0.9999894111,0.9999811753,0.9999705864,0.9999576446,0.9999423497,0.9999247018,0.9999047011,0.9998823475,0.9998576410,0.9998305818,0.9998011699,0.9997694054,0.9997352883, + 0.9996988187,0.9996599967,0.9996188225,0.9995752960,0.9995294175,0.9994811870,0.9994306046,0.9993776704,0.9993223846,0.9992647473,0.9992047586,0.9991424187,0.9990777278,0.9990106859,0.9989412932,0.9988695499, + 0.9987954562,0.9987190122,0.9986402182,0.9985590742,0.9984755806,0.9983897374,0.9983015449,0.9982110034,0.9981181129,0.9980228738,0.9979252862,0.9978253504,0.9977230666,0.9976184351,0.9975114561,0.9974021299, + 0.9972904567,0.9971764367,0.9970600703,0.9969413578,0.9968202993,0.9966968952,0.9965711458,0.9964430514,0.9963126122,0.9961798286,0.9960447009,0.9959072294,0.9957674145,0.9956252564,0.9954807555,0.9953339121, + 0.9951847267,0.9950331994,0.9948793308,0.9947231211,0.9945645707,0.9944036801,0.9942404495,0.9940748793,0.9939069700,0.9937367219,0.9935641355,0.9933892111,0.9932119492,0.9930323502,0.9928504145,0.9926661424, + 0.9924795346,0.9922905913,0.9920993131,0.9919057004,0.9917097537,0.9915114733,0.9913108598,0.9911079137,0.9909026354,0.9906950254,0.9904850843,0.9902728124,0.9900582103,0.9898412785,0.9896220175,0.9894004278, + 0.9891765100,0.9889502645,0.9887216920,0.9884907929,0.9882575677,0.9880220171,0.9877841416,0.9875439418,0.9873014182,0.9870565713,0.9868094018,0.9865599103,0.9863080972,0.9860539633,0.9857975092,0.9855387353, + 0.9852776424,0.9850142310,0.9847485018,0.9844804554,0.9842100924,0.9839374134,0.9836624192,0.9833851103,0.9831054874,0.9828235512,0.9825393023,0.9822527414,0.9819638691,0.9816726862,0.9813791933,0.9810833912, + 0.9807852804,0.9804848618,0.9801821360,0.9798771037,0.9795697657,0.9792601226,0.9789481753,0.9786339244,0.9783173707,0.9779985149,0.9776773578,0.9773539001,0.9770281427,0.9767000861,0.9763697313,0.9760370790, + 0.9757021300,0.9753648851,0.9750253451,0.9746835107,0.9743393828,0.9739929622,0.9736442497,0.9732932461,0.9729399522,0.9725843689,0.9722264971,0.9718663375,0.9715038910,0.9711391584,0.9707721407,0.9704028387, + 0.9700312532,0.9696573851,0.9692812354,0.9689028048,0.9685220943,0.9681391047,0.9677538371,0.9673662922,0.9669764710,0.9665843745,0.9661900034,0.9657933589,0.9653944417,0.9649932529,0.9645897933,0.9641840640, + 0.9637760658,0.9633657998,0.9629532669,0.9625384680,0.9621214043,0.9617020765,0.9612804858,0.9608566331,0.9604305194,0.9600021457,0.9595715131,0.9591386225,0.9587034749,0.9582660714,0.9578264130,0.9573845008, + 0.9569403357,0.9564939189,0.9560452514,0.9555943341,0.9551411683,0.9546857549,0.9542280951,0.9537681899,0.9533060404,0.9528416476,0.9523750127,0.9519061368,0.9514350210,0.9509616663,0.9504860739,0.9500082450, + 0.9495281806,0.9490458819,0.9485613499,0.9480745859,0.9475855910,0.9470943664,0.9466009131,0.9461052324,0.9456073254,0.9451071933,0.9446048373,0.9441002585,0.9435934582,0.9430844375,0.9425731976,0.9420597398, + 0.9415440652,0.9410261751,0.9405060706,0.9399837530,0.9394592236,0.9389324835,0.9384035341,0.9378723764,0.9373390119,0.9368034417,0.9362656672,0.9357256895,0.9351835099,0.9346391298,0.9340925504,0.9335437730, + 0.9329927988,0.9324396293,0.9318842656,0.9313267091,0.9307669611,0.9302050229,0.9296408958,0.9290745813,0.9285060805,0.9279353948,0.9273625257,0.9267874743,0.9262102421,0.9256308305,0.9250492408,0.9244654743, + 0.9238795325,0.9232914167,0.9227011283,0.9221086687,0.9215140393,0.9209172415,0.9203182767,0.9197171463,0.9191138517,0.9185083943,0.9179007756,0.9172909970,0.9166790599,0.9160649658,0.9154487161,0.9148303122, + 0.9142097557,0.9135870479,0.9129621904,0.9123351846,0.9117060320,0.9110747341,0.9104412923,0.9098057081,0.9091679831,0.9085281187,0.9078861165,0.9072419779,0.9065957045,0.9059472978,0.9052967593,0.9046440906, + 0.9039892931,0.9033323685,0.9026733182,0.9020121439,0.9013488470,0.9006834292,0.9000158920,0.8993462370,0.8986744657,0.8980005797,0.8973245807,0.8966464702,0.8959662498,0.8952839210,0.8945994856,0.8939129451, + 0.8932243012,0.8925335554,0.8918407094,0.8911457648,0.8904487232,0.8897495864,0.8890483559,0.8883450333,0.8876396204,0.8869321188,0.8862225301,0.8855108561,0.8847970984,0.8840812587,0.8833633387,0.8826433400, + 0.8819212643,0.8811971135,0.8804708891,0.8797425928,0.8790122264,0.8782797917,0.8775452902,0.8768087238,0.8760700942,0.8753294031,0.8745866523,0.8738418435,0.8730949784,0.8723460589,0.8715950867,0.8708420635, + 0.8700869911,0.8693298713,0.8685707060,0.8678094968,0.8670462455,0.8662809540,0.8655136241,0.8647442575,0.8639728561,0.8631994217,0.8624239561,0.8616464611,0.8608669386,0.8600853904,0.8593018184,0.8585162243, + 0.8577286100,0.8569389774,0.8561473284,0.8553536647,0.8545579884,0.8537603011,0.8529606049,0.8521589016,0.8513551931,0.8505494813,0.8497417680,0.8489320552,0.8481203448,0.8473066387,0.8464909388,0.8456732470, + 0.8448535652,0.8440318955,0.8432082396,0.8423825996,0.8415549774,0.8407253750,0.8398937942,0.8390602371,0.8382247056,0.8373872016,0.8365477272,0.8357062844,0.8348628750,0.8340175011,0.8331701647,0.8323208678, + 0.8314696123,0.8306164003,0.8297612338,0.8289041148,0.8280450453,0.8271840273,0.8263210628,0.8254561540,0.8245893028,0.8237205112,0.8228497814,0.8219771153,0.8211025150,0.8202259826,0.8193475201,0.8184671296, + 0.8175848132,0.8167005729,0.8158144108,0.8149263291,0.8140363297,0.8131444148,0.8122505866,0.8113548470,0.8104571983,0.8095576424,0.8086561816,0.8077528179,0.8068475535,0.8059403906,0.8050313311,0.8041203774, + 0.8032075315,0.8022927955,0.8013761717,0.8004576622,0.7995372691,0.7986149946,0.7976908409,0.7967648102,0.7958369046,0.7949071263,0.7939754776,0.7930419605,0.7921065773,0.7911693302,0.7902302214,0.7892892532, + 0.7883464276,0.7874017470,0.7864552136,0.7855068296,0.7845565972,0.7836045186,0.7826505962,0.7816948321,0.7807372286,0.7797777879,0.7788165124,0.7778534042,0.7768884657,0.7759216990,0.7749531066,0.7739826906, + 0.7730104534,0.7720363972,0.7710605243,0.7700828370,0.7691033376,0.7681220285,0.7671389119,0.7661539902,0.7651672656,0.7641787405,0.7631884173,0.7621962981,0.7612023855,0.7602066817,0.7592091890,0.7582099098, + 0.7572088465,0.7562060014,0.7552013769,0.7541949753,0.7531867990,0.7521768504,0.7511651319,0.7501516458,0.7491363945,0.7481193805,0.7471006060,0.7460800735,0.7450577854,0.7440337442,0.7430079521,0.7419804117, + 0.7409511254,0.7399200955,0.7388873245,0.7378528148,0.7368165689,0.7357785892,0.7347388781,0.7336974381,0.7326542717,0.7316093812,0.7305627692,0.7295144381,0.7284643904,0.7274126286,0.7263591551,0.7253039724, + 0.7242470830,0.7231884893,0.7221281939,0.7210661993,0.7200025080,0.7189371224,0.7178700451,0.7168012785,0.7157308253,0.7146586879,0.7135848688,0.7125093706,0.7114321957,0.7103533469,0.7092728264,0.7081906370, + 0.7071067812,0.7060212614,0.7049340804,0.7038452405,0.7027547445,0.7016625947,0.7005687939,0.6994733446,0.6983762494,0.6972775108,0.6961771315,0.6950751140,0.6939714609,0.6928661748,0.6917592584,0.6906507141, + 0.6895405447,0.6884287528,0.6873153409,0.6862003117,0.6850836678,0.6839654118,0.6828455464,0.6817240742,0.6806009978,0.6794763199,0.6783500431,0.6772221701,0.6760927036,0.6749616461,0.6738290004,0.6726947691, + 0.6715589548,0.6704215604,0.6692825883,0.6681420414,0.6669999223,0.6658562337,0.6647109782,0.6635641586,0.6624157776,0.6612658378,0.6601143421,0.6589612930,0.6578066933,0.6566505457,0.6554928530,0.6543336178, + 0.6531728430,0.6520105311,0.6508466850,0.6496813074,0.6485144010,0.6473459686,0.6461760130,0.6450045368,0.6438315429,0.6426570340,0.6414810128,0.6403034822,0.6391244449,0.6379439036,0.6367618612,0.6355783205, + 0.6343932842,0.6332067551,0.6320187359,0.6308292296,0.6296382389,0.6284457666,0.6272518155,0.6260563884,0.6248594881,0.6236611175,0.6224612794,0.6212599765,0.6200572118,0.6188529880,0.6176473079,0.6164401745, + 0.6152315906,0.6140215589,0.6128100824,0.6115971639,0.6103828063,0.6091670123,0.6079497850,0.6067311270,0.6055110414,0.6042895309,0.6030665985,0.6018422471,0.6006164794,0.5993892984,0.5981607070,0.5969307081, + 0.5956993045,0.5944664992,0.5932322950,0.5919966950,0.5907597019,0.5895213186,0.5882815482,0.5870403935,0.5857978575,0.5845539430,0.5833086529,0.5820619903,0.5808139581,0.5795645591,0.5783137964,0.5770616729, + 0.5758081914,0.5745533550,0.5732971667,0.5720396293,0.5707807459,0.5695205193,0.5682589527,0.5669960488,0.5657318108,0.5644662415,0.5631993440,0.5619311212,0.5606615762,0.5593907119,0.5581185312,0.5568450373, + 0.5555702330,0.5542941215,0.5530167056,0.5517379884,0.5504579729,0.5491766622,0.5478940592,0.5466101669,0.5453249884,0.5440385267,0.5427507849,0.5414617659,0.5401714727,0.5388799085,0.5375870763,0.5362929791, + 0.5349976199,0.5337010018,0.5324031279,0.5311040012,0.5298036247,0.5285020015,0.5271991348,0.5258950275,0.5245896827,0.5232831035,0.5219752929,0.5206662541,0.5193559902,0.5180445041,0.5167317990,0.5154178780, + 0.5141027442,0.5127864006,0.5114688504,0.5101500967,0.5088301425,0.5075089911,0.5061866453,0.5048631085,0.5035383837,0.5022124740,0.5008853826,0.4995571125,0.4982276670,0.4968970490,0.4955652618,0.4942323085, + 0.4928981922,0.4915629161,0.4902264833,0.4888888969,0.4875501601,0.4862102761,0.4848692480,0.4835270789,0.4821837721,0.4808393306,0.4794937577,0.4781470564,0.4767992301,0.4754502817,0.4741002147,0.4727490320, + 0.4713967368,0.4700433325,0.4686888220,0.4673332087,0.4659764958,0.4646186863,0.4632597836,0.4618997907,0.4605387110,0.4591765475,0.4578133036,0.4564489824,0.4550835871,0.4537171210,0.4523495872,0.4509809890, + 0.4496113297,0.4482406123,0.4468688402,0.4454960165,0.4441221446,0.4427472276,0.4413712687,0.4399942713,0.4386162385,0.4372371737,0.4358570799,0.4344759606,0.4330938189,0.4317106580,0.4303264813,0.4289412921, + 0.4275550934,0.4261678887,0.4247796812,0.4233904741,0.4220002708,0.4206090744,0.4192168884,0.4178237158,0.4164295601,0.4150344245,0.4136383122,0.4122412267,0.4108431711,0.4094441487,0.4080441629,0.4066432169, + 0.4052413140,0.4038384576,0.4024346509,0.4010298972,0.3996241998,0.3982175622,0.3968099874,0.3954014789,0.3939920401,0.3925816741,0.3911703843,0.3897581741,0.3883450467,0.3869310055,0.3855160538,0.3841001950, + 0.3826834324,0.3812657692,0.3798472089,0.3784277548,0.3770074102,0.3755861785,0.3741640630,0.3727410670,0.3713171940,0.3698924471,0.3684668300,0.3670403457,0.3656129978,0.3641847896,0.3627557244,0.3613258056, + 0.3598950365,0.3584634206,0.3570309612,0.3555976617,0.3541635254,0.3527285558,0.3512927561,0.3498561298,0.3484186802,0.3469804108,0.3455413250,0.3441014260,0.3426607173,0.3412192023,0.3397768844,0.3383337670, + 0.3368898534,0.3354451471,0.3339996514,0.3325533699,0.3311063058,0.3296584625,0.3282098436,0.3267604523,0.3253102922,0.3238593665,0.3224076788,0.3209552324,0.3195020308,0.3180480774,0.3165933756,0.3151379288, + 0.3136817404,0.3122248139,0.3107671527,0.3093087603,0.3078496400,0.3063897954,0.3049292297,0.3034679466,0.3020059493,0.3005432414,0.2990798263,0.2976157074,0.2961508882,0.2946853722,0.2932191627,0.2917522632, + 0.2902846773,0.2888164082,0.2873474595,0.2858778347,0.2844075372,0.2829365705,0.2814649379,0.2799926431,0.2785196894,0.2770460803,0.2755718193,0.2740969099,0.2726213554,0.2711451595,0.2696683256,0.2681908571, + 0.2667127575,0.2652340303,0.2637546790,0.2622747070,0.2607941179,0.2593129151,0.2578311022,0.2563486825,0.2548656596,0.2533820370,0.2518978182,0.2504130066,0.2489276057,0.2474416192,0.2459550503,0.2444679027, + 0.2429801799,0.2414918853,0.2400030224,0.2385135948,0.2370236060,0.2355330594,0.2340419586,0.2325503070,0.2310581083,0.2295653658,0.2280720832,0.2265782638,0.2250839114,0.2235890292,0.2220936210,0.2205976901, + 0.2191012402,0.2176042746,0.2161067971,0.2146088110,0.2131103199,0.2116113274,0.2101118369,0.2086118520,0.2071113762,0.2056104131,0.2041089661,0.2026070388,0.2011046348,0.1996017576,0.1980984107,0.1965945977, + 0.1950903220,0.1935855873,0.1920803970,0.1905747548,0.1890686641,0.1875621286,0.1860551517,0.1845477369,0.1830398880,0.1815316083,0.1800229014,0.1785137709,0.1770042204,0.1754942534,0.1739838734,0.1724730840, + 0.1709618888,0.1694502912,0.1679382950,0.1664259035,0.1649131205,0.1633999494,0.1618863938,0.1603724572,0.1588581433,0.1573434556,0.1558283977,0.1543129730,0.1527971853,0.1512810380,0.1497645347,0.1482476790, + 0.1467304745,0.1452129247,0.1436950332,0.1421768035,0.1406582393,0.1391393442,0.1376201216,0.1361005752,0.1345807085,0.1330605252,0.1315400287,0.1300192227,0.1284981108,0.1269766965,0.1254549834,0.1239329751, + 0.1224106752,0.1208880872,0.1193652148,0.1178420615,0.1163186309,0.1147949266,0.1132709522,0.1117467112,0.1102222073,0.1086974440,0.1071724250,0.1056471537,0.1041216339,0.1025958690,0.1010698628,0.0995436187, + 0.0980171403,0.0964904314,0.0949634953,0.0934363358,0.0919089565,0.0903813609,0.0888535526,0.0873255352,0.0857973123,0.0842688876,0.0827402645,0.0812114468,0.0796824380,0.0781532416,0.0766238614,0.0750943008, + 0.0735645636,0.0720346532,0.0705045734,0.0689743276,0.0674439196,0.0659133528,0.0643826309,0.0628517576,0.0613207363,0.0597895707,0.0582582645,0.0567268212,0.0551952443,0.0536635377,0.0521317047,0.0505997490, + 0.0490676743,0.0475354842,0.0460031821,0.0444707719,0.0429382569,0.0414056410,0.0398729276,0.0383401204,0.0368072229,0.0352742389,0.0337411719,0.0322080254,0.0306748032,0.0291415088,0.0276081458,0.0260747178, + 0.0245412285,0.0230076815,0.0214740803,0.0199404286,0.0184067299,0.0168729879,0.0153392063,0.0138053885,0.0122715383,0.0107376592,0.0092037548,0.0076698287,0.0061358846,0.0046019261,0.0030679568,0.0015339802, + 0.0000000000,-0.0015339802,-0.0030679568,-0.0046019261,-0.0061358846,-0.0076698287,-0.0092037548,-0.0107376592,-0.0122715383,-0.0138053885,-0.0153392063,-0.0168729879,-0.0184067299,-0.0199404286,-0.0214740803,-0.0230076815, + -0.0245412285,-0.0260747178,-0.0276081458,-0.0291415088,-0.0306748032,-0.0322080254,-0.0337411719,-0.0352742389,-0.0368072229,-0.0383401204,-0.0398729276,-0.0414056410,-0.0429382569,-0.0444707719,-0.0460031821,-0.0475354842, + -0.0490676743,-0.0505997490,-0.0521317047,-0.0536635377,-0.0551952443,-0.0567268212,-0.0582582645,-0.0597895707,-0.0613207363,-0.0628517576,-0.0643826309,-0.0659133528,-0.0674439196,-0.0689743276,-0.0705045734,-0.0720346532, + -0.0735645636,-0.0750943008,-0.0766238614,-0.0781532416,-0.0796824380,-0.0812114468,-0.0827402645,-0.0842688876,-0.0857973123,-0.0873255352,-0.0888535526,-0.0903813609,-0.0919089565,-0.0934363358,-0.0949634953,-0.0964904314, + -0.0980171403,-0.0995436187,-0.1010698628,-0.1025958690,-0.1041216339,-0.1056471537,-0.1071724250,-0.1086974440,-0.1102222073,-0.1117467112,-0.1132709522,-0.1147949266,-0.1163186309,-0.1178420615,-0.1193652148,-0.1208880872, + -0.1224106752,-0.1239329751,-0.1254549834,-0.1269766965,-0.1284981108,-0.1300192227,-0.1315400287,-0.1330605252,-0.1345807085,-0.1361005752,-0.1376201216,-0.1391393442,-0.1406582393,-0.1421768035,-0.1436950332,-0.1452129247, + -0.1467304745,-0.1482476790,-0.1497645347,-0.1512810380,-0.1527971853,-0.1543129730,-0.1558283977,-0.1573434556,-0.1588581433,-0.1603724572,-0.1618863938,-0.1633999494,-0.1649131205,-0.1664259035,-0.1679382950,-0.1694502912, + -0.1709618888,-0.1724730840,-0.1739838734,-0.1754942534,-0.1770042204,-0.1785137709,-0.1800229014,-0.1815316083,-0.1830398880,-0.1845477369,-0.1860551517,-0.1875621286,-0.1890686641,-0.1905747548,-0.1920803971,-0.1935855873, + -0.1950903220,-0.1965945977,-0.1980984107,-0.1996017576,-0.2011046348,-0.2026070388,-0.2041089661,-0.2056104131,-0.2071113762,-0.2086118520,-0.2101118369,-0.2116113274,-0.2131103199,-0.2146088110,-0.2161067971,-0.2176042746, + -0.2191012402,-0.2205976901,-0.2220936210,-0.2235890292,-0.2250839114,-0.2265782638,-0.2280720832,-0.2295653658,-0.2310581083,-0.2325503070,-0.2340419586,-0.2355330594,-0.2370236060,-0.2385135948,-0.2400030224,-0.2414918853, + -0.2429801799,-0.2444679027,-0.2459550503,-0.2474416192,-0.2489276057,-0.2504130066,-0.2518978182,-0.2533820370,-0.2548656596,-0.2563486825,-0.2578311022,-0.2593129151,-0.2607941179,-0.2622747070,-0.2637546790,-0.2652340303, + -0.2667127575,-0.2681908571,-0.2696683256,-0.2711451595,-0.2726213555,-0.2740969099,-0.2755718193,-0.2770460803,-0.2785196894,-0.2799926431,-0.2814649379,-0.2829365705,-0.2844075372,-0.2858778347,-0.2873474595,-0.2888164082, + -0.2902846773,-0.2917522632,-0.2932191627,-0.2946853722,-0.2961508882,-0.2976157074,-0.2990798263,-0.3005432414,-0.3020059493,-0.3034679466,-0.3049292297,-0.3063897954,-0.3078496400,-0.3093087603,-0.3107671527,-0.3122248139, + -0.3136817404,-0.3151379288,-0.3165933756,-0.3180480774,-0.3195020308,-0.3209552324,-0.3224076788,-0.3238593665,-0.3253102922,-0.3267604523,-0.3282098436,-0.3296584625,-0.3311063058,-0.3325533699,-0.3339996514,-0.3354451471, + -0.3368898534,-0.3383337670,-0.3397768844,-0.3412192023,-0.3426607173,-0.3441014260,-0.3455413250,-0.3469804108,-0.3484186802,-0.3498561298,-0.3512927561,-0.3527285558,-0.3541635254,-0.3555976617,-0.3570309612,-0.3584634206, + -0.3598950365,-0.3613258056,-0.3627557244,-0.3641847896,-0.3656129978,-0.3670403457,-0.3684668300,-0.3698924471,-0.3713171940,-0.3727410670,-0.3741640630,-0.3755861785,-0.3770074102,-0.3784277548,-0.3798472089,-0.3812657692, + -0.3826834324,-0.3841001950,-0.3855160538,-0.3869310055,-0.3883450467,-0.3897581741,-0.3911703843,-0.3925816741,-0.3939920401,-0.3954014789,-0.3968099874,-0.3982175622,-0.3996241998,-0.4010298972,-0.4024346509,-0.4038384576, + -0.4052413140,-0.4066432169,-0.4080441629,-0.4094441487,-0.4108431711,-0.4122412267,-0.4136383122,-0.4150344245,-0.4164295601,-0.4178237158,-0.4192168884,-0.4206090744,-0.4220002708,-0.4233904741,-0.4247796812,-0.4261678887, + -0.4275550934,-0.4289412921,-0.4303264813,-0.4317106580,-0.4330938189,-0.4344759606,-0.4358570799,-0.4372371737,-0.4386162385,-0.4399942713,-0.4413712687,-0.4427472276,-0.4441221446,-0.4454960165,-0.4468688402,-0.4482406123, + -0.4496113297,-0.4509809890,-0.4523495872,-0.4537171210,-0.4550835871,-0.4564489824,-0.4578133036,-0.4591765475,-0.4605387110,-0.4618997907,-0.4632597836,-0.4646186863,-0.4659764958,-0.4673332087,-0.4686888220,-0.4700433325, + -0.4713967368,-0.4727490320,-0.4741002147,-0.4754502817,-0.4767992301,-0.4781470564,-0.4794937577,-0.4808393306,-0.4821837721,-0.4835270789,-0.4848692480,-0.4862102761,-0.4875501601,-0.4888888969,-0.4902264833,-0.4915629161, + -0.4928981922,-0.4942323085,-0.4955652618,-0.4968970490,-0.4982276670,-0.4995571125,-0.5008853826,-0.5022124740,-0.5035383837,-0.5048631085,-0.5061866453,-0.5075089911,-0.5088301425,-0.5101500967,-0.5114688504,-0.5127864006, + -0.5141027442,-0.5154178780,-0.5167317990,-0.5180445041,-0.5193559902,-0.5206662541,-0.5219752929,-0.5232831035,-0.5245896827,-0.5258950275,-0.5271991348,-0.5285020015,-0.5298036247,-0.5311040012,-0.5324031279,-0.5337010018, + -0.5349976199,-0.5362929791,-0.5375870763,-0.5388799085,-0.5401714727,-0.5414617659,-0.5427507849,-0.5440385267,-0.5453249884,-0.5466101669,-0.5478940592,-0.5491766622,-0.5504579729,-0.5517379884,-0.5530167056,-0.5542941215, + -0.5555702330,-0.5568450373,-0.5581185312,-0.5593907119,-0.5606615762,-0.5619311212,-0.5631993440,-0.5644662415,-0.5657318108,-0.5669960488,-0.5682589527,-0.5695205193,-0.5707807459,-0.5720396293,-0.5732971667,-0.5745533550, + -0.5758081914,-0.5770616729,-0.5783137964,-0.5795645591,-0.5808139581,-0.5820619903,-0.5833086529,-0.5845539430,-0.5857978575,-0.5870403935,-0.5882815482,-0.5895213186,-0.5907597019,-0.5919966950,-0.5932322950,-0.5944664992, + -0.5956993045,-0.5969307081,-0.5981607070,-0.5993892984,-0.6006164794,-0.6018422471,-0.6030665985,-0.6042895309,-0.6055110414,-0.6067311270,-0.6079497850,-0.6091670123,-0.6103828063,-0.6115971639,-0.6128100824,-0.6140215589, + -0.6152315906,-0.6164401745,-0.6176473079,-0.6188529880,-0.6200572118,-0.6212599765,-0.6224612794,-0.6236611175,-0.6248594881,-0.6260563884,-0.6272518155,-0.6284457666,-0.6296382389,-0.6308292296,-0.6320187359,-0.6332067551, + -0.6343932842,-0.6355783205,-0.6367618612,-0.6379439036,-0.6391244449,-0.6403034822,-0.6414810128,-0.6426570340,-0.6438315429,-0.6450045368,-0.6461760130,-0.6473459686,-0.6485144010,-0.6496813074,-0.6508466850,-0.6520105311, + -0.6531728430,-0.6543336178,-0.6554928530,-0.6566505457,-0.6578066933,-0.6589612930,-0.6601143421,-0.6612658378,-0.6624157776,-0.6635641586,-0.6647109782,-0.6658562337,-0.6669999223,-0.6681420414,-0.6692825883,-0.6704215604, + -0.6715589548,-0.6726947691,-0.6738290004,-0.6749616461,-0.6760927036,-0.6772221701,-0.6783500431,-0.6794763199,-0.6806009978,-0.6817240742,-0.6828455464,-0.6839654118,-0.6850836678,-0.6862003117,-0.6873153409,-0.6884287528, + -0.6895405447,-0.6906507141,-0.6917592584,-0.6928661748,-0.6939714609,-0.6950751140,-0.6961771315,-0.6972775108,-0.6983762494,-0.6994733446,-0.7005687939,-0.7016625947,-0.7027547445,-0.7038452405,-0.7049340804,-0.7060212614, + -0.7071067812,-0.7081906370,-0.7092728264,-0.7103533469,-0.7114321957,-0.7125093706,-0.7135848688,-0.7146586879,-0.7157308253,-0.7168012785,-0.7178700451,-0.7189371224,-0.7200025080,-0.7210661993,-0.7221281939,-0.7231884893, + -0.7242470830,-0.7253039724,-0.7263591551,-0.7274126286,-0.7284643904,-0.7295144381,-0.7305627692,-0.7316093812,-0.7326542717,-0.7336974381,-0.7347388781,-0.7357785892,-0.7368165689,-0.7378528148,-0.7388873245,-0.7399200955, + -0.7409511254,-0.7419804117,-0.7430079521,-0.7440337442,-0.7450577854,-0.7460800735,-0.7471006060,-0.7481193805,-0.7491363945,-0.7501516458,-0.7511651319,-0.7521768504,-0.7531867990,-0.7541949753,-0.7552013769,-0.7562060014, + -0.7572088465,-0.7582099098,-0.7592091890,-0.7602066817,-0.7612023855,-0.7621962981,-0.7631884173,-0.7641787405,-0.7651672656,-0.7661539902,-0.7671389119,-0.7681220285,-0.7691033376,-0.7700828370,-0.7710605243,-0.7720363972, + -0.7730104534,-0.7739826906,-0.7749531066,-0.7759216990,-0.7768884657,-0.7778534042,-0.7788165124,-0.7797777879,-0.7807372286,-0.7816948321,-0.7826505962,-0.7836045186,-0.7845565972,-0.7855068296,-0.7864552136,-0.7874017470, + -0.7883464276,-0.7892892532,-0.7902302214,-0.7911693302,-0.7921065773,-0.7930419605,-0.7939754776,-0.7949071263,-0.7958369046,-0.7967648102,-0.7976908409,-0.7986149946,-0.7995372691,-0.8004576622,-0.8013761717,-0.8022927955, + -0.8032075315,-0.8041203774,-0.8050313311,-0.8059403906,-0.8068475535,-0.8077528179,-0.8086561816,-0.8095576424,-0.8104571983,-0.8113548470,-0.8122505866,-0.8131444148,-0.8140363297,-0.8149263291,-0.8158144108,-0.8167005729, + -0.8175848132,-0.8184671296,-0.8193475201,-0.8202259826,-0.8211025150,-0.8219771153,-0.8228497814,-0.8237205112,-0.8245893028,-0.8254561540,-0.8263210628,-0.8271840273,-0.8280450453,-0.8289041148,-0.8297612338,-0.8306164003, + -0.8314696123,-0.8323208678,-0.8331701647,-0.8340175011,-0.8348628750,-0.8357062844,-0.8365477272,-0.8373872016,-0.8382247056,-0.8390602371,-0.8398937942,-0.8407253750,-0.8415549774,-0.8423825996,-0.8432082396,-0.8440318955, + -0.8448535652,-0.8456732470,-0.8464909388,-0.8473066387,-0.8481203448,-0.8489320552,-0.8497417680,-0.8505494813,-0.8513551931,-0.8521589016,-0.8529606049,-0.8537603011,-0.8545579884,-0.8553536647,-0.8561473284,-0.8569389774, + -0.8577286100,-0.8585162243,-0.8593018184,-0.8600853904,-0.8608669386,-0.8616464611,-0.8624239561,-0.8631994217,-0.8639728561,-0.8647442575,-0.8655136241,-0.8662809540,-0.8670462455,-0.8678094968,-0.8685707060,-0.8693298713, + -0.8700869911,-0.8708420635,-0.8715950867,-0.8723460589,-0.8730949784,-0.8738418435,-0.8745866523,-0.8753294031,-0.8760700942,-0.8768087238,-0.8775452902,-0.8782797917,-0.8790122264,-0.8797425928,-0.8804708891,-0.8811971135, + -0.8819212643,-0.8826433400,-0.8833633387,-0.8840812587,-0.8847970984,-0.8855108561,-0.8862225301,-0.8869321188,-0.8876396204,-0.8883450333,-0.8890483559,-0.8897495864,-0.8904487232,-0.8911457648,-0.8918407094,-0.8925335554, + -0.8932243012,-0.8939129451,-0.8945994856,-0.8952839210,-0.8959662498,-0.8966464702,-0.8973245807,-0.8980005797,-0.8986744657,-0.8993462370,-0.9000158920,-0.9006834292,-0.9013488470,-0.9020121439,-0.9026733182,-0.9033323685, + -0.9039892931,-0.9046440906,-0.9052967593,-0.9059472978,-0.9065957045,-0.9072419779,-0.9078861165,-0.9085281187,-0.9091679831,-0.9098057081,-0.9104412923,-0.9110747341,-0.9117060320,-0.9123351846,-0.9129621904,-0.9135870479, + -0.9142097557,-0.9148303122,-0.9154487161,-0.9160649658,-0.9166790599,-0.9172909970,-0.9179007756,-0.9185083943,-0.9191138517,-0.9197171463,-0.9203182767,-0.9209172415,-0.9215140393,-0.9221086687,-0.9227011283,-0.9232914167, + -0.9238795325,-0.9244654743,-0.9250492408,-0.9256308305,-0.9262102421,-0.9267874743,-0.9273625257,-0.9279353948,-0.9285060805,-0.9290745813,-0.9296408958,-0.9302050229,-0.9307669611,-0.9313267091,-0.9318842656,-0.9324396293, + -0.9329927988,-0.9335437730,-0.9340925504,-0.9346391298,-0.9351835099,-0.9357256895,-0.9362656672,-0.9368034417,-0.9373390119,-0.9378723764,-0.9384035341,-0.9389324835,-0.9394592236,-0.9399837530,-0.9405060706,-0.9410261751, + -0.9415440652,-0.9420597398,-0.9425731976,-0.9430844375,-0.9435934582,-0.9441002585,-0.9446048373,-0.9451071933,-0.9456073254,-0.9461052324,-0.9466009131,-0.9470943664,-0.9475855910,-0.9480745859,-0.9485613499,-0.9490458819, + -0.9495281806,-0.9500082450,-0.9504860739,-0.9509616663,-0.9514350210,-0.9519061368,-0.9523750127,-0.9528416476,-0.9533060404,-0.9537681899,-0.9542280951,-0.9546857549,-0.9551411683,-0.9555943341,-0.9560452514,-0.9564939189, + -0.9569403357,-0.9573845008,-0.9578264130,-0.9582660714,-0.9587034749,-0.9591386225,-0.9595715131,-0.9600021457,-0.9604305194,-0.9608566331,-0.9612804858,-0.9617020765,-0.9621214043,-0.9625384680,-0.9629532669,-0.9633657998, + -0.9637760658,-0.9641840640,-0.9645897933,-0.9649932529,-0.9653944417,-0.9657933589,-0.9661900034,-0.9665843745,-0.9669764710,-0.9673662922,-0.9677538371,-0.9681391047,-0.9685220943,-0.9689028048,-0.9692812354,-0.9696573851, + -0.9700312532,-0.9704028387,-0.9707721407,-0.9711391584,-0.9715038910,-0.9718663375,-0.9722264971,-0.9725843689,-0.9729399522,-0.9732932461,-0.9736442497,-0.9739929622,-0.9743393828,-0.9746835107,-0.9750253451,-0.9753648851, + -0.9757021300,-0.9760370790,-0.9763697313,-0.9767000861,-0.9770281427,-0.9773539001,-0.9776773578,-0.9779985149,-0.9783173707,-0.9786339244,-0.9789481753,-0.9792601226,-0.9795697657,-0.9798771037,-0.9801821360,-0.9804848618, + -0.9807852804,-0.9810833912,-0.9813791933,-0.9816726862,-0.9819638691,-0.9822527414,-0.9825393023,-0.9828235512,-0.9831054874,-0.9833851103,-0.9836624192,-0.9839374134,-0.9842100924,-0.9844804554,-0.9847485018,-0.9850142310, + -0.9852776424,-0.9855387353,-0.9857975092,-0.9860539633,-0.9863080972,-0.9865599103,-0.9868094018,-0.9870565713,-0.9873014182,-0.9875439418,-0.9877841416,-0.9880220171,-0.9882575677,-0.9884907929,-0.9887216920,-0.9889502645, + -0.9891765100,-0.9894004278,-0.9896220175,-0.9898412785,-0.9900582103,-0.9902728124,-0.9904850843,-0.9906950254,-0.9909026354,-0.9911079137,-0.9913108598,-0.9915114733,-0.9917097537,-0.9919057004,-0.9920993131,-0.9922905913, + -0.9924795346,-0.9926661424,-0.9928504145,-0.9930323502,-0.9932119492,-0.9933892111,-0.9935641355,-0.9937367219,-0.9939069700,-0.9940748793,-0.9942404495,-0.9944036801,-0.9945645707,-0.9947231211,-0.9948793308,-0.9950331994, + -0.9951847267,-0.9953339121,-0.9954807555,-0.9956252564,-0.9957674145,-0.9959072294,-0.9960447009,-0.9961798286,-0.9963126122,-0.9964430514,-0.9965711458,-0.9966968952,-0.9968202993,-0.9969413578,-0.9970600703,-0.9971764367, + -0.9972904567,-0.9974021299,-0.9975114561,-0.9976184351,-0.9977230666,-0.9978253504,-0.9979252862,-0.9980228738,-0.9981181129,-0.9982110034,-0.9983015449,-0.9983897374,-0.9984755806,-0.9985590742,-0.9986402182,-0.9987190122, + -0.9987954562,-0.9988695499,-0.9989412932,-0.9990106859,-0.9990777278,-0.9991424187,-0.9992047586,-0.9992647473,-0.9993223846,-0.9993776704,-0.9994306046,-0.9994811870,-0.9995294175,-0.9995752960,-0.9996188225,-0.9996599967, + -0.9996988187,-0.9997352883,-0.9997694054,-0.9998011699,-0.9998305818,-0.9998576410,-0.9998823475,-0.9999047011,-0.9999247018,-0.9999423497,-0.9999576446,-0.9999705864,-0.9999811753,-0.9999894111,-0.9999952938,-0.9999988235, + -1.0000000000,-0.9999988235,-0.9999952938,-0.9999894111,-0.9999811753,-0.9999705864,-0.9999576446,-0.9999423497,-0.9999247018,-0.9999047011,-0.9998823475,-0.9998576410,-0.9998305818,-0.9998011699,-0.9997694054,-0.9997352883, + -0.9996988187,-0.9996599967,-0.9996188225,-0.9995752960,-0.9995294175,-0.9994811870,-0.9994306046,-0.9993776704,-0.9993223846,-0.9992647473,-0.9992047586,-0.9991424187,-0.9990777278,-0.9990106859,-0.9989412932,-0.9988695499, + -0.9987954562,-0.9987190122,-0.9986402182,-0.9985590742,-0.9984755806,-0.9983897374,-0.9983015449,-0.9982110034,-0.9981181129,-0.9980228738,-0.9979252862,-0.9978253504,-0.9977230666,-0.9976184351,-0.9975114561,-0.9974021299, + -0.9972904567,-0.9971764367,-0.9970600703,-0.9969413578,-0.9968202993,-0.9966968952,-0.9965711458,-0.9964430514,-0.9963126122,-0.9961798286,-0.9960447009,-0.9959072294,-0.9957674145,-0.9956252564,-0.9954807555,-0.9953339121, + -0.9951847267,-0.9950331994,-0.9948793308,-0.9947231211,-0.9945645707,-0.9944036801,-0.9942404495,-0.9940748793,-0.9939069700,-0.9937367219,-0.9935641355,-0.9933892111,-0.9932119492,-0.9930323502,-0.9928504145,-0.9926661424, + -0.9924795346,-0.9922905913,-0.9920993131,-0.9919057004,-0.9917097537,-0.9915114733,-0.9913108598,-0.9911079137,-0.9909026354,-0.9906950254,-0.9904850843,-0.9902728124,-0.9900582103,-0.9898412785,-0.9896220175,-0.9894004278, + -0.9891765100,-0.9889502645,-0.9887216920,-0.9884907929,-0.9882575677,-0.9880220171,-0.9877841416,-0.9875439418,-0.9873014182,-0.9870565713,-0.9868094018,-0.9865599103,-0.9863080972,-0.9860539633,-0.9857975092,-0.9855387353, + -0.9852776424,-0.9850142310,-0.9847485018,-0.9844804554,-0.9842100924,-0.9839374134,-0.9836624192,-0.9833851103,-0.9831054874,-0.9828235512,-0.9825393023,-0.9822527414,-0.9819638691,-0.9816726862,-0.9813791933,-0.9810833912, + -0.9807852804,-0.9804848618,-0.9801821360,-0.9798771037,-0.9795697657,-0.9792601226,-0.9789481753,-0.9786339244,-0.9783173707,-0.9779985149,-0.9776773578,-0.9773539001,-0.9770281427,-0.9767000861,-0.9763697313,-0.9760370790, + -0.9757021300,-0.9753648851,-0.9750253451,-0.9746835107,-0.9743393828,-0.9739929622,-0.9736442497,-0.9732932461,-0.9729399522,-0.9725843689,-0.9722264971,-0.9718663375,-0.9715038910,-0.9711391584,-0.9707721407,-0.9704028387, + -0.9700312532,-0.9696573851,-0.9692812354,-0.9689028048,-0.9685220943,-0.9681391047,-0.9677538371,-0.9673662922,-0.9669764710,-0.9665843745,-0.9661900034,-0.9657933589,-0.9653944417,-0.9649932529,-0.9645897933,-0.9641840640, + -0.9637760658,-0.9633657998,-0.9629532669,-0.9625384680,-0.9621214043,-0.9617020765,-0.9612804858,-0.9608566331,-0.9604305194,-0.9600021457,-0.9595715131,-0.9591386225,-0.9587034749,-0.9582660714,-0.9578264130,-0.9573845008, + -0.9569403357,-0.9564939189,-0.9560452513,-0.9555943341,-0.9551411683,-0.9546857549,-0.9542280951,-0.9537681899,-0.9533060404,-0.9528416476,-0.9523750127,-0.9519061368,-0.9514350210,-0.9509616663,-0.9504860739,-0.9500082450, + -0.9495281806,-0.9490458819,-0.9485613499,-0.9480745859,-0.9475855910,-0.9470943664,-0.9466009131,-0.9461052324,-0.9456073254,-0.9451071933,-0.9446048373,-0.9441002585,-0.9435934582,-0.9430844375,-0.9425731976,-0.9420597398, + -0.9415440652,-0.9410261751,-0.9405060706,-0.9399837530,-0.9394592236,-0.9389324835,-0.9384035341,-0.9378723764,-0.9373390119,-0.9368034417,-0.9362656672,-0.9357256895,-0.9351835099,-0.9346391298,-0.9340925504,-0.9335437730, + -0.9329927988,-0.9324396293,-0.9318842656,-0.9313267091,-0.9307669611,-0.9302050229,-0.9296408958,-0.9290745813,-0.9285060805,-0.9279353948,-0.9273625257,-0.9267874743,-0.9262102421,-0.9256308305,-0.9250492408,-0.9244654743, + -0.9238795325,-0.9232914167,-0.9227011283,-0.9221086687,-0.9215140393,-0.9209172415,-0.9203182767,-0.9197171463,-0.9191138517,-0.9185083943,-0.9179007756,-0.9172909970,-0.9166790599,-0.9160649658,-0.9154487161,-0.9148303122, + -0.9142097557,-0.9135870479,-0.9129621904,-0.9123351846,-0.9117060320,-0.9110747341,-0.9104412923,-0.9098057081,-0.9091679831,-0.9085281187,-0.9078861165,-0.9072419779,-0.9065957045,-0.9059472978,-0.9052967593,-0.9046440906, + -0.9039892931,-0.9033323685,-0.9026733182,-0.9020121439,-0.9013488470,-0.9006834292,-0.9000158920,-0.8993462370,-0.8986744657,-0.8980005797,-0.8973245807,-0.8966464702,-0.8959662498,-0.8952839210,-0.8945994856,-0.8939129451, + -0.8932243012,-0.8925335554,-0.8918407094,-0.8911457648,-0.8904487232,-0.8897495864,-0.8890483559,-0.8883450333,-0.8876396204,-0.8869321188,-0.8862225301,-0.8855108561,-0.8847970984,-0.8840812587,-0.8833633387,-0.8826433400, + -0.8819212643,-0.8811971135,-0.8804708891,-0.8797425928,-0.8790122264,-0.8782797917,-0.8775452902,-0.8768087238,-0.8760700942,-0.8753294031,-0.8745866523,-0.8738418435,-0.8730949784,-0.8723460589,-0.8715950867,-0.8708420635, + -0.8700869911,-0.8693298713,-0.8685707060,-0.8678094968,-0.8670462455,-0.8662809540,-0.8655136241,-0.8647442575,-0.8639728561,-0.8631994217,-0.8624239561,-0.8616464611,-0.8608669386,-0.8600853904,-0.8593018184,-0.8585162243, + -0.8577286100,-0.8569389774,-0.8561473284,-0.8553536647,-0.8545579884,-0.8537603011,-0.8529606049,-0.8521589016,-0.8513551931,-0.8505494813,-0.8497417680,-0.8489320552,-0.8481203448,-0.8473066387,-0.8464909388,-0.8456732470, + -0.8448535652,-0.8440318955,-0.8432082396,-0.8423825996,-0.8415549774,-0.8407253750,-0.8398937942,-0.8390602371,-0.8382247056,-0.8373872016,-0.8365477272,-0.8357062844,-0.8348628750,-0.8340175011,-0.8331701647,-0.8323208678, + -0.8314696123,-0.8306164003,-0.8297612338,-0.8289041148,-0.8280450453,-0.8271840273,-0.8263210628,-0.8254561540,-0.8245893028,-0.8237205112,-0.8228497814,-0.8219771153,-0.8211025150,-0.8202259826,-0.8193475201,-0.8184671296, + -0.8175848132,-0.8167005729,-0.8158144108,-0.8149263291,-0.8140363297,-0.8131444148,-0.8122505866,-0.8113548470,-0.8104571983,-0.8095576424,-0.8086561816,-0.8077528179,-0.8068475535,-0.8059403906,-0.8050313311,-0.8041203774, + -0.8032075315,-0.8022927955,-0.8013761717,-0.8004576622,-0.7995372691,-0.7986149946,-0.7976908409,-0.7967648102,-0.7958369046,-0.7949071263,-0.7939754776,-0.7930419605,-0.7921065773,-0.7911693302,-0.7902302214,-0.7892892532, + -0.7883464276,-0.7874017470,-0.7864552136,-0.7855068296,-0.7845565972,-0.7836045186,-0.7826505962,-0.7816948321,-0.7807372286,-0.7797777879,-0.7788165124,-0.7778534042,-0.7768884657,-0.7759216990,-0.7749531066,-0.7739826906, + -0.7730104534,-0.7720363972,-0.7710605243,-0.7700828370,-0.7691033376,-0.7681220285,-0.7671389119,-0.7661539902,-0.7651672656,-0.7641787405,-0.7631884173,-0.7621962981,-0.7612023855,-0.7602066817,-0.7592091890,-0.7582099098, + -0.7572088465,-0.7562060014,-0.7552013769,-0.7541949753,-0.7531867990,-0.7521768504,-0.7511651319,-0.7501516458,-0.7491363945,-0.7481193805,-0.7471006060,-0.7460800735,-0.7450577854,-0.7440337442,-0.7430079521,-0.7419804117, + -0.7409511254,-0.7399200955,-0.7388873245,-0.7378528148,-0.7368165689,-0.7357785892,-0.7347388781,-0.7336974381,-0.7326542717,-0.7316093812,-0.7305627692,-0.7295144381,-0.7284643904,-0.7274126286,-0.7263591551,-0.7253039724, + -0.7242470830,-0.7231884893,-0.7221281939,-0.7210661993,-0.7200025080,-0.7189371224,-0.7178700451,-0.7168012785,-0.7157308253,-0.7146586879,-0.7135848688,-0.7125093706,-0.7114321957,-0.7103533469,-0.7092728264,-0.7081906370, + -0.7071067812,-0.7060212614,-0.7049340804,-0.7038452405,-0.7027547445,-0.7016625947,-0.7005687939,-0.6994733446,-0.6983762494,-0.6972775108,-0.6961771315,-0.6950751140,-0.6939714609,-0.6928661748,-0.6917592584,-0.6906507141, + -0.6895405447,-0.6884287528,-0.6873153409,-0.6862003117,-0.6850836678,-0.6839654118,-0.6828455464,-0.6817240742,-0.6806009978,-0.6794763199,-0.6783500431,-0.6772221701,-0.6760927036,-0.6749616461,-0.6738290004,-0.6726947691, + -0.6715589548,-0.6704215604,-0.6692825883,-0.6681420414,-0.6669999223,-0.6658562337,-0.6647109782,-0.6635641586,-0.6624157776,-0.6612658378,-0.6601143421,-0.6589612930,-0.6578066933,-0.6566505457,-0.6554928530,-0.6543336178, + -0.6531728430,-0.6520105311,-0.6508466850,-0.6496813074,-0.6485144010,-0.6473459686,-0.6461760130,-0.6450045368,-0.6438315429,-0.6426570340,-0.6414810128,-0.6403034822,-0.6391244449,-0.6379439036,-0.6367618612,-0.6355783205, + -0.6343932842,-0.6332067550,-0.6320187359,-0.6308292296,-0.6296382389,-0.6284457666,-0.6272518155,-0.6260563884,-0.6248594881,-0.6236611175,-0.6224612794,-0.6212599765,-0.6200572118,-0.6188529880,-0.6176473079,-0.6164401745, + -0.6152315906,-0.6140215589,-0.6128100824,-0.6115971639,-0.6103828063,-0.6091670123,-0.6079497850,-0.6067311270,-0.6055110414,-0.6042895309,-0.6030665985,-0.6018422471,-0.6006164794,-0.5993892984,-0.5981607070,-0.5969307081, + -0.5956993045,-0.5944664992,-0.5932322950,-0.5919966950,-0.5907597019,-0.5895213186,-0.5882815482,-0.5870403935,-0.5857978575,-0.5845539430,-0.5833086529,-0.5820619903,-0.5808139581,-0.5795645591,-0.5783137964,-0.5770616729, + -0.5758081914,-0.5745533550,-0.5732971667,-0.5720396293,-0.5707807459,-0.5695205193,-0.5682589527,-0.5669960488,-0.5657318108,-0.5644662415,-0.5631993440,-0.5619311212,-0.5606615762,-0.5593907119,-0.5581185312,-0.5568450373, + -0.5555702330,-0.5542941215,-0.5530167056,-0.5517379884,-0.5504579729,-0.5491766622,-0.5478940592,-0.5466101669,-0.5453249884,-0.5440385267,-0.5427507849,-0.5414617659,-0.5401714727,-0.5388799085,-0.5375870763,-0.5362929791, + -0.5349976199,-0.5337010018,-0.5324031279,-0.5311040012,-0.5298036247,-0.5285020015,-0.5271991348,-0.5258950275,-0.5245896827,-0.5232831035,-0.5219752929,-0.5206662541,-0.5193559902,-0.5180445041,-0.5167317990,-0.5154178780, + -0.5141027442,-0.5127864006,-0.5114688504,-0.5101500967,-0.5088301425,-0.5075089911,-0.5061866453,-0.5048631085,-0.5035383837,-0.5022124740,-0.5008853826,-0.4995571125,-0.4982276670,-0.4968970490,-0.4955652618,-0.4942323085, + -0.4928981922,-0.4915629161,-0.4902264833,-0.4888888969,-0.4875501601,-0.4862102761,-0.4848692480,-0.4835270789,-0.4821837721,-0.4808393306,-0.4794937577,-0.4781470564,-0.4767992301,-0.4754502817,-0.4741002147,-0.4727490320, + -0.4713967368,-0.4700433325,-0.4686888220,-0.4673332087,-0.4659764958,-0.4646186863,-0.4632597836,-0.4618997907,-0.4605387110,-0.4591765475,-0.4578133036,-0.4564489824,-0.4550835871,-0.4537171210,-0.4523495872,-0.4509809890, + -0.4496113297,-0.4482406123,-0.4468688402,-0.4454960165,-0.4441221446,-0.4427472276,-0.4413712687,-0.4399942713,-0.4386162385,-0.4372371737,-0.4358570799,-0.4344759606,-0.4330938189,-0.4317106580,-0.4303264813,-0.4289412921, + -0.4275550934,-0.4261678887,-0.4247796812,-0.4233904741,-0.4220002708,-0.4206090744,-0.4192168884,-0.4178237158,-0.4164295601,-0.4150344245,-0.4136383122,-0.4122412267,-0.4108431711,-0.4094441487,-0.4080441629,-0.4066432169, + -0.4052413140,-0.4038384576,-0.4024346509,-0.4010298972,-0.3996241998,-0.3982175622,-0.3968099874,-0.3954014789,-0.3939920401,-0.3925816741,-0.3911703843,-0.3897581741,-0.3883450467,-0.3869310055,-0.3855160538,-0.3841001950, + -0.3826834324,-0.3812657692,-0.3798472089,-0.3784277548,-0.3770074102,-0.3755861785,-0.3741640630,-0.3727410670,-0.3713171940,-0.3698924471,-0.3684668300,-0.3670403457,-0.3656129978,-0.3641847896,-0.3627557244,-0.3613258056, + -0.3598950365,-0.3584634206,-0.3570309612,-0.3555976617,-0.3541635254,-0.3527285558,-0.3512927561,-0.3498561298,-0.3484186802,-0.3469804108,-0.3455413250,-0.3441014260,-0.3426607173,-0.3412192023,-0.3397768844,-0.3383337670, + -0.3368898534,-0.3354451471,-0.3339996514,-0.3325533699,-0.3311063058,-0.3296584625,-0.3282098436,-0.3267604523,-0.3253102922,-0.3238593665,-0.3224076788,-0.3209552324,-0.3195020308,-0.3180480774,-0.3165933756,-0.3151379288, + -0.3136817404,-0.3122248139,-0.3107671527,-0.3093087603,-0.3078496400,-0.3063897954,-0.3049292297,-0.3034679466,-0.3020059493,-0.3005432414,-0.2990798263,-0.2976157074,-0.2961508882,-0.2946853722,-0.2932191627,-0.2917522632, + -0.2902846773,-0.2888164082,-0.2873474595,-0.2858778347,-0.2844075372,-0.2829365705,-0.2814649379,-0.2799926431,-0.2785196894,-0.2770460803,-0.2755718193,-0.2740969099,-0.2726213554,-0.2711451595,-0.2696683256,-0.2681908571, + -0.2667127575,-0.2652340303,-0.2637546790,-0.2622747070,-0.2607941179,-0.2593129151,-0.2578311022,-0.2563486825,-0.2548656596,-0.2533820370,-0.2518978182,-0.2504130066,-0.2489276057,-0.2474416192,-0.2459550503,-0.2444679027, + -0.2429801799,-0.2414918853,-0.2400030224,-0.2385135948,-0.2370236060,-0.2355330594,-0.2340419586,-0.2325503070,-0.2310581083,-0.2295653658,-0.2280720832,-0.2265782638,-0.2250839114,-0.2235890292,-0.2220936210,-0.2205976901, + -0.2191012402,-0.2176042746,-0.2161067971,-0.2146088110,-0.2131103199,-0.2116113274,-0.2101118369,-0.2086118520,-0.2071113762,-0.2056104131,-0.2041089661,-0.2026070388,-0.2011046348,-0.1996017576,-0.1980984107,-0.1965945977, + -0.1950903220,-0.1935855873,-0.1920803970,-0.1905747548,-0.1890686641,-0.1875621286,-0.1860551517,-0.1845477369,-0.1830398880,-0.1815316083,-0.1800229014,-0.1785137709,-0.1770042204,-0.1754942534,-0.1739838734,-0.1724730840, + -0.1709618888,-0.1694502912,-0.1679382950,-0.1664259035,-0.1649131205,-0.1633999494,-0.1618863938,-0.1603724572,-0.1588581433,-0.1573434556,-0.1558283977,-0.1543129730,-0.1527971853,-0.1512810380,-0.1497645347,-0.1482476790, + -0.1467304745,-0.1452129247,-0.1436950331,-0.1421768035,-0.1406582393,-0.1391393442,-0.1376201216,-0.1361005752,-0.1345807085,-0.1330605252,-0.1315400287,-0.1300192227,-0.1284981108,-0.1269766965,-0.1254549834,-0.1239329751, + -0.1224106752,-0.1208880872,-0.1193652148,-0.1178420615,-0.1163186309,-0.1147949266,-0.1132709522,-0.1117467112,-0.1102222073,-0.1086974440,-0.1071724250,-0.1056471537,-0.1041216339,-0.1025958690,-0.1010698628,-0.0995436187, + -0.0980171403,-0.0964904314,-0.0949634953,-0.0934363358,-0.0919089565,-0.0903813609,-0.0888535526,-0.0873255352,-0.0857973123,-0.0842688876,-0.0827402645,-0.0812114468,-0.0796824380,-0.0781532416,-0.0766238614,-0.0750943008, + -0.0735645636,-0.0720346532,-0.0705045734,-0.0689743276,-0.0674439196,-0.0659133528,-0.0643826309,-0.0628517576,-0.0613207363,-0.0597895707,-0.0582582645,-0.0567268212,-0.0551952443,-0.0536635377,-0.0521317047,-0.0505997490, + -0.0490676743,-0.0475354842,-0.0460031821,-0.0444707719,-0.0429382569,-0.0414056410,-0.0398729276,-0.0383401204,-0.0368072229,-0.0352742389,-0.0337411719,-0.0322080254,-0.0306748032,-0.0291415088,-0.0276081458,-0.0260747178, + -0.0245412285,-0.0230076815,-0.0214740803,-0.0199404286,-0.0184067299,-0.0168729879,-0.0153392063,-0.0138053885,-0.0122715383,-0.0107376592,-0.0092037548,-0.0076698287,-0.0061358846,-0.0046019261,-0.0030679568,-0.0015339802, + }; + + diff --git a/src/libparsec/include/utl_list.h b/src/libparsec/include/utl_list.h new file mode 100644 index 0000000..7bbb3a0 --- /dev/null +++ b/src/libparsec/include/utl_list.h @@ -0,0 +1,254 @@ +/* +* PARSEC HEADER: UTL_List.h +*/ + +#ifndef _UTL_LIST_H_ +#define _UTL_LIST_H_ + +#include <stdio.h> + + +// type for data in the list -------------------------------------------------- +// +typedef void* UTL_listdata; + +// struct defining one entry in the UTL_List ---------------------------------- +// +template <class T> +class UTL_listentry_s +{ +public: + T m_data; + UTL_listentry_s* m_pPrev; + UTL_listentry_s* m_pNext; +}; + +// class for holding a single linked list ------------------------------------- +// +template <class T> +class UTL_List { +protected: + UTL_listentry_s<T>* m_pHead; + UTL_listentry_s<T>* m_pTail; + int m_nNumEntries; + + // unlinkg an entry from the list + void _Unlink( UTL_listentry_s<T>* node ) + { + ASSERT( node != NULL ); + + // unlink from list + if ( node->m_pNext != NULL ) { + node->m_pNext->m_pPrev = node->m_pPrev; + } + if ( node->m_pPrev != NULL ) { + node->m_pPrev->m_pNext = node->m_pNext; + } + + // correct head/tail pointers + if ( node->m_pPrev == NULL ) { + ASSERT( node == m_pHead ); + m_pHead = node->m_pNext; + } + if ( node->m_pNext == NULL ) { + ASSERT( node == m_pTail ); + m_pTail = node->m_pPrev; + } + + m_nNumEntries--; + } + +public: + UTL_List() + { + m_pHead = NULL; + m_pTail = NULL; + m_nNumEntries = 0; + } + + ~UTL_List() + { + Clear(); + } + + // clear all entries in the list + void Clear() + { + UTL_listentry_s<T>* next; + for( UTL_listentry_s<T>* node = m_pHead; node != NULL; ) { + next = node->m_pNext; + delete node; + node = next; + } + m_nNumEntries = 0; + m_pHead = NULL; + m_pTail = NULL; + } + void RemoveAll() { Clear(); } + + // append an entry at the tail of the list + UTL_listentry_s<T>* AppendTail( T _data ) + { + UTL_listentry_s<T>* newentry = new UTL_listentry_s<T>; + newentry->m_data = _data; + newentry->m_pPrev = m_pTail; + newentry->m_pNext = NULL; + if ( m_pTail != NULL ) { + m_pTail->m_pNext = newentry; + m_pTail = newentry; + } else { + ASSERT( m_pHead == NULL ); + m_pHead = newentry; + m_pTail = newentry; + } + + m_nNumEntries++; + + return newentry; + } + + // append an entry at the head of the list + UTL_listentry_s<T>* AppendHead( T _data ) + { + UTL_listentry_s<T>* newentry = new UTL_listentry_s<T>; + newentry->m_data = _data; + newentry->m_pPrev = NULL; + newentry->m_pNext = m_pHead; + if ( m_pHead != NULL ) { + m_pHead->m_pPrev = newentry; + m_pHead = newentry; + } else { + ASSERT( m_pTail == NULL ); + m_pHead = newentry; + m_pTail = newentry; + } + + m_nNumEntries++; + + return newentry; + } + + // return the head entry of the list + UTL_listentry_s<T>* GetHead() const { return m_pHead; } + + // return the tail entry of the list + UTL_listentry_s<T>* GetTail() const { return m_pTail; } + + // find an entry with a specific data + UTL_listentry_s<T>* Find( T& data ) const + { + for( UTL_listentry_s<T>* node = m_pHead; node != NULL; ) { + if ( node->m_data == data ) { + return node; + } + node = node->m_pNext; + } + return NULL; + } + + + + // remove an entry specified by its data + //FIXME: evt. introduce key into UTL_listentry_s<T> + bool_t Remove( T& _data ) + { + UTL_listentry_s<T>* node = Find( _data ); + if ( node != NULL ) { + _Unlink( node ); + delete node; + return true; + } + + return false; + } + + // dump contents + void Dump() const + { + int nEntry = 0; + printf( "# of entries: %d", m_nNumEntries ); + for( UTL_listentry_s<T>* node = m_pHead; node != NULL; ) { + printf( "%03d: adress: %8x, data: %8x prev: %8x next: %8x\n", nEntry, (int)node, (int)node->m_data, (int)node->m_pPrev, (int)node->m_pNext ); + node = node->m_pNext; + nEntry++; + } + } + + // return the # of entries + int GetNumEntries() const + { + return m_nNumEntries; + } + + // return the entry at a specified index + UTL_listentry_s<T>* GetEntryAtIndex( int nIndex ) const + { + // TODO: MINGW32 fails on this for some reason... might have to look into why... + //ASSERT( ( nIndex >= 0 ) && ( nIndex < m_nNumEntries ) ); + int nEntry = 0; + for( UTL_listentry_s<T>* node = m_pHead; node != NULL; ) { + + if ( nEntry == nIndex ) { + return node; + } + + node = node->m_pNext; + nEntry++; + } + + return NULL; + } + + // remove entry from list, returns data in entry + T RemoveHead() + { + ASSERT( GetHead() != NULL ); + return RemoveEntry( GetHead() ); + } + + // remove tail entry from list, returns data in entry + T RemoveTail() + { + ASSERT( GetTail() != NULL ); + return RemoveEntry( GetTail() ); + } + + // remove entry from list, returns data in entry + T RemoveEntry( UTL_listentry_s<T>* entry ) + { + ASSERT( entry != NULL ); + _Unlink( entry ); + T data = entry->m_data; + delete entry; + return data; + } + + // call a function for each entry in the list, stop iteration upon fuction failing + void ForEach( int (*procfunc)( UTL_listentry_s<T>* node, void* param ), void* param ) + { + for( UTL_listentry_s<T>* node = m_pHead; node != NULL; ) { + + // call the processing function + if ( (*procfunc) (node, param ) == FALSE ) { + break; + } + + node = node->m_pNext; + } + } +}; + +/* +template <class T> +class UTL_ListWalker +{ +protected: + void* m_pData; +public: + UTL_ListWalker( ) + virtual void Callback( UTL_listentry_s<T>* entry ) = 0; +}; + +*/ +#endif // _UTL_LIST_H_ + diff --git a/src/libparsec/include/utl_logfile.h b/src/libparsec/include/utl_logfile.h new file mode 100644 index 0000000..ffd44cb --- /dev/null +++ b/src/libparsec/include/utl_logfile.h @@ -0,0 +1,53 @@ +/* + * PARSEC HEADER: utl_logfile.h + */ + +#ifndef _UTL_LOGFILE_H_ +#define _UTL_LOGFILE_H_ + +// max. length of temporary buffer -------------------------------------------- +// +#define MAX_LOG_BUFFER_LEN 4096 + +// class for logging information ---------------------------------------------- +// +class UTL_LogFile +{ +protected: + char m_szBuffer[ MAX_LOG_BUFFER_LEN + 1 ]; + size_t m_nBufferLen; + FILE* m_pFile; + refframe_t m_LastFlushRefframe; + +protected: + + // add an entry to the logfile + void _AddEntry( const char* szEntry, size_t len2 ); + +public: + + // standard ctor + UTL_LogFile( const char* szFilename = NULL ); + + // standard dtor + ~UTL_LogFile(); + + // open the logfile + int Open( const char* szFilename ); + + // printf like adding to the logfile + int printf( const char *format, ... ); + + // flush the buffer to the disk file + void Flush(); +}; + + +// external functions --------------------------------------------------------- +// + +// flush all registerd logfiles +void UTL_FlushRegisteredLogfiles(); + + +#endif // !_UTL_LOGFILE_H_ diff --git a/src/libparsec/include/utl_math.h b/src/libparsec/include/utl_math.h new file mode 100644 index 0000000..9fb5f93 --- /dev/null +++ b/src/libparsec/include/utl_math.h @@ -0,0 +1,438 @@ +/* + * PARSEC HEADER: x_math.h + */ + +#ifndef _X_MATH_H_ +#define _X_MATH_H_ + + +// ---------------------------------------------------------------------------- +// MATHEMATICS SUBSYSTEM - +// ---------------------------------------------------------------------------- + + +// thou shalt choose wise +#define USE_DOTPRODUCT_MACRO + + + +// matrix that can be used as destination (MAT2) +extern pXmatrx DestXmatrx; + +// interpolation info for remote player --------------------------------------- +// +struct playerlerp_s { + + fixed_t curspeed; + bams_t curyaw; + bams_t curpitch; + bams_t curroll; + geomv_t curslidehorz; + geomv_t curslidevert; + + Xmatrx dstposition; + geomv_t transvec_x; // delta vec during + geomv_t transvec_y; // transition + geomv_t transvec_z; + int transition; // time countdown + + Quaternion srcquat; // start of slerp + Quaternion dstquat; // end of slerp + float curalpha; // current slerp alpha + float incalpha; // delta for slerp alpha +}; + +// hermite arclen interpolation data ------------------------------------------ +// +struct Hermite_ArcLen +{ + int num_steps; + float* table_u; + float* table_s; + Vector3* table_Vecs; + float total_arc_len; +}; + +// external functions (MATH) + +void AdjointMtx( const Xmatrx smatrx, Xmatrx dmatrx ); + +void MtxMtxMUL( const Xmatrx matrxb, const Xmatrx matrxa, Xmatrx dmatrx ); +void MtxMtxMULt( const Xmatrx matrxb, const Xmatrx matrxa, Xmatrx dmatrx ); +void MtxVctMUL( const Xmatrx matrx, const Vector3 *svect, Vector3 *dvect ); +void MtxVctMULt( const Xmatrx matrx, const Vector3 *svect, Vector3 *dvect ); +void DirVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ); +void RightVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ); +void UpVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ); +void VctReflect( const Vector3 *ivec, const Vector3 *normal, Vector3 *destvec ); +void CalcMovement( Vector3* move_offset, const Xmatrx frame, fixed_t forward, geomv_t horiz, geomv_t vert, refframe_t refframes ); + +void GetSinCos( dword angle, sincosval_s *resultp ); + +void ObjRotX( Xmatrx matrix, bams_t pitch ); +void ObjRotY( Xmatrx matrix, bams_t yaw ); +void ObjRotZ( Xmatrx matrix, bams_t roll ); +void CamRotX( Xmatrx matrix, bams_t pitch ); +void CamRotY( Xmatrx matrix, bams_t yaw ); +void CamRotZ( Xmatrx matrix, bams_t roll ); + +geomv_t DotProduct( const Vector3 *vect1, const Vector3 *vect2 ); +void CrossProduct( const Vector3 *vect1, const Vector3 *vect2, Vector3 *cproduct ); +void CrossProduct2( const geomv_t *vect1, const geomv_t *vect2, geomv_t *cproduct ); + +void ReOrthoMtx( Xmatrx matrix ); + +void ProcessObject( GenObject *object ); + + +// external functions (MAT2) + +geomv_t VctLen( Vector3 *vec ); +geomv_t VctLenX( Vector3 *vec ); +void NormVct( Vector3 *vec ); +void NormVctX( Vector3 *vec ); +void NormMtx( Xmatrx matrix ); +void ReOrthoNormMtx( Xmatrx matrix ); +void MakeIdMatrx( Xmatrx matrx ); +void MakeNonTranslationMatrx( const Xmatrx matrx, Xmatrx dmatrx ); +void CalcOrthoInverse( const Xmatrx matrx, Xmatrx dmatrx ); +void CalcObjSpaceCamera( const GenObject *objectp, Vector3 *cameravec ); +void TransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ); +void BackTransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ); + +int QuaternionIsUnit( const Quaternion *quat ); +int QuaternionIsUnit_f( const Quaternion_f *quat ); +void QuaternionMakeUnit( Quaternion *quat ); +void QuaternionMakeUnit_f( Quaternion_f *quat ); +void QuaternionInvertUnit( Quaternion *quat ); +void QuaternionInvertUnit_f( Quaternion_f *quat ); +void QuaternionInvertGeneral( Quaternion *quat ); +void QuaternionInvertGeneral_f( Quaternion_f *quat ); +void QuaternionFromMatrx( Quaternion *quat, const Xmatrx matrix ); +void QuaternionFromMatrx_f( Quaternion_f *quat, const Xmatrx matrix ); +void MatrxFromQuaternion( Xmatrx matrix, const Quaternion *quat ); +void MatrxFromQuaternion_f( Xmatrx matrix, const Quaternion_f *quat ); +void MatrxFromAngularDisplacement( Xmatrx matrix, bams_t angle, Vertex3 *axis ); +void QuaternionMUL( Quaternion *qd, const Quaternion *qb, const Quaternion *qa ); +void QuaternionMUL_f( Quaternion_f *qd, const Quaternion_f *qb, const Quaternion_f *qa ); +void QuaternionSlerp( Quaternion *qd, const Quaternion *qa, const Quaternion *qb, float alpha ); +void QuaternionSlerp_f( Quaternion_f *qd, const Quaternion_f *qa, const Quaternion_f *qb, float alpha ); +void QuaternionSlerpFrames( Xmatrx slerp_frame, Xmatrx start_frame, Xmatrx end_frame, float t ); +void CalcSlerpedMatrix( Xmatrx matrix, const playerlerp_s *playerlerp ); + +void Hermite_Interpolate( Vector3* dest, float t, const Vector3* start, const Vector3* end, const Vector3* start_tan, const Vector3* end_tan ); +Hermite_ArcLen* Hermite_ArcLen_InitData( int num_steps, const Vector3* start, const Vector3* end, const Vector3* start_tan, const Vector3* end_tan ); +void Hermite_ArcLen_KillData( Hermite_ArcLen* hermite_data ); +void Hermite_ArcLen_Interpolate( const Hermite_ArcLen* hermite_data, float s, Vector3* interp ); + +void DumpMatrix( Xmatrx mat ); + + +// geometric value MUL instruction -------------------------------------------- +// +#define GEOMV_MUL(a,b) ((a)*(b)) + + +// geometric value DIV instruction -------------------------------------------- +// +#define GEOMV_DIV(a,b) ((a)/(b)) + + +// dot product macro/function encapsulation ----------------------------------- +// +#ifdef USE_DOTPRODUCT_MACRO + #define DOT_PRODUCT(u,v) \ + (GEOMV_MUL((u)->X,(v)->X)+GEOMV_MUL((u)->Y,(v)->Y)+GEOMV_MUL((u)->Z,(v)->Z)) +#else + #define DOT_PRODUCT(u,v) DotProduct((u),(v)) +#endif + + +// make vector identity (NULL vector) ----------------------------------------- +// +inline +void MakeIdVector( Vector3& vec ) +{ + vec.X = vec.Y = vec.Z = GEOMV_0; +} + + +// fetch x vector of matrix --------------------------------------------------- +// +inline +void FetchXVector( const Xmatrx matrx, Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + vec->X = matrx[ 0 ][ 0 ]; + vec->Y = matrx[ 1 ][ 0 ]; + vec->Z = matrx[ 2 ][ 0 ]; +} + + +// fetch y vector of matrix --------------------------------------------------- +// +inline +void FetchYVector( const Xmatrx matrx, Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + vec->X = matrx[ 0 ][ 1 ]; + vec->Y = matrx[ 1 ][ 1 ]; + vec->Z = matrx[ 2 ][ 1 ]; +} + + +// fetch z vector of matrix --------------------------------------------------- +// +inline +void FetchZVector( const Xmatrx matrx, Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + vec->X = matrx[ 0 ][ 2 ]; + vec->Y = matrx[ 1 ][ 2 ]; + vec->Z = matrx[ 2 ][ 2 ]; +} + + +// fetch t vector of matrix (translation part) -------------------------------- +// +inline +void FetchTVector( const Xmatrx matrx, Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + vec->X = matrx[ 0 ][ 3 ]; + vec->Y = matrx[ 1 ][ 3 ]; + vec->Z = matrx[ 2 ][ 3 ]; +} + + +// store x vector of matrix --------------------------------------------------- +// +inline +void StoreXVector( Xmatrx matrx, const Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + matrx[ 0 ][ 0 ] = vec->X; + matrx[ 1 ][ 0 ] = vec->Y; + matrx[ 2 ][ 0 ] = vec->Z; +} + + +// store y vector of matrix --------------------------------------------------- +// +inline +void StoreYVector( Xmatrx matrx, const Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + matrx[ 0 ][ 1 ] = vec->X; + matrx[ 1 ][ 1 ] = vec->Y; + matrx[ 2 ][ 1 ] = vec->Z; +} + + +// store z vector of matrix --------------------------------------------------- +// +inline +void StoreZVector( Xmatrx matrx, const Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + matrx[ 0 ][ 2 ] = vec->X; + matrx[ 1 ][ 2 ] = vec->Y; + matrx[ 2 ][ 2 ] = vec->Z; +} + + +// store t vector of matrix (translation part) -------------------------------- +// +inline +void StoreTVector( Xmatrx matrx, const Vector3 *vec ) +{ + ASSERT( matrx != NULL ); + ASSERT( vec != NULL ); + + matrx[ 0 ][ 3 ] = vec->X; + matrx[ 1 ][ 3 ] = vec->Y; + matrx[ 2 ][ 3 ] = vec->Z; +} + + +// primitive vector arithmetics ----------------------------------------------- +// +#define VECADD(c,a,b) { \ + (c)->X = (a)->X+(b)->X; \ + (c)->Y = (a)->Y+(b)->Y; \ + (c)->Z = (a)->Z+(b)->Z; \ +} + +#define VECADD_UVW(c,a,b) { \ + (c)->X = (a)->X+(b)->X; \ + (c)->Y = (a)->Y+(b)->Y; \ + (c)->Z = (a)->Z+(b)->Z; \ + (c)->W = (a)->W+(b)->W; \ + (c)->U = (a)->U+(b)->U; \ + (c)->V = (a)->V+(b)->V; \ +} + +#define VECADD_RGBA(c,a,b) { \ + (c)->X = (a)->X+(b)->X; \ + (c)->Y = (a)->Y+(b)->Y; \ + (c)->Z = (a)->Z+(b)->Z; \ + (c)->R = (a)->R+(b)->R; \ + (c)->G = (a)->G+(b)->G; \ + (c)->B = (a)->B+(b)->B; \ + (c)->A = (a)->A+(b)->A; \ +} + +#define VECADD_UVW_RGBA(c,a,b) { \ + (c)->X = (a)->X+(b)->X; \ + (c)->Y = (a)->Y+(b)->Y; \ + (c)->Z = (a)->Z+(b)->Z; \ + (c)->W = (a)->W+(b)->W; \ + (c)->U = (a)->U+(b)->U; \ + (c)->V = (a)->V+(b)->V; \ + (c)->R = (a)->R+(b)->R; \ + (c)->G = (a)->G+(b)->G; \ + (c)->B = (a)->B+(b)->B; \ + (c)->A = (a)->A+(b)->A; \ +} + +#define VECSUB(c,a,b) { \ + (c)->X = (a)->X-(b)->X; \ + (c)->Y = (a)->Y-(b)->Y; \ + (c)->Z = (a)->Z-(b)->Z; \ +} + +#define VECSUB_UVW(c,a,b) { \ + (c)->X = (a)->X-(b)->X; \ + (c)->Y = (a)->Y-(b)->Y; \ + (c)->Z = (a)->Z-(b)->Z; \ + (c)->W = (a)->W-(b)->W; \ + (c)->U = (a)->U-(b)->U; \ + (c)->V = (a)->V-(b)->V; \ +} + +#define VECSUB_RGBA(c,a,b) { \ + (c)->X = (a)->X-(b)->X; \ + (c)->Y = (a)->Y-(b)->Y; \ + (c)->Z = (a)->Z-(b)->Z; \ + (c)->R = (a)->R-(b)->R; \ + (c)->G = (a)->G-(b)->G; \ + (c)->B = (a)->B-(b)->B; \ + (c)->A = (a)->A-(b)->A; \ +} + +#define VECSUB_UVW_RGBA(c,a,b) { \ + (c)->X = (a)->X-(b)->X; \ + (c)->Y = (a)->Y-(b)->Y; \ + (c)->Z = (a)->Z-(b)->Z; \ + (c)->W = (a)->W-(b)->W; \ + (c)->U = (a)->U-(b)->U; \ + (c)->V = (a)->V-(b)->V; \ + (c)->R = (a)->R-(b)->R; \ + (c)->G = (a)->G-(b)->G; \ + (c)->B = (a)->B-(b)->B; \ + (c)->A = (a)->A-(b)->A; \ +} + +// multiply vector with scalar ------------------------------------------------ +// +#define VECMULS(c,a,b) { \ + (c)->X = (b) * (a)->X; \ + (c)->Y = (b) * (a)->Y; \ + (c)->Z = (b) * (a)->Z; \ +} + + +// saxpy vector arithmetics --------------------------------------------------- +// + +// y = a*x+y (a is scalar) +#define SAXPY(a,x,y) { \ + (y)->X = GEOMV_MUL((a),(x)->X)+(y)->X; \ + (y)->Y = GEOMV_MUL((a),(x)->Y)+(y)->Y; \ + (y)->Z = GEOMV_MUL((a),(x)->Z)+(y)->Z; \ +} + +// c = a*x+y (a is scalar) +#define CSAXPY(c,a,x,y) { \ + (c)->X = GEOMV_MUL((a),(x)->X)+(y)->X; \ + (c)->Y = GEOMV_MUL((a),(x)->Y)+(y)->Y; \ + (c)->Z = GEOMV_MUL((a),(x)->Z)+(y)->Z; \ +} + +// c = a*x+y (a is scalar) +// also calculates [uvw] +#define CSAXPY_UVW(c,a,x,y) { \ + (c)->X = GEOMV_MUL((a),(x)->X)+(y)->X; \ + (c)->Y = GEOMV_MUL((a),(x)->Y)+(y)->Y; \ + (c)->Z = GEOMV_MUL((a),(x)->Z)+(y)->Z; \ + (c)->W = GEOMV_MUL((a),(x)->W)+(y)->W; \ + (c)->U = GEOMV_MUL((a),(x)->U)+(y)->U; \ + (c)->V = GEOMV_MUL((a),(x)->V)+(y)->V; \ +} + + +// accelerated dot product with plane normal (struct Plane3) ------------------ +// +#define PLANE_DOT(p,x) ( PLANE_AXIAL(p) ? \ + ( PLANE_AXISCOMP(p) * ((geomv_t*)x)[ PLANE_CMPAXIS(p) ] ) : \ + DOT_PRODUCT(PLANE_NORMAL(p),(x)) ) + + +// reject/accept point tests for a cull plane --------------------------------- +// +#define PLANEDIST_REJECTPOINT(p,b) ( \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.reject[ 0 ] ], (p)->plane.X ) + \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.reject[ 1 ] ], (p)->plane.Y ) + \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.reject[ 2 ] ], (p)->plane.Z ) - \ + (p)->plane.D ) + +#define PLANEDIST_ACCEPTPOINT(p,b) ( \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.accept[ 0 ] ], (p)->plane.X ) + \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.accept[ 1 ] ], (p)->plane.Y ) + \ + GEOMV_MUL( (b)->minmax[ (p)->reacx.accept[ 2 ] ], (p)->plane.Z ) - \ + (p)->plane.D ) + + +// project 3-D vertex onto screen --------------------------------------------- +// +#define PROJECT_TO_SCREEN(v,s) { \ + (s).X = GEOMV_TO_COORD( GEOMV_DIV( (v).X, (v).Z ) ) + Screen_XOfs; \ + (s).Y = GEOMV_TO_COORD( GEOMV_DIV( (v).Y, (v).Z ) ) + Screen_YOfs; \ +} + + +// elementary transformations into screen space ------------------------------- +// +#define SCREENSPACE_XOZ(v,z) ( GEOMV_TO_COORD( GEOMV_MUL( (v).X, (z) ) ) + Screen_XOfs ) +#define SCREENSPACE_YOZ(v,z) ( GEOMV_TO_COORD( GEOMV_MUL( (v).Y, (z) ) ) + Screen_YOfs ) +#define SCREENSPACE_OOZ(v) ( GEOMV_DIV( GEOMV_1, (v).Z ) ) + + +// depth value calculation ---------------------------------------------------- +// +#ifdef FRACTIONAL_DEPTH_VALUES + #define DEPTHBUFF_VALUE(z) ( (depth_t) (z) ) + #define DEPTHBUFF_OOZ(z) ( (depth_t) GEOMV_DIV( GEOMV_1, (z) ) ) +#else + #define DEPTHBUFF_VALUE(z) ( (word)GEOMV_TO_FIXED(z) ) + #define DEPTHBUFF_OOZ(z) ( (word)GEOMV_TO_FIXED( GEOMV_DIV(GEOMV_1,(z)) ) ) +#endif + + +#endif // _X_MATH_H_ + + diff --git a/src/libparsec/include/utl_math2.h b/src/libparsec/include/utl_math2.h new file mode 100644 index 0000000..ab2a0fd --- /dev/null +++ b/src/libparsec/include/utl_math2.h @@ -0,0 +1,49 @@ +/* + * PARSEC HEADER: xac_mat2.h + */ + +#ifndef _XAC_MAT2_H_ +#define _XAC_MAT2_H_ + + +// xac_mat2.c implements the following functions +// --------------------------------------------- +// geomv_t VctLen( Vector3 *vec ); +// geomv_t VctLenX( Vector3 *vec ); +// void NormVct( Vertex3 *vec ); +// void NormVctX( Vertex3 *vec ); +// void NormMtx( Xmatrx matrix ); +// void MakeIdMatrx( Xmatrx matrx ); +// void MakeNonTranslationMatrx( const Xmatrx matrx, Xmatrx dmatrx ); +// void CalcOrthoInverse( const Xmatrx matrx, Xmatrx dmatrx ); +// void CalcObjSpaceCamera( const GenObject *objectp, Vertex3 *cameravec ); +// void TransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ); +// void BackTransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ); +// int QuaternionIsUnit( const Quaternion *quat ); +// int QuaternionIsUnit_f( const Quaternion_f *quat ); +// void QuaternionMakeUnit( Quaternion *quat ); +// void QuaternionMakeUnit_f( Quaternion_f *quat ); +// void QuaternionInvertUnit( Quaternion *quat ); +// void QuaternionInvertUnit_f( Quaternion_f *quat ); +// void QuaternionInvertGeneral( Quaternion *quat ); +// void QuaternionInvertGeneral_f( Quaternion_f *quat ); +// void QuaternionFromMatrx( Quaternion *quat, const Xmatrx matrix ); +// void QuaternionFromMatrx_f( Quaternion_f *quat, const Xmatrx matrix ); +// void MatrxFromQuaternion( Xmatrx matrix, const Quaternion *quat ); +// void MatrxFromQuaternion_f( Xmatrx matrix, const Quaternion_f *quat ); +// void MatrxFromAngularDisplacement( Xmatrx matrix, bams_t angle, Vertex3 *axis ); +// void QuaternionMUL( Quaternion *qd, const Quaternion *qb, const Quaternion *qa ); +// void QuaternionMUL_f( Quaternion_f *qd, const Quaternion_f *qb, const Quaternion_f *qa ); +// void QuaternionSlerp( Quaternion *qd, const Quaternion *qa, const Quaternion *qb, float alpha ); +// void QuaternionSlerp_f( Quaternion_f *qd, const Quaternion_f *qa, const Quaternion_f *qb, float alpha ); +// void Hermite_Interpolate( Vector3* dest, float t, const Vector3* start, const Vector3* end, const Vector3* start_tan, const Vector3* end_tan, float start_tan_scale, float end_tan_scale ); +// void DumpMatrix( Xmatrx mat ); + +// xac_mat2.c implements the following variables +// --------------------------------------------- +// extern pXmatrx DestXmatrx; + + +#endif // _XAC_MAT2_H_ + + diff --git a/src/libparsec/include/utl_model.h b/src/libparsec/include/utl_model.h new file mode 100644 index 0000000..030df4f --- /dev/null +++ b/src/libparsec/include/utl_model.h @@ -0,0 +1,59 @@ +/* + * PARSEC HEADER: x_model.h + */ + +#ifndef _X_MODEL_H_ +#define _X_MODEL_H_ + + +// ---------------------------------------------------------------------------- +// MODEL GEOMETRY SUBSYSTEM - +// ---------------------------------------------------------------------------- + + +// BSP group + +int BSP_FindColliderLine( CullBSPNode *tree, Vertex3 *v0, Vertex3 *v1, dword *colnode, geomv_t *colt ); + + +// CULL group + +void CULL_ReAcIndexBox3( ReAcIndexBox3 *reac, Plane3 *plane ); +void CULL_ReAcPointBox3( ReAcPointBox3 *reac, CullBox3 *cullbox, Plane3 *plane ); +void CULL_MakeVolumeCullVolume( Plane3 *volume, CullPlane3 *cullvolume, dword cullmask ); +int CULL_BoxAgainstCullVolume( CullBox3 *cullbox, CullPlane3 *volume, dword *cullmask ); +int CULL_BoxAgainstVolume( CullBox3 *cullbox, Plane3 *volume, dword *cullmask ); +int CULL_SphereAgainstVolume( Sphere3 *sphere, Plane3 *volume, dword *cullmask ); + + +// CLIP group + +IterPolygon3* CLIP_VolumeIterTriangle3( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterRectangle3( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterPolygon3( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_VolumeIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *volume, dword cullmask ); +IterPolygon3* CLIP_PlaneIterTriangle3( IterTriangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterRectangle3( IterRectangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterPolygon3( IterPolygon3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *plane ); +IterPolygon3* CLIP_PlaneIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *plane ); + +IterLine2* CLIP_RectangleIterLine2( IterLine2 *line, Rectangle2 *rect ); +IterLine3* CLIP_PlaneIterLine3( IterLine3 *line, Plane3 *plane ); + +GenObject* CLIP_VolumeGenObject( GenObject *clipobj, Plane3 *volume, dword cullmask ); +GenObject* CLIP_PlaneGenObject( GenObject *clipobj, Plane3 *plane ); + + +#endif // _X_MODEL_H_ + + diff --git a/src/libparsec/net_pckt_gmsv.cpp b/src/libparsec/net_pckt_gmsv.cpp new file mode 100644 index 0000000..02bb16e --- /dev/null +++ b/src/libparsec/net_pckt_gmsv.cpp @@ -0,0 +1,507 @@ +/* + * PARSEC - Packet Functions + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:45 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +//#include "aud_defs.h" +#include "net_defs.h" +//#include "sys_defs.h" + +// mathematics header +#include "utl_math.h" + +// network code config +#include "net_conf.h" + +// subsystem linkage info +#include "linkinfo.h" + +// local module header +#include "net_pckt_gmsv.h" + +// proprietary module headers +#if defined ( PARSEC_SERVER ) || defined ( PARSEC_MASTER ) + #include "con_aux_sv.h" + #include "net_game_sv.h" +#elif defined PARSEC_CLIENT + #include "con_aux.h" + #include "net_stream.h" + #include "net_game.h" + #include "net_rmev.h" +#endif // PARSEC_SERVER + +#include "net_csdf.h" +#include "net_pckt.h" +#include "net_swap.h" +#include "net_util.h" + + + +// flags ---------------------------------------------------------------------- +// +#ifndef PARSEC_MASTER + //#define LOG_PACKETS // define this to get logs of incoming/outgoing packets +#endif // PARSEC_MASTER + + +#ifdef PARSEC_CLIENT + + #ifdef DBIND_PROTOCOL + + #undef NETs_HandleOutPacket + #undef NETs_HandleOutPacket_DEMO + #undef NETs_HandleInPacket + #undef NETs_HandleInPacket_DEMO + #undef NETs_NetPacketExternal_DEMO_GetSize + #undef NETs_StdGameHeader + #undef NETs_WritePacketInfo + + #define NETs_HandleOutPacket NETs_GAMESERVER_HandleOutPacket + #define NETs_HandleOutPacket_DEMO NETs_GAMESERVER_HandleOutPacket_DEMO + #define NETs_HandleInPacket NETs_GAMESERVER_HandleInPacket + #define NETs_HandleInPacket_DEMO NETs_GAMESERVER_HandleInPacket_DEMO + #define NETs_NetPacketExternal_DEMO_GetSize NETs_GAMESERVER_NetPacketExternal_DEMO_GetSize + #define NETs_StdGameHeader NETs_GAMESERVER_StdGameHeader + #define NETs_WritePacketInfo NETs_GAMESERVER_WritePacketInfo + + #endif // DBIND_PROTOCOL + +#endif // PARSEC_CLIENT + + + +#ifdef LOG_PACKETS + + #include "utl_logfile.h" + + static UTL_LogFile g_PacketInLogfile( "packets.in.log" ); + static UTL_LogFile g_PacketOutLogfile( "packets.out.log" ); +#endif // LOG_PACKETS + + + +// flags ---------------------------------------------------------------------- +// +#define _SET_RE_LISTSIZE_ON_PACK +//#define SHOW_CRC32_WHEN_SENDING + +// protocol type signature ---------------------------------------------------- +// +const char net_packet_signature_gameserver[] = "PCS"; + +#ifdef PARSEC_CLIENT + + extern NET_Stream ServerStream; + + // fill standard fields in gamedata header ( gameserver ) ---------------- + // + void NETs_StdGameHeader( byte command, NetPacket* gamepacket ) + { + ASSERT( gamepacket != NULL ); + + NetPacket_GMSV* gamepacket_GMSV = (NetPacket_GMSV*) gamepacket; + + // clear header and remote event list area + memset( gamepacket_GMSV, 0, NET_MAX_NETPACKET_INTERNAL_LEN ); + + gamepacket_GMSV->Command = command; + gamepacket_GMSV->SendPlayerId = LocalPlayerId; + + //FIXME: for debugging purposes, we should call OutPacket() with filled RE list in gamepacket + ServerStream.OutPacket( gamepacket_GMSV ); + + // RE list size always includes the RE terminator + ((RE_Header* )&gamepacket_GMSV->RE_List)->RE_Type = RE_EMPTY; + gamepacket_GMSV->RE_ListSize = sizeof( dword ); + } + +#endif // PARSEC_CLIENT + +// return the packetsize of a external DEMO packet ( PEER ) ------------------- +// +size_t NETs_NetPacketExternal_DEMO_GetSize( const NetPacketExternal* ext_gamepacket ) +{ + ASSERT( ext_gamepacket != NULL ); +#ifdef PARSEC_CLIENT + ASSERT( NET_ProtocolGMSV() ); +#endif // PARSEC_CLIENT + + // header is always needed + size_t psize = sizeof( NetPacketExternal_DEMO_GMSV ) - sizeof( dword ); + + // add size of remote event list + RE_Header* relist = (RE_Header *) &((NetPacketExternal_DEMO_GMSV*)ext_gamepacket)->RE_List; + psize += NET_RmEvList_GetSize( relist ); + + ASSERT( psize <= (size_t)NET_MAX_DATA_LENGTH ); + return psize; +} + +// determine actually needed size of packet (strip unused remote event area) -- +// +PRIVATE +size_t GMSV_NetPacketExternal_GetSize( NetPacketExternal_GMSV* ext_gamepacket_GMSV ) +{ + //NOTE: + // even though this function is operating on a packet in network byte-order, + // swapping is not necessary since all accesses are byte-sized. (that is, + // byte-ordering is entirely irrelevant.) + + // header is always needed + size_t psize = sizeof( NetPacketExternal_GMSV ) - sizeof( dword ); + + // add size of remote event list + psize += NET_RmEvList_GetSize( (RE_Header *) &ext_gamepacket_GMSV->RE_List ); + + //ASSERT( psize <= (size_t)NET_MAX_DATA_LENGTH ); + if(psize >= (size_t)NET_MAX_DATA_LENGTH ) + MSGOUT("CRAZYSPENCE: Packet size larger than %d: %d",NET_MAX_DATA_LENGTH,psize); + return psize; +} + +// swap endianness of whole (external) network packet ------------------------- +// +PRIVATE +void GMSV_NetPacketExternal_Swap( NetPacketExternal* ext_gamepacket, int incoming ) +{ + ASSERT( ext_gamepacket != NULL ); + + NetPacketExternal_GMSV* ext_gamepacket_GMSV = (NetPacketExternal_GMSV*)ext_gamepacket; + +#ifdef ENABLE_PACKET_SWAPPING + + ext_gamepacket_GMSV->Protocol = NET_SWAP_16( ext_gamepacket_GMSV->Protocol ); + + ext_gamepacket_GMSV->MessageId = NET_SWAP_32( ext_gamepacket_GMSV->MessageId ); + ext_gamepacket_GMSV->SendPlayerId = NET_SWAP_32( ext_gamepacket_GMSV->SendPlayerId ); + ext_gamepacket_GMSV->ReliableMessageId = NET_SWAP_32( ext_gamepacket_GMSV->ReliableMessageId ); + ext_gamepacket_GMSV->AckMessageId = NET_SWAP_32( ext_gamepacket_GMSV->AckMessageId ); + ext_gamepacket_GMSV->AckReliableMessageId = NET_SWAP_32( ext_gamepacket_GMSV->AckReliableMessageId ); + + // swap entire RE list + NET_RmEvList_Swap( (RE_Header*) &ext_gamepacket_GMSV->RE_List, incoming ); + +#endif // ENABLE_PACKET_SWAPPING +} + + +// store the CRC in an external packet ---------------------------------------- +// +PRIVATE +void GMSV_NetPacketExternal_StoreCRC( NetPacketExternal_GMSV* ext_gamepacket, size_t pktsize ) +{ + // challenge we got from server + //FIXME: this should go into a module NET_GLOB_GMSV + //extern int CS_connect_challenge; + + // set the crc32 field to known value and calculate the CRC for the header + ext_gamepacket->crc32 = 0; + ext_gamepacket->crc32 = NET_CalcCRC( (void*)ext_gamepacket, pktsize ); + +#ifdef SHOW_CRC32_WHEN_SENDING + DBGTXT( MSGOUT( "CRC32 of packet %d is %x", ext_gamepacket->MessageId, ext_gamepacket->crc32 ); ); +#endif // SHOW_CRC32_WHEN_SENDING + + // swap CRC + ext_gamepacket->crc32 = NET_SWAP_32( ext_gamepacket->crc32 ); +} + +// translate internal packet to external DEMO packet ( gameserver ) ----------- +// +size_t NETs_HandleOutPacket_DEMO( const NetPacket* int_gamepacket, NetPacketExternal* ext_gamepacket ) +{ + //FIXME: implement DEMO recording in GMSV mode + ASSERT( FALSE ); + return 0; +} + +// pack an internal packet to an external packet ( gameserver ) --------------- +// +size_t NETs_HandleOutPacket( const NetPacket* int_gamepacket, NetPacketExternal* ext_gamepacket ) +{ + ASSERT( int_gamepacket != NULL ); + ASSERT( ext_gamepacket != NULL ); +#ifdef PARSEC_CLIENT + ASSERT( NET_ProtocolGMSV() ); +#endif // PARSEC_CLIENT + + NetPacket_GMSV* int_gamepacket_GMSV = (NetPacket_GMSV*) int_gamepacket; + NetPacketExternal_GMSV* ext_gamepacket_GMSV = (NetPacketExternal_GMSV*) ext_gamepacket; + +#ifdef PARSEC_CLIENT + ASSERT( int_gamepacket_GMSV->SendPlayerId != PLAYERID_SERVER ); + ASSERT( int_gamepacket_GMSV->SendPlayerId != PLAYERID_MASTERSERVER ); +#elif defined PARSEC_SERVER + ASSERT( int_gamepacket_GMSV->SendPlayerId == PLAYERID_SERVER ); +#elif defined PARSEC_MASTER + ASSERT( int_gamepacket_GMSV->SendPlayerId == PLAYERID_MASTERSERVER ); +#endif // PARSEC_MASTER + + // fill header for external packets + strncpy( ext_gamepacket_GMSV->Signature, net_packet_signature_gameserver, SIGNATURE_LEN_GAMESERVER ); + ext_gamepacket_GMSV->Signature[ SIGNATURE_LEN_GAMESERVER ] = 0; + ext_gamepacket_GMSV->Protocol = PROTOCOL_GAMESERVER; + ext_gamepacket_GMSV->MajorVersion = CLSV_PROTOCOL_MAJOR; + ext_gamepacket_GMSV->MinorVersion = CLSV_PROTOCOL_MINOR; + + // pack internal packet data to external packet + ext_gamepacket_GMSV->SendPlayerId = int_gamepacket_GMSV->SendPlayerId; + + ext_gamepacket_GMSV->MessageId = int_gamepacket_GMSV->MessageId; + ext_gamepacket_GMSV->ReliableMessageId = int_gamepacket_GMSV->ReliableMessageId; + ext_gamepacket_GMSV->AckMessageId = int_gamepacket_GMSV->AckMessageId; + ext_gamepacket_GMSV->AckReliableMessageId = int_gamepacket_GMSV->AckReliableMessageId; + + ext_gamepacket_GMSV->Command = (byte)int_gamepacket_GMSV->Command; + + + //FIXME: [1/30/2002] remove this, when RE_Listsize is correctly maintained +#ifdef _SET_RE_LISTSIZE_ON_PACK + int_gamepacket_GMSV->RE_ListSize = NET_RmEvList_GetSize( (RE_Header*)&int_gamepacket_GMSV->RE_List ); +#endif // _SET_RE_LISTSIZE_ON_PACK + + // check that RE_ListSize corresponds with the actual length of the remote event list + ASSERT( int_gamepacket_GMSV->RE_ListSize == NET_RmEvList_GetSize( (RE_Header*)&int_gamepacket_GMSV->RE_List ) ); + + memcpy( (void*)&ext_gamepacket_GMSV->RE_List, (void*)&int_gamepacket_GMSV->RE_List, int_gamepacket_GMSV->RE_ListSize ); + + // get the size of the packet + size_t pktsize = GMSV_NetPacketExternal_GetSize( ext_gamepacket_GMSV ); + + // establish network byte-order for external packet ( outgoing ) + GMSV_NetPacketExternal_Swap( ext_gamepacket_GMSV, FALSE ); + + // store the CRC in the packet + GMSV_NetPacketExternal_StoreCRC( ext_gamepacket_GMSV, pktsize ); + +#ifdef ENCRYPT_PACKETS + + // encrypt packet payload & modify protocol to indicate an encrypted packet + if ( !( AUX_NETCODE_FLAGS & 2 ) ) { + + NET_EncryptData( &ext_gamepacket_GMSV->crc32, pktsize - offsetof( NetPacketExternal_GMSV, crc32 ) ); + + // establish host byte order, modify field, and establish network order again + ext_gamepacket_GMSV->Protocol = NET_SWAP_16( ext_gamepacket_GMSV->Protocol ); + ext_gamepacket_GMSV->Protocol |= PROTOCOL_ENCRYPTED; + ext_gamepacket_GMSV->Protocol = NET_SWAP_16( ext_gamepacket_GMSV->Protocol ); + } + +#endif // ENCRYPT_PACKETS + + +#ifdef LOG_PACKETS + g_PacketOutLogfile.printf( "%d", int_gamepacket_GMSV->MessageId ); +#endif // LOG_PACKETS + + + return pktsize; +} + +// translate an external GMSV DEMO packet to internal GMSV packet ------------- +// +int NETs_HandleInPacket_DEMO( const NetPacketExternal* ext_gamepacket, NetPacket* int_gamepacket, size_t* psize_external ) +{ + //NOTE: sets psize_external to the packetsize of the external packet + // ( needed for playback from compiled demos ) + + //FIXME: implement DEMO recording in GMSV mode + ASSERT( FALSE ); + return 0; +} + +// handle an incoming packet ( gameserver ) ------------------------------- +// +int NETs_HandleInPacket( const NetPacketExternal* ext_gamepacket, const int ext_pktsize, NetPacket* int_gamepacket ) +{ + ASSERT( int_gamepacket != NULL ); + ASSERT( ( ext_pktsize > 0 ) && ( ext_pktsize <= NET_MAX_DATA_LENGTH ) ); + ASSERT( ext_gamepacket != NULL ); + +#ifdef PARSEC_CLIENT + ASSERT( NET_ProtocolGMSV() ); +#endif // PARSEC_CLIENT + + // sanity check for packet len + if ( ext_pktsize > NET_MAX_DATA_LENGTH ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket: dropped packet [invalid packet len]." ); ); + return FALSE; + } + + NetPacket_GMSV* int_gamepacket_GMSV = (NetPacket_GMSV*) int_gamepacket; + NetPacketExternal_GMSV* ext_gamepacket_GMSV = (NetPacketExternal_GMSV*) ext_gamepacket; + + // establish host byte order + ext_gamepacket_GMSV->Protocol = NET_SWAP_16( ext_gamepacket_GMSV->Protocol ); + +#ifdef ENCRYPT_PACKETS + + // check whether the packet supposedly is encrypted + if ( ext_gamepacket_GMSV->Protocol & PROTOCOL_ENCRYPTED ) { + + // decrypt external packet + if ( !( AUX_NETCODE_FLAGS & 2 ) ) { + NET_DecryptData( &ext_gamepacket_GMSV->crc32, ext_pktsize - offsetof( NetPacketExternal_GMSV, crc32 ) ); + } + + // revert to decrypted protocol + ext_gamepacket_GMSV->Protocol &= ~PROTOCOL_ENCRYPTED; + } + +#endif // ENCRYPT_PACKETS + + // establish network byte order + ext_gamepacket_GMSV->Protocol = NET_SWAP_16( ext_gamepacket_GMSV->Protocol ); + + if ( !( AUX_NETCODE_FLAGS & 1 ) ) { + + // as the CRC has been calculated with the crc32 field stored in the packet beeing set to zero. + // we need to do this here as well, backup CRC for compare + dword crc32_stored = NET_SWAP_32( ext_gamepacket_GMSV->crc32 ); + ext_gamepacket_GMSV->crc32 = 0; + + // calculate CRC over packet + dword crc32 = NET_CalcCRC( ext_gamepacket_GMSV, ext_pktsize ); + + // check whether CRC is correct + if ( crc32 != crc32_stored ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket(): dropped packet [CRC check failed]. calc.:%x stored:=%x", crc32, crc32_stored ); ); + return FALSE; + } + } + + // convert external packet from packet byte-order to host byte-order + GMSV_NetPacketExternal_Swap( ext_gamepacket_GMSV, TRUE ); + + // check for correct signature + if ( strncmp( ext_gamepacket_GMSV->Signature, net_packet_signature_gameserver, SIGNATURE_LEN_GAMESERVER ) != 0 ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket(): dropped packet [invalid signature]." ); ); + return FALSE; + } + + // check for correct protocol + if ( ext_gamepacket_GMSV->Protocol != PROTOCOL_GAMESERVER ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket(): dropped packet [invalid protocol]." ); ); + return FALSE; + } + + // check for correct protocol version + if ( ( ext_gamepacket_GMSV->MajorVersion != CLSV_PROTOCOL_MAJOR ) || ( ext_gamepacket_GMSV->MinorVersion != CLSV_PROTOCOL_MINOR ) ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket(): dropped packet [incompatible protocol version]." ); ); + return FALSE; + } + + // unpack external packet data to internal packet + int_gamepacket_GMSV->SendPlayerId = ext_gamepacket_GMSV->SendPlayerId; + + int_gamepacket_GMSV->MessageId = ext_gamepacket_GMSV->MessageId; + int_gamepacket_GMSV->ReliableMessageId = ext_gamepacket_GMSV->ReliableMessageId; + int_gamepacket_GMSV->AckMessageId = ext_gamepacket_GMSV->AckMessageId; + int_gamepacket_GMSV->AckReliableMessageId = ext_gamepacket_GMSV->AckReliableMessageId; + + int_gamepacket_GMSV->Command = (int)ext_gamepacket_GMSV->Command; + //int_gamepacket_GMSV->params[ 0 ] = (int)ext_gamepacket_GMSV->param1; + //int_gamepacket_GMSV->params[ 1 ] = (int)ext_gamepacket_GMSV->param2; + //int_gamepacket_GMSV->params[ 2 ] = (int)ext_gamepacket_GMSV->param3; + //int_gamepacket_GMSV->params[ 3 ] = ext_gamepacket_GMSV->param4; + +/* +#ifdef PARSEC_SERVER // disable this because the server will send the master server packets with this id. + ASSERT( int_gamepacket_GMSV->SendPlayerId != PLAYERID_SERVER ); +#endif // PARSEC_SERVER +*/ + // check whether external remote event list is well formed ( integrity and length ) + if ( NET_RmEvList_IsWellFormed( (RE_Header*)&ext_gamepacket_GMSV->RE_List ) == FALSE ) { + DBGTXT( MSGOUT( "NETs_HandleInPacket(): dropped packet [invalid RE list]." ); ); + return FALSE; + } + + // determine remote event list size ( includes RE termination ) + int_gamepacket_GMSV->RE_ListSize = NET_RmEvList_GetSize( (RE_Header*)&ext_gamepacket_GMSV->RE_List ); + memcpy( (void*)&int_gamepacket_GMSV->RE_List, (void*)&ext_gamepacket_GMSV->RE_List, int_gamepacket_GMSV->RE_ListSize ); + +#ifdef LOG_PACKETS + g_PacketInLogfile.printf( "%d", int_gamepacket_GMSV->MessageId ); +#endif // LOG_PACKETS + + return TRUE; +} + + +// fp to which PacketInfo functions write ------------------------------------- +// +extern FILE *dest_fp_PacketInfo; + + +#ifndef PARSEC_MASTER + +// write verbose packet info as comment to recording file --------------------- +// +void NETs_WritePacketInfo( FILE *fp, NetPacketExternal* ext_gamepacket ) +{ + ASSERT( fp != NULL ); + ASSERT( ext_gamepacket != NULL ); + + // store fp for PrInf_ functions + dest_fp_PacketInfo = fp; + + // create packet copy and swap from network byte-order + NetPacketExternal_GMSV* ext_gamepacket_copy = (NetPacketExternal_GMSV*) ALLOCMEM( NET_MAX_DATA_LENGTH ); + if ( ext_gamepacket_copy == NULL ) + return; + + memcpy( ext_gamepacket_copy, ext_gamepacket, NET_MAX_DATA_LENGTH ); + + // swap to host byte order + GMSV_NetPacketExternal_Swap( ext_gamepacket_copy, TRUE ); + + NET_PacketInfo( ";-- srcid=%d, msgid=%d, relmsgid=%d, ackmsgid=%d, ackrelmsgid=%d\n", + ext_gamepacket_copy->SendPlayerId, + ext_gamepacket_copy->MessageId, + ext_gamepacket_copy->ReliableMessageId, + ext_gamepacket_copy->AckMessageId, + ext_gamepacket_copy->AckReliableMessageId ); + + NET_PacketInfo( ";-- command %d\n", ext_gamepacket_copy->Command ); + + // process remote event list + NET_RmEvList_WriteInfo( fp, (RE_Header *) &ext_gamepacket_copy->RE_List ); +} + +#endif // !PARSEC_MASTER diff --git a/src/libparsec/net_stream.cpp b/src/libparsec/net_stream.cpp new file mode 100644 index 0000000..5901f42 --- /dev/null +++ b/src/libparsec/net_stream.cpp @@ -0,0 +1,587 @@ +/* + * PARSEC - stream class - shared + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:45 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" +#include "sys_defs.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_stream.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + #include "con_aux_sv.h" +#else + #include "con_aux.h" +#endif +#include "e_relist.h" + + +// default retransmit timeout is 200ms ---------------------------------------- +// +#define DEFAULT_RETRANSMIT_TIMEOUT FRAME_MEASURE_TIMEBASE / ( 1000 / 200 ) + + +// flags ---------------------------------------------------------------------- +// +#define _FORCED_RELIABLE_DROPPING +//#define _IDEMPOTENCY_TESTING // enable this to ALWAYS resent a packet ONCE + + + +// reset the FIFO entry ------------------------------------------------------- +// +void StreamFIFOEntry_s::Reset() +{ + // decrease reference counter + if ( m_pREList != NULL ) { + m_pREList->Release(); + } + + m_pREList = NULL; + m_Timeout = -1; + m_nRetransmitCount = 0; +} + + +// init the FIFO entry -------------------------------------------------------- +// +void StreamFIFOEntry_s::InitEntry( E_REList* pREList ) +{ + m_pREList = pREList; + m_Timeout = -1; + m_nRetransmitCount = 0; + + // increase reference counter + m_pREList->AddRef(); +} + + + + +// default ctor --------------------------------------------------------------- +// +NET_Stream::NET_Stream() +{ + Reset(); + m_ReliableRetransmit_Frames = DEFAULT_RETRANSMIT_TIMEOUT; +} + +// reset the stream to defaults ----------------------------------------------- +// +void NET_Stream::Reset() +{ + //MSGOUT("NET_Stream::Reset()"); + + // NOTE: + // no message with # ( normal/reliable ) of 0 is sent over the wire + // + Out_MessageId = 1; // first message sent is 1 + Out_ReliableMessageId = 1; + + I_ACK_MessageId = 0; + I_ACK_ReliableMessageId = 0; + + YOU_ACK_MessageId = 0; + YOU_ACK_ReliableMessageId = 0; + + for( int hid = 0; hid < MSGID_HISTORY_SIZE; hid++ ) { + message_id_history[ hid ] = 0; + } + + FlushReliableBuffer(); + + // default to support reliable transfer + m_EnableReliable = true; + + // set ids of the partners for this stream + m_nPeerID = PLAYERID_ANONYMOUS; + m_nSenderID = PLAYERID_INVALID; + + m_bIsConnected = false; +} + + +// set the stream to connected mode ( accepts non datagrams ) ----------------- +void NET_Stream::SetConnected() +{ + m_bIsConnected = true; +} + + +// append a RE list to the FIFO ---------------------------------------------- +// +int NET_Stream::AppendToReliableFIFO( E_REList* pREList ) +{ + ASSERT( pREList != NULL ); + + //MSGOUT( "AppendToReliableFIFO(): " ); + //pREList->Dump(); + if ( pREList->GetSize() == 0 ) { + ASSERT( FALSE ); + return FALSE; + } + + if ( !m_EnableReliable ) { + ASSERT( FALSE ); + return FALSE; + } + + // check whether the new append would cause the FIFO to overflow + int nNextWritePos = _FIFO_GetNextWritePos(); + StreamFIFOEntry_s* pEntry = &m_FIFOEntries[ nNextWritePos ]; + if ( pEntry->m_pREList != NULL ) { + DBGTXT( + MSGOUT("NET_Stream::AppendToReliableFIFO(): FIFO overflow." ); + for( int nEntry = 0; nEntry < MAX_NUM_RELIABLE_BACKLOG; nEntry++ ) { + MSGOUT( "================================\n" ); + MSGOUT( "FIFO: %d\n", nEntry ); + m_FIFOEntries[ nEntry ].m_pREList->Dump(); + MSGOUT( "================================\n" ); + } + ); + + return FALSE; + } + + // otherwise append the RE list to the end of the FIFO + pEntry->InitEntry( pREList ); + + m_nFIFO_WritePos = nNextWritePos; + + return TRUE; +} + + +// update the timeout for a specific FIFO slot -------------------------------- +// +void NET_Stream::_FIFO_UpdateTimeOut( StreamFIFOEntry_s* pEntry ) +{ + ASSERT( pEntry != NULL ); + pEntry->m_Timeout = ( SYSs_GetRefFrameCount() + m_ReliableRetransmit_Frames ); +} + + +// reset all reliable handling ------------------------------------------------ +// +void NET_Stream::FlushReliableBuffer() +{ + m_MessageId_ReliableWasSent = 0; + + // reset FIFO + m_nFIFO_WritePos = -1; + m_nFIFO_ReadPos = 0; + for( int nEntry = 0; nEntry < MAX_NUM_RELIABLE_BACKLOG; nEntry++ ) { + m_FIFOEntries[ nEntry ].Reset(); + } +} + + +// retrieve the next reliable RE list from FIFO to send ----------------------- +// +E_REList* NET_Stream::GetNextReliableToSend() +{ + // sanety checks + if( YOU_ACK_MessageId >= Out_MessageId ) + return NULL; + if( YOU_ACK_ReliableMessageId >= Out_ReliableMessageId ) + return NULL; + + StreamFIFOEntry_s* pEntry = &m_FIFOEntries[ m_nFIFO_ReadPos ]; + E_REList* pREList = pEntry->m_pREList; + + // nothing in FIFO + if ( pREList == NULL ) { + //DBGOUT( "NET_Stream::GetNextReliableToSend(): %d nothing in FIFO", m_nPeerID ); + return NULL; + } + + // check for first transmit of top entry in FIFO + if ( pEntry->m_Timeout == -1 ) { + + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d first transmit FIFO entry: %d", m_nPeerID, m_nFIFO_ReadPos ); + + // update timeout value & first-transmit + _FIFO_UpdateTimeOut( pEntry ); + return pREList; + } + + // if last sent reliable is not yet ACK + // retransmit if timeout, do nothing otherwise + if ( YOU_ACK_MessageId < m_MessageId_ReliableWasSent ) { + + ASSERT( pEntry->m_Timeout != -1 ); + + // timer expired ? + if ( pEntry->m_Timeout < SYSs_GetRefFrameCount() ) { + + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d timer expired - retransmit #%d - FIFO entry: %d", m_nPeerID, pEntry->m_nRetransmitCount + 1, m_nFIFO_ReadPos ); + + // update timeout value & return for retransmit + pEntry->m_nRetransmitCount++; + _FIFO_UpdateTimeOut( pEntry ); + return pREList; + } + + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d entry %d not yet ACK", m_nPeerID, m_nFIFO_ReadPos ); + + return NULL; + } + + ASSERT( YOU_ACK_MessageId >= m_MessageId_ReliableWasSent ); + + // if last sent reliable is ACK + // remove top Pos from FIFO AND transmit next reliable in FIFO + if ( YOU_ACK_ReliableMessageId == ( Out_ReliableMessageId - 1 ) ) { + + // remove message if still in backbuffer + if ( pREList != NULL ) { +#ifdef _IDEMPOTENCY_TESTING + if ( pEntry->m_nRetransmitCount == 0 ) { + pEntry->m_nRetransmitCount++; + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d IDEMPOTENCY TESTING entry %d", m_nPeerID, m_nFIFO_ReadPos ); + + // update timeout value & return for retransmit + _FIFO_UpdateTimeOut( pEntry ); + return pREList; + + } else { + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d removing from FIFO due to ACK : %d", m_nPeerID, m_nFIFO_ReadPos ); + pEntry->Reset(); + } +#else + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d removing from FIFO due to ACK : %d", m_nPeerID, m_nFIFO_ReadPos ); + pEntry->Reset(); +#endif // _IDEMPOTENCY_TESTING + } + + // step to next entry + m_nFIFO_ReadPos = _FIFO_GetNextReadPos(); + pEntry = &m_FIFOEntries[ m_nFIFO_ReadPos ]; + pREList = pEntry->m_pREList; + + if ( pREList != NULL ) { + + ASSERT( pEntry->m_Timeout == -1 ); + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d first transmit FIFO entry: %d", m_nPeerID, m_nFIFO_ReadPos ); + + // update timeout value + _FIFO_UpdateTimeOut( pEntry ); + + return pREList; + } else { + + //DBGOUT( "NET_Stream::GetNextReliableToSend(): %d nothing in FIFO", m_nPeerID ); + return NULL; + } + + } else { + + // if last sent reliable is NACK + // retransmit top of FIFO + ASSERT( YOU_ACK_ReliableMessageId < ( Out_ReliableMessageId - 1 ) ); + + DBGOUT( "NET_Stream::GetNextReliableToSend(): %d NACK detected - retransmit - FIFO entry: %d", m_nPeerID, m_nFIFO_ReadPos ); + + // update timeout value & retransmit + pEntry->m_nRetransmitCount++; + _FIFO_UpdateTimeOut( pEntry ); + return pREList; + } +} + + +// check input packet for rejection and maintain ACKs correctly ----------- +// +int NET_Stream::InPacket( NetPacket_GMSV* gamepacket_GMSV ) +{ + ASSERT( gamepacket_GMSV != NULL ); + + // datagrams are ignored + if ( gamepacket_GMSV->MessageId == MSGID_DATAGRAM ) { + return TRUE; + } + + // nothing todo until connected + if ( m_bIsConnected == false ) { + DBGTXT( MSGOUT( "NET_Stream::InPacket(): ignoring non-datagram packets on disconnected stream" ); ); + return FALSE; + } + +#ifdef _FORCED_RELIABLE_DROPPING +#ifdef PARSEC_CLIENT + + if ( AUX_NETCODE_FLAGS & 32 ) { + return FALSE; + } + + if ( ( AUX_NETCODE_FLAGS & 64 ) && ( gamepacket_GMSV->ReliableMessageId != NO_RELIABLE ) ) { + static int numreliable = -1; + + numreliable++; + + // only accept every 5th reliable packet + if ( ( numreliable % 5 ) != 4 ) { + return FALSE; + } + } + +#endif // PARSEC_CLIENT +#endif // _FORCED_RELIABLE_DROPPING + + // debug output +#ifdef INTERNAL_VERSION + if ( AUX_DEBUG_NETSTREAM_DUMP & 1 ) { + LOGOUT(( "-------------------------------------------------------------------------------" )); + LOGOUT(( "(%2d), InPacket from %2d, MessageId %5d, ReliableMessageId %5d, AckMessageId %5d, AckReliableMessageId %5d", + m_nSenderID, + m_nPeerID, + gamepacket_GMSV->MessageId, + gamepacket_GMSV->ReliableMessageId, + gamepacket_GMSV->AckMessageId, + gamepacket_GMSV->AckReliableMessageId + )); + + E_REList* relist = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + relist->AppendList( (RE_Header*)&gamepacket_GMSV->RE_List ); + relist->Dump(); + relist->Release(); + + LOGOUT(( "-------------------------------------------------------------------------------" )); + } +#endif // INTERNAL_VERSION + + // do not process older messages ( I already sent an ACK ) + //FIXME: what do we do with reliable remote events here ? -> SOLUTION: we remove them as well, as they must already have been retransmitted in later packets + if ( I_ACK_MessageId >= gamepacket_GMSV->MessageId ) { + MSGOUT( "NET_Stream::InPacket(): ignoring msgid %d ( already got %d )", gamepacket_GMSV->MessageId, I_ACK_MessageId ); + return FALSE; + } + + // ACK that we received this message + I_ACK_MessageId = max( I_ACK_MessageId, gamepacket_GMSV->MessageId ); + + // get the ACK from partner + YOU_ACK_MessageId = max( YOU_ACK_MessageId, gamepacket_GMSV->AckMessageId ); + + // if we receive a ACK for a message we didnt yet send, we discard the packet + if ( YOU_ACK_MessageId >= Out_MessageId ) { + //ASSERT( FALSE ); + DBGTXT( MSGOUT( "NET_Stream::InPacket(): receiving ACK for unsent packet %d ( next outgoing is %d )", YOU_ACK_MessageId, Out_MessageId - 1 ); ); + return FALSE; + } + + // handle reliable versions ? + if ( m_EnableReliable ) { + + if ( gamepacket_GMSV->ReliableMessageId != NO_RELIABLE ) { + // ACK that we received this message + I_ACK_ReliableMessageId = max( I_ACK_ReliableMessageId, gamepacket_GMSV->ReliableMessageId ); + } + // get the ACK from partner + YOU_ACK_ReliableMessageId = max( YOU_ACK_ReliableMessageId, gamepacket_GMSV->AckReliableMessageId ); + + // be sure the partner doesnt spoof us ( ACK for msg that was not yet sent ! ) + //ASSERT( YOU_ACK_ReliableMessageId < Out_ReliableMessageId ); + YOU_ACK_ReliableMessageId = min( YOU_ACK_ReliableMessageId, Out_ReliableMessageId ); + + } else { + + // check whether we got a reliable message + if ( gamepacket_GMSV->ReliableMessageId != NO_RELIABLE ) { + ASSERT( FALSE ); + MSGOUT( "NET_Stream::InPacket(): received reliable message on UNRELIABLE stream !" ); + return FALSE; + } + } + + return TRUE; +} + + +// fill in fields in outgoing packet -------------------------------------- +// +void NET_Stream::OutPacket( NetPacket_GMSV* gamepacket_GMSV, int reliable /*= FALSE*/ ) +{ + ASSERT( gamepacket_GMSV != NULL ); + + gamepacket_GMSV->MessageId = Out_MessageId; + gamepacket_GMSV->ReliableMessageId = NO_RELIABLE; + gamepacket_GMSV->AckMessageId = I_ACK_MessageId; + gamepacket_GMSV->AckReliableMessageId = NO_RELIABLE; + + // handle reliable message # + if( reliable ) { + + // check whether reliable transfer is disabled + if ( !m_EnableReliable ) { + ASSERT( FALSE ); + MSGOUT( "NET_Stream::OutPacket(): trying to send reliable message on UNRELIABLE stream !" ); + } else { + gamepacket_GMSV->ReliableMessageId = Out_ReliableMessageId; + + // remember the message id that carried the reliable + m_MessageId_ReliableWasSent = Out_MessageId; + + // increase reliable message counter ( wrap-around ) + Out_ReliableMessageId = ( Out_ReliableMessageId == UINT_MAX ) ? 1 : Out_ReliableMessageId + 1; + } + } + + // ACK reliable + if ( m_EnableReliable ) { + gamepacket_GMSV->AckReliableMessageId = I_ACK_ReliableMessageId; + } + + // increase message counter ( wrap-around, check for MSGID_DATAGRAM ) + Out_MessageId = ( Out_MessageId == ( MSGID_DATAGRAM - 1 ) ) ? 1 : Out_MessageId + 1; + +#ifdef INTERNAL_VERSION + // debug output + if ( AUX_DEBUG_NETSTREAM_DUMP & 2 ) { + + LOGOUT(( "-------------------------------------------------------------------------------" )); + LOGOUT(( "(%2d), OutPacket to %2d, MessageId %5d, ReliableMessageId %5d, AckMessageId %5d, AckReliableMessageId %5d", + m_nSenderID, + m_nPeerID, + gamepacket_GMSV->MessageId, + gamepacket_GMSV->ReliableMessageId, + gamepacket_GMSV->AckMessageId, + gamepacket_GMSV->AckReliableMessageId + )); + + E_REList* relist = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + relist->AppendList( (RE_Header*)&gamepacket_GMSV->RE_List ); + relist->Dump(); + relist->Release(); + LOGOUT(( "------------------------------------------" )); + } +#endif // INTERNAL_VERSION +} + + +// check whether to filter out a duplicate packet ----------------------------- +// +int NET_Stream::FilterPacketDuplicate( int messageid ) +{ + // init message id for last packet with sane value + // if this is the first packet from this player + if ( I_ACK_MessageId == 0 ) { + //FIXME: cbx - 2002/02/28 - we must init message_id_history to 0 if + // this is the FIRST packet not the SECOND. This caused a very + // subtle bug, preventing recorded demos from playing a second time + // in one session, mainly because PKTP_CONNECT packets are droppped + // as they have a SendPlayerId of 0, which did not have a + // cleared message_id_history at the first packet ! + if ( messageid >= 1 ) { + int previd = messageid - 1; + I_ACK_MessageId = previd; + for ( int hid = 0; hid < MSGID_HISTORY_SIZE; hid++ ) { + message_id_history[ hid ] = previd; + } + } + } + + // discard duplicate packets remembered in history buffer + int hid =0; + for ( hid = MSGID_HISTORY_SIZE - 1; hid >= 0; hid-- ) { + if ( message_id_history[ hid ] == messageid ) { + // filter out packet + return TRUE; + } + } + + // update history buffer + for ( hid = 1; hid < MSGID_HISTORY_SIZE; hid++ ) { + message_id_history[ hid - 1 ] = message_id_history[ hid ]; + } + message_id_history[ MSGID_HISTORY_SIZE - 1 ] = messageid; + + // calculate packet loss using message id comparisons + int previd = I_ACK_MessageId; + int numlost = messageid - ( previd + 1 ); + + // log missing packets + LogPacketLossStats( numlost, FALSE, TRUE ); + + // got this packet + LogPacketLossStats( 1, TRUE, TRUE ); + + // take this packet + return FALSE; +} + + +// log packet loss statistics ------------------------------------------------- +// +void NET_Stream::LogPacketLossStats( int numpackets, int packetok, int incoming ) +{ + //FIXME: STATS() + + // negative values might happen if we used + // mismatched packet ids to calc numpackets + if ( numpackets < 1 ) { + return; + } + + // guard against more lost packets than we can display + if ( numpackets > PACKET_LOSS_METER_LENGTH ) { + numpackets = PACKET_LOSS_METER_LENGTH; + } + + // select receive/transmit graph + char *graph = incoming ? packet_graph_recv : packet_graph_send; + + // scroll packet graph leftward + int pos = 0; + for ( pos = 0; pos < PACKET_LOSS_METER_LENGTH - numpackets; pos++ ) { + graph[ pos ] = graph[ pos + numpackets ]; + } + + // insert new values at the right + for ( ; pos < PACKET_LOSS_METER_LENGTH; pos++ ) { + graph[ pos ] = ( packetok ? 0 : 1 ); + } +} + diff --git a/src/libparsec/net_swap.cpp b/src/libparsec/net_swap.cpp new file mode 100644 index 0000000..f44f054 --- /dev/null +++ b/src/libparsec/net_swap.cpp @@ -0,0 +1,546 @@ +/* + * PARSEC - Packet Byte-Order Swapping + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001-2002 + * Copyright (c) Andreas Varga <sid@parsec.org> 1998-2000 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_swap.h" + +#ifdef PARSEC_CLIENT + #include "net_rmev.h" +#endif // PARSEC_CLIENT + + + +// converts a network geomv_t (little-endian float) into native geomv_t ------- +// +void Geomv_in( geomv_t *value ) +{ + //NOTE: + // geomv_t vars are sent over the net as floats. + // thus, incoming floats have to be converted to geomv_t's. + + dword tmp = NET_SWAP_32( DW32( *value ) ); + geomv_t tmp2 = FLOAT_TO_GEOMV( *(float *)&tmp ); + *(dword *)value = DW32( tmp2 ); +} + + +// converts a native geomv_t into network geomv_t (little-endian float) ------- +// +void Geomv_out( geomv_t *value ) +{ + //NOTE: + // geomv_t vars are sent over the net as floats. + // thus, outgoing geomv_t's have to be converted to floats. + + float tmp = GEOMV_TO_FLOAT( *value ); + dword tmp2 = NET_SWAP_32( DW32( tmp ) ); + *(dword *)value = tmp2; +} + + +// swap endianness of incoming vector ----------------------------------------- +// +void Vertex3_in( Vertex3 *vec ) +{ + Geomv_in( &vec->X ); + Geomv_in( &vec->Y ); + Geomv_in( &vec->Z ); + vec->VisibleFrame = 0; +} + + +// swap endianness of outgoing vector ----------------------------------------- +// +void Vertex3_out( Vertex3 *vec ) +{ + Geomv_out( &vec->X ); + Geomv_out( &vec->Y ); + Geomv_out( &vec->Z ); + vec->VisibleFrame = 0; +} + + +// swap endianness of incoming matrix ----------------------------------------- +// +void Xmatrx_in( Xmatrx matrix ) +{ + Geomv_in( &matrix[ 0 ][ 0 ] ); + Geomv_in( &matrix[ 0 ][ 1 ] ); + Geomv_in( &matrix[ 0 ][ 2 ] ); + Geomv_in( &matrix[ 0 ][ 3 ] ); + Geomv_in( &matrix[ 1 ][ 0 ] ); + Geomv_in( &matrix[ 1 ][ 1 ] ); + Geomv_in( &matrix[ 1 ][ 2 ] ); + Geomv_in( &matrix[ 1 ][ 3 ] ); + Geomv_in( &matrix[ 2 ][ 0 ] ); + Geomv_in( &matrix[ 2 ][ 1 ] ); + Geomv_in( &matrix[ 2 ][ 2 ] ); + Geomv_in( &matrix[ 2 ][ 3 ] ); +} + + +// swap endianness of outgoing matrix ----------------------------------------- +// +void Xmatrx_out( Xmatrx matrix ) +{ + Geomv_out( &matrix[ 0 ][ 0 ] ); + Geomv_out( &matrix[ 0 ][ 1 ] ); + Geomv_out( &matrix[ 0 ][ 2 ] ); + Geomv_out( &matrix[ 0 ][ 3 ] ); + Geomv_out( &matrix[ 1 ][ 0 ] ); + Geomv_out( &matrix[ 1 ][ 1 ] ); + Geomv_out( &matrix[ 1 ][ 2 ] ); + Geomv_out( &matrix[ 1 ][ 3 ] ); + Geomv_out( &matrix[ 2 ][ 0 ] ); + Geomv_out( &matrix[ 2 ][ 1 ] ); + Geomv_out( &matrix[ 2 ][ 2 ] ); + Geomv_out( &matrix[ 2 ][ 3 ] ); +} + + +// swap endianness of incoming ShipCreateInfo structure ----------------------- +// +void ShipCreateInfo_in( ShipCreateInfo *createinfo ) +{ + createinfo->ShipIndex = NET_SWAP_32( createinfo->ShipIndex ); + Xmatrx_in( createinfo->ObjPosition ); +} + + +// swap endianness of outgoing ShipCreateInfo structure ----------------------- +// +void ShipCreateInfo_out( ShipCreateInfo *createinfo ) +{ + createinfo->ShipIndex = NET_SWAP_32( createinfo->ShipIndex ); + Xmatrx_out( createinfo->ObjPosition ); +} + + +// swap endianness of incoming ShipRemInfo structure -------------------------- +// +void SWAP_ShipRemInfo_in( ShipRemInfo *reminfo ) +{ + ASSERT( reminfo != NULL ); + + Xmatrx_in( reminfo->ObjPosition ); + + reminfo->CurDamage = NET_SWAP_16( reminfo->CurDamage ); + reminfo->CurShield = NET_SWAP_16( reminfo->CurShield ); + reminfo->CurSpeed = NET_SWAP_32( reminfo->CurSpeed ); + reminfo->CurYaw = NET_SWAP_32( reminfo->CurYaw ); + reminfo->CurPitch = NET_SWAP_32( reminfo->CurPitch ); + reminfo->CurRoll = NET_SWAP_32( reminfo->CurRoll ); + + Geomv_in( &reminfo->CurSlideHorz ); + Geomv_in( &reminfo->CurSlideVert ); +} + + +// swap endianness of outgoing ShipRemInfo structure -------------------------- +// +void SWAP_ShipRemInfo_out( ShipRemInfo *reminfo ) +{ + ASSERT( reminfo != NULL ); + + Xmatrx_out( reminfo->ObjPosition ); + + reminfo->CurDamage = NET_SWAP_16( reminfo->CurDamage ); + reminfo->CurShield = NET_SWAP_16( reminfo->CurShield ); + reminfo->CurSpeed = NET_SWAP_32( reminfo->CurSpeed ); + reminfo->CurYaw = NET_SWAP_32( reminfo->CurYaw ); + reminfo->CurPitch = NET_SWAP_32( reminfo->CurPitch ); + reminfo->CurRoll = NET_SWAP_32( reminfo->CurRoll ); + + Geomv_out( &reminfo->CurSlideHorz ); + Geomv_out( &reminfo->CurSlideVert ); +} + + +// swap endianness of incoming ServerInfo structure --------------------------- +// +void ServerInfo_in( ServerInfo *svinfo ) +{ + ASSERT( svinfo != NULL ); +} + + +// swap endianness of outgoing ServerInfo structure --------------------------- +// +void ServerInfo_out( ServerInfo *svinfo ) +{ + ASSERT( svinfo != NULL ); +} + +// swap endianness of all REs in RE list -------------------------------------- +// +void NET_RmEvList_Swap( RE_Header* relist, int incoming ) +{ + ASSERT( relist != NULL ); + + // change byte order of remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + switch ( relist->RE_Type ) { + + case RE_DELETED: + // ignore + break; + + case RE_CREATEOBJECT: + { + RE_CreateObject *re_co = (RE_CreateObject *) relist; + re_co->ObjectClass = NET_SWAP_16( re_co->ObjectClass ); + re_co->HostObjId = NET_SWAP_32( re_co->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_co->ObjPosition ); + } else { + Xmatrx_out( re_co->ObjPosition ); + } + re_co->Flags = NET_SWAP_32( re_co->Flags ); + } + break; + + case RE_CREATELASER: + { + RE_CreateLaser *re_cl = (RE_CreateLaser *) relist; + re_cl->ObjectClass = NET_SWAP_16( re_cl->ObjectClass ); + re_cl->HostObjId = NET_SWAP_32( re_cl->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_cl->ObjPosition ); + Vertex3_in( &re_cl->DirectionVec ); + } else { + Xmatrx_out( re_cl->ObjPosition ); + Vertex3_out( &re_cl->DirectionVec ); + } + } + break; + + case RE_CREATEMISSILE: + { + RE_CreateMissile *re_cm = (RE_CreateMissile *) relist; + re_cm->ObjectClass = NET_SWAP_16( re_cm->ObjectClass ); + re_cm->HostObjId = NET_SWAP_32( re_cm->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_cm->ObjPosition ); + Vertex3_in( &re_cm->DirectionVec ); + } else { + Xmatrx_out( re_cm->ObjPosition ); + Vertex3_out( &re_cm->DirectionVec ); + } + re_cm->TargetHostObjId = NET_SWAP_32( re_cm->TargetHostObjId ); + } + break; + + case RE_PARTICLEOBJECT: + { + RE_ParticleObject *re_po = (RE_ParticleObject *) relist; + re_po->ObjectType = NET_SWAP_16( re_po->ObjectType ); + if ( incoming ) { + Vertex3_in( &re_po->Origin ); + } else { + Vertex3_out( &re_po->Origin ); + } + } + break; + case RE_CREATEMINE: + { + RE_CreateMine *re_ce = (RE_CreateMine *) relist; + re_ce->ExtraIndex = NET_SWAP_16( re_ce->ExtraIndex ); + re_ce->HostObjId = NET_SWAP_32( re_ce->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_ce->ObjPosition ); + } else { + Xmatrx_out( re_ce->ObjPosition ); + } + + } + case RE_CREATEEXTRA: + { + RE_CreateExtra *re_ce = (RE_CreateExtra *) relist; + re_ce->ExtraIndex = NET_SWAP_16( re_ce->ExtraIndex ); + re_ce->HostObjId = NET_SWAP_32( re_ce->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_ce->ObjPosition ); + } else { + Xmatrx_out( re_ce->ObjPosition ); + } + } + break; + + case RE_KILLOBJECT: + { + RE_KillObject *re_ko = (RE_KillObject *) relist; + re_ko->HostObjId = NET_SWAP_32( re_ko->HostObjId ); + } + break; + + case RE_SENDTEXT: + // nothing to swap + break; + + case RE_PLAYERNAME: + // nothing to swap + break; + + case RE_PLAYERLIST: + { + RE_PlayerList *re_pl = (RE_PlayerList *) relist; + + for ( int pid = 0; pid < MAX_NET_UDP_PEER_PLAYERS; pid++ ) + if ( incoming ) + ShipCreateInfo_in( &re_pl->ShipInfoTable[ pid ] ); + else + ShipCreateInfo_out( &re_pl->ShipInfoTable[ pid ] ); + } + break; + + case RE_CONNECTQUEUE: + { + RE_ConnectQueue *re_cq = (RE_ConnectQueue *) relist; + re_cq->NumRequests = NET_SWAP_16( re_cq->NumRequests ); + } + break; + + case RE_WEAPONSTATE: + { + RE_WeaponState *re_ws = (RE_WeaponState *) relist; + re_ws->WeaponMask = NET_SWAP_32( re_ws->WeaponMask ); + // re_ws->Specials = NET_SWAP_32( re_ws->Specials ); + re_ws->CurEnergy = NET_SWAP_32( re_ws->CurEnergy ); + } + break; + + case RE_STATESYNC: + { + RE_StateSync *re_ss = (RE_StateSync *) relist; + re_ss->StateKey = NET_SWAP_16( re_ss->StateKey ); + re_ss->StateValue = NET_SWAP_32( re_ss->StateValue ); + } + break; + + case RE_CREATESWARM: + { + RE_CreateSwarm *re_cs = (RE_CreateSwarm *) relist; + if ( incoming ) + Vertex3_in( &re_cs->Origin ); + else + Vertex3_out( &re_cs->Origin ); + re_cs->TargetHostObjId = NET_SWAP_32( re_cs->TargetHostObjId ); + re_cs->RandSeed = NET_SWAP_32( re_cs->RandSeed ); + } + break; + + case RE_CREATEEMP: + { + RE_CreateEmp *re_ce = (RE_CreateEmp *) relist; + re_ce->Upgradelevel = NET_SWAP_32( re_ce->Upgradelevel ); + re_ce->SenderId = NET_SWAP_32( re_ce->SenderId); + } + break; + case RE_OWNERSECTION: + { + RE_OwnerSection* re_os = (RE_OwnerSection*) relist; + re_os->owner = NET_SWAP_32( re_os->owner ); + } + break; + + case RE_PLAYERSTATUS: + { + RE_PlayerStatus* playerstatus = (RE_PlayerStatus*) relist; + + playerstatus->player_status = NET_SWAP_16( playerstatus->player_status ); + playerstatus->senderid = NET_SWAP_32( playerstatus->senderid ); + playerstatus->objectindex = NET_SWAP_32( playerstatus->objectindex ); + playerstatus->RefFrame = NET_SWAP_32( playerstatus->RefFrame ); + } + break; + + case RE_PLAYERANDSHIPSTATUS: + { + RE_PlayerAndShipStatus* pas_status = (RE_PlayerAndShipStatus*) relist; + + pas_status->player_status = NET_SWAP_16( pas_status->player_status ); + pas_status->senderid = NET_SWAP_32( pas_status->senderid ); + pas_status->objectindex = NET_SWAP_32( pas_status->objectindex ); + pas_status->RefFrame = NET_SWAP_32( pas_status->RefFrame ); + + pas_status->CurDamage = NET_SWAP_16( pas_status->CurDamage ); + pas_status->CurShield = NET_SWAP_16( pas_status->CurShield ); + pas_status->CurSpeed = NET_SWAP_32( pas_status->CurSpeed ); + pas_status->CurYaw = NET_SWAP_32( pas_status->CurYaw ); + pas_status->CurPitch = NET_SWAP_32( pas_status->CurPitch ); + pas_status->CurRoll = NET_SWAP_32( pas_status->CurRoll ); + + // swap endianness of ShipRemInfo + if ( incoming ) { + Xmatrx_in( pas_status->ObjPosition ); + Geomv_in ( &pas_status->CurSlideHorz ); + Geomv_in ( &pas_status->CurSlideVert ); + } else { + Xmatrx_out( pas_status->ObjPosition ); + Geomv_out ( &pas_status->CurSlideHorz ); + Geomv_out ( &pas_status->CurSlideVert ); + } + + pas_status->CurEnergy = NET_SWAP_32( pas_status->CurEnergy ); + } + break; + case RE_KILLSTATS: + // nothing to swap + break; + case RE_GAMESTATE: + { + RE_GameState* gamestate = (RE_GameState*) relist; + gamestate->GameTime = NET_SWAP_32( gamestate->GameTime ); + } + break; + + case RE_COMMANDINFO: + // nothing to swap + break; + + case RE_CLIENTINFO: + // nothing to swap + break; + + case RE_CREATEEXTRA2: + { + RE_CreateExtra2* re_ce2 = (RE_CreateExtra2 *) relist; + re_ce2->ExtraIndex = NET_SWAP_16( re_ce2->ExtraIndex ); + re_ce2->HostObjId = NET_SWAP_32( re_ce2->HostObjId ); + if ( incoming ) { + Xmatrx_in( re_ce2->ObjPosition ); + Vertex3_in( (Vertex3*)&re_ce2->DriftVec ); + } else { + Xmatrx_out( re_ce2->ObjPosition ); + Vertex3_out( (Vertex3*)&re_ce2->DriftVec ); + } + re_ce2->DriftTimeout = NET_SWAP_32( re_ce2->DriftTimeout ); + } + break; + + case RE_IPV4SERVERINFO: + { + RE_IPv4ServerInfo* re_si = (RE_IPv4ServerInfo*) relist; + // for re_si->node NO SWAPPING is needed + re_si->serverid = NET_SWAP_32( re_si->serverid ); + re_si->xpos = NET_SWAP_32( re_si->xpos ); + re_si->ypos = NET_SWAP_32( re_si->ypos ); + } + break; + + case RE_SERVERLINKINFO: + { + RE_ServerLinkInfo* re_sli = (RE_ServerLinkInfo*) relist; + re_sli->flags = NET_SWAP_16( re_sli->flags ); + re_sli->serverid1 = NET_SWAP_16( re_sli->serverid1 ); + re_sli->serverid2 = NET_SWAP_16( re_sli->serverid2 ); + } + break; + + case RE_MAPOBJECT: + { + RE_MapObject* re_mo = (RE_MapObject*) relist; + re_mo->map_objectid = NET_SWAP_16( re_mo->map_objectid ); + re_mo->xpos = NET_SWAP_32( re_mo->xpos ); + re_mo->ypos = NET_SWAP_32( re_mo->ypos ); + re_mo->w = NET_SWAP_32( re_mo->w ); + re_mo->h = NET_SWAP_32( re_mo->h ); + } + break; + case RE_STARGATE: + { + RE_Stargate* re_stg = (RE_Stargate*) relist; + + // for re_stg->destination_node NO SWAPPING is needed + re_stg->serverid = NET_SWAP_16( re_stg->serverid ); + re_stg->rotspeed = NET_SWAP_32( re_stg->rotspeed ); + re_stg->radius = NET_SWAP_32( re_stg->radius ); + re_stg->actdistance = NET_SWAP_32( re_stg->actdistance ); + re_stg->partvel = NET_SWAP_32( re_stg->partvel ); + re_stg->modulrad1 = NET_SWAP_32( re_stg->modulrad1 ); + re_stg->modulrad2 = NET_SWAP_32( re_stg->modulrad2 ); + re_stg->numpartactive = NET_SWAP_16( re_stg->numpartactive ); + re_stg->actcyllen = NET_SWAP_16( re_stg->actcyllen ); + re_stg->modulspeed = NET_SWAP_16( re_stg->modulspeed ); + + if ( incoming ) { + Geomv_in( &re_stg->pos[ 0 ] ); + Geomv_in( &re_stg->pos[ 1 ] ); + Geomv_in( &re_stg->pos[ 2 ] ); + + Geomv_in( &re_stg->dir[ 0 ] ); + Geomv_in( &re_stg->dir[ 1 ] ); + Geomv_in( &re_stg->dir[ 2 ] ); + } else { + Geomv_out( &re_stg->pos[ 0 ] ); + Geomv_out( &re_stg->pos[ 1 ] ); + Geomv_out( &re_stg->pos[ 2 ] ); + + Geomv_out( &re_stg->dir[ 0 ] ); + Geomv_out( &re_stg->dir[ 1 ] ); + Geomv_out( &re_stg->dir[ 2 ] ); + } + } + break; + //break; + //break; + //break; + //break; + default: + MSGOUT( "NET_RmEvList_Swap(): unknown remote event (%d).", relist->RE_Type ); + } + + // advance to next event in list + //MSGOUT("%d, %d ", NET_RmEvGetSize( relist ), relist->RE_BlockSize); + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || + ( relist->RE_BlockSize == NET_RmEvGetSize( relist ) ) ); + relist = (RE_Header *) ( (char *) relist + NET_RmEvGetSize( relist ) ); + } +} + diff --git a/src/libparsec/net_util.cpp b/src/libparsec/net_util.cpp new file mode 100644 index 0000000..7d2db88 --- /dev/null +++ b/src/libparsec/net_util.cpp @@ -0,0 +1,573 @@ +/* + * PARSEC - Utility Functions - shared + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" +//#include "vid_defs.h" + +// drawing subsystem +//#include "d_bmap.h" +//#include "d_font.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_util.h" + +// proprietary module headers +//#include "e_color.h" +//#include "net_swap.h" +//#include "sys_bind.h" + + +// lookup table for fast CRC32 calculation ------------------------------------ +// +static const dword crc32lookup[ 256 ] = +{ + 0x00000000ul, 0x77073096ul, 0xEE0E612Cul, 0x990951BAul, + 0x076DC419ul, 0x706AF48Ful, 0xE963A535ul, 0x9E6495A3ul, + 0x0EDB8832ul, 0x79DCB8A4ul, 0xE0D5E91Eul, 0x97D2D988ul, + 0x09B64C2Bul, 0x7EB17CBDul, 0xE7B82D07ul, 0x90BF1D91ul, + 0x1DB71064ul, 0x6AB020F2ul, 0xF3B97148ul, 0x84BE41DEul, + 0x1ADAD47Dul, 0x6DDDE4EBul, 0xF4D4B551ul, 0x83D385C7ul, + 0x136C9856ul, 0x646BA8C0ul, 0xFD62F97Aul, 0x8A65C9ECul, + 0x14015C4Ful, 0x63066CD9ul, 0xFA0F3D63ul, 0x8D080DF5ul, + 0x3B6E20C8ul, 0x4C69105Eul, 0xD56041E4ul, 0xA2677172ul, + 0x3C03E4D1ul, 0x4B04D447ul, 0xD20D85FDul, 0xA50AB56Bul, + 0x35B5A8FAul, 0x42B2986Cul, 0xDBBBC9D6ul, 0xACBCF940ul, + 0x32D86CE3ul, 0x45DF5C75ul, 0xDCD60DCFul, 0xABD13D59ul, + 0x26D930ACul, 0x51DE003Aul, 0xC8D75180ul, 0xBFD06116ul, + 0x21B4F4B5ul, 0x56B3C423ul, 0xCFBA9599ul, 0xB8BDA50Ful, + 0x2802B89Eul, 0x5F058808ul, 0xC60CD9B2ul, 0xB10BE924ul, + 0x2F6F7C87ul, 0x58684C11ul, 0xC1611DABul, 0xB6662D3Dul, + 0x76DC4190ul, 0x01DB7106ul, 0x98D220BCul, 0xEFD5102Aul, + 0x71B18589ul, 0x06B6B51Ful, 0x9FBFE4A5ul, 0xE8B8D433ul, + 0x7807C9A2ul, 0x0F00F934ul, 0x9609A88Eul, 0xE10E9818ul, + 0x7F6A0DBBul, 0x086D3D2Dul, 0x91646C97ul, 0xE6635C01ul, + 0x6B6B51F4ul, 0x1C6C6162ul, 0x856530D8ul, 0xF262004Eul, + 0x6C0695EDul, 0x1B01A57Bul, 0x8208F4C1ul, 0xF50FC457ul, + 0x65B0D9C6ul, 0x12B7E950ul, 0x8BBEB8EAul, 0xFCB9887Cul, + 0x62DD1DDFul, 0x15DA2D49ul, 0x8CD37CF3ul, 0xFBD44C65ul, + 0x4DB26158ul, 0x3AB551CEul, 0xA3BC0074ul, 0xD4BB30E2ul, + 0x4ADFA541ul, 0x3DD895D7ul, 0xA4D1C46Dul, 0xD3D6F4FBul, + 0x4369E96Aul, 0x346ED9FCul, 0xAD678846ul, 0xDA60B8D0ul, + 0x44042D73ul, 0x33031DE5ul, 0xAA0A4C5Ful, 0xDD0D7CC9ul, + 0x5005713Cul, 0x270241AAul, 0xBE0B1010ul, 0xC90C2086ul, + 0x5768B525ul, 0x206F85B3ul, 0xB966D409ul, 0xCE61E49Ful, + 0x5EDEF90Eul, 0x29D9C998ul, 0xB0D09822ul, 0xC7D7A8B4ul, + 0x59B33D17ul, 0x2EB40D81ul, 0xB7BD5C3Bul, 0xC0BA6CADul, + 0xEDB88320ul, 0x9ABFB3B6ul, 0x03B6E20Cul, 0x74B1D29Aul, + 0xEAD54739ul, 0x9DD277AFul, 0x04DB2615ul, 0x73DC1683ul, + 0xE3630B12ul, 0x94643B84ul, 0x0D6D6A3Eul, 0x7A6A5AA8ul, + 0xE40ECF0Bul, 0x9309FF9Dul, 0x0A00AE27ul, 0x7D079EB1ul, + 0xF00F9344ul, 0x8708A3D2ul, 0x1E01F268ul, 0x6906C2FEul, + 0xF762575Dul, 0x806567CBul, 0x196C3671ul, 0x6E6B06E7ul, + 0xFED41B76ul, 0x89D32BE0ul, 0x10DA7A5Aul, 0x67DD4ACCul, + 0xF9B9DF6Ful, 0x8EBEEFF9ul, 0x17B7BE43ul, 0x60B08ED5ul, + 0xD6D6A3E8ul, 0xA1D1937Eul, 0x38D8C2C4ul, 0x4FDFF252ul, + 0xD1BB67F1ul, 0xA6BC5767ul, 0x3FB506DDul, 0x48B2364Bul, + 0xD80D2BDAul, 0xAF0A1B4Cul, 0x36034AF6ul, 0x41047A60ul, + 0xDF60EFC3ul, 0xA867DF55ul, 0x316E8EEFul, 0x4669BE79ul, + 0xCB61B38Cul, 0xBC66831Aul, 0x256FD2A0ul, 0x5268E236ul, + 0xCC0C7795ul, 0xBB0B4703ul, 0x220216B9ul, 0x5505262Ful, + 0xC5BA3BBEul, 0xB2BD0B28ul, 0x2BB45A92ul, 0x5CB36A04ul, + 0xC2D7FFA7ul, 0xB5D0CF31ul, 0x2CD99E8Bul, 0x5BDEAE1Dul, + 0x9B64C2B0ul, 0xEC63F226ul, 0x756AA39Cul, 0x026D930Aul, + 0x9C0906A9ul, 0xEB0E363Ful, 0x72076785ul, 0x05005713ul, + 0x95BF4A82ul, 0xE2B87A14ul, 0x7BB12BAEul, 0x0CB61B38ul, + 0x92D28E9Bul, 0xE5D5BE0Dul, 0x7CDCEFB7ul, 0x0BDBDF21ul, + 0x86D3D2D4ul, 0xF1D4E242ul, 0x68DDB3F8ul, 0x1FDA836Eul, + 0x81BE16CDul, 0xF6B9265Bul, 0x6FB077E1ul, 0x18B74777ul, + 0x88085AE6ul, 0xFF0F6A70ul, 0x66063BCAul, 0x11010B5Cul, + 0x8F659EFFul, 0xF862AE69ul, 0x616BFFD3ul, 0x166CCF45ul, + 0xA00AE278ul, 0xD70DD2EEul, 0x4E048354ul, 0x3903B3C2ul, + 0xA7672661ul, 0xD06016F7ul, 0x4969474Dul, 0x3E6E77DBul, + 0xAED16A4Aul, 0xD9D65ADCul, 0x40DF0B66ul, 0x37D83BF0ul, + 0xA9BCAE53ul, 0xDEBB9EC5ul, 0x47B2CF7Ful, 0x30B5FFE9ul, + 0xBDBDF21Cul, 0xCABAC28Aul, 0x53B39330ul, 0x24B4A3A6ul, + 0xBAD03605ul, 0xCDD70693ul, 0x54DE5729ul, 0x23D967BFul, + 0xB3667A2Eul, 0xC4614AB8ul, 0x5D681B02ul, 0x2A6F2B94ul, + 0xB40BBE37ul, 0xC30C8EA1ul, 0x5A05DF1Bul, 0x2D02EF8Dul, +}; + + +// fast CRC calculation ------------------------------------------------------- +// +dword NET_CalcCRC( void* buf, size_t len ) +{ + dword crc32 = ~0; + + for( size_t i = 0; i < len; i++ ) { + + byte lookup = (byte)( (crc32 ^ (((byte *)buf)[ i ])) & 0xff ); + + crc32 = ( (crc32 >> 8) & 0x00fffffful ) ^ crc32lookup[ lookup ]; + } + crc32 = ~crc32; + + return crc32; +} + + +// encrypt payload section of packet ------------------------------------------ +// +void NET_EncryptData( void* packet, size_t psize ) +{ + //NOTE: + // this function is used by NETs_HandleOutPacket{_DEMO} after packing, + // swapping and CRC calculation + + //FIXME: evt. we change the Protocol field, to indicate, that we have an + // encrypted packet + //strcpy( packet->Signature, net_cryp_signature ); + + extern float fsin_tab[]; + + // leave signature unencoded + byte *block = (byte *) packet; + + //FIXME: exclude MessageId from encryption and use it as a basepointer + // into the fsin_tab + + for ( size_t epos = 0; epos < psize; epos++ ) { + + // lsbs of mantissa have highest frequency + byte xorkey = (byte)DW32( fsin_tab[ epos ] ) & 0xff; + block[ epos ] ^= xorkey; + } +} + + +// decrypt payload section of packet ------------------------------------------ +// +void NET_DecryptData( void* packet, size_t psize ) +{ + //NOTE: + // this function is used by NETs_HandleInPacket{_DEMO} before CRC is checked + // and packet is swapped and unpacked + + //FIXME: evt. we must check, whether this is an encrypted packet at all + //if ( strcmp( packet->Signature, net_cryp_signature ) != 0 ) { + // return; + //} + + // reset signature + //strcpy( packet->Signature, net_game_signature ); + + extern float fsin_tab[]; + + // skip signature + byte *block = (byte *) packet; + + for ( size_t epos = 0; epos < psize; epos++ ) { + + // lsbs of mantissa have highest frequency + byte xorkey = (byte)DW32( fsin_tab[ epos ] ) & 0xff; + block[ epos ] ^= xorkey; + } +} + +#ifdef PACKETINFO_WRITING_AVAILABLE + + +// fp to which PrInf_ functions write ----------------------------------------- +// +FILE *dest_fp_PacketInfo; + + +// output wrapper function ---------------------------------------------------- +// +int NET_PacketInfo( const char *bstr, ... ) +{ + va_list ap; + va_start( ap, bstr ); + + // simply write to text-file + int rc = vfprintf( dest_fp_PacketInfo, bstr, ap ); + + va_end( ap ); + return rc; +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATEOBJECT( RE_Header *relist ) +{ + RE_CreateObject *re_co = (RE_CreateObject *) relist; + + NET_PacketInfo( ";-- objclass=%d, hostobjid=%d, flags=%0x\n", re_co->ObjectClass, re_co->HostObjId, re_co->Flags ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATELASER( RE_Header *relist ) +{ + RE_CreateLaser *re_cl = (RE_CreateLaser *) relist; + + NET_PacketInfo( ";-- objclass=%d, hostobjid=%d\n", re_cl->ObjectClass, re_cl->HostObjId ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATEMISSILE( RE_Header *relist ) +{ + RE_CreateMissile *re_cm = (RE_CreateMissile *) relist; + + NET_PacketInfo( ";-- objclass=%d, hostobjid=%d, target=%d\n", re_cm->ObjectClass, re_cm->HostObjId, re_cm->TargetHostObjId ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATEEXTRA( RE_Header *relist ) +{ + RE_CreateExtra *re_ce = (RE_CreateExtra *) relist; + + NET_PacketInfo( ";-- extraindex=%d, hostobjid=%d\n", re_ce->ExtraIndex, re_ce->HostObjId ); +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATEEXTRA2( RE_Header *relist ) +{ + RE_CreateExtra2 *re_ce = (RE_CreateExtra2 *) relist; + + NET_PacketInfo( ";-- extraindex=%d, hostobjid=%d\n", re_ce->ExtraIndex, re_ce->HostObjId ); +} + +void PrInf_CREATEMINE( RE_Header *relist ) +{ + RE_CreateMine *re_ce = (RE_CreateMine *) relist; + + NET_PacketInfo( ";-- extraindex=%d, hostobjid=%d\n", re_ce->ExtraIndex, re_ce->HostObjId ); +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_IPV4SERVERINFO( RE_Header *relist ) +{ + RE_IPv4ServerInfo* re_si = (RE_IPv4ServerInfo *) relist; + + //FIXME: include "net_util_sv.h" + //NET_PacketInfo( ";-- node: %s\n", NODE_Print( (node_t*)re_ipsi->node ) ); +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_SERVERLINKINFO( RE_Header *relist ) +{ + RE_ServerLinkInfo* re_sli = (RE_ServerLinkInfo *) relist; + + NET_PacketInfo( ";-- index1=%d, index2=%d\n", re_sli->serverid1, re_sli->serverid2 ); +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_MAPOBJECT( RE_Header *relist ) +{ + RE_MapObject* re_mo = (RE_MapObject *) relist; + + NET_PacketInfo( ";-- map_objectid=%d, name=%s, xpos=%d, ypos=%d, w=%d, h=%d, texname=%s\n", + re_mo->map_objectid, re_mo->name, + re_mo->xpos, re_mo->ypos, + re_mo->w, re_mo->h, + re_mo->texname ); +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_STARGATE( RE_Header *relist ) +{ + RE_Stargate* re_stg = (RE_Stargate *) relist; + + //FIXME: more information + NET_PacketInfo( ";-- serverid=%d\n", re_stg->serverid ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_KILLOBJECT( RE_Header *relist ) +{ + RE_KillObject *re_ko = (RE_KillObject *) relist; + + NET_PacketInfo( ";-- list=%d, flags=%d, hostobjid=%d\n", re_ko->ListId, re_ko->Flags, re_ko->HostObjId ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_SENDTEXT( RE_Header *relist ) +{ + RE_SendText *re_st = (RE_SendText *) relist; + + NET_PacketInfo( ";-- text=\"%s\"\n", re_st->TextStart ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_PLAYERNAME( RE_Header *relist ) +{ + RE_PlayerName *re_pn = (RE_PlayerName *) relist; + + NET_PacketInfo( ";-- name=\"%s\"\n", re_pn->PlayerName ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_PARTICLEOBJECT( RE_Header *relist ) +{ + RE_ParticleObject *re_po = (RE_ParticleObject *) relist; + + NET_PacketInfo( ";-- pobjtype=%d\n", re_po->ObjectType ); +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_PLAYERLIST( RE_Header *relist ) +{ + //TODO: +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CONNECTQUEUE( RE_Header *relist ) +{ + //TODO: +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_WEAPONSTATE( RE_Header *relist ) +{ + //TODO: +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_STATESYNC( RE_Header *relist ) +{ + //TODO: +} + + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATESWARM( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CREATEEMP( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_OWNERSECTION( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_PLAYERSTATUS( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_PLAYERANDSHIPSTATUS( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_KILLSTATS( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_GAMESTATE( RE_Header *relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_COMMANDINFO( RE_Header* relist ) +{ + //TODO: +} + +// print remote-event info ---------------------------------------------------- +// +void PrInf_CLIENTINFO( RE_Header* relist ) +{ + //TODO: +} + +// list of remote-event names ------------------------------------------------- +// +static const char *re_names[] = { + + "RE_EMPTY", + "RE_DELETED", + + "RE_CREATEOBJECT", + "RE_CREATELASER", + "RE_CREATEMISSILE", + "RE_CREATEEXTRA", + "RE_KILLOBJECT", + "RE_SENDTEXT", + "RE_PLAYERNAME", + "RE_PARTICLEOBJECT", + "RE_PLAYERLIST", + "RE_CONNECTQUEUE", + "RE_WEAPONSTATE", + "RE_STATESYNC", + "RE_CREATESWARM", + "RE_CREATEEMP", + "RE_OWNERSECTION", + "RE_PLAYERSTATUS", + "RE_PLAYERANDSHIPSTATUS", + "RE_KILLSTATS", + "RE_GAMESTATE", + "RE_COMMANDINFO", + "RE_CLIENTINFO", + "RE_CREATEEXTRA2", + "RE_IPV4SERVERINFO", + "RE_SERVERLINKINFO", + "RE_MAPOBJECT", + "RE_STARGATE", + "RE_CREATEMINE", +}; + + +// list of remote-event info printing functions ------------------------------- +// +static void (*re_funcs[])(RE_Header*) = { + + NULL, + NULL, + + PrInf_CREATEOBJECT, + PrInf_CREATELASER, + PrInf_CREATEMISSILE, + PrInf_CREATEEXTRA, + PrInf_KILLOBJECT, + PrInf_SENDTEXT, + PrInf_PLAYERNAME, + PrInf_PARTICLEOBJECT, + PrInf_PLAYERLIST, + PrInf_CONNECTQUEUE, + PrInf_WEAPONSTATE, + PrInf_STATESYNC, + PrInf_CREATESWARM, + PrInf_CREATEEMP, + PrInf_OWNERSECTION, + PrInf_PLAYERSTATUS, + PrInf_PLAYERANDSHIPSTATUS, + PrInf_KILLSTATS, + PrInf_GAMESTATE, + PrInf_COMMANDINFO, + PrInf_CLIENTINFO, + PrInf_CREATEEXTRA2, + PrInf_IPV4SERVERINFO, + PrInf_SERVERLINKINFO, + PrInf_MAPOBJECT, + PrInf_STARGATE, +}; + + +#ifndef PARSEC_MASTER + +// write verbose RE list info as a comment to recording file ------------------ +// +void NET_RmEvList_WriteInfo( FILE* fp, RE_Header* relist ) +{ + ASSERT( fp != NULL ); + ASSERT( relist != NULL ); + + // process remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + if ( relist->RE_Type < RE_NUMEVENTS ) { + + NET_PacketInfo( ";-- rmev=%d (%s)\n", relist->RE_Type, re_names[ relist->RE_Type ] ); + if ( re_funcs[ relist->RE_Type ] != NULL ) + (*re_funcs[ relist->RE_Type ])( relist ); + + } else { + NET_PacketInfo( ";** unknown remote-event: %d\n", relist->RE_Type ); + } + + // advance to next event + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || + ( relist->RE_BlockSize == NET_RmEvGetSize( relist ) ) ); + + relist = (RE_Header *) ( (char *) relist + NET_RmEvGetSize( relist ) ); + } +} + +#endif // !PARSEC_MASTER + +#endif // PACKETINFO_WRITING_AVAILABLE + + + diff --git a/src/libparsec/net_wrap.cpp b/src/libparsec/net_wrap.cpp new file mode 100644 index 0000000..8a11ed5 --- /dev/null +++ b/src/libparsec/net_wrap.cpp @@ -0,0 +1,132 @@ +/* + * PARSEC - libunp Wrapper + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_wrap.h" + +#ifdef SYSTEM_TARGET_WINDOWS + +int inet_aton(const char *cp, struct in_addr *ap) +{ + int dots = 0; + register dword acc = 0, addr = 0; + + do { + register char cc = *cp; + + switch (cc) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + acc = acc * 10 + (cc - '0'); + break; + + case '.': + if (++dots > 3) { + return 0; + } + /* Fall through */ + + case '\0': + if (acc > 255) { + return 0; + } + addr = addr << 8 | acc; + acc = 0; + break; + + default: + return 0; + } + } while (*cp++) ; + + /* Normalize the address */ + if (dots < 3) { + addr <<= 8 * (3 - dots) ; + } + + /* Store it if requested */ + if (ap) { + ap->s_addr = htonl(addr); + } + + return 1; +} + +const char* inet_ntop( int family, const void* addrptr, char* strptr, size_t len) +{ + strncpy( strptr, inet_ntoa( *((in_addr*)addrptr) ) , len - 1 ); + strptr[ len - 1 ] = 0; + return strptr; +} + + +const char* hstrerror(int err) +{ + if (err == 0) + return("no error"); + + if (err == HOST_NOT_FOUND) + return("Unknown host"); + + if (err == TRY_AGAIN) + return("Hostname lookup failure"); + + if (err == NO_RECOVERY) + return("Unknown server error"); + + if (err == NO_DATA) + return("No address associated with name"); + + return("unknown error"); +} + +#endif // SYSTEM_TARGET_WINDOWS + diff --git a/src/libparsec/obj_clas.cpp b/src/libparsec/obj_clas.cpp new file mode 100644 index 0000000..812bf96 --- /dev/null +++ b/src/libparsec/obj_clas.cpp @@ -0,0 +1,290 @@ +/* + * PARSEC - Object Class Management + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" +#include "od_class.h" + +// global externals +#include "globals.h" +#ifdef PARSEC_SERVER + #include "e_world_trans.h" +#endif // PARSEC_SERVER + +// local module header +#include "obj_clas.h" + +// proprietary module headers +#include "obj_cust.h" +#include "obj_type.h" + + +// flags +//#define ALLOW_ONLY_KNOWN_CLASSES + + + +// fetch object class via name ------------------------------------------------ +// +GenObject *OBJ_FetchObjectClass( const char *classname ) +{ + ASSERT( classname != NULL ); + ASSERT( NumObjClasses == NumLoadedObjects ); + + // scan entire table of object classes + int classid = 0; + for ( classid = 0; classid < NumLoadedObjects; classid++ ) + if ( stricmp( ObjectInfo[ classid ].name, classname ) == 0 ) + break; + + if ( classid < NumObjClasses ) { + + ASSERT( ObjClasses[ classid ] != NULL ); + ASSERT( ObjClasses[ classid ]->ObjectClass == (dword)classid ); + return ObjClasses[ classid ]; + + } else { + + return NULL; + } +} + + +// fetch object class id via name --------------------------------------------- +// +dword OBJ_FetchObjectClassId( const char *classname ) +{ + ASSERT( classname != NULL ); + ASSERT( NumObjClasses == NumLoadedObjects ); + + // scan entire table of object classes + for ( int classid = 0; classid < NumLoadedObjects; classid++ ) + if ( stricmp( ObjectInfo[ classid ].name, classname ) == 0 ) + return classid; + + // no object class of this name found + return CLASS_ID_INVALID; +} + + +// fetch object class via name or id if already acquired ---------------------- +// +GenObject *OBJ_ReacquireObjectClass( dword *classid, const char *classname ) +{ + ASSERT( classid != NULL ); + ASSERT( classname != NULL ); + + GenObject *classpo = NULL; + dword tmpclassid = *classid; + + if ( tmpclassid == CLASS_ID_INVALID ) { + tmpclassid = OBJ_FetchObjectClassId( classname ); + } + if ( tmpclassid != CLASS_ID_INVALID ) { + ASSERT( tmpclassid < (dword)NumObjClasses ); + classpo = ObjClasses[ tmpclassid ]; + } + + *classid = tmpclassid; + return classpo; +} + + +// init default values for object class --------------------------------------- +// +PRIVATE +void InitDefaultClassFields( GenObject *classpo, dword classid ) +{ + ASSERT( classpo != NULL ); + ASSERT( classid < MAX_DISTINCT_OBJCLASSES ); + ASSERT( classid <= (dword)NumObjClasses ); + + //NOTE: + // ( classid == NumObjClasses ) is allowed since + // this will occur when a new class is being added. + // (NumObjClasses will only be increased afterwards.) + + switch ( classid ) { + + case SHIP_CLASS_1: + break; + + case SHIP_CLASS_2: + break; + + case SHIP_CLASS_3: + break; + + case LASER0_CLASS_1: + break; + + case LASER0_CLASS_2: + break; + + case LASER1_CLASS_1: + break; + + case LASER2_CLASS_1: + break; + + case DUMB_CLASS_1: + break; + + case GUIDE_CLASS_1: + break; + + case SWARM_CLASS_1: + break; + + case ENERGY_EXTRA_CLASS: + break; + + case DUMB_PACK_CLASS: + break; + + case GUIDE_PACK_CLASS: + break; + + case HELIX_DEVICE_CLASS: + break; + + case LIGHTNING_DEVICE_CLASS: + break; + + case MINE_PACK_CLASS: + break; + + case MINE_CLASS_1: + break; + + case REPAIR_EXTRA_CLASS: + break; + + case AFTERBURNER_DEVICE_CLASS: + break; + + case SWARM_PACK_CLASS: + break; + + case INVISIBILITY_CLASS: + break; + + case INVULNERABILITY_CLASS: + break; + + case PHOTON_DEVICE_CLASS: + break; + + case DECOY_DEVICE_CLASS: + break; + + case LASERUPGRADE1_CLASS: + break; + + case LASERUPGRADE2_CLASS: + break; + +#ifdef ALLOW_ONLY_KNOWN_CLASSES + + default: + PERROR( "unknown object class id: %d.", classid ); +#endif + + } +} + + +// init class member variables to default values ------------------------------ +// +void OBJ_InitClass( dword classid ) +{ + ASSERT( classid < MAX_DISTINCT_OBJCLASSES ); + ASSERT( classid <= (dword)NumObjClasses ); + + GenObject *classpo = ObjClasses[ classid ]; + + //NOTE: + // ( classid == NumObjClasses ) is allowed since + // this will occur when a new class is being added. + // (NumObjClasses will only be increased afterwards.) + + //NOTE: + // distinction between "object classes" and "object types" + // ------------------------------------------------------- + // different _objclasses_ originate in different object data files; + // i.e. the list of objects that should be loaded is parsed and each + // entry is read and inserted into the array containing pointers to + // all _objclasses_. Thus each object loaded gets a sequentially + // (in the order encountered in the control file) assigned number, + // that is, its *objclass_number*. (these numbers are also contained + // in file "od_class.h" in order to be used by the object control + // code. If the order of entries in the control file doesn't + // correspond to this header file then faulty behavior will occur. + // + // different objclass does not necessarily mean that objects *behave* + // differently in the game as it does only mean that geometry and + // shading data are different. therefore another concept manages + // *behavior* of objects: + // + // an _objtype_ describes how an object should be handled by the + // engine and also what data structure is used to manage the object + // in memory. e.g. all objects of the same type are managed by the + // same data structure and handled equally by the engine. + // + // i.e. objectclasses Laser#1..Laser#5 could all be the same type + // of laser (concerning their behavior) but look differently. + // The game *always* instantiates _objectclasses_ (as the look of + // the object has to be determined), their type is determined + // automatically. (as it is contained in the objectclass structure.) + + if ( ( classpo->ObjectType & TYPENUMBERMASK ) < NUM_DISTINCT_OBJTYPES ) { + + // init default values for object *type* + OBJ_InitDefaultTypeFields( classpo ); + + // init default values for object *class* + InitDefaultClassFields( classpo, classid ); + + } else { + + // init type and class fields for custom type + OBJ_InitCustomType( classpo ); + } + + // ensure correct clipping when rendering + // directly from class template + classpo->CullMask = 0x3f; +} + + + diff --git a/src/libparsec/obj_creg.cpp b/src/libparsec/obj_creg.cpp new file mode 100644 index 0000000..62b1266 --- /dev/null +++ b/src/libparsec/obj_creg.cpp @@ -0,0 +1,464 @@ +/* + * PARSEC - Object Class Registration + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" +#include "od_class.h" + +// global externals +#include "globals.h" +#ifdef PARSEC_SERVER + #include "e_world_trans.h" +#endif // PARSEC_SERVER + +// local module header +#include "obj_creg.h" + +// proprietary module headers +#include "con_arg.h" +#ifdef PARSEC_SERVER + #include "con_com_sv.h" + #include "con_main_sv.h" +#else // !PARSEC_SERVER + #include "con_com.h" + #include "con_main.h" + #include "e_supp.h" +#endif // !PARSEC_SERVER +#include "obj_clas.h" + + + +// string constants ----------------------------------------------------------- +// +static char intlist_invalid[] = "intlist invalid."; +static char no_ship_class[] = "object class is no ship."; +static char too_many_ships[] = "no more ships allowed."; +static char no_extra_class[] = "object class is no extra."; +static char too_many_extras[] = "no more extras allowed."; +static char invalid_texture[] = "invalid texture specified."; + + +// class registration entry --------------------------------------------------- +// +struct classregfunc_s { + + classreg_fpt regfunc; + classregfunc_s *next; +}; + +classregfunc_s *classregfunc_list = NULL; + + +// register class-registration callback --------------------------------------- +// +int OBJ_RegisterClassRegistration( classreg_fpt regfunc ) +{ + ASSERT( regfunc != NULL ); + + //NOTE: + // registration callback functions must be idempotent. + // (they may be called multiple times, but semantics + // equivalent to call-once must be guaranteed.) + + classregfunc_s *newregfunc = (classregfunc_s *) ALLOCMEM( sizeof( classregfunc_s ) ); + if ( newregfunc == NULL ) { + ASSERT( 0 ); + return FALSE; + } + + // prepend to list + newregfunc->regfunc = regfunc; + newregfunc->next = classregfunc_list; + classregfunc_list = newregfunc; + + return TRUE; +} + + +// key table for do_creg command ---------------------------------------------- +// +key_value_s do_creg_key_value[] = { + + { "intlist", NULL, KEYVALFLAG_PARENTHESIZE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_DO_CREG_INTLIST +}; + + +// console command for registering all pending classes ("do_creg") ------------ +// +PRIVATE +int Cmd_DO_CREG( char *intliststr ) +{ + //NOTE: + //CONCOM: + // do_creg_command ::= 'do_creg' [<int_list>] + // int_list ::= <int> [<int_list>] + + ASSERT( intliststr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( intliststr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( do_creg_key_value, intliststr ) ) + return TRUE; + + #define MAX_INTLIST_LENGTH 16 + int intlist[ MAX_INTLIST_LENGTH ]; + int numints = 0; + + // try to read optional int list + if ( do_creg_key_value[ KEY_DO_CREG_INTLIST ].value != NULL ) { + numints = ScanKeyValueIntList( &do_creg_key_value[ KEY_DO_CREG_INTLIST ], intlist, 1, MAX_INTLIST_LENGTH ); + if ( numints < 1 ) { + CON_AddLine( intlist_invalid ); + return TRUE; + } + } + + // call all registered functions + for ( classregfunc_s *scan = classregfunc_list; scan; scan = scan->next ) { + ASSERT( scan->regfunc != NULL ); + (*scan->regfunc)( numints, intlist ); + } + + return TRUE; +} + + +// global ship class table ---------------------------------------------------- +// +dword ShipClasses[ MAX_SHIP_CLASSES ] = { + + SHIP_CLASS_1, // shipclassid 00: firebird + SHIP_CLASS_3, // shipclassid 01: bluespire + SHIP_CLASS_2, // shipclassid 02: cormoran +}; + +int NumShipClasses = 3; //CALC_NUM_ARRAY_ENTRIES( ShipClasses ); + + +// reverse lookup ship class table -------------------------------------------- +// +int ObjClassShipIndex[ MAX_DISTINCT_OBJCLASSES ]; + + +// register a new ship class -------------------------------------------------- +// +int OBJ_RegisterShipClass( dword classid ) +{ + ASSERT( classid < (dword)NumObjClasses ); + ASSERT( OBJECT_TYPE_SHIP( ObjClasses[ classid ] ) ); + + if ( NumShipClasses >= MAX_SHIP_CLASSES ) { + return FALSE; + } + + // turn specified class into a ship class + ShipClasses[ NumShipClasses ] = classid; + ObjClassShipIndex[ classid ] = NumShipClasses; + + NumShipClasses++; + + return TRUE; +} + + +// key table for shipclass command -------------------------------------------- +// +key_value_s shipclass_key_value[] = { + + { "class", NULL, KEYVALFLAG_PARENTHESIZE }, + { "id", NULL, KEYVALFLAG_NONE }, + { "texture", NULL, KEYVALFLAG_PARENTHESIZE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_SHIPCLASS_CLASS, + KEY_SHIPCLASS_ID, + KEY_SHIPCLASS_TEXTURE +}; + + +// console command for registering a new ship class ("shipclass") ------------- +// +PRIVATE +int Cmd_SHIPCLASS( char *classstr ) +{ + //NOTE: + //CONCOM: + // shipclass_command ::= 'shipclass' <class_spec> [<monitor_texture_spec>] + // class_spec ::= 'class' <classname> | 'id' <classid> + // monitor_texture_spec ::= 'texture' <texturename> + + ASSERT( classstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( classstr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( shipclass_key_value, classstr ) ) + return TRUE; + + // get object class (either name or id) + dword objclass = ScanKeyValueObjClass( shipclass_key_value, KEY_SHIPCLASS_CLASS, KEY_SHIPCLASS_ID ); + if ( objclass == CLASS_ID_INVALID ) { + return TRUE; + } + + if ( !OBJECT_TYPE_SHIP( ObjClasses[ objclass ] ) ) { + CON_AddLine( no_ship_class ); + return TRUE; + } + + if ( NumShipClasses >= MAX_SHIP_CLASSES ) { + CON_AddLine( too_many_ships ); + return TRUE; + } + + // check if class is already registered + int firstreg = TRUE; + char *classname = shipclass_key_value[ KEY_SHIPCLASS_CLASS ].value; + ASSERT( ( classname == NULL ) || ( stricmp( classname, ObjectInfo[ objclass ].name ) == 0 ) ); + classname = ObjectInfo[ objclass ].name; + + for ( int sid = 0; sid < NumShipClasses; sid++ ) { + if ( strcmp( classname, ObjectInfo[ ShipClasses[ sid ] ].name ) == 0 ) { + firstreg = FALSE; + break; + } + } + + // turn specified class into a ship class + if ( firstreg ) { + ShipClasses[ NumShipClasses ] = objclass; + ObjClassShipIndex[ objclass ] = NumShipClasses; + NumShipClasses++; + } + +#ifdef PARSEC_CLIENT + + // check for shipmonitor texture name and save + // texturemap pointer for use in H_COCKPT.C + char *texturename = shipclass_key_value[ KEY_SHIPCLASS_TEXTURE ].value; + if ( texturename != NULL ) { + TextureMap *texmap = FetchTextureMap( texturename ); + if ( texmap != NULL ) { + extern TextureMap *MonitorTextures[]; + MonitorTextures[ ObjClassShipIndex[ objclass ] ] = texmap; + } else { + CON_AddLine( invalid_texture ); + return TRUE; + } + } + +#endif // PARSEC_CLIENT + + return TRUE; +} + + +// global extra class table --------------------------------------------------- +// +dword ExtraClasses[ MAX_EXTRA_CLASSES ] = { + + ENERGY_EXTRA_CLASS, // extra classindex 00: energy boost + DUMB_PACK_CLASS, // extra classindex 01: missile pack (dumb missiles) + GUIDE_PACK_CLASS, // extra classindex 02: missile pack (guided missiles) + HELIX_DEVICE_CLASS, // extra classindex 03: dazzling laser/helix cannon + LIGHTNING_DEVICE_CLASS, // extra classindex 04: thief laser/lightning device + MINE_PACK_CLASS, // extra classindex 05: mine pack (proximity mines) + REPAIR_EXTRA_CLASS, // extra classindex 06: repair damage + AFTERBURNER_DEVICE_CLASS, // extra classindex 07: afterburner + SWARM_PACK_CLASS, // extra classindex 08: missile pack (swarm missiles) + INVISIBILITY_CLASS, // extra classindex 09: invisibility (not used yet) + PHOTON_DEVICE_CLASS, // extra classindex 10: photon cannon + DECOY_DEVICE_CLASS, // extra classindex 11: decoy device + LASERUPGRADE1_CLASS, // extra classindex 12: laser upgrade 1 + LASERUPGRADE2_CLASS, // extra classindex 13: laser upgrade 2 + INVULNERABILITY_CLASS, // extra classindex 14: invulnerability + MINE_CLASS_1, // extra classindex 15: mine + CLASS_ID_INVALID, // extra classindex 16: emp upgrade 1 + CLASS_ID_INVALID, // extra classindex 17: emp upgrade 2 +}; + +int NumExtraClasses = 16; //CALC_NUM_ARRAY_ENTRIES( ExtraClasses ); + + +// reverse lookup extra class table ------------------------------------------- +// +int ObjClassExtraIndex[ MAX_DISTINCT_OBJCLASSES ]; + + +// register a new extra class ------------------------------------------------- +// +int OBJ_RegisterExtraClass( int index, dword classid ) +{ + ASSERT( classid < (dword)NumObjClasses ); + ASSERT( OBJECT_TYPE_EXTRA( ObjClasses[ classid ] ) ); + + if ( index < NumExtraClasses ) { + + } else { + + if ( NumExtraClasses >= MAX_EXTRA_CLASSES ) { + return FALSE; + } + + // turn specified class into an extra class + ExtraClasses[ NumExtraClasses ] = classid; + ObjClassExtraIndex[ classid ] = NumExtraClasses; + + NumExtraClasses++; + } + + return TRUE; +} + + +// key table for extraclass command ------------------------------------------- +// +key_value_s extraclass_key_value[] = { + + { "class", NULL, KEYVALFLAG_PARENTHESIZE }, + { "id", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_EXTRACLASS_CLASS, + KEY_EXTRACLASS_ID +}; + + +// console command for registering a new extra class ("extraclass") ----------- +// +PRIVATE +int Cmd_EXTRACLASS( char *classstr ) +{ + //NOTE: + //CONCOM: + // extraclass_command ::= 'extraclass' <class_spec> + // class_spec ::= 'class' <classname> | 'id' <classid> + + ASSERT( classstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( classstr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( extraclass_key_value, classstr ) ) + return TRUE; + + // get object class (either name or id) + dword objclass = ScanKeyValueObjClass( extraclass_key_value, KEY_EXTRACLASS_CLASS, KEY_EXTRACLASS_ID ); + if ( objclass == CLASS_ID_INVALID ) { + return TRUE; + } + + if ( !OBJECT_TYPE_EXTRA( ObjClasses[ objclass ] ) ) { + CON_AddLine( no_extra_class ); + return TRUE; + } + + if ( NumExtraClasses >= MAX_EXTRA_CLASSES ) { + CON_AddLine( too_many_extras ); + return TRUE; + } + + // turn specified class into an extra class + OBJ_RegisterExtraClass( NumExtraClasses, objclass ); + + return TRUE; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( OBJ_CREG ) +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "do_creg" command + regcom.command = "do_creg"; + regcom.numparams = 1; + regcom.execute = Cmd_DO_CREG; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // register "shipclass" command + regcom.command = "shipclass"; + regcom.numparams = 1; + regcom.execute = Cmd_SHIPCLASS; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // init reverse lookup of ship classes + unsigned int cid = 0; + for ( cid = 0; cid < MAX_DISTINCT_OBJCLASSES; cid++ ) { + ObjClassShipIndex[ cid ] = SHIPINDEX_NO_SHIP; + for ( int scid = 0; scid < NumShipClasses; scid++ ) { + if ( ShipClasses[ scid ] == cid ) { + ObjClassShipIndex[ cid ] = scid; + break; + } + } + } + + // register "extraclass" command + regcom.command = "extraclass"; + regcom.numparams = 1; + regcom.execute = Cmd_EXTRACLASS; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // init reverse lookup of extra classes + for ( cid = 0; cid < MAX_DISTINCT_OBJCLASSES; cid++ ) { + ObjClassExtraIndex[ cid ] = EXTRAINDEX_NO_EXTRA; + for ( unsigned int ecid = 0; ecid < (dword)NumExtraClasses; ecid++ ) { + if ( ExtraClasses[ ecid ] == cid ) { + ObjClassExtraIndex[ cid ] = ecid; + break; + } + } + } +} + + + diff --git a/src/libparsec/obj_cust.cpp b/src/libparsec/obj_cust.cpp new file mode 100644 index 0000000..fcd997c --- /dev/null +++ b/src/libparsec/obj_cust.cpp @@ -0,0 +1,361 @@ +/* + * PARSEC - Custom Object Types + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" +#ifdef PARSEC_SERVER + #include "e_world_trans.h" +#endif // PARSEC_SERVER + +// local module header +#include "obj_cust.h" + +// proprietary module headers +//#include "obj_ctrl.h" + + + +// string constants ----------------------------------------------------------- +// +static char custom_type_invalid[] = "invalid custom object type."; + + +// custom type table ---------------------------------------------------------- +// +int num_custom_types = 0; +custom_type_info_s custom_type_info[ MAX_NUM_CUSTOM_TYPES ]; + + +// look up custom type via name ----------------------------------------------- +// +dword OBJ_FetchCustomTypeId( const char *name ) +{ + ASSERT( name != NULL ); + + // search for type name in table + for ( int tid = 0; tid < num_custom_types; tid++ ) + if ( strcmp( custom_type_info[ tid ].type_name, name ) == 0 ) + return custom_type_info[ tid ].type_id; + + return TYPE_ID_INVALID; +} + + +// determine type name of custom type ----------------------------------------- +// +const char *OBJ_FetchCustomTypeName( dword objtypeid ) +{ + if ( !TYPEID_TYPE_CUSTOM( objtypeid ) ) + return NULL; + + int tindx = ( objtypeid & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; + + ASSERT( tindx >= 0 ); + ASSERT( tindx < num_custom_types ); + + if ( custom_type_info[ tindx ].type_id != objtypeid ) + return NULL; + + // fetch name from table + return custom_type_info[ tindx ].type_name; +} + + +// get the flags for a custom type -------------------------------------------- +// +int OBJ_GetCustomTypeFlags( dword objtypeid ) +{ + if ( !TYPEID_TYPE_CUSTOM( objtypeid ) ) + return 0; + + int tindx = ( objtypeid & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; + + ASSERT( tindx >= 0 ); + ASSERT( tindx < num_custom_types ); + + if ( custom_type_info[ tindx ].type_id != objtypeid ) + return 0; + + // fetch flags from table + return custom_type_info[ tindx ].type_flags; +} + +// determine instance size of custom type ------------------------------------- +// +size_t OBJ_FetchCustomTypeSize( dword objtypeid ) +{ + ASSERT( TYPEID_TYPE_CUSTOM( objtypeid ) ); + int tindx = ( objtypeid & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; + + ASSERT( tindx >= 0 ); + ASSERT( tindx < num_custom_types ); + ASSERT( custom_type_info[ tindx ].type_id == objtypeid ); + + if ( custom_type_info[ tindx ].type_id != objtypeid ) { + + // point of no return + PANIC( custom_type_invalid ); + } + + // fetch size from table + return custom_type_info[ tindx ].type_size; +} + + +// fetch template (object with default/user-altered values) for custom type --- +// +CustomObject *OBJ_FetchCustomTypeTemplate( dword objtypeid ) +{ + ASSERT( TYPEID_TYPE_CUSTOM( objtypeid ) ); + int tindx = ( objtypeid & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; + + ASSERT( tindx >= 0 ); + ASSERT( tindx < num_custom_types ); + ASSERT( custom_type_info[ tindx ].type_id == objtypeid ); + + if ( custom_type_info[ tindx ].type_id != objtypeid ) + return NULL; + + // fetch template from table + return custom_type_info[ tindx ].type_template; +} + + +// init custom object from supplied custom type template ---------------------- +// +int OBJ_InitFromCustomTypeTemplate( CustomObject *obj, CustomObject *templ ) +{ + ASSERT( obj != NULL ); + + // copy over template if available + if ( templ != NULL ) { + + ASSERT( obj->InstanceSize >= sizeof( CustomObject ) ); + + // base part must be left untouched + size_t userareasize = obj->InstanceSize - sizeof( CustomObject ); + if ( userareasize > 0 ) { + memcpy( (char*)obj + sizeof( CustomObject ), + (char*)templ + sizeof( CustomObject ), + userareasize ); + } + + return TRUE; + } + + // no template, default init should be done + return FALSE; +} + + +// init instance (class) of custom object type -------------------------------- +// +void OBJ_InitCustomType( GenObject *classpo ) +{ + ASSERT( classpo != NULL ); + ASSERT( OBJECT_TYPE_CUSTOM( classpo ) ); + + CustomObject *obj = (CustomObject *) classpo; + + int customid = ( classpo->ObjectType & TYPENUMBERMASK ) - NUM_DISTINCT_OBJTYPES; + if ( ( customid < 0 ) || ( customid >= num_custom_types ) ) { + ASSERT( 0 ); + return; + } + + if ( custom_type_info[ customid ].type_id != classpo->ObjectType ) { + ASSERT( 0 ); + return; + } + + // init fields of struct CustomObject + obj->callback_instant = custom_type_info[ customid ].callback_instant; + obj->callback_destroy = custom_type_info[ customid ].callback_destroy; + obj->callback_animate = custom_type_info[ customid ].callback_animate; + obj->callback_collide = custom_type_info[ customid ].callback_collide; + obj->callback_notify = custom_type_info[ customid ].callback_notify; + obj->callback_persist = custom_type_info[ customid ].callback_persist; + + // invoke class init callback if available + if ( custom_type_info[ customid ].callback_init != NULL ) { + (*custom_type_info[ customid ].callback_init)( obj ); + } +} + + +// register new custom type, assign next available id ------------------------- +// +dword OBJ_RegisterCustomType( custom_type_info_s *info ) +{ + ASSERT( info != NULL ); + + // guard against maximum number of custom types + if ( num_custom_types >= MAX_NUM_CUSTOM_TYPES ) { + ASSERT( 0 ); + info->type_id = TYPE_ID_INVALID; + return TYPE_ID_INVALID; + } + + // guard against maximum number of type ids + if ( num_custom_types + NUM_DISTINCT_OBJTYPES > TYPENUMBERMASK ) { + ASSERT( 0 ); + info->type_id = TYPE_ID_INVALID; + return TYPE_ID_INVALID; + } + + // assign next sequential id + dword tindx = num_custom_types; + info->type_id = ( NUM_DISTINCT_OBJTYPES + tindx ) | CUSTM_LIST_NO | + ( info->type_id & ~( TYPENUMBERMASK | TYPELISTMASK ) ); + + // init table entry + custom_type_info[ tindx ].type_name = info->type_name; + custom_type_info[ tindx ].type_id = info->type_id; + custom_type_info[ tindx ].type_size = info->type_size; + custom_type_info[ tindx ].type_template = info->type_template; + custom_type_info[ tindx ].type_flags = info->type_flags; + custom_type_info[ tindx ].callback_init = info->callback_init; + custom_type_info[ tindx ].callback_instant = info->callback_instant; + custom_type_info[ tindx ].callback_destroy = info->callback_destroy; + custom_type_info[ tindx ].callback_animate = info->callback_animate; + custom_type_info[ tindx ].callback_collide = info->callback_collide; + custom_type_info[ tindx ].callback_notify = info->callback_notify; + custom_type_info[ tindx ].callback_persist = info->callback_persist; + + // one more custom type + num_custom_types++; + + // return id (caller field type_id is now valid) + return info->type_id; +} + + +// register custom object with genobject (insert at head of list) ------------- +// +void OBJ_RegisterNotifyCustomObject( GenObject *genobj, CustomObject *customobj ) +{ + ASSERT( genobj != NULL ); + ASSERT( customobj != NULL ); + + //NOTE: + // if the custom object needs a pointer to the GenObject it has + // been registered with, it must store this pointer in its own + // mem area, i.e., in the struct derived from CustomObject. + + // every custom object can only be part of a single list + ASSERT( customobj->NotifyCustmObjects == NULL ); + + // insert at head of list + customobj->NotifyCustmObjects = genobj->NotifyCustmObjects; + genobj->NotifyCustmObjects = customobj; +} + + +// unregister custom object from genobject (delete from list if contained) ---- +// +int OBJ_UnregisterNotifyCustomObject( GenObject *genobj, CustomObject *customobj ) +{ + ASSERT( genobj != NULL ); + ASSERT( customobj != NULL ); + + // scan list for specified custom object + GenObject *prev = genobj; + CustomObject *scan = genobj->NotifyCustmObjects; + for ( ; scan != NULL; scan = scan->NotifyCustmObjects ) { + + // remove from list when found + if ( scan == customobj ) { + prev->NotifyCustmObjects = scan->NotifyCustmObjects; + scan->NotifyCustmObjects = NULL; + return TRUE; + } + prev = scan; + } + + // custom object was not registered + return FALSE; +} + + +// notify custom objects registered with genobject ---------------------------- +// +void OBJ_NotifyCustomObjectsList( GenObject *genobj, int event ) +{ + ASSERT( genobj != NULL ); + + // if the event is delete, the list must be unlinked + int unlinklist = ( event == CUSTOM_NOTIFY_GENOBJECT_DELETE ); + + // walk list of registered custom objects + GenObject *prev = genobj; + CustomObject *customobj = genobj->NotifyCustmObjects; + for ( ; customobj != NULL; customobj = customobj->NotifyCustmObjects ) { + + // call notify callback if it is valid + if ( customobj->callback_notify != NULL ) { + (*customobj->callback_notify)( customobj, genobj, event ); + } + + // step to next element, unlink list if desired + if ( unlinklist ) { + prev->NotifyCustmObjects = NULL; + prev = customobj; + } + } +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( OBJ_CUST ) +{ + //NOTE: + // register a type that consists only of + // geometry. this can be used to view + // objects using the summon command. + + custom_type_info_s info; + memset( &info, 0, sizeof( info ) ); + + info.type_name = "geometry"; + info.type_size = sizeof( CustomObject ); + + OBJ_RegisterCustomType( &info ); +} + + + diff --git a/src/libparsec/obj_odt.cpp b/src/libparsec/obj_odt.cpp new file mode 100644 index 0000000..5fbd23a --- /dev/null +++ b/src/libparsec/obj_odt.cpp @@ -0,0 +1,2088 @@ +/* + * PARSEC - ODT File Functions + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * Copyright (c) Clemens Beer <cbx@parsec.org> 1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "gd_heads.h" +#include "objstruc.h" +#include "od_odt.h" + +// global externals +#include "globals.h" +#ifdef PARSEC_SERVER + #include "e_world_trans.h" +#endif // PARSEC_SERVER + +// mathematics header +#include "utl_math.h" + +// local module header +#include "obj_odt.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + #include "con_aux_sv.h" +#else // !PARSEC_SERVER + #include "con_aux.h" + #include "con_shad.h" + #include "e_shader.h" + //#include "e_supp.h" + #include "obj_ctrl.h" +#endif // !PARSEC_SERVER + +#include "obj_clas.h" +#include "obj_type.h" +#include "sys_file.h" +#include "sys_swap.h" + + +// flags +//#define OD2_BBOX_VALID + + + +// string constants ----------------------------------------------------------- +// +static char object_not_found[] = "object \"%s\" not found"; +static char object_readerror[] = "object \"%s\" readerror"; +static char corrupt_object[] = "corrupt object file."; +static char corrupt_type[] = "corrupt type definition."; +static char no_object_mem[] = "not enough mem for object class-data."; + + +// alignment to enforce for object geometry data ------------------------------ +// +#define OBJ_GEOMETRY_ALIGNMENT_VAL 0x1f +#define OBJ_GEOMETRY_ALIGNMENT_MASK (~OBJ_GEOMETRY_ALIGNMENT_VAL) + + +// default objload_xx flags --------------------------------------------------- +// +#define ODT_OBJLOAD_DEFAULT ( OBJLOAD_WEDGENORMALS | OBJLOAD_WEDGELIGHTED | OBJLOAD_POLYWEDGEINDEXES ) +#define OD2_OBJLOAD_DEFAULT ( OBJLOAD_WEDGENORMALS | OBJLOAD_WEDGELIGHTED | OBJLOAD_POLYWEDGEINDEXES ) + + +// map texture name to pointer ------------------------------------------------ +// +PRIVATE +TextureMap *OBJODT_FetchTexture( char *texname ) +{ +#ifdef PARSEC_SERVER + return NULL; +#else + if ( texname == NULL ) { + return NULL; + } + + // make sure the texture name is all lower case since it is + // not possible to specify upper case chars in the console + strlwr( texname ); + + TextureMap* FetchTextureMap( const char *texname ); + TextureMap *tmap = FetchTextureMap( texname ); + + // error if no texture of specified name could be found + if ( tmap == NULL ) { + + // display error message +// MSGOUT( "texture %s needed by object not found.", texname ); + + // fall back on default texture if possible + tmap = FetchTextureMap( "texinval" ); + if ( tmap == NULL ) { + + // hard exit if texture not found and default not available + PERROR( "OBJODT_FetchTexture(): texture not found: \"%s\".", texname ); + } + } + + return tmap; +#endif // !PARSEC_SERVER +} + + +// tables for corners and wedges ---------------------------------------------- +// +#define MAX_AVERAGE_POLYS_PER_VTX 8 + +// linear array subrange +struct range_info_s { + + int start; + int count; +}; + +// corner (vertex,poly) +struct corner_info_s { + + int vertid; + int polyid; +}; + +static range_info_s* corner_info_vtxrange = NULL; +static corner_info_s* corner_info_corners = NULL; +static int corner_info_num_corners; + +// wedge (set of corners) +struct wedge_info_s { + + int cornerstart; + int cornercount; + + Vector3 normal; +}; + +static range_info_s* wedge_info_vtxrange = NULL; +static wedge_info_s* wedge_info_wedges = NULL; +static int wedge_info_num_wedges; + + +// generate corner info tables ------------------------------------------------ +// +PRIVATE +void OBJODT_CreateVertexCornerInfo( GenObject *gobj ) +{ + ASSERT( gobj != NULL ); + + ASSERT( corner_info_vtxrange == NULL ); + ASSERT( corner_info_corners == NULL ); + + int numverts = gobj->NumPolyVerts; + int maxpolyids = numverts * MAX_AVERAGE_POLYS_PER_VTX; + + // alloc tables + corner_info_vtxrange = (range_info_s *) ALLOCMEM( numverts * sizeof( range_info_s ) ); + if ( corner_info_vtxrange == NULL ) + OUTOFMEM( 0 ); + corner_info_corners = (corner_info_s *) ALLOCMEM( maxpolyids * sizeof( corner_info_s ) ); + if ( corner_info_corners == NULL ) + OUTOFMEM( 0 ); + + int cornerbase = 0; + int vidbase = gobj->NumNormals; + + //NOTE: + // sort order is on vertices. i.e., all corners incident + // with a specific vertex will be stored consecutively. + + // scan all vertices + for ( int vid = 0; vid < numverts; vid++ ) { + + corner_info_vtxrange[ vid ].start = cornerbase; + corner_info_vtxrange[ vid ].count = 0; + + // scan all polys + for ( unsigned int pid = 0; pid < gobj->NumPolys; pid++ ) { + + dword *vindxs = gobj->PolyList[ pid ].VertIndxs; + for ( int indx = gobj->PolyList[ pid ].NumVerts; indx > 0; indx-- ) { + if ( *vindxs++ == (dword)( vid + vidbase ) ) { + ASSERT( cornerbase < maxpolyids ); + corner_info_corners[ cornerbase ].vertid = vid; + corner_info_corners[ cornerbase ].polyid = pid; + corner_info_vtxrange[ vid ].count++; + cornerbase++; + } + } + } + } + + // store number of corners + corner_info_num_corners = cornerbase; +} + + +// fetch normal corresponding to corner --------------------------------------- +// +PRIVATE +Vector3 *OBJODT_FetchCornerNormal( GenObject *gobj, int corner ) +{ + ASSERT( gobj != NULL ); + ASSERT( (dword)corner < (dword)corner_info_num_corners ); + + dword cornerpoly = corner_info_corners[ corner ].polyid; + ASSERT( cornerpoly < gobj->NumPolys ); + + dword cornerface = gobj->PolyList[ cornerpoly ].FaceIndx; + ASSERT( cornerface < gobj->NumFaces ); + + dword cornernorm = gobj->FaceList[ cornerface ].FaceNormalIndx; + ASSERT( cornernorm < gobj->NumNormals ); + + return &gobj->VertexList[ cornernorm ]; +} + + +// additional configurable parameters for object loading ---------------------- +// +PUBLIC +odt_loading_params_s odt_loading_params = { + + 0, // maximum number of face anims (0==default) + 0, // maximum number of vertex anims (0==default) + FLOAT_TO_GEOMV( 0.5f ), // threshold for dot product of normals to merge +}; + + +// generate wedge info tables (sets of corners) ------------------------------- +// +PRIVATE +void OBJODT_CreateVertexWedgeInfo( GenObject *gobj ) +{ + ASSERT( gobj != NULL ); + + ASSERT( wedge_info_vtxrange == NULL ); + ASSERT( wedge_info_wedges == NULL ); + + int numverts = gobj->NumPolyVerts; + int maxwedges = corner_info_num_corners; + + // alloc tables + wedge_info_vtxrange = (range_info_s *) ALLOCMEM( numverts * sizeof( range_info_s ) ); + if ( wedge_info_vtxrange == NULL ) + OUTOFMEM( 0 ); + memset( wedge_info_vtxrange, 0, numverts * sizeof( range_info_s ) ); + + wedge_info_wedges = (wedge_info_s *) ALLOCMEM( maxwedges * sizeof( wedge_info_s ) ); + if ( wedge_info_wedges == NULL ) + OUTOFMEM( 0 ); + memset( wedge_info_wedges, 0, maxwedges * sizeof( wedge_info_s ) ); + + //NOTE: + // sort order is on vertices. i.e., all wedges incident + // with a specific vertex will be stored consecutively. + + // scan all vertices + int wedgebase = 0; + for ( int vid = 0; vid < numverts; vid++ ) { + + wedge_info_vtxrange[ vid ].start = wedgebase; + wedge_info_vtxrange[ vid ].count = 0; + + // scan corners for this vertex + int start = corner_info_vtxrange[ vid ].start; + int beyond = corner_info_vtxrange[ vid ].count + start; + + int runs[ 32 ]; + + // bring corners into wedge-order, determine number of wedges + int cbase = start; + int numwedges = 0; + for ( numwedges = 0; cbase < beyond; numwedges++ ) { + + int crun = 1; + int cstop = beyond; + + // try to grow run + int cscan = 0; + for ( cscan = cbase + 1; cscan < cstop; ) { + + // merging allowed if at least one normal within threshold + Vector3 *norm = OBJODT_FetchCornerNormal( gobj, cscan ); + int ccmp = 0; + for ( ccmp = cbase; ccmp < cbase + crun; ccmp++ ) { + + Vector3 *cmpnorm = OBJODT_FetchCornerNormal( gobj, ccmp ); + geomv_t ndiff = GEOMV_1 - DOT_PRODUCT( norm, cmpnorm ); + ABS_GEOMV( ndiff ); + if ( ndiff < odt_loading_params.merge_normals_threshold ) { + + // grow run, continue with next element + crun++; + cscan++; + break; + } + } + + if ( ccmp == cbase + crun ) { + + // shorten test range + cstop--; + + // swap non-mergeable corner beyond test range + corner_info_s temp = corner_info_corners[ cstop ]; + corner_info_corners[ cstop ] = corner_info_corners[ cscan ]; + corner_info_corners[ cscan ] = temp; + } + } + + // store length of run (one wedge) + ASSERT( numwedges < 32 ); + runs[ numwedges ] = crun; + + // base for next run + cbase += crun; + } + + // merge runs (corners) into wedges + int cornerstart = start; + for ( int wedge = 0; wedge < numwedges; wedge++ ) { + + wedge_info_wedges[ wedgebase ].cornerstart = cornerstart; + wedge_info_wedges[ wedgebase ].cornercount = runs[ wedge ]; + + wedge_info_wedges[ wedgebase ].normal.X = GEOMV_0; + wedge_info_wedges[ wedgebase ].normal.Y = GEOMV_0; + wedge_info_wedges[ wedgebase ].normal.Z = GEOMV_0; + + // sum all corner normals for this wedge + int cornerbeyond = cornerstart + runs[ wedge ]; + for ( int corner = cornerstart; corner < cornerbeyond; corner++ ) { + + Vector3 *cornernorm = OBJODT_FetchCornerNormal( gobj, corner ); + wedge_info_wedges[ wedgebase ].normal.X += cornernorm->X; + wedge_info_wedges[ wedgebase ].normal.Y += cornernorm->Y; + wedge_info_wedges[ wedgebase ].normal.Z += cornernorm->Z; + } + + // normalize resulting normal (averaging implicit) + NormVctX( &wedge_info_wedges[ wedgebase ].normal ); + + cornerstart = cornerbeyond; + + wedge_info_vtxrange[ vid ].count++; + wedgebase++; + } + } + + // set total number of wedges + wedge_info_num_wedges = wedgebase; +} + + +// free storage for corner and wedge info tables ------------------------------ +// +PRIVATE +void OBJODT_FreeVertexCornerWedgeInfo() +{ + // free corner info + if ( corner_info_vtxrange != NULL ) { + FREEMEM( corner_info_vtxrange ); + corner_info_vtxrange = NULL; + } + if ( corner_info_corners != NULL ) { + FREEMEM( corner_info_corners ); + corner_info_corners = NULL; + } + + // free wedge info + if ( wedge_info_vtxrange != NULL ) { + FREEMEM( wedge_info_vtxrange ); + wedge_info_vtxrange = NULL; + } + if ( wedge_info_wedges != NULL ) { + FREEMEM( wedge_info_wedges ); + wedge_info_wedges = NULL; + } +} + + +// pointer correction macro --------------------------------------------------- +// +#define CORRECT_POINTER(p) ( ( (p) != NULL ) ? ( (char*)(p) + pdiff ) : NULL ) + + +// correct data pointers contained in lod object to new object base ----------- +// +PRIVATE +void OBJODT_CorrectPointersLodObject( GenLodObject *lodobj, ptrdiff_t pdiff, int postcorrect ) +{ + ASSERT( lodobj != NULL ); + + Poly *polylist = lodobj->PolyList; + Face *facelist = lodobj->FaceList; + + lodobj->VertexList = (Vertex3 *) CORRECT_POINTER( lodobj->VertexList ); + lodobj->X_VertexList = (Vertex3 *) CORRECT_POINTER( lodobj->X_VertexList ); + lodobj->S_VertexList = (SPoint *) CORRECT_POINTER( lodobj->S_VertexList ); + lodobj->PolyList = (Poly *) CORRECT_POINTER( lodobj->PolyList ); + lodobj->FaceList = (Face *) CORRECT_POINTER( lodobj->FaceList ); + lodobj->VisPolyList = (dword *) CORRECT_POINTER( lodobj->VisPolyList ); + lodobj->SortedPolyList = (dword *) CORRECT_POINTER( lodobj->SortedPolyList ); + lodobj->AuxList = (void *) CORRECT_POINTER( lodobj->AuxList ); + lodobj->BSPTree = (BSPNode *) CORRECT_POINTER( lodobj->BSPTree ); + lodobj->AuxBSPTree = (CullBSPNode*) CORRECT_POINTER( lodobj->AuxBSPTree ); + lodobj->AuxObject = (void *) CORRECT_POINTER( lodobj->AuxObject ); + lodobj->WedgeVertIndxs = (dword *) CORRECT_POINTER( lodobj->WedgeVertIndxs ); + lodobj->WedgeNormals = (Vector3 *) CORRECT_POINTER( lodobj->WedgeNormals ); + lodobj->WedgeColors = (colrgba_s *) CORRECT_POINTER( lodobj->WedgeColors ); + lodobj->WedgeTexCoords = (TexCoord2 *) CORRECT_POINTER( lodobj->WedgeTexCoords ); + lodobj->WedgeLighted = (colrgba_s *) CORRECT_POINTER( lodobj->WedgeLighted ); + lodobj->WedgeSpecular = (colrgba_s *) CORRECT_POINTER( lodobj->WedgeSpecular ); + lodobj->WedgeFogged = (colrgba_s *) CORRECT_POINTER( lodobj->WedgeFogged ); + + // if correction takes place after relocation + // the lists are already at their new positions + if ( postcorrect ) { + polylist = lodobj->PolyList; + facelist = lodobj->FaceList; + } + + // correct pointers contained in poly structures + for ( unsigned int pid = 0; pid < lodobj->NumPolys; pid++ ) { + if (&polylist[pid] != NULL) + polylist[ pid ].VertIndxs = (dword *) CORRECT_POINTER( polylist[ pid ].VertIndxs ); + } + + // correct pointers contained in face structures + for ( unsigned int fid = 0; fid < lodobj->NumFaces; fid++ ) { + if (&facelist[fid] != NULL) + facelist[ fid ].ExtInfo = (FaceExtInfo *) CORRECT_POINTER( facelist[ fid ].ExtInfo ); + } +} + + +// correct data pointers to new object base (base data) ----------------------- +// +PRIVATE +void OBJODT_CorrectPointersBaseData( GenObject *obj, ptrdiff_t pdiff, int postcorrect ) +{ + ASSERT( obj != NULL ); + + GenLodInfo *lodinfo = obj->LodObjects; + + obj->LodObjects = (GenLodInfo *) CORRECT_POINTER( obj->LodObjects ); + obj->FaceAnimStates = (FaceAnimState *) CORRECT_POINTER( obj->FaceAnimStates ); + obj->VtxAnimStates = (VtxAnimState *) CORRECT_POINTER( obj->VtxAnimStates ); + + // if correction takes place after relocation + // the lod infos are already at their new positions + if ( postcorrect ) { + + lodinfo = obj->LodObjects; + + // correct pointers contained in lod infos + for ( int lod = 0; lod < obj->NumLodObjects; lod++ ) { + if (&lodinfo[lod] != NULL) { + lodinfo[ lod ].LodObject = (GenLodObject *) CORRECT_POINTER( lodinfo[ lod ].LodObject ); + OBJODT_CorrectPointersLodObject( lodinfo[ lod ].LodObject, pdiff, TRUE ); + } + } + + } else { + + // correct pointers contained in lod infos + for ( int lod = 0; lod < obj->NumLodObjects; lod++ ) { + OBJODT_CorrectPointersLodObject( lodinfo[ lod ].LodObject, pdiff, FALSE ); + lodinfo[ lod ].LodObject = (GenLodObject *) CORRECT_POINTER( lodinfo[ lod ].LodObject ); + } + } +} + + +// correct data pointers to new object base (geometry data) ------------------- +// +PRIVATE +void OBJODT_CorrectPointersGeomData( GenObject *obj, ptrdiff_t pdiff, int postcorrect ) +{ + ASSERT( obj != NULL ); + + Poly *polylist = obj->PolyList; + Face *facelist = obj->FaceList; + + obj->VertexList = (Vertex3 *) CORRECT_POINTER( obj->VertexList ); + obj->X_VertexList = (Vertex3 *) CORRECT_POINTER( obj->X_VertexList ); + obj->S_VertexList = (SPoint *) CORRECT_POINTER( obj->S_VertexList ); + obj->PolyList = (Poly *) CORRECT_POINTER( obj->PolyList ); + obj->FaceList = (Face *) CORRECT_POINTER( obj->FaceList ); + obj->VisPolyList = (dword *) CORRECT_POINTER( obj->VisPolyList ); + obj->SortedPolyList = (dword *) CORRECT_POINTER( obj->SortedPolyList ); + obj->AuxList = (void *) CORRECT_POINTER( obj->AuxList ); + obj->BSPTree = (BSPNode *) CORRECT_POINTER( obj->BSPTree ); + obj->AuxBSPTree = (CullBSPNode*) CORRECT_POINTER( obj->AuxBSPTree ); + obj->AuxObject = (void *) CORRECT_POINTER( obj->AuxObject ); + obj->WedgeVertIndxs = (dword *) CORRECT_POINTER( obj->WedgeVertIndxs ); + obj->WedgeNormals = (Vector3 *) CORRECT_POINTER( obj->WedgeNormals ); + obj->WedgeColors = (colrgba_s *) CORRECT_POINTER( obj->WedgeColors ); + obj->WedgeTexCoords = (TexCoord2 *) CORRECT_POINTER( obj->WedgeTexCoords ); + obj->WedgeLighted = (colrgba_s *) CORRECT_POINTER( obj->WedgeLighted ); + obj->WedgeSpecular = (colrgba_s *) CORRECT_POINTER( obj->WedgeSpecular ); + obj->WedgeFogged = (colrgba_s *) CORRECT_POINTER( obj->WedgeFogged ); + + // if correction takes place after relocation + // the lists are already at their new positions + if ( postcorrect ) { + polylist = obj->PolyList; + facelist = obj->FaceList; + } + + // correct pointers contained in poly structures + for ( unsigned int pid = 0; pid < obj->NumPolys; pid++ ) { + if (&polylist[pid] != NULL) + polylist[ pid ].VertIndxs = (dword *) CORRECT_POINTER( polylist[ pid ].VertIndxs ); + } + + // correct pointers contained in face structures + for ( unsigned int fid = 0; fid < obj->NumFaces; fid++ ) { + if (&facelist[fid] != NULL) + facelist[ fid ].ExtInfo = (FaceExtInfo *) CORRECT_POINTER( facelist[ fid ].ExtInfo ); + } +} + + +// store wedge indexes as poly corner info ------------------------------------ +// +PRIVATE +void OBJODT_StorePolyWedgeIndexes( GenObject *gobj, dword flags ) +{ + ASSERT( gobj != NULL ); + + if ( ( flags & OBJLOAD_POLYWEDGEINDEXES ) == 0 ) + return; + + // determine where wedge indexes should be stored + dword wbase = 1; + if ( flags & OBJLOAD_POLYCORNERCOLORS ) + wbase++; + + // augment polys with wedge indexes + for ( unsigned int pid = 0; pid < gobj->NumPolys; pid++ ) { + + dword *vertindxs = gobj->PolyList[ pid ].VertIndxs; + dword *indxbeyond = &vertindxs[ gobj->PolyList[ pid ].NumVerts ]; + dword *wedgeindxs = &vertindxs[ gobj->PolyList[ pid ].NumVerts * wbase ]; + + // map all vertex indexes + for ( ; vertindxs < indxbeyond; vertindxs++ ) { + + int windx = -1; + int vindx = *vertindxs - gobj->NumNormals; + + // check all wedges of this vertex + int wstart = wedge_info_vtxrange[ vindx ].start; + int wbeyond = wedge_info_vtxrange[ vindx ].count + wstart; + for ( ; wstart < wbeyond; wstart++ ) { + + // check all corners of this wedge + int cstart = wedge_info_wedges[ wstart ].cornerstart; + int cbeyond = wedge_info_wedges[ wstart ].cornercount + cstart; + for ( ; cstart < cbeyond; cstart++ ) { + + if ( (dword)corner_info_corners[ cstart ].polyid == pid ) { + windx = wstart; + cstart = cbeyond; + wstart = wbeyond; + } + } + } + + // store corresponding wedge index + ASSERT( windx != -1 ); + *wedgeindxs++ = windx; + } + + // specify that wedge index array is present + gobj->PolyList[ pid ].Flags = POLYFLAG_WEDGEINDEXES; + } +} + + +// create wedge data structures ----------------------------------------------- +// +PRIVATE +GenObject *OBJODT_CreateWedgeData( GenObject *gobj, size_t *objmemsize, dword flags ) +{ + ASSERT( gobj != NULL ); + ASSERT( objmemsize != NULL ); + + if ( ( flags & OBJLOAD_WEDGE_INFO ) == 0 ) + return gobj; + + // don't override wedges from file + // (always 0 right now) + if ( gobj->NumWedges > 0 ) { + return gobj; + } + + size_t basesize = *objmemsize; + + // create corner and wedge info, + // determine number of wedges + OBJODT_CreateVertexCornerInfo( gobj ); + OBJODT_CreateVertexWedgeInfo( gobj ); + dword numwedges = wedge_info_num_wedges; + + // GenObject::WedgeVertIndxs + *objmemsize += sizeof( dword ) * numwedges; + + // GenObject::WedgeNormals + if ( flags & OBJLOAD_WEDGENORMALS ) { + *objmemsize += sizeof( Vector3 ) * numwedges; + } + + // GenObject::WedgeColors + if ( flags & OBJLOAD_WEDGECOLORS ) { + *objmemsize += sizeof( colrgba_s ) * numwedges; + } + + // GenObject::WedgeTexCoords + if ( flags & OBJLOAD_WEDGETEXCOORDS ) { + *objmemsize += sizeof( TexCoord2 ) * numwedges; + } + + // GenObject::WedgeLighted + if ( flags & OBJLOAD_WEDGELIGHTED ) { + *objmemsize += sizeof( colrgba_s ) * numwedges; + } + + // GenObject::WedgeSpecular + if ( flags & OBJLOAD_WEDGESPECULAR ) { + *objmemsize += sizeof( colrgba_s ) * numwedges; + } + + // GenObject::WedgeFogged + if ( flags & OBJLOAD_WEDGEFOGGED ) { + *objmemsize += sizeof( colrgba_s ) * numwedges; + } + + // allocate memory for expanded object + char *curobjmem = (char *) ALLOCMEM( *objmemsize ); + if ( curobjmem == NULL ) + OUTOFMEM( no_object_mem ); + + // copy original data + memset( curobjmem, 0, *objmemsize ); + memcpy( curobjmem, gobj, basesize ); + + GenObject *cobj = gobj; + gobj = (GenObject *) curobjmem; + + // correct pointers + ptrdiff_t pdiff = (char*)gobj - (char*)cobj; + OBJODT_CorrectPointersBaseData( gobj, pdiff, TRUE ); + OBJODT_CorrectPointersGeomData( gobj, pdiff, TRUE ); + + // free old object + FREEMEM( cobj ); + char *heappos = curobjmem + basesize; + + // store number of wedges + gobj->NumWedges = numwedges; + + // store pointers to wedge data + gobj->WedgeVertIndxs = (dword *) heappos; + heappos += sizeof( dword ) * numwedges; + + if ( flags & OBJLOAD_WEDGENORMALS ) { + gobj->WedgeNormals = (Vector3 *) heappos; + heappos += sizeof( Vector3 ) * numwedges; + } + if ( flags & OBJLOAD_WEDGECOLORS ) { + gobj->WedgeColors = (colrgba_s *) heappos; + heappos += sizeof( colrgba_s ) * numwedges; + } + if ( flags & OBJLOAD_WEDGETEXCOORDS ) { + gobj->WedgeTexCoords = (TexCoord2 *) heappos; + heappos += sizeof( TexCoord2 ) * numwedges; + } + if ( flags & OBJLOAD_WEDGELIGHTED ) { + gobj->WedgeLighted = (colrgba_s *) heappos; + heappos += sizeof( colrgba_s ) * numwedges; + } + if ( flags & OBJLOAD_WEDGESPECULAR ) { + gobj->WedgeSpecular = (colrgba_s *) heappos; + heappos += sizeof( colrgba_s ) * numwedges; + } + if ( flags & OBJLOAD_WEDGEFOGGED ) { + gobj->WedgeFogged = (colrgba_s *) heappos; + heappos += sizeof( colrgba_s ) * numwedges; + } + + // store wedge data + for ( unsigned int wedge = 0; wedge < numwedges; wedge++ ) { + + int vid = corner_info_corners[ wedge_info_wedges[ wedge ].cornerstart ].vertid; + gobj->WedgeVertIndxs[ wedge ] = vid + gobj->NumNormals; + + if ( flags & OBJLOAD_WEDGENORMALS ) { + gobj->WedgeNormals[ wedge ] = wedge_info_wedges[ wedge ].normal; + } + if ( flags & OBJLOAD_WEDGECOLORS ) { + //TODO: + } + if ( flags & OBJLOAD_WEDGETEXCOORDS ) { + //TODO: + } + } + + // store wedge indexes as poly corner info + OBJODT_StorePolyWedgeIndexes( gobj, flags ); + + // free temporary tables + OBJODT_FreeVertexCornerWedgeInfo(); + + return gobj; +} + + +// determine if face is texture mapped ---------------------------------------- +// +PRIVATE +int ODT_FaceTextured( ODT_Face *face ) +{ + return ( ( face->Shading == ODT_afftex_shad ) || + ( face->Shading == ODT_ipol1tex_shad ) || + ( face->Shading == ODT_ipol2tex_shad ) || + ( face->Shading == ODT_persptex_shad ) ); +} + + +// these are global to reduce automatic variables in recursive traversal ------ +// +static ODT_BSPNode *odt_tree; +static BSPNode *gen_tree; +static CullBSPNode *aux_tree; +static GenObject *base_obj; + +static int odt_numnodes; +static int odt_numcontained; +static int odt_maxnodeid; + + +// recursively swap bsp tree and determine number of nodes -------------------- +// +PRIVATE +void ODT_SwapBSPTree( int node, int inlist ) +{ + if ( node == 0 ) + return; + + if ( node > odt_maxnodeid ) + odt_maxnodeid = node; + + odt_tree[ node ].Polygon = SWAP_32( odt_tree[ node ].Polygon ); + odt_tree[ node ].Contained = SWAP_32( odt_tree[ node ].Contained ); + odt_tree[ node ].FrontTree = SWAP_32( odt_tree[ node ].FrontTree ); + odt_tree[ node ].BackTree = SWAP_32( odt_tree[ node ].BackTree ); + + if ( odt_tree[ node ].BackTree > 0 ) { + ASSERT( !inlist ); + ODT_SwapBSPTree( odt_tree[ node ].BackTree, FALSE ); + } + + if ( odt_tree[ node ].FrontTree > 0 ) { + ASSERT( !inlist ); + ODT_SwapBSPTree( odt_tree[ node ].FrontTree, FALSE ); + } + + if ( odt_tree[ node ].Contained > 0 ) { + ODT_SwapBSPTree( odt_tree[ node ].Contained, TRUE ); + } + + if ( inlist ) { + odt_numcontained++; + } else { + odt_numnodes++; + } +} + + +// recursively build bsp tree ------------------------------------------------- +// +PRIVATE +void ODT_BuildBSPTree( int node ) +{ + if ( node == 0 ) + return; + + ASSERT( (dword)node <= (dword)odt_maxnodeid ); + + gen_tree[ node ].Polygon = odt_tree[ node ].Polygon; + gen_tree[ node ].Contained = odt_tree[ node ].Contained; + gen_tree[ node ].FrontTree = odt_tree[ node ].FrontTree; + gen_tree[ node ].BackTree = odt_tree[ node ].BackTree; + + if ( odt_tree[ node ].BackTree > 0 ) { + ODT_BuildBSPTree( odt_tree[ node ].BackTree ); + } + + if ( odt_tree[ node ].FrontTree > 0 ) { + ODT_BuildBSPTree( odt_tree[ node ].FrontTree ); + } + + if ( odt_tree[ node ].Contained > 0 ) { + ODT_BuildBSPTree( odt_tree[ node ].Contained ); + } +} + + +// recursively build aux bsp tree --------------------------------------------- +// +PRIVATE +void ODT_BuildBSPTreeAux( int node ) +{ + if ( node == 0 ) + return; + + ASSERT( (dword)node <= (dword)odt_maxnodeid ); + + dword polyid = odt_tree[ node ].Polygon; + ASSERT( polyid < 32768 ); + + aux_tree[ node ].polygons[ 0 ] = 0; + aux_tree[ node ].polygons[ 1 ] = (short) polyid; + aux_tree[ node ].numpolys[ 0 ] = 0; + aux_tree[ node ].numpolys[ 1 ] = 1; + + // node polygon + ASSERT( polyid < base_obj->NumPolys ); + Poly *poly = &base_obj->PolyList[ polyid ]; + + // dot node normal with first polygon vertex + dword normalindx = base_obj->FaceList[ poly->FaceIndx ].FaceNormalIndx; + geomv_t planeoffset = DOT_PRODUCT( &base_obj->VertexList[ normalindx ], + &base_obj->VertexList[ *poly->VertIndxs ] ); + // set explicit plane spec + aux_tree[ node ].plane.X = base_obj->VertexList[ normalindx ].X; + aux_tree[ node ].plane.Y = base_obj->VertexList[ normalindx ].Y; + aux_tree[ node ].plane.Z = base_obj->VertexList[ normalindx ].Z; + aux_tree[ node ].plane.D = planeoffset; + +// aux_tree[ node ].minmax = ?; + + aux_tree[ node ].flags = 0; + aux_tree[ node ].visframe = 0; + aux_tree[ node ].subtrees[ 0 ] = odt_tree[ node ].BackTree; + aux_tree[ node ].subtrees[ 1 ] = odt_tree[ node ].FrontTree; + + if ( odt_tree[ node ].BackTree > 0 ) { + ODT_BuildBSPTreeAux( odt_tree[ node ].BackTree ); + } + + if ( odt_tree[ node ].FrontTree > 0 ) { + ODT_BuildBSPTreeAux( odt_tree[ node ].FrontTree ); + } + +//FIXME: +// strip contained list +// if ( odt_tree[ node ].Contained > 0 ) { +// ODT_BuildBSPTreeAux( odt_tree[ node ].Contained ); +// } + +} + + +// convert odt shading spec into internal shader spec ------------------------- +// +PRIVATE +void ODT_ConvertShading( GenObject *gobj, dword faceid, ODT_Face *odtface, shader_s *shader ) +{ +#ifdef PARSEC_CLIENT + + ASSERT( gobj != NULL ); + ASSERT( faceid < gobj->NumFaces ); + ASSERT( odtface != NULL ); + + // allow overriding shader specified in file + if ( SetFaceShader( gobj, ACTIVE_LOD, faceid, shader ) ) + return; + + Face *face = &gobj->FaceList[ faceid ]; + + switch ( odtface->Shading ) { + + case ODT_no_shad: + case ODT_flat_shad: + case ODT_gouraud_shad: + face->ShadingIter = iter_rgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_USECOLORINDEX; + break; + + case ODT_afftex_shad: + case ODT_ipol1tex_shad: + case ODT_ipol2tex_shad: + face->ShadingIter = iter_texrgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_ENABLETEXTURE | FACE_SHADING_TEXIPOLATE; + break; + + case ODT_persptex_shad: + face->ShadingIter = iter_texrgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_ENABLETEXTURE; + break; + +// case ODT_material_shad: +// case ODT_texmat_shad: + + default: + PANIC( "invalid ODT shading specification." ); + } + +#endif // PARSEC_CLIENT +} + + +// create (internal) object from (external) odt object ------------------------ +// +PRIVATE +size_t ODT_CreateObject( ODT_GenObject *cobj, dword flags, shader_s *shader ) +{ + ASSERT( cobj != NULL ); + + // default flags may be requested + if ( flags == OBJLOAD_DEFAULT ) { + flags = ODT_OBJLOAD_DEFAULT; + } + + // swap important header fields + cobj->InstanceSize = SWAP_32( cobj->InstanceSize ); + cobj->NumVerts = SWAP_32( cobj->NumVerts ); + cobj->NumPolyVerts = SWAP_32( cobj->NumPolyVerts ); + cobj->NumNormals = SWAP_32( cobj->NumNormals ); + cobj->NumPolys = SWAP_32( cobj->NumPolys ); + cobj->NumFaces = SWAP_32( cobj->NumFaces ); + + //NOTE: + // some very old ODT files have an invalid InstanceSize field. + // never mind, we recalculate it anyway. + + ASSERT( cobj->NumVerts == cobj->NumPolyVerts + cobj->NumNormals ); + ASSERT( cobj->NumPolys >= cobj->NumFaces ); + + // new base address for object data + size_t newdatabase = (size_t) cobj; + + // correct header relative pointers in object header to absolute pointers + cobj->VertexList = (ODT_Vertex3 *) ( SWAP_32( (size_t)cobj->VertexList ) + newdatabase ); + cobj->X_VertexList = (ODT_Vertex3 *) ( SWAP_32( (size_t)cobj->X_VertexList ) + newdatabase ); + cobj->P_VertexList = (ODT_ProjPoint *) ( SWAP_32( (size_t)cobj->P_VertexList ) + newdatabase ); + cobj->S_VertexList = (ODT_SPoint *) ( SWAP_32( (size_t)cobj->S_VertexList ) + newdatabase ); + cobj->PolyList = (ODT_Poly *) ( SWAP_32( (size_t)cobj->PolyList ) + newdatabase ); + cobj->FaceList = (ODT_Face *) ( SWAP_32( (size_t)cobj->FaceList ) + newdatabase ); + cobj->VisPolyList = (ODT_VisPolys *) ( SWAP_32( (size_t)cobj->VisPolyList ) + newdatabase ); + cobj->BSPTree = (ODT_BSPNode *) ( SWAP_32( (size_t)cobj->BSPTree ) + newdatabase ); + + // size of generic header plus size of type specific header + size_t instancesize = OBJ_FetchTypeSize( cobj->ObjectType ); + + // face anim state array may be included at end of instance data + int numfaceanimstates = 0; + ptrdiff_t faceanimstatebase = 0; + if ( flags & OBJLOAD_FACEANIMS ) { + + // default is simply a fixed number of anim states, + // since we do not know the number of textures + numfaceanimstates = ( odt_loading_params.max_face_anim_states > 0 ) ? + odt_loading_params.max_face_anim_states : 16; + + // safeguard + if ( numfaceanimstates > 256 ) { + numfaceanimstates = 256; + } + + size_t alignmentpadding = ( ( instancesize + 3 ) & ~0x03 ) - instancesize; + size_t sz_faceanimstates = numfaceanimstates * sizeof( FaceAnimState ); + + faceanimstatebase = instancesize + alignmentpadding; + instancesize += sz_faceanimstates + alignmentpadding; + } + + // calc necessary alignment padding for data (area behind header) + size_t alignmentpadding = ( ( instancesize + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - instancesize; + ASSERT( alignmentpadding <= OBJ_GEOMETRY_ALIGNMENT_VAL ); + + // swap bsp tree and count number of nodes + odt_numnodes = 0; + odt_numcontained = 0; + odt_maxnodeid = 0; + odt_tree = cobj->BSPTree; + + ODT_SwapBSPTree( 1, FALSE ); +// ASSERT( odt_maxnodeid == odt_numnodes + odt_numcontained ); //FIXME: + + //NOTE: + // apparently some ODT files contain bsp trees where there + // are unused nodes in the interior of the array. therefore, + // the above assertion may indeed fail. should look into this. + + // calc some numbers not available in header + int numpolyvindexs = ( (size_t)cobj->FaceList - (size_t)cobj->PolyList - + cobj->NumPolys * sizeof( ODT_Poly ) ) / sizeof( dword ); + int numodtbspnodes = odt_maxnodeid + 1; + + // reserve an extended face info for every face + int numfaceexinfos = ( numfaceanimstates > 0 ) ? cobj->NumFaces : 0; + + // determine how many dwords to reserve + // for each corner in a polygon + size_t cornersize = 1; + if ( flags & OBJLOAD_POLYCORNERCOLORS ) + cornersize++; + if ( flags & OBJLOAD_POLYWEDGEINDEXES ) + cornersize++; + + // determine sizes of data areas + size_t sz_vertexlist = cobj->NumVerts * sizeof( Vertex3 ); + size_t sz_xvertexlist = cobj->NumVerts * sizeof( Vertex3 ); + size_t sz_svertexlist = cobj->NumVerts * sizeof( SPoint ); + size_t sz_polylist = cobj->NumPolys * sizeof( Poly ); + size_t sz_polyindexes = numpolyvindexs * sizeof( dword ) * cornersize; + size_t sz_facelist = cobj->NumFaces * sizeof( Face ); + size_t sz_faceextinfo = numfaceexinfos * sizeof( FaceExtInfo ); + size_t sz_vispolylist = cobj->NumPolys * sizeof( dword ); + size_t sz_bsptree = numodtbspnodes * sizeof( BSPNode ); + size_t sz_auxbsptree = numodtbspnodes * sizeof( CullBSPNode ); + + // calc data size + size_t datasize = 0; + datasize += sz_vertexlist; // VertexList + datasize += sz_xvertexlist; // X_VertexList + datasize += sz_svertexlist; // S_VertexList + datasize += sz_polylist; // PolyList + datasize += sz_polyindexes; // +poly vertex/wedge indexes + datasize += sz_facelist; // FaceList + datasize += sz_faceextinfo; // +extended face infos + datasize += sz_vispolylist; // VisPolyList + datasize += sz_bsptree; // BSPTree + datasize += sz_auxbsptree; // AuxBSPTree + + // calc size of memory block the object will occupy + size_t objmemsize = instancesize + alignmentpadding + datasize; + + // allocate memory for object + char *curobjmem = (char *) ALLOCMEM( objmemsize ); + if ( curobjmem == NULL ) + OUTOFMEM( no_object_mem ); + + // preclear memory + memset( curobjmem, 0, objmemsize ); + + // init pointer to new class + GenObject *gobj = (GenObject *) curobjmem; + + // init header fields + gobj->NextObj = NULL; + gobj->PrevObj = NULL; + gobj->NextVisObj = NULL; + + gobj->ObjectNumber = 0; + gobj->HostObjNumber = 0; + gobj->ObjectType = cobj->ObjectType; + gobj->ObjectClass = cobj->ObjectClass; + gobj->InstanceSize = instancesize; + + gobj->NumVerts = cobj->NumVerts; + gobj->NumPolyVerts = cobj->NumPolyVerts; + gobj->NumNormals = cobj->NumNormals; + gobj->NumPolys = cobj->NumPolys; + gobj->NumFaces = cobj->NumFaces; + + gobj->VertexList = (Vertex3 *) ( (char*)gobj + instancesize + alignmentpadding ); + gobj->X_VertexList = (Vertex3 *) ( (char*)gobj->VertexList + sz_vertexlist ); + gobj->S_VertexList = (SPoint *) ( (char*)gobj->X_VertexList + sz_xvertexlist ); + gobj->PolyList = (Poly *) ( (char*)gobj->S_VertexList + sz_svertexlist ); + gobj->FaceList = (Face *) ( (char*)gobj->PolyList + sz_polylist + sz_polyindexes ); + gobj->VisPolyList = (dword *) ( (char*)gobj->FaceList + sz_facelist + sz_faceextinfo ); + gobj->SortedPolyList = NULL; + gobj->AuxList = NULL; + gobj->BSPTree = (BSPNode *) ( (char*)gobj->VisPolyList + sz_vispolylist ); + gobj->AuxBSPTree = (CullBSPNode*)( (char*)gobj->BSPTree + sz_bsptree ); + // = ( *) ( (char*)gobj->AuxBSPTree + sz_auxbsptree ); + + gobj->NumFaceAnims = numfaceanimstates; + gobj->ActiveFaceAnims = 0; + gobj->FaceAnimStates = ( flags & OBJLOAD_FACEANIMS ) ? + (FaceAnimState *) ( (char*)gobj + faceanimstatebase ) : NULL; + + gobj->NumVtxAnims = 0; + gobj->ActiveVtxAnims = 0; + gobj->VtxAnimStates = NULL; + + gobj->BoundingSphere = FIXED_TO_GEOMV( SWAP_32( DW32( cobj->BoundingSphere ) ) ); + gobj->BoundingSphere2 = FIXED_TO_GEOMV( SWAP_32( DW32( cobj->BoundingSphere2 ) ) ); + + // axial bounding box + geomv_t mins[ 3 ]; + geomv_t maxs[ 3 ]; + + // init to swapped maximum extents + for ( int dim = 0; dim < 3; dim++ ) { + mins[ dim ] = gobj->BoundingSphere; + maxs[ dim ] = -gobj->BoundingSphere; + } + + // init list of vertices + ODT_Vertex3 *odtvtxs = cobj->VertexList; + Vertex3 *genvtxs = gobj->VertexList; + + for ( int vct = gobj->NumVerts; vct > 0; vct--, odtvtxs++, genvtxs++ ) { + + genvtxs->X = FIXED_TO_GEOMV( SWAP_32( DW32( odtvtxs->X ) ) ); + genvtxs->Y = FIXED_TO_GEOMV( SWAP_32( DW32( odtvtxs->Y ) ) ); + genvtxs->Z = FIXED_TO_GEOMV( SWAP_32( DW32( odtvtxs->Z ) ) ); + genvtxs->VisibleFrame = 0; + + // determine min-max coordinates in each dimension for bounding box + mins[ 0 ] = min( mins[ 0 ], genvtxs->X ); + maxs[ 0 ] = max( maxs[ 0 ], genvtxs->X ); + + mins[ 1 ] = min( mins[ 1 ], genvtxs->Y ); + maxs[ 1 ] = max( maxs[ 1 ], genvtxs->Y ); + + mins[ 2 ] = min( mins[ 2 ], genvtxs->Z ); + maxs[ 2 ] = max( maxs[ 2 ], genvtxs->Z ); + } + + // store bounding box via min-max vertices + gobj->BoundingBox[ 0 ].X = mins[ 0 ]; + gobj->BoundingBox[ 0 ].Y = mins[ 1 ]; + gobj->BoundingBox[ 0 ].Z = mins[ 2 ]; + + gobj->BoundingBox[ 1 ].X = maxs[ 0 ]; + gobj->BoundingBox[ 1 ].Y = maxs[ 1 ]; + gobj->BoundingBox[ 1 ].Z = maxs[ 2 ]; + + // init list of polygons + ODT_Poly *odtpolys = cobj->PolyList; + Poly *genpolys = gobj->PolyList; + dword *genindxs = (dword *) ( (char*)gobj->PolyList + sz_polylist ); + + int numindxs = 0; + for ( int pct = gobj->NumPolys; pct > 0; pct--, odtpolys++, genpolys++ ) { + + genpolys->NumVerts = SWAP_32( odtpolys->NumVerts ); + genpolys->FaceIndx = SWAP_32( odtpolys->FaceIndx ); + genpolys->VertIndxs = genindxs; + genpolys->Flags = POLYFLAG_DEFAULT; + odtpolys->VertIndxs = (dword *) ( SWAP_32( (size_t)odtpolys->VertIndxs ) + newdatabase ); + + // grab all vertex indexes + dword *odtindxs = odtpolys->VertIndxs; + for ( int vict = genpolys->NumVerts; vict > 0; vict--, numindxs++ ) { + ASSERT( numindxs < numpolyvindexs ); + *genindxs++ = SWAP_32( *odtindxs ); + odtindxs++; + } + + // skip area reserved for additional corner info + genindxs += genpolys->NumVerts * ( cornersize - 1 ); + } + ASSERT( numindxs == numpolyvindexs ); + + // init list of faces + ODT_Face *odtfaces = cobj->FaceList; + + for ( dword faceid = 0; faceid < gobj->NumFaces; faceid++, odtfaces++ ) { + + Face *face = &gobj->FaceList[ faceid ]; + + // swap shading and texname fields + odtfaces->Shading = SWAP_32( odtfaces->Shading ); + odtfaces->TexMap = ODT_FaceTextured( odtfaces ) ? + (char *) ( SWAP_32( (size_t)odtfaces->TexMap ) + newdatabase ) : NULL; + + face->TexMap = OBJODT_FetchTexture( odtfaces->TexMap ); + ODT_ConvertShading( gobj, faceid, odtfaces, shader ); + + face->ExtInfo = NULL; + + face->ColorRGB = SWAP_32( odtfaces->ColorRGB ); + // set unspecified color to white + if ( face->ColorRGB == 0 ) + face->ColorRGB = 0xffffffff; + + face->ColorIndx = SWAP_32( odtfaces->ColorIndx ); + face->FaceNormalIndx = SWAP_32( odtfaces->FaceNormalIndx ); + face->VisibleFrame = VISFRAME_NEVER; + + face->TexXmatrx[0][0] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[0][0] ) ) ); + face->TexXmatrx[0][1] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[0][1] ) ) ); + face->TexXmatrx[0][2] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[0][2] ) ) ); + face->TexXmatrx[0][3] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[0][3] ) ) ); + face->TexXmatrx[1][0] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[1][0] ) ) ); + face->TexXmatrx[1][1] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[1][1] ) ) ); + face->TexXmatrx[1][2] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[1][2] ) ) ); + face->TexXmatrx[1][3] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[1][3] ) ) ); + face->TexXmatrx[2][0] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[2][0] ) ) ); + face->TexXmatrx[2][1] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[2][1] ) ) ); + face->TexXmatrx[2][2] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[2][2] ) ) ); + face->TexXmatrx[2][3] = FIXED_TO_GEOMV( SWAP_32( DW32( odtfaces->TexXmatrx[2][3] ) ) ); + } + + // init bsp tree + odt_tree = cobj->BSPTree; + gen_tree = gobj->BSPTree; + aux_tree = gobj->AuxBSPTree; + base_obj = gobj; + + ODT_BuildBSPTree( 1 ); + ODT_BuildBSPTreeAux( 1 ); + + // create wedge data structures + gobj = OBJODT_CreateWedgeData( gobj, &objmemsize, flags ); + + // enter object into class array + ObjClasses[ gobj->ObjectClass ] = gobj; + + // init class and type data of object + OBJ_InitClass( gobj->ObjectClass ); + + // return mem size of object + return objmemsize; +} + + +// table of textures used by an object ---------------------------------------- +// +struct texused_s { + + dword num; + TextureMap** table; + +} textures_used; + + +// presort object faces on certain attributes --------------------------------- +// +PRIVATE +void OD2_PreSortAttributes( GenObject *obj ) +{ + ASSERT( obj != NULL ); + +#ifndef PARSEC_SERVER + // sort polygons on texture + if ( AUX_OBJ_SORT_POLYS_ON_TEXTURE ) + { + + dword *sortedindexes = obj->SortedPolyList; + + // sort textured faces + for ( unsigned int tid = 0; tid < textures_used.num; tid++ ) { + + // map to compare with + TextureMap *curmap = textures_used.table[ tid ]; + + // process polygon list + Poly *plist = obj->PolyList; + for ( unsigned int pid = 0; pid < obj->NumPolys; pid++, plist++ ) { + + // store index if same texture + if ( obj->FaceList[ plist->FaceIndx ].TexMap == curmap ) { + *sortedindexes++ = pid; + } + ASSERT( ( sortedindexes - obj->SortedPolyList ) <= (int)obj->NumPolys ); + } + } + + // append faces without textures + Poly *plist = obj->PolyList; + for ( unsigned int pid = 0; pid < obj->NumPolys; pid++, plist++ ) { + + // store index if no texture + if ( obj->FaceList[ plist->FaceIndx ].TexMap == NULL ) { + *sortedindexes++ = pid; + } + ASSERT( ( sortedindexes - obj->SortedPolyList ) <= (int)obj->NumPolys ); + } + + ASSERT( ( sortedindexes - obj->SortedPolyList ) == (int)obj->NumPolys ); + + } + else +#endif // !PARSEC_SERVER + { + // ensure the uninitialized list won't be used + obj->SortedPolyList = NULL; + } +} + + +// determine if face is texture mapped ---------------------------------------- +// +PRIVATE +int OD2_FaceTextured( OD2_Face *face ) +{ + return ( ( face->Shading == ( OD2_shad_afftex & OD2_shadmask_base ) ) || + ( face->Shading == ( OD2_shad_ipol1tex & OD2_shadmask_base ) ) || + ( face->Shading == ( OD2_shad_ipol2tex & OD2_shadmask_base ) ) || + ( face->Shading == ( OD2_shad_persptex & OD2_shadmask_base ) ) ); +} + + +// convert od2 shading spec into internal shader spec ------------------------- +// +PRIVATE +void OD2_ConvertShading( GenObject *gobj, dword faceid, OD2_Face *odtface, shader_s *shader ) +{ +#ifdef PARSEC_CLIENT + + ASSERT( gobj != NULL ); + ASSERT( faceid < gobj->NumFaces ); + ASSERT( odtface != NULL ); + + // allow overriding shader specified in file + if ( SetFaceShader( gobj, ACTIVE_LOD, faceid, shader ) ) + return; + + Face *face = &gobj->FaceList[ faceid ]; + + switch ( odtface->Shading ) { + + case ( OD2_shad_ambient & OD2_shadmask_base ): + case ( OD2_shad_flat & OD2_shadmask_base ): + case ( OD2_shad_gouraud & OD2_shadmask_base ): + face->ShadingIter = iter_rgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_USECOLORINDEX; + break; + + case ( OD2_shad_afftex & OD2_shadmask_base ): + case ( OD2_shad_ipol1tex & OD2_shadmask_base ): + case ( OD2_shad_ipol2tex & OD2_shadmask_base ): + face->ShadingIter = iter_texrgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_ENABLETEXTURE | FACE_SHADING_TEXIPOLATE; + break; + + case ( OD2_shad_persptex & OD2_shadmask_base ): + face->ShadingIter = iter_texrgb | iter_overwrite; + face->ShadingFlags = FACE_SHADING_ENABLETEXTURE; + break; + +// case ( OD2_shad_material & OD2_shadmask_base ): +// case ( OD2_shad_texmat & OD2_shadmask_base ): + + default: + PANIC( "invalid OD2 shading specification." ); + } +#endif // PARSEC_CLIENT +} + + +// converts a float as contained in odt2 file into native geomv_t ----------- +// +INLINE +geomv_t OD2_Geomv_in( float value ) +{ + dword tmp = SWAP_32( DW32( value ) ); + return FLOAT_TO_GEOMV( *(float *)&tmp ); +} + + +// create (internal) object from (external) odt2 object ----------------------- +// +PRIVATE +size_t OD2_CreateObject( OD2_Root *cobj, dword flags, shader_s *shader ) +{ + ASSERT( cobj != NULL ); + + // default flags may be requested + if ( flags == OBJLOAD_DEFAULT ) { + flags = OD2_OBJLOAD_DEFAULT; + } + + // currently only version 1.0 valid + if ( ( cobj->major != 1 ) || ( cobj->minor != 0 ) ) { + return FALSE; + } + + // swap important header fields + cobj->rootflags = SWAP_32( cobj->rootflags ); + cobj->rootflags2 = SWAP_32( cobj->rootflags2 ); + cobj->InstanceSize = SWAP_32( cobj->InstanceSize ); + cobj->NumVerts = SWAP_32( cobj->NumVerts ); + cobj->NumPolyVerts = SWAP_32( cobj->NumPolyVerts ); + cobj->NumNormals = SWAP_32( cobj->NumNormals ); + cobj->NumPolys = SWAP_32( cobj->NumPolys ); + cobj->NumFaces = SWAP_32( cobj->NumFaces ); + cobj->NumTextures = SWAP_32( cobj->NumTextures ); + + ASSERT( cobj->InstanceSize == sizeof( OD2_Root ) ); + ASSERT( cobj->NumVerts >= cobj->NumPolyVerts + cobj->NumNormals ); + ASSERT( cobj->NumPolys >= cobj->NumFaces ); + + // new base address for object data + size_t newdatabase = (size_t) cobj; + + // correct header relative pointers in object header to absolute pointers + cobj->NodeList = (OD2_Node *) ( SWAP_32( (size_t)cobj->NodeList ) + newdatabase ); + cobj->Children[ 0 ] = (OD2_Child *) ( SWAP_32( (size_t)cobj->Children[ 0 ] )+ newdatabase ); + cobj->Children[ 1 ] = (OD2_Child *) ( SWAP_32( (size_t)cobj->Children[ 1 ] )+ newdatabase ); + cobj->VertexList = (OD2_Vertex3 *) ( SWAP_32( (size_t)cobj->VertexList ) + newdatabase ); + cobj->PolyList = (OD2_Poly *) ( SWAP_32( (size_t)cobj->PolyList ) + newdatabase ); + cobj->FaceList = (OD2_Face *) ( SWAP_32( (size_t)cobj->FaceList ) + newdatabase ); + + // size of generic header plus size of type specific header + size_t instancesize = OBJ_FetchTypeSize( cobj->ObjectType ); + + // face anim state array may be included at end of instance data + int numfaceanimstates = 0; + ptrdiff_t faceanimstatebase = 0; + if ( flags & OBJLOAD_FACEANIMS ) { + + // default is the number of textures + numfaceanimstates = ( odt_loading_params.max_face_anim_states > 0 ) ? + odt_loading_params.max_face_anim_states : cobj->NumTextures; + + // safeguard + if ( numfaceanimstates > 256 ) { + numfaceanimstates = 256; + } + + size_t alignmentpadding = ( ( instancesize + 3 ) & ~0x03 ) - instancesize; + size_t sz_faceanimstates = numfaceanimstates * sizeof( FaceAnimState ); + + faceanimstatebase = instancesize + alignmentpadding; + instancesize += sz_faceanimstates + alignmentpadding; + } + + // vertex anim state array may be included at end of instance data + int numvtxanimstates = 0; + ptrdiff_t vtxanimstatebase = 0; + if ( flags & OBJLOAD_VTXANIMS ) { + + // default is simply a fixed number + numvtxanimstates = ( odt_loading_params.max_vtx_anim_states > 0 ) ? + odt_loading_params.max_vtx_anim_states : 4; + + // safeguard + if ( numvtxanimstates > 64 ) { + numvtxanimstates = 64; + } + + // number of additional base object info states + int numbases = 1; + + // need space for every lod (instance data will be taken from lod 0) + lodinfo_s *lodinfo = ObjectInfo[ cobj->ObjectClass ].lodinfo; + if ( lodinfo != NULL ) { + ASSERT( lodinfo->numlods > 0 ); + numvtxanimstates *= lodinfo->numlods; + numbases = lodinfo->numlods; + } + + // reserve additional anim states for base object infos (beyond) + size_t alignmentpadding = ( ( instancesize + 3 ) & ~0x03 ) - instancesize; + size_t sz_vtxanimstates = ( numvtxanimstates + numbases ) * sizeof( VtxAnimState ); + + vtxanimstatebase = instancesize + alignmentpadding; + instancesize += sz_vtxanimstates + alignmentpadding; + } + + // calc necessary alignment padding for data (area behind header) + size_t alignmentpadding = ( ( instancesize + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - instancesize; + ASSERT( alignmentpadding <= OBJ_GEOMETRY_ALIGNMENT_VAL ); + + // calc some numbers not available in header + int numpolyvindexs = ( (size_t)cobj->FaceList - (size_t)cobj->PolyList - + cobj->NumPolys * sizeof( OD2_Poly ) ) / sizeof( dword ); + + // reserve an extended face info for every face + int numfaceexinfos = ( numfaceanimstates > 0 ) ? cobj->NumFaces : 0; + + // determine how many dwords to reserve + // for each corner in a polygon + size_t cornersize = 1; + if ( flags & OBJLOAD_POLYCORNERCOLORS ) + cornersize++; + if ( flags & OBJLOAD_POLYWEDGEINDEXES ) + cornersize++; + + // determine sizes of data areas + size_t sz_vertexlist = cobj->NumVerts * sizeof( Vertex3 ); + size_t sz_xvertexlist = cobj->NumVerts * sizeof( Vertex3 ); + size_t sz_svertexlist = cobj->NumVerts * sizeof( SPoint ); + size_t sz_sortedpolylist = cobj->NumPolys * sizeof( dword ); + size_t sz_polylist = cobj->NumPolys * sizeof( Poly ); + size_t sz_polyindexes = numpolyvindexs * sizeof( dword ) * cornersize; + size_t sz_facelist = cobj->NumFaces * sizeof( Face ); + size_t sz_faceextinfo = numfaceexinfos * sizeof( FaceExtInfo ); + size_t sz_vispolylist = cobj->NumPolys * sizeof( dword ); + + // calc data size + size_t datasize = 0; + datasize += sz_vertexlist; // VertexList + datasize += sz_xvertexlist; // X_VertexList + datasize += sz_svertexlist; // S_VertexList + datasize += sz_sortedpolylist; // SortedPolyList + datasize += sz_polylist; // PolyList + datasize += sz_polyindexes; // +poly vertex/wedge indexes + datasize += sz_facelist; // FaceList + datasize += sz_faceextinfo; // +extended face infos + datasize += sz_vispolylist; // VisPolyList + + // calc size of memory block the object will occupy + size_t objmemsize = instancesize + alignmentpadding + datasize; + + // allocate memory for object + char *curobjmem = (char *) ALLOCMEM( objmemsize ); + if ( curobjmem == NULL ) + OUTOFMEM( no_object_mem ); + + // preclear memory + memset( curobjmem, 0, objmemsize ); + + // init pointer to new class + GenObject *gobj = (GenObject *) curobjmem; + + // init header fields + gobj->NextObj = NULL; + gobj->PrevObj = NULL; + gobj->NextVisObj = NULL; + + gobj->ObjectNumber = 0; + gobj->HostObjNumber = 0; + gobj->ObjectType = cobj->ObjectType; + gobj->ObjectClass = cobj->ObjectClass; + gobj->InstanceSize = instancesize; + + gobj->NumVerts = cobj->NumVerts; + gobj->NumPolyVerts = cobj->NumPolyVerts; + gobj->NumNormals = cobj->NumNormals; + gobj->NumPolys = cobj->NumPolys; + gobj->NumFaces = cobj->NumFaces; + + gobj->VertexList = (Vertex3 *) ( (char*)gobj + instancesize + alignmentpadding ); + gobj->X_VertexList = (Vertex3 *) ( (char*)gobj->VertexList + sz_vertexlist ); + gobj->S_VertexList = (SPoint *) ( (char*)gobj->X_VertexList + sz_xvertexlist ); + gobj->SortedPolyList = (dword *) ( (char*)gobj->S_VertexList + sz_svertexlist ); + gobj->PolyList = (Poly *) ( (char*)gobj->SortedPolyList + sz_sortedpolylist ); + gobj->FaceList = (Face *) ( (char*)gobj->PolyList + sz_polylist + sz_polyindexes ); + gobj->VisPolyList = (dword *) ( (char*)gobj->FaceList + sz_facelist + sz_faceextinfo ); + // = ( *) ( (char*)gobj->VisPolyList + sz_vispolylist ); + gobj->AuxList = NULL; + gobj->BSPTree = NULL; + gobj->AuxBSPTree = NULL; + + gobj->NumFaceAnims = numfaceanimstates; + gobj->ActiveFaceAnims = 0; + gobj->FaceAnimStates = ( flags & OBJLOAD_FACEANIMS ) ? + (FaceAnimState *) ( (char*)gobj + faceanimstatebase ) : NULL; + + gobj->NumVtxAnims = numvtxanimstates; + gobj->ActiveVtxAnims = 0; + gobj->VtxAnimStates = ( flags & OBJLOAD_VTXANIMS ) ? + (VtxAnimState *) ( (char*)gobj + vtxanimstatebase ) : NULL; + + dword tmp = SWAP_32( DW32( cobj->BoundingSphere ) ); + float boundrad = *(float *)&tmp; + gobj->BoundingSphere = FLOAT_TO_GEOMV( boundrad ); + gobj->BoundingSphere2 = FLOAT_TO_GEOMV( boundrad * boundrad ); + + // axial bounding box + geomv_t mins[ 3 ]; + geomv_t maxs[ 3 ]; + +#ifdef OD2_BBOX_VALID + + // take bbox from file + for ( int dim = 0; dim < 3; dim++ ) { + mins[ dim ] = FLOAT_TO_GEOMV( cobj->BoundingBox.mins[ dim ] ); + maxs[ dim ] = FLOAT_TO_GEOMV( cobj->BoundingBox.maxs[ dim ] ); + } + +#else + + // init bbox to swapped maximum extents + for ( int dim = 0; dim < 3; dim++ ) { + mins[ dim ] = gobj->BoundingSphere; + maxs[ dim ] = -gobj->BoundingSphere; + } + +#endif + + // init list of vertices + OD2_Vertex3 *odtvtxs = cobj->VertexList; + Vertex3 *genvtxs = gobj->VertexList; + + for ( int vct = gobj->NumVerts; vct > 0; vct--, odtvtxs++, genvtxs++ ) { + + genvtxs->X = OD2_Geomv_in( odtvtxs->X ); + genvtxs->Y = OD2_Geomv_in( odtvtxs->Y ); + genvtxs->Z = OD2_Geomv_in( odtvtxs->Z ); + genvtxs->VisibleFrame = 0; + +#ifndef OD2_BBOX_VALID + + mins[ 0 ] = min( mins[ 0 ], genvtxs->X ); + maxs[ 0 ] = max( maxs[ 0 ], genvtxs->X ); + + mins[ 1 ] = min( mins[ 1 ], genvtxs->Y ); + maxs[ 1 ] = max( maxs[ 1 ], genvtxs->Y ); + + mins[ 2 ] = min( mins[ 2 ], genvtxs->Z ); + maxs[ 2 ] = max( maxs[ 2 ], genvtxs->Z ); +#endif + + } + + // store bounding box via min-max vertices + gobj->BoundingBox[ 0 ].X = mins[ 0 ]; + gobj->BoundingBox[ 0 ].Y = mins[ 1 ]; + gobj->BoundingBox[ 0 ].Z = mins[ 2 ]; + + gobj->BoundingBox[ 1 ].X = maxs[ 0 ]; + gobj->BoundingBox[ 1 ].Y = maxs[ 1 ]; + gobj->BoundingBox[ 1 ].Z = maxs[ 2 ]; + + // init list of polygons + OD2_Poly *odtpolys = cobj->PolyList; + Poly *genpolys = gobj->PolyList; + dword *genindxs = (dword *) ( (char*)gobj->PolyList + sz_polylist ); + + int numindxs = 0; + for ( int pct = gobj->NumPolys; pct > 0; pct--, odtpolys++, genpolys++ ) { + + genpolys->NumVerts = SWAP_32( odtpolys->NumVerts ); + genpolys->FaceIndx = SWAP_32( odtpolys->FaceIndx ); + genpolys->VertIndxs = genindxs; + genpolys->Flags = POLYFLAG_DEFAULT; + odtpolys->VertIndxs = (dword *) ( SWAP_32( (size_t)odtpolys->VertIndxs ) + newdatabase ); + + // grab all vertex indexes + dword *odtindxs = odtpolys->VertIndxs; + for ( int vict = genpolys->NumVerts; vict > 0; vict--, numindxs++ ) { + ASSERT( numindxs < numpolyvindexs ); + *genindxs++ = SWAP_32( *odtindxs ); + odtindxs++; + } + + // skip area reserved for additional corner info + genindxs += genpolys->NumVerts * ( cornersize - 1 ); + } + ASSERT( numindxs == numpolyvindexs ); + + // create temporary texture table + textures_used.num = cobj->NumTextures; + textures_used.table = ( textures_used.num > 0 ) ? (TextureMap **) + ALLOCMEM( textures_used.num * sizeof( TextureMap* ) ) : NULL; + + // init list of faces + OD2_Face *odtfaces = cobj->FaceList; + + unsigned int numtexturesused = 0; + for ( dword faceid = 0; faceid < gobj->NumFaces; faceid++, odtfaces++ ) { + + Face *face = &gobj->FaceList[ faceid ]; + + // swap shading and texname fields + odtfaces->Shading = SWAP_32( odtfaces->Shading ); + odtfaces->TexMap = OD2_FaceTextured( odtfaces ) ? (char *) + ( SWAP_32( (size_t)odtfaces->TexMap ) + newdatabase ) : NULL; + + face->TexMap = OBJODT_FetchTexture( odtfaces->TexMap ); + OD2_ConvertShading( gobj, faceid, odtfaces, shader ); + + face->ExtInfo = NULL; + + face->ColorRGB = SWAP_32( odtfaces->ColorRGB ); + // set unspecified color to white + if ( face->ColorRGB == 0 ) + face->ColorRGB = 0xffffffff; + + face->ColorIndx = SWAP_32( odtfaces->ColorIndx ); + face->FaceNormalIndx = SWAP_32( odtfaces->FaceNormalIndx ); + face->VisibleFrame = VISFRAME_NEVER; + + face->TexXmatrx[0][0] = OD2_Geomv_in( odtfaces->TexXmatrx[0][0] ); + face->TexXmatrx[0][1] = OD2_Geomv_in( odtfaces->TexXmatrx[0][1] ); + face->TexXmatrx[0][2] = OD2_Geomv_in( odtfaces->TexXmatrx[0][2] ); + face->TexXmatrx[0][3] = OD2_Geomv_in( odtfaces->TexXmatrx[0][3] ); + face->TexXmatrx[1][0] = OD2_Geomv_in( odtfaces->TexXmatrx[1][0] ); + face->TexXmatrx[1][1] = OD2_Geomv_in( odtfaces->TexXmatrx[1][1] ); + face->TexXmatrx[1][2] = OD2_Geomv_in( odtfaces->TexXmatrx[1][2] ); + face->TexXmatrx[1][3] = OD2_Geomv_in( odtfaces->TexXmatrx[1][3] ); + face->TexXmatrx[2][0] = OD2_Geomv_in( odtfaces->TexXmatrx[2][0] ); + face->TexXmatrx[2][1] = OD2_Geomv_in( odtfaces->TexXmatrx[2][1] ); + face->TexXmatrx[2][2] = OD2_Geomv_in( odtfaces->TexXmatrx[2][2] ); + face->TexXmatrx[2][3] = OD2_Geomv_in( odtfaces->TexXmatrx[2][3] ); + + if ( face->TexMap != NULL ) { + + // enter texture into list if not used before + ASSERT( textures_used.table != NULL ); + unsigned int tid = 0; + for ( tid = 0; tid < numtexturesused; tid++ ) + if ( textures_used.table[ tid ] == face->TexMap ) + break; + if ( tid == numtexturesused ) { + ASSERT( numtexturesused < textures_used.num ); + textures_used.table[ tid ] = face->TexMap; + numtexturesused++; + } + } + } + +#ifdef PARSEC_CLIENT + + // this will only fire if at least two textures are missing (the first + // missing texture will count texinvalid and therefore not change the count) + if ( numtexturesused != textures_used.num ) { + MSGOUT( "using %d fewer textures for object than specified.", ( textures_used.num - numtexturesused ) ); + } + +#endif // PARSEC_CLIENT + + // create wedge data structures + gobj = OBJODT_CreateWedgeData( gobj, &objmemsize, flags ); + + // perform presorting for face attributes + OD2_PreSortAttributes( gobj ); + + // free temporary texture table + if ( textures_used.table != NULL ) { + FREEMEM( textures_used.table ); + textures_used.table = NULL; + } + + // enter object into class array + ObjClasses[ gobj->ObjectClass ] = gobj; + + // init class and type data of object + OBJ_InitClass( gobj->ObjectClass ); + + // return mem size of object + return objmemsize; +} + + +// temporary tables to store info about object lods --------------------------- +// +static GenObject* object_lod_classes[ MAX_OBJECT_LODS ]; +static size_t object_lod_sizes[ MAX_OBJECT_LODS ]; + + +#ifdef PARSEC_SERVER +//FIXME: HACK: this function must be moved from OBJ_CTRL to a shared module + +// switch object detail level ------------------------------------------------- +// +void OBJ_SwitchObjectLod( GenObject *obj, dword lod ) +{ + ASSERT( obj != NULL ); + ASSERT( lod < obj->NumLodObjects ); + + // store active lod + obj->CurrentLod = lod; + + // retrieve source geometry + ASSERT( obj->LodObjects != NULL ); + GenLodObject *lodobj = obj->LodObjects[ lod ].LodObject; + + // switch geometry + ASSERT( lodobj != NULL ); + obj->NumVerts = lodobj->NumVerts; + obj->NumPolyVerts = lodobj->NumPolyVerts; + obj->NumNormals = lodobj->NumNormals; + obj->VertexList = lodobj->VertexList; + obj->X_VertexList = lodobj->X_VertexList; + obj->S_VertexList = lodobj->S_VertexList; + obj->NumPolys = lodobj->NumPolys; + obj->PolyList = lodobj->PolyList; + obj->NumFaces = lodobj->NumFaces; + obj->FaceList = lodobj->FaceList; + obj->VisPolyList = lodobj->VisPolyList; + obj->SortedPolyList = lodobj->SortedPolyList; + obj->AuxList = lodobj->AuxList; + obj->BSPTree = lodobj->BSPTree; + obj->AuxBSPTree = lodobj->AuxBSPTree; + obj->AuxObject = lodobj->AuxObject; + obj->NumWedges = lodobj->NumWedges; + obj->NumLayers = lodobj->NumLayers; + obj->WedgeFlags = lodobj->WedgeFlags; + obj->WedgeVertIndxs = lodobj->WedgeVertIndxs; + obj->WedgeNormals = lodobj->WedgeNormals; + obj->WedgeColors = lodobj->WedgeColors; + obj->WedgeTexCoords = lodobj->WedgeTexCoords; + obj->WedgeLighted = lodobj->WedgeLighted; + obj->WedgeSpecular = lodobj->WedgeSpecular; + obj->WedgeFogged = lodobj->WedgeFogged; + obj->ActiveFaceAnims = lodobj->ActiveFaceAnims; + obj->ActiveVtxAnims = lodobj->ActiveVtxAnims; +} +#endif // PARSEC_SERVER + + +// merge lod objects into single object --------------------------------------- +// +PRIVATE +size_t InitClassFromODTLods( dword classid ) +{ + ASSERT( classid < MAX_DISTINCT_OBJCLASSES ); + + lodinfo_s *lodinfo = ObjectInfo[ classid ].lodinfo; + ASSERT( lodinfo != NULL ); + + int numlods = lodinfo->numlods; + ASSERT( (dword)numlods <= MAX_OBJECT_LODS ); + + // determine resulting size + size_t objmemsize = 0; + + size_t baseinstancesize = object_lod_classes[ 0 ]->InstanceSize; + size_t lodspecsize = numlods * ( sizeof( GenLodInfo ) + sizeof( GenLodObject ) ); + objmemsize += baseinstancesize + lodspecsize; + int lod = 0; + for ( lod = 0; lod < numlods; lod++ ) { + + GenObject *curobj = object_lod_classes[ lod ]; + ASSERT( curobj != NULL ); + + ASSERT( curobj->NumLodObjects == 0 ); + ASSERT( curobj->LodObjects == NULL ); + + size_t alignmentpadding = ( ( objmemsize + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - objmemsize; + objmemsize += alignmentpadding; + + size_t instancesize = curobj->InstanceSize; + alignmentpadding = ( ( instancesize + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - instancesize; + + objmemsize += object_lod_sizes[ lod ] - instancesize - alignmentpadding; + } + + // allocate memory for object + char *curobjmem = (char *) ALLOCMEM( objmemsize ); + if ( curobjmem == NULL ) + OUTOFMEM( no_object_mem ); + memset( curobjmem, 0, objmemsize ); + + GenObject* gobj = (GenObject *) curobjmem; + GenLodInfo* genlodinfo = (GenLodInfo *) ( curobjmem + baseinstancesize ); + GenLodObject* genlodobject = (GenLodObject *) ( curobjmem + baseinstancesize + numlods * sizeof( GenLodInfo ) ); + + // initialize object + memcpy( gobj, object_lod_classes[ 0 ], baseinstancesize ); + + ptrdiff_t pdiff = (char*)gobj - (char*)object_lod_classes[ 0 ]; + OBJODT_CorrectPointersBaseData( gobj, pdiff, TRUE ); + + gobj->NumLodObjects = numlods; + gobj->LodObjects = genlodinfo; + + size_t curfillofs = baseinstancesize + lodspecsize; + for ( lod = 0; lod < numlods; lod++ ) { + + GenObject *curobj = object_lod_classes[ lod ]; + ASSERT( curobj != NULL ); + + size_t alignmentpadding = ( ( curfillofs + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - curfillofs; + curfillofs += alignmentpadding; + + size_t instancesize = curobj->InstanceSize; + alignmentpadding = ( ( instancesize + OBJ_GEOMETRY_ALIGNMENT_VAL ) + & OBJ_GEOMETRY_ALIGNMENT_MASK ) - instancesize; + // correct pointers + pdiff = (char*)gobj - (char*)curobj; + pdiff += curfillofs - instancesize - alignmentpadding; + OBJODT_CorrectPointersGeomData( curobj, pdiff, FALSE ); + + // copy pointers + GenLodObject *lodobj = &genlodobject[ lod ]; + + lodobj->NumVerts = curobj->NumVerts; + lodobj->NumPolyVerts = curobj->NumPolyVerts; + lodobj->NumNormals = curobj->NumNormals; + lodobj->VertexList = curobj->VertexList; + lodobj->X_VertexList = curobj->X_VertexList; + lodobj->S_VertexList = curobj->S_VertexList; + lodobj->NumPolys = curobj->NumPolys; + lodobj->PolyList = curobj->PolyList; + lodobj->NumFaces = curobj->NumFaces; + lodobj->FaceList = curobj->FaceList; + lodobj->VisPolyList = curobj->VisPolyList; + lodobj->SortedPolyList = curobj->SortedPolyList; + lodobj->AuxList = curobj->AuxList; + lodobj->BSPTree = curobj->BSPTree; + lodobj->AuxBSPTree = curobj->AuxBSPTree; + lodobj->AuxObject = curobj->AuxObject; + lodobj->NumWedges = curobj->NumWedges; + lodobj->NumLayers = curobj->NumLayers; + lodobj->WedgeFlags = curobj->WedgeFlags; + lodobj->WedgeVertIndxs = curobj->WedgeVertIndxs; + lodobj->WedgeNormals = curobj->WedgeNormals; + lodobj->WedgeColors = curobj->WedgeColors; + lodobj->WedgeTexCoords = curobj->WedgeTexCoords; + lodobj->WedgeLighted = curobj->WedgeLighted; + lodobj->WedgeSpecular = curobj->WedgeSpecular; + lodobj->WedgeFogged = curobj->WedgeFogged; + lodobj->ActiveFaceAnims = curobj->ActiveFaceAnims; + lodobj->ActiveVtxAnims = curobj->ActiveVtxAnims; + + // copy data + size_t datasize = object_lod_sizes[ lod ] - instancesize - alignmentpadding; + memcpy( curobjmem + curfillofs, (char*)curobj + instancesize + alignmentpadding, datasize ); + curfillofs += datasize; + + // store info + genlodinfo[ lod ].Flags = 0x0000; + genlodinfo[ lod ].MagTreshold = lodinfo->lodmags[ lod ]; + genlodinfo[ lod ].MinTreshold = lodinfo->lodmins[ lod ]; + genlodinfo[ lod ].LodObject = lodobj; + } + + // init base to lod 0 + // (mandatory due to pointer correction) + OBJ_SwitchObjectLod( gobj, 0 ); + + // set new class pointer + ObjClasses[ classid ] = gobj; + + // return mem size of object + return objmemsize; +} + + +// load a single object from an odt file, insert into global class table ------ +// +PRIVATE +size_t InitClassFromODT( dword classid, dword flags, shader_s *shader ) +{ + ASSERT( classid < MAX_DISTINCT_OBJCLASSES ); + + // determine file size + size_t odtobjsize = SYS_GetFileLength( ObjectInfo[ classid ].file ); + if ( odtobjsize == (dword)-1 ) + FERROR( object_not_found, ObjectInfo[ classid ].file ); + if ( odtobjsize < sizeof( ODT_GenObject ) ) + PERROR( corrupt_object ); + + // allocate temporary memory for odt object + char *odtobjmem = (char *) ALLOCMEM( odtobjsize ); + if ( odtobjmem == NULL ) + OUTOFMEM( no_object_mem ); + + FILE *fp = SYS_fopen( ObjectInfo[ classid ].file, "rb" ); + if ( fp == NULL ) + FERROR( object_not_found, ObjectInfo[ classid ].file ); + + // read odt data in one chunk + if ( SYS_fread( odtobjmem, 1, odtobjsize, fp ) != odtobjsize ) + FERROR( object_readerror, ObjectInfo[ classid ].file ); + + if ( SYS_fclose( fp ) != 0 ) + FERROR( object_readerror, ObjectInfo[ classid ].file ); + + // determine whether file is ODT2 + int isodt2 = ( strcmp( odtobjmem, "ODT2" ) == 0 ); + + // actual object mem size + size_t objmemsize = 0; + + if ( isodt2 ) { + + // init important header fields + OD2_Root *cobj = (OD2_Root *) odtobjmem; + + cobj->ObjectType = ObjectInfo[ classid ].type; + cobj->ObjectClass = classid; + + // convert odt2 to internal object format + objmemsize = OD2_CreateObject( cobj, flags, shader ); + + } else { + + // init important header fields + ODT_GenObject *cobj = (ODT_GenObject *) odtobjmem; + + cobj->ObjectNumber = 0; + cobj->HostObjNumber = 0; + cobj->ObjectType = ObjectInfo[ classid ].type; + cobj->ObjectClass = classid; + + // convert odt to internal object format + objmemsize = ODT_CreateObject( cobj, flags, shader ); + } + + // memory for loaded data is temporary + FREEMEM( odtobjmem ); + + // return actual object mem size + return objmemsize; +} + + +// load object from odt file -------------------------------------------------- +// +int OBJ_LoadODT( dword classid, dword flags, shader_s *shader ) +{ + ASSERT( classid < MAX_DISTINCT_OBJCLASSES ); + + //NOTE: + // object type of specified object class must already + // be valid in the global ObjectInfo[] table before + // calling this function. + + if ( ObjectInfo[ classid ].lodinfo == NULL ) { + + // simply load one object class + return ( InitClassFromODT( classid, flags, shader ) > 0 ); + + } else { + + // fetch info table + lodinfo_s *lodinfo = ObjectInfo[ classid ].lodinfo; + int numlods = lodinfo->numlods; + if ( numlods > MAX_OBJECT_LODS ) { + ASSERT( 0 ); + numlods = MAX_OBJECT_LODS; + } + + // save base filename + char *savebase = ObjectInfo[ classid ].file; + + // load object classes for all lods + int lod = 0; + for ( lod = 0; lod < numlods; lod++ ) { + + // read lod file, init class + ObjectInfo[ classid ].file = lodinfo->filetab[ lod ]; + size_t objmemsize = InitClassFromODT( classid, flags, shader ); + if ( objmemsize == 0 ) { + // return which lod failed + return -lod; + } + + object_lod_classes[ lod ] = ObjClasses[ classid ]; + object_lod_sizes[ lod ] = objmemsize; + } + + // restore base filename + ObjectInfo[ classid ].file = savebase; + + // merge lod objects into single object + size_t objmemsize = InitClassFromODTLods( classid ); + + // free single objects + for ( lod = 0; lod < numlods; lod++ ) { + FREEMEM( object_lod_classes[ lod ] ); + } + + return ( objmemsize > 0 ); + } +} + + + diff --git a/src/libparsec/obj_type.cpp b/src/libparsec/obj_type.cpp new file mode 100644 index 0000000..0d40d21 --- /dev/null +++ b/src/libparsec/obj_type.cpp @@ -0,0 +1,745 @@ +/* + * PARSEC - Object Type Management + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:40 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" +#include "od_class.h" +#include "od_props.h" + +// global externals +#include "globals.h" + +// local module header +#include "obj_type.h" + +// proprietary module headers +#include "obj_cust.h" +#ifdef PARSEC_SERVER + #include "g_main_sv.h" +#else // !PARSEC_SERVER + #include "obj_game.h" +#endif // !PARSEC_SERVER + + + +// flags +#define ALLOW_ONLY_KNOWN_TYPES + + + +// object type information tables -------------------------------------------- +// + +// type init structure for ShipObject +struct ShipObj_TI { + + int MaxDamage; + int MaxShield; + fixed_t MaxSpeed; + int MaxEnergy; + int MaxFuel; + int Weapons; + int Specials; + int MaxNumMissls; + int MaxNumHomMissls; + int MaxNumPartMissls; + int MaxNumMines; + bams_t YawPerRefFrame; + bams_t PitchPerRefFrame; + bams_t RollPerRefFrame; + geomv_t XSlidePerRefFrame; + geomv_t YSlidePerRefFrame; + int SpeedIncPerRefFrame; + int SpeedDecPerRefFrame; + int FireRepeatDelay; + int FireDisableDelay; + int MissileDisableDelay; + geomv_t ObjCamMinDistance; + geomv_t ObjCamMaxDistance; + geomv_t ObjCamStartDist; + bams_t ObjCamStartPitch; + bams_t ObjCamStartYaw; + bams_t ObjCamStartRoll; + + dword Laser1_Class[ 4 ][ 4 ]; + geomv_t Laser1_X[ 4 ][ 4 ]; + geomv_t Laser1_Y[ 4 ][ 4 ]; + geomv_t Laser1_Z[ 4 ][ 4 ]; + + dword Missile1_Class[ 4 ]; + geomv_t Missile1_X[ 4 ]; + geomv_t Missile1_Y[ 4 ]; + geomv_t Missile1_Z[ 4 ]; + + dword Missile2_Class[ 4 ]; + geomv_t Missile2_X[ 4 ]; + geomv_t Missile2_Y[ 4 ]; + geomv_t Missile2_Z[ 4 ]; + + geomv_t Mine1_X; + geomv_t Mine1_Y; + geomv_t Mine1_Z; + + geomv_t Spread_X[ 4 ]; + geomv_t Spread_Y; + geomv_t Spread_Z; + + geomv_t Helix_X; + geomv_t Helix_Y; + geomv_t Helix_Z; + + geomv_t Beam_X[ 4 ]; + geomv_t Beam_Y; + geomv_t Beam_Z; + + geomv_t Fume_X[ 4 ]; + geomv_t Fume_Y; + geomv_t Fume_Z; + +}; + +// type init structure for ProjectileObject +struct ProjectileObj_TI { + + int LifeTimeCount; + fixed_t Speed; + dword HitPoints; + +}; + +// type init structure for TargetMissileObject +struct TargetMissObj_TI { + + dword Latency; + bams_t MaxRotation; + +}; + +// type init structure for ExtraObject +struct ExtraObj_TI { + + int LifeTimeCount; + bams_t SelfRotX; + bams_t SelfRotY; + bams_t SelfRotZ; + +}; + +// type init structure for MineObject +struct MineObj_TI { + + int HitPoints; + int LifeTimeCount; + bams_t SelfRotX; + bams_t SelfRotY; + bams_t SelfRotZ; + +}; + + +// type property init tables + +ShipObj_TI ShipObj_TIs[ NUM_SHIP_TYPES ] = { + + { + SHIP1_MAXDAMAGE, SHIP1_MAXSHIELD, SHIP1_MAX_SPEED, SHIP1_MAX_ENERGY, + SHIP1_MAX_FUEL, SHIP1_WEAPONS, 0, + SHIP1_NUM_MISSLS, SHIP1_NUM_HOMMISSLS, SHIP1_NUM_SWARMMISSLS, SHIP1_NUM_MINES, + SHIP_YAW_PER_REFFRAME, SHIP_PITCH_PER_REFFRAME, SHIP_ROLL_PER_REFFRAME, + SHIP_SLIDE_PER_REFFRAME, SHIP_SLIDE_PER_REFFRAME, SHIP_SPEED_INC_PER_REFFRAME, + SHIP_SPEED_DEC_PER_REFFRAME, SHIP_FIRE_REPEAT_DELAY, SHIP_FIRE_DISABLE_DELAY, + SHIP_MISSILE_DISABLE_DELAY, + SHIP1_OBJCAM_MINDISTANCE, SHIP1_OBJCAM_MAXDISTANCE, SHIP1_OBJCAM_STARTDIST, + SHIP1_OBJCAM_STARTPITCH, SHIP1_OBJCAM_STARTYAW, SHIP1_OBJCAM_STARTROLL, + { { LASER0_CLASS_1, LASER0_CLASS_2, LASER0_CLASS_2, LASER0_CLASS_1 }, + { LASER1_CLASS_1, LASER1_CLASS_1, LASER1_CLASS_1, LASER1_CLASS_1 }, + { LASER2_CLASS_1, LASER2_CLASS_1, LASER2_CLASS_1, LASER2_CLASS_1 }, + { 0, 0, 0, 0 } }, + { { LASER1_START_X_1, LASER1_START_X_2, LASER1_START_X_3, LASER1_START_X_4 }, + { LASER1_START_X_1, LASER1_START_X_2, LASER1_START_X_3, LASER1_START_X_4 }, + { LASER1_START_X_1, LASER1_START_X_2, LASER1_START_X_3, LASER1_START_X_4 }, + { LASER1_START_X_1, LASER1_START_X_2, LASER1_START_X_3, LASER1_START_X_4 } }, + { { LASER1_START_Y, LASER1_START_Y, LASER1_START_Y, LASER1_START_Y }, + { LASER1_START_Y, LASER1_START_Y, LASER1_START_Y, LASER1_START_Y }, + { LASER1_START_Y, LASER1_START_Y, LASER1_START_Y, LASER1_START_Y }, + { LASER1_START_Y, LASER1_START_Y, LASER1_START_Y, LASER1_START_Y } }, + { { LASER1_START_Z, LASER1_START_Z, LASER1_START_Z, LASER1_START_Z }, + { LASER1_START_Z, LASER1_START_Z, LASER1_START_Z, LASER1_START_Z }, + { LASER1_START_Z, LASER1_START_Z, LASER1_START_Z, LASER1_START_Z }, + { LASER1_START_Z, LASER1_START_Z, LASER1_START_Z, LASER1_START_Z } }, + DUMB_CLASS_1, DUMB_CLASS_1, DUMB_CLASS_1, DUMB_CLASS_1, + MISSILE1_START_X_1, MISSILE1_START_X_2, MISSILE1_START_X_3, MISSILE1_START_X_4, + MISSILE1_START_Y, MISSILE1_START_Y, MISSILE1_START_Y, MISSILE1_START_Y, + MISSILE1_START_Z, MISSILE1_START_Z, MISSILE1_START_Z, MISSILE1_START_Z, + GUIDE_CLASS_1, GUIDE_CLASS_1, GUIDE_CLASS_1, GUIDE_CLASS_1, + HOMMISS1_START_X_1, HOMMISS1_START_X_2, HOMMISS1_START_X_3, + HOMMISS1_START_X_4, HOMMISS1_START_Y, HOMMISS1_START_Z, + MINE1_START_X, MINE1_START_Y, MINE1_START_Z, + SPREAD_START_X_1, SPREAD_START_X_2, SPREAD_START_X_3, + SPREAD_START_X_4, SPREAD_START_Y, SPREAD_START_Z, + HELIX_START_X, HELIX_START_Y, HELIX_START_Z, + BEAM_START_X_1, BEAM_START_X_2, BEAM_START_X_3, + BEAM_START_X_4, BEAM_START_Y, BEAM_START_Z, + PROP_FUME_START_X1, PROP_FUME_START_X2, PROP_FUME_START_X3, + PROP_FUME_START_X4, PROP_FUME_START_Y, PROP_FUME_START_Z, + }, + + { + SHIP2_MAXDAMAGE, SHIP2_MAXSHIELD, SHIP2_MAX_SPEED, SHIP2_MAX_ENERGY, + SHIP2_MAX_FUEL, SHIP2_WEAPONS, 0, + SHIP2_NUM_MISSLS, SHIP2_NUM_HOMMISSLS, SHIP2_NUM_SWARMMISSLS, SHIP2_NUM_MINES, + SHIP_YAW_PER_REFFRAME, SHIP_PITCH_PER_REFFRAME, SHIP_ROLL_PER_REFFRAME, + SHIP_SLIDE_PER_REFFRAME, SHIP_SLIDE_PER_REFFRAME, SHIP_SPEED_INC_PER_REFFRAME, + SHIP_SPEED_DEC_PER_REFFRAME, SHIP_FIRE_REPEAT_DELAY, SHIP_FIRE_DISABLE_DELAY, + SHIP_MISSILE_DISABLE_DELAY, + SHIP2_OBJCAM_MINDISTANCE, SHIP2_OBJCAM_MAXDISTANCE, SHIP2_OBJCAM_STARTDIST, + SHIP2_OBJCAM_STARTPITCH, SHIP2_OBJCAM_STARTYAW, SHIP2_OBJCAM_STARTROLL, + { { LASER0_CLASS_1, LASER0_CLASS_2, LASER0_CLASS_2, LASER0_CLASS_1 }, + { LASER1_CLASS_1, LASER1_CLASS_1, LASER1_CLASS_1, LASER1_CLASS_1 }, + { LASER2_CLASS_1, LASER2_CLASS_1, LASER2_CLASS_1, LASER2_CLASS_1 }, + { 0, 0, 0, 0 } }, + { { _2_LASER1_START_X_1, _2_LASER1_START_X_2, _2_LASER1_START_X_3, _2_LASER1_START_X_4 }, + { _2_LASER1_START_X_1, _2_LASER1_START_X_2, _2_LASER1_START_X_3, _2_LASER1_START_X_4 }, + { _2_LASER1_START_X_1, _2_LASER1_START_X_2, _2_LASER1_START_X_3, _2_LASER1_START_X_4 }, + { _2_LASER1_START_X_1, _2_LASER1_START_X_2, _2_LASER1_START_X_3, _2_LASER1_START_X_4 } }, + { { _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y }, + { _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y }, + { _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y }, + { _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y, _2_LASER1_START_Y } }, + { { _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z }, + { _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z }, + { _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z }, + { _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z, _2_LASER1_START_Z } }, + DUMB_CLASS_1, DUMB_CLASS_1, DUMB_CLASS_1, DUMB_CLASS_1, + _2_MISSILE1_START_X_1, _2_MISSILE1_START_X_2, _2_MISSILE1_START_X_3, _2_MISSILE1_START_X_4, + _2_MISSILE1_START_Y, _2_MISSILE1_START_Y, _2_MISSILE1_START_Y, _2_MISSILE1_START_Y, + _2_MISSILE1_START_Z, _2_MISSILE1_START_Z, _2_MISSILE1_START_Z, _2_MISSILE1_START_Z, + GUIDE_CLASS_1, GUIDE_CLASS_1, GUIDE_CLASS_1, GUIDE_CLASS_1, + HOMMISS1_START_X_1, HOMMISS1_START_X_2, HOMMISS1_START_X_3, + HOMMISS1_START_X_4, HOMMISS1_START_Y, HOMMISS1_START_Z, + _2_MINE1_START_X, _2_MINE1_START_Y, _2_MINE1_START_Z, + _2_SPREAD_START_X_1, _2_SPREAD_START_X_2, _2_SPREAD_START_X_3, + _2_SPREAD_START_X_4,_2_SPREAD_START_Y, _2_SPREAD_START_Z, + _2_HELIX_START_X, _2_HELIX_START_Y, _2_HELIX_START_Z, + _2_BEAM_START_X_1, _2_BEAM_START_X_2, _2_BEAM_START_X_3, + _2_BEAM_START_X_4, _2_BEAM_START_Y, _2_BEAM_START_Z, + _2_PROP_FUME_START_X1, _2_PROP_FUME_START_X2, _2_PROP_FUME_START_X3, + _2_PROP_FUME_START_X4, _2_PROP_FUME_START_Y, _2_PROP_FUME_START_Z, + } + +}; + +ProjectileObj_TI ProjectileObj_TIs[ NUM_PROJECTILE_TYPES ] = { + + { LASER1_LIFETIME, LASER1_SPEED, LASER1_HITPOINTS }, + { LASER2_LIFETIME, LASER2_SPEED, LASER2_INTENSITY }, + { LASER3_LIFETIME, LASER3_SPEED, LASER3_THEFTDAMAGE }, + { MISSILE1_LIFETIME, MISSILE1_SPEED, MISSILE1_HITPOINTS }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { HOMMISS1_LIFETIME, HOMMISS1_SPEED, HOMMISS1_HITPOINTS }, + { 0, 0, 0 } + +}; + +TargetMissObj_TI TargetMissObj_TIs[ NUM_TARGETMISSILE_TYPES ] = { + + { HOMMISS1_LATENCY, HOMMISS1_MAX_ROT }, + { 0, 0 } + +}; + +ExtraObj_TI ExtraObj_TIs[ NUM_EXTRA_TYPES - NUM_MINE_TYPES ] = { + + { ENERGYEXTRA_LIFETIME, + ENERGYEXTRA_SELFROTX, ENERGYEXTRA_SELFROTY, ENERGYEXTRA_SELFROTZ }, + { MISSILEEXTRA_LIFETIME, + MISSILEEXTRA_SELFROTX, MISSILEEXTRA_SELFROTY, MISSILEEXTRA_SELFROTZ }, + { DEVICEEXTRA_LIFETIME, + DEVICEEXTRA_SELFROTX, DEVICEEXTRA_SELFROTY, DEVICEEXTRA_SELFROTZ } + +}; + +MineObj_TI MineObj_TIs[ NUM_MINE_TYPES ] = { + + { MINE1_HITPOINTS, MINE1_LIFETIME, + MINE1_SELFROTX, MINE1_SELFROTY, MINE1_SELFROTZ }, + +}; + +int LaserEnergyNeeds[ NUM_LASER_TYPES ] = { + + LASER1_ENERGY, LASER2_ENERGY, LASER3_ENERGY + +}; + + +// names of standard object types --------------------------------------------- +// +PUBLIC +const char *objtype_name[ NUM_DISTINCT_OBJTYPES ] = { + + "*Ship_1*", + "*Ship_2*", + "*Laser_1*", + "*Laser_2*", + "*Laser_3*", + "*Missile_1*", + "*Missile_2*", + "*Missile_3*", + "*Missile_4*", + "*Missile_5*", + "*Extra_1*", + "*Extra_2*", + "*Extra_3*", + "*Mine_1*", +}; + + +// ids of standard object types ----------------------------------------------- +// +PUBLIC +dword objtype_id[ NUM_DISTINCT_OBJTYPES ] = { + + SHIP1TYPE, + SHIP2TYPE, + LASER1TYPE, + LASER2TYPE, + LASER3TYPE, + MISSILE1TYPE, + MISSILE2TYPE, + MISSILE3TYPE, + MISSILE4TYPE, + MISSILE5TYPE, + EXTRA1TYPE, + EXTRA2TYPE, + EXTRA3TYPE, + MINE1TYPE, +}; + + +// structure sizes of standard object types ----------------------------------- +// +PRIVATE +size_t objtype_size[ NUM_DISTINCT_OBJTYPES ] = { + + sizeof( Ship1Obj ), + sizeof( Ship2Obj ), + sizeof( Laser1Obj ), + sizeof( Laser2Obj ), + sizeof( Laser3Obj ), + sizeof( Missile1Obj ), + sizeof( Missile2Obj ), + sizeof( Missile3Obj ), + sizeof( Missile4Obj ), + sizeof( Missile5Obj ), + sizeof( Extra1Obj ), + sizeof( Extra2Obj ), + sizeof( Extra3Obj ), + sizeof( Mine1Obj ), +}; + + +// translate type string to type id ------------------------------------------- +// +dword OBJ_FetchTypeIdFromName( const char* typestr ) +{ + ASSERT( typestr != NULL ); + + //NOTE: + // if the type name cannot be resolved + // TYPE_ID_INVALID will be returned. + + // scan basic type string table + int tid = 0; + for ( tid = 0; tid < NUM_DISTINCT_OBJTYPES; tid++ ) { + + const char *tname = objtype_name[ tid ]; + size_t slen = strlen( tname ); + if ( ( tname[ 0 ] == '*' ) && ( tname[ slen - 1 ] == '*' ) ) { + + ++tname; + const char *scan = NULL; + for ( scan = typestr; *tname != '*'; tname++, scan++ ) + if ( tolower( *tname ) != tolower( *scan ) ) + break; + if ( ( *tname == '*' ) && ( *scan == '\0' ) ) + break; + + } else if ( stricmp( tname, typestr ) == 0 ) { + + break; + } + } + + if ( tid < NUM_DISTINCT_OBJTYPES ) { + + // found basic type + return objtype_id[ tid ]; + + } else { + + // try custom type + return OBJ_FetchCustomTypeId( typestr ); + } +} + + +// fetch instance size of specified type -------------------------------------- +// +size_t OBJ_FetchTypeSize( dword objtypeid ) +{ + dword typebase = objtypeid & TYPENUMBERMASK; + + if ( typebase < NUM_DISTINCT_OBJTYPES ) { + + // simply use table + return objtype_size[ typebase ]; + + } else { + + // scan custom types + return OBJ_FetchCustomTypeSize( objtypeid ); + } +} + + +// init default values for object type (basic initialization) ----------------- +// +void OBJ_InitDefaultTypeFields( GenObject *classpo ) +{ + ASSERT( classpo != NULL ); + + switch ( classpo->ObjectType ) { + + case SHIP1TYPE: + case SHIP2TYPE: + { + + ShipObject *shippo = (ShipObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - + ( SHIP1TYPE & TYPENUMBERMASK ); + + shippo->MaxDamage = ShipObj_TIs[ tno ].MaxDamage; + shippo->CurShield = ShipObj_TIs[ tno ].MaxShield; + shippo->MaxShield = ShipObj_TIs[ tno ].MaxShield; + shippo->MaxSpeed = ShipObj_TIs[ tno ].MaxSpeed; + shippo->CurEnergy = ShipObj_TIs[ tno ].MaxEnergy; + shippo->MaxEnergy = ShipObj_TIs[ tno ].MaxEnergy; + shippo->CurFuel = ShipObj_TIs[ tno ].MaxFuel; + shippo->MaxFuel = ShipObj_TIs[ tno ].MaxFuel; + shippo->Weapons = ShipObj_TIs[ tno ].Weapons; + shippo->Specials = ShipObj_TIs[ tno ].Specials; + shippo->NumMissls = ShipObj_TIs[ tno ].MaxNumMissls; + shippo->NumHomMissls = ShipObj_TIs[ tno ].MaxNumHomMissls; + shippo->NumPartMissls = ShipObj_TIs[ tno ].MaxNumPartMissls; + shippo->NumMines = ShipObj_TIs[ tno ].MaxNumMines; + shippo->MaxNumMissls = ShipObj_TIs[ tno ].MaxNumMissls; + shippo->MaxNumHomMissls = ShipObj_TIs[ tno ].MaxNumHomMissls; + shippo->MaxNumPartMissls = ShipObj_TIs[ tno ].MaxNumPartMissls; + shippo->MaxNumMines = ShipObj_TIs[ tno ].MaxNumMines; + shippo->YawPerRefFrame = ShipObj_TIs[ tno ].YawPerRefFrame; + shippo->PitchPerRefFrame = ShipObj_TIs[ tno ].PitchPerRefFrame; + shippo->RollPerRefFrame = ShipObj_TIs[ tno ].RollPerRefFrame; + shippo->XSlidePerRefFrame = ShipObj_TIs[ tno ].XSlidePerRefFrame; + shippo->YSlidePerRefFrame = ShipObj_TIs[ tno ].YSlidePerRefFrame; + shippo->SpeedIncPerRefFrame = ShipObj_TIs[ tno ].SpeedIncPerRefFrame; + shippo->SpeedDecPerRefFrame = ShipObj_TIs[ tno ].SpeedDecPerRefFrame; + shippo->FireRepeatDelay = ShipObj_TIs[ tno ].FireRepeatDelay; + shippo->FireDisableDelay = ShipObj_TIs[ tno ].FireDisableDelay; + shippo->MissileDisableDelay = ShipObj_TIs[ tno ].MissileDisableDelay; + shippo->ObjCamMinDistance = ShipObj_TIs[ tno ].ObjCamMinDistance; + shippo->ObjCamMaxDistance = ShipObj_TIs[ tno ].ObjCamMaxDistance; + shippo->ObjCamStartDist = ShipObj_TIs[ tno ].ObjCamStartDist; + shippo->ObjCamStartPitch = ShipObj_TIs[ tno ].ObjCamStartPitch; + shippo->ObjCamStartYaw = ShipObj_TIs[ tno ].ObjCamStartYaw; + shippo->ObjCamStartRoll = ShipObj_TIs[ tno ].ObjCamStartRoll; + + shippo->Laser1_Class[ 0 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Class[ 0 ][ 0 ]; + shippo->Laser1_Class[ 0 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Class[ 0 ][ 1 ]; + shippo->Laser1_Class[ 0 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Class[ 0 ][ 2 ]; + shippo->Laser1_Class[ 0 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Class[ 0 ][ 3 ]; + + shippo->Laser1_Class[ 1 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Class[ 1 ][ 0 ]; + shippo->Laser1_Class[ 1 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Class[ 1 ][ 1 ]; + shippo->Laser1_Class[ 1 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Class[ 1 ][ 2 ]; + shippo->Laser1_Class[ 1 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Class[ 1 ][ 3 ]; + + shippo->Laser1_Class[ 2 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Class[ 2 ][ 0 ]; + shippo->Laser1_Class[ 2 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Class[ 2 ][ 1 ]; + shippo->Laser1_Class[ 2 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Class[ 2 ][ 2 ]; + shippo->Laser1_Class[ 2 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Class[ 2 ][ 3 ]; + + shippo->Laser1_Class[ 3 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Class[ 3 ][ 0 ]; + shippo->Laser1_Class[ 3 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Class[ 3 ][ 1 ]; + shippo->Laser1_Class[ 3 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Class[ 3 ][ 2 ]; + shippo->Laser1_Class[ 3 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Class[ 3 ][ 3 ]; + + shippo->Laser1_X[ 0 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_X[ 0 ][ 0 ]; + shippo->Laser1_X[ 0 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_X[ 0 ][ 1 ]; + shippo->Laser1_X[ 0 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_X[ 0 ][ 2 ]; + shippo->Laser1_X[ 0 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_X[ 0 ][ 3 ]; + + shippo->Laser1_X[ 1 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_X[ 1 ][ 0 ]; + shippo->Laser1_X[ 1 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_X[ 1 ][ 1 ]; + shippo->Laser1_X[ 1 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_X[ 1 ][ 2 ]; + shippo->Laser1_X[ 1 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_X[ 1 ][ 3 ]; + + shippo->Laser1_X[ 2 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_X[ 2 ][ 0 ]; + shippo->Laser1_X[ 2 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_X[ 2 ][ 1 ]; + shippo->Laser1_X[ 2 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_X[ 2 ][ 2 ]; + shippo->Laser1_X[ 2 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_X[ 2 ][ 3 ]; + + shippo->Laser1_X[ 3 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_X[ 3 ][ 0 ]; + shippo->Laser1_X[ 3 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_X[ 3 ][ 1 ]; + shippo->Laser1_X[ 3 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_X[ 3 ][ 2 ]; + shippo->Laser1_X[ 3 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_X[ 3 ][ 3 ]; + + shippo->Laser1_Y[ 0 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Y[ 0 ][ 0 ]; + shippo->Laser1_Y[ 0 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Y[ 0 ][ 1 ]; + shippo->Laser1_Y[ 0 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Y[ 0 ][ 2 ]; + shippo->Laser1_Y[ 0 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Y[ 0 ][ 3 ]; + + shippo->Laser1_Y[ 1 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Y[ 1 ][ 0 ]; + shippo->Laser1_Y[ 1 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Y[ 1 ][ 1 ]; + shippo->Laser1_Y[ 1 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Y[ 1 ][ 2 ]; + shippo->Laser1_Y[ 1 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Y[ 1 ][ 3 ]; + + shippo->Laser1_Y[ 2 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Y[ 2 ][ 0 ]; + shippo->Laser1_Y[ 2 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Y[ 2 ][ 1 ]; + shippo->Laser1_Y[ 2 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Y[ 2 ][ 2 ]; + shippo->Laser1_Y[ 2 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Y[ 2 ][ 3 ]; + + shippo->Laser1_Y[ 3 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Y[ 3 ][ 0 ]; + shippo->Laser1_Y[ 3 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Y[ 3 ][ 1 ]; + shippo->Laser1_Y[ 3 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Y[ 3 ][ 2 ]; + shippo->Laser1_Y[ 3 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Y[ 3 ][ 3 ]; + + shippo->Laser1_Z[ 0 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Z[ 0 ][ 0 ]; + shippo->Laser1_Z[ 0 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Z[ 0 ][ 1 ]; + shippo->Laser1_Z[ 0 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Z[ 0 ][ 2 ]; + shippo->Laser1_Z[ 0 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Z[ 0 ][ 3 ]; + + shippo->Laser1_Z[ 1 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Z[ 1 ][ 0 ]; + shippo->Laser1_Z[ 1 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Z[ 1 ][ 1 ]; + shippo->Laser1_Z[ 1 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Z[ 1 ][ 2 ]; + shippo->Laser1_Z[ 1 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Z[ 1 ][ 3 ]; + + shippo->Laser1_Z[ 2 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Z[ 2 ][ 0 ]; + shippo->Laser1_Z[ 2 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Z[ 2 ][ 1 ]; + shippo->Laser1_Z[ 2 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Z[ 2 ][ 2 ]; + shippo->Laser1_Z[ 2 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Z[ 2 ][ 3 ]; + + shippo->Laser1_Z[ 3 ][ 0 ] = ShipObj_TIs[ tno ].Laser1_Z[ 3 ][ 0 ]; + shippo->Laser1_Z[ 3 ][ 1 ] = ShipObj_TIs[ tno ].Laser1_Z[ 3 ][ 1 ]; + shippo->Laser1_Z[ 3 ][ 2 ] = ShipObj_TIs[ tno ].Laser1_Z[ 3 ][ 2 ]; + shippo->Laser1_Z[ 3 ][ 3 ] = ShipObj_TIs[ tno ].Laser1_Z[ 3 ][ 3 ]; + + shippo->Missile1_Class[ 0 ] = ShipObj_TIs[ tno ].Missile1_Class[ 0 ]; + shippo->Missile1_Class[ 1 ] = ShipObj_TIs[ tno ].Missile1_Class[ 1 ]; + shippo->Missile1_Class[ 2 ] = ShipObj_TIs[ tno ].Missile1_Class[ 2 ]; + shippo->Missile1_Class[ 3 ] = ShipObj_TIs[ tno ].Missile1_Class[ 3 ]; + shippo->Missile1_X[ 0 ] = ShipObj_TIs[ tno ].Missile1_X[ 0 ]; + shippo->Missile1_X[ 1 ] = ShipObj_TIs[ tno ].Missile1_X[ 1 ]; + shippo->Missile1_X[ 2 ] = ShipObj_TIs[ tno ].Missile1_X[ 2 ]; + shippo->Missile1_X[ 3 ] = ShipObj_TIs[ tno ].Missile1_X[ 3 ]; + shippo->Missile1_Y[ 0 ] = ShipObj_TIs[ tno ].Missile1_Y[ 0 ]; + shippo->Missile1_Y[ 1 ] = ShipObj_TIs[ tno ].Missile1_Y[ 1 ]; + shippo->Missile1_Y[ 2 ] = ShipObj_TIs[ tno ].Missile1_Y[ 2 ]; + shippo->Missile1_Y[ 3 ] = ShipObj_TIs[ tno ].Missile1_Y[ 3 ]; + shippo->Missile1_Z[ 0 ] = ShipObj_TIs[ tno ].Missile1_Z[ 0 ]; + shippo->Missile1_Z[ 1 ] = ShipObj_TIs[ tno ].Missile1_Z[ 1 ]; + shippo->Missile1_Z[ 2 ] = ShipObj_TIs[ tno ].Missile1_Z[ 2 ]; + shippo->Missile1_Z[ 3 ] = ShipObj_TIs[ tno ].Missile1_Z[ 3 ]; + + shippo->Missile2_Class[ 0 ] = ShipObj_TIs[ tno ].Missile2_Class[ 0 ]; + shippo->Missile2_Class[ 1 ] = ShipObj_TIs[ tno ].Missile2_Class[ 1 ]; + shippo->Missile2_Class[ 2 ] = ShipObj_TIs[ tno ].Missile2_Class[ 2 ]; + shippo->Missile2_Class[ 3 ] = ShipObj_TIs[ tno ].Missile2_Class[ 3 ]; + shippo->Missile2_X[ 0 ] = ShipObj_TIs[ tno ].Missile2_X[ 0 ]; + shippo->Missile2_X[ 1 ] = ShipObj_TIs[ tno ].Missile2_X[ 1 ]; + shippo->Missile2_X[ 2 ] = ShipObj_TIs[ tno ].Missile2_X[ 2 ]; + shippo->Missile2_X[ 3 ] = ShipObj_TIs[ tno ].Missile2_X[ 3 ]; + shippo->Missile2_Y[ 0 ] = ShipObj_TIs[ tno ].Missile2_Y[ 0 ]; + shippo->Missile2_Y[ 1 ] = ShipObj_TIs[ tno ].Missile2_Y[ 1 ]; + shippo->Missile2_Y[ 2 ] = ShipObj_TIs[ tno ].Missile2_Y[ 2 ]; + shippo->Missile2_Y[ 3 ] = ShipObj_TIs[ tno ].Missile2_Y[ 3 ]; + shippo->Missile2_Z[ 0 ] = ShipObj_TIs[ tno ].Missile2_Z[ 0 ]; + shippo->Missile2_Z[ 1 ] = ShipObj_TIs[ tno ].Missile2_Z[ 1 ]; + shippo->Missile2_Z[ 2 ] = ShipObj_TIs[ tno ].Missile2_Z[ 2 ]; + shippo->Missile2_Z[ 3 ] = ShipObj_TIs[ tno ].Missile2_Z[ 3 ]; + + shippo->Mine1_X = ShipObj_TIs[ tno ].Mine1_X; + shippo->Mine1_Y = ShipObj_TIs[ tno ].Mine1_Y; + shippo->Mine1_Z = ShipObj_TIs[ tno ].Mine1_Z; + + shippo->SpreadSpeed = SPREADFIRE_SPEED; + shippo->SpreadLifeTime = SPREADFIRE_LIFETIME; + + shippo->Spread_X[ 0 ] = ShipObj_TIs[ tno ].Spread_X[ 0 ]; + shippo->Spread_X[ 1 ] = ShipObj_TIs[ tno ].Spread_X[ 1 ]; + shippo->Spread_X[ 2 ] = ShipObj_TIs[ tno ].Spread_X[ 2 ]; + shippo->Spread_X[ 3 ] = ShipObj_TIs[ tno ].Spread_X[ 3 ]; + shippo->Spread_Y = ShipObj_TIs[ tno ].Spread_Y; + shippo->Spread_Z = ShipObj_TIs[ tno ].Spread_Z; + + shippo->HelixSpeed = HELIX_SPEED; + shippo->HelixLifeTime = HELIX_LIFETIME; + + shippo->Helix_X = ShipObj_TIs[ tno ].Helix_X; + shippo->Helix_Y = ShipObj_TIs[ tno ].Helix_Y; + shippo->Helix_Z = ShipObj_TIs[ tno ].Helix_Z; + + shippo->PhotonSpeed = PHOTON_SPEED; + shippo->PhotonLifeTime = PHOTON_LIFETIME; + + shippo->Beam_X[ 0 ] = ShipObj_TIs[ tno ].Beam_X[ 0 ]; + shippo->Beam_X[ 1 ] = ShipObj_TIs[ tno ].Beam_X[ 1 ]; + shippo->Beam_X[ 2 ] = ShipObj_TIs[ tno ].Beam_X[ 2 ]; + shippo->Beam_X[ 3 ] = ShipObj_TIs[ tno ].Beam_X[ 3 ]; + shippo->Beam_Y = ShipObj_TIs[ tno ].Beam_Y; + shippo->Beam_Z = ShipObj_TIs[ tno ].Beam_Z; + + shippo->FumeFreq = PROP_FUME_FREQUENCY; + shippo->FumeSpeed = PROP_FUME_SPEED; + shippo->FumeLifeTime = PROP_FUME_LIFETIME; + shippo->FumeCount = 0; + + shippo->Fume_X[ 0 ] = ShipObj_TIs[ tno ].Fume_X[ 0 ]; + shippo->Fume_X[ 1 ] = ShipObj_TIs[ tno ].Fume_X[ 1 ]; + shippo->Fume_X[ 2 ] = ShipObj_TIs[ tno ].Fume_X[ 2 ]; + shippo->Fume_X[ 3 ] = ShipObj_TIs[ tno ].Fume_X[ 3 ]; + shippo->Fume_Y = ShipObj_TIs[ tno ].Fume_Y; + shippo->Fume_Z = ShipObj_TIs[ tno ].Fume_Z; + + shippo->Orbit = NULL; + + shippo->afterburner_previous_speed = 0; + shippo->afterburner_active = FALSE; + shippo->afterburner_energy = AFTERBURNER_ENERGY; + + } + break; + + case LASER1TYPE: + case LASER2TYPE: + case LASER3TYPE: + { + + LaserObject *laserpo = (LaserObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - + ( LASER1TYPE & TYPENUMBERMASK ); + + laserpo->LifeTimeCount = ProjectileObj_TIs[ tno ].LifeTimeCount; + laserpo->Speed = ProjectileObj_TIs[ tno ].Speed; + laserpo->HitPoints = ProjectileObj_TIs[ tno ].HitPoints; + laserpo->EnergyNeeded = LaserEnergyNeeds[ tno ]; + + } + break; + + case MISSILE4TYPE: + { + + TargetMissileObject *targetmisspo = (TargetMissileObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - + ( MISSILE4TYPE & TYPENUMBERMASK ); + + targetmisspo->Latency = TargetMissObj_TIs[ tno ].Latency; + targetmisspo->MaxRotation = TargetMissObj_TIs[ tno ].MaxRotation; + + } + /* FALLTHROUGH */ + + case MISSILE1TYPE: + case MISSILE2TYPE: + case MISSILE3TYPE: + { + + ProjectileObject *projectilepo = (ProjectileObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - + ( LASER1TYPE & TYPENUMBERMASK ); + + projectilepo->LifeTimeCount = ProjectileObj_TIs[ tno ].LifeTimeCount; + projectilepo->Speed = ProjectileObj_TIs[ tno ].Speed; + projectilepo->HitPoints = ProjectileObj_TIs[ tno ].HitPoints; + + } + break; + + case MINE1TYPE: + { + + MineObject *minepo = (MineObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - + ( MINE1TYPE & TYPENUMBERMASK ); + + minepo->LifeTimeCount = MineObj_TIs[ tno ].LifeTimeCount; + minepo->SelfRotX = MineObj_TIs[ tno ].SelfRotX; + minepo->SelfRotY = MineObj_TIs[ tno ].SelfRotY; + minepo->SelfRotZ = MineObj_TIs[ tno ].SelfRotZ; + minepo->HitPoints = MineObj_TIs[ tno ].HitPoints; + minepo->Owner = OWNER_LOCAL_PLAYER; + + } + break; + + case EXTRA1TYPE: + case EXTRA2TYPE: + case EXTRA3TYPE: + { + + ExtraObject *extrapo = (ExtraObject*) classpo; + int tno = ( classpo->ObjectType & TYPENUMBERMASK ) - ( EXTRA1TYPE & TYPENUMBERMASK ); + + extrapo->LifeTimeCount = ExtraObj_TIs[ tno ].LifeTimeCount; + extrapo->SelfRotX = ExtraObj_TIs[ tno ].SelfRotX; + extrapo->SelfRotY = ExtraObj_TIs[ tno ].SelfRotY; + extrapo->SelfRotZ = ExtraObj_TIs[ tno ].SelfRotZ; + extrapo->VisibleFrame_Reset_Frames = 0; + + } + break; + +#ifdef ALLOW_ONLY_KNOWN_TYPES + + default: + PERROR( "unknown object type number: %d.", classpo->ObjectType ); +#endif + + } +} + + + diff --git a/src/libparsec/sl_path.cpp b/src/libparsec/sl_path.cpp new file mode 100644 index 0000000..57b844e --- /dev/null +++ b/src/libparsec/sl_path.cpp @@ -0,0 +1,290 @@ +/* + * PARSEC - Path Processing + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1997-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#ifndef SYSTEM_TARGET_WINDOWS + +// C library +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// POSIX headers +#include <dirent.h> + +// compilation flags/debug support +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// local module header +#include "sl_path.h" + +// proprietary module headers +#ifdef PARSEC_SERVER +#include "con_ext_sv.h" +#include "con_main_sv.h" +#else // !PARSEC_SERVER +#include "con_ext.h" +#include "con_main.h" +#include "e_demo.h" +#endif // !PARSEC_SERVER + + + +// temporary path string ------------------------------------------------------ +// +static char path_string[ PATH_MAX + 1 ]; + + +// process path read from console/script and create valid system path --------- +// +char *SYSs_ProcessPathString( char *path ) +{ + ASSERT( path != NULL ); + + for ( char *scan = path; *scan != 0; scan++ ) { + + // substitute slashes for backslashes + if ( *scan == '\\' ) { + *scan = '/'; + } + } + + return path; +} + + +// scan to file name extension in supplied string ----------------------------- +// +char *SYSs_ScanToExtension( char *fname ) +{ + ASSERT( fname != NULL ); + + char *scan = fname + strlen( fname ); + while ( ( scan != fname ) && ( *scan != '.' ) ) + scan--; + + return scan; +} + + +// strip path (directory names) from file name -------------------------------- +// +char *SYSs_StripPath( char *fname ) +{ + ASSERT( fname != NULL ); + + char *scan = fname + strlen( fname ); + while ( ( scan != fname ) && ( *scan != '/' ) ) + scan--; + + if ( *scan == '/' ) + scan++; + + return scan; +} + + +// temporary storage for path modification ------------------------------------ +// +static char modify_path[ PATH_MAX + 1 ]; + + +// acquire scripts located at specified path ---------------------------------- +// +int SYSs_AcquireScriptPath( char *path, int comtype, char *prefix ) +{ + ASSERT( path != NULL ); + ASSERT( comtype >= 0 ); +// ASSERT( prefix != NULL ); + + // wildcard extension must be supplied + ASSERT( strlen( path ) > 4 ); + + //NOTE: + // this function strips the wildcard from the script path and + // checks the extension manually, since the wildcard extension + // to POSIX's opendir() is apparently not supported under linux. + + // make a copy we can modify + strncpy( modify_path, path, PATH_MAX ); + modify_path[ PATH_MAX ] = 0; + path = modify_path; + + static char con_wcard[] = "*" CON_FILE_EXTENSION; + static char *con_fext = con_wcard + 1; + static size_t wcardlen = strlen( con_wcard ); + + // filter wildcard for console scripts + size_t pathlen = strlen( path ); + if ( pathlen >= wcardlen ) { + if ( stricmp( path + pathlen - wcardlen, con_wcard ) == 0 ) { + path[ pathlen - wcardlen ] = '.'; + path[ pathlen - wcardlen + 1 ] = 0; + } + } + + // open script directory + DIR *dirp = opendir( path ); + + if ( dirp != NULL ) { + + int countbase = num_external_commands; + dirent *direntp; + + // read script names up to maximum number + while ( ( direntp = readdir( dirp ) ) && + ( num_external_commands < MAX_EXTERNAL_COMMANDS ) ) { + + char *prefixed = direntp->d_name; + + if ( prefix != NULL ) { + strcpy( path_string, prefix ); + strcat( path_string, "/" ); + strcat( path_string, direntp->d_name ); + prefixed = SYSs_ProcessPathString( path_string ); + } + + size_t len = strlen( prefixed ) - wcardlen + 1; + + // do manual wildcard checking + if ( len < 1 ) + continue; + if ( stricmp( prefixed + len, con_fext ) != 0 ) + continue; + + // simply skip file names that are too long + if ( len > COMMAND_NAME_ALLOC_LEN ) + continue; + + // store base name + strncpy( external_commands[ num_external_commands ], prefixed, len ); + external_commands[ num_external_commands ][ len ] = 0; + + // set type and convert to lower-case + external_command_types[ num_external_commands ] = comtype; + strlwr( external_commands[ num_external_commands ] ); + + num_external_commands++; + } + + closedir( dirp ); + return ( num_external_commands - countbase ); + } + + return 0; +} + + +// acquire demos located at specified path ------------------------------------ +// +int SYSs_AcquireDemoPath( char *path, char *prefix ) +{ + ASSERT( path != NULL ); +// ASSERT( prefix != NULL ); + + // wildcard extension must be supplied + ASSERT( strlen( path ) > 4 ); + +#ifdef PARSEC_CLIENT + + //NOTE: + // this function strips the wildcard from the demo path and + // checks the extension manually, since the wildcard extension + // to POSIX's opendir() is apparently not supported under linux. + + // make a copy we can modify + strncpy( modify_path, path, PATH_MAX ); + modify_path[ PATH_MAX ] = 0; + path = modify_path; + + static char dem_wcard[] = "*" CON_FILE_COMPILED_EXTENSION; + static char *dem_fext = dem_wcard + 1; + static size_t wcardlen = strlen( dem_wcard ); + + // filter wildcard for demo names + size_t pathlen = strlen( path ); + if ( pathlen >= wcardlen ) { + if ( stricmp( path + pathlen - wcardlen, dem_wcard ) == 0 ) { + path[ pathlen - wcardlen ] = '.'; + path[ pathlen - wcardlen + 1 ] = 0; + } + } + + // open demo directory + DIR *dirp = opendir( path ); + + if ( dirp != NULL ) { + + int countbase = num_registered_demos; + dirent *direntp; + + // read demo names up to maximum number + while ( ( direntp = readdir( dirp ) ) && + ( num_registered_demos < max_registered_demos ) ) { + + long len = strlen( direntp->d_name ) - wcardlen + 1; + + // do manual wildcard checking + if ( len < 1 ) + continue; + if ( stricmp( direntp->d_name + len, dem_fext ) != 0 ) + continue; + + // store demo name + int demoid = num_registered_demos; + if ( registered_demo_names[ demoid ] != NULL ) { + FREEMEM( registered_demo_names[ demoid ] ); + registered_demo_names[ demoid ] = NULL; + } + registered_demo_names[ demoid ] = (char *) ALLOCMEM( len + 1 ); + if ( registered_demo_names[ demoid ] == NULL ) + OUTOFMEM( 0 ); + strncpy( registered_demo_names[ demoid ], direntp->d_name, len ); + registered_demo_names[ demoid ][ len ] = 0; + + // convert to lower-case + strlwr( registered_demo_names[ demoid ] ); + + num_registered_demos++; + } + + closedir( dirp ); + return ( num_registered_demos - countbase ); + } + +#endif // PARSEC_CLIENT + + return 0; +} + +#endif // !SYSTEM_TARGET_WINDOWS + diff --git a/src/libparsec/sl_timer.cpp b/src/libparsec/sl_timer.cpp new file mode 100644 index 0000000..1455729 --- /dev/null +++ b/src/libparsec/sl_timer.cpp @@ -0,0 +1,267 @@ +/* + * PARSEC - Frame Timing + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#ifndef SYSTEM_TARGET_WINDOWS + +// C library includes +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// time functions +#include <sys/time.h> +#include <unistd.h> + +// compilation flags/debug support +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#ifdef PARSEC_CLIENT +#include "aud_defs.h" +#include "inp_defs.h" +#endif //PARSEC_CLIENT +#include "sys_defs.h" + +// local module header +#include "sl_timer.h" + + + +// global variables for frame timing ------------------------------------------ +// +volatile int FrameRate; +volatile int FrameCounter; +volatile int RefTimeCount; +volatile int RefFrameCount; + + +// static timer vars ---------------------------------------------------------- +// +static refframe_t sl_timfreqsec; +static hprec_t sl_timfreqfac; +static int sl_timsecbase; +static int sl_frmsecbase; + + +// reference frame count pausing ---------------------------------------------- +// +static int refframe_count_paused = FALSE; +static refframe_t refframe_count_pauseval = REFFRAME_INVALID; +static refframe_t refframe_count_pauseofs = 0; + + +// base frequency of gettimeofday() is 1MHz ----------------------------------- +// +#define BASE_FREQ 1000000.0 + + +// init frame timing ---------------------------------------------------------- +// +int SYSs_InitFrameTimer() +{ + int static init_done = FALSE; + + if ( init_done ) { + + // get high-precision time + struct timeval time_timeval; + struct timezone time_timezone; + gettimeofday( &time_timeval, &time_timezone ); + + // calc refframe count for old frequency + time_t secframes = ( time_timeval.tv_sec - sl_timsecbase ) * sl_timfreqsec; + refframe_t refframecount = refframe_t( time_timeval.tv_usec * sl_timfreqfac + secframes ); + + // calc correction factor for new frequency + sl_timfreqsec = FRAME_MEASURE_TIMEBASE; + sl_timfreqfac = FRAME_MEASURE_TIMEBASE / BASE_FREQ; + + // calc offset to ensure monotonically increasing refframecount + // even though we now use the new frequency + secframes = ( time_timeval.tv_sec - sl_timsecbase ) * sl_timfreqsec; + RefFrameCount = refframe_t( time_timeval.tv_usec * sl_timfreqfac + secframes ); + refframe_count_pauseofs += RefFrameCount - refframecount; + + } else { + + // calculate factor to adjust to our time quantum + sl_timfreqsec = FRAME_MEASURE_TIMEBASE; + sl_timfreqfac = FRAME_MEASURE_TIMEBASE / BASE_FREQ; + + // set initial count + SYSs_InitRefFrameCount(); + + init_done = TRUE; + } + + return TRUE; +} + + +// deinit frame timing -------------------------------------------------------- +// +int SYSs_KillFrameTimer() +{ + // not needed + return 1; +} + + +// init reference frame counting ---------------------------------------------- +// +void SYSs_InitRefFrameCount() +{ + // secbase for frame rate measurement not set + sl_frmsecbase = -1; + + // get high-precision time + struct timeval time_timeval; + struct timezone time_timezone; + gettimeofday( &time_timeval, &time_timezone ); + + // set base in seconds + sl_timsecbase = (int) time_timeval.tv_sec; + + // calc number of elapsed reference frames + int secframes = int(( time_timeval.tv_sec - sl_timsecbase ) * sl_timfreqsec ); + RefFrameCount = (int)( time_timeval.tv_usec * sl_timfreqfac ) + secframes; + + // init refframe count pausing/offset + refframe_count_paused = FALSE; + refframe_count_pauseval = REFFRAME_INVALID; + refframe_count_pauseofs = 0; +} + + +// get count of current reference frame --------------------------------------- +// +refframe_t SYSs_GetRefFrameCount() +{ + // get high-precision time + struct timeval time_timeval; + struct timezone time_timezone; + gettimeofday( &time_timeval, &time_timezone ); + + // calc number of elapsed reference frames + int secframes = int(( time_timeval.tv_sec - sl_timsecbase ) * sl_timfreqsec ); + RefFrameCount = (int)( time_timeval.tv_usec * sl_timfreqfac ) + secframes; + + return RefFrameCount - refframe_count_pauseofs; +} + + +// pause reference frame counting --------------------------------------------- +// +void SYSs_PauseRefFrameCount() +{ + if ( !refframe_count_paused ) { + + SYSs_GetRefFrameCount(); + + refframe_count_pauseval = RefFrameCount; + refframe_count_paused = TRUE; + } +} + + +// resume reference frame counting -------------------------------------------- +// +void SYSs_ResumeRefFrameCount() +{ + if ( refframe_count_paused ) { + + SYSs_GetRefFrameCount(); + + refframe_count_pauseofs += RefFrameCount - refframe_count_pauseval; + refframe_count_pauseval = REFFRAME_INVALID; + refframe_count_paused = FALSE; + } +} + + +// wait for specified number of reference frames ------------------------------ +// +void SYSs_Wait( refframe_t refframes ) +{ + int basecount = SYSs_GetRefFrameCount(); + + while ( SYSs_GetRefFrameCount() - basecount < refframes ) { + SYSs_Yield(); + } +} + + +// use yield function to calculate frame rate --------------------------------- +// +int SYSs_Yield() +{ + +#ifdef PARSEC_CLIENT + + // yield to sound driver + AUDs_MaintainSound(); + + // must be called to retrieve key strokes from buffer + INPs_Collect(); + +#endif // PARSEC_CLIENT + + // get high-precision time + struct timeval time_timeval; + struct timezone time_timezone; + gettimeofday( &time_timeval, &time_timezone ); + + // set base if not done yet + if ( sl_frmsecbase == -1 ) { + sl_frmsecbase = time_timeval.tv_sec; + } + + // flush framecounter every second + if ( ( time_timeval.tv_sec - sl_frmsecbase ) > 0 ) { + sl_frmsecbase = time_timeval.tv_sec; + FrameRate = FrameCounter; + FrameCounter = 0; + } + + return 1; +} + + +#ifdef PARSEC_SERVER + +REGISTER_MODULE( SL_TIMER ) +{ + SYSs_InitFrameTimer(); +} + +#endif + +#endif // !SYSTEM_TARGET_WINDOWS diff --git a/src/libparsec/sw_path.cpp b/src/libparsec/sw_path.cpp new file mode 100644 index 0000000..9369d6b --- /dev/null +++ b/src/libparsec/sw_path.cpp @@ -0,0 +1,346 @@ +/* + * PARSEC - Path Processing + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1997-1999 + * Copyright (c) Clemens Beer <cbx@parsec.org> 1998 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#ifdef SYSTEM_TARGET_WINDOWS + +// C library +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef SYSTEM_COMPILER_GCC +// POSIX headers +#include <dirent.h> +#endif + +// compilation flags/debug support +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// i/o system calls +#include "sys_io.h" + +// local module header +#include "sw_path.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + #include "con_ext_sv.h" +#else // !PARSEC_SERVER + #include "con_ext.h" + #include "e_demo.h" +#endif // !PARSEC_SERVER + + + + +// temporary path string ------------------------------------------------------ +// +static char path_string[ PATH_MAX + 1 ]; + + +// process path read from console/script and create valid system path --------- +// +char *SYSs_ProcessPathString( char *path ) +{ + ASSERT( path != NULL ); + + for ( char *scan = path; *scan != 0; scan++ ) { + + // substitute backslashes for slashes + if ( *scan == '/' ) { + *scan = '\\'; + } + } + + return path; +} + + +// scan to file name extension in supplied string ----------------------------- +// +char *SYSs_ScanToExtension( char *fname ) +{ + ASSERT( fname != NULL ); + + char *scan = fname + strlen( fname ); + while ( ( scan != fname ) && ( *scan != '.' ) ) + scan--; + + return scan; +} + + +// strip path (directory names) from file name -------------------------------- +// +char *SYSs_StripPath( char *fname ) +{ + ASSERT( fname != NULL ); + + char *scan = fname + strlen( fname ); + while ( ( scan != fname ) && ( *scan != '\\' ) ) + scan--; + + if ( *scan == '\\' ) + scan++; + + return scan; +} + + +// acquire scripts located at specified path ---------------------------------- +// +int SYSs_AcquireScriptPath( char *path, int comtype, char *prefix ) +{ + ASSERT( path != NULL ); + ASSERT( comtype >= 0 ); +// ASSERT( prefix != NULL ); + + // wildcard extension must be supplied + ASSERT( strlen( path ) > 4 ); + +#ifdef SYSTEM_COMPILER_MSVC + + // open script directory + struct _finddata_t c_file; + long hFile = _findfirst( path, &c_file ); + + if ( hFile != -1L ) { + + int countbase = num_external_commands; + + while ( num_external_commands < MAX_EXTERNAL_COMMANDS ) { + + char *prefixed = c_file.name; + + if ( prefix != NULL ) { + strcpy( path_string, prefix ); + strcat( path_string, "/" ); + strcat( path_string, c_file.name ); + prefixed = SYSs_ProcessPathString( path_string ); + } + + // skip extension + int len = strlen( prefixed ) - 4; + ASSERT( len >= 0 ); + + // release-safe; simply skip file names that are too long + if ( ( len >= 0 ) && ( len <= COMMAND_NAME_ALLOC_LEN ) ) { + + // store base name + strncpy( external_commands[ num_external_commands ], prefixed, len ); + external_commands[ num_external_commands ][ len ] = 0; + + // set type and convert to lower-case + external_command_types[ num_external_commands ] = comtype; + strlwr( external_commands[ num_external_commands ] ); + + num_external_commands++; + } + + if ( _findnext( hFile, &c_file ) != 0 ) { + break; + } + } + + _findclose( hFile ); + return ( num_external_commands - countbase ); + } + +#else // SYSTEM_COMPILER_MSVC + + // open script directory + DIR *dirp = opendir( path ); + + if ( dirp != NULL ) { + + int countbase = num_external_commands; + dirent *direntp; + + // read script names up to maximum number + while ( ( direntp = readdir( dirp ) ) && + ( num_external_commands < MAX_EXTERNAL_COMMANDS ) ) { + + char *prefixed = direntp->d_name; + + if ( prefix != NULL ) { + strcpy( path_string, prefix ); + strcat( path_string, "/" ); + strcat( path_string, direntp->d_name ); + prefixed = SYSs_ProcessPathString( path_string ); + } + + // skip extension + int len = strlen( prefixed ) - 4; + ASSERT( len >= 0 ); + + // release-safe + if ( len < 0 ) + continue; + + // simply skip file names that are too long + if ( len > COMMAND_NAME_ALLOC_LEN ) + continue; + + // store base name + strncpy( external_commands[ num_external_commands ], prefixed, len ); + external_commands[ num_external_commands ][ len ] = 0; + + // set type and convert to lower-case + external_command_types[ num_external_commands ] = comtype; + strlwr( external_commands[ num_external_commands ] ); + + num_external_commands++; + } + + closedir( dirp ); + return ( num_external_commands - countbase ); + } + +#endif // SYSTEM_COMPILER_MSVC + + return 0; +} + + +// acquire demos located at specified path ------------------------------------ +// +int SYSs_AcquireDemoPath( char *path, char *prefix ) +{ + ASSERT( path != NULL ); +// ASSERT( prefix != NULL ); + + // wildcard extension must be supplied + ASSERT( strlen( path ) > 4 ); + +#ifdef PARSEC_CLIENT + +#ifdef SYSTEM_COMPILER_MSVC + + // open demo directory + struct _finddata_t c_file; + long hFile = _findfirst( path, &c_file ); + + if ( hFile != -1L ) { + + int countbase = num_registered_demos; + + while ( num_registered_demos < max_registered_demos ) { + + // skip extension + int len = strlen( c_file.name ) - 4; + ASSERT( len >= 0 ); + + // release-safe + if ( len >= 0 ) { + + // store demo name + int demoid = num_registered_demos; + if ( registered_demo_names[ demoid ] != NULL ) { + FREEMEM( registered_demo_names[ demoid ] ); + registered_demo_names[ demoid ] = NULL; + } + registered_demo_names[ demoid ] = (char *) ALLOCMEM( len + 1 ); + if ( registered_demo_names[ demoid ] == NULL ) + OUTOFMEM( 0 ); + strncpy( registered_demo_names[ demoid ], c_file.name, len ); + registered_demo_names[ demoid ][ len ] = 0; + + // convert to lower-case + strlwr( registered_demo_names[ demoid ] ); + + num_registered_demos++; + } + + if ( _findnext( hFile, &c_file ) != 0 ) { + break; + } + } + + _findclose( hFile ); + return ( num_registered_demos - countbase ); + } + +#else // !SYSTEM_COMPILER_MSVC + + // open demo directory + DIR *dirp = opendir( path ); + + if ( dirp != NULL ) { + + int countbase = num_registered_demos; + dirent *direntp; + + // read demo names up to maximum number + while ( ( direntp = readdir( dirp ) ) && + ( num_registered_demos < max_registered_demos ) ) { + + // skip extension + int len = strlen( direntp->d_name ) - 4; + ASSERT( len >= 0 ); + + // release-safe + if ( len < 0 ) + continue; + + // store demo name + int demoid = num_registered_demos; + if ( registered_demo_names[ demoid ] != NULL ) { + FREEMEM( registered_demo_names[ demoid ] ); + registered_demo_names[ demoid ] = NULL; + } + registered_demo_names[ demoid ] = (char *) ALLOCMEM( len + 1 ); + if ( registered_demo_names[ demoid ] == NULL ) + OUTOFMEM( 0 ); + strncpy( registered_demo_names[ demoid ], direntp->d_name, len ); + registered_demo_names[ demoid ][ len ] = 0; + + // convert to lower-case + strlwr( registered_demo_names[ demoid ] ); + + num_registered_demos++; + } + + closedir( dirp ); + return ( num_registered_demos - countbase ); + } + +#endif // !SYSTEM_COMPILER_MSVC + +#endif // PARSEC_CLIENT + + return 0; +} + + +#endif // SYSTEM_TARGET_WINDOWS diff --git a/src/libparsec/sw_timer.cpp b/src/libparsec/sw_timer.cpp new file mode 100755 index 0000000..78d73ed --- /dev/null +++ b/src/libparsec/sw_timer.cpp @@ -0,0 +1,232 @@ +/* + * PARSEC - Frame Timing + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-2000 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#ifdef SYSTEM_TARGET_WINDOWS + +// C library includes +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// time functions + +// compilation flags/debug support +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#ifdef PARSEC_CLIENT +#include "aud_defs.h" +#include "inp_defs.h" +#endif //PARSEC_CLIENT +#include "sys_defs.h" + +// windows headers +#include <windows.h> + +// local module header +#include "sw_timer.h" + + + +// global variables for frame timing ------------------------------------------ +// +volatile int FrameRate; +volatile int FrameCounter; +volatile int RefTimeCount; +volatile int RefFrameCount; + + +// timer vars ----------------------------------------------------------------- +// +MMRESULT sw_SecTimerID; // ID of the timer that is called each second +__int64 sw_curTimer; // current timer value +hprec_t sw_dTimerFreqFac; // factor from timer to refframes +__int64 sw_TimerFreq; // frequency of performance timer + + +// reference frame count pausing ---------------------------------------------- +// +static int refframe_count_paused = FALSE; +static refframe_t refframe_count_pauseval = REFFRAME_INVALID; +static refframe_t refframe_count_pauseofs = 0; + + +// callback for Sec.Timer to set the current framerate ----------------------- +// +void CALLBACK +SW_SecTimeProc( UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2 ) +{ + FrameRate = FrameCounter; + FrameCounter = 0; +} + + +// init frame timer handler --------------------------------------------------- +// +int SYSs_InitFrameTimer() +{ + int static init_done = FALSE; + + if ( init_done ) { + + // calc refframe count for old frequency + QueryPerformanceCounter( (LARGE_INTEGER*) &sw_curTimer ); + refframe_t refframecount = (int) ( sw_curTimer * sw_dTimerFreqFac ); + + // calc correction factor for new frequency + sw_dTimerFreqFac = (hprec_t)FRAME_MEASURE_TIMEBASE / sw_TimerFreq; + + // calc offset to ensure monotonically increasing refframecount + // even though we now use the new frequency + RefFrameCount = (int) ( sw_curTimer * sw_dTimerFreqFac ); + refframe_count_pauseofs += RefFrameCount - refframecount; + + } else { + + // query the frequency of the performance counter and calculate + // the factor to adjust to our FRAME_MEASURE_TIMEBASE + QueryPerformanceFrequency( (LARGE_INTEGER *) &sw_TimerFreq ); + sw_dTimerFreqFac = (hprec_t)FRAME_MEASURE_TIMEBASE / sw_TimerFreq; + + // create the timer which is called every second + sw_SecTimerID = timeSetEvent( 1000, 0, &SW_SecTimeProc, 0, TIME_PERIODIC ); + + // set initial count + SYSs_InitRefFrameCount(); + + init_done = TRUE; + } + + return 1; +} + + +// de-init frame timer handler ------------------------------------------------ +// +int SYSs_KillFrameTimer() +{ + // terminate the seconds timer + timeKillEvent( sw_SecTimerID ); + + return 1; +} + + +// init reference frame counting ---------------------------------------------- +// +void SYSs_InitRefFrameCount() +{ + SYSs_GetRefFrameCount(); + + // init refframe count pausing/offset + refframe_count_paused = FALSE; + refframe_count_pauseval = REFFRAME_INVALID; + refframe_count_pauseofs = 0; +} + + +// get count of current reference frame --------------------------------------- +// +refframe_t SYSs_GetRefFrameCount() +{ + QueryPerformanceCounter( (LARGE_INTEGER*) &sw_curTimer ); + RefFrameCount = (int) ( sw_curTimer * sw_dTimerFreqFac ); + + return RefFrameCount - refframe_count_pauseofs; +} + + +// pause reference frame counting --------------------------------------------- +// +void SYSs_PauseRefFrameCount() +{ + if ( !refframe_count_paused ) { + + SYSs_GetRefFrameCount(); + + refframe_count_pauseval = RefFrameCount; + refframe_count_paused = TRUE; + } +} + + +// resume reference frame counting -------------------------------------------- +// +void SYSs_ResumeRefFrameCount() +{ + if ( refframe_count_paused ) { + + SYSs_GetRefFrameCount(); + + refframe_count_pauseofs += RefFrameCount - refframe_count_pauseval; + refframe_count_pauseval = REFFRAME_INVALID; + refframe_count_paused = FALSE; + } +} + + +// wait for specified number of reference frames ------------------------------ +// +void SYSs_Wait( refframe_t refframes ) +{ + refframe_t basecount = SYSs_GetRefFrameCount(); + + while ( SYSs_GetRefFrameCount() - basecount < refframes ) { + SYSs_Yield(); + } +} + + +// guaranteed to be called once per frame ------------------------------------- +// +int SYSs_Yield() +{ +#ifdef PARSEC_CLIENT + + // yield to sound driver + AUDs_MaintainSound(); + + // must be called to retrieve key strokes from buffer + INPs_Collect(); + +#endif // PARSEC_CLIENT + + return 1; +} + +#ifdef PARSEC_SERVER + +REGISTER_MODULE( SW_TIMER ) +{ + SYSs_InitFrameTimer(); +} + +#endif // PARSEC_SERVER + +#endif // SYSTEM_TARGET_WINDOWS diff --git a/src/libparsec/sys_date.cpp b/src/libparsec/sys_date.cpp new file mode 100644 index 0000000..a68c2ee --- /dev/null +++ b/src/libparsec/sys_date.cpp @@ -0,0 +1,124 @@ +/* + * PARSEC - Build Info + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// local module header +#include "sys_date.h" + + + +// determine target system + +#if defined( SYSTEM_TARGET_WINDOWS ) + #define SYSTEM_TEXT "/windows " +#elif defined( SYSTEM_TARGET_LINUX ) + #define SYSTEM_TEXT "/linux " +#elif defined( SYSTEM_TARGET_OSX ) + #define SYSTEM_TEXT "/osx " +#else + #define SYSTEM_TEXT "/unknown " +#endif + + +// determine build + +#ifdef DEBUG + #define BUILD_TEXT "openparsec" SYSTEM_TEXT "debug build " CLIENT_BUILD_NUMBER +#else + #define BUILD_TEXT "openparsec" SYSTEM_TEXT "release build " CLIENT_BUILD_NUMBER +#endif + + +// helper macros + +#define BUILD_STR(x) #x +#define BUILD_VER(x) BUILD_STR(x) + + +// determine compiler + +#if defined( SYSTEM_COMPILER_MSVC ) + #define BUILD_COMPILER "compiler: microsoft visual c++ (" BUILD_VER(_MSC_VER) ")" +#elif defined( SYSTEM_COMPILER_CLANG ) + #define BUILD_COMPILER "compiler: clang " BUILD_VER(__clang_major__.__clang_minor__.__clang_patchlevel__) +#elif defined( SYSTEM_COMPILER_LLVM_GCC ) + #define BUILD_COMPILER "compiler: llvm-gcc " BUILD_VER(__GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__) +#elif defined( SYSTEM_COMPILER_GCC ) + #define BUILD_COMPILER "compiler: gnu c++ " BUILD_VER(__GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__) +#else + #error "unsupported compiler!" +#endif + + +// determine binding + +#define BUILD_BINDING "subsystem binding: static" + + +// determine endianness + +#if defined( SYSTEM_BIG_ENDIAN ) + #define BUILD_ENDIANNESS "endianness: big endian" +#else + #define BUILD_ENDIANNESS "endianness: little endian" +#endif + + +//NOTE: +// create build information. +// this module is compiled on every make/build to +// ensure build information is always up to date. + +const char build_text[] = BUILD_TEXT; +const char build_date[] = __DATE__; +const char build_time[] = __TIME__; + +const char build_comp[] = BUILD_COMPILER; +const char build_bind[] = BUILD_BINDING; +const char build_endn[] = BUILD_ENDIANNESS; + + + +// return current system date and time ---------------------------------------- +// +char *SYS_SystemTime() +{ + // fetch system time + time_t curtime = time( NULL ); + char * timestr = ctime( &curtime ); + + return timestr; +} + + + diff --git a/src/libparsec/sys_file.cpp b/src/libparsec/sys_file.cpp new file mode 100644 index 0000000..65f0541 --- /dev/null +++ b/src/libparsec/sys_file.cpp @@ -0,0 +1,892 @@ +/* + * PARSEC - File System Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:46 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2001 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "gd_heads.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// i/o system calls +#include "sys_io.h" + +// local module header +#include "sys_file.h" + +// proprietary module headers +#ifdef PARSEC_SERVER + #include "con_aux_sv.h" + #include "con_ext_sv.h" + #include "con_main_sv.h" +#else // !PARSEC_SERVER + #include "con_aux.h" + #include "con_ext.h" + #include "con_main.h" + #include "e_demo.h" +#endif // !PARSEC_SERVER + + +#include "sys_path.h" +#include "sys_swap.h" + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + + +// default maximum number of data packages ------------------------------------ +// +#define DEFAULT_MAX_PACKAGES 32 + + +// current and maximum number of data packages -------------------------------- +// +PUBLIC int num_data_packages = 0; +static int max_data_packages = DEFAULT_MAX_PACKAGES; + + +// data package info tables --------------------------------------------------- +// +PUBLIC char* package_filename[ DEFAULT_MAX_PACKAGES ]; +static size_t package_filebase[ DEFAULT_MAX_PACKAGES ]; +static packageheader_s package_header[ DEFAULT_MAX_PACKAGES ]; +static pfileinfo_s* package_items[ DEFAULT_MAX_PACKAGES ]; +static size_t package_headersize[ DEFAULT_MAX_PACKAGES ]; +static size_t package_numitems[ DEFAULT_MAX_PACKAGES ]; + + +// register a data package ---------------------------------------------------- +// +int SYS_RegisterPackage( const char *packname, size_t baseofs, char *prefix ) +{ + ASSERT( packname != NULL ); +// ASSERT( prefix != NULL ); + + // guard against overflow + if ( num_data_packages >= max_data_packages ) { + return FALSE; + } + + int packid = num_data_packages; + + // may be necessary if error occurred earlier on + if ( package_filename[ packid ] != NULL ) { + FREEMEM( package_filename[ packid ] ); + package_filename[ packid ] = NULL; + } + + // must be done here since it is not required of the caller to convert the + // supplied path prior to calling this function (to ease mod registration) + char *path = SYSs_ProcessPathString( (char*)packname ); + + // alloc filename + package_filename[ packid ] = (char *) ALLOCMEM( strlen( path ) + 1 ); + if ( package_filename[ packid ] == NULL ) { + return FALSE; + } + + // store base info + strcpy( package_filename[ packid ], path ); + package_filebase[ packid ] = baseofs; + + // open for reading at specified offset + FILE *fp = fopen( package_filename[ packid ], "rb" ); + if ( fp == NULL ) { + return FALSE; + } + if ( fseek( fp, package_filebase[ packid ], SEEK_SET ) != 0 ) { + fclose( fp ); + return FALSE; + } + + // read fixed-size part of header + size_t bytesread = fread( &package_header[ packid ], 1, sizeof( packageheader_s ), fp ); + if ( bytesread != sizeof( packageheader_s ) ) { + fclose( fp ); + return FALSE; + } + + // swap endianness of fixed-size part of header + SYS_SwapPackageHeader( &package_header[ packid ] ); + + // fetch size of remaining header and number of contained items + package_headersize[ packid ] = package_header[ packid ].headersize; + package_numitems[ packid ] = package_header[ packid ].numitems; + + // may be necessary if error occurred earlier on + if ( package_items[ packid ] != NULL ) { + FREEMEM( package_items[ packid ] ); + package_items[ packid ] = NULL; + } + + // read file list + pfileinfodisk_s *diskitems = (pfileinfodisk_s *) ALLOCMEM( package_headersize[ packid ] ); + if ( diskitems == NULL ) { + fclose( fp ); + return FALSE; + } + bytesread = fread( diskitems, 1, package_headersize[ packid ], fp ); + if ( bytesread != package_headersize[ packid ] ) { + fclose( fp ); + return FALSE; + } + + // swap endianness of file info list + pfileinfodisk_s *items = diskitems; + unsigned int curit = 0; + for ( curit = 0; curit < package_numitems[ packid ]; curit++ ) { + SYS_SwapPFileInfo( &items[ curit ] ); + } + + fclose( fp ); + num_data_packages++; + + // copy file info list for use in memory + package_items[ packid ] = (pfileinfo_s *) ALLOCMEM( package_numitems[ packid ] * sizeof( pfileinfo_s ) ); + if ( package_items[ packid ] == NULL ) { + return FALSE; + } + + char *prefixpath = NULL; + if ( prefix != NULL ) { + + // must be done to ensure files containing path delimiters + // can be found later on when comparing with paths that have + // also been processed to match the host system conventions + strncpy( paste_str, prefix, PASTE_STR_LEN - 1 ); + paste_str[ PASTE_STR_LEN - 1 ] = 0; + strcat( paste_str, "/" ); + prefixpath = SYSs_ProcessPathString( paste_str ); + } + + int sizenames = 0; + size_t prefixlen = ( prefixpath != NULL ) ? ( strlen( prefixpath ) + 1 ) : 0; + + // count total storage amount for filenames + for ( curit = 0; curit < package_numitems[ packid ]; curit++ ) { + sizenames += prefixlen + strlen( diskitems[ curit ].file ) + 1; + } + + // allocate filename storage + char *namelist = (char *) ALLOCMEM( sizenames ); + if ( namelist == NULL ) { + return FALSE; + } + + // copy filenames into storage and pfileinfodisk_s into pfileinfo_s + for ( curit = 0; curit < package_numitems[ packid ]; curit++ ) { + + if ( prefix == NULL || prefixpath == NULL ) { + strcpy( namelist, diskitems[ curit ].file ); + } else { + strcpy( namelist, prefixpath ); + strcat( namelist, diskitems[ curit ].file ); + } + + pfileinfodisk_s * diskitem = &diskitems[ curit ]; + + package_items[ packid ][ curit ].file = namelist; + package_items[ packid ][ curit ].foffset = diskitem->foffset; + package_items[ packid ][ curit ].flength = diskitem->flength; + package_items[ packid ][ curit ].fp = (FILE *) diskitem->fp; + package_items[ packid ][ curit ].fcurpos = diskitem->fcurpos; + + namelist += prefixlen + strlen( diskitems[ curit ].file ) + 1; + } + + FREEMEM( diskitems ); + + return TRUE; +} + + +// override all files in old package with newer versions in new package ------- +// +int SYS_OverridePackage( const char* oldpackname, const char* newpackname ) +{ + //NOTE: + // packages must have already been registered + + int oldid = -1; + int newid = -1; + + // find old package + for ( int packid = 0; packid < num_data_packages; packid++ ) { + + if ( stricmp( package_filename[ packid ], oldpackname ) == 0 ) { + + oldid = packid; + + } else if ( stricmp( package_filename[ packid ], newpackname ) == 0 ) { + + newid = packid; + } + } + + // packages must exist and be different + ASSERT( oldid != -1 ); + ASSERT( newid != -1 ); + ASSERT( newid != oldid ); + + if ( oldid == -1 || + newid == -1 || + oldid == newid ) { + return FALSE; + } + + // replace all items found in both packages with a dummy name in old package + + pfileinfo_s *newitems = package_items[ newid ]; + + // scan all items of new package + for ( unsigned int curit = 0; curit < package_numitems[ newid ]; curit++ ) { + + // scan all items of old package + pfileinfo_s *olditems = package_items[ oldid ]; + + for ( unsigned int curoldit = 0; curoldit < package_numitems[ oldid ]; curoldit++ ) { + + if ( stricmp( newitems[ curit ].file, olditems[ curoldit ].file ) == 0 ) { + + strcpy( olditems[ curoldit ].file, "dummy.old" ); + } + } + } + + return TRUE; +} + + +// acquire scripts contained in package files --------------------------------- +// +int SYS_AcquirePackageScripts( int comtype ) +{ + // scan all registered packages + for ( int packid = 0; packid < num_data_packages; packid++ ) { + + // scan all items of this package + for ( unsigned int curit = 0; curit < package_numitems[ packid ]; curit++ ) { + + // guard against overflow of maximum number of scripts + if ( num_external_commands >= MAX_EXTERNAL_COMMANDS ) + break; + + int scriptid = num_external_commands; + pfileinfo_s *item = &package_items[ packid ][ curit ]; + + // extension is mandatory + long len = strlen( item->file ) - 4; + +// ASSERT( ( len >= 0 ) && ( len <= COMMAND_NAME_ALLOC_LEN ) ); + if ( len < 0 ) + continue; + + // check script extension + if ( strcmp( item->file + len, CON_FILE_EXTENSION ) != 0 ) + continue; + + // store base name + strncpy( external_commands[ scriptid ], item->file, len ); + external_commands[ scriptid ][ len ] = 0; + + // set type and convert to lower-case + external_command_types[ scriptid ] = comtype; + strlwr( external_commands[ scriptid ] ); + + num_external_commands++; + } + } + + return TRUE; +} + + +// acquire demos contained in package files ----------------------------------- +// +int SYS_AcquirePackageDemos() +{ +#ifdef PARSEC_CLIENT + // scan all registered packages + for ( unsigned int packid = 0; packid < (unsigned int)num_data_packages; packid++ ) { + + // scan all items of this package + for ( unsigned int curit = 0; curit < package_numitems[ packid ]; curit++ ) { + + // guard against overflow of registered demos + if ( num_registered_demos >= max_registered_demos ) + break; + + int demoid = num_registered_demos; + pfileinfo_s *item = &package_items[ packid ][ curit ]; + + // extension is mandatory + long len = strlen( item->file ) - 4; +// ASSERT( ( len >= 0 ) && ( len <= COMMAND_NAME_ALLOC_LEN ) ); + if ( len < 0 ) + continue; + + // check demo extension + if ( strcmp( item->file + len, CON_FILE_COMPILED_EXTENSION ) != 0 ) + continue; + + // store demo name + if ( registered_demo_names[ demoid ] != NULL ) { + FREEMEM( registered_demo_names[ demoid ] ); + registered_demo_names[ demoid ] = NULL; + } + registered_demo_names[ demoid ] = (char *) ALLOCMEM( len + 1 ); + if ( registered_demo_names[ demoid ] == NULL ) + continue; + strncpy( registered_demo_names[ demoid ], item->file, len ); + registered_demo_names[ demoid ][ len ] = 0; + + // convert to lower-case + strlwr( registered_demo_names[ demoid ] ); + + num_registered_demos++; + } + } +#endif // PARSEC_CLIENT + return TRUE; +} + + +// determine file length of real system file ---------------------------------- +// +PRIVATE +long int SYS_SysGetFileLength( const char *filename ) +{ + ASSERT( filename != NULL ); + + FILE *fp = fopen( filename, "rb" ); + if ( fp == NULL ) + return -1L; + + if ( fseek( fp, 0, SEEK_END ) != 0 ) + return -1L; + + long int siz = ftell( fp ); + + fclose( fp ); + return siz; +} + +// check the internal version agains the pscdata*.dat version +// +int SYS_CheckDataVersion(){ + // attempt to open the version file + FILE *ver_file = SYS_fopen("psdatver.txt", "rb"); + if(ver_file == NULL) { + MSGOUT("Unable to open psdatver.txt. Maybe you need to update your pscdata*.dat files?"); + return false; + } + + char verstr[4]; + // attempt to read the file into the verstr buffer + int read_rc = SYS_fread((void *)verstr, sizeof(char), 3, ver_file); + verstr[3] = '\0'; + if (read_rc <= 0) { + MSGOUT("Unable to read psdatver.txt. Maybe you need to update your pscdata*.dat files?"); + return false; + } + + // now let's try to convert the string to a integer so we can check the version + //int data_version = 0; + //data_version = (int)strtol(verstr, NULL, 10); + MSGOUT("pscdata version %s, internal version %s", verstr, PSCDATA_VERSION); + if(strcmp(verstr, PSCDATA_VERSION)) { + MSGOUT("psdatver.txt version mismatch: Internal version %s does not match data file version %s.", verstr, PSCDATA_VERSION); + return false; + } + + SYS_fclose(ver_file); + + return true; +} + + +// fetch item return structure for the following two routines ----------------- +// +struct fetchitem_s { + + int packid; + pfileinfo_s* item; +}; + +#define FETCH_CACHE_MASK 0x03 +#define FETCH_CACHE_SIZE ( FETCH_CACHE_MASK + 1 ) + +static int _fetch_cache_pos = 0; +static fetchitem_s _fetch_item; +static fetchitem_s _fetch_cache[ FETCH_CACHE_SIZE ]; + + +// fetch item by file name ---------------------------------------------------- +// +PRIVATE +fetchitem_s *FetchItemByName( const char *filename ) +{ + ASSERT( filename != NULL ); + + // scan all registered packages + for ( int packid = 0; packid < num_data_packages; packid++ ) { + + // scan all items of this package + pfileinfo_s *items = package_items[ packid ]; + + for ( unsigned int curit = 0; curit < package_numitems[ packid ]; curit++ ) { + if ( stricmp( items[ curit ].file, filename ) == 0 ) { + _fetch_item.packid = packid; + _fetch_item.item = &items[ curit ]; + return &_fetch_item; + } + } + } + + return NULL; +} + + +// fetch item by file pointer ------------------------------------------------- +// +PRIVATE +fetchitem_s *FetchItemByFile( FILE *fp ) +{ + ASSERT( fp != NULL ); + + // try cache first + for ( int cp = 0; cp < FETCH_CACHE_SIZE; cp++ ) { + if ( _fetch_cache[ cp ].item == NULL ) { + continue; + } + if ( _fetch_cache[ cp ].item->fp == fp ) { + return &_fetch_cache[ cp ]; + } + } + + // scan all registered packages + for ( int packid = 0; packid < num_data_packages; packid++ ) { + + // scan all items of this package + pfileinfo_s *items = package_items[ packid ]; + unsigned int curit = 0; + for ( curit = 0; curit < package_numitems[ packid ]; curit++ ) { + if ( items[ curit ].fp == fp ) + break; + } + + if ( curit < package_numitems[ packid ] ) { + + // enter into cache + int cp = _fetch_cache_pos; + _fetch_cache[ cp ].packid = packid; + _fetch_cache[ cp ].item = &items[ curit ]; + + _fetch_cache_pos++; + _fetch_cache_pos &= FETCH_CACHE_MASK; + + // return info for found item + return &_fetch_cache[ cp ]; + } + } + + return NULL; +} + + +// determine file length ------------------------------------------------------ +// +long int SYS_GetFileLength( const char *filename ) +{ + ASSERT( filename != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return SYS_SysGetFileLength( filename ); + } + + fetchitem_s *fetchitem = FetchItemByName( filename ); + if ( fetchitem != NULL ) { + return fetchitem->item->flength; + } + + // fallback + return SYS_SysGetFileLength( filename ); +} + + +// open file ------------------------------------------------------------------ +// +FILE *SYS_fopen( const char *filename, const char *mode ) +{ + ASSERT( filename != NULL ); + ASSERT( mode != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return fopen( filename, mode ); + } + + // open package for reading at correct offset if file found as item + fetchitem_s *fetchitem = FetchItemByName( filename ); + if ( fetchitem != NULL ) { + + // open package file + FILE *fp = fopen( package_filename[ fetchitem->packid ], mode ); + + // this may indeed happen if too few handles available + ASSERT( fp != NULL ); + if ( fp == NULL ) { + return NULL; + } + + // set read position to start of item in package + size_t readpos = package_filebase[ fetchitem->packid ]; + readpos += fetchitem->item->foffset; + fseek( fp, readpos, SEEK_SET ); + + // init item state + fetchitem->item->fp = fp; + fetchitem->item->fcurpos = 0; + + return fp; + } + + // fallback + return fopen( filename, mode ); +} + + +// close file ----------------------------------------------------------------- +// +int SYS_fclose( FILE *fp ) +{ + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return fclose( fp ); + } + + // clear file pointer if file found as item + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + fetchitem->item->fp = NULL; + } + + // close file (package file/real file) + return fclose( fp ); +} + + +// read from file ------------------------------------------------------------- +// +size_t SYS_fread( void *buf, size_t elsize, size_t nelem, FILE *fp ) +{ + ASSERT( buf != NULL ); + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return fread( buf, elsize, nelem, fp ); + } + + // read file from package if found as item + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + + // size in bytes + size_t readsize = nelem * elsize; + + // make sure we are not reading past eof + pfileinfo_s *item = fetchitem->item; + size_t beyond = item->fcurpos + readsize; + if ( beyond > item->flength ) { + readsize = ( item->flength > item->fcurpos ) ? + item->flength - item->fcurpos : 0; + } + + // read data + if ( readsize == 0 ) + return 0; + size_t bytesread = fread( buf, 1, readsize, fp ); + item->fcurpos += bytesread; + return bytesread; + } + + // fallback + return fread( buf, elsize, nelem, fp ); +} + + +// seek to file position ------------------------------------------------------ +// +int SYS_fseek( FILE *fp, long int offset, int whence ) +{ + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return fseek( fp, offset, whence ); + } + + // position in package if file found as item + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + + switch ( whence ) { + + case SEEK_SET: + fetchitem->item->fcurpos = (dword) offset; + break; + + case SEEK_CUR: + fetchitem->item->fcurpos += offset; + break; + + case SEEK_END: + fetchitem->item->fcurpos = fetchitem->item->flength; + fetchitem->item->fcurpos += offset; + break; + + default: + return -1; + } + + long int packofs = package_filebase[ fetchitem->packid ]; + packofs += fetchitem->item->foffset; + packofs += fetchitem->item->fcurpos; + return fseek( fp, packofs, SEEK_SET ); + } + + // fallback + return fseek( fp, offset, whence ); +} + + +// tell file position --------------------------------------------------------- +// +long int SYS_ftell( FILE *fp ) +{ + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return ftell( fp ); + } + + // position in package if file found as item + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + return fetchitem->item->fcurpos; + } + + // fallback + return ftell( fp ); +} + + +// get eof state of file ------------------------------------------------------ +// +int SYS_feof( FILE *fp ) +{ + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_DATA_FILES ) { + return feof( fp ); + } + + //NOTE: + // the semantics of this function when used for files contained in + // packages is not exactly identical to the semantics of feof(). + // the eof state is directly queried using the current (read) position + // in the file, whereas feof() doesn't return eof until a read operation + // has actually been performed beyond eof. therefore it will also return + // eof if the read position has only been set with SYS_fseek(), but not + // yet been used by SYS_fread(), which differs from the reference behavior. + + // query position in package if file found as item + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + return ( fetchitem->item->fcurpos >= fetchitem->item->flength ); + } + + // fallback + return feof( fp ); +} + + +// last character read by Item_getc() ----------------------------------------- +// +static int last_c; + + +// getc() for package file ---------------------------------------------------- +// +inline +int Item_getc( pfileinfo_s *item ) +{ + if ( item->fcurpos >= item->flength ) { + last_c = EOF; + } else { + last_c = getc( item->fp ); + item->fcurpos++; + } + + return last_c; +} + + +// ungetc() for package file -------------------------------------------------- +// +inline +int Item_ungetc( pfileinfo_s *item ) +{ + if ( last_c != EOF ) { + ungetc( last_c, item->fp ); + item->fcurpos--; + } + + return last_c; +} + + +// read a line of text from a file -------------------------------------------- +// +char *SYS_fgets( char *string, int n, FILE *fp ) +{ + ASSERT( string != NULL ); + ASSERT( fp != NULL ); + + if ( AUX_DISABLE_PACKAGE_SCRIPTS ) { + return fgets( string, n, fp ); + } + + fetchitem_s *fetchitem = FetchItemByFile( fp ); + if ( fetchitem != NULL ) { + + // n includes the terminator + if ( n <= 0 ) { + return NULL; + } + + // read until eol, eof, or string mem end + int c = EOF; + char *output = NULL; + for ( output = string; --n > 0; ) { + + c = Item_getc( fetchitem->item ); + + // check for eof + if ( c == EOF ) { + if ( output == string ) { + return NULL; + } else { + break; + } + } + + // store read character + *output++ = c; + + if ( c == 0x0d ) { + break; + } + if ( c == 0x0a ) { + break; + } + } + + // try to read 0x0a after 0x0d + if ( c == 0x0d ) { + + if ( Item_getc( fetchitem->item ) == 0x0a ) { + output[ -1 ] = '\n'; + } else { + Item_ungetc( fetchitem->item ); + } + + // try to read 0x0d after 0x0a + } else if ( c == 0x0a ) { + + if ( Item_getc( fetchitem->item ) == 0x0d ) { + output[ -1 ] = '\n'; + } else { + Item_ungetc( fetchitem->item ); + } + } + + // terminate string + *output = 0; + return string; + } + + // fallback + return fgets( string, n, fp ); +} + + +// open file (operating system level) ----------------------------------------- +// +int SYS_open( const char *path, int access ) +{ + // dummy + return 0; +} + + +// close file (operating system level) ---------------------------------------- +// +int SYS_close( int handle ) +{ + // dummy + return 1; +} + + +// read file (operating system level) ----------------------------------------- +// +int SYS_read( int handle, char *buffer, int len ) +{ + // dummy + return 0; +} + + +// get file length (operating system level) ----------------------------------- +// +long int SYS_filelength( int handle ) +{ + // dummy + return 0; +} + + + diff --git a/src/libparsec/sys_swap.cpp b/src/libparsec/sys_swap.cpp new file mode 100644 index 0000000..ef86311 --- /dev/null +++ b/src/libparsec/sys_swap.cpp @@ -0,0 +1,153 @@ +/* + * PARSEC - Swap Endianness of Data + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:42 $ + * + * Orginally written by: + * Copyright (c) Andreas Varga <sid@parsec.org> 1998-1999 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "gd_heads.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// local module header +#include "sys_swap.h" + + + +// swap endianness of packageheader_s ----------------------------------------- +// +void SYS_SwapPackageHeader( packageheader_s *p ) +{ + ASSERT( p != NULL ); + + p->numitems = SWAP_32( p->numitems ); + p->headersize = SWAP_32( p->headersize ); + p->datasize = SWAP_32( p->datasize ); + p->packsize = SWAP_32( p->packsize ); +} + + +// swap endianness of packageheader_s ----------------------------------------- +// +void SYS_SwapPFileInfo( pfileinfodisk_s *p ) +{ + ASSERT( p != NULL ); + + p->foffset = SWAP_32( p->foffset ); + p->flength = SWAP_32( p->flength ); + p->fcurpos = SWAP_32( p->fcurpos ); +} + + +// swap endianness of BdtHeader ----------------------------------------------- +// +void SYS_SwapBdtHeader( BdtHeader *b ) +{ + ASSERT( b != NULL ); + + b->width = SWAP_32( b->width ); + b->height = SWAP_32( b->height ); +} + + +// swap endianness of FntHeader ----------------------------------------------- +// +void SYS_SwapFntHeader( FntHeader *f ) +{ + ASSERT( f != NULL ); + + f->width = SWAP_32( f->width ); + f->height = SWAP_32( f->height ); +} + + +// swap endianness of TexHeader ----------------------------------------------- +// +void SYS_SwapTexHeader( TexHeader *t ) +{ + ASSERT( t != NULL ); + + t->width = SWAP_32( t->width ); + t->height = SWAP_32( t->height ); +} + + +// swap endianness of DemHeader ----------------------------------------------- +// +void SYS_SwapDemHeader( DemHeader *d ) +{ + ASSERT( d != NULL ); + + d->headersize = SWAP_32( d->headersize ); +} + + +// swap endianness of PfgHeader ----------------------------------------------- +// +void SYS_SwapPfgHeader( PfgHeader *p ) +{ + ASSERT( p != NULL ); + + p->srcwidth = SWAP_32( p->srcwidth ); + p->width = SWAP_16( p->width ); + p->height = SWAP_16( p->height ); +} + + +// swap endianness of font geometry table ------------------------------------- +// +void SYS_SwapPfgTable( int fixsize, dword *geomtab, size_t tabsize ) +{ + ASSERT( geomtab != NULL ); + + //NOTE: + // proportional fonts are swapped on-the-fly and need + // not be swapped here. + +#ifdef SYSTEM_BIG_ENDIAN + + if ( fixsize ) { + + ASSERT( ( tabsize & 0x03 ) == 0x00 ); + + for ( dword indx = 0; indx < tabsize; indx+=4 ) { + geomtab[ indx >> 2 ] = SWAP_32( geomtab[ indx >> 2 ] ); + } + } + +#endif + +} + + + diff --git a/src/libparsec/utl_bsp.cpp b/src/libparsec/utl_bsp.cpp new file mode 100644 index 0000000..e95cb3a --- /dev/null +++ b/src/libparsec/utl_bsp.cpp @@ -0,0 +1,205 @@ +/* + * PARSEC - BSP Tree Operations + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "utl_bsp.h" + + + +// static tree traversal variables -------------------------------------------- +// +static Vertex3* bsp_line_v0; +static Vertex3* bsp_line_v1; +static CullBSPNode* bsp_tree; +static dword bsp_collider; +static geomv_t bsp_coll_t; + + +// traversal function to find line segment <-> bsp node collision ------------- +// +PRIVATE +int BSP_FindCollider( dword nodeid, geomv_t t0, geomv_t t1 ) +{ + ASSERT( nodeid != 0 ); + + //NOTE: + // nodeid==0: tree NULL + // nodeid==1: tree root + + //NOTE: + // baseseg: [ (t=0) v0 --------------------- v1 (t=1) ] + // subseg: [ (d0) t0 --------- t1 (d1) ] + // seg0: [ t0 --- t ] + // seg1: [ t --- t1 ] + + static CullBSPNode *node; + node = &bsp_tree[ nodeid ]; + + // signed distances of baseseg vertices to current plane + static geomv_t d0; + static geomv_t d1; + d0 = PLANE_DOT( &node->plane, bsp_line_v0 ) - PLANE_OFFSET( &node->plane ); + d1 = PLANE_DOT( &node->plane, bsp_line_v1 ) - PLANE_OFFSET( &node->plane ); + + static dword seg0treeid; + dword seg1treeid; + int seg0solid; + + // determine halfspace (subtree) of v0 + if ( GEOMV_GEZERO( d0 ) ) { + seg0solid = FALSE; // leaf would be empty + seg0treeid = node->subtrees[ 1 ]; // fronttree + seg1treeid = node->subtrees[ 0 ]; // backtree + } else { + seg0solid = TRUE; // leaf would be solid + seg0treeid = node->subtrees[ 0 ]; // backtree + seg1treeid = node->subtrees[ 1 ]; // fronttree + } + + // special case if baseseg not straddling + if ( ( DW32( d0 ) ^ DW32( d1 ) ) < 0x80000000 ) { + +pushseg: + // classify if seg in leaf + if ( seg0treeid == 0 ) + return seg0solid; + + // push down without clipping (tail rec) + return BSP_FindCollider( seg0treeid, t0, t1 ); + } + + // drop distance signs + ABS_GEOMV( d0 ); + ABS_GEOMV( d1 ); + + // calc projected length + static geomv_t seglen; + seglen = d0 + d1; + ASSERT( seglen >= 0 ); + + // simply push down if baseseg is on + if ( seglen <= FLOAT_TO_GEOMV( 0.00001 ) ) { + goto pushseg; + } + + // calc intersection parameter using baseseg + geomv_t t = GEOMV_DIV( d0, seglen ); + + // subseg not straddling: case 1 + if ( t <= t0 ) { + + // invert classification (subseg in v1's halfspace) + seg0solid = !seg0solid; + seg0treeid = seg1treeid; + + goto pushseg; + } + + // subseg not straddling: case 2 + if ( t >= t1 ) { + goto pushseg; + } + + // check seg0 first + if ( seg0treeid != 0 ) { + + // push seg0 into its tree if not leaf + if ( BSP_FindCollider( seg0treeid, t0, t ) ) + return TRUE; + + } else if ( seg0solid ) { + + // collision if seg0 in solid leaf + return TRUE; + } + + // this node becomes potential collider (ray passes through its plane) + bsp_collider = nodeid; + bsp_coll_t = t; + + // check if seg1's tree is a leaf + if ( seg1treeid == 0 ) { + + // classification of seg1 is inverse of seg0's + return !seg0solid; + } + + // push seg1 into its tree + return BSP_FindCollider( seg1treeid, t, t1 ); +} + + +// find collider (tree node) for specified line segment ----------------------- +// +int BSP_FindColliderLine( CullBSPNode *tree, Vertex3 *v0, Vertex3 *v1, dword *colnode, geomv_t *colt ) +{ + ASSERT( tree != NULL ); + ASSERT( v0 != NULL ); + ASSERT( v1 != NULL ); + + // set root pointer and lineseg + bsp_tree = tree; + bsp_line_v0 = v0; + bsp_line_v1 = v1; + bsp_coll_t = GEOMV_0; + + // no potential collider until first boundary pierced + bsp_collider = 0; + + // clip lineseg into bsp tree + int collided = BSP_FindCollider( 1, GEOMV_0, GEOMV_1 ); + + // set collider (node id) and t (parameter of collision) + if ( colnode != NULL ) + *colnode = bsp_collider; + if ( colt != NULL ) + *colt = bsp_coll_t; + + return collided; +} + + + diff --git a/src/libparsec/utl_clip.cpp b/src/libparsec/utl_clip.cpp new file mode 100644 index 0000000..ec9c237 --- /dev/null +++ b/src/libparsec/utl_clip.cpp @@ -0,0 +1,1447 @@ +/* + * PARSEC - Iter-Primitive Clipping Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:46 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "utl_clip.h" + + + +// clip IterTriangle3 against volume (set of planes); (XYZ UVW RGBA) ---------- +// +IterPolygon3 *CLIP_VolumeIterTriangle3( IterTriangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_VolumeIterPolygon3( iterpoly, volume, cullmask ); +} + + +// clip IterTriangle3 against volume (set of planes); (XYZ UVW) --------------- +// +IterPolygon3 *CLIP_VolumeIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_VolumeIterPolygon3_UVW( iterpoly, volume, cullmask ); +} + + +// clip IterTriangle3 against volume (set of planes); (XYZ RGBA) -------------- +// +IterPolygon3 *CLIP_VolumeIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_VolumeIterPolygon3_RGBA( iterpoly, volume, cullmask ); +} + + +// clip IterRectangle3 against volume (set of planes); (XYZ UVW RGBA) --------- +// +IterPolygon3 *CLIP_VolumeIterRectangle3( IterRectangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_VolumeIterPolygon3( iterpoly, volume, cullmask ); +} + + +// clip IterRectangle3 against volume (set of planes); (XYZ UVW) -------------- +// +IterPolygon3 *CLIP_VolumeIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_VolumeIterPolygon3_UVW( iterpoly, volume, cullmask ); +} + + +// clip IterRectangle3 against volume (set of planes); (XYZ RGBA) ------------- +// +IterPolygon3 *CLIP_VolumeIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_VolumeIterPolygon3_RGBA( iterpoly, volume, cullmask ); +} + + +// clip IterTriangle3 against single plane; (XYZ UVW RGBA) -------------------- +// +IterPolygon3 *CLIP_PlaneIterTriangle3( IterTriangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_PlaneIterPolygon3( iterpoly, plane ); +} + + +// clip IterTriangle3 against single plane; (XYZ UVW) ------------------------- +// +IterPolygon3 *CLIP_PlaneIterTriangle3_UVW( IterTriangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_PlaneIterPolygon3_UVW( iterpoly, plane ); +} + + +// clip IterTriangle3 against single plane; (XYZ RGBA) ------------------------ +// +IterPolygon3 *CLIP_PlaneIterTriangle3_RGBA( IterTriangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original triangle's NumVerts field will be set to 3 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 3; + + return CLIP_PlaneIterPolygon3_RGBA( iterpoly, plane ); +} + + +// clip IterRectangle3 against single plane; (XYZ UVW RGBA) ------------------- +// +IterPolygon3 *CLIP_PlaneIterRectangle3( IterRectangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_PlaneIterPolygon3( iterpoly, plane ); +} + + +// clip IterRectangle3 against single plane; (XYZ UVW) ------------------------ +// +IterPolygon3 *CLIP_PlaneIterRectangle3_UVW( IterRectangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_PlaneIterPolygon3_UVW( iterpoly, plane ); +} + + +// clip IterRectangle3 against single plane; (XYZ RGBA) ----------------------- +// +IterPolygon3 *CLIP_PlaneIterRectangle3_RGBA( IterRectangle3 *poly, Plane3 *plane ) +{ + //NOTE: + // the original rectangle's NumVerts field will be set to 4 + // here, in order to enable processing as general polygon. + + IterPolygon3 *iterpoly = (IterPolygon3 *) poly; + iterpoly->NumVerts = 4; + + return CLIP_PlaneIterPolygon3_RGBA( iterpoly, plane ); +} + + +// clip IterPolygon3 against volume (set of planes); (XYZ UVW RGBA) ----------- +// +IterPolygon3 *CLIP_VolumeIterPolygon3( IterPolygon3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( volume != NULL ); + + // check all planes that have not been culled already + for ( int curplane = 0; cullmask != 0x00; cullmask >>= 1, curplane++ ) { + + if ( cullmask & 0x01 ) { + + // clip against current plane + poly = CLIP_PlaneIterPolygon3( poly, &volume[ curplane ] ); + + // one plane rejects: whole status is trivial reject + if ( poly == NULL ) + return poly; + } + } + + // return clipped polygon/status + return poly; +} + + +// clip IterPolygon3 against volume (set of planes); (XYZ UVW) ---------------- +// +IterPolygon3 *CLIP_VolumeIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( volume != NULL ); + + // check all planes that have not been culled already + for ( int curplane = 0; cullmask != 0x00; cullmask >>= 1, curplane++ ) { + + if ( cullmask & 0x01 ) { + + // clip against current plane + poly = CLIP_PlaneIterPolygon3_UVW( poly, &volume[ curplane ] ); + + // one plane rejects: whole status is trivial reject + if ( poly == NULL ) + return poly; + } + } + + // return clipped polygon/status + return poly; +} + + +// clip IterPolygon3 against volume (set of planes); (XYZ RGBA) --------------- +// +IterPolygon3 *CLIP_VolumeIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( volume != NULL ); + + // check all planes that have not been culled already + for ( int curplane = 0; cullmask != 0x00; cullmask >>= 1, curplane++ ) { + + if ( cullmask & 0x01 ) { + + // clip against current plane + poly = CLIP_PlaneIterPolygon3_RGBA( poly, &volume[ curplane ] ); + + // one plane rejects: whole status is trivial reject + if ( poly == NULL ) + return poly; + } + } + + // return clipped polygon/status + return poly; +} + + +// static storage for clipped output polygons --------------------------------- +// +static IterPolygon3 clip_polys[ 2 ][ MAX_ITERPOLY_VERTICES ]; // excessive +static geomv_t plane_distances[ MAX_ITERPOLY_VERTICES ]; +static dword outcode_acceptall[ MAX_ITERPOLY_VERTICES ]; + + +// attribute clipping macros -------------------------------------------------- +// +#define POLY_CLIP_RGBA(d,t,c,p) \ + int R = (int)(c)->R - (int)(p)->R; \ + int G = (int)(c)->G - (int)(p)->G; \ + int B = (int)(c)->B - (int)(p)->B; \ + int A = (int)(c)->A - (int)(p)->A; \ + (d)->R = (int)(p)->R + (int)( GEOMV_TO_FLOAT( t ) * R + 0.5 ); \ + (d)->G = (int)(p)->G + (int)( GEOMV_TO_FLOAT( t ) * G + 0.5 ); \ + (d)->B = (int)(p)->B + (int)( GEOMV_TO_FLOAT( t ) * B + 0.5 ); \ + (d)->A = (int)(p)->A + (int)( GEOMV_TO_FLOAT( t ) * A + 0.5 ); + + +// clip IterPolygon3 against single plane; (XYZ UVW RGBA) --------------------- +// +IterPolygon3 *CLIP_PlaneIterPolygon3( IterPolygon3 *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + // fetch geometry + IterVertex3 *vtxs = poly->Vtxs; + int numverts = poly->NumVerts; + + ASSERT( vtxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_ITERPOLY_VERTICES ); + + dword outcode = 0x00; + + // refs instead of embedded vertex data? + IterVertex3** refs = NULL; + + if ( poly->flags & ITERFLAG_VERTEXREFS ) { + refs = (IterVertex3**) vtxs; + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, refs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + } else { + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, &vtxs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + IterPolygon3 *destpoly = (IterPolygon3 *) clip_polys[ poly == (IterPolygon3*)clip_polys ]; + IterVertex3 *destvtxs = destpoly->Vtxs; + + // use last vertex first + int prev_vtx = numverts - 1; + + if ( refs == NULL ) { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + + destvtxs++; + } + + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + } else { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, refs[ cur_vtx ], refs[ prev_vtx ] ); + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, refs[ cur_vtx ], refs[ prev_vtx ] ); + + destvtxs++; + } + + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + } + + // set new number of vertices + destpoly->NumVerts = destvtxs - destpoly->Vtxs; + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // set poly info + destpoly->flags = poly->flags & ~ITERFLAG_VERTEXREFS; + destpoly->itertype = poly->itertype; + destpoly->raststate = poly->raststate; + destpoly->rastmask = poly->rastmask; + destpoly->plane = poly->plane; + destpoly->texmap = poly->texmap; + + // return clipped polygon in static storage + return destpoly; +} + + +// clip IterPolygon3 against single plane; (XYZ UVW) -------------------------- +// +IterPolygon3 *CLIP_PlaneIterPolygon3_UVW( IterPolygon3 *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + // fetch geometry + IterVertex3 *vtxs = poly->Vtxs; + int numverts = poly->NumVerts; + + ASSERT( vtxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_ITERPOLY_VERTICES ); + + dword outcode = 0x00; + + // refs instead of embedded vertex data? + IterVertex3** refs = NULL; + + if ( poly->flags & ITERFLAG_VERTEXREFS ) { + refs = (IterVertex3**) vtxs; + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, refs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + } else { + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, &vtxs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + IterPolygon3 *destpoly = (IterPolygon3 *) clip_polys[ poly == (IterPolygon3*)clip_polys ]; + IterVertex3 *destvtxs = destpoly->Vtxs; + + // use last vertex first + int prev_vtx = numverts - 1; + + if ( refs == NULL ) { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // duplicate rgba + *(dword*)&destvtxs->R = *(dword*)&vtxs[ cur_vtx ].R; + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // duplicate rgba + *(dword*)&destvtxs->R = *(dword*)&vtxs[ cur_vtx ].R; + + destvtxs++; + } + + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + } else { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // duplicate rgba + *(dword*)&destvtxs->R = *(dword*)&refs[ cur_vtx ]->R; + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz, uvw + IterVertex3 dvec; + VECSUB_UVW( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY_UVW( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // duplicate rgba + *(dword*)&destvtxs->R = *(dword*)&refs[ cur_vtx ]->R; + + destvtxs++; + } + + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + } + + // set new number of vertices + destpoly->NumVerts = destvtxs - destpoly->Vtxs; + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // set poly info + destpoly->flags = poly->flags & ~ITERFLAG_VERTEXREFS; + destpoly->itertype = poly->itertype; + destpoly->raststate = poly->raststate; + destpoly->rastmask = poly->rastmask; + destpoly->plane = poly->plane; + destpoly->texmap = poly->texmap; + + // return clipped polygon in static storage + return destpoly; +} + + +// clip IterPolygon3 against single plane; (XYZ RGBA) ------------------------- +// +IterPolygon3 *CLIP_PlaneIterPolygon3_RGBA( IterPolygon3 *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static IterPolygon3 (the clipped polygon) + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + // fetch geometry + IterVertex3 *vtxs = poly->Vtxs; + int numverts = poly->NumVerts; + + ASSERT( vtxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_ITERPOLY_VERTICES ); + + dword outcode = 0x00; + + // refs instead of embedded vertex data? + IterVertex3** refs = NULL; + + if ( poly->flags & ITERFLAG_VERTEXREFS ) { + refs = (IterVertex3**) vtxs; + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, refs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + } else { + + // check all vertices, calc outcode and distances + for ( int vcount = numverts; vcount > 0; vcount-- ) { + plane_distances[ vcount-1 ] = PLANE_DOT( plane, &vtxs[ vcount-1 ] ) - + PLANE_OFFSET( plane ); + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + IterPolygon3 *destpoly = (IterPolygon3 *) clip_polys[ poly == (IterPolygon3*)clip_polys ]; + IterVertex3 *destvtxs = destpoly->Vtxs; + + // use last vertex first + int prev_vtx = numverts - 1; + + if ( refs == NULL ) { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + IterVertex3 dvec; + VECSUB( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // duplicate uvw + destvtxs->W = vtxs[ cur_vtx ].W; + destvtxs->U = vtxs[ cur_vtx ].U; + destvtxs->V = vtxs[ cur_vtx ].V; + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + IterVertex3 dvec; + VECSUB( &dvec, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + CSAXPY( destvtxs, tpara, &dvec, &vtxs[ prev_vtx ] ); + + // duplicate uvw + destvtxs->W = vtxs[ cur_vtx ].W; + destvtxs->U = vtxs[ cur_vtx ].U; + destvtxs->V = vtxs[ cur_vtx ].V; + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, &vtxs[ cur_vtx ], &vtxs[ prev_vtx ] ); + + destvtxs++; + } + + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = vtxs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + } else { + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + IterVertex3 dvec; + VECSUB( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // duplicate uvw + destvtxs->W = refs[ cur_vtx ]->W; + destvtxs->U = refs[ cur_vtx ]->U; + destvtxs->V = refs[ cur_vtx ]->V; + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, refs[ cur_vtx ], refs[ prev_vtx ] ); + + destvtxs++; + } + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + IterVertex3 dvec; + VECSUB( &dvec, refs[ cur_vtx ], refs[ prev_vtx ] ); + CSAXPY( destvtxs, tpara, &dvec, refs[ prev_vtx ] ); + + // duplicate uvw + destvtxs->W = refs[ cur_vtx ]->W; + destvtxs->U = refs[ cur_vtx ]->U; + destvtxs->V = refs[ cur_vtx ]->V; + + // interpolate rgba + POLY_CLIP_RGBA( destvtxs, tpara, refs[ cur_vtx ], refs[ prev_vtx ] ); + + destvtxs++; + } + + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current vertex + *destvtxs++ = *refs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + } + + // set new number of vertices + destpoly->NumVerts = destvtxs - destpoly->Vtxs; + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // set poly info + destpoly->flags = poly->flags & ~ITERFLAG_VERTEXREFS; + destpoly->itertype = poly->itertype; + destpoly->raststate = poly->raststate; + destpoly->rastmask = poly->rastmask; + destpoly->plane = poly->plane; + destpoly->texmap = poly->texmap; + + // return clipped polygon in static storage + return destpoly; +} + + +// static storage for clipped output lines ------------------------------------ +// +static IterLine2 clip_lines2[ 2 ][ MAX_ITERLINE_VERTICES ]; // excessive +static IterLine3 clip_lines3[ 2 ][ MAX_ITERLINE_VERTICES ]; // excessive + + +// attribute clipping macros -------------------------------------------------- +// +#define LINE_CLIP_RGBA() \ + int R = (int)vtxs[ v1 ].R - (int)vtxs[ v0 ].R; \ + int G = (int)vtxs[ v1 ].G - (int)vtxs[ v0 ].G; \ + int B = (int)vtxs[ v1 ].B - (int)vtxs[ v0 ].B; \ + int A = (int)vtxs[ v1 ].A - (int)vtxs[ v0 ].A; \ + destvtxs[ d0 ].R = (int)vtxs[ v0 ].R + (int)( tpara * R + 0.5 ); \ + destvtxs[ d0 ].G = (int)vtxs[ v0 ].G + (int)( tpara * G + 0.5 ); \ + destvtxs[ d0 ].B = (int)vtxs[ v0 ].B + (int)( tpara * B + 0.5 ); \ + destvtxs[ d0 ].A = (int)vtxs[ v0 ].A + (int)( tpara * A + 0.5 ); +/* +#define LINE_CLIP_UVW() \ + float du = vtxs[ v1 ].U - vtxs[ v0 ].U; \ + float dv = vtxs[ v1 ].V - vtxs[ v0 ].V; \ + float dw = vtxs[ v1 ].W - vtxs[ v0 ].W; \ + destvtxs[ d0 ].U = vtxs[ v0 ].U + ( tpara * du ); \ + destvtxs[ d0 ].V = vtxs[ v0 ].V + ( tpara * du ); \ + destvtxs[ d0 ].W = vtxs[ v0 ].W + ( tpara * du ); +*/ + + +// clip IterLine2 against 2-D rectangle; (XYZ UVW RGBA) ----------------------- +// +IterLine2 *CLIP_RectangleIterLine2( IterLine2 *line, Rectangle2 *rect ) +{ + //NOTE: + // this function returns: + // - NULL if the line is trivial reject + // - line if the line is trivial accept + // - pointer to a static IterLine2 (the clipped line) + + //NOTE: + //TODO: + // not supported: + // - closed line-strips + // - texture coordinates + // - depth coordinate + + ASSERT( line != NULL ); + ASSERT( rect != NULL ); + + ASSERT( rect->left <= rect->right ); + ASSERT( rect->top <= rect->bottom ); + + // fetch geometry + IterVertex2 *vtxs = line->Vtxs; + int numverts = line->NumVerts; + + ASSERT( vtxs != NULL ); + ASSERT( numverts > 1 ); + ASSERT( numverts <= MAX_ITERLINE_VERTICES ); + + byte outcode[ 2 ]; + + // first outcode + outcode[ 0 ] = 0x00; + if ( vtxs[ 0 ].X < rect->left ) + outcode[ 0 ] |= 0x01; + if ( vtxs[ 0 ].X > rect->right ) + outcode[ 0 ] |= 0x02; + if ( vtxs[ 0 ].Y < rect->top ) + outcode[ 0 ] |= 0x04; + if ( vtxs[ 0 ].Y > rect->bottom ) + outcode[ 0 ] |= 0x08; + + // special case: single line + if ( numverts == 2 ) { + + // second outcode + outcode[ 1 ] = 0x00; + if ( vtxs[ 1 ].X < rect->left ) + outcode[ 1 ] |= 0x01; + if ( vtxs[ 1 ].X > rect->right ) + outcode[ 1 ] |= 0x02; + if ( vtxs[ 1 ].Y < rect->top ) + outcode[ 1 ] |= 0x04; + if ( vtxs[ 1 ].Y > rect->bottom ) + outcode[ 1 ] |= 0x08; + + // trivial accept if both vertices in rectangle + if ( ( outcode[ 0 ] == 0 ) && ( outcode[ 1 ] == 0 ) ) { + return line; + } + + // trivial reject if both vertices in same outside + if ( ( outcode[ 0 ] & outcode[ 1 ] ) != 0 ) { + return NULL; + } + } + + // toggle static output storage + IterLine2 *destline = (IterLine2 *) clip_lines2[ line == (IterLine2*)clip_lines2 ]; + IterVertex2 *destvtxs = destline->Vtxs; + + float rectl = RASTV_TO_FLOAT( rect->left ); + float rectr = RASTV_TO_FLOAT( rect->right ); + float rectt = RASTV_TO_FLOAT( rect->top ); + float rectb = RASTV_TO_FLOAT( rect->bottom ); + + // source indexes + int vtx0 = 0; + int vtx1 = 1; + + // destination indexes + int dst0 = 0; + int dst1 = 1; + + // emitted vertices + destline->NumVerts = 0; + + #define RESTART_OFF 0x00 + #define RESTART_VERTEX 0x01 + #define RESTART_OUTCODE 0x02 + + // initial restart + int restart = RESTART_VERTEX; + + // process numverts - 1 lines + for ( int lct = numverts - 1; lct > 0; lct-- ) { + + int o0 = vtx0 & 0x01; + int o1 = vtx1 & 0x01; + + int deltaverts = ( restart & RESTART_VERTEX ) + 1; + destline->NumVerts += deltaverts; + + if ( restart ) { + + // copy restart vertex + destvtxs[ dst0 ] = vtxs[ vtx0 ]; + destvtxs[ dst0 ].flags |= ITERVTXFLAG_RESTART; + + if ( restart & RESTART_OUTCODE ) { + + outcode[ o0 ] = 0x00; + if ( vtxs[ vtx0 ].X < rect->left ) + outcode[ o0 ] |= 0x01; + if ( vtxs[ vtx0 ].X > rect->right ) + outcode[ o0 ] |= 0x02; + if ( vtxs[ vtx0 ].Y < rect->top ) + outcode[ o0 ] |= 0x04; + if ( vtxs[ vtx0 ].Y > rect->bottom ) + outcode[ o0 ] |= 0x08; + } + + restart = RESTART_OFF; + } + + // copy next vertex + destvtxs[ dst1 ] = vtxs[ vtx1 ]; + + // next outcode + outcode[ o1 ] = 0x00; + if ( vtxs[ vtx1 ].X < rect->left ) + outcode[ o1 ] |= 0x01; + if ( vtxs[ vtx1 ].X > rect->right ) + outcode[ o1 ] |= 0x02; + if ( vtxs[ vtx1 ].Y < rect->top ) + outcode[ o1 ] |= 0x04; + if ( vtxs[ vtx1 ].Y > rect->bottom ) + outcode[ o1 ] |= 0x08; + + // trivial accept if both vertices in rectangle + if ( ( outcode[ o0 ] == 0 ) && ( outcode[ o1 ] == 0 ) ) { + goto accept; + } + + // trivial reject if both vertices in same outside + if ( ( outcode[ o0 ] & outcode[ o1 ] ) != 0 ) { + destline->NumVerts -= deltaverts; + restart = RESTART_VERTEX; + goto reject; + } + + // read source vertices + float fx[ 2 ], fy[ 2 ]; + fx[ vtx0 & 1 ] = RASTV_TO_FLOAT( vtxs[ vtx0 ].X ); + fy[ vtx0 & 1 ] = RASTV_TO_FLOAT( vtxs[ vtx0 ].Y ); + fx[ vtx1 & 1 ] = RASTV_TO_FLOAT( vtxs[ vtx1 ].X ); + fy[ vtx1 & 1 ] = RASTV_TO_FLOAT( vtxs[ vtx1 ].Y ); + + for ( ;; ) { + + int v0 = vtx0; + int v1 = vtx1; + int d0 = dst0; + + if ( outcode[ v0 & 1 ] == 0 ) { + + // swap if first is inside + SWAP_VALUES_32( v0, v1 ); + d0 = dst1; + + // endvertex will change + restart = RESTART_VERTEX | RESTART_OUTCODE; + } + + int f0 = v0 & 0x01; + int f1 = v1 & 0x01; + + float deltax = fx[ f1 ] - fx[ f0 ]; + float deltay = fy[ f1 ] - fy[ f0 ]; + + if ( outcode[ f0 ] & 0x01 ) { + + // clip against left + float lseg0 = rectl - fx[ f0 ]; + float tpara = lseg0 / ( fx[ f1 ] - fx[ f0 ] ); + + fx[ f0 ] = rectl; + fy[ f0 ] += tpara * deltay; + + LINE_CLIP_RGBA(); + + } else if ( outcode[ f0 ] & 0x02 ) { + + // clip against right + float lseg0 = fx[ f0 ] - rectr; + float tpara = lseg0 / ( fx[ f0 ] - fx[ f1 ] ); + + fx[ f0 ] = rectr; + fy[ f0 ] += tpara * deltay; + + LINE_CLIP_RGBA(); + + } else if ( outcode[ f0 ] & 0x04 ) { + + // clip against top + float lseg0 = rectt - fy[ f0 ]; + float tpara = lseg0 / ( fy[ f1 ] - fy[ f0 ] ); + + fx[ f0 ] += tpara * deltax; + fy[ f0 ] = rectt; + + LINE_CLIP_RGBA(); + + } else if ( outcode[ f0 ] & 0x08 ) { + + // clip against bottom + float lseg0 = fy[ f0 ] - rectb; + float tpara = lseg0 / ( fy[ f0 ] - fy[ f1 ] ); + + fx[ f0 ] += tpara * deltax; + fy[ f0 ] = rectb; + + LINE_CLIP_RGBA(); + } + + // new first outcode + outcode[ f0 ] = 0x00; + if ( fx[ f0 ] < rectl ) + outcode[ f0 ] |= 0x01; + if ( fx[ f0 ] > rectr ) + outcode[ f0 ] |= 0x02; + if ( fy[ f0 ] < rectt ) + outcode[ f0 ] |= 0x04; + if ( fy[ f0 ] > rectb ) + outcode[ f0 ] |= 0x08; + + // trivial accept if both vertices in rectangle + if ( ( outcode[ f0 ] == 0 ) && ( outcode[ f1 ] == 0 ) ) { + break; + } + + // trivial reject if both vertices in same outside + if ( ( outcode[ f0 ] & outcode[ f1 ] ) != 0 ) { + destline->NumVerts -= deltaverts; + restart = RESTART_VERTEX; + goto reject; + } + } + + // store clipped vertices + destvtxs[ dst0 ].X = FLOAT_TO_RASTV( fx[ o0 ] ); + destvtxs[ dst0 ].Y = FLOAT_TO_RASTV( fy[ o0 ] ); + destvtxs[ dst1 ].X = FLOAT_TO_RASTV( fx[ o1 ] ); + destvtxs[ dst1 ].Y = FLOAT_TO_RASTV( fy[ o1 ] ); + + // make room for two new vertices + // instead of just one + if ( restart ) { + dst0++; + dst1++; + } +accept: + // advance destination + dst0++; + dst1++; +reject: + // advance source + vtx0++; + vtx1++; + } + + // test for degenerated lines + if ( destline->NumVerts < 2 ) + return NULL; + + // set line info + destline->flags = line->flags; + destline->itertype = line->itertype; + destline->raststate = line->raststate; + destline->rastmask = line->rastmask; + destline->texmap = line->texmap; + + // return clipped line in static storage + return destline; +} + + +// clip IterLine3 against single plane; (XYZ UVW RGBA) ------------------------ +// +IterLine3 *CLIP_PlaneIterLine3( IterLine3 *line, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the line is trivial reject + // - line if the line is trivial accept + // - pointer to a static IterLine3 (the clipped line) + + ASSERT( line != NULL ); + ASSERT( plane != NULL ); + + //TODO: + + return line; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( UTL_CLIP ) +{ + // limit is 31 due to bit-twiddling!! + ASSERT( MAX_ITERPOLY_VERTICES < 32 ); + + // fill trivial accept table for all vertex counts + dword outcode = 0x02; + for ( int code = 0; code < MAX_ITERPOLY_VERTICES; code++ ) { + + outcode_acceptall[ code ] = outcode; + outcode = ( outcode << 1 ) | 0x02; + } +} + + + diff --git a/src/libparsec/utl_clpo.cpp b/src/libparsec/utl_clpo.cpp new file mode 100644 index 0000000..15ff8bd --- /dev/null +++ b/src/libparsec/utl_clpo.cpp @@ -0,0 +1,1188 @@ +/* + * PARSEC - Object Clipping Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:46 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "utl_clpo.h" + + +// flags +#define CLIP_ORIENTED_EDGES +//#define INSANE_LIMITS + + + +// clipped object limitations ------------------------------------------------- +// +#ifdef INSANE_LIMITS + #define CLIPPED_MAX_VERTS 16384 + #define CLIPPED_MAX_POLYS 8192 + #define CLIPPED_MAX_INSTANCE_SIZE ( sizeof( GenObject ) + 32768 ) +#else + #define CLIPPED_MAX_VERTS 4096 + #define CLIPPED_MAX_POLYS 1024 + #define CLIPPED_MAX_INSTANCE_SIZE ( sizeof( GenObject ) + 16384 ) +#endif // INSANE_LIMITS + +#define MAX_CLIPPOLY_VERTICES 31 + + +// storage sizes for genobject data areas ------------------------------------- +// +#define SZ_VERTEXLIST ( CLIPPED_MAX_VERTS * sizeof( Vertex3 ) ) +#define SZ_XVERTEXLIST ( CLIPPED_MAX_VERTS * sizeof( Vertex3 ) ) +#define SZ_SVERTEXLIST ( CLIPPED_MAX_VERTS * sizeof( SPoint ) ) +#define SZ_POLYLIST ( CLIPPED_MAX_POLYS * sizeof( Poly ) ) +#define SZ_POLYINDEXES ( CLIPPED_MAX_POLYS * MAX_CLIPPOLY_VERTICES * sizeof( dword ) * 2 ) + + +// create clipped genobject from unclipped genobject (against volume) --------- +// +static GenObject *clipped_obj = NULL; +static size_t clipped_obj_size = + CLIPPED_MAX_INSTANCE_SIZE + + SZ_VERTEXLIST + SZ_XVERTEXLIST + SZ_SVERTEXLIST + + SZ_POLYLIST + SZ_POLYINDEXES; + + +// globals needed by the following routines ----------------------------------- +// +Vertex3* clp_vtxlist; // pointer to vertices +int clp_nextindx; // next vertex index for clipped vertices +dword* clp_wcolors; // lighted wedge colors + + +// static storage for clipped output polygons --------------------------------- +// +static Poly clip_polys[ 2 ][ MAX_CLIPPOLY_VERTICES ]; // excessive +static geomv_t plane_distances[ MAX_CLIPPOLY_VERTICES ]; +static dword outcode_acceptall[ MAX_CLIPPOLY_VERTICES ]; +static dword temp_colors[ MAX_CLIPPOLY_VERTICES ]; + + +// clip Poly against single plane --------------------------------------------- +// +Poly *CLIP_PlanePoly( Poly *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static Poly (the clipped polygon) + + //NOTE: + // clp_vtxlist and clp_nextindx have to be + // set correctly before calling this function. + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + // fetch geometry + dword *indxs = poly->VertIndxs; + int numverts = poly->NumVerts; + + ASSERT( indxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_CLIPPOLY_VERTICES ); + + // check all vertices, calc outcode and distances + dword outcode = 0x00; + for ( int vcount = numverts; vcount > 0; vcount-- ) { + + plane_distances[ vcount-1 ] = + PLANE_DOT( plane, &clp_vtxlist[ indxs[ vcount-1 ] ] ) - + PLANE_OFFSET( plane ); + + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + Poly *destpoly = (Poly *) clip_polys[ poly == (Poly*)clip_polys ]; + dword *destindxs = (dword *) ( destpoly + 1 ); + + destpoly->FaceIndx = poly->FaceIndx; + destpoly->VertIndxs = destindxs; + destpoly->Flags = poly->Flags; + + // use last vertex first + int prev_vtx = numverts - 1; + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = plane_distances[ prev_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } +#endif + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = prevd - plane_distances[ prev_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + *destindxs++ = clp_nextindx++; + } +#endif + // store current index + *destindxs++ = indxs[ cur_vtx ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current index + *destindxs++ = indxs[ cur_vtx ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + // set new number of vertices + destpoly->NumVerts = (dword) (destindxs - destpoly->VertIndxs); + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // return clipped polygon in static storage + return destpoly; +} + + +// attribute clipping macros -------------------------------------------------- +// +#define CLIP_WEDGE_RGBA(d,t,c,p) \ + int R = (int)((colrgba_s*)&clp_wcolors[ indxs[(c)+numverts] ])->R - (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->R; \ + int G = (int)((colrgba_s*)&clp_wcolors[ indxs[(c)+numverts] ])->G - (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->G; \ + int B = (int)((colrgba_s*)&clp_wcolors[ indxs[(c)+numverts] ])->B - (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->B; \ + int A = (int)((colrgba_s*)&clp_wcolors[ indxs[(c)+numverts] ])->A - (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->A; \ + ((colrgba_s*)(d))->R = (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->R + (int)( GEOMV_TO_FLOAT( t ) * R + 0.5 ); \ + ((colrgba_s*)(d))->G = (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->G + (int)( GEOMV_TO_FLOAT( t ) * G + 0.5 ); \ + ((colrgba_s*)(d))->B = (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->B + (int)( GEOMV_TO_FLOAT( t ) * B + 0.5 ); \ + ((colrgba_s*)(d))->A = (int)((colrgba_s*)&clp_wcolors[ indxs[(p)+numverts] ])->A + (int)( GEOMV_TO_FLOAT( t ) * A + 0.5 ); + + +// clip Poly against single plane --------------------------------------------- +// +Poly *CLIP_PlanePolyWedgeColors( Poly *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static Poly (the clipped polygon) + + //NOTE: + // clp_vtxlist, clp_nextindx, and clp_wcolors have + // to be set correctly before calling this function. + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + ASSERT( ( poly->Flags & POLYFLAG_WEDGEINDEXES ) != 0 ); + ASSERT( ( poly->Flags & POLYFLAG_CORNERCOLORS ) == 0 ); + + // fetch geometry + dword *indxs = poly->VertIndxs; + int numverts = poly->NumVerts; + + ASSERT( indxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_CLIPPOLY_VERTICES ); + + // check all vertices, calc outcode and distances + dword outcode = 0x00; + for ( int vcount = numverts; vcount > 0; vcount-- ) { + + plane_distances[ vcount-1 ] = + PLANE_DOT( plane, &clp_vtxlist[ indxs[ vcount-1 ] ] ) - + PLANE_OFFSET( plane ); + + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + Poly *destpoly = (Poly *) clip_polys[ poly == (Poly*)clip_polys ]; + dword *destindxs = (dword *) ( destpoly + 1 ); + dword *tempcolors = temp_colors; + + destpoly->FaceIndx = poly->FaceIndx; + destpoly->VertIndxs = destindxs; + destpoly->Flags = poly->Flags; + + // use last vertex first + int prev_vtx = numverts - 1; + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = plane_distances[ prev_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, prev_vtx, cur_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } +#endif + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = prevd - plane_distances[ prev_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, prev_vtx, cur_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_WEDGE_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } +#endif + // store current index and color + *destindxs++ = indxs[ cur_vtx ]; + *tempcolors++ = clp_wcolors[ indxs[ cur_vtx + numverts ] ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current index and color + *destindxs++ = indxs[ cur_vtx ]; + *tempcolors++ = clp_wcolors[ indxs[ cur_vtx + numverts ] ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + // set new number of vertices + destpoly->NumVerts = destindxs - destpoly->VertIndxs; + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // apppend colors to vertex indexes + ASSERT( (dword)( tempcolors - temp_colors ) == destpoly->NumVerts ); + memcpy( destindxs, temp_colors, destpoly->NumVerts * sizeof( dword ) ); + + destpoly->Flags &= ~POLYFLAG_WEDGEINDEXES; + destpoly->Flags |= POLYFLAG_CORNERCOLORS; + + // return clipped polygon in static storage + return destpoly; +} + + +// attribute clipping macros -------------------------------------------------- +// +#define CLIP_CORNER_RGBA(d,t,c,p) \ + int R = (int)((colrgba_s*)&indxs[(c)+numverts])->R - (int)((colrgba_s*)&indxs[(p)+numverts])->R; \ + int G = (int)((colrgba_s*)&indxs[(c)+numverts])->G - (int)((colrgba_s*)&indxs[(p)+numverts])->G; \ + int B = (int)((colrgba_s*)&indxs[(c)+numverts])->B - (int)((colrgba_s*)&indxs[(p)+numverts])->B; \ + int A = (int)((colrgba_s*)&indxs[(c)+numverts])->A - (int)((colrgba_s*)&indxs[(p)+numverts])->A; \ + ((colrgba_s*)(d))->R = (int)((colrgba_s*)&indxs[(p)+numverts])->R + (int)( GEOMV_TO_FLOAT( t ) * R + 0.5 ); \ + ((colrgba_s*)(d))->G = (int)((colrgba_s*)&indxs[(p)+numverts])->G + (int)( GEOMV_TO_FLOAT( t ) * G + 0.5 ); \ + ((colrgba_s*)(d))->B = (int)((colrgba_s*)&indxs[(p)+numverts])->B + (int)( GEOMV_TO_FLOAT( t ) * B + 0.5 ); \ + ((colrgba_s*)(d))->A = (int)((colrgba_s*)&indxs[(p)+numverts])->A + (int)( GEOMV_TO_FLOAT( t ) * A + 0.5 ); + + +// clip Poly against single plane --------------------------------------------- +// +Poly *CLIP_PlanePolyCornerColors( Poly *poly, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static Poly (the clipped polygon) + + //NOTE: + // clp_vtxlist and clp_nextindx have to be + // set correctly before calling this function. + + ASSERT( poly != NULL ); + ASSERT( plane != NULL ); + + ASSERT( ( poly->Flags & POLYFLAG_CORNERCOLORS ) != 0 ); + ASSERT( ( poly->Flags & POLYFLAG_WEDGEINDEXES ) == 0 ); + + // fetch geometry + dword *indxs = poly->VertIndxs; + int numverts = poly->NumVerts; + + ASSERT( indxs != NULL ); + ASSERT( numverts > 2 ); + ASSERT( numverts <= MAX_CLIPPOLY_VERTICES ); + + // check all vertices, calc outcode and distances + dword outcode = 0x00; + for ( int vcount = numverts; vcount > 0; vcount-- ) { + + plane_distances[ vcount-1 ] = + PLANE_DOT( plane, &clp_vtxlist[ indxs[ vcount-1 ] ] ) - + PLANE_OFFSET( plane ); + + if ( GEOMV_GTZERO( plane_distances[ vcount-1 ] ) ) + outcode |= 0x01; + outcode <<= 1; + } + + // trivial reject if no vertex in positive halfspace + if ( outcode == 0x00 ) + return NULL; + + // trivial accept if all vertices in negative halfspace + if ( outcode == outcode_acceptall[ numverts-1 ] ) + return poly; + + // duplicate last vertex code + if ( outcode & ( ~outcode_acceptall[ numverts-1 ] >> 1 ) ) + outcode |= 0x01; + + // toggle static output storage + Poly *destpoly = (Poly *) clip_polys[ poly == (Poly*)clip_polys ]; + dword *destindxs = (dword *) ( destpoly + 1 ); + dword *tempcolors = temp_colors; + + destpoly->FaceIndx = poly->FaceIndx; + destpoly->VertIndxs = destindxs; + destpoly->Flags = poly->Flags; + + // use last vertex first + int prev_vtx = numverts - 1; + + // process all edges + for ( int cur_vtx = 0; cur_vtx < numverts; outcode >>= 1, cur_vtx++ ) { + + switch ( outcode & 0x03 ) { + + // current neg, previous neg, stay invisible +// case 0x00: +// // skip vertex +// break; + + // current neg, previous pos, switch to neg halfspace + case 0x01: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = plane_distances[ prev_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, prev_vtx, cur_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = prevd - plane_distances[ cur_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } +#endif + } + break; + + // current pos, previous neg, switch to pos halfspace + case 0x02: + { + + ASSERT( clp_nextindx < CLIPPED_MAX_VERTS ); + +#ifdef CLIP_ORIENTED_EDGES + + // check direction (vertex index order) + if ( indxs[ cur_vtx ] >= indxs[ prev_vtx ] ) { + + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + + } else { + + geomv_t prevd = plane_distances[ cur_vtx ]; + geomv_t seglen = prevd - plane_distances[ prev_vtx ]; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ prev_vtx ] ], + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ cur_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, prev_vtx, cur_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } + } +#else + geomv_t prevd = plane_distances[ prev_vtx ]; + geomv_t seglen = plane_distances[ cur_vtx ] - prevd; + ASSERT( seglen >= 0 ); + + // don't create intersection vertex if both on plane + if ( seglen > FLOAT_TO_GEOMV( 0.00001 ) ) { + + geomv_t tpara = GEOMV_DIV( -prevd, seglen ); + + // interpolate xyz + Vector3 dvec; + VECSUB( &dvec, &clp_vtxlist[ indxs[ cur_vtx ] ], + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + CSAXPY( &clp_vtxlist[ clp_nextindx ], tpara, &dvec, + &clp_vtxlist[ indxs[ prev_vtx ] ] ); + clp_vtxlist[ clp_nextindx ].VisibleFrame = 0; + + // interpolate rgba + CLIP_CORNER_RGBA( tempcolors, tpara, cur_vtx, prev_vtx ); + tempcolors++; + + *destindxs++ = clp_nextindx++; + } +#endif + // store current index and color + *destindxs++ = indxs[ cur_vtx ]; + *tempcolors++ = indxs[ cur_vtx + numverts ]; + } + break; + + // current pos, previous pos, stay visible + case 0x03: + // store current index and color + *destindxs++ = indxs[ cur_vtx ]; + *tempcolors++ = indxs[ cur_vtx + numverts ]; + break; + } + + // remember previous vertex + prev_vtx = cur_vtx; + } + + // set new number of vertices + destpoly->NumVerts = destindxs - destpoly->VertIndxs; + + // test for degenerated polygons + if ( destpoly->NumVerts < 3 ) + return NULL; + + // apppend colors to vertex indexes + ASSERT( (dword)( tempcolors - temp_colors ) == destpoly->NumVerts ); + memcpy( destindxs, temp_colors, destpoly->NumVerts * sizeof( dword ) ); + + // return clipped polygon in static storage + return destpoly; +} + + +// clip Poly against volume (set of planes) ----------------------------------- +// +Poly *CLIP_VolumePoly( Poly *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static Poly (the clipped polygon) + + //NOTE: + // clp_vtxlist and clp_nextindx have to be + // set correctly before calling this function. + + ASSERT( poly != NULL ); + ASSERT( volume != NULL ); + + // check all planes that have not been culled already + for ( int curplane = 0; cullmask != 0x00; cullmask >>= 1, curplane++ ) { + + if ( cullmask & 0x01 ) { + + // clip against current plane + poly = CLIP_PlanePoly( poly, &volume[ curplane ] ); + + // one plane rejects: whole status is trivial reject + if ( poly == NULL ) + return poly; + } + } + + // return clipped polygon/status + return poly; +} + + +// clip Poly against volume (set of planes) ----------------------------------- +// +Poly *CLIP_VolumePolyColors( Poly *poly, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the polygon is trivial reject + // - poly if the polygon is trivial accept + // - pointer to a static Poly (the clipped polygon) + + //NOTE: + // clp_vtxlist and clp_nextindx have to be + // set correctly before calling this function. + + ASSERT( poly != NULL ); + ASSERT( volume != NULL ); + + // check all planes that have not been culled already + for ( int curplane = 0; cullmask != 0x00; cullmask >>= 1, curplane++ ) { + + if ( cullmask & 0x01 ) { + + // clip against current plane + if ( poly->Flags & POLYFLAG_WEDGEINDEXES ) { + poly = CLIP_PlanePolyWedgeColors( poly, &volume[ curplane ] ); + } else { + poly = CLIP_PlanePolyCornerColors( poly, &volume[ curplane ] ); + } + + // one plane rejects: whole status is trivial reject + if ( poly == NULL ) + return poly; + } + } + + // return clipped polygon/status + return poly; +} + + +// create clipped genobject from unclipped genobject (against volume) --------- +// +GenObject *CLIP_VolumeGenObject( GenObject *clipobj, Plane3 *volume, dword cullmask ) +{ + //NOTE: + // this function returns: + // - NULL if the object is trivial reject + // - pointer to a "pseudo-static" GenObject + // (the clipped object, may be trivial accept) + + ASSERT( clipobj != NULL ); + ASSERT( volume != NULL ); + + if ( clipped_obj == NULL ) { + + clipped_obj = (GenObject *) ALLOCMEM( clipped_obj_size ); + if ( clipped_obj == NULL ) { + OUTOFMEM( 0 ); + } + } + + // init first +#ifdef DEBUG + memset( clipped_obj, 0xcc, clipped_obj_size ); +#endif + + // fetch pointers to original vertex and polyon list + Vertex3 *vtxlist = clipobj->VertexList; + Poly *srcpoly = clipobj->PolyList; + int numpolys = clipobj->NumPolys; + + // copy over old header (including type fields) + ASSERT( clipobj->InstanceSize <= CLIPPED_MAX_INSTANCE_SIZE ); + memcpy( clipped_obj, clipobj, clipobj->InstanceSize ); + + // set pointers to new lists + clipped_obj->VertexList = (Vertex3 *) ( (char*)clipped_obj + clipped_obj->InstanceSize ); + clipped_obj->X_VertexList = (Vertex3 *) ( (char*)clipped_obj->VertexList + SZ_VERTEXLIST ); + clipped_obj->S_VertexList = (SPoint *) ( (char*)clipped_obj->X_VertexList + SZ_XVERTEXLIST ); + clipped_obj->PolyList = (Poly *) ( (char*)clipped_obj->S_VertexList + SZ_SVERTEXLIST ); + + // create pointers to new lists + clp_vtxlist = clipped_obj->VertexList; + clp_nextindx = clipped_obj->NumVerts; + Poly *dstpoly = clipped_obj->PolyList; + dword *dstindx = (dword *) ( (char*)dstpoly + numpolys * sizeof( Poly ) ); + + // copy over original vertices + ASSERT( clipobj->NumVerts <= CLIPPED_MAX_VERTS ); + memcpy( clp_vtxlist, vtxlist, clipobj->NumVerts * sizeof( Vertex3 ) ); + + // copy over original polygons (without indexes) + ASSERT( numpolys <= CLIPPED_MAX_POLYS ); + memcpy( dstpoly, srcpoly, numpolys * sizeof( Poly ) ); + + // clip all polygons + int polyemitted = FALSE; + for ( int pid = numpolys; pid > 0; pid--, dstpoly++ ) { + + Poly *clp = NULL; + + if ( dstpoly->Flags & POLYFLAG_CORNERCOLORS ) { + + // corner colors contained in polygon + clp = CLIP_VolumePolyColors( dstpoly, volume, cullmask ); + + } else if ( ( dstpoly->Flags & POLYFLAG_WEDGEINDEXES ) && + ( clipobj->WedgeLighted != NULL ) ) { + + // use wedge indexes to fetch colors + clp_wcolors = (dword *)clipobj->WedgeLighted; + clp = CLIP_VolumePolyColors( dstpoly, volume, cullmask ); + + } else { + + // only geometry + dstpoly->Flags = POLYFLAG_DEFAULT; + clp = CLIP_VolumePoly( dstpoly, volume, cullmask ); + } + + // check clip result + if ( clp != NULL ) { + + if ( clp != dstpoly ) { + + // copy vertex indexlist + size_t vindxnum = clp->NumVerts; + if ( clp->Flags & POLYFLAG_CORNERCOLORS ) + vindxnum += clp->NumVerts; + if ( clp->Flags & POLYFLAG_WEDGEINDEXES ) + vindxnum += clp->NumVerts; + memcpy( dstindx, clp->VertIndxs, vindxnum * sizeof( dword ) ); + + dstpoly->NumVerts = clp->NumVerts; + dstpoly->VertIndxs = dstindx; + dstpoly->Flags = clp->Flags; + dstindx += vindxnum; + } + polyemitted = TRUE; + + } else { + + //NOTE: + // the original vertex index-list stays + // intact. so if someone wants to retrieve + // vertices for, say, plane distance + // computation, this is still possible, + // although the polygon is clipped entirely. + + // make sure polygon gets rejected + dstpoly->NumVerts = 0; + } + } + + // set correct number of vertices for entire object + int numnewverts = clp_nextindx - clipped_obj->NumVerts; + ASSERT( numnewverts >= 0 ); + clipped_obj->NumVerts += numnewverts; + clipped_obj->NumPolyVerts += numnewverts; + + return polyemitted ? clipped_obj : NULL; +} + + +// create clipped genobject from unclipped genobject (against single plane) --- +// +GenObject *CLIP_PlaneGenObject( GenObject *clipobj, Plane3 *plane ) +{ + //NOTE: + // this function returns: + // - NULL if the object is trivial reject + // - clipobj if the object is trivial accept + // - pointer to a "pseudo-static" GenObject (the clipped object) + + ASSERT( clipobj != NULL ); + ASSERT( plane != NULL ); + + //TODO: + + return NULL; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( UTL_CLPO ) +{ + // limit is 31 due to bit-twiddling!! + ASSERT( MAX_CLIPPOLY_VERTICES < 32 ); + + // fill trivial accept table for all vertex counts + dword outcode = 0x02; + for ( int code = 0; code < MAX_CLIPPOLY_VERTICES; code++ ) { + + outcode_acceptall[ code ] = outcode; + outcode = ( outcode << 1 ) | 0x02; + } +} + + + diff --git a/src/libparsec/utl_cull.cpp b/src/libparsec/utl_cull.cpp new file mode 100644 index 0000000..893d82f --- /dev/null +++ b/src/libparsec/utl_cull.cpp @@ -0,0 +1,278 @@ +/* + * PARSEC - Culling Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "utl_cull.h" + + + +// determine indexes of reject and accept points with respect to a plane ------ +// +void CULL_ReAcIndexBox3( ReAcIndexBox3 *reac, Plane3 *plane ) +{ + ASSERT( reac != NULL ); + ASSERT( plane != NULL ); + + //NOTE: + // reac->reject will be the point with the + // greatest signed distance to the plane. + // reac->accept will be the point with the + // least signed distance to the plane. + + if ( GEOMV_NEGATIVE( plane->X ) ) { + reac->reject[ 0 ] = 0; + reac->accept[ 0 ] = 3; + } else { + reac->reject[ 0 ] = 3; + reac->accept[ 0 ] = 0; + } + + if ( GEOMV_NEGATIVE( plane->Y ) ) { + reac->reject[ 1 ] = 1; + reac->accept[ 1 ] = 4; + } else { + reac->reject[ 1 ] = 4; + reac->accept[ 1 ] = 1; + } + + if ( GEOMV_NEGATIVE( plane->Z ) ) { + reac->reject[ 2 ] = 2; + reac->accept[ 2 ] = 5; + } else { + reac->reject[ 2 ] = 5; + reac->accept[ 2 ] = 2; + } +} + + +// determine coordinates of reject and accept points with respect to a plane -- +// +void CULL_ReAcPointBox3( ReAcPointBox3 *reac, CullBox3 *cullbox, Plane3 *plane ) +{ + ASSERT( reac != NULL ); + ASSERT( cullbox != NULL ); + ASSERT( plane != NULL ); + + //NOTE: + // reac->reject will be the point with the + // greatest signed distance to the plane. + // reac->accept will be the point with the + // least signed distance to the plane. + + if ( GEOMV_NEGATIVE( plane->X ) ) { + reac->reject.X = cullbox->minmax[ 0 ]; + reac->accept.X = cullbox->minmax[ 3 ]; + } else { + reac->reject.X = cullbox->minmax[ 3 ]; + reac->accept.X = cullbox->minmax[ 0 ]; + } + + if ( GEOMV_NEGATIVE( plane->Y ) ) { + reac->reject.Y = cullbox->minmax[ 1 ]; + reac->accept.Y = cullbox->minmax[ 4 ]; + } else { + reac->reject.Y = cullbox->minmax[ 4 ]; + reac->accept.Y = cullbox->minmax[ 1 ]; + } + + if ( GEOMV_NEGATIVE( plane->Z ) ) { + reac->reject.Z = cullbox->minmax[ 2 ]; + reac->accept.Z = cullbox->minmax[ 5 ]; + } else { + reac->reject.Z = cullbox->minmax[ 5 ]; + reac->accept.Z = cullbox->minmax[ 2 ]; + } +} + + +// augment set of planes by reject/accept points for culling ------------------ +// +void CULL_MakeVolumeCullVolume( Plane3 *volume, CullPlane3 *cullvolume, dword cullmask ) +{ + ASSERT( volume != NULL ); + ASSERT( cullvolume != NULL ); + + for ( ; cullmask != 0x00; cullmask >>= 1, volume++, cullvolume++ ) { + + if ( cullmask & 0x01 ) { + + // copy plane + cullvolume->plane = *volume; + + // calc reac indexes + CULL_ReAcIndexBox3( &cullvolume->reacx, &cullvolume->plane ); + } + } +} + + +// cull an axial bounding box against a cull volume (set of cull planes) ------ +// +int CULL_BoxAgainstCullVolume( CullBox3 *cullbox, CullPlane3 *volume, dword *cullmask ) +{ + //NOTE: + // this function returns: + // - TRUE if the box is trivial reject + // - FALSE if the box is not trivial reject + // - if ( *cullmask == 0x00 ) afterwards the box is trivial accept + // - if ( *cullmask != 0x00 ) afterwards the box needs to be clipped + + ASSERT( cullbox != NULL ); + ASSERT( volume != NULL ); + ASSERT( cullmask != NULL ); + + dword curmask = *cullmask; + CullPlane3* cullplane = volume; + + for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) { + + if ( curmask & 0x01 ) { + + // one plane rejects: whole status is trivial reject + geomv_t dist = PLANEDIST_REJECTPOINT( cullplane, cullbox ); + if ( GEOMV_NEGATIVE( dist ) ) { + return TRUE; + } + + // mask plane if trivial accept + dist = PLANEDIST_ACCEPTPOINT( cullplane, cullbox ); + if ( GEOMV_POSITIVE( dist ) ) { + *cullmask &= ~( 1 << curplane ); + } + } + + // sizeof( CullPlane3 ) is no power of two + cullplane = (CullPlane3 *)( (char *)cullplane + sizeof( cullplane[ 0 ] ) ); + } + + return FALSE; +} + + +// cull an axial bounding box against a volume (set of planes) ---------------- +// +int CULL_BoxAgainstVolume( CullBox3 *cullbox, Plane3 *volume, dword *cullmask ) +{ + //NOTE: + // this function returns: + // - TRUE if the box is trivial reject + // - FALSE if the box is not trivial reject + // - if ( *cullmask == 0x00 ) afterwards the box is trivial accept + // - if ( *cullmask != 0x00 ) afterwards the box needs to be clipped + + ASSERT( cullbox != NULL ); + ASSERT( volume != NULL ); + ASSERT( cullmask != NULL ); + + dword curmask = *cullmask; + + for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) { + + if ( curmask & 0x01 ) { + + Plane3 *plane = &volume[ curplane ]; + + // determine reject/accept points + ReAcPointBox3 reac; + CULL_ReAcPointBox3( &reac, cullbox, plane ); + + // one plane rejects: whole status is trivial reject + if ( PLANE_DOT( plane, &reac.reject ) <= PLANE_OFFSET( plane ) ) { + return TRUE; + } + + // mask plane if trivial accept + if ( PLANE_DOT( plane, &reac.accept ) >= PLANE_OFFSET( plane ) ) { + *cullmask &= ~( 1 << curplane ); + } + } + } + + return FALSE; +} + + +// cull a bounding sphere against a volume (set of planes) -------------------- +// +int CULL_SphereAgainstVolume( Sphere3 *sphere, Plane3 *volume, dword *cullmask ) +{ + //NOTE: + // this function returns: + // - TRUE if the sphere is trivial reject + // - FALSE if the sphere is not trivial reject + // - if ( *cullmask == 0x00 ) afterwards the sphere is trivial accept + // - if ( *cullmask != 0x00 ) afterwards the sphere needs to be clipped + + ASSERT( sphere != NULL ); + ASSERT( volume != NULL ); + ASSERT( cullmask != NULL ); + + dword curmask = *cullmask; + + for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) { + + if ( curmask & 0x01 ) { + + Plane3 *plane = &volume[ curplane ]; + geomv_t dist = PLANE_DOT( plane, sphere ) - PLANE_OFFSET( plane ); + + // one plane rejects: whole status is trivial reject + if ( dist < -sphere->R ) { + return TRUE; + } + + // mask plane if trivial accept + if ( dist > sphere->R ) { + *cullmask &= ~( 1 << curplane ); + } + } + } + + return FALSE; +} + + + diff --git a/src/libparsec/utl_logfile.cpp b/src/libparsec/utl_logfile.cpp new file mode 100644 index 0000000..60ee101 --- /dev/null +++ b/src/libparsec/utl_logfile.cpp @@ -0,0 +1,260 @@ +/* + * PARSEC - Logfile class + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:46 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdarg.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// C library +#ifdef SYSTEM_TARGET_WINDOWS +# include <time.h> +#else +# include <sys/time.h> +#endif + +// platform specific includes +#ifdef SYSTEM_TARGET_WINDOWS + #include "windows.h" + #include "mmsystem.h" + #pragma comment( lib, "winmm.lib" ) +#endif // SYSTEM_TARGET_WINDOWS + + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "sys_defs.h" + +// local module header +#include "utl_logfile.h" + + +// flags ---------------------------------------------------------------------- +// +#define ENABLE_AUTO_FLUSH + +// constants ------------------------------------------------------------------ +// +#define MAX_REGISTERED_LOGFILES 10 + + + +// global logfile ------------------------------------------------------------- +// +#ifdef ENABLE_LOGOUT_COMMAND + + UTL_LogFile g_Logfile( "global.log" ); + +#endif // ENABLE_LOGOUT_COMMAND + +// global list of registered logfiles ----------------------------------------- +// +static UTL_LogFile* g_RegisteredLogfiles[ MAX_REGISTERED_LOGFILES ]; +static int g_nNumRegisteredLogfiles = 0; + + +// register a logfile globally to ensure it is flushed upon program termination +// +PRIVATE +int RegisterLogfile( UTL_LogFile* pLogfile ) +{ + ASSERT( pLogfile != NULL ); + + // check if list is full + if ( g_nNumRegisteredLogfiles >= MAX_REGISTERED_LOGFILES ) { + return FALSE; + } + + // append to list + g_RegisteredLogfiles[ g_nNumRegisteredLogfiles ] = pLogfile; + g_nNumRegisteredLogfiles++; + + return TRUE; +} + + +// flush all registerd logfiles ----------------------------------------------- +// +void UTL_FlushRegisteredLogfiles() +{ + for( int nLogfile = 0; nLogfile < g_nNumRegisteredLogfiles; nLogfile++ ) { + g_RegisteredLogfiles[ nLogfile ]->Flush(); + } +} + + +// add an entry to the logfile ------------------------------------------------ +// +void UTL_LogFile::_AddEntry( const char* szEntry, size_t len2 ) +{ + ASSERT( szEntry != NULL ); + + //FIXME: use SYSs_GetCurTimeString() + + // prepend the current date/time + +#ifdef SYSTEM_TARGET_WINDOWS + + //FIXME: recheck whether SYSs_GetCurTimeString() works properly + //fprintf( fp, "%s: ", SYSs_GetCurTimeString() ); + + LARGE_INTEGER now; + LARGE_INTEGER TimeFreq; + QueryPerformanceCounter( &now ); + QueryPerformanceFrequency( &TimeFreq ); + + timeval tv; + tv.tv_usec = (long) ( ( now.QuadPart % TimeFreq.QuadPart * 1000000 ) / TimeFreq.QuadPart ); + tv.tv_sec = (long) ( now.QuadPart / TimeFreq.QuadPart ); + +#else + + struct timeval tv; + struct timezone tz; + gettimeofday( &tv, &tz ); + +#endif + + char szTimeString[ 32 + 1 ]; + snprintf( szTimeString, 32, "%u.%06u\t", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec ); + szTimeString[ 32 ] = 0; + + size_t len1 = strlen( szTimeString ); + + if ( ( m_nBufferLen + len1 + len2 ) >= MAX_LOG_BUFFER_LEN ) { + Flush(); + } + + // check whether to directly write to the file + if ( ( len1 + len2 ) >= MAX_LOG_BUFFER_LEN ) { + fwrite( szTimeString, 1, len1, m_pFile ); + fwrite( szEntry, 1, len2, m_pFile ); + } else { + // copy strings to buffer + memcpy( &m_szBuffer[ m_nBufferLen ], szTimeString, len1 ); + memcpy( &m_szBuffer[ m_nBufferLen + len1 ], szEntry, len2 ); + m_nBufferLen += ( len1 + len2 ); + m_szBuffer[ m_nBufferLen ] = 0; + +#define REFFRAME_TO_FORCE_FLUSH DEFAULT_REFFRAME_FREQUENCY + +#ifdef ENABLE_AUTO_FLUSH + // check for forced flush + if ( ( m_LastFlushRefframe + REFFRAME_TO_FORCE_FLUSH ) < SYSs_GetRefFrameCount() ) { + Flush(); + } +#endif // ENABLE_AUTO_FLUSH + } +} + +// standard ctor -------------------------------------------------------------- +// +UTL_LogFile::UTL_LogFile( const char* szFilename /* = NULL */) : + m_nBufferLen( 0 ), + m_pFile( NULL ) +{ + m_szBuffer[ 0 ] = 0; + + if ( szFilename != NULL ) { + if ( !Open( szFilename ) ) { + MSGOUT( "error opening logfile '%s'", szFilename ); + } + } + + m_LastFlushRefframe = SYSs_GetRefFrameCount(); + + // register the logfile + RegisterLogfile( this ); +} + +// standard dtor -------------------------------------------------------------- +// +UTL_LogFile::~UTL_LogFile() +{ + if ( m_pFile != NULL ) { + Flush(); + fclose( m_pFile ); + } +} + +// open the logfile ----------------------------------------------------------- +// +int UTL_LogFile::Open( const char* szFilename ) +{ + ASSERT( szFilename != NULL ); + ASSERT( m_pFile == NULL ); + + m_pFile = fopen( szFilename, "a" ); + return ( m_pFile != NULL ); +} + +// printf like adding to the logfile ------------------------------------------ +// +int UTL_LogFile::printf( const char *format, ... ) +{ + long formatlen = strlen( format ); + if ( formatlen < 1 ) { + return -1; + } + + char szTemp[ MAX_LOG_BUFFER_LEN + 1 ]; + + va_list ap; + va_start( ap, format ); + int rc = vsnprintf( szTemp, MAX_LOG_BUFFER_LEN, format, ap ); + va_end( ap ); + + if ( rc > 0 ) { + strcat( szTemp, "\n" ); + _AddEntry( szTemp, rc + 1 ); + } + + return rc; +} + +// flush the buffer to the disk file ------------------------------------------ +// +void UTL_LogFile::Flush() +{ + ASSERT( m_pFile != NULL ); + + fwrite( m_szBuffer, m_nBufferLen, 1, m_pFile ); + + m_szBuffer[ 0 ] = 0; + m_nBufferLen = 0; + + m_LastFlushRefframe = SYSs_GetRefFrameCount(); + + fflush( m_pFile ); +} diff --git a/src/libparsec/utl_math.cpp b/src/libparsec/utl_math.cpp new file mode 100644 index 0000000..72943d6 --- /dev/null +++ b/src/libparsec/utl_math.cpp @@ -0,0 +1,620 @@ +/* + * PARSEC - Math Code I (ANSI-C) + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999 + * Copyright (c) Andreas Varga <sid@parsec.org> 1998 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// local module header + + +// flags +//#define USE_SINCOSTABLE + + +// sine/cosine tables --------------------------------------------------------- +// +float fsin_tab[] = +#include "utl_fsin.h" + +float fcos_tab[] = +#include "utl_fcos.h" + + +// adjoint matrix sub-determinant table --------------------------------------- +// +dword adj_tab[ 4*9 ] = { + +#define M_WIDTH 4 // number of row elements + + M_WIDTH*1+1, // [1][1] + M_WIDTH*2+3, // [2][2] + M_WIDTH*1+3, // [1][2] + M_WIDTH*2+1, // [2][1] + + M_WIDTH*0+3, // [0][2] + M_WIDTH*2+1, // [2][1] + M_WIDTH*0+1, // [0][1] + M_WIDTH*2+3, // [2][2] + + M_WIDTH*0+1, // [0][1] + M_WIDTH*1+3, // [1][2] + M_WIDTH*0+3, // [0][2] + M_WIDTH*1+1, // [1][1] + + M_WIDTH*1+3, // [1][2] + M_WIDTH*2+0, // [2][0] + M_WIDTH*1+0, // [1][0] + M_WIDTH*2+3, // [2][2] + + M_WIDTH*0+0, // [0][0] + M_WIDTH*2+3, // [2][2] + M_WIDTH*0+3, // [0][2] + M_WIDTH*2+0, // [2][0] + + M_WIDTH*0+3, // [0][2] + M_WIDTH*1+0, // [1][0] + M_WIDTH*0+0, // [0][0] + M_WIDTH*1+3, // [1][2] + + M_WIDTH*1+0, // [1][0] + M_WIDTH*2+1, // [2][1] + M_WIDTH*1+1, // [1][1] + M_WIDTH*2+0, // [2][0] + + M_WIDTH*0+1, // [0][1] + M_WIDTH*2+0, // [2][0] + M_WIDTH*0+0, // [0][0] + M_WIDTH*2+1, // [2][1] + + M_WIDTH*0+0, // [0][0] + M_WIDTH*1+1, // [1][1] + M_WIDTH*0+1, // [0][1] + M_WIDTH*1+0, // [1][0] +}; + + +// calculate adjoint 3x3 matrix ----------------------------------------------- +// +void AdjointMtx( const Xmatrx smatrx, Xmatrx dmatrx ) +{ + ASSERT( smatrx != NULL ); + ASSERT( dmatrx != NULL ); + ASSERT( smatrx != dmatrx ); + + geomv_t *pdmatrx = (geomv_t *) dmatrx; + + int tabindx = 0; + for ( int curdet = 0; curdet < 9; curdet++, tabindx+=4 ) { + + geomv_t A = *( (geomv_t *)smatrx + adj_tab[ tabindx + 0 ] ); + geomv_t B = *( (geomv_t *)smatrx + adj_tab[ tabindx + 2 ] ); + geomv_t C = *( (geomv_t *)smatrx + adj_tab[ tabindx + 3 ] ); + geomv_t D = *( (geomv_t *)smatrx + adj_tab[ tabindx + 1 ] ); + + geomv_t d1 = GEOMV_MUL( A, D ); + geomv_t d2 = GEOMV_MUL( B, C ); + + pdmatrx[ curdet ] = d1 - d2; + } +} + + +// multiply two 4x4 matrices -------------------------------------------------- +// +void MtxMtxMUL( const Xmatrx matrxb, const Xmatrx matrxa, Xmatrx dmatrx ) +{ + ASSERT( matrxb != NULL ); + ASSERT( matrxa != NULL ); + ASSERT( dmatrx != NULL ); + ASSERT( matrxb != dmatrx ); + ASSERT( matrxa != dmatrx ); + + //NOTE: + // D = B * A + // --------- + // [ d d d d ] [ b b b b ] [ a a a a ] + // [ d d d d ] = [ b b b b ] * [ a a a a ] + // [ d d d d ] [ b b b b ] [ a a a a ] + // [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ] + + dmatrx[0][0] = GEOMV_MUL(matrxb[0][0],matrxa[0][0]) + GEOMV_MUL(matrxb[0][1],matrxa[1][0]) + GEOMV_MUL(matrxb[0][2],matrxa[2][0]); + dmatrx[0][1] = GEOMV_MUL(matrxb[0][0],matrxa[0][1]) + GEOMV_MUL(matrxb[0][1],matrxa[1][1]) + GEOMV_MUL(matrxb[0][2],matrxa[2][1]); + dmatrx[0][2] = GEOMV_MUL(matrxb[0][0],matrxa[0][2]) + GEOMV_MUL(matrxb[0][1],matrxa[1][2]) + GEOMV_MUL(matrxb[0][2],matrxa[2][2]); + dmatrx[0][3] = GEOMV_MUL(matrxb[0][0],matrxa[0][3]) + GEOMV_MUL(matrxb[0][1],matrxa[1][3]) + GEOMV_MUL(matrxb[0][2],matrxa[2][3]) + matrxb[0][3]; + dmatrx[1][0] = GEOMV_MUL(matrxb[1][0],matrxa[0][0]) + GEOMV_MUL(matrxb[1][1],matrxa[1][0]) + GEOMV_MUL(matrxb[1][2],matrxa[2][0]); + dmatrx[1][1] = GEOMV_MUL(matrxb[1][0],matrxa[0][1]) + GEOMV_MUL(matrxb[1][1],matrxa[1][1]) + GEOMV_MUL(matrxb[1][2],matrxa[2][1]); + dmatrx[1][2] = GEOMV_MUL(matrxb[1][0],matrxa[0][2]) + GEOMV_MUL(matrxb[1][1],matrxa[1][2]) + GEOMV_MUL(matrxb[1][2],matrxa[2][2]); + dmatrx[1][3] = GEOMV_MUL(matrxb[1][0],matrxa[0][3]) + GEOMV_MUL(matrxb[1][1],matrxa[1][3]) + GEOMV_MUL(matrxb[1][2],matrxa[2][3]) + matrxb[1][3]; + dmatrx[2][0] = GEOMV_MUL(matrxb[2][0],matrxa[0][0]) + GEOMV_MUL(matrxb[2][1],matrxa[1][0]) + GEOMV_MUL(matrxb[2][2],matrxa[2][0]); + dmatrx[2][1] = GEOMV_MUL(matrxb[2][0],matrxa[0][1]) + GEOMV_MUL(matrxb[2][1],matrxa[1][1]) + GEOMV_MUL(matrxb[2][2],matrxa[2][1]); + dmatrx[2][2] = GEOMV_MUL(matrxb[2][0],matrxa[0][2]) + GEOMV_MUL(matrxb[2][1],matrxa[1][2]) + GEOMV_MUL(matrxb[2][2],matrxa[2][2]); + dmatrx[2][3] = GEOMV_MUL(matrxb[2][0],matrxa[0][3]) + GEOMV_MUL(matrxb[2][1],matrxa[1][3]) + GEOMV_MUL(matrxb[2][2],matrxa[2][3]) + matrxb[2][3]; +} + + +// multiply two 4x4 matrices (neglects translation part of matrix a) ---------- +// +void MtxMtxMULt( const Xmatrx matrxb, const Xmatrx matrxa, Xmatrx dmatrx ) +{ + ASSERT( matrxb != NULL ); + ASSERT( matrxa != NULL ); + ASSERT( dmatrx != NULL ); + ASSERT( matrxb != dmatrx ); + ASSERT( matrxa != dmatrx ); + + //NOTE: + // D = B * A + // --------- + // [ d d d d ] [ b b b b ] [ a a a 0 ] + // [ d d d d ] = [ b b b b ] * [ a a a 0 ] + // [ d d d d ] [ b b b b ] [ a a a 0 ] + // [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ] + + dmatrx[0][0] = GEOMV_MUL(matrxb[0][0],matrxa[0][0]) + GEOMV_MUL(matrxb[0][1],matrxa[1][0]) + GEOMV_MUL(matrxb[0][2],matrxa[2][0]); + dmatrx[0][1] = GEOMV_MUL(matrxb[0][0],matrxa[0][1]) + GEOMV_MUL(matrxb[0][1],matrxa[1][1]) + GEOMV_MUL(matrxb[0][2],matrxa[2][1]); + dmatrx[0][2] = GEOMV_MUL(matrxb[0][0],matrxa[0][2]) + GEOMV_MUL(matrxb[0][1],matrxa[1][2]) + GEOMV_MUL(matrxb[0][2],matrxa[2][2]); + dmatrx[0][3] = matrxb[0][3]; + dmatrx[1][0] = GEOMV_MUL(matrxb[1][0],matrxa[0][0]) + GEOMV_MUL(matrxb[1][1],matrxa[1][0]) + GEOMV_MUL(matrxb[1][2],matrxa[2][0]); + dmatrx[1][1] = GEOMV_MUL(matrxb[1][0],matrxa[0][1]) + GEOMV_MUL(matrxb[1][1],matrxa[1][1]) + GEOMV_MUL(matrxb[1][2],matrxa[2][1]); + dmatrx[1][2] = GEOMV_MUL(matrxb[1][0],matrxa[0][2]) + GEOMV_MUL(matrxb[1][1],matrxa[1][2]) + GEOMV_MUL(matrxb[1][2],matrxa[2][2]); + dmatrx[1][3] = matrxb[1][3]; + dmatrx[2][0] = GEOMV_MUL(matrxb[2][0],matrxa[0][0]) + GEOMV_MUL(matrxb[2][1],matrxa[1][0]) + GEOMV_MUL(matrxb[2][2],matrxa[2][0]); + dmatrx[2][1] = GEOMV_MUL(matrxb[2][0],matrxa[0][1]) + GEOMV_MUL(matrxb[2][1],matrxa[1][1]) + GEOMV_MUL(matrxb[2][2],matrxa[2][1]); + dmatrx[2][2] = GEOMV_MUL(matrxb[2][0],matrxa[0][2]) + GEOMV_MUL(matrxb[2][1],matrxa[1][2]) + GEOMV_MUL(matrxb[2][2],matrxa[2][2]); + dmatrx[2][3] = matrxb[2][3]; +} + + +// multiply 4x4 matrix by 4x1 matrix (column vector) -------------------------- +// +void MtxVctMUL( const Xmatrx matrx, const Vector3 *svect, Vector3 *dvect ) +{ + ASSERT( matrx != NULL ); + ASSERT( svect != NULL ); + ASSERT( dvect != NULL ); + ASSERT( svect != dvect ); + + dvect->X = GEOMV_MUL(matrx[0][0],svect->X) + GEOMV_MUL(matrx[0][1],svect->Y) + GEOMV_MUL(matrx[0][2],svect->Z) + matrx[0][3]; + dvect->Y = GEOMV_MUL(matrx[1][0],svect->X) + GEOMV_MUL(matrx[1][1],svect->Y) + GEOMV_MUL(matrx[1][2],svect->Z) + matrx[1][3]; + dvect->Z = GEOMV_MUL(matrx[2][0],svect->X) + GEOMV_MUL(matrx[2][1],svect->Y) + GEOMV_MUL(matrx[2][2],svect->Z) + matrx[2][3]; +} + + +// multiply 4x4 matrix by 4x1 matrix (column vector); skip translation -------- +// +void MtxVctMULt( const Xmatrx matrx, const Vector3 *svect, Vector3 *dvect ) +{ + ASSERT( matrx != NULL ); + ASSERT( svect != NULL ); + ASSERT( dvect != NULL ); + ASSERT( svect != dvect ); + + //NOTE: + // actually 3x3 matrix times 3x1 matrix since all + // homogeneous components (including translation!) + // are neglected (assumed to be zero/one). + + dvect->X = GEOMV_MUL(matrx[0][0],svect->X) + GEOMV_MUL(matrx[0][1],svect->Y) + GEOMV_MUL(matrx[0][2],svect->Z); + dvect->Y = GEOMV_MUL(matrx[1][0],svect->X) + GEOMV_MUL(matrx[1][1],svect->Y) + GEOMV_MUL(matrx[1][2],svect->Z); + dvect->Z = GEOMV_MUL(matrx[2][0],svect->X) + GEOMV_MUL(matrx[2][1],svect->Y) + GEOMV_MUL(matrx[2][2],svect->Z); +} + + +// multiply basis vector 3 by scalar (generate direction vector) -------------- +// +void DirVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ) +{ + ASSERT( matrx != NULL ); + ASSERT( dvect != NULL ); + + dvect->X = GEOMV_MUL( matrx[ 0 ][ 2 ], scalar ); + dvect->Y = GEOMV_MUL( matrx[ 1 ][ 2 ], scalar ); + dvect->Z = GEOMV_MUL( matrx[ 2 ][ 2 ], scalar ); +} + +// multiply basis vector 3 by scalar (generate horizontal slide vector) ------- +// +void RightVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ) +{ + ASSERT( matrx != NULL ); + ASSERT( dvect != NULL ); + + dvect->X = GEOMV_MUL( matrx[ 0 ][ 0 ], scalar ); + dvect->Y = GEOMV_MUL( matrx[ 1 ][ 0 ], scalar ); + dvect->Z = GEOMV_MUL( matrx[ 2 ][ 0 ], scalar ); +} + +// multiply basis vector 3 by scalar (generate vertical slide vector) --------- +// +void UpVctMUL( const Xmatrx matrx, geomv_t scalar, Vector3 *dvect ) +{ + ASSERT( matrx != NULL ); + ASSERT( dvect != NULL ); + + dvect->X = GEOMV_MUL( matrx[ 0 ][ 1 ], scalar ); + dvect->Y = GEOMV_MUL( matrx[ 1 ][ 1 ], scalar ); + dvect->Z = GEOMV_MUL( matrx[ 2 ][ 1 ], scalar ); +} + +// Reflect incident vector (ivec) on surface normal to produce reflection (destvec) +// 'normal' needs to be normalized, ivec doesn't +// +void VctReflect( const Vector3 *ivec, const Vector3 *normal, Vector3 *destvec ) +{ + ASSERT(ivec != NULL); + ASSERT(destvec != NULL); + ASSERT(normal != NULL); + + float dot = DotProduct(ivec, normal); + + destvec->X = ivec->X - 2.0f * dot * normal->X; + destvec->Y = ivec->Y - 2.0f * dot * normal->Y; + destvec->Z = ivec->Z - 2.0f * dot * normal->Z; +} + +// calculate new position from forward/horizontal/vertical movements ---------- +// +void CalcMovement( Vector3* movement, const Xmatrx frame, fixed_t forward, geomv_t horiz, geomv_t vert, refframe_t refframes ) +{ + ASSERT( movement != NULL ); + ASSERT( frame != NULL ); + + // horizontal-slide + Vector3 rightvec; + geomv_t horiz_slide = horiz * refframes; + RightVctMUL( frame, horiz_slide, &rightvec ); + movement->X = rightvec.X; + movement->Y = rightvec.Y; + movement->Z = rightvec.Z; + + // vertical-slide + Vector3 upvec; + geomv_t vert_slide = vert * refframes; + UpVctMUL( frame, vert_slide, &upvec ); + movement->X += upvec.X; + movement->Y += upvec.Y; + movement->Z += upvec.Z; + + // forward movement + Vector3 dirvec; + fixed_t forward_movement = forward * refframes; + DirVctMUL( frame, FIXED_TO_GEOMV( forward_movement ), &dirvec ); + movement->X += dirvec.X; + movement->Y += dirvec.Y; + movement->Z += dirvec.Z; +} + +// fetch sine/cosine value for given angle from table ------------------------- +// +void GetSinCos( dword angle, sincosval_s *resultp ) +{ + ASSERT( resultp != NULL ); + +#ifdef USE_SINCOSTABLE + + //NOTE: + // uses 32K table (4K entries for sin and cos each) + // angles are in BAMS + + int tabindx = ( angle & 0xffff ) >> 4; + resultp->sinval = FLOAT_TO_GEOMV( fsin_tab[ tabindx ] ); + resultp->cosval = FLOAT_TO_GEOMV( fcos_tab[ tabindx ] ); + +#else + + resultp->sinval = FLOAT_TO_GEOMV( sin( BAMS_TO_RAD( angle ) ) ); + resultp->cosval = FLOAT_TO_GEOMV( cos( BAMS_TO_RAD( angle ) ) ); + +#endif + +} + + +// rotate vector space around x axis (multiply from the right) ---------------- +// +void ObjRotX( Xmatrx matrix, bams_t pitch ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( pitch, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = GEOMV_1; + rotmtx[0][1] = GEOMV_0; + rotmtx[0][2] = GEOMV_0; +// rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = GEOMV_0; + rotmtx[1][1] = sincosv.cosval; + rotmtx[1][2] = -sincosv.sinval; +// rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = GEOMV_0; + rotmtx[2][1] = sincosv.sinval; + rotmtx[2][2] = sincosv.cosval; +// rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMULt( matrix, rotmtx, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// rotate vector space around y axis (multiply from the right) ---------------- +// +void ObjRotY( Xmatrx matrix, bams_t yaw ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( yaw, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = sincosv.cosval; + rotmtx[0][1] = GEOMV_0; + rotmtx[0][2] = sincosv.sinval; +// rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = GEOMV_0; + rotmtx[1][1] = GEOMV_1; + rotmtx[1][2] = GEOMV_0; +// rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = -sincosv.sinval; + rotmtx[2][1] = GEOMV_0; + rotmtx[2][2] = sincosv.cosval; +// rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMULt( matrix, rotmtx, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// rotate vector space around z axis (multiply from the right) ---------------- +// +void ObjRotZ( Xmatrx matrix, bams_t roll ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( roll, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = sincosv.cosval; + rotmtx[0][1] = -sincosv.sinval; + rotmtx[0][2] = GEOMV_0; +// rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = sincosv.sinval; + rotmtx[1][1] = sincosv.cosval; + rotmtx[1][2] = GEOMV_0; +// rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = GEOMV_0; + rotmtx[2][1] = GEOMV_0; + rotmtx[2][2] = GEOMV_1; +// rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMULt( matrix, rotmtx, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// rotate vector space around x axis (multiply from the left) ----------------- +// +void CamRotX( Xmatrx matrix, bams_t pitch ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( pitch, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = GEOMV_1; + rotmtx[0][1] = GEOMV_0; + rotmtx[0][2] = GEOMV_0; + rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = GEOMV_0; + rotmtx[1][1] = sincosv.cosval; + rotmtx[1][2] = -sincosv.sinval; + rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = GEOMV_0; + rotmtx[2][1] = sincosv.sinval; + rotmtx[2][2] = sincosv.cosval; + rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMUL( rotmtx, matrix, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// rotate vector space around y axis (multiply from the left) ----------------- +// +void CamRotY( Xmatrx matrix, bams_t yaw ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( yaw, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = sincosv.cosval; + rotmtx[0][1] = GEOMV_0; + rotmtx[0][2] = sincosv.sinval; + rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = GEOMV_0; + rotmtx[1][1] = GEOMV_1; + rotmtx[1][2] = GEOMV_0; + rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = -sincosv.sinval; + rotmtx[2][1] = GEOMV_0; + rotmtx[2][2] = sincosv.cosval; + rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMUL( rotmtx, matrix, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// rotate vector space around z axis (multiply from the left) ----------------- +// +void CamRotZ( Xmatrx matrix, bams_t roll ) +{ + ASSERT( matrix != NULL ); + + sincosval_s sincosv; + GetSinCos( roll, &sincosv ); + + Xmatrx rotmtx; + rotmtx[0][0] = sincosv.cosval; + rotmtx[0][1] = -sincosv.sinval; + rotmtx[0][2] = GEOMV_0; + rotmtx[0][3] = GEOMV_0; + rotmtx[1][0] = sincosv.sinval; + rotmtx[1][1] = sincosv.cosval; + rotmtx[1][2] = GEOMV_0; + rotmtx[1][3] = GEOMV_0; + rotmtx[2][0] = GEOMV_0; + rotmtx[2][1] = GEOMV_0; + rotmtx[2][2] = GEOMV_1; + rotmtx[2][3] = GEOMV_0; + + Xmatrx destmtx; + MtxMtxMUL( rotmtx, matrix, destmtx ); + memcpy( matrix, destmtx, sizeof( Xmatrx ) ); +} + + +// calc dot-product of two vectors (*v1 * *v2) -------------------------------- +// +geomv_t DotProduct( const Vector3 *vect1, const Vector3 *vect2 ) +{ + ASSERT( vect1 != NULL ); + ASSERT( vect2 != NULL ); + + return GEOMV_MUL( vect1->X, vect2->X ) + GEOMV_MUL( vect1->Y, vect2->Y ) + GEOMV_MUL( vect1->Z, vect2->Z ); +} + + +// calc cross product of two vectors (*cproduct = *v1 x *v2) ------------------ +// +void CrossProduct( const Vector3 *vect1, const Vector3 *vect2, Vector3 *cproduct ) +{ + ASSERT( vect1 != NULL ); + ASSERT( vect2 != NULL ); + ASSERT( cproduct != NULL ); + ASSERT( vect1 != cproduct ); + ASSERT( vect2 != cproduct ); + + cproduct->X = GEOMV_MUL( vect1->Y, vect2->Z ) - GEOMV_MUL( vect1->Z, vect2->Y ); + cproduct->Y = GEOMV_MUL( vect1->Z, vect2->X ) - GEOMV_MUL( vect1->X, vect2->Z ); + cproduct->Z = GEOMV_MUL( vect1->X, vect2->Y ) - GEOMV_MUL( vect1->Y, vect2->X ); +} + + +// calc cross product of two vectors imbedded in matrix ----------------------- +// +void CrossProduct2( const geomv_t *vect1, const geomv_t *vect2, geomv_t *cproduct ) +{ + ASSERT( vect1 != NULL ); + ASSERT( vect2 != NULL ); + ASSERT( cproduct != NULL ); + ASSERT( vect1 != cproduct ); + ASSERT( vect2 != cproduct ); + + cproduct[0] = GEOMV_MUL( vect1[4], vect2[8] ) - GEOMV_MUL( vect1[8], vect2[4] ); + cproduct[4] = GEOMV_MUL( vect1[8], vect2[0] ) - GEOMV_MUL( vect1[0], vect2[8] ); + cproduct[8] = GEOMV_MUL( vect1[0], vect2[4] ) - GEOMV_MUL( vect1[4], vect2[0] ); +} + + +// re-orthogonalize matrix column vectors ------------------------------------- +// +void ReOrthoMtx( Xmatrx matrix ) +{ + ASSERT( matrix != NULL ); + + //TODO: + // replace with numerically more + // sane version. + + CrossProduct2( &matrix[ 0 ][ 0 ], &matrix[ 0 ][ 1 ], &matrix[ 0 ][ 2 ] ); + CrossProduct2( &matrix[ 0 ][ 1 ], &matrix[ 0 ][ 2 ], &matrix[ 0 ][ 0 ] ); +} + +#ifdef PARSEC_CLIENT + +// process entire object (transforms and projects all vertices) --------------- +// +void ProcessObject( GenObject *object ) +{ + ASSERT( object != NULL ); + + // leave normals alone + int base = object->NumNormals; + + Vertex3 *vtxlist = &object->VertexList[ base ]; + Vertex3 *x_vtxlist = &object->X_VertexList[ base ]; + SPoint *s_vtxlist = &object->S_VertexList[ base ]; + + for ( int numvtxs = object->NumPolyVerts; numvtxs > 0; numvtxs--, vtxlist++ ) { + + // only transform and project actually visible vertices + if ( vtxlist->VisibleFrame == CurVisibleFrame ) { + + // transform vertex into view-space + MtxVctMUL( object->CurrentXmatrx, vtxlist, x_vtxlist ); + + // project vertex onto screen (but do not add origin offset!!) + s_vtxlist->X = GEOMV_TO_COORD( GEOMV_DIV( x_vtxlist->X, x_vtxlist->Z ) ); + s_vtxlist->Y = GEOMV_TO_COORD( GEOMV_DIV( x_vtxlist->Y, x_vtxlist->Z ) ); + } + + x_vtxlist++; + s_vtxlist++; + } +} + + +#endif // PARSEC_CLIENT + + + diff --git a/src/libparsec/utl_math2.cpp b/src/libparsec/utl_math2.cpp new file mode 100644 index 0000000..c783fe0 --- /dev/null +++ b/src/libparsec/utl_math2.cpp @@ -0,0 +1,1231 @@ +/* + * PARSEC - Math Code II (ANSI-C) + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-1999 + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001 + * + * 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 2 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// local module header + + +// to prevent warnings when converting doubles to floats +#ifdef SYSTEM_COMPILER_MSVC + #pragma warning ( disable : 4244 ) +#endif // SYSTEM_COMPILER_MSVC + +// global matrix that can be used as destination by assembly math code -------- +// +ALLOC_DESTXMATRX( DestXmatrx ); + + +// calculate vector length ---------------------------------------------------- +// +geomv_t VctLenX( Vector3 *vec ) +{ + ASSERT( vec != NULL ); + + float x = GEOMV_TO_FLOAT( vec->X ); + float y = GEOMV_TO_FLOAT( vec->Y ); + float z = GEOMV_TO_FLOAT( vec->Z ); + + float norm = sqrtf( x*x + y*y + z*z ); + + return FLOAT_TO_GEOMV( norm ); +} + + +// calculate vector length (approximated version) ----------------------------- +// +geomv_t VctLen( Vector3 *vec ) +{ + ASSERT( vec != NULL ); + + //NOTE: + // this version approximates a vector's length + // by using the following formula: + // len = vmax + (11/32)vmed + (1/4)vmin + // [this gives a result that is accurate within 8%] + + geomv_t vmax = vec->X; + geomv_t vmed = vec->Y; + geomv_t vmin = vec->Z; + + ABS_GEOMV( vmax ); + ABS_GEOMV( vmed ); + ABS_GEOMV( vmin ); + + if ( DW32( vmax ) < DW32( vmed ) ) + SWAP_GEOMV( vmax, vmed ); + if ( DW32( vmax ) < DW32( vmin ) ) + SWAP_GEOMV( vmax, vmin ); + if ( DW32( vmed ) < DW32( vmin ) ) + SWAP_GEOMV( vmed, vmin ); + + geomv_t norm = vmax + ( vmed * ( 11.0f / 8.0f ) + vmin ) / 4.0f; + + return norm; +} + + +// normalize 3-D vector ------------------------------------------------------- +// +void NormVctX( Vector3 *vec ) +{ + //NOTE: + // this function doesn't handle null + // vectors transparently. there is only + // an assertion. otherwise NaN's will be + // the result. + + ASSERT( vec != NULL ); + + float x = GEOMV_TO_FLOAT( vec->X ); + float y = GEOMV_TO_FLOAT( vec->Y ); + float z = GEOMV_TO_FLOAT( vec->Z ); + + float norm = sqrtf( x*x + y*y + z*z ); + + ASSERT( norm > 1e-7 ); +// if ( norm <= 1e-7 ) { +// return; +// } + + vec->X = FLOAT_TO_GEOMV( x / norm ); + vec->Y = FLOAT_TO_GEOMV( y / norm ); + vec->Z = FLOAT_TO_GEOMV( z / norm ); +} + + +// normalize 3-D vector (approximated version) -------------------------------- +// +void NormVct( Vector3 *vec ) +{ + //NOTE: + // this function doesn't handle null + // vectors transparently. there is only + // an assertion. otherwise NaN's will be + // the result. + + ASSERT( vec != NULL ); + + geomv_t vmax = vec->X; + geomv_t vmed = vec->Y; + geomv_t vmin = vec->Z; + + ABS_GEOMV( vmax ); + ABS_GEOMV( vmed ); + ABS_GEOMV( vmin ); + + if ( DW32( vmax ) < DW32( vmed ) ) + SWAP_GEOMV( vmax, vmed ); + if ( DW32( vmax ) < DW32( vmin ) ) + SWAP_GEOMV( vmax, vmin ); + if ( DW32( vmed ) < DW32( vmin ) ) + SWAP_GEOMV( vmed, vmin ); + + geomv_t norm = vmax + ( vmed * ( 11.0f / 8.0f ) + vmin ) / 4.0f; + + ASSERT( norm > GEOMV_VANISHING ); +// if ( norm <= GEOMV_VANISHING ) { +// return; +// } + + vec->X = GEOMV_DIV( vec->X, norm ); + vec->Y = GEOMV_DIV( vec->Y, norm ); + vec->Z = GEOMV_DIV( vec->Z, norm ); +} + + +// normalize vectors of upper left 3x3 submatrix ------------------------------ +// +void NormMtx( Xmatrx matrix ) +{ + // normalize matrix column vectors + for ( int i = 0; i < 3; i++ ) { + + float x = GEOMV_TO_FLOAT( matrix[ 0 ][ i ] ); + float y = GEOMV_TO_FLOAT( matrix[ 1 ][ i ] ); + float z = GEOMV_TO_FLOAT( matrix[ 2 ][ i ] ); + + float norm = sqrtf( x*x + y*y + z*z ); + + matrix[ 0 ][ i ] = FLOAT_TO_GEOMV( x / norm ); + matrix[ 1 ][ i ] = FLOAT_TO_GEOMV( y / norm ); + matrix[ 2 ][ i ] = FLOAT_TO_GEOMV( z / norm ); + } +} + + +// re-orthonormalize upper left 3x3 submatrix --------------------------------- +// +void ReOrthoNormMtx( Xmatrx matrix ) +{ + ReOrthoMtx( matrix ); + NormMtx( matrix ); +} + + +// create identity matrix ----------------------------------------------------- +// +void MakeIdMatrx( Xmatrx matrx ) +{ + matrx[ 0 ][ 0 ] = GEOMV_1; + matrx[ 0 ][ 1 ] = GEOMV_0; + matrx[ 0 ][ 2 ] = GEOMV_0; + matrx[ 0 ][ 3 ] = GEOMV_0; + matrx[ 1 ][ 0 ] = GEOMV_0; + matrx[ 1 ][ 1 ] = GEOMV_1; + matrx[ 1 ][ 2 ] = GEOMV_0; + matrx[ 1 ][ 3 ] = GEOMV_0; + matrx[ 2 ][ 0 ] = GEOMV_0; + matrx[ 2 ][ 1 ] = GEOMV_0; + matrx[ 2 ][ 2 ] = GEOMV_1; + matrx[ 2 ][ 3 ] = GEOMV_0; +} + + +// create matrix with translation vector (0,0,0) ------------------------------ +// +void MakeNonTranslationMatrx( const Xmatrx matrx, Xmatrx dmatrx ) +{ + dmatrx[ 0 ][ 0 ] = matrx[ 0 ][ 0 ]; + dmatrx[ 0 ][ 1 ] = matrx[ 0 ][ 1 ]; + dmatrx[ 0 ][ 2 ] = matrx[ 0 ][ 2 ]; + dmatrx[ 0 ][ 3 ] = GEOMV_0; + dmatrx[ 1 ][ 0 ] = matrx[ 1 ][ 0 ]; + dmatrx[ 1 ][ 1 ] = matrx[ 1 ][ 1 ]; + dmatrx[ 1 ][ 2 ] = matrx[ 1 ][ 2 ]; + dmatrx[ 1 ][ 3 ] = GEOMV_0; + dmatrx[ 2 ][ 0 ] = matrx[ 2 ][ 0 ]; + dmatrx[ 2 ][ 1 ] = matrx[ 2 ][ 1 ]; + dmatrx[ 2 ][ 2 ] = matrx[ 2 ][ 2 ]; + dmatrx[ 2 ][ 3 ] = GEOMV_0; +} + + +// calculate the inverse of an orthogonal matrix ------------------------------ +// +void CalcOrthoInverse( const Xmatrx matrx, Xmatrx dmatrx ) +{ + //NOTE: + // assumes matrx is an T*R matrix, where + // T is translation only and R is orthogonal. + + Vector3 tvec; + Vector3 dvec; + + // transpose 3x3 submatrix + dmatrx[ 0 ][ 0 ] = matrx[ 0 ][ 0 ]; + dmatrx[ 0 ][ 1 ] = matrx[ 1 ][ 0 ]; + dmatrx[ 0 ][ 2 ] = matrx[ 2 ][ 0 ]; +// dmatrx[ 0 ][ 3 ] = GEOMV_0; // implicit + dmatrx[ 1 ][ 0 ] = matrx[ 0 ][ 1 ]; + dmatrx[ 1 ][ 1 ] = matrx[ 1 ][ 1 ]; + dmatrx[ 1 ][ 2 ] = matrx[ 2 ][ 1 ]; +// dmatrx[ 1 ][ 3 ] = GEOMV_0; // implicit + dmatrx[ 2 ][ 0 ] = matrx[ 0 ][ 2 ]; + dmatrx[ 2 ][ 1 ] = matrx[ 1 ][ 2 ]; + dmatrx[ 2 ][ 2 ] = matrx[ 2 ][ 2 ]; +// dmatrx[ 2 ][ 3 ] = GEOMV_0; // implicit + + // invert translation vector + tvec.X = -matrx[ 0 ][ 3 ]; + tvec.Y = -matrx[ 1 ][ 3 ]; + tvec.Z = -matrx[ 2 ][ 3 ]; + + // apply transformation to translation vector + MtxVctMULt( dmatrx, &tvec, &dvec ); + + // store result (new translation vector) + dmatrx[ 0 ][ 3 ] = dvec.X; + dmatrx[ 1 ][ 3 ] = dvec.Y; + dmatrx[ 2 ][ 3 ] = dvec.Z; +} + + +// calculate camera origin in object space as defined by CurrentXmatrx -------- +// +void CalcObjSpaceCamera( const GenObject *objectp, Vector3 *cameravec ) +{ + ASSERT( objectp != NULL ); + ASSERT( cameravec != NULL ); + + //NOTE: + // assumes CurrentXmatrx is an T*R matrix, where + // T is translation only and R is orthogonal. + + //NOTE: + // the calculation of the inverse CurrentXmatrx is sped up by + // calculating R^-1 and T^-1 separately, multiplying them afterwards + + Xmatrx inv; + inv[ 0 ][ 0 ] = objectp->CurrentXmatrx[ 0 ][ 0 ]; + inv[ 0 ][ 1 ] = objectp->CurrentXmatrx[ 1 ][ 0 ]; + inv[ 0 ][ 2 ] = objectp->CurrentXmatrx[ 2 ][ 0 ]; +// inv[ 0 ][ 3 ] = GEOMV_0; // implicit + inv[ 1 ][ 0 ] = objectp->CurrentXmatrx[ 0 ][ 1 ]; + inv[ 1 ][ 1 ] = objectp->CurrentXmatrx[ 1 ][ 1 ]; + inv[ 1 ][ 2 ] = objectp->CurrentXmatrx[ 2 ][ 1 ]; +// inv[ 1 ][ 3 ] = GEOMV_0; // implicit + inv[ 2 ][ 0 ] = objectp->CurrentXmatrx[ 0 ][ 2 ]; + inv[ 2 ][ 1 ] = objectp->CurrentXmatrx[ 1 ][ 2 ]; + inv[ 2 ][ 2 ] = objectp->CurrentXmatrx[ 2 ][ 2 ]; +// inv[ 2 ][ 3 ] = GEOMV_0; // implicit + + Vertex3 camobjloc; + camobjloc.X = -objectp->CurrentXmatrx[ 0 ][ 3 ]; + camobjloc.Y = -objectp->CurrentXmatrx[ 1 ][ 3 ]; + camobjloc.Z = -objectp->CurrentXmatrx[ 2 ][ 3 ]; + + MtxVctMULt( inv, &camobjloc, cameravec ); +} + + +// transform volume with transformation matrix -------------------------------- +// +void TransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ) +{ + ASSERT( vol_in != NULL ); + ASSERT( vol_out != NULL ); + + //NOTE: + // assumes matrx is an T*R matrix, where + // T is translation only and R is orthogonal. + + Vector3 tvec; + tvec.X = matrx[ 0 ][ 3 ]; + tvec.Y = matrx[ 1 ][ 3 ]; + tvec.Z = matrx[ 2 ][ 3 ]; + + // transform all non-masked planes + for ( ; cullmask != 0x00; cullmask >>= 1, vol_in++, vol_out++ ) { + + if ( cullmask & 0x01 ) { + + // transform normal + MtxVctMULt( matrx, PLANE_NORMAL( vol_in ), PLANE_NORMAL( vol_out ) ); + + // transform distance + PLANE_OFFSET( vol_out ) = PLANE_OFFSET( vol_in ) + + DOT_PRODUCT( &tvec, PLANE_NORMAL( vol_out ) ); + } + } +} + + +// transform volume with inverse of transformation matrix --------------------- +// +void BackTransformVolume( const Xmatrx matrx, Plane3 *vol_in, Plane3 *vol_out, dword cullmask ) +{ + ASSERT( vol_in != NULL ); + ASSERT( vol_out != NULL ); + + //NOTE: + // assumes matrx is an T*R matrix, where + // T is translation only and R is orthogonal. + + // transpose R (yields R^-1) + Xmatrx rinv; + rinv[ 0 ][ 0 ] = matrx[ 0 ][ 0 ]; + rinv[ 0 ][ 1 ] = matrx[ 1 ][ 0 ]; + rinv[ 0 ][ 2 ] = matrx[ 2 ][ 0 ]; +// rinv[ 0 ][ 3 ] = GEOMV_0; // implicit + rinv[ 1 ][ 0 ] = matrx[ 0 ][ 1 ]; + rinv[ 1 ][ 1 ] = matrx[ 1 ][ 1 ]; + rinv[ 1 ][ 2 ] = matrx[ 2 ][ 1 ]; +// rinv[ 1 ][ 3 ] = GEOMV_0; // implicit + rinv[ 2 ][ 0 ] = matrx[ 0 ][ 2 ]; + rinv[ 2 ][ 1 ] = matrx[ 1 ][ 2 ]; + rinv[ 2 ][ 2 ] = matrx[ 2 ][ 2 ]; +// rinv[ 2 ][ 3 ] = GEOMV_0; // implicit + + // invert T + Vector3 tvec; + tvec.X = -matrx[ 0 ][ 3 ]; + tvec.Y = -matrx[ 1 ][ 3 ]; + tvec.Z = -matrx[ 2 ][ 3 ]; + + // transform all non-masked planes + for ( ; cullmask != 0x00; cullmask >>= 1, vol_in++, vol_out++ ) { + + if ( cullmask & 0x01 ) { + + // transform distance + PLANE_OFFSET( vol_out ) = PLANE_OFFSET( vol_in ) + + DOT_PRODUCT( &tvec, PLANE_NORMAL( vol_in ) ); + // transform normal + MtxVctMULt( rinv, PLANE_NORMAL( vol_in ), PLANE_NORMAL( vol_out ) ); + } + } +} + + +// check whether general quaternion is unit quaternion ------------------------ +// +int QuaternionIsUnit( const Quaternion *quat ) +{ + ASSERT( quat != NULL ); + + float qlen2 = GEOMV_TO_FLOAT( quat->X ) * GEOMV_TO_FLOAT( quat->X ) + + GEOMV_TO_FLOAT( quat->Y ) * GEOMV_TO_FLOAT( quat->Y ) + + GEOMV_TO_FLOAT( quat->Z ) * GEOMV_TO_FLOAT( quat->Z ) + + GEOMV_TO_FLOAT( quat->W ) * GEOMV_TO_FLOAT( quat->W ); + + return ( ( qlen2 > ( 1.0f - 1e-5f ) ) && ( qlen2 < ( 1.0f + 1e-5f ) ) ); +} + +int QuaternionIsUnit_f( const Quaternion_f *quat ) +{ + ASSERT( quat != NULL ); + + float qlen2 = quat->X * quat->X + quat->Y * quat->Y + + quat->Z * quat->Z + quat->W * quat->W; + + return ( ( qlen2 > ( 1.0f - 1e-5f ) ) && ( qlen2 < ( 1.0f + 1e-5f ) ) ); +} + + +// convert general quaternion into unit quaternion ---------------------------- +// +void QuaternionMakeUnit( Quaternion *quat ) +{ + ASSERT( quat != NULL ); + + float W = GEOMV_TO_FLOAT( quat->W ); + float X = GEOMV_TO_FLOAT( quat->X ); + float Y = GEOMV_TO_FLOAT( quat->Y ); + float Z = GEOMV_TO_FLOAT( quat->Z ); + + float invnorm = 1.0f / ( W*W + X*X + Y*Y + Z*Z ); + invnorm = sqrtf( invnorm ); + + quat->W = FLOAT_TO_GEOMV( W * invnorm ); + quat->X = FLOAT_TO_GEOMV( X * invnorm ); + quat->Y = FLOAT_TO_GEOMV( Y * invnorm ); + quat->Z = FLOAT_TO_GEOMV( Z * invnorm ); +} + +void QuaternionMakeUnit_f( Quaternion_f *quat ) +{ + ASSERT( quat != NULL ); + + float W = quat->W; + float X = quat->X; + float Y = quat->Y; + float Z = quat->Z; + + float invnorm = 1.0f / ( W*W + X*X + Y*Y + Z*Z ); + invnorm = sqrtf( invnorm ); + + quat->W = W * invnorm; + quat->X = X * invnorm; + quat->Y = Y * invnorm; + quat->Z = Z * invnorm; +} + + +// invert a unit quaternion --------------------------------------------------- +// +void QuaternionInvertUnit( Quaternion *quat ) +{ + ASSERT( quat != NULL ); + + quat->X = -quat->X; + quat->Y = -quat->Y; + quat->Z = -quat->Z; +} + +void QuaternionInvertUnit_f( Quaternion_f *quat ) +{ + ASSERT( quat != NULL ); + + quat->X = -quat->X; + quat->Y = -quat->Y; + quat->Z = -quat->Z; +} + + +// invert a general quaternion ------------------------------------------------ +// +void QuaternionInvertGeneral( Quaternion *quat ) +{ + ASSERT( quat != NULL ); + + float W = GEOMV_TO_FLOAT( quat->W ); + float X = GEOMV_TO_FLOAT( quat->X ); + float Y = GEOMV_TO_FLOAT( quat->Y ); + float Z = GEOMV_TO_FLOAT( quat->Z ); + + float invmag = 1.0f / ( W*W + X*X + Y*Y + Z*Z ); + + quat->W = FLOAT_TO_GEOMV( -W * invmag ); + quat->X = FLOAT_TO_GEOMV( -X * invmag ); + quat->Y = FLOAT_TO_GEOMV( -Y * invmag ); + quat->Z = FLOAT_TO_GEOMV( -Z * invmag ); +} + +void QuaternionInvertGeneral_f( Quaternion_f *quat ) +{ + ASSERT( quat != NULL ); + + float W = quat->W; + float X = quat->X; + float Y = quat->Y; + float Z = quat->Z; + + float invmag = 1.0f / ( W*W + X*X + Y*Y + Z*Z ); + + quat->W = -W * invmag; + quat->X = -X * invmag; + quat->Y = -Y * invmag; + quat->Z = -Z * invmag; +} + + +// diagonal forward cycling --------------------------------------------------- +// +static int nxt_wrp[ 3 ] = { 1, 2, 0 }; + + +// create a unit quaternion from a rotation matrix ---------------------------- +// +void QuaternionFromMatrx( Quaternion *quat, const Xmatrx matrix ) +{ + ASSERT( quat != NULL ); + ASSERT( matrix != NULL ); + + float fdiag[ 3 ]; + fdiag[ 0 ] = GEOMV_TO_FLOAT( matrix[ 0 ][ 0 ] ); + fdiag[ 1 ] = GEOMV_TO_FLOAT( matrix[ 1 ][ 1 ] ); + fdiag[ 2 ] = GEOMV_TO_FLOAT( matrix[ 2 ][ 2 ] ); + + // temp result + float qt[4] = {1.0f, 0.0f, 0.0f, 0.0f}; // (W,X,Y,Z) + + float trace = fdiag[ 0 ] + fdiag[ 1 ] + fdiag[ 2 ]; + if ( trace > 0.0 ) { + + float scale = sqrtf( trace + 1.0f ); // 2W=sqrt(4W^2) + qt[ 0 ] = scale * 0.5f; // W + scale = 0.5f / scale; // 1/(4W) + + qt[ 1 ] = ( GEOMV_TO_FLOAT( matrix[ 2 ][ 1 ] ) - GEOMV_TO_FLOAT( matrix[ 1 ][ 2 ] ) ) * scale; + qt[ 2 ] = ( GEOMV_TO_FLOAT( matrix[ 0 ][ 2 ] ) - GEOMV_TO_FLOAT( matrix[ 2 ][ 0 ] ) ) * scale; + qt[ 3 ] = ( GEOMV_TO_FLOAT( matrix[ 1 ][ 0 ] ) - GEOMV_TO_FLOAT( matrix[ 0 ][ 1 ] ) ) * scale; + + } else { + + int mxi = 0; + if ( fdiag[ 1 ] > fdiag[ 0 ] ) + mxi = 1; + if ( fdiag[ 2 ] > fdiag[ mxi ] ) + mxi = 2; + + int nx1 = nxt_wrp[ mxi ]; + int nx2 = nxt_wrp[ nx1 ]; + + float scale = sqrtf( fdiag[ mxi ] - ( fdiag[ nx1 ] + fdiag[ nx2 ] ) + 1.0f ); + qt[ mxi+1 ] = scale * 0.5f; + scale = 0.5f / scale; + + qt[ 0 ] = ( GEOMV_TO_FLOAT( matrix[ nx2 ][ nx1 ] ) - GEOMV_TO_FLOAT( matrix[ nx1 ][ nx2 ] ) ) * scale; + qt[ nx1+1 ] = ( GEOMV_TO_FLOAT( matrix[ nx1 ][ mxi ] ) + GEOMV_TO_FLOAT( matrix[ mxi ][ nx1 ] ) ) * scale; + qt[ nx2+1 ] = ( GEOMV_TO_FLOAT( matrix[ nx2 ][ mxi ] ) + GEOMV_TO_FLOAT( matrix[ mxi ][ nx2 ] ) ) * scale; + } + + quat->W = FLOAT_TO_GEOMV( qt[ 0 ] ); + quat->X = FLOAT_TO_GEOMV( qt[ 1 ] ); + quat->Y = FLOAT_TO_GEOMV( qt[ 2 ] ); + quat->Z = FLOAT_TO_GEOMV( qt[ 3 ] ); +} + +void QuaternionFromMatrx_f( Quaternion_f *quat, const Xmatrx matrix ) +{ + ASSERT( quat != NULL ); + ASSERT( matrix != NULL ); + + float fdiag[ 3 ]; + fdiag[ 0 ] = GEOMV_TO_FLOAT( matrix[ 0 ][ 0 ] ); + fdiag[ 1 ] = GEOMV_TO_FLOAT( matrix[ 1 ][ 1 ] ); + fdiag[ 2 ] = GEOMV_TO_FLOAT( matrix[ 2 ][ 2 ] ); + + // direct result + float *qt = (float *) quat; // (W,X,Y,Z) + + float trace = fdiag[ 0 ] + fdiag[ 1 ] + fdiag[ 2 ]; + if ( trace > 0.0 ) { + + float scale = sqrtf( trace + 1.0f ); // 2W=sqrt(4W^2) + qt[ 0 ] = scale * 0.5f; // W + scale = 0.5f / scale; // 1/(4W) + + qt[ 1 ] = ( GEOMV_TO_FLOAT( matrix[ 2 ][ 1 ] ) - GEOMV_TO_FLOAT( matrix[ 1 ][ 2 ] ) ) * scale; + qt[ 2 ] = ( GEOMV_TO_FLOAT( matrix[ 0 ][ 2 ] ) - GEOMV_TO_FLOAT( matrix[ 2 ][ 0 ] ) ) * scale; + qt[ 3 ] = ( GEOMV_TO_FLOAT( matrix[ 1 ][ 0 ] ) - GEOMV_TO_FLOAT( matrix[ 0 ][ 1 ] ) ) * scale; + + } else { + + int mxi = 0; + if ( fdiag[ 1 ] > fdiag[ 0 ] ) + mxi = 1; + if ( fdiag[ 2 ] > fdiag[ mxi ] ) + mxi = 2; + + int nx1 = nxt_wrp[ mxi ]; + int nx2 = nxt_wrp[ nx1 ]; + + float scale = sqrtf( fdiag[ mxi ] - ( fdiag[ nx1 ] + fdiag[ nx2 ] ) + 1.0f ); + qt[ mxi+1 ] = scale * 0.5f; + scale = 0.5f / scale; + + qt[ 0 ] = ( GEOMV_TO_FLOAT( matrix[ nx2 ][ nx1 ] ) - GEOMV_TO_FLOAT( matrix[ nx1 ][ nx2 ] ) ) * scale; + qt[ nx1+1 ] = ( GEOMV_TO_FLOAT( matrix[ nx1 ][ mxi ] ) + GEOMV_TO_FLOAT( matrix[ mxi ][ nx1 ] ) ) * scale; + qt[ nx2+1 ] = ( GEOMV_TO_FLOAT( matrix[ nx2 ][ mxi ] ) + GEOMV_TO_FLOAT( matrix[ mxi ][ nx2 ] ) ) * scale; + } +} + + +// create a rotation matrix from a unit quaternion ---------------------------- +// +void MatrxFromQuaternion( Xmatrx matrix, const Quaternion *quat ) +{ + ASSERT( matrix != NULL ); + ASSERT( quat != NULL ); + + //NOTE: + // the translation in the matrix will be + // left untouched. + + //NOTE: + // unit quaternion check is only assertion. + + ASSERT( QuaternionIsUnit( quat ) ); + + // calculate intermediate terms + geomv_t X2 = quat->X * 2; + geomv_t Y2 = quat->Y * 2; + geomv_t Z2 = quat->Z * 2; + + geomv_t XX = GEOMV_MUL( quat->X, X2 ); + geomv_t YY = GEOMV_MUL( quat->Y, Y2 ); + geomv_t ZZ = GEOMV_MUL( quat->Z, Z2 ); + geomv_t XY = GEOMV_MUL( quat->X, Y2 ); + geomv_t XZ = GEOMV_MUL( quat->X, Z2 ); + geomv_t YZ = GEOMV_MUL( quat->Y, Z2 ); + geomv_t WX = GEOMV_MUL( quat->W, X2 ); + geomv_t WY = GEOMV_MUL( quat->W, Y2 ); + geomv_t WZ = GEOMV_MUL( quat->W, Z2 ); + + // convert quaternion into rotation matrix + matrix[ 0 ][ 0 ] = GEOMV_1 - ( YY + ZZ ); + matrix[ 0 ][ 1 ] = ( XY - WZ ); + matrix[ 0 ][ 2 ] = ( XZ + WY ); +// matrix[ 0 ][ 3 ] = GEOMV_0; + matrix[ 1 ][ 0 ] = ( XY + WZ ); + matrix[ 1 ][ 1 ] = GEOMV_1 - ( XX + ZZ ); + matrix[ 1 ][ 2 ] = ( YZ - WX ); +// matrix[ 1 ][ 3 ] = GEOMV_0; + matrix[ 2 ][ 0 ] = ( XZ - WY ); + matrix[ 2 ][ 1 ] = ( YZ + WX ); + matrix[ 2 ][ 2 ] = GEOMV_1 - ( XX + YY ); +// matrix[ 2 ][ 3 ] = GEOMV_0; +} + +void MatrxFromQuaternion_f( Xmatrx matrix, const Quaternion_f *quat ) +{ + ASSERT( matrix != NULL ); + ASSERT( quat != NULL ); + + //NOTE: + // the translation in the matrix will be + // left untouched. + + //NOTE: + // unit quaternion check is only assertion. + + ASSERT( QuaternionIsUnit_f( quat ) ); + + // calculate intermediate terms + float X2 = quat->X * 2; + float Y2 = quat->Y * 2; + float Z2 = quat->Z * 2; + + float XX = quat->X * X2; + float YY = quat->Y * Y2; + float ZZ = quat->Z * Z2; + float XY = quat->X * Y2; + float XZ = quat->X * Z2; + float YZ = quat->Y * Z2; + float WX = quat->W * X2; + float WY = quat->W * Y2; + float WZ = quat->W * Z2; + + // convert quaternion into rotation matrix + matrix[ 0 ][ 0 ] = FLOAT_TO_GEOMV( 1 - ( YY + ZZ ) ); + matrix[ 0 ][ 1 ] = FLOAT_TO_GEOMV( ( XY - WZ ) ); + matrix[ 0 ][ 2 ] = FLOAT_TO_GEOMV( ( XZ + WY ) ); +// matrix[ 0 ][ 3 ] = GEOMV_0; + matrix[ 1 ][ 0 ] = FLOAT_TO_GEOMV( ( XY + WZ ) ); + matrix[ 1 ][ 1 ] = FLOAT_TO_GEOMV( 1 - ( XX + ZZ ) ); + matrix[ 1 ][ 2 ] = FLOAT_TO_GEOMV( ( YZ - WX ) ); +// matrix[ 1 ][ 3 ] = GEOMV_0; + matrix[ 2 ][ 0 ] = FLOAT_TO_GEOMV( ( XZ - WY ) ); + matrix[ 2 ][ 1 ] = FLOAT_TO_GEOMV( ( YZ + WX ) ); + matrix[ 2 ][ 2 ] = FLOAT_TO_GEOMV( 1 - ( XX + YY ) ); +// matrix[ 2 ][ 3 ] = GEOMV_0; +} + + +// create a rotation matrix from an angular displacement (angle, axis) -------- +// +void MatrxFromAngularDisplacement( Xmatrx matrix, bams_t angle, Vertex3 *axis ) +{ + ASSERT( matrix != NULL ); + ASSERT( axis != NULL ); + + //NOTE: + // NULL axes are not handled transparently. + + // normalize axis of rotation + NormVctX( axis ); + + // calculate unit quaternion corresponding to rotation + float phi2 = -BAMS_TO_RAD( angle ) / 2; + float sinphi2 = sinf( phi2 ); + + Quaternion_f quat; + quat.W = cosf( phi2 ); + quat.X = sinphi2 * GEOMV_TO_FLOAT( axis->X ); + quat.Y = sinphi2 * GEOMV_TO_FLOAT( axis->Y ); + quat.Z = sinphi2 * GEOMV_TO_FLOAT( axis->Z ); + + // calculate intermediate terms + float X2 = quat.X * quat.X; + float Y2 = quat.Y * quat.Y; + float Z2 = quat.Z * quat.Z; + float XY = quat.X * quat.Y; + float XZ = quat.X * quat.Z; + float YZ = quat.Y * quat.Z; + float WX = quat.W * quat.X; + float WY = quat.W * quat.Y; + float WZ = quat.W * quat.Z; + + // convert quaternion into rotation matrix + matrix[ 0 ][ 0 ] = FLOAT_TO_GEOMV( 1 - ( Y2 + Z2 ) * 2 ); + matrix[ 0 ][ 1 ] = FLOAT_TO_GEOMV( ( XY - WZ ) * 2 ); + matrix[ 0 ][ 2 ] = FLOAT_TO_GEOMV( ( XZ + WY ) * 2 ); + matrix[ 0 ][ 3 ] = GEOMV_0; + matrix[ 1 ][ 0 ] = FLOAT_TO_GEOMV( ( XY + WZ ) * 2 ); + matrix[ 1 ][ 1 ] = FLOAT_TO_GEOMV( 1 - ( X2 + Z2 ) * 2 ); + matrix[ 1 ][ 2 ] = FLOAT_TO_GEOMV( ( YZ - WX ) * 2 ); + matrix[ 1 ][ 3 ] = GEOMV_0; + matrix[ 2 ][ 0 ] = FLOAT_TO_GEOMV( ( XZ - WY ) * 2 ); + matrix[ 2 ][ 1 ] = FLOAT_TO_GEOMV( ( YZ + WX ) * 2 ); + matrix[ 2 ][ 2 ] = FLOAT_TO_GEOMV( 1 - ( X2 + Y2 ) * 2 ); + matrix[ 2 ][ 3 ] = GEOMV_0; +} + + +// multiply two general quaternions ------------------------------------------- +// +void QuaternionMUL( Quaternion *qd, const Quaternion *qb, const Quaternion *qa ) +{ + ASSERT( qd != NULL ); + ASSERT( qb != NULL ); + ASSERT( qa != NULL ); + + //NOTE: + // QD = QB*QA; + + float BW = GEOMV_TO_FLOAT( qb->W ), AW = GEOMV_TO_FLOAT( qa->W ); + float BX = GEOMV_TO_FLOAT( qb->X ), AX = GEOMV_TO_FLOAT( qa->X ); + float BY = GEOMV_TO_FLOAT( qb->Y ), AY = GEOMV_TO_FLOAT( qa->Y ); + float BZ = GEOMV_TO_FLOAT( qb->Z ), AZ = GEOMV_TO_FLOAT( qa->Z ); + + qd->W = FLOAT_TO_GEOMV( BW*AW - BX*AX - BY*AY - BZ*AZ ); + qd->X = FLOAT_TO_GEOMV( BY*AZ - AY*BZ + BW*AX + AW*BX ); + qd->Y = FLOAT_TO_GEOMV( BZ*AX - AZ*BX + BW*AY + AW*BY ); + qd->Z = FLOAT_TO_GEOMV( BX*AY - AX*BY + BW*AZ + AW*BZ ); +} + +void QuaternionMUL_f( Quaternion_f *qd, const Quaternion_f *qb, const Quaternion_f *qa ) +{ + ASSERT( qd != NULL ); + ASSERT( qb != NULL ); + ASSERT( qa != NULL ); + + //NOTE: + // QD = QB*QA; + + float BW = qb->W, AW = qa->W; + float BX = qb->X, AX = qa->X; + float BY = qb->Y, AY = qa->Y; + float BZ = qb->Z, AZ = qa->Z; + + qd->W = BW*AW - BX*AX - BY*AY - BZ*AZ; + qd->X = BY*AZ - AY*BZ + BW*AX + AW*BX; + qd->Y = BZ*AX - AZ*BX + BW*AY + AW*BY; + qd->Z = BX*AY - AX*BY + BW*AZ + AW*BZ; +} + + +// flags and bounds for quaternion slerp -------------------------------------- +// +#define SLERP_ALWAYS_SHORTEST + +#define EPS_COSOM 1e-5 + + +// interpolate spherically between two unit quaternions ----------------------- +// +void QuaternionSlerp( Quaternion *qd, const Quaternion *qa, const Quaternion *qb, float alpha ) +{ + ASSERT( qd != NULL ); + ASSERT( qa != NULL ); + ASSERT( qb != NULL ); + + //NOTE: + // QD = SLERP(QA,QB,ALPHA); + // ( = QA->[ALPHA*ANGLE]->QB ) ) + + float scalea; + float scaleb; + + float AW = GEOMV_TO_FLOAT( qa->W ), BW = GEOMV_TO_FLOAT( qb->W ); + float AX = GEOMV_TO_FLOAT( qa->X ), BX = GEOMV_TO_FLOAT( qb->X ); + float AY = GEOMV_TO_FLOAT( qa->Y ), BY = GEOMV_TO_FLOAT( qb->Y ); + float AZ = GEOMV_TO_FLOAT( qa->Z ), BZ = GEOMV_TO_FLOAT( qb->Z ); + + float cosom = AX * BX + AY * BY + AZ * BZ + AW * BW; + +#ifdef SLERP_ALWAYS_SHORTEST + + // resolve ambiguity + if ( cosom < 0.0f ) { + cosom = -cosom; + BW = -BW; + BX = -BX; + BY = -BY; + BZ = -BZ; + } + + if ( ( 1.0f - cosom ) > EPS_COSOM ) { + + // full slerp + float omega = acosf( cosom ); + float sinom = 1.0f / sinf( omega ); + + alpha *= omega; + scalea = sinf( omega - alpha ) * sinom; + scaleb = sinf( alpha ) * sinom; + + } else { + + // use lerp if cos(omega) about 1.0 + scalea = 1.0f - alpha; + scaleb = alpha; + } + + qd->W = FLOAT_TO_GEOMV( scalea * AW + scaleb * BW ); + qd->X = FLOAT_TO_GEOMV( scalea * AX + scaleb * BX ); + qd->Y = FLOAT_TO_GEOMV( scalea * AY + scaleb * BY ); + qd->Z = FLOAT_TO_GEOMV( scalea * AZ + scaleb * BZ ); + +#else // SLERP_ALWAYS_SHORTEST + + if ( ( 1.0f + cosom ) > EPS_COSOM ) { + + if ( ( 1.0f - cosom ) > EPS_COSOM ) { + + // full slerp + float omega = acos( cosom ); + float sinom = 1.0f / sin( omega ); + + alpha *= omega; + scalea = sin( omega - alpha ) * sinom; + scaleb = sin( alpha ) * sinom; + + } else { + + // use lerp if cos(omega) about 1.0 + scalea = 1.0f - alpha; + scaleb = alpha; + } + + qd->W = FLOAT_TO_GEOMV( scalea * AW + scaleb * BW ); + qd->X = FLOAT_TO_GEOMV( scalea * AX + scaleb * BX ); + qd->Y = FLOAT_TO_GEOMV( scalea * AY + scaleb * BY ); + qd->Z = FLOAT_TO_GEOMV( scalea * AZ + scaleb * BZ ); + + } else { + + // handle diametrically opposite quaternions + qd->W = qa->Z; + qd->X = -qa->Y; + qd->Y = qa->X; + qd->Z = -qa->W; + + alpha *= HPREC_HALF_PI; + scalea = sin( HPREC_HALF_PI - alpha ); + scaleb = sin( alpha ); + + qd->X = FLOAT_TO_GEOMV( scalea * AX + scaleb * GEOMV_TO_FLOAT( qd->X ) ); + qd->Y = FLOAT_TO_GEOMV( scalea * AY + scaleb * GEOMV_TO_FLOAT( qd->Y ) ); + qd->Z = FLOAT_TO_GEOMV( scalea * AZ + scaleb * GEOMV_TO_FLOAT( qd->Z ) ); + } + +#endif // SLERP_ALWAYS_SHORTEST + +} + +void QuaternionSlerp_f( Quaternion_f *qd, const Quaternion_f *qa, const Quaternion_f *qb, float alpha ) +{ + ASSERT( qd != NULL ); + ASSERT( qa != NULL ); + ASSERT( qb != NULL ); + + //NOTE: + // QD = SLERP(QA,QB,ALPHA); + // ( = QA->[ALPHA*ANGLE]->QB ) ) + + float scalea; + float scaleb; + + float BW = qb->W; + float BX = qb->X; + float BY = qb->Y; + float BZ = qb->Z; + + float cosom = qa->X * BX + qa->Y * BY + qa->Z * BZ + qa->W * BW; + +#ifdef SLERP_ALWAYS_SHORTEST + + // resolve ambiguity + if ( cosom < 0.0f ) { + cosom = -cosom; + BW = -BW; + BX = -BX; + BY = -BY; + BZ = -BZ; + } + + if ( ( 1.0f - cosom ) > EPS_COSOM ) { + + // full slerp + float omega = acosf( cosom ); + float sinom = 1.0f / sinf( omega ); + + alpha *= omega; + scalea = sinf( omega - alpha ) * sinom; + scaleb = sinf( alpha ) * sinom; + + } else { + + // use lerp if cos(omega) about 1.0 + scalea = 1.0f - alpha; + scaleb = alpha; + } + + qd->W = scalea * qa->W + scaleb * BW; + qd->X = scalea * qa->X + scaleb * BX; + qd->Y = scalea * qa->Y + scaleb * BY; + qd->Z = scalea * qa->Z + scaleb * BZ; + +#else // SLERP_ALWAYS_SHORTEST + + if ( ( 1.0f + cosom ) > EPS_COSOM ) { + + if ( ( 1.0f - cosom ) > EPS_COSOM ) { + + // full slerp + float omega = acos( cosom ); + float sinom = 1.0f / sin( omega ); + + alpha *= omega; + scalea = sin( omega - alpha ) * sinom; + scaleb = sin( alpha ) * sinom; + + } else { + + // use lerp if cos(omega) about 1.0 + scalea = 1.0f - alpha; + scaleb = alpha; + } + + qd->W = scalea * qa->W + scaleb * BW; + qd->X = scalea * qa->X + scaleb * BX; + qd->Y = scalea * qa->Y + scaleb * BY; + qd->Z = scalea * qa->Z + scaleb * BZ; + + } else { + + // handle diametrically opposite quaternions + qd->W = qa->Z; + qd->X = -qa->Y; + qd->Y = qa->X; + qd->Z = -qa->W; + + alpha *= HPREC_HALF_PI; + scalea = sin( HPREC_HALF_PI - alpha ); + scaleb = sin( alpha ); + + qd->X = scalea * qa->X + scaleb * qd->X; + qd->Y = scalea * qa->Y + scaleb * qd->Y; + qd->Z = scalea * qa->Z + scaleb * qd->Z; + } + +#endif // SLERP_ALWAYS_SHORTEST + +} + +// do a quaternion slerp from frame to frame ---------------------------------- +// +void QuaternionSlerpFrames( Xmatrx slerp_frame, Xmatrx start_frame, Xmatrx end_frame, float t ) +{ + // get source orientation quaternion + Quaternion srcquat; + QuaternionFromMatrx( &srcquat, start_frame ); + QuaternionMakeUnit( &srcquat ); + + // get destination orientation quaternion + Quaternion dstquat; + QuaternionFromMatrx( &dstquat, end_frame ); + QuaternionMakeUnit( &dstquat ); + + // do slerp from src to dst (filter output this frame) + Quaternion slerpquat; + QuaternionSlerp( &slerpquat, &srcquat, &dstquat, t ); + QuaternionMakeUnit( &slerpquat ); + + // fill R part of view camera matrix (filtered orientation this frame) + MatrxFromQuaternion( slerp_frame, &slerpquat ); +} + +// calc rotation matrix as result of slerp between two quaternions ------------ +// +void CalcSlerpedMatrix( Xmatrx matrix, const playerlerp_s *playerlerp ) +{ + ASSERT( matrix != NULL ); + ASSERT( playerlerp != NULL ); + + // do slerp from src to dst + Quaternion slerpquat; + QuaternionSlerp( &slerpquat, &playerlerp->srcquat, &playerlerp->dstquat, playerlerp->curalpha ); + QuaternionMakeUnit( &slerpquat ); + + // fill R part of matrix + MatrxFromQuaternion( matrix, &slerpquat ); +} + + +// interpolate using the Hermite Interpolation -------------------------------- +// +void Hermite_Interpolate( Vector3* dest, float t, const Vector3* start, const Vector3* end, + const Vector3* start_tan, const Vector3* end_tan ) +{ + // do a Hermite interpolation for the position + float s = t; + float s2 = s * s; + float s3 = s2 * s; + + // calculate the basis functions + float h1 = 2 * s3 - 3 * s2 + 1; + float h2 = -2 * s3 + 3 * s2; + float h3 = s3 - 2 * s2 + s; + float h4 = s3 - s2; + + Vector3 h1P1, h2P2, h3T1, h4T2; + + VECMULS( &h1P1, start, (geomv_t)h1 ); + VECMULS( &h2P2, end, (geomv_t)h2 ); + VECMULS( &h3T1, start_tan, (geomv_t)h3 ); + VECMULS( &h4T2, end_tan, (geomv_t)h4 ); + + Vector3 hermite_pos; + VECADD( &hermite_pos, &h1P1, &h2P2 ); + VECADD( &hermite_pos, &h3T1, &hermite_pos ); + VECADD( &hermite_pos, &h4T2, &hermite_pos ); + + memcpy( dest, &hermite_pos, sizeof( Vector3 ) ); +} + + +// init a the Hermite ArcLen interpolation struct ----------------------------- +// +Hermite_ArcLen* Hermite_ArcLen_InitData( int num_steps, const Vector3* start, const Vector3* end, + const Vector3* start_tan, const Vector3* end_tan ) +{ + Hermite_ArcLen* hermite_data = (Hermite_ArcLen*)ALLOCMEM( sizeof( Hermite_ArcLen ) ); + + // init the arrays + size_t allocsize1 = (size_t)num_steps * sizeof( float ); + size_t allocsize2 = (size_t)num_steps * sizeof( Vector3 ); + hermite_data->table_u = (float*)ALLOCMEM( allocsize1 ); + hermite_data->table_s = (float*)ALLOCMEM( allocsize1 ); + hermite_data->table_Vecs = (Vector3*)ALLOCMEM( allocsize2 ); + + memset( hermite_data->table_u, 0, allocsize1 ); + memset( hermite_data->table_s, 0, allocsize1 ); + memset( hermite_data->table_Vecs, 0, allocsize2 ); + + //NOTE: u is original parameter space, s is arclen parameter space + + // store the # of steps for the interpolation + hermite_data->num_steps = num_steps; + + // store u and corresponding value + int step = 0; + for(step = 0; step < num_steps; step++ ) { + + // normalize u + float u = (float)step / (float)( num_steps - 1 ); + + hermite_data->table_u[ step ] = u; + + Hermite_Interpolate( &hermite_data->table_Vecs[ step ], u, start, end, start_tan, end_tan ); + } + + // calculate total arclength + hermite_data->total_arc_len = 0.0f; + + // store arclen for interpolation step s == 0 + hermite_data->table_s[ 0 ] = 0.0f; + + Vector3 diff; + for( step = 1; step < num_steps; step++ ) { + + // get the (approximated) arclen of vector ( step - 1 ) -> ( step ) + VECSUB( &diff, &hermite_data->table_Vecs[ step - 1 ], &hermite_data->table_Vecs[ step ] ); + float arc_len = GEOMV_TO_FLOAT( VctLenX( &diff ) ); + hermite_data->total_arc_len += arc_len; + + // store accumulated arclen in table_s + hermite_data->table_s[ step ] = hermite_data->total_arc_len; + } + + // normalize arc lens + for( step = 0; step < num_steps; step++ ) { + hermite_data->table_s[ step ] = hermite_data->table_s[ step ] / hermite_data->total_arc_len; + } + + return hermite_data; +} + +// kill data needed for the Hermite ArcLen interpolation ---------------------- +// +void Hermite_ArcLen_KillData( Hermite_ArcLen* hermite_data ) +{ + ASSERT( hermite_data != NULL ); + ASSERT( hermite_data->table_u != NULL ); + ASSERT( hermite_data->table_s != NULL ); + ASSERT( hermite_data->table_Vecs != NULL ); + + FREEMEM( hermite_data->table_u ); + FREEMEM( hermite_data->table_s ); + FREEMEM( hermite_data->table_Vecs ); +} + +// do arclen interpolation of the supplied hermite arclen data ---------------- +// +void Hermite_ArcLen_Interpolate( const Hermite_ArcLen* hermite_data, float s, Vector3* interp ) +{ + ASSERT( hermite_data != NULL ); + ASSERT( ( s >= 0 ) && ( s <= 1.0f ) ); + ASSERT( interp != NULL ); + + //NOTE: given a parameter s in arclen [0,1] we find an u in original parameter space + + ASSERT( hermite_data->num_steps >= 2 ); + + int left = 0; + int right = ( hermite_data->num_steps - 1 ); + + float* table_s = hermite_data->table_s; + + int start = 0, end = 0; + + for( ; right >= left; ) { + int x = ( left + right ) / 2; + + if( table_s[ x ] == s ) { + memcpy( interp, &hermite_data->table_Vecs[ x ], sizeof( Vector3 ) ); + return; + } else if ( s < table_s[ x ] ) { + if ( s > table_s[ x - 1 ] ) { + start = x - 1; + end = x; + break; + } else { + right = x - 1; + } + } else { + if ( s < table_s[ x + 1 ] ) { + start = x; + end = x + 1; + break; + } else { + left = x + 1; + } + } + } + + Vector3* start_vec = &hermite_data->table_Vecs[ start ]; + Vector3* end_vec = &hermite_data->table_Vecs[ end ]; + + float alpha = ( s - table_s[ start ] ) / ( table_s[ end ] - table_s[ start ] ); + + interp->X = start_vec->X + GEOMV_TO_FLOAT( end_vec->X - start_vec->X ) * FLOAT_TO_GEOMV( alpha ); + interp->Y = start_vec->Y + GEOMV_TO_FLOAT( end_vec->Y - start_vec->Y ) * FLOAT_TO_GEOMV( alpha ); + interp->Z = start_vec->Z + GEOMV_TO_FLOAT( end_vec->Z - start_vec->Z ) * FLOAT_TO_GEOMV( alpha ); +} + + +// dump the contents of a matrix ---------------------------------------------- +// +void DumpMatrix( Xmatrx mat ) +{ + MSGOUT( "%10.4f %10.4f %10.4f %10.4f | %10.4f %10.4f %10.4f %10.4f | %10.4f %10.4f %10.4f %10.4f", + mat[ 0 ][ 0 ], mat[ 0 ][ 1 ], mat[ 0 ][ 2 ], mat[ 0 ][ 3 ], + mat[ 1 ][ 0 ], mat[ 1 ][ 1 ], mat[ 1 ][ 2 ], mat[ 1 ][ 3 ], + mat[ 2 ][ 0 ], mat[ 2 ][ 1 ], mat[ 2 ][ 2 ], mat[ 2 ][ 3 ] ); +} + + |
