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_camera.cpp | 644 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 644 insertions(+) create mode 100644 src/parsec/g_camera.cpp (limited to 'src/parsec/g_camera.cpp') diff --git a/src/parsec/g_camera.cpp b/src/parsec/g_camera.cpp new file mode 100644 index 0000000..08ab77e --- /dev/null +++ b/src/parsec/g_camera.cpp @@ -0,0 +1,644 @@ +/* + * PARSEC - Camera Code + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:36 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger 1996-1999 + * Copyright (c) Andreas Varga 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 +#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" + +// mathematics header +#include "utl_math.h" + +// local module header +#include "g_camera.h" + +// proprietary module headers +#include "con_arg.h" +#include "con_aux.h" +#include "con_com.h" +#include "con_main.h" + + +// flags +#define APPLY_SMOOTHING_TO_POSITION + + + +// string constants ----------------------------------------------------------- +// +static char sway_inval_period[] = "period(2) invalid."; +static char sway_inval_ampl[] = "amplitude(2) invalid."; +static char sway_inval_phase[] = "phase invalid."; +static char sway_set_defaults[] = "resetting to defaults."; + + +// init start position of camera ---------------------------------------------- +// +void CAMERA_InitShipOrigin() +{ + // place camera at absolute origin + MakeIdMatrx( ShipViewCamera ); + + // rotate and translate camera --------------------------- + // : matrix is "reversed": + // : camerarotation right means matrixrotation left, etc. + ShipViewCamera[ 0 ][ 3 ] += FLOAT_TO_GEOMV( 0.0 ); + ShipViewCamera[ 1 ][ 3 ] += FLOAT_TO_GEOMV( 0.0 ); + ShipViewCamera[ 2 ][ 3 ] += FLOAT_TO_GEOMV( 70.0/3.0 /*70.0/4.0*/ ); // higher means obj smaller +/* + CamRotX( &ShipViewCamera, (bams_t) 0x0000 ); + CamRotY( &ShipViewCamera, (bams_t) 0x0000 ); + CamRotZ( &ShipViewCamera, (bams_t) 0x0000 ); +*/ + // fill position matrix of local ship (MyShip) + CalcOrthoInverse( ShipViewCamera, MyShip->ObjPosition ); + + // make sure filter will work correctly + CAMERA_ResetFilter(); +} + + +// fill a matrix with the current fixed star camera --------------------------- +// +void CAMERA_MakeFixedStarCam( Camera dstcam ) +{ + ASSERT( dstcam != NULL ); + + memcpy( dstcam, ViewCamera, sizeof( Camera ) ); + + dstcam[ 0 ][ 3 ] = GEOMV_0; + dstcam[ 1 ][ 3 ] = GEOMV_0; + dstcam[ 2 ][ 3 ] = GEOMV_0; +} + + +// get actual viewing (rendering) camera -------------------------------------- +// +void CAMERA_GetViewCamera() +{ + // do transformations for object camera + if ( ObjCameraActive ) { + + // create current view matrix for object camera + MtxMtxMUL( ObjectCamera, ShipViewCamera, DestXmatrx ); + memcpy( ViewCamera, DestXmatrx, sizeof( Camera ) ); + + } else { + + // use ship view camera directly + memcpy( ViewCamera, ShipViewCamera, sizeof( Camera ) ); + } +} + + +// view camera storage -------------------------------------------------------- +// +static Camera viewcam_prefilt; +static Camera viewcam_postfilt; +static int viewcam_modify_in_progress = FALSE; + + +// reset/init view camera smoothing filter ------------------------------------ +// +void CAMERA_ResetFilter() +{ + //NOTE: + // this function will work both outside and during a modification + // cycle. for both cases it ensures predictable filter behavior. + + // init view camera matrices + memcpy( viewcam_prefilt, ShipViewCamera, sizeof( Camera ) ); + memcpy( viewcam_postfilt, ShipViewCamera, sizeof( Camera ) ); +} + + +// begin view camera modification section ------------------------------------- +// +void CAMERA_BeginModify() +{ + ASSERT( !viewcam_modify_in_progress ); + if ( viewcam_modify_in_progress ) + return; + viewcam_modify_in_progress = TRUE; + + if ( !AUX_ENABLE_SMOOTH_SHIP_CONTROL ) { + return; + } + + // save filtered view camera + memcpy( viewcam_postfilt, ShipViewCamera, sizeof( Camera ) ); + + // restore non-filtered view camera + memcpy( ShipViewCamera, viewcam_prefilt, sizeof( Camera ) ); +} + + +// end view camera modification section and filter camera movement ------------ +// +void CAMERA_EndModify() +{ + ASSERT( viewcam_modify_in_progress ); + if ( !viewcam_modify_in_progress ) + return; + viewcam_modify_in_progress = FALSE; + + // save non-filtered view camera + memcpy( viewcam_prefilt, ShipViewCamera, sizeof( Camera ) ); + + if ( !AUX_ENABLE_SMOOTH_SHIP_CONTROL ) { + return; + } + + // determine interpolation alpha from filter constant + if ( AUXDATA_SMOOTH_SHIP_CONTROL_FACTOR < 1 ) + AUXDATA_SMOOTH_SHIP_CONTROL_FACTOR = 100; + float filtalpha = AUXDATA_SMOOTH_SHIP_CONTROL_FACTOR / 1000.0f; + filtalpha *= CurScreenRefFrames * 0.06f; + if ( filtalpha > 1.0f ) + filtalpha = 1.0f; + + // filtered orientation (filter output last frame) + Quaternion srcquat; + QuaternionFromMatrx( &srcquat, viewcam_postfilt ); + QuaternionMakeUnit( &srcquat ); + + // non-filtered orientation (filter input this frame) + Quaternion dstquat; + QuaternionFromMatrx( &dstquat, ShipViewCamera ); + QuaternionMakeUnit( &dstquat ); + + // do slerp from src to dst (filter output this frame) + Quaternion slerpquat; + QuaternionSlerp( &slerpquat, &srcquat, &dstquat, filtalpha ); + QuaternionMakeUnit( &slerpquat ); + + // fill R part of view camera matrix (filtered orientation this frame) + MatrxFromQuaternion( ShipViewCamera, &slerpquat ); + + //NOTE: + // the T part of the view camera matrix has to be + // corrected for the new R part. + // if R=R2*R1 and R is changed by the filter to + // just R1, T has to be corrected to R2^-1*T to + // account for the missing rotation of the translation. + + // determine R2^-1 + Quaternion hrotquat = slerpquat; + QuaternionInvertUnit( &hrotquat ); + QuaternionMUL( &hrotquat, &dstquat, &hrotquat ); + QuaternionInvertUnit( &hrotquat ); + + // convert R2^-1 to rotation matrix (T irrelevant) + Xmatrx hrotmatrx; + MatrxFromQuaternion( hrotmatrx, &hrotquat ); + + // calculate R2^-1*T and remember it as new T + Vector3 oldtvec, newtvec; + FetchTVector( ShipViewCamera, &oldtvec ); + MtxVctMULt( hrotmatrx, &oldtvec, &newtvec ); + + // invert post-filter rotation (filter output last frame) + Quaternion srcquatinv = srcquat; + QuaternionInvertUnit( &srcquatinv ); + + // determine incremental rotation for pseudo stars + Quaternion incrotquat; + QuaternionMUL( &incrotquat, &slerpquat, &srcquatinv ); + QuaternionMakeUnit( &incrotquat ); + + if ( !ObjCameraActive ) { + + // fill R part of pseudo star matrix + MatrxFromQuaternion( PseudoStarMovement, &incrotquat ); + + } else { + + Xmatrx objcaminv; + CalcOrthoInverse( ObjectCamera, objcaminv ); + MtxMtxMUL( objcaminv, PseudoStarMovement, DestXmatrx ); + memcpy( PseudoStarMovement, DestXmatrx, sizeof( Camera ) ); + + Xmatrx incrotmat; + MatrxFromQuaternion( incrotmat, &incrotquat ); + incrotmat[ 0 ][ 3 ] = GEOMV_0; + incrotmat[ 1 ][ 3 ] = GEOMV_0; + incrotmat[ 2 ][ 3 ] = GEOMV_0; + + MtxMtxMUL( incrotmat, PseudoStarMovement, DestXmatrx ); + +#ifndef APPLY_SMOOTHING_TO_POSITION + MtxMtxMUL( ObjectCamera, DestXmatrx, PseudoStarMovement ); +#endif + + } + +#ifdef APPLY_SMOOTHING_TO_POSITION + + // translation from last frame to this frame + Quaternion xlatquat; + QuaternionMUL( &xlatquat, &slerpquat, &srcquatinv ); + QuaternionMakeUnit( &xlatquat ); + + Xmatrx xlatmatrx; + MatrxFromQuaternion( xlatmatrx, &xlatquat ); + + // translate last t vector to this frame + Vector3 lasttvec, thistvec; + FetchTVector( viewcam_postfilt, &lasttvec ); + MtxVctMULt( xlatmatrx, &lasttvec, &thistvec ); + + // interpolation vector from last filtered to new filtered t + float lerpx = GEOMV_TO_FLOAT( newtvec.X - thistvec.X ) * filtalpha; + float lerpy = GEOMV_TO_FLOAT( newtvec.Y - thistvec.Y ) * filtalpha; + float lerpz = GEOMV_TO_FLOAT( newtvec.Z - thistvec.Z ) * filtalpha; + + //MSGOUT( "CAMERA_EndModify(): LERP: %6.3f/%6.3f/%6.3f", lerpx, lerpy, lerpz ); + + Vector3 deltatvec; + deltatvec.X = FLOAT_TO_GEOMV( lerpx ); + deltatvec.Y = FLOAT_TO_GEOMV( lerpy ); + deltatvec.Z = FLOAT_TO_GEOMV( lerpz ); + + // set new t for view camera + newtvec.X = thistvec.X + deltatvec.X; + newtvec.Y = thistvec.Y + deltatvec.Y; + newtvec.Z = thistvec.Z + deltatvec.Z; + + if ( !ObjCameraActive ) { + + // update T of pseudo star matrix (incremental) + StoreTVector( PseudoStarMovement, &deltatvec ); + + } else { + + DestXmatrx[ 0 ][ 3 ] += deltatvec.X; + DestXmatrx[ 1 ][ 3 ] += deltatvec.Y; + DestXmatrx[ 2 ][ 3 ] += deltatvec.Z; + + MtxMtxMUL( ObjectCamera, DestXmatrx, PseudoStarMovement ); + } + +#endif // APPLY_SMOOTHING_TO_POSITION + + // update T of view camera + StoreTVector( ShipViewCamera, &newtvec ); +} + + +// frame camera changes for pseudostars transformation ------------------------ +// +int pseudo_framecam_is_id = TRUE; +Xmatrx pseudo_framecam; + + +// view camera before framecam changes are applied ---------------------------- +// +static Camera prev_viewcam; + + +// full sine waves for cockpit swaying ---------------------------------------- +// +static bams_t *cam_sway_tab_x = NULL; +static bams_t *cam_sway_tab_y = NULL; + +static int cam_sway_len_x; +static int cam_sway_len_y; + + +// alter view camera for rendering the frame (frame camera) ------------------- +// +void CAMERA_BeginFrameView() +{ + static refframe_t refframecount = 0; + + // make id implicitly + pseudo_framecam_is_id = TRUE; + + if ( !AUX_ENABLE_COCKPIT_SWAYING ) { + + // avoid jumping after successive disabling/enabling + refframecount = 0; + + if ( !AUX_ENABLE_COCKPIT_RATTLING ) { + return; + } + } + + // save previous view camera + memcpy( prev_viewcam, ViewCamera, sizeof( Camera ) ); + + if ( InFloatingMenu || EntryMode || ObjCameraActive ) { + + // avoid jumping after successive mode switches + refframecount = 0; + + return; + } + + // pseudo must be incremental + MakeIdMatrx( pseudo_framecam ); + + if ( AUX_ENABLE_COCKPIT_SWAYING ) { + + // advance time only if no user interaction + if ( ( CurYaw == 0 ) && ( CurPitch == 0 ) && ( CurRoll == 0 ) && + ( CurSlideHorz == 0 ) && ( CurSlideVert == 0 ) ) { + + refframecount += CurScreenRefFrames; + } + + ASSERT( cam_sway_tab_x != NULL ); + ASSERT( cam_sway_tab_y != NULL ); + + // (yaw,pitch)/(screen_x,screen_y)-lissajous + bams_t rotangle1 = cam_sway_tab_y[ refframecount % cam_sway_len_y ]; + bams_t rotangle2 = cam_sway_tab_x[ refframecount % cam_sway_len_x ]; + + #define SWAY_SPEED_THRESHOLD 20000 + + // no swaying above certain speed + if ( MyShip->CurSpeed > SWAY_SPEED_THRESHOLD ) { + + // avoid jumping after resetting speed + refframecount = 0; + + } else { + + if ( MyShip->CurSpeed > 0 ) { + + // linearly decrease swaying with increasing speed + int invspeed = SWAY_SPEED_THRESHOLD - MyShip->CurSpeed; + float sfac = (float)invspeed / SWAY_SPEED_THRESHOLD; + + rotangle1 = (bams_t)(rotangle1 * sfac); + rotangle2 = (bams_t)(rotangle2 * sfac); + } + + // pitch-sway + CamRotX( ViewCamera, rotangle1 ); + CamRotX( pseudo_framecam, rotangle1 ); + + if ( AUX_ENABLE_COCKPIT_SWAYING == 1 ) { + + // yaw-sway + CamRotY( ViewCamera, rotangle2 ); + CamRotY( pseudo_framecam, rotangle2 ); + + } else { + + // roll-sway + CamRotZ( ViewCamera, rotangle2 ); + CamRotZ( pseudo_framecam, rotangle2 ); + } + + pseudo_framecam_is_id = FALSE; + } + } + + if ( AUX_ENABLE_COCKPIT_RATTLING && SetScreenBlue ) { + + bams_t rotangle_x = RAND() % 0x0100; + bams_t rotangle_y = RAND() % 0x0100; + bams_t rotangle_z = RAND() % 0x0100; + + CamRotX( ViewCamera, rotangle_x ); + CamRotX( pseudo_framecam, rotangle_x ); + + CamRotY( ViewCamera, rotangle_y ); + CamRotY( pseudo_framecam, rotangle_y ); + + CamRotZ( ViewCamera, rotangle_z ); + CamRotZ( pseudo_framecam, rotangle_z ); + + pseudo_framecam_is_id = FALSE; + } +} + + +// restore changes made for frame view camera --------------------------------- +// +void CAMERA_EndFrameView() +{ + if ( !AUX_ENABLE_COCKPIT_SWAYING && !AUX_ENABLE_COCKPIT_RATTLING ) + return; + + //NOTE: + // pseudo stars matrix must not be restored here, since it + // is incremental (and identity on call of this function). + + // restore previous view camera + memcpy( ViewCamera, prev_viewcam, sizeof( Camera ) ); +} + + +// cockpit swaying defaults --------------------------------------------------- +// +#define DEFAULT_TABLENGTH_X 900 // freqs x:y=1:2 +#define DEFAULT_TABLENGTH_Y 450 + +#define DEFAULT_AMPLITUDE_X 85 // ampls x:y=2:1 +#define DEFAULT_AMPLITUDE_Y 43 + +#define DEFAULT_PHASE 0 // in sync + +#define MAX_SWAYTAB_LENGTH 4096 +#define MAX_SWAY_AMPLITUDE 1000 + + +// precalculate swaying tables for given parameters --------------------------- +// +PRIVATE +void InitSwayingTable( int tablena, int tablenb, int ampla, int amplb, int phase ) +{ + ASSERT( ( tablena > 0 ) && ( tablena <= MAX_SWAYTAB_LENGTH ) ); + ASSERT( ( tablenb > 0 ) && ( tablenb <= MAX_SWAYTAB_LENGTH ) ); + ASSERT( ( ampla >= -MAX_SWAY_AMPLITUDE ) && ( ampla <= MAX_SWAY_AMPLITUDE ) ); + ASSERT( ( amplb >= -MAX_SWAY_AMPLITUDE ) && ( amplb <= MAX_SWAY_AMPLITUDE ) ); + + if ( cam_sway_tab_x != NULL ) { + FREEMEM( cam_sway_tab_x ); + cam_sway_tab_x = NULL; + cam_sway_tab_y = NULL; + } + + cam_sway_tab_x = (bams_t *) ALLOCMEM( ( tablena + tablenb ) * sizeof( bams_t ) ); + if ( cam_sway_tab_x == NULL ) + OUTOFMEM( 0 ); + cam_sway_tab_y = &cam_sway_tab_x[ tablena ]; + + cam_sway_len_x = tablena; + cam_sway_len_y = tablenb; + + // precalc full sine waves in time resolution + // exactly as needed for cockpit swaying + + hprec_t angle = 0; + hprec_t delta = HPREC_TWO_PI / tablena; + int reft = 0; + for ( reft = 0; reft < tablena; reft++ ) { + cam_sway_tab_x[ reft ] = -(int)( ampla * sin( angle ) ); + angle += delta; + } + + // ensure correct modulus for negative quotient + // and produce inverted phase + int phneg = ( phase < 0 ); + if ( phneg ) + phase = -phase; + phase = phase % tablenb; + if ( !phneg ) + phase = tablenb - phase; + + angle = 0; + delta = HPREC_TWO_PI / tablenb; + for ( reft = 0; reft < tablenb; reft++ ) { + cam_sway_tab_y[ ( reft + phase ) % tablenb ] = -(int)( amplb * sin( angle ) ); + angle += delta; + } +} + + +// key table for swaying command ---------------------------------------------- +// +key_value_s swaying_key_value[] = { + + { "period", NULL, KEYVALFLAG_PARENTHESIZE }, + { "amplitude", NULL, KEYVALFLAG_PARENTHESIZE }, + { "phase", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_SWAYING_PERIOD, + KEY_SWAYING_AMPLITUDE, + KEY_SWAYING_PHASE +}; + + +// specify swaying by setting lissajous figure parameters --------------------- +// +PRIVATE +int Cmd_SWAYING( char *paramstr ) +{ + //NOTE: + //CONCOM: + // swaying_command ::= 'gfx.swaying' [] [] [] + // period_spec ::= '(' ')' + // ampl_spec ::= '(' ')' + // phase_spec ::= + + ASSERT( paramstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( paramstr ); + + // scan out all values to keys + if ( !ScanKeyValuePairs( swaying_key_value, paramstr ) ) + return TRUE; + + // defaults + int tablengths[] = { DEFAULT_TABLENGTH_X, DEFAULT_TABLENGTH_Y }; + int amplitudes[] = { DEFAULT_AMPLITUDE_X, DEFAULT_AMPLITUDE_Y }; + int phase = DEFAULT_PHASE; + int alldefaults = TRUE; + + if ( swaying_key_value[ KEY_SWAYING_PERIOD ].value != NULL ) { + if ( ScanKeyValueIntList( &swaying_key_value[ KEY_SWAYING_PERIOD ], + tablengths, 2, 2 ) == 0 ) { + CON_AddLine( sway_inval_period ); + return TRUE; + } + alldefaults = FALSE; + } + + if ( ( tablengths[ 0 ] < 1 ) || ( tablengths[ 0 ] > MAX_SWAYTAB_LENGTH ) || + ( tablengths[ 1 ] < 1 ) || ( tablengths[ 1 ] > MAX_SWAYTAB_LENGTH ) ) { + CON_AddLine( sway_inval_period ); + return TRUE; + } + + if ( swaying_key_value[ KEY_SWAYING_AMPLITUDE ].value != NULL ) { + if ( ScanKeyValueIntList( &swaying_key_value[ KEY_SWAYING_AMPLITUDE ], + amplitudes, 2, 2 ) == 0 ) { + CON_AddLine( sway_inval_ampl ); + return TRUE; + } + alldefaults = FALSE; + } + + if ( ( amplitudes[ 0 ] < -MAX_SWAY_AMPLITUDE ) || ( amplitudes[ 0 ] > MAX_SWAY_AMPLITUDE ) || + ( amplitudes[ 1 ] < -MAX_SWAY_AMPLITUDE ) || ( amplitudes[ 1 ] > MAX_SWAY_AMPLITUDE ) ) { + CON_AddLine( sway_inval_ampl ); + return TRUE; + } + + if ( ScanKeyValueInt( &swaying_key_value[ KEY_SWAYING_PHASE ], &phase ) < 0 ) { + CON_AddLine( sway_inval_phase ); + return TRUE; + } + + if ( alldefaults && ( phase == DEFAULT_PHASE ) ) { + CON_AddLine( sway_set_defaults ); + } + + // init swaying table + InitSwayingTable( tablengths[ 0 ], tablengths[ 1 ], + amplitudes[ 0 ], amplitudes[ 1 ], phase ); + return TRUE; +} + + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( G_CAMERA ) +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "gfx.swaying" command + regcom.command = "gfx.swaying"; + regcom.numparams = 1; + regcom.execute = Cmd_SWAYING; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); + + // init default swaying table + InitSwayingTable( DEFAULT_TABLENGTH_X, DEFAULT_TABLENGTH_Y, + DEFAULT_AMPLITUDE_X, DEFAULT_AMPLITUDE_Y, DEFAULT_PHASE ); +} + + + -- cgit v1.2.3