diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
| commit | c068f22329d5cc722622a2183bbb22eef2093df7 (patch) | |
| tree | 12d56c1aede67988a55e241364606bfbb4dba933 /src/parsec/m_viewer.cpp | |
| download | openparsec-main.tar.xz openparsec-main.zip | |
Diffstat (limited to 'src/parsec/m_viewer.cpp')
| -rw-r--r-- | src/parsec/m_viewer.cpp | 1220 |
1 files changed, 1220 insertions, 0 deletions
diff --git a/src/parsec/m_viewer.cpp b/src/parsec/m_viewer.cpp new file mode 100644 index 0000000..30cb441 --- /dev/null +++ b/src/parsec/m_viewer.cpp @@ -0,0 +1,1220 @@ +/* + * PARSEC - Spacecraft/Objects Viewer + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:38 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-2000 + * Copyright (c) Andreas Varga <sid@parsec.org> 1999-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" + +// subsystem headers +#include "sys_defs.h" + +// drawing subsystem +#include "d_font.h" + +// rendering subsystem +#include "r_obj.h" + +// mathematics header +#include "utl_math.h" + +// local module header +#include "m_viewer.h" + +// proprietary module headers +#include "con_arg.h" +#include "con_aux.h" +#include "con_com.h" +#include "con_main.h" +#include "e_color.h" +#include "e_draw.h" +#include "e_mouse.h" +#include "e_supp.h" +#include "m_main.h" +#include "obj_clas.h" +#include "obj_creg.h" +#include "obj_ctrl.h" + + + +// string constants ----------------------------------------------------------- +// +static char no_ship_class[] = "object class is no ship."; +static char no_registered_class[] = "object class is not registered as ship."; +static char text_too_large[] = "max text size exceeded."; +static char clear_arg_invalid[] = "clear argument invalid."; + + +// generic string paste area -------------------------------------------------- +// +#define PASTE_STR_LEN 2047 +static char paste_str[ PASTE_STR_LEN + 1 ]; + + +// spacecraft viewer areas for mouse-over detection --------------------------- +// +#define SCV_NUM_MOUSE_AREAS 5 + +static mouse_area_s scv_mouse_areas[ SCV_NUM_MOUSE_AREAS ] = { + + { 248, 202, 29, 37 }, // button left + { 248, 240, 29, 37 }, // button right + { 248, 40, 29, 89 }, // button up + { 248, 359, 29, 89 }, // button down + { 282, 0, 640, 480 }, // ship area +}; + +static mouse_area_scaled_s scv_mouse_areas_scaled[ SCV_NUM_MOUSE_AREAS ]; + + +// detect whether mouse position is over spacecraft viewer item --------------- +// +int MouseOverViewerItem( int mousex, int mousey ) +{ + // make sure area coordinates match resolution + static resinfo_s scv_last_screen_res; + if (scv_last_screen_res != GameScreenRes) { + MouseCalcScaledAreas( scv_mouse_areas, scv_mouse_areas_scaled, SCV_NUM_MOUSE_AREAS ); + scv_last_screen_res = GameScreenRes; + } + + // check against clickable areas in spacecraft viewer + if ( MouseOverArea( &scv_mouse_areas_scaled[ 0 ], mousex, mousey ) ) { + return MOUSE_OVER_LEFTARROW; + } + if ( MouseOverArea( &scv_mouse_areas_scaled[ 1 ], mousex, mousey ) ) { + return MOUSE_OVER_RIGHTARROW; + } + if ( MouseOverArea( &scv_mouse_areas_scaled[ 2 ], mousex, mousey ) ) { + return MOUSE_OVER_UPARROW; + } + if ( MouseOverArea( &scv_mouse_areas_scaled[ 3 ], mousex, mousey ) ) { + return MOUSE_OVER_DOWNARROW; + } + if ( MouseOverArea( &scv_mouse_areas_scaled[ 4 ], mousex, mousey ) ) { + return MOUSE_OVER_SHIP; + } + + return MOUSE_OVER_NOTHING; +} + + +// spacecraft viewer background texture info ---------------------------------- +// +struct scv_background_info_s { + + float xpos; + float ypos; + float width; + float height; + int owidth; + int oheight; + + TextureMap* texmap; + const char* texname; +}; + +static scv_background_info_s scv_background_info[] = { + + { 0.0, 0.0, 0.4, 0.533, 256, 256, NULL, "scv00" }, + { 0.4, 0.0, 0.4, 0.533, 256, 256, NULL, "scv01" }, + { 0.8, 0, 0.2, 0.533, 128, 256, NULL, "scv02" }, + { 0.0, 0.533, 0.4, 0.533, 256, 224, NULL, "scv10" }, + { 0.4, 0.533, 0.4, 0.533, 256, 224, NULL, "scv11" }, + { 0.8, 0.533, 0.2, 0.533, 128, 224, NULL, "scv12" }, + + { 0, 0, 0, 0, 0, 0, NULL, NULL } +}; + +static int scv_background_valid = FALSE; + + +// try to acquire textures for logo animation --------------------------------- +// +PRIVATE +int AcquireScvTextures() +{ + if ( scv_background_valid ) + return TRUE; + + scv_background_valid = TRUE; + + for ( int tid = 0; scv_background_info[ tid ].texname; tid++ ) { + + TextureMap *texmap = FetchTextureMap( scv_background_info[ tid ].texname ); + scv_background_info[ tid ].texmap = texmap; + + if ( texmap == NULL ) { + scv_background_valid = FALSE; + } + } + + return scv_background_valid; +} + + +// spacecraft viewer configuration and state variables ------------------------ +// +static Camera SpacecraftCamera; + +#define SCV_SHIP_RIGHT 0 +#define SCV_SHIP_LEFT ( m_sintab_size - 1 ) +#define SCV_SHIP_SCALE 1.0f //2.0f +#define SCV_SHIP_CENTER_X 40.0f +#define SCV_SHIP_CENTER_Y 5.0f +#define SCV_SHIP_CENTER_Z 15.0f +#define SCV_SHIP_SLIDE_SPEED 12 + +#define SCV_TEXT_X 0.06 // 38 +#define SCV_TEXT_Y 0.17 // 82 +#define SCV_TEXT_W 0.28 // 182 +#define SCV_TEXT_H 0.66 // 318 + +#define SCV_CAM_PITCH ( (bams_t) 0x0d00 ) +#define SCV_CAM_YAW ( (bams_t) -0x0d00 ) +#define SCV_CAM_ROLL ( (bams_t) 0x0000 ) +#define SCV_CAM_DIST FIXED_TO_GEOMV( 0x600000 ) + +#define SCV_OBJROTSPEED ((bams_t) 0x00a0/10) + +#define SCV_BG_ALPHA_LOW 0 +#define SCV_BG_ALPHA_HIGH 255 +#define SCV_BG_FADE_SPEED 12 +#define SCV_BG_FADE_QUANTUM 10 + + +//#define USE_SCV_SHIP_SCALE // undef if SCV_SHIP_SCALE == 1.0f + +#ifdef USE_SCV_SHIP_SCALE +static Xmatrx scv_ship_scale_matrx = { + + { FLOAT_TO_GEOMV( SCV_SHIP_SCALE ), GEOMV_0, GEOMV_0, GEOMV_0 }, + { GEOMV_0, FLOAT_TO_GEOMV( SCV_SHIP_SCALE ), GEOMV_0, GEOMV_0 }, + { GEOMV_0, GEOMV_0, FLOAT_TO_GEOMV( SCV_SHIP_SCALE ), GEOMV_0 } +}; +#endif + +//NOTE: +// scv_ship_pos_matrx[ 0 ][ 3 ] will be modified (reset) +// by DrawSpacecraft() to reflect the correctly slided +// x position of the ship. + +static Xmatrx scv_ship_pos_matrx = { + + { FLOAT_TO_GEOMV( 1.0f ), FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( SCV_SHIP_CENTER_X ) }, + { FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( 1.0f ), FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( SCV_SHIP_CENTER_Y ) }, + { FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( 0.0f ), FLOAT_TO_GEOMV( 1.0f ), FLOAT_TO_GEOMV( SCV_SHIP_CENTER_Z ) } +}; + +#define MAX_TEXT_LEN 1024 + +enum { + + CAPTION_LINE, + TEXT_LINE, + + NUM_SHIP_LINES +}; + +static int scv_ship_slidepos = SCV_SHIP_RIGHT; +static int scv_ship_slidetarget = 0; +static refframe_t scv_ship_lastref = REFFRAME_INVALID; + +static int scv_bg_fadepos = SCV_BG_ALPHA_LOW; +static int scv_bg_fadetarget = SCV_BG_ALPHA_LOW; +static refframe_t scv_bg_lastref = REFFRAME_INVALID; + +static int scv_ship_textcnt[ MAX_SHIP_CLASSES ]; +static char* scv_ship_text[ MAX_SHIP_CLASSES ][ NUM_SHIP_LINES ]; + +int cur_scv_mode = SCVMODE_SPACECRAFT; +int cur_scv_ship = 0; + + +// object viewer ring specifics ----------------------------------------------- +// +#define RING_ARC ( 0x10000 / NUM_SCV_OBJECTS ) +#define RING_RADIUS 70.0f + +#define RING_POS_RIGHT 0 +#define RING_POS_LEFT ( m_sintab_size - 1 ) + +#define RING_SLIDE_SPEED 12 + +int scv_ring_objects[ NUM_SCV_OBJECTS ] = { + + EXTRAINDX_AFTERBURNER_DEVICE, // 0 + EXTRAINDX_DUMB_PACK, // 1 + EXTRAINDX_GUIDE_PACK, // 2 + EXTRAINDX_LASERUPGRADE1, // 3 + EXTRAINDX_LASERUPGRADE2, // 4 + EXTRAINDX_HELIX_DEVICE, // 5 + EXTRAINDX_LIGHTNING_DEVICE, // 6 + EXTRAINDX_PHOTON_DEVICE, // 7 + EXTRAINDX_MINE_PACK, // 8 + EXTRAINDX_REPAIR_EXTRA, // 9 + EXTRAINDX_INVULNERABILITY, // 10 + EXTRAINDX_ENERGY_EXTRA, // 11 + EXTRAINDX_SWARM_PACK, // 12 + EXTRAINDX_EMPUPGRADE1, // 13 + EXTRAINDX_EMPUPGRADE2, // 14 +}; + +int scv_drawing_order[ NUM_SCV_OBJECTS ] = { 1, 2, 3, 4, 5, 6, 7, 8, 13, 14, 9, 11, 0, 10, 12 }; + +static bams_t scv_ring_spin_ofs = 0x0000; +static bams_t scv_ring_correction_ofs = 0xdd00; +static int scv_ring_slidepos = RING_POS_RIGHT; +static int scv_ring_slidetarget = 0; +static refframe_t scv_ring_lastref = REFFRAME_INVALID; + +int scv_ring_spinning = 0; +int scv_object_selindx = 0; + +#define NUM_OBJECT_LINES 2 + +static const char *object_text[ NUM_SCV_OBJECTS ][ NUM_OBJECT_LINES ] = { + + { "energy boost", + "collecting this will increase your energy" + }, + + { "damage repair", + "this will repair any damages of your ship" + }, + + { "emp upgrade 1", + "increases the efficiency of your EMP device" + }, + + { "emp upgrade 2", + "gives you ultimate EMP power" + }, + + { "proximity mine pack", + "collect these to get some proximity mines" + }, + + { "photon cannon", + "collect this device to equip your ship with a photon cannon" + }, + + { "lightning device", + "adds a lightning cannon to your ship" + }, + + { "helix cannon", + "collect this to get the helix shot" + }, + + { "laser upgrade 2", + "the ultimate laser upgrade" + }, + + { "laser upgrade 1", + "improves strength and speed of your laser" + }, + + { "guided missile pack", + "this will give you some guided missiles" + }, + + { "dumb missile pack", + "increases your number of dumb missiles" + }, + + { "swarm missile pack", + "contains very dangerous swarm missiles" + }, + + { "invulnerability shield", + "this power-up makes your ship invulnerable" + }, + + { "afterburner", + "gives your ship a speed boost if activated" + }, + +}; + + +// fade the background alpha to a specified target ---------------------------- +// +PRIVATE +void DoViewerFading() +{ + if ( scv_bg_fadepos == scv_bg_fadetarget ) { + scv_bg_lastref = REFFRAME_INVALID; + return; + } + + if ( scv_bg_fadepos < scv_bg_fadetarget ) { + + // fade in + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_bg_lastref == REFFRAME_INVALID ) { + scv_bg_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_bg_lastref; + for ( ; delta >= SCV_BG_FADE_SPEED; delta -= SCV_BG_FADE_SPEED ) { + scv_bg_fadepos += SCV_BG_FADE_QUANTUM; + if ( scv_bg_fadepos >= scv_bg_fadetarget ) { + scv_bg_fadepos = scv_bg_fadetarget; + scv_bg_lastref = REFFRAME_INVALID; + break; + } + scv_bg_lastref += SCV_BG_FADE_SPEED; + } + } + + } else { + + // fade out + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_bg_lastref == REFFRAME_INVALID ) { + scv_bg_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_bg_lastref; + for ( ; delta >= SCV_BG_FADE_SPEED; delta -= SCV_BG_FADE_SPEED ) { + scv_bg_fadepos -= SCV_BG_FADE_QUANTUM; + if ( scv_bg_fadepos <= scv_bg_fadetarget ) { + scv_bg_fadepos = scv_bg_fadetarget; + scv_bg_lastref = REFFRAME_INVALID; + break; + } + scv_bg_lastref += SCV_BG_FADE_SPEED; + } + } + } +} + + +// draw spacecraft viewer background ------------------------------------------ +// +PRIVATE +void DrawViewerBackground() +{ + DoViewerFading(); + + // check whether actual drawing disabled + if ( AUX_DISABLE_FLOATING_MENU_DRAWING ) + return; + +#if ( SCV_BG_ALPHA_LOW == 0 ) + + // skip drawing code if background viewer is completely faded out + if ( scv_bg_fadepos == SCV_BG_ALPHA_LOW ) + return; + +#endif + + texscreenrect_s rect; + + dword itertype = iter_texrgba | iter_premulblend; + rect.alpha = scv_bg_fadepos; + + for ( int tid = 0; tid < 6; tid++ ) { + + switch ( tid ) { + + case 0: + rect.x = 0; + rect.y = 0; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(scv_background_info[ tid ].width * Screen_Width); + rect.scaled_h = (int)(scv_background_info[ tid ].height * Screen_Height); + break; + + case 1: + rect.x += rect.scaled_w; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(scv_background_info[ tid ].width * Screen_Width); + break; + + case 2: + rect.x += rect.scaled_w; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(Screen_Width - rect.scaled_w * 2); + break; + + case 3: + rect.x = 0; + rect.y += rect.scaled_h; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(scv_background_info[ tid ].width * Screen_Width); + rect.scaled_h = (int)(Screen_Height - rect.scaled_h); + break; + + case 4: + rect.x += rect.scaled_w; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(scv_background_info[ tid ].width * Screen_Width); + break; + + case 5: + rect.x += rect.scaled_w; + rect.w = scv_background_info[ tid ].owidth; + rect.h = scv_background_info[ tid ].oheight; + rect.scaled_w = (int)(Screen_Width - rect.scaled_w * 2); + break; + } + + rect.texofsx = 0; + rect.texofsy = 0; + rect.itertype = itertype; + rect.texmap = scv_background_info[ tid ].texmap; + + DRAW_TexturedScreenRect( &rect, NULL ); + } +} + + +// set fade target for background to high (in) -------------------------------- +// +void FadeInBackground() +{ + scv_bg_fadetarget = SCV_BG_ALPHA_HIGH; +} + + +// set fade target for background to low (out) -------------------------------- +// +void FadeOutBackground() +{ + scv_bg_fadetarget = SCV_BG_ALPHA_LOW; +} + + +// check if background is at its desired fade position ------------------------ +// +int FadeFinishedBackground() +{ + return ( scv_bg_fadepos == scv_bg_fadetarget ); +} + + +// slide the ship to its specifed target x position --------------------------- +// +PRIVATE +void DoSpacecraftSliding() +{ + if ( scv_ship_slidepos == scv_ship_slidetarget ) { + scv_ship_lastref = REFFRAME_INVALID; + return; + } + + if ( scv_ship_slidepos < scv_ship_slidetarget ) { + + // slide right + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_ship_lastref == REFFRAME_INVALID ) { + scv_ship_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_ship_lastref; + for ( ; delta >= SCV_SHIP_SLIDE_SPEED; delta -= SCV_SHIP_SLIDE_SPEED ) { + scv_ship_slidepos++; + if ( scv_ship_slidepos >= scv_ship_slidetarget ) { + scv_ship_slidepos = scv_ship_slidetarget; + scv_ship_lastref = REFFRAME_INVALID; + break; + } + scv_ship_lastref += SCV_SHIP_SLIDE_SPEED; + } + } + + } else { + + // slide left + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_ship_lastref == REFFRAME_INVALID ) { + scv_ship_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_ship_lastref; + for ( ; delta >= SCV_SHIP_SLIDE_SPEED; delta -= SCV_SHIP_SLIDE_SPEED ) { + scv_ship_slidepos--; + if ( scv_ship_slidepos <= scv_ship_slidetarget ) { + scv_ship_slidepos = scv_ship_slidetarget; + scv_ship_lastref = REFFRAME_INVALID; + break; + } + scv_ship_lastref += SCV_SHIP_SLIDE_SPEED; + } + } + } +} + + +// draw currently selected ship in spacecraft viewer -------------------------- +// +PRIVATE +void DrawSpacecraft() +{ + DoSpacecraftSliding(); + + // check whether actual drawing disabled + if ( AUX_DISABLE_FLOATING_MENU_DRAWING ) + return; + + float shippos = SCV_SHIP_CENTER_X; + if ( scv_ship_slidepos != -1 ) + shippos += m_sintab[ scv_ship_slidepos ]; + scv_ship_pos_matrx[ 0 ][ 3 ] = FLOAT_TO_GEOMV( shippos ); + + ASSERT( cur_scv_ship < NumShipClasses ); + GenObject *shippo = ObjClasses[ ShipClasses[ cur_scv_ship ] ]; + + bams_t objview_roty = SCV_OBJROTSPEED * CurScreenRefFrames; + ObjRotY( scv_ship_pos_matrx, -objview_roty ); + + // reorthogonalize position matrix + if ( !AUX_DISABLE_REORTHO_IN_VIEWERS ) { + ReOrthoNormMtx( scv_ship_pos_matrx ); + } + + pXmatrx curmatrx = scv_ship_pos_matrx; + +#ifdef USE_SCV_SHIP_SCALE + + // pre-scale + MtxMtxMUL( scv_ship_pos_matrx, scv_ship_scale_matrx, DestXmatrx ); + curmatrx = DestXmatrx; + + //FIXME: + //NOTE: + // ( SCV_SHIP_SCALE != 1.0f ) is currently only a hack + // for screenshots. the problem ist that the matrix is + // not orthogonal afterwards and backface-culling (as + // well as bsp-traversal if used) depends on this + // orthogonality. + +#endif + + // copy matrix into all ships (ensures that all + // ships have the same orientation after switching) + for ( int sid = 0; sid < NumShipClasses; sid++ ) { + memcpy( ObjClasses[ ShipClasses[ sid ] ]->ObjPosition, curmatrx, sizeof( Xmatrx ) ); + } + + // open direct object rendering + R_DirectObjectRendering( 0x01 ); + + // render object + OBJ_AutoSelectObjectLod( shippo ); + R_ReCalcAndRenderObject( shippo, SpacecraftCamera ); + + // close direct object rendering + R_DirectObjectRendering( 0x00 ); +} + + +// set slide target for ship to left (in) ------------------------------------- +// +void SlideInShip() +{ + scv_ship_slidetarget = SCV_SHIP_LEFT; +} + + +// set slide target for ship to right (out) ----------------------------------- +// +void SlideOutShip() +{ + scv_ship_slidetarget = SCV_SHIP_RIGHT; +} + + +// check if ship is at its desirect slide position ---------------------------- +// +int SlideFinishedShip() +{ + return ( scv_ship_slidepos == scv_ship_slidetarget ); +} + + +// ---------------------------------------------------------------------------- +// +PRIVATE +void MaintainObjectRingSpinning() +{ + + extern int rotkey_active_left; + extern int rotkey_active_right; + + if ( scv_ring_spinning == 1 ) { + + scv_ring_spin_ofs += ( 25 * CurScreenRefFrames ); + if ( scv_ring_spin_ofs >= RING_ARC ) { + if ( !rotkey_active_left ) + scv_ring_spinning = 0; + scv_ring_spin_ofs = 0x0000; + if ( ++scv_object_selindx >= NUM_SCV_OBJECTS ) { + scv_object_selindx = 0; + } + } + + } else if ( scv_ring_spinning == -1 ) { + + scv_ring_spin_ofs -= ( 25 * CurScreenRefFrames ); + if ( scv_ring_spin_ofs <= -RING_ARC ) { + if ( !rotkey_active_right ) + scv_ring_spinning = 0; + scv_ring_spin_ofs = 0x0000; + if ( --scv_object_selindx < 0 ) { + scv_object_selindx = NUM_SCV_OBJECTS - 1; + } + } + } +} + + +// slide the ring to its specifed target x position --------------------------- +// +PRIVATE +void DoObjectsRingSliding() +{ + if ( scv_ring_slidepos == scv_ring_slidetarget ) { + scv_ring_lastref = REFFRAME_INVALID; + return; + } + + if ( scv_ring_slidepos < scv_ring_slidetarget ) { + + // slide right + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_ring_lastref == REFFRAME_INVALID ) { + scv_ring_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_ring_lastref; + for ( ; delta >= RING_SLIDE_SPEED; delta -= RING_SLIDE_SPEED ) { + scv_ring_slidepos++; + if ( scv_ring_slidepos >= scv_ring_slidetarget ) { + scv_ring_slidepos = scv_ring_slidetarget; + scv_ring_lastref = REFFRAME_INVALID; + break; + } + scv_ring_lastref += RING_SLIDE_SPEED; + } + } + + } else { + + // slide left + refframe_t refframecount = SYSs_GetRefFrameCount(); + if ( scv_ring_lastref == REFFRAME_INVALID ) { + scv_ring_lastref = refframecount; + } else { + refframe_t delta = refframecount - scv_ring_lastref; + for ( ; delta >= RING_SLIDE_SPEED; delta -= RING_SLIDE_SPEED ) { + scv_ring_slidepos--; + if ( scv_ring_slidepos <= scv_ring_slidetarget ) { + scv_ring_slidepos = scv_ring_slidetarget; + scv_ring_lastref = REFFRAME_INVALID; + break; + } + scv_ring_lastref += RING_SLIDE_SPEED; + } + } + } +} + + +// draw currently selected ship in spacecraft viewer -------------------------- +// +void DrawObjectsRing() +{ + // spin object ring + if ( scv_ring_spinning != 0 ) { + MaintainObjectRingSpinning(); + } + + DoObjectsRingSliding(); + + // check whether actual drawing disabled + if ( AUX_DISABLE_FLOATING_MENU_DRAWING ) + return; + + // open direct object rendering + R_DirectObjectRendering( 0x01 ); + + for ( int oid = 0; oid < NUM_SCV_OBJECTS; oid++ ) { + + // fetch current object class id in correct drawing order + int extraindex = scv_ring_objects[ scv_drawing_order[ ( oid ) % NUM_SCV_OBJECTS ] ]; + + dword classid = ExtraClasses[ extraindex ]; + + if ( classid == CLASS_ID_INVALID ) { + continue; + } + + GenObject *objpo = ObjClasses[ classid ]; + + // translate object to its position on the ring + bams_t angle = ( RING_ARC * ( oid + scv_object_selindx ) ) + + scv_ring_spin_ofs + scv_ring_correction_ofs; + sincosval_s sincosv; + GetSinCos( angle, &sincosv ); + float sinus = GEOMV_TO_FLOAT( sincosv.sinval ); + float cosinus = GEOMV_TO_FLOAT( sincosv.cosval ); + + float objposx = SCV_SHIP_CENTER_X + ( sinus * RING_RADIUS ) - 5.0f; + if ( scv_ring_slidepos != -1 ) + objposx += m_sintab[ scv_ring_slidepos ]; + + objpo->ObjPosition[ 0 ][ 3 ] = FLOAT_TO_GEOMV( objposx ); + objpo->ObjPosition[ 1 ][ 3 ] = FLOAT_TO_GEOMV( SCV_SHIP_CENTER_Z - 27.0 ); + objpo->ObjPosition[ 2 ][ 3 ] = FLOAT_TO_GEOMV( SCV_SHIP_CENTER_Y + ( cosinus * RING_RADIUS ) ); + + // rotate object + bams_t objview_rot = SCV_OBJROTSPEED * CurScreenRefFrames; + ObjRotX( objpo->ObjPosition, objview_rot ); + ObjRotY( objpo->ObjPosition, objview_rot ); + ObjRotZ( objpo->ObjPosition, objview_rot ); + + // reorthogonalize position matrix + if ( !AUX_DISABLE_REORTHO_IN_VIEWERS ) { + ReOrthoNormMtx( objpo->ObjPosition ); + } + + // render object + OBJ_AutoSelectObjectLod( objpo ); + R_ReCalcAndRenderObject( objpo, SpacecraftCamera ); + } + + // close direct object rendering + R_DirectObjectRendering( 0x00 ); +} + + +// set slide target for objects ring to left (in) ----------------------------- +// +void SlideInRing() +{ + scv_ring_slidetarget = RING_POS_LEFT; +} + + +// set slide target for objects ring to right (out) --------------------------- +// +void SlideOutRing() +{ + scv_ring_slidetarget = RING_POS_RIGHT; +} + + +// check if object ring is at its desired slide position ---------------------- +// +int SlideFinishedRing() +{ + return ( scv_ring_slidepos == scv_ring_slidetarget ); +} + + +// type for writestring function pointer -------------------------------------- +// +typedef void (*WSFP)( ... ); + +//NOTE: +// this declaration is in global scope because of the extern "C". +// only gcc needs the otherwise redundant curly braces. + + +// draw description text in spacecraft and object viewer ---------------------- +// +void DrawViewerTexts() +{ + // check whether actual drawing disabled + if ( AUX_DISABLE_FLOATING_MENU_DRAWING ) + return; + +#if ( SCV_BG_ALPHA_LOW == 0 ) + + // skip drawing code if background viewer is completely faded out + if ( scv_bg_fadepos == SCV_BG_ALPHA_LOW ) + return; + +#endif + + int old_alpha = PanelTextColor.A; + PanelTextColor.A = (int)(scv_bg_fadepos * ( (float) old_alpha / (float) SCV_BG_ALPHA_HIGH )); + + extern int hud_line_dist; + + int chwidth = CharsetInfo[ HUD_CHARSETNO ].width; + int chheight = hud_line_dist; + + // determine whether translucency should be used + int translucent = VID_TRANSLUCENCY_SUPPORTED; + + D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer, + CharsetInfo[ HUD_CHARSETNO ].geompointer, + NULL, + CharsetInfo[ HUD_CHARSETNO ].width, + CharsetInfo[ HUD_CHARSETNO ].height ); + + // write text transparent only for color depths below 32 bit per pixel + WSFP wstrfp = ( translucent ) ? + (WSFP) &D_WriteTrString : + (WSFP) &D_WriteString; + + unsigned int text_x = (unsigned int)(SCV_TEXT_X * Screen_Width); + unsigned int text_y = (unsigned int)(SCV_TEXT_Y * Screen_Height); + unsigned int text_w = (unsigned int)(SCV_TEXT_W * Screen_Width); + unsigned int max_text_y = (unsigned int)(( SCV_TEXT_Y + SCV_TEXT_H ) * Screen_Height); + + char **text; + int ship_id = 0; + char *text_ptr = paste_str; + + // select text source + switch ( cur_scv_mode ) { + + case SCVMODE_SPACECRAFT: + text = scv_ship_text[ cur_scv_ship ]; + break; + + case SCVMODE_OBJECTSRING: + text = (char **) object_text[ scv_object_selindx ]; + break; + + default: + ASSERT( 0 ); + // avoid crash + return; + } + + // draw caption (always centered) + if ( text[ CAPTION_LINE ] != NULL ) { + + strcpy( paste_str, text[ CAPTION_LINE ] ); + + unsigned int len = strlen( paste_str ) * chwidth; + unsigned int cnt = 0; + int last_space = 0; + + if ( len > text_w ) { + + // draw wrapped text (multiple lines) + while ( cnt <= strlen( text_ptr ) ) { + if ( text_ptr[ cnt ] == 0x20 || text_ptr[ cnt ] == 0x00 || text_ptr[ cnt ] == '.' ) { + if ( ( cnt * chwidth ) < text_w ) { + last_space = cnt; + cnt++; + } else { + text_ptr[ last_space ] = 0x00; + int len2 = strlen( text_ptr ) * chwidth; + int xofs = ( text_w - len2 ) / 2; + + wstrfp( text_ptr, text_x + xofs, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + text_ptr = &text_ptr[ last_space + 1 ]; + cnt = 0; + } + } + else + cnt++; + } + + // draw rest of string + int len2 = strlen( text_ptr ) * chwidth; + int xofs = ( text_w - len2 ) / 2; + wstrfp( text_ptr, text_x + xofs, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + + + } else { + + // draw single line + int xofs = ( text_w - len ) / 2; + + wstrfp( text[ CAPTION_LINE ], text_x + xofs, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + } + } + + // create empty line between caption and normal text + text_y += chheight; + + // draw normal text (not centered) + if ( text[ TEXT_LINE ] != NULL ) { + + strcpy( paste_str, text[ TEXT_LINE ] ); + + unsigned int len = strlen( paste_str ) * chwidth; + unsigned int cnt = 0; + int last_space = 0; + text_ptr = paste_str; + + if ( len > text_w ) { + + // draw wrapped text (multiple lines) + while ( cnt <= strlen( text_ptr ) && text_y <= max_text_y ) { + if ( text_ptr[ cnt ] == 0x20 || text_ptr[ cnt ] == 0x00 ) { + if ( ( cnt * chwidth ) < text_w ) { + last_space = cnt; + cnt++; + } else { + text_ptr[ last_space ] = 0x00; + + wstrfp( text_ptr, text_x, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + text_ptr = &text_ptr[ last_space + 1 ]; + cnt = 0; + } + } + else + cnt++; + } + if ( text_y <= max_text_y ) { + // draw rest of string + wstrfp( text_ptr, text_x, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + } + + } else { + + // draw single line + wstrfp( text[ TEXT_LINE ], text_x, text_y, TRTAB_PANELTEXT ); + text_y += chheight; + } + } + + PanelTextColor.A = old_alpha; +} + + +// draw spacecraft viewer ----------------------------------------------------- +// +void DrawSpacecraftViewer() +{ + // make sure textures are available + if ( !AcquireScvTextures() ) + return; + + // draw content + switch ( cur_scv_mode ) { + + case SCVMODE_SPACECRAFT: + DrawSpacecraft(); + break; + + case SCVMODE_OBJECTSRING: + DrawObjectsRing(); + break; + + default: + ASSERT( 0 ); + break; + } + + // draw frame + DrawViewerBackground(); + + // draw description texts + DrawViewerTexts(); +} + + +// key table for shipdesc command -------------------------------------------- +// +key_value_s shipdesc_key_value[] = { + + { "class", NULL, KEYVALFLAG_PARENTHESIZE }, + { "id", NULL, KEYVALFLAG_NONE }, + { "text", NULL, KEYVALFLAG_PARENTHESIZE }, + { "caption", NULL, KEYVALFLAG_PARENTHESIZE }, + { "clear", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_SHIPDESC_CLASS, + KEY_SHIPDESC_ID, + KEY_SHIPDESC_TEXT, + KEY_SHIPDESC_CAPTION, + KEY_SHIPDESC_CLEAR +}; + + +// console command for defining ship description texts ("shipdesc") ----------- +// +PRIVATE +int Cmd_SHIPDESC( char *classstr ) +{ + //NOTE: + //CONCOM: + // shipdesc_command ::= 'shipdesc' <class_spec> [<text_spec>] + // [<caption_spec>] [<clear_spec>] + // class_spec ::= 'class' <classname> | 'id' <classid> + // text_spec ::= 'text' <textline> + // caption_spec ::= 'caption' <captiontext> + // clear_spec ::= 'clear' ['caption'|'text'] + + ASSERT( classstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( classstr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( shipdesc_key_value, classstr ) ) + return TRUE; + + // get object class (either name or id) + dword objclass = ScanKeyValueObjClass( shipdesc_key_value, KEY_SHIPDESC_CLASS, KEY_SHIPDESC_ID ); + if ( objclass == CLASS_ID_INVALID ) { + return TRUE; + } + + if ( !OBJECT_TYPE_SHIP( ObjClasses[ objclass ] ) ) { + CON_AddLine( no_ship_class ); + return TRUE; + } + + // reverse look-up ship id + int shipindex = ObjClassShipIndex[ objclass ]; + if ( shipindex == SHIPINDEX_NO_SHIP ) { + CON_AddLine( no_registered_class ); + return TRUE; + } + ASSERT( (dword)shipindex < (dword)NumShipClasses ); + + char **text = scv_ship_text[ shipindex ]; + + //NOTE: + // the clear key is checked before all others in order to + // make adding new text after clearing the old one possible. + + // check for clearing + char *cleararg = shipdesc_key_value[ KEY_SHIPDESC_CLEAR ].value; + if ( cleararg != NULL ) { + + if ( strcmp( cleararg, "caption" ) == 0 ) { + + // free caption + if ( text[ CAPTION_LINE ] != NULL ) { + FREEMEM( text[ CAPTION_LINE ] ); + text[ CAPTION_LINE ] = NULL; + } + + } else if ( strcmp( cleararg, "text" ) == 0 ) { + + // free text + if ( text[ TEXT_LINE ] != NULL ) { + FREEMEM( text[ TEXT_LINE ] ); + text[ TEXT_LINE ] = NULL; + scv_ship_textcnt[ shipindex ] = 0; + } + ASSERT( scv_ship_textcnt[ shipindex ] == 0 ); + + } else { + + CON_AddLine( clear_arg_invalid ); + return TRUE; + } + } + + // add a textline to the ship description text if specified + char *textline = shipdesc_key_value[ KEY_SHIPDESC_TEXT ].value; + if ( textline != NULL ) { + + // check if text will fit + if ( ( scv_ship_textcnt[ shipindex ] + strlen( textline ) ) >= MAX_TEXT_LEN ) { + CON_AddLine( text_too_large ); + return TRUE; + } + + if ( text[ TEXT_LINE ] == NULL ) { + + text[ TEXT_LINE ] = (char *) ALLOCMEM( MAX_TEXT_LEN ); + if ( text[ TEXT_LINE ] == NULL ) + OUTOFMEM( 0 ); + } + + strcpy( text[ TEXT_LINE ] + scv_ship_textcnt[ shipindex ], textline ); + scv_ship_textcnt[ shipindex ] += strlen( textline ); + } + + // overwrite ship description text caption if specified + char *caption = shipdesc_key_value[ KEY_SHIPDESC_CAPTION ].value; + if ( caption != NULL ) { + + if ( text[ CAPTION_LINE ] != NULL ) + FREEMEM( text[ CAPTION_LINE ] ); + text[ CAPTION_LINE ] = (char *) ALLOCMEM( strlen( caption ) + 1 ); + + strcpy( text[ CAPTION_LINE ], caption ); + } + + return TRUE; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( M_VIEWER ) +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "shipdesc" command + regcom.command = "shipdesc"; + regcom.numparams = 1; + regcom.execute = Cmd_SHIPDESC; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // init start matrix of spacecraft viewer camera + MakeIdMatrx( SpacecraftCamera ); + CamRotX( SpacecraftCamera, SCV_CAM_PITCH ); + CamRotY( SpacecraftCamera, SCV_CAM_YAW ); + CamRotZ( SpacecraftCamera, SCV_CAM_ROLL ); + SpacecraftCamera[ 2 ][ 3 ] += SCV_CAM_DIST; + + // initialize ship description text array + for ( int sid = 0; sid < MAX_SHIP_CLASSES; sid++ ) { + scv_ship_text[ sid ][ CAPTION_LINE ] = NULL; + scv_ship_text[ sid ][ TEXT_LINE ] = NULL; + scv_ship_textcnt[ sid ] = 0; + } +} + + + |
