From c068f22329d5cc722622a2183bbb22eef2093df7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 11:16:07 +0200 Subject: initial import --- src/parsec/g_stgate.cpp | 1653 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1653 insertions(+) create mode 100644 src/parsec/g_stgate.cpp (limited to 'src/parsec/g_stgate.cpp') diff --git a/src/parsec/g_stgate.cpp b/src/parsec/g_stgate.cpp new file mode 100644 index 0000000..801fd03 --- /dev/null +++ b/src/parsec/g_stgate.cpp @@ -0,0 +1,1653 @@ +/* + * PARSEC - Stargate Model + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:37 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer 1999-2002 + * Copyright (c) Markus Hadwiger 1999-2000 + * Copyright (c) Andreas Varga 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 +#include +#include +#include + +// 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" + +// drawing subsystem +#include "d_bmap.h" +#include "d_font.h" +#include "d_iter.h" +#include "d_misc.h" + +// subsystem linkage info +#include "linkinfo.h" + +// mathematics header +#include "utl_math.h" + +// model header +#include "utl_model.h" + +// local module header +#include "g_stgate.h" + +// proprietary module headers +#include "con_info.h" +#include "e_callbk.h" +#include "e_color.h" +#include "e_supp.h" +#include "h_supp.h" +//#include "net_game_gmsv.h" +#include "net_serv.h" +#include "net_udpdf.h" +#include "net_wrap.h" +#include "obj_clas.h" +#include "obj_creg.h" +#include "obj_ctrl.h" +#include "obj_cust.h" +#include "part_api.h" + + +// flags +//#define _VISUALIZE_BBOX +//#define _VISUALIZE_BRECT +#define USE_COMPILED_VTX_ARRAYS +#define USE_STRIPORDER_TRIANGLES +//#define DISABLE_RING_FLARES + + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 255 +static char paste_str[ PASTE_STR_LEN + 1 ]; + + +// stargate limits and constants ---------------------------------------------- +// +#define STARGATE_RADIUS 50.0f +#define STARGATE_NUM_PLATES 12 // number of plates the stargate consists of +#define STARGATE_NUM_FLARES STARGATE_NUM_PLATES // number of flares attached to the stargate +#define STARGATE_INTERIOR_NUM_RINGS 15 +#define STARGATE_INTERIOR_VERTS_PER_RING ( STARGATE_NUM_PLATES * 2 ) +#define STARGATE_INTERIOR_NUM_VERTS ( ( STARGATE_INTERIOR_VERTS_PER_RING * STARGATE_INTERIOR_NUM_RINGS ) + 1 ) +#define STARGATE_INTERIOR_RADIUS ( STARGATE_RADIUS * 0.98f ) + +#define STARGATE_RING_NUM_PARTS STARGATE_NUM_PLATES +#define STARGATE_PART_RADIUS STARGATE_RADIUS +#define STARGATE_RADIUS_EXPANSION 1.0f +#define STARGATE_NUM_RINGS 20 +#define STARGATE_RING_PART_ZSPACING 10.0f +#define STARGATE_PART_ZOFFSET INT_TO_GEOMV( -2 ) + +#define STARGATE_INTERIOR_TEXTURE_NAME "sg_int.3df" +#define STARGATE_FLARE_PDEF_NAME "sgateposlt" + + +#if ( STARGATE_INTERIOR_NUM_RINGS > 32 ) + #error "too many rings in stargate interior" +#endif + + +// module local functions ----------------------------------------------------- +// +PRIVATE int StargateInstantiate_InitInteriorVertices( Stargate *stargate ); + +//PRIVATE int StargateModify_RealizeNode( GenObject* base ); +PRIVATE int StargateModify_ActiveChanged( GenObject* base ); +PRIVATE int StargateModify_AutoactivateChanged( GenObject* base ); +PRIVATE void StargateModify_CreateActiveParticles( CustomObject *base ); + + +// offset definitions into the Stargate --------------------------------------- +// +#define OFS_ROTSPEED offsetof( Stargate, rotspeed ) +#define OFS_RADIUS offsetof( Stargate, radius ) +#define OFS_DESTNAME offsetof( Stargate, destination_name ) +//#define OFS_DESTIP offsetof( Stargate, destination_ip ) +//#define OFS_DESTPORT offsetof( Stargate, destination_port ) +#define OFS_ACTDISTANCE offsetof( Stargate, actdistance ) +#define OFS_DORMANT offsetof( Stargate, dormant ) +#define OFS_ACTIVE offsetof( Stargate, active ) +#define OFS_AUTOACTIVATE offsetof( Stargate, autoactivate ) +#define OFS_NUMPARTACTIVE offsetof( Stargate, numpartactive ) +#define OFS_ACTCYLLEN offsetof( Stargate, actcyllen ) +#define OFS_PARTVEL offsetof( Stargate, partvel ) +#define OFS_MODULSPEED offsetof( Stargate, modulspeed ) +#define OFS_MODULRAD1 offsetof( Stargate, modulrad1 ) +#define OFS_MODULRAD2 offsetof( Stargate, modulrad2 ) +#define OFS_ACTTIME offsetof( Stargate, acttime ) +#define OFS_FLARE_NAME offsetof( Stargate, flare_name ) +#define OFS_INTERIOR_NAME offsetof( Stargate, interior_name ) + + +// list of console-accessible properties -------------------------------------- +// +PRIVATE +proplist_s Stargate_PropList[] = { + + { "rotspeed", OFS_ROTSPEED, 0, 0xffff, PROPTYPE_INT, NULL }, + { "radius", OFS_RADIUS, 0x10000, 0x4000000, PROPTYPE_FLOAT, NULL }, + //{ "destname", OFS_DESTNAME, 0, MAX_SERVER_NAME, PROPTYPE_STRING, NULL }, + //{ "destip", OFS_DESTIP, 0, STARGATE_MAX_DEST_IP, PROPTYPE_STRING, StargateModify_RealizeNode }, + //{ "destport", OFS_DESTPORT, 1024, 65535, PROPTYPE_INT, StargateModify_RealizeNode }, + { "actdistance", OFS_ACTDISTANCE, 0x10000, 0x4000000, PROPTYPE_FLOAT, NULL }, + { "dormant", OFS_DORMANT, 0x0, 0x1, PROPTYPE_INT, NULL }, + { "active", OFS_ACTIVE, 0x0, 0x1, PROPTYPE_INT, StargateModify_ActiveChanged }, + { "autoactivate", OFS_AUTOACTIVATE, 0x0, 0x1, PROPTYPE_INT, StargateModify_AutoactivateChanged }, + { "numpartactive", OFS_NUMPARTACTIVE, 1, 2048, PROPTYPE_INT, NULL }, + { "actcyllen", OFS_ACTCYLLEN, 0, 2048, PROPTYPE_INT, NULL }, + { "partvel", OFS_PARTVEL, 0x10000, 0x4000000, PROPTYPE_FLOAT, NULL }, + { "modulspeed", OFS_MODULSPEED, 0, 0xffff, PROPTYPE_INT, NULL }, + { "modulrad1", OFS_MODULRAD1, 0x10000, 0x4000000, PROPTYPE_FLOAT, NULL }, + { "modulrad2", OFS_MODULRAD2, 0x10000, 0x4000000, PROPTYPE_FLOAT, NULL }, + { "acttime", OFS_ACTTIME, 0, FRAME_MEASURE_TIMEBASE*10, PROPTYPE_INT, NULL }, + { "flare_name", OFS_FLARE_NAME, 0, MAX_TEXNAME, PROPTYPE_STRING, NULL }, + { "interior_name", OFS_INTERIOR_NAME, 0, MAX_TEXNAME, PROPTYPE_STRING, NULL }, + + { NULL, 0, 0, 0, 0, NULL }, +}; + + +// type fields init function for stargate ------------------------------------- +// +PRIVATE +void StargateInitType( CustomObject *base ) +{ + ASSERT( base != NULL ); + + Stargate *stargate = (Stargate *) base; + + stargate->rotspeed = 0x0004; + stargate->radius = STARGATE_PART_RADIUS; + stargate->actdistance = 300; + stargate->dormant = FALSE; + stargate->active = FALSE; + stargate->autoactivate = TRUE; + stargate->numpartactive = 600; + stargate->actcyllen = 300; + stargate->partvel = 150; + stargate->modulspeed = DEG_TO_BAMS( 1.0f ); + stargate->modulate_bams = BAMS_DEG0; + stargate->modulrad1 = 5.0f; + stargate->modulrad2 = 2.0f; + stargate->modulfade = 2.0f; + stargate->acttime = FRAME_MEASURE_TIMEBASE; + + stargate->activating = FALSE; + stargate->curactcyllen = 0; + stargate->manually_activated = FALSE; + stargate->actring = 0.0f; + + strcpy( stargate->flare_name, STARGATE_FLARE_PDEF_NAME ); + strcpy( stargate->interior_name, STARGATE_INTERIOR_TEXTURE_NAME ); + + stargate->pcluster = NULL; + stargate->interior_vtxlist = NULL; + stargate->interior_viewvtxs = NULL; + stargate->interior_u = NULL; + stargate->interior_v = NULL; + stargate->interior_texmap = NULL; + + stargate->ping = -1; + stargate->lastpinged = 0; +} + +/* +// notification callback when eihter IP or port is changed -------------------- +// +PRIVATE +int StargateModify_RealizeNode( GenObject* base ) +{ + ASSERT( base != NULL ); + Stargate* stargate = (Stargate *) base; + + // try to resolve DNS name to IP address (still as string) + char resolved_name[ MAX_IPADDR_LEN + 1 ]; + if ( NET_ResolveHostName( stargate->destination_ip, resolved_name, NULL ) ) { + MSGOUT( "stargate->destinaiton %s resolved to %s", stargate->destination_ip, resolved_name ); + } else { + // DNS lookup failed + return FALSE; + } + + // save server address for later use by NET_GMSV.C + inet_aton( resolved_name, &stargate->destination_node ); + UDP_StoreNodePort( &stargate->destination_node, stargate->destination_port ); + + return TRUE; +} +*/ + +// notification callback when "active" changed -------------------------------- +// +PRIVATE +int StargateModify_ActiveChanged( GenObject* base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + + // manual activation/deactivation only if autoactivate off + if ( stargate->autoactivate ) { + return TRUE; + } + + // prevent manual activation when stargate dormant + if ( stargate->dormant ) { + stargate->active = FALSE; + } + + if ( stargate->active ) { + + if ( !stargate->manually_activated ) { + stargate->manually_activated = TRUE; + StargateModify_CreateActiveParticles( stargate ); + } + + } else { + + stargate->manually_activated = FALSE; + } + + return TRUE; +} + + +// notification callback when "autoactivate" changed -------------------------- +// +PRIVATE +int StargateModify_AutoactivateChanged( GenObject* base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + + // deactivate the stargate when it's active due to a manual activation + if ( stargate->autoactivate && stargate->manually_activated ) { + stargate->active = FALSE; + stargate->manually_activated = FALSE; + } + + return TRUE; +} + + +// particle animation callback for setting the stargate-active particles ------ +// +PRIVATE +void StargateAnimate_Particles( genobject_pcluster_s* pcluster ) +{ + ASSERT( pcluster != NULL ); + + Stargate *stargate = (Stargate *) pcluster->baseobject; + + for ( int curp = 0; curp < pcluster->numel; curp++ ) { + + particle_s* curparticle = &pcluster->rep[ curp ]; + + // skip inactive particles + if ( ( curparticle->flags & PARTICLE_ACTIVE ) == 0 ) + continue; + + // move along vector + Vector3 advvec; + advvec.Z = curparticle->velocity.Z * CurScreenRefFrames; + curparticle->position.Z += advvec.Z; + + // check whether particle is sucked into the stargate and + // reposition it at the beginning of the tunnel + if ( curparticle->position.Z > 0 ) { + + if ( stargate->active ) { + + geomv_t basez = STARGATE_PART_ZOFFSET + curparticle->position.Z; + if ( stargate->activating ) { + curparticle->position.Z = + basez - INT_TO_GEOMV( stargate->curactcyllen ); + } else { + curparticle->position.Z = + basez - INT_TO_GEOMV( stargate->actcyllen ); + } + + } else { + + // if stargate switches to inactive, do not reactivate + // the particle at the cylinder beginning + curparticle->flags &= ~PARTICLE_ACTIVE; + } + } + } +} + + +// init flares of stargate ring ----------------------------------------------- +// +INLINE +void StargateInstantiate_InitFlares( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + //TODO: this way resolution changes are not handled + extern float cur_particle_resoscale; + + // attach flares to the stargate + pdef_s *pdef = PRT_AcquireParticleDefinition( stargate->flare_name, NULL ); + if ( pdef == NULL ) { + return; + } + + // init the extinfo structure + pextinfo_s extinfo; + PRT_InitParticleExtInfo( &extinfo, pdef, NULL, NULL ); + + // specify the reference z value ( directly modifies the width/height of a flare particle) + float ref_z = 100.0f * cur_particle_resoscale; + + dword rendflags = PART_REND_POINTVIS | PART_REND_NODEPTHCMP; + int bitmap = iter_texrgba | iter_additiveblend | rendflags; + int color = 0; + + // specify the angle and angleoffset for the flares + float distangle = 360.0f / STARGATE_NUM_FLARES; + float offsangle = distangle * 0.5f; + + // create a genobject particle cluster + genobject_pcluster_s *pcluster = PRT_CreateGenObjectParticleCluster( + stargate, STARGATE_NUM_FLARES, NULL, FALSE ); + + // flare ring radius + geomv_t radius = FLOAT_TO_GEOMV( STARGATE_PART_RADIUS ); + + // create particles with equal angular distance + for ( int flare = 0; flare < STARGATE_NUM_FLARES; flare++ ) { + + // calculate the sin/cos for the x/y positions between the stargate solids + sincosval_s sincosv; + bams_t flarebams = DEG_TO_BAMS( distangle * flare + offsangle ); + GetSinCos( flarebams, &sincosv ); + + // set the position for each flare particle + Vertex3 origin; + origin.X = GEOMV_MUL( radius, sincosv.cosval ); + origin.Y = GEOMV_MUL( radius, sincosv.sinval ); + origin.Z = GEOMV_0; + + // init the particle + particle_s particle; + PRT_InitParticle( particle, bitmap, color, PRT_NO_SIZEBOUND, ref_z, + &origin, NULL, INFINITE_LIFETIME, LocalPlayerId, &extinfo ); + + // and attach it to the particle cluster + PRT_AddGenObjectParticle( particle, stargate, pcluster, 0, NULL ); + + // advance one texture frame + extinfo.tex_pos++; + + // wrap around to repeat position if more flares than texture frames + if ( extinfo.tex_pos > pdef->tex_end ) { + extinfo.tex_pos = pdef->tex_rep; + } + } +} + + +// allocated tables needed for interior rendering ----------------------------- +// +INLINE +void StargateInstantiate_AllocInterior( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + size_t vtxssize = sizeof( Vertex3 ) * STARGATE_INTERIOR_NUM_VERTS * 2; + size_t texcosize = sizeof( geomv_t ) * STARGATE_INTERIOR_NUM_VERTS * 2; + + void *memblock = ALLOCMEM( vtxssize + texcosize ); + if ( memblock == NULL ) + OUTOFMEM( "no mem for stargate data." ); + + stargate->interior_vtxlist = (Vertex3 *) + memblock; + stargate->interior_viewvtxs = (Vertex3 *) + ( (char*)memblock + sizeof( Vertex3 ) * STARGATE_INTERIOR_NUM_VERTS ); + stargate->interior_u = (geomv_t *) + ( (char*)memblock + sizeof( Vertex3 ) * STARGATE_INTERIOR_NUM_VERTS * 2 ); + stargate->interior_v = (geomv_t *) + ( (char*)stargate->interior_u + sizeof( geomv_t ) * STARGATE_INTERIOR_NUM_VERTS ); + + stargate->interior_texmap = NULL; +} + + +// stargate constructor (class instantiation) --------------------------------- +// +PRIVATE +void StargateInstantiate( CustomObject *base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + +#ifndef DISABLE_RING_FLARES + + // init ring flares + StargateInstantiate_InitFlares( stargate ); + +#endif // !DISABLE_RING_FLARES + + // alloc interior data + StargateInstantiate_AllocInterior( stargate ); + + // init the interior mesh + StargateInstantiate_InitInteriorVertices( stargate ); + + // only when connected the stargate is dormant by default + stargate->dormant = NET_ConnectedGMSV() ? TRUE : FALSE; +} + + +//FIXME: +pdef_s *PDEF_pflare03(); + + +// do one step of the activation sequence ------------------------------------- +// +PRIVATE +void StargateAnimate_StepActivationSequence( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + //FIXME: + // we need a better way to get access to the pcluster attached to the genobject + // -> set pcluster->animtype to SAT_STARGATE_TUNNEL or something, to allow use + // of PRT_ObjectHasAttachedClustersOfType + + ASSERT( stargate->pcluster != NULL ); + + //FIXME: + pdef_s *pdef = PDEF_pflare03(); + + // check whether the required particle definition is available + if ( pdef != NULL ) { + + pdef_s *pdef = PDEF_pflare03(); //FIXME: ???? + + //TODO: this way resolution changes are not handled + extern float cur_particle_resoscale; + + // create the extinfo structure + pextinfo_s extinfo; + PRT_InitParticleExtInfo( &extinfo, pdef, NULL, NULL ); + + particle_s particle; + + dword rendflags = PART_REND_NONE; + int bitmap = iter_texrgba | iter_specularadd | rendflags; + int color = 0; + + //FIXME: constant + float ref_z = 50.0f * cur_particle_resoscale; + + //FIXME: constant for number of arcs + sincosval_s sincosv; + GetSinCos( DEG_TO_BAMS( 360 / STARGATE_RING_NUM_PARTS ), &sincosv ); + + Vertex3 origin; + + Vertex3 velocity; + velocity.X = GEOMV_0; + velocity.Y = GEOMV_0; + velocity.Z = FLOAT_TO_GEOMV( stargate->partvel / ( INT2FLOAT( FRAME_MEASURE_TIMEBASE ) ) ); + + // number of particles to create in one step + int numparticlesonce; + int curseglen; + + // calculate the number of frames to complete the activation sequence + ASSERT( CurScreenRefFrames > 0 ); + float fFrames2CompleteActivation = (float)stargate->acttime / CurScreenRefFrames; + + // check whether all particles should be added at once + if ( fFrames2CompleteActivation <= 1.0f ) { + + numparticlesonce = stargate->numpartactive - stargate->pcluster->numel; + + // set the length of the cylinder segment in this iteration + curseglen = stargate->actcyllen - stargate->curactcyllen; + + } else { + + numparticlesonce = (int)( (float)stargate->numpartactive / fFrames2CompleteActivation ); + + // set the length of the cylinder segment in this iteration + curseglen = (int)( (float)stargate->actcyllen / fFrames2CompleteActivation ); + + // do not allow the tunnel to be longer than actcyllen + curseglen = min( stargate->actcyllen - stargate->curactcyllen, curseglen ); + } + + stargate->actring = stargate->actring + + INT2FLOAT( STARGATE_INTERIOR_NUM_RINGS ) / fFrames2CompleteActivation; + + // ensure that at least one particle is added each frame + numparticlesonce = max( numparticlesonce, 1 ); + + // add the particles to the cluster + for ( int pcnt = 0; pcnt < numparticlesonce; pcnt++ ) { + + // randomize angle around 360 degrees + // CAVEAT: this relies on RAND_MAX being >= 0x7fff + ASSERT( RAND_MAX >= 0x7fff ); + bams_t theta = ( RAND() & 0x7fff ) << 2; + float rad_variance = (float)( ( RAND() % 101 ) - 50 ) / 1000.0f * STARGATE_PART_RADIUS; + + GetSinCos( theta, &sincosv ); + + geomv_t radius = FLOAT_TO_GEOMV( STARGATE_PART_RADIUS + rad_variance ); + + origin.X = GEOMV_MUL( radius, sincosv.cosval ); + origin.Y = GEOMV_MUL( radius, sincosv.sinval ); + + if ( curseglen > 0 ) { + origin.Z = STARGATE_PART_ZOFFSET - + INT_TO_GEOMV( stargate->curactcyllen + ( RAND() % curseglen ) ); + } else { + origin.Z = STARGATE_PART_ZOFFSET - + INT_TO_GEOMV( stargate->curactcyllen ); + } + + // init the particle information + PRT_InitParticle( particle, bitmap, color, PRT_NO_SIZEBOUND, ref_z, + &origin, &velocity, INFINITE_LIFETIME, LocalPlayerId, &extinfo ); + + PRT_AddGenObjectParticle( + particle, stargate, stargate->pcluster, 0, StargateAnimate_Particles ); + } + + // advance the activation cylinder length + stargate->curactcyllen += curseglen; + + // the activation is finished, so reset the flag for activation sequence + if ( stargate->pcluster->numel >= stargate->numpartactive ) { + stargate->activating = FALSE; + } + } +} + + +// create activated stargate particles ---------------------------------------- +// +PRIVATE +void StargateModify_CreateActiveParticles( CustomObject *base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + + pdef_s *pdef = PDEF_pflare03(); + if ( pdef == NULL ) { + return; + } + + // create the genobject particle cluster + stargate->pcluster = PRT_CreateGenObjectParticleCluster( + stargate, stargate->numpartactive, StargateAnimate_Particles, FALSE ); + + // ensure that cluster is not culled when genobject is culled + stargate->pcluster->type |= CT_DONT_CULL_WITH_GENOBJECT; + + // set performance hints + stargate->pcluster->type |= CT_HINT_PARTICLES_IDENTICAL; + stargate->pcluster->type |= CT_CLUSTER_GLOBAL_EXTINFO; + stargate->pcluster->type |= CT_HINT_PARTICLES_HAVE_EXTINFO; + + // set the flag to indicate we are currently activating the stargate + stargate->activating = TRUE; + + // set the begin of the current activation cylinder part + stargate->curactcyllen = 0; + + stargate->actring = 0.0f; + + // and do the first step of the animation sequence + StargateAnimate_StepActivationSequence( stargate ); +} + + +// screenspace bounding rectangle --------------------------------------------- +// +struct boundrect_s { + + sgrid_t min_x; + sgrid_t max_x; + + sgrid_t min_y; + sgrid_t max_y; +}; + + +// calculate the conservative 2d bounding rectangle of a genobject in screenspace ---- +// +PRIVATE +int CalculateBoundingRectFromBSphere( GenObject *object, boundrect_s* boundrect ) +{ + ASSERT( object != NULL ); + ASSERT( boundrect != NULL ); + + geomv_t target_bsphere = object->BoundingSphere; + int target_square; + + Vector3 pos; + Vector3 pos_t; + + pos.X = object->ObjPosition[ 0 ][ 3 ]; + pos.Y = object->ObjPosition[ 1 ][ 3 ]; + pos.Z = object->ObjPosition[ 2 ][ 3 ]; + + MtxVctMUL( ViewCamera, &pos, &pos_t ); + + // don't draw if object is behind local ship + if ( pos_t.Z <= GEOMV_0 ) + return FALSE; + + // project bounding sphere radius to screenspace + target_square = GEOMV_TO_COORD( GEOMV_DIV( target_bsphere, pos_t.Z ) ); + + // calc position of ship in screenspace + SPoint sloc; + PROJECT_TO_SCREEN( pos_t, sloc ); + + boundrect->min_x = sloc.X - target_square; + boundrect->min_y = sloc.Y - target_square; + + boundrect->max_x = sloc.X + target_square; + boundrect->max_y = sloc.Y + target_square; + + return TRUE; +} + + +// ---------------------------------------------------------------------------- +// +#define PING_WAIT_MAX (5 * 1000) + +static refframe_t stargate_ping_wait = 0; + + +// determine whether stargate is dormant or not ------------------------------- +// +PRIVATE +void DetermineStargateDormantState( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + + // only while connected + if ( !NET_ConnectedGMSV() ) { + return; + } + + // re-issue a server ping, once every 5 seconds + if ( ( stargate_ping_wait += CurScreenRefFrames ) > PING_WAIT_MAX ) { + + stargate_ping_wait = 0; + +// int ping = -1; + if ( stargate->destination_node.address[ 0 ] != 0 ) { + + NET_ServerPing( &stargate->destination_node, TRUE, FALSE ); + } + + //NOTE: + // ping result is not valid here, since we didn't wait + // for the arrival of the ping packet. The ping time will + // be available once the NET_ProcessPingPacket() function + // has processed the returned packet. + + //NOTE: + // when a ping packet arrives, NET_ProcessPingPacket() + // sets Stargate::dormant, Stargate::ping, Stargate::lastpinged. + + refframe_t curtime = SYSs_GetRefFrameCount(); + + // if we didn't get a pingreply for quite some time, we assume the + // server went down or was quit, so we switch the stargate to dormant state + if ( ( curtime - stargate->lastpinged ) > ( PING_WAIT_MAX * 2 ) ) { + + stargate->dormant = TRUE; + stargate->ping = -1; + stargate->active = FALSE; + } + } + +} + + +// ---------------------------------------------------------------------------- +// +PRIVATE +void DrawStargateText( char *text, boundrect_s *boundrect, int top ) +{ + // look for OpenParsec approved name + char *tmpdomain = strstr(text, ".openparsec.com\0"); + if(tmpdomain != NULL) { + // if it does not equal null, we found one, so truncate it and add a * + tmpdomain[0]='*'; + tmpdomain[1]='\0'; + } + + int width = strlen( text ) * CharsetInfo[ HUD_CHARSETNO ].width; + int height = CharsetInfo[ HUD_CHARSETNO ].height; + + int xpos = boundrect->min_x + ( boundrect->max_x - boundrect->min_x - width ) / 2; + int ypos = top ? ( boundrect->min_y - height - 2 ) : boundrect->max_y; + + xpos -= 1; + ypos -= 1; + + width += 3; + height += 3; + + // check against screen boundaries + if ( xpos < 0 ) + return; + if ( ypos < 0 ) + return; + if ( ( xpos + width ) > Screen_Width ) + return; + if ( ( ypos + height ) > Screen_Height ) + return; + + D_DrawTrRect( xpos, ypos, width, height, TRTAB_PANELBACK ); + D_WriteTrString( text, xpos + 1, ypos + 2, TRTAB_PANELTEXT ); +} + + +// draw stargate destination text --------------------------------------------- +// +PRIVATE +int StargateDraw_HUD( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + // set the string context for displaying HUD information + D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer, + CharsetInfo[ HUD_CHARSETNO ].geompointer, + NULL, + CharsetInfo[ HUD_CHARSETNO ].width, + CharsetInfo[ HUD_CHARSETNO ].height ); + + // calculate the screenspace bounding rectangle of the stargate + boundrect_s boundrect; + if ( CalculateBoundingRectFromBSphere( stargate, &boundrect ) ) { + + if ( NetConnected == NETWORK_GAME_ON ) { + + // draw name of destination system + DrawStargateText( stargate->destination_name, &boundrect, TRUE ); + + // draw ping text + if ( stargate->ping == -1 ) { + sprintf( paste_str, "system unreachable" ); + } else { + sprintf( paste_str, "ping: %dms", stargate->ping ); + } + DrawStargateText( paste_str, &boundrect, FALSE ); + } + } + + return TRUE; +} + + +// init interior vertexlist of stargate --------------------------------------- +// +PRIVATE +int StargateInstantiate_InitInteriorVertices( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + // get pointer to texture map + stargate->interior_texmap = FetchTextureMap( stargate->interior_name ); + if ( stargate->interior_texmap == NULL ) { + MSGOUT( "texture '%s' was not found.", stargate->interior_name ); + return FALSE; + } + + // middle point of interior mesh + stargate->interior_vtxlist[ 0 ].X = INT_TO_GEOMV( 0 ); + stargate->interior_vtxlist[ 0 ].Y = INT_TO_GEOMV( 0 ); + stargate->interior_vtxlist[ 0 ].Z = INT_TO_GEOMV( 0 ); + + int uWidth = ( 1 << stargate->interior_texmap->Width ); + int vHeight = ( 1 << stargate->interior_texmap->Height ); + + geomv_t uScaleFactor = GEOMV_DIV( INT_TO_GEOMV( uWidth ), FLOAT_TO_GEOMV( 2 * STARGATE_INTERIOR_RADIUS ) ); + geomv_t vScaleFactor = GEOMV_DIV( INT_TO_GEOMV( vHeight ), FLOAT_TO_GEOMV( 2 * STARGATE_INTERIOR_RADIUS ) ); + + stargate->interior_u[ 0 ] = GEOMV_MUL( 0 + STARGATE_INTERIOR_RADIUS, uScaleFactor ); /*INT_TO_GEOMV ( ( 1L << stargate->interior_texmap->Width ) >> 1 );*/ + stargate->interior_v[ 0 ] = GEOMV_MUL( 0 + STARGATE_INTERIOR_RADIUS, vScaleFactor );/*INT_TO_GEOMV ( ( 1L << stargate->interior_texmap->Height ) >> 1 );*/ + + hprec_t interior_mesh_angle_deg = 360.0 / STARGATE_INTERIOR_VERTS_PER_RING; + sincosval_s sincosv; + + for ( int nRingSegment = 0; nRingSegment < STARGATE_INTERIOR_VERTS_PER_RING; nRingSegment++ ) { + + // get the sin/cos for the current ringsegment + bams_t interior_mesh_bams = DEG_TO_BAMS( interior_mesh_angle_deg * hprec_t(nRingSegment) ) ; + GetSinCos( interior_mesh_bams, &sincosv ); + + for( int nRing = 0; nRing < STARGATE_INTERIOR_NUM_RINGS; nRing++ ) { + + float fRadius = STARGATE_INTERIOR_RADIUS / STARGATE_INTERIOR_NUM_RINGS * ( nRing + 1 ); + + int nVertexIndex = ( 1 + ( STARGATE_INTERIOR_VERTS_PER_RING * nRing + nRingSegment ) ); + + Vertex3* pVertex3 = &stargate->interior_vtxlist[ nVertexIndex ]; + + pVertex3->X = GEOMV_MUL( FLOAT_TO_GEOMV( fRadius ) , sincosv.cosval ); + pVertex3->Y = GEOMV_MUL( FLOAT_TO_GEOMV( fRadius ) , sincosv.sinval ); + pVertex3->Z = GEOMV_0; + + stargate->interior_u[ nVertexIndex ] = GEOMV_MUL( pVertex3->X + STARGATE_INTERIOR_RADIUS, uScaleFactor ); + stargate->interior_v[ nVertexIndex ] = GEOMV_MUL( pVertex3->Y + STARGATE_INTERIOR_RADIUS, vScaleFactor ); + } + } + + return TRUE; +} + + +// modulate the vertices of the interior mesh of the stargate ----------------- +// +PRIVATE +int StargateAnimate_ModulateInteriorVertices( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + if ( stargate->modulfade > stargate->modulrad2 ) { + stargate->modulfade -= ( CurScreenRefFrames / 14.0f ); + } else { + stargate->modulfade = stargate->modulrad2; + } + + // modulate the wave + stargate->modulate_bams += stargate->modulspeed * CurScreenRefFrames; + + sincosval_s sincosv; + GetSinCos( stargate->modulate_bams, &sincosv ); + + Vertex3* pVertex3 = &stargate->interior_vtxlist[ 0 ]; + + //pVertex3->X += GEOMV_MUL( FLOAT_TO_GEOMV( 1.0f ) , sincosv.sinval ); + //pVertex3->Y += GEOMV_MUL( FLOAT_TO_GEOMV( 5.0f ) , sincosv.sinval ); + pVertex3->Z = GEOMV_MUL( FLOAT_TO_GEOMV( stargate->modulrad1 ) , sincosv.sinval ); + + for ( int ring = 0; ring < ( STARGATE_INTERIOR_NUM_RINGS - 1 ); ring++ ) { + + bams_t angdelt = DEG_TO_BAMS( 360.0f / ( STARGATE_INTERIOR_NUM_RINGS + 1 ) ); + bams_t angtemp = stargate->modulate_bams + ( ( ring + 1 ) * angdelt ); + GetSinCos( angtemp, &sincosv ); + + for( int ringseg = 0; ringseg < STARGATE_INTERIOR_VERTS_PER_RING; ringseg++ ) { + + int vindx = 1 + ( STARGATE_INTERIOR_VERTS_PER_RING * ring + ringseg ); + Vertex3* pVertex3 = &stargate->interior_vtxlist[ vindx ]; + //pVertex3->X += GEOMV_MUL( FLOAT_TO_GEOMV( 1.0f ) , sincosv.sinval ); + //pVertex3->Y += GEOMV_MUL( FLOAT_TO_GEOMV( 5.0f ) , sincosv.sinval ); + pVertex3->Z = GEOMV_MUL( FLOAT_TO_GEOMV( stargate->modulfade ) , sincosv.sinval ); + } + } + + return TRUE; +} + + +#ifndef USE_COMPILED_VTX_ARRAYS + +// macro to set the properties of a itervertex -------------------------------- +// +#define SET_ITER_VTX( P_ITER_VTX, P_IN_VTX, P_OUT_VTX, P_VTX_U, P_VTX_V, VTX_RED, VTX_GREEN, VTX_BLUE, VTX_ALPHA ) \ + MtxVctMUL( DestXmatrx, (P_IN_VTX), (P_OUT_VTX) ); \ + (P_ITER_VTX)->X = (P_OUT_VTX)->X; \ + (P_ITER_VTX)->Y = (P_OUT_VTX)->Y; \ + (P_ITER_VTX)->Z = (P_OUT_VTX)->Z; \ + (P_ITER_VTX)->W = GEOMV_1; \ + (P_ITER_VTX)->U = *(P_VTX_U); \ + (P_ITER_VTX)->V = *(P_VTX_V); \ + (P_ITER_VTX)->R = VTX_RED; \ + (P_ITER_VTX)->G = VTX_GREEN; \ + (P_ITER_VTX)->B = VTX_BLUE; \ + (P_ITER_VTX)->A = VTX_ALPHA; + + +// draw interior using triangle strips ---------------------------------------- +// +INLINE +void StargateDraw_InteriorTriStrips( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + int numstripverts = STARGATE_INTERIOR_NUM_RINGS * 2 + 1; + + // use multiple tristrips + IterTriStrip3* itstrip = (IterTriStrip3*) + ALLOCMEM( (size_t)&((IterTriStrip3*)0)->Vtxs[ numstripverts ] ); + + // set vertex color to white + byte _red = 255; + byte _green = 255; + byte _blue = 255; + byte _alpha = 255; + + for ( int ringseg = 0; ringseg < STARGATE_INTERIOR_VERTS_PER_RING; ringseg++ ) { +/* + _alpha = 0; + _red = 0; + _green = 0; + _blue = 0; +*/ + SET_ITER_VTX( &itstrip->Vtxs[ 0 ], &stargate->interior_vtxlist[ 0 ], &stargate->interior_viewvtxs[ 0 ], + &stargate->interior_u[ 0 ], &stargate->interior_u[ 0 ], _red, _green, _blue, _alpha ); + + int nIndex = 1; + for( int nRing = 0; nRing < STARGATE_INTERIOR_NUM_RINGS; nRing++ ) { + + // fade alpha to zero + _alpha = 255 - (nRing + 1) * ( 255 / STARGATE_INTERIOR_NUM_RINGS ); + + int _animring = nRing + FLOAT2INT( stargate->actring ); + _animring = max( STARGATE_INTERIOR_NUM_RINGS, _animring ); +/* + _alpha = FLOAT2INT( INT2FLOAT( _animring ) * ( 255.0f / INT2FLOAT( STARGATE_INTERIOR_NUM_RINGS ) ) ); + _red = FLOAT2INT( INT2FLOAT( _animring ) * ( 128.0f / INT2FLOAT( STARGATE_INTERIOR_NUM_RINGS ) ) ); + _green = FLOAT2INT( INT2FLOAT( _animring ) * ( 128.0f / INT2FLOAT( STARGATE_INTERIOR_NUM_RINGS ) ) ); + _blue = FLOAT2INT( INT2FLOAT( _animring ) * ( 128.0f / INT2FLOAT( STARGATE_INTERIOR_NUM_RINGS ) ) ); +*/ + int nVertexIndex_1 = 1 + ( STARGATE_INTERIOR_VERTS_PER_RING * nRing + ringseg ); + int nVertexIndex_2 = 1 + ( STARGATE_INTERIOR_VERTS_PER_RING * nRing + ( ( ringseg + 1 ) % STARGATE_INTERIOR_VERTS_PER_RING ) ); + + Vertex3* pVertex3_1 = &stargate->interior_vtxlist[ nVertexIndex_1 ]; + Vertex3* pVertex3_2 = &stargate->interior_vtxlist[ nVertexIndex_2 ]; + + + SET_ITER_VTX( &itstrip->Vtxs[ nIndex ], pVertex3_1, &stargate->interior_viewvtxs[ nIndex ], + &stargate->interior_u[ nVertexIndex_1 ], &stargate->interior_v[ nVertexIndex_1 ], + _red, _green, _blue, _alpha ); + + nIndex++; + SET_ITER_VTX( &itstrip->Vtxs[ nIndex ], pVertex3_2, &stargate->interior_viewvtxs[ nIndex ], + &stargate->interior_u[ nVertexIndex_2 ], &stargate->interior_v[ nVertexIndex_2 ], + _red, _green, _blue, _alpha ); + + nIndex++; + } + + itstrip->NumVerts = numstripverts; + itstrip->flags = ITERFLAG_Z_DIV_XYZ | ITERFLAG_Z_DIV_UVW | + ITERFLAG_Z_TO_DEPTH; + itstrip->itertype = iter_texrgba | iter_specularadd; + itstrip->raststate = rast_zcompare/*rast_zbuffer */| rast_texclamp | rast_chromakeyoff; + itstrip->rastmask = rast_nomask; + itstrip->texmap = stargate->interior_texmap; + + D_DrawIterTriStrip3( itstrip, 0x3f ); + } + + FREEMEM( itstrip ); +} + +#endif // !USE_COMPILED_VTX_ARRAYS + + +#if defined( USE_COMPILED_VTX_ARRAYS ) && defined( USE_STRIPORDER_TRIANGLES ) + +// draw interior using compiled vertex arrays and strip order triangles ------- +// +INLINE +void StargateDraw_InteriorStripOrderTris( IterArray3 *itarray ) +{ + ASSERT( itarray != NULL ); + + size_t numstrips = STARGATE_INTERIOR_VERTS_PER_RING; + size_t numstriptris = STARGATE_INTERIOR_NUM_RINGS * 2 - 1; + size_t numtriindxs = numstrips * numstriptris * 3; + + dword *vindxs = (dword *) ALLOCMEM( numtriindxs * sizeof( dword ) ); + if ( vindxs == NULL ) + OUTOFMEM( "no mem for interior indexes." ); + + int dstindx = 0; + + // store all strips but last + int seg = 0; + for ( seg = 0; seg < STARGATE_INTERIOR_VERTS_PER_RING - 1; seg++ ) { + + int srcindx = 1 + seg; + + vindxs[ dstindx + 0 ] = 0; + vindxs[ dstindx + 1 ] = srcindx; + vindxs[ dstindx + 2 ] = srcindx + 1; + dstindx += 3; + int ring = 1; + for ( ring = 1; ring < STARGATE_INTERIOR_NUM_RINGS; ring++ ) { + + srcindx += STARGATE_INTERIOR_VERTS_PER_RING; + + vindxs[ dstindx + 0 ] = vindxs[ dstindx - 2 ]; + vindxs[ dstindx + 1 ] = vindxs[ dstindx - 1 ]; + vindxs[ dstindx + 2 ] = srcindx; + dstindx += 3; + + vindxs[ dstindx + 0 ] = vindxs[ dstindx - 2 ]; + vindxs[ dstindx + 1 ] = vindxs[ dstindx - 1 ]; + vindxs[ dstindx + 2 ] = srcindx + 1; + dstindx += 3; + } + } + + // store last strip + { + int srcindx = 1 + seg; + + vindxs[ dstindx + 0 ] = 0; + vindxs[ dstindx + 1 ] = srcindx; + vindxs[ dstindx + 2 ] = srcindx - seg; + dstindx += 3; + + for ( int ring = 1; ring < STARGATE_INTERIOR_NUM_RINGS; ring++ ) { + + srcindx += STARGATE_INTERIOR_VERTS_PER_RING; + + vindxs[ dstindx + 0 ] = vindxs[ dstindx - 2 ]; + vindxs[ dstindx + 1 ] = vindxs[ dstindx - 1 ]; + vindxs[ dstindx + 2 ] = srcindx; + dstindx += 3; + + vindxs[ dstindx + 0 ] = vindxs[ dstindx - 2 ]; + vindxs[ dstindx + 1 ] = vindxs[ dstindx - 1 ]; + vindxs[ dstindx + 2 ] = srcindx - seg; + dstindx += 3; + } + } + + // draw indexed triangles in a single call + D_DrawIterArrayIndexed( + ITERARRAY_MODE_TRIANGLES, numtriindxs, vindxs, 0x3f ); + + FREEMEM( vindxs ); +} + +#endif // USE_COMPILED_VTX_ARRAYS && USE_STRIPORDER_TRIANGLES + + +#if defined( USE_COMPILED_VTX_ARRAYS ) && !defined( USE_STRIPORDER_TRIANGLES ) + +// draw interior using compiled vertex arrays and indexed strips -------------- +// +INLINE +void StargateDraw_InteriorIndexedStrips( IterArray3 *itarray ) +{ + ASSERT( itarray != NULL ); + + size_t numstripvtxs = STARGATE_INTERIOR_NUM_RINGS * 2 + 1; + dword *vindxs = (dword *) ALLOCMEM( numstripvtxs * sizeof( dword ) ); + if ( vindxs == NULL ) + OUTOFMEM( "no mem for strip indexes." ); + + // apex stays fixed + vindxs[ 0 ] = 0; + + // draw all strips but last + for ( int seg = 0; seg < STARGATE_INTERIOR_VERTS_PER_RING - 1; seg++ ) { + + int srcindx = 1 + seg; + int dstindx = 1; + for ( int ring = 0; ring < STARGATE_INTERIOR_NUM_RINGS; ring++ ) { + + vindxs[ dstindx++ ] = srcindx; + vindxs[ dstindx++ ] = srcindx + 1; + srcindx += STARGATE_INTERIOR_VERTS_PER_RING; + } + + // draw indexed tristrip + D_DrawIterArrayIndexed( + ITERARRAY_MODE_TRISTRIP, numstripvtxs, vindxs, 0x3f ); + } + + // draw last strip + { + int srcindx = 1 + seg; + int dstindx = 1; + for ( int ring = 0; ring < STARGATE_INTERIOR_NUM_RINGS; ring++ ) { + + vindxs[ dstindx++ ] = srcindx; + vindxs[ dstindx++ ] = srcindx - seg; + srcindx += STARGATE_INTERIOR_VERTS_PER_RING; + } + + // draw indexed tristrip + D_DrawIterArrayIndexed( + ITERARRAY_MODE_TRISTRIP, numstripvtxs, vindxs, 0x3f ); + } + + FREEMEM( vindxs ); +} + +#endif // USE_COMPILED_VTX_ARRAYS && !USE_STRIPORDER_TRIANGLES + + +#ifdef USE_COMPILED_VTX_ARRAYS + +// draw interior using compiled vertex arrays --------------------------------- +// +INLINE +void StargateDraw_InteriorCompiledArrays( Stargate *stargate ) +{ + ASSERT( stargate != NULL ); + + // create vertex array + IterArray3 *itarray = (IterArray3 *) ALLOCMEM( + (size_t)&((IterArray3*)0)->Vtxs[ STARGATE_INTERIOR_NUM_VERTS ] ); + if ( itarray == NULL ) + OUTOFMEM( "STARGATE: no mem for vertex array." ); + + itarray->NumVerts = STARGATE_INTERIOR_NUM_VERTS; + itarray->arrayinfo = ITERARRAY_USE_COLOR | + ITERARRAY_USE_TEXTURE | ITERARRAY_GLOBAL_TEXTURE; + itarray->flags = ITERFLAG_Z_DIV_XYZ | ITERFLAG_Z_DIV_UVW | + ITERFLAG_Z_TO_DEPTH; + itarray->itertype = iter_texrgba | iter_specularadd; + itarray->raststate = rast_zcompare/*rast_zbuffer */| rast_texclamp | + rast_chromakeyoff; + itarray->rastmask = rast_nomask; + itarray->texmap = stargate->interior_texmap; + + // fill vertex array + itarray->Vtxs[ 0 ].X = stargate->interior_vtxlist[ 0 ].X; + itarray->Vtxs[ 0 ].Y = stargate->interior_vtxlist[ 0 ].Y; + itarray->Vtxs[ 0 ].Z = stargate->interior_vtxlist[ 0 ].Z; + itarray->Vtxs[ 0 ].W = GEOMV_1; + itarray->Vtxs[ 0 ].U = stargate->interior_u[ 0 ]; + itarray->Vtxs[ 0 ].V = stargate->interior_v[ 0 ]; + itarray->Vtxs[ 0 ].R = 255; + itarray->Vtxs[ 0 ].G = 255; + itarray->Vtxs[ 0 ].B = 255; + itarray->Vtxs[ 0 ].A = 255; + + int dst = 1; + for ( int seg = 0; seg < STARGATE_INTERIOR_VERTS_PER_RING; seg++ ) { + for( int ring = 0; ring < STARGATE_INTERIOR_NUM_RINGS; ring++ ) { + + itarray->Vtxs[ dst ].X = stargate->interior_vtxlist[ dst ].X; + itarray->Vtxs[ dst ].Y = stargate->interior_vtxlist[ dst ].Y; + itarray->Vtxs[ dst ].Z = stargate->interior_vtxlist[ dst ].Z; + itarray->Vtxs[ dst ].W = GEOMV_1; + itarray->Vtxs[ dst ].U = stargate->interior_u[ dst ]; + itarray->Vtxs[ dst ].V = stargate->interior_v[ dst ]; + itarray->Vtxs[ dst ].R = itarray->Vtxs[ 0 ].R; + itarray->Vtxs[ dst ].G = itarray->Vtxs[ 0 ].G; + itarray->Vtxs[ dst ].B = itarray->Vtxs[ 0 ].B; + itarray->Vtxs[ dst ].A = itarray->Vtxs[ 0 ].A - + ( ring + 1 ) * ( 255 / STARGATE_INTERIOR_NUM_RINGS ); + dst++; + } + } + + // setup transformation matrix + D_LoadIterMatrix( DestXmatrx ); + + // lock array + D_LockIterArray3( itarray, 0, itarray->NumVerts ); + +#ifdef USE_STRIPORDER_TRIANGLES + + // draw interior with strip order triangles + StargateDraw_InteriorStripOrderTris( itarray ); + +#else // USE_STRIPORDER_TRIANGLES + + // draw interior with indexed triangle strips + StargateDraw_InteriorIndexedStrips( itarray ); + +#endif // USE_STRIPORDER_TRIANGLES + + // unlock array + D_UnlockIterArray(); + + // restore identity transformation + D_LoadIterMatrix( NULL ); + + // free vertex array + FREEMEM( itarray ); +} + +#endif // USE_COMPILED_VTX_ARRAYS + + +// draw interior of stargate -------------------------------------------------- +// +PRIVATE +int StargateDraw_Interior( void *param ) +{ + ASSERT( param != NULL ); + Stargate *stargate = (Stargate *) param; + + // check whether the object is visible at all + if ( stargate->VisibleFrame != CurVisibleFrame ) + return TRUE; + + if ( stargate->interior_texmap == NULL ) + return FALSE; + + // draw the HUD text stating the stargate target solarsystem + if ( !ObjCameraActive ) { + StargateDraw_HUD( stargate ); + } + + // determine whether stargate is dormant or not + DetermineStargateDormantState( stargate ); + + // don't draw interior if stargate is dormant + // to be consistent with Stargate (movie and tv-series) + if ( stargate->dormant ) { + return TRUE; + } + + // calculate transformation matrix + MtxMtxMUL( ViewCamera, stargate->ObjPosition, DestXmatrx ); + +#ifdef USE_COMPILED_VTX_ARRAYS + + // draw interior using compiled vertex arrays + StargateDraw_InteriorCompiledArrays( stargate ); + +#else // USE_COMPILED_VTX_ARRAYS + + // draw interior using triangle strips + StargateDraw_InteriorTriStrips( stargate ); + +#endif // USE_COMPILED_VTX_ARRAYS + + return TRUE; +} + + +// callback type and flags ---------------------------------------------------- +// +static int callback_type = CBTYPE_DRAW_CUSTOM_ITER | CBFLAG_REMOVE; + + +// stargate animation callback ------------------------------------------------ +// +PRIVATE +int StargateAnimate( CustomObject *base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + + // simply rotate around Z + ObjRotZ( stargate->ObjPosition, stargate->rotspeed * CurScreenRefFrames ); + + // modulate the interior vertices (sinusoidal effect) + StargateAnimate_ModulateInteriorVertices( stargate ); + + // register the drawing callback for drawing the interior of the stargate + CALLBACK_RegisterCallback( callback_type, StargateDraw_Interior, (void *) base ); + + // and do the activation sequence, if activating + if ( stargate->activating ) { + StargateAnimate_StepActivationSequence( stargate ); + } + + return TRUE; +} + + +// stargate destructor (instance destruction) --------------------------------- +// +PRIVATE +void StargateDestroy( CustomObject *base ) +{ + ASSERT( base != NULL ); + Stargate *stargate = (Stargate *) base; + + // destroy attached vertex info + ASSERT( stargate->interior_vtxlist != NULL ); + FREEMEM( stargate->interior_vtxlist ); + stargate->interior_vtxlist = NULL; + stargate->interior_viewvtxs = NULL; + stargate->interior_u = NULL; + stargate->interior_v = NULL; + + // ensure pending callbacks are destroyed to avoid + // calling them with invalid pointers + int numremoved = CALLBACK_DestroyCallback( callback_type, (void *) base ); + ASSERT( numremoved <= 1 ); +} + + +// check whether a ship is in range of a stargate ----------------------------- +// +PRIVATE +int ShipInStargateRange( Stargate *stargate, ShipObject *ship, geomv_t range ) +{ + ASSERT( stargate != NULL ); + ASSERT( ship != NULL ); + + //NOTE: + // the ship is treated as a sphere for activation + // range detection. + + Vector3 gatenormal; + FetchZVector( stargate->ObjPosition, &gatenormal ); + + Vertex3 gatepos; + FetchTVector( stargate->ObjPosition, &gatepos ); + + Vertex3 shippos; + FetchTVector( ship->ObjPosition, &shippos ); + + geomv_t shipdot = -DOT_PRODUCT( &gatenormal, &shippos ); + geomv_t gatedot = -DOT_PRODUCT( &gatenormal, &gatepos ); + geomv_t distance = shipdot - gatedot; + + // bounding sphere touching in negative halfspace is still ok + distance += ship->BoundingSphere; + + // not in range if ship in wrong halfspace + if ( GEOMV_NEGATIVE( distance ) ) { + return FALSE; + } + + // in range if ship bounding sphere intersects gate range hemisphere + range += ship->BoundingSphere * 2; + return ( distance < range ); +} + + +// check whether a ship is in jump range of a stargate ------------------------ +// +PRIVATE +int ShipInStargateJumpRange( Stargate *stargate, ShipObject *ship, geomv_t range ) +{ + ASSERT( stargate != NULL ); + ASSERT( ship != NULL ); + + //NOTE: + // the ship is treated as a point for jump + // range detection. + + Vector3 gatenormal; + FetchZVector( stargate->ObjPosition, &gatenormal ); + + Vertex3 gatepos; + FetchTVector( stargate->ObjPosition, &gatepos ); + + Vertex3 shippos; + FetchTVector( ship->ObjPosition, &shippos ); + + geomv_t shipdot = -DOT_PRODUCT( &gatenormal, &shippos ); + geomv_t gatedot = -DOT_PRODUCT( &gatenormal, &gatepos ); + geomv_t distance = shipdot - gatedot; + + // not in range if ship in wrong halfspace ( already behind stargate ) + if ( GEOMV_NEGATIVE( distance ) ) { + return FALSE; + } + + // check whether inside of boundingsphere around stargate + Vector3 stargate_ship; + VECSUB( &stargate_ship, &shippos, &gatepos ); + + geomv_t stargate_ship_len = VctLenX( &stargate_ship ); + if ( stargate_ship_len > stargate->BoundingSphere ) { + return FALSE; + } + + // inside the activation distance/range ? + if ( distance < range ) { + + Vector3 shipnormal; + FetchZVector( ship->ObjPosition, &shipnormal ); + + // ship must be flying approximately head-on into the gate + //FIXME: cone_angle like for teleporter + geomv_t dirdot = DOT_PRODUCT( &gatenormal, &shipnormal ); + return ( dirdot > FLOAT_TO_GEOMV( 0.7f ) ); + } + + return FALSE; +} + + +// stargate collision callback ------------------------------------------------ +// +PRIVATE +int StargateCollide( CustomObject *base ) +{ + ASSERT( base != NULL ); + + Stargate *stargate = (Stargate *) base; + + // dormant stargate is simply graphics + if ( stargate->dormant ) { + return TRUE; + } + + int inrange = 0x00; + + // check local ship + if ( ShipInStargateRange( stargate, MyShip, stargate->actdistance ) ) { + inrange |= 0x01; + } + + // check all other ships + if ( inrange == 0x00 ) { + + ShipObject *walkships = FetchFirstShip(); + for ( ; walkships; walkships = (ShipObject *) walkships->NextObj ) { + + if ( ShipInStargateRange( stargate, walkships, stargate->actdistance ) ) { + inrange |= 0x02; + break; + } + } + } + + // only toggle active when autoactivation is set + if ( stargate->autoactivate ) { + + if ( inrange != 0x00 ) { + + if ( !stargate->active ) { + + // create the active stargate particles + StargateModify_CreateActiveParticles( stargate ); + + // activate stargate + stargate->active = TRUE; + } + + } else { + + // deactivate stargate + stargate->active = FALSE; + + // and clear the activating sequence to stop adding particles + stargate->activating = FALSE; + } + } + + if ( !stargate->active ) { + return TRUE; + } + + if ( inrange == 0x00 ) { + return TRUE; + } + +#ifdef LINKED_PROTOCOL_GAMESERVER + + // check for fly-through sequence if connected to game server + if ( !NET_ConnectedGMSV() ) { + return TRUE; + } + + // radius of hemisphere used for jump range detection + geomv_t jumpdistance = FLOAT_TO_GEOMV( stargate->BoundingSphere * 0.25f ); + + // check local ship for jump + if ( ( inrange == 0x01 ) && ShipInStargateJumpRange( stargate, MyShip, jumpdistance ) ) { + + // schedule server jump if not already done + if ( CurJumpServerNode == NULL ) { + + CurJumpServerNode = (node_t *) ALLOCMEM( sizeof( node_t ) ); + if ( CurJumpServerNode == NULL ) + OUTOFMEM( 0 ); + memcpy( CurJumpServerNode, &stargate->destination_node, sizeof( node_t ) ); + + //TODO: + // initiate animation and sfx + ShowMessage( "prepare to jump!!!" ); + } + + } else { + + // check all other ships + ShipObject *walkships = FetchFirstShip(); + for ( ; walkships; walkships = (ShipObject *) walkships->NextObj ) { + + if ( ShipInStargateJumpRange( stargate, walkships, jumpdistance ) ) { + + //FIXME: constants + stargate->modulfade = 120.0f; + break; + } + } + } + +#endif // LINKED_PROTOCOL_GAMESERVER + + return TRUE; +} + +// handle persistency --------------------------------------------------------- +// +int StargatePersistFromStream( CustomObject* base, int tostream, void* rl ) +{ + ASSERT( base != NULL ); + ASSERT( tostream == FALSE ); + Stargate* stargate = (Stargate*) base; + + // read from RE + if ( rl != NULL ) { + + RE_Stargate* re_stg = (RE_Stargate*)rl; + ASSERT( re_stg != NULL ); + + int active_changed = ( stargate->active != re_stg->active ); + int autoactivate_changed= ( stargate->autoactivate != re_stg->autoactivate ); + + stargate->serverid = re_stg->serverid; + + stargate->dormant = re_stg->dormant; + stargate->active = re_stg->active; + stargate->rotspeed = re_stg->rotspeed; + stargate->radius = re_stg->radius; + + stargate->actdistance = re_stg->actdistance; + stargate->numpartactive = re_stg->numpartactive; + stargate->actcyllen = re_stg->actcyllen; + stargate->partvel = re_stg->partvel; + stargate->modulspeed = re_stg->modulspeed; + stargate->modulrad1 = re_stg->modulrad1; + stargate->modulrad2 = re_stg->modulrad2; + + strncpy( stargate->flare_name, re_stg->flare_name, MAX_TEXNAME ); + stargate->flare_name[ MAX_TEXNAME ] = 0; + + strncpy( stargate->interior_name, re_stg->interior_name, MAX_TEXNAME ); + stargate->interior_name[ MAX_TEXNAME ] = 0; + + stargate->acttime = re_stg->acttime; + stargate->autoactivate = re_stg->autoactivate; + + if ( active_changed ) { + StargateModify_ActiveChanged( stargate ); + } + + if ( autoactivate_changed ) { + StargateModify_AutoactivateChanged( stargate ); + } + } + + return TRUE; +} + + + +// register object type for stargate ------------------------------------------ +// +PRIVATE +void StargateRegisterCustomType() +{ + custom_type_info_s info; + memset( &info, 0, sizeof( info ) ); + + info.type_name = "stargate"; + info.type_id = 0x00000000; + info.type_size = sizeof( Stargate ); + info.type_template = NULL; + info.type_flags = CUSTOM_TYPE_DEFAULT; + info.callback_init = StargateInitType; + info.callback_instant = StargateInstantiate; + info.callback_destroy = StargateDestroy; + info.callback_animate = StargateAnimate; + info.callback_collide = StargateCollide; + info.callback_notify = NULL; + info.callback_persist = StargatePersistFromStream; + + OBJ_RegisterCustomType( &info ); + CON_RegisterCustomType( info.type_id, Stargate_PropList ); +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( G_STGATE ) +{ + // register type + StargateRegisterCustomType(); +} + + + -- cgit v1.2.3