aboutsummaryrefslogtreecommitdiff
path: root/src/libparsec
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
committerFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
commitc068f22329d5cc722622a2183bbb22eef2093df7 (patch)
tree12d56c1aede67988a55e241364606bfbb4dba933 /src/libparsec
downloadopenparsec-main.tar.xz
openparsec-main.zip
initial importHEADmain
Diffstat (limited to 'src/libparsec')
-rw-r--r--src/libparsec/con_arg.cpp1083
-rw-r--r--src/libparsec/con_tab.cpp312
-rw-r--r--src/libparsec/con_vald.cpp94
-rw-r--r--src/libparsec/debug.cpp497
-rw-r--r--src/libparsec/e_modulemanager.cpp147
-rw-r--r--src/libparsec/e_relist.cpp1027
-rw-r--r--src/libparsec/g_emp.cpp1443
-rw-r--r--src/libparsec/g_extra.cpp1598
-rw-r--r--src/libparsec/include/con_arg.h68
-rw-r--r--src/libparsec/include/con_tab.h16
-rw-r--r--src/libparsec/include/con_vald.h20
-rw-r--r--src/libparsec/include/config.h170
-rw-r--r--src/libparsec/include/debug.h227
-rw-r--r--src/libparsec/include/debugsys.h57
-rw-r--r--src/libparsec/include/def_draw.h4
-rw-r--r--src/libparsec/include/def_papi.h4
-rw-r--r--src/libparsec/include/def_prot.h26
-rw-r--r--src/libparsec/include/def_rend.h4
-rw-r--r--src/libparsec/include/def_vid.h4
-rw-r--r--src/libparsec/include/e_modulemanager.h87
-rw-r--r--src/libparsec/include/e_relist.h328
-rw-r--r--src/libparsec/include/g_emp.h249
-rw-r--r--src/libparsec/include/g_extra.h142
-rw-r--r--src/libparsec/include/g_shipobject.h214
-rw-r--r--src/libparsec/include/g_stgate.h69
-rw-r--r--src/libparsec/include/gd_bmap.h147
-rw-r--r--src/libparsec/include/gd_color.h57
-rw-r--r--src/libparsec/include/gd_const.h63
-rw-r--r--src/libparsec/include/gd_font.h25
-rw-r--r--src/libparsec/include/gd_heads.h132
-rw-r--r--src/libparsec/include/gd_help.h77
-rw-r--r--src/libparsec/include/gd_host.h79
-rw-r--r--src/libparsec/include/gd_limit.h72
-rw-r--r--src/libparsec/include/gd_tabs.h134
-rw-r--r--src/libparsec/include/gd_type.h60
-rw-r--r--src/libparsec/include/general.h75
-rw-r--r--src/libparsec/include/globals.h53
-rw-r--r--src/libparsec/include/keycodes.h28
-rwxr-xr-xsrc/libparsec/include/keys_sdl.h449
-rw-r--r--src/libparsec/include/keys_server.h392
-rw-r--r--src/libparsec/include/linkinfo.h33
-rw-r--r--src/libparsec/include/net_conf.h48
-rw-r--r--src/libparsec/include/net_csdf.h143
-rw-r--r--src/libparsec/include/net_defs.h1000
-rw-r--r--src/libparsec/include/net_limits.h20
-rw-r--r--src/libparsec/include/net_pckt.h38
-rw-r--r--src/libparsec/include/net_pckt_gmsv.h23
-rw-r--r--src/libparsec/include/net_ports.h18
-rw-r--r--src/libparsec/include/net_stream.h148
-rw-r--r--src/libparsec/include/net_swap.h21
-rw-r--r--src/libparsec/include/net_util.h40
-rw-r--r--src/libparsec/include/net_wrap.h114
-rw-r--r--src/libparsec/include/obj_clas.h20
-rw-r--r--src/libparsec/include/obj_creg.h46
-rw-r--r--src/libparsec/include/obj_cust.h77
-rw-r--r--src/libparsec/include/obj_name.h53
-rw-r--r--src/libparsec/include/obj_odt.h65
-rw-r--r--src/libparsec/include/obj_type.h24
-rw-r--r--src/libparsec/include/objstruc.h47
-rw-r--r--src/libparsec/include/od_class.h106
-rw-r--r--src/libparsec/include/od_geomv.h218
-rw-r--r--src/libparsec/include/od_masks.h64
-rw-r--r--src/libparsec/include/od_odt.h359
-rw-r--r--src/libparsec/include/od_prim.h676
-rw-r--r--src/libparsec/include/od_props.h248
-rw-r--r--src/libparsec/include/od_rast.h124
-rw-r--r--src/libparsec/include/od_struc.h430
-rw-r--r--src/libparsec/include/od_texdf.h146
-rw-r--r--src/libparsec/include/od_trafo.h62
-rw-r--r--src/libparsec/include/od_types.h430
-rw-r--r--src/libparsec/include/parttype.h432
-rw-r--r--src/libparsec/include/platform.h79
-rwxr-xr-xsrc/libparsec/include/platform_sdl.h21
-rw-r--r--src/libparsec/include/sl_path.h20
-rw-r--r--src/libparsec/include/sl_timer.h30
-rw-r--r--src/libparsec/include/sw_path.h20
-rwxr-xr-xsrc/libparsec/include/sw_timer.h30
-rw-r--r--src/libparsec/include/sys_date.h27
-rw-r--r--src/libparsec/include/sys_defs.h38
-rw-r--r--src/libparsec/include/sys_file.h44
-rw-r--r--src/libparsec/include/sys_io.h37
-rw-r--r--src/libparsec/include/sys_path.h22
-rw-r--r--src/libparsec/include/sys_swap.h26
-rw-r--r--src/libparsec/include/utl_bsp.h16
-rw-r--r--src/libparsec/include/utl_clip.h35
-rw-r--r--src/libparsec/include/utl_clpo.h17
-rw-r--r--src/libparsec/include/utl_cull.h21
-rw-r--r--src/libparsec/include/utl_fcos.h261
-rw-r--r--src/libparsec/include/utl_fsin.h261
-rw-r--r--src/libparsec/include/utl_list.h254
-rw-r--r--src/libparsec/include/utl_logfile.h53
-rw-r--r--src/libparsec/include/utl_math.h438
-rw-r--r--src/libparsec/include/utl_math2.h49
-rw-r--r--src/libparsec/include/utl_model.h59
-rw-r--r--src/libparsec/net_pckt_gmsv.cpp507
-rw-r--r--src/libparsec/net_stream.cpp587
-rw-r--r--src/libparsec/net_swap.cpp546
-rw-r--r--src/libparsec/net_util.cpp573
-rw-r--r--src/libparsec/net_wrap.cpp132
-rw-r--r--src/libparsec/obj_clas.cpp290
-rw-r--r--src/libparsec/obj_creg.cpp464
-rw-r--r--src/libparsec/obj_cust.cpp361
-rw-r--r--src/libparsec/obj_odt.cpp2088
-rw-r--r--src/libparsec/obj_type.cpp745
-rw-r--r--src/libparsec/sl_path.cpp290
-rw-r--r--src/libparsec/sl_timer.cpp267
-rw-r--r--src/libparsec/sw_path.cpp346
-rwxr-xr-xsrc/libparsec/sw_timer.cpp232
-rw-r--r--src/libparsec/sys_date.cpp124
-rw-r--r--src/libparsec/sys_file.cpp892
-rw-r--r--src/libparsec/sys_swap.cpp153
-rw-r--r--src/libparsec/utl_bsp.cpp205
-rw-r--r--src/libparsec/utl_clip.cpp1447
-rw-r--r--src/libparsec/utl_clpo.cpp1188
-rw-r--r--src/libparsec/utl_cull.cpp278
-rw-r--r--src/libparsec/utl_logfile.cpp260
-rw-r--r--src/libparsec/utl_math.cpp620
-rw-r--r--src/libparsec/utl_math2.cpp1231
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( &regcom, 0, sizeof( user_command_s ) );
+
+ regcom.command = "mcbdump";
+ regcom.numparams = 0;
+ regcom.execute = Cmd_MCBDUMP;
+ regcom.statedump = NULL;
+ CON_RegisterUserCommand( &regcom );
+}
+
+
+#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( &regcom, 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( &regcom );
+}
+
+
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( &regcom, 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( &regcom );
+
+ memset( &regcom, 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( &regcom );
+
+ memset( &regcom, 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( &regcom );
+
+ // register "emp" command
+ regcom.command = "emp";
+ regcom.numparams = 0;
+ regcom.execute = Cmd_EMP;
+ regcom.statedump = NULL;
+ CON_RegisterUserCommand( &regcom );
+
+ // 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( &regcom, 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( &regcom );
+
+ // register "shipclass" command
+ regcom.command = "shipclass";
+ regcom.numparams = 1;
+ regcom.execute = Cmd_SHIPCLASS;
+ regcom.statedump = NULL;
+ CON_RegisterUserCommand( &regcom );
+
+ // 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( &regcom );
+
+ // 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 ] );
+}
+
+