If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!
Proto:Hydro Thunder (Dreamcast)
This page details one or more prototype versions of Hydro Thunder (Dreamcast).
A prototype from June 16, 1999 was dumped by Laurent and features more uncompiled source code that is not in the final build.
Contents
- 1 Uncompiled Source Code
- 1.1 wpr_attract.c
- 1.2 hydro.hob
- 1.3 text.c
- 1.4 statemgr.c
- 1.5 mesh3d.c
- 1.6 ai_craft.c
- 1.7 text.c (Copy 2)
- 1.8 init3dfx.c
- 1.9 hud_radar.c
- 1.10 ai_chase_icop.c
- 1.11 anim3d.c
- 1.12 xfm.c
- 1.13 mesh3d.c (Copy 2)
- 1.14 dcTexture.c
- 1.15 dcDebug.c
- 1.16 hud.c
- 1.17 controls.c
- 1.18 wpr_hiscore.c
- 1.19 race.c
- 1.20 audits.c
- 1.21 Sg_gd.mak
- 2 Website Fragments
Uncompiled Source Code
wpr_attract.c
A copy of wpr_attract.c that is not in a program listing can be found at 0x1ED8800.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* wpr_attract.c - */
/**/
/* Author: Michael Starich */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1998*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 03/30/98 Starich Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "wpr_attract.h"
#include "wpr_defs.h"
#include "gutil.h"
#include "text.h"
#include "controls.h"
#include "wpr_memmgr.h"
#include "mesh3d.h"
#include "obsys.h"
#include "blit.h"
#include "tracks.h"
#include "terrain.h"
#include "xclib.h"
#include "temp.h"
#include "gameloop.h"
#include "particle.h"
#include "tripwire.h"
#include "objectid.h"
#include "fx.h"
#include "fx_splash.h"
#include "fx_particles.h"
#include "sky.h"
#include "boats.h"
#include "anim_fish.h"
#include "anim_land.h"
#include "anim_water.h"
#include "waterspray.h"
#include "anim_air.h"
#include "mtx3.h"
#include "audio.h"
#include "soundcall.h"
#include "auditor.h"
#include "scissor.h"
#include "race.h"
#include "ai_craft.h"
#include "ai_rabbit.h"
#include "physcoll.h"
#include "cam_mgr.h"
#include "r2format.h"
#include "sysmem.h"
#include "hi_score.h"
#include "powerup.h"
#include "hud.h"
#include "fog.h"
#include "wpr_banker.h"
#include "audits.h"
#include "viewport.h"
/*====================*/
/* private definitions*/
#define _ATTRACT_FILE_LOGGING_ON 0
#define _SPIT_DEBUG_INFO_OUT_TO_A_FILE 0 /* set to 0 to disable*/
#define _DEMO_FOV ( XMATH_1_BRADIANS * 90 )
#define _FLAG_TRACKDEMO 0x1
#define _FLAG_CREDITS 0x2
#define _FLAG_JOIN_GAME 0x4
#define _FLAG_ACTIVE ( _FLAG_TRACKDEMO | _FLAG_CREDITS | _FLAG_JOIN_GAME )
#define _NUM_ATTRACT_RACERS 8
#define _MAX_SCREEN_AREA_SUM ( 512.0f * 400.0f * 7.0f )
#define _MAX_SPRAY_PARTICLES 200
#define _FRAMES_TO_GET_UP_AND_RUNNING 13
#define _PHYSDATASET_ATTRACT 1 /* Special "saved-off" attract mode physdata dataset */
#define _FLAG_LOADING_LARGE_DEMO_LEVEL 0x1
#define _FLAG_UPDATING_COIN_COUNTER 0x2
#define _CREDIT_SPACING 26.0f
typedef struct
{
u8 nFlags;
u8 nNextStage;
u8 nNextActiveStage;
u8 nR;
u8 nG;
u8 nB;
u16 nTimeInStage; /* in 60ths of a sec*/
char *pszObName;
u16 nParm1; /* track num*/
u16 nParm2; /* start offset*/
u16 nParm3; /* ai boat offset*/
u16 nParm4; /* should we start the music*/
u16 nParm5; /* script index*/
u16 nParm6;
} AttractInfo_t;
/* in demomode nParm1 = track num, nParm2 = starting pos offset, nParm3 = ai boat type offset*/
/* in hiscore nParm1 = 1st track num, nParm2 = 2nd track num*/
#define _DEMO_SCRIPT_COMMAND_LENGTH 11
#define DEMO_VIEW_BUTTONS CAM_MGR_COUNT
#define DEMO_HIGH_SCORES ( DEMO_VIEW_BUTTONS + 1 )
#define DEMO_BLUE_ARROW ( DEMO_HIGH_SCORES + 1 )
#define DEMO_RED_ARROW ( DEMO_BLUE_ARROW + 1 )
#define DEMO_BLUE_BOOST ( DEMO_RED_ARROW + 1 )
#define DEMO_RED_BOOST ( DEMO_BLUE_BOOST + 1 )
#define DEMO_THROTTLE ( DEMO_RED_BOOST + 1 )
#define ESPN_FROM_POINT ( DEMO_THROTTLE + 1 )
#define ESPN_FROM_CURRENT ( ESPN_FROM_POINT + 1 )
#define STATIONARY_FROM_CURRENT ( ESPN_FROM_CURRENT + 1 )
#define DEMO_SCROLL_CREDITS ( STATIONARY_FROM_CURRENT + 1 )
#define NUM_DEMO_COMMANDS ( DEMO_SCROLL_CREDITS )
typedef struct
{
u32 nLineNum;
f32 fDeltaFrames;
char acCommand[_DEMO_SCRIPT_COMMAND_LENGTH + 1];
u32 nNumParameters;
} DemoRecord_t;
typedef struct
{
char aszCommandName[_DEMO_SCRIPT_COMMAND_LENGTH + 1];
u16 nCommandCode;
u16 nNumParameters;
/* nNumParameters f32s follow, these are the parameters*/
} ScriptCommands_t;
typedef struct
{
ScriptCommands_t *pScriptEntry;
f32 *pfParameters;
u16 nFrameNumber;
u16 nActionCode;
} Commands_t;
#define _DO_NOT_DRAW_OVERLAY -1
typedef enum
{
ICON_VIEW_BUTTONS_TEXT = 0,
ICON_VIEW_BUTTON1,
ICON_VIEW_BUTTON2,
ICON_VIEW_BUTTON3,
ICON_TRACKNAME_PLATE1,
ICON_TRACKNAME_PLATE2,
ICON_TRACKNAME_GRAVEYARD,
ICON_TRACKNAME_LOSTISLAND,
ICON_TRACKNAME_VENICE,
ICON_TRACKNAME_LAKEPOWELL,
ICON_TRACKNAME_ARCTIC,
ICON_TRACKNAME_NILE,
ICON_TRACKNAME_NY,
ICON_TRACKNAME_GREECE,
ICON_TRACKNAME_CHINA,
ICON_TRACKNAME_TEST,
ICON_TRACKNAME_LOOP1,
ICON_TRACKNAME_LOOP2,
ICON_TRACKNAME_LOOP3,
ICON_LETTER_0,
ICON_LETTER_1,
ICON_LETTER_2,
ICON_LETTER_3,
ICON_LETTER_4,
ICON_LETTER_5,
ICON_LETTER_6,
ICON_LETTER_7,
ICON_LETTER_8,
ICON_LETTER_9,
ICON_LETTER_A,
ICON_LETTER_B,
ICON_LETTER_C,
ICON_LETTER_D,
ICON_LETTER_E,
ICON_LETTER_F,
ICON_LETTER_G,
ICON_LETTER_H,
ICON_LETTER_I,
ICON_LETTER_J,
ICON_LETTER_K,
ICON_LETTER_L,
ICON_LETTER_M,
ICON_LETTER_N,
ICON_LETTER_O,
ICON_LETTER_P,
ICON_LETTER_Q,
ICON_LETTER_R,
ICON_LETTER_S,
ICON_LETTER_T,
ICON_LETTER_U,
ICON_LETTER_V,
ICON_LETTER_W,
ICON_LETTER_X,
ICON_LETTER_Y,
ICON_LETTER_Z,
ICON_LETTER_PERIOD,
ICON_LETTER_COLON,
ICON_BANSHEE,
ICON_TIDAL_BLADE,
ICON_RAD_HAZARD,
ICON_MISS_BEHAVE,
ICON_DAMN_THE_TORPEDOES,
ICON_CUT_THROAT,
ICON_RAZORBACK,
ICON_THRESHER,
ICON_MIDWAY,
ICON_SEADOG,
ICON_COP,
ICON_HOVERCRAFT,
ICON_TINY,
ICON_WWW_ADDRESS,
ICON_LETTER_QUESTION_MARK,
ICON_LETTER_EXCLAMATION_POINT,
ICON_TEAM_HYDRO,
ICON_COUNT
} Icons_t;
#define _MAX_NUM_HIGH_SCORE_CHARS 17
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
#if TARGET==DREAMCAST // Lost island levels taken out (they don't load!)
const static AttractInfo_t _StageInfo[WPR_ATTRACT_STAGE_COUNT] = {
/*========================================================*/
/* WPR_ATTRACT_ENTER*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
450, /* nTimeInStage*/
"BWWLOGOAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6 */
/*========================================================*/
/* WPR_ATTRACT_HYDRO_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_ARCTIC_1, /* nNextStage*/
WPR_ATTRACT_ARCTIC_1, /* nNextActiveStage*/
0, 255, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHYDRAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_DIRECTIONS_1 */
0, /* nFlags */
WPR_ATTRACT_LAKE_POWELL_2,/* nNextStage */
WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage */
64, 255, 128, /* nR nG, nB */
90, /* nTimeInStage*/
"BWWDIREAT10", /* pszObName */
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_3DFX_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_2,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage*/
255, 0, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWLOGOAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_HYDRO_LOGO_2*/
0, /* nFlags*/
WPR_ATTRACT_ARCTIC_2, /* nNextStage*/
WPR_ATTRACT_ARCTIC_2, /* nNextActiveStage*/
0, 255, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHYDRAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_HTRA_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_CREDITS,/* nNextStage*/
WPR_ATTRACT_CREDITS,/* nNextActiveStage*/
0, 255, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHTRAAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_MIDWAY_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_CREDITS, /* nNextStage*/
WPR_ATTRACT_CREDITS, /* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWLOGOAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*======================================================== */
/* WPR_ATTRACT_DIRECTIONS_2*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWDIREAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_JOIN */
_FLAG_JOIN_GAME, /* nFlags */
WPR_ATTRACT_ENTER, /* nNextStage */
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage */
0, 0, 0, /* nR nG, nB*/
0, /* nTimeInStage */
"BWWJOINAT10", /* pszObName */
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LAKE_POWELL_1 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_HYDRO_LOGO_1,/* nNextStage */
WPR_ATTRACT_ARCTIC_1, /* nNextActiveStage*/
255, 128, 64, /* nR nG, nB*/
3150, /* nTimeInStage */
"H2WPWELTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
1, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_ARCTIC_1 */
_FLAG_TRACKDEMO, /* nFlags*/
WPR_ATTRACT_3DFX_LOGO_1,/* nNextStage */
WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage*/
64, 32, 16, /* nR nG, nB*/
3100, /* nTimeInStage */
"H1WARCTTRH0", /* pszObName */
TRACKS_ARTIC, /* nParm1*/
0, /* nParm2*/
1, /* nParm3*/
0, /* nParm4*/
1, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LOST_ISLAND_1 */
// _FLAG_TRACKDEMO, /* nFlags */
// WPR_ATTRACT_3DFX_LOGO_1,/* nNextStage */
// WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage*/
// 128, 255, 255, /* nR nG, nB*/
// 2800, /* nTimeInStage */
// "H3WAMAZTRH0", /* pszObName */
// TRACKS_AMAZON, /* nParm1*/
// 0, /* nParm2*/
// 2, /* nParm3*/
// 1, /* nParm4*/
// 2, /* nParm5*/
// 0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LAKE_POWELL_2 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_HYDRO_LOGO_2,/* nNextStage */
WPR_ATTRACT_ARCTIC_2, /* nNextActiveStage */
255, 0, 255, /* nR nG, nB */
3150, /* nTimeInStage */
"H2WPWELTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
3, /* nParm3*/
0, /* nParm4*/
3, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_ARCTIC_2 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_MIDWAY_LOGO_1,/* nNextStage */
WPR_ATTRACT_CREDITS, /* nNextActiveStage */
128, 128, 0, /* nR nG, nB */
3150, /* nTimeInStage */
"H1WARCTTRH0", /* pszObName */
TRACKS_ARTIC, /* nParm1*/
0, /* nParm2*/
4, /* nParm3*/
1, /* nParm4*/
4, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LOST_ISLAND_2 */
// _FLAG_TRACKDEMO, /* nFlags */
// WPR_ATTRACT_MIDWAY_LOGO_1,/* nNextStage */
// WPR_ATTRACT_CREDITS, /* nNextActiveStage */
// 128, 0, 128, /* nR nG, nB */
// 2800, /* nTimeInStage */
// "H3WAMAZTRH0", /* pszObName */
// TRACKS_AMAZON, /* nParm1*/
// 0, /* nParm2*/
// 5, /* nParm3*/
// 0, /* nParm4*/
// 5, /* nParm5*/
// 0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_CREDITS*/
_FLAG_CREDITS, /* nFlags */
WPR_ATTRACT_DIRECTIONS_2,/* nNextStage */
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage */
32, 128, 64, /* nR nG, nB */
6930, /* nTimeInStage */
"HWTCREDTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
1, /* nParm4*/
6, /* nParm5*/
0, /* nParm6*/
};
#else // DREAMCAST
const static AttractInfo_t _StageInfo[WPR_ATTRACT_STAGE_COUNT] = {
/*========================================================*/
/* WPR_ATTRACT_ENTER*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
#if TARGET==ULTRA64 /* Long delay on 'Hydro' logo screen */
300*100, /* nTimeInStage */
"BWWHYDRAT11", /* pszObName */
#else /*ULTRA64*/
450, /* nTimeInStage*/
"BWWLOGOAT10", /* pszObName*/
#endif /*ULTRA64*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6 */
/*========================================================*/
/* WPR_ATTRACT_HYDRO_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_ARCTIC_1, /* nNextStage*/
WPR_ATTRACT_ARCTIC_1, /* nNextActiveStage*/
0, 255, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHYDRAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_DIRECTIONS_1 */
0, /* nFlags */
WPR_ATTRACT_LOST_ISLAND_1,/* nNextStage */
WPR_ATTRACT_LOST_ISLAND_1,/* nNextActiveStage */
64, 255, 128, /* nR nG, nB */
90, /* nTimeInStage*/
"BWWDIREAT10", /* pszObName */
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_3DFX_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_2,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage*/
255, 0, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWW3DFXAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_HYDRO_LOGO_2*/
0, /* nFlags*/
WPR_ATTRACT_ARCTIC_2, /* nNextStage*/
WPR_ATTRACT_ARCTIC_2, /* nNextActiveStage*/
0, 255, 0, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHYDRAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_HTRA_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_LOST_ISLAND_2,/* nNextStage*/
WPR_ATTRACT_LOST_ISLAND_2,/* nNextActiveStage*/
0, 255, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWHTRAAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_MIDWAY_LOGO_1*/
0, /* nFlags*/
WPR_ATTRACT_CREDITS, /* nNextStage*/
WPR_ATTRACT_CREDITS, /* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWLOGOAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*======================================================== */
/* WPR_ATTRACT_DIRECTIONS_2*/
0, /* nFlags*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextStage*/
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage*/
0, 0, 255, /* nR nG, nB*/
90, /* nTimeInStage*/
"BWWDIREAT10", /* pszObName*/
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_JOIN */
_FLAG_JOIN_GAME, /* nFlags */
WPR_ATTRACT_ENTER, /* nNextStage */
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage */
0, 0, 0, /* nR nG, nB*/
0, /* nTimeInStage */
"BWWJOINAT10", /* pszObName */
0, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
0, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LAKE_POWELL_1 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_HYDRO_LOGO_1,/* nNextStage */
WPR_ATTRACT_ARCTIC_1, /* nNextActiveStage*/
255, 128, 64, /* nR nG, nB*/
3150, /* nTimeInStage */
"H2WPWELTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
1, /* nParm4*/
0, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_ARCTIC_1 */
_FLAG_TRACKDEMO, /* nFlags*/
WPR_ATTRACT_DIRECTIONS_1,/* nNextStage */
WPR_ATTRACT_LOST_ISLAND_1,/* nNextActiveStage*/
64, 32, 16, /* nR nG, nB*/
3100, /* nTimeInStage */
"H1WARCTTRH0", /* pszObName */
TRACKS_ARTIC, /* nParm1*/
0, /* nParm2*/
1, /* nParm3*/
0, /* nParm4*/
1, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LOST_ISLAND_1 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_3DFX_LOGO_1,/* nNextStage */
WPR_ATTRACT_LAKE_POWELL_2,/* nNextActiveStage*/
128, 255, 255, /* nR nG, nB*/
2800, /* nTimeInStage */
"H3WAMAZTRH0", /* pszObName */
TRACKS_AMAZON, /* nParm1*/
0, /* nParm2*/
2, /* nParm3*/
1, /* nParm4*/
2, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LAKE_POWELL_2 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_HYDRO_LOGO_2,/* nNextStage */
WPR_ATTRACT_ARCTIC_2, /* nNextActiveStage */
255, 0, 255, /* nR nG, nB */
3150, /* nTimeInStage */
"H2WPWELTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
3, /* nParm3*/
0, /* nParm4*/
3, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_ARCTIC_2 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_HTRA_LOGO_1,/* nNextStage */
WPR_ATTRACT_LOST_ISLAND_2,/* nNextActiveStage */
128, 128, 0, /* nR nG, nB */
3150, /* nTimeInStage */
"H1WARCTTRH0", /* pszObName */
TRACKS_ARTIC, /* nParm1*/
0, /* nParm2*/
4, /* nParm3*/
1, /* nParm4*/
4, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_LOST_ISLAND_2 */
_FLAG_TRACKDEMO, /* nFlags */
WPR_ATTRACT_MIDWAY_LOGO_1,/* nNextStage */
WPR_ATTRACT_CREDITS, /* nNextActiveStage */
128, 0, 128, /* nR nG, nB */
2800, /* nTimeInStage */
"H3WAMAZTRH0", /* pszObName */
TRACKS_AMAZON, /* nParm1*/
0, /* nParm2*/
5, /* nParm3*/
0, /* nParm4*/
5, /* nParm5*/
0, /* nParm6*/
/*========================================================*/
/* WPR_ATTRACT_CREDITS*/
_FLAG_CREDITS, /* nFlags */
WPR_ATTRACT_DIRECTIONS_2,/* nNextStage */
WPR_ATTRACT_LAKE_POWELL_1,/* nNextActiveStage */
32, 128, 64, /* nR nG, nB */
6930, /* nTimeInStage */
"HWTCREDTRH0", /* pszObName */
TRACKS_LAKEPOWELL, /* nParm1*/
0, /* nParm2*/
0, /* nParm3*/
1, /* nParm4*/
6, /* nParm5*/
0, /* nParm6*/
};
#endif //DREAMCAST
static WprAttractStage_t _StageNum;
static u8 _nR, _nG, _nB;
static BOOL8 _bActive;
static BOOL8 _bLoadOk;
static u8 *_pCurStaticScreen;
static u16 _nFrameCount;
static TerrainInit_t CurWorld;
static ControlState_t _HumanControls;
static u8 *_pJoin1, *_pJoin2;
static volatile u32 _nCoinUpdateISRState;
static u32 _nLoopCounter;
static BOOL _DemoModeLoaded;
ScriptCommands_t _aCommandInfoLookup[NUM_DEMO_COMMANDS] = {
/* aszCommandName nCommandCode nNumParameters Parameter description*/
"GAMECAMERA1", CAM_MGR_GAME_CAM1, 1, /* target boat*/
"GAMECAMERA2", CAM_MGR_GAME_CAM2, 1, /* target boat*/
"GAMECAMERA3", CAM_MGR_GAME_CAM3, 1, /* target boat*/
"ESPN_CAMERA", CAM_MGR_ESPN_CAM, 3, /* dummy cam, target boat, FOV*/
"STATIONARY_", CAM_MGR_STATIONARY_CAM, 2, /* dummy cam, FOV*/
"MOUNTED_CAM", CAM_MGR_MOUNTED_CAM, 8, /* mount boat, angle, distance, height, heading, pitch, roll, FOV*/
"MOUNTED_SWI", CAM_MGR_SWIVEL_MOUNTED_CAM, 8, /* mount boat, angle, distance, height, heading, pitch, roll, FOV*/
"TARGET_MOUN", CAM_MGR_MOUNTED_TARGET_CAM, 6, /* mount boat, angle, distance, height, target boat, FOV*/
"TARGET_SWIV", CAM_MGR_SWIVEL_MOUNTED_TARGET_CAM, 6, /* mount boat, angle, distance, height, target boat, FOV*/
"CIRCLING_CA", CAM_MGR_CIRCLE_CAM, 7, /* target boat, angle, distance, height, direction, rotate with boat (0/1), FOV*/
"CHASING_CAM", CAM_MGR_CHASE_CAM, 6, /* dummy cam, target boat, start speed, end speed, acceleration, FOV*/
"PANORAMA_CA", CAM_MGR_PANORAMA_CAM, 2, /* dummy cam, FOV*/
"DOLLY_CAMER", CAM_MGR_DOLLY_CAM, 4, /* start dummy cam, end dummy cam, frames, FOV*/
"DOLLY_TARGE", CAM_MGR_DOLLY_TARGET_CAM, 5, /* start dummy cam, end dummy cam, frames, boat target, FOV*/
"VIEW_BUTTON", DEMO_VIEW_BUTTONS, 2, /* on/off, target boat*/
"HIGH_SCORE_", DEMO_HIGH_SCORES, 2, /* on/off, track num */
"BLUE_ARROW_", DEMO_BLUE_ARROW, 1, /* on/off */
"RED_AROW_DE", DEMO_RED_ARROW, 1, /* on/off */
"BLUE_BOOST_", DEMO_BLUE_BOOST, 1, /* on/off */
"RED_BOOST_D", DEMO_RED_BOOST, 1, /* on/off*/
"THROTTLE_DE", DEMO_THROTTLE, 1, /* on/off*/
"ESPN_FROM_P", ESPN_FROM_POINT, 5, /* x, y, z, target boat, FOV*/
"ESPN_FROM_C", ESPN_FROM_CURRENT, 2, /* target boat, FOV*/
"STAT_FROM_C", STATIONARY_FROM_CURRENT, 1, /* FOV*/
"SCROLL_CRED", DEMO_SCROLL_CREDITS, 2, /* on/off, scroll speed*/
};
static HcompDemoScriptDef_t *_pLoadedFile;
static Commands_t *_pFirstCommand;
static u16 _nNumCommands;
static u16 _nCurrentCommand;
static Mesh3d_t *_paOverLayIcons[ICON_COUNT];
static BOOL8 _bOverLayOk;
static BOOL8 _bFlashOn;
static s16 _nViewWords;
static u16 _nCounter;
static u16 _nTrackNum;
static u16 _nOverLayMode;
static u16 _nTargetBoat;
static f32 _fScrollSpeed;
static f32 _fScrollFirstY;
static f32 _fScrollLastY;
static BOOL _bScrollCredits;
static ObsysLoadDef_t _aLoadTable[] = {
(void *)&_paOverLayIcons[ICON_VIEW_BUTTONS_TEXT], "GWWDIRETXH0",
(void *)&_paOverLayIcons[ICON_VIEW_BUTTON1], "GWWPILOONH0",
(void *)&_paOverLayIcons[ICON_VIEW_BUTTON2], "GWWLOW_ONH0",
(void *)&_paOverLayIcons[ICON_VIEW_BUTTON3], "GWWHIGHONH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_PLATE1], "GWWPLATHCH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_PLATE2], "GWWPLATHCH1",
(void *)&_paOverLayIcons[ICON_TRACKNAME_GRAVEYARD], "GWWPLATGRH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_LOSTISLAND],"GWWPLATSPH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_VENICE], "GWWPLATVEH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_LAKEPOWELL],"GWWPLATLPH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_ARCTIC], "GWWPLATACH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_NILE], "GWWPLATNRH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_NY], "GWWPLATNYH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_GREECE], "GWWPLATGIH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_CHINA], "GWWPLATCHH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_TEST], "GWWPLATCHH0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_LOOP1], "GWWPLATL1H0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_LOOP2], "GWWPLATL2H0",
(void *)&_paOverLayIcons[ICON_TRACKNAME_LOOP3], "GWWPLATL3H0",
(void *)&_paOverLayIcons[ICON_LETTER_0], "GWWFONTATH0",
(void *)&_paOverLayIcons[ICON_LETTER_1], "GWWFONTATH1",
(void *)&_paOverLayIcons[ICON_LETTER_2], "GWWFONTATH2",
(void *)&_paOverLayIcons[ICON_LETTER_3], "GWWFONTATH3",
(void *)&_paOverLayIcons[ICON_LETTER_4], "GWWFONTATH4",
(void *)&_paOverLayIcons[ICON_LETTER_5], "GWWFONTATH5",
(void *)&_paOverLayIcons[ICON_LETTER_6], "GWWFONTATH6",
(void *)&_paOverLayIcons[ICON_LETTER_7], "GWWFONTATH7",
(void *)&_paOverLayIcons[ICON_LETTER_8], "GWWFONTATH8",
(void *)&_paOverLayIcons[ICON_LETTER_9], "GWWFONTATH9",
(void *)&_paOverLayIcons[ICON_LETTER_A], "GWWFONTATHA",
(void *)&_paOverLayIcons[ICON_LETTER_B], "GWWFONTATHB",
(void *)&_paOverLayIcons[ICON_LETTER_C], "GWWFONTATHC",
(void *)&_paOverLayIcons[ICON_LETTER_D], "GWWFONTATHD",
(void *)&_paOverLayIcons[ICON_LETTER_E], "GWWFONTATHE",
(void *)&_paOverLayIcons[ICON_LETTER_F], "GWWFONTATHF",
(void *)&_paOverLayIcons[ICON_LETTER_G], "GWWFONTATHG",
(void *)&_paOverLayIcons[ICON_LETTER_H], "GWWFONTATHH",
(void *)&_paOverLayIcons[ICON_LETTER_I], "GWWFONTATHI",
(void *)&_paOverLayIcons[ICON_LETTER_J], "GWWFONTATHJ",
(void *)&_paOverLayIcons[ICON_LETTER_K], "GWWFONTATHK",
(void *)&_paOverLayIcons[ICON_LETTER_L], "GWWFONTATHL",
(void *)&_paOverLayIcons[ICON_LETTER_M], "GWWFONTATHM",
(void *)&_paOverLayIcons[ICON_LETTER_N], "GWWFONTATHN",
(void *)&_paOverLayIcons[ICON_LETTER_O], "GWWFONTATH0",
(void *)&_paOverLayIcons[ICON_LETTER_P], "GWWFONTATHP",
(void *)&_paOverLayIcons[ICON_LETTER_Q], "GWWFONTATHQ",
(void *)&_paOverLayIcons[ICON_LETTER_R], "GWWFONTATHR",
(void *)&_paOverLayIcons[ICON_LETTER_S], "GWWFONTATHS",
(void *)&_paOverLayIcons[ICON_LETTER_T], "GWWFONTATHT",
(void *)&_paOverLayIcons[ICON_LETTER_U], "GWWFONTATHU",
(void *)&_paOverLayIcons[ICON_LETTER_V], "GWWFONTATHV",
(void *)&_paOverLayIcons[ICON_LETTER_W], "GWWFONTATHW",
(void *)&_paOverLayIcons[ICON_LETTER_X], "GWWFONTATHX",
(void *)&_paOverLayIcons[ICON_LETTER_Y], "GWWFONTATHY",
(void *)&_paOverLayIcons[ICON_LETTER_Z], "GWWFONTATHZ",
(void *)&_paOverLayIcons[ICON_LETTER_PERIOD], "GWWFONT_PH0",
(void *)&_paOverLayIcons[ICON_LETTER_COLON], "GWWFONT_CH0",
(void *)&_paOverLayIcons[ICON_BANSHEE], "GWWBANSHSH0",
(void *)&_paOverLayIcons[ICON_TIDAL_BLADE], "GWWTIDAHSH0",
(void *)&_paOverLayIcons[ICON_RAD_HAZARD], "GWWRADHHSH0",
(void *)&_paOverLayIcons[ICON_MISS_BEHAVE], "GWWMISSHSH0",
(void *)&_paOverLayIcons[ICON_DAMN_THE_TORPEDOES], "GWWDAMNHSH0",
(void *)&_paOverLayIcons[ICON_CUT_THROAT], "GWWCUTTHSH0",
(void *)&_paOverLayIcons[ICON_RAZORBACK], "GWWRAZRHSH0",
(void *)&_paOverLayIcons[ICON_THRESHER], "GWWTHREHSH0",
(void *)&_paOverLayIcons[ICON_MIDWAY], "GWWMIDWHSH0",
(void *)&_paOverLayIcons[ICON_SEADOG], "GWWSEADHSH0",
(void *)&_paOverLayIcons[ICON_COP], "GWWCOPBHSH0",
(void *)&_paOverLayIcons[ICON_HOVERCRAFT], "GWWHOVRHSH0",
(void *)&_paOverLayIcons[ICON_TINY], "GWWTINYHSH0",
(void *)&_paOverLayIcons[ICON_WWW_ADDRESS], "GWWWWW_ATH0",
(void *)&_paOverLayIcons[ICON_LETTER_QUESTION_MARK],"GWWFONT_QH0",
(void *)&_paOverLayIcons[ICON_LETTER_EXCLAMATION_POINT],"GWWFONT_EH0",
(void *)&_paOverLayIcons[ICON_TEAM_HYDRO], "GWWHYDR_TH0",
NULL, NULL,
};
const static char *_pszCreditList[] = {
NULL,/* don't change this, used for spacing and coloring of [1]*/
"Project Lead",
"Steven Ranck",
NULL,
"Lead Programmer",
"Steven Ranck",
NULL,
"Art Director",
"Eric Browning",
NULL,
"SCLFX Engine",
"Steven Ranck",
NULL,
"Programming",
"Steven Ranck",
"Michael Starich",
"Scott Patterson",
NULL,
"Lead Artist",
"Eric Browning",
NULL,
"Art",
"Eric Browning",
"Scott Goffman",
"Brian Silva",
"Dale Henderscheid", /* 25*/
"Gary Carbonell",
"Andy Wilson",
NULL,
"Animation",
"Scott Goffman",
NULL,
"Music and Sound",
"Orpheus SoundStation",
NULL,
"Track Design",
"Scott Goffman",
"Dale Henderscheid",
"Brian Silva",
"Eric Browning",
"Steve Kramer",
"John Stookey",
"Steven Ranck",
NULL,
"Boat Design",
"Gary Carbonell",
"Scott Goffman",
"Andy Wilson",
"Eric Browning",
NULL,
"Tools Programming", /* 50*/
"Steven Ranck",
"Lori Miller",
"Dusty Monk",
"Scott Patterson",
"Detmar Peterke",
NULL,
"Diego Hardware Development",
"Steven Ranck",
"Steve Calfee",
"Howard A. Delman",
"Bill DeStein",
"Mike Klug",
"Cary Mednick",
"Andy Eloff",
"Steve Norris",
NULL,
"Diego Software Development",
"Randy Johns",
"Detmar Peterke",
"Steven Ranck",
NULL,
"Super Do-Anything-To-Help-Get-",/* 72*/
"The-Game-Into-Production Dude",/* 73*/
"Brian Johnson",
NULL,
"Video Development",
"Cary Mednick",
"Mark Meyers",
NULL,
"Mechanical",
"Peter Dorn",
"Tom Kopera",
NULL,
"Cabinet Art",
"Eric Browning",
"Nik Ehrlich",
NULL,
"Voice Talent",
"Brian Silva",
NULL,
"Additional Voice Talent",
"Eric Browning",
"Kevin Wang",
"Steven Ranck",
"Scott Goffman",
"David Simon",
"Justin Heber",
NULL,
"Assets Tracking",
"Scott Goffman",
NULL,
"Lead Tester",
"Dan Wagner",
NULL,
"Testers",
"Jeff Greenhut",
"Donte Knippel",
"Kevin Wang",
"Seth McNew",
"Sheila Padua Julaton",
NULL,
"Additional Testing",
"Edward Duran",
"Jason Shigenaka",
NULL,
"Special Thanks To",
"Brian Johnson",
"Michael Hunley",
"Ben Diamand",
"David Simon",
"Randy Honeycutt",
"Pat Goschy",
"Mike Peters",
"Nelson Caldani",
"Sheridan Oursler",
"Rosalind Dugas",
"All of our family members",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"",
"Hydro Thunder was designed",
"and built from scratch in",
"San Diego, CA by Team Hydro:",
"Steven Ranck Eric Browning",
"Scott Goffman Brian Silva",
"Gary Carbonell Michael Starich",
"Dale Henderscheid Andy Wilson",
"Scott Patterson and",
"Orpheus SoundStation",
};
#define _NUM_CREDIT_LINES ( sizeof( _pszCreditList ) / sizeof( char * ) )
static Mesh3d_t *_paHighScoreTable[CMOS_HI_SCORES_PER_TRACK][_MAX_NUM_HIGH_SCORE_CHARS];
/*===================*/
/* private prototypes*/
static void _DrawOldTextSystem( f32 fTime );
static BOOL _InitDemoMode( u32 nTrack, char *pszObName, u16 nStartPosOffset, u16 nAiOffSet, u16 nScriptIndex ,u32 StageNum); // DPL
static void _EndDemoMode( void );
static void _DemoModeWork( void );
static void _DemoModeDraw( void );
static BOOL _InitCreditsMode( u32 nTrack, char *pszObName, u16 nScriptIndex );
static void _CreditsModeWork( void );
static void _CreditsModeDraw( void );
static BOOL _LoadScriptFile( u16 nScriptIndex );
static void _DoScriptCommands( u32 nFrameNum );
static void _ConvertAngleLengthHeight2Vec3( f32 fAngle, f32 fLength, f32 fHeight, Vec3_t *pResult );
static void _OverLayLoad( void );
static void _OverLayToggle( BOOL bEnable, u32 nTextCode, u32 nTargetBoat, u32 nTrackNum, f32 fSpeed );
static void _OverLayWork( void );
static void _OverLayDraw( void );
static Mesh3d_t *_GetMeshForThisLetter( u8 nChar );
static void _SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad( void );
#if _SPIT_DEBUG_INFO_OUT_TO_A_FILE
static void _RecordDebugInfo2AFile( BOOL bBefore );
#endif
/*=================*/
/* public functions*/
BOOL wpr_attract_ModuleInit( void ) {
return TRUE;
}
/* Call when you would like to make wpr_attract the active wrapper module*/
/* loads up no artwork but resets all variables to their default values.*/
/* only needs to be called once at the beginning of attract mode*/
void wpr_attract_Init( void ) {
/* Select our special "saved-off" attract mode physdata dataset...*/
physdata_SetDataset( _PHYSDATASET_ATTRACT, FALSE );
/* enable powerups to be collected during the attract mode by the ai*/
powerup_EnableAiCollection( TRUE );
/* this is a kludge so that ai boats can pick up powerups*/
Hud_nState = HUD_GO;
_bLoadOk = FALSE;
_bActive = FALSE;
_nCoinUpdateISRState = 0;
_StageNum = WPR_ATTRACT_ENTER;
/* clear out all old memory*/
wpr_memmgr_FreeNonCommonStuff();
_pCurStaticScreen = NULL;
_nFrameCount = 0;
_pJoin1 = _pJoin2 = NULL;
_nLoopCounter = 0;
controls_TurnAllLightsOff();
}
/* call before leaving the attract module*/
void wpr_attract_Close( void ) {
_bLoadOk = FALSE;
_nCoinUpdateISRState = 0;
_EndDemoMode();
/* disable powerup collection by ai boats*/
powerup_EnableAiCollection( FALSE );
/* Make sure master physdata dataset is selected!!!!!!!*/
physdata_SetDataset( 0, FALSE );
_nLoopCounter = 0;
_bScrollCredits = FALSE;
}
/* loads a particular stage of attract mode, if we are loading*/
/* a static stage we release all allocated memory first, if we are*/
/* loading an active stage we will simply load the stage and not*/
/* free any memory. ( if we are loading an Active, we will use*/
/* the obsys abort system )*/
/* if the load fails, we will use the old text based system*/
/* Returns FALSE if obsys was aborted by a purchased game, */
/* TRUE if all other cases*/
BOOL wpr_attract_LoadStage( WprAttractStage_t StageNum ) {
char szObName[OBJECT_NAME_LENGTH+1];
BOOL bLastObsysState, bObsysAborted;
#if TARGET==ULTRA64
u32 TexAddr;
#endif /*ULTRA64*/
XASSERT( StageNum < WPR_ATTRACT_STAGE_COUNT );
_nR = _StageInfo[StageNum].nR;
_nG = _StageInfo[StageNum].nG;
_nB = _StageInfo[StageNum].nB;
_bLoadOk = FALSE;
/* if the requested load is not active, free all memory and then load our screen*/
if( !(_StageInfo[StageNum].nFlags & _FLAG_ACTIVE) ) {
_EndDemoMode();
_DemoModeLoaded = FALSE;
wpr_memmgr_FreeNonCommonStuff();
// dcEnableCDCaching(FALSE);
// r2file_OpenForRead("hydrodc.r2");
_pCurStaticScreen = obsys_Load( _StageInfo[StageNum].pszObName );
if( _pCurStaticScreen ) {
#if TARGET==ULTRA64 /* Blit logo screen */
/* Make sprite palette/swap bytes */
TexAddr = grTexMinAddress(0);
_pCurStaticScreen = blit_N64CreateRaw(&TexAddr,_pCurStaticScreen, 512-32-32,240-16-16);
#endif /*ULTRA64*/
_bLoadOk = TRUE;
}
} else {
/* the the requested load is active, just load it and don't free any memory*/
if( _StageInfo[StageNum].nFlags & _FLAG_TRACKDEMO ) {
_nFrameCount = 0;
bLastObsysState = obsys_EnableLoadAbort( TRUE );
_nCoinUpdateISRState = _FLAG_LOADING_LARGE_DEMO_LEVEL;
// StageNum = WPR_ATTRACT_ARCTIC_2; // DPL
_bLoadOk = _InitDemoMode( _StageInfo[StageNum].nParm1, _StageInfo[StageNum].pszObName,
_StageInfo[StageNum].nParm2, _StageInfo[StageNum].nParm3, _StageInfo[StageNum].nParm5 ,StageNum);
_nCoinUpdateISRState = 0;
bObsysAborted = obsys_WasLastLoadAborted();
mesh3d_ResetCache();
obsys_EnableLoadAbort( bLastObsysState );
if( bObsysAborted ) {
/* our load was aborted, return false so the the calling function can handle this*/
_EndDemoMode();
return FALSE;
}
} else if( _StageInfo[StageNum].nFlags & _FLAG_JOIN_GAME ) {
/* this is a special case, it is not really active, but treat it as if it were*/
_EndDemoMode();
wpr_memmgr_FreeNonCommonStuff();
_nFrameCount = 0;
_pJoin1 = obsys_Load( _StageInfo[StageNum].pszObName );
xclib_strcpy( szObName, _StageInfo[StageNum].pszObName );
szObName[9] = '2';
_pJoin2 = obsys_Load( szObName );
if( _pJoin1 && _pJoin2 ) {
_bLoadOk = TRUE;
}
} else if( _StageInfo[StageNum].nFlags & _FLAG_CREDITS ) {
_nFrameCount = 0;
bLastObsysState = obsys_EnableLoadAbort( TRUE );
_nCoinUpdateISRState = _FLAG_LOADING_LARGE_DEMO_LEVEL;
_bLoadOk = _InitCreditsMode( _StageInfo[StageNum].nParm1, _StageInfo[StageNum].pszObName, _StageInfo[StageNum].nParm5 );
_nCoinUpdateISRState = 0;
bObsysAborted = obsys_WasLastLoadAborted();
mesh3d_ResetCache();
obsys_EnableLoadAbort( bLastObsysState );
if( bObsysAborted ) {
/* our load was aborted, return false so the the calling function can handle this*/
_EndDemoMode();
return FALSE;
}
}
}
return TRUE;
}
/* returns the current stage that attract mode is in*/
WprAttractStage_t wpr_attract_GetCurrentStage( void ) {
return _StageNum;
}
/* returns the next stage that should be loaded, active or not*/
WprAttractStage_t wpr_attract_GetNextStage( void ) {
return ( _StageInfo[_StageNum].nNextStage );
}
/* returns the number of the next ACTIVE stage*/
WprAttractStage_t wpr_attract_GetNextActiveStage() {
return ( _StageInfo[_StageNum].nNextActiveStage );
}
/* set the current stage*/
void wpr_attract_SetCurrentStage( WprAttractStage_t StageNum ) {
XASSERT( StageNum < WPR_ATTRACT_STAGE_COUNT );
_StageNum = StageNum;
_bActive = wpr_attract_IsCurrentStageActive();
/* if we are at the first stage log in with the auditor*/
if( StageNum == WPR_ATTRACT_ENTER || StageNum == WPR_ATTRACT_MIDWAY_LOGO_1 ) {
++_nLoopCounter;
if( (_nLoopCounter % 13) == 12 ) {
auditor_LogAttractModeEvent();
audits_PeriodicAttractModeUpdate();
}
}
}
/* returns 0 if no sound should be played, */
u32 wpr_attract_ShouldWeStartMusicForThisSegment( WprAttractStage_t StageNum ) {
if( _StageInfo[StageNum].nParm4 == 0 ) {
return 0;
} else {
if( StageNum == WPR_ATTRACT_CREDITS ) {
/* the credits screen has a special piece of music*/
return SOUNDCALL_WRAP_ATTRACT_MUSIC2;
} else {
return WPR_DEFS_ATTRACT_MUSIC;
}
}
}
/* tells us whether we are currently in an active or static stage*/
BOOL wpr_attract_IsCurrentStageActive( void ) {
return ( _StageInfo[_StageNum].nFlags & _FLAG_ACTIVE );
}
void wpr_attract_Work( void ) {
/* there is only work to do if we were able to load everything that we needed*/
if( _bLoadOk ) {
/* only active screens have work to be done...*/
if( wpr_attract_IsCurrentStageActive() ) {
if( _StageInfo[_StageNum].nFlags & _FLAG_TRACKDEMO ) {
++_nFrameCount;
_DemoModeWork();
} else if( _StageInfo[_StageNum].nFlags & _FLAG_CREDITS ) {
++_nFrameCount;
_CreditsModeWork();
} else {
++_nFrameCount;
}
}
}
}
void wpr_attract_DrawCoinUpdateDuringLargeLoad( void ) {
/* only execute this if we are loading a large level and not currently updating the counter*/
if( _nCoinUpdateISRState & _FLAG_LOADING_LARGE_DEMO_LEVEL ) {
if( !(_nCoinUpdateISRState & _FLAG_UPDATING_COIN_COUNTER) ) {
_nCoinUpdateISRState |= _FLAG_UPDATING_COIN_COUNTER;
}
}
}
void wpr_attract_Draw( f32 fTime ) {
f32 fTimeLimit;
s32 nBlit;
if( !_bLoadOk ) {
_DrawOldTextSystem( fTime );
} else {
/* current stage is not active, just blit the image to the screen*/
if( !wpr_attract_IsCurrentStageActive() ) {
if(_DemoModeLoaded) // Don't do blit if stage loaded (not enough vram left)
return;
#if TARGET==ULTRA64 /* Blit logo screen */
blit_N64Raw(_pCurStaticScreen, 32,16, 512-32-32,240-16-16);
#else /*ULTRA64*/
nBlit = blit_CreateTexture(_pCurStaticScreen - 4);
if(nBlit == -1)
return;
blit_Dreamcast(nBlit, _pCurStaticScreen - 4, 0, 0);
blit_FreeBlitTextures();
#endif /*ULTRA64*/
} else { /* the current stage is active...*/
if( _StageInfo[_StageNum].nFlags & _FLAG_TRACKDEMO ) {
_DemoModeDraw();
if( fTime <= 0.40f ) {
fTime *= (1.0f/0.40f);
gutil_DrawBlackOrWhiteScreenFade( 1.0f - fTime, TRUE );
} else {
fTimeLimit = (f32)( wpr_attract_GetCurrentStageTimeLimit() * (1.0f/60.0f) );
fTimeLimit -= fTime;
if( fTimeLimit < 0.0f ) {
fTimeLimit = 0.0f;
}
if( fTimeLimit <= 0.40f ) {
fTimeLimit *= (1.0f/0.40f);
gutil_DrawBlackOrWhiteScreenFade( 1.0f - fTimeLimit, TRUE );
}
}
} else if( _StageInfo[_StageNum].nFlags &_FLAG_JOIN_GAME ) {
/* we are displaying the "join network game" screen*/
if( (_nFrameCount & 0x1F) <= 20 ) {
blit_Raw( _pJoin1-sizeof(u32), 0, 0 );
} else {
blit_Raw( _pJoin2-sizeof(u32), 0, 0 );
}
} else if( _StageInfo[_StageNum].nFlags & _FLAG_CREDITS ) {
/* clear the frame buffer...*/
gutil_ClearFrameBuffer3( _nR, _nG, _nB );
_CreditsModeDraw();
if( fTime <= 0.40f ) {
fTime *= (1.0f/0.40f);
gutil_DrawBlackOrWhiteScreenFade( 1.0f - fTime, TRUE );
} else {
fTimeLimit = (f32)( wpr_attract_GetCurrentStageTimeLimit() * (1.0f/60.0f) );
fTimeLimit -= fTime;
if( fTimeLimit < 0.0f ) {
fTimeLimit = 0.0f;
}
if( fTimeLimit <= 0.40f ) {
fTimeLimit *= (1.0f/0.40f);
gutil_DrawBlackOrWhiteScreenFade( 1.0f - fTimeLimit, TRUE );
}
}
} else {
/* clear the frame buffer...*/
gutil_ClearFrameBuffer3( _nR, _nG, _nB );
}
}
}
}
u32 wpr_attract_GetCurrentStageTimeLimit( void ) {
return ( _StageInfo[_StageNum].nTimeInStage );
}
/* will unload any memory, load the first attract stage,*/
/* set it as the current stage. This can be called from */
/* any attract stage*/
void wpr_attract_ResetToFirstStage( void ) {
wpr_attract_LoadStage( WPR_ATTRACT_ENTER );
wpr_attract_SetCurrentStage( WPR_ATTRACT_ENTER );
}
/*==================*/
/* private functions*/
static void _DrawOldTextSystem( f32 fTime ) {
/* clear the frame buffer*/
gutil_ClearFrameBuffer3( _nR, _nG, _nB );
/* for join mode, draw something a little different*/
if( _StageNum == WPR_ATTRACT_JOIN ) {
text_SetFont( TEXT_FONT_LARGE );
Text_fScale = 1.25f;
text_PrintStr( 75.0f, 150.0f, "Join Network Game\n" );
Text_fScale = 1.0f;
} else { /* all other stages...*/
/* draw the stage number*/
text_SetFont( TEXT_FONT_LARGE );
Text_fScale = 1.20f;
text_PrintStr( 25.0f, 15.0f, "ATTRACT MODE\n" );
Text_fScale = 1.0f;
text_PrintF( 25.0f, 75.0f, "Stage number %d\n", _StageNum );
/* if this is an active page go ahead and print the time*/
if( _bActive ) {
text_SetFont( TEXT_FONT_SMALL );
text_PrintF( 25.0f, 110.0f, "Time (secs) %f\n", fTime );
} else {
text_SetFont( TEXT_FONT_SMALL );
text_PrintStr( 25.0f, 110.0f, "Static screen here.\n" );
text_PrintStr( 25.0f, 145.0f, "Waiting to sync up.\n" );
}
}
}
static BOOL _InitDemoMode( u32 nTrack, char *pszObName, u16 nStartPosOffset, u16 nAiOffSet, u16 nScriptIndex , u32 StageNum) {
u32 i;
_DemoModeLoaded = FALSE;
#if _ATTRACT_FILE_LOGGING_ON
switch(StageNum){
case WPR_ATTRACT_LAKE_POWELL_1:
dcStartFileLogging("pwlatt1.txt");
break;
case WPR_ATTRACT_LAKE_POWELL_2:
dcStartFileLogging("pwlatt2.txt");
break;
case WPR_ATTRACT_ARCTIC_1:
dcStartFileLogging("artatt1.txt");
break;
case WPR_ATTRACT_ARCTIC_2:
dcStartFileLogging("artatt2.txt");
break;
default:
while(1);
}
#else
// dcEnableCDCaching(FALSE);
// r2file_OpenForRead("hydrodc.r2");
switch(StageNum){
case WPR_ATTRACT_LAKE_POWELL_1:
obsys_LoadR2Objects("pwlatt1.r2");
break;
case WPR_ATTRACT_LAKE_POWELL_2:
obsys_LoadR2Objects("pwlatt2.r2");
break;
case WPR_ATTRACT_ARCTIC_1:
obsys_LoadR2Objects("artatt1.r2");
break;
case WPR_ATTRACT_ARCTIC_2:
obsys_LoadR2Objects("artatt2.r2");
break;
default:
while(1);
}
#endif
/* set our random seed for attract mode*/
race_SeedRandom( 1.0f );
/* set our track and timing values*/
tracks_SetCurrentTrack( nTrack, 0 );
/* Turn off fog*/
fog_Enable( FALSE );
gutil_ScreenCoverage_ResetTotal();
gutil_ScreenCoverage_SetLimit( _MAX_SCREEN_AREA_SUM );
/* Flag to draw water...*/
water_EnableCalc( TRUE );
water_EnableDraw( TRUE );
/* reset our player array to the defaults*/
for( i=0; i < _NUM_ATTRACT_RACERS; i++ ) {
xclib_MemSet( &Player_aData[i], 0, sizeof( Player_t ) );
Player_aData[i].nId = i;
Player_aData[i].nPlace = i+1;
Player_aData[i].nEarnedStartPlace = i+1;
controls_ZeroControlStruct( &Player_aData[i].Controls );
powerup_ResetBooster( &Player_aData[i].Powerup );
}
controls_ZeroControlStruct( &_HumanControls );
/* set the number of human racers*/
Player_nHumanCount = 0;
/* set the number of ai racers*/
Player_nAiCount = _NUM_ATTRACT_RACERS;
/* set the total number of racers*/
Player_nTotalCount = Player_nHumanCount + Player_nAiCount;
/* set up our active player pointers array*/
for(i=0; i<Player_nTotalCount; i++) {
Player_apData[i] = &Player_aData[i];
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
gameloop_ResetCounter();
xfm_Reset();
particle_ResetSystem();
tripwire_Reset();
objectid_Reset();
fx_ResetSystem();
fx_splash_ResetSystem();
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
fx_splash_InitSystem();
fx_particles_ResetSystem();
fx_particles_InitSystem();
world_SetWhiteSat( 0.0f );
sky_SetWhiteSat( 0.0f );
ai_craft_Reset();
ai_rabbit_InitDemoMode();
physcoll_ResetSystem();
cam_mgr_ResetSystem();
if( waterspray_InitSystem( _MAX_SPRAY_PARTICLES ) == 0 ) {
XASSERT_NOW;
}
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* Load all objects including track...*/
tracks_LoadWaterTextures( Tracks_nCurrentTrack,TRUE ); /*PAB ULTRA64 Fade water */
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
terrain_Load( pszObName, &CurWorld );
if( !CurWorld.pWorld ) {
return FALSE;
}
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* attach the loaded track*/
terrain_Attach( &CurWorld );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* SSP - fill in angle values for each path edge*/
paths_CalcEdgeAngles( World_pWorld->pPathEdge, World_pWorld->nPathEdges );
/* SSP - check for wrong null pointers problem*/
paths_FixWrongNullPointers( World_pWorld->pPathSector, World_pWorld->nPathSectors );
/* SSP - set our path sector data from the world that was just loaded*/
paths_TrackPathSet( World_pWorld->pPathSector, World_pWorld->nPathSectors, 0 );
terrain_LoadObjects( objectid_Process );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
terrain_LoadWaterfalls();
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
terrain_LoadFx();
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
_OverLayLoad();
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
sky_LoadSkyForATrack( TRUE );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* Init stuff...*/
/* setup boat types and pole positions*/
ai_player_SetPolePositionsAndBoatTypes( AI_PLAYER_BOAT_ORDER_LIST_DEMO, nAiOffSet );
for( i=0; i < _NUM_ATTRACT_RACERS; i++ ) {
boats_Init( Player_aData[i].nBoatType, BOATS_LOD_HIGH, i, &Player_aData[i], nStartPosOffset );
Player_aData[i].Phys.nControlFlags &= ~PHYS_CONTROLFLAG_STARTINGLINE_321GO;
/* turn off boat sounds*/
Player_aData[i].Phys.nControlFlags |= PHYS_CONTROLFLAG_SILENT;
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
}
ai_player_Init();
anim_fish_LoadTanksForATrack( Tracks_nCurrentTrack );
anim_land_InitTerrainJumps( World_pMesh );
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* we update our rank here so that it is correct for the first time we run race_Work()*/
player_InitPathSectorStuff();
player_UpdateRank();
/* load our script file for this level*/
if( !_LoadScriptFile( nScriptIndex ) ) {
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
#if _ATTRACT_FILE_LOGGING_ON
dcStopFileLogging();
#else
dcEnableCDCaching(FALSE);
r2file_OpenForRead("hydrodc.r2");
#endif
if(StageNum == WPR_ATTRACT_LAKE_POWELL_1 || WPR_ATTRACT_LAKE_POWELL_2)
dcEnableFog(FALSE);
else
dcEnableFog(TRUE);
_DemoModeLoaded = TRUE;
return TRUE;
}
static void _EndDemoMode( void ) {
controls_TurnLightsOff( CONTROLS_ALL_VIEW_LIGHTS );
phys_FreeAll();
particle_ResetSystem();
fx_ResetSystem();
fx_splash_ResetSystem();
fx_particles_ResetSystem();
/* Turn off water*/
water_EnableCalc( FALSE );
water_EnableDraw( FALSE );
/* resets the path sector system*/
paths_TrackPathClear();
/* Turn off fog*/
fog_Enable( FALSE );
world_SetWhiteSat( 0.0f );
sky_SetWhiteSat( 0.0f );
cam_mgr_ResetSystem();
/* turn off any overlaid text*/
_OverLayToggle( FALSE, 0, 0, 0, 0.0f );
text_ReleaseFont( TEXT_FONT_USER_COLORED_HUD2 );
_bScrollCredits = FALSE;
}
static void _DemoModeWork( void ) {
u32 i;
controls_CopyControlStruct( &Player_aData[Player_nHuman].Controls, &_HumanControls );
ai_player_Work();
controls_CopyControlStruct( &_HumanControls, &Player_aData[Player_nHuman].Controls );
for( i=0; i < _NUM_ATTRACT_RACERS; i++ ) {
/* Set physics input parameters...*/
Player_aData[i].Phys.fSteer = Player_aData[i].Controls.fWithDeadZone[CONTROLS_WHEEL];
Player_aData[i].Phys.fSteerNoDeadZone = Player_aData[i].Controls.fNoDeadZone[CONTROLS_WHEEL]; /* SER: Added 980923*/
Player_aData[i].Phys.fThrottle = Player_aData[i].Controls.fWithDeadZone[CONTROLS_THROTTLE];
Player_aData[i].Phys.bHydroBoostersOn = (Player_aData[i].Controls.nButtons & CONTROLS_THROTTLE_BUTTON) ? TRUE : FALSE;
}
#if _SPIT_DEBUG_INFO_OUT_TO_A_FILE
_RecordDebugInfo2AFile( TRUE );
#endif
/* Move and collide all boats...*/
phys_SimulateAll();
#if _SPIT_DEBUG_INFO_OUT_TO_A_FILE
_RecordDebugInfo2AFile( FALSE );
#endif
/* Update speedometer and tachometer...*/
for( i=0; i < _NUM_ATTRACT_RACERS; i++ ) {
Player_aData[i].fSpeedMph = Player_aData[i].Phys.fSpeedMPH;
Player_aData[i].fRPM = Player_aData[i].Phys.fPropRPM * 10000.0f;
}
worldob_CallAllWorkFcns( Gameloop_nDeltaFrames , Gameloop_n2xFrameCounter);
worldcoll_Work();
/* 7) Update camera position and orientation.*/
_DoScriptCommands( _nFrameCount );
/* 8) Update particles.*/
particle_CallWorkFunctions();
particle_CallCellBlocksWorkFunctions();
waterspray_Work();
/* 9) Update water effects (rooster tails, wakes, wave objects, etc.).*/
/* 10) Transform object lights from model-space to world-space.*/
worldob_TransformAllObjectLights();
/* 11) Update player positions...*/
player_UpdateRank();
phys_Work();
/* slide texture coordinates on jumps, arrow signs, and checkpts*/
anim_land_ScrollJumpsAndArrowSigns();
anim_water_ScrollChkPtsAndFloatingArrowSigns();
}
static void _DemoModeDraw( void ) {
BOOL bPriorFogState;
Vec3_t CamPos;
fog_Enable( FALSE ); /* Turn off fog*/
gutil_ScreenCoverage_ResetTotal();
world_SetWhiteSat( anim_air_GetLensFlareWhiteSat() );
mesh3d_ClearLightList();
anim_air_Lightning();
cam_mgr_GetLastCamPos( &CamPos );
if( !world_SetFog( Gamecam_pSector, CamPos.p[0], CamPos.p[2] ) ) {
/* Don't fog sky...*/
bPriorFogState = fog_Enable( FALSE );
} else {
/* Fog sky...*/
bPriorFogState = fog_GetEnableState();
}
cam_mgr_SetUpCurrentCam();
sky_SetWhiteSat( anim_air_GetLensFlareWhiteSat() );
sky_Draw ();
fog_Enable( bPriorFogState );
world_DrawSectorViewDir( Gamecam_pSector, SECTOR_DIRECTION_FORWARD, FALSE ); /*PAB*/
fog_Enable( FALSE );
anim_air_DoLensFlare();
_OverLayDraw();
}
static BOOL _InitCreditsMode( u32 nTrack, char *pszObName, u16 nScriptIndex ) {
XASSERT( nTrack < TRACKS_COUNT );
race_SeedRandom( 1.0f );
tracks_SetCurrentTrack( nTrack, 0 );
fog_Enable( FALSE );
gutil_ScreenCoverage_ResetTotal();
gutil_ScreenCoverage_SetLimit( _MAX_SCREEN_AREA_SUM );
water_EnableCalc( TRUE );
water_EnableDraw( TRUE );
gameloop_ResetCounter();
xfm_Reset();
particle_ResetSystem();
tripwire_Reset();
objectid_Reset();
world_SetWhiteSat( 0.0f );
ai_craft_Reset();
cam_mgr_ResetSystem();
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* Load all objects including track...*/
tracks_LoadWaterTextures( Tracks_nCurrentTrack,TRUE ); /*PAB ULTRA64 Fade water */
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
terrain_Load( pszObName, &CurWorld );
if( !CurWorld.pWorld ) {
return FALSE;
}
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
/* attach the loaded track*/
terrain_Attach( &CurWorld );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
terrain_LoadObjects( objectid_Process );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
text_LoadFont( TEXT_FONT_USER_COLORED_HUD2 );
if( obsys_WasLastLoadAborted() ) {
/* make sure that we have not gotten a button interupt*/
return FALSE;
}
anim_fish_LoadTanksForATrack( Tracks_nCurrentTrack );
if( !_LoadScriptFile( nScriptIndex ) ) {
return FALSE;
}
_SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad();
return TRUE;
}
static void _CreditsModeWork( void ) {
worldob_CallAllWorkFcns( Gameloop_nDeltaFrames , Gameloop_n2xFrameCounter);
_DoScriptCommands( _nFrameCount );
worldob_TransformAllObjectLights();
if( _bScrollCredits ) {
if( _fScrollLastY > (Viewport_half_vres_f + 100.0f) ) {
_fScrollFirstY -= _fScrollSpeed;
_fScrollLastY -= _fScrollSpeed;
XMATH_CLAMPMIN( _fScrollLastY, Viewport_half_vres_f );
}
}
}
static void _CreditsModeDraw( void ) {
u32 i, j;
f32 fY;
BOOL bPriorFogState;
Vec3_t CamPos;
fog_Enable( FALSE );
gutil_ScreenCoverage_ResetTotal();
mesh3d_ClearLightList();
cam_mgr_GetLastCamPos( &CamPos );
if( !world_SetFog( Gamecam_pSector, CamPos.p[0], CamPos.p[2] ) ) {
/* Don't fog sky...*/
bPriorFogState = fog_Enable( FALSE );
} else {
/* Fog sky...*/
bPriorFogState = fog_GetEnableState();
}
cam_mgr_SetUpCurrentCam();
fog_Enable( bPriorFogState );
world_DrawSectorViewDir( Gamecam_pSector, SECTOR_DIRECTION_FORWARD, FALSE ); /*PAB*/
fog_Enable( FALSE );
if( _bScrollCredits ) {
text_SetFont( TEXT_FONT_USER_COLORED_HUD2 );
text_SetStyle( FSTYLE_CENTER | FSTYLE_PITCHED );
i = _NUM_CREDIT_LINES;
fY = _fScrollFirstY;
j = 0;
for( i=1; i < _NUM_CREDIT_LINES; i++ ) {
if( _pszCreditList[i] ) {
if( fY > -25.0f && fY < (Viewport_vres_f + 25.0f) ) {
if( _pszCreditList[i-1] ) {
/* not a section heading, color this way*/
switch( i )
{
case 73:
case (_NUM_CREDIT_LINES-7):
case (_NUM_CREDIT_LINES-8):
case (_NUM_CREDIT_LINES-9):
text_SetConstantColor( 0, 255, 255, 255 );
break;
default:
/*text_SetConstantColor( 0, 0, 128, 200 );*/
text_SetConstantColor( 0, 0, 255, 100 );
break;
}
Text_fScale = 0.35f;
} else {
/* section heading, color this way*/
text_SetConstantColor( 0, 255, 255, 255 );
Text_fScale = 0.40f;
}
#if TARGET==DREAMCAST
text_PrintStr( 256.0f, fY, (char *)_pszCreditList[i] );
#else // DREAMCAST
text_PrintStr( Viewport_half_hres_f, fY, (char *)_pszCreditList[i] );
#endif // DREAMCAST
++j;
if( j == 5 ) {
/* flush the text buffer every 4 lines or so*/
j = 0;
text_Flush();
}
}
}
fY += _CREDIT_SPACING;
}
}
}
static BOOL _LoadScriptFile( u16 nScriptIndex ) {
void *pSysmemFrame;
ObsysFrame_t ObsysFrame;
char szUpperIdString[_DEMO_SCRIPT_COMMAND_LENGTH + 1];
u32 i, j, nFrameNum;
DemoRecord_t *pRecord;
ScriptCommands_t *pScriptCommand;
void *pPtr;
/* set to the default values*/
_pFirstCommand = NULL;
_pLoadedFile = NULL;
_nNumCommands = 0;
_nCurrentCommand = 0;
/* Get a memory frames...*/
pSysmemFrame = sysmem_StartFrame();
ObsysFrame = obsys_StartFrame();
/* load our script file for this particular attract mode stage*/
switch( nScriptIndex )
{
case 0:
/* powell 1*/
pPtr = obsys_Load( "D2WDEMOSRH0" );
break;
case 1:
/* artic 1*/
pPtr = obsys_Load( "D1WDEMOSRH0" );
break;
case 2:
/* amazon 1*/
pPtr = obsys_Load( "D3WDEMOSRH0" );
break;
case 3:
/* powell 2*/
pPtr = obsys_Load( "D2WDEMOSRH1" );
break;
case 4:
/* artic 2*/
pPtr = obsys_Load( "D1WDEMOSRH1" );
break;
case 5:
/* amazon 2*/
pPtr = obsys_Load( "D3WDEMOSRH1" );
break;
case 6:
/* credits*/
pPtr = obsys_Load( "DWWCREDSRH0" );
break;
default:
pPtr = NULL;
break;
}
if( !pPtr ) {
/* couldn't load our script file*/
goto ERROR;
}
_pLoadedFile = (HcompDemoScriptDef_t *)( (u32)pPtr - sizeof( u32 ) );
_nNumCommands = _pLoadedFile->nRecordCount;
if( !_nNumCommands ) {
/* no records available*/
goto ERROR;
}
pRecord = (DemoRecord_t *)( (u32)_pLoadedFile + sizeof( HcompDemoScriptDef_t ) );
/* allocate the needed memory for all of these commands*/
_pFirstCommand = (Commands_t *)SYSMEM_ALLOC( sizeof( Commands_t ) * _nNumCommands );
if( !_pFirstCommand ) {
/* couldn't allocate enough memory*/
goto ERROR;
}
nFrameNum = 1;
for( i=0; i < _nNumCommands; i++ ) {
/* convert our string to all uppercase*/
xclib_strcpy( szUpperIdString, pRecord->acCommand );
xclib_StringUpper( szUpperIdString );
/* make sure that we have a valid string command*/
for( j=0; j < NUM_DEMO_COMMANDS; j++ ) {
pScriptCommand = &_aCommandInfoLookup[j];
if( !xclib_stricmp( szUpperIdString, pScriptCommand->aszCommandName ) ) {
break;
}
}
if( j >= NUM_DEMO_COMMANDS ) {
/* this command string did not match our list of commands*/
xprintferr( "UNKNOWN COMMAND IN ATTRACT SCRIPT, CHECK LINE NUMBER %d\n", pRecord->nLineNum );
goto ERROR;
break;
}
/* make sure that we have the correct number of parameters for this command*/
if( pScriptCommand->nNumParameters != pRecord->nNumParameters ) {
/* this command had the wrong number of parameters for this command*/
xprintferr( "ATTRACT SCRIPT LINE %d HAS %d PARAMETERS, IT SHOULD HAVE %d\n",
pRecord->nLineNum, pRecord->nNumParameters, pScriptCommand->nNumParameters );
goto ERROR;
break;
}
/* fill in our command info */
_pFirstCommand[i].pScriptEntry = pScriptCommand;
_pFirstCommand[i].pfParameters = (f32 *)( (u32)pRecord + sizeof( DemoRecord_t ) );
nFrameNum += (u32)pRecord->fDeltaFrames;
_pFirstCommand[i].nFrameNumber = nFrameNum;
_pFirstCommand[i].nActionCode = pScriptCommand->nCommandCode;
/* advance our record ptr*/
pRecord = (DemoRecord_t *)( (u32)pRecord + sizeof( DemoRecord_t ) + ( sizeof( f32 ) * pRecord->nNumParameters ) );
}
return TRUE;
ERROR:
/* an error occured, free our memory*/
sysmem_ReleaseFrame( pSysmemFrame );
obsys_ReleaseFrame( ObsysFrame );
_pFirstCommand = NULL;
_pLoadedFile = NULL;
_nNumCommands = 0;
_nCurrentCommand = 0;
return FALSE;
}
static void _DoScriptCommands( u32 nFrameNum ) {
Commands_t *pCommand;
u32 nSourceBoatNum, nTargetBoatNum, n1stObNum, nFOV, n2ndObNum, nFrames, nTrackNum;
s32 nHeading, nPitch, nRoll, nDegrees;
BOOL bRotateByHeading, bDoCameraWork = TRUE, bEnable;
Vec3_t BodySpace;
f32 fSpeed;
pCommand = &_pFirstCommand[_nCurrentCommand];
while( (_nCurrentCommand < _nNumCommands) && (pCommand->nFrameNumber == nFrameNum) )
{
switch( pCommand->nActionCode )
{
case CAM_MGR_GAME_CAM1:
nTargetBoatNum = (u32)pCommand->pfParameters[0];
cam_mgr_InitGameCamToPlayer( nTargetBoatNum, GAMECAM_VIEW_NOBOAT );
bDoCameraWork = FALSE;
break;
case CAM_MGR_GAME_CAM2:
nTargetBoatNum = (u32)pCommand->pfParameters[0];
cam_mgr_InitGameCamToPlayer( nTargetBoatNum, GAMECAM_VIEW_LOW );
bDoCameraWork = FALSE;
break;
case CAM_MGR_GAME_CAM3:
nTargetBoatNum = (u32)pCommand->pfParameters[0];
cam_mgr_InitGameCamToPlayer( nTargetBoatNum, GAMECAM_VIEW_HIGH );
bDoCameraWork = FALSE;
break;
case CAM_MGR_ESPN_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
nTargetBoatNum = (u32)pCommand->pfParameters[1];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[2] );
cam_mgr_InitEspnCamFromOb( n1stObNum, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_STATIONARY_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[1] );
cam_mgr_InitStationaryCam( n1stObNum, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_MOUNTED_CAM:
nSourceBoatNum = (u32)pCommand->pfParameters[0];
_ConvertAngleLengthHeight2Vec3( pCommand->pfParameters[1], pCommand->pfParameters[2], pCommand->pfParameters[3], &BodySpace );
nHeading = (s32)( pCommand->pfParameters[4] * 182.0416666667f );
nPitch = (s32)(pCommand->pfParameters[5] * 182.0416666667f );
nRoll = (s32)(pCommand->pfParameters[6] * 182.0416666667f );
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[7] );
cam_mgr_InitMountedCam( nSourceBoatNum, &BodySpace, nHeading, nPitch, nRoll, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_SWIVEL_MOUNTED_CAM:
nSourceBoatNum = (u32)pCommand->pfParameters[0];
_ConvertAngleLengthHeight2Vec3( pCommand->pfParameters[1], pCommand->pfParameters[2], pCommand->pfParameters[3], &BodySpace );
nHeading = (s32)( pCommand->pfParameters[4] * 182.0416666667f );
nPitch = (s32)(pCommand->pfParameters[5] * 182.0416666667f );
nRoll = (s32)(pCommand->pfParameters[6] * 182.0416666667f );
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[7] );
cam_mgr_InitSwivelMountCam( nSourceBoatNum, &BodySpace, nHeading, nPitch, nRoll, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_MOUNTED_TARGET_CAM:
nSourceBoatNum = (u32)pCommand->pfParameters[0];
_ConvertAngleLengthHeight2Vec3( pCommand->pfParameters[1], pCommand->pfParameters[2], pCommand->pfParameters[3], &BodySpace );
nTargetBoatNum = (u32)pCommand->pfParameters[4];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[5] );
cam_mgr_InitMountedTargetCam( nSourceBoatNum, &BodySpace, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_SWIVEL_MOUNTED_TARGET_CAM:
nSourceBoatNum = (u32)pCommand->pfParameters[0];
_ConvertAngleLengthHeight2Vec3( pCommand->pfParameters[1], pCommand->pfParameters[2], pCommand->pfParameters[3], &BodySpace );
nTargetBoatNum = (u32)pCommand->pfParameters[4];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[5] );
cam_mgr_InitSwivelMountTargetCam( nSourceBoatNum, &BodySpace, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_CIRCLE_CAM:
nSourceBoatNum = (u32)pCommand->pfParameters[0];
_ConvertAngleLengthHeight2Vec3( pCommand->pfParameters[1], pCommand->pfParameters[2], pCommand->pfParameters[3], &BodySpace );
nDegrees = (s32)( pCommand->pfParameters[4] * 182.0416666667f );
bRotateByHeading = ( pCommand->pfParameters[5] == 0.0f ) ? FALSE : TRUE;
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[6] );
cam_mgr_InitCirclingCam( nSourceBoatNum, &BodySpace, nDegrees, bRotateByHeading, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_CHASE_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
nTargetBoatNum = (u32)pCommand->pfParameters[1];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[5] );
cam_mgr_InitChaseCam( n1stObNum, nTargetBoatNum, pCommand->pfParameters[2], pCommand->pfParameters[3], pCommand->pfParameters[4], nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_PANORAMA_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[1] );
cam_mgr_InitPanoramaCam( n1stObNum, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_DOLLY_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
n2ndObNum = (u32)pCommand->pfParameters[1] - 1;
nFrames = (u32)pCommand->pfParameters[2];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[3] );
cam_mgr_InitDollyCam( n1stObNum, n2ndObNum, nFrames, nFOV );
bDoCameraWork = FALSE;
break;
case CAM_MGR_DOLLY_TARGET_CAM:
n1stObNum = (u32)pCommand->pfParameters[0] - 1;
n2ndObNum = (u32)pCommand->pfParameters[1] - 1;
nFrames = (u32)pCommand->pfParameters[2];
nTargetBoatNum = (u32)pCommand->pfParameters[3];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[4] );
cam_mgr_InitDollyTargetCam( n1stObNum, n2ndObNum, nFrames, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case ESPN_FROM_POINT:
vec3_Set( &BodySpace, pCommand->pfParameters[0], pCommand->pfParameters[1], pCommand->pfParameters[2] );
nTargetBoatNum = (u32)pCommand->pfParameters[3];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[4] );
cam_mgr_InitEspnCamFromVec( &BodySpace, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case ESPN_FROM_CURRENT:
nTargetBoatNum = (u32)pCommand->pfParameters[0];
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[1] );
cam_mgr_GetLastCamPos( &BodySpace );
cam_mgr_InitEspnCamFromVec( &BodySpace, nTargetBoatNum, nFOV );
bDoCameraWork = FALSE;
break;
case DEMO_VIEW_BUTTONS:
bEnable = ( pCommand->pfParameters[0] == 0.0f ) ? FALSE : TRUE;
nTargetBoatNum = (u32)pCommand->pfParameters[1];
_OverLayToggle( bEnable, DEMO_VIEW_BUTTONS, nTargetBoatNum, 0, 0.0f );
bDoCameraWork = FALSE;
break;
case DEMO_HIGH_SCORES:
bEnable = ( pCommand->pfParameters[0] == 0.0f ) ? FALSE : TRUE;
nTrackNum = (u32)pCommand->pfParameters[1];
_OverLayToggle( bEnable, DEMO_HIGH_SCORES, 0, nTrackNum, 0.0f );
break;
case STATIONARY_FROM_CURRENT:
nFOV = XMATH_DEGREES_TO_BRADIANS( pCommand->pfParameters[0] );
n1stObNum = cam_mgr_CreateDummyCameraObFromCurrent( 1 );
cam_mgr_InitStationaryCam( n1stObNum, nFOV );
bDoCameraWork = FALSE;
break;
case DEMO_SCROLL_CREDITS:
bEnable = ( pCommand->pfParameters[0] == 0.0f ) ? FALSE : TRUE;
fSpeed = pCommand->pfParameters[1];
_bScrollCredits = TRUE;
_fScrollSpeed = fSpeed;
_fScrollFirstY = Viewport_vres_f + 25.0f;
_fScrollLastY = _fScrollFirstY + ((_NUM_CREDIT_LINES - 1) * _CREDIT_SPACING);
bDoCameraWork = FALSE;
break;
case DEMO_BLUE_ARROW:
case DEMO_RED_ARROW:
case DEMO_BLUE_BOOST:
case DEMO_RED_BOOST:
case DEMO_THROTTLE:
default:
XASSERT_NOW;
break;
}
++_nCurrentCommand;
pCommand = &_pFirstCommand[_nCurrentCommand];
}
if( bDoCameraWork ) {
cam_mgr_Work();
_OverLayWork();
}
}
static void _ConvertAngleLengthHeight2Vec3( f32 fAngle, f32 fLength, f32 fHeight, Vec3_t *pResult ) {
Vec2_t Temp;
s32 nBradians;
nBradians = XMATH_DEGREES_TO_BRADIANS( fAngle );
vec2_Set( &Temp, 0.0f, fLength );
vec2_RotateBradians( &Temp, nBradians );
vec3_Set( pResult, Temp.p[0], fHeight, Temp.p[1] );
}
static void _OverLayLoad( void ) {
/* load all of our textures*/
if( obsys_LoadGroup( _aLoadTable, FALSE ) != -1 ) {
/* all of the textures could not loaded*/
_bOverLayOk = FALSE;
} else {
/* everything loaded ok*/
_bOverLayOk = TRUE;
_nViewWords = _DO_NOT_DRAW_OVERLAY;
_nCounter = 0;
_bFlashOn = TRUE;
_nOverLayMode = 0;
_nTargetBoat = 0;
_nTrackNum = 0;
_fScrollSpeed = 0.0f;
_fScrollFirstY = 0.0f;
_fScrollLastY = 0.0f;
}
}
static void _OverLayToggle( BOOL bEnable, u32 nTextCode, u32 nTargetBoat, u32 nTrackNum, f32 fSpeed ) {
CmosHiScore_t *pLine;
u32 i, j, nTemp;
s32 nMin, nSecs, nCSecs;
if( !bEnable ) {
/* turn all words off*/
_nViewWords = _DO_NOT_DRAW_OVERLAY;
return;
}
if( !_bOverLayOk ) {
/* system is off*/
return;
}
switch( nTextCode )
{
case DEMO_VIEW_BUTTONS:
/* goes through the hi, low, noboat, low, and high camera views (625 frames)*/
_nViewWords = ICON_VIEW_BUTTON3;
_nCounter = 0;
_bFlashOn = TRUE;
_nTargetBoat = nTargetBoat;
cam_mgr_InitGameCamToPlayer( _nTargetBoat, GAMECAM_VIEW_HIGH );
break;
case DEMO_HIGH_SCORES:
if( nTrackNum >= TRACKS_COUNT ) {
xprintferr( "Error in attract mode script, hi score display track num invalid, using track 0 instead\n" );
nTrackNum = 0;
}
_nCounter = 0;
_nTrackNum = nTrackNum;
_nViewWords = ICON_TRACKNAME_GRAVEYARD + _nTrackNum;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
j = 0;
pLine = &Hi_Score_Table.Table[_nTrackNum][i];
if( i < 9 ) {
_paHighScoreTable[i][j++] = NULL;
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_1 + i];
} else {
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_1];
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0];
}
_paHighScoreTable[i][j++] = NULL;
_paHighScoreTable[i][j++] = _GetMeshForThisLetter( pLine->cInitials[0] );
_paHighScoreTable[i][j++] = _GetMeshForThisLetter( pLine->cInitials[1] );
_paHighScoreTable[i][j++] = _GetMeshForThisLetter( pLine->cInitials[2] );
_paHighScoreTable[i][j++] = NULL;
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_BANSHEE + pLine->nBoat];
_paHighScoreTable[i][j++] = NULL;
xmath_ConvertAFloatSecs2NumOfMinSecCSec( pLine->fTime, &nMin, &nSecs, &nCSecs );
XMATH_CLAMPMAX( nMin, 99 );
XMATH_CLAMPMAX( nSecs, 59 );
XMATH_CLAMPMAX( nCSecs, 99 );
nTemp = (u32)(nMin/10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nTemp];
nMin -= (nTemp * 10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nMin];
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_COLON];
nTemp = (u32)(nSecs/10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nTemp];
nSecs -= (nTemp * 10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nSecs];
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_PERIOD];
nTemp = (u32)(nCSecs/10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nTemp];
nCSecs -= (nTemp * 10);
_paHighScoreTable[i][j++] = _paOverLayIcons[ICON_LETTER_0 + nCSecs];
}
break;
case DEMO_BLUE_ARROW:
case DEMO_RED_ARROW:
case DEMO_BLUE_BOOST:
case DEMO_RED_BOOST:
case DEMO_THROTTLE:
default:
_nViewWords = _DO_NOT_DRAW_OVERLAY;
XASSERT_NOW;
break;
}
_nOverLayMode = nTextCode;
}
BOOL wpr_attact_IsTextCurrentlyOnScreen( void ) {
return ( _nViewWords != _DO_NOT_DRAW_OVERLAY );
}
static void _OverLayWork( void ) {
if( !_bOverLayOk ) {
return;
}
if( _nViewWords == _DO_NOT_DRAW_OVERLAY ) {
return;
}
switch( _nOverLayMode )
{
case DEMO_VIEW_BUTTONS:
/* goes through the hi, low, noboat, low, and high camera views (625 frames)*/
++_nCounter;
if( (_nCounter & 0x3) == 0x3 ) {
_bFlashOn = !_bFlashOn;
}
if( _nCounter == 125 || _nCounter == 375 ) {
_nViewWords = ICON_VIEW_BUTTON2;
cam_mgr_InitGameCamToPlayer( _nTargetBoat, GAMECAM_VIEW_LOW );
} else if( _nCounter == 250 ) {
_nViewWords = ICON_VIEW_BUTTON1;
cam_mgr_InitGameCamToPlayer( _nTargetBoat, GAMECAM_VIEW_NOBOAT );
} else if( _nCounter == 500 ) {
_nViewWords = ICON_VIEW_BUTTON3;
cam_mgr_InitGameCamToPlayer( _nTargetBoat, GAMECAM_VIEW_HIGH );
} else if( _nCounter >= 625 ) {
_nViewWords = _DO_NOT_DRAW_OVERLAY;
controls_TurnLightsOff( CONTROLS_ALL_VIEW_LIGHTS );
}
break;
case DEMO_HIGH_SCORES:
++_nCounter;
break;
case DEMO_BLUE_ARROW:
case DEMO_RED_ARROW:
case DEMO_BLUE_BOOST:
case DEMO_RED_BOOST:
case DEMO_THROTTLE:
default:
XASSERT_NOW;
break;
}
}
static void _OverLayDraw( void ) {
static const f32 _fButtonYPlacement[3] = { -56.0f, -13.0f, 30.0f };
u32 nPriorState;
int i, j;
f32 fX, fY, fScale, fOpacity, fXlat;
u32 nSinStep;
if( !_bOverLayOk ) {
return;
}
/* draw the frame counter if requested*/
#if SYS_WINDEV_TARGET
if( *Wintap_pGuiSettings->pbDisplayFrameCounter ) {
text_SetFont( TEXT_FONT_SMALL );
text_SetStyle( FSTYLE_PITCHED );
Text_fScale = 0.75f;
text_PrintF( 400, 10, "Frame %d\n", _nFrameCount );
}
#endif
if( _nViewWords == _DO_NOT_DRAW_OVERLAY ) {
/* always draw the web address and team hydro logo*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
nPriorState = gutil_ZbufferSetState( GUTIL_ZBUFFER_STATE_WRITE_ONLY );
mesh3d_DrawOrtho( _paOverLayIcons[ICON_WWW_ADDRESS], 125.0f, 175.0f, WPR_DEFS_LAYER1_Z, 0, 1.0f );
mesh3d_DrawOrtho( _paOverLayIcons[ICON_TEAM_HYDRO], -105.0f, 148.0f, WPR_DEFS_LAYER1_Z, 0, 1.0f );
gutil_ZbufferSetState( nPriorState );
controls_TurnLightsOff( CONTROLS_ALL_VIEW_LIGHTS );
return;
}
switch( _nOverLayMode )
{
case DEMO_VIEW_BUTTONS:
/* setup the ortho draw*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
nPriorState = gutil_ZbufferSetState( GUTIL_ZBUFFER_STATE_WRITE_ONLY );
mesh3d_DrawOrtho( _paOverLayIcons[ICON_VIEW_BUTTONS_TEXT], -110.0f, 121.0f, WPR_DEFS_LAYER1_Z, 0, 1.0f );
for( i=ICON_VIEW_BUTTON1; i <= ICON_VIEW_BUTTON3; i++ ) {
if( i == _nViewWords && _bFlashOn ) {
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
} else {
mesh3d_SetOrthoEffects( 0.25f, 0.25f, 0.25f, 1.0f, 0.0f );
}
mesh3d_DrawOrtho( _paOverLayIcons[i], -200.0f, _fButtonYPlacement[i - ICON_VIEW_BUTTON1], WPR_DEFS_LAYER1_Z, 0, 1.0f );
}
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
gutil_ZbufferSetState( nPriorState );
if( _bFlashOn ) {
switch( _nViewWords )
{
case ICON_VIEW_BUTTON1:
/* no boat view*/
controls_TurnLightsOff( CONTROLS_LIGHT_VIEW_LOW | CONTROLS_LIGHT_VIEW_HIGH );
controls_TurnLightsOn( CONTROLS_LIGHT_VIEW_NOBOAT );
break;
case ICON_VIEW_BUTTON2:
/* low view*/
controls_TurnLightsOff( CONTROLS_LIGHT_VIEW_NOBOAT | CONTROLS_LIGHT_VIEW_HIGH );
controls_TurnLightsOn( CONTROLS_LIGHT_VIEW_LOW );
break;
case ICON_VIEW_BUTTON3:
/* high view*/
controls_TurnLightsOff( CONTROLS_LIGHT_VIEW_NOBOAT | CONTROLS_LIGHT_VIEW_LOW );
controls_TurnLightsOn( CONTROLS_LIGHT_VIEW_HIGH );
break;
}
} else {
controls_TurnLightsOff( CONTROLS_ALL_VIEW_LIGHTS );
}
break;
case DEMO_HIGH_SCORES:
gutil_DrawBlackOrWhiteScreenFade( 0.40f, TRUE );
/* setup the ortho draw*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
nPriorState = gutil_ZbufferSetState( GUTIL_ZBUFFER_STATE_WRITE_ONLY );
if( _nCounter > 10 ) {
mesh3d_DrawOrtho( _paOverLayIcons[ICON_TRACKNAME_PLATE1], 0.0f, 0.0f, WPR_DEFS_LAYER1_Z, 0, 1.0f );
mesh3d_DrawOrtho( _paOverLayIcons[ICON_TRACKNAME_PLATE2], 0.0f, 0.0f, WPR_DEFS_LAYER1_Z, 0, 1.0f );
mesh3d_DrawOrtho( _paOverLayIcons[_nViewWords], 0.0f, 0.0f, WPR_DEFS_LAYER2_Z, 0, 1.0f );
fY = 115.0f;
nSinStep = _nCounter * 2500;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
fX = -200.0f;
for( j=0; j < _MAX_NUM_HIGH_SCORE_CHARS; j++ ) {
if( _paHighScoreTable[i][j] ) {
fScale = xmath_sin( nSinStep + (i * 5000) + (j * 5000) ) * 0.075f;
fOpacity = (1.0f - (2.0f * 0.075f)) + (2.0f * fScale);
if( fScale <= 0.05f ) {
if( i == 0 ) {
fOpacity *= 0.5f;
fOpacity += 0.5f;
}
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, fOpacity, 0.0f );
} else {
if( i != 0 ) {
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, fScale * fScale * 50.0f );
} else {
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, fScale * 10.0f );
}
}
fXlat = fScale * 15.0f;
if( j != 7 ) {
fScale += 0.70f;
mesh3d_DrawOrtho( _paHighScoreTable[i][j], fX + fXlat, fY + fXlat, WPR_DEFS_LAYER2_Z, 0, fScale );
} else {
fScale *= 0.5f;
fScale += 0.30f;
mesh3d_DrawOrtho( _paHighScoreTable[i][j], fX + fXlat, fY + fXlat, WPR_DEFS_LAYER2_Z, XMATH_90_BRADIANS, fScale );
}
}
switch( j )
{
case 10:
case 11:
case 13:
case 14:
fX += 18.0f;
break;
case 1:
fX += 20.0f;
break;
default:
fX += 25.0f;
break;
}
}
fY -= 28.0f;
}
} else {
fY = 115.0f;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
if( i & 0x1 ) {
fX = -670.0f + (_nCounter * 45.0f);
} else {
fX = 270.0f + (_nCounter * -45.0f);
}
for( j=0; j < _MAX_NUM_HIGH_SCORE_CHARS; j++ ) {
if( _paHighScoreTable[i][j] ) {
if( j != 7 ) {
fScale = 0.70f;
} else {
fScale = 0.30f;
}
mesh3d_DrawOrtho( _paHighScoreTable[i][j], fX, fY, WPR_DEFS_LAYER2_Z, 0, fScale );
}
switch( j )
{
case 10:
case 11:
case 13:
case 14:
fX += 18.0f;
break;
case 1:
fX += 20.0f;
break;
default:
fX += 25.0f;
break;
}
}
fY -= 28.0f;
}
}
gutil_ZbufferSetState( nPriorState );
break;
case DEMO_BLUE_ARROW:
case DEMO_RED_ARROW:
case DEMO_BLUE_BOOST:
case DEMO_RED_BOOST:
case DEMO_THROTTLE:
default:
XASSERT_NOW;
break;
}
}
static Mesh3d_t *_GetMeshForThisLetter( u8 nChar ) {
u32 nLetter;
if( nChar >= 'A' && nChar <= 'Z' ) {
nLetter = ICON_LETTER_A + nChar - 'A';
return _paOverLayIcons[nLetter];
} else if( nChar >= '0' && nChar <= '9' ) {
nLetter = ICON_LETTER_0 + nChar - '0';
return _paOverLayIcons[nLetter];
} else if( nChar == ':' ) {
return _paOverLayIcons[ICON_LETTER_COLON];
} else if( nChar == '.' ) {
return _paOverLayIcons[ICON_LETTER_PERIOD];
} else if( nChar == '?' ) {
return _paOverLayIcons[ICON_LETTER_QUESTION_MARK];
} else if( nChar == '!' ) {
return _paOverLayIcons[ICON_LETTER_EXCLAMATION_POINT];
}
return NULL;
}
static void _SeeIfWeNeedToUpdateTheCoinCountVisualDuringALoad( void ) {
if( _nCoinUpdateISRState & _FLAG_UPDATING_COIN_COUNTER ) {
if( _pCurStaticScreen ) {
blit_Raw( _pCurStaticScreen-sizeof(u32), 0, 0 );
wpr_banker_Draw( FALSE );
text_Flush();
gameloop_SwapFrameBuffer();
}
_nCoinUpdateISRState &= (~_FLAG_UPDATING_COIN_COUNTER);
}
}
#if _SPIT_DEBUG_INFO_OUT_TO_A_FILE
#include <stdio.h>
static void _RecordDebugInfo2AFile( BOOL bBefore ) {
FILE *pFile;
int i;
#if SYS_DEBUG
char pszFileName[] = "htwin_debug_info.txt";
#else
char pszFileName[] = "htwin_release_info.txt";
#endif
pFile = fopen( pszFileName, "at" );
if( !pFile ) {
return;
}
#if 0
if( (Gameloop_nFrameCounter - 1) == 0 ) {
/* write out the header*/
fprintf( pFile, "FRAME NUMBER,BOAT1 X,BOAT1 Y,BOAT1 Z,BOAT1 STEER,BOAT1 THROTTLE,HULL DIR X,HULL DIR Y,HULL DIR Z,LINEAR VEL X,LINEAR VEL Y,LINEAR VEL Z,ANGULAR VEL X,ANGULAR VEL Y,ANGULAR VEL Z\n" );
}
#endif
#if 0
fprintf( pFile, "%d,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f,%.20f\n", Gameloop_nFrameCounter,
Player_aData[0].pWorldOb->Orient.Pos.p[0],
Player_aData[0].pWorldOb->Orient.Pos.p[1],
Player_aData[0].pWorldOb->Orient.Pos.p[2],
Player_aData[0].Phys.fSteer,
Player_aData[0].Phys.fThrottle,
Player_aData[0].pHullDir->p[0],
Player_aData[0].pHullDir->p[1],
Player_aData[0].pHullDir->p[2],
Player_aData[0].Phys.pMotion->LinearVelocity_WS.p[0],
Player_aData[0].Phys.pMotion->LinearVelocity_WS.p[1],
Player_aData[0].Phys.pMotion->LinearVelocity_WS.p[2],
Player_aData[0].Phys.pMotion->AngularVelocity_WS.p[0],
Player_aData[0].Phys.pMotion->AngularVelocity_WS.p[1],
Player_aData[0].Phys.pMotion->AngularVelocity_WS.p[2] );
#endif
fprintf( pFile, "%d,%d,", bBefore, Gameloop_nFrameCounter );
for(i=0;i<8;i++)
{
fprintf( pFile, "0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,",
*(int*)&Player_aData[i].Phys.pMotion->LinearVelocity_WS.p[0],
*(int*)&Player_aData[i].Phys.pMotion->LinearVelocity_WS.p[1],
*(int*)&Player_aData[i].Phys.pMotion->LinearVelocity_WS.p[2],
*(int*)&Player_aData[i].Phys.pMotion->AngularVelocity_WS.p[0],
*(int*)&Player_aData[i].Phys.pMotion->AngularVelocity_WS.p[1],
*(int*)&Player_aData[i].Phys.pMotion->AngularVelocity_WS.p[2] );
}
fprintf( pFile, "\n" );
fclose( pFile );
}
#endif
hydro.hob
Found at 0x67EF000.
////////////////////////////////////////////////////////////////////////////////////// // hydro.hob // Autogenerated header file containing object ID's and arguments. // Do not edit this file manually as H2O looks for specific syntax // in order to parse it. Instead, you should use the Object Information // Editing UI within H2O. // // Author: H2O ////////////////////////////////////////////////////////////////////////////////////// // THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT. // Copyright (c) 1998 // // The contents of this file may not be disclosed to third // parties, copied or duplicated in any form, in whole or in part, // without the prior written permission of Midway Home Entertainment. ////////////////////////////////////////////////////////////////////////////////////// // Modification History: // // Date Who Description // -------- ---------- -------------------------------------------------------------- // 09/16/98 H2O Autogenerated ////////////////////////////////////////////////////////////////////////////////////// #ifndef __HYDRO_HOB__ #define __HYDRO_HOB__ #define NO_ID 0x00000000 // Object No ID #define NO_ID_NO_ARG 0x00000000 // Arg No Arg #define DRIVER 0x00000002 // Object Driver #define DRIVER_TRAIN 0x0000001E // Arg Train #define DRIVER_COPCAR1 0x0000001F // Arg CopCar1 #define DRIVER_COPCAR2 0x00000020 // Arg CopCar2 #define DRIVER_COPCAR3 0x00000021 // Arg CopCar3 #define DRIVER_COPCAR4 0x00000022 // Arg CopCar4 #define DRIVER_COPCAR5 0x00000023 // Arg CopCar5 #define DRIVER_COPCAR6 0x00000024 // Arg CopCar6 #define FLYER 0x00000003 // Object Flyer #define FLYER_HANG_GLIDER 0x00000001 // Arg Hang Glider #define FLYER_POLICE_COPTER 0x0000000A // Arg Police Copter #define FLYER_HOT_AIR_BALLOON 0x00000014 // Arg Hot Air Balloon #define FLYER_SEA_PLANE 0x0000001E // Arg Sea Plane #define FLYER_OIL_COPTER 0x0000000B // Arg Oil Copter #define FLYER_FLYING_SPEARS 0x00000028 // Arg Flying Spears #define FLYER_DRAGON_KITE_A 0x00000032 // Arg Dragon Kite A #define FLYER_DRAGON_KITE_B 0x00000033 // Arg Dragon Kite B #define LIGHT 0x00000005 // Object Light #define LIGHT_ARROW_SIGN 0x00000014 // Arg Arrow Sign #define LIGHT_LENS_FLARE1 0x0000001E // Arg Lens Flare1 #define LIGHT_LENS_FLARE2 0x0000001F // Arg Lens Flare2 #define LIGHT_LIGHTHOUSE 0x00000028 // Arg Lighthouse #define LIGHT_SPARKLE_LARGE 0x00000032 // Arg Sparkle Large #define LIGHT_SPARKLE_MED 0x00000033 // Arg Sparkle Med #define LIGHT_SPARKLE_SMALL 0x00000034 // Arg Sparkle Small #define LIGHT_FINISHLINE 0x00000015 // Arg FinishLine #define FIRE 0x00000006 // Object Fire #define FIRE_CAMPFIRE 0x00000001 // Arg Campfire #define FIRE_LAVA_CRACK 0x0000000A // Arg Lava Crack #define FIRE_VOLCANO 0x0000000B // Arg Volcano #define FIRE_BIG_VOLCANO_SMOKE_CLOUD 0x0000000C // Arg Big Volcano Smoke Cloud #define HANGING 0x00000004 // Object Hanging #define HANGING_SWING_15_DEG_IN_2_SECS 0x00000001 // Arg Swing 15 deg in 2 secs #define HANGING_ROTATING_SHIP 0x0000000A // Arg Rotating Ship #define HANGING_OIL_CRANE_SWING_Z 0x00000014 // Arg Oil Crane Swing Z #define HANGING_OIL_CRANE_SWING_Y 0x00000015 // Arg Oil Crane Swing Y #define FLOATING 0x00000007 // Object Floating #define FLOATING_RED_AND_WHITE_BUOY 0x00000001 // Arg Red and white buoy #define FLOATING_AMAZON_RIVER 0x0000000A // Arg Amazon River #define FLOATING_ARROW_SIGN 0x00000002 // Arg Arrow Sign #define FLOATING_CHECKPT 0x00000003 // Arg CheckPt #define FLOATING_WHALE 0x00000014 // Arg Whale #define FLOATING_FUNERAL_BARGE 0x00000015 // Arg Funeral Barge #define POWERUP 0x00000001 // Object Powerup #define POWERUP_LG_FLOATSTATICBOOST 0x00000002 // Arg LG FloatStaticBoost #define POWERUP_SM_FLOATSTATICBOOST 0x00000001 // Arg SM FloatStaticBoost #define POWERUP_SM_HOVERSTATICBOOST 0x00000003 // Arg SM HoverStaticBoost #define POWERUP_LG_HOVERSTATICBOOST 0x00000004 // Arg LG HoverStaticBoost #define POWERUP_SM_FLOATMOVE25FTBOOST 0x00000005 // Arg SM FloatMove25FtBoost #define POWERUP_LG_FLOATMOVE25FTBOOST 0x00000006 // Arg LG FloatMove25FtBoost #define POWERUP_SM_FLOATMOVE50FTBOOST 0x00000007 // Arg SM FloatMove50FtBoost #define POWERUP_LG_FLOATMOVE50FTBOOST 0x00000008 // Arg LG FloatMove50FtBoost #define POWERUP_SM_FLOATMOVE100FTBOOST 0x00000009 // Arg SM FloatMove100FtBoost #define POWERUP_LG_FLOATMOVE100FTBOOST 0x0000000A // Arg LG FloatMove100FtBoost #define POWERUP_SM_HOVERMOVE25FTBOOST 0x0000000B // Arg SM HoverMove25FtBoost #define POWERUP_LG_HOVERMOVE25FTBOOST 0x0000000C // Arg LG HoverMove25FtBoost #define POWERUP_SM_HOVERMOVE50FTBOOST 0x0000000D // Arg SM HoverMove50FtBoost #define POWERUP_LG_HOVERMOVE50FTBOOST 0x0000000E // Arg LG HoverMove50FtBoost #define POWERUP_SM_HOVERMOVE100FTBOOST 0x0000000F // Arg SM HoverMove100FtBoost #define POWERUP_LG_HOVERMOVE100FTBOOST 0x00000010 // Arg LG HoverMove100FtBoost #define SPINNING 0x00000008 // Object Spinning #define SPINNING_LOCAL_X__1_SEC_REV 0x00000001 // Arg Local X, 1 sec/rev #define SPINNING_LOCAL_X__5_SECS_REV 0x00000002 // Arg Local X, 5 secs/rev #define SPINNING_LOCAL_X__10_SECS_REV 0x00000003 // Arg Local X, 10 secs/rev #define SPINNING_LOCAL_Y__1_SEC_REV 0x00000004 // Arg Local Y, 1 sec/rev #define SPINNING_LOCAL_Y__5_SECS_REV 0x00000005 // Arg Local Y, 5 secs/rev #define SPINNING_LOCAL_Y__10_SECS_REV 0x00000006 // Arg Local Y, 10 secs/rev #define SPINNING_LOCAL_Z__1_SEC_REV 0x00000007 // Arg Local Z, 1 sec/rev #define SPINNING_LOCAL_Z__5_SECS_REV 0x00000008 // Arg Local Z, 5 secs/rev #define SPINNING_LOCAL_Z__10_SECS_REV 0x00000009 // Arg Local Z, 10 secs/rev #define SPINNING_WORLD_X__1_SEC_REV 0x0000000A // Arg World X, 1 sec/rev #define SPINNING_WORLD_X__5_SECS_REV 0x0000000B // Arg World X, 5 secs/rev #define SPINNING_WORLD_X__10_SECS_REV 0x0000000C // Arg World X, 10 secs/rev #define SPINNING_WORLD_Y__1_SEC_REV 0x0000000D // Arg World Y, 1 sec/rev #define SPINNING_WORLD_Y__5_SECS_REV 0x0000000E // Arg World Y, 5 secs/rev #define SPINNING_WORLD_Y__10_SECS_REV 0x0000000F // Arg World Y, 10 secs/rev #define SPINNING_WORLD_Z__1_SEC_REV 0x00000010 // Arg World Z, 1 sec/rev #define SPINNING_WORLD_Z__5_SECS_REV 0x00000011 // Arg World Z, 5 secs/rev #define SPINNING_WORLD_Z__10_SECS_REV 0x00000012 // Arg World Z, 10 secs/rev #define SPINNING_LOCAL_X__20_SECS_REV 0x00000013 // Arg Local X, 20 secs/rev #define SPINNING_LOCAL_Y__20_SECS_REV 0x00000014 // Arg Local Y, 20 secs/rev #define SPINNING_LOCAL_Z__20_SECS_REV 0x00000015 // Arg Local Z, 20 secs/rev #define SPINNING_WORLD_X__20_SECS_REV 0x00000016 // Arg World X, 20 secs/rev #define SPINNING_WORLD_Y__20_SECS_REV 0x00000017 // Arg World Y, 20 secs/rev #define SPINNING_WORLD_Z__20_SECS_REV 0x00000018 // Arg World Z, 20 secs/rev #define DISPLAY 0x00000009 // Object Display #define DISPLAY_OFF_1 0x00000001 // Arg Off 1 #define DISPLAY_OFF_2 0x00000002 // Arg Off 2 #define DISPLAY_OFF_3 0x00000003 // Arg Off 3 #define DISPLAY_OFF_4 0x00000004 // Arg Off 4 #define DISPLAY_OFF_5 0x00000005 // Arg Off 5 #define DISPLAY_ON_1 0x00000006 // Arg On 1 #define DISPLAY_ON_2 0x00000007 // Arg On 2 #define DISPLAY_ON_3 0x00000008 // Arg On 3 #define DISPLAY_ON_4 0x00000009 // Arg On 4 #define DISPLAY_ON_5 0x0000000A // Arg On 5 #define SLIDETCS 0x0000000A // Object SlideTCs #define SLIDETCS_DOWN_SLOW 0x00000001 // Arg Down Slow #define SLIDETCS_DOWN_MED 0x00000002 // Arg Down Med #define SLIDETCS_DOWN_FAST 0x00000003 // Arg Down Fast #define SLIDETCS_UP_SLOW 0x00000006 // Arg Up Slow #define SLIDETCS_UP_MED 0x00000007 // Arg Up Med #define SLIDETCS_UP_FAST 0x00000008 // Arg Up Fast #define SLIDETCS_LEFT_SLOW 0x0000000B // Arg Left Slow #define SLIDETCS_LEFT_MED 0x0000000C // Arg Left Med #define SLIDETCS_LEFT_FAST 0x0000000D // Arg Left Fast #define SLIDETCS_RIGHT_SLOW 0x00000010 // Arg Right Slow #define SLIDETCS_RIGHT_MED 0x00000011 // Arg Right Med #define SLIDETCS_RIGHT_FAST 0x00000012 // Arg Right Fast #define BIRDS 0x0000000B // Object Birds #define BIRDS_SOAR_LARGE_CIRCLE 0x00000001 // Arg Soar Large Circle #define BIRDS_SOAR_MED_CIRCLE 0x00000002 // Arg Soar Med Circle #define BIRDS_SOAR_SMALL_CIRCLE 0x00000003 // Arg Soar Small Circle #define BIRDS_FLAP_SOAR_LARGE_CIRCLE 0x00000006 // Arg Flap Soar Large Circle #define BIRDS_FLAP_SOAR_MED_CIRCLE 0x00000007 // Arg Flap Soar Med Circle #define BIRDS_FLAP_SOAR_SMALL_CIRCLE 0x00000008 // Arg Flap Soar Small Circle #define BIRDS_BATS 0x0000000B // Arg Bats #define BIRDS_V_FORMATION_1000_FEET 0x00000010 // Arg V Formation 1000 Feet #define BIRDS_V_FORMATION_2000_FEET 0x00000011 // Arg V Formation 2000 Feet #define BIRDS_V_FORMATION_3000_FEET 0x00000012 // Arg V Formation 3000 Feet #define BIRDS_V_FORMATION_4000_FEET 0x00000013 // Arg V Formation 4000 Feet #define BIRDS_V_FORMATION_5000_FEET 0x00000014 // Arg V Formation 5000 Feet #define BIRDS_DUCK_GROUP1 0x00000019 // Arg Duck Group1 #define BIRDS_DUCK_GROUP2 0x0000001A // Arg Duck Group2 #define BIRDS_DUCK_GROUP3 0x0000001B // Arg Duck Group3 #define BIRDS_DUCK_GROUP4 0x0000001C // Arg Duck Group4 #define BIRDS_DUCK_GROUP5 0x0000001D // Arg Duck Group5 #define ANIMATE 0x0000000C // Object Animate #define ANIMATE_LOOPING 0x00000001 // Arg Looping #define ANIMATE_EVERY_1_TO_2_SECS 0x00000002 // Arg Every 1 to 2 Secs #define ANIMATE_EVERY_2_TO_4_SECS 0x00000003 // Arg Every 2 to 4 Secs #define ANIMATE_EVERY_4_TO_8_SECS 0x00000004 // Arg Every 4 to 8 Secs #define ANIMATE_EVERY_5_TO_10_SECS 0x00000005 // Arg Every 5 to 10 Secs #define ANIMATE_EVERY_10_TO_15_SECS 0x00000006 // Arg Every 10 to 15 Secs #define ANIMATE_LOOP_AND_MOVE_OB 0x0000000A // Arg Loop and Move_Ob #define ANIMATE_LOOP_AND_ROT_OB 0x0000000B // Arg Loop and Rot_Ob #define ANIMATE_LOOP_AND_MOVE_ROT_OB 0x0000000C // Arg Loop and Move_Rot_Ob #define ANIMATE_MOVE_OB 0x0000000D // Arg Move_Ob #define ANIMATE_ROT_OB 0x0000000E // Arg Rot_Ob #define ANIMATE_MOVE_ROT_OB 0x0000000F // Arg Move_Rot_Ob #define ANIMATE_MESH_SWAP_30_FRAMES 0x00000014 // Arg Mesh Swap 30 Frames #define ANIMATE_MESH_SWAP_45_FRAMES 0x00000015 // Arg Mesh Swap 45 Frames #define ANIMATE_MESH_SWAP_60_FRAMES 0x00000016 // Arg Mesh Swap 60 Frames #define WATERCRAFT 0x0000000D // Object Watercraft #define WATERCRAFT_THROTTLE_0_05 0x00000001 // Arg Throttle 0.05 #define WATERCRAFT_THROTTLE_0_1 0x00000002 // Arg Throttle 0.1 #define WATERCRAFT_THROTTLE_0_2 0x00000003 // Arg Throttle 0.2 #define WATERCRAFT_THROTTLE_0_3 0x00000004 // Arg Throttle 0.3 #define WATERCRAFT_THROTTLE_0_4 0x00000005 // Arg Throttle 0.4 #define WATERCRAFT_THROTTLE_0_5 0x00000006 // Arg Throttle 0.5 #define PHYSICSCRAFT 0x0000000E // Object Physicscraft #define PHYSICSCRAFT_POLICE 0x00000001 // Arg Police #define PHYSICSCRAFT_MAGNET 0x00000002 // Arg Magnet #define PHYSICSCRAFT_DRUNK 0x00000003 // Arg Drunk #define PHYSICSCRAFT_CROSS 0x00000004 // Arg Cross #define PHYSICSCRAFT_ASSHOLE 0x00000005 // Arg Asshole #define PHYSICSCRAFT_BLOCKER 0x00000006 // Arg Blocker #endif // __HYDRO_HOB__
text.c
Found at 0x6879000.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* text.c - text string handling routines*/
/**/
/* Author: Michael Hunley */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* NOTES:*/
/* It is important that all fonts be drawn with a 2 pixel outer boarder to account*/
/* for bilinear interpolation when scaled. At creation time I do not know if it*/
/* should be alpha (0,0,0 black) or a colored boarder that mimics the letter.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 11/25/97 Hunley Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "text.h"
#include "viewport.h"
#include "obsys.h"
#include "gutil.h"
#include "tmem.h"
#include "material.h"
#include "xmath.h"
#include "xclib.h"
#include "stdarg.h"
/*====================*/
/* private definitions*/
#if TARGET==ULTRA64
unsigned short int *N64ConstantColour;
BOOL N64ScaleFont=FALSE;
float N64OrigScale=0;
/* As 'scaled font's will look crap, have 'x' versions of font in same texture page */
/* Simply check for 'scale' match and use this font, else default! */
typedef struct {
float Scale;
int FontOffset;
} N64FontScale;
#endif /*ULTRA64 */
#if TARGET==ULTRA64
typedef struct _tag_FontMap {
u16 nXOff;
u8 nWidthN64;
} FontMap_t;
#else /*ULTRA64 */
typedef struct _tag_FontMap {
u32 nXOff;
u32 nWidth;
} FontMap_t;
#endif /*ULTRA64 */
typedef struct _tag_FontHdr {
u8 nWidth; /* width of a space (avg. char width)*/
u8 nHeight; /* Height of all */
u8 nSpacing;
u8 nYSpacing;
} FontHdr_t;
typedef struct _tag_TextImage {
const char pszName[OBJECT_NAME_LENGTH + 1]; /* Object name in R2 file*/
TexDef_t *pTexDef;
} TextImage_t;
typedef struct TextImageList_s {
u32 nCount;
TextImage_t *pTextImageArray;
} TextImageList_t;
typedef struct _tag_Font {
BOOL bLoaded;
TextImageList_t *pTextImageList;
FontMap_t *pMapping; /* ascii character map*/
FontHdr_t *pHeader; /* master info per font*/
u32 nHeight;
#if TARGET==ULTRA64
N64FontScale * N64ScaleTable;
#endif /*ULTRA64 */
} TextFont_t;
/*=================*/
/* public variables*/
f32 Text_fX, Text_fY;
u32 Text_nAttr;
u32 Text_nStyle;
f32 Text_fScale=1.0f;
/* Table Data*/
char Text_aHexChar[16] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F'
};
/*==================*/
/* private variables*/
static u16 _nNumLetters;
static TextLetter_t _pBuffer[TEXT_MAX_LETTERS];
static char _aCharBuffer[STRING_MAX_LENGTH + 1];
static FontMap_t *_pWidthTable;
static FontHdr_t *_pHdr;
static char _str[STRING_MAX_LENGTH + 1];
#if TARGET==ULTRA64
static N64FontScale * _N64ScaleTable;
#endif /*ULTRA64 */
static GrVertex _A, _B, _C, _D;
static GrColor_t _ConstantColor;
/* These MUST be set before font rountines are used*/
static u8 _nCurFont=0; /* The current font to use*/
static u8 _nWidth;
static u8 _nHeight;
static u8 _nSpacing;
static u32 _nYSpacing;
static f32 _fHeight;
static f32 _fSpacing;
/**/
/* Logical Character ASCII lookup table*/
/* Starts with ascii char 32 (space)*/
/* a 50 prints a space*/
/**/
static u8 _ASCIITable[] = {
50, /* 32 (Space)*/
36, /* 33 !*/
42, /* 34 "*/
46, /* 35 #*/
47, /* 36 $*/
50, /* 37 %*/
50, /* 38 &*/
41, /* 39 '*/
48, /* 40 ( or [<--]*/
49, /* 41 ) or [End]*/
44, /* 42 **/
38, /* 43 +*/
50, /* 44 ,*/
39, /* 45 -*/
43, /* 46 .*/
45, /* 47 /*/
35, /* 48 0*/
26, /* 49 1*/
27, /* 50 2*/
28, /* 51 3*/
29, /* 52 4*/
30, /* 53 5*/
31, /* 54 6*/
32, /* 55 7*/
33, /* 56 8*/
34, /* 57 9*/
40, /* 58 :*/
50, /* 59 //*/
50, /* 60 <*/
50, /* 61 =*/
50, /* 62 >*/
37, /* 63 ?*/
50, /* 64 @*/
0, /* 65 A*/
1, /* 66 B*/
2, /* 67 C*/
3, /* 68 D*/
4, /* 69 E*/
5, /* 70 F*/
6, /* 71 G*/
7, /* 72 H*/
8, /* 73 I*/
9, /* 74 J*/
10, /* 75 K*/
11, /* 76 L*/
12, /* 77 M*/
13, /* 78 N*/
14, /* 79 O*/
15, /* 80 P*/
16, /* 81 Q*/
17, /* 82 R*/
18, /* 83 S*/
19, /* 84 T*/
20, /* 88 U*/
21, /* 86 V*/
22, /* 87 W*/
23, /* 88 X*/
24, /* 89 Y*/
25, /* 90 Z*/
50, /* 91*/
50, /* 92*/
50, /* 93*/
50, /* 94*/
50, /* 95*/
50, /* 96*/
0, /* 97 a*/
1, /* 98 b*/
2, /* 99 c*/
3, /* 100 d*/
4, /* 101 e*/
5, /* 102 f*/
6, /* 103 g*/
7, /* 104 h*/
8, /* 105 i*/
9, /* 106 j*/
10, /* 107 k*/
11, /* 108 l*/
12, /* 109 m*/
13, /* 110 n*/
14, /* 111 o*/
15, /* 112 p*/
16, /* 113 q*/
17, /* 114 r*/
18, /* 115 s*/
19, /* 116 t*/
20, /* 117 u*/
21, /* 118 v*/
22, /* 119 w*/
23, /* 120 x*/
24, /* 121 y*/
25, /* 122 z*/
50, /* 123*/
50, /* 124*/
50, /* 125*/
50, /* 126*/
50 /* 127*/
};
#if TARGET==ULTRA64
/* offset map for the 16 high font */
static FontMap_t _SFontSpacing[] = {
0, 16, /* A */
12, 16, /* B */
24, 16, /* C */
36, 16, /* D */
48, 16, /* E */
58, 16, /* F */
68, 16, /* G */
80, 16, /* H */
92, 16, /* I */
98, 16, /* J */
108, 16, /* K */
119, 16, /* L */
129, 16, /* M */
145, 16, /* N */
157, 16, /* O */
169, 16, /* P */
181, 16, /* Q */
193, 16, /* R */
205, 16, /* S */
217, 16, /* T */
229, 16, /* U */
241, 16, /* V */
256, 16, /* W */
272, 16, /* X */
284, 16, /* Y */
296, 16, /* Z */
308, 16, /* 1 */
316, 16, /* 2 */
327, 16, /* 3 */
338, 16, /* 4 */
352, 16, /* 5 */
364, 16, /* 6 */
376, 16, /* 7 */
387, 16, /* 8 */
399, 16, /* 9 */
411, 16, /* 0 */
423, 16, /* ! */
430, 16, /* ? */
441, 16, /* + */
453, 16, /* - */
461, 16, /* : */
466, 16, /* ' */
471, 16, /* " */
480, 16, /* . */
485, 16, /* * */
497, 16, /* / */
516, 16, /* # */
523, 16, /* $ */
533, 16, /* ( */
541, 16, /* ) */
549, 16, /* Space */
};
/* offset map for the 26 high font */
static FontMap_t _LFontSpacing[] = {
0, 16, /* A */
17, 16, /* B */
34, 16, /* C */
51, 16, /* D */
68, 16, /* E */
83, 16, /* F */
98, 16, /* G */
116, 16, /* H */
133, 16, /* I */
141, 16, /* J */
158, 16, /* K */
176, 16, /* L */
191, 16, /* M */
214, 16, /* N */
234, 16, /* O */
256, 16, /* P */
273, 16, /* Q */
290, 16, /* R */
307, 16, /* S */
324, 16, /* T */
341, 16, /* U */
358, 16, /* V */
375, 16, /* W */
396, 16, /* X */
413, 16, /* Y */
430, 16, /* Z */
447, 16, /* 1 */
457, 16, /* 2 */
474, 16, /* 3 */
491, 16, /* 4 */
512, 16, /* 5 */
529, 16, /* 6 */
546, 16, /* 7 */
563, 16, /* 8 */
580, 16, /* 9 */
597, 16, /* 0 */
614, 16, /* ! */
623, 16, /* ? */
640, 16, /* + */
656, 16, /* - */
669, 16, /* : */
676, 16, /* ' */
683, 16, /* " */
696, 16, /* . */
703, 16, /* * */
713, 16, /* / */
730, 16, /* # */
743, 16, /* $ */
758, 16, /* [<--] */
758, 16, /* [End] */
758, 16, /* Space */
};
/* offset map for the chrome font (44 texels high) */
static FontMap_t _CFontSpacing[] = {
0 , 16, /* a */
39 , 16, /* b */
72 , 16, /* c */
107 , 16, /* d */
142 , 16, /* e */
173 , 16, /* f */
202 , 16, /* g */
285 , 16, /* h */
239 , 16, /* i */
319 , 16, /* j */
341 , 16, /* k */
256 , 16, /* l */
376 , 16, /* m */
414 , 16, /* n */
448 , 16, /* o */
512 , 16, /* p */
544 , 16, /* q */
586 , 16, /* r */
621 , 16, /* s */
655 , 16, /* t */
687 , 16, /* u */
721 , 16, /* v */
768 , 16, /* w */
817 , 16, /* x */
855 , 16, /* y */
893 , 16, /* z */
958 , 16, /* 1 */
977 , 16, /* 2 */
1024 , 16, /* 3 */
1056 , 16, /* 4 */
1089 , 16, /* 5 */
1121 , 16, /* 6 */
1151 , 16, /* 7 */
1181 , 16, /* 8 */
1212 , 16, /* 9 */
924 , 16, /* 0 */
1453 , 16, /* ! */
1243 , 16, /* ? */
1310 , 16, /* + */
1337 , 16, /* - */
1008 , 16, /* : */
1480 , 16, /* ' */
484 , 16, /* " */
1467 , 16, /* . */
1359 , 16, /* * */
1386 , 16, /* / */
1410 , 16, /* # */
1280 , 16, /* $ */
1492, 16, /* [<--] */
1492, 16, /* [End] */
1492, 16, /* Space */
};
/* offset map for the 50 high font (hud1) */
static FontMap_t _H1FontSpacing[] = {
0, 16, /* A */
31, 16, /* B */
60, 16, /* C */
85, 16, /* D */
115, 16, /* E */
137, 16, /* F */
159, 16, /* G */
189, 16, /* H */
217, 16, /* I */
230, 16, /* J */
256, 16, /* K */
286, 16, /* L */
307, 16, /* M */
345, 16, /* N */
376, 16, /* O */
409, 16, /* P */
437, 16, /* Q */
470, 16, /* R */
512, 16, /* S */
536, 16, /* T */
561, 16, /* U */
589, 16, /* V */
620, 16, /* W */
665, 16, /* X */
695, 16, /* Y */
725, 16, /* Z */
768, 16, /* 1 */
790, 16, /* 2 */
819, 16, /* 3 */
849, 16, /* 4 */
880, 16, /* 5 */
910, 16, /* 6 */
940, 16, /* 7 */
965, 16, /* 8 */
995, 16, /* 9 */
1024, 16, /* 0 */
1055, 16, /* ! */
1069, 16, /* ? */
1091, 16, /* + */
1122, 16, /* - */
1145, 16, /* : */
1159, 16, /* ' */
1169, 16, /* " */
1189, 16, /* . */
1200, 16, /* * NOT USED */
1200, 16, /* / NOT USED */
1200, 16, /* # NOT USED */
1200, 16, /* $ NOT USED */
1200, 16, /* ( NOT USED */
1200, 16, /* ) NOT USED */
1200, 16, /* Space */
};
/* offset map for the 50 high font (hud2) */
static FontMap_t _H2FontSpacing[] = {
0, 14, /* A 14x17 / nXOff, nXWidth */
16, 14, /* B 14x17 */
32, 12, /* C 12x17 */
48, 13, /* D 13x17 */
64, 12, /* E 12x17 */
80, 13, /* F 13x17 */
96, 14, /* G 14x17 */
112, 14, /* H 14x17 */
128, 5, /* I 5x17 */
144, 11, /* J 11x17 */
160, 15, /* K 15x17 */
176, 11, /* L 11x17 */
192, 18, /* M 18x17 */
224, 15, /* N 15x17 */
240, 14, /* O 14x17 */
256, 14, /* P 14x17 */
272, 15, /* Q 15x17 */
288, 14, /* R 14x17 */
304, 13, /* S 13x17 */
320, 14, /* T 14x17 */
336, 15, /* U 15x17 */
352, 15, /* V 15x17 */
368, 22, /* W 22x17 */
400, 16, /* X 16x17 */
416, 16, /* Y 16x17 */
432, 14, /* Z 14x17 */
448, 7, /* 1 7x17 */
464, 14, /* 2 14x17 */
480, 14, /* 3 14x17 */
496, 15, /* 4 15x17 */
512, 15, /* 5 15x17 */
528, 15, /* 6 15x17 */
544, 13, /* 7 13x17 */
560, 14, /* 8 14x17 */
576, 14, /* 9 14x17 */
592, 14, /* 0 14x17 */
608, 5, /* ! 5x17 */
624, 14, /* ? 14x17 */
640, 13, /* + 13x17 */
656, 6, /* - 6x17 */
672, 5, /* : 5x17 */
688, 3, /* ' 3x17 */
704, 8, /* " 8x17 */
720, 6, /* . 6x17 */
736, 14, /* * NOT USED */
736, 14, /* / NOT USED */
736, 14, /* # NOT USED */
736, 14, /* $ NOT USED */
736, 14, /* ( NOT USED */
736, 14, /* ) NOT USED */
736, 14, /* Space */
};
static FontMap_t _H2FontSpacing_50[] = {
0, 12, /* A 14x17 / nXOff, nXWidth */
16, 12, /* B 14x17 */
32, 10, /* C 12x17 */
48, 11, /* D 13x17 */
64, 11, /* E 12x17 */
80, 11, /* F 13x17 */
96, 12, /* G 14x17 */
112, 12, /* H 14x17 */
128, 4, /* I 5x17 */
144, 10, /* J 11x17 */
160, 13, /* K 15x17 */
176, 10, /* L 11x17 */
192, 15, /* M 18x17 */
224, 13, /* N 15x17 */
240, 12, /* O 14x17 */
256, 12, /* P 14x17 */
272, 13, /* Q 15x17 */
288, 11, /* R 14x17 */
304, 12, /* S 13x17 */
320, 11, /* T 14x17 */
336, 13, /* U 15x17 */
352, 13, /* V 15x17 */
368, 18, /* W 22x17 */
400, 14, /* X 16x17 */
416, 13, /* Y 16x17 */
432, 11, /* Z 14x17 */
448, 6, /* 1 7x17 */
464, 12, /* 2 14x17 */
480, 12, /* 3 14x17 */
496, 13, /* 4 15x17 */
512, 12, /* 5 15x17 */
528, 12, /* 6 15x17 */
544, 11, /* 7 13x17 */
560, 12, /* 8 14x17 */
576, 12, /* 9 14x17 */
592, 12, /* 0 14x17 */
608, 5, /* ! 5x17 */
624, 12, /* ? 14x17 */
640, 11, /* + 13x17 */
656, 5, /* - 6x17 */
672, 4, /* : 5x17 */
688, 3, /* ' 3x17 */
704, 7, /* " 8x17 */
720, 5, /* . 6x17 */
736, 12, /* * NOT USED */
736, 12, /* / NOT USED */
736, 12, /* # NOT USED */
736, 12, /* $ NOT USED */
736, 12, /* ( NOT USED */
736, 12, /* ) NOT USED */
736, 12, /* Space */
};
static FontMap_t _H2FontSpacing_35[] = {
0, 8, /* A 14x17 / nXOff, nXWidth */
16, 8, /* B 14x17 */
32, 7, /* C 12x17 */
48, 7, /* D 13x17 */
64, 6, /* E 12x17 */
80, 6, /* F 13x17 */
96, 8, /* G 14x17 */
112, 8, /* H 14x17 */
128, 3, /* I 5x17 */
144, 7, /* J 11x17 */
160, 8, /* K 15x17 */
176, 6, /* L 11x17 */
192, 10, /* M 18x17 */
224, 8, /* N 15x17 */
240, 8, /* O 14x17 */
256, 8, /* P 14x17 */
272, 9, /* Q 15x17 */
288, 8, /* R 14x17 */
304, 7, /* S 13x17 */
320, 8, /* T 14x17 */
336, 7, /* U 15x17 */
352, 8, /* V 15x17 */
368, 12, /* W 22x17 */
400, 8, /* X 16x17 */
416, 8, /* Y 16x17 */
432, 8, /* Z 14x17 */
448, 4, /* 1 7x17 */
464, 8, /* 2 14x17 */
480, 8, /* 3 14x17 */
496, 8, /* 4 15x17 */
512, 8, /* 5 15x17 */
528, 8, /* 6 15x17 */
544, 7, /* 7 13x17 */
560, 8, /* 8 14x17 */
576, 8, /* 9 14x17 */
592, 8, /* 0 14x17 */
608, 2, /* ! 5x17 */
624, 8, /* ? 14x17 */
640, 8, /* + 13x17 */
656, 4, /* - 6x17 */
672, 2, /* : 5x17 */
688, 2, /* ' 3x17 */
704, 6, /* " 8x17 */
720, 2, /* . 6x17 */
736, 8, /* * NOT USED */
736, 8, /* / NOT USED */
736, 8, /* # NOT USED */
736, 8, /* $ NOT USED */
736, 8, /* ( NOT USED */
736, 8, /* ) NOT USED */
736, 8, /* Space */
};
/* offset map for the 50 high font (hud2) */
static FontMap_t _H2FontSpacing_150[] = {
0, 0, /* A 14x17 / nXOff, nXWidth */
0, 0, /* B 14x17 */
0, 0, /* C 12x17 */
0, 0, /* D 13x17 */
0, 0, /* E 12x17 */
0, 0, /* F 13x17 */
320, 28, /* G 14x17 */
0, 0, /* H 14x17 */
0, 0, /* I 5x17 */
0, 0, /* J 11x17 */
0, 0, /* K 15x17 */
0, 0, /* L 11x17 */
0, 0, /* M 18x17 */
0, 0, /* N 15x17 */
352, 26, /* O 14x17 */
0, 0, /* P 14x17 */
0, 0, /* Q 15x17 */
0, 0, /* R 14x17 */
0, 0, /* S 13x17 */
0, 0, /* T 14x17 */
0, 0, /* U 15x17 */
0, 0, /* V 15x17 */
0, 0, /* W 22x17 */
0, 0, /* X 16x17 */
0, 0, /* Y 16x17 */
0, 0, /* Z 14x17 */
0, 14, /* 1 7x17 */
32, 28, /* 2 14x17 */
64, 27, /* 3 14x17 */
96, 31, /* 4 15x17 */
128, 29, /* 5 15x17 */
160, 30, /* 6 15x17 */
192, 27, /* 7 13x17 */
224, 28, /* 8 14x17 */
256, 28, /* 9 14x17 */
288, 28, /* 0 14x17 */
384, 11, /* ! 5x17 */
0, 0, /* ? 14x17 */
0, 0, /* + 13x17 */
0, 0, /* - 6x17 */
0, 0, /* : 5x17 */
0, 0, /* ' 3x17 */
0, 0, /* " 8x17 */
0, 0, /* . 6x17 */
0, 0, /* * NOT USED */
0, 0, /* / NOT USED */
0, 0, /* # NOT USED */
0, 0, /* $ NOT USED */
0, 0, /* ( NOT USED */
0, 0, /* ) NOT USED */
416, 0, /* Space */
};
#else /*ULTRA64 */
/* offset map for the 16 high font*/
static FontMap_t _SFontSpacing[] = {
0, 12, /* A*/
12, 12, /* B*/
24, 12, /* C*/
36, 12, /* D*/
48, 10, /* E*/
58, 10, /* F*/
68, 12, /* G*/
80, 12, /* H*/
92, 6, /* I*/
98, 10, /* J*/
108, 11, /* K*/
119, 10, /* L*/
129, 16, /* M*/
145, 12, /* N*/
157, 12, /* O*/
169, 12, /* P*/
181, 12, /* Q*/
193, 12, /* R*/
205, 12, /* S*/
217, 12, /* T*/
229, 12, /* U*/
241, 12, /* V*/
256, 16, /* W*/
272, 12, /* X*/
284, 12, /* Y*/
296, 12, /* Z*/
308, 8, /* 1*/
316, 11, /* 2*/
327, 11, /* 3*/
338, 14, /* 4*/
352, 12, /* 5*/
364, 12, /* 6*/
376, 11, /* 7*/
387, 12, /* 8*/
399, 12, /* 9*/
411, 12, /* 0*/
423, 7, /* !*/
430, 11, /* ?*/
441, 12, /* +*/
453, 8, /* -*/
461, 5, /* :*/
466, 5, /* '*/
471, 9, /* "*/
480, 5, /* .*/
485, 12, /* **/
497, 12, /* /*/
516, 11, /* #*/
523, 10, /* $*/
533, 8, /* (*/
541, 8, /* )*/
549, 8, /* Space*/
};
/* offset map for the 26 high font*/
static FontMap_t _LFontSpacing[] = {
0, 17, /* A*/
17, 17, /* B*/
34, 17, /* C*/
51, 17, /* D*/
68, 15, /* E*/
83, 15, /* F*/
98, 18, /* G*/
116, 17, /* H*/
133, 8, /* I*/
141, 17, /* J*/
158, 18, /* K*/
176, 15, /* L*/
191, 23, /* M*/
214, 20, /* N*/
234, 19, /* O*/
256, 17, /* P*/
273, 17, /* Q*/
290, 17, /* R*/
307, 17, /* S*/
324, 17, /* T*/
341, 17, /* U*/
358, 17, /* V*/
375, 21, /* W*/
396, 17, /* X*/
413, 17, /* Y*/
430, 17, /* Z*/
447, 10, /* 1*/
457, 17, /* 2*/
474, 17, /* 3*/
491, 19, /* 4*/
512, 17, /* 5*/
529, 17, /* 6*/
546, 17, /* 7*/
563, 17, /* 8*/
580, 17, /* 9*/
597, 17, /* 0*/
614, 9, /* !*/
623, 17, /* ?*/
640, 16, /* +*/
656, 13, /* -*/
669, 7, /* :*/
676, 7, /* '*/
683, 13, /* "*/
696, 7, /* .*/
703, 10, /* **/
713, 17, /* /*/
730, 13, /* #*/
743, 15, /* $*/
758, 10, /* [<--]*/
758, 10, /* [End]*/
758, 10, /* Space*/
};
/* offset map for the 50 high font (hud1)*/
static FontMap_t _H1FontSpacing[] = {
0, 30, /* A */
31, 28, /* B */
60, 24, /* C */
85, 29, /* D */
115, 21, /* E */
137, 21, /* F */
159, 29, /* G */
189, 27, /* H */
217, 12, /* I */
230, 19, /* J */
256, 29, /* K */
286, 20, /* L */
307, 37, /* M */
345, 30, /* N */
376, 32, /* O */
409, 27, /* P */
437, 32, /* Q */
470, 28, /* R */
512, 23, /* S */
536, 24, /* T */
561, 27, /* U */
589, 30, /* V */
620, 44, /* W */
665, 29, /* X */
695, 29, /* Y */
725, 25, /* Z */
768, 21, /* 1 */
790, 28, /* 2 */
819, 29, /* 3 */
849, 30, /* 4 */
880, 29, /* 5 */
910, 29, /* 6 */
940, 24, /* 7 */
965, 29, /* 8 */
995, 28, /* 9 */
1024, 30, /* 0 */
1055, 13, /* ! */
1069, 21, /* ? */
1091, 30, /* + */
1122, 22, /* - */
1145, 13, /* : */
1159, 9, /* ' */
1169, 19, /* " */
1189, 10, /* . */
1200, 24, /* * NOT USED */
1200, 24, /* / NOT USED*/
1200, 24, /* # NOT USED */
1200, 24, /* $ NOT USED */
1200, 24, /* ( NOT USED */
1200, 24, /* ) NOT USED */
1200, 24, /* Space */
};
/* offset map for the 50 high font (hud2)*/
static FontMap_t _H2FontSpacing[] = {
0, 40, /* A */
41, 41, /* B */
83, 36, /* C */
120, 37, /* D */
158, 34, /* E */
193, 37, /* F */
256, 40, /* G */
297, 41, /* H */
339, 16, /* I */
356, 33, /* J */
390, 45, /* K */
436, 33, /* L */
512, 51, /* M */
564, 45, /* N */
610, 39, /* O */
650, 39, /* P */
690, 43, /* Q */
768, 39, /* R */
808, 37, /* S */
846, 39, /* T */
886, 42, /* U */
929, 45, /* V */
1024, 62, /* W */
1087, 48, /* X */
1136, 47, /* Y */
1184, 39, /* Z */
1224, 21, /* 1*/
/* page break here*/
65536, 41, /* 2 */
65578, 41, /* 3 */
65620, 44, /* 4 */
65665, 42, /* 5 */
65708, 43, /* 6 */
65752, 39, /* 7 */
65792, 41, /* 8 */
65834, 42, /* 9 */
65877, 42, /* 0 */
65920, 16, /* ! */
65937, 41, /* ? */
65979, 40, /* + */
66020, 19, /* - */
66048, 16, /* : */
66065, 10, /* ' */
66076, 22, /* " */
66099, 16, /* . */
66116, 22, /* * NOT USED*/
66116, 22, /* / NOT USED*/
66116, 22, /* # NOT USED */
66116, 22, /* $ NOT USED */
66116, 22, /* ( NOT USED */
66116, 22, /* ) NOT USED */
66116, 22, /* Space */
};
#endif /*ULTRA64 */
static FontHdr_t _SFontHdr = {
FONT2_WIDTH,
FONT2_HEIGHT,
FONT2_SPACING,
FONT2_YSPACING,
};
static FontHdr_t _LFontHdr = {
FONT1_WIDTH,
FONT1_HEIGHT,
FONT1_SPACING,
FONT1_YSPACING,
};
static FontHdr_t _H1FontHdr = {
FONT3_WIDTH,
FONT3_HEIGHT,
FONT3_SPACING,
FONT3_YSPACING,
};
static FontHdr_t _H2FontHdr = {
FONT3_WIDTH,
FONT3_HEIGHT,
FONT3_SPACING,
FONT3_YSPACING,
};
static FontHdr_t _UCH2FontHdr = {
FONT3_WIDTH,
FONT3_HEIGHT,
FONT3_SPACING,
FONT3_YSPACING,
};
#if TARGET==ULTRA64
static FontHdr_t _UCH2FontHdr_50 = {
FONT3_50_WIDTH,
FONT3_50_HEIGHT,
FONT3_50_SPACING,
FONT3_50_YSPACING,
};
static FontHdr_t _UCH2FontHdr_35 = {
FONT3_35_WIDTH,
FONT3_35_HEIGHT,
FONT3_35_SPACING,
FONT3_35_YSPACING,
};
static FontHdr_t _UCH2FontHdr_150 = {
FONT3_150_WIDTH,
FONT3_150_HEIGHT,
FONT3_150_SPACING,
FONT3_150_YSPACING,
};
#endif /*ULTRA64 */
static TextImage_t _aLFontTextImage[] = {
"T_TFONTLG90", NULL
};
static TextImageList_t _LFontTextImageList = {
1,
_aLFontTextImage
};
static TextImage_t _aSFontTextImage[] = {
"T_TFONTSM10", NULL/* "T_TFONTSM90", NULL*/
};
static TextImageList_t _SFontTextImageList = {
1,
_aSFontTextImage
};
static TextImage_t _aH1FontTextImage[] = {
"THWHUDTLA20", NULL
};
static TextImageList_t _H1FontTextImageList = {
1,
_aH1FontTextImage
};
static TextImage_t _aH2FontTextImage[] = {
"THWHUDTLA21", NULL,
"THWHUDTLA22", NULL,
};
static TextImageList_t _H2FontTextImageList = {
2,
_aH2FontTextImage
};
#if TARGET==ULTRA64
/* Place all font on single texture, blit as sprite so size doesn't matter (she said!) */
/* _H2FontSpacing, &_H2FontHdr - change FontSpacing, for my */
static TextImage_t _aUCH2FontTextImage[] = { /*PAB Game font, \art\textures\wrapper\hud */
"THWHUDTLA21", NULL, /* 0.75 */
"THWHUDTLA22", NULL, /* 0.5 */
"THWHUDTLA23", NULL, /* 0.35 */
"THWHUDTLA24", NULL /* 1.5 */
};
static TextImageList_t _UCH2FontTextImageList = {
4,&_aUCH2FontTextImage[0] /*PAB Load 'x' font files, for scales */
};
static TextImageList_t _UCH2FontTextImageList_50 = { 0,&_aUCH2FontTextImage[1] };
static TextImageList_t _UCH2FontTextImageList_35 = { 0,&_aUCH2FontTextImage[2] };
static TextImageList_t _UCH2FontTextImageList_150 = { 0,&_aUCH2FontTextImage[3] };
#else /*ULTRA64 */
static TextImage_t _aUCH2FontTextImage[] = {
"THWHUDTLA51", NULL,
"THWHUDTLA52", NULL,
};
static TextImageList_t _UCH2FontTextImageList = {
2,
_aUCH2FontTextImage
};
#endif /*ULTRA64 */
/* Note: All fonts are assumed to be on 1 or more 256x256 texture pages*/
#if TARGET==ULTRA64
/* Scale to font set tables, store scaled fonts as new fonts on same texture page */
N64FontScale UCH2FontScale[] = {
{ 1.6, 3 }, /* 1,2,3,4th (end race) */
{ 1.5, 3 }, /* 1,2,3 GO */
{ 0.75, 0 }, /* Timer on HUD */
{ 0.65, 0 }, /* Time extended */
{ 0.67, 0 }, /* 'x' of 16 */
{ 0.5, 1 }, /* 16 */
{ 0.45, 1 }, /* 'PAB' (end race) */
{ 0.38, 2 }, /* 'best time' (end race) */
{ 0.35, 2 }, /* 'of' */
{ 0.33, 2 }, /* 'of' */
{ 0.3, 2 }, /* 'best time' */
{ -1, 0 } /*term */
};
static TextFont_t _aFontTab[TEXT_MAX_FONTS] = {
//NOTE!
// Arcade only seems to use:- LARGE,SMALL and USER_COLORED_HUD2!!!
{ FALSE, &_LFontTextImageList, _LFontSpacing, &_LFontHdr, 0, NULL },
{ FALSE, &_SFontTextImageList, _SFontSpacing, &_SFontHdr, 0, NULL },
{ FALSE, &_H1FontTextImageList, _H1FontSpacing, &_H1FontHdr, 0, NULL },
{ FALSE, &_H2FontTextImageList, _H2FontSpacing, &_H2FontHdr, 0, NULL },
{ FALSE, &_UCH2FontTextImageList, _H2FontSpacing, &_UCH2FontHdr, 0, UCH2FontScale },
{ FALSE, &_UCH2FontTextImageList_50, _H2FontSpacing_50, &_UCH2FontHdr_50, 0, NULL },
{ FALSE, &_UCH2FontTextImageList_35, _H2FontSpacing_35, &_UCH2FontHdr_35, 0, NULL },
{ FALSE, &_UCH2FontTextImageList_150, _H2FontSpacing_150, &_UCH2FontHdr_150, 0, NULL },
};
#else /*ULTRA64 */
static TextFont_t _aFontTab[TEXT_MAX_FONTS] = {
{ FALSE, &_LFontTextImageList, _LFontSpacing, &_LFontHdr, 0 },
{ FALSE, &_SFontTextImageList, _SFontSpacing, &_SFontHdr, 0 },
{ FALSE, &_H1FontTextImageList, _H1FontSpacing, &_H1FontHdr, 0 },
{ FALSE, &_H2FontTextImageList, _H2FontSpacing, &_H2FontHdr, 0 },
{ FALSE, &_UCH2FontTextImageList, _H2FontSpacing, &_UCH2FontHdr, 0 },
};
#endif /*ULTRA64 */
/*===================*/
/* private prototypes*/
static void _SendAll( TextLetter_t *pLetter, u32 nLetters );
#if TARGET==ULTRA64
static char * _SPrintF(char *pFormat, va_list pArg);
#else
static char * __cdecl _SPrintF( char *pFormat, va_list pArg );
#endif /*ULTRA64 */
static char * _BuildNumberStr( long Num, BOOL bUnsigned );
static void _NumString( char **ppStrPtr, u32 val );
static char * _CopyNumAndStr( long Num, char *Str );
/*=================*/
/* public functions*/
BOOL text_ModuleInit( void ) {
text_ResetSystem();
_A.oow = _B.oow = _C.oow = _D.oow = 1.0f;
return TRUE;
}
void text_ResetSystem( void ) {
TextImageList_t * pImageList;
u8 i, j;
_nCurFont = 0;
Text_nAttr = TEXT_NORMAL | TEXT_BUFFER;
Text_nStyle = FSTYLE_PITCHED;
Text_fScale = 1.0f;
Text_fX=0.0f;
Text_fY=0.0f;
for( i=0; i<TEXT_MAX_FONTS; i++ ) {
_aFontTab[i].bLoaded = FALSE;
pImageList = _aFontTab[i].pTextImageList;
for( j=0; j<pImageList->nCount; j++ )
pImageList->pTextImageArray[j].pTexDef = (TexDef_t *) NULL;
}
_pHdr = _aFontTab[0].pHeader;
_pWidthTable = _aFontTab[0].pMapping;
_ConstantColor = GFXDEFS_INTARGB_TO_GRCOLOR( 0, 255, 255, 255 );
#if TARGET==ULTRA64
N64ConstantColour = NULL;
#endif /*ULTRA64*/
}
BOOL text_LoadFont( TextFontID Font ) {
GrAspectRatio_t index;
FontHdr_t * pHdr;
TextImageList_t * pImageList;
u32 i;
if( Font > TEXT_MAX_FONTS || Font < 0) {
return FALSE;
}
if( !_aFontTab[Font].bLoaded ) {
pImageList = _aFontTab[Font].pTextImageList;
for( i=0; i<pImageList->nCount; i++ ) {
if( (pImageList->pTextImageArray[i].pTexDef = (TexDef_t *)obsys_Load(pImageList->pTextImageArray[i].pszName)) == NULL)
{
return FALSE;
}
}
_aFontTab[Font].bLoaded = TRUE;
index = pImageList->pTextImageArray[0].pTexDef->TexInfo.aspectRatio;
pHdr = _aFontTab[Font].pHeader;
_aFontTab[Font].nHeight = (int) Tmem_afTexScale_T[ index ];
}
return TRUE;
}
void text_ReleaseFont( TextFontID Font ) {
if( Font > TEXT_MAX_FONTS || Font < 0 ) {
return;
}
_aFontTab[Font].bLoaded = FALSE;
}
BOOL text_SetFont( TextFontID Font ) {
if ( Font > TEXT_MAX_FONTS || Font < 0) {
return FALSE;
}
if (!(_aFontTab[Font].bLoaded)) {
return FALSE;
}
_pHdr = _aFontTab[Font].pHeader;
_pWidthTable = _aFontTab[Font].pMapping;
Text_nAttr = TEXT_ATTRDEFAULTS;
if (_pWidthTable==NULL)
Text_nStyle = 0;
else
Text_nStyle = FSTYLE_PITCHED;
_nCurFont = Font;
Text_fScale = 1.0f;
_nWidth = _pHdr->nWidth;
_nHeight = _pHdr->nHeight;
_nSpacing = _pHdr->nSpacing;
_nYSpacing = _pHdr->nYSpacing;
_fHeight = (f32)_nHeight;
_fSpacing = (f32)_nSpacing;
_ConstantColor = GFXDEFS_INTARGB_TO_GRCOLOR( 0, 255, 255, 255 );
return TRUE;
}
void text_SetBuffering( BOOL bBuffering ) {
if (bBuffering)
Text_nAttr |= TEXT_BUFFER;
else
Text_nAttr &= (TEXT_BUFFER ^ 0xFFFFFFFF);
}
void text_SetAttr( unsigned int attr ) {
Text_nAttr = (Text_nAttr & TEXT_ATTRSAVE) | (attr & TEXT_ATTRSET);
if( !(Text_nAttr & TEXT_HIGHLIGHT) ) {
Text_nAttr |= TEXT_NORMAL;
}
}
void text_ClearAttr( unsigned int attr ) {
Text_nAttr &= ~attr;
if( !(Text_nAttr & TEXT_HIGHLIGHT) ) {
Text_nAttr |= TEXT_NORMAL;
}
}
void text_SetStyle( unsigned long Style ) {
Text_nStyle = Style;
}
char * text_BuildHexString( long number, char* hexnumber ) {
hexnumber += 10;
*hexnumber-- = '\0';
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
number >>= 4;
*hexnumber-- = Text_aHexChar[number&0x0f];
*hexnumber-- = 'X';
*hexnumber = '0';
return( hexnumber );
}
#if TARGET==ULTRA64
#include "u64draw.h"
#include "u64sprite.h"
// Palettes for HUD coloured font, export from 'Sprite64' utility from file \hydro\gfx\textures\wrapper\hud\hudpal.pcx
unsigned short int TextPalette_Orange[] = { 0x0000,0x6841,0x7841,0x8881,0x9901,0xB141,0xC1C1,0xD241,0xDA81,0xDB01,0xE381,0xEC01,0xEC81,0xF541,0xF5C1,0xFE41 };
unsigned short int TextPalette_Blue[] = { 0x0000,0x0005,0x0007,0x0009,0x000B,0x000D,0x0011,0x0013,0x0017,0x001B,0x001F,0x0023,0x0027,0x002B,0x002F,0x0035 };
unsigned short int TextPalette_SkyBlue[] = { 0x0000,0x0045,0x0047,0x0089,0x008B,0x00CD,0x0111,0x0113,0x0157,0x019B,0x01DF,0x0223,0x0267,0x02AB,0x02EF,0x0375 };
unsigned short int TextPalette_Cyan[] = { 0x0000,0x0085,0x00C7,0x0109,0x014B,0x018D,0x0211,0x0253,0x02D7,0x035B,0x03DF,0x0463,0x04E7,0x056B,0x05EF,0x06B5 };
unsigned short int TextPalette_Green[] = { 0x0000,0x0081,0x00C1,0x0101,0x0141,0x0181,0x0201,0x0241,0x02C1,0x0341,0x03C1,0x0441,0x04C1,0x0541,0x05C1,0x0681 };
unsigned short int TextPalette_Lime[] = { 0x0000,0x0881,0x08C1,0x1101,0x1141,0x1981,0x2201,0x2241,0x2AC1,0x3341,0x3BC1,0x4441,0x4CC1,0x5541,0x5DC1,0x6E81 };
unsigned short int TextPalette_Red[] = { 0x0000,0x1001,0x1801,0x2001,0x2801,0x3001,0x4001,0x4801,0x5801,0x6801,0x7801,0x8801,0x9801,0xA801,0xB801,0xD001 };
unsigned short int TextPalette_Magenta[] = { 0x0000,0x1005,0x1807,0x2009,0x280B,0x300D,0x4011,0x4813,0x5817,0x681B,0x781F,0x8823,0x9827,0xA82B,0xB82F,0xD035 };
unsigned short int TextPalette_Yellow[] = { 0x0000,0x1081,0x18C1,0x2101,0x2941,0x3181,0x4201,0x4A41,0x5AC1,0x6B41,0x7BC1,0x8C41,0x9CC1,0xAD41,0xBDC1,0xD681 };
unsigned short int TextPalette_White[] = { 0x0000,0x1085,0x18C7,0x2109,0x294B,0x318D,0x4211,0x4A53,0x5AD7,0x6B5B,0x7BDF,0x8C63,0x9CE7,0xAD6B,0xBDEF,0xD6B5 };
#endif /*ULTRA64 */
#if TARGET==ULTRA64
int text_StrWidth_N64( char *Text ) {
int Length=0,nLetters=0;
s32 c;
while (nLetters<STRING_MAX_LENGTH && (c = (int) Text[nLetters]-32)>=0) {
Length += _pWidthTable[_ASCIITable[c]].nWidthN64 + _pHdr->nSpacing;
nLetters++; /* Next character */
}
return(Length);
}
void text_PrintStr( f32 X, f32 Y, char *Text ) {
//#if 0
TextImageList_t *pImageList;
TexDef_t *pTexDef;
FontMap_t *pFontMap;
TextLetter_t Letter;
u32 TexAddr;
s32 c,nLetters;
int scrx,scry;
int i,w,h,basex,basey,CurFontOffset;
BOOL OldN64ScaleFont;
/* Find screen x,y - all text is now done in screen coords */
scrx = (X*N64OrthoScaleX)+12;
scry = (Y*N64OrthoScaleY)+12;
/* Find textures, on one texture page(doesn't change per character, so use index '0') */
/*!!! Could use multiple texture pages, and set this [0] to scale version??? */
/* Scan to find offset for scale of font and select */
CurFontOffset = 0;
if ( (_N64ScaleTable = _aFontTab[_nCurFont].N64ScaleTable) ) {
i=0;
while(_N64ScaleTable[i].Scale>0) {
// If scaling, make sure use same font source
if (N64ScaleFont) {
if (_N64ScaleTable[i].Scale==N64OrigScale) {
CurFontOffset = _N64ScaleTable[i].FontOffset;
goto got_it;
}
}
else {
if (_N64ScaleTable[i].Scale==Text_fScale) {
CurFontOffset = _N64ScaleTable[i].FontOffset;
goto got_it;
}
}
i++; /* Next font */
}
// CONSOLE("Can't find scale match %f\n",Text_fScale); / Comment this in to see if need to create scaled fonts!
}
// else
// CONSOLE("Can't find scale table %d\n",_nCurFont);
got_it:
_pHdr = _aFontTab[_nCurFont+CurFontOffset].pHeader;
_pWidthTable = _aFontTab[_nCurFont+CurFontOffset].pMapping;
pImageList = _aFontTab[_nCurFont+CurFontOffset].pTextImageList;
pTexDef = pImageList->pTextImageArray[0].pTexDef;
/* Do we have texture for this font? */
if (pTexDef) {
TexAddr = pTexDef->aTMUTexInfo[0].nTmemStartAddress;
if (RunGameHiRes) {
OldN64ScaleFont = N64ScaleFont;
N64ScaleFont = TRUE; //hi-res
}
/* Start sprite off by setting render mode and palette */
if ( (N64ConstantColour) && ((_nCurFont>=TEXT_FONT_USER_COLORED_HUD2) && (_nCurFont<=TEXT_FONT_USER_COLORED_HUD2_150)) )
BeginSprite(&N64GfxDlPtr,TexAddr,N64ConstantColour,SPRITE_FLAG_16COLOUR);
else
BeginSprite(&N64GfxDlPtr,TexAddr,TexAddr+N64TEXTURE_SIZE_16COL(pTexDef->nWidth,pTexDef->nHeight),SPRITE_FLAG_16COLOUR);
if (RunGameHiRes)
N64ScaleFont = OldN64ScaleFont; //hi-res
/* Justify */
if( Text_nStyle & FSTYLE_CENTER_X ) {
if (RunGameHiRes)
scrx -= (text_StrWidth_N64(Text)*(512.0/320.0))/2;
else
scrx -= text_StrWidth_N64(Text)/2;
}
/* Scan string */
nLetters = 0;
while (nLetters<STRING_MAX_LENGTH && (c = (int) Text[nLetters]-32)>=0) {
/* Get character to plot(logical index), and fontmap table */
pFontMap = &_pWidthTable[_ASCIITable[c]];
/* Need :- x,y,character, *FontMap_t to get sprite offset etc... */
basex = pFontMap->nXOff&0xff; /* 'X' offset into texture */
basey = (pFontMap->nXOff>>8)*_pHdr->nHeight; /* 'Y' offset into texture */
w = (pFontMap->nWidthN64+15)&0xfffffff0; /* w/h, width is multiple of 16 pixels(8 bytes) */
h = _pHdr->nHeight;
/* Draw character */
if (N64ScaleFont) {
if (RunGameHiRes)
DrawScaledSpriteChar(&N64GfxDlPtr,TexAddr,NULL,w,h,scrx,scry
,256,256,basex,basey,(Text_fScale/N64OrigScale)*(512.0/320.0),Text_fScale/N64OrigScale,SPRITE_FLAG_16COLOUR);
else
DrawScaledSpriteChar(&N64GfxDlPtr,TexAddr,NULL,w,h,scrx,scry
,256,256,basex,basey,Text_fScale/N64OrigScale,Text_fScale/N64OrigScale,SPRITE_FLAG_16COLOUR);
}
else {
if (RunGameHiRes)
DrawScaledSpriteChar(&N64GfxDlPtr,TexAddr,NULL,w,h,scrx,scry
,256,256,basex,basey,512.0/320.0,1.0,SPRITE_FLAG_16COLOUR);
else
DrawSpriteChar(&N64GfxDlPtr,TexAddr,NULL,w,h,scrx,scry
,256,256,basex,basey,SPRITE_FLAG_16COLOUR);
}
/* Advance screen coords */
if (RunGameHiRes)
scrx += (pFontMap->nWidthN64 + _pHdr->nSpacing)*(512.0/320.0);
else
scrx += pFontMap->nWidthN64 + _pHdr->nSpacing;
nLetters++; /* Next character */
}
/* If used scale font, end sprite as was using 1-cycle mode */
if (N64ScaleFont)
EndScaleSprite(&N64GfxDlPtr);
}
//#endif
}
#else /* ULTRA64 */
/* create the render data to print the string Text at pixel (X, Y)*/
void text_PrintStr( f32 X, f32 Y, char *Text ) {
static char LText[STRING_MAX_LENGTH+1];
static u16 val;
s32 i, c, nLetters, iend, iinc;
f32 fSpace, fWidth, fOffset, fTextY;
u32 Val;
TextLetter_t *pLetter;
TextImageList_t *pImageList;
#ifdef _DEBUG
if ( !_aFontTab[_nCurFont].bLoaded )
return;
#else
XASSERT( _aFontTab[_nCurFont].bLoaded );
#endif
Text_fX = X;
Text_fY = Y;
/* Get string length and convert to logical chars */
nLetters = 0;
while( nLetters < STRING_MAX_LENGTH && (c = (int)Text[nLetters]-32) >= 0 ) {
LText[nLetters++] = _ASCIITable[c];
}
if( nLetters+_nNumLetters >= TEXT_MAX_LETTERS ) {
return;
}
/* setup the text data buffer*/
pLetter = _pBuffer + _nNumLetters;
if( Text_nAttr & TEXT_BUFFER ) {
_nNumLetters += nLetters;
}
/* Set letter spacing and set offsets */
fSpace = _fSpacing;
if( Text_nStyle & FSTYLE_CENTER_X ) {
if( Text_nStyle & FSTYLE_PITCHED ) {
fSpace = 0;
for( i=0; i < nLetters; i++ ) {
fSpace += (f32)_pWidthTable[ (int)LText[i] ].nWidth + 1.0f;
}
Text_fX -= 0.5f * Text_fScale * fSpace;
} else {
Text_fX -= 0.5f * Text_fScale * fSpace * ( (f32)nLetters );
}
}
if( Text_nStyle & FSTYLE_CENTER_Y ) {
fTextY = Y - (_fHeight * 0.5f * Text_fScale);
} else {
fTextY = Y;
}
/* set up loop values for justify */
if( Text_nStyle & FSTYLE_RIGHTJUST ) {
i = nLetters-1;
iend = -1;
iinc = -1;
} else {
i = 0;
iend = nLetters;
iinc = 1;
}
fOffset = 0;
pImageList = _aFontTab[_nCurFont].pTextImageList;
while( i != iend ) {
c = (int) LText[i];
fWidth = (f32)_pWidthTable[c].nWidth;
Val = _pWidthTable[c].nXOff;
if (Text_nStyle & FSTYLE_PITCHED)
fSpace = fWidth;
else {
fOffset = fSpace - fWidth;
}
if (Text_nStyle & FSTYLE_RIGHTJUST) {
Text_fX -= (fSpace-(fOffset*0.5f))*Text_fScale;
}
else {
Text_fX += (fOffset*0.5f)*Text_fScale;
}
fOffset *= 0.5f;
pLetter->nAttr = Text_nAttr&TEXT_POLYMASK;
pLetter->fX = Text_fX;
pLetter->fY = fTextY;
pLetter->fWidth = fWidth - 1.0f;
pLetter->fHeight = _fHeight - 1.0f;
pLetter->fScale = Text_fScale;
pLetter->nOffset = Val & 0xffff;
Val = Val >> 16;
#ifdef _DEBUG
if( Val >= pImageList->nCount )
Val = 0;
#endif
pLetter->pTexDef = pImageList->pTextImageArray[Val].pTexDef;
pLetter->fYOff = (f32)_aFontTab[_nCurFont].nHeight;
pLetter->ConstantColor = _ConstantColor;
val++;
val &= 0x3ff;
pLetter++;
if( !(Text_nStyle & FSTYLE_RIGHTJUST) ) {
Text_fX += (fSpace+fOffset)*Text_fScale+1.0f;
} else {
Text_fX -= ((fOffset * Text_fScale) + 1.0f);
}
i += iinc;
}
if( !(Text_nAttr & TEXT_BUFFER) ) {
_SendAll( _pBuffer + _nNumLetters, nLetters );
}
}
#endif /*ULTRA64 */
void text_PrintChar( f32 X, f32 Y, char c ) {
_str[0] = c;
_str[1] = '\0';
text_PrintStr( X, Y, _str );
}
void text_PrintNumber( f32 X, f32 Y, long Num ) {
char * pStrPtr;
if( Text_nStyle & FSTYLE_HEX ) {
pStrPtr = text_BuildHexString( Num, _str );
} else {
pStrPtr = _BuildNumberStr( Num, (Text_nStyle & FSTYLE_UNSIGNED) );
}
text_PrintStr( X, Y, pStrPtr );
}
/* simplified version of printf, only accepts the following formatting options:*/
/* %d - long number*/
/* %f - float number with 2 decimal places of fraction*/
/* %s - string insertion*/
/* %u - unsigned number*/
/* %x - unsigned hex number*/
/* a zero (0) after the % will affect %d and %u only*/
/* a number (x) before the type will affect %d and %u only*/
/* the number sets the number of spaces to fill with blanks (right justify to fill x spaces)*/
/* the preceding zero will prepend 0s instead of blanks*/
/* e.g. %02d will force printing 03 instead of 3*/
#if TARGET==ULTRA64
void text_PrintF( f32 X, f32 Y, char *pFormat, ... ) {
char * pStrPtr;
va_list pArg;
va_start(pArg, pFormat); /* start the arg list */
pStrPtr = _SPrintF( pFormat, pArg );
text_PrintStr( X, Y, pStrPtr );
}
#else /*ULTRA64 */
void __cdecl text_PrintF( f32 X, f32 Y, char *pFormat, ... ) {
char * pStrPtr;
va_list pArg;
va_start(pArg, pFormat); /* start the arg list*/
pStrPtr = _SPrintF( pFormat, pArg );
text_PrintStr( X, Y, pStrPtr );
}
#endif /*ULTRA64 */
/* specialized print function for HUD messages to the player*/
/* if there needs to be a space in between the Str should have it built in*/
void text_PrintNumAndStr( f32 X, f32 Y, long Num, char *Str ) {
char *StrPtr;
StrPtr = _CopyNumAndStr(Num, Str);
text_PrintStr( X, Y, StrPtr);
}
/* text_Flush() - Send all the text polys to the screen in buffered mode*/
void text_Flush( void ) {
#if TARGET!=ULTRA64
/* On N64, we simply plot text character sprites as we scan them, so not flushing needed! */
XASSERT( ("Text: Buffer overflow", _nNumLetters<TEXT_MAX_LETTERS) );
if ( Text_nAttr & TEXT_BUFFER ) {
_SendAll( _pBuffer, _nNumLetters );
}
/* reset buffer*/
_nNumLetters = 0;
#endif /*ULTRA64 */
}
#if TARGET!=ULTRA64 /* This doesn't seem to be used! Doh! */
f32 text_StrWidth( char *Text ) {
f32 len=0;
char c;
while( c = *Text++ ) {
len += Text_fScale * ((f32)_pWidthTable[_ASCIITable[c-32]].nWidth) + 1.5f;
}
return( len );
}
#endif /*ULTRA64 */
void text_SetConstantColor( u8 nWhiteSat, u8 nR, u8 nG, u8 nB ) {
_ConstantColor = GFXDEFS_INTARGB_TO_GRCOLOR( nWhiteSat, nR, nG, nB );
#if TARGET==ULTRA64
N64ConstantColour = NULL;
// When set text colour, set index into palette for us!
if (nR==0) {
//0, 0, 255 - Blue (2) *
//0, 128, 200 - Sky Blue (3) *
//0, 128, 255 - Darken sky Blue (as Sky)
//0, 255, 255 - Cyan (4) *
//0, 255, 0 - Green (5) *
if (nG==0)
N64ConstantColour = TextPalette_Blue;
else if (nG==128)
N64ConstantColour = TextPalette_SkyBlue;
else if (nG==255) {
if (nB==255)
N64ConstantColour = TextPalette_Cyan;
else if (nB==0)
N64ConstantColour = TextPalette_Green;
}
}
else if (nR==128) {
//128, 255, 0 - Lime Green (6) *
if (nG==255)
N64ConstantColour = TextPalette_Lime;
}
else if (nR==255) {
//255, 0, 0 - Red (7) *
//255, 0, 255 - Magenta (8) *
//255, 128, 0 - Orange (1) *
//255, 175, 0 - Bright Orange(as Orange)
//255, 255, 0 - Yellow (9) *
//255, 255, 255 - White (10) *
if (nG==0) {
if (nB==0)
N64ConstantColour = TextPalette_Red;
else if (nB==255)
N64ConstantColour = TextPalette_Magenta;
}
else if (nG==255) {
if (nB==0)
N64ConstantColour = TextPalette_Yellow;
else if (nB==255)
N64ConstantColour = TextPalette_White;
}
else {
if (nB==0)
N64ConstantColour = TextPalette_Orange;
}
}
if (N64ConstantColour==NULL) {
CONSOLE("N64 Cannot find constant colour(text.c) %d,%d,%d\n",(int)nR&0xff,(int)nG&0xff,(int)nB&0xff);
for(;;);
}
#endif /*ULTRA64*/
}
/*==================*/
/* private functions*/
#if TARGET!=ULTRA64 && TARGET!=DREAMCAST
static void _SendAll( TextLetter_t *pLetter, u32 nLetters ) {
f32 fX, fY, fScale, fS, fT, fHeight, fWidth;
int nTextureFormat;
GrColor_t Color;
if( !nLetters ) {
/* no letters to draw, just return*/
return;
}
/* setup the texture and palette info*/
material_PushState();
/* render each TextLetter_t*/
material_ConstantColorValue( _ConstantColor );
Color = _ConstantColor;
nTextureFormat = -1;
while( nLetters-- ) {
tmem_Select( pLetter->pTexDef );
tmem_SetTileMode( pLetter->pTexDef, 0, 0);
/* setup the color/alpha combine modes*/
if( nTextureFormat != pLetter->pTexDef->TexInfo.format ) {
nTextureFormat = pLetter->pTexDef->TexInfo.format;
switch( nTextureFormat )
{
case GR_TEXFMT_P_8:
material_Defaults();
material_ColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_NONE,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
material_AlphaTestReferenceValue( (GrAlpha_t) 1 );
material_ChromakeyMode( GR_CHROMAKEY_ENABLE );
break;
case GR_TEXFMT_ARGB_1555:
case GR_TEXFMT_ARGB_4444:
material_Defaults();
material_ColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_NONE,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
material_AlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_NONE,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
break;
case GR_TEXFMT_ALPHA_INTENSITY_44:
case GR_TEXFMT_ALPHA_INTENSITY_88:
material_ColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA,
GR_COMBINE_FACTOR_LOCAL,
GR_COMBINE_LOCAL_CONSTANT,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
material_AlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_CONSTANT,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
break;
default:
/* unhandled texture fomat*/
xprintferr( "TEXT: Unhandled font texture format\n" );
continue;
break;
}
}
/* set the constant color*/
if( Color != pLetter->ConstantColor ) {
material_ConstantColorValue( pLetter->ConstantColor );
Color = pLetter->ConstantColor;
}
fS = (f32)( pLetter->nOffset & 0xff );
fT = pLetter->fYOff - ( (pLetter->nOffset >> 8) * (pLetter->fHeight + 1.0f) );
fX = pLetter->fX;
fY = Viewport_vres - pLetter->fY;
fWidth = pLetter->fWidth;
fHeight = pLetter->fHeight;
fScale = pLetter->fScale;
_A.x = _C.x = GFXDEFS_SNAPVERT( fX );
_A.y = _B.y = GFXDEFS_SNAPVERT( fY );
_B.x = _D.x = GFXDEFS_SNAPVERT( fX + (fScale * fWidth) );
_C.y = _D.y = GFXDEFS_SNAPVERT( fY - (fScale * fHeight) );
_A.tmuvtx[0].sow = _A.tmuvtx[1].sow = _C.tmuvtx[0].sow = _C.tmuvtx[1].sow = fS + 0.5f;
_A.tmuvtx[0].tow = _A.tmuvtx[1].tow = _B.tmuvtx[0].tow = _B.tmuvtx[1].tow = fT - 0.5f;
_B.tmuvtx[0].sow = _B.tmuvtx[1].sow = _D.tmuvtx[0].sow = _D.tmuvtx[1].sow = fS + fWidth - 0.5f;
_C.tmuvtx[0].tow = _C.tmuvtx[1].tow = _D.tmuvtx[0].tow = _D.tmuvtx[1].tow = fT - fHeight + 0.5f;
GUTIL_DRAW_TRIANGLE( &_A, &_B, &_C );
GUTIL_DRAW_TRIANGLE( &_B, &_D, &_C );
pLetter++;
}
/* restore the material info*/
material_PopState( 1 );
}
#endif /*ULTRA64 */
#if TARGET==DREAMCAST
static void _SendAll( TextLetter_t *pLetter, u32 nLetters ) {
f32 fX, fY, fScale, fS, fT, ftW, ftH, fHeight, fWidth;
int nTextureFormat,nTexture;
GrColor_t Color;
if( !nLetters ) {
/* no letters to draw, just return */
return;
}
Color = _ConstantColor;
nTextureFormat = -1;
while( nLetters-- ) {
if(pLetter->pTexDef == NULL)
return;
nTexture = pLetter->pTexDef->aTMUTexInfo[0].nTmemStartAddress;
if(nTexture != -1){
dcSetCurrentVertexContext(&dcTextureTable[nTexture].AlphaBlendedTexVC);
}
fS = (f32)( pLetter->nOffset & 0xff );
fT = pLetter->fYOff - ( (pLetter->nOffset >> 8) * (pLetter->fHeight + 1.0f) );
fS *= (1.0f/256.0f);
fT *= (1.0f/256.0f);
fX = pLetter->fX;
fY = 400.0f - (pLetter->fY + dcOrthoYOffset);
fWidth = pLetter->fWidth;
fHeight = pLetter->fHeight;
fScale = pLetter->fScale;
ftW = fWidth * (1.0f/256.0f);
ftH = fHeight * (1.0f/256.0f);
kmxxGetCurrentPtr(&VertexBufferDesc);
kmxxStartVertexStrip(&VertexBufferDesc);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
DCSCALEXCOORD(fX),
DCSCALEYCOORD(400.0f-(fY- (fScale * fHeight))), 3.0f,
fS, fT - ftH,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
DCSCALEXCOORD(fX + (fScale * fWidth)),
DCSCALEYCOORD(400.0f-(fY-(fScale * fHeight))), 3.0f,
fS + ftW, fT - ftH,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP,
DCSCALEXCOORD(fX),
DCSCALEYCOORD(400.0f - fY), 3.0f,
fS, fT,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
DCSCALEXCOORD(fX + (fScale * fWidth)),
DCSCALEYCOORD(400.0f-fY), 3.0f,
fS + ftW, fT,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
DCSCALEXCOORD(fX + (fScale * fWidth)),
DCSCALEYCOORD(400.0f-(fY- (fScale * fHeight))), 3.0f,
fS + ftW, fT - ftH,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP,
DCSCALEXCOORD(fX),
DCSCALEYCOORD(400.0f-fY), 3.0f,
fS, fT,
pLetter->ConstantColor|0xff000000, 0xff000000);
kmxxReleaseCurrentPtr(&VertexBufferDesc);
pLetter++;
}
/* restore the material info */
}
#endif /*DREAMCAST*/
#if TARGET==ULTRA64
static char * _SPrintF( char *pFormat, va_list pArg ) {
#else /*ULTRA64 */
static char * __cdecl _SPrintF( char *pFormat, va_list pArg ) {
#endif /*ULTRA64 */
char *pNext, *pStrPtr, *pCopy, c;
BOOL bZero;
u8 Spaces;
f32 fVal;
long nVal;
pStrPtr = _aCharBuffer;
for( pNext = pFormat; *pNext; pNext++ ) {
if( *pNext != '%' ) {
*pStrPtr++ = *pNext;
} else {
if( *++pNext == '0' ) {
bZero = TRUE;
pNext++;
} else {
bZero = FALSE;
}
Spaces = 0;
while( *pNext > '0' && *pNext < '9' ) {
Spaces = Spaces * 10 + (u8)( *pNext++ - '0' );
}
switch( *pNext )
{
case 'd':
pCopy = _BuildNumberStr(va_arg(pArg, int), 0);
if (Spaces) {
c = (bZero)?'0':' ';
Spaces -= xclib_strlen(pCopy);
while (Spaces-- > 0) {
*pStrPtr++ = c;
}
}
break;
case 'f':
fVal = (float) va_arg(pArg, f64);
nVal = (long) fVal;
pCopy = _BuildNumberStr(nVal, 0);
if (Spaces) {
c = (bZero)?'0':' ';
Spaces -= xclib_strlen(pCopy);
while (Spaces-- > 0) {
*pStrPtr++ = c;
}
}
while (*pCopy)
*pStrPtr++ = *pCopy++;
*pStrPtr++ = '.';
if( fVal<0 )
{
fVal = -fVal;
nVal = -nVal;
}
fVal -= (f32) nVal;
pCopy = _BuildNumberStr((long) (fVal*100.0f), 1);
if( xclib_strlen(pCopy)<2 )
*pStrPtr++ = '0';
break;
case 's':
pCopy = va_arg(pArg, char *);
break;
case 'u':
pCopy = _BuildNumberStr(va_arg(pArg, unsigned int), 1);
if (Spaces) {
c = (bZero)?'0':' ';
Spaces -= xclib_strlen(pCopy);
while (Spaces-- > 0) {
*pStrPtr++ = c;
}
}
break;
case 'x':
pCopy = text_BuildHexString(va_arg(pArg, unsigned int), _str);
break;
default:
XASSERT_NOW;
}
while( *pCopy ) {
*pStrPtr++ = *pCopy++;
}
}
}
*pStrPtr = NULL;
return( _aCharBuffer );
}
static char * _BuildNumberStr( long Num, BOOL bUnsigned ) {
u32 nVal;
char * pStrPtr;
BOOL bSign=FALSE;
if (Num<0)
{
if (!bUnsigned)
{
Num = -Num;
bSign=TRUE;
}
}
nVal = Num;
pStrPtr = &_str[STRING_MAX_LENGTH];
*pStrPtr ='\0';
if (nVal==0)
{
pStrPtr--;
*pStrPtr = '0';
} else {
_NumString(&pStrPtr, nVal);
if (bSign) {
pStrPtr--;
*pStrPtr = '-';
}
}
return (pStrPtr);
}
static void _NumString( char **ppStrPtr, u32 val ) {
u32 m;
u32 Digit;
while( val!=0 )
{
m = (u32) ((f32) val*0.10);
Digit = (u32) ((unsigned int) val - 10*m);
val = m;
*ppStrPtr -= 1;
*(*ppStrPtr) = Digit+'0';
}
}
static char * _CopyNumAndStr( long Num, char *Str ) {
char *pStrPtr;
pStrPtr = &_str[STRING_MAX_LENGTH - xclib_strlen(Str)];
xclib_strcpy(pStrPtr, Str);
if (Num<=0)
{
pStrPtr--;
*pStrPtr = '0';
} else {
_NumString(&pStrPtr, Num);
}
return( pStrPtr );
}
statemgr.c
Found at 0x7C02000.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* statemgr.c - "handles all game state management"*/
/**/
/* Author: Michael Starich */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1998*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 03/19/98 Starich Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "statemgr.h"
#include "net_defs.h"
#include "net_link.h"
#include "player.h"
#include "timer.h"
#include "wpr_memmgr.h"
#include "wpr_attract.h"
#include "wpr_banker.h"
#include "wpr_select.h"
#include "gutil.h"
#include "obsys.h"
#include "sysmem.h"
#include "terrain.h"
#include "gameloop.h"
#include "text.h"
#include "operator.h"
#include "race.h"
#include "tracks.h"
#include "hi_score.h"
#include "hud.h"
#include "wpr_hiscore.h"
#include "cmos.h"
#include "boats.h"
#include "waterspray.h"
#include "temp.h"
#include "audio.h"
#include "wpr_defs.h"
#include "auditor.h"
#include "blit.h"
#include "ai_rabbit.h"
#include "bonuskeys.h"
#include "audits.h"
#include "sysmsg.h"
#include "leader_lights.h"
#include "watchdog.h"
#include "gameheap.h" /* PAB */
#if TARGET==ULTRA64 /*Point where can move arcade memory system around!!!*/
#include "u64draw.h"
#include "silib.h"
#endif
/*====================*/
/* private definitions*/
#define _TIME_TO_ANIMATE_A_TRACK_SELECTION 120 /* in 60th of a sec (2.0sec)*/
#define _TIME_TO_ANIMATE_A_BOAT_SELECTION 85 /* in 60th of a sec (1.42sec)*/
#define _SECS_TO_WAIT_TO_FOR_EMPTY_SELECT_MODE 0.5f /* in seconds*/
#define _NUM_TIMES_TO_SEND_HEREIAM_MSG 3
#define _NUM_TIMES_TO_SEND_ONLINE_MSG 3
typedef enum
{
_NO_ERROR = 0,
_NET_INIT_FAILED_TURN_OFF_NETWORK,
_WRONG_VERSION,
_BAD_UNIT_ID,
_BAD_R2FILE_CHECKSUM,
_WRONG_VERSION_AND_BAD_R2FILE_CHECKSUM,
_ERROR_COUNT
} ErrorCodes_t;
/*=================*/
/* public variables*/
StateInfo_t *Statemgr_pLocalData;
/*==================*/
/* private variables*/
static BOOL _bOkToShutdown;
static void *_pSysmemFrame;
static ObsysFrame_t _ObsysFrame;
static u32 _nTimerId;
static f32 _fTime;
static u16 _nErrorCode;
static BOOL8 _bAttractSegmentLoaded;
static BOOL8 _bDrawBankInfo;
static u32 _nTimeOut;
static u32 _nTrackSelectTicks;
static u32 _nBoatSelectTicks;
static f32 _fHiScoreSecs;
static StateInfo_t _StateData;
static f32 _fTime2EnterHiScore;
static u16 _nNumOnlineMsgsSent;
static u16 _nNumHereIAmMsgSent;
static u32 _nNumContinues;
/* used to keep track of the number of continues*/
static BOOL8 _bAlreadyEnteredIntials;
static char _cInitial1, _cInitial2, _cInitial3;
static f32 _fContinueSecs;
static BOOL _bAllowAdvancedBoats;
static u32 _nNeverResetFrameCounter;
static u32 _nAttractModeMusicSample;
u32 nPlayerSelecting;
u32 nBoatTypes[2];
/*===================*/
/* private prototypes*/
static void _DisplayHydroLogo( void );
static void _CommonStartupStuff( void );
static void _CommonExitStuff( void );
static void _ChangeStates( u32 nNewState );
static void _HiScoreLogic( BOOL bReset );
static void _GameSeedLogic( BOOL bReset );
static void _SeedUpNetSyncedRace( void );
static u32 _GetInstanceCountOfAHighScoreOnOneUnit( CmosHiScore_t *pHiScore );
static u32 _GetInstanceCountOfAHighScoreInSyncedList( CmosHiScore_t *pHiScore );
/*=================*/
/* public functions*/
BOOL statemgr_ModuleInit( void ) {
/* reset all global variables*/
_bOkToShutdown = FALSE;
_StateData.nCurrentState = STATEMGR_STARTUP;
Statemgr_pLocalData = &_StateData;
_nTimerId = 0;
_nErrorCode = _NO_ERROR;
_nTimeOut = 0;
_bAttractSegmentLoaded = FALSE;
_nTrackSelectTicks = (u32)(OperatorSettings.fTrackSelectSecs * 60.0f);
_nBoatSelectTicks = (u32)(OperatorSettings.fBoatSelectSecs * 60.0f);
_fHiScoreSecs = OperatorSettings.fHiScoreSecs;
_bDrawBankInfo = FALSE;
_fTime2EnterHiScore = 0.0f;
_nNumOnlineMsgsSent = 0;
_nNumHereIAmMsgSent = 0;
/* continue mode vars*/
_fContinueSecs = OperatorSettings.fContinueSecs;
_nNumContinues = 0;
_bAlreadyEnteredIntials = FALSE;
_cInitial1 = _cInitial2 = _cInitial3 = ' ';
bonuskeys_ResetSystem();
_bAllowAdvancedBoats = OperatorSettings.bAlwaysEnableAdvancedBoats;
_nNeverResetFrameCounter = 0;
_nAttractModeMusicSample = 0;
return TRUE;
}
/* call ONCE from the top of the gameloop, */
/* needs to happen after all module inits!*/
/* will init link software, link hardware,*/
/* and wrappers*/
void statemgr_Init( void ) {
_bOkToShutdown = TRUE;
_nNeverResetFrameCounter = 0;
/* allocate a timer */
_nTimerId = timer_AllocTimer ();
/* this is the only place where unload all and load common should happen!!!!*/
audio_UnloadAllBanks();
/* load the wrapper bank, it stays loaded at all times*/
if( !audio_LoadBank( AUDIO_BANK_WRAPPERS ) ) {
xprintferr( "STATEMGR: COULD NOT LOAD THE WRAPPER BANK\n" );
}
/* load the common bank, it stays loaded at all times*/
if( !audio_LoadBank( AUDIO_BANK_COMMON ) ) {
xprintferr( "STATEMGR: ERROR, COULD NOT LOAD THE COMMON BANK\n" );
}
/* load the game common bank, it stays loaded at all times*/
if( !audio_LoadBank( AUDIO_BANK_GAME_COMMON ) ) {
xprintferr( "STATEMGR: ERROR, COULD NOT LOAD THE GAME COMMON BANK\n" );
}
_CommonStartupStuff();
_bDrawBankInfo = FALSE;
/* if we successfully init the hardware we should */
/* try to find units to add to the link*/
if( net_link_Init() ) {
_ChangeStates( STATEMGR_LINK_BOOTUP );
} else {
if( Net_Link_nFlags & NET_DEFS_FLAGS_OPERATOR_NET_OFF ) {
/* the network failed because the operator has the network turned off, */
/* go ahead and start attract mode and just be a single unit*/
_ChangeStates( STATEMGR_ATTRACT );
} else if( Net_Link_nFlags & NET_DEFS_FLAGS_NET_COMM_FAIL ) {
/* there was a problem initing the link, and the */
/* operator wants the link on, goto error mode*/
_nErrorCode = _NET_INIT_FAILED_TURN_OFF_NETWORK;
_ChangeStates( STATEMGR_ERROR );
}
}
}
/* call ONCE when reseting (in WINDEV)*/
/* will shutdown link software, link hardware,*/
/* and wrappers*/
void statemgr_Shutdown( void ) {
if( _bOkToShutdown ) {
/* send out a unit off message*/
net_link_SendErrorMsg( NET_DEFS_ERROR_UNIT_TURNED_OFF, (u16)OperatorSettings.nNetUnitID );
timer_ReleaseTimer( _nTimerId );
_nTimerId = 0;
_nErrorCode = _NO_ERROR;
_bDrawBankInfo = FALSE;
net_link_Shutdown();
_nNumOnlineMsgsSent = 0;
_nNumHereIAmMsgSent = 0;
_bOkToShutdown = FALSE;
}
}
void statemgr_Work( int nParm ) {
u32 nTimer, nNextStage, nGroupSize, nTemp, nPlayers, i;
s32 nTemp1, nTemp2;
f32 fStagePercent = 0.0f;
BOOL bSkipAttractStage;
++_nNeverResetFrameCounter;
nPlayers = bEUROCOM_SPLITSCREEN ? 2 : 1;
switch( Statemgr_pLocalData->nCurrentState )
{
case STATEMGR_LINK_BOOTUP:
WATCHDOG_NEW_SECS( 10 );
nTimer = timer_ElapsedTicks( _nTimerId );
/* check our messages one more time, it is very important to not miss any messages during this time*/
net_link_PreWorkReceive( 1 );
/* check to see if we should high tail it to error mode*/
if( Net_Link_nFlags & NET_DEFS_FLAGS_ERROR_EXISTS ) {
/* see what type of error we have got*/
if( Net_Link_nFlags & (NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH) ) {
if( (Net_Link_nFlags & (NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH)) ==
(NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH) ) {
/* both data and code don't match*/
_nErrorCode = _WRONG_VERSION_AND_BAD_R2FILE_CHECKSUM;
_ChangeStates( STATEMGR_ERROR );
} else if( Net_Link_nFlags & NET_DEFS_FLAGS_WRONG_VERSION ) {
/* only the code version was wrong*/
_nErrorCode = _WRONG_VERSION;
_ChangeStates( STATEMGR_ERROR );
} else {
/* only the data was wrong*/
_nErrorCode = _BAD_R2FILE_CHECKSUM;
_ChangeStates( STATEMGR_ERROR );
}
} else if( Net_Link_nFlags & NET_DEFS_FLAGS_ID_ALREADY_USED ) {
_nErrorCode = _BAD_UNIT_ID;
_ChangeStates( STATEMGR_ERROR );
}
} else if( nTimer >= _nTimeOut ) {
/* see if we have any errors*/
if( Net_Link_nFlags & (NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH) ) {
if( (Net_Link_nFlags & (NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH)) ==
(NET_DEFS_FLAGS_WRONG_VERSION | NET_DEFS_FLAGS_R2FILE_MISMATCH) ) {
/* both data and code don't match*/
_nErrorCode = _WRONG_VERSION_AND_BAD_R2FILE_CHECKSUM;
_ChangeStates( STATEMGR_ERROR );
} else if( Net_Link_nFlags & NET_DEFS_FLAGS_WRONG_VERSION ) {
/* only the code version was wrong*/
_nErrorCode = _WRONG_VERSION;
_ChangeStates( STATEMGR_ERROR );
} else {
/* only the data was wrong*/
_nErrorCode = _BAD_R2FILE_CHECKSUM;
_ChangeStates( STATEMGR_ERROR );
}
} else if( Net_Link_nFlags & NET_DEFS_FLAGS_ID_ALREADY_USED ) {
_nErrorCode = _BAD_UNIT_ID;
_ChangeStates( STATEMGR_ERROR );
} else {
/* everything is ok, time to start attract mode*/
xprintf( "STATEMGR: Times up, switching to ATTRACT mode!\n" );
_ChangeStates( STATEMGR_ATTRACT );
}
} else {
if( (_nNumHereIAmMsgSent < _NUM_TIMES_TO_SEND_HEREIAM_MSG) && Gameloop_bOddFrame ) {
/* resend a NET_DEFS_MSG_HEREIAM (every other frame)*/
net_link_SendGenericMsg( NET_DEFS_MSG_HEREIAM, NET_DEFS_SEND_TO_ALL, 0 );
++_nNumHereIAmMsgSent;
}
if( nTimer > NET_DEFS_BOOTUP_SEND_ONLINE_MSG ) {
/* send _NUM_TIMES_TO_SEND_ONLINE_MSG online msgs, 2 frames apart, that way we handle dropped packets*/
if( (_nNumOnlineMsgsSent < _NUM_TIMES_TO_SEND_ONLINE_MSG) && Gameloop_bOddFrame ) {
/* send a NET_DEFS_MSG_ONLINE*/
net_link_SendGenericMsg( NET_DEFS_MSG_ONLINE, NET_DEFS_SEND_TO_ALL, 0 );
++_nNumOnlineMsgsSent;
}
}
}
_fTime = (f32)(nTimer * (1.0f/60.0f));
break;
case STATEMGR_ATTRACT:
WATCHDOG_NEW_SECS( 10 );
/* check our messages one more time, it is very important to not miss any messages during this time*/
net_link_PreWorkReceive( 1 );
nTimer = timer_ElapsedTicks( _nTimerId );
/* 1st: see if we should display the "join net game" screen*/
if( Net_Link_nSelectMask ) {
/* see if our current track is "join net game" screen, if not make it our current and set up next screen*/
if( wpr_attract_GetCurrentStage() != WPR_ATTRACT_JOIN ) {
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* stop the music*/
audio_GameIDStop( _nAttractModeMusicSample );
}
wpr_attract_LoadStage( WPR_ATTRACT_JOIN );
wpr_attract_SetCurrentStage( WPR_ATTRACT_JOIN );
wpr_banker_ResetFlashTime();
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
Net_Link_nAttractSyncCount = 0;
leader_lights_EnableAttractMode( 0, 0, FALSE );
}
} else {
if( Net_Link_bResetAttractMode || Net_Link_bNewAttractMember ) {
/* 2nd: if somebody has told us to reset to our first stage, do so now*/
/* 3rd: have we gotten any new members to attract mode*/
wpr_attract_ResetToFirstStage();
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
wpr_banker_ResetFlashTime();
_bAttractSegmentLoaded = FALSE;
Net_Link_nAttractSyncCount = 0;
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* fade out the attract music*/
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 2.5f );
}
leader_lights_EnableAttractMode( 0, 0, FALSE );
} else if( Net_Link_bAdvanceAttractStage ) {
/* 4th: somebody advanced the attract mode, lets do the same ( only if we are currently in an active stage )*/
if( wpr_attract_IsCurrentStageActive() ) {
/* change into our static screen stage and sync up with the other units*/
nNextStage = wpr_attract_GetNextStage();
wpr_attract_LoadStage( nNextStage );
wpr_attract_SetCurrentStage( nNextStage );
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
wpr_banker_ResetFlashTime();
_bAttractSegmentLoaded = FALSE;
Net_Link_nAttractSyncCount = 0;
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* fade out the attract music*/
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 2.5f );
}
leader_lights_EnableAttractMode( 0, 0, FALSE );
}
} else {
bSkipAttractStage = FALSE;
if( Controls_InputState.nButtons & (CONTROLS_VIEW1_BUTTON | CONTROLS_VIEW2_BUTTON | CONTROLS_VIEW3_BUTTON) ) {
/* 5th: if we are in an active attract mode and are more than 2.0 secs away from the end and more than 1.0 secs from the start*/
/* then advance to the next stage and let everybody else know about it*/
if( wpr_attract_IsCurrentStageActive() && (wpr_attract_GetCurrentStage() != WPR_ATTRACT_JOIN) ) {
if( ( (nTimer + 120) < _nTimeOut ) && ( nTimer > 60 ) ) {
/* send a message to everyone about the advance*/
net_link_SendGenericMsg( NET_DEFS_MSG_ATTRACT_ADVANCE, NET_DEFS_SEND_TO_ALL, 0 );
/* change into our static screen stage and sync up with the other units*/
nNextStage = wpr_attract_GetNextStage();
wpr_attract_LoadStage( nNextStage );
wpr_attract_SetCurrentStage( nNextStage );
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
wpr_banker_ResetFlashTime();
_bAttractSegmentLoaded = FALSE;
Net_Link_nAttractSyncCount = 0;
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* fade out the attract music*/
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 2.5f );
}
bSkipAttractStage = TRUE;
leader_lights_EnableAttractMode( 0, 0, FALSE );
}
}
}
if( !bSkipAttractStage ) {
/* we did not skip ahead to the next attract mode, see if our regular timer is up and it is time to advance */
if( nTimer >= _nTimeOut ) {
/* our wait time is up, lets see if we need to go to a static screen so that we can sync up*/
if( wpr_attract_IsCurrentStageActive() ) {
/* change into our static screen stage and sync up with the other units*/
nNextStage = wpr_attract_GetNextStage();
wpr_attract_LoadStage( nNextStage );
wpr_attract_SetCurrentStage( nNextStage );
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
wpr_banker_ResetFlashTime();
_bAttractSegmentLoaded = FALSE;
Net_Link_nAttractSyncCount = 0;
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* fade out the attract music*/
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 2.5f );
}
leader_lights_EnableAttractMode( 0, 0, FALSE );
} else { /* we are in a static screen, we need to sync up with everyone else*/
if( !_bAttractSegmentLoaded ) {
/* we have not loaded what we need to, we shall do so now, if the banker instructions are currently on the screen*/
if( wpr_banker_AreTheInstructionsCurrentlyDisplayed() ) {
/* make sure to handle a puchased game during a large load*/
if( wpr_attract_LoadStage( wpr_attract_GetNextStage() ) ) {
/* send a NET_DEFS_MSG_ATTRACT_SYNC msg*/
++Net_Link_nAttractSyncCount;
net_link_SendGenericMsg( NET_DEFS_MSG_ATTRACT_SYNC, NET_DEFS_SEND_TO_ALL, 0 );
_bAttractSegmentLoaded = TRUE;
}
}
} else {
/* we have loaded what we need to, lets see if we can move forward*/
nGroupSize = net_link_GetCurrentGroupSize();
if( Net_Link_nAttractSyncCount >= nGroupSize ) {
nNextStage = wpr_attract_GetNextStage();
/* start the music up for the next attract mode, only if all units are in attract mode*/
_nAttractModeMusicSample = wpr_attract_ShouldWeStartMusicForThisSegment( nNextStage );
if( _nAttractModeMusicSample ) {
if( !OperatorSettings.bSilentAttractMode ) {
if( OperatorSettings.bNetOffline || (net_link_GetNumberOfUnitsOnline() == nGroupSize) ) {
audio_Trigger( _nAttractModeMusicSample,
OperatorSettings.nAttractModeVolume,
AUDIO_PAN_CABINET, AUDIO_TYPE_MUSIC, AUDIO_PRIORITY_MUSIC );
}
}
}
wpr_attract_SetCurrentStage( nNextStage );
gameloop_ResetCounter();
/* reset the timers*/
timer_ResetTime( _nTimerId, 0 );
wpr_banker_ResetFlashTime();
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
nTimer = 0;
Net_Link_nAttractSyncCount = 0;
_bAttractSegmentLoaded = FALSE;
nTemp = net_link_GetNumberOfUnitsOnline();
if( nTemp == nGroupSize && nTemp > 1 ) {
/* all units are in attract mode do some leader light stuff*/
leader_lights_EnableAttractMode( net_link_GetOnlineUnitMask(),
OperatorSettings.nNetUnitID,
TRUE );
}
} else {
/* if we haven't gotten all of our sync messages by now, reset everyone's attract mode*/
if( nTimer > (_nTimeOut + 2000) ) {
net_link_SendGenericMsg( NET_DEFS_MSG_ATTRACT_RESET, NET_DEFS_SEND_TO_ALL, 0 );
wpr_attract_ResetToFirstStage();
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
wpr_banker_ResetFlashTime();
_bAttractSegmentLoaded = FALSE;
Net_Link_nAttractSyncCount = 0;
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* fade out the attract music*/
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 2.5f );
}
}
}
}
}
}
}
}
}
/* all vars can be reset for the next frame*/
Net_Link_bNewAttractMember = FALSE;
Net_Link_bAdvanceAttractStage = FALSE;
Net_Link_bResetAttractMode = FALSE;
/* convert our time to float secs*/
_fTime = (f32)(nTimer * (1.0f/60.0f));
if( !(Net_Link_nFlags & NET_DEFS_FLAGS_NEED_TO_RELINK) ) {
/* see if a game has been purchased*/
if( wpr_banker_BuyAGame( FALSE, TRUE ) ) {
/* unattach a button callback to the throttle button*/
controls_EnableACallbackToAButtonPress( FALSE, CONTROLS_THROTTLE_BUTTON );
if( !OperatorSettings.bSilentAttractMode && _nAttractModeMusicSample ) {
/* if we were playing any music other than WPR_DEFS_ATTRACT_MUSIC, fade it out*/
if( _nAttractModeMusicSample != WPR_DEFS_ATTRACT_MUSIC ) {
audio_GameIDFadeOutAndStop( _nAttractModeMusicSample, 1.25f );
_nAttractModeMusicSample = 0;
}
}
_DisplayHydroLogo();
audio_Trigger( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 225, AUDIO_PAN_CABINET, AUDIO_TYPE_GENERAL, AUDIO_PRIORITY_GENERAL );
wpr_attract_Close();
_ChangeStates( STATEMGR_SELECTION );
audio_GameIDFadeOutAndStop( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 0.5f );
leader_lights_EnableAttractMode( 0, 0, FALSE );
audits_LogANewRacePurchase();
} else {
wpr_attract_Work();
leader_lights_DoAttractWork();
}
} else {
/* unattach a button callback to the throttle button*/
controls_EnableACallbackToAButtonPress( FALSE, CONTROLS_THROTTLE_BUTTON );
/* we need to switch to relink mode, do so now*/
_ChangeStates( STATEMGR_RELINK );
leader_lights_EnableAttractMode( 0, 0, FALSE );
}
break;
case STATEMGR_SELECTION:
WATCHDOG_NEW_SECS( 10 );
nTimer = timer_ElapsedTicks( _nTimerId );
/* check our messages one more time, it is very important to not miss any messages during this time*/
net_link_PreWorkReceive( 1 );
switch( wpr_select_GetCurrentStage() )
{
case WPR_SELECT_TRACK:
/* see if a track has been selected*/
if( Net_Link_nTrackNum != -1 ) {
/* a selection has been made already*/
wpr_select_SetSelection( Net_Link_nTrackNum );
wpr_select_EnableSelectionChanges( FALSE );
/* record what happened with the auditor*/
auditor_TrackSelected( AUDITOR_METHODS_NET_SELECTED, Net_Link_nTrackNum, (f32)(nTimer * (1.0f/60.0f)) );
wpr_select_LoadStage( WPR_SELECT_TRACK_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_TRACK_ANIM );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
} else { /* no track has been selected, see if we have chosen one*/
for(i = 0; i < nPlayers; i++){
nTemp1 = wpr_select_CheckForSelection( i );
if( nTemp1 > Net_Link_nTrackNum){
/* a selection has been made, record it and send to everyone on the link*/
Net_Link_nTrackNum = nTemp1;
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_TRACK, NET_DEFS_SEND_TO_ALL, 0 );
/* record what happened with the auditor*/
auditor_TrackSelected( AUDITOR_METHODS_BUTTON, Net_Link_nTrackNum, (f32)(nTimer * (1.0f/60.0f)) );
wpr_select_SetSelection( Net_Link_nTrackNum );
wpr_select_EnableSelectionChanges( FALSE );
wpr_select_LoadStage( WPR_SELECT_TRACK_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_TRACK_ANIM );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
break;
}
else {
/* see if time is up, if so force a selection*/
if( nTimer >= _nTrackSelectTicks && !Temp_bNoTimers ) {
Net_Link_nTrackNum = wpr_select_GetCurrentSelection();
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_TRACK, NET_DEFS_SEND_TO_ALL, 0 );
/* record what happened with the auditor*/
auditor_TrackSelected( AUDITOR_METHODS_TIMEOUT, Net_Link_nTrackNum, (f32)(nTimer * (1.0f/60.0f)) );
wpr_select_SetSelection( Net_Link_nTrackNum );
wpr_select_EnableSelectionChanges( FALSE );
wpr_select_LoadStage( WPR_SELECT_TRACK_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_TRACK_ANIM );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
}
}
}
}
nTimer = _nTrackSelectTicks - nTimer;
break;
case WPR_SELECT_TRACK_ANIM:
/* see if a different selection came in since we made our selection*/
if( Net_Link_nTrackNum != wpr_select_GetCurrentSelection() ) {
wpr_select_SetSelection( Net_Link_nTrackNum );
controls_ResetLatches();
}
fStagePercent = (f32)( nTimer * (1.0f/_TIME_TO_ANIMATE_A_TRACK_SELECTION) );
XMATH_CLAMP( fStagePercent, 0.0f, 1.0f );
/* the selection has been made, we are simply animating the selection while we resolve any errors*/
if( nTimer >= _TIME_TO_ANIMATE_A_TRACK_SELECTION ) {
wpr_select_InitBoatSelect( bonuskeys_GetBonus1State(), bonuskeys_GetBonus2State(), _bAllowAdvancedBoats, TRUE );
wpr_select_EnableSelectionChanges( TRUE );
wpr_select_LoadStage( WPR_SELECT_BOAT );
wpr_select_SetCurrentStage( WPR_SELECT_BOAT );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
}
break;
case WPR_SELECT_BOAT:
/* see if a boat has been selected*/
nTemp2 = wpr_select_CheckForSelection(nPlayerSelecting);
if( nTemp2 > -1 ) {
Net_Link_nBoatNum = nTemp2;
wpr_select_SetSelection( nTemp2 );
wpr_select_EnableSelectionChanges( FALSE );
wpr_select_LoadStage( WPR_SELECT_BOAT_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_BOAT_ANIM );
timer_ResetTime( _nTimerId, 0 );
/* record the boat selection with the auditor*/
auditor_BoatSelected( AUDITOR_METHODS_BUTTON, Net_Link_nBoatNum, (f32)(nTimer * (1.0f/60.0f)) );
nBoatTypes[nPlayerSelecting] = nTemp2;
nTimer = 0;
} else { /* we have not selected a boat, but see if time is up*/
/* see if time is up, if so force a selection*/
if( nTimer >= _nBoatSelectTicks && !Temp_bNoTimers ) {
Net_Link_nBoatNum = wpr_select_GetCurrentSelection();
wpr_select_SetSelection( Net_Link_nBoatNum );
wpr_select_EnableSelectionChanges( FALSE );
wpr_select_LoadStage( WPR_SELECT_BOAT_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_BOAT_ANIM );
timer_ResetTime( _nTimerId, 0 );
/* record the boat selection with the auditor*/
auditor_BoatSelected( AUDITOR_METHODS_TIMEOUT, Net_Link_nBoatNum, (f32)(nTimer * (1.0f/60.0f)) );
nTimer = 0;
} else {
/* handle the no ai code*/
if( !(Net_Link_nSecretCodes & SECRET_CODES_NO_AI) ) {
/* the code has not been entered, see if we have done so*/
if( wpr_select_GetNoAi() ) {
Net_Link_nSecretCodes |= SECRET_CODES_NO_AI;
}
}
/* handle the no catchup code */
if( !(Net_Link_nSecretCodes & SECRET_CODES_NO_CATCHUP) ) {
/* the code has not been entered, see if we have done so*/
if( wpr_select_GetNoCatchUp() ) {
Net_Link_nSecretCodes |= SECRET_CODES_NO_CATCHUP;
}
}
}
}
nTimer = _nBoatSelectTicks - nTimer;
break;
case WPR_SELECT_BOAT_ANIM:
fStagePercent = (f32)( nTimer * (1.0f/_TIME_TO_ANIMATE_A_BOAT_SELECTION) );
XMATH_CLAMP( fStagePercent, 0.0f, 1.0f );
/* animate the selection and then switch to gameseed mode*/
if( nTimer >= _TIME_TO_ANIMATE_A_BOAT_SELECTION ) {
/* before we wrap up the select mode, make sure that we record the advanced boat code state just*/
/* in case this person continues*/
nPlayerSelecting++;
if(nPlayerSelecting == nPlayers){
_bAllowAdvancedBoats = wpr_select_CanWeSelectAnAdvancedBoat();
_ChangeStates( STATEMGR_GAMESEED );
nPlayerSelecting = 0;
}
else{
wpr_select_ReInitBoatSelect();
wpr_select_EnableSelectionChanges( TRUE );
// wpr_select_LoadStage( WPR_SELECT_BOAT );
wpr_select_SetCurrentStage( WPR_SELECT_BOAT );
timer_ResetTime( _nTimerId, 0 );
controls_ResetLatches();
}
}
break;
case WPR_SELECT_OPTIONS_ANIM:
fStagePercent = (f32)( nTimer * (1.0f/_TIME_TO_ANIMATE_A_TRACK_SELECTION) );
XMATH_CLAMP( fStagePercent, 0.0f, 1.0f );
/* the selection has been made, we are simply animating the selection while we resolve any errors*/
if( nTimer >= _TIME_TO_ANIMATE_A_TRACK_SELECTION ) {
wpr_select_SetSelection( nTemp2 );
wpr_select_EnableSelectionChanges(TRUE);
wpr_select_InitTrackSelect( bonuskeys_GetBonus1State(), bonuskeys_GetBonus2State(), _bAllowAdvancedBoats );
wpr_select_LoadStage( WPR_SELECT_TRACK );
wpr_select_SetCurrentStage( WPR_SELECT_TRACK );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
}
break;
case WPR_SELECT_OPTIONS:
nTemp1 = wpr_select_CheckForSelection(0);
if( nTemp1 > -1) {
wpr_select_SetSelection(nTemp1);
wpr_select_EnableSelectionChanges( FALSE );
wpr_select_LoadStage( WPR_SELECT_OPTIONS_ANIM );
wpr_select_SetCurrentStage( WPR_SELECT_OPTIONS_ANIM );
timer_ResetTime( _nTimerId, 0 );
nTimer = 0;
}
break;
}
_fTime = (f32)(nTimer * (1.0f/60.0f));
wpr_select_Work( fStagePercent );
break;
case STATEMGR_GAMESEED:
/* watchdog stuff is very trick here, it will be updated in gameseed logic...*/
nTimer = timer_ElapsedTicks( _nTimerId );
_fTime = (f32)(nTimer * (1.0f/60.0f));
_GameSeedLogic( FALSE );
break;
case STATEMGR_HISCORE:
WATCHDOG_NEW_SECS( 10 );
nTimer = timer_ElapsedTicks( _nTimerId );
_fTime = (f32)(nTimer * (1.0f/60.0f) );
_HiScoreLogic( FALSE );
break;
case STATEMGR_ERROR:
WATCHDOG_NEW_SECS( 10 );
break;
case STATEMGR_RELINK:
WATCHDOG_NEW_SECS( 10 );
if( !(Net_Link_nFlags & NET_DEFS_FLAGS_NEED_TO_RELINK) ) {
/* we must have relinked with all of the required units*/
net_link_SendGenericMsg( NET_DEFS_MSG_END_RELINK, NET_DEFS_SEND_TO_ALL, 0 );
controls_ResetLatches();
Net_Link_nSelectMask = 0;
Net_Link_nTrackNum = -1;
_ChangeStates( STATEMGR_ATTRACT );
break;
}
if( !(Gameloop_nFrameCounter % 75) ) {
net_link_SendGenericMsg( NET_DEFS_MSG_RELINK, NET_DEFS_SEND_TO_ALL, 0 );
}
/* update the amount of coins input into the machine so that when we do relink we haven't lost money*/
wpr_banker_BuyAGame( FALSE, FALSE );
break;
default:
/* should never reach here!!!*/
XASSERT_NOW;
break;
}
}
void statemgr_Draw( int nParm ) {
u32 i, nUnitsToConsiderMask, nUnitsOnlineMask, nIdBitMask, nOnlineHistoryMask;
float fUnitTime;
switch( Statemgr_pLocalData->nCurrentState )
{
case STATEMGR_LINK_BOOTUP:
fUnitTime = _fTime/((float)NET_DEFS_BOOTUP_SEND_ONLINE_MSG*(1.0f/60.0f));
XMATH_CLAMPMAX( fUnitTime, 1.0f );
if( fUnitTime < 0.98f ) {
if( Controls_InputState.nButtons & CONTROLS_THROTTLE_BUTTON ) {
timer_ResetTime( _nTimerId, 0 );
fUnitTime = 0.0f;
}
}
sysmsg_Display_EstablishingLink(
OperatorSettings.nNetUnitID,
net_link_GetHeardFromMask(),
fUnitTime
);
break;
case STATEMGR_ATTRACT:
wpr_attract_Draw( _fTime );
if( _bDrawBankInfo ) {
wpr_banker_Draw( FALSE );
}
break;
case STATEMGR_SELECTION:
wpr_select_Draw( _fTime );
break;
case STATEMGR_GAMESEED:
break;
case STATEMGR_HISCORE:
wpr_hiscore_Draw( _fTime );
if( _bDrawBankInfo ) {
wpr_banker_Draw( TRUE );
}
break;
case STATEMGR_ERROR:
switch( _nErrorCode ) {
case _NET_INIT_FAILED_TURN_OFF_NETWORK:
sysmsg_Display_InitFailure();
break;
case _WRONG_VERSION:
sysmsg_Display_VersionMismatch( TRUE, FALSE );
break;
case _BAD_R2FILE_CHECKSUM:
sysmsg_Display_VersionMismatch( FALSE, TRUE );
break;
case _WRONG_VERSION_AND_BAD_R2FILE_CHECKSUM:
sysmsg_Display_VersionMismatch( TRUE, TRUE );
break;
case _BAD_UNIT_ID:
sysmsg_Display_ConflictingId();
break;
default:
XASSERT_NOW;
break;
}
break;
case STATEMGR_RELINK:
nOnlineHistoryMask = net_link_ReturnOnlineHistoryMask();
nUnitsToConsiderMask = 0;
nUnitsOnlineMask = 0;
for( i=0, nIdBitMask=1; i<NET_DEFS_MAX_LINKED_UNITS; i++, nIdBitMask<<=1 ) {
if( nOnlineHistoryMask & nIdBitMask ) {
nUnitsToConsiderMask |= nIdBitMask;
if( net_link_IsReLinkNeededWithThisUnit(i) != 2 ) {
nUnitsOnlineMask |= nIdBitMask;
}
}
}
sysmsg_Display_ReestablishingLink( OperatorSettings.nNetUnitID, nUnitsToConsiderMask, nUnitsOnlineMask );
wpr_banker_DrawCoinBalanceOnly();
break;
default:
/* should never reach here!!!*/
XASSERT_NOW;
break;
}
/* flush out any text in the system*/
text_Flush();
}
/* handle skipping the wrappers and get us into a game*/
void statemgr_SkipWrappersAndSetupGame( BOOL bNewGameLoopWork ) {
u32 nTrackNum;
f32 fTrackFreeRacePercentage, fGlobalFreeRacePercentage, fTrackBias, fGlobalBias;
/* if this function is called before we even get into the*/
/* main game loop, then we need to free the memory that */
/* we already allocated for the wrappers*/
if( !bNewGameLoopWork ) {
/* exit the wrappers, freeing all memory and reseting for next time*/
_CommonExitStuff();
/* turn the network off since we are skipping the wrappers*/
statemgr_Shutdown();
}
/*tmem_ReleaseAll();*/
#if SYS_WINDEV_TARGET
/* a windows build, we have sliders so use those selections*/
Temp_bNoTimers = Wintap_pGuiSettings->bNoTimer;
nTrackNum = Wintap_pGuiSettings->nTrack;
tracks_SetCurrentTrack( nTrackNum, OperatorSettings.naTimeDifficulty[ nTrackNum ] );
player_ResetPlayersToDefaults();
Player_aData[Player_nHuman].nBoatType = Wintap_pGuiSettings->nBoat;
#else
/* r5000 build, mock up setting tab controls */
if(bEUROCOM_SPLITSCREEN) /* No timer countdown during game :) */
Temp_bNoTimers = TRUE;
else /*EUROCOM_NOTIMERS */
Temp_bNoTimers = FALSE;
// nTrackNum = TRACKS_LOOP2;
nTrackNum = TRACKS_AMAZON;
// nTrackNum = TRACKS_LAKEPOWELL;
// nTrackNum = TRACKS_SHIPGRAVEYARD;
// nTrackNum = TRACKS_NILE;
// nTrackNum = TRACKS_VENICE;
// nTrackNum = TRACKS_GREECE;
#if TARGET==ULTRA64
nTrackNum = TRACKS_LAKEPOWELL;
#endif /*ULTRA64*/
tracks_SetCurrentTrack( nTrackNum, 4 );
player_ResetPlayersToDefaults();
Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_RAZORBACK;
#if TARGET==DREAMCAST
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_BANSHEE;
Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_TIDAL_BLADE;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_RAD_HAZARD;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_MISS_BEHAVE;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_DAMN_THE_TORPEDOES;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_CUT_THROAT;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_RAZORBACK;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_THRESHER;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_MIDWAY;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_SEADOG;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_COP;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_HOVERCRAFT;
// Player_aData[Player_nHuman].nBoatType = BOATS_TYPE_TINY;
#endif // DREAMCAST
waterspray_SetDrawMode( TRUE );
#endif
ai_rabbit_GetUnsyncedData( nTrackNum, &fTrackFreeRacePercentage, &fGlobalFreeRacePercentage, &fTrackBias, &fGlobalBias );
ai_rabbit_SetNetSyncedData( OperatorSettings.naAiDifficulty[ nTrackNum ], 0,
OperatorSettings.bMaxFreeRaceEnable, OperatorSettings.nMaxFreeRacePercent,
fTrackFreeRacePercentage, fGlobalFreeRacePercentage, fTrackBias, fGlobalBias );
race_DisplayLoadingScreen( Tracks_nCurrentTrack, Player_aData[Player_nHuman].nBoatType, TRUE );
race_SeedRandom( xmath_RandomFloat() );
race_Init( FALSE );
controls_ZeroCachedControls();
Statemgr_pLocalData->nCurrentState = STATEMGR_RACE;
Gameloop_bNewWorkFunction = bNewGameLoopWork;
#if TARGET==ULTRA64 /* Choose game video mode */
// This is actually when we enter race screen - if skip wrapper!
SetVideoMode(VIDEO_MODE_320x240,FALSE);
ClearScreen = FALSE; /* Stop clearing screen - need for attract, but not game! */
ClearZ = TRUE; /* Clearing Z Buffer for game */
CONSOLE("Water: %d\n",WaterTextureMemory);
CONSOLE("Backgrnd: %d\n",BackgroundTextureMemory);
CONSOLE("Objs: %d\n",ObjectsTextureMemory );
CONSOLE("Boats: %d\n",BoatsTextureMemory);
CONSOLE("(Total): %d\n",(TEXTURES_END_LOWRES-TEXTURES_START_LOWRES)-tmem_GetFreeMem(0));
#endif /*ULTRA64 */
}
/* handle all details after a race*/
void statemgr_EndRace( void ) {
BOOL bFinished;
/* this function should only be called if we are in RACE mode*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_RACE );
bFinished = ( Player_aData[Player_nHuman].fFinishTime == 0.0f ) ? FALSE : TRUE;
audits_EndARace( Player_aData[Player_nHuman].nPlace,
Tracks_nCurrentTrack,
Player_aData[Player_nHuman].nBoatType,
bFinished,
(Player_aData[Player_nFirstPlaceHuman].fFinishTime == 0.0f),
Player_nHumanCount );
ai_rabbit_UpdateLocalMachineWins( bFinished, Player_aData[Player_nHuman].nPlace );
bonuskeys_AfterRaceUpdate( bFinished,
_nTimerId,
Player_aData[Player_nHuman].fFinishTime,
hi_score_GetBestTrackTime( Tracks_nCurrentTrack ) );
if( !_bAllowAdvancedBoats && bFinished ) {
_bAllowAdvancedBoats = TRUE;
}
_CommonStartupStuff();
/* reset our group to just be ourself*/
net_link_ResetGroup( TRUE );
/* change to the HI_SCORE state*/
_ChangeStates( STATEMGR_HISCORE );
/* Redirect game loop to statemgr functions...*/
gameloop_SetWorkFunc( statemgr_Work, 0 );
gameloop_SetDrawFunc( statemgr_Draw, 0 );
}
/*================== */
/* private functions*/
static void _DisplayHydroLogo( void ) {
u8 *pBlit;
u32 nBlit;
/* Load screen blit from R2...*/
pBlit = obsys_Load( "BWWHYDRAT10" );
if( pBlit ) {
nBlit = blit_CreateTexture(pBlit-sizeof(u32));
if(nBlit == -1)
return;
blit_Dreamcast(nBlit, pBlit-sizeof(u32), 0, 0);
gameloop_SwapFrameBuffer();
blit_Dreamcast(nBlit, pBlit-sizeof(u32), 0, 0);
gameloop_SwapFrameBuffer();
blit_FreeBlitTextures();
} else {
/* Blit not found. Clear screen anyway...*/
gutil_ClearFrameBufferToBlack();
gameloop_SwapFrameBuffer();
}
}
/* stuff that we need to do before we enter*/
/* the wrappers, (do one time only)*/
static void _CommonStartupStuff( void ) {
#if TARGET==ULTRA64 /*Point where can move arcade memory system around!!!*/
CONSOLE("\n\nCOMMONSTARTUPSTUFF 0x%X 0x%X\n\n\n",_nHeapPtr[0]-_nOrigHeapPtr[0],_nOrigHeapPtr[1]-_nHeapPtr[1]);
// For N64 we need low memory to be EMPTY so we can move the pointer around to vary allocations beneath!!
if ( (_nHeapPtr[0]-_nOrigHeapPtr[0])!=0 ) {
CONSOLE("SHITE! Low memory still allocated\n");
}
// Right, now can set memory up for attract mode!! (Wait for gfx to complete)
HiResMemorySetup(TRUE);
SetVideoMode(VIDEO_MODE_512x240_INTERLACED,FALSE); //TRUE); //Enter-attract
#endif /*ULTRA64*/
/*tmem_ReleaseAll();*/
/* Get our memory frames...*/
_pSysmemFrame = sysmem_StartFrame();
_ObsysFrame = obsys_StartFrame();
/* load our fonts for printing text to the screen*/
text_ResetSystem();
text_LoadFont( TEXT_FONT_LARGE );
text_LoadFont( TEXT_FONT_SMALL );
/* load common wrapper stuff*/
wpr_memmgr_Init();
/* reset our frame counters*/
gameloop_ResetCounter();
/* init the viewport*/
terrain_Viewport();
}
/* stuff that we need to do right before exiting*/
/* the wrappers, (do one time only)*/
static void _CommonExitStuff( void ) {
/* reset our wrappers for the next time*/
wpr_select_Close();
wpr_hiscore_Close();
wpr_attract_Close();
wpr_memmgr_Close();
/* free all of our memory that the wrappers allocated*/
sysmem_ReleaseFrame( _pSysmemFrame );
obsys_ReleaseFrame( _ObsysFrame );
/*tmem_ReleaseAll();*/
#if TARGET==ULTRA64 /*Point where can move arcade memory system around!!!*/
CONSOLE("\n\nCOMMONEXITSTUFF 0x%X 0x%X\n\n\n",_nHeapPtr[0]-_nOrigHeapPtr[0],_nOrigHeapPtr[1]-_nHeapPtr[1]);
// For N64 we need low memory to be EMPTY so we can move the pointer around to vary allocations beneath!!
if ( (_nHeapPtr[0]-_nOrigHeapPtr[0])!=0 ) {
CONSOLE("SHITE! Low memory still allocated\n");
}
// Need this to stop 'white-out' from select screens
gutil_DrawBlackOrWhiteScreenFade(0,TRUE);
SetVideoMode(VIDEO_MODE_320x240,FALSE);
// Set for low-res
LoResMemorySetup();
// And draw loading screen!
race_DisplayLoadingScreen( Net_Link_nTrackNum, Net_Link_nBoatNum, FALSE );
#endif /*ULTRA64*/
}
/* used to change control states*/
static void _ChangeStates( u32 nNewState ) {
switch( nNewState )
{
case STATEMGR_LINK_BOOTUP:
/* only able to switch to STATEMGR_LINK_BOOTUP from STATEMGR_STARTUP only*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_STARTUP );
xprintf( "STATEMGR: Switching to LINK_BOOTUP mode!\n" );
/* send a NET_DEFS_MSG_HEREIAM*/
net_link_SendGenericMsg( NET_DEFS_MSG_HEREIAM, NET_DEFS_SEND_TO_ALL, 0 );
_nNumHereIAmMsgSent = 1;
/* reset our timer*/
timer_Update();
timer_ResetTime( _nTimerId, 0 );
/* set our timeout time*/
_nTimeOut = NET_DEFS_BOOTUP_TIMEOUT;
break;
case STATEMGR_ATTRACT:
/* do different actions depending on our current state*/
switch( Statemgr_pLocalData->nCurrentState )
{
case STATEMGR_STARTUP:
/* the link is not up, otherwise we would be coming from LINK_BOOTUP mode reset our timer*/
timer_Update();
timer_ResetTime( _nTimerId, 0 );
/* init attract mode*/
wpr_attract_Init();
wpr_attract_ResetToFirstStage();
Net_Link_bNewAttractMember = FALSE;
Net_Link_bAdvanceAttractStage = FALSE;
Net_Link_bResetAttractMode = FALSE;
Net_Link_nAttractSyncCount = 0;
break;
case STATEMGR_RELINK:
case STATEMGR_LINK_BOOTUP:
case STATEMGR_HISCORE:
/* reset our timer*/
timer_ResetTime( _nTimerId, 0 );
/* init attract mode*/
wpr_attract_Init();
wpr_attract_ResetToFirstStage();
Net_Link_bNewAttractMember = FALSE;
Net_Link_bAdvanceAttractStage = FALSE;
Net_Link_bResetAttractMode = FALSE;
Net_Link_nAttractSyncCount = 0;
/* send a NET_DEFS_MSG_ATTRACT_ENTER*/
net_link_SendGenericMsg( NET_DEFS_MSG_ATTRACT_ENTER, NET_DEFS_SEND_TO_ALL, 0 );
break;
default:
/* we can't switch to ATTRACT mode from any other modes*/
XASSERT_NOW;
break;
}
/* set our timeout time*/
_nTimeOut = wpr_attract_GetCurrentStageTimeLimit();
_bAttractSegmentLoaded = FALSE;
wpr_banker_ResetFlashTime();
_bDrawBankInfo = TRUE;
controls_ResetLatches();
/* attach a button callback to the throttle button*/
controls_EnableACallbackToAButtonPress( TRUE, CONTROLS_THROTTLE_BUTTON );
_nAttractModeMusicSample = 0;
break;
case STATEMGR_SELECTION:
/* do different actions depending on our current state*/
switch( Statemgr_pLocalData->nCurrentState )
{
case STATEMGR_ATTRACT:
case STATEMGR_HISCORE:
#if SYS_WINDEV_TARGET
/* a windows build, we have sliders so use those selections*/
Temp_bNoTimers = Wintap_pGuiSettings->bNoTimer;
#else
/* r5000 build, mock up setting tab controls */
#endif
Net_Link_nSecretCodes = SECRET_CODES_NONE;
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_ENTER, NET_DEFS_SEND_TO_ALL, 0 );
/* a big load, this could be a problem*/
wpr_select_InitOptionsSelect();
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_ENTER, NET_DEFS_SEND_TO_ALL, 0 );
wpr_select_LoadStage( WPR_SELECT_OPTIONS );
wpr_select_SetCurrentStage( WPR_SELECT_OPTIONS );
wpr_select_EnableSelectionChanges( TRUE );
// wpr_select_InitTrackSelect( bonuskeys_GetBonus1State(), bonuskeys_GetBonus2State(), _bAllowAdvancedBoats );
// net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_ENTER, NET_DEFS_SEND_TO_ALL, 0 );
// wpr_select_LoadStage( WPR_SELECT_TRACK );
// wpr_select_SetCurrentStage( WPR_SELECT_TRACK );
// wpr_select_EnableSelectionChanges( TRUE );
/* don't let any message slip by during this important time*/
/* this may be needed */
/*net_link_PreWorkReceive( 1 );*/
net_link_ResetGroup( FALSE );
net_link_ManageSelectMask( TRUE, net_link_GetMyUnitIdMask() );
/* reset our timer*/
timer_Update();
timer_ResetTime( _nTimerId, 0 );
break;
default:
/* we can't switch to STATEMGR_SELECTION mode from any other modes*/
XASSERT_NOW;
break;
}
wpr_banker_ResetFlashTime();
_bDrawBankInfo = FALSE;
/* resend our select enter msg, just in case it got lost*/
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_ENTER, NET_DEFS_SEND_TO_ALL, 0 );
break;
case STATEMGR_GAMESEED:
/* we can only switch to GAMESEED mode from SELECTION mode*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_SELECTION );
xprintf( "STATEMGR: Switching to STATEMGR_GAMESEED mode!\n" );
_GameSeedLogic( TRUE );
break;
case STATEMGR_RACE:
/* we can only switch to RACE mode from GAMESEED mode*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_GAMESEED );
xprintf( "STATEMGR: Switching to STATEMGR_RACE mode!\n" );
break;
case STATEMGR_HISCORE:
/* we can only switch to HISCORE mode from RACE mode*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_RACE );
xprintf( "STATEMGR: Switching to STATEMGR_HISCORE mode!\n" );
_HiScoreLogic( TRUE );
break;
case STATEMGR_ERROR:
/* WE CAN SWITCH TO THIS STATE FROM ANY MODE*/
/* since we switching to an error state, let everyone know about it*/
net_link_SendErrorMsg( NET_DEFS_ERROR_SWITCHING_2_ERROR_STATE, (u16)OperatorSettings.nNetUnitID );
/* no matter what error we have, shut down the net link*/
net_link_Shutdown();
break;
case STATEMGR_RELINK:
/* we can only switch to RELINK mode from ATTRACT mode*/
XASSERT( Statemgr_pLocalData->nCurrentState == STATEMGR_ATTRACT );
audio_GameIDStop( WPR_DEFS_ATTRACT_MUSIC );
wpr_attract_Close();
gameloop_ResetCounter();
Gameloop_nFrameCounter = 70;
audits_LogARelinkSession();
break;
default:
XASSERT_NOW;
break;
}
/* since we didn't get an error, it is cool to switch our states around*/
Statemgr_pLocalData->nCurrentState = nNewState;
}
static void _HiScoreLogic( BOOL bReset ) {
static u32 _nHiScoreState = 0;
static f32 _fCoinBalance = 0;
BOOL bTemp;
f32 fCurrentBalance;
if( bReset ) {
_nHiScoreState = 0;
}
switch( _nHiScoreState )
{
/* load and init the high score screen*/
case 0:
wpr_hiscore_Init( TRUE,
Tracks_nCurrentTrack,
Player_aData[Player_nHuman].fFinishTime,
Player_aData[Player_nHuman].nBoatType );
/* reset our timer*/
timer_Update();
timer_ResetTime( _nTimerId, 0 );
if( Player_aData[Player_nHuman].nPlace == 1 ) {
++Net_Link_nNumFreeRacesInARow;
} else {
Net_Link_nNumFreeRacesInARow = 0;
}
/* check to see if we need to allow the user to enter a high score or*/
/* can we simply just display the high scores and allow the user to move*/
/* on to a new game*/
if( wpr_hiscore_AreWeStillEnteringInitials() ) {
_nHiScoreState = 2;
_bDrawBankInfo = TRUE;
wpr_banker_ResetFlashTime();
controls_ResetLatches();
/* this is a good time to write out our saved data to the cmos and the audit file*/
cmos_CopyAllGlobalStructs2Cmos();
auditor_WriteOutLastEvent();
_fCoinBalance = wpr_banker_CurrentCreditBalance();
_fTime = _fContinueSecs;
} else {
/* if we have already entered our initials, auto enter those values as the high score entry*/
#if 1
if( _bAlreadyEnteredIntials ) {
wpr_hiscore_SeedUpInitials( _cInitial1, _cInitial2, _cInitial3 );
wpr_hiscore_ForceInitialEntry();
auditor_HighScoreEntry( AUDITOR_METHODS_BUTTON,
0.0f,
wpr_hiscore_GetHighScoreSlot() + 1,
_cInitial1,
_cInitial2,
_cInitial3 );
/* this is a good time to write out our saved data to the cmos and the audit file*/
cmos_CopyAllGlobalStructs2Cmos();
auditor_WriteOutLastEvent();
_nHiScoreState = 2;
_bDrawBankInfo = TRUE;
wpr_banker_ResetFlashTime();
controls_ResetLatches();
_fCoinBalance = wpr_banker_CurrentCreditBalance();
_fTime = _fContinueSecs;
} else {
_nHiScoreState = 1;
_bDrawBankInfo = FALSE;
_fTime2EnterHiScore = 0.0f;
_fTime = _fHiScoreSecs;
}
#else
if( _bAlreadyEnteredIntials ) {
wpr_hiscore_SeedUpInitials( _cInitial1, _cInitial2, _cInitial3 );
}
_nHiScoreState = 1;
_bDrawBankInfo = FALSE;
_fTime2EnterHiScore = 0.0f;
_fTime = _fHiScoreSecs;
#endif
}
break;
/* waiting for the user to finish inputing his initials (or timeout)*/
case 1:
wpr_hiscore_Work();
_fTime2EnterHiScore += Gameloop_fTargetFrameTime;
/* see if it is time to move on, if timers are on*/
bTemp = FALSE;
_fTime = _fHiScoreSecs - _fTime;
if( _fTime < 0.0f ) {
_fTime = 0.0f;
}
if( _fTime <= 0.0f && !Temp_bNoTimers ) {
wpr_hiscore_ForceInitialEntry();
bTemp = TRUE;
/* what initials were selected*/
_bAlreadyEnteredIntials = TRUE;
wpr_hiscore_GetEnteredInitials( &_cInitial1, &_cInitial2, &_cInitial3 );
auditor_HighScoreEntry( AUDITOR_METHODS_TIMEOUT,
_fTime2EnterHiScore,
wpr_hiscore_GetHighScoreSlot() + 1,
_cInitial1,
_cInitial2,
_cInitial3 );
} else if( wpr_hiscore_AreWeStillEnteringInitials() ) {
bTemp = TRUE;
/* what initials were selected*/
_bAlreadyEnteredIntials = TRUE;
wpr_hiscore_GetEnteredInitials( &_cInitial1, &_cInitial2, &_cInitial3 );
auditor_HighScoreEntry( AUDITOR_METHODS_BUTTON,
_fTime2EnterHiScore,
wpr_hiscore_GetHighScoreSlot() + 1,
_cInitial1,
_cInitial2,
_cInitial3 );
}
if( bTemp ) {
/* reset our timer*/
_fTime = _fContinueSecs;
timer_ResetTime( _nTimerId, 0 );
/* this is a good time to write out our saved data to the cmos and the audit file*/
cmos_CopyAllGlobalStructs2Cmos();
auditor_WriteOutLastEvent();
_nHiScoreState = 2;
_bDrawBankInfo = TRUE;
wpr_banker_ResetFlashTime();
controls_ResetLatches();
_fCoinBalance = wpr_banker_CurrentCreditBalance();
}
break;
/* watch the hiscore display until it locks into its final position*/
case 2:
/*
ONLY NEEDED IF WANT TO SCROLL BEFORE DISPLAYING THE COUNTDOWN TIMER!!!
wpr_hiscore_Work();
// see if the user has purchased a game
if( wpr_banker_BuyAGame( TRUE, TRUE ) ) {
_DisplayHydroLogo();
audio_Trigger( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 225, AUDIO_PAN_CABINET, AUDIO_TYPE_GENERAL, AUDIO_PRIORITY_GENERAL );
if( Player_bHumanWonFreeRace ) {
Player_bHumanWonFreeRace = FALSE;
} else {
auditor_StartRaceEvent( AUDITOR_METHODS_CONTINUE );
}
wpr_hiscore_Close();
_ChangeStates( STATEMGR_SELECTION );
audio_GameIDFadeOutAndStop( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 0.5f );
// we have continued
++_nNumContinues;
} else {
// see if it is time to start the timer
if( wpr_hiscore_HaveWeSeenTheInitialsLongEnough() ) {
// reset our timer
timer_ResetTime( _nTimerId, 0 );
_nHiScoreState = 3;
}
_fCoinBalance = wpr_banker_CurrentCreditBalance();
_fTime = _fContinueSecs;
}
break;
*/
/* simply wait for a new game or a timeout*/
case 3:
wpr_hiscore_Work();
_fTime = _fContinueSecs - _fTime;
/* see if we should deduct time */
if( (Gameloop_nFrameCounter & 0x3) == 0x3 ) {
if( Controls_InputState.nButtons & (CONTROLS_VIEW1_BUTTON | CONTROLS_VIEW2_BUTTON | CONTROLS_VIEW3_BUTTON) ) {
timer_AdjustOffset( -45, _nTimerId );
_fTime -= 0.75f;
}
}
if( _fTime < 0.0f ) {
_fTime = 0.0f;
}
/* see if it is time to move on*/
if( _fTime <= 0.0f ) {
wpr_hiscore_Close();
if( !Player_bHumanWonFreeRace ) {
/* no continue*/
_nNumContinues = 0;
_bAllowAdvancedBoats = OperatorSettings.bAlwaysEnableAdvancedBoats;
Net_Link_nNumFreeRacesInARow = 0;
_bAlreadyEnteredIntials = FALSE;
/* reset the bonus track key vars*/
bonuskeys_ResetSystem();
/* go back to attract mode*/
_ChangeStates( STATEMGR_ATTRACT );
} else {
_DisplayHydroLogo();
audio_Trigger( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 225, AUDIO_PAN_CABINET, AUDIO_TYPE_GENERAL, AUDIO_PRIORITY_GENERAL );
audits_LogAFreeGameWin();
auditor_StartRaceEvent( AUDITOR_METHODS_FREERACE );
Player_bHumanWonFreeRace = FALSE;
_ChangeStates( STATEMGR_SELECTION );
audio_GameIDFadeOutAndStop( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 0.5f );
/* we have continued*/
++_nNumContinues;
}
} else {
/* time is not up, see if the user has purchased a game*/
if( wpr_banker_BuyAGame( TRUE, TRUE ) ) {
_DisplayHydroLogo();
audio_Trigger( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 225, AUDIO_PAN_CABINET, AUDIO_TYPE_GENERAL, AUDIO_PRIORITY_GENERAL );
if( Player_bHumanWonFreeRace ) {
Player_bHumanWonFreeRace = FALSE;
audits_LogAFreeGameWin();
} else {
auditor_StartRaceEvent( AUDITOR_METHODS_CONTINUE );
audits_LogAContinue();
}
wpr_hiscore_Close();
_ChangeStates( STATEMGR_SELECTION );
audio_GameIDFadeOutAndStop( SOUNDCALL_WRAP_GRAPHIC_EFFECT_1, 0.5f );
/* we have continued*/
++_nNumContinues;
} else {
/* if coins were deposited, reset the timer*/
fCurrentBalance = wpr_banker_CurrentCreditBalance();
if( _fCoinBalance != fCurrentBalance ) {
_fCoinBalance = fCurrentBalance;
timer_ResetTime( _nTimerId, 0 );
_fTime = _fContinueSecs;
wpr_hiscore_CoinDepositedResetTimer();
}
}
}
break;
default:
XASSERT_NOW;
break;
}
}
/*/////////////////////////*/
/* GAMESEED LOGIC FUNCTIONS*/
/*/////////////////////////*/
static void _DisplayWaitForNetPlayers( u8 *p1, u8 *p2, u32 nCounter ) {
if( nCounter & 0x10 ) {
if( p2 ) {
blit_Raw( p2-sizeof(u32), 0, 0 );
}
} else {
if( p1 ) {
blit_Raw( p1-sizeof(u32), 0, 0 );
}
}
}
static void _GameSeedLogic( BOOL bReset ) {
static u32 _nStartFrame;
static u32 _nGameSeedState = 0;
static u32 _nFrameCounter = 0;
static BOOL _bDisplayJoinMsg, _bResetTimer;
static u8 *_pJoin[2];
u32 nTemp, nTimer;
ObsysFrame_t ObsysFrame;
if( bReset ) {
_nGameSeedState = 0;
_nFrameCounter = 0;
_pJoin[0] = _pJoin[1] = NULL;
_bResetTimer = FALSE;
}
switch( _nGameSeedState )
{
/* display the loading screen and tell everyone that we are now in seed mode*/
case 0:
WATCHDOG_NEW_SECS( 10 );
net_link_ResetGroup( FALSE );
net_link_InitSeedData();
/* unlock our group for new members*/
net_link_SetGroupLockState( FALSE );
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_BOAT, NET_DEFS_SEND_TO_ALL, 0 );
/* put the load screen on both buffers, this buys us some time too*/
#if TARGET!=ULTRA64 /* Only draw loading screen once */
if( net_link_GetNumberOfUnitsOnline() > 1 ) {
_bDisplayJoinMsg = TRUE;
_pJoin[0] = obsys_Load( "BWWLOADBT1X" );
_pJoin[1] = obsys_Load( "BWWLOADBT1Y" );
race_DisplayLoadingScreen( Net_Link_nTrackNum, Net_Link_nBoatNum, FALSE );
_DisplayWaitForNetPlayers( _pJoin[0], _pJoin[1], 0 );
gameloop_SwapFrameBuffer();
race_DisplayLoadingScreen( Net_Link_nTrackNum, Net_Link_nBoatNum, FALSE );
_DisplayWaitForNetPlayers( _pJoin[0], _pJoin[1], 0 );
} else {
_bDisplayJoinMsg = FALSE;
ObsysFrame = obsys_StartFrame();
race_LoadLoadingScreen(Net_Link_nTrackNum, Net_Link_nBoatNum);
bonuskeys_LoadPreRaceDisplay();
race_DisplayLoadingScreen( Net_Link_nTrackNum, Net_Link_nBoatNum, FALSE );
bonuskeys_PreRaceDisplay();
dcRender();
dcSwapFrameBuffer();
race_DisplayLoadingScreen( Net_Link_nTrackNum, Net_Link_nBoatNum, FALSE );
bonuskeys_PreRaceDisplay();
dcRender();
dcSwapFrameBuffer();
blit_FreeBlitTextures();
dcEnableRendering(FALSE);
obsys_ReleaseFrame(ObsysFrame);
}
#else
_bDisplayJoinMsg = FALSE;
// Store track-boat ID(change before we get to draw them!)
LoadingScreen_nTrackNum = Net_Link_nTrackNum;
LoadingScreen_nBoatNum = Net_Link_nBoatNum;
#endif /*ULTRA64*/
/* resend our boat select message, just in case it was lost*/
net_link_SendGenericMsg( NET_DEFS_MSG_SELECT_BOAT, NET_DEFS_SEND_TO_ALL, 0 );
/* remove ourself from select mode, everybody else will do so when they receive our boatselect msg*/
net_link_ManageSelectMask( FALSE, net_link_GetMyUnitIdMask() );
++_nGameSeedState;
break;
/* wait for everyone to be out of select mode for _SECS_TO_WAIT_TO_FOR_EMPTY_SELECT_MODE time */
case 1:
if( !(_nNeverResetFrameCounter & 0x3F) ) {
/* update the watchdog every 64 frames*/
WATCHDOG_NEW_SECS( 10 );
}
if( !Net_Link_nSelectMask ) {
/* everyone is out of select mode, let's make sure it stays that way*/
if( _fTime >= _SECS_TO_WAIT_TO_FOR_EMPTY_SELECT_MODE ) {
/* send a gameseed group size message to everyone on the link*/
net_link_SendGenericMsg( NET_DEFS_MSG_GAMESEED_GROUPSIZE, NET_DEFS_SEND_TO_ALL, 0 );
Net_Link_SeedData.nGroupSizeMask |= net_link_GetMyUnitIdMask();
++Net_Link_SeedData.nNumGroupSizeMsgs;
/* fade the select music down*/
audio_GameIDFadeOutAndStop( WPR_DEFS_SELECT_MUSIC, 1.25f );
/* start the radio chatter*/
audio_Trigger( SOUNDCALL_GCOM_RACE_START_CHATTER, WPR_DEFS_RADIO_CHATTER_VOLUME, AUDIO_PAN_CABINET, AUDIO_TYPE_GENERAL, AUDIO_PRIORITY_GENERAL );
/* reset our timer*/
timer_ResetTime( _nTimerId, 0 );
/* lock our group from accepting new members*/
net_link_SetGroupLockState( TRUE );
++_nGameSeedState;
_nFrameCounter = 0;
}
} else {
/* keep reseting the clock until select mode is clear for _SECS_TO_WAIT_TO_FOR_EMPTY_SELECT_MODE secs*/
timer_ResetTime( _nTimerId, 0 );
if( !_bResetTimer ) {
_bResetTimer = TRUE;
_nStartFrame = _nNeverResetFrameCounter - 0x10;/* force 'waiting for other players' on */
}
}
if( _bDisplayJoinMsg ) {
if( _bResetTimer ) {
/* we had to wait for someone in select mode, flash 'waiting for other players'*/
_DisplayWaitForNetPlayers( _pJoin[0], _pJoin[1], _nNeverResetFrameCounter - _nStartFrame );
} else {
_DisplayWaitForNetPlayers( _pJoin[0], _pJoin[1], 0 );
}
}
break;
/* wait for the group size number of gameseed group size messages*/
case 2:
if( !(_nNeverResetFrameCounter & 0x3F) ) {
/* update the watchdog every 64 frames*/
WATCHDOG_NEW_SECS( 10 );
}
if( net_link_GetCurrentGroupSize() == Net_Link_SeedData.nNumGroupSizeMsgs ) {
/* start boat startup sound*/
if( boats_IsBoatAHydro( Net_Link_nBoatNum ) ) {
audio_Trigger( SOUNDCALL_GCOM_RACE_START_WATER_TURBULENCE,
WPR_DEFS_ENGINE_START_VOLUME,
WPR_DEFS_ENGINE_START_PAN_HYDRO,
AUDIO_TYPE_GENERAL,
AUDIO_PRIORITY_GENERAL );
} else {
audio_Trigger( SOUNDCALL_GCOM_RACE_START_BOAT_MOTORS,
WPR_DEFS_ENGINE_START_VOLUME,
WPR_DEFS_ENGINE_START_PAN_PROP,
AUDIO_TYPE_GENERAL,
AUDIO_PRIORITY_GENERAL );
}
net_link_ResolveGameAddress();
net_link_SendGameSeed();
if( _bDisplayJoinMsg ) {
/* replace the waiting for other players with bonus key info, put this on both buffers*/
bonuskeys_PreRaceDisplay();
bonuskeys_PreRaceDisplay();
}
++_nGameSeedState;
/* exit the wrappers, freeing all memory and reseting for next time*/
_CommonExitStuff();
_nFrameCounter = 0;
WATCHDOG_NEW_SECS( 30 );
} else {
++_nFrameCounter;
if( !(_nFrameCounter % 25) ) {
/* resend our groupsize msg*/
net_link_SendGenericMsg( NET_DEFS_MSG_GAMESEED_GROUPSIZE, NET_DEFS_SEND_TO_ALL, 0 );
}
if( _bDisplayJoinMsg ) {
_DisplayWaitForNetPlayers( _pJoin[0], _pJoin[1], _nNeverResetFrameCounter - _nStartFrame );
}
}
break;
/* wait for us to receive all of the game seed msg needed*/
case 3:
nTemp = net_link_GetCurrentGroupSize();
if( nTemp == Net_Link_SeedData.nNumSeeds && _nFrameCounter > 5 ) {
/* make sure the watchdog timer doesn't timeout during our load of the level, pretty long load...*/
WATCHDOG_NEW_SECS( 30 );
_SeedUpNetSyncedRace();
race_Init( _nNumContinues == 0 );
net_link_ResolveGameAddress();
/* tell everybody else that we are loading and ready to go! */
++Net_Link_SeedData.nNumGoMsgs;
Net_Link_SeedData.nGoMask |= net_link_GetMyUnitIdMask();
net_link_SendGenericMsg( NET_DEFS_MSG_GAMESEED_GO, NET_DEFS_SEND_TO_GROUP, 0 );
++_nGameSeedState;
timer_Update();
timer_ResetTime( _nTimerId, 0 );
/* set the watchdog here so that we don't wait too long for everyone's go message*/
WATCHDOG_NEW_SECS( 30 );
/* wait to hear that everybody else is ready to go too*/
while( Net_Link_SeedData.nNumGoMsgs != nTemp ) {
nTimer = timer_ElapsedTicks( _nTimerId );
if( nTimer > 300 ) {
/* resend our go message*/
net_link_SendGenericMsg( NET_DEFS_MSG_GAMESEED_GO, NET_DEFS_SEND_TO_GROUP, 0 );
timer_ResetTime( _nTimerId, 0 );
}
net_link_PreWorkReceive( 1 );
nTemp = net_link_GetCurrentGroupSize();
timer_Update();
}
/* fade the radio chatter and engine startup, and switch to race mode*/
audio_GameIDFadeOutAndStop( SOUNDCALL_GCOM_RACE_START_CHATTER, 1.75f );
if( boats_IsBoatAHydro( Net_Link_nBoatNum ) ) {
audio_GameIDFadeOutAndStop( SOUNDCALL_GCOM_RACE_START_WATER_TURBULENCE, 1.75f );
} else {
audio_GameIDFadeOutAndStop( SOUNDCALL_GCOM_RACE_START_BOAT_MOTORS, 1.75f );
}
_ChangeStates( STATEMGR_RACE );
#if TARGET==ULTRA64 /* Choose game video mode */
// This is actually when we enter race screen!
if (RunGameHiRes)
SetVideoMode(VIDEO_MODE_512x240_INTERLACED,FALSE);
else
SetVideoMode(VIDEO_MODE_320x240,FALSE);
ClearScreen = FALSE; /* Stop clearing screen - need for attract, but not game! */
ClearZ = TRUE; /* Clearing Z Buffer for game */
#endif /*ULTRA64 */
WATCHDOG_NEW_SECS( 10 );
} else {
/* every 75 frames, resend our gameseed message*/
++_nFrameCounter;
if( (_nFrameCounter % 75) == 74 ) {
net_link_SendGameSeed();
} else if( _nFrameCounter == 4 ) {
/* make sure that we resend our gameseed msg at least once*/
net_link_SendGameSeed();
}
}
break;
default:
XASSERT_NOW;
break;
}
}
/* only call this when all gameseed msg have been received from every unit in our group*/
/* this function will sort all of the information and will write it out to the various*/
/* tables, player structs, etc...*/
/* AFTER CALLING THIS FUNCTION YOU CAN SWITCH TO RACE MODE...*/
static void _SeedUpNetSyncedRace( void ) {
u32 i, j, nUnitMask, nLimit, nTemp1, nTemp2, nTemp3, nListIndex;
u8 nBoat;
char cInitials[3];
f32 fTime;
CmosHiScore_t *pHiScore;
/* make sure that at least your information is in the seed data*/
XASSERT( Net_Link_SeedData.nNumSeeds > 0 );
/*/////////////////////////////////////////////////////////////////////////////////*/
/* COMBINE ALL OF THE SEED MESSAGES INTO OUR SYNCED DATA (FIRST SET DEFAULT VALUES)*/
Net_Link_SeedData.nSyncNumHighScores = 0;
Net_Link_SeedData.nSyncTrackNum = 12345; /* bogus value so that we select the lowest track number*/
Net_Link_SeedData.nSyncNumPolePositions = 0;
Net_Link_SeedData.nSyncDifficulty = 12345; /* bogus value so that we select the lowest difficulty*/
Net_Link_SeedData.bSyncNoTimers = FALSE;
Net_Link_SeedData.nSyncSecretCodes = NET_LINK_ALL_SECRET_CODES;/* set to all codes and if anybody did not enter a code, disable that code*/
Net_Link_SeedData.fSyncRandomSeed = 0.0f;
Net_Link_SeedData.fSyncStartingSecs = 0.0f;
Net_Link_SeedData.bSyncChaserGoesOffWithAi = FALSE;
Net_Link_SeedData.bSyncMaxFreeRaceEnable = FALSE;
Net_Link_SeedData.nSyncMaxFreeRacePercent = 123;
Net_Link_SeedData.nSyncAiDifficulty = 0;
Net_Link_SeedData.fSyncTrackWinPercent = 0.0f;
Net_Link_SeedData.fSyncGlobalWinPercent = 0.0f;
Net_Link_SeedData.fSyncTrackBias = 0.0f;
Net_Link_SeedData.fSyncGlobalBias = 0.0f;
Net_Link_SeedData.nSyncNumFreeRacesInARow = 0;
for( j=0; j < TRACK_MAX_CHECKPOINTS; j++ ) {
Net_Link_SeedData.afSyncSplitTimes[j] = 0.0f;
Net_Link_SeedData.afSyncChkPtSecs[j] = 0.0f;
}
for( i=0; i < NET_DEFS_MAX_LINKED_UNITS; i++ ) {
nUnitMask = 1 << i;
if( Net_Link_SeedData.nSeedMask & nUnitMask ) {
/* do some pre filtering to our sortable list of high scores so that we don't get doubles*/
for( j=0; j < CMOS_HI_SCORES_PER_TRACK; j++ ) {
pHiScore = &Net_Link_SeedData.aSeedHighScores[i][j];
nTemp1 = _GetInstanceCountOfAHighScoreOnOneUnit( pHiScore );
nTemp2 = _GetInstanceCountOfAHighScoreInSyncedList( pHiScore );
if( nTemp1 > nTemp2 ) {
hi_score_CopyHiScoreStruct( &Net_Link_SeedData.aSyncHighScores[ Net_Link_SeedData.nSyncNumHighScores++ ], pHiScore );
}
}
if( Net_Link_SeedData.nSyncTrackNum == 12345 ) {
Net_Link_SeedData.nSyncTrackNum = Net_Link_SeedData.anSeedTrackSelected[i];
} else {
/* use our track priority list to decide which track to race*/
nTemp1 = Tracks_anTrackSelectionPriority[ Net_Link_SeedData.anSeedTrackSelected[i] ];
nTemp2 = Tracks_anTrackSelectionPriority[ Net_Link_SeedData.nSyncTrackNum ];
if( nTemp1 < nTemp2 ) {
Net_Link_SeedData.nSyncTrackNum = Net_Link_SeedData.anSeedTrackSelected[i];
}
}
/* accept only the best split times*/
for( j=0; j < TRACK_MAX_CHECKPOINTS; j++ ) {
if( Net_Link_SeedData.afSyncSplitTimes[j] == 0.0f ) {
Net_Link_SeedData.afSyncSplitTimes[j] = Net_Link_SeedData.afSeedSplitTimes[i][j];
} else {
if( Net_Link_SeedData.afSeedSplitTimes[i][j] != 0.0f ) {
if( Net_Link_SeedData.afSeedSplitTimes[i][j] < Net_Link_SeedData.afSyncSplitTimes[j] ) {
Net_Link_SeedData.afSyncSplitTimes[j] = Net_Link_SeedData.afSeedSplitTimes[i][j];
}
}
}
}
j = Net_Link_SeedData.nSyncNumPolePositions;
Net_Link_SeedData.anSyncPolePositions[j][0] = i;/* unit id*/
Net_Link_SeedData.anSyncPolePositions[j][1] = Net_Link_SeedData.anSeedPolePosition[i];/* pole position*/
Net_Link_SeedData.anSyncPolePositions[j][2] = ( Net_Link_SeedData.anSeedPolePosition[i] * NET_DEFS_MAX_LINKED_UNITS ) + i;/* magic number to sort by*/
++Net_Link_SeedData.nSyncNumPolePositions;
if( Net_Link_SeedData.anSeedDifficulty[i] < Net_Link_SeedData.nSyncDifficulty ) {
Net_Link_SeedData.nSyncDifficulty = Net_Link_SeedData.anSeedDifficulty[i];
}
if( Net_Link_SeedData.abSeedNoTimers[i] ) {
Net_Link_SeedData.bSyncNoTimers = TRUE;
}
/* handle secret codes, if anybody didn't enter the code, nobody plays with the code on*/
if( !(Net_Link_SeedData.anSeedSecretCodes[i] & SECRET_CODES_NO_AI) ) {
Net_Link_SeedData.nSyncSecretCodes &= ~SECRET_CODES_NO_AI;
}
if( !(Net_Link_SeedData.anSeedSecretCodes[i] & SECRET_CODES_NO_CATCHUP) ) {
Net_Link_SeedData.nSyncSecretCodes &= ~SECRET_CODES_NO_CATCHUP;
}
if( Net_Link_SeedData.afSeedRandomSeed[i] > Net_Link_SeedData.fSyncRandomSeed ) {
Net_Link_SeedData.fSyncRandomSeed = Net_Link_SeedData.afSeedRandomSeed[i];
}
if( Net_Link_SeedData.afSeedStartingSecs[i] > Net_Link_SeedData.fSyncStartingSecs ) {
Net_Link_SeedData.fSyncStartingSecs = Net_Link_SeedData.afSeedStartingSecs[i];
}
for( j=0; j < TRACK_MAX_CHECKPOINTS; j++ ) {
if( Net_Link_SeedData.afSeedChkPtSecs[i][j] > Net_Link_SeedData.afSyncChkPtSecs[j] ) {
Net_Link_SeedData.afSyncChkPtSecs[j] = Net_Link_SeedData.afSeedChkPtSecs[i][j];
}
}
if( Net_Link_SeedData.abSeedChaserGoesOffWithAi[i] ) {
Net_Link_SeedData.bSyncChaserGoesOffWithAi = TRUE;
}
if( Net_Link_SeedData.abSeedMaxFreeRaceEnable[i] ) {
Net_Link_SeedData.bSyncMaxFreeRaceEnable = TRUE;
}
if( Net_Link_SeedData.anSeedMaxFreeRacePercent[i] < Net_Link_SeedData.nSyncMaxFreeRacePercent ) {
Net_Link_SeedData.nSyncMaxFreeRacePercent = Net_Link_SeedData.anSeedMaxFreeRacePercent[i];
}
if( Net_Link_SeedData.anSeedAiDifficulty[i] > Net_Link_SeedData.nSyncAiDifficulty ) {
Net_Link_SeedData.nSyncAiDifficulty = Net_Link_SeedData.anSeedAiDifficulty[i];
}
if( Net_Link_SeedData.afSeedTrackWinPercent[i] > Net_Link_SeedData.fSyncTrackWinPercent ) {
Net_Link_SeedData.fSyncTrackWinPercent = Net_Link_SeedData.afSeedTrackWinPercent[i];
}
if( Net_Link_SeedData.afSeedGlobalWinPercent[i] > Net_Link_SeedData.fSyncGlobalWinPercent ) {
Net_Link_SeedData.fSyncGlobalWinPercent = Net_Link_SeedData.afSeedGlobalWinPercent[i];
}
if( Net_Link_SeedData.afSeedTrackBias[i] > Net_Link_SeedData.fSyncTrackBias ) {
Net_Link_SeedData.fSyncTrackBias = Net_Link_SeedData.afSeedTrackBias[i];
}
if( Net_Link_SeedData.afSeedGlobalBias[i] > Net_Link_SeedData.fSyncGlobalBias ) {
Net_Link_SeedData.fSyncGlobalBias = Net_Link_SeedData.afSeedGlobalBias[i];
}
if( Net_Link_SeedData.anSeedNumFreeRacesInARow[i] > Net_Link_SeedData.nSyncNumFreeRacesInARow ) {
Net_Link_SeedData.nSyncNumFreeRacesInARow = Net_Link_SeedData.anSeedNumFreeRacesInARow[i];
}
}
}
/*//////////////////////////////////////////////////////*/
/* NOW SET ALL OF OUR GAME VARS TO OUR NET SYNCED VALUES*/
/* set our track and timing values*/
tracks_SetCurrentTrack( Net_Link_SeedData.nSyncTrackNum, Net_Link_SeedData.nSyncDifficulty );
Tracks_fCurrentStartSecs = Net_Link_SeedData.fSyncStartingSecs;
Player_fCountdownSecs = Net_Link_SeedData.fSyncStartingSecs;
for( i=0; i < TRACK_MAX_CHECKPOINTS; i++ ) {
Tracks_afCurrentChkPtSecs[i] = Net_Link_SeedData.afSyncChkPtSecs[i];
}
if(bEUROCOM_SPLITSCREEN)
Player_nHumanCount = 2; //PAB This gets reset here so make it two!!!
else
Player_nHumanCount = Net_Link_SeedData.nNumSeeds;
/* reset our player array to the defaults*/
player_ResetPlayersToDefaults();
/* reset our cached controls, so that everyone start with zeroed out control values*/
controls_ZeroCachedControls();
/* set up the initial frame times*/
for( i=0; i< PLAYER_MAX_HUMAN_RACERS; i++ ) {
Player_afHumanFrameTime[i] = 0.015f;
}
if(bEUROCOM_SPLITSCREEN){
Player_nAiCount = 0;
Player_aData[0].nBoatType = nBoatTypes[0];
Player_aData[1].nBoatType = nBoatTypes[1];
}
else{
Player_aData[0].nBoatType = nBoatTypes[0];
Player_nAiCount = (Net_Link_SeedData.nSyncSecretCodes & SECRET_CODES_NO_AI) ? 0 : (PLAYER_MAX_RACERS - Player_nHumanCount);
}
Player_nTotalCount = Player_nHumanCount + Player_nAiCount;
/* set the boat types, and whether they are human*/
// for( i=0; i < NET_DEFS_MAX_LINKED_UNITS; i++ ) {
// if( Net_Link_SeedData.nSeedMask & (1 << i) ) {
// Player_aData[i].nFlags |= PLAYER_FLAG_HUMAN;
// Player_aData[i].nBoatType = Net_Link_SeedData.anSeedBoatSelected[i];
// }
// }
if( Player_nAiCount ) {
/* set up our active player pointers array*/
for(i=0; i<Player_nTotalCount; i++) {
Player_apData[i] = &Player_aData[i];
}
} else {
j = 0;
for( i=0; i < NET_DEFS_MAX_LINKED_UNITS; i++ ) {
if( Player_aData[i].nFlags & PLAYER_FLAG_HUMAN ) {
Player_apData[j++] = &Player_aData[i];
}
}
}
/* record that a race was played*/
audits_StartARace();
/* record the humans with the auditor*/
auditor_PreRace( Player_nHumanCount, Net_Link_SeedData.nSeedMask, Net_Link_SeedData.nSyncDifficulty );
/* set up the human list*/
nListIndex = 0;
for( i=0; i< Player_nTotalCount; i++ ) {
if( Player_apData[i]->nFlags & PLAYER_FLAG_HUMAN ) {
Player_anHumanList[ nListIndex++ ] = Player_apData[i]->nId;
}
}
/* since everyone synced up whether or not to use timers, lets use this synced value*/
Temp_bNoTimers = Net_Link_SeedData.bSyncNoTimers;
/* everyone should set the ai's difficulty to synced values*/
ai_rabbit_SetNetSyncedData( Net_Link_SeedData.nSyncAiDifficulty,
Net_Link_SeedData.nSyncNumFreeRacesInARow,
Net_Link_SeedData.bSyncMaxFreeRaceEnable,
Net_Link_SeedData.nSyncMaxFreeRacePercent,
Net_Link_SeedData.fSyncTrackWinPercent,
Net_Link_SeedData.fSyncGlobalWinPercent,
Net_Link_SeedData.fSyncTrackBias,
Net_Link_SeedData.fSyncGlobalBias );
/* bubble sort the pole positions based on the magic number*/
nLimit = Net_Link_SeedData.nNumSeeds - 1;
for( i=0; i < nLimit; i++ ) {
for( j=i+1; j < Net_Link_SeedData.nNumSeeds; j++) {
/* compare the two magic number values*/
if( Net_Link_SeedData.anSyncPolePositions[i][2] > Net_Link_SeedData.anSyncPolePositions[j][2] ) {
/* swap these values*/
nTemp1 = Net_Link_SeedData.anSyncPolePositions[i][0];
nTemp2 = Net_Link_SeedData.anSyncPolePositions[i][1];
nTemp3 = Net_Link_SeedData.anSyncPolePositions[i][2];
Net_Link_SeedData.anSyncPolePositions[i][0] = Net_Link_SeedData.anSyncPolePositions[j][0];
Net_Link_SeedData.anSyncPolePositions[i][1] = Net_Link_SeedData.anSyncPolePositions[j][1];
Net_Link_SeedData.anSyncPolePositions[i][2] = Net_Link_SeedData.anSyncPolePositions[j][2];
Net_Link_SeedData.anSyncPolePositions[j][0] = nTemp1;
Net_Link_SeedData.anSyncPolePositions[j][1] = nTemp2;
Net_Link_SeedData.anSyncPolePositions[j][2] = nTemp3;
}
}
}
/* resolve any pole position conflicts and record it in the player structure,*/
for( i=0; i < Net_Link_SeedData.nNumSeeds; i++ ) {
j = Net_Link_SeedData.anSyncPolePositions[i][0];
Player_aData[j].nPlace = Player_aData[j].nEarnedStartPlace = i+1;
Net_Link_SeedData.anSyncPolePositions[i][1] = (i+1);
}
/* bubble sort the high scores also*/
/* only necessary if we have more than 1 in our group*/
if( Net_Link_SeedData.nNumSeeds > 1 ) {
nLimit = Net_Link_SeedData.nSyncNumHighScores - 1;
for( i=0; i < nLimit; i++ ) {
for( j=i+1; j < Net_Link_SeedData.nSyncNumHighScores; j++ ) {
/* compare the two values*/
if( Net_Link_SeedData.aSyncHighScores[i].fTime > Net_Link_SeedData.aSyncHighScores[j].fTime ) {
/* swap these values*/
nBoat = Net_Link_SeedData.aSyncHighScores[i].nBoat;
cInitials[0] = Net_Link_SeedData.aSyncHighScores[i].cInitials[0];
cInitials[1] = Net_Link_SeedData.aSyncHighScores[i].cInitials[1];
cInitials[2] = Net_Link_SeedData.aSyncHighScores[i].cInitials[2];
fTime = Net_Link_SeedData.aSyncHighScores[i].fTime;
Net_Link_SeedData.aSyncHighScores[i].nBoat = Net_Link_SeedData.aSyncHighScores[j].nBoat;
Net_Link_SeedData.aSyncHighScores[i].cInitials[0] = Net_Link_SeedData.aSyncHighScores[j].cInitials[0];
Net_Link_SeedData.aSyncHighScores[i].cInitials[1] = Net_Link_SeedData.aSyncHighScores[j].cInitials[1];
Net_Link_SeedData.aSyncHighScores[i].cInitials[2] = Net_Link_SeedData.aSyncHighScores[j].cInitials[2];
Net_Link_SeedData.aSyncHighScores[i].fTime = Net_Link_SeedData.aSyncHighScores[j].fTime;
Net_Link_SeedData.aSyncHighScores[j].nBoat = nBoat;
Net_Link_SeedData.aSyncHighScores[j].cInitials[0] = cInitials[0];
Net_Link_SeedData.aSyncHighScores[j].cInitials[1] = cInitials[1];
Net_Link_SeedData.aSyncHighScores[j].cInitials[2] = cInitials[2];
Net_Link_SeedData.aSyncHighScores[j].fTime = fTime;
}
}
}
/*////////////////////////////////////////////*/
/* write out the high score table to our table*/
/*////////////////////////////////////////////*/
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
hi_score_CopyHiScoreStruct( &Hi_Score_Table.Table[Tracks_nCurrentTrack][i], &Net_Link_SeedData.aSyncHighScores[i] );
}
/*///////////////////////////////////////*/
/* write out the split times to our table*/
/*///////////////////////////////////////*/
for( i=0; i < TRACK_MAX_CHECKPOINTS; i++ ) {
Hud_SplitTimes.fCheckPointTimes[Tracks_nCurrentTrack][i] = Net_Link_SeedData.afSyncSplitTimes[i];
}
}
/*//////////////////////////////////////////////*/
/* Seed our net friendly random number generator*/
/*//////////////////////////////////////////////*/
race_SeedRandom( Net_Link_SeedData.fSyncRandomSeed );
/*//////////////////////*/
/* turn off catchup code*/
/*//////////////////////*/
if( Net_Link_SeedData.nSyncSecretCodes & SECRET_CODES_NO_CATCHUP ) {
player_EnableHumanToHumanCheats( FALSE );
}
/* should we check for a free race*/
player_SetCheckForFreeRaceVar( Net_Link_SeedData.nSyncSecretCodes, Player_nHumanCount );
}
static u32 _GetInstanceCountOfAHighScoreOnOneUnit( CmosHiScore_t *pHiScore ) {
u32 i, j, nCount, nMaxCount;
nMaxCount = 0;
for( i=0; i < NET_DEFS_MAX_LINKED_UNITS; i++ ) {
if( Net_Link_SeedData.nSeedMask & (1 << i) ) {
nCount = 0;
for( j=0; j < CMOS_HI_SCORES_PER_TRACK; j++ ) {
if( hi_score_Compare2Scores( pHiScore, &Net_Link_SeedData.aSeedHighScores[i][j] ) ) {
++nCount;
}
}
if( nCount > nMaxCount ) {
nMaxCount = nCount;
}
}
}
return nMaxCount;
}
static u32 _GetInstanceCountOfAHighScoreInSyncedList( CmosHiScore_t *pHiScore ) {
u32 i, nCount;
nCount = 0;
for( i=0; i < Net_Link_SeedData.nSyncNumHighScores; i++ ) {
if( hi_score_Compare2Scores( pHiScore, &Net_Link_SeedData.aSyncHighScores[i] ) ) {
++nCount;
}
}
return nCount;
}
mesh3d.c
A seemingly complete version of mesh3d.c can be found at 0x7C16000.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* mesh3d.c - General 3D mesh definitions.*/
/**/
/* Author: Steve Ranck*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 04-14-97 Ranck Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "gfxdefs.h"
#include "vec3.h"
#include "xfm.h"
#include "viewport.h"
#include "glide.h"
#include "gutil.h"
#include "xmath.h"
#include "tmem.h"
#include "mesh3d.h"
#include "light.h"
#include "blit.h"
#include "sysmem.h"
#include "glcount.h"
#include "material.h"
#include "xclib.h"
#include <private.h>
#define _INLINE_ASM_ENABLED FALSE
#define _ASM_TRANSFORM_ENABLED TRUE
#define _ASM_LIGHTING_ENABLED TRUE
#define _DYNAMIC_LIGHTING_ENABLED TRUE
#define _LIGHTING_CACHE_ENABLED TRUE
#define OLD_OOW_CALC_METHOD 0
#define MY_TEMP_TEST 0
#define MY_TEMP_TEST2 0
#define MESH3D_ZTUG_DELTA_DEPTH_BIAS 5
#ifdef MESH3D_USE_32BIT_TC_INDEX_FIELDS
static Mesh3dMtlDef_t _UnmappedTextureMtl_1Sided = {
0, 0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
static Mesh3dMtlDef_t _UnmappedTextureMtl_2Sided = {
MESH3D_MTLFLAG_2SIDED, 0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
#else
static Mesh3dMtlDef_t _UnmappedTextureMtl_1Sided = {
0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
static Mesh3dMtlDef_t _UnmappedTextureMtl_2Sided = {
MESH3D_MTLFLAG_2SIDED, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
#endif
/*==================================================================================*/
/* Public Variables:*/
#if MESH3D_ENABLE_STATS
u32 Mesh3d_nTrisCulled_BackfaceTest;
u32 Mesh3d_nTrisCulled_TriBoundTest;
u32 Mesh3d_nTrisCulled_TriVtxTest;
u32 Mesh3d_nTrisCulled_TriClipTest;
u32 Mesh3d_nTrisDrawn_Unclipped;
u32 Mesh3d_nTrisDrawn_Clipped;
#endif
#if MESH3D_TRI_HIGHLIGHT_CODE
BOOL Mesh3d_bDisplayFaceNorms;
BOOL Mesh3d_bDisplayVtxNorms;
RGBn_t Mesh3d_FaceNormColor;
RGBn_t Mesh3d_VtxNormColor;
float Mesh3d_fNormLength;
BOOL Mesh3d_bWireframeMode; /* FALSE: normal rendering, TRUE: opaque tris and wireframes*/
RGBn_t Mesh3d_WireframeColor; /* Color when Mesh3d_bWireframeMode is TRUE*/
Mesh3dPolyDrawFcn_t *Mesh3d_pPolyDrawFcn; /* Called for every poly drawn (NULL=none)*/
#endif
Mesh3dVtxCache_t *Mesh3d_pVtxCache;
Mesh3dVlCache_t *Mesh3d_pVlCache;
u32 Mesh3d_nNextAvailVtxCacheIndex;
u32 Mesh3d_nNextAvailVlCacheIndex;
u32 Mesh3d_nCacheKey;
u32 Mesh3d_nLastFrameCounter;
u32 Mesh3d_nMaxVtxCacheIndex;
u32 Mesh3d_nMaxVlCacheIndex;
#if MESH3D_HIGHLIGHT_2SIDED
BOOL Mesh3d_bHighlight2Sided;
#endif
/*==================================================================================*/
/* Private Variables:*/
static BOOL _bCacheEnable;
static int _nMaterialFilter;
static Mesh3dMtlDef_t *_pCurrentMaterial;
static u32 _nMaterialFlags;
static TexDef_t *_pMaterialTexDef;
static float _fMaterialShininess;
static float _fMaterialShinyStrength;
static float _fMaterialSpecularProduct;
static BOOL _bMaterialTexture;
static BOOL _bMaterial2Sided;
static BOOL _bMaterialReflective;
static BOOL _bMaterialNoDiffuse;
BOOL _bMaterialNoDynLight;
static BOOL _bMaterialAlphaLit;
static BOOL _bMaterialTileS;
static BOOL _bMaterialTileT;
static BOOL _bMaterialZtug;
BOOL _bMaterialNoIncidenceAtten; /* For lighting*/
static u32 _nMaterialAlphaLightColor;
static float _fOrthoYScale = 1.0f;
static int _nUntuggedDepthBiasLevel;
static int _nTuggedDepthBiasLevel;
static BOOL _bZtugOn;
static RGBf_t _AlphaLightColor;
static u32 _nAlphaLightState;
Mesh3dAmbient_t _Ambient; /* ambient light*/
static float _fWhiteSat; /* white saturation level (0=normal, 1=fully white)*/
static u32 _dwWhiteSat;
static float _fR, _fG, _fB, _fA; /* temporary variables used for lighting*/
static float _fRGBA[4];
static Vec3_t _Vtx3d, _VtxUnitNorm, _VtxToCam;
static float _Vtx[6];
static float _fInvMagVtxToCam;
static BOOL _bMustCalcInvMagVtxToCam;
static u32 _nFindMtlById_ID;
static u32 _nFindMtlById_GrpIndex;
static u32 _nFindMtlById_TlIndex;
static Mesh3d_t *_pFindMtlById_Mesh;
static float _fOrthoRedBias;
static float _fOrthoGreenBias;
static float _fOrthoBlueBias;
static float _fOrthoOpaqueness;
static float _fOrthoWhiteSat;
static u32 _dwOrthoWhiteSat;
static BOOL _bOrthoUseScreenCoverageDraw;
static GrColor_t _OrthoConstColor;
static u32 _nNextPrintedMsgFrameCounter;
static MidwayLight_t *_apLightList[MESH3D_MAX_ACTIVE_LIGHTS];
static MidwayLight_t **_ppLightList;
static u32 _nNumLights;
static u32 _nLightListStartIndex;
static u32 _nIncludedPositionalLights;
static u32 _nIncludedDirectionalLights;
MidwayLight_t *_apPosGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apDirGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apSpotGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apFlashGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
u32 _nNumGrpLights;
u32 _nNumPosGrpLights;
u32 _nNumDirGrpLights;
u32 _nNumSpotGrpLights;
u32 _nNumFlashGrpLights;
BOOL _bWorldMesh; /* mesh vertices are in world-space*/
static BOOL _bReflectSurface;
static float _fReflectSurfaceHeight_WorldSpace;
static Vec3_t _PointOnReflectSurface_Camspace;
static Vec3_t _ReflectSurfaceUnitNorm_Camspace;
static float _fNegDistAboveReflectSurface_Camspace;
static float _fReflectSurfaceAnimateCounter;
#if MESH3D_BOUNDING_VIEW_ENABLED
static Mesh3dTriDef_t *_pHighlightedTri; /* NULL=none*/
static int _nTriSphereCrossesPlanesMaskTmp;
static int _nTriSphereCrossesPlanesMask;
static BOOL _bViewOrthoBoundEnabled;
static BOOL _bViewBoundEnabled;
static BOOL _bViewMeshSphere;
static BOOL _bViewMeshVolume;
static BOOL _bViewGroupSphere;
static BOOL _bViewGroupVolume;
static BOOL _bViewTriSphere;
static int _nSelectedTriNum;
static int _nSelectedMatNum;
static int _nSelectedGrpNum;
#endif
static Mesh3d_t _SensorMesh;
static Mesh3dGrpDef_t _SensorGrp;
static Vec3_t _avModelViewNorm[4]; /* viewport normals in model space:*/
/* [0]=left, [1]=right, [2]=bottom, [3]=top*/
static Mesh3dVtxCache_t clippedvtx[40], *grvp[40];
extern float dcCullTest(float *pCamPos, float *pPos, float *pNorm);
extern void dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest);
extern void dcTransformVerticesA(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest);
extern void dcComputeDirLight(MidwayLight_t **pLightList, int NumLights, float *pNormal, float Rgb[3] );
extern void dcComputeSpotLight(MidwayLight_t **pLightList, int NumLights, float *pNormal, float Rgb[3] );
extern void dcComputeVtxLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn );
extern void dcComputeMotifLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl );
extern void dcOutputTri(Mesh3dVtxCache_t*, Mesh3dVtxCache_t*, Mesh3dVtxCache_t*);
extern void dcLightTri( Mesh3d_t *pMesh, Mesh3dGrpDef_t * pGrp, Mesh3dVtxCache_t *apVtxCache[3], Mesh3dTriVtx_t *pTriVtx);
extern Mesh3dVtxCache_t _dcVertexBuffer[8192];
/*==================================================================================*/
/* Prototypes:*/
static BOOL _SetOrthoMaterial( int *pnTmuIndex, u32 nMtlFlags );
static void _SetMaterial( BOOL bLightAlphaTexels );
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _ClipTriToFrustumAndDraw( u32 nTriNum, Mesh3dVtxCache_t **ppVtxCache, int nTriCrossesPlanesMask );
#else
static void _ClipTriToFrustumAndDraw( Mesh3dVtxCache_t **ppVtxCache, int nTriCrossesPlanesMask );
#endif
//static void _ComputeVtxLighting( Mesh3dGrpDef_t *pGrp, GrVertex *pGrVertex, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn );
//static void _ComputeFlashLight( void );
static void _ComputeOmniLight( void );
static void _ComputeDirLight( void );
static void _ComputeSpotLight( void );
static void _ComputeFlashLight_NoNormal( void );
static void _ComputeOmniLight_NoNormal( void );
static void _ComputeDirLight_NoNormal( void );
static void _ComputeSpotLight_NoNormal( void );
static void _DrawOrthoSphere( Vec3_t *pCenter, float fRadius, u32 nColorRGB555, float fViewportX, float fViewportY, int nRoll, float fScale );
static void _DrawProjectedSphere( Vec3_t *pCenter, float fRadius, u32 nColorRGB555 );
#if MESH3D_BOUNDING_VIEW_ENABLED
static void _UpdateViewBoundVars( void );
#endif
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _DrawConvexPolyWireframe( int nNumVerts, Mesh3dVtxCache_t *apVtxCache[] );
#endif
static void _IntersectPosLightListWithBound( Mesh3d_t *pMesh, Mesh3dBound_t *pBound, BOOL bTestingGroupBound );
static void _ComputeReflectParameters( void );
static void _WabbleScreenPoint( float *pfScreenX, float *pfScreenY, float fCamspaceX, float fCamspaceY, float fCamspaceZ );
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _DisplayFaceNormal( Mesh3dVtxCache_t **ppVtxCache, Vec3_t *pFaceUnitNorm );
static void _DisplayVtxNormal( Mesh3dVtxCache_t *pVtxCache, Mesh3dVnDef_t *pVtxNorm );
static void _DrawNormal( Vec3_t *pHead, Vec3_t *pTail, int nRed, int nGreen, int nBlue );
#endif
//*****************************************************************************
// SH4 Inline Asm Code:
//*****************************************************************************
//=============================================================================
// Transform a list of vertices to screen space
// extern void dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest, BOOL bClips);
// if bPlanesMask is 0 faster transform is used (no camera x,y,z is saved off)
#if _INLINE_ASM_ENABLED
#pragma inline_asm(_dcTransformVertices)
static void _dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest, BOOL nPlanesMask)
{
tst r7, r7
bf LTRANS1 ; Clipped transform
mov.l L064, r0 ; Viewport_zscreen
fmov.s @r0, fr10
mov.l L065, r1 ; dcViewportYTrans
fmov.s @r1, fr8
xor r7, r7
mova f320, r0
fmov.s @r0, fr9 ; 320.0f
add #16, r6
L004:
mov r4, r3
add #32, r3
pref @r3 ; fetch next 32 bytes into the cache
;transform 1st vertex
fmov.s @r4+, fr0 ; get model v
fmov.s @r4+, fr1
fmov.s @r4+, fr2
fldi1 fr3
add.l #4, r4
fldi1 fr7
ftrv xmtrx, fv0 ; mtrx * v
fmov.s @r4+, fr4 ; get model v
fmul fr2, fr2
fmov.s @r4+, fr5
fsrra fr2 ; 1/z*z
fmov.s @r4+, fr6
fmov.s fr2, @-r6
fmul fr10, fr2 ; q = Viewport_zscreen * ooz
fmov fr8, fr11
fmul fr2, fr1 ; y = q * cam y
fsub fr1, fr11 ; dcViewportYTrans - y
fmov.s fr11, @-r6
fmul fr2, fr0 ; x = q * cam x
fadd fr9, fr0
fmov.s fr0, @-r6
add.l #108, r6
;transform 2nd vertex
ftrv xmtrx, fv4 ; mtrx * v
add.l #4, r4
fmul fr6, fr6
add #-2, r5
fsrra fr6 ; 1/z*z
fmov.s fr6, @-r6
fmul fr10, fr6 ; q = Viewport_zscreen * ooz
fmov fr8, fr11
fmul fr6, fr5 ; y = q * cam y
fsub fr5, fr11 ; dcViewportYTrans - y
fmov.s fr11, @-r6
fmul fr6, fr4 ; x = q * cam x
fadd fr9, fr4
fmov.s fr4, @-r6
cmp/gt r7, r5
bt/s L004
add.l #108, r6
bra L060
nop
LTRANS1:
mov.l L064, r0 ; Viewport_zscreen
fmov.s @r0, fr7
mov.l L065, r0 ; dcViewportYTrans
fmov.s @r0, fr8
mova f320, r0
fmov.s @r0, fr9 ; 320.0f
fldi0 fr10
L001:
fldi1 fr3
fmov.s @r4+, fr0 ; get model v
fmov.s @r4+, fr1
fmov.s @r4+, fr2
ftrv xmtrx, fv0 ; mtrx * v
add.l #4, r4
mov r6, r2
add.l #44, r2
fmov.s fr2, @-r2
fmov.s fr1, @-r2
fmov.s fr0, @-r2
fcmp/gt fr10, fr2
bf L003
fmul fr2, fr2
add.l #-16, r2
fsrra fr2 ;1/z*z
fmov.s fr2, @-r2
fmul fr7, fr2 ; q = Viewport_zscreen * ooz
fmov fr8, fr4
fmul fr2, fr1 ; y = q * cam y
fsub fr1, fr4 ; dcViewportYTrans - y
fmov.s fr4, @-r2
fmul fr2, fr0 ; x = q * cam x
fadd fr9, fr0
fmov.s fr0, @-r2
L003:
add #-1, r5
tst r5, r5
bf/s L001
add.l #96, r6
bra L060
nop
L064:
.DATA.L _Viewport_zscreen
L065
.DATA.L _dcViewportYTrans
f320:
.FDATA.S F'320.0
L060:
}
//=============================================================================
// Light a vertex
//
#pragma inline_asm(_dcComputeVtxLighting)
static void _dcComputeVtxLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn )
{
mov.l r13, @-r15
mov.l r14, @-r15
fmov.s fr12, @-r15
fmov.s fr13, @-r15
fmov.s fr14, @-r15
fmov.s fr15, @-r15
mov #12, r0 ;get Vtx intensity
fmov.s @(r0,r6),fr11
; Ambient
mov r5, r13
mov #28, r0 ;pVn
mov.l @(r0,r15), r14
mov.l L016, r0
add #20, r0
mov #16, r1
mov.l #H'84, r1
fmov.s @r0+, fr15 ;_Ambient.ScaledColor
add r1, r4
fmov.s @r0+, fr14
add #8, r7
fmov.s @r0+, fr13
mov r4, r3 ;pGrp->aMotifConstColor[0].rgb
add #H'10, r3
;Compute motif lights
; SLOT 0
mov @r4+, r0 ;nMotif
tst r0, r0
bt L020
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L019
mov r3, r0
L019
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L020:
add #12, r3
add #4, r7
;SLOT 1
mov @r4+, r0 ;nMotif
tst r0, r0
bt L054
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L053
mov r3, r0
L053:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L054:
add #12, r3
add #4, r7
;SLOT 2
mov @r4+, r0 ;nMotif
tst r0, r0
bt L056
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L055
mov r3, r0
L055:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L056:
add #12, r3
add #4, r7
;SLOT 3
mov @r4+, r0 ;nMotif
tst r0, r0
bt L058
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L057
mov r3, r0
L057:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L058:
;Do dynamic lighting
mov.l L028, r1
mov.l @r1, r0
tst r0, r0
bt L063 ;__nNumGrpLights
mov.l L030, r1
mov.l @r1, r0
tst r0, r0
bt L062
L063
bra L033
nop
L062:
;Compute directional light
mov.l L031, r1
mov.l @r1, r5 ;__nNumDirGrpLights
tst r5, r5
bt L050
mov.l L032, r4 ;__apDirGrpLight
fmov.s @r14+, fr4 ;Vtx normal
fmov.s @r14+, fr5
fmov.s @r14+, fr6
add #-12, r14
fldi0 fr7
mov.l #H'80, r1
mov.l #H'90, r2
L005:
mov.l @r4+, r0 ;pLight
mov.l r0, r3
add r1, r3
fmov.s @r3+, fr0 ;fLx = pLight->ModSpaceUnitDir.p[0]
fmov.s @r3+, fr1 ;fLy = pLight->ModSpaceUnitDir.p[1]
fmov.s @r3+, fr2 ;fLz = pLight->ModSpaceUnitDir.p[2]
fldi0 fr3
fipr fv4, fv0 ;x * fLx + y * fLy + z * fLz;
fcmp/gt fr7, fr3
bf L006
fmov fr3, fr0
add r2, r0
fmov.s @r0+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr3
fmac fr0, fr3, fr13
L006:
add #-1, r5
tst r5, r5
bf L005
L050:
;Compute omni light
mov.l L039, r1
mov.l @r1, r5 ;__nPosGrpLights
tst r5, r5
bt L041
mov.l L040, r4 ;__apPosGrpLight
mov r6, r0 ;pVtx
fmov.s @r0+, fr8
fmov.s @r0+, fr9
fmov.s @r0+, fr10
fldi0 fr7
L043:
mov.l @r4+, r3 ;pLight
mov.l r3, r2
add #104, r2 ;ModSpacePos
fmov.s @r2+, fr4
fsub fr8, fr4 ;ModSpacePos - Vtx
fmov.s @r2+, fr5
fsub fr9, fr5
fmov.s @r2+, fr6
fsub fr10, fr6 ;get dist
fmov fr4, fr0
fmov fr5, fr1
fmov fr6, fr2
fldi0 fr3
fipr fv0, fv0
mov #120, r0 ; dist > pLight->fModSpaceRadius2 ?
fmov.s @(r0,r3), fr12
fcmp/gt fr12, fr3
bt L042
fmov fr3, fr11 ;fLightDist2
fmov.s @r14+, fr0 ;Vtx normal
fmov.s @r14+, fr1
fldi0 fr3
fmov.s @r14+, fr2
add #-12, r14
fipr fv4, fv0
fcmp/gt fr7, fr3
bf L042
mov #28, r0
fmov.s @(r0,r3), fr2 ;pLight->fRadialAttenuation
fmul fr11, fr2 ; * fLightDist2
fmov fr12, fr0 ;pLight->fModSpaceRadius2
fsub fr2, fr0
mov #124, r0
fmov.s @(r0,r3), fr1 ;pLight->fModSpaceInvRadius2
fmul fr1, fr0
mov.l #H'90, r0
add r0, r3
fmov.s @r3+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr15
fmov.s @r3+, fr2 ;g = pLight->ScaledColor.rgb[1];
fmac fr0, fr2, fr14
fmov.s @r3+, fr3 ;b = pLight->ScaledColor.rgb[2];
fmac fr0, fr3, fr13
L042:
add #-1, r5
tst r5, r5
bf L043
L041:
;Compute spot light
mov.l L045, r1
mov.l @r1, r5 ;__nSpotGrpLights
tst r5, r5
bt L061
mov.l L044, r4 ;__apSpotGrpLight
mov.l #H'80, r3
L012:
mov.l @r4+, r1 ;pLight
mov.l r1, r2
add #104, r2
mov r6, r0 ;pVtx
fmov.s @r0+, fr0
fmov.s @r2+, fr4 ;pLight->ModSpacePos.p - pVtx
fsub fr0, fr4
fmov.s @r0+, fr1
fmov.s @r2+, fr5
fsub fr1, fr5
fmov.s @r0+, fr2
fmov.s @r2+, fr6
fsub fr2, fr6
fldi0 fr7
; fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
fmov fr4, fr0
fmov fr5, fr1
fmov fr6, fr2
fldi0 fr3
fipr fv0, fv0
fmov fr3, fr11
; if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
mov #120, r0
fmov.s @(r0,r1), fr12
fcmp/gt fr12, fr3
bt L013
; fDot = pVec[0]*fLx + pVec[1]*fLy + pVec[2]*fLz;
fmov.s @r14+, fr0
fmov.s @r14+, fr1
fldi0 fr3
fmov.s @r14+, fr2
add #-12, r14
fipr fv4, fv0
; if( fDot < 0 ) continue;
fcmp/gt fr7, fr3
bf L013
fmov fr3, fr10
; fDx = pLight->ModSpaceUnitDir.p[0];
; fDy = pLight->ModSpaceUnitDir.p[1];
; fDz = pLight->ModSpaceUnitDir.p[2];
mov r1, r2
add r3, r2
fmov.s @r2+, fr0
fmov.s @r2+, fr1
fldi0 fr3
fmov.s @r2+, fr2
; fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
fipr fv4, fv0
; if( fDot2 <= 0.00001f ) continue;
fcmp/gt fr7, fr3
bf L013
; fInvLightDist = 1.0f / xmath_sqrt( fLightDist2 );
fmov fr11, fr9
fsrra fr9
; fDot2 *= fInvLightDist;
; fT2 = fDot2*fDot2*fDot2
fmul fr9, fr3
fmov fr3, fr1
fmul fr3, fr3 ; fDot * fDot
fmul fr1, fr3 ; * fDot
; fT1 = fT2*fT2;
fmul fr3, fr3
; fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
; * pLight->fModSpaceInvRadius2;
mov #28, r0
fmov.s @(r0,r1), fr2 ;pLight->fRadialAttenuation
fmul fr11, fr2 ; * fLightDist2
fmov fr12, fr0 ;pLight->fModSpaceRadius2
fsub fr2, fr0
mov #124, r0
fmov.s @(r0,r1), fr1 ;pLight->fModSpaceInvRadius2
fmul fr1, fr0
fmul fr3, fr0
mov.l #H'A0, r0
mov.b @(r0,r1),r0 ;pLight->bNoIncidenceAtten
mov.l L048, r2 ;__bMaterialNoIncidenceAtten
extu.b r0, r0
mov.l @r2, r2
or r2, r0
tst r0, r0
bf L049
fmul fr10, fr0
fmul fr9, fr0
L049:
mov.l #H'90, r0
add r0, r1
fmov.s @r1+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr13
fmov.s @r1+, fr2 ;g = pLight->ScaledColor.rgb[1];
fmac fr0, fr2, fr14
fmov.s @r1+, fr3 ;b = pLight->ScaledColor.rgb[2];
fmac fr0, fr3, fr15
L013:
add #-1, r5
tst r5, r5
bf L012
L061:
L033:
;Convert r,g,b to argb
fldi1 fr1
mova L024, r0
fmov.s @r0, fr0 ;255.0f
;r
fcmp/gt fr1, fr13 ;clamp to 255
bf L025
fmov fr0, fr13
bra L038
nop
L025:
fmul fr0, fr13 ;* 255.0f
L038:
ftrc fr13, fpul ;r = r > 255 ? 255 : r
sts fpul, r2
;g
fcmp/gt fr1, fr14
bf L026
fmov fr0, fr14
bra L036
nop
L026:
fmul fr0, fr14
L036:
ftrc fr14, fpul
sts fpul, r3
;b
fcmp/gt fr1, fr15
bf L027
fmov fr0, fr15
bra L037
nop
L027:
fmul fr0, fr15
L037:
ftrc fr15, fpul
sts fpul, r4
shll8 r3
fmov.s @r15+, fr15
shll16 r2
fmov.s @r15+, fr14
shll8 r1 ; *pArgb = ((r << 16) | (g << 8) | b) | 0xff000000;
fmov.s @r15+, fr13
shll16 r1
fmov.s @r15+, fr12
or r2, r3
mov.l @r15+, r14
or r4, r3
mov.l #H'FF000000,r0
or r3, r1
or r0, r1
mov r1, @r13
mov.l @r15+, r13
bra L080
nop
.ALIGN 4
L016:
.DATA.L __Ambient
L021:
.DATA.L _Light_aLightMotifTable
L024:
.FDATA.S F'255.0
L028:
.DATA.L __nNumGrpLights
L030:
.DATA.L __bMaterialNoDynLight
L031:
.DATA.L __nNumDirGrpLights
L032:
.DATA.L __apDirGrpLight
L039:
.DATA.L __nNumPosGrpLights;
L040:
.DATA.L __apPosGrpLight
L044:
.DATA.L __apSpotGrpLight
L045:
.DATA.L __nNumSpotGrpLights
L048:
.DATA.L __bMaterialNoIncidenceAtten
L080:
}
#endif
/*==================================================================================*/
/* Public Functions:*/
/* mesh3d_SystemInit:*/
/* Initializes the mesh3d system and sets certain global parameters*/
/* to default values.*/
BOOL mesh3d_ModuleInit( void ) {
u32 nVtxCacheBytes, nVlCacheBytes;
#if SYS_WINDEV_DEBUG
u32 i;
#endif
mesh3d_EnableCache( TRUE );
Mesh3d_nMaxVtxCacheIndex = 0;
Mesh3d_nMaxVlCacheIndex = 0;
nVtxCacheBytes = MESH3D_MAX_CACHED_VTX * sizeof(Mesh3dVtxCache_t);
nVlCacheBytes = MESH3D_MAX_CACHED_VL * sizeof(Mesh3dVlCache_t);
// Mesh3d_pVtxCache = (Mesh3dVtxCache_t *)SYSMEM_ALLOC( nVtxCacheBytes );
Mesh3d_pVlCache = (Mesh3dVlCache_t *)SYSMEM_ALLOC( nVlCacheBytes );
xprintf( "Allocated %i bytes for mesh3d caches.\n", nVtxCacheBytes+nVlCacheBytes );
mesh3d_ResetCache();
_pFindMtlById_Mesh = NULL;
_bReflectSurface = FALSE;
_nNumLights = 0;
_nLightListStartIndex = 0;
_ppLightList = _apLightList;
_nNumPosGrpLights = 0;
_nNumDirGrpLights = 0;
_nNumSpotGrpLights = 0;
_nNumFlashGrpLights = 0;
_nNumGrpLights = 0;
mesh3d_SetMaterialFilterMode( 0 );
mesh3d_SetWhiteSat( 0.0f );
mesh3d_SetAmbientLight( 1.0f, 1.0f, 1.0f, 1.0f );
mesh3d_SetAmbientEffects( 1.0f );
/* Normal alpha light color is white...*/
_nAlphaLightState = 0;
mesh3d_SetAlphaLightColor( 1.0f, 1.0f, 1.0f, 1.0f );
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
mesh3d_EnableOrthoScreenCoverageDrawState( FALSE );
/* Init sensor stuff...*/
xclib_MemSet( &_SensorMesh, 0, sizeof(Mesh3d_t) );
xclib_MemSet( &_SensorGrp, 0, sizeof(Mesh3dGrpDef_t) );
_SensorMesh.nGrpCount = 1;
_SensorMesh.pGrp = &_SensorGrp;
_SensorMesh.Bound.fBoundRadius = 1.0f;
_SensorGrp.Bound.fBoundRadius = 1.0f;
_nNextPrintedMsgFrameCounter = 0;
return TRUE;
}
/* Sets the mesh reflection-wabble mode and reflection plane world height.*/
/* Returns the prior state of the enable flag.*/
BOOL mesh3d_SetReflectMode( BOOL bEnable, float fWorldReflectPlaneHeight ) {
BOOL bOldMode;
bOldMode = _bReflectSurface;
_bReflectSurface = bEnable;
_fReflectSurfaceHeight_WorldSpace = fWorldReflectPlaneHeight;
return bOldMode;
}
/* Returns the current state of the reflection-wabble enable flag.*/
/* If pfWorldReflectPlaneHeight is not NULL, it is filled with the*/
/* current reflection plane world height.*/
BOOL mesh3d_GetReflectMode( float *pfWorldReflectPlaneHeight ) {
if( pfWorldReflectPlaneHeight ) {
*pfWorldReflectPlaneHeight = _fReflectSurfaceHeight_WorldSpace;
}
return _bReflectSurface;
}
/* Fills pAmbientLightState with the current ambient light state.*/
/* Fields within the structure should not be modified.*/
/* This function also saves the state of the ambient effects.*/
void mesh3d_GetAmbientLightState( Mesh3dAmbient_t *pAmbientLightState ) {
*pAmbientLightState = _Ambient;
}
/* Restores the ambient light state to the state contained in pAmbientLightState.*/
/* pAmbientLightState must have been obtained using mesh3d_GetAmbientLightState().*/
/* This function also restores the state of the ambient effects.*/
void mesh3d_SetAmbientLightState( Mesh3dAmbient_t *pAmbientLightState ) {
_Ambient = *pAmbientLightState;
}
/* fRed, fGreen, and fBlue are from 0.0f to 1.0f and indicate the ambient light color.*/
/* fIntensity is from 0.0f to 1.0f and indicates the intensity of the specified*/
/* color.*/
void mesh3d_SetAmbientLight( float fRed, float fGreen, float fBlue, float fIntensity ) {
XASSERT_UNIT_FLOAT( fRed );
XASSERT_UNIT_FLOAT( fGreen );
XASSERT_UNIT_FLOAT( fBlue );
XASSERT_UNIT_FLOAT( fIntensity );
_Ambient.Color.rgb[2] = fRed;
_Ambient.Color.rgb[1] = fGreen;
_Ambient.Color.rgb[0] = fBlue;
_Ambient.fIntensity = fIntensity;
_Ambient.ScaledColor.rgb[2] = fRed * fIntensity;
_Ambient.ScaledColor.rgb[1] = fGreen * fIntensity;
_Ambient.ScaledColor.rgb[0] = fBlue * fIntensity;
}
/* Fills *pfRed, *pfGreen, *pfBlue, and *pfIntensity with the current values*/
/* set by the most recent call to mesh3d_SetAmbientLight().*/
/* All values have the range 0.0f to 1.0f.*/
void mesh3d_GetAmbientLight( float *pfRed, float *pfGreen, float *pfBlue, float *pfIntensity ) {
*pfRed = _Ambient.Color.rgb[2];
*pfGreen = _Ambient.Color.rgb[1];
*pfBlue = _Ambient.Color.rgb[0];
*pfIntensity = _Ambient.fIntensity;
}
/* Fills *pfRed, *pfGreen, and *pfBlue with the current values set by the*/
/* most recent call to mesh3d_SetAmbientLight(). The values are pre-scaled*/
/* by the intensity value most recently passed to mesh3d_SetAmbientLight().*/
/* All values have the range 0.0f to 1.0f.*/
void mesh3d_GetAmbientScaledLight( float *pfRed, float *pfGreen, float *pfBlue ) {
*pfRed = _Ambient.ScaledColor.rgb[2];
*pfGreen = _Ambient.ScaledColor.rgb[1];
*pfBlue = _Ambient.ScaledColor.rgb[0];
}
/* fOpaqueness is a value from 0.0f (transparent) to 1.0f (opaque).*/
void mesh3d_SetAmbientEffects( float fOpaqueness ) {
XASSERT_UNIT_FLOAT( fOpaqueness );
_Ambient.fOpaqueness = fOpaqueness;
_Ambient.nScaledOpaqueness = (u32)(fOpaqueness * 255.0f) << 24;
}
/* Returns the current white saturation level (0=none, 1=fully white).*/
float mesh3d_GetWhiteSat( void ) {
return _fWhiteSat;
}
/* Sets the current white saturation level (0=none, 1=fully white).*/
void mesh3d_SetWhiteSat( float fWhiteSat ) {
XASSERT_UNIT_FLOAT( fWhiteSat );
_fWhiteSat = fWhiteSat;
_dwWhiteSat = dcRGB( (u32)(_fWhiteSat * 255.0f),
(u32)(_fWhiteSat * 255.0f),
(u32)(_fWhiteSat * 255.0f) );
}
/* Returns the current material filter mode. See MESH3D_MTL_FILTER for info.*/
/* Note that more than one bit may be set.*/
int mesh3d_GetMaterialFilterMode( void ) {
return _nMaterialFilter;
}
/* Sets the current material filter mode. See MESH3D_MTL_FILTER for info.*/
/* Note that more than one bit may be set.*/
void mesh3d_SetMaterialFilterMode( int nMaterialFilter ) {
XASSERT( (nMaterialFilter & ~(MESH3D_MTL_FILTER_OUT_MAIN|MESH3D_MTL_FILTER_OUT_COLLIDE)) == 0 );
_nMaterialFilter = nMaterialFilter;
}
/* Sets the color used to light alpha lights.*/
/* All parameters have the range of 0.0f to 1.0f.*/
/* Returns the previous state which can be used by mesh3d_SetAlphaLightState()*/
/* to restore the state to its previous condition.*/
u32 mesh3d_SetAlphaLightColor( float fRed, float fGreen, float fBlue, float fIntensity ) {
u32 nPriorState;
XASSERT_UNIT_FLOAT( fRed );
XASSERT_UNIT_FLOAT( fGreen );
XASSERT_UNIT_FLOAT( fBlue );
XASSERT_UNIT_FLOAT( fIntensity );
nPriorState = _nAlphaLightState;
fIntensity *= 255.0f;
_AlphaLightColor.rgb[2] = fRed * fIntensity;
_AlphaLightColor.rgb[1] = fGreen * fIntensity;
_AlphaLightColor.rgb[0] = fBlue * fIntensity;
_nAlphaLightState = ((u32)_AlphaLightColor.rgb[2]<<16)
| ((u32)_AlphaLightColor.rgb[1]<<8)
| ((u32)_AlphaLightColor.rgb[0]);
return nPriorState;
}
/* Returns the current alpha light state. The returned value can be*/
/* passed to mesh3d_SetAlphaLightState() to restore the alpha light state.*/
u32 mesh3d_GetAlphaLightState( void ) {
return _nAlphaLightState;
}
/* Restores the alpha light state. The return value is the prior state.*/
u32 mesh3d_SetAlphaLightState( u32 nAlphaLightState ) {
u32 nPreviousState;
XASSERT( !(nAlphaLightState & 0xff000000) );
nPreviousState = _nAlphaLightState;
if( nAlphaLightState != _nAlphaLightState ) {
_AlphaLightColor.rgb[2] = (float)(nAlphaLightState>>16);
_AlphaLightColor.rgb[1] = (float)( (nAlphaLightState>>8) & 0xff );
_AlphaLightColor.rgb[0] = (float)( nAlphaLightState & 0xff);
_nAlphaLightState = nAlphaLightState;
}
return nPreviousState;
}
/* Clears the active light list.*/
/* Invalidates all Light and Dark Frames.*/
/* If you simply want to temporarily disable all current lights*/
/* on the light stack while drawing your object, use*/
/* mesh3d_ClearLightFrame() instead.*/
void mesh3d_ClearLightList( void ) {
_nNumLights = 0;
_nLightListStartIndex = 0;
_ppLightList = _apLightList;
}
/* Starts a lighting frame. The value returned can be passed to*/
/* mesh3d_ReleaseLightFrame() to restore the lighting stack state.*/
/* All lights currently in the mesh3d light buffer remain in effect*/
/* and will light objects drawn with mesh3d_Draw() or associated*/
/* functions. To clear the current frame to black, use*/
/* mesh3d_ClearLightFrame().*/
u32 mesh3d_StartLightFrame( void ) {
return (_nNumLights | (_nLightListStartIndex<<16) );
}
/* Disables all lights in the current light frame.*/
/* Should be called only when a call to mesh3d_StartLightFrame()*/
/* has previously been made.*/
void mesh3d_ClearLightFrame( void ) {
_nLightListStartIndex = _nNumLights;
_ppLightList = &_apLightList[_nLightListStartIndex];
_nNumLights = 0;
}
/* Restores the lighting stack to its state at the time nLightFrame*/
/* was sampled.*/
void mesh3d_ReleaseLightFrame( u32 nLightFrame ) {
_nNumLights = nLightFrame & 0xffff;
_nLightListStartIndex = nLightFrame>>16;
_ppLightList = &_apLightList[_nLightListStartIndex];
}
/* Adds a light to the active light list.*/
/* If the light already exists in the list, simply returns (TRUE).*/
/* Returns TRUE if successful.*/
/* Returns FALSE if the light list is full.*/
BOOL mesh3d_AddLight( MidwayLight_t *pLight ) {
u32 nNewFlags;
u32 i;
for( i=0; i<_nNumLights; i++ ) {
if( _ppLightList[i] == pLight ) {
/* Light already exists in list. Simply exit...*/
return TRUE;
}
}
switch( pLight->nType ) {
case LIGHT_TYPE_OMNI:
nNewFlags = LIGHT_FLAG_HASPOS;
break;
case LIGHT_TYPE_DIR:
case LIGHT_TYPE_FLASH:
nNewFlags = LIGHT_FLAG_HASDIR;
break;
case LIGHT_TYPE_SPOT:
nNewFlags = LIGHT_FLAG_HASPOS|LIGHT_FLAG_HASDIR;
break;
default:
XASSERT_NOW; /* Invalid light nType field*/
}
if( _nNumLights < MESH3D_MAX_ACTIVE_LIGHTS ) {
_ppLightList[_nNumLights++] = pLight;
pLight->nFlags &= ~(LIGHT_FLAG_HASPOS|LIGHT_FLAG_HASDIR);
pLight->nFlags |= nNewFlags;
return TRUE;
} else {
if( Gameloop_nFrameCounter > _nNextPrintedMsgFrameCounter ) {
xprintferr( "WARNING: More than %d dynamic lights\nlighting an object.\n", MESH3D_MAX_ACTIVE_LIGHTS );
_nNextPrintedMsgFrameCounter = Gameloop_nFrameCounter+30;
}
return FALSE;
}
}
static void _ComputeOmniLight( void ) {
register float fLightDist2,x,y,z,fDot;
register MidwayLight_t *pLight;
register s32 i;
x = _Vtx[3];
y = _Vtx[4];
z = _Vtx[5];
for(i = _nNumPosGrpLights-1; i >= 0; --i) {
pLight = _apPosGrpLight[i];
{
register fLx,fLy,fLz;
/* Calculate light vector from vertex to light (toward light)...*/
fLx = pLight->ModSpacePos.p[0] - x;
fLy = pLight->ModSpacePos.p[1] - y;
fLz = pLight->ModSpacePos.p[2] - z;
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 )
continue;
fDot = _Vtx[0]*fLx + _Vtx[1]*fLy + _Vtx[2]*fLz;
if( fDot < 0 )
continue;
}
{
float fInvLightDist,fRadialAtten,fIntensity;
/* Vertex is within light's range... */
fInvLightDist = fsrra(fLightDist2);
fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
if( !(pLight->bNoIncidenceAtten|_bMaterialNoIncidenceAtten) ) {
fIntensity = fRadialAtten * fDot * fInvLightDist;
}
else {
fIntensity = fRadialAtten;
}
_fRGBA[0] += pLight->ScaledColor.rgb[2] * fIntensity;
_fRGBA[1] += pLight->ScaledColor.rgb[1] * fIntensity;
_fRGBA[2] += pLight->ScaledColor.rgb[0] * fIntensity;
}
}
}
static void _ComputeDirLight( void ) {
register float fDot,x,y,z;
register MidwayLight_t *pLight;
register s32 i;
x = _Vtx[0];
y = _Vtx[1];
z = _Vtx[2];
for(i = _nNumDirGrpLights-1; i >=0; --i) {
pLight = _apDirGrpLight[i];
/* Get light vector from vertex to light (toward light)... */
{
register float fLx,fLy,fLz;
fLx = pLight->ModSpaceUnitDir.p[0];
fLy = pLight->ModSpaceUnitDir.p[1];
fLz = pLight->ModSpaceUnitDir.p[2];
fDot = x * fLx + y * fLy + z * fLz;
if(fDot <= 0 )
continue;
}
{
register float r,g,b;
r = pLight->ScaledColor.rgb[2];
g = pLight->ScaledColor.rgb[1];
b = pLight->ScaledColor.rgb[0];
if( !(pLight->bNoIncidenceAtten|_bMaterialNoIncidenceAtten) ) {
_fRGBA[0] += r * fDot;
_fRGBA[1] += g * fDot;
_fRGBA[2] += b * fDot;
}
else {
_fRGBA[0] += r;
_fRGBA[1] += g;
_fRGBA[2] += b;
}
}
}
}
static void _ComputeSpotLight( void ) {
float fIntensity, fDot, fDot2, fLightDist2, fInvLightDist;
float fSpotAtten, fLx, fLy, fLz, fRx, fRy, fRz;
float fRadialAtten, fDx, fDy, fDz, fT1, fT2, fT3, fT4;
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumSpotGrpLights; i++ ) {
pLight = _apSpotGrpLight[i];
/* Calculate light vector from vertex to light (toward light)... */
fLx = pLight->ModSpacePos.p[0] - _Vtx[3];
fLy = pLight->ModSpacePos.p[1] - _Vtx[4];
fLz = pLight->ModSpacePos.p[2] - _Vtx[5];
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
/* Vertex is within light's range... */
fDot = _Vtx[0]*fLx + _Vtx[1]*fLy + _Vtx[2]*fLz;
if( fDot <= 0.00001f ) continue;
/* Calculate attenuation based on spotlight direction... */
fDx = pLight->ModSpaceUnitDir.p[0];
fDy = pLight->ModSpaceUnitDir.p[1];
fDz = pLight->ModSpaceUnitDir.p[2];
fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
if( fDot2 <= 0.00001f ) continue;
fInvLightDist = 1.0f / xmath_sqrt( fLightDist2 );
fDot2 *= fInvLightDist;
switch( pLight->nSpotFocusCode ) {
case SPOTLIGHT_FOCUS_WIDEST:
fT1 = fDot2*fDot2*fDot2;
break;
case SPOTLIGHT_FOCUS_WIDER:
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_WIDE:
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2*fT2;
break;
case SPOTLIGHT_FOCUS_MEDIUM:
fT3 = fDot2*fDot2*fDot2;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHT:
fT3 = fDot2*fDot2*fDot2;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHTER:
fT4 = fDot2*fDot2*fDot2;
fT3 = fT4*fT4*fT4;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHTEST:
fT4 = fDot2*fDot2*fDot2;
fT3 = fT4*fT4*fT4;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2*fT2;
break;
default:
XASSERT_NOW; /* Invalid spot focus code ! */
}
fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
fSpotAtten = fT1 * fRadialAtten;
if( fSpotAtten < 0.00001f ) continue;
if( !(pLight->bNoIncidenceAtten|_bMaterialNoIncidenceAtten) ) {
fIntensity = fSpotAtten * fDot * fInvLightDist;
} else {
fIntensity = fSpotAtten;
}
_fRGBA[0] += pLight->ScaledColor.rgb[2] * fIntensity;
_fRGBA[1] += pLight->ScaledColor.rgb[1] * fIntensity;
_fRGBA[2] += pLight->ScaledColor.rgb[0] * fIntensity;
}
}
/*
static void _ComputeSpotLight( void ) {
float fIntensity, fDot, fDot2, fLightDist2, fInvLightDist;
float fSpotAtten, fLx, fLy, fLz, fRx, fRy, fRz;
float fRadialAtten, fDx, fDy, fDz, fT1, fT2, fT3, fT4;
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumSpotGrpLights; i++ ) {
pLight = _apSpotGrpLight[i];
// Calculate light vector from vertex to light (toward light)...
fLx = pLight->ModSpacePos.p[0] - _Vtx[3];
fLy = pLight->ModSpacePos.p[1] - _Vtx[4];
fLz = pLight->ModSpacePos.p[2] - _Vtx[5];
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
// Vertex is within light's range...
fDot = _Vtx[0]*fLx + _Vtx[1]*fLy + _Vtx[2]*fLz;
if( fDot < 0 ) continue;
// Calculate attenuation based on spotlight direction...
fDx = pLight->ModSpaceUnitDir.p[0];
fDy = pLight->ModSpaceUnitDir.p[1];
fDz = pLight->ModSpaceUnitDir.p[2];
fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
if( fDot2 <= 0 ) continue;
fInvLightDist = 1.0f / xmath_sqrt( fLightDist2 );
fDot2 *= fInvLightDist;
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2;
fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
fSpotAtten = fT1 * fRadialAtten;
if( fSpotAtten < 0)
continue;
if( !(pLight->bNoIncidenceAtten|_bMaterialNoIncidenceAtten) ) {
fIntensity = fSpotAtten * fDot * fInvLightDist;
} else {
fIntensity = fSpotAtten;
}
_fRGBA[0] += pLight->ScaledColor.rgb[2] * fIntensity;
_fRGBA[1] += pLight->ScaledColor.rgb[1] * fIntensity;
_fRGBA[2] += pLight->ScaledColor.rgb[0] * fIntensity;
}
}
*/
/* Senses the light RGBA value from the specified model-space position and direction.*/
/* Note that the direction points toward the direction to sense (the direction the sensor*/
/* points). The alpha (A) value is the white saturation value from flash lights.*/
/* To use this function, the transformation matrix stack must first be set up, which*/
/* establishes the model space where pModelSpacePos and pModelSpaceDir reside.*/
/* bWorldSpace can be set for speed optimization if the current matrix stack represents*/
/* world space.*/
void mesh3d_LightSensor( const Vec3_t *pModelSpacePos, const Vec3_t *pModelSpaceDir, ARGBf_t *pSensedLight, BOOL bWorldSpace ) {
#if TARGET!=ULTRA64
vec3_Copy( &_SensorMesh.Bound.BoundCenter, pModelSpacePos );
vec3_Copy( &_SensorGrp.Bound.BoundCenter, pModelSpacePos );
_bWorldMesh = bWorldSpace;
_BuildGroupLightList( &_SensorMesh, &_SensorGrp );
vec3_CalcUnit( &_Vtx[0], pModelSpaceDir );
/* Start with ambient light...*/
_fRGBA[0] = _Ambient.ScaledColor.rgb[2];
_fRGBA[1] = _Ambient.ScaledColor.rgb[1];
_fRGBA[2] = _Ambient.ScaledColor.rgb[0];
/* Add in dynamic lighting...*/
if( _nNumGrpLights ) {
_Vtx[3] = pModelSpacePos->p[0];
_Vtx[4] = pModelSpacePos->p[1];
_Vtx[5] = pModelSpacePos->p[2];
_fMaterialSpecularProduct = 0.0f;
_bMaterialNoIncidenceAtten = FALSE;
if( _nNumPosGrpLights ) {
_ComputeOmniLight();
}
if( _nNumDirGrpLights ) {
_ComputeDirLight();
}
if( _nNumSpotGrpLights ) {
_ComputeSpotLight();
}
// if( _nNumFlashGrpLights ) {
// _ComputeFlashLight();
// }
}
pSensedLight->argb[2] = (_fRGBA[0]>1.0f) ? 1.0f : _fRGBA[0];
pSensedLight->argb[1] = (_fRGBA[1]>1.0f) ? 1.0f : _fRGBA[1];
pSensedLight->argb[0] = (_fRGBA[2]>1.0f) ? 1.0f : _fRGBA[2];
pSensedLight->argb[3] = 1.0f;
#endif /*ULTRA64*/
}
static void _ComputeFlashLight_NoNormal( void ) {
u32 i;
for( i=0; i<_nNumFlashGrpLights; i++ ) {
_fA += _apFlashGrpLight[i]->ScaledColor.rgb[0];
}
}
static void _ComputeDirLight_NoNormal( void ) {
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumDirGrpLights; i++ ) {
pLight = _apDirGrpLight[i];
_fR += pLight->ScaledColor.rgb[2];
_fG += pLight->ScaledColor.rgb[1];
_fB += pLight->ScaledColor.rgb[0];
}
}
static void _ComputeSpotLight_NoNormal( void ) {
float fDot2, fLightDist2, fInvLightDist;
float fSpotAtten, fLx, fLy, fLz;
float fRadialAtten, fDx, fDy, fDz, fT1, fT2, fT3, fT4;
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumSpotGrpLights; i++ ) {
pLight = _apSpotGrpLight[i];
/* Calculate light vector from vertex to light (toward light)... */
fLx = pLight->ModSpacePos.p[0] - _Vtx3d.p[0];
fLy = pLight->ModSpacePos.p[1] - _Vtx3d.p[1];
fLz = pLight->ModSpacePos.p[2] - _Vtx3d.p[2];
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
/* Calculate attenuation based on spotlight direction... */
fDx = pLight->ModSpaceUnitDir.p[0];
fDy = pLight->ModSpaceUnitDir.p[1];
fDz = pLight->ModSpaceUnitDir.p[2];
fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
if( fDot2 <= 0.00001f ) continue;
fInvLightDist = 1.0f / xmath_sqrt( fLightDist2 );
fDot2 *= fInvLightDist;
switch( pLight->nSpotFocusCode ) {
case SPOTLIGHT_FOCUS_WIDEST:
fT1 = fDot2*fDot2*fDot2;
break;
case SPOTLIGHT_FOCUS_WIDER:
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_WIDE:
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2*fT2;
break;
case SPOTLIGHT_FOCUS_MEDIUM:
fT3 = fDot2*fDot2*fDot2;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHT:
fT3 = fDot2*fDot2*fDot2;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHTER:
fT4 = fDot2*fDot2*fDot2;
fT3 = fT4*fT4*fT4;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2;
break;
case SPOTLIGHT_FOCUS_TIGHTEST:
fT4 = fDot2*fDot2*fDot2;
fT3 = fT4*fT4*fT4;
fT2 = fT3*fT3*fT3;
fT1 = fT2*fT2*fT2;
break;
default:
XASSERT_NOW; /* Invalid spot focus code ! */
}
fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
fSpotAtten = fT1 * fRadialAtten;
if( fSpotAtten < 0.00001f ) continue;
_fR += pLight->ScaledColor.rgb[2] * fSpotAtten;
_fG += pLight->ScaledColor.rgb[1] * fSpotAtten;
_fB += pLight->ScaledColor.rgb[0] * fSpotAtten;
}
}
static void _ComputeOmniLight_NoNormal( void ) {
float fIntensity, fLightDist2;
float fLx, fLy, fLz;
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumPosGrpLights; i++ ) {
pLight = _apPosGrpLight[i];
/* Calculate light vector from vertex to light (toward light)... */
fLx = pLight->ModSpacePos.p[0] - _Vtx3d.p[0];
fLy = pLight->ModSpacePos.p[1] - _Vtx3d.p[1];
fLz = pLight->ModSpacePos.p[2] - _Vtx3d.p[2];
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
/* Vertex is within light's range... */
fIntensity = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
_fR += pLight->ScaledColor.rgb[2] * fIntensity;
_fG += pLight->ScaledColor.rgb[1] * fIntensity;
_fB += pLight->ScaledColor.rgb[0] * fIntensity;
}
}
#if 0
static void _ComputeSpotLight_NoNormal( void ) {
float fDot2, fLightDist2, fInvLightDist;
float fSpotAtten, fLx, fLy, fLz;
float fRadialAtten, fDx, fDy, fDz, fT1, fT2, fT3, fT4;
MidwayLight_t *pLight;
u32 i;
for( i=0; i<_nNumSpotGrpLights; i++ ) {
pLight = _apSpotGrpLight[i];
/* Calculate light vector from vertex to light (toward light)... */
fLx = pLight->ModSpacePos.p[0] - _Vtx3d.p[0];
fLy = pLight->ModSpacePos.p[1] - _Vtx3d.p[1];
fLz = pLight->ModSpacePos.p[2] - _Vtx3d.p[2];
fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
/* Calculate attenuation based on spotlight direction... */
fDx = pLight->ModSpaceUnitDir.p[0];
fDy = pLight->ModSpaceUnitDir.p[1];
fDz = pLight->ModSpaceUnitDir.p[2];
fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
if( fDot2 <= 0.00001f ) continue;
fInvLightDist = fsrra(fLightDist2);
fDot2 *= fInvLightDist;
fT2 = fDot2*fDot2*fDot2;
fT1 = fT2*fT2;
fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
* pLight->fModSpaceInvRadius2;
fSpotAtten = fT1 * fRadialAtten;
if( fSpotAtten < 0.00001f ) continue;
_fR += pLight->ScaledColor.rgb[2] * fSpotAtten;
_fG += pLight->ScaledColor.rgb[1] * fSpotAtten;
_fB += pLight->ScaledColor.rgb[0] * fSpotAtten;
}
}
#endif
void mesh3d_LightSensorPoint( const Vec3_t *pWorldSpacePos, ARGBf_t *pSensedLight ) {
_bWorldMesh = TRUE;
_BuildGroupLightList( NULL, NULL );
/* Start with ambient light... */
_fR = _Ambient.ScaledColor.rgb[2];
_fG = _Ambient.ScaledColor.rgb[1];
_fB = _Ambient.ScaledColor.rgb[0];
_fA = 0.0f;
/* Add in dynamic lighting... */
if( _nNumGrpLights ) {
_Vtx3d.p[0] = pWorldSpacePos->p[0];
_Vtx3d.p[1] = pWorldSpacePos->p[1];
_Vtx3d.p[2] = pWorldSpacePos->p[2];
if( _nNumPosGrpLights ) {
_ComputeOmniLight_NoNormal();
}
if( _nNumDirGrpLights ) {
_ComputeDirLight_NoNormal();
}
if( _nNumSpotGrpLights ) {
_ComputeSpotLight_NoNormal();
}
if( _nNumFlashGrpLights ) {
_ComputeFlashLight_NoNormal();
}
}
pSensedLight->argb[3] = (_fA>1.0f) ? 1.0f : _fA;
pSensedLight->argb[2] = (_fR>1.0f) ? 1.0f : _fR;
pSensedLight->argb[1] = (_fG>1.0f) ? 1.0f : _fG;
pSensedLight->argb[0] = (_fB>1.0f) ? 1.0f : _fB;
}
/* Finds the min and max points of a bounding box. If there are not at*/
/* least 4 points in the bounding box, then pMax and pMin will be filled*/
/* up with a box created by using the provided radius.*/
void mesh3d_FindMinMaxPtsOfBoundingBox( const Mesh3dBound_t *pBound, Vec3_t *pMax, Vec3_t *pMin ) {
u32 i;
/* Make sure that we have enough points to do comparsions with...*/
if( pBound->nNumBoundPoints >= 4 ) {
/* Set both vectors to 0...*/
pMax->p[0] = pMax->p[1] = pMax->p[2] = pMin->p[0] = pMin->p[1] = pMin->p[2] = 0.0f;
for( i=0; i<pBound->nNumBoundPoints; i++ ) {
/* First compare x's...*/
if( pBound->aBoundPoints[i].p[0] < pMin->p[0] ) {
pMin->p[0] = pBound->aBoundPoints[i].p[0];
}
if( pBound->aBoundPoints[i].p[0] > pMax->p[0] ) {
pMax->p[0] = pBound->aBoundPoints[i].p[0];
}
/* Next compare y's...*/
if( pBound->aBoundPoints[i].p[1] < pMin->p[1] ) {
pMin->p[1] = pBound->aBoundPoints[i].p[1];
}
if( pBound->aBoundPoints[i].p[1] > pMax->p[1] ) {
pMax->p[1] = pBound->aBoundPoints[i].p[1];
}
/* Finally compare z's...*/
if( pBound->aBoundPoints[i].p[2] < pMin->p[2] ) {
pMin->p[2] = pBound->aBoundPoints[i].p[2];
}
if( pBound->aBoundPoints[i].p[2] > pMax->p[2] ) {
pMax->p[2] = pBound->aBoundPoints[i].p[2];
}
}
} else {
/* This mesh doesn't have a bounding box.*/
/* Use 4 vecs 90 degress apart of mag = fRadius...*/
pMax->p[0] = pMax->p[1] = pMax->p[2] = XMATH_SIN45 * pBound->fBoundRadius;
pMin->p[0] = pMin->p[1] = pMin->p[2] = -XMATH_SIN45 * pBound->fBoundRadius;
}
}
/* Overrides the tiling mode for the specified mesh.*/
/* If pMtl is NULL, the tiling mode for all materials in the mesh are overridden.*/
/* If pMtl is not NULL, only the material pointed to by pMtl is altered.*/
/* S and T tiling modes can be individually altered by setting the bAlterS and bAlterT*/
/* parameters. If bAlterS is TRUE then bTileS is recognized. If bAlterT is TRUE then*/
/* bTileT is recognized. If either of these bAlter parameters are FALSE then their*/
/* corresponding bTile parameter is ignored.*/
void mesh3d_OverrideTilingMode( Mesh3d_t *pMesh, Mesh3dMtlDef_t *pMtl, BOOL bAlterS, BOOL bAlterT, BOOL bTileS, BOOL bTileT ) {
u32 i, nMtlCount;
if( pMtl ) {
/* Override for just this one material...*/
if( bAlterS ) {
if( bTileS ) {
pMtl->nFlags |= MESH3D_MTLFLAG_TILE_S;
} else {
pMtl->nFlags &= ~MESH3D_MTLFLAG_TILE_S;
}
}
if( bAlterT ) {
if( bTileT ) {
pMtl->nFlags |= MESH3D_MTLFLAG_TILE_T;
} else {
pMtl->nFlags &= ~MESH3D_MTLFLAG_TILE_T;
}
}
} else {
/* Override for entire mesh...*/
pMtl = pMesh->pMtl;
nMtlCount = pMesh->nMtlCount;
for( i=0; i<nMtlCount; i++, pMtl++ ) {
if( bAlterS ) {
if( bTileS ) {
pMtl->nFlags |= MESH3D_MTLFLAG_TILE_S;
} else {
pMtl->nFlags &= ~MESH3D_MTLFLAG_TILE_S;
}
}
if( bAlterT ) {
if( bTileT ) {
pMtl->nFlags |= MESH3D_MTLFLAG_TILE_T;
} else {
pMtl->nFlags &= ~MESH3D_MTLFLAG_TILE_T;
}
}
}
}
}
/* If pMtl is NULL then all of the s t coordinates will be changed, */
/* otherwise only the texture coordinates of the material will be changed*/
/**/
/* NOTE: it is the caller's responsiblity to make sure that clamping or */
/* wrapping mode is set as needed*/
void mesh3d_SlideST( Mesh3d_t *pMesh, Mesh3dMtlDef_t *pMtl, f32 fDs, f32 fDt ) {
#if TARGET!=ULTRA64 /* N64 has short int UVs */
u32 i;
Mesh3dTcDef_t *pTc;
#if TARGET==DREAMCAST
fDs *= (1.0f/256.0f);
fDt *= (1.0f/256.0f);
#endif /* DREAMCAST */
/* if no material ptr was passed in, do the all of the texture coordinates*/
if( pMtl == NULL ) {
pTc = pMesh->pTc;
for( i=0; i < pMesh->nTcCount; i++, ++pTc ) {
pTc->s += fDs;
pTc->t += fDt;
}
} else {
pTc = pMesh->pTc;
pTc += pMtl->nTcIndex;
for( i=0; i < pMtl->nTcCount; i++, ++pTc ) {
pTc->s += fDs;
pTc->t += fDt;
}
}
#endif /*ULTRA64 */
}
/* Finds the specified texture name in the given mesh.*/
/* Returns a pointer to the material using the texture.*/
/* Returns NULL if the texture name is not used by the mesh.*/
/**/
/* NOTE: This is not a speedy call. Not a good idea to call*/
/* this each game loop!*/
Mesh3dMtlDef_t *mesh3d_FindTextureByName( Mesh3d_t *pMesh, cchar *pszObName ) {
#if TARGET!=ULTRA64 /* N64 no longer uses triangle lists */
TexDef_t *pTexDef;
Mesh3dTlDef_t *pTlDef;
Mesh3dGrpDef_t *pGrpDef;
u32 g, tl, nNumGrps, nNumTls;
pTexDef = tmem_FindTexture( pszObName );
if( pTexDef ) {
/* found texture object name in tmem*/
nNumGrps = pMesh->nGrpCount;
pGrpDef = pMesh->pGrp;
for( g=0; g<nNumGrps; g++, pGrpDef++ ) {
/* each group...*/
nNumTls = pGrpDef->nTlCount;
pTlDef = pGrpDef->pTl;
for( tl=0; tl<nNumTls; tl++, pTlDef++ ) {
/* each triangle list in group...*/
if( pTlDef->pMtl->pTexDef == pTexDef ) {
/* found material with matching texture definition...*/
return pTlDef->pMtl;
}
}
}
}
#endif /*ULTRA64 */
return NULL;
}
/* Finds the first occurence of a material with the specified nID.*/
/* Use subsequent calls to mesh3d_FindNextMaterialById() to find*/
/* other materials with the same nID.*/
Mesh3dMtlDef_t *mesh3d_FindFirstMaterialById( Mesh3d_t *pMesh, u32 nID ) {
#if TARGET!=ULTRA64 /* N64 no longer uses triangle lists */
Mesh3dTlDef_t *pTlDef;
Mesh3dGrpDef_t *pGrpDef;
u32 g, tl, nNumGrps, nNumTls;
_nFindMtlById_ID = nID;
_pFindMtlById_Mesh = pMesh;
nNumGrps = pMesh->nGrpCount;
pGrpDef = pMesh->pGrp;
for( g=0; g<nNumGrps; g++, pGrpDef++ ) {
/* each group...*/
nNumTls = pGrpDef->nTlCount;
pTlDef = pGrpDef->pTl;
for( tl=0; tl<nNumTls; tl++, pTlDef++ ) {
/* each triangle list in group...*/
if( pTlDef->pMtl->nID == nID ) {
/* found material with matching texture definition...*/
_nFindMtlById_GrpIndex = g;
_nFindMtlById_TlIndex = tl;
return pTlDef->pMtl;
}
}
}
#endif /*ULTRA64 */
return NULL;
}
/* After a call to mesh3d_FindFirstMaterialById() has been made,*/
/* one or more calls to mesh3d_FindNextMaterialById() can be made*/
/* to find further occurences.*/
Mesh3dMtlDef_t *mesh3d_FindNextMaterialById( void ) {
#if TARGET!=ULTRA64 /* N64 no longer uses triangle lists */
Mesh3dTlDef_t *pTlDef;
Mesh3dGrpDef_t *pGrpDef;
u32 g, tl, nNumGrps, nNumTls;
XASSERT( (u32)_pFindMtlById_Mesh );
nNumGrps = _pFindMtlById_Mesh->nGrpCount;
if( _nFindMtlById_GrpIndex >= nNumGrps ) {
return NULL;
}
pGrpDef = &_pFindMtlById_Mesh->pGrp[_nFindMtlById_GrpIndex];
_nFindMtlById_TlIndex++;
nNumTls = pGrpDef->nTlCount;
if( _nFindMtlById_TlIndex >= nNumTls ) {
_nFindMtlById_TlIndex = 0;
_nFindMtlById_GrpIndex++;
pGrpDef++;
if( _nFindMtlById_GrpIndex >= nNumGrps ) {
return NULL;
}
nNumTls = pGrpDef->nTlCount;
}
pTlDef = &pGrpDef->pTl[_nFindMtlById_TlIndex];
tl = _nFindMtlById_TlIndex;
for( g=_nFindMtlById_GrpIndex; g<nNumGrps; g++, pGrpDef++ ) {
/* each group...*/
if( g != _nFindMtlById_GrpIndex ) {
pTlDef = pGrpDef->pTl;
tl = 0;
}
nNumTls = pGrpDef->nTlCount;
for( ; tl<nNumTls; tl++, pTlDef++ ) {
/* each triangle list in group...*/
if( pTlDef->pMtl->nID == _nFindMtlById_ID ) {
/* found material with matching texture definition...*/
_nFindMtlById_GrpIndex = g;
_nFindMtlById_TlIndex = tl;
return pTlDef->pMtl;
}
}
}
_nFindMtlById_GrpIndex = g;
_nFindMtlById_TlIndex = tl;
#endif /*ULTRA64 */
return NULL;
}
#define _INFINITE_LOD_SEARCH_COUNT 1000
/* Returns TRUE if successful.*/
/* Returns FALSE if an error was printed.*/
BOOL mesh3d_FixupMeshPointers( Mesh3d_t *pMesh, const char *pszObName ) {
Mesh3dGrpDef_t *pGrp;
Mesh3dTlDef_t *pTl;
Mesh3dMtlDef_t *pMtl;
Mesh3dTcDef_t *pTc;
int k, g, tl, nTcIndex, nTcCount, nAspectRatioIndex;
u32 nGrpCount, nTlCount;
float fTexScaleS, fTexScaleT;
BOOL bTileS, bTileT;
Mesh3d_t *pMeshLod, *pNextMeshLod;
/*
pMeshLod = pMesh;
for( k=0; k<_INFINITE_LOD_SEARCH_COUNT; k++ ) {
pMeshLod = pMeshLod->pLowerLodMesh;
if( pMeshLod == NULL ) {
break;
}
}
if( k == _INFINITE_LOD_SEARCH_COUNT ) {
xprintferr( "MAJOR ART PROBLEM: Object %s has infinite LOD list.\n", pszObName );
xprintferr( " Disabling LODs for this object.\n" );
xprintferr( " FIX THIS PROBLEM ASAP.\n" );
pMeshLod = pMesh;
for( k=0; k<_INFINITE_LOD_SEARCH_COUNT; k++ ) {
pNextMeshLod = pMeshLod->pLowerLodMesh;
pMeshLod->pLowerLodMesh = NULL;
pMeshLod = pNextMeshLod;
if( pMeshLod == NULL ) {
break;
}
}
return FALSE;
}
*/
pTc = pMesh->pTc;
nGrpCount = pMesh->nGrpCount;
pGrp = pMesh->pGrp;
for( g=0; (u32)g<pMesh->nGrpCount; g++, pGrp++ ) {
/* each group...*/
nTlCount = pGrp->nTlCount;
pTl = pGrp->pTl;
for( tl=0; (u32)tl<pGrp->nTlCount; tl++, pTl++ ) {
pMtl = pTl->pMtl;
/* Fixup all texture coordinates in this material...*/
if( pMtl->nFlags & MESH3D_MTLFLAG_TEXTURE ) {
if( pMtl->pTexDef == NULL ) {
/* This texture was not found by the loader system.*/
/* Make it a solid red color instead...*/
pMtl->nFlags &= ~MESH3D_MTLFLAG_TEXTURE;
pMtl->ConstColor.argb[3] = 1.0f;
pMtl->ConstColor.argb[2] = 1.0f;
pMtl->ConstColor.argb[1] = 0.0f;
pMtl->ConstColor.argb[0] = 0.0f;
} else {
/* Texture found by loader system...*/
if( pMtl->nTcCount==0 || pTc==NULL ) {
/* Material flagged for texture coordinates, but*/
/* no texture coordinates exist...*/
if( pMtl->nFlags & MESH3D_MTLFLAG_2SIDED ) {
pTl->pMtl = &_UnmappedTextureMtl_2Sided;
} else {
pTl->pMtl = &_UnmappedTextureMtl_1Sided;
}
} else {
/* Texture found and texture coordinates supplied...*/
if( !(pMtl->nFlags & MESH3D_MTLFLAG_ST_FIXED_UP) ) {
pMtl->nFlags |= MESH3D_MTLFLAG_ST_FIXED_UP;
/* Convert all texture coordinates used by this material to 3Dfx format...*/
nAspectRatioIndex = pMtl->pTexDef->TexInfo.aspectRatio;
fTexScaleS = Tmem_afTexScale_S[ nAspectRatioIndex ];
fTexScaleT = Tmem_afTexScale_T[ nAspectRatioIndex ];
nTcIndex = pMtl->nTcIndex;
nTcCount = pMtl->nTcCount;
bTileS = bTileT = FALSE;
for( k=0; k<nTcCount; k++, nTcIndex++ ) {
/* Each tc in this material...*/
if( pTc[nTcIndex].s<0.0f || pTc[nTcIndex].s>1.0f ) bTileS = TRUE;
if( pTc[nTcIndex].t<0.0f || pTc[nTcIndex].t>1.0f ) bTileT = TRUE;
#if TARGET!=DREAMCAST
pTc[nTcIndex].s = pTc[nTcIndex].s * fTexScaleS + 0.5f;
pTc[nTcIndex].t = pTc[nTcIndex].t * fTexScaleT + 0.5f;
#endif /* TARGET!=DREAMCAST */
}
pMtl->nFlags &= ~(MESH3D_MTLFLAG_TILE_S | MESH3D_MTLFLAG_TILE_T);
if( bTileS ) pMtl->nFlags |= MESH3D_MTLFLAG_TILE_S;
if( bTileT ) pMtl->nFlags |= MESH3D_MTLFLAG_TILE_T;
}
}
}
}
}
}
return TRUE;
}
/* Enables or Disables the caching system.*/
/* Default is Enabled.*/
/* If disabled, cached vertices will be disgarded between mesh draws.*/
/* Returns the prior state.*/
BOOL mesh3d_EnableCache( BOOL bEnable ) {
BOOL bOldCacheEnableState = _bCacheEnable;
_bCacheEnable = bEnable;
return bOldCacheEnableState;
}
/* Returns the current cache state.*/
BOOL mesh3d_GetCacheEnableState( void ) {
return _bCacheEnable;
}
void mesh3d_ResetCache( void ) {
Mesh3d_nNextAvailVtxCacheIndex = 0;
Mesh3d_nNextAvailVlCacheIndex = 0;
Mesh3d_nCacheKey = 0;
Mesh3d_nLastFrameCounter = 0;
#if SYS_WINDEV_DEBUG
Mesh3d_nMaxVtxCacheIndex = 0;
Mesh3d_nMaxVlCacheIndex = 0;
#endif
}
/* copies a given Mesh3dBound_t struct*/
void mesh3d_CopyBoundingData( Mesh3dBound_t *pDest, Mesh3dBound_t *pSrc ) {
u32 i;
vec3_Copy( &pDest->BoundCenter, &pSrc->BoundCenter );
pDest->fBoundRadius = pSrc->fBoundRadius;
pDest->nNumBoundPoints = pSrc->nNumBoundPoints;
for( i=0; i < pSrc->nNumBoundPoints; i++ ) {
vec3_Copy( &pDest->aBoundPoints[i], &pSrc->aBoundPoints[i] );
}
}
/* allocate and copys the CollSphereList from a mesh, */
/* returns NULL if there was no CollSphereList in the mesh*/
/* or memory could not be allocated */
CollSphereList_t *mesh3d_CreateCollSphereListFromMesh( const Mesh3d_t *pMesh ) {
CollSphereList_t *pSphereList;
CollSphere_t *pHdSphere, *pArray;
u32 i, nCount;
if( !pMesh->pCollSphereList ) {
/* The passed in mesh must have a CollSphereList...*/
return NULL;
}
pSphereList = (CollSphereList_t *)SYSMEM_ALLOC( sizeof( CollSphereList_t ) );
if( !pSphereList ) {
/* The required memory could not be allocated...*/
return NULL;
}
nCount = pMesh->pCollSphereList->nCollSphereArrayCount;
pHdSphere = (CollSphere_t *)SYSMEM_ALLOC( nCount * sizeof( CollSphere_t ) );
if( !pHdSphere ) {
/* The required memory could not be allocated...*/
return NULL;
}
/* We got our memory, just copy the contents and get out of here... */
pSphereList->nCollSphereArrayCount = nCount;
pSphereList->pCollSphereArray = pHdSphere;
pArray = pMesh->pCollSphereList->pCollSphereArray;
for( i=0; i < nCount; i++ ) {
pHdSphere[i].fRadius = pArray[i].fRadius;
vec3_Copy( &pHdSphere[i].Center, &pArray[i].Center );
}
return pSphereList;
}
/* Tests if the specified bounding volume is outside the frustum.*/
/* If not entirely outside, determines which planes the bounding*/
/* volume intersects.*/
/**/
/* nCrossesPlanesMask indicates which planes any larger encompassing*/
/* volume intersects. If there is no larger encompassing volume,*/
/* set nCrossesPlanesMask to 0xf. Here is the definition of the*/
/* bits in nCrossesPlanesMask:*/
/* bit 0: 1=bounding volume intersects left frustum plane*/
/* bit 1: 1=bounding volume intersects right frustum plane*/
/* bit 2: 1=bounding volume intersects bottom frustum plane*/
/* bit 3: 1=bounding volume intersects top frustum plane*/
/**/
/* Returns -1 if the bounding volume is outside.*/
/* Returns a revised version of nCrossesPlanesMask (non-negative) otherwise.*/
int mesh3d_TestBoundWithFrustum( Mesh3dBound_t *pBound, int nCrossesPlanesMask ) {
int i, k, nStillCrossesPlanesMask;
u32 nNumBoundingPoints, nWalkingBit, anCrossCount[4];
float fBoundRadius, fNegBoundRadius, x, y, z, fMag, fDot;
Vec3_t *pvBoundCenter, *pvModelViewNorm, *pvCamViewNorm, vTempVec;
Vec3_t *pvBoundPoints;
/*----------------------------------------------------------------------------------*/
/* Note that Xfm_pStackTop->mr[3][0..2] is the camera's point in model space.*/
XASSERT( !(nCrossesPlanesMask & 0xfffffff0) );
/*----------------------------------------------------------------------------------*/
/* Transform viewport side planes into model space.*/
/* Check to see if mesh's bounding sphere is totally inside,*/
/* outside, or crosses each plane.*/
if( nCrossesPlanesMask /*&& pBound->fBoundRadius>0.0f*/ ) {
/* Bounding sphere crosses at least one plane...*/
nStillCrossesPlanesMask = 0;
fBoundRadius = pBound->fBoundRadius;
pvBoundCenter = &pBound->BoundCenter;
fNegBoundRadius = -fBoundRadius;
vTempVec.p[0] = Xfm_pStackTop->mr[3][0] - pvBoundCenter->p[0];
vTempVec.p[1] = Xfm_pStackTop->mr[3][1] - pvBoundCenter->p[1];
vTempVec.p[2] = Xfm_pStackTop->mr[3][2] - pvBoundCenter->p[2];
pvModelViewNorm = _avModelViewNorm;
pvCamViewNorm = Viewport_rect_norm;
for( i=0, nWalkingBit=1; i<4; i++, nWalkingBit<<=1 ) {
if( nCrossesPlanesMask & nWalkingBit ) {
for( k=0; k<3; k++ ) {
pvModelViewNorm->p[k] = pvCamViewNorm->p[0] * Xfm_pStackTop->mr[0][k]
+ pvCamViewNorm->p[1] * Xfm_pStackTop->mr[1][k]
+ pvCamViewNorm->p[2] * Xfm_pStackTop->mr[2][k];
}
/* Unitize transformed plane normal...*/
x=pvModelViewNorm->p[0]; y=pvModelViewNorm->p[1]; z=pvModelViewNorm->p[2];
fMag = 1.0f/xmath_sqrt( x*x + y*y + z*z );
pvModelViewNorm->p[0]*=fMag;
pvModelViewNorm->p[1]*=fMag;
pvModelViewNorm->p[2]*=fMag;
fDot = vTempVec.p[0]*pvModelViewNorm->p[0]
+ vTempVec.p[1]*pvModelViewNorm->p[1]
+ vTempVec.p[2]*pvModelViewNorm->p[2];
if( fDot > fBoundRadius ) {
/* bounding circle is completely outside plane*/
return -1;
}
if( fDot >= fNegBoundRadius ) {
/* Bounding volume intersects plane*/
nStillCrossesPlanesMask |= nWalkingBit;
}
}
pvModelViewNorm++;
pvCamViewNorm++;
}
nCrossesPlanesMask &= nStillCrossesPlanesMask;
}
/*----------------------------------------------------------------------------------*/
/* If mesh's bounding sphere crosses at least one plane, check crossed planes*/
/* against bounding volume and see which planes it crosses.*/
if( nCrossesPlanesMask && pBound->nNumBoundPoints ) {
/* Bounding sphere crosses at least one plane...*/
nStillCrossesPlanesMask = 0;
nNumBoundingPoints = pBound->nNumBoundPoints;
anCrossCount[0] = anCrossCount[1] = anCrossCount[2] = anCrossCount[3] = 0;
pvBoundPoints = pBound->aBoundPoints;
for( k=0; (u32)k<nNumBoundingPoints; k++, pvBoundPoints++ ) {
vTempVec.p[0] = Xfm_pStackTop->mr[3][0] - pvBoundPoints->p[0];
vTempVec.p[1] = Xfm_pStackTop->mr[3][1] - pvBoundPoints->p[1];
vTempVec.p[2] = Xfm_pStackTop->mr[3][2] - pvBoundPoints->p[2];
for( i=0, nWalkingBit=1; i<4; i++, nWalkingBit<<=1 ) {
if( nCrossesPlanesMask & nWalkingBit ) {
pvModelViewNorm = &_avModelViewNorm[i];
fDot = vTempVec.p[0]*pvModelViewNorm->p[0]
+ vTempVec.p[1]*pvModelViewNorm->p[1]
+ vTempVec.p[2]*pvModelViewNorm->p[2];
if( fDot > 0.0f ) {
/* Bounding point outside frustum plane...*/
anCrossCount[i]++;
nStillCrossesPlanesMask |= nWalkingBit;
}
}
}
}
/* If all bounding volume points are outside any frustum side,*/
/* cull entire mesh:*/
for( i=0; i<4; i++ ) {
if( anCrossCount[i] == nNumBoundingPoints ) {
return -1;
}
}
/* If all bounding volume points are inside any frustum side,*/
/* don't include those sides for triangle culling tests:*/
nCrossesPlanesMask &= nStillCrossesPlanesMask;
}
return nCrossesPlanesMask;
}
/* Sets special effects used by subsequent mesh3d_DrawOrtho() calls.*/
/* All values have a range of 0.0f to 1.0f.*/
/* fRedBias, fGreenBias, and fBlueBias indicate the color bias. If no color bias is*/
/* desired, use 1.0f for all 3 components.*/
/* fOpaqueness indicates the opaqueness of the object. 0.0f is completely*/
/* transparent, and 1.0f is completely opaque.*/
/* fWhiteSat indicates the white saturation level applied. 0.0f indicates none.*/
/* 1.0f indicates white.*/
void mesh3d_SetOrthoEffects( float fRedBias, float fGreenBias, float fBlueBias,
float fOpaqueness, float fWhiteSat ) {
_fOrthoRedBias = fRedBias;
_fOrthoGreenBias = fGreenBias;
_fOrthoBlueBias = fBlueBias;
_fOrthoOpaqueness = fOpaqueness * 255.0f;
_fOrthoWhiteSat = fWhiteSat;
_dwOrthoWhiteSat = dcRGB( (u32)(_fOrthoWhiteSat * 255.0f),
(u32)(_fOrthoWhiteSat * 255.0f),
(u32)(_fOrthoWhiteSat * 255.0f) );
_OrthoConstColor = GFXDEFS_FLOATARGB_TO_GRCOLOR( fWhiteSat, fRedBias, fGreenBias, fBlueBias );
}
/* Sets the state that all future calls to mesh3d_DrawOrtho will use.*/
/* returns the prior state (default is false)*/
BOOL mesh3d_EnableOrthoScreenCoverageDrawState( BOOL bEnable ) {
BOOL bOldValue;
bOldValue = _bOrthoUseScreenCoverageDraw;
_bOrthoUseScreenCoverageDraw = bEnable;
return bOldValue;
}
/* Returns a pointer to the mesh for the appropriate LOD based on the distance*/
/* from the camera (top of matrix stack). pBaseMesh points to the highest-LOD*/
/* mesh in the series. If pnLod is not NULL, it is filled with the LOD number,*/
/* where 0 indicates the base mesh passed in, 1 is the next lower LOD, etc.*/
Mesh3d_t *mesh3d_DetermineLod( Mesh3d_t *pBaseMesh, int *pnLod ) {
float fCamDist2, fDx, fDy, fDz;
Mesh3d_t *pMesh;
int nLod,i;
Mesh3d_t *p[16];
pMesh = pBaseMesh;
nLod = 0; /* Init to highest LOD*/
if( pBaseMesh->pLowerLodMesh ) {
/* Calculate distance from mesh to camera (squared)...*/
fDx = Xfm_pStackTop->mr[3][0];
fDy = Xfm_pStackTop->mr[3][1];
fDz = Xfm_pStackTop->mr[3][2];
fCamDist2 = fDx*fDx + fDy*fDy + fDz*fDz;
while( (pBaseMesh=pBaseMesh->pLowerLodMesh) && (pBaseMesh->fSwitchInCamDist2<fCamDist2) ) {
pMesh = pBaseMesh;
nLod++;
}
}
if( pnLod ) {
*pnLod = nLod;
}
return pMesh;
}
/* Same as mesh3d_Draw(), but determines the appropriate LOD to draw.*/
/* See mesh3d_DetermineLod() for info on LODs.*/
int mesh3d_DrawWithLod( Mesh3d_t *pBaseMesh, int nCrossesPlanesMask, BOOL bLightAlphaTexels ) {
Mesh3d_t *pMesh;
pMesh = mesh3d_DetermineLod( pBaseMesh, NULL );
return mesh3d_Draw( pMesh, nCrossesPlanesMask, bLightAlphaTexels );
}
static void _SetMaterial( BOOL bLightAlphaTexels ) {
GrColor_t ConstantColor;
if( !_bMaterialZtug ) {
if( _bZtugOn ) {
gutil_SetDepthBiasLevel( _nUntuggedDepthBiasLevel );
_bZtugOn = FALSE;
}
} else {
if( !_bZtugOn ) {
gutil_SetDepthBiasLevel( _nTuggedDepthBiasLevel );
_bZtugOn = TRUE;
}
}
#if MESH3D_HIGHLIGHT_2SIDED
if( _bMaterial2Sided && Mesh3d_bHighlight2Sided ) {
material_ConstantColorValue( GFXDEFS_INTARGB_TO_GRCOLOR( 255, 0, 255, 0 ) );
material_ColorCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
material_AlphaCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
return;
}
#endif
if( _bMaterialTexture ) {
/* Texture mapped material:*/
tmem_Select( _pMaterialTexDef );
tmem_SetTileMode( _pMaterialTexDef, _bMaterialTileS, _bMaterialTileT );
if( !(_Ambient.fOpaqueness!=1.0f || _pMaterialTexDef->TexInfo.format!=GR_TEXFMT_ARGB_1555) ) {
/* Keep sharp alpha-cutout edges on 100% opaque ARGB1555 textures...*/
material_AlphaTestReferenceValue( (GrAlpha_t)250 );
} else {
/* Bilerp alpha-cutout edges...*/
material_AlphaTestReferenceValue( (GrAlpha_t)1 );
}
if( _pMaterialTexDef->TexInfo.format != GR_TEXFMT_ALPHA_8 ) {
material_ColorCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA,
GR_COMBINE_FACTOR_LOCAL,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE
);
} else {
material_ColorCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_NONE,
GR_COMBINE_OTHER_ITERATED,
FXFALSE
);
}
if( !_bMaterialAlphaLit ) {
/* Alpha bits indicate transparent texels (0=transparent, 1=opaque)...*/
if( _Ambient.fOpaqueness == 1.0f ) {
/* 100% opaque...*/
material_AlphaCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE
);
} else {
/* transparency...*/
material_AlphaCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_TEXTURE_ALPHA,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
material_ConstantColorValue( (GrColor_t)_Ambient.nScaledOpaqueness );
}
} else {
/* Alpha bits indicate lit texels, NOT transparent texels...*/
material_AlphaControlsITRGBLighting( FXTRUE );
material_ConstantColorValue( _nMaterialAlphaLightColor );
if( _Ambient.fOpaqueness == 1.0f ) {
/* 100% opaque...*/
material_AlphaCombine(
GR_COMBINE_FUNCTION_ZERO,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_TEXTURE,
FXTRUE
);
} else {
/* transparency...*/
material_AlphaCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
}
}
} else {
/* Non-texture mapped material:*/
ConstantColor =
((u32)(_pCurrentMaterial->ConstColor.argb[3]*_Ambient.fOpaqueness*255.0f)<<24) /* A */
+ ((u32)(_pCurrentMaterial->ConstColor.argb[2]*255.0f)<<16) /* R */
+ ((u32)(_pCurrentMaterial->ConstColor.argb[1]*255.0f)<<8) /* G */
+ (u32)(_pCurrentMaterial->ConstColor.argb[0]*255.0f); /* B */
material_ConstantColorValue( (GrColor_t)ConstantColor );
material_ColorCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA,
GR_COMBINE_FACTOR_LOCAL,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
material_AlphaCombine(
GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_ONE,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_CONSTANT,
FXFALSE
);
}
}
static void _BuildGroupLightList( Mesh3d_t *pMesh, Mesh3dGrpDef_t *pGrp ) {
MidwayLight_t *pLight;
u32 i, j, nMotif, nNumBoundPoints;
float fIntensity, fDot, fDx, fDy, fDz;
BOOL bIncludedLights;
Vec3_t ModSpacePos, ModSpaceUnitDir, *pBoundPoints;
/* Main triangle loop uses these variables...*/
_nNumGrpLights = 0;
_nNumPosGrpLights = 0;
_nNumDirGrpLights = 0;
_nNumSpotGrpLights = 0;
_nNumFlashGrpLights = 0;
if( !_nNumLights ) {
/* Exit immediately if no lights...*/
return;
}
/*----------------------------------------------------------------------------------*/
/* Count the total number of enabled positional and directional lights in list.*/
/* Initialize the MESH3D_LIGHT_FLAG_INCLUDE bit of each light's nFlags field and*/
/* compute light color values...*/
_nIncludedPositionalLights = 0;
_nIncludedDirectionalLights = 0;
bIncludedLights = FALSE;
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
pLight->nFlags &= ~LIGHT_FLAG_INCLUDE;
if( pLight->nFlags & LIGHT_FLAG_ENABLE ) {
nMotif = pLight->nMotif;
if( nMotif!=SLMOTIF_CONSTANT && Gameloop_nFrameCounter!=pLight->nColorCalcFrame ) {
/* Compute light values from motif table...*/
fIntensity = pLight->fIntensity;
if( nMotif != SLMOTIF_CONSTANT ) {
pLight->ScaledColor.rgb[2] = Light_aLightMotifTable[nMotif].Color.rgb[2] * fIntensity;
pLight->ScaledColor.rgb[1] = Light_aLightMotifTable[nMotif].Color.rgb[1] * fIntensity;
pLight->ScaledColor.rgb[0] = Light_aLightMotifTable[nMotif].Color.rgb[0] * fIntensity;
pLight->fSpecIntensity = gutil_RgbToIntensity(
pLight->ScaledColor.rgb[2],
pLight->ScaledColor.rgb[1],
pLight->ScaledColor.rgb[0]
);
}
pLight->nColorCalcFrame = Gameloop_nFrameCounter;
}
if( pLight->ScaledColor.rgb[0]>0.004f || pLight->ScaledColor.rgb[1]>0.004f || pLight->ScaledColor.rgb[2]>0.004f ) {
/* Light is not black. Add it...*/
pLight->nFlags |= LIGHT_FLAG_INCLUDE;
if( pLight->nFlags & LIGHT_FLAG_HASPOS ) {
_nIncludedPositionalLights++;
} else {
_nIncludedDirectionalLights++;
}
bIncludedLights = TRUE;
}
}
}
if( !bIncludedLights ) {
/* Exit if no included lights...*/
return;
}
/*----------------------------------------------------------------------------------*/
/* For all included positional lights, transform the world position to*/
/* camera space and intersect with mesh's bounds...*/
if( _nIncludedPositionalLights && !_bWorldMesh ) {
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( (pLight->nFlags & (LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS))==(LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS) ) {
if( pLight->nCamSpaceStackKeyPos != Xfm_nCameraKey ) {
/* Light needs to be transformed into this camera space...*/
fDx = pLight->WorldSpacePos.p[0];
fDy = pLight->WorldSpacePos.p[1];
fDz = pLight->WorldSpacePos.p[2];
for( j=0; j<3; j++ ) {
pLight->CamSpacePos.p[j] =
Xfm_aStack[0].mf[0][j] * fDx
+ Xfm_aStack[0].mf[1][j] * fDy
+ Xfm_aStack[0].mf[2][j] * fDz
+ Xfm_aStack[0].mf[3][j];
}
pLight->fCamSpaceRadius = pLight->fWorldSpaceRadius * Xfm_aStack[0].sf;
pLight->nCamSpaceStackKeyPos = Xfm_nCameraKey;
}
}
}
if( pMesh ) {
_IntersectPosLightListWithBound( pMesh, &pMesh->Bound, FALSE );
}
}
/*----------------------------------------------------------------------------------*/
/* Intersect all remaining positional lights with the group...*/
if( pMesh && _nIncludedPositionalLights && (_bWorldMesh || pMesh->nGrpCount>1) ) {
_IntersectPosLightListWithBound( pMesh, &pGrp->Bound, TRUE );
}
if( !(_nIncludedPositionalLights | _nIncludedDirectionalLights) ) {
/* Exit if no remaining lights...*/
return;
}
/*----------------------------------------------------------------------------------*/
/* Transform lights into model space...*/
if( _bWorldMesh ) {
/* This is a world mesh. Model space is the same as world space...*/
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( pLight->nFlags & LIGHT_FLAG_INCLUDE ) {
if( Xfm_nStackKey != pLight->nModSpaceStackKey ) {
if( pLight->nFlags & LIGHT_FLAG_HASPOS ) {
pLight->ModSpacePos.p[0] = pLight->WorldSpacePos.p[0];
pLight->ModSpacePos.p[1] = pLight->WorldSpacePos.p[1];
pLight->ModSpacePos.p[2] = pLight->WorldSpacePos.p[2];
pLight->fModSpaceRadius = pLight->fWorldSpaceRadius;
pLight->fModSpaceRadius2 = pLight->fModSpaceRadius * pLight->fModSpaceRadius;
pLight->fModSpaceInvRadius2 = 1.0f / pLight->fModSpaceRadius2;
}
if( pLight->nFlags & LIGHT_FLAG_HASDIR ) {
vec3_CalcUnit( &pLight->ModSpaceUnitDir, &pLight->WorldSpaceDir );
}
pLight->nModSpaceStackKey = Xfm_nStackKey;
}
}
}
} else {
/* This is not a world mesh...*/
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( pLight->nFlags & LIGHT_FLAG_INCLUDE ) {
if( Xfm_nStackKey != pLight->nModSpaceStackKey ) {
if( pLight->nFlags & LIGHT_FLAG_HASPOS ) {
fDx = pLight->CamSpacePos.p[0];
fDy = pLight->CamSpacePos.p[1];
fDz = pLight->CamSpacePos.p[2];
for( j=0; j<3; j++ ) {
pLight->ModSpacePos.p[j] =
Xfm_pStackTop->mr[0][j] * fDx
+ Xfm_pStackTop->mr[1][j] * fDy
+ Xfm_pStackTop->mr[2][j] * fDz
+ Xfm_pStackTop->mr[3][j];
}
pLight->fModSpaceRadius = pLight->fCamSpaceRadius * Xfm_pStackTop->sr;
pLight->fModSpaceRadius2 = pLight->fModSpaceRadius * pLight->fModSpaceRadius;
pLight->fModSpaceInvRadius2 = 1.0f / pLight->fModSpaceRadius2;
}
if( pLight->nFlags & LIGHT_FLAG_HASDIR ) {
if( pLight->nCamSpaceStackKeyDir != Xfm_nCameraKey ) {
/* Light direction needs to be transformed into this camera space...*/
fDx = pLight->WorldSpaceDir.p[0];
fDy = pLight->WorldSpaceDir.p[1];
fDz = pLight->WorldSpaceDir.p[2];
for( j=0; j<3; j++ ) {
pLight->CamSpaceDir.p[j] =
Xfm_aStack[0].mf[0][j] * fDx
+ Xfm_aStack[0].mf[1][j] * fDy
+ Xfm_aStack[0].mf[2][j] * fDz;
}
pLight->nCamSpaceStackKeyDir = Xfm_nCameraKey;
}
/* Transform light direction into model space...*/
fDx = pLight->CamSpaceDir.p[0];
fDy = pLight->CamSpaceDir.p[1];
fDz = pLight->CamSpaceDir.p[2];
for( j=0; j<3; j++ ) {
pLight->ModSpaceUnitDir.p[j] =
Xfm_pStackTop->mr[0][j] * fDx
+ Xfm_pStackTop->mr[1][j] * fDy
+ Xfm_pStackTop->mr[2][j] * fDz;
}
vec3_Unit( &pLight->ModSpaceUnitDir );
}
pLight->nModSpaceStackKey = Xfm_nStackKey;
}
}
}
}
/*----------------------------------------------------------------------------------*/
/* Build the main light list used by the triangle drawing loop and compute*/
/* light color values. While we're iterating though the lights, do one final*/
/* culling test for spotlights...*/
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( pLight->nFlags & LIGHT_FLAG_INCLUDE ) {
if( (pLight->nFlags & (LIGHT_FLAG_HASPOS|LIGHT_FLAG_HASDIR))==(LIGHT_FLAG_HASPOS|LIGHT_FLAG_HASDIR) ) {
/* This is a spotlight (position and direction).*/
/* Cull light if the group is completely on the*/
/* backside of the spotlight...*/
ModSpacePos.p[0] = pLight->ModSpacePos.p[0];
ModSpacePos.p[1] = pLight->ModSpacePos.p[1];
ModSpacePos.p[2] = pLight->ModSpacePos.p[2];
ModSpaceUnitDir.p[0] = pLight->ModSpaceUnitDir.p[0];
ModSpaceUnitDir.p[1] = pLight->ModSpaceUnitDir.p[1];
ModSpaceUnitDir.p[2] = pLight->ModSpaceUnitDir.p[2];
/* Bounding sphere test...*/
if( pMesh ) {
fDx = pGrp->Bound.BoundCenter.p[0] - ModSpacePos.p[0];
fDy = pGrp->Bound.BoundCenter.p[1] - ModSpacePos.p[1];
fDz = pGrp->Bound.BoundCenter.p[2] - ModSpacePos.p[2];
fDot = fDx*ModSpaceUnitDir.p[0] + fDy*ModSpaceUnitDir.p[1] + fDz*ModSpaceUnitDir.p[2];
if( fDot > pGrp->Bound.fBoundRadius ) {
/* Spotlight won't effect this group. Cull it!*/
pLight->nFlags &= ~LIGHT_FLAG_INCLUDE;
_nIncludedPositionalLights--;
continue;
}
/* Bounding volume test...*/
nNumBoundPoints = pGrp->Bound.nNumBoundPoints;
if( nNumBoundPoints ) {
pBoundPoints = pGrp->Bound.aBoundPoints;
for( j=0; j<nNumBoundPoints; j++, pBoundPoints++ ) {
fDx = pBoundPoints->p[0] - ModSpacePos.p[0];
fDy = pBoundPoints->p[1] - ModSpacePos.p[1];
fDz = pBoundPoints->p[2] - ModSpacePos.p[2];
fDot = fDx*ModSpaceUnitDir.p[0] + fDy*ModSpaceUnitDir.p[1] + fDz*ModSpaceUnitDir.p[2];
if( fDot < 0.0f ) {
/* This bound point is on lit-side of spotlite...*/
break;
}
}
if( j == nNumBoundPoints ) {
/* All bound points are on unlit-side of spotlite...*/
pLight->nFlags &= ~LIGHT_FLAG_INCLUDE;
_nIncludedPositionalLights--;
continue;
}
}
}
}
/* Expand flags...*/
pLight->bNoIncidenceAtten = pLight->nFlags & LIGHT_FLAG_NO_INCIDENCE;
/* Add light to appropriate light list...*/
switch( pLight->nType ) {
case LIGHT_TYPE_OMNI:
_apPosGrpLight[_nNumPosGrpLights++] = pLight;
break;
case LIGHT_TYPE_DIR:
_apDirGrpLight[_nNumDirGrpLights++] = pLight;
break;
case LIGHT_TYPE_SPOT:
_apSpotGrpLight[_nNumSpotGrpLights++] = pLight;
break;
case LIGHT_TYPE_FLASH:
_apFlashGrpLight[_nNumFlashGrpLights++] = pLight;
break;
default:
XASSERT_NOW; /* Invalid light type*/
}
_nNumGrpLights++;
}
}
}
/* Don't call this if _nIncludedPositionalLights is 0 (for performance reasons).*/
static void _IntersectPosLightListWithBound( Mesh3d_t *pMesh, Mesh3dBound_t *pBound, BOOL bTestingGroupBound ) {
MidwayLight_t *pLight;
float fBoundRadius, fDeltaRadius, fDeltaRadius2, fDistance2;
float fCx, fCy, fCz, fDx, fDy, fDz;
Vec3_t BoundCenter;
u32 i;
fCx = pBound->BoundCenter.p[0];
fCy = pBound->BoundCenter.p[1];
fCz = pBound->BoundCenter.p[2];
if( _bWorldMesh ) {
/* This is a world mesh. Model space is the same as world space...*/
fBoundRadius = pBound->fBoundRadius;
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( (pLight->nFlags & (LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS))==(LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS) ) {
if( bTestingGroupBound || pLight->pIntersectMesh!=pMesh || pLight->nIntersectStackKey!=Xfm_nStackKey ) {
fDeltaRadius = pLight->fWorldSpaceRadius + fBoundRadius;
fDx = pLight->WorldSpacePos.p[0] - fCx;
fDy = pLight->WorldSpacePos.p[1] - fCy;
fDz = pLight->WorldSpacePos.p[2] - fCz;
fDeltaRadius2 = fDeltaRadius * fDeltaRadius;
fDistance2 = fDx*fDx + fDy*fDy + fDz*fDz;
if( fDistance2 > fDeltaRadius2 ) {
/* Light does not intersect this mesh. Unflag it...*/
pLight->nFlags &= ~LIGHT_FLAG_INCLUDE;
_nIncludedPositionalLights--;
}
pLight->pIntersectMesh = pMesh;
pLight->nIntersectStackKey = Xfm_nStackKey;
}
}
}
} else {
/* This is not a world mesh...*/
fBoundRadius = pBound->fBoundRadius * Xfm_pStackTop->sf;
/* Transform bound to camera space...*/
for( i=0; i<3; i++ ) {
BoundCenter.p[i] =
Xfm_pStackTop->mf[0][i] * fCx
+ Xfm_pStackTop->mf[1][i] * fCy
+ Xfm_pStackTop->mf[2][i] * fCz
+ Xfm_pStackTop->mf[3][i];
}
for( i=0; i<_nNumLights; i++ ) {
pLight = _ppLightList[i];
if( (pLight->nFlags & (LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS))==(LIGHT_FLAG_INCLUDE|LIGHT_FLAG_HASPOS) ) {
if( bTestingGroupBound || pLight->pIntersectMesh!=pMesh || pLight->nIntersectStackKey!=Xfm_nStackKey ) {
fDeltaRadius = pLight->fCamSpaceRadius + fBoundRadius;
fDx = pLight->CamSpacePos.p[0] - BoundCenter.p[0];
fDy = pLight->CamSpacePos.p[1] - BoundCenter.p[1];
fDz = pLight->CamSpacePos.p[2] - BoundCenter.p[2];
fDeltaRadius2 = fDeltaRadius * fDeltaRadius;
fDistance2 = fDx*fDx + fDy*fDy + fDz*fDz;
if( fDistance2 > fDeltaRadius2 ) {
/* Light does not intersect this mesh. Unflag it...*/
pLight->nFlags &= ~LIGHT_FLAG_INCLUDE;
_nIncludedPositionalLights--;
}
pLight->pIntersectMesh = pMesh;
pLight->nIntersectStackKey = Xfm_nStackKey;
}
}
}
}
}
static void _ComputeReflectParameters( void ) {
u32 k;
Vec3_t PointOnReflectSurface_Worldspace;
PointOnReflectSurface_Worldspace.p[0] = Xfm_pStackCam->pos.p[0];
PointOnReflectSurface_Worldspace.p[1] = _fReflectSurfaceHeight_WorldSpace;
PointOnReflectSurface_Worldspace.p[2] = Xfm_pStackCam->pos.p[2];
for( k=0; k<3; k++ ) {
_PointOnReflectSurface_Camspace.p[k] =
Xfm_pStackCam->xfm.mf[0][k] * PointOnReflectSurface_Worldspace.p[0]
+ Xfm_pStackCam->xfm.mf[1][k] * PointOnReflectSurface_Worldspace.p[1]
+ Xfm_pStackCam->xfm.mf[2][k] * PointOnReflectSurface_Worldspace.p[2]
+ Xfm_pStackCam->xfm.mf[3][k];
}
_ReflectSurfaceUnitNorm_Camspace.p[0] = Xfm_pStackCam->xfm.mf[1][0];
_ReflectSurfaceUnitNorm_Camspace.p[1] = Xfm_pStackCam->xfm.mf[1][1];
_ReflectSurfaceUnitNorm_Camspace.p[2] = Xfm_pStackCam->xfm.mf[1][2];
_fNegDistAboveReflectSurface_Camspace
= _PointOnReflectSurface_Camspace.p[0]*_ReflectSurfaceUnitNorm_Camspace.p[0]
+ _PointOnReflectSurface_Camspace.p[1]*_ReflectSurfaceUnitNorm_Camspace.p[1]
+ _PointOnReflectSurface_Camspace.p[2]*_ReflectSurfaceUnitNorm_Camspace.p[2];
_fReflectSurfaceAnimateCounter = Gameloop_fFrameCounter * 4096.0f;
}
static void _WabbleScreenPoint( float *pfScreenX, float *pfScreenY, float fCamspaceX, float fCamspaceY, float fCamspaceZ ) {
float fDistBelow, fRatio, fIntersectX, fIntersectZ, fAmp, fIntersectDist2;
float fWorldspaceIntersectX, fWorldspaceIntersectZ;
int nAngle;
if( _fNegDistAboveReflectSurface_Camspace > 0.0f ) {
return;
}
fDistBelow = (_PointOnReflectSurface_Camspace.p[0]-fCamspaceX)*_ReflectSurfaceUnitNorm_Camspace.p[0]
+ (_PointOnReflectSurface_Camspace.p[1]-fCamspaceY)*_ReflectSurfaceUnitNorm_Camspace.p[1]
+ (_PointOnReflectSurface_Camspace.p[2]-fCamspaceZ)*_ReflectSurfaceUnitNorm_Camspace.p[2];
if( fDistBelow < 1.0f ) {
return;
}
fRatio = _fNegDistAboveReflectSurface_Camspace / (_fNegDistAboveReflectSurface_Camspace - fDistBelow);
fIntersectX = fCamspaceX * fRatio;
fIntersectZ = fCamspaceZ * fRatio;
fIntersectDist2 = fIntersectX*fIntersectX + fIntersectZ*fIntersectZ;
if( fIntersectDist2 == 0.0f ) {
return;
}
fAmp = 300000.0f / (fIntersectDist2*10.0f + 50000.0f);
if( fAmp > 6.0f ) {
fAmp = 6.0f;
}
fWorldspaceIntersectX = Xfm_pStackCam->xfm.mr[0][0] * fCamspaceX
+ Xfm_pStackCam->xfm.mr[1][0] * fCamspaceY
+ Xfm_pStackCam->xfm.mr[2][0] * fCamspaceZ
+ Xfm_pStackCam->xfm.mr[3][0];
fWorldspaceIntersectZ = Xfm_pStackCam->xfm.mr[0][2] * fCamspaceX
+ Xfm_pStackCam->xfm.mr[1][2] * fCamspaceY
+ Xfm_pStackCam->xfm.mr[2][2] * fCamspaceZ
+ Xfm_pStackCam->xfm.mr[3][2];
nAngle = (int)( fWorldspaceIntersectX*133.0f + fWorldspaceIntersectZ*150.0f + _fReflectSurfaceAnimateCounter);
*pfScreenX += fAmp * xmath_sin( nAngle );
*pfScreenY += fAmp * xmath_cos( nAngle );
}
/************************************/
/* DREAMCAST MESH DRAWING FUNCTIONS */
/************************************/
/* Wabble look-up-table, simple sin wave to add to 3D vertex X/Z */
float WabbleTable[32] = {
-15,-15,-14,-13,-11,-9,-6,-3,
0,3,6,9,11,13,15,16,
16,16,15,13,11,9,6,3,
0,-3,-6,-9,-11,-13,-14,-15
};
static KMVERTEX3 Tri[3]={
KM_VERTEXPARAM_NORMAL, 0, 0, 0, 0, 0, 0, 0,
KM_VERTEXPARAM_NORMAL, 0, 0, 0, 0, 0, 0, 0,
KM_VERTEXPARAM_ENDOFSTRIP, 0, 0, 0, 0, 0, 0, 0
};
typedef struct{
float Cam[4];
float Screen[4];
}dcVertex_t;
/**********************************************************************************/
extern Mesh3dVtxCache_t _dcVertexBuffer[8192];
static void _ComputeVtxLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn ) {
register int nMotif, i;
register float fMotifIntensity;
u32 r, g, b;
_Vtx[0] = pVn->UnitNorm.p[0];
_Vtx[1] = pVn->UnitNorm.p[1];
_Vtx[2] = pVn->UnitNorm.p[2];
/* Start with ambient light... */
_fRGBA[0] = _Ambient.ScaledColor.rgb[2];
_fRGBA[1] = _Ambient.ScaledColor.rgb[1];
_fRGBA[2] = _Ambient.ScaledColor.rgb[0];
/* Compute static lighting... */
/* Slot 0... */
nMotif = pGrp->anMotif[0];
if( nMotif == SLMOTIF_CONSTANT ) {
_fRGBA[0] += pGrp->aMotifConstColor[0].rgb[2] * pVl->afMotifIntensity[0];
_fRGBA[1] += pGrp->aMotifConstColor[0].rgb[1] * pVl->afMotifIntensity[0];
_fRGBA[2] += pGrp->aMotifConstColor[0].rgb[0] * pVl->afMotifIntensity[0];
} else if( nMotif != SLMOTIF_NONE ) {
_fRGBA[0] += Light_aLightMotifTable[nMotif].Color.rgb[2] * pVl->afMotifIntensity[0];
_fRGBA[1] += Light_aLightMotifTable[nMotif].Color.rgb[1] * pVl->afMotifIntensity[0];
_fRGBA[2] += Light_aLightMotifTable[nMotif].Color.rgb[0] * pVl->afMotifIntensity[0];
}
/* Slot 1... */
nMotif = pGrp->anMotif[1];
if( nMotif == SLMOTIF_CONSTANT ) {
_fRGBA[0] += pGrp->aMotifConstColor[1].rgb[2] * pVl->afMotifIntensity[1];
_fRGBA[1] += pGrp->aMotifConstColor[1].rgb[1] * pVl->afMotifIntensity[1];
_fRGBA[2] += pGrp->aMotifConstColor[1].rgb[0] * pVl->afMotifIntensity[1];
} else if( nMotif != SLMOTIF_NONE ) {
_fRGBA[0] += Light_aLightMotifTable[nMotif].Color.rgb[2] * pVl->afMotifIntensity[1];
_fRGBA[1] += Light_aLightMotifTable[nMotif].Color.rgb[1] * pVl->afMotifIntensity[1];
_fRGBA[2] += Light_aLightMotifTable[nMotif].Color.rgb[0] * pVl->afMotifIntensity[1];
}
/* Slot 2... */
nMotif = pGrp->anMotif[2];
if( nMotif == SLMOTIF_CONSTANT ) {
_fRGBA[0] += pGrp->aMotifConstColor[2].rgb[2] * pVl->afMotifIntensity[2];
_fRGBA[1] += pGrp->aMotifConstColor[2].rgb[1] * pVl->afMotifIntensity[2];
_fRGBA[2] += pGrp->aMotifConstColor[2].rgb[0] * pVl->afMotifIntensity[2];
} else if( nMotif != SLMOTIF_NONE ) {
_fRGBA[0] += Light_aLightMotifTable[nMotif].Color.rgb[2] * pVl->afMotifIntensity[2];
_fRGBA[1] += Light_aLightMotifTable[nMotif].Color.rgb[1] * pVl->afMotifIntensity[2];
_fRGBA[2] += Light_aLightMotifTable[nMotif].Color.rgb[0] * pVl->afMotifIntensity[2];
}
/* Slot 3... */
nMotif = pGrp->anMotif[3];
if( nMotif == SLMOTIF_CONSTANT ) {
_fRGBA[0] += pGrp->aMotifConstColor[3].rgb[2] * pVl->afMotifIntensity[3];
_fRGBA[1] += pGrp->aMotifConstColor[3].rgb[1] * pVl->afMotifIntensity[3];
_fRGBA[2] += pGrp->aMotifConstColor[3].rgb[0] * pVl->afMotifIntensity[3];
} else if( nMotif != SLMOTIF_NONE ) {
_fRGBA[0] += Light_aLightMotifTable[nMotif].Color.rgb[2] * pVl->afMotifIntensity[3];
_fRGBA[1] += Light_aLightMotifTable[nMotif].Color.rgb[1] * pVl->afMotifIntensity[3];
_fRGBA[2] += Light_aLightMotifTable[nMotif].Color.rgb[0] * pVl->afMotifIntensity[3];
}
/* Multiply by vertex light... */
// if(pVtx->fVtxIntensity != 1.0f) {
// fMotifIntensity = pVtx->fVtxIntensity;
// _fRGBA[0] *= fMotifIntensity;
// _fRGBA[1] *= fMotifIntensity;
// _fRGBA[2] *= fMotifIntensity;
// }
// Add in dynamic lighting...
if(_nNumGrpLights && !_bMaterialNoDynLight) {
_Vtx[3] = pVtx->Point.p[0];
_Vtx[4] = pVtx->Point.p[1];
_Vtx[5] = pVtx->Point.p[2];
if( _nNumPosGrpLights ) {
_ComputeOmniLight();
}
if( _nNumDirGrpLights ) {
_ComputeDirLight();
// dcComputeDirLight(_apDirGrpLight, _nNumDirGrpLights, _Vtx, _fRGBA );
}
if( _nNumSpotGrpLights ) {
// dcStartTiming();
// dcComputeSpotLight(_apSpotGrpLight, _nNumSpotGrpLights, _Vtx, _fRGBA );
_ComputeSpotLight();
// dcEndTiming();
}
// if( _nNumFlashGrpLights ) {
// _ComputeFlashLight();
// }
}
r = (u32)((_fRGBA[0]>1.0f) ? 255.0f : _fRGBA[0]*255.0f);
g = (u32)((_fRGBA[1]>1.0f) ? 255.0f : _fRGBA[1]*255.0f);
b = (u32)((_fRGBA[2]>1.0f) ? 255.0f : _fRGBA[2]*255.0f);
*pArgb = ((r << 16) | (g << 8) | b) | 0xff000000;
}
static void _ComputeFlashLight(u32 *pSpecular, float *pVtx) {
register float fDot,SpecInten;
register MidwayLight_t *pLight;
register u32 i,n;
SpecInten = 0;
for( i=0; i<_nNumFlashGrpLights; i++ ) {
pLight = _apFlashGrpLight[i];
fDot = pVtx[0]*pLight->ModSpaceUnitDir.p[0]
+ pVtx[1]*pLight->ModSpaceUnitDir.p[1]
+ pVtx[2]*pLight->ModSpaceUnitDir.p[2];
if( fDot <= 0 ) continue;
if( !(pLight->bNoIncidenceAtten|_bMaterialNoIncidenceAtten) ) {
SpecInten += pLight->ScaledColor.rgb[0] * fDot;
} else {
SpecInten += pLight->ScaledColor.rgb[0];
}
}
SpecInten = SpecInten > 1.0f ? 1.0f : SpecInten;
n = (u32)(SpecInten * 128.0f);
*pSpecular = dcRGB(n, n, n);
}
/* Transform vertices to screen space */
#if _ASM_TRANSFORM_ENABLED
static void _Transform(Mesh3dVtxDef_t *pVtx, int NumVerts)
{
float v[4];
int Diff,WabbleFactor;
register Mesh3dVtxCache_t *pVtxCache;
register float q,ooz,yt;
yt = dcViewportYTrans;
pVtxCache = _dcVertexBuffer;
v[3] = 1.0f;
for(; NumVerts; --NumVerts){
v[0] = pVtx->Point.p[0];
v[1] = pVtx->Point.p[1];
v[2] = pVtx->Point.p[2];
if( _bReflectSurface )
{
Diff = v[1]-_fReflectSurfaceHeight_WorldSpace;
if (Diff>10) {
/* Find wabble factor */
WabbleFactor = WabbleTable[((int)v[0]+Gameloop_nFrameCounter)&31];
/* If near to surface lessen wabble */
if (Diff<100)
WabbleFactor >>= 2;
/* Wabble that vertex */
v[0] += WabbleFactor;
v[2] += WabbleFactor;
}
}
ftrv(v, pVtxCache->CamspaceVtx);
if(pVtxCache->CamspaceVtx[2] > 0){
ooz = 1.0f / pVtxCache->CamspaceVtx[2];
pVtxCache->ScreenspaceVtx.u.fZ = ooz;
q = Viewport_zscreen * ooz;
pVtxCache->ScreenspaceVtx.fX = 320.0f + q * pVtxCache->CamspaceVtx[0];
pVtxCache->ScreenspaceVtx.fY = dcViewportYTrans - q * pVtxCache->CamspaceVtx[1];
}
pVtxCache++;
pVtx++;
}
}
#endif // ASM_TRANSFORM
int mesh3d_DrawGroup_NoFrustumTest( Mesh3d_t *pMesh, Mesh3dGrpDef_t *pGrp, int nCrossesPlanesMask, BOOL bLightAlphaTexels )
{
int i, n;
int nTlCount, nTriCount;
BOOL bMaterialTexture, bMaterialAlphaLit, bMaterial2Sided, bMaterialNoDiffuse;
BOOL bMaterialNoDynLight, bNoDynamicLighting, bMotifLightingOnly;
float Mtx[4][4];
float a, r, g, b,x,y,z,d;
Mesh3dVtxDef_t *pVtxList, *pVtx;
Mesh3dTcDef_t *pTcList;
Mesh3dVnDef_t *pVnList, *pVn;
Mesh3dVlDef_t *pVlList;
Mesh3dTlDef_t *pCurrentTl;
Vec3_t *pVec;
TexDef_t *pMaterialTexDef;
Mesh3dVtxCache_t *apVtxCache[3], aTriVtx[4];
Mesh3dMtlDef_t* pCurrentMaterial;
Mesh3dVtxCache_t *pVtxCache;
Mesh3dVtxDef_t *pCurrentVtx;
Mesh3dTriVtx_t *pTriVtx;
Mesh3dTriDef_t *pCurrentTri;
u32 ConstColor,NumMotifs;
_bWorldMesh = pMesh->nFlags & MESH3D_FLAG_WORLD;
// Update cache key
if( !_bCacheEnable ) {
Mesh3d_nLastFrameCounter = Gameloop_nFrameCounter - 1;
}
if( Mesh3d_nLastFrameCounter != Gameloop_nFrameCounter ) {
/* The frame counter has changed. We must reset our */
/* caches and update the cache key. */
Mesh3d_nLastFrameCounter = Gameloop_nFrameCounter;
Mesh3d_nNextAvailVlCacheIndex = 0;
Mesh3d_nCacheKey++;
}
pVtxList = pMesh->pVtx;
pTcList = pMesh->pTc;
pVnList = pMesh->pVn;
pVlList = pMesh->pVl;
// Get num motifs that are not constant
NumMotifs = 0;
for(i = 0; i < 4; i++){
if(pGrp->anMotif[i] > SLMOTIF_CONSTANT)
NumMotifs++;
}
// Get light list for this group
_BuildGroupLightList( pMesh, pGrp );
// Lighting flags
bNoDynamicLighting = _bWorldMesh && !NumMotifs && !_nNumSpotGrpLights && !_nNumFlashGrpLights;
bMotifLightingOnly = _bWorldMesh && !_nNumSpotGrpLights;
#if !_DYNAMIC_LIGHTING_ENABLED
bNoDynamicLighting = TRUE;
#endif
// if( _bReflectSurface ) {
// _ComputeReflectParameters();
// }
// Load matrix for sh4
{
register float *p,*p1;
p = &Xfm_pStackTop->mf[0][0];
p1 = &Mtx[0][0];
*p1++ = *p++;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = 0;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = 0;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = 0;
*p1++ = *p++;
*p1++ = *p++;
*p1++ = *p;
*p1++ = 0;
}
ld_ext(Mtx);
DCASSERT(pGrp->NumVerts < 8192, "");
// Transform all points to screen space
#if !_ASM_TRANSFORM_ENABLED
// dcStartTiming();
_Transform(&pVtxList[pGrp->FirstVtx], pGrp->NumVerts);
// dcEndTiming();
#else
#if _INLINE_ASM_ENABLED
// dcStartTiming();
_dcTransformVertices(&pVtxList[pGrp->FirstVtx], pGrp->NumVerts, _dcVertexBuffer, nCrossesPlanesMask);
// dcEndTiming();
#else
if(!nCrossesPlanesMask){
dcTransformVerticesA(&pVtxList[pGrp->FirstVtx], pGrp->NumVerts, _dcVertexBuffer);
}
else{
dcTransformVertices(&pVtxList[pGrp->FirstVtx], pGrp->NumVerts, _dcVertexBuffer);
}
#endif
#endif
// Start iterating through the group hierarchy, drawing triangles...
nTlCount = pGrp->nTlCount;
pCurrentTl = pGrp->pTl;
for(;nTlCount; --nTlCount, pCurrentTl++ )
{
// Each triangle list:
pCurrentMaterial = pCurrentTl->pMtl;
if( ((_nMaterialFilter & MESH3D_MTL_FILTER_OUT_MAIN) && !(pCurrentMaterial->nFlags & MESH3D_MTLFLAG_COLLISION))
|| ((_nMaterialFilter & MESH3D_MTL_FILTER_OUT_COLLIDE) && (pCurrentMaterial->nFlags & MESH3D_MTLFLAG_COLLISION)) )
continue;
// Cache material properties...
n = pCurrentMaterial->nFlags;
pMaterialTexDef = pCurrentMaterial->pTexDef;
bMaterialTexture = n & MESH3D_MTLFLAG_TEXTURE;
bMaterial2Sided = n & MESH3D_MTLFLAG_2SIDED;
bMaterialAlphaLit = n & MESH3D_MTLFLAG_ALPHA_LIT;
bMaterialNoDiffuse = n & MESH3D_MTLFLAG_IGNORE_DIFFUSE;
bMaterialNoDynLight = n & MESH3D_MTLFLAG_IGNORE_DYNLIGHT;
_bMaterialNoIncidenceAtten = n & MESH3D_MTLFLAG_NO_INCIDENCE_ATTEN;
if(bMaterialTexture){
i = pMaterialTexDef->aTMUTexInfo[0].nTmemStartAddress;
if(i != -1){
// Semi trans poly
if((dcTextureTable[i].Type & 0xff) == KM_TEXTURE_ARGB4444){
kmSetVertexRenderState(&dcTextureTable[i].AlphaBlendedTexVC);
}
// Punch through poly for 1555 texture
else if( _Ambient.fOpaqueness==1.0f && !bMaterialAlphaLit &&
(dcTextureTable[i].Type & 0xff) == KM_TEXTURE_ARGB1555)
kmSetVertexRenderState(&dcTextureTable[i].PunchThroughTexVC);
else
kmSetVertexRenderState(&dcTextureTable[i].OpaqueTexVC);
}
}
else
kmSetVertexRenderState(&NonTexturedVC);
a = _Ambient.nScaledOpaqueness;
r = pCurrentMaterial->ConstColor.argb[2] * 255.0f;
g = pCurrentMaterial->ConstColor.argb[1] * 255.0f;
b = pCurrentMaterial->ConstColor.argb[0] * 255.0f;
ConstColor = dcRGBA((s32)r, (s32)g, (s32)b, (s32)a);
kmxxGetCurrentPtr(&VertexBufferDesc);
kmxxStartVertexStrip(&VertexBufferDesc);
kmxxReleaseCurrentPtr(&VertexBufferDesc);
// Each tri:
nTriCount = pCurrentTl->nTriCount;
pCurrentTri = pCurrentTl->pTri;
for(; nTriCount; --nTriCount, pCurrentTri++) {
pTriVtx = pCurrentTri->TriVtx;
// Perform backface culling
if(!bMaterial2Sided) {
if(dcCullTest(&Xfm_pStackTop->mr[3][0], pVtxList[pTriVtx[0].nVtxIndex].Point.p, pCurrentTri->FaceUnitNorm.p ) < 0.0f)
continue;
}
// TODO precalc index in converter
{
register nFirstVtx, nVtxIndex;
register Mesh3dVtxCache_t *pVtx,*pVertexBuff,**apTri;
nFirstVtx = pGrp->FirstVtx;
pVertexBuff = _dcVertexBuffer;
apTri = apVtxCache;
for(i = 0; i < 3; i++){
nVtxIndex = pTriVtx[i].nVtxIndex - nFirstVtx;
pVtx = pVertexBuff + nVtxIndex;
pVtx->ScreenspaceVtx.uOffsetRGB.dwPacked = _dwWhiteSat;
*apTri++ = pVtx;
}
}
// Outside screen ?
if(nCrossesPlanesMask){
register Mesh3dVtxCache_t *p1,*p2,*p3;
p1 = apVtxCache[0];
p2 = apVtxCache[1];
p3 = apVtxCache[2];
if( p1->CamspaceVtx[2] < 0 && p2->CamspaceVtx[2] < 0 && p3->CamspaceVtx[2] < 0 )
continue;
if( p1->ScreenspaceVtx.fX < 0 && p2->ScreenspaceVtx.fX < 0 && p3->ScreenspaceVtx.fX < 0 )
continue;
if( p1->ScreenspaceVtx.fX > 640.0f && p2->ScreenspaceVtx.fX > 640.0f && p3->ScreenspaceVtx.fX > 640.0f )
continue;
}
// Compute lighting
if( !bMaterialNoDiffuse) {
register KMVERTEX3 *pVtx;
register Mesh3dVlDef_t *pCurrentVl;
register int i;
if(!bNoDynamicLighting){
for(i = 2; i >= 0; --i){
pVtx = &apVtxCache[i]->ScreenspaceVtx;
pCurrentVl = &pVlList[ pTriVtx[i].nVlIndex ];
// Cached - get colour and specular
#if _LIGHTING_CACHE_ENABLED
if( pCurrentVl->nVlCacheKey == Mesh3d_nCacheKey ) {
pVtx->uBaseRGB.dwPacked = Mesh3d_pVlCache[ pCurrentVl->nVlCacheIndex ].Argb;
pVtx->uOffsetRGB.dwPacked = Mesh3d_pVlCache[ pCurrentVl->nVlCacheIndex ].Spec;
}
// Not cached
else{
#endif // _LIGHTING_CACHE_ENABLED
// If it's a background tri and no spots lights do motifs only
if(bMotifLightingOnly)
dcComputeMotifLighting( pGrp, &pVtx->uBaseRGB.dwPacked, &pVtxList[pTriVtx[i].nVtxIndex], pCurrentVl);
// Do motifs and dynamic lighting
else{
#if _ASM_LIGHTING_ENABLED
dcComputeVtxLighting( pGrp, &pVtx->uBaseRGB.dwPacked, &pVtxList[pTriVtx[i].nVtxIndex], pCurrentVl, &pVnList[ pCurrentVl->nVnIndex ] );
#else //_ASM_LIGHTING_ENABLED
_ComputeVtxLighting( pGrp, &pVtx->uBaseRGB.dwPacked, &pVtxList[pTriVtx[i].nVtxIndex], pCurrentVl, &pVnList[ pCurrentVl->nVnIndex ] );
#endif // _ASM_LIGHTING_ENABLED
}
// Do jazzy specular stuff
if(_nNumFlashGrpLights && _nNumGrpLights){
_ComputeFlashLight(&pVtx->uOffsetRGB.dwPacked, &pVtxList[pTriVtx[i].nVtxIndex]);
}
// Add newly calculated color to vertex lighting cache...
#if _LIGHTING_CACHE_ENABLED
pCurrentVl->nVlCacheIndex = Mesh3d_nNextAvailVlCacheIndex;
Mesh3d_pVlCache[Mesh3d_nNextAvailVlCacheIndex].Argb = pVtx->uBaseRGB.dwPacked;
Mesh3d_pVlCache[Mesh3d_nNextAvailVlCacheIndex].Spec = pVtx->uOffsetRGB.dwPacked;
pCurrentVl->nVlCacheKey = Mesh3d_nCacheKey;
Mesh3d_nNextAvailVlCacheIndex++;
}
#endif // _LIGHTING_CACHE_ENABLED
}
}
}
// No lighting
else{
register KMVERTEX3 *pVtx;
for(i = 2; i >= 0; --i){
pVtx = &apVtxCache[i]->ScreenspaceVtx;
pVtx->uBaseRGB.dwPacked = ConstColor;
}
}
// Z Clip
if(nCrossesPlanesMask){
if( apVtxCache[0]->CamspaceVtx[2] < 0.0f || apVtxCache[1]->CamspaceVtx[2] < 0.0f
|| apVtxCache[2]->CamspaceVtx[2] < 0.0f ){
for(i = 0; i < 3; i++){
if(bMaterialTexture){
apVtxCache[i]->CamspaceVtx[3] = pTcList[pTriVtx[i].nTcIndex].s;
apVtxCache[i]->CamspaceVtx[4] = pTcList[pTriVtx[i].nTcIndex].t;
}
apVtxCache[i]->CamspaceVtx[5] = (float)((apVtxCache[i]->ScreenspaceVtx.uBaseRGB.dwPacked >> 16) & 0xff);
apVtxCache[i]->CamspaceVtx[6] = (float)((apVtxCache[i]->ScreenspaceVtx.uBaseRGB.dwPacked >> 8) & 0xff);
apVtxCache[i]->CamspaceVtx[7] = (float)((apVtxCache[i]->ScreenspaceVtx.uBaseRGB.dwPacked ) & 0xff);
apVtxCache[i]->CamspaceVtx[8] = (float)(apVtxCache[i]->ScreenspaceVtx.uOffsetRGB.dwPacked & 0xff);
}
_ClipTriToFrustumAndDraw( apVtxCache, 0xf );
continue;
}
}
{
register float x,y,ooz,s,t,*pf;
register int rgba,spec,j;
kmxxGetCurrentPtr(&VertexBufferDesc);
for( j = 2; j >= 0; --j){
pf = &apVtxCache[j]->ScreenspaceVtx.fX;
x = *pf++;
y = *pf++;
ooz = *pf++;
pf += 2;
rgba = *(u32*)pf++;
spec = *pf;
pf = &pTcList[pTriVtx[j].nTcIndex].s;
s = *pf++;
t = *pf;
kmxxSetVertex_3(j ? KM_VERTEXPARAM_NORMAL : KM_VERTEXPARAM_ENDOFSTRIP, x, y, ooz, s, t, rgba, spec);
}
kmxxReleaseCurrentPtr(&VertexBufferDesc);
}
}
}
// material_PopState(1);
return 0;
}
static void _ClipTriToFrustumAndDraw( Mesh3dVtxCache_t **ppVtxCache, int nTriCrossesPlanesMask )
{
int i, j, k, num_in, start_out, tris, grvp_in_index, grvp_out_index;
float prevd, thisd, scale, x, y, w, q, ooz;
u32 nWalkingBit,n,a;
Mesh3dVtxCache_t *pin, *prev_pin, *bufp;
for( i=0; i<3; i++ )
{
grvp[i] = ppVtxCache[i];
}
a = _Ambient.nScaledOpaqueness;
bufp = clippedvtx;
grvp_in_index = 0;
grvp_out_index = 3;
num_in = 3;
for( j=0, nWalkingBit=1; j<4; j++, nWalkingBit<<=1 )
{
if( nTriCrossesPlanesMask & nWalkingBit )
{
start_out = grvp_out_index;
pin = grvp[grvp_in_index+num_in-1];
prevd = pin->CamspaceVtx[0]*Viewport_rect_norm[j].p[0]
+ pin->CamspaceVtx[1]*Viewport_rect_norm[j].p[1]
+ pin->CamspaceVtx[2]*Viewport_rect_norm[j].p[2]
- GUTIL_CLIPPING_AVOID_DIVZERO_MARGIN;
for( i=0; i<num_in; i++ )
{
prev_pin = pin;
if( prevd>0.0f ) grvp[grvp_out_index++] = pin;
pin = grvp[grvp_in_index++];
thisd = pin->CamspaceVtx[0]*Viewport_rect_norm[j].p[0]
+ pin->CamspaceVtx[1]*Viewport_rect_norm[j].p[1]
+ pin->CamspaceVtx[2]*Viewport_rect_norm[j].p[2]
- GUTIL_CLIPPING_AVOID_DIVZERO_MARGIN;
if( (prevd>0.0f) != (thisd>0.0f) ) {
/* vertices are on opposite sides of nearplane */
scale = prevd / (prevd-thisd);
for( k=0; k<9; k++ ) {
bufp->CamspaceVtx[k] = prev_pin->CamspaceVtx[k]
+ (pin->CamspaceVtx[k] - prev_pin->CamspaceVtx[k] )*scale;
}
grvp[ grvp_out_index++ ] = bufp++;
}
prevd = thisd;
}
num_in = grvp_out_index - start_out;
if( num_in==0 ) {
return;
}
}
}
for( i=0, j=grvp_in_index; i<num_in; i++, j++ )
{
pin = grvp[j];
ooz = 1.0f / pin->CamspaceVtx[2];
q = Viewport_zscreen * ooz;
x = 320.0f + q * pin->CamspaceVtx[0];
y = dcViewportYTrans - q * pin->CamspaceVtx[1];
pin->ScreenspaceVtx.u.fZ = ooz;
pin->ScreenspaceVtx.fX = x;
pin->ScreenspaceVtx.fY = y;
pin->ScreenspaceVtx.fU = pin->CamspaceVtx[3];
pin->ScreenspaceVtx.fV = pin->CamspaceVtx[4];
pin->ScreenspaceVtx.uBaseRGB.dwPacked = dcRGBA( (unsigned int)pin->CamspaceVtx[5],
(unsigned int)pin->CamspaceVtx[6],
(unsigned int)pin->CamspaceVtx[7],
0xff
);
n = pin->CamspaceVtx[8];
pin->ScreenspaceVtx.uOffsetRGB.dwPacked = dcRGB(n, n, n);
}
tris = num_in - 2;
kmxxGetCurrentPtr(&VertexBufferDesc);
kmxxStartVertexStrip(&VertexBufferDesc);
for( i=0; i<tris; i++ )
{
{
register float x,y,ooz,s,t,*pf;
register int argb,spec;
pf = &grvp[grvp_in_index]->ScreenspaceVtx.fX;
x = *pf++;
y = *pf++;
ooz = *pf++;
s = *pf++;
t = *pf++;
argb = *(u32*)pf++;
spec = *(u32*)pf++;
kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL, x, y, ooz, s, t, argb, spec);
pf = &grvp[grvp_in_index+i+1]->ScreenspaceVtx.fX;
x = *pf++;
y = *pf++;
ooz = *pf++;
s = *pf++;
t = *pf++;
argb = *(u32*)pf++;
spec = *(u32*)pf++;
kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL, x, y, ooz, s, t, argb, spec);
pf = &grvp[grvp_in_index+i+2]->ScreenspaceVtx.fX;
x = *pf++;
y = *pf++;
ooz = *pf++;
s = *pf++;
t = *pf++;
argb = *(u32*)pf++;
spec = *(u32*)pf++;
kmxxSetVertex_3(KM_VERTEXPARAM_ENDOFSTRIP, x, y, ooz, s, t, argb, spec);
// dcEndTiming();
}
}
kmxxReleaseCurrentPtr(&VertexBufferDesc);
}
int mesh3d_DrawGroup( Mesh3d_t *pMesh, Mesh3dGrpDef_t *pGrp, int nCrossesPlanesMask, BOOL bLightAlphaTexels )
{
nCrossesPlanesMask = mesh3d_TestBoundWithFrustum( &pGrp->Bound, nCrossesPlanesMask);
if(nCrossesPlanesMask < 0)
return -1;
mesh3d_DrawGroup_NoFrustumTest( pMesh, pGrp, nCrossesPlanesMask, bLightAlphaTexels );
return 0;
}
int mesh3d_Draw( Mesh3d_t *pMesh, int nCrossesPlanesMask, BOOL bLightAlphaTexels ) {
register int i, nGroupCrossesPlanesMask;
register u32 nGroupCount;
register Mesh3dGrpDef_t *pCurrentGroup;
nCrossesPlanesMask = mesh3d_TestBoundWithFrustum( &pMesh->Bound, nCrossesPlanesMask );
if(nCrossesPlanesMask < 0)
return -1;
nGroupCount = pMesh->nGrpCount;
pCurrentGroup = pMesh->pGrp;
for( i=0; (u32)i<nGroupCount; i++, pCurrentGroup++ ) {
mesh3d_DrawGroup_NoFrustumTest( pMesh, pCurrentGroup, nCrossesPlanesMask, bLightAlphaTexels );
}
return nCrossesPlanesMask;
}
void mesh3d_SetOrthoYScale(float fScale)
{
_fOrthoYScale = fScale;
}
void mesh3d_DrawOrtho( Mesh3d_t *pMesh, float fScreenX, float fScreenY, float fScreenZ,
int nRoll, float fScale ) {
float fScaledSin, fScaledCos, fOneOverScreenZ, f65535OverScreenZ, x, y, fVtxX, fVtxY;
float fViewportX, fViewportY, u, v;
int i, k, g, tl, t, vp, nNumVtxOutside, nTmuIndex, nTexture;
BOOL bTextured, bCullBackside;
u32 nGroupCount, nTlCount, nTriCount, nMtlFlags, nVtxIndex;
u32 nTriCrossesPlanesMask,Spec,n;
Mesh3dGrpDef_t *pCurrentGroup;
Mesh3dTlDef_t *pCurrentTl;
Mesh3dVtxDef_t *pVtxList;
Mesh3dTcDef_t *pTcList;
Mesh3dTriDef_t *pCurrentTri;
Mesh3dTriVtx_t *pTriVtx;
GrVertex aGrVertex[3], *pGrVertex;
TexDef_t *pTexDef;
fScreenZ = 32000.0f / fScreenZ;
fScaledSin = xmath_sin( nRoll ) * fScale;
fScaledCos = xmath_cos( nRoll ) * fScale;
fViewportX = fScreenX + 255.0;
fViewportY = fScreenY + 200.0;
nGroupCount = pMesh->nGrpCount;
pCurrentGroup = pMesh->pGrp;
for( g=0; (u32)g<nGroupCount; g++, pCurrentGroup++ ) {
/* Each group: */
pVtxList = pMesh->pVtx;
pTcList = pMesh->pTc;
nTlCount = pCurrentGroup->nTlCount;
pCurrentTl = pCurrentGroup->pTl;
for( tl=0; (u32)tl<nTlCount; tl++, pCurrentTl++ ) {
/* Each triangle list: */
_pCurrentMaterial = pCurrentTl->pMtl;
nMtlFlags = _pCurrentMaterial->nFlags;
bCullBackside = !(nMtlFlags & MESH3D_MTLFLAG_2SIDED);
bTextured = nMtlFlags & MESH3D_MTLFLAG_TEXTURE;
if( bTextured ) {
/* Texture mapped material: */
pTexDef = _pCurrentMaterial->pTexDef;
nTexture = pTexDef->aTMUTexInfo[0].nTmemStartAddress;
if(nTexture != -1){
// Make sure UV clamping is on...
// if(dcTextureTable[nTexture].AlphaBlendedTexVC.ClampUV != KM_CLAMP_UV){
// dcTextureTable[nTexture].AlphaBlendedTexVC.RenderState = KM_CLAMPUV;
// dcTextureTable[nTexture].AlphaBlendedTexVC.ClampUV = KM_CLAMP_UV;
// kmProcessVertexRenderState(&dcTextureTable[nTexture].AlphaBlendedTexVC);
// }
// Semi trans poly
// if((dcTextureTable[nTexture].Type & 7) == KM_TEXTURE_ARGB4444){
// }
// Punch through poly for 1555 texture
// else if((dcTextureTable[nTexture].Type & 7) == KM_TEXTURE_ARGB1555)
// kmSetVertexRenderState(&dcTextureTable[nTexture].PunchThroughTexVC);
// else
// kmSetVertexRenderState(&dcTextureTable[nTexture].OpaqueTexVC);
/* Disable z-buffer */
// if(dcTextureTable[nTexture].AlphaBlendedTexVC.DepthMode != KM_ALWAYS){
// dcTextureTable[nTexture].AlphaBlendedTexVC.RenderState = KM_DEPTHMODE;
// dcTextureTable[nTexture].AlphaBlendedTexVC.DepthMode = KM_ALWAYS;
// kmProcessVertexRenderState(&dcTextureTable[nTexture].AlphaBlendedTexVC);
// }
kmSetVertexRenderState(&dcTextureTable[nTexture].AlphaBlendedTexVC);
}
}
else{
dcSetCurrentVertexContext(&NonTexturedNoZBuffVC);
}
nTriCount = pCurrentTl->nTriCount;
pCurrentTri = pCurrentTl->pTri;
kmxxGetCurrentPtr(&VertexBufferDesc);
kmxxStartVertexStrip(&VertexBufferDesc);
for( t=0; (u32)t<nTriCount; t++, pCurrentTri++ ) {
/* Each triangle: */
pTriVtx = pCurrentTri->TriVtx;
/* Transform vertices: */
for( i=0, pGrVertex=aGrVertex; i<3; i++, pGrVertex++ ){
/* Each vertex: */
nVtxIndex = pTriVtx[i].nVtxIndex;
x = pVtxList[nVtxIndex].Point.p[0];
y = pVtxList[nVtxIndex].Point.p[1] * _fOrthoYScale;
fVtxX = x*fScaledCos - y*fScaledSin + fViewportX;
fVtxY = x*fScaledSin + y*fScaledCos + fViewportY;
fVtxY -= dcOrthoYOffset;
if( bTextured ) {
k = pTriVtx[i].nTcIndex;
u = pTcList[k].s;
v = pTcList[k].t;
vp = i < 2 ? KM_VERTEXPARAM_NORMAL : KM_VERTEXPARAM_ENDOFSTRIP;
kmxxSetVertex_3( vp,
DCSCALEXCOORD(fVtxX),
DCSCALEYCOORD(400.0f - fVtxY),
fScreenZ,
u,
v,
_OrthoConstColor|((u32)_fOrthoOpaqueness << 24),
_dwOrthoWhiteSat
);
}
}
}
kmxxReleaseCurrentPtr(&VertexBufferDesc);
}
}
}
ai_craft.c
Found at 0x8328078.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* ai_craft.c - non-player craft artificial intelligence routines*/
/* watercraft are managed by code in this file*/
/* physicscraft are managed by code in this file*/
/**/
/* Author: Scott Patterson */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1998*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 01/12/98 Patterson Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "vec2.h"
#include "vec3.h"
#include "paths.h"
#include "anim3d.h"
#include "phys.h"
#include "ai_params.h"
#include "worldob.h"
#include "sysmem.h"
#include "obsys.h"
#include "glcount.h"
#include "waterspray.h"
#include "hydro.hob"
#include "terrain.h"
#include "ai_drive.h"
#include "xclib.h"
#include "gamecoll.h"
#include "gutil.h"
#include "audio_spkr.h"
#include "soundcall.h"
#include "temp.h"
#include "audio.h"
#include "audio_mgr.h"
#include "ai_craft.h"
#include "ai_chase_acop.h"
#include "ai_chase_icop.h"
#include "ai_chase_mcop.h"
#include "ai_chase_ccop.h"
#include "ai_chase_ncop.h"
#include "ai_chase_gcop.h"
#include "ai_chase_whal.h"
#include "ai_chase_jucr.h"
#include "tracks.h"
/*====================*/
/* private definitions*/
u32 AiCraft_nNumChasers;
Phys_t *AiCraft_apChaserPhys[AI_CRAFT_NUM_CHASERS_MAX];
#define AI_CRAFT_PHYSICS_ACTIVATION_DIST 4000.0f
#define AI_CRAFT_POLICE_ACTIVATION_DIST 750.0f/*500.0f changed by mrs 10/13/98*/
#define AI_CRAFT_POLICE_DEACTIVATION_DIST 6666.6f/*10000.0f changed by mrs 10/13/98*/
#define AI_CRAFT_MAGNET_ACTIVATION_DIST 1000.0f
#define AI_CRAFT_MAGNET_DEACTIVATION_DIST 2000.0f
#define AI_CRAFT_DRUNK_ACTIVATION_DIST 1000.0f
#define AI_CRAFT_DRUNK_DEACTIVATION_DIST 2000.0f
#define AI_CRAFT_CROSS_ACTIVATION_DIST 1000.0f
#define AI_CRAFT_CROSS_DEACTIVATION_DIST 2000.0f
#define AI_CRAFT_ASSHOLE_ACTIVATION_DIST 1000.0f
#define AI_CRAFT_ASSHOLE_DEACTIVATION_DIST 2000.0f
#define AI_CRAFT_BLOCKER_ACTIVATION_DIST 1000.0f
#define AI_CRAFT_BLOCKER_DEACTIVATION_DIST 2000.0f
typedef struct
{
/* move it*/
Vec2_t PathPos; /* the path position we are going to*/
u32 nPathIndex; /* the path position index we are going to*/
Vec3_t LinearVelocity3D; /* World space velocity of this watercraft*/
f32 fLastSteer;
f32 fThrottle;
PathLoopInstance_t *pPathLoopInstance;
/* animate it?*/
AnimData_t *pBoatAnimData;
/* draw extra parts?*/
Mesh3d_t *pObjectMesh;
AnimData_t *pObjectAnimData;
/* draw even more extra parts?*/
u32 nExtraMeshCount;
Mesh3d_t *apExtraMeshes[AI_CRAFT_MAX_EXTRA_MESHES];
AnimData_t *apExtraMeshAnimData[AI_CRAFT_MAX_EXTRA_MESHES];
} Watercraft_t;
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
/*===================*/
/* private prototypes*/
static void _WorkWatercraft( WorldOb_t *pWorldOb );
static void _DrawWatercraft( WorldOb_t *pWorldOb );
static void _WorkPhysicscraft( WorldOb_t *pWorldOb );
static void _DrawPhysicscraft( WorldOb_t *pWorldOb );
static BOOL _GetClosestHumanBehind( f32 fCompareDistToGo, u32 nExceptionBits, u32 *pnPlayerNum, f32 *pfDistBehind );
static BOOL _Physicscraft_FindHumanInBackwardProximity( Physicscraft_t *pPhysicscraft, Phys_t **ppHumanPhys, f32 fProximity );
static void _ExcludeThisPlayerFromPhysicscraftFocus( Physicscraft_t *pPhysicscraft, u32 nPlayerNum );
static BOOL _Physicscraft_DeActivateOnForwardTravel( Physicscraft_t *pPhysicscraft, f32 fForwardTravel );
static BOOL _Physicscraft_DeActivateOnBackwardTravel( Physicscraft_t *pPhysicscraft, f32 fBackwardTravel );
static BOOL _Physicscraft_DeActivateOnForwardFocusProximity( Physicscraft_t *pPhysicscraft, f32 fForwardFocusProximity );
static BOOL _Physicscraft_DeActivateOnBackwardFocusProximity( Physicscraft_t *pPhysicscraft, f32 fBackwardFocusProximity );
static void _PhysicscraftMeshSpecificInit( Physicscraft_t *pPhysicscraft, const char *pMeshName, u32 nId );
static void _PhysicscraftMeshSpecificReset( Physicscraft_t *pPhysicscraft );
static void _PhysicscraftMeshSpecificIdle( Physicscraft_t *pPhysicscraft );
static void _PhysicscraftMeshSpecificWork( Physicscraft_t *pPhysicscraft );
static void _PhysicscraftMeshSpecificDraw( Physicscraft_t *pPhysicscraft );
/*=================*/
/* public functions*/
BOOL ai_craft_ModuleInit ( void )
{
AiCraft_nNumChasers = 0;
return TRUE;
}
void ai_craft_Reset( void )
{
AiCraft_nNumChasers = 0;
}
/* called to init watercraft*/
/* pWorldOb is the world ob that is becoming watercraft*/
/* nId it the object id*/
int ai_craft_InitWatercraft( WorldOb_t *pWorldOb, u32 nId )
{
Watercraft_t *pWatercraft;
Vec2_t StartPos2D;
char szObName[OBJECT_NAME_LENGTH+1];
u32 i;
/* Alloc the mem for the watercraft struct*/
pWatercraft = SYSMEM_ALLOCANDZERO( sizeof(Watercraft_t) );
if( pWatercraft )
{
pWatercraft->pPathLoopInstance = paths_GetClosestPathLoop( pWorldOb->Orient.Pos.p[0], pWorldOb->Orient.Pos.p[2] );
if( pWatercraft->pPathLoopInstance )
{
/* we found a closest path instance*/
/* get the start location and the start index*/
paths_GetPathLoopStartPos( &StartPos2D,
&pWatercraft->nPathIndex,
pWatercraft->pPathLoopInstance );
/* init the watercraft structure*/
pWorldOb->Orient.Pos.p[0] = StartPos2D.p[0];
pWorldOb->Orient.Pos.p[1] = water_GetHeight( NULL, StartPos2D.p[0], StartPos2D.p[1] );
pWorldOb->Orient.Pos.p[2] = StartPos2D.p[1];
paths_GetPathLoopNextPos( &pWatercraft->PathPos,
&pWatercraft->nPathIndex,
pWatercraft->nPathIndex,
pWatercraft->pPathLoopInstance );
pWatercraft->LinearVelocity3D.p[0] = 0.0f;
pWatercraft->LinearVelocity3D.p[1] = 0.0f;
pWatercraft->LinearVelocity3D.p[2] = 0.0f;
pWatercraft->fLastSteer = 0.0f;
switch( pWorldOb->nUserArg )
{
case WATERCRAFT_THROTTLE_0_05:
pWatercraft->fThrottle = 0.05f;
break;
case WATERCRAFT_THROTTLE_0_1:
pWatercraft->fThrottle = 0.1f;
break;
case WATERCRAFT_THROTTLE_0_2:
pWatercraft->fThrottle = 0.2f;
break;
case WATERCRAFT_THROTTLE_0_3:
pWatercraft->fThrottle = 0.3f;
break;
case WATERCRAFT_THROTTLE_0_4:
pWatercraft->fThrottle = 0.4f;
break;
case WATERCRAFT_THROTTLE_0_5:
pWatercraft->fThrottle = 0.5f;
break;
default:
pWatercraft->fThrottle = 0.2f;
break;
}
/* determine if any additional meshes or animations are to be loaded*/
/* get the name of the mesh*/
obsys_GetObjectNameFromSystemMemPointer( pWorldOb->pMesh, szObName );
/* check for boat animation*/
szObName[0] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pWatercraft->pBoatAnimData = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pWatercraft->pBoatAnimData )
{
anim3d_Load( szObName, pWatercraft->pBoatAnimData );
}
} else {
pWatercraft->pBoatAnimData = 0;
}
/* check for additional geometry*/
szObName[0] = 'G';
szObName[7] = 'M';
szObName[8] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pWatercraft->pObjectMesh = (Mesh3d_t *)obsys_Load( szObName );
/* does the additional geometry have animation?*/
szObName[0] = 'A';
szObName[7] = 'M';
szObName[8] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pWatercraft->pObjectAnimData = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pWatercraft->pObjectAnimData )
{
anim3d_Load( szObName, pWatercraft->pObjectAnimData );
}
} else {
pWatercraft->pObjectAnimData = 0;
}
} else {
pWatercraft->pObjectMesh = 0;
pWatercraft->pObjectAnimData = 0;
}
pWatercraft->nExtraMeshCount = 0;
for( i=0 ; i<AI_CRAFT_MAX_EXTRA_MESHES ; i++ )
{
/* check for extra parts to show*/
szObName[0] = 'G';
szObName[7] = 'P';
szObName[8] = '1' + i;
if( obsys_ObjectExists( szObName ) )
{
pWatercraft->apExtraMeshes[i] = (Mesh3d_t *)obsys_Load( szObName );;
/* does the additional geometry have animation?*/
szObName[0] = 'A';
szObName[7] = 'P';
szObName[8] = '1' + i;
if( obsys_ObjectExists( szObName ) )
{
pWatercraft->apExtraMeshAnimData[i] = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pWatercraft->apExtraMeshAnimData[i] )
{
anim3d_Load( szObName, pWatercraft->apExtraMeshAnimData[i] );
}
} else {
pWatercraft->apExtraMeshAnimData[i] = 0;
}
pWatercraft->nExtraMeshCount++;
} else {
pWatercraft->apExtraMeshes[i] = 0;
break;
}
}
/* got waterspray?*/
szObName[0] = 'G';
szObName[7] = 'S';
szObName[8] = 'E';
if( obsys_ObjectExists( szObName ) )
{
#ifndef EUROCOM_PLAYERSPRAYONLY
waterspray_InitFromMesh( szObName, NULL, pWorldOb, NULL, NULL );
#endif
}
/* link the watercraft data to the worldob for access in the work and draw functions*/
pWorldOb->pUserObject = pWatercraft;
/* set the work and draw functions*/
pWorldOb->pWorkFcn = _WorkWatercraft;
pWorldOb->pDrawFcn = _DrawWatercraft;
}
}
return TERRAIN_INITFCN_RETVAL_ADD;
}
/* called to init watercraft*/
/* pWorldOb is the world ob that is becoming watercraft*/
/* nId it the object id*/
int ai_craft_InitPhysicscraft( WorldOb_t *pWorldOb, u32 nId )
{
PathSector_t *pRetPathSector;
Physicscraft_t *pPhysicscraft;
char szObName[OBJECT_NAME_LENGTH+1];
const char *pPhysDataName;
u32 i;
void *pMemFrame;
if( !Temp_bLoadAi )
{
return TERRAIN_INITFCN_RETVAL_DONT_ADD;
}
/* get the name of the mesh*/
obsys_GetObjectNameFromSystemMemPointer( pWorldOb->pMesh, szObName );
szObName[0] = 'p';
pPhysDataName = physdata_FindDataNameFromR2PName( szObName );
if( !pPhysDataName )
{
xprintferr( ">>>Error: Physicscraft physics file %s not found for mesh, world ob not added.\n", szObName );
return TERRAIN_INITFCN_RETVAL_DONT_ADD;
}
/* start a frame in case we have errors*/
pMemFrame = sysmem_StartFrame();
/* Alloc the mem for the physboat struct*/
pPhysicscraft = SYSMEM_ALLOCANDZERO( sizeof(Physicscraft_t) );
if( pPhysicscraft )
{
/* setup as a physics based object*/
pWorldOb->nFlags &= ~WORLDOB_FLAG_FLOAT;
pWorldOb->nFlags |= WORLDOB_FLAG_SPECIAL_PHYS;
worldob_Add( pWorldOb, NULL );
pWorldOb->pMotion = &pPhysicscraft->Motion;
if( phys_InitBoat( pPhysDataName, &pPhysicscraft->Phys, &pWorldOb->pMesh->Bound, pWorldOb, FALSE, TRUE, PHYS_TYPE_CHASER ) )
{
gamecoll_BuildCollisionObject_ForTerrainId( pWorldOb->nGameId, pWorldOb, &pPhysicscraft->Phys, NULL, pWorldOb->pMesh->pCollSphereList );
/* set the work and draw functions*/
pWorldOb->pWorkFcn = _WorkPhysicscraft;
pWorldOb->pDrawFcn = _DrawPhysicscraft;
} else {
xprintferr( ">>>Error: Physicscraft phys_InitBoat failed, world ob not added.\n", szObName );
worldob_Delete( pWorldOb );
sysmem_ReleaseFrame( pMemFrame );
return TERRAIN_INITFCN_RETVAL_DONT_ADD;
}
pPhysicscraft->Phys.nControlFlags |= PHYS_CONTROLFLAG_DISABLE;
/*pPhysicscraft->Phys.nControlFlags |= PHYS_CONTROLFLAG_SILENT;*/
/* initialize our path sector information*/
player_InitPathSectorProgressInfo( &pPhysicscraft->Phys );
pPhysicscraft->Initial2DPos.p[0] = pWorldOb->Orient.Pos.p[0];
pPhysicscraft->Initial2DPos.p[1] = pWorldOb->Orient.Pos.p[2];
if(paths_GetPathSectorFromWorldPos( &pRetPathSector,
&pPhysicscraft->Initial2DPos,
pPhysicscraft->Phys.PathSectorTracking.pBoatPathSector ) )
{
player_UpdatePathSectorProgress( pRetPathSector, &pPhysicscraft->Initial2DPos, &pPhysicscraft->Phys );
}
pPhysicscraft->fInitialRaceDistToGo = pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace;
pPhysicscraft->nPlayerExcludeBits = 0;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_IDLE;
pPhysicscraft->pWorldOb = pWorldOb;
pPhysicscraft->nFlags = 0;
pPhysicscraft->nMightyHullCount = 0;
/* add this chaser to a list so it can be displayed on the radar map*/
if( AiCraft_nNumChasers < AI_CRAFT_NUM_CHASERS_MAX )
{
AiCraft_apChaserPhys[AiCraft_nNumChasers] = &pPhysicscraft->Phys;
AiCraft_nNumChasers++;
}
/* initialize our drive info*/
ai_drive_InitDriveInfo( &pPhysicscraft->DriveInfo );
/* do all the extra parts and animation setup*/
/* check for boat animation*/
szObName[0] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pPhysicscraft->pBoatAnimData = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pPhysicscraft->pBoatAnimData )
{
anim3d_Load( szObName, pPhysicscraft->pBoatAnimData );
}
} else {
pPhysicscraft->pBoatAnimData = 0;
}
/* check for additional geometry*/
szObName[0] = 'G';
szObName[7] = 'M';
szObName[8] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pPhysicscraft->pObjectMesh = (Mesh3d_t *)obsys_Load( szObName );
/* does the additional geometry have animation?*/
szObName[0] = 'A';
szObName[7] = 'M';
szObName[8] = 'A';
if( obsys_ObjectExists( szObName ) )
{
pPhysicscraft->pObjectAnimData = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pPhysicscraft->pObjectAnimData )
{
anim3d_Load( szObName, pPhysicscraft->pObjectAnimData );
}
} else {
pPhysicscraft->pObjectAnimData = 0;
}
} else {
pPhysicscraft->pObjectMesh = 0;
pPhysicscraft->pObjectAnimData = 0;
}
pPhysicscraft->nExtraMeshCount = 0;
for( i=0 ; i<AI_CRAFT_MAX_EXTRA_MESHES ; i++ )
{
/* check for extra parts to show*/
szObName[0] = 'G';
szObName[7] = 'P';
szObName[8] = '1' + i;
if( obsys_ObjectExists( szObName ) )
{
pPhysicscraft->apExtraMeshes[i] = (Mesh3d_t *)obsys_Load( szObName );
/* do the extra parts have animation?*/
szObName[0] = 'A';
szObName[7] = 'P';
szObName[8] = '1' + i;
if( obsys_ObjectExists( szObName ) )
{
pPhysicscraft->apExtraMeshAnimData[i] = SYSMEM_ALLOC( sizeof(AnimData_t) );
if( pPhysicscraft->apExtraMeshAnimData[i] )
{
anim3d_Load( szObName, pPhysicscraft->apExtraMeshAnimData[i] );
}
} else {
pPhysicscraft->apExtraMeshAnimData[i] = 0;
}
pPhysicscraft->nExtraMeshCount++;
} else {
pPhysicscraft->apExtraMeshes[i] = 0;
break;
}
}
/* got waterspray?*/
szObName[0] = 'G';
szObName[7] = 'S';
szObName[8] = 'E';
if( obsys_ObjectExists( szObName ) )
{
#ifndef EUROCOM_PLAYERSPRAYONLY
waterspray_InitFromMesh( szObName, NULL, pWorldOb, NULL, NULL );
#endif
}
/* get the name of the mesh again*/
obsys_GetObjectNameFromSystemMemPointer( pWorldOb->pMesh, szObName );
_PhysicscraftMeshSpecificInit( pPhysicscraft, szObName, nId );
/* link the Physicscraft data to the worldob for access in the work and draw functions*/
pWorldOb->pUserObject = pPhysicscraft;
}
return TERRAIN_INITFCN_RETVAL_DONT_ADD;
}
/* called to notify physicscraft that they have been hit*/
/* pWorldOb is the physicscraft that has been hit*/
/* bMightyHull tells us if we have been mighty hulled*/
/* pPlayer is the player that has hit us*/
void ai_craft_JustHitThisPhysicscraft( WorldOb_t *pWorldOb, BOOL bMightyHull, Player_t *pPlayer )
{
Physicscraft_t *pPhysicscraft;
pPhysicscraft = (Physicscraft_t *)pWorldOb->pUserObject;
if( bMightyHull )
{
pPhysicscraft->nFlags |= AI_PHYSICSCRAFT_FLAG_HIT_BY_MIGHTY_HULL;
} else {
pPhysicscraft->nFlags |= AI_PHYSICSCRAFT_FLAG_HIT_NORMAL;
}
pPhysicscraft->nMightyHullCount++;
if( pPlayer && bMightyHull )
{
_ExcludeThisPlayerFromPhysicscraftFocus( pPhysicscraft, pPlayer->nId );
}
}
#define AI_CRAFT_MESH_SPECIFIC_DATA_COUNT 8
typedef void (*PhysicscraftMeshSpecificInitFunc)( Physicscraft_t *pPhysicscraft, u32 nId );
typedef void (*PhysicscraftMeshSpecificResetFunc)( Physicscraft_t *pPhysicscraft );
typedef void (*PhysicscraftMeshSpecificIdleFunc)( Physicscraft_t *pPhysicscraft );
typedef void (*PhysicscraftMeshSpecificWorkFunc)( Physicscraft_t *pPhysicscraft );
typedef void (*PhysicscraftMeshSpecificDrawFunc)( Physicscraft_t *pPhysicscraft );
typedef struct {
char *pMeshName;
PhysicscraftMeshSpecificInitFunc Init;
PhysicscraftMeshSpecificResetFunc Reset;
PhysicscraftMeshSpecificIdleFunc Idle;
PhysicscraftMeshSpecificWorkFunc Work;
PhysicscraftMeshSpecificDrawFunc Draw;
} AiCraftMeshSpecificDataMap_t;
/* for every known mesh we associate known phys data*/
AiCraftMeshSpecificDataMap_t _MeshSpecificDataMap[AI_CRAFT_MESH_SPECIFIC_DATA_COUNT] = {
{ "GPXCOPBHUH0", ai_chase_acop_AmericanPoliceInit, ai_chase_acop_AmericanPoliceReset, ai_chase_acop_AmericanPoliceIdle, ai_chase_acop_AmericanPoliceWork, ai_chase_acop_AmericanPoliceDraw },
{ "GVXCOPBHUH0", ai_chase_icop_ItalianPoliceInit, ai_chase_icop_ItalianPoliceReset, ai_chase_icop_ItalianPoliceIdle, ai_chase_icop_ItalianPoliceWork, ai_chase_icop_ItalianPoliceDraw },
{ "GGXCOPBHUH0", ai_chase_mcop_MilitaryPoliceInit, ai_chase_mcop_MilitaryPoliceReset, ai_chase_mcop_MilitaryPoliceIdle, ai_chase_mcop_MilitaryPoliceWork, ai_chase_mcop_MilitaryPoliceDraw },
{ "GRXCOPBHUH0", ai_chase_gcop_GreekPoliceInit, ai_chase_gcop_GreekPoliceReset, ai_chase_gcop_GreekPoliceIdle, ai_chase_gcop_GreekPoliceWork, ai_chase_gcop_GreekPoliceDraw },
{ "GCXCOPBHUH0", ai_chase_ccop_ChinesePoliceInit, ai_chase_ccop_ChinesePoliceReset, ai_chase_ccop_ChinesePoliceIdle, ai_chase_ccop_ChinesePoliceWork, ai_chase_ccop_ChinesePoliceDraw },
{ "GYXRESCHUH0", ai_chase_ncop_NewYorkPoliceInit, ai_chase_ncop_NewYorkPoliceReset, ai_chase_ncop_NewYorkPoliceIdle, ai_chase_ncop_NewYorkPoliceWork, ai_chase_ncop_NewYorkPoliceDraw },
{ "GAXCHASHUH0", ai_chase_whal_WhalingBoatInit, ai_chase_whal_WhalingBoatReset, ai_chase_whal_WhalingBoatIdle, ai_chase_whal_WhalingBoatWork, ai_chase_whal_WhalingBoatDraw },
{ "GJXJUCRHUH0", ai_chase_jucr_JungleCruiseInit, ai_chase_jucr_JungleCruiseReset, ai_chase_jucr_JungleCruiseIdle, ai_chase_jucr_JungleCruiseWork, ai_chase_jucr_JungleCruiseDraw },
};
void _PhysicscraftMeshSpecificInit( Physicscraft_t *pPhysicscraft, const char *pMeshName, u32 nId )
{
BOOL bHasSpecificEntry = FALSE;
u32 i;
/* find physdata for this mesh*/
for( i=0 ; i < AI_CRAFT_MESH_SPECIFIC_DATA_COUNT ; i++ ) {
if( !xclib_stricmp( pMeshName, _MeshSpecificDataMap[i].pMeshName ) )
{
/* Names match...*/
pPhysicscraft->nMeshSpecificType = i;
bHasSpecificEntry = TRUE;
break;
}
}
if( !bHasSpecificEntry )
{
pPhysicscraft->nMeshSpecificType = -1;
return;
}
/* if we are here we have specific functions for this mesh*/
_MeshSpecificDataMap[pPhysicscraft->nMeshSpecificType].Init( pPhysicscraft, nId );
}
void _PhysicscraftMeshSpecificReset( Physicscraft_t *pPhysicscraft )
{
ai_params_SetBoatParams( 0, &pPhysicscraft->DriveInfo.BoatParams );
pPhysicscraft->DriveInfo.nPathDecisionFlags = PATHS_DECISION_DEFAULT;
pPhysicscraft->DriveInfo.fLanePosition = AI_DRIVE_INIT_LANE_POS;
pPhysicscraft->DriveInfo.fLastLookAhead = AI_DRIVE_INIT_LOOK_AHEAD;
pPhysicscraft->DriveInfo.fLastLanePos = AI_DRIVE_INIT_LANE_POS;
pPhysicscraft->DriveInfo.fLastWheelBias = 0.0f;
pPhysicscraft->Phys.fCheatLevel = 0.1f;
/*pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_LITE_MODE;*/
/*pPhysicscraft->Phys.nControlFlags |= PHYS_CONTROLFLAG_PHYS_TRANSITION;*/
if( pPhysicscraft->nMeshSpecificType >= 0 )
{
/* if we are here we have specific functions for this mesh*/
_MeshSpecificDataMap[pPhysicscraft->nMeshSpecificType].Reset( pPhysicscraft );
}
}
void _PhysicscraftMeshSpecificIdle( Physicscraft_t *pPhysicscraft )
{
pPhysicscraft->Phys.fCheatLevel = 0.0f; /* no need to cheat a boat that won't be moving*/
/*pPhysicscraft->Phys.nControlFlags |= PHYS_CONTROLFLAG_LITE_MODE;*/
/*pPhysicscraft->Phys.nControlFlags |= PHYS_CONTROLFLAG_PHYS_TRANSITION;*/
if( pPhysicscraft->nMeshSpecificType >= 0 )
{
/* if we are here we have specific functions for this mesh*/
_MeshSpecificDataMap[pPhysicscraft->nMeshSpecificType].Idle( pPhysicscraft );
}
}
void _PhysicscraftMeshSpecificWork( Physicscraft_t *pPhysicscraft )
{
if( pPhysicscraft->nMeshSpecificType >= 0 )
{
/* if we are here we have specific functions for this mesh*/
_MeshSpecificDataMap[pPhysicscraft->nMeshSpecificType].Work( pPhysicscraft );
}
}
void _PhysicscraftMeshSpecificDraw( Physicscraft_t *pPhysicscraft )
{
if( pPhysicscraft->nMeshSpecificType >= 0 )
{
/* if we are here we have specific functions for this mesh*/
_MeshSpecificDataMap[pPhysicscraft->nMeshSpecificType].Draw( pPhysicscraft );
}
}
/*==================*/
/* private functions*/
static void _MoveWorldObOnLitePhys( WorldOb_t *pWorldOb, f32 fSteer, f32 fThrottle, Vec3_t *pLinearVelocity3D )
{
WorldSector_t *pSector;
Vec2_t XZDir, VelVec;
f32 fTemp, fMPH;
f32 fPrevHeight, fWaterHeight;
int nHeading;
int nNewHeading, nNewPitch, nNewRoll;
Vec3_t *pPos;
Mtx3_t *pRot;
pPos = &pWorldOb->Orient.Pos;
pRot = &pWorldOb->Orient.Rot;
/* get current heading info out of the rotation matrix*/
XZDir.p[0] = pRot->m[2][0];
XZDir.p[1] = pRot->m[2][2];
nHeading = xmath_atan( XZDir.p[0], XZDir.p[1] );
/* compute the new boat velocity...*/
VelVec.p[0] = pLinearVelocity3D->p[0];
VelVec.p[1] = pLinearVelocity3D->p[2];
if(fThrottle > 0.0f)
{
fTemp = fThrottle * 1.5f;
} else {
fTemp = 0.0f;
}
/* increase velocity based on throttle*/
VelVec.p[0] += (fTemp * XZDir.p[0]);
VelVec.p[1] += (fTemp * XZDir.p[1]);
/* damp velocity so that no throttle lead to slowing down*/
VelVec.p[0] *= 0.94f;
VelVec.p[1] *= 0.94f;
fTemp = vec2_CalcMag( &VelVec );
fMPH = fTemp * ( (1.0f/5280.0f) * (30.0f * 3600.0f) );
pLinearVelocity3D->p[0] = VelVec.p[0];
pLinearVelocity3D->p[2] = VelVec.p[1];
/* move the boat...*/
pPos->p[0] += VelVec.p[0];
pPos->p[2] += VelVec.p[1];
pSector = world_FindSectorContainingPoint( pWorldOb->Tws.pCenterSector,
pPos->p[0],
pPos->p[2] );
/* autotrack the boat to the water...*/
fPrevHeight = pPos->p[1];
fWaterHeight = water_GetHeight( pSector, pPos->p[0], pPos->p[2] );
fWaterHeight += fMPH*0.02f;
if( fPrevHeight < (fWaterHeight + 0.1f) ) {
pPos->p[1] += ( (fWaterHeight - fPrevHeight) * 0.25f );
pLinearVelocity3D->p[1] = 0.0f;
} else if (fPrevHeight > (fWaterHeight - 0.1f) ) {
pLinearVelocity3D->p[1] -= 0.125f;
pPos->p[1] += pLinearVelocity3D->p[1];
}
/* clamp the y position to no less than 10 feet below the water*/
/* we do this to avoid the switch to full physics and vertical launch problem*/
if(pPos->p[1] < fWaterHeight - 10.0f)
{
pPos->p[1] = fWaterHeight - 10.0f;
}
nNewHeading = nHeading + (int)(fSteer * 1000.0f);
nNewPitch = (int)(fMPH * -14.0f);
nNewRoll = (int)(fSteer * fMPH * -40.0f);
orient_BuildRotYXZ( &pWorldOb->Orient, nNewHeading, nNewPitch, nNewRoll );
}
static void _WorkWatercraft( WorldOb_t *pWorldOb )
{
Vec2_t Diff;
Watercraft_t *pWatercraft;
f32 fSteer;
f32 fDistance;
u32 i;
pWatercraft = (Watercraft_t *)pWorldOb->pUserObject;
/* if we are too close to our goal point, choose another one*/
Diff.p[0] = pWorldOb->Orient.Pos.p[0] - pWatercraft->PathPos.p[0];
Diff.p[1] = pWorldOb->Orient.Pos.p[2] - pWatercraft->PathPos.p[1];
fDistance = vec2_CalcMag( &Diff );
if( fDistance <= 200.0f ) {
paths_GetPathLoopNextPos( &pWatercraft->PathPos, &pWatercraft->nPathIndex, pWatercraft->nPathIndex, pWatercraft->pPathLoopInstance );
}
/* create our virtual steering value based on the point we want to head toward*/
fSteer = ai_drive_SteerWorldObToPoint( pWorldOb, &pWatercraft->PathPos );
fSteer = xmath_LimitChange( fSteer, pWatercraft->fLastSteer, 0.05f );
pWatercraft->fLastSteer = fSteer;
/* move the boat with our lite physics code*/
_MoveWorldObOnLitePhys( pWorldOb, fSteer, pWatercraft->fThrottle, &pWatercraft->LinearVelocity3D );
/* if the boat animates, do the animation work*/
if( pWatercraft->pBoatAnimData )
{
anim3d_Animate( pWatercraft->pBoatAnimData );
}
/* if we have a "man" to animate, do his animation work*/
if( pWatercraft->pObjectMesh )
{
if( pWatercraft->pObjectAnimData )
{
anim3d_Animate( pWatercraft->pObjectAnimData );
}
}
/* animate any additional geometry*/
for( i=0 ; i<pWatercraft->nExtraMeshCount ; i++ )
{
if( pWatercraft->apExtraMeshes[i] )
{
if( pWatercraft->apExtraMeshAnimData[i] )
{
anim3d_Animate( pWatercraft->apExtraMeshAnimData[i] );
}
}
}
/* update the TWS*/
worldob_UpdateTrackingWorldSphere( pWorldOb, FALSE );
}
static void _DrawWatercraft( WorldOb_t *pWorldOb )
{
Watercraft_t *pWatercraft;
u32 i;
pWatercraft = (Watercraft_t *)pWorldOb->pUserObject;
if( pWatercraft->pBoatAnimData )
{
/* if the boat animates, draw the groups*/
anim3d_Draw( pWorldOb->pMesh, pWatercraft->pBoatAnimData, pWatercraft->pBoatAnimData->nFrame );
} else {
/* the boat does not animate, just draw it*/
mesh3d_DrawWithLod( pWorldOb->pMesh, 0xf, TRUE );
}
if( pWatercraft->pObjectMesh )
{
if( pWatercraft->pObjectAnimData )
{
/* if the "man" animates, draw the groups*/
anim3d_Draw( pWatercraft->pObjectMesh, pWatercraft->pObjectAnimData, pWatercraft->pObjectAnimData->nFrame );
} else {
/* the "man" does not animate, draw him*/
mesh3d_DrawWithLod( pWatercraft->pObjectMesh, 0xf, TRUE );
}
}
/* draw any additional geometry*/
for( i=0 ; i<pWatercraft->nExtraMeshCount ; i++ )
{
if( pWatercraft->apExtraMeshes[i] )
{
if( pWatercraft->apExtraMeshAnimData[i] )
{
/* if the extra part animates, draw the groups*/
anim3d_Draw( pWatercraft->apExtraMeshes[i], pWatercraft->apExtraMeshAnimData[i], pWatercraft->apExtraMeshAnimData[i]->nFrame );
} else {
/* the extra part does not animate, draw it*/
mesh3d_DrawWithLod( pWatercraft->apExtraMeshes[i], 0xf, TRUE );
}
}
}
}
/* get the closest human behind that had not been marked in the nPlayerBits*/
BOOL _GetClosestHumanBehind( f32 fCompareDistToGo, u32 nExcludeBits, u32 *pnPlayerNum, f32 *pfDistBehind )
{
u32 i;
BOOL bFoundBehind = FALSE;
f32 fFoundDist, fNewDist;
u32 nFoundPlayerNum;
Player_t *pPlayer;
for( i=0; i<Player_nTotalCount; i++ )
{
pPlayer = Player_apData[i];
if( (pPlayer->nFlags & PLAYER_FLAG_HUMAN) && !(nExcludeBits & (1 << pPlayer->nId)) )
{
if( fCompareDistToGo < pPlayer->Phys.PathSectorTracking.fDistToGoInTheRace )
{
/* found a human that is behind*/
if( !bFoundBehind )
{
nFoundPlayerNum = pPlayer->nId;
fFoundDist = pPlayer->Phys.PathSectorTracking.fDistToGoInTheRace - fCompareDistToGo;
bFoundBehind = TRUE;
} else {
fNewDist = pPlayer->Phys.PathSectorTracking.fDistToGoInTheRace - fCompareDistToGo;
if( fFoundDist > fNewDist )
{
nFoundPlayerNum = pPlayer->nId;
fFoundDist = fNewDist;
}
}
}
}
}
if( bFoundBehind )
{
*pnPlayerNum = nFoundPlayerNum;
*pfDistBehind = fFoundDist;
return TRUE;
} else {
return FALSE;
}
}
BOOL _Physicscraft_FindLeadHuman( Physicscraft_t *pPhysicscraft, Phys_t **ppHumanPhys )
{
u32 i, nThisHuman;
Phys_t *pNewPhys;
for( i=0; i<Player_nNumRanked; i++ )
{
nThisHuman = Player_anRank[i];
if( (Player_aData[nThisHuman].nFlags & PLAYER_FLAG_HUMAN) && !(pPhysicscraft->nPlayerExcludeBits & (1 << nThisHuman)) )
{
pNewPhys = &Player_aData[nThisHuman].Phys;
*ppHumanPhys = pNewPhys;
return TRUE;
}
}
return FALSE;
}
BOOL _Physicscraft_FindHumanInBackwardProximity( Physicscraft_t *pPhysicscraft, Phys_t **ppHumanPhys, f32 fProximity )
{
u32 nClosestPlayer;
f32 fClosestDist;
/* is there a human close enough to prey upon?*/
if( _GetClosestHumanBehind( pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace,
pPhysicscraft->nPlayerExcludeBits, &nClosestPlayer, &fClosestDist ) )
{
if( fClosestDist < fProximity )
{
/* we have just decided to interact with a human, record our initial position and exclude this player in the future*/
pPhysicscraft->fInitialRaceDistToGo = pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace;
/* we no longer exclude after finding a human //pPhysicscraft->nPlayerExcludeBits |= 1 << nClosestPlayer;*/
*ppHumanPhys = &Player_aData[nClosestPlayer].Phys;
return TRUE;
}
}
return FALSE;
}
void _ExcludeThisPlayerFromPhysicscraftFocus( Physicscraft_t *pPhysicscraft, u32 nPlayerNum )
{
pPhysicscraft->nPlayerExcludeBits |= 1 << nPlayerNum;
}
BOOL _Physicscraft_DeActivateOnForwardTravel( Physicscraft_t *pPhysicscraft, f32 fForwardTravel )
{
f32 fDistFromInitial;
/* have we traveled too far from our initial position?*/
fDistFromInitial = pPhysicscraft->fInitialRaceDistToGo - pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace;
if( fDistFromInitial > fForwardTravel )
{
return TRUE;
}
return FALSE;
}
#if 0 //PAB UNUSED
BOOL _Physicscraft_DeActivateOnBackwardTravel( Physicscraft_t *pPhysicscraft, f32 fBackwardTravel )
{
f32 fDistFromInitial;
/* have we traveled too far from our initial position?*/
fDistFromInitial = pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace - pPhysicscraft->fInitialRaceDistToGo;
if( fDistFromInitial > fBackwardTravel )
{
return TRUE;
}
return FALSE;
}
#endif
#if 0 //PAB UNUSED
BOOL _Physicscraft_DeActivateOnForwardFocusProximity( Physicscraft_t *pPhysicscraft, f32 fForwardFocusProximity )
{
f32 fDist;
/* have we traveled too far from our initial position?*/
fDist = pPhysicscraft->pFocusPhys->PathSectorTracking.fDistToGoInTheRace - pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace;
if( fDist > fForwardFocusProximity )
{
return TRUE;
}
return FALSE;
}
#endif
#if 0 //PAB UNUSED
BOOL _Physicscraft_DeActivateOnBackwardFocusProximity( Physicscraft_t *pPhysicscraft, f32 fBackwardFocusProximity )
{
f32 fDist;
/* have we traveled too far from our initial position?*/
fDist = pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace - pPhysicscraft->pFocusPhys->PathSectorTracking.fDistToGoInTheRace;
if( fDist > fBackwardFocusProximity )
{
return TRUE;
}
return FALSE;
}
#endif
static void _WorkPhysicscraft( WorldOb_t *pWorldOb )
{
Physicscraft_t *pPhysicscraft;
PathSector_t *pRetPathSector;
Vec2_t SelfPos;
Phys_t *pFocusPhys;
f32 fSteer, fThrottle, fActivationDist;
u32 i;
pPhysicscraft = (Physicscraft_t *)pWorldOb->pUserObject;
/* SSP - switch to tws center*/
/*SelfPos.p[0] = pWorldOb->Orient.Pos.p[0];*/
/*SelfPos.p[1] = pWorldOb->Orient.Pos.p[2];*/
SelfPos.p[0] = pWorldOb->Tws.CurrentWorldPos.p[0];
SelfPos.p[1] = pWorldOb->Tws.CurrentWorldPos.p[1];
/* update our path sector progress*/
if( paths_GetPathSectorFromWorldPos( &pRetPathSector, &SelfPos, pPhysicscraft->Phys.PathSectorTracking.pBoatPathSector ) )
{
player_UpdatePathSectorProgress( pRetPathSector, &SelfPos, &pPhysicscraft->Phys );
}
fSteer = 0.0f;
fThrottle = 0.0f;
switch( pWorldOb->nUserArg )
{
case PHYSICSCRAFT_POLICE:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if(Tracks_nCurrentTrack!=TRACKS_ARTIC)
{
fActivationDist = AI_CRAFT_POLICE_ACTIVATION_DIST;
} else {
fActivationDist = AI_CRAFT_POLICE_ACTIVATION_DIST + 1000;
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, fActivationDist ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_ACTIVE:
if( _Physicscraft_FindLeadHuman( pPhysicscraft, &pFocusPhys ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
ai_drive_Police( pPhysicscraft->pFocusPhys, &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
} else {
ai_drive_Normal( &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
}
if( _Physicscraft_DeActivateOnForwardTravel( pPhysicscraft, AI_CRAFT_POLICE_DEACTIVATION_DIST ) )
{
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_DISABLE;
_PhysicscraftMeshSpecificIdle( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_DISABLE:
fSteer = 0.0f;
fThrottle = 0.0f;
break;
}
break;
case PHYSICSCRAFT_MAGNET:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, AI_CRAFT_MAGNET_ACTIVATION_DIST ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_ACTIVE:
if( _Physicscraft_FindLeadHuman( pPhysicscraft, &pFocusPhys ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
ai_drive_Magnet( pPhysicscraft->pFocusPhys, &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
} else {
ai_drive_Normal( &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
}
if( _Physicscraft_DeActivateOnForwardTravel( pPhysicscraft, AI_CRAFT_MAGNET_DEACTIVATION_DIST ) )
{
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_DISABLE;
_PhysicscraftMeshSpecificIdle( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_DISABLE:
fSteer = 0.0f;
fThrottle = 0.0f;
break;
}
break;
case PHYSICSCRAFT_DRUNK:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, AI_CRAFT_DRUNK_ACTIVATION_DIST ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_ACTIVE:
if( _Physicscraft_FindLeadHuman( pPhysicscraft, &pFocusPhys ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
ai_drive_Drunk( pPhysicscraft->pFocusPhys, &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
} else {
ai_drive_Normal( &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
}
if( _Physicscraft_DeActivateOnForwardTravel( pPhysicscraft, AI_CRAFT_DRUNK_DEACTIVATION_DIST ) )
{
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_DISABLE;
_PhysicscraftMeshSpecificIdle( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_DISABLE:
fSteer = 0.0f;
fThrottle = 0.0f;
break;
}
break;
case PHYSICSCRAFT_CROSS:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, AI_CRAFT_CROSS_ACTIVATION_DIST ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_ACTIVE:
if( _Physicscraft_FindLeadHuman( pPhysicscraft, &pFocusPhys ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
ai_drive_Cross( pPhysicscraft->pFocusPhys, &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
} else {
ai_drive_Normal( &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
}
if( _Physicscraft_DeActivateOnForwardTravel( pPhysicscraft, AI_CRAFT_CROSS_DEACTIVATION_DIST ) )
{
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_DISABLE;
_PhysicscraftMeshSpecificIdle( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_DISABLE:
fSteer = 0.0f;
fThrottle = 0.0f;
break;
}
break;
case PHYSICSCRAFT_ASSHOLE:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, AI_CRAFT_ASSHOLE_ACTIVATION_DIST ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_ACTIVE:
if( _Physicscraft_FindLeadHuman( pPhysicscraft, &pFocusPhys ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
ai_drive_Asshole( pPhysicscraft->pFocusPhys, &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
} else {
ai_drive_Normal( &pPhysicscraft->Phys, &pPhysicscraft->DriveInfo, &fSteer, &fThrottle );
}
if( _Physicscraft_DeActivateOnForwardTravel( pPhysicscraft, AI_CRAFT_ASSHOLE_DEACTIVATION_DIST ) )
{
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_DISABLE;
_PhysicscraftMeshSpecificIdle( pPhysicscraft );
}
break;
case AI_CRAFT_PHYSICSCRAFT_DISABLE:
fSteer = 0.0f;
fThrottle = 0.0f;
break;
}
break;
case PHYSICSCRAFT_BLOCKER:
switch( pPhysicscraft->nMode )
{
case AI_CRAFT_PHYSICSCRAFT_IDLE:
fSteer = 0.0f;
fThrottle = 0.0f;
if( pPhysicscraft->Phys.nControlFlags & PHYS_CONTROLFLAG_DISABLE )
{
if( (Player_aData[Player_nFirstPlaceHuman].Phys.PathSectorTracking.fDistToGoInTheRace -
pPhysicscraft->Phys.PathSectorTracking.fDistToGoInTheRace) > AI_CRAFT_PHYSICS_ACTIVATION_DIST )
{
pPhysicscraft->Phys.nControlFlags &= ~PHYS_CONTROLFLAG_DISABLE;
}
}
if( _Physicscraft_FindHumanInBackwardProximity( pPhysicscraft, &pFocusPhys, AI_CRAFT_BLOCKER_ACTIVATION_DIST ) )
{
pPhysicscraft->pFocusPhys = pFocusPhys;
pPhysicscraft->nMode = AI_CRAFT_PHYSICSCRAFT_ACTIVE;
_PhysicscraftMeshSpecificReset( pPhysicscraft );
}
break;
case AI_C
text.c (Copy 2)
A small fragment from a second copy of text.c can be found at 0x832A078.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* text.c - text string handling routines*/
/**/
/* Author: Michael Hunley */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* NOTES:*/
/* It is important that all fonts be drawn with a 2 pixel outer boarder to account*/
/* for bilinear interpolation when scaled. At creation time I do not know if it*/
/* should be alpha (0,0,0 black) or a colored boarder that mimics the letter.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 11/25/97 Hunley Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "text.h"
#include "viewport.h"
#include "obsys.h"
#include "gutil.h"
#include "tmem.h"
#include "material.h"
#include "xmath.h"
#include "xclib.h"
#include "stdarg.h"
/*====================*/
/* private definitions*/
#if TARGET==ULTRA64
unsigned short int *N64ConstantColour;
BOOL N64ScaleFont=FALSE;
float N64OrigScale=0;
/* As 'scaled font's will look crap, have 'x' versions of font in same texture page */
/* Simply check for 'scale' match and use this font, else default! */
typedef struct {
float Scale;
int FontOffset;
} N64FontScale;
#endif /*ULTRA64 */
#if TARGET==ULTRA64
typedef struct _tag_FontMap {
u16 nXOff;
u8 nWidthN64;
} FontMap_t;
#else /*ULTRA64 */
typedef struct _tag_FontMap {
u32 nXOff;
u32 nWidth;
} FontMap_t;
#endif /*ULTRA64 */
typedef struct _tag_FontHdr {
u8 nWidth; /* width of a space (avg. char width)*/
u8 nHeight; /* Height of all */
u8 nSpacing;
u8 nYSpacing;
} FontHdr_t;
typedef struct _tag_TextImage {
const char pszName[OBJECT_NAME_LENGTH + 1]; /* Object name in R2 file*/
TexDef_t *pTexDef;
} TextImage_t;
typedef struct TextImageList_s {
u32 nCount;
TextImage_t *pTextImageArray;
} TextImageList_t;
typedef struct _tag_Font {
BOOL bLoaded;
TextImageList_t *pTextImageList;
FontMap_t *pMapping; /* ascii character map*/
FontHdr_t *pHeader; /* master info per font*/
u32 nHeight;
#if TARGET==ULTRA64
N64FontScale * N64ScaleTable;
#endif /*ULTRA64 */
} TextFont_t;
/*=================*/
/* public variables*/
f32 Text_fX, Text_fY;
u32 Text_nAttr;
u32 Text_nStyle;
f32 Text_fScale=1.0f;
/* Table Data*/
char Text_aHexChar[16] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F'
};
/*==================*/
/* private variables*/
static u16 _nNumLetters;
static TextLetter_t _pBuffer[TEXT_MAX_LETTERS];
static char _aCharBuffer[STRING_MAX_LENGTH + 1];
static FontMap_t *_pWidthTable;
static FontHdr_t *_pHdr;
static char _str[STRING_MAX_LENGTH + 1];
#if TARGET==ULTRA64
static N64FontScale * _N64ScaleTable;
#endif /*ULTRA64 */
static GrVertex _A, _B, _C, _D;
static GrColor_t _ConstantColor;
/* These MUST be set before font rountines are used*/
static u8 _nCurFont=0; /* The current font to use*/
static u8 _nWidth;
static u8 _nHeight;
static u8 _nSpacing;
static u32 _nYSpacing;
static f32 _fHeight;
static f32 _fSpacing;
/**/
/* Logical Character ASCII lookup table*/
/* Starts with ascii char 32 (space)*/
/* a 50 prints a space*/
/**/
static
init3dfx.c
Found at 1x1915878.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* init3dfx.c - Initialization and shutdown functions for the 3Dfx chipset and Glide.*/
/**/
/* Author: Steve Ranck*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 01-17-97 Ranck Created.*/
/* 09-22-97 Starich Ported to glide 2.42 - to see changes search for STARICH:*/
/* 04/21/98 Ranck Added a call to grSstWinClose() from within init3dfx_Shutdown().*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "gfxdefs.h"
#include "init3dfx.h"
#include "material.h"
#include "glide.h"
#include "xclib.h"
#include "xmath.h"
enum INIT3DFX_CHIPSET Init3dfx_nChipsetCode; /* See INIT3DFX_CHIPSET_* for info*/
enum INIT3DFX_RES Init3dfx_nResCode; /* Monitor resolution mode*/
enum INIT3DFX_MONITOR_TYPE Init3dfx_nMonitorType; /* Monitor type code*/
int Init3dfx_nHorizontalPixels; /* Pixels across screen*/
int Init3dfx_nVerticalPixels; /* Pixels up screen*/
int Init3dfx_nBitsPerPixel; /* Bits per pixel in frame buffer*/
u32 Init3dfx_nFBIRev; /* 3Dfx FBI revision*/
u32 Init3dfx_nFBIMemBytes; /* FBI memory size in bytes*/
u32 Init3dfx_nTMUCount; /* Number of TMUs actually connected*/
u32 Init3dfx_anTMURev[INIT3DFX_MAX_TMUS]; /* 3Dfx TMU revision*/
u32 Init3dfx_anTMUMemBytes[INIT3DFX_MAX_TMUS]; /* Texture memory size in bytes*/
/* These are aligned on a TMU-compatible boundary:*/
u32 Init3dfx_anTMUMinAddress[INIT3DFX_MAX_TMUS]; /* Minimum start address in texture mem*/
u32 Init3dfx_anTMUMaxAddress[INIT3DFX_MAX_TMUS]; /* Maximum start address in texture mem*/
static BOOL _bDoGlideShutdown;
/* Voodoo1 video timing struct:*/
typedef struct {
FxU32 hSyncOn;
FxU32 hSyncOff;
FxU32 vSyncOn;
FxU32 vSyncOff;
FxU32 hBackPorch;
FxU32 vBackPorch;
FxU32 xDimension;
FxU32 yDimension;
FxU32 memOffset;
FxU32 memFifoEntries_1MB;
FxU32 memFifoEntries_2MB;
FxU32 memFifoEntries_4MB;
FxU32 tilesInX_Over2;
FxU32 vFifoThreshold;
FxBool video16BPPIsOK;
FxBool video24BPPIsOK;
float clkFreq16bpp;
float clkFreq24bpp;
} sst1VideoTimingStruct_Voodoo1;
/* 512x400 NTSC (coinop) settings (new settings that don't hang 3Dfx)...*/
sst1VideoTimingStruct_Voodoo1 CoinopVidTiming512x400_Voodoo1 = {
23, /* Hsync On */
640, /* Hsync Off */
3, /* Vsync On */
430, /* Vsync Off */
111, /* hBackPorch */
27, /* vBackPorch */
512, /* Horizontal Resolution */
400, /* Vertical Resolution */
100, /* Memory Offset */
0x0, /* memFifoEntries_1MB ... 32256 entries in memory fifo (no Z)*/
0x100, /* memFifoEntries_2MB ... 57344 entries in memory fifo*/
0x100, /* memFifoEntries_4MB ... 57344 entries in memory fifo*/
8, /* tilesInX_Over2*/
23, /* vFifoThreshold*/
FXTRUE, /* video16BPPIsOK*/
FXTRUE, /* video24BPPIsOK*/
16.55f, /* 16bpp clock timing */
33.11f /* 24bpp clock timing */
};
/* Voodoo2 video timing struct:*/
typedef struct {
FxU32 hSyncOn;
FxU32 hSyncOff;
FxU32 vSyncOn;
FxU32 vSyncOff;
FxU32 hBackPorch;
FxU32 vBackPorch;
FxU32 xDimension;
FxU32 yDimension;
FxU32 refreshRate;
FxU32 miscCtrl;
FxU32 memOffset;
FxU32 tilesInX;
FxU32 vFifoThreshold;
FxBool video16BPPIsOK;
FxBool video24BPPIsOK;
float clkFreq16bpp;
float clkFreq24bpp;
} sst1VideoTimingStruct_Voodoo2;
/* 512x400 NTSC (coinop) settings (new settings that don't hang 3Dfx)...*/
sst1VideoTimingStruct_Voodoo2 CoinopVidTiming512x400_Voodoo2 = {
23, /* Hsync On*/
640, /* Hsync Off*/
3, /* Vsync On*/
430, /* Vsync Off*/
111, /* hBackPorch*/
27, /* vBackPorch*/
512, /* Horizontal Resolution*/
400, /* Vertical Resolution*/
60, /* Refresh Rate*/
0, /* Misc. Control*/
104, /* Memory Offset*/
16, /* tilesInX_Over2*/
25, /* vFifoThreshold*/
FXFALSE, /* video16BPPIsOK*/
FXTRUE, /* video24BPPIsOK*/
16.55f, /* 16bpp clock timing*/
33.11f /* 24bpp clock timing*/
};
FX_ENTRY void FX_CALL grSstVidMode( FxU32 whichSst, void *vidTimings );
static void _SetStateToShutdown( void );
typedef struct {
GrScreenResolution_t GrScreenRes;
BOOL bUseVidTimingStruct;
int nHorizontalPixels;
int nVerticalPixels;
int nBitsPerPixel;
enum INIT3DFX_MONITOR_TYPE nMonitorType;
} Init3dfxResInfo_t;
static const Init3dfxResInfo_t _aInit3dfxResInfo[INIT3DFX_RES_COUNT] = {
GR_RESOLUTION_512x384, FALSE, 512, 384, 16, INIT3DFX_MONITOR_TYPE_PC,
GR_RESOLUTION_512x384, TRUE, 512, 400, 16, INIT3DFX_MONITOR_TYPE_COINOP,
GR_RESOLUTION_640x480, FALSE, 640, 480, 16, INIT3DFX_MONITOR_TYPE_PC,
GR_RESOLUTION_800x600, FALSE, 800, 600, 16, INIT3DFX_MONITOR_TYPE_PC,
};
void init3dfx_ModuleInit( void ) {
Init3dfx_nChipsetCode = INIT3DFX_CHIPSET_UNKNOWN;
_SetStateToShutdown();
}
/* For the parameters that are non-NULL, fills in the appropriate information*/
/* about the specified resolution (nResCode).*/
/**/
/* Possible return values:*/
/* INIT3DFX_RETCODE_OK*/
/* INIT3DFX_RETCODE_INVALID_RESCODE*/
BOOL init3dfx_GetResInfo( enum INIT3DFX_RES nResCode,
int *pnHorizontalPixels, int *pnVerticalPixels, int *pnBitsPerPixel,
enum INIT3DFX_MONITOR_TYPE *pnMonitorType ) {
if( nResCode<0 || nResCode>=INIT3DFX_RES_COUNT ) {
/* Invalid resolution code specified...*/
return FALSE;
}
if( pnHorizontalPixels ) *pnHorizontalPixels = _aInit3dfxResInfo[nResCode].nHorizontalPixels;
if( pnVerticalPixels ) *pnVerticalPixels = _aInit3dfxResInfo[nResCode].nVerticalPixels;
if( pnBitsPerPixel ) *pnBitsPerPixel = _aInit3dfxResInfo[nResCode].nBitsPerPixel;
if( pnMonitorType ) *pnMonitorType = _aInit3dfxResInfo[nResCode].nMonitorType;
/* Success!*/
return TRUE;
}
/* nResCode indicates the monitor resolution mode.*/
/* pFxConfig may be NULL, in which case an internal structure is used.*/
/**/
/* The following variables are set up:*/
/* Init3dfx_nResCode*/
/* Init3dfx_nMonitorType*/
/* Init3dfx_nHorizontalPixels*/
/* Init3dfx_nVerticalPixels*/
/* Init3dfx_nBitsPerPixel*/
/* Init3dfx_nFBIMemBytes*/
/* Init3dfx_nFBIRev*/
/* Init3dfx_nTMUCount*/
/* Init3dfx_anTMUMemBytes*/
/* Init3dfx_anTMURev*/
/* Init3dfx_anTMUMinAddress*/
/* Init3dfx_anTMUMaxAddress*/
/**/
/* Possible return values:*/
/* INIT3DFX_RETCODE_OK*/
/* INIT3DFX_RETCODE_SSTQUERY_FAILED*/
/* INIT3DFX_RETCODE_SSTOPEN_FAILED*/
/* INIT3DFX_RETCODE_NO3DFX*/
/* INIT3DFX_RETCODE_UNSUPPORTED_3DFX_TYPE*/
/* INIT3DFX_RETCODE_UNSUPPORTED_FBI_REV*/
/* INIT3DFX_RETCODE_INVALID_RESCODE*/
/* INIT3DFX_RETCODE_UNSUPPORTED_3DFX_RES*/
/**/
/* NOTE: Even if an error is returned, init3dfx_Shutdown() must be called to*/
/* release possibly-allocated resources.*/
int init3dfx_Init( enum INIT3DFX_RES nResCode, GrHwConfiguration *pFxConfig ) {
GrHwConfiguration *pConfig, FxConfig;
u32 nFrameBufferBitsRequired, nFrameBits;
u32 i;
/* Shut down Glide if it requires so...*/
init3dfx_Shutdown();
if( nResCode == INIT3DFX_RES_UNKNOWN ) {
return INIT3DFX_RETCODE_OK;
}
if( nResCode<0 || nResCode>=INIT3DFX_RES_COUNT ) {
return INIT3DFX_RETCODE_INVALID_RESCODE;
}
/* If the caller specified a GrHwConfiguration structure, use it.*/
/* Otherwise, use our own private structure...*/
pConfig = pFxConfig ? pFxConfig : &FxConfig;
#ifdef GLIDE_211
/* Init glide with proper video settings...*/
if( _aInit3dfxResInfo[nResCode].bUseVidTimingStruct ) {
/* Glide 2.11 doesn't support Voodoo2,*/
/* So use Voodoo1 timing structure...*/
grSstVidMode( 0, &CoinopVidTiming512x400_Voodoo1 );
} else {
grSstVidMode( 0, NULL );
}
/* Initialize 3Dfx...*/
grGlideInit();
if( !grSstQueryHardware( pConfig ) ) {
return INIT3DFX_RETCODE_SSTQUERY_FAILED;
}
Init3dfx_nChipsetCode = INIT3DFX_CHIPSET_VOODOO1;
grSstSelect( 0 );
/* STARICH: CHANGED IN PORT TO GLIDE 2.42!*/
if( !grSstOpen( _aInit3dfxResInfo[nResCode].GrScreenRes,
GR_REFRESH_60Hz,
GR_COLORFORMAT_ARGB,
GR_ORIGIN_LOWER_LEFT,
GR_SMOOTHING_ENABLE,
2 ) ) {
#else /* this is the newest version of glide*/
/* Initialize 3Dfx...*/
grGlideInit();
if( !grSstQueryHardware( pConfig ) ) {
return INIT3DFX_RETCODE_SSTQUERY_FAILED;
}
/* Init glide with proper video settings...*/
if( _aInit3dfxResInfo[nResCode].bUseVidTimingStruct ) {
if( pConfig->SSTs[0].sstBoard.VoodooConfig.fbiRev >= 0x100 ) {
/* Voodoo2...*/
grSstVidMode( 0, &CoinopVidTiming512x400_Voodoo2 );
} else {
/* Voodoo1...*/
grSstVidMode( 0, &CoinopVidTiming512x400_Voodoo1 );
}
} else {
grSstVidMode( 0, NULL );
}
/* Determine if we're running on a Voodoo1 or a Voodoo2...*/
if( pConfig->SSTs[0].sstBoard.VoodooConfig.fbiRev >= 0x100 ) {
/* Voodoo2...*/
Init3dfx_nChipsetCode = INIT3DFX_CHIPSET_VOODOO2;
} else {
/* Voodoo1...*/
Init3dfx_nChipsetCode = INIT3DFX_CHIPSET_VOODOO1;
}
grSstSelect( 0 );
if ( !grSstWinOpen( 0,
_aInit3dfxResInfo[nResCode].GrScreenRes,
GR_REFRESH_60Hz,
GR_COLORFORMAT_ARGB,
GR_ORIGIN_LOWER_LEFT,
2,
1 ) ) {
#endif
return INIT3DFX_RETCODE_SSTOPEN_FAILED;
}
/* Since we made it to this point, we must remember to shut down Glide...*/
_bDoGlideShutdown = TRUE;
/* Verify the base engine requirements are met by the hardware...*/
if( pConfig->num_sst == 0 ) {
return INIT3DFX_RETCODE_NO3DFX;
}
if( pConfig->SSTs[0].type != GR_SSTTYPE_VOODOO ) {
return INIT3DFX_RETCODE_UNSUPPORTED_3DFX_TYPE;
}
if( pConfig->SSTs[0].sstBoard.VoodooConfig.fbiRev < 2 ) {
return INIT3DFX_RETCODE_UNSUPPORTED_FBI_REV;
}
/* Check frame buffer memory requirements...*/
nFrameBufferBitsRequired = _aInit3dfxResInfo[nResCode].nHorizontalPixels
* _aInit3dfxResInfo[nResCode].nVerticalPixels
* _aInit3dfxResInfo[nResCode].nBitsPerPixel
* 3; /* 2 frame buffers and 1 depth buffer*/
nFrameBits = pConfig->SSTs[0].sstBoard.VoodooConfig.fbRam * 1024 * 1024 * 8;
if( nFrameBufferBitsRequired > nFrameBits ) {
/* Not enough memory...*/
return INIT3DFX_RETCODE_UNSUPPORTED_3DFX_RES;
}
/* The base 3dfx hardware is in place.*/
Init3dfx_nResCode = nResCode;
Init3dfx_nMonitorType = _aInit3dfxResInfo[nResCode].nMonitorType;
Init3dfx_nHorizontalPixels = _aInit3dfxResInfo[nResCode].nHorizontalPixels;
Init3dfx_nVerticalPixels = _aInit3dfxResInfo[nResCode].nVerticalPixels;
Init3dfx_nBitsPerPixel = _aInit3dfxResInfo[nResCode].nBitsPerPixel;
Init3dfx_nFBIMemBytes = pConfig->SSTs[0].sstBoard.VoodooConfig.fbRam * 1024 * 1024;
Init3dfx_nFBIRev = pConfig->SSTs[0].sstBoard.VoodooConfig.fbiRev;
Init3dfx_nTMUCount = pConfig->SSTs[0].sstBoard.VoodooConfig.nTexelfx;
for( i=0; i<Init3dfx_nTMUCount; i++ ) {
Init3dfx_anTMUMemBytes[i] = pConfig->SSTs[0].sstBoard.VoodooConfig.tmuConfig[i].tmuRam * 1024 * 1024;
Init3dfx_anTMURev[i] = pConfig->SSTs[0].sstBoard.VoodooConfig.tmuConfig[i].tmuRev;
Init3dfx_anTMUMinAddress[i] = XMATH_BYTE_ALIGN_UP( grTexMinAddress( i ), INIT3DFX_TMU_MEM_BYTE_ALIGNMENT );
Init3dfx_anTMUMaxAddress[i] = XMATH_BYTE_ALIGN_DOWN( grTexMaxAddress( i ), INIT3DFX_TMU_MEM_BYTE_ALIGNMENT );
}
for( i=Init3dfx_nTMUCount; i<INIT3DFX_MAX_TMUS; i++ ) {
Init3dfx_anTMUMemBytes[i] = 0;
Init3dfx_anTMURev[i] = 0;
Init3dfx_anTMUMinAddress[i] = 0;
Init3dfx_anTMUMaxAddress[i] = 0;
}
/* Call modules who need to be informed that the glide state has changed...*/
gfxdefs_SetDefaults();
material_ModuleInit();
/* Success!*/
return INIT3DFX_RETCODE_OK;
}
void init3dfx_Shutdown( void ) {
/* Shut down Glide only if we need to...*/
if( _bDoGlideShutdown ) {
grSstWinClose();
grGlideShutdown();
_SetStateToShutdown();
}
}
static void _SetStateToShutdown( void ) {
int i;
_bDoGlideShutdown = FALSE;
Init3dfx_nResCode = INIT3DFX_RES_UNKNOWN;
Init3dfx_nTMUCount = 0;
Init3dfx_nFBIMemBytes = 0;
Init3dfx_nFBIRev = 0;
for( i=0; i<INIT3DFX_MAX_TMUS; i++ ) {
Init3dfx_anTMUMemBytes[i] = 0;
Init3dfx_anTMURev[i] = 0;
Init3dfx_anTMUMinAddress[i] = 0;
Init3dfx_anTMUMaxAddress[i] = 0;
}
}
hud_radar.c
Found at 1x19F2800.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* hud_radar.c - */
/**/
/* Author: Michael Starich */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1998*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 06/02/98 Starich Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "hud_radar.h"
#include "vec2.h"
#include "vec3.h"
#include "tracks.h"
#include "player.h"
#include "mesh3d.h"
#include "gutil.h"
#include "xclib.h"
#include "gameheap.h"
#include "obsys.h"
#include "material.h"
#include "glcount.h"
#include "ai_craft.h"
#if TARGET==ULTRA64 /*Put HUD objects into array so can group together for speedier draw*/
#include "hud.h"
extern void AddHudN64Obj_DrawOrtho(int DrawOrthoID, Mesh3d_t *pMesh, float fScreenX, float fScreenY, float fScreenZ, int nRoll, float fScale);
extern void AddHudN64Obj_DrawOrtho2(int DrawOrthoID, Mesh3d_t *pMesh, float fScreenX, float fScreenY, float fScreenZ, int nRoll, float fScale, int XOffset,int YOffset,int MaterialID,u32 nFlags);
extern void AddHudN64Obj_DrawRotatedSprite(int DrawOrthoID, u8 *Sprite,u16 *Palette,int SprWidth,int SprHeight,s32 x, s32 y,int DrawLeft,int DrawTop,int DrawRight,int DrawBottom,u32 Angle,int Transparency);
#endif /*ULTRA64*/
/*///////////////////////////////////////////////////////////*/
/* NOTES:*/
/* tga origin is upper left corner*/
/* tile origin is lower left corner*/
/* screen origin is lower left corner, center for ortho draws*/
/* the scale factor is 1022 pixels is 24000 ft in world space*/
/*///////////////////////////////////////////////////////////*/
/*====================*/
/* private definitions*/
#define RADAR_TILE_BIT 5
#define RADAR_TILE_SIZE ( 1 << RADAR_TILE_BIT )
#define RADAR_TILE_MASK ( RADAR_TILE_SIZE - 1 )
#define DX( x ) (x & RADAR_TILE_MASK)
#define TX( x ) ( ( x & (~RADAR_TILE_MASK) ) >> RADAR_TILE_BIT )
#define RADAR_PALETTE_SIZE 256
#if TARGET == DREAMCAST
#define RADAR_WIDTH 128
#define RADAR_HEIGHT 128
#else // DREAMCAST
#define RADAR_WIDTH 128
#define RADAR_HEIGHT 128
#endif // DREAMCAST
#define RADAR_HALF_WIDTH ( RADAR_WIDTH/2 )
#define RADAR_HALF_HEIGHT ( RADAR_HEIGHT/2 )
#define RADAR_DY -10 /* make sure that this number is less than RADAR_HALF_HEIGHT*/
#define RADAR_LEFT_OFFSET ( -RADAR_HALF_WIDTH )
#define RADAR_RIGHT_OFFSET ( RADAR_HALF_WIDTH )
#define RADAR_TOP_OFFSET ( RADAR_HALF_HEIGHT )
#define RADAR_BOTTOM_OFFSET ( -RADAR_HALF_HEIGHT )
#define RADAR_BOX_Y 0 /* how much do we move the top of the box down (must be positive)*/
#define RADAR_BOX_X 0 /* how much do we move the right edge to the left (must be negative)*/
#define BOX_WIDTH ( RADAR_WIDTH + RADAR_BOX_X )
#define BOX_HEIGHT ( RADAR_HEIGHT - RADAR_BOX_Y )
#define MEM_DEST_START ( 2 * (RADAR_WIDTH * RADAR_BOX_Y) ) /* multiply these by 2 (16 bit mask)*/
#define MEM_LINE_OFFSET ( 2 * (RADAR_WIDTH - BOX_WIDTH ) )
#define NUM_TILES_ACROSS ( ( BOX_WIDTH/RADAR_TILE_SIZE ) + 1 )
#define NUM_TILES_DOWN ( ( BOX_HEIGHT/RADAR_TILE_SIZE ) + 1 )
#define RADAR_SCREEN_RADIUS ( (f32)RADAR_HALF_WIDTH )
#define RADAR_PIXEL_RADIUS2 ( RADAR_SCREEN_RADIUS * RADAR_SCREEN_RADIUS )
#define _RADAR_NAME_TEMPLATE "R.WRADA_A90"
#define _RADAR_CHAR_INDEX_TRACK 1
#define _SCALE 1.0f
#define Z_DEPTH 1.0f
#if TARGET==DREAMCAST
#define ARGB32TORGB555(a)( ((a & 0xff0000) >> (16+3)) << 10 | ((a & 0xff00) >> (8+3)) << 5 | ((a & 0xff) >> 3) )
#endif // DREAMCAST
typedef struct
{
u8 nPixels[RADAR_TILE_SIZE][RADAR_TILE_SIZE];
} Tile_t;
typedef struct
{
int nTileOffset;
} TileInfo_t;
typedef struct
{
u32 nEntries[RADAR_PALETTE_SIZE];
} Palette_t;
typedef struct
{
u32 nNumTiles;
u32 nNumAcross;
u32 nNumDown;
} TileHeader_t;
typedef struct
{
u8 *pHd;
u16 nWidth;
u16 nHeight;
} TileCutInfo_t;
#define _SIZE0F_TILE ( sizeof( Tile_t ) )
#define _SIZEOF_TILEINFO ( sizeof( TileInfo_t ) )
#define _SIZEOF_PALETTE ( sizeof( Palette_t ) )
#define _SIZEOF_TILEHEADER ( sizeof( TileHeader_t ) )
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
static const Vec2_t _MapStarting = { 193.0f, 135.0f }; /* origin at the center of the screen*/
static const Vec2_t _RadarXYLookup[4] = {
(f32)RADAR_LEFT_OFFSET, (f32)RADAR_BOTTOM_OFFSET,
(f32)RADAR_LEFT_OFFSET, (f32)RADAR_TOP_OFFSET,
(f32)RADAR_RIGHT_OFFSET, (f32)RADAR_TOP_OFFSET,
(f32)RADAR_RIGHT_OFFSET, (f32)RADAR_BOTTOM_OFFSET,
};
static const Vec2_t _RadarSTLookup[4] = {
0.0f, 0.0f,
0.0f, 256.0f,
256.0f, 256.0f,
256.0f, 0.0f,
};
const static f32 _afVtxIntensity[4] = {
100.0f, 0.0f, 50.0f, 255.0f,
};
static const Vec2_t _RadarStartingOffset[TRACKS_COUNT] = /* these put the origin of the world at the starting */
{ /* line on the map */
327.0f, 1282.0f,/* SHIPGRAVEYARD */
304.0f, 1406.0f,/* AMAZON*/
143.0f, 565.0f, /* VENICE*/
223.0f, 1004.0f,/* LAKEPOWELL*/
258.0f, 574.0f, /* ARTIC*/
30.0f, 2384.0f,/* NILE*/
206.0f, 1491.0f,/* NY*/
424.0f, 824.0f, /* GREECE*/
1551.0f,746.0f, /* CHINA*/
0.0f, 0.0f, /* TEST*/
332.0f, 150.0f, /* LOOP1*/
234.0f, 116.0f, /* LOOP2*/
0.0f, 0.0f, /* LOOP3*/
};
const static f32 _nStaticStepLookup[3] = {
0.33f, 0.5f, 0.85f
};
static Tile_t *_pTileHd;
static TileInfo_t *_pTileInfoHd;
static Palette_t *_pTilePalette;
static TileHeader_t *_pTileHeader;
static u16 *_pMask;
static TexDef_t *_pRadarTMem;
static GrVertex _aRadarVtx[4], _aStaticVtx[4];
static TileCutInfo_t _aCutInfo[NUM_TILES_DOWN][NUM_TILES_ACROSS];
static int _nRadarImageW, _nRadarImageH;
static u32 _nMemStartOffSet, _nMemNextLineOffSet;
/* screen positions*/
static Vec2_t _MapCenterPt;
static Vec2_t _DrawSpace;
/* meshes*/
static Mesh3d_t *_pBoatIcon;
static Mesh3d_t *_pRadarFrame;
/* static vars*/
static TexDef_t *_pStaticTexture;
static int _nStaticRollAngle;
static f32 _fRadarStaticIntensity;
static int _nAnimatingStaticState;
static int _nPrevStaticState;
static f32 _fPrevStaticIntensity;
static f32 _fStaticDelta;
static u32 _nFlickerCount;
static f32 _fStaticStepSize;
static f32 _fRadarStaticGoal;
/* load vars*/
static BOOL _bRadarOk = FALSE;
/*===================*/
/* private prototypes*/
static void _BuildRadarTextureInfo( u32 *npRows, u32 *npCols );
static void _DrawRadarStatic( f32 fX, f32 fY, f32 fIntensity );
static void _PutMeshOnRadarMap( Vec3_t *pWPos, u32 nHeading, Mesh3d_t *pMesh, u32 nColorKey, u32 nAngle, f32 fOpaqueness );
static void _World2Pixel( Vec2_t *pDest, f32 fX, f32 fZ );
static void _Pixel2World( Vec2_t *pDest, f32 fX, f32 fZ );
/*=================*/
/* public functions*/
void hud_radar_Load( void ) {
u32 i, nHeapSizeBefore, nHeapSizeAfter;
char szName[OBJECT_NAME_LENGTH+1];
#if TARGET==DREAMCAST
char *pTexMem;
u16 *p16;
DCTEXTUREHEADER *pTexHeader;
#endif // DREAMCAST
_bRadarOk = FALSE;
_pTileHd = NULL;
_pTileInfoHd = NULL;
_pTilePalette = NULL;
_pTileHeader = NULL;
_pMask = NULL;
_pRadarTMem = NULL;
#if TARGET==ULTRA64 /*Just load and draw Radar frame...*/
_pRadarFrame = (Mesh3d_t *)obsys_Load( "GHWRADAFRH0" );
_DrawSpace.p[0] = _MapStarting.p[0];
_DrawSpace.p[1] = _MapStarting.p[1];
_bRadarOk = TRUE;
#endif /*ULTRA64*/
for( i = 0; i < 4; i++ ) {
/* set the grVertex array used by the radar, go ahead and set s and t for both tmus, */
/* so that either way we are covered*/
_aRadarVtx[i].z = _aRadarVtx[i].r = _aRadarVtx[i].g = _aRadarVtx[i].b = _aRadarVtx[i].a = 0.0f;
_aRadarVtx[i].ooz = _aRadarVtx[i].oow = GUTIL_OOW_MAX;
_aRadarVtx[i].tmuvtx[0].sow = _aRadarVtx[i].tmuvtx[1].sow = _RadarSTLookup[i].p[0];
_aRadarVtx[i].tmuvtx[0].tow = _aRadarVtx[i].tmuvtx[1].tow = _RadarSTLookup[i].p[1];
/* set the grVertex array used by the static, go ahead and set s and t for both tmus, */
/* so that either way we are covered*/
_aStaticVtx[i].z = _aStaticVtx[i].r = _aStaticVtx[i].g = _aStaticVtx[i].b = _aStaticVtx[i].a = 0.0f;
_aStaticVtx[i].ooz = _aStaticVtx[i].oow = GUTIL_OOW_MAX;
_aStaticVtx[i].tmuvtx[0].sow = _aStaticVtx[i].tmuvtx[1].sow = _RadarSTLookup[i].p[0];
_aStaticVtx[i].tmuvtx[0].tow = _aStaticVtx[i].tmuvtx[1].tow = _RadarSTLookup[i].p[1];
}
/* load the radar map files (also the mask and allocate texture space also)*/
xclib_strcpy( szName, _RADAR_NAME_TEMPLATE );
szName[_RADAR_CHAR_INDEX_TRACK] = Tracks_Info[Tracks_nCurrentTrack].cTexChar;
nHeapSizeBefore = gameheap_GetSize();
#if TARGET==ULTRA64
szName[0] = '_'; // Radar name is '_xxxxxxxxx' as binary file!
_pTileHeader = (TileHeader_t *)obsys_Load( szName );
if( _pTileHeader == NULL ) {
return;
}
nHeapSizeAfter = gameheap_GetSize();
xprintf( "Loaded radar map '%s' of size: %i bytes.\n", szName, nHeapSizeBefore - nHeapSizeAfter );
#else /*ULTRA64*/
_pTileHeader = (TileHeader_t *)obsys_Load( szName );
if( _pTileHeader == NULL ) {
return;
}
nHeapSizeAfter = gameheap_GetSize();
xprintf( "Loaded radar map '%s' of size: %i bytes.\n", szName, nHeapSizeBefore - nHeapSizeAfter );
_pTilePalette = (Palette_t *)( (u32)_pTileHeader + _SIZEOF_TILEHEADER );
_pTileInfoHd = (TileInfo_t *)( (u32)_pTilePalette + _SIZEOF_PALETTE );
_pTileHd = (Tile_t *)( (u32)_pTileInfoHd + (_pTileHeader->nNumTiles * _SIZEOF_TILEINFO) );
_nRadarImageW = _pTileHeader->nNumAcross * RADAR_TILE_SIZE;
_nRadarImageH = _pTileHeader->nNumDown * RADAR_TILE_SIZE;
_pMask = (u16 *)obsys_LoadTextureIntoSysmem ("THWHUD_MP60", NULL, NULL);
if( _pMask == NULL ) {
return;
}
#if TARGET==DREAMCAST
// Make a 64x64 empty 1555 texture
pTexMem = syMalloc((128*128*2) + 16);
memset(pTexMem, 0xff, (128*128*2) + 16);
DCASSERT(pTexMem != NULL, "syMalloc");
pTexHeader = (DCTEXTUREHEADER*)pTexMem;
pTexHeader->Width = 128;
pTexHeader->Height = 128;
pTexHeader->Id = 'PVRT';
pTexHeader->DataSize = (128*128*2)+8;
pTexHeader->Type = KM_TEXTURE_RECTANGLE | KM_TEXTURE_ARGB1555;
_pRadarTMem = tmem_LoadTexture( "***********", 128, 128, GR_TEXFMT_AP_88, pTexMem, -1, 0);
if( _pRadarTMem == NULL ) {
return;
}
syFree(pTexMem);
// Convert argb 32 bit palette to a 555 format
p16 = (u16*)_pTilePalette->nEntries;
for(i = 0; i < 256; i++){
*p16++ = ARGB32TORGB555(_pTilePalette->nEntries[i]);
}
#else // DREAMCAST
_pRadarTMem = tmem_LoadTexture( "***********", 128, 128, GR_TEXFMT_AP_88, NULL, -1, _pTilePalette->nEntries );
if( _pRadarTMem == NULL ) {
return;
}
#endif // DREAMCAST
#endif /*ULTRA64*/
_DrawSpace.p[0] = _MapStarting.p[0];
_DrawSpace.p[1] = _MapStarting.p[1];
/* load the radar static texture*/
_pStaticTexture = (TexDef_t *)obsys_Load ("THWHUD_SA50");
if( _pStaticTexture == NULL ) {
return;
}
_fRadarStaticIntensity = 0.0f;
_nStaticRollAngle = 0;
_nAnimatingStaticState = _nPrevStaticState = 0;
_fStaticStepSize = 0.0f;
_fRadarStaticGoal = 0.0f;
_fPrevStaticIntensity = 0.0f;
_nFlickerCount = 0;
_fStaticDelta = 0.0f;
/* load the little boat icon mesh*/
_pBoatIcon = (Mesh3d_t *)obsys_Load( "GHWRADAPLH0" );
if( _pBoatIcon == NULL ) {
return;
}
_pRadarFrame = (Mesh3d_t *)obsys_Load( "GHWRADAFRH0" );
if( _pRadarFrame == NULL ) {
return;
}
_bRadarOk = TRUE;
}
/* TRIPWIRE FUNCTION:*/
/* call this function everytime our boat trips the static adjust tripwire*/
/* forward causes + action, reverse causes - action.*/
/* nStepSize */
/* 0 = +- .33*/
/* 1 = +- .50*/
/* 2 = +- 0.85*/
void hud_radar_TW_AdjustStatic1( WorldOb_t *pWorldOb, u32 nStepSize, BOOL bForward ) {
if( !_bRadarOk ) {
return;
}
if( bForward ) {
if( _fRadarStaticIntensity == 1.0f ) {
return;
}
_fRadarStaticGoal = _fRadarStaticIntensity + _nStaticStepLookup[nStepSize];
if( _fRadarStaticGoal > 1.0f ) {
_fRadarStaticGoal = 1.0f;
}
_nAnimatingStaticState = 1;
_fStaticStepSize = (_fRadarStaticGoal - _fRadarStaticIntensity)*(1.0f/60.0f);
} else {
if( _fRadarStaticIntensity == 0.0f ) {
return;
}
_fRadarStaticGoal = _fRadarStaticIntensity - _nStaticStepLookup[nStepSize];
if( _fRadarStaticGoal < 0.0f ) {
_fRadarStaticGoal = 0.0f;
}
_nAnimatingStaticState = -1;
_fStaticStepSize = (_fRadarStaticIntensity - _fRadarStaticGoal)*(-1.0f/600.0f);
}
}
/* TRIPWIRE FUNCTION:*/
/* call this function everytime our boat trips the static adjust tripwire*/
/* reverse causes + action, forward causes - action.*/
/* nStepSize */
/* 0 = +- .33*/
/* 1 = +- .50*/
/* 2 = +- 0.85*/
void hud_radar_TW_AdjustStatic2( WorldOb_t *pWorldOb, u32 nStepSize, BOOL bForward ) {
if( !_bRadarOk ) {
return;
}
if( bForward ) {
if( _fRadarStaticIntensity == 0.0f ) {
return;
}
_fRadarStaticGoal = _fRadarStaticIntensity - _nStaticStepLookup[nStepSize];
if( _fRadarStaticGoal < 0.0f ) {
_fRadarStaticGoal = 0.0f;
}
_nAnimatingStaticState = -1;
_fStaticStepSize = (_fRadarStaticIntensity - _fRadarStaticGoal)*(-1.0f/60.0f);
} else {
if( _fRadarStaticIntensity == 1.0f ) {
return;
}
_fRadarStaticGoal = _fRadarStaticIntensity + _nStaticStepLookup[nStepSize];
if( _fRadarStaticGoal > 1.0f ) {
_fRadarStaticGoal = 1.0f;
}
_nAnimatingStaticState = 1;
_fStaticStepSize = (_fRadarStaticGoal - _fRadarStaticIntensity)*(1.0f/60.0f);
}
}
void hud_radar_TW_FlickerStatic( WorldOb_t *pWorldOb, u32 nStepSize, BOOL bForward ) {
if( !_bRadarOk ) {
return;
}
/* make sure that we are not already in the flicker state*/
if( _nAnimatingStaticState != 69 ) {
_nPrevStaticState = _nAnimatingStaticState;
_fPrevStaticIntensity = _fRadarStaticIntensity;
_nAnimatingStaticState = 69;
}
_nFlickerCount = 0;
_fStaticDelta = 1.0f - _fRadarStaticIntensity;
_fStaticDelta *= 0.69f;
}
void hud_radar_Work( f32 fDx, f32 fDy ) {
if( !_bRadarOk ) {
return;
}
/*////////////////////////////////////////////////*/
/* if we are animating the static level, do it now*/
/*////////////////////////////////////////////////*/
switch( _nAnimatingStaticState )
{
case 1:
_fRadarStaticIntensity += _fStaticStepSize;
if( _fRadarStaticIntensity >= _fRadarStaticGoal ) {
_fRadarStaticIntensity = _fRadarStaticGoal;
_nAnimatingStaticState = 0;
}
break;
case 0:
break;
case -1:
_fRadarStaticIntensity += _fStaticStepSize;
if( _fRadarStaticIntensity <= _fRadarStaticGoal ) {
_fRadarStaticIntensity = _fRadarStaticGoal;
_nAnimatingStaticState = 0;
}
break;
case 69:
++_nFlickerCount;
switch( _nFlickerCount )
{
case 1:
case 2:
case 3:
_fRadarStaticIntensity += (_fStaticDelta * 0.33f);
break;
case 10:
case 11:
_fRadarStaticIntensity -= (_fStaticDelta * 0.33f);
break;
case 12:
_nAnimatingStaticState = _nPrevStaticState;
_fRadarStaticIntensity = _fPrevStaticIntensity;
break;
default:
break;
}
break;
default:
break;
}
/* compute the new screen pos of the radar map*/
_DrawSpace.p[0] = GFXDEFS_SNAPVERT( _MapStarting.p[0] + fDx );
_DrawSpace.p[1] = GFXDEFS_SNAPVERT( _MapStarting.p[1] + fDy );
hud_radar_ConstructRadarInfo( 0 );
}
/* nStep = 0, build the radar texture info and copy it to*/
/* a continuous piece of system memory*/
/* nStep = 1, move the texture from sys memory to texture memory*/
/* NOTE: This function must be called before this gameloop's call to*/
/* hud_DrawWithRoll, otherwise we will display last frames radar screen*/
#if TARGET!=DREAMCAST
void hud_radar_ConstructRadarInfo( u32 nStep ) {
u32 nRows, nCols, j, k, m;
s32 i;
u8 *p = (u8 *)_pMask, *pTemp;
#if TARGET!=ULTRA64 /* No hud radar */
if( !_bRadarOk ) {
return;
}
if( nStep == 0 ) {
/* figure out what part of the map we need and fill in our info array*/
_BuildRadarTextureInfo( &nRows, &nCols );
/* copy the needed tiles into our system memory (where ever the mask is located)*/
/* make sure that p is positioned correctly to start off with*/
p += _nMemStartOffSet;
/* tiles down*/
for( i = nRows-1; i >= 0; i-- ) {
/* tile height*/
for( j = 0; j < _aCutInfo[i][0].nHeight; j++ ) {
/* tiles across*/
for( k = 0; k < nCols; k++ ) {
/* this tile is not in our tile set fill with color 0*/
if( _aCutInfo[i][k].pHd == NULL ) {
/* tile width*/
for( m = 0; m < _aCutInfo[i][k].nWidth; m++ ) {
*p = 0;
p += 2;
}
} else {
/* this tile is in our tile set*/
pTemp = _aCutInfo[i][k].pHd + ( RADAR_TILE_SIZE * j);
/* tile width*/
for( m = 0; m < _aCutInfo[i][k].nWidth; m++ ) {
*p = *pTemp;
++pTemp;
p += 2;
}
}
}
/* adjust our pointer to the next line*/
p += _nMemNextLineOffSet;
}
}
} else if( nStep == 1 ) {
/* move the sys memory radar image to texture memory*/
#if TARGET==DREAMCAST
dcLoadTexture(_pRadarTMem->aTMUTexInfo[0].nTmemStartAddress, _pMask);
#else // DREAMCAST
tmem_Replace (_pRadarTMem, _pMask);
#endif // DREAMCAST
}
#endif /*ULTRA64 */
}
#endif
#if TARGET!=ULTRA64 && TARGET!=DREAMCAST/* Re-direct hud radar draw */
/* doesn't restore any material states, simply sets the needed states, same*/
/* for ortho draw states!!!!*/
void hud_radar_Draw( f32 fR, f32 fG, f32 fB, f32 fOpaqueness, f32 fWhiteSat ) {
u32 nAngle, i, nPriorZbufState;
f32 fSin, fCos, fX, fY, fSample1, fSample2, fIntensity;
Vec2_t aRadarPoint[4];
int nIndex1, nIndex2;
Player_t *pPlayer;
if( !_bRadarOk ) {
return;
}
/* make sure that hud_ConstructRadarInfo has been called twice,*/
/* once with 0 passed in, to build the radar in sys memory, and */
/* another time to move the texture to texture memory. This is a */
/* needed to avoid 3dfx problems.*/
material_ColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_LOCAL,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
material_AlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_TEXTURE_ALPHA,
GR_COMBINE_LOCAL_CONSTANT,
GR_COMBINE_OTHER_ITERATED,
FXFALSE );
material_ConstantColorValue( GFXDEFS_FLOATARGB_TO_GRCOLOR( fWhiteSat, 1.0f, 1.0f, 1.0f ) );
/* select the texture and set the tile mode*/
tmem_Select( _pRadarTMem );
tmem_SetTileMode( _pRadarTMem, FALSE, FALSE );
/* finally lets put the radar on the screen and get the hell outta here*/
fX = _DrawSpace.p[0] + 255.0f;
fY = _DrawSpace.p[1] + 200.0f;
nAngle = -Player_aData[Player_nHuman].Phys.nHeading;
fSin = xmath_sin( nAngle );
fCos = xmath_cos( nAngle );
fSample1 = (float)(0x3fff - (nAngle & 0x3fff)) * (1.0f/16383.0f);
fSample2 = (float)(nAngle & 0x3fff) * (1.0f/16384.0f);
/* rotate all of the points in radar pivot space*/
for( i=0; i < 4; i++ ) {
nIndex1 = ((nAngle >> 14)+i) & 0x3;
nIndex2 = (nIndex1 + 1) & 0x3;
vec2_CalcRotationTrig( &aRadarPoint[i], &_RadarXYLookup[i], fSin, fCos );
_aRadarVtx[i].x = GFXDEFS_SNAPVERT( aRadarPoint[i].p[0] + fX );
_aRadarVtx[i].y = GFXDEFS_SNAPVERT( aRadarPoint[i].p[1] + fY );
_aRadarVtx[i].a = fOpaqueness * 255.0f;
fIntensity = _afVtxIntensity[nIndex1]*fSample1 + _afVtxIntensity[nIndex2]*fSample2;
_aRadarVtx[i].r = fIntensity;
_aRadarVtx[i].g = fIntensity;
_aRadarVtx[i].b = fIntensity;
}
#if TARGET==DREAMCAST
i = _pRadarTMem->aTMUTexInfo[0].nTmemStartAddress;
dcSetCurrentVertexContext(&dcTextureTable[i].AlphaBlendedTexVC);
kmxxGetCurrentPtr(&VertexBufferDesc);
kmxxStartVertexStrip(&VertexBufferDesc);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
_aRadarVtx[0].x,
480.0f - _aRadarVtx[0].y,
1.0f,
_aRadarVtx[0].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[0].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
_aRadarVtx[1].x,
480.0f - _aRadarVtx[1].y,
1.0f,
_aRadarVtx[1].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[1].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP,
_aRadarVtx[2].x,
480.0f - _aRadarVtx[2].y,
1.0f,
_aRadarVtx[2].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[2].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
_aRadarVtx[0].x,
480.0f - _aRadarVtx[0].y,
1.0f,
_aRadarVtx[0].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[0].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxSetVertex_3( KM_VERTEXPARAM_NORMAL,
_aRadarVtx[2].x,
480.0f - _aRadarVtx[2].y,
1.0f,
_aRadarVtx[2].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[2].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxSetVertex_3( KM_VERTEXPARAM_ENDOFSTRIP,
_aRadarVtx[3].x,
480.0f - _aRadarVtx[3].y,
1.0f,
_aRadarVtx[3].tmuvtx[0].sow * DCRECIP256,
_aRadarVtx[3].tmuvtx[0].tow * DCRECIP256,
0xffffffff,
0xff000000
);
kmxxReleaseCurrentPtr(&VertexBufferDesc);
#else // DREAMCAST
/* draw the two triangles*/
GUTIL_DRAW_TRIANGLE( &_aRadarVtx[0], &_aRadarVtx[1], &_aRadarVtx[2] );
GUTIL_DRAW_TRIANGLE( &_aRadarVtx[0], &_aRadarVtx[2], &_aRadarVtx[3] );
#endif // DREAMCAST
/* Always draw, but don't update zbuffer...*/
nPriorZbufState = gutil_ZbufferSetState( GUTIL_ZBUFFER_STATE_DISABLE );
/*********************************/
/* draw ai boats on the radar map**/
/*********************************/
for( i=0; i < Player_nTotalCount; i++ ) {
pPlayer = Player_apData[i];
/* don't compare our boat, stupid, what are you an idiot?*/
if( (pPlayer->pWorldOb != NULL) && !(pPlayer->nFlags & PLAYER_FLAG_HUMAN) ) {
/* color ai players color 1*/
_PutMeshOnRadarMap( &pPlayer->pWorldOb->Orient.Pos,
pPlayer->Phys.nHeading,
_pBoatIcon,
2,/* green*/
nAngle,
fOpaqueness );
}
}
/***********************************/
/* draw ai chasers on the radar map**/
/***********************************/
for( i=0; i < AiCraft_nNumChasers; i++ ) {
_PutMeshOnRadarMap( &AiCraft_apChaserPhys[i]->pBoatWorldOb->Orient.Pos,
AiCraft_apChaserPhys[i]->nHeading,
_pBoatIcon,
3,/* blue*/
nAngle,
fOpaqueness );
}
/******************************************/
/* draw other human boats on the radar map**/
/******************************************/
for( i=0; i < Player_nTotalCount; i++ ) {
pPlayer = Player_apData[i];
/* don't compare our boat, stupid, what are you an idiot?*/
if( !(pPlayer->nFlags & PLAYER_FLAG_LOCAL) && (pPlayer->pWorldOb != NULL) ) {
if( pPlayer->nFlags & PLAYER_FLAG_HUMAN ) {
/* flash other human players if they are in mighty hull mode*/
if( !(pPlayer->Phys.nStatusBits & PHYS_STATUSBIT_MIGHTY_HULL) ) {
/* color other human players color 0*/
_PutMeshOnRadarMap( &pPlayer->pWorldOb->Orient.Pos,
pPlayer->Phys.nHeading,
_pBoatIcon,
0,/* red*/
nAngle,
fOpaqueness );
} else {
nIndex1 = ( (Gameloop_nFrameCounter & 0x7) < 0x4 ) ? 0 : 1;
_PutMeshOnRadarMap( &pPlayer->pWorldOb->Orient.Pos,
pPlayer->Phys.nHeading,
_pBoatIcon,
nIndex1,/* red\white flash*/
nAngle,
fOpaqueness );
}
}
}
}
/*****************************/
/* draw our boat on the radar**/
/*****************************/
if( (Gameloop_nFrameCounter >> 3) & 1 ) {
mesh3d_SetOrthoEffects(1.0f, 1.0f, 1.0f, fOpaqueness, 0.0f);
mesh3d_DrawOrtho( _pBoatIcon,
_DrawSpace.p[0],
_DrawSpace.p[1] + RADAR_DY,
Z_DEPTH,
0,/* white*/
_SCALE );
}
gutil_ZbufferSetState( nPriorZbufState );
/************************/
/* draw any radar static**/
/************************/
if( _fRadarStaticIntensity > 0.0f ) {
_DrawRadarStatic( fX, fY, _fRadarStaticIntensity );
}
/***********************/
/* draw the radar frame**/
/***********************/
mesh3d_SetOrthoEffects( fR, fG, fB, fOpaqueness, fWhiteSat );
mesh3d_DrawOrtho( _pRadarFrame,
_DrawSpace.p[0],
_DrawSpace.p[1],
Z_DEPTH,
0,
_SCALE - 0.02f );
}
#endif /*ULTRA64*/
#if TARGET==ULTRA64
#include "u64draw.h"
#include "u64sprite.h"
u64 RadarSection[2][(64*64)/2/sizeof(u64)];
u64 RadarMask[] = { //2048 bytes
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x000000FFFFFFFFFF,0xFFFFFFFFF0000000,0x0000000000000000,
0x0000000000000000,0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFF0000,0x0000000000000000,
0x0000000000000000,0x00FFFFFFFFFFFFFF,0xFFFFFFFFFFFFFF00,0x0000000000000000,
0x0000000000000000,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0x0000000000000000,
0x00000000000000FF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFF00000000000000,
0x000000000000FFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFF0000000000000,
0x000000000000FFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFF000000000000,
0x0000000000FFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFF00000000000,
0x0000000000FFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFF0000000000,
0x00000000FFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFF000000000,
0x00000000FFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFF00000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFF00000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFF0000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFF0000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFF00000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x0000FFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFF000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFF0000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFF0000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFF00000000,
0x000000FFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFF00000000,
0x00000000FFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFF000000000,
0x00000000FFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFF0000000000,
0x0000000000FFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFF00000000000,
0x0000000000FFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFF000000000000,
0x000000000000FFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFF0000000000000,
0x000000000000FFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFF00000000000000,
0x00000000000000FF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xF000000000000000,
0x0000000000000000,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0x0000000000000000,
0x0000000000000000,0x00FFFFFFFFFFFFFF,0xFFFFFFFFFFFFFF00,0x0000000000000000,
0x0000000000000000,0x0000FFFFFFFFFFFF,0xFFFFFFFFFFF00000,0x0000000000000000,
0x0000000000000000,0x00000000FFFFFFFF,0xFFFFFFFF00000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
};
u64 RadarStatic[] = { //2048 bytes
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000211135730,0x0035713510000000,0x0000000000000000,
0x0000000000000000,0x0000656200037780,0x7537246536670000,0x0000000000000000,
0x0000000000000000,0x0063343039515983,0xF525555235652300,0x0000000000000000,
0x0000000000000000,0x637403415B856613,0x8106862011255311,0x0000000000000000,
0x0000000000000074,0x3573048535763101,0x40A7273403355113,0x3200000000000000,
0x0000000000000673,0x2533388714942455,0x6092936833655212,0x3400000000000000,
0x0000000000004753,0x404AA5465398377B,0x3303A23363646512,0x1472000000000000,
0x0000000000075269,0x5145800695653938,0x050D032037514315,0x33A5300000000000,
0x000000000027A515,0x3014021355337A10,0x034A023257754235,0x2025750000000000,
0x000000000335FB10,0x005B1320004A8202,0x35510303D8977754,0x2225547000000000,
0x000000001A839921,0x556756831029B205,0x642830058133A822,0x3355557600000000,
0x0000000535500015,0xDD55BDDA6225A537,0x1F55820580A60266,0x2231378500000000,
0x0000000512740237,0xB525259DB9858A5A,0x28625811614329D7,0x3310576210000000,
0x0000005333530331,0x555A16D9AD825767,0x56D6380520124576,0x2000552040000000,
0x00000015B9213336,0x8B7888863226DA7A,0x2682D91533422346,0x5011114214000000,
0x00000853B8275246,0x3656D86B707A5725,0x53506645D5155204,0x5135253353000000,
0x0000055157794232,0x21369758619B0253,0x4B7011378612A615,0x7533530543000000,
0x0000311229F84631,0x5B95267234551033,0x5AD5A21202524335,0x3343302301000000,
0x0000236529D41896,0x98A537997A966022,0x80AD7A4000230241,0x0035411100200000,
0x00003AD538620388,0x5397BB977DA9D26A,0xA3AF287510013532,0x3102730320000000,
0x00005B84A7154033,0x06A5B9513855857B,0xABFF802620245214, @
ai_chase_icop.c
Found at 1x1C46877.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* ai_chase_icop.c - */
/**/
/* Author: Scott Patterson */
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1998*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 09/09/98 Patterson Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "ai_craft.h"
#include "soundcall.h"
#include "audio_spkr.h"
#include "sysmem.h"
#include "audio.h"
#include "audio_mgr.h"
#include "obsys.h"
#include "gutil.h"
#include "ai_chase_icop.h"
/*====================*/
/* private definitions*/
#define AI_CRAFT_ITALIAN_BULLHORN_CHOICE_COUNT 4
#define AI_CRAFT_ITALIAN_BULLHORN_VOLUME 255
#define AI_CRAFT_ITALIAN_BULLHORN_WAIT_TIME 75 /*180*/
static u32 _ItalianBullHornChoices[AI_CRAFT_ITALIAN_BULLHORN_CHOICE_COUNT] = {
SOUNDCALL_EUROPEAN_POLICE_WARNING_1,
SOUNDCALL_EUROPEAN_POLICE_WARNING_2,
SOUNDCALL_EUROPEAN_POLICE_WARNING_3,
SOUNDCALL_EUROPEAN_POLICE_WARNING_4,
};
#define _NUM_SIREN_FRAMES 24
#define _SIREN_SEPERATION ( _NUM_SIREN_FRAMES/2 )
typedef struct {
Mesh3d_t *pSiren; /* the red/blue geometry*/
u8 nLeftIndex;
u8 nRightIndex;
}AiCraftItalianSirens_t;
#define AI_CRAFT_ITALIAN_SIREN_SILENCE_COUNT 90
typedef struct {
BOOL bSirenSoundTriggered;
u32 nSirenSilenceCount;
Audio_Spkr_t *pSirenSpeaker;
AiCraftItalianSirens_t Sirens;
u32 nBullHornWaitTime;
u32 nBullHornSequentialRand;
}ItalianPoliceSpecific_t;
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
static Xfm_t _ItalianPolicePosterXfm, _ItalianPoliceLeftSiren, _ItalianPoliceRightSiren;
static Vec3_t _ItalianPolicePosterPos = { 0.0f, 23.3f, -2.4f };
static Vec3_t _ItalianPoliceLeftSirenPos = { -3.8f, 23.3f, -2.4f };
static Vec3_t _ItalianPoliceRightSirenPos = { 3.8f, 23.3f, -2.4f };
/*===================*/
/* private prototypes*/
static void _InitItalianSirenLights( AiCraftItalianSirens_t *pItalianSirens, u32 nId );
static void _WorkItalianSirenLights( AiCraftItalianSirens_t *pItalianSirens );
static void _DrawItalianSirenLights( AiCraftItalianSirens_t *pItalianSirens, WorldOb_t *pBoatWorldOb );
/*=================*/
/* public functions*/
BOOL ai_chase_icop_ModuleInit( void )
{
Xfm_t xfmScale, xfmTranslate;
xfm_BuildXlatFromVec( &_ItalianPolicePosterXfm, &_ItalianPolicePosterPos );
xfm_BuildScale1( &xfmScale, 0.3f );
xfm_BuildXlatFromVec( &xfmTranslate, &_ItalianPoliceLeftSirenPos );
xfm_Mult( &_ItalianPoliceLeftSiren, &xfmTranslate, &xfmScale );
xfm_BuildXlatFromVec( &xfmTranslate, &_ItalianPoliceRightSirenPos );
xfm_Mult( &_ItalianPoliceRightSiren, &xfmTranslate, &xfmScale );
return TRUE;
}
void ai_chase_icop_ItalianPoliceInit( Physicscraft_t *pPhysicscraft, u32 nId )
{
ItalianPoliceSpecific_t *pItalianPoliceSpecific;
pItalianPoliceSpecific = SYSMEM_ALLOCANDZERO( sizeof(ItalianPoliceSpecific_t) );
if( pItalianPoliceSpecific )
{
_InitItalianSirenLights( &pItalianPoliceSpecific->Sirens, nId );
pPhysicscraft->pMeshSpecificData = pItalianPoliceSpecific;
ai_chase_icop_ItalianPoliceReset( pPhysicscraft );
}
}
void ai_chase_icop_ItalianPoliceReset( Physicscraft_t *pPhysicscraft )
{
ItalianPoliceSpecific_t *pItalianPoliceSpecific;
pItalianPoliceSpecific = (ItalianPoliceSpecific_t *)pPhy
anim3d.c
Found at 1x1C47878.
/*///////////////////////////////////////////////////////////////////////*/
/* FILE: anim3d.c //*/
/* CREATED BY: Michael Starich //*/
/* //*/
/*///////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT //*/
/* Copyright (c) 1997, All Rights Reserved. //*/
/* //*/
/* The contents of this file may not be disclosed to third //*/
/* parties, copied or duplicated in any form, in whole or in part, //*/
/* without the prior written permission of Midway Home Entertainment //*/
/*///////////////////////////////////////////////////////////////////////*/
/* MODIFICATION HISTORY: //*/
/* //*/
/* DATE WHO DESCRIPTION //*/
/* -------------------------------------------------------------------//*/
/* 4/3/97 STARICH created, Animation API - just basic functionality //*/
/*///////////////////////////////////////////////////////////////////////*/
#include "anim3d.h"
#include "gendefs.h"
#include "obsys.h"
#include "mesh3d.h"
#include "xfm.h"
#include "xmath.h"
#include "sysmem.h"
/*=======================================================================*/
/* Private Definitions:*/
/*=======================================================================*/
/* Public Variables:*/
/*=======================================================================*/
/* Private Variables:*/
static const u32 _nSizeOfHeader = sizeof( AnimHeader_t );
static const u32 _nSizeOfNodeDef = sizeof( NodeDef_t );
static const u32 _nSizeOfXfm = sizeof( Xfm_t );
static Xfm_t _PosterX;
static Xfm_t _PosterY;
/*=======================================================================*/
/* Private Prototypes:*/
static void _PosterAboutY( void );
static void _PosterAboutX( void );
/*=======================================================================*/
/* Public Functions:*/
BOOL anim3d_ModuleInit( void ) {
/* see the 2 global xfms to the identity*/
xfm_Identity( &_PosterX );
_PosterX.type = XFM_TYPE_R;
xfm_Identity( &_PosterY );
_PosterY.type = XFM_TYPE_R;
return TRUE;
}
AnimData_t *anim3d_Load( const char *pszObjName, AnimData_t *pAD ) {
AnimHeader_t *pHead;
/* make sure that pAD is valid*/
if( !pAD ) {
return NULL;
}
pHead = (AnimHeader_t *)obsys_Load( (char *)pszObjName );
if( !pHead ) {
return NULL;
}
pAD->pHd = pHead;
pAD->pHdNodeDef = (NodeDef_t *)((u32)pHead + _nSizeOfHeader);
pAD->pCurrentNodeDef = pAD->pHdNodeDef;
pAD->pCurrentXfm = (Xfm_t *)( (u32) pHead + _nSizeOfHeader + pHead->nNodes * _nSizeOfNodeDef);
pAD->nFrame = 1;
return pAD;
}
/* increases the frame counter for a given animation*/
/* return values */
/* TRUE if advanced regular*/
/* FALSE if we had to loop back to the beginning */
BOOL anim3d_Animate( AnimData_t *pData ) {
/* advance the frame counters and make sure to loop around when reaching the last frame*/
++pData->nFrame;
if( pData->nFrame >= pData->pHd->nFrames ) {
pData->nFrame = 1;
return FALSE;
}
return TRUE;
}
/* draws the current frame for a particular mesh structure*/
/* return values:*/
/* -1 = error, no frame drawn*/
/* 1 = drew the last frame (this would be a good time to trigger an event */
/* if this is a non looping animation)*/
/* 2 = drew a regular frame and advanced the counters to the next frame*/
int anim3d_AnimateAndDraw( Mesh3d_t *pMesh, AnimData_t *pData ) {
/* make sure this mesh has at least as many groups as there are animation nodes*/
xfm.c
Found at 1x1C49878.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* xfm.c - 3D transform functions*/
/**/
/* Author: Steve Ranck*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 01-17-97 Ranck Created.*/
/* 09-09-97 Starich Modified Postering xfm functions.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "xfm.h"
#include "vec3.h"
#include "xmath.h"
#include "viewport.h"
typedef void (*_xfmfcn_t)( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _GxG( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _GxT( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _GxR( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _GxS( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _TxG( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _TxT( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _TxR( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _TxS( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _RxG( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _RxT( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _RxR( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _RxS( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _SxG( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _SxT( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _SxR( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static void _SxS( Xfm_t *xr, Xfm_t *x1, Xfm_t *x2 );
static _xfmfcn_t xfmfcn[4][4] = {
_GxG, _GxT, _GxR, _GxS,
_TxG, _TxT, _TxR, _TxS,
_RxG, _RxT, _RxR, _RxS,
_SxG, _SxT, _SxR, _SxS,
};
Xfm_t Xfm_aStack[ XFM_STACK_ELEMENTS ]; /* transformation stack*/
Xfm_t *Xfm_pStackTop; /* points to the xfm on the top of the stack*/
int Xfm_nStackElements; /* number of xfms currently on the stack*/
Cam_t *Xfm_pStackCam; /* points to the camera last used to initialize stack*/
u32 Xfm_nCameraKey; /* increments each time the stack is initialized*/
u32 Xfm_nStackKey; /* increments each time the stack top changes*/
#if TARGET==DREAMCAST
f32 Xfm_mIdentity[4][3] = {
1.0f, 0.0f, 0.0f, /* column 0*/
0.0f, 1.0f, 0.0f, /* column 1*/
0.0f, 0.0f, 1.0f, /* column 2*/
0.0f, 0.0f, 0.0f /* column 3*/
};
#else
f32 Xfm_mIdentity[4][3] = {
1.0f, 0.0f, 0.0f, /* column 0*/
0.0f, 1.0f, 0.0f, /* column 1*/
0.0f, 0.0f, 1.0f, /* column 2*/
0.0f, 0.0f, 0.0f /* column 3*/
};
#endif // DREAMCAST
BOOL xfm_ModuleInit( void ) {
xfm_Reset();
return TRUE;
}
void xfm_Reset( void ) {
Xfm_nCameraKey = 1;
Xfm_nStackKey = 1;
}
Xfm_t *xfm_Zero( Xfm_t *xr ) {
int r;
for( r=0; r<3; r++ ) {
xr->mf[0][r] = xr->mf[1][r] = xr->mf[2][r] = xr->mf[3][r] = 0.0f;
xr->mr[0][r] = xr->mr[1][r] = xr->mr[2][r] = xr->mr[3][r] = 0.0f;
}
xr->sf = xr->sr = 1.0f;
xr->type = XFM_TYPE_GEN;
return xr;
}
int xfm_GetHeading( Xfm_t *pXfm ) {
return ( xmath_atan( pXfm->mf[2][0], pXfm->mf[2][2] ) );
}
int xfm_GetCamHeading( Cam_t *pCam ) {
return ( xmath_atan( pCam->xfm.mr[2][0], pCam->xfm.mr[2][2] ) );
}
int xfm_GetCamPitch( Cam_t *pCam ) {
return ( XMATH_NORM2NEG_BRADIANS( xmath_atan( -pCam->xfm.mr[2][1], pCam->xfm.mr[1][1] ) ) );
}
int xfm_GetCamRoll( Cam_t *pCam ) {
return ( XMATH_NORM2NEG_BRADIANS( xmath_atan( pCam->xfm.mr[0][1], pCam->xfm.mr[1][1] ) ) );
}
Xfm_t *xfm_Copy( Xfm_t *xdest, Xfm_t *xsrc ) {
int r;
for( r=0; r<3; r —
mesh3d.c (Copy 2)
A small fragment from a second copy of mesh3d.c can be found at 1x1C60800.
/*////////////////////////////////////////////////////////////////////////////////////*/
/* mesh3d.c - General 3D mesh definitions.*/
/**/
/* Author: Steve Ranck*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* THIS CODE IS PROPRIETARY PROPERTY OF MIDWAY HOME ENTERTAINMENT.*/
/* Copyright (c) 1997*/
/**/
/* The contents of this file may not be disclosed to third*/
/* parties, copied or duplicated in any form, in whole or in part,*/
/* without the prior written permission of Midway Home Entertainment.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
/* Modification History:*/
/**/
/* Date Who Description*/
/* -------- ---------- --------------------------------------------------------------*/
/* 04-14-97 Ranck Created.*/
/*////////////////////////////////////////////////////////////////////////////////////*/
#include "gendefs.h"
#include "gfxdefs.h"
#include "vec3.h"
#include "xfm.h"
#include "viewport.h"
#include "glide.h"
#include "gutil.h"
#include "xmath.h"
#include "tmem.h"
#include "mesh3d.h"
#include "light.h"
#include "blit.h"
#include "sysmem.h"
#include "glcount.h"
#include "material.h"
#include "xclib.h"
#include <private.h>
#define _INLINE_ASM_ENABLED FALSE
#define _ASM_TRANSFORM_ENABLED TRUE
#define _ASM_LIGHTING_ENABLED TRUE
#define _DYNAMIC_LIGHTING_ENABLED TRUE
#define _LIGHTING_CACHE_ENABLED TRUE
#define OLD_OOW_CALC_METHOD 0
#define MY_TEMP_TEST 0
#define MY_TEMP_TEST2 0
#define MESH3D_ZTUG_DELTA_DEPTH_BIAS 5
#ifdef MESH3D_USE_32BIT_TC_INDEX_FIELDS
static Mesh3dMtlDef_t _UnmappedTextureMtl_1Sided = {
0, 0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
static Mesh3dMtlDef_t _UnmappedTextureMtl_2Sided = {
MESH3D_MTLFLAG_2SIDED, 0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
#else
static Mesh3dMtlDef_t _UnmappedTextureMtl_1Sided = {
0, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
static Mesh3dMtlDef_t _UnmappedTextureMtl_2Sided = {
MESH3D_MTLFLAG_2SIDED, 0, 0, 0, 0.0f, 0.0f, NULL, 0.0f, 1.0f, 1.0f, 1.0f
};
#endif
/*==================================================================================*/
/* Public Variables:*/
#if MESH3D_ENABLE_STATS
u32 Mesh3d_nTrisCulled_BackfaceTest;
u32 Mesh3d_nTrisCulled_TriBoundTest;
u32 Mesh3d_nTrisCulled_TriVtxTest;
u32 Mesh3d_nTrisCulled_TriClipTest;
u32 Mesh3d_nTrisDrawn_Unclipped;
u32 Mesh3d_nTrisDrawn_Clipped;
#endif
#if MESH3D_TRI_HIGHLIGHT_CODE
BOOL Mesh3d_bDisplayFaceNorms;
BOOL Mesh3d_bDisplayVtxNorms;
RGBn_t Mesh3d_FaceNormColor;
RGBn_t Mesh3d_VtxNormColor;
float Mesh3d_fNormLength;
BOOL Mesh3d_bWireframeMode; /* FALSE: normal rendering, TRUE: opaque tris and wireframes*/
RGBn_t Mesh3d_WireframeColor; /* Color when Mesh3d_bWireframeMode is TRUE*/
Mesh3dPolyDrawFcn_t *Mesh3d_pPolyDrawFcn; /* Called for every poly drawn (NULL=none)*/
#endif
Mesh3dVtxCache_t *Mesh3d_pVtxCache;
Mesh3dVlCache_t *Mesh3d_pVlCache;
u32 Mesh3d_nNextAvailVtxCacheIndex;
u32 Mesh3d_nNextAvailVlCacheIndex;
u32 Mesh3d_nCacheKey;
u32 Mesh3d_nLastFrameCounter;
u32 Mesh3d_nMaxVtxCacheIndex;
u32 Mesh3d_nMaxVlCacheIndex;
#if MESH3D_HIGHLIGHT_2SIDED
BOOL Mesh3d_bHighlight2Sided;
#endif
/*==================================================================================*/
/* Private Variables:*/
static BOOL _bCacheEnable;
static int _nMaterialFilter;
static Mesh3dMtlDef_t *_pCurrentMaterial;
static u32 _nMaterialFlags;
static TexDef_t *_pMaterialTexDef;
static float _fMaterialShininess;
static float _fMaterialShinyStrength;
static float _fMaterialSpecularProduct;
static BOOL _bMaterialTexture;
static BOOL _bMaterial2Sided;
static BOOL _bMaterialReflective;
static BOOL _bMaterialNoDiffuse;
BOOL _bMaterialNoDynLight;
static BOOL _bMaterialAlphaLit;
static BOOL _bMaterialTileS;
static BOOL _bMaterialTileT;
static BOOL _bMaterialZtug;
BOOL _bMaterialNoIncidenceAtten; /* For lighting*/
static u32 _nMaterialAlphaLightColor;
static float _fOrthoYScale = 1.0f;
static int _nUntuggedDepthBiasLevel;
static int _nTuggedDepthBiasLevel;
static BOOL _bZtugOn;
static RGBf_t _AlphaLightColor;
static u32 _nAlphaLightState;
Mesh3dAmbient_t _Ambient; /* ambient light*/
static float _fWhiteSat; /* white saturation level (0=normal, 1=fully white)*/
static u32 _dwWhiteSat;
static float _fR, _fG, _fB, _fA; /* temporary variables used for lighting*/
static float _fRGBA[4];
static Vec3_t _Vtx3d, _VtxUnitNorm, _VtxToCam;
static float _Vtx[6];
static float _fInvMagVtxToCam;
static BOOL _bMustCalcInvMagVtxToCam;
static u32 _nFindMtlById_ID;
static u32 _nFindMtlById_GrpIndex;
static u32 _nFindMtlById_TlIndex;
static Mesh3d_t *_pFindMtlById_Mesh;
static float _fOrthoRedBias;
static float _fOrthoGreenBias;
static float _fOrthoBlueBias;
static float _fOrthoOpaqueness;
static float _fOrthoWhiteSat;
static u32 _dwOrthoWhiteSat;
static BOOL _bOrthoUseScreenCoverageDraw;
static GrColor_t _OrthoConstColor;
static u32 _nNextPrintedMsgFrameCounter;
static MidwayLight_t *_apLightList[MESH3D_MAX_ACTIVE_LIGHTS];
static MidwayLight_t **_ppLightList;
static u32 _nNumLights;
static u32 _nLightListStartIndex;
static u32 _nIncludedPositionalLights;
static u32 _nIncludedDirectionalLights;
MidwayLight_t *_apPosGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apDirGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apSpotGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
MidwayLight_t *_apFlashGrpLight[MESH3D_MAX_ACTIVE_LIGHTS];
u32 _nNumGrpLights;
u32 _nNumPosGrpLights;
u32 _nNumDirGrpLights;
u32 _nNumSpotGrpLights;
u32 _nNumFlashGrpLights;
BOOL _bWorldMesh; /* mesh vertices are in world-space*/
static BOOL _bReflectSurface;
static float _fReflectSurfaceHeight_WorldSpace;
static Vec3_t _PointOnReflectSurface_Camspace;
static Vec3_t _ReflectSurfaceUnitNorm_Camspace;
static float _fNegDistAboveReflectSurface_Camspace;
static float _fReflectSurfaceAnimateCounter;
#if MESH3D_BOUNDING_VIEW_ENABLED
static Mesh3dTriDef_t *_pHighlightedTri; /* NULL=none*/
static int _nTriSphereCrossesPlanesMaskTmp;
static int _nTriSphereCrossesPlanesMask;
static BOOL _bViewOrthoBoundEnabled;
static BOOL _bViewBoundEnabled;
static BOOL _bViewMeshSphere;
static BOOL _bViewMeshVolume;
static BOOL _bViewGroupSphere;
static BOOL _bViewGroupVolume;
static BOOL _bViewTriSphere;
static int _nSelectedTriNum;
static int _nSelectedMatNum;
static int _nSelectedGrpNum;
#endif
static Mesh3d_t _SensorMesh;
static Mesh3dGrpDef_t _SensorGrp;
static Vec3_t _avModelViewNorm[4]; /* viewport normals in model space:*/
/* [0]=left, [1]=right, [2]=bottom, [3]=top*/
static Mesh3dVtxCache_t clippedvtx[40], *grvp[40];
extern float dcCullTest(float *pCamPos, float *pPos, float *pNorm);
extern void dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest);
extern void dcTransformVerticesA(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest);
extern void dcComputeDirLight(MidwayLight_t **pLightList, int NumLights, float *pNormal, float Rgb[3] );
extern void dcComputeSpotLight(MidwayLight_t **pLightList, int NumLights, float *pNormal, float Rgb[3] );
extern void dcComputeVtxLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn );
extern void dcComputeMotifLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl );
extern void dcOutputTri(Mesh3dVtxCache_t*, Mesh3dVtxCache_t*, Mesh3dVtxCache_t*);
extern void dcLightTri( Mesh3d_t *pMesh, Mesh3dGrpDef_t * pGrp, Mesh3dVtxCache_t *apVtxCache[3], Mesh3dTriVtx_t *pTriVtx);
extern Mesh3dVtxCache_t _dcVertexBuffer[8192];
/*==================================================================================*/
/* Prototypes:*/
static BOOL _SetOrthoMaterial( int *pnTmuIndex, u32 nMtlFlags );
static void _SetMaterial( BOOL bLightAlphaTexels );
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _ClipTriToFrustumAndDraw( u32 nTriNum, Mesh3dVtxCache_t **ppVtxCache, int nTriCrossesPlanesMask );
#else
static void _ClipTriToFrustumAndDraw( Mesh3dVtxCache_t **ppVtxCache, int nTriCrossesPlanesMask );
#endif
//static void _ComputeVtxLighting( Mesh3dGrpDef_t *pGrp, GrVertex *pGrVertex, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn );
//static void _ComputeFlashLight( void );
static void _ComputeOmniLight( void );
static void _ComputeDirLight( void );
static void _ComputeSpotLight( void );
static void _ComputeFlashLight_NoNormal( void );
static void _ComputeOmniLight_NoNormal( void );
static void _ComputeDirLight_NoNormal( void );
static void _ComputeSpotLight_NoNormal( void );
static void _DrawOrthoSphere( Vec3_t *pCenter, float fRadius, u32 nColorRGB555, float fViewportX, float fViewportY, int nRoll, float fScale );
static void _DrawProjectedSphere( Vec3_t *pCenter, float fRadius, u32 nColorRGB555 );
#if MESH3D_BOUNDING_VIEW_ENABLED
static void _UpdateViewBoundVars( void );
#endif
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _DrawConvexPolyWireframe( int nNumVerts, Mesh3dVtxCache_t *apVtxCache[] );
#endif
static void _IntersectPosLightListWithBound( Mesh3d_t *pMesh, Mesh3dBound_t *pBound, BOOL bTestingGroupBound );
static void _ComputeReflectParameters( void );
static void _WabbleScreenPoint( float *pfScreenX, float *pfScreenY, float fCamspaceX, float fCamspaceY, float fCamspaceZ );
#if MESH3D_TRI_HIGHLIGHT_CODE
static void _DisplayFaceNormal( Mesh3dVtxCache_t **ppVtxCache, Vec3_t *pFaceUnitNorm );
static void _DisplayVtxNormal( Mesh3dVtxCache_t *pVtxCache, Mesh3dVnDef_t *pVtxNorm );
static void _DrawNormal( Vec3_t *pHead, Vec3_t *pTail, int nRed, int nGreen, int nBlue );
#endif
//*****************************************************************************
// SH4 Inline Asm Code:
//*****************************************************************************
//=============================================================================
// Transform a list of vertices to screen space
// extern void dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest, BOOL bClips);
// if bPlanesMask is 0 faster transform is used (no camera x,y,z is saved off)
#if _INLINE_ASM_ENABLED
#pragma inline_asm(_dcTransformVertices)
static void _dcTransformVertices(Mesh3dVtxDef_t *pVtx, int NumVerts, Mesh3dVtxCache_t *pDest, BOOL nPlanesMask)
{
tst r7, r7
bf LTRANS1 ; Clipped transform
mov.l L064, r0 ; Viewport_zscreen
fmov.s @r0, fr10
mov.l L065, r1 ; dcViewportYTrans
fmov.s @r1, fr8
xor r7, r7
mova f320, r0
fmov.s @r0, fr9 ; 320.0f
add #16, r6
L004:
mov r4, r3
add #32, r3
pref @r3 ; fetch next 32 bytes into the cache
;transform 1st vertex
fmov.s @r4+, fr0 ; get model v
fmov.s @r4+, fr1
fmov.s @r4+, fr2
fldi1 fr3
add.l #4, r4
fldi1 fr7
ftrv xmtrx, fv0 ; mtrx * v
fmov.s @r4+, fr4 ; get model v
fmul fr2, fr2
fmov.s @r4+, fr5
fsrra fr2 ; 1/z*z
fmov.s @r4+, fr6
fmov.s fr2, @-r6
fmul fr10, fr2 ; q = Viewport_zscreen * ooz
fmov fr8, fr11
fmul fr2, fr1 ; y = q * cam y
fsub fr1, fr11 ; dcViewportYTrans - y
fmov.s fr11, @-r6
fmul fr2, fr0 ; x = q * cam x
fadd fr9, fr0
fmov.s fr0, @-r6
add.l #108, r6
;transform 2nd vertex
ftrv xmtrx, fv4 ; mtrx * v
add.l #4, r4
fmul fr6, fr6
add #-2, r5
fsrra fr6 ; 1/z*z
fmov.s fr6, @-r6
fmul fr10, fr6 ; q = Viewport_zscreen * ooz
fmov fr8, fr11
fmul fr6, fr5 ; y = q * cam y
fsub fr5, fr11 ; dcViewportYTrans - y
fmov.s fr11, @-r6
fmul fr6, fr4 ; x = q * cam x
fadd fr9, fr4
fmov.s fr4, @-r6
cmp/gt r7, r5
bt/s L004
add.l #108, r6
bra L060
nop
LTRANS1:
mov.l L064, r0 ; Viewport_zscreen
fmov.s @r0, fr7
mov.l L065, r0 ; dcViewportYTrans
fmov.s @r0, fr8
mova f320, r0
fmov.s @r0, fr9 ; 320.0f
fldi0 fr10
L001:
fldi1 fr3
fmov.s @r4+, fr0 ; get model v
fmov.s @r4+, fr1
fmov.s @r4+, fr2
ftrv xmtrx, fv0 ; mtrx * v
add.l #4, r4
mov r6, r2
add.l #44, r2
fmov.s fr2, @-r2
fmov.s fr1, @-r2
fmov.s fr0, @-r2
fcmp/gt fr10, fr2
bf L003
fmul fr2, fr2
add.l #-16, r2
fsrra fr2 ;1/z*z
fmov.s fr2, @-r2
fmul fr7, fr2 ; q = Viewport_zscreen * ooz
fmov fr8, fr4
fmul fr2, fr1 ; y = q * cam y
fsub fr1, fr4 ; dcViewportYTrans - y
fmov.s fr4, @-r2
fmul fr2, fr0 ; x = q * cam x
fadd fr9, fr0
fmov.s fr0, @-r2
L003:
add #-1, r5
tst r5, r5
bf/s L001
add.l #96, r6
bra L060
nop
L064:
.DATA.L _Viewport_zscreen
L065
.DATA.L _dcViewportYTrans
f320:
.FDATA.S F'320.0
L060:
}
//=============================================================================
// Light a vertex
//
#pragma inline_asm(_dcComputeVtxLighting)
static void _dcComputeVtxLighting( Mesh3dGrpDef_t *pGrp, u32 *pArgb, Mesh3dVtxDef_t *pVtx, Mesh3dVlDef_t *pVl, Mesh3dVnDef_t *pVn )
{
mov.l r13, @-r15
mov.l r14, @-r15
fmov.s fr12, @-r15
fmov.s fr13, @-r15
fmov.s fr14, @-r15
fmov.s fr15, @-r15
mov #12, r0 ;get Vtx intensity
fmov.s @(r0,r6),fr11
; Ambient
mov r5, r13
mov #28, r0 ;pVn
mov.l @(r0,r15), r14
mov.l L016, r0
add #20, r0
mov #16, r1
mov.l #H'84, r1
fmov.s @r0+, fr15 ;_Ambient.ScaledColor
add r1, r4
fmov.s @r0+, fr14
add #8, r7
fmov.s @r0+, fr13
mov r4, r3 ;pGrp->aMotifConstColor[0].rgb
add #H'10, r3
;Compute motif lights
; SLOT 0
mov @r4+, r0 ;nMotif
tst r0, r0
bt L020
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L019
mov r3, r0
L019
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L020:
add #12, r3
add #4, r7
;SLOT 1
mov @r4+, r0 ;nMotif
tst r0, r0
bt L054
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L053
mov r3, r0
L053:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L054:
add #12, r3
add #4, r7
;SLOT 2
mov @r4+, r0 ;nMotif
tst r0, r0
bt L056
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L055
mov r3, r0
L055:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L056:
add #12, r3
add #4, r7
;SLOT 3
mov @r4+, r0 ;nMotif
tst r0, r0
bt L058
cmp/eq #1, r0 ;nMotif == SLMOTIF_CONSTANT ?
bf L057
mov r3, r0
L057:
fmov.s @r7, fr0 ;fMotifIntensity
fmul fr11, fr0 ;* Vtx intensity
fmov.s @r0+, fr3
fmac fr0, fr3, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr1
fmac fr0, fr1, fr13
L058:
;Do dynamic lighting
mov.l L028, r1
mov.l @r1, r0
tst r0, r0
bt L063 ;__nNumGrpLights
mov.l L030, r1
mov.l @r1, r0
tst r0, r0
bt L062
L063
bra L033
nop
L062:
;Compute directional light
mov.l L031, r1
mov.l @r1, r5 ;__nNumDirGrpLights
tst r5, r5
bt L050
mov.l L032, r4 ;__apDirGrpLight
fmov.s @r14+, fr4 ;Vtx normal
fmov.s @r14+, fr5
fmov.s @r14+, fr6
add #-12, r14
fldi0 fr7
mov.l #H'80, r1
mov.l #H'90, r2
L005:
mov.l @r4+, r0 ;pLight
mov.l r0, r3
add r1, r3
fmov.s @r3+, fr0 ;fLx = pLight->ModSpaceUnitDir.p[0]
fmov.s @r3+, fr1 ;fLy = pLight->ModSpaceUnitDir.p[1]
fmov.s @r3+, fr2 ;fLz = pLight->ModSpaceUnitDir.p[2]
fldi0 fr3
fipr fv4, fv0 ;x * fLx + y * fLy + z * fLz;
fcmp/gt fr7, fr3
bf L006
fmov fr3, fr0
add r2, r0
fmov.s @r0+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr15
fmov.s @r0+, fr2
fmac fr0, fr2, fr14
fmov.s @r0+, fr3
fmac fr0, fr3, fr13
L006:
add #-1, r5
tst r5, r5
bf L005
L050:
;Compute omni light
mov.l L039, r1
mov.l @r1, r5 ;__nPosGrpLights
tst r5, r5
bt L041
mov.l L040, r4 ;__apPosGrpLight
mov r6, r0 ;pVtx
fmov.s @r0+, fr8
fmov.s @r0+, fr9
fmov.s @r0+, fr10
fldi0 fr7
L043:
mov.l @r4+, r3 ;pLight
mov.l r3, r2
add #104, r2 ;ModSpacePos
fmov.s @r2+, fr4
fsub fr8, fr4 ;ModSpacePos - Vtx
fmov.s @r2+, fr5
fsub fr9, fr5
fmov.s @r2+, fr6
fsub fr10, fr6 ;get dist
fmov fr4, fr0
fmov fr5, fr1
fmov fr6, fr2
fldi0 fr3
fipr fv0, fv0
mov #120, r0 ; dist > pLight->fModSpaceRadius2 ?
fmov.s @(r0,r3), fr12
fcmp/gt fr12, fr3
bt L042
fmov fr3, fr11 ;fLightDist2
fmov.s @r14+, fr0 ;Vtx normal
fmov.s @r14+, fr1
fldi0 fr3
fmov.s @r14+, fr2
add #-12, r14
fipr fv4, fv0
fcmp/gt fr7, fr3
bf L042
mov #28, r0
fmov.s @(r0,r3), fr2 ;pLight->fRadialAttenuation
fmul fr11, fr2 ; * fLightDist2
fmov fr12, fr0 ;pLight->fModSpaceRadius2
fsub fr2, fr0
mov #124, r0
fmov.s @(r0,r3), fr1 ;pLight->fModSpaceInvRadius2
fmul fr1, fr0
mov.l #H'90, r0
add r0, r3
fmov.s @r3+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr15
fmov.s @r3+, fr2 ;g = pLight->ScaledColor.rgb[1];
fmac fr0, fr2, fr14
fmov.s @r3+, fr3 ;b = pLight->ScaledColor.rgb[2];
fmac fr0, fr3, fr13
L042:
add #-1, r5
tst r5, r5
bf L043
L041:
;Compute spot light
mov.l L045, r1
mov.l @r1, r5 ;__nSpotGrpLights
tst r5, r5
bt L061
mov.l L044, r4 ;__apSpotGrpLight
mov.l #H'80, r3
L012:
mov.l @r4+, r1 ;pLight
mov.l r1, r2
add #104, r2
mov r6, r0 ;pVtx
fmov.s @r0+, fr0
fmov.s @r2+, fr4 ;pLight->ModSpacePos.p - pVtx
fsub fr0, fr4
fmov.s @r0+, fr1
fmov.s @r2+, fr5
fsub fr1, fr5
fmov.s @r0+, fr2
fmov.s @r2+, fr6
fsub fr2, fr6
fldi0 fr7
; fLightDist2 = fLx*fLx + fLy*fLy + fLz*fLz;
fmov fr4, fr0
fmov fr5, fr1
fmov fr6, fr2
fldi0 fr3
fipr fv0, fv0
fmov fr3, fr11
; if( fLightDist2 > pLight->fModSpaceRadius2 ) continue;
mov #120, r0
fmov.s @(r0,r1), fr12
fcmp/gt fr12, fr3
bt L013
; fDot = pVec[0]*fLx + pVec[1]*fLy + pVec[2]*fLz;
fmov.s @r14+, fr0
fmov.s @r14+, fr1
fldi0 fr3
fmov.s @r14+, fr2
add #-12, r14
fipr fv4, fv0
; if( fDot < 0 ) continue;
fcmp/gt fr7, fr3
bf L013
fmov fr3, fr10
; fDx = pLight->ModSpaceUnitDir.p[0];
; fDy = pLight->ModSpaceUnitDir.p[1];
; fDz = pLight->ModSpaceUnitDir.p[2];
mov r1, r2
add r3, r2
fmov.s @r2+, fr0
fmov.s @r2+, fr1
fldi0 fr3
fmov.s @r2+, fr2
; fDot2 = fDx*fLx + fDy*fLy + fDz*fLz;
fipr fv4, fv0
; if( fDot2 <= 0.00001f ) continue;
fcmp/gt fr7, fr3
bf L013
; fInvLightDist = 1.0f / xmath_sqrt( fLightDist2 );
fmov fr11, fr9
fsrra fr9
; fDot2 *= fInvLightDist;
; fT2 = fDot2*fDot2*fDot2
fmul fr9, fr3
fmov fr3, fr1
fmul fr3, fr3 ; fDot * fDot
fmul fr1, fr3 ; * fDot
; fT1 = fT2*fT2;
fmul fr3, fr3
; fRadialAtten = (pLight->fModSpaceRadius2 - pLight->fRadialAttenuation*fLightDist2)
; * pLight->fModSpaceInvRadius2;
mov #28, r0
fmov.s @(r0,r1), fr2 ;pLight->fRadialAttenuation
fmul fr11, fr2 ; * fLightDist2
fmov fr12, fr0 ;pLight->fModSpaceRadius2
fsub fr2, fr0
mov #124, r0
fmov.s @(r0,r1), fr1 ;pLight->fModSpaceInvRadius2
fmul fr1, fr0
fmul fr3, fr0
mov.l #H'A0, r0
mov.b @(r0,r1),r0 ;pLight->bNoIncidenceAtten
mov.l L048, r2 ;__bMaterialNoIncidenceAtten
extu.b r0, r0
mov.l @r2, r2
or r2, r0
tst r0, r0
bf L049
fmul fr10, fr0
fmul fr9, fr0
L049:
mov.l #H'90, r0
add r0, r1
fmov.s @r1+, fr1 ;r = pLight->ScaledColor.rgb[0];
fmac fr0, fr1, fr13
fmov.s @r1+, fr2 ;g = pLight->ScaledColor.rgb[1];
fmac fr0, fr2, fr14
fmov.s @r1+, fr3 ;b = pLight->ScaledColor.rgb[2];
fmac fr0, fr3, fr15
L013:
add #-1, r5
tst r5, r5
bf L012
L061:
L033:
;Convert r,g,b to argb
fldi1 fr1
mova L024, r0
fmov.s @r0, fr0 ;255.0f
;r
fcmp/gt fr1, fr13 ;clamp to 255
bf L025
fmov fr0, fr13
bra L038
nop
L025:
fmul fr0, fr13 ;* 255.0f
L038:
ftrc fr13, fpul ;r = r > 255 ? 255 : r
sts fpul, r2
;g
fcmp/gt fr1, fr14
bf L026
fmov fr0, fr14
bra L036
nop
L026:
fmul fr0, fr14
L036:
ftrc fr14, fpul
sts fpul, r3
;b
fcmp/gt fr1, fr15
bf L027
fmov fr0, fr15
bra L037
nop
L027:
fmul fr0, fr15
L037:
ftrc fr15, fpul
sts fpul, r4
shll8 r3
fmov.s @r15+, fr15
shll16 r2
fmov.s @r15+, fr14
shll8 r1 ; *pArgb = ((r << 16) | (g << 8) | b) | 0xff000000;
fmov.s @r15+, fr13
shll16 r1
fmov.s @r15+, fr12
or r2, r3
mov.l @r15+, r14
or r4, r3
mov.l #H'FF000000,r0
or r3, r1
or r0, r1
mov r1, @r13
mov.l @r15+, r13
bra L080
nop
.ALIGN 4
L016:
.DATA.L __Ambient
L021:
.DATA.L _Light_aLightMotifTable
L024:
.FDATA.S F'255.0
L028:
.DATA.L __nNumGrpLights
L030:
.DATA.L __bMaterialNoDynLight
L031:
.DATA.L __nNumDirGrpLights
L032:
.DATA.L __apDirGrpLight
L039:
.DATA.L __nNumPosGrpLights;
L040:
.DATA.L __apPosGrpLight
L044:
.DATA.L __apSpotGrpLight
L045:
.DATA.L __nNumSpotGrpLights
L048:
.DATA.L __bMaterialNoIncidenceAtten
L080:
}
#endif
/*==================================================================================*/
/* Public Functions:*/
/* mesh3d_SystemInit:*/
/* Initializes the mesh3d system and sets certain global parameters*/
/* to default values.*/
BOOL mesh3d_ModuleInit( void ) {
u32 nVtxCacheBytes, nVlCacheBytes;
#if SYS_WINDEV_DEBUG
u32 i;
#endif
mesh3d_EnableCache( TRUE );
Mesh3d_nMaxVtxCacheIndex = 0;
Mesh3d_nMaxVlCacheIndex = 0;
nVtxCacheBytes = MESH3D_MAX_CACHED_VTX * sizeof(Mesh3dVtxCache_t);
nVlCacheBytes = MESH3D_MAX_CACHED_VL * sizeof(Mesh3dVlCache_t);
// Mesh3d_pVtxCache = (Mesh3dVtxCache_t *)SYSMEM_ALLOC( nVtxCacheBytes );
Mesh3d_pVlCache = (Mesh3dVlCache_t *)SYSMEM_ALLOC( nVlCacheBytes );
xprintf( "Allocated %i bytes for mesh3d caches.\n", nVtxCacheBytes+nVlCacheBytes );
mesh3d_ResetCache();
_pFindMtlById_Mesh = NULL;
_bReflectSurface = FALSE;
_nNumLights = 0;
_nLightListStartIndex = 0;
_ppLightList = _apLightList;
_nNumPosGrpLights = 0;
_nNumDirGrpLights = 0;
_nNumSpotGrpLights = 0;
_nNumFlashGrpLights = 0;
_nNumGrpLights = 0;
mesh3d_SetMaterialFilterMode( 0 );
mesh3d_SetWhiteSat( 0.0f );
mesh3d_SetAmbientLight( 1.0f, 1.0f, 1.0f, 1.0f );
mesh3d_SetAmbientEffects( 1.0f );
/* Normal alpha light color is white...*/
_nAlphaLightState = 0;
mesh3d_SetAlphaLightColor( 1.0f, 1.0f, 1.0f, 1.0f );
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
mesh3d_EnableOrthoScreenCoverageDrawState( FALSE );
/* Init sensor stuff...*/
xclib_MemSet( &_SensorMesh, 0, sizeof(Mesh3d_t) );
xclib_MemSet( &_SensorGrp, 0, sizeof(Mesh3dGrpDef_t) );
_SensorMesh.nGrpCount = 1;
_SensorMesh.pGrp = &_SensorGrp;
_SensorMesh.Bound.fBoundRadius = 1.0f;
_SensorGrp.Bound.fBoundRadius = 1.0f;
_nNextPrintedMsgFrameCounter = 0;
return TRUE;
}
/* Sets the mesh reflection-wabble mode and reflection plane world height.*/
/* Returns the prior state of the enable flag.*/
BOOL mesh3d_SetReflectMode( BOOL bEnable, float fWorldReflectPlaneHeight ) {
BOOL bOldMode;
bOldMode = _bReflectSurface;
_bReflectSurface = bEnable;
_fReflectSurfaceHeight_WorldSpace = fWorldReflectPlaneHeight;
return bOldMode;
}
/* Returns the current state of the reflection-wabble enable flag.*/
/* If pfWorldReflectPlaneHeight is not NULL, it is filled with the*/
/* current reflection plane world height.*/
BOOL mesh3d_GetReflectMode( float *pfWorldReflectPlaneHeight ) {
if( pfWorldReflectPlaneHeight ) {
*pfWorldReflectPlaneHeight = _fReflectSurfaceHeight_WorldSpace;
}
return _bReflectSurface;
}
/* Fills pAmbientLigh
dcTexture.c
Found at 1x1C5C800.
/******************************************************************************
Dreamcast Shell for Kamui and Shinobi
*******************************************************************************
dcTexture.c
Texture handling
David Long '98
*******************************************************************************/
#include "dcInclude.h"
/*
extern unsigned char TestTexture[];
*/
#define TEXTURE_VIEWER_TEXW 320
#define TEXTURE_VIEWER_TEXH 240
#define TEXTURE_VIEWER_OPAQUE 0
#define TEXTURE_VIEWER_SEMITRANSPARENT 1
#define TEXTURE_VIEWER_PUNCHTHROUGH 2
DCTEXTURE dcTextureTable[DCMAXTEXTURES];
int dcNumTextures;
KMVERTEXCONTEXT NonTexturedVC;
KMVERTEXCONTEXT NonTexturedNoZBuffVC;
KMVERTEXCONTEXT NonTexturedAlphaBlendedVC;
static KMVERTEXCONTEXT _TPageVC;
static KMVERTEXCONTEXT *_pCurrentVC;
static KMVERTEX_03 V[4];
static KMVERTEX_03 Pts[4];
static void dcDrawTexture(unsigned int TxPage, int Type);
/*
static void CreateTestTexture();
*/
/* Initialise a vertex context struct to default values */
void dcInitVertexContext(PKMVERTEXCONTEXT pVertexContext)
{
/* ’¸“_CONTEXT‚̶¬ */
pVertexContext->RenderState = KM_DEPTHMODE | KM_CULLINGMODE /* ISP/TSP IW */
| KM_SCREENCOORDINATION | KM_SHADINGMODE
| KM_MODIFIER | KM_ZWRITEDISABLE /* TSP CW */
| KM_SRCBLENDINGMODE | KM_DSTBLENDINGMODE
| KM_SRCSELECT | KM_DSTSELECT
| KM_FOGMODE | KM_USESPECULAR
| KM_USEALPHA | KM_IGNORETEXTUREALPHA
| KM_FLIPUV | KM_CLAMPUV
| KM_FILTERMODE | KM_SUPERSAMPLE
| KM_MIPMAPDADJUST | KM_TEXTURESHADINGMODE
| KM_PARAMTYPE | KM_LISTTYPE /* Param CW */
| KM_COLORTYPE | KM_USESPECULAR
| KM_UVFORMAT;
pVertexContext->RenderState |= KM_USERCLIPMODE;
pVertexContext->UserClipMode = KM_USERCLIP_INSIDE;
/* for ParameterControlWord */
pVertexContext->ParamType = KM_POLYGON;
pVertexContext->ListType = KM_OPAQUE_POLYGON;
pVertexContext->ColorType = KM_PACKEDCOLOR;
pVertexContext->bUseSpecular = FALSE;
pVertexContext->UVFormat = KM_32BITUV;
/* for ISP/TSP InstructionWord */
pVertexContext->DepthMode = KM_GREATEREQUAL;
pVertexContext->CullingMode = KM_NOCULLING;
pVertexContext->ScreenCoordination = KM_SCREEN;
pVertexContext->ShadingMode = KM_NOTEXTUREGOURAUD;
pVertexContext->SelectModifier = KM_NOMODIFIER;
pVertexContext->bZWriteDisable = FALSE; /* ARC1‚ɂ͂Ȃ¢ */
/* for TSP ControlWord */
pVertexContext->SRCBlendingMode = KM_SRCALPHA;
pVertexContext->DSTBlendingMode = KM_INVSRCALPHA;
pVertexContext->bSRCSel = FALSE; /* ARC1‚ɂ͂Ȃ¢ */
pVertexContext->bDSTSel = FALSE; /* ARC1‚ɂ͂Ȃ¢ */
pVertexContext->FogMode = KM_FOGTABLE; /* 11‚ÍƒŠƒU[ƒu */
pVertexContext->bUseSpecular = TRUE;
pVertexContext->bUseAlpha = FALSE;
pVertexContext->FlipUV = KM_NOFLIP;
pVertexContext->ClampUV = KM_NOCLAMP;
pVertexContext->FilterMode = KM_BILINEAR;
pVertexContext->bSuperSample = FALSE;
pVertexContext->MipMapAdjust = 0x00000004; /* D=1.00 */
pVertexContext->TextureShadingMode = KM_MODULATE_ALPHA;
/* for Texture ControlBit */
/* No effect on ARC1 */
pVertexContext->bColorClamp = FALSE;
pVertexContext->PaletteBank = 0;
/* for GlobalColorData */
pVertexContext->fFaceColorAlpha = 1.0f; /* Face Color Alpha */
pVertexContext->fFaceColorRed = 1.0f; /* Face Color Red */
pVertexContext->fFaceColorGreen = 1.0f; /* Face Color Green */
pVertexContext->fFaceColorBlue = 1.0f; /* Face Color Blue */
pVertexContext->fOffsetColorAlpha = 0.0f; /* Specular Color Alpha */
pVertexContext->fOffsetColorRed = 0.0f; /* Specular Color Red */
pVertexContext->fOffsetColorGreen = 0.0f; /* Specular Color Green */
pVertexContext->fOffsetColorBlue = 0.0f; /* Specular Color Blue */
kmProcessVertexRenderState(pVertexContext);
}
// Load data into a texture surface
void dcLoadTexture(unsigned int TexIndex, void *pData)
{
KMSTATUS kms;
DCASSERT(TexIndex < dcNumTextures, "dcLoadTexture");
kms = kmLoadTexture(&dcTextureTable[TexIndex].TexSurfaceDesc, pData, FALSE, FALSE);
DCCHECKKMSTATUS(kms, "kmLoadTexture");
}
/* Alloc and load a texture */
void dcAllocAndLoadTexture(PKMSURFACEDESC *pSurfDesc, int Width,
int Height, KMTEXTURETYPE Type, void *pData)
{
KMSTATUS kms;
DCASSERT(pSurfDesc != NULL, "dcAllocAndLoadTexture: invalid parameter");
DCASSERT(pData != NULL, "dcAllocAndLoadTexture: invalid parameter");
kms = kmCreateTextureSurface(pSurfDesc, Width, Height, Type);
DCCHECKKMSTATUS(kms, "kmCreatetextureSurface");
kms = kmLoadTexture(pSurfDesc, pData, FALSE, FALSE);
DCCHECKKMSTATUS(kms, "kmLoadTexture");
}
/* Free last texture in table */
void dcReleaseTexture(int nTexture)
{
KMSTATUS kms;
kms = kmFreeTexture(&dcTextureTable[nTexture].TexSurfaceDesc);
DCCHECKKMSTATUS(kms, "kmFreeTexture");
}
/* Call to initialise texture allocation system */
void dcInitTextureSystem()
{
KMSTATUS kms;
dcNumTextures = 0;
/* Init tpage util vertex context */
dcInitVertexContext(&_TPageVC);
dcInitVertexContext(&NonTexturedVC);
dcInitVertexContext(&NonTexturedNoZBuffVC);
dcInitVertexContext(&NonTexturedAlphaBlendedVC);
NonTexturedNoZBuffVC.RenderState = KM_DEPTHMODE;
NonTexturedNoZBuffVC.DepthMode = KM_ALWAYS;
kms = kmProcessVertexRenderState(&NonTexturedNoZBuffVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
kms = kmProcessVertexRenderState(&NonTexturedNoZBuffVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
NonTexturedAlphaBlendedVC.RenderState |= KM_LISTTYPE;
NonTexturedAlphaBlendedVC.ListType = KM_TRANS_POLYGON;
NonTexturedAlphaBlendedVC.RenderState |= KM_USEALPHA;
NonTexturedAlphaBlendedVC.bUseAlpha = TRUE;
kms = kmProcessVertexRenderState(&NonTexturedAlphaBlendedVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
kms = kmProcessVertexRenderState(&NonTexturedAlphaBlendedVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
}
/* Free all textures from and including table index to end of table */
void dcReleaseTextureBlock(int TexIndex)
{
int i;
for(i = TexIndex; i < dcNumTextures; i++)
dcReleaseTexture(i);
dcNumTextures = TexIndex;
}
/* Initialise texture vertex contexts */
void dcInitTexture(DCTEXTURE *pTexture)
{
KMSTATUS kms;
/* Initialise render states for opaque and alpha blended */
dcInitVertexContext(&pTexture->OpaqueTexVC);
pTexture->OpaqueTexVC.RenderState = KM_SHADINGMODE;
pTexture->OpaqueTexVC.ShadingMode = KM_TEXTUREGOURAUD;
pTexture->OpaqueTexVC.pTextureSurfaceDesc = &pTexture->TexSurfaceDesc;
kms = kmProcessVertexRenderState(&pTexture->OpaqueTexVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
dcInitVertexContext(&pTexture->AlphaBlendedTexVC);
pTexture->AlphaBlendedTexVC.RenderState = KM_SHADINGMODE|KM_LISTTYPE|KM_USEALPHA;
pTexture->AlphaBlendedTexVC.ShadingMode = KM_TEXTUREGOURAUD;
pTexture->AlphaBlendedTexVC.pTextureSurfaceDesc = &pTexture->TexSurfaceDesc;
pTexture->AlphaBlendedTexVC.ListType = KM_TRANS_POLYGON;
pTexture->AlphaBlendedTexVC.bUseAlpha = TRUE;
kms = kmProcessVertexRenderState(&pTexture->AlphaBlendedTexVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
dcInitVertexContext(&pTexture->AlphaBlendedTexVC1);
pTexture->AlphaBlendedTexVC1.RenderState = KM_SHADINGMODE|KM_LISTTYPE|KM_USEALPHA
|KM_DSTBLENDINGMODE|KM_SRCBLENDINGMODE;
pTexture->AlphaBlendedTexVC1.ShadingMode = KM_TEXTUREGOURAUD;
pTexture->AlphaBlendedTexVC1.pTextureSurfaceDesc = &pTexture->TexSurfaceDesc;
pTexture->AlphaBlendedTexVC1.ListType = KM_TRANS_POLYGON;
pTexture->AlphaBlendedTexVC1.bUseAlpha = TRUE;
pTexture->AlphaBlendedTexVC1.SRCBlendingMode = KM_ONE;
pTexture->AlphaBlendedTexVC1.DSTBlendingMode = KM_ONE;
kms = kmProcessVertexRenderState(&pTexture->AlphaBlendedTexVC1);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
dcInitVertexContext(&pTexture->PunchThroughTexVC);
pTexture->PunchThroughTexVC.RenderState = KM_SHADINGMODE|KM_LISTTYPE|KM_USEALPHA;
pTexture->PunchThroughTexVC.ShadingMode = KM_TEXTUREGOURAUD;
pTexture->PunchThroughTexVC.pTextureSurfaceDesc = &pTexture->TexSurfaceDesc;
pTexture->PunchThroughTexVC.ListType = KM_PUNCHTHROUGH_POLYGON;
pTexture->PunchThroughTexVC.bUseAlpha = TRUE;
kms = kmProcessVertexRenderState(&pTexture->PunchThroughTexVC);
DCCHECKKMSTATUS(kms, "ProcessVertexRenderState");
}
/* Allocate memory and load a texture */
int dcCreateTexture(int Width, int Height, KMTEXTURETYPE Type, void *pData, char *pName)
{
KMSTATUS kms;
// dcPrintStr("Creating Kamui texture... \n", Type);
// dcPrintStr("Texture Name: %s\n", pName);
// dcPrintStr("Texture Width: %d\n", Width);
// dcPrintStr("Texture Height: %d\n", Height);
// dcPrintStr("Texture Type: %d\n", Type);
// dcPrintStr(" ------- \n", Type);
DCASSERT(dcNumTextures < DCMAXTEXTURES, "dcCreateTextureTwiddled: texture table full - increase DCMAXTEXTURES");
DCASSERT(pData != NULL, "dcCreateTextureTwiddled: invalid parameter");
/* Create a texture surface and load */
dcAllocAndLoadTexture(&dcTextureTable[dcNumTextures].TexSurfaceDesc,
Width, Height, Type, pData);
dcInitTexture(&dcTextureTable[dcNumTextures]);
dcTextureTable[dcNumTextures].Type = Type;
dcTextureTable[dcNumTextures].pData = pData;
dcTextureTable[dcNumTextures].pName = pName;
dcNumTextures++;
return dcNumTextures-1;
}
void dcSetCurrentVertexContext(KMVERTEXCONTEXT *pContext)
{
kmSetVertexRenderState(pContext);
}
#ifdef TEXTURE_VIEWER_ENABLED
/* Texture viewing util */
void dcTextureViewer()
{
BOOL bQuit = FALSE;
int Type;
NJS_PERIPHERAL *per;
int Texture = 0;
KMSTATUS kms;
dcSetBackground(FALSE);
while(!bQuit){
dcSetViewport(480.0f, 0);
dcSetViewportClipping();
txt_ClearScreen();
// print texture number type, format
txt_SetCursor(2, 1);
txt_DispString("Texture number: %d", Texture);
txt_SetCursor(2, 2);
switch(dcTextureTable[Texture].Type & 0xffffff00){
case KM_TEXTURE_TWIDDLED:
txt_DispString("Texture type: KM_TEXTURE_TWIDDLED");break;
case KM_TEXTURE_TWIDDLED_MM:
txt_DispString("Texture type: KM_TEXTURE_TWIDDLED_MM");break;
case KM_TEXTURE_VQ:
txt_DispString("Texture type: KM_TEXTURE_VQ");break;
case KM_TEXTURE_VQ_MM:
txt_DispString("Texture type: KM_TEXTURE_VQ_MM");break;
case KM_TEXTURE_PALETTIZE4:
txt_DispString("Texture type: KM_TEXTURE_PALETTIZE4");break;
case KM_TEXTURE_PALETTIZE8:
txt_DispString("Texture type: KM_TEXTURE_PALETTIZE8");break;
case KM_TEXTURE_PALETTIZE8_MM:
txt_DispString("Texture type: KM_TEXTURE_PALETTIZE8_MM");break;
case KM_TEXTURE_STRIDE:
txt_DispString("Texture type: KM_TEXTURE_STRIDE");break;
case KM_TEXTURE_RECTANGLE:
txt_DispString("Texture type: KM_TEXTURE_RECTANGLE");break;
case KM_TEXTURE_BMP:
txt_DispString("Texture type: KM_TEXTURE_BMP");break;
case KM_TEXTURE_BMP_MM:
txt_DispString("Texture type: KM_TEXTURE_BMP_MM");break;
case KM_TEXTURE_SMALLVQ:
txt_DispString("Texture type: KM_TEXTURE_SMALLVQ");break;
case KM_TEXTURE_SMALLVQ_MM:
txt_DispString("Texture type: KM_TEXTURE_SMALLVQ_MM");break;
}
txt_SetCursor(2, 3);
Type = TEXTURE_VIEWER_OPAQUE;
switch(dcTextureTable[Texture].Type & 0xff){
case KM_TEXTURE_ARGB1555:
txt_DispString("Texture format: KM_TEXTURE_ARGB1555");
Type = TEXTURE_VIEWER_PUNCHTHROUGH;
break;
case KM_TEXTURE_RGB565:
txt_DispString("Texture format: KM_TEXTURE_RGB565");
break;
case KM_TEXTURE_ARGB4444:
txt_DispString("Texture format: KM_TEXTURE_ARGB4444");
Type = TEXTURE_VIEWER_SEMITRANSPARENT;
break;
case KM_TEXTURE_YUV422:
txt_DispString("Texture format: KM_TEXTURE_YUV422");
break;
case KM_TEXTURE_BUMP:
txt_DispString("Texture format: KM_TEXTURE_BUMP");
break;
case KM_TEXTURE_RGB555:
txt_DispString("Texture format: KM_TEXTURE_RGB555");
break;
case KM_TEXTURE_YUV420:
txt_DispString("Texture format: KM_TEXTURE_YUV420");
break;
}
dcDrawTexture(Texture, Type);
txt_SetCursor(2, 4);
txt_DispString("Name: %s", dcTextureTable[Texture].pName);
txt_DispScreen(VertexBufferDesc);
kms = kmRender(); /* Render !! */
DCCHECKKMSTATUS(kms, "kmRender");
kms = kmFlipFrameBuffer();
DCCHECKKMSTATUS(kms, "kmFlipFrameBuffer");
pdExecPeripheralServer();
per = pdGetPeripheral(PDD_PORT_A0);
if(per->press & PDD_DGT_KR){
if(Texture < dcNumTextures-1)
Texture++;
}
if(per->press & PDD_DGT_KL){
if(Texture)
Texture--;
}
if(per->press & PDD_DGT_TY)
bQuit = TRUE;
}
txt_ClearScreen();
dcSetBackground(TRUE);
}
static void dcDrawTexture(unsigned int TxPage, int Type)
{
float x1 = 320.0f - TEXTURE_VIEWER_TEXW / 2;
float x2 = 320.0f + TEXTURE_VIEWER_TEXW / 2;
float y1 = 240.0f - TEXTURE_VIEWER_TEXH / 2;
float y2 = 240.0f + TEXTURE_VIEWER_TEXH / 2;
unsigned int argb;
switch(Type){
case TEXTURE_VIEWER_SEMITRANSPARENT:
argb = 0x80ffffff;
dcSetCurrentVertexContext(&dcTextureTable[TxPage].AlphaBlendedTexVC);
break;
case TEXTURE_VIEWER_OPAQUE:
argb = 0xffffffff;
dcSetCurrentVertexContext(&dcTextureTable[TxPage].OpaqueTexVC);
break;
case TEXTURE_VIEWER_PUNCHTHROUGH:
argb = 0xffffffff;
dcSetCurrentVertexContext(&dcTextureTable[TxPage].PunchThroughTexVC);
break;
}
Pts[1].fX = x1;
Pts[1].fY = 480.0f - y1;
Pts[1].fU = 0;
Pts[1].fV = 0;
Pts[1].u.fZ = 65535.0f;
Pts[1].uBaseRGB.dwPacked = argb;
Pts[1].uOffsetRGB.dwPacked = 0;
Pts[0].fX = x2;
Pts[0].fY = 480.0f - y1;
Pts[0].fU = 1.0f;
Pts[0].fV = 0;
Pts[0].u.fZ = 65535.0f;
Pts[0].uBaseRGB.dwPacked = argb;
Pts[0].uOffsetRGB.dwPacked = 0;
Pts[2].fX = x2;
Pts[2].fY = 480.0f - y2;
Pts[2].fU = 1.0f;
Pts[2].fV = 1.0f;
Pts[2].u.fZ = 65535.0f;
Pts[2].uBaseRGB.dwPacked = argb;
Pts[2].uOffsetRGB.dwPacked = 0;
Pts[3].fX = x1;
Pts[3].fY = 480.0f - y2;
Pts[3].fU = 0;
Pts[3].fV = 1.0f;
Pts[3].u.fZ = 65535.0f;
Pts[3].uBaseRGB.dwPacked = argb;
Pts[3].uOffsetRGB.dwPacked = 0;
dcDrawGourTexQuad(Pts);
}
#endif
/*
static void CreateTestTexture()
{
unsigned short *pSrc;
unsigned char *pDst;
int i;
unsigned int Red,Green,Blue,Alpha;
KMSTATUS kms;
DCTEXTUREHEADER *pHeader;
pDst = (unsigned char*)BmpTex;
pSrc = (unsigned short*)&TestTexture[16];
for(i = 0; i < 256*256; i++){
Alpha = 0xff;
Blue = (pSrc[i] & 0x1f) << 3;
Green = ((pSrc[i] >> 5) & 0x3f) << 2;
Red = ((pSrc[i] >> 11) & 0x1f) << 3;
*pDst++ = Alpha;
*pDst++ = Blue;
*pDst++ = Green;
*pDst++ = Red;
}
pHeader = (DCTEXTUREHEADER*)&BmpTex;
pHeader->Width = 256;
pHeader->Height = 256;
pHeader->Type = KM_TEXTURE_BMP;
pHeader->DataSize = 256*256*4+8;
pHeader->Id = (unsigned int) "PVRT";
}
*/ "GHWBOOSFRH1", /* Booster Frame */
(void *)&_pMesh[4], "GHWBOOSDLH0", /* Booster Dial */
(void *)&_pMesh[5], "GHWBOOSNDH0", /* Booster Needle */
(void *)&_pMesh[6], "GHWBOOSLTH0", /* Booster light */
(void *)&_pMesh[7], "GHWSPDMDLH0", /* Speedometer Dial */
NULL, NULL,
};
#else /* DREAMCAST */
static ObsysLoadDef_t _aLoadTable[] = {
(void *)&_pMesh[0], "GHWSPDMFRH0", /* Speedometer*/
(void *)&_pMesh[1], "GHWSPDMNDH0", /* Speedometer Needle*/
(void *)&_pMesh[2], "GHWSPDMNDH1", /* RPM Needle*/
(void *)&_pMesh[3], "GHWBOOSFRH1", /* Booster Frame*/
(void *)&_pMesh[4], "GHWBOOSDLH0", /* Booster Dial*/
(void *)&_pMesh[5], "GHWBOOSNDH0", /* Booster Needle*/
(void *)&_pMesh[6], "GHWBOOSLTH0", /* Booster light*/
NULL, NULL,
};
#endif /* ULTRA */
/* after race camera flash globals*/
static BOOL _bCameraFlashSystemOk;
static WorldOb_t _aCameraFlashObs[_MAX_CAMERA_FLASH_BULBS];
static FlashBulb_t _aFlashBulbs[_MAX_CAMERA_FLASH_BULBS];
static u32 _nSparkleFrameCache;
dcDebug.c
Found at 1x1C97878.
/******************************************************************************
Dreamcast Shell for Kamui and Shinobi
*******************************************************************************
dcDebug.c
Main initialisation functions
David Long '98
*******************************************************************************/
#include "dcInclude.h"
#include <sg_chain.h>
#include <sg_syhw.h> /* Hardware initialization library. */
extern Uint8* _BSG_END; /* End of BSG/BSG32 section. */
/* Program area address. */
#define P1AREA 0x80000000
/* Define work RAM end address. */
#define WORK_END (((Uint32)_BSG_END) & 0xe0000000 | 0x0d000000)
/* Modify the following values as necessary. */
/***** Ninja or Kamui *******************************/
#define USE_NINJA 0 /* 0...Use Kamui graphics library. */
/* 1...Use Ninja graphics library (DEFAULT). */
/***** Heap Location at end of Section B ***********/
#define USE_B_END 1 /* 0...No heap at Section B, specify HEAP_SIZE manually. */
/* 1...Heap located at end of Section B (DEFAULT) */
/* Total memory capacity available for syMalloc() is approximately 4MB. */
/* Define HEAP_SIZE only if heap not located at end of Section B. */
#if !USE_B_END
#define HEAP_SIZE 0x004000004
#endif
#define MODE_2V
#ifdef MODE_2V
#define VBUFFER_SIZE (400000) /* Size of Kamui vertex buffer in dwords */
#else
#define VBUFFER_SIZE (1024*1024)
#endif
/* Size of vertex buffer. */
/* Declaration of global work area. */
Uint8 gMapleRecvBuf[1024 * 24 * 2 + 32];
Uint8 gMapleSendBuf[1024 * 24 * 2 + 32];
/* Heap area for use by syMalloc(). */
#if USE_B_END
#define HEAP_AREA ((void*)((((Uint32)_BSG_END | P1AREA) & 0xffffffe0) + 0x20))
#define HEAP_SIZE (WORK_END - (Uint32)HEAP_AREA)
#else
#define HEAP_AREA ((void*)((Uint32)WORK_END - (Uint32)HEAP_SIZE))
#endif
static PKMSURFACEDESC psurface[2]; /* array of pointers to surfaces */
static KMPACKEDARGB border;
static KMSURFACEDESC PrimarySurfaceDesc; /* Primary frame buffer */
static KMSURFACEDESC BackSurfaceDesc; /* Back-buffer frame buffer */
KMVERTEXBUFFDESC VertexBufferDesc; /* Vertex-buffer */
#ifndef MODE_2V
static KMSYSTEMCONFIGSTRUCT kmsc = {
sizeof(KMSYSTEMCONFIGSTRUCT),
KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER, /* set any special flags = clear frame buffer */
psurface, /* pointer to array of surface pointers */
2, /* number of buffers = 2 */
640,480, /* width and height of surface */
KM_DSPBPP_RGB565, /* bits per pixel */
0x100000, /* allocate amount of VRAM for texture = 4MB */
&VertexBufferDesc, /* pointer to vertex buffer descriptor */
0, /* pointer to vertex buffer - ** malloc now on application side */
VBUFFER_SIZE, /* size in DWORDS of vertex buffer - must be multiple of 32 */
{60.f,0.f,20.f,0.f,20.f}, /* percentage of vbuf to use for each type of vertex */
0,0,0,0,0,0,0, /* reserved */
KM_VERTEXBUFMODEL_NORMAL /* latency model = 3VB */
};
#else
KMSYSTEMCONFIGSTRUCT kmsc =
{
sizeof(KMSYSTEMCONFIGSTRUCT),
KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER /* Special flags (i.e. clear frame buffer). */
| KM_CONFIGFLAG_ENABLE_2V_LATENCY
,psurface, /* Pointer to array of FB surface pointers. */
2, /* number of buffers = 2 */
640,480, /* width and height of surface */
KM_DSPBPP_RGB565, /* Bits per pixel. */
0x100000,
hud.c
Found at 1x192C800.
k( TRUE );
} else if( _fTimer >= 2.1f ) {
if( !_bCalledPreGoHydroStart ) {
_bCalledPreGoHydroStart = TRUE;
phys_HydroStart_PreGo();
}
} else if( _fTimer >= 2.0f ) {
if( _nTextState != _TEXT_1 ) {
hud_text_SetFlag( FALSE, HUD_TEXT_FLAGS_DRAW_2 );
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_DRAW_1 );
audio_mgr_TriggerSpeech( AUDIOMGR_SPEECH_1 );
}
_nTextState = _TEXT_1;
} else if ( _fTimer >= 1.0f ) {
if( _nTextState != _TEXT_2 ) {
hud_text_SetFlag( FALSE, HUD_TEXT_FLAGS_DRAW_3 );
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_DRAW_2 );
audio_mgr_TriggerSpeech( AUDIOMGR_SPEECH_2 );
}
_nTextState = _TEXT_2;
}
_fTextTimer = _fTimer;
break;
case HUD_GO:
/* increment our game timers*/
Player_fElapsedSecs += Gameloop_fTargetFrameTime;
/* count down the time, if timers are turned on*/
if( !Temp_bNoTimers ) {
Player_fCountdownSecs -= Gameloop_fTargetFrameTime;
if( Player_fCountdownSecs <= 0.0f ) {
Player_fCountdownSecs = 0.0f;
}
}
/* maintain go timer*/
_fTimer += Gameloop_fTargetFrameTime;
if( _fTimer >= _GO_TIME_SECS ) {
hud_SwitchBoard( HUD_REGULAR_GAME );
hud_wrongway_Enable( TRUE );
_nTextState = _TEXT_NONE;
hud_text_SetFlag( FALSE, HUD_TEXT_FLAGS_DRAW_GO );
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_PUSH_THROTTLE );
}
break;
case HUD_REGULAR_GAME:
/* increment our game timers*/
Player_fElapsedSecs += Gameloop_fTargetFrameTime;
/* count down the time, if timers are turned on and no human has crossed the finish line*/
if( !Temp_bNoTimers && !_bFinishLineCrossed) {
Player_fCountdownSecs -= Gameloop_fTargetFrameTime;
if( Player_fCountdownSecs <= 0.0f ) {
Player_fCountdownSecs = 0.0f;
}
}
/* has a human player crossed the finish line?*/
if( _bFinishLineCrossed ) {
if( _bFreeRaceTime ) {
/* set up a time period after somebody crosses the finish line */
/* where the other racers can try to finish too*/
_fTimer = 0.0f;
_bFreeRaceTime = TRUE;
} else {
/* keep an eye on the timer, then set the boats to drift*/
_fTimer += Gameloop_fTargetFrameTime;
if( _fTimer >= _RACE_AFTER_FINISH_SECS ) {
if( !_bDrift ) {
/* setup the drift period*/
_fTimer = 0.0f;
_bDrift = TRUE;
player_EnableBoatDrift( TRUE );
} else {
/* keep an eye on the timer, then set the fade out*/
_fTimer += Gameloop_fTargetFrameTime;
if( _fTimer >= _DRIFT_AFTER_FINISH_SECS ) {
/* drift time is over, start the fade out*/
_fScreenFadeIntensity = 0.0f;
_fTimer = 0.0f;
hud_SwitchBoard( HUD_FADE_OUT );
race_LockPlayersRank();
hud_wrongway_Enable( FALSE );
/* if we have not crossed the finish line yet, we must be a loser*/
if( Player_aData[Player_nHuman].fFinishTime == 0.0f ) {
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_GAME_OVER );
audio_mgr_PlayWinnerLoserMusic( FALSE );
/* record our finish states with the auditor*/
auditor_FinishInfo( AUDITOR_METHODS_DID_NOT_FINISH,
Player_aData[Player_nHuman].fFinishTime,
Player_aData[Player_nFirstPlace].fFinishTime,
Player_fElapsedSecs,
Player_aData[Player_nHuman].nPlace,
Player_fCountdownSecs,
Player_aData[Player_nHuman].Phys.fUnitSuckness );
} else {
/* record our finish states with the auditor*/
auditor_FinishInfo( AUDITOR_METHODS_FINISHED,
Player_aData[Player_nHuman].fFinishTime,
Player_aData[Player_nFirstPlace].fFinishTime,
Player_fElapsedSecs,
Player_aData[Player_nHuman].nPlace,
Player_fCountdownSecs,
Player_aData[Player_nHuman].Phys.fUnitSuckness );
}
/* turn off some of the text elements*/
hud_text_SetFlag( FALSE,
HUD_TEXT_FLAGS_DRAW_RANK |
HUD_TEXT_FLAGS_DRAW_COUNTDOWN |
HUD_TEXT_FLAGS_ELAPSED_TIME |
HUD_TEXT_FLAGS_SBOOSTER |
HUD_TEXT_FLAGS_LBOOSTER |
HUD_TEXT_FLAGS_PUSH_THROTTLE |
HUD_TEXT_FLAGS_TIME_EXTENDED |
HUD_TEXT_FLAGS_SPLIT_TIME );
}
}
}
}
}
/* are we out of time?*/
else if( Player_fCountdownSecs == 0.0f ) {
if( !_bDrift ) {
/* setup the drift period*/
_fTimer = 0.0f;
_bDrift = TRUE;
player_EnableBoatDrift( TRUE );
} else {
_fTimer += Gameloop_fTargetFrameTime;
if( _fTimer >= _DRIFT_AFTER_TIMEOUT_SECS ) {
/* drift time is over, start the fade out*/
_fScreenFadeIntensity = 0.0f;
_fTimer = 0.0f;
/* disable all but the finishline tripwire*/
tripwire_TurnSystemOff();
hud_SwitchBoard( HUD_FADE_OUT );
race_LockPlayersRank();
hud_wrongway_Enable( FALSE );
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_TIME_EXPIRED );
/* turn off some of the text elements*/
hud_text_SetFlag( FALSE,
HUD_TEXT_FLAGS_DRAW_RANK |
HUD_TEXT_FLAGS_DRAW_COUNTDOWN |
HUD_TEXT_FLAGS_ELAPSED_TIME |
HUD_TEXT_FLAGS_SBOOSTER |
HUD_TEXT_FLAGS_LBOOSTER |
HUD_TEXT_FLAGS_PUSH_THROTTLE |
HUD_TEXT_FLAGS_TIME_EXTENDED |
HUD_TEXT_FLAGS_SPLIT_TIME );
/* record our finish states with the auditor*/
auditor_FinishInfo( AUDITOR_METHODS_OUT_OF_TIME,
Player_aData[Player_nHuman].fFinishTime,
Player_aData[Player_nFirstPlace].fFinishTime,
Player_fElapsedSecs,
Player_aData[Player_nHuman].nPlace,
Player_fCountdownSecs,
Player_aData[Player_nHuman].Phys.fUnitSuckness );
}
}
} else {
/* nobody has crossed the finish and we still have time in the race*/
if( _nLastFramesPosition != 8624 ) {
/* handle multi or single player place*/
if( Player_nHumanCount > 1 ) {
if( _nLastFramesPosition != Player_nLocalPlaceAmongHumans ) {
_nLastFramesPosition = Player_nLocalPlaceAmongHumans;
audio_mgr_PlaceChange( _nLastFramesPosition );
}
} else {
if( _nLastFramesPosition != Player_aData[Player_nHuman].nPlace ) {
_nLastFramesPosition = Player_aData[Player_nHuman].nPlace;
audio_mgr_PlaceChange( _nLastFramesPosition );
}
}
} else {
/* handle multi or single player place*/
_nLastFramesPosition = ( Player_nHumanCount > 1 ) ? Player_nLocalPlaceAmongHumans : Player_aData[Player_nHuman].nPlace;
}
}
_fTextTimer += Gameloop_fTargetFrameTime;
break;
case HUD_FADE_OUT:
/* increment our game timers*/
Player_fElapsedSecs += Gameloop_fTargetFrameTime;
/* count down the time, if timers are turned on*/
if( !Temp_bNoTimers && !_bFinishLineCrossed) {
Player_fCountdownSecs -= Gameloop_fTargetFrameTime;
if( Player_fCountdownSecs <= 0.0f ) {
Player_fCountdownSecs = 0.0f;
}
}
_fScreenFadeIntensity += _FADE_STEP_SIZE;
if( _fScreenFadeIntensity >= 1.0f ) {
_fScreenFadeIntensity = 1.0f;
hud_SwitchBoard( HUD_DONE );
audio_GameIDFadeOutAndStop( SOUNDCALL_FINISHLINE_CROWD, 3.0f );
_fTimer = 0.0f;
hud_TurnOffCameraFlashes();
}
_fTextTimer += Gameloop_fTargetFrameTime;
break;
case HUD_DONE:
/* just display black for a very short while and then end the race*/
_fTimer += Gameloop_fTargetFrameTime;
if( _fTimer >= _DISPLAY_BLACK_TIME ) {
_fTimer = 0.0f;
bReturnValue = TRUE;
} else if( _fTimer >= (_DISPLAY_BLACK_TIME * 0.20f) ) {
/* stop all flashing and force the text on for the rest of the time*/
hud_text_ForceOn();
}
_fTextTimer += Gameloop_fTargetFrameTime;
break;
}
return bReturnValue;
}
/* must still call hud_ConstructRadarInfo(1) at the beginning of the work functions*/
void hud_Draw()
{
u32 nPriorZbufState;
Mesh3dAmbient_t Ambient;
/* only draw the hud if everything was loaded okay*/
if( _bTexturesLoaded ) {
/* set the hud color by looking into the human player's worldob*/
hud_SetColor( Player_aData[Player_nHuman].pWorldOb->SensedLight.argb[2],
Player_aData[Player_nHuman].pWorldOb->SensedLight.argb[1],
Player_aData[Player_nHuman].pWorldOb->SensedLight.argb[0], 0);
// Player_aData[Player_nHuman].pWorldOb->SensedLight.argb[3] );
material_PushState();
material_Defaults();
mesh3d_GetAmbientLightState( &Ambient );
/* don't compare these pixels and don't write to the z buffer*/
nPriorZbufState = gutil_ZbufferSetState ( GUTIL_ZBUFFER_STATE_WRITE_ONLY );
/* now that everything is set up, draw the elements that make */
/* up the hud for whatever state we are currently in */
switch (Hud_nState)
{
case HUD_INIT_AND_READY:
/* we only need to fade the screen, and any lens flare, in at this point*/
anim_air_DoLensFlare();
gutil_DrawBlackOrWhiteScreenFade( _fScreenFadeIntensity, TRUE );
break;
case HUD_BEGIN:
/* continue fading the screen up, but now draw the hud too*/
_DrawLensFlareAndHud();
gutil_DrawBlackOrWhiteScreenFade( _fScreenFadeIntensity, TRUE );
break;
case HUD_COUNTDOWN:
_DrawLensFlareAndHud();
break;
case HUD_GO:
_DrawLensFlareAndHud();
break;
case HUD_REGULAR_GAME:
#if _DRAW_HUD_AFTER_LENS_FLARE
anim_air_DoLensFlare();
_DrawHud();
#else
_DrawHud();
anim_air_DoLensFlare();
#endif
break;
case HUD_FADE_OUT:
_DrawLensFlareAndHud();
/* fade the screen up*/
gutil_DrawBlackOrWhiteScreenFade( _fScreenFadeIntensity, TRUE );
break;
case HUD_DONE:
/* since the screen is black is at this point, go ahead and fill the screen with black*/
if(!bEUROCOM_SPLITSCREEN){
grConstantColorValue(0xff000000);
gutil_DrawSolidBox(0, 639, 0, 479);
}
break;
}
/* draw all text overlays*/
if( _bDrawHud ) {
hud_text_Draw( _fDxCache, _fDyCache, _fTextTimer );
}
/* restore z buffer state*/
gutil_ZbufferSetState( nPriorZbufState );
material_PopState(1);
mesh3d_SetAmbientLightState( &Ambient );
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f );
}
}
void hud_EnableDisplay( BOOL bEnable ) {
_bDrawHud = bEnable;
}
f32 hud_GetCameraFlashWhiteSat( void ) {
return _fLastCameraFlashWhiteSat;
}
/* arrange for all camera flashes to be turned off*/
void hud_TurnOffCameraFlashes( void ) {
u32 i;
FlashBulb_t *pPtr;
for( i=0; i < _MAX_CAMERA_FLASH_BULBS; i++ ) {
pPtr = (FlashBulb_t *)_aCameraFlashObs[i].pUserObject;
pPtr->bKillWorldOb = TRUE;
}
}
/*=======================================================================*/
/* Private Functions:*/
/* fades the hud in (direction == 1) or out (direction == -1) all other values are ignored*/
/* returns TRUE when the fade is complete, or FALSE if the fade is not done yet*/
static BOOL _FadeHud( int direction ) {
static BOOL bReset = TRUE;
static f32 fTimer = 0.0f;
if( bReset ) {
if( direction == 1 ) {
_fOpaqueness = 0.0f;
bReset = FALSE;
} else if( direction == -1 ) {
_fOpaqueness = 1.0f;
bReset = FALSE;
}
} else if( direction == 1 ) {
/* do the fade in work*/
_fOpaqueness += _FADE_IN_DELTA;
if( _fOpaqueness > 1.0f ) {
_fOpaqueness = 1.0f;
}
/* check the timer*/
fTimer += Gameloop_fTargetFrameTime;
if( fTimer >= _FADE_IN_LENGTH ) {
_fOpaqueness = 1.0f;
fTimer = 0.0f;
bReset = TRUE;
return TRUE;
}
} else if( direction == -1 ) {
/* do the fade out work*/
_fOpaqueness -= _FADE_OUT_DELTA;
if( _fOpaqueness < 0.0f ) {
_fOpaqueness = 0.0f;
}
/* check the timer*/
fTimer += Gameloop_fTargetFrameTime;
if( fTimer >= _FADE_OUT_LENGTH ) {
_fOpaqueness = 0.0f;
fTimer = 0.0f;
bReset = TRUE;
return TRUE;
}
}
/* if we made it here, this must not be the last frame*/
return FALSE;
}
/* draw the speedometer and related devices, this call will draw parts of the hud which are */
/* drawn for every hud mode, any special cases should have their own function*/
static void _DrawHud( void ) {
/* only draw the hud if it is currently on*/
if( !_bDrawHud ) {
return;
}
#if TARGET==ULTRA64 /*Group HUD objects together for n64*/
InitDrawHudN64();
#endif /*ULTRA64*/
/*********************/
/* draw the radar map**/
/*********************/
if(!bEUROCOM_SPLITSCREEN)
hud_radar_Draw( _fRIntensity, _fGIntensity, _fBIntensity, _fOpaqueness, _fWhiteSat );
/***********************/
/* draw the speedometer**/
/***********************/
_DrawSpeedometer();
/*************************/
/* draw booster indicator**/
/*************************/
_DrawBoosterIndicator();
#if TARGET==ULTRA64 /*Group HUD objects together for n64*/
EndDrawHudN64();
#endif /*ULTRA64*/
}
static void _DrawLensFlareAndHud( void ) {
#if _DRAW_HUD_AFTER_LENS_FLARE
anim_air_DoLensFlare();
_DrawHud();
#else
_DrawHud();
anim_air_DoLensFlare();
#endif
}
static void _DrawBoosterIndicator( void ) {
f32 fPercent;
BOOL bDraw;
u32 nTemp;
u32 nBoosterOffsetX = 0;
u32 nBoosterOffsetY = 0;
if(bEUROCOM_SPLITSCREEN){
nBoosterOffsetX = 422.0f;
nBoosterOffsetY = 100.0f;
}
/***********************/
/* draw the booster dial*/
/***********************/
if( Player_aData[Player_nHuman].Powerup.fBoosterTime == 0.0f ) {
/* the dial is off, dim it a little*/
mesh3d_SetOrthoEffects( 0.4f, 0.4f, 0.4f, _fOpaqueness, 0.0f );
} else {
/* the dial is on, give it a yellowish little look*/
mesh3d_SetOrthoEffects( 0.93f, 0.93f, 0.67f, _fOpaqueness, 0.0f );
}
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_DIAL],
_aDrawPos[_PARTS_BOOSTER].p[0] + 3.0f + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER].p[1] + nBoosterOffsetY,
_Z_DEPTH,
0,
_SCALE );
/************************************/
/* draw the booster needle and shadow*/
/************************************/
if( Player_aData[Player_nHuman].Powerup.fBoosterTime > 0.0f ) {
if( Player_aData[Player_nHuman].Powerup.fBoosterTime <= POWERUP_MAX_BOOST_ALLOWED ) {
fPercent = POWERUP_OOMAX_BOOST_ALLOWED * Player_aData[Player_nHuman].Powerup.fBoosterTime;
} else {
fPercent = 1.0f;
}
fPercent *= _BOOSTER_NEEDLE_RANGE;
fPercent += _BOOSTER_MIN_ANGLE;
_nLastBoosterNeedlePos = xmath_AngleInterpolate( _nLastBoosterNeedlePos, (s16)fPercent, 0.15f );
} else {
_nLastBoosterNeedlePos = _BOOSTER_MIN_ANGLE;
}
/* draw the booster needle shadow*/
#if TARGET==ULTRA64 /*Draw boost needle*/
if (UseHiRes)
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_BOOST_NEEDLE,(u32)_pMesh[_MESHES_BOOSTER_NEEDLE]+16*2,_pMesh[_MESHES_BOOSTER_NEEDLE],16,23, (_aDrawPos[_PARTS_BOOSTER].p[0]*(320-32)/512)-6,N64_SCRYVERT(_aDrawPos[_PARTS_BOOSTER].p[1])-1, -6,16,6,0, _nLastBoosterNeedlePos - 1000,0xff);
else
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_BOOST_NEEDLE,(u32)_pMesh[_MESHES_BOOSTER_NEEDLE]+16*2,_pMesh[_MESHES_BOOSTER_NEEDLE],16,23, N64_SCRXVERT(_aDrawPos[_PARTS_BOOSTER].p[0])+1,N64_SCRYVERT(_aDrawPos[_PARTS_BOOSTER].p[1])-2, -6,16,6,0, _nLastBoosterNeedlePos - 1000,0xff);
#else /*ULTRA64*/
mesh3d_SetOrthoEffects( 0.0f, 0.0f, 0.0f, _fOpaqueness * 0.50f, 0.0f );
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_NEEDLE],
_aDrawPos[_PARTS_BOOSTER].p[0] + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER].p[1] + nBoosterOffsetY,
_Z_DEPTH,
_nLastBoosterNeedlePos - 1000,
_SCALE );
if( Player_aData[Player_nHuman].Powerup.fBoosterTime == 0.0f ) {
/* the dial is off, dim it a little*/
mesh3d_SetOrthoEffects( 0.4f, 0.4f, 0.4f, _fOpaqueness, 0.0f );
} else {
/* the dial is on*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, _fOpaqueness, 0.0f );
}
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_NEEDLE],
_aDrawPos[_PARTS_BOOSTER].p[0] + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER].p[1] + nBoosterOffsetY,
_Z_DEPTH,
_nLastBoosterNeedlePos,
_SCALE );
#endif /*ULTRA64*/
/************************/
/* draw the booster frame*/
/************************/
#if TARGET==ULTRA64 /*Draw booster frame+alpha*/
AddHudN64Obj_DrawOrtho2(DRAWORTHO_BOOST_SURROUND,
_pMesh[_MESHES_BOOSTER_FRAME],
_aDrawPos[_PARTS_BOOSTER].p[0],
_aDrawPos[_PARTS_BOOSTER].p[1],
_Z_DEPTH,
0,
_SCALE,
0,0,0, _pMesh[_MESHES_BOOSTER_FRAME]->nFlags&~MESH3D_FLAG_N64ALPHA );
// Overlay 'alpha' on top(Material index 1)
// AddHudN64Obj_DrawOrtho2(DRAWORTHO_BOOST_ALPHA,
// _pMesh[_MESHES_BOOSTER_FRAME],
// _aDrawPos[_PARTS_BOOSTER].p[0],
// _aDrawPos[_PARTS_BOOSTER].p[1],
// _Z_DEPTH,
// 0,
// _SCALE,
// 0,0,1, _pMesh[_MESHES_BOOSTER_FRAME]->nFlags|MESH3D_FLAG_N64ALPHA );
#else /*ULTRA64*/
mesh3d_SetOrthoEffects( _fRIntensity, _fGIntensity, _fBIntensity, _fOpaqueness, _fWhiteSat );
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_FRAME],
_aDrawPos[_PARTS_BOOSTER].p[0] + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER].p[1] + nBoosterOffsetY,
_Z_DEPTH,
0,
_SCALE );
#endif /*ULTRA64*/
/**********************/
/* draw the booster LED*/
/**********************/
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaColours = TRUE;
#endif /*ULTRA64*/
if( Player_aData[Player_nHuman].Powerup.fBoosterTime > 0.0f ) {
fPercent = POWERUP_OOMAX_BOOST_ALLOWED * Player_aData[Player_nHuman].Powerup.fBoosterTime;
if( fPercent < 0.10f ) {
nTemp = Gameloop_nFrameCounter & 0x7;
bDraw = ( nTemp <= 0x4 );
/* color the light red*/
mesh3d_SetOrthoEffects( 1.0f, 0.0f, 0.0f, _fOpaqueness, 0.0f );
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaTrans = OverrideAlphaOpaque = 0x1f<<11;
#endif /*ULTRA64*/
if( (nTemp == 0) &&
(Player_aData[Player_nHuman].Controls.nButtons & CONTROLS_THROTTLE_BUTTON) &&
(Player_aData[Player_nHuman].fFinishTime == 0.0f) ) {
audio_Trigger( SOUNDCALL_HYDRO_BOOST_LOW_WARNING,
240,
AUDIO_PAN_CABINET,
AUDIO_TYPE_GENERAL,
AUDIO_PRIORITY_GENERAL );
}
} else if( fPercent < 0.20f ) {
nTemp = Gameloop_nFrameCounter & 0xF;
bDraw = ( nTemp <= 0x8 );
/* color the light red*/
mesh3d_SetOrthoEffects( 1.0f, 0.0f, 0.0f, _fOpaqueness, 0.0f );
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaTrans = OverrideAlphaOpaque = 0x1f<<11;
#endif /*ULTRA64*/
if( (nTemp == 0) &&
(Player_aData[Player_nHuman].Controls.nButtons & CONTROLS_THROTTLE_BUTTON) &&
(Player_aData[Player_nHuman].fFinishTime == 0.0f) ) {
audio_Trigger( SOUNDCALL_HYDRO_BOOST_LOW_WARNING,
255,
AUDIO_PAN_CABINET,
AUDIO_TYPE_GENERAL,
AUDIO_PRIORITY_GENERAL );
}
} else if( fPercent < 0.33f ) {
bDraw = TRUE;
/* color the light red*/
mesh3d_SetOrthoEffects( 1.0f, 0.0f, 0.0f, _fOpaqueness, 0.0f );
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaTrans = OverrideAlphaOpaque = 0x1f<<11;
#endif /*ULTRA64*/
} else if( fPercent < 0.66f ) {
bDraw = TRUE;
/* color the light yellow*/
mesh3d_SetOrthoEffects( 0.65f, 1.0f, 0.0f, _fOpaqueness, 0.0f );
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaTrans = OverrideAlphaOpaque = (0x1f<<11) | (0x1f<<6);
#endif /*ULTRA64*/
} else {
bDraw = TRUE;
/* color the light green*/
mesh3d_SetOrthoEffects( 0.2f, 1.0f, 0.2f, _fOpaqueness, 0.0f );
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaTrans = OverrideAlphaOpaque = (0x1f<<6);
#endif /*ULTRA64*/
}
if( bDraw ) {
#if TARGET==ULTRA64
AddHudN64Obj_DrawOrtho(DRAWORTHO_BOOST_LED,
_pMesh[_MESHES_BOOSTER_LIGHT],
_aDrawPos[_PARTS_BOOSTER_LED].p[0],
_aDrawPos[_PARTS_BOOSTER_LED].p[1],
_Z_DEPTH,
0,
_SCALE );
#else /*ULTRA64*/
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_LIGHT],
_aDrawPos[_PARTS_BOOSTER_LED].p[0] + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER_LED].p[1] + nBoosterOffsetY,
_Z_DEPTH,
0,
_SCALE );
#endif /*ULTRA64*/
}
} else {
mesh3d_SetOrthoEffects( 1.0f, 0.0f, 0.0f, _fOpaqueness * 0.1f, 0.0f );
#if TARGET!=ULTRA64 /*Boost led*/
mesh3d_DrawOrtho( _pMesh[_MESHES_BOOSTER_LIGHT],
_aDrawPos[_PARTS_BOOSTER_LED].p[0] + nBoosterOffsetX,
_aDrawPos[_PARTS_BOOSTER_LED].p[1] + nBoosterOffsetY,
_Z_DEPTH,
0,
_SCALE );
#endif /*ULTRA64*/
}
#if TARGET==ULTRA64 /*Boost led*/
OverrideAlphaColours = FALSE;
#endif /*ULTRA64*/
}
static void _DrawSpeedometer( void ) {
f32 fTemp, fSpeed, fRpm;
u32 i;
int nDelta, nNeedlePos;
#if TARGET==ULTRA64 /*Draw speedo dial*/
AddHudN64Obj_DrawOrtho(DRAWORTHO_SPEEDO_DIAL,
_pMesh[_MESHES_SPEED_DIAL],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
0,
_SCALE );
#elif TARGET==DREAMCAST
mesh3d_DrawOrtho( _pMesh[_MESHES_SPEED_DIAL],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
0,
_SCALE );
#else /*ULTRA64*/
/*******************************/
/* draw the speedometer backing**/
/*******************************/
material_ColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_LOCAL,
GR_COMBINE_LOCAL_ITERATED,
GR_COMBINE_OTHER_TEXTURE,
FXFALSE );
material_AlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
GR_COMBINE_FACTOR_TEXTURE_ALPHA,
GR_COMBINE_LOCAL_CONSTANT,
GR_COMBINE_OTHER_ITERATED,
FXFALSE );
material_ConstantColorValue( GFXDEFS_FLOATARGB_TO_GRCOLOR( _fWhiteSat, 1.0f, 1.0f, 1.0f ) );
#if TARGET==DREAMCAST
nTexture = _pSpeedometer->aTMUTexInfo[0].nTmemStartAddress;
if(nTexture != -1){
/* Disable z-buffer */
if(dcTextureTable[nTexture].AlphaBlendedTexVC.DepthMode != KM_ALWAYS){
dcTextureTable[nTexture].AlphaBlendedTexVC.RenderState = KM_DEPTHMODE;
dcTextureTable[nTexture].AlphaBlendedTexVC.DepthMode = KM_ALWAYS;
kmProcessVertexRenderState(&dcTextureTable[nTexture].AlphaBlendedTexVC);
}
dcSetCurrentVertexContext(&dcTextureTable[nTexture].AlphaBlendedTexVC);
}
#else /* DREAMCAST */
tmem_Select( _pSpeedometer );
#endif /* DREAMCAST */
tmem_SetTileMode( _pSpeedometer, FALSE, FALSE );
fTemp = _fOpaqueness * _FULL_OPAQUENESS;
for( i=0; i < 4; i++ ) {
#if TARGET==DREAMCAST
_aSpeedVtx[i].tmuvtx[0].sow = _aSpeedVtx[i].tmuvtx[1].sow / 256.0f;
_aSpeedVtx[i].tmuvtx[0].tow = _aSpeedVtx[i].tmuvtx[1].tow / 256.0f;
_aSpeedVtx[i].x = _SpeedometerXYLookup[i].p[0] + _aDrawPos[_PARTS_SPEEDOMETER_LOWER_LEFT].p[0];
_aSpeedVtx[i].y = _SpeedometerXYLookup[i].p[1] + _aDrawPos[_PARTS_SPEEDOMETER_LOWER_LEFT].p[1];
_aSpeedVtx[i].a = fTemp;
#else /* DREAMCAST */
_aSpeedVtx[i].x = GFXDEFS_SNAPVERT( _SpeedometerXYLookup[i].p[0] + _aDrawPos[_PARTS_SPEEDOMETER_LOWER_LEFT].p[0] );
_aSpeedVtx[i].y = GFXDEFS_SNAPVERT( _SpeedometerXYLookup[i].p[1] + _aDrawPos[_PARTS_SPEEDOMETER_LOWER_LEFT].p[1] );
_aSpeedVtx[i].a = fTemp;
#endif /* DREAMCAST */
}
/* draw the two triangles*/
GUTIL_DRAW_TRIANGLE( &_aSpeedVtx[0], &_aSpeedVtx[1], &_aSpeedVtx[2] );
GUTIL_DRAW_TRIANGLE( &_aSpeedVtx[0], &_aSpeedVtx[2], &_aSpeedVtx[3] );
#endif /*ULTRA64*/
/**************************************/
/* set the ortho effects for full rgb **/
/* (not affected by intensity setting)* */
/* but able to fade in and out **/
/**************************************/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, _fOpaqueness, 0.0f );
/******************************/
/* draw the speedometer needle**/
/******************************/
nNeedlePos = _NEEDLE_ZERO_OFFSET;
fSpeed = Player_aData[Player_nHuman].fSpeedMph * 0.85f;
fSpeed += ( ( (1.0f/160.0f) * fSpeed) * xmath_sin(Gameloop_nFrameCounter * 4500) );
XMATH_CLAMP( fSpeed, 0.0f, _MAX_MPH );
/* Generate an exponential curve so it appears that the speedometer matches*/
/* the boat's visual speed...*/
fSpeed *= fSpeed * (1.0f/_MAX_MPH);
nNeedlePos -= (int)(fSpeed * _BRADIANS_PER_MPH);
nDelta = nNeedlePos - _nLastNeedlePos[Player_nHuman];
if (nDelta < -_MAX_BRADIANS_PER_FRAME_MPH)
nNeedlePos = _nLastNeedlePos[Player_nHuman] - _MAX_BRADIANS_PER_FRAME_MPH;
else if (nDelta > _MAX_BRADIANS_PER_FRAME_MPH)
nNeedlePos = _nLastNeedlePos[Player_nHuman] + _MAX_BRADIANS_PER_FRAME_MPH;
_nLastNeedlePos[Player_nHuman] = nNeedlePos;
/* draw the needle shadow*/
#if TARGET==ULTRA64 /*Draw Speedo needle*/
if (UseHiRes)
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_SPEEDO_NEEDLE,(u32)_pMesh[_MESHES_SPEED_NEEDLE]+16*2,_pMesh[_MESHES_SPEED_NEEDLE],16,35, (_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0]*(320-32)/512)-6,N64_SCRYVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1])-2, -6,20,6,0, nNeedlePos + 750,0xff);
else
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_SPEEDO_NEEDLE,(u32)_pMesh[_MESHES_SPEED_NEEDLE]+16*2,_pMesh[_MESHES_SPEED_NEEDLE],16,35, N64_SCRXVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0])+1,N64_SCRYVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1])-2, -6,20,6,0, nNeedlePos + 750,0xff);
#else /*ULTRA64*/
mesh3d_SetOrthoEffects( 0.0f, 0.0f, 0.0f, _fOpaqueness * 0.5f, 0.0f );
mesh3d_DrawOrtho( _pMesh[_MESHES_SPEED_NEEDLE],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
nNeedlePos + 750,
_SCALE );
/* draw the needle*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, _fOpaqueness, 0.0f );
mesh3d_DrawOrtho( _pMesh[_MESHES_SPEED_NEEDLE],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
nNeedlePos,
_SCALE );
#endif /*ULTRA64*/
/**********************/
/* draw the rpm needle**/
/**********************/
/* figure out where to put the rpm Needle*/
nNeedlePos = _RPM_TAB_ZERO_OFFSET;
fRpm = Player_aData[Player_nHuman].fRPM;
fRpm += ( ( (1.0f/70.0f) * fRpm) * xmath_sin(Gameloop_nFrameCounter * 10000) );
if (fRpm > _MAX_RPM)
fRpm = _MAX_RPM;
else if (fRpm < 0.0f)
{
fRpm *= -1.0f;
if (fRpm > _MAX_RPM)
fRpm = _MAX_RPM;
}
nNeedlePos += (int)(fRpm * _BRADIANS_PER_RPM);
nDelta = nNeedlePos - _nLastTabPos;
if (nDelta < -_MAX_BRADIANS_PER_FRAME_RPM)
nNeedlePos = _nLastTabPos - _MAX_BRADIANS_PER_FRAME_RPM;
else if (nDelta > _MAX_BRADIANS_PER_FRAME_RPM)
nNeedlePos = _nLastTabPos + _MAX_BRADIANS_PER_FRAME_RPM;
_nLastTabPos = nNeedlePos;
#if TARGET==ULTRA64 /*Draw RPM needle*/
if (UseHiRes)
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_RPM_NEEDLE,(u32)_pMesh[_MESHES_RPM_NEEDLE]+16*2,_pMesh[_MESHES_SPEED_NEEDLE],16,32, (_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0]*(320-32)/512)-6,N64_SCRYVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1])-2, -6,18,6,0, nNeedlePos - 750,0xff);
else
AddHudN64Obj_DrawRotatedSprite(DRAWORTHO_RPM_NEEDLE,(u32)_pMesh[_MESHES_RPM_NEEDLE]+16*2,_pMesh[_MESHES_SPEED_NEEDLE],16,32, N64_SCRXVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0])+1,N64_SCRYVERT(_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1])-2, -6,18,6,0, nNeedlePos - 750,0xff);
#else /*ULTRA64*/
/* draw the needle shadow*/
mesh3d_SetOrthoEffects( 0.0f, 0.0f, 0.0f, _fOpaqueness * 0.5f, 0.0f );
mesh3d_DrawOrtho (_pMesh[_MESHES_RPM_NEEDLE],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
nNeedlePos - 750,
_SCALE );
/* draw the needle*/
mesh3d_SetOrthoEffects( 1.0f, 1.0f, 1.0f, _fOpaqueness, 0.0f );
mesh3d_DrawOrtho (_pMesh[_MESHES_RPM_NEEDLE],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
nNeedlePos,
_SCALE );
#endif /*ULTRA64*/
/*****************************/
/* draw the speedometer frame**/
/*****************************/
#if TARGET==ULTRA64 /*Draw speedo frame+alpha*/
AddHudN64Obj_DrawOrtho2(DRAWORTHO_SPEEDO_SURROUND,
_pMesh[_MESHES_SPEEDOMETER],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
0,
_SCALE,
0,0,0, _pMesh[_MESHES_SPEEDOMETER]->nFlags&~MESH3D_FLAG_N64ALPHA );
// Overlay 'alpha' on top(Material index 1)
// OverrideAlphaColours = TRUE;
// OverrideAlphaTrans = 0x0000; OverrideAlphaOpaque = 0xffff;
// AddHudN64Obj_DrawOrtho2(DRAWORTHO_SPEEDO_ALPHA,
// _pMesh[_MESHES_SPEEDOMETER],
// _aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
// _aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
// _Z_DEPTH,
// 0,
// _SCALE,
// 0,0,1, _pMesh[_MESHES_SPEEDOMETER]->nFlags|MESH3D_FLAG_N64ALPHA );
// OverrideAlphaColours = FALSE;
#else /*ULTRA64*/
mesh3d_SetOrthoEffects( _fRIntensity, _fGIntensity, _fBIntensity, _fOpaqueness, _fWhiteSat );
mesh3d_DrawOrtho( _pMesh[_MESHES_SPEEDOMETER],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[0],
_aDrawPos[_PARTS_SPEEDOMETER_CENTER].p[1],
_Z_DEPTH,
0,
_SCALE );
#endif /*ULTRA64*/
}
static void _HandleLocalHumanAfterFinishLineStuff( Player_t *pPlayer, BOOL bTieSituation ) {
f32 fBestTime;
u32 nPlace;
BOOL bNewHighScore;
/* turn on the finish stats*/
fBestTime = hi_score_GetBestTrackTime( Tracks_nCurrentTrack );
bNewHighScore = ( hi_score_WhatPlaceIsThisScore( pPlayer->fFinishTime, Tracks_nCurrentTrack ) > -1 );
hud_text_SetupFinishStats( fBestTime,
Hi_Score_Table.Table[Tracks_nCurrentTrack][0].cInitials[0],
Hi_Score_Table.Table[Tracks_nCurrentTrack][0].cInitials[1],
Hi_Score_Table.Table[Tracks_nCurrentTrack][0].cInitials[2],
bNewHighScore );
/* turn off some of the other text elements*/
hud_text_SetFlag( FALSE,
HUD_TEXT_FLAGS_DRAW_RANK |
HUD_TEXT_FLAGS_DRAW_COUNTDOWN |
HUD_TEXT_FLAGS_ELAPSED_TIME |
HUD_TEXT_FLAGS_SBOOSTER |
HUD_TEXT_FLAGS_LBOOSTER |
HUD_TEXT_FLAGS_PUSH_THROTTLE |
HUD_TEXT_FLAGS_TIME_EXPIRED |
HUD_TEXT_FLAGS_SPLIT_TIME |
HUD_TEXT_FLAGS_GAME_OVER |
HUD_TEXT_FLAGS_TIME_EXTENDED );
hud_wrongway_Enable( FALSE );
_fTextTimer = 0.0f;
/* handle multi or single player place cases*/
// nPlace = ( Player_nHumanCount > 1 ) ? Player_nLocalPlaceAmongHumans : pPlayer->nPlace;
nPlace = pPlayer->nPlace;
if( nPlace == 1 ) {
/* we are the winner of this game*/
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_WINNER );
audio_mgr_PlayWinnerLoserMusic( TRUE );
} else {
audio_mgr_PlayWinnerLoserMusic( FALSE );
}
if( pPlayer->fFinishTime < fBestTime ) {
audio_mgr_FinishLine( nPlace, TRUE );
} else {
audio_mgr_FinishLine( nPlace, FALSE );
}
// If player was first updated unlocking mechanism
if(nPlace == 1)
bonuskeys_UpdateTrackUnlockingSystem();
/* see if this person has won a free game*/
Player_bHumanWonFreeRace = player_ShouldWeAwardAFreeRace( pPlayer->nPlace, Player_nLocalPlaceAmongHumans );
if( Player_bHumanWonFreeRace ) {
hud_text_SetFlag( TRUE, HUD_TEXT_FLAGS_FREE_RACE_WON );
}
if( !bTieSituation && nPlace == 1 ) {
if(!bEUROCOM_SPLITSCREEN){
/* only change the camera the first time this function is called, not for tie resolution situations*/
race_SetupWinnerCamera( Player_nHuman );
_TurnOnCameraFlashes( pPlayer );
}
}
}
static void _InitCameraFlashSystem( void ) {
WorldOb_t *pWorldOb;
Mesh3d_t *pMesh;
u32 i;
FlashBulb_t *pPtr;
_bCameraFlashSystemOk = FALSE;
pMesh = (Mesh3d_t *)obsys_Load( "G_FGLOWSLHA" );
if( pMesh ) {
for( i=0; i < _MAX_CAMERA_FLASH_BULBS; i++ ) {
pWorldOb = &_aCameraFlashObs[i];
worldob_InitMesh( pWorldOb, pMesh );
pPtr = &_aFlashBulbs[i];
pPtr->bTurnOn = FALSE;
pPtr->nOffFrames = (i % _FRAMES_BETWEEN_SPARKLES);
pPtr->nRoll = i * 3456;
pPtr->fOpacity = 0.0f;
pPtr->fScaleStep = 0.0f;
pPtr->bKillWorldOb = FALSE;
pPtr->fScale = 1.0f;
/* turn the draw off, make sure it posters when it is drawn and is drawn after the water*/
pWorldOb->nFlags |= ( WORLDOB_FLAG_DONT_DRAW | WORLDOB_FLAG_DRAW_AFTER_WATER | WORLDOB_FLAG_STATIONARY );
pWorldOb->pUserObject = pPtr;
/* Set the work and draw functions*/
pWorldOb->pWorkFcn = _WorkSparkle;
pWorldOb->pDrawFcn = _DrawSparkle;
}
_bCameraFlashSystemOk = TRUE;
_nSparkleFrameCache = 0;
_nNumSparklesThisFrame = 0;
_fCameraFlashWhiteSat = 0.0f;
_fLastCameraFlashWhiteSat = 0.0f;
xfm_Identity( &_IdentityXfm );
_fDrawMinX = -(Viewport_half_hres_f + 65.0f);
_fDrawMaxX = Viewport_half_hres_f + 65.0f;
_fDrawMinY = -(Viewport_half_vres_f + 75.0f);
_fDrawMaxY = Viewport_half_vres_f + 75.0f;
pOwner = NULL;
_nLastIndex = 0;
}
}
static void _TurnOnCameraFlashes( Player_t *pPlayer ) {
u32 i;
WorldOb_t *pWorldOb;
f32 fWaterHeight, fHeight;
Orient_t *pOrient;
if( !_bCameraFlashSystemOk ) {
return;
}
pWorldOb = pPlayer->pWorldOb;
pOrient = &pPlayer->pWorldOb->Orient;
fWaterHeight = water_GetHeight( pWorldOb->Tws.pCenterSector, pOrient->Pos.p[0], pOrient->Pos.p[2] ) + _WATER_Y_OFFSET;
for( i=0; i < _MAX_CAMERA_FLASH_BULBS; i++ ) {
pWorldOb = &_aCameraFlashObs[i];
fHeight = fWaterHeight + ( xmath_RandomFloat() * _SPARKLE_Y_RANGE );
vec3_Set( &pWorldOb->Orient.Pos, pOrient->Pos.p[0], fHeight, pOrient->Pos.p[2] );
worldob_Add( pWorldOb, NULL );
}
_nSparkleFrameCache = 0;
_nNumSparklesThisFrame = 0;
_fCameraFlashWhiteSat = 0.0f;
_fLastCameraFlashWhiteSat = 0.0f;
audio_TriggerAndFadeIn( SOUNDCALL_FINISHLINE_CROWD,
200,
0.65f,
AUDIO_PAN_CABINET,
AUDIO_TYPE_FINISHLINE,
AUDIO_PRIORITY_FINISHLINE );
pOwner = &pOrient->Pos;
}
static void _WorkSparkle( WorldOb_t *pWorldOb ) {
FlashBulb_t *pPtr = (FlashBulb_t *)pWorldOb->pUserObject;
f32 fRandom, fScale;
u32 nIndex;
if( _nSparkleFrameCache != Gameloop_nFrameCounter ) {
_nSparkleFrameCache = Gameloop_nFrameCounter;
_nNumSparklesThisFrame = 0;
_fLastCameraFlashWhiteSat = _fCameraFlashWhiteSat;
_fCameraFlashWhiteSat = 0.0f;
}
/* this this particle off*/
if( pWorldOb->nFlags & WORLDOB_FLAG_DONT_DRAW ) {
if( !pPtr->bKillWorldOb ) {
++pPtr->nOffFrames;
if( _nNumSparklesThisFrame < _MAX_SPARKLES_ON_PER_FRAME && pPtr->nOffFrames > _FRAMES_BETWEEN_SPARKLES ) {
/* see if we should turn this sparkle on*/
fRandom = xmath_RandomFloat();
if( fRandom < _SPARKLE_ON_PROBABLITY ) {
++_nNumSparklesThisFrame;
pWorldOb->nFlags &= ~WORLDOB_FLAG_DONT_DRAW;
fRandom *= _SPARKLE_UNITIZE_PROBABLITY;
pPtr->fScale = _SPARKLE_MIN_SCALE;
pPtr->bTurnOn = TRUE;
pPtr->nRoll += _SPARKLE_ROT_PER_FRAME;
fScale = (2.5f * _SPARKLE_MIN_SCALE) + ( fRandom * _SPARKLE_MAX_SCALE );
pPtr->fScaleStep = (fScale - _SPARKLE_MIN_SCALE) * _SPARKLE_STEP_SIZE;
pPtr->fOpacity = 0.05f;
nIndex = xmath_RandomChoice( _MAX_CAMERA_FLASH_BULBS );
if( nIndex == _nLastIndex ) {
nIndex = _nLastIndex = 0;
}
pWorldOb->Orient.Pos.p[0] = pOwner->p[0] + ( _aFlashPos[nIndex].p[0] * _SPARKLE_DISTANCE_SCALE );
pWorldOb->Orient.Pos.p[2] = pOwner->p[2] + ( _aFlashPos[nIndex].p[1] * _SPARKLE_DISTANCE_SCALE );
worldob_UpdateTrackingWorldSphere( pWorldOb, FALSE );
}
}
if( pPtr->nOffFrames == ( _FRAMES_BETWEEN_SPARKLES + 10 ) ) {
pPtr->nOffFrames = 0;
}
} else {
pWorldOb->nFlags |= WORLDOB_FLAG_DISABLE;
_fLastCameraFlashWhiteSat = 0.0f;
}
} else {
/* this sparkle is on, do some work*/
pPtr->nRoll += _SPARKLE_ROT_PER_FRAME;
if( pPtr->bTurnOn ) {
pPtr->fScale += pPtr->fScaleStep;
pPtr->fOpacity += _SPARKLE_OPACITY_PER_FRAME;
if( pPtr->fOpacity >= _SPARKLE_MAX_OPACITY ) {
pPtr->bTurnOn = FALSE;
pPtr->fOpacity = _SPARKLE_MAX_OPACITY;
}
} else {
pPtr->fScale *= 0.66f;
pPtr->fOpacity -= _SPARKLE_OPACITY_PER_FRAME;
if( pPtr->fOpacity <= 0.5f ) {
pWorldOb->nFlags |= WORLDOB_FLAG_DONT_DRAW;
pPtr->nOffFrames = 0;
if( pPtr->bKillWorldOb ) {
pWorldOb->nFlags |= WORLDOB_FLAG_DISABLE;
_fLastCameraFlashWhiteSat = 0.0f;
}
}
}
}
}
static void _DrawSparkle( WorldOb_t *pWorldOb ) {
FlashBulb_t *pPtr = (FlashBulb_t *)pWorldOb->pUserObject;
u32 nPriorZbufState;
Vec3_t CamPoint;
Vec2_t ScreenPoint;
BOOL bOldState;
/* since our worldob is already pushe
< 1
controls.c
Found at 1x193F800.
d[_MAX_ANALOG_DEVICES];
u32 nSampledButtonState;
u32 nSampledConfigurationSwitches;
} ControlsData_t;
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
static BOOL _bInputReady;
static ControlsData_t _ControlsData;
#if _CACHE_LIGHT_WRITES_TO_HARDWARE
static u32 _nCachedLightState;
#endif
#if _CACHE_FORCE_FEEDBACK_WRITES_TO_HARDWARE
static f32 _afCachedFFBIntensity[_MAX_FORCE_FEEDBACK_DEVICES];
#endif
#if _CIB1000_FORCE_FEEDBACK
static BOOL _bComEnabled;
static volatile u32 _nComPhase; /* 0 or 1*/
static int _nComMotorDriverValue;
static volatile int _nNextComMotorDriverValue; /* -1=none*/
#endif
static u32 _nLightState;
/*===================*/
/* private prototypes*/
static void CALLBACK _SamplingCB( UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2 );
#if _CIB1000_FORCE_FEEDBACK
static void _SetupForceFeedbackValue( float fIntensity );
static void CALLBACK _ComTimerCallback( UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2 );
static void _SendComString( const char *pszComString );
static void _SendComStringSlow( const char *pszComString );
static void _SendMotorDriverValue( int nMotorDriverValue );
static void _SynchronousAndSlow_SendMotorDriverValue( int nMotorDriverValue );
#endif
#if DIEGO_IO
static void _Diegoio_comm_callback( void );
static void _DiegoIoSetupForceFeedbackValue( float fIntensity );
#endif
/*=================*/
/* public functions*/
/* Called by game initialization module.*/
/* Returns TRUE if successful, or FALSE otherwise.*/
BOOL controldriver_ModuleInit( void ) {
UINT wNumDevs;
BOOL bReturn;
u32 i;
return TRUE;
}
/* Called by game shutdown module.*/
void controldriver_ModuleClose( void ) {
}
/* Resets the entire control driver module.*/
/* Every part of the module is set to its default value, as though*/
/* controldriver_ModuleInit() were called for the first time.*/
void controldriver_ModuleReset( void ) {
controldriver_ModuleClose();
controldriver_ModuleInit();
}
/* Sets the rate at which the control driver activates its background task.*/
/* The background task reads the analog and digital inputs, and writes*/
/* the force feedback and lamp values. It also calls callback functions*/
/* as needed.*/
/**/
/* fPeriod indicates the time in seconds between background tasks.*/
/* The default is CONTROL_DRIVER_DEFAULT_BACKGROUND_PERIOD.*/
/* fPeriod must be greater than 0, and is considered an approximate value.*/
/* The actual established period is constrained by hardware and operating system*/
/* limitations.*/
void controldriver_SetBackgroundSampleRate( float fPeriod ) {
}
/* Returns the current background sample rate.*/
/* The value returned is the time in seconds between periodic background tasks, and*/
/* simply reflects the parameter passed into the last call to controldriver_SetBackgroundSampleRate().*/
/* If the parameter passed to controldriver_SetBackgroundSampleRate() was approximated by*/
/* the controls driver, that approximation is not reflected in this function's return value.*/
float controldriver_GetBackgroundSampleRate( void ) {
return 0.0f;
}
/* Returns the number of analog inputs supported by this driver.*/
/* The value returned will be constant throughout the duration of the game, but*/
/* might vary between separate runs depending on the hardware.*/
u32 controldriver_GetAnalogCount( void ) {
return 0;
}
/* Returns the number of force feedback amplifiers supported by this driver.*/
/* The value returned will be constant throughout the duration of the game, but*/
/* might vary between separate runs depending on the hardware.*/
u32 controldriver_GetForceFeedbackCount( void ) {
return 0;
}
/* Returns the number of coin slot readers supported by this driver.*/
/* The value returned will be constant throughout the duration of the game, but*/
/* might vary between separate runs depending on the hardware.*/
u32 controldriver_GetCoinSlotCount( void ) {
return 0;
}
rup or reset, the values are retrieved*/
/* from persistent storage and controldriver_SetAnalogCalibration() is called. The*/
/* analog range mappings will be set for subsequent calls to controldriver_ReadAnalog().*/
/**/
/* The default values are fMinExtreme=0.0f, fNeutral=0.5f, and fMaxExtreme=1.0f.*/
/**/
/* Note that this calibration method works for both implicitely-calibrated devices (like*/
/* those calibrated through the Windows Control Panel) and explicitly-calibrated devices*/
/* (like the Diego I/O).*/
/* */
/* NEUTRAL MUST BE BETWEEN MIN AND MAX, IF IT IS NOT, A MESSAGE WILL */
/* BE PRINTED AND THE MIDPOINT BETWEEN MIN AND MAX WILL BE SET AS THE NEUTRAL POINT!!!*/
void controldriver_SetAnalogCalibration( u32 nAnalogNum, float fMinExtreme, float fNeutral, float fMaxExtreme ) {
}
/* Retrieves the current values of the fMinExtreme, fNeutral, and fMaxExtreme parameters*/
/* set via the most recent call to controldriver_SetAnalogCalibration. Note that any of*/
/* pfMinExtreme, pfNeutral, or pfMaxExtreme may be NULL in which case the parameter will*/
/* not be stored. If controldriver_SetAnalogCalibration() has not been called yet, the driver*/
/* returns default values (see controldriver_SetAnalogCalibration()).*/
void controldriver_GetAnalogCalibration( u32 nAnalogNum, float *pfMinExtreme, float *pfNeutral, float *pfMaxExtreme ) {
}
/* Returns a bitmask representing the state of general digital game inputs.*/
/* The polarity of the bits depends entirely on the hardware connection.*/
u32 controldriver_ReadButtons( void ) {
PDS_PERIPHERAL *per;
u32 Buttons = 0;
if(Controls_Index)
per = pdGetPeripheral(PDD_PORT_B0);
else
per = pdGetPeripheral(PDD_PORT_A0);
if(per->on & PDD_DGT_TA)
Buttons |= 0x1;
if(per->on & PDD_DGT_TB)
Buttons |= 0x2;
if(per->on & PDD_DGT_TX)
Buttons |= 0x4;
if(per->on & PDD_DGT_TY)
Buttons |= 0x8;
return Buttons;
}
/* Returns a bitmask representing the state of configuration DIP switch inputs.*/
/* The polarity of the bits depends entirely on the hardware connection.*/
u32 controldriver_ReadConfigurationSwitches( void ) {
return _ControlsData.nSampledConfigurationSwitches;
}
/* Establishes a callback function that will be called when a certain button state has been*/
/* detected. The particular button state is established through the controldriver_SetButtonCallbackMask()*/
/* function.*/
/* If pCallbackFcn is NULL, the callback functionality is disabled (NULL is the default).*/
void controldriver_SetButtonCallbackFunction( ControlDriver_ButtonCallbackFcn_t *pCallbackFcn ) {
_ControlsData.pButtonCallbackFcn = pCallbackFcn;
}
/* Returns the current button callback function pointer, or NULL if none is set.*/
ControlDriver_ButtonCallbackFcn_t *controldriver_GetButtonCallbackFunction( void ) {
return _ControlsData.pButtonCallbackFcn;
}
/* The control driver module has the ability to asynchronously call the button callback function*/
/* established through the controldriver_SetButtonCallbackFunction() function when a particular*/
/* button state is sensed. This function establishes the button state that will trigger a call*/
/* to the callback function.*/
/**/
/* Set bits in nButtonMask indicate buttons that are to be considered at all. Out of those set bits,*/
/* the corresponding bits in nStateMask indicate whether the read button bit should be a 0 or 1*/
/* to trigger the callback call. The state mask is necessary because the polarity of the button*/
/* bits depends entirely on the hardware connection.*/
/**/
/* Example:*/
/* nButtonMask = 00000000 00000000 00000001 01001000 binary*/
/* nStateMask = 00000000 00000000 00000001 00001000 binary*/
/**/
/* Therefore, the callback function will be called asynchronously*/
/* when any of these conditions are met:*/
/* A) Button bit 3 is 1,*/
/* B) Button bit 6 is 0,*/
/* C) Button bit 8 is 1*/
/**/
/* IMPORTANT: The background task is disabled while the callback function is executing.*/
/* The callback function should execute as quickly as possible and then exit,*/
/* which will resume the control driver background task.*/
void controldriver_SetButtonCallbackMask( u32 nButtonMask, u32 nStateMask ) {
}
/* Returns the current button mask and state mask values.*/
/* Either pnButtonMask or pnStateMask may be NULL. Only non-NULL pointers will*/
/* be filled with values.*/
void controldriver_GetButtonCallbackMask( u32 *pnButtonMask, u32 *pnStateMask ) {
}
/* Sets a new force feedback intensity.*/
/* The valid range for fIntensity is -1.0f to +1.0f.*/
/* nForceFeedbackNum indicates which force feedback amplifier to use: 0=1st, 1=2nd, etc.*/
/* A value of 0.0f indicates no feedback (neutral).*/
/* If nForceFeedbackNum is out of range for this driver, no action is performed.*/
/* The polarity of the value depends entirely on the hardware connection.*/
/**/
/* Note: The value is sent to the hardware on the next background task.*/
/* Multiple calls to this function before the background task executes is fully supported.*/
void controldriver_SetForceFeedback( u32 nForceFeedbackNum, float fIntensity ) {
}
/* Returns the current force feedback value.*/
/* The return value range is -1.0f to +1.0f, with 0.0f indicating neutral.*/
/* nForceFeedbackNum indicates which force feedback amplifier to use: 0=1st, 1=2nd, etc.*/
/* If nForceFeedbackNum is out of range for this driver, 0.0f is returned.*/
/* The polarity of the value depends entirely on the hardware connection.*/
float controldriver_GetForceFeedback( u32 nForceFeedbackNum ) {
return 0.0f;
}
/* Turns the indicated lamps off.*/
/* Only set bits in nLightMask will unlight the associated lamps.*/
/**/
/* Note: The value is sent to the hardware on the next background task.*/
/* Multiple calls to this function before the background task executes is fully supported.*/
void controldriver_TurnLampsOff( u32 nLightMask ) {
}
/* Turns the indicated lamps on.*/
/* Only set bits in nLightMask will light the associated lamps.*/
/**/
/* Note: The value is sent to the hardware on the next background task.*/
/* Multiple calls to this function before the background task executes is fully supported.*/
void controldriver_TurnLampsOn( u32 nLightMask ) {
}
/* Returns the current state of all lamps in the form of a bitmask.*/
/* Set bits indicate lit lamps.*/
u32 controldriver_GetLampState( void ) {
return _ControlsData.nLightMask;
}
/* Establishes a callback function that will be called asynchronously when a coin has been*/
/* deposited in any coin slot (including bill readers).*/
/* If pCallbackFcn is NULL, the callback functionality is disabled (NULL is the default).*/
void controldriver_SetCoinCallbackFunction( ControlDriver_CoinCallbackFcn_t *pCallbackFcn ) {
_ControlsData.pCoinCallbackFcn = pCallbackFcn;
}
/* Returns the current force feedback callback function pointer, or NULL if none is set.*/
ControlDriver_CoinCallbackFcn_t *controldriver_GetCoinCallbackFunction( void ) {
return _ControlsData.pCoinCallbackFcn;
}
/* Increments the specified coin counter by 1.*/
/* nCoinCointerNum indicates which coin counter to increment: 0=1st, 1=2nd, etc.*/
/* If nCoinCointerNum is out of range for this driver, no action is performed.*/
/**/
/* Note: The coin counter is actually incremented on the next background task.*/
/* Multiple calls to this function before the background task executes is fully supported.*/
void controldriver_IncrementCoinCounter( u32 nCoinCounterNum ) {
}
/* Returns TRUE if controldriver_ResetMotherboard() functionality is implemented by this driver.*/
BOOL controldriver_IsResetMotherboardSupported( void ) {
/* reset is not supported under win95 driver*/
return FALSE;
}
/* If motherboard reset functionality is implemented by this driver, this function resets the motherboard.*/
/* If motherboard reset functionality is not implemented by this driver, this function takes no action*/
/* and simply returns.*/
/**/
/* Note: The reset signal is actually activated on the next background task.*/
/* Therefore, this function may return and further code may continue to*/
/* execute before the reset actually takes place.*/
void controldriver_ResetMotherboard( void ) {
/* reset is not supported under win95 driver*/
}
/* Returns TRUE if controldriver_ConsoleEscKeyHit() functionality is implemented by this driver.*/
BOOL controldriver_IsConsoleEscKeyHitSupported( void ) {
#if CONSOLE_HYDRO
return TRUE;
#else
return FALSE;
#endif
}
/* If implemented, returns TRUE if the Escape key was detected. Otherwise, returns FALSE.*/
/* Use controldriver_IsConsoleEscKeyHitSupported() to determine if this functionality is*/
/* implemented in this driver.*/
/**/
/* This function is normally used as a method to quit a console game version.*/
/**/
/* Note: There may be a delay from the time the Escape key is pressed and when it is*/
/* realized by this function. The control driver samples the keyboard at a*/
/* much slower rate than it samples I/O. The rate is fully at the discretion*/
/* of the driver, as is the decision whether to support the Escape key functionality.*/
BOOL controldriver_ConsoleEscKeyHit( void ) {
return FALSE;
}
/*==================*/
/* private functions*/
#if DIEGO_IO
static void _Diegoio_comm_callback( void ) {
_SamplingCB(0,0,0,0,0);
}
#endif
static void CALLBACK _SamplingCB( UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2 ) {
}
#if _CIB1000_FORCE_FEEDBACK
/*/////////////////////////*/
/* FORCE FEEDBACK FUNCTIONS*/
/*/////////////////////////*/
static void _SetupForceFeedbackValue( float fIntensity ) {
}
static void CALLBACK _ComTimerCallback( UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2 ) {
}
static void _SendComString( const char *pszComString ) {
}
static void _SendComStringSlow( const char *pszComString ) {
}
static void _SendMotorDriverValue( int nMotorDriverValue ) {
}
static void _SynchronousAndSlow_SendMotorDriverValue( int nMotorDriverValue ) {
}
#endif
#if _MIDWAY_TNT_
#if DIEGO_IO
/*///////////////////////////////////////////*/
/* Interface to the Diego IO board driver.*/
/*///////////////////////////////////////////*/
/* Emulates the windows direct input API.*/
WINMMAPI UINT WINAPI joyGetNumDevs(void)
{
return 1;
}
static JOYCAPS _JoyCapsTNT = { 0, /*wMid*/
0, /*wPid*/
"", /*szPname*/
0, /*wXmin*/
0xFF, /*wXmax*/
0, /*wYmin*/
0xFF, /*wYmax*/
0, /*wZmin*/
0, /*wZmax*/
8, /*wNumButtons*/
10, /*wPeriodMin*/
20000, /*wPeriodMax*/
0, /*wRmin*/
0, /*wRmax*/
0, /*wUmin*/
0, /*wUmax*/
0, /*wVmin*/
0, /*wVmax*/
0, /*wCaps*/
2, /*wMaxAxes*/
2, /*wNumAxes*/
4, /*wMaxButtons*/
"", /*szRegKey*/
"" /*szOEMVxD*/
};
WINMMAPI MMRESULT WINAPI joyGetDevCaps(UINT uJoyID, LPJOYCAPS pjc, UINT cbjc)
{
return JOYERR_NOERROR;
}
WINMMAPI MMRESULT WINAPI joyGetPos(UINT uJoyID, LPJOYINFO pji)
{
return JOYERR_NOERROR;
}
static void _DiegoIoSetupForceFeedbackValue(float fIntensity)
{
}
#else
/*////////////////////////////////////////////////////////////////////////////////////////////*/
/*////////////////////////////////////////////////////////////////////////////////////////////*/
/* Crummy Keyboard driver for TNT.*/
/*////////////////////////////////////////////////////////////////////////////////////////////*/
/*////////////////////////////////////////////////////////////////////////////////////////////*/
/* Emulates the windows direct input API.*/
WINMMAPI UINT WINAPI joyGetNumDevs(void)
{
return 1;
}
static JOYCAPS _JoyCapsTNT = { 0, /*wMid*/
0, /*wPid*/
"", /*szPname*/
20000, /*wXmin*/
40000, /*wXmax*/
20000, /*wYmin*/
40000, /*wYmax*/
20000, /*wZmin*/
40000, /*wZ<b‡
wpr_hiscore.c
Found at 1x1956800.
.0f-12.0f, -70.0f+8.0f, /* center */
108.0f-26.0f, -70.0f+8.0f, /* right */
};
#else /*ULTRA64*/
static const Vec2_t _aInitialPlates[3] = {
-108.0f, -70.0f, /* left*/
0.0f, -70.0f, /* center*/
108.0f, -70.0f, /* right*/
};
#endif /*ULTRA64*/
const static f32 _afBoatScale[BOATS_COUNT] = {
1.0f, /* BOATS_TYPE_BANSHEE */
0.95f,/* BOATS_TYPE_TIDAL_BLADE */
1.0f, /* BOATS_TYPE_RAD_HAZARD */
1.0f, /* BOATS_TYPE_MISS_BEHAVE */
1.0f, /* BOATS_TYPE_DAMN_THE_TORPEDOES */
1.0f, /* BOATS_TYPE_CUT_THROAT */
1.05f,/* BOATS_TYPE_RAZORBACK */
1.0f, /* BOATS_TYPE_THRESHER*/
1.0f, /* BOATS_TYPE_MIDWAY*/
#if TARGET!=ULTRA64 /*Don't allow secret boats*/
1.3f, /* BOATS_TYPE_SEADOG*/
0.90f,/* BOATS_TYPE_COP*/
1.0f, /* BOATS_TYPE_HOVERCRAFT*/
0.70f,/* BOATS_TYPE_TINY*/
#endif /*ULTRA64*/
};
static const Vec3_t _SelectionForceDown = { 0.0f, -1234567.0f, 0.0f };
static const Vec3_t _DisplayCam1Pos = { _END_X_POS, 180.0f, 160.0f };
static const Vec3_t _DisplayCam2Pos = { _END_X_POS, 180.0f, 450.0f };
static const Vec3_t _DisplayCam3Pos = { _END_X_POS, 180.0f, 675.0f };
static const char _acLetterEntry[_NUMBER_CHARS_ACCEPTED] = {
'0', /* 0*/
'1', /* 1*/
'2', /* 2*/
'3', /* 3*/
'4', /* 4*/
'5', /* 5*/
'6', /* 6*/
'7', /* 7*/
'8', /* 8*/
'9', /* 9*/
'A', /* 10*/
'B', /* 11*/
'C', /* 12*/
'D', /* 13*/
'E', /* 14*/
'F', /* 15*/
'G', /* 16*/
'H', /* 17*/
'I', /* 18*/
'J', /* 19*/
'K', /* 20*/
'L', /* 21*/
'M', /* 22*/
'N', /* 23*/
'O', /* 24*/
'P', /* 25*/
'Q', /* 26*/
'R', /* 27*/
'S', /* 28*/
'T', /* 29*/
'U', /* 30*/
'V', /* 31*/
'W', /* 32*/
'X', /* 33*/
'Y', /* 34*/
'Z', /* 35*/
'?', /* 36*/
'!', /* 37*/
'>', /* 38*/
'<', /* 39*/
'=', /* 40*/
};
static u32 _nTrack;
static const TrackInfo_t *_pTrackInfo;
static s32 _nCurrentLetter;
static CmosHiScore_t _NewHighScore;
static u32 _nHighScoreSlot;
static u32 _nInitialIndex;
static HiScoreStages_t _StageNum;
static Cam_t _Camera;
static WorldSector_t *_pCamSector;
static u32 _nCamHeading, _nCamPitch, _nCamRoll;
static Vec3_t _CamPos;
static WorldLt_t *_pWLight;
static u32 _nCounter;
static BOOL _bFlashOn;
static Cam_t _2ndCamera;
static MidwayLight_t _2ndLight;
static u32 _nSubState;
static u32 _nFrameCount;
static u32 _nFirstEnteredWorldObIndex;
static u32 _nLastEnteredWorldObIndex;
static BOOL _bTexturesLoaded; /* we loaded all needed artwork, if not use old wrapper text system*/
static WorldOb_t *_paWObs;
static Motion_t *_paMotion;
static Phys_t *_paPhys;
static char _acMyTimeString[15];
static BOOL _bContinueMode;
static BOOL _bContinueOnlyMode;
static Mesh3d_t *_pText_EnterInitials;
static Mesh3d_t *_pText_Numbers[10];
static Mesh3d_t *_pText_Select;
static Mesh3d_t *_pText_Accept;
static Mesh3d_t *_pIcon_Wheel;
static Mesh3d_t *_pIcon_Wheel_Shadow;
static Mesh3d_t *_pIcon_Throttle;
static Mesh3d_t *_pIcon_Arrow;
static Mesh3d_t *_pInitialPlate;
static Mesh3d_t *_pBrackets;
static Mesh3d_t *_pHeading1;
static Mesh3d_t *_pHeading2;
static Mesh3d_t *_pTrackNames[TRACKS_COUNT];
static Mesh3d_t *_pBoats[BOATS_COUNT];
static Mesh3d_t *_pYourTime;
static Mesh3d_t *_pPlayAgain;
static Mesh3d_t *_pFreeGame;
static ObsysLoadDef_t aLoadTable[] =
{
/* BACKGROUNDS*/
(void *)&_pText_EnterInitials, "GWWENTR__H0",
(void *)&_pText_Numbers[0], "GWWTIME__H0", /* 0*/
(void *)&_pText_Numbers[1], "GWWTIME__H1", /* 1*/
(void *)&_pText_Numbers[2], "GWWTIME__H2", /* 2*/
(void *)&_pText_Numbers[3], "GWWTIME__H3", /* 3*/
(void *)&_pText_Numbers[4], "GWWTIME__H4", /* 4*/
(void *)&_pText_Numbers[5], "GWWTIME__H5", /* 5*/
(void *)&_pText_Numbers[6], "GWWTIME__H6", /* 6*/
(void *)&_pText_Numbers[7], "GWWTIME__H7", /* 7*/
(void *)&_pText_Numbers[8], "GWWTIME__H8", /* 8*/
(void *)&_pText_Numbers[9], "GWWTIME__H9", /* 9*/
(void *)&_pText_Select, "GWWSELE__H1",
(void *)&_pText_Accept, "GWWACCE__H1",
(void *)&_pIcon_Wheel, "GWWWHEEICH1",
(void *)&_pIcon_Wheel_Shadow, "GWWWHEESHH1",
(void *)&_pIcon_Throttle, "GWWTHOTICH0",
(void *)&_pIcon_Arrow, "GWWARRO__H1",
(void *)&_pInitialPlate, "GWWPLATHSH0",
(void *)&_pBrackets, "GWWBRAK__H0",
(void *)&_pHeading1, "GWWPLATHCH0",
(void *)&_pHeading2, "GWWPLATHCH1",
(void *)&_pTrackNames[0], "GWWPLATGRH0", /* TRACKS_SHIPGRAVEYARD*/
(void *)&_pTrackNames[1], "GWWPLATSPH0", /* TRACKS_AMAZON */
(void *)&_pTrackNames[2], "GWWPLATVEH0", /* TRACKS_VENICE */
(void *)&_pTrackNames[3], "GWWPLATLPH0", /* TRACKS_LAKEPOWELL */
(void *)&_pTrackNames[4], "GWWPLATACH0", /* TRACKS_ARTIC */
(void *)&_pTrackNames[5], "GWWPLATNRH0", /* TRACKS_NILE */
(void *)&_pTrackNames[6], "GWWPLATNYH0", /* TRACKS_NY */
(void *)&_pTrackNames[7], "GWWPLATGIH0", /* TRACKS_GREECE */
(void *)&_pTrackNames[8], "GWWPLATCHH0", /* TRACKS_CHINA*/
(void *)&_pTrackNames[9], "GWWPLATCHH0", /* TRACKS_TEST*/
(void *)&_pTrackNames[10], "GWWPLATL1H0", /* TRACKS_LOOP1*/
(void *)&_pTrackNames[11], "GWWPLATL2H0", /* TRACKS_LOOP2*/
(void *)&_pTrackNames[12], "GWWPLATL3H0", /* TRACKS_LOOP3*/
(void *)&_pBoats[0], "GBBBANSHUM0", /* BOATS_TYPE_BANSHEE */
(void *)&_pBoats[1], "GBBTIDAHUM0", /* BOATS_TYPE_TIDAL_BLADE */
(void *)&_pBoats[2], "GBBRADHHUM0", /* BOATS_TYPE_RAD_HAZARD */
(void *)&_pBoats[3], "GBBMISSHUM0", /* BOATS_TYPE_MISS_BEHAVE */
(void *)&_pBoats[4], "GBBDAMNHUM0", /* BOATS_TYPE_DAMN_THE_TORPEDOES */
(void *)&_pBoats[5], "GBBCUTTHUM0", /* BOATS_TYPE_CUT_THROAT */
(void *)&_pBoats[6], "GBBRAZRHUM0", /* BOATS_TYPE_RAZORBACK */
(void *)&_pBoats[7], "GBBTHREHUM0", /* BOATS_TYPE_THRESHER*/
(void *)&_pBoats[8], "GBBMIDWHUM0", /* BOATS_TYPE_MIDWAY*/
(void *)&_pBoats[9], "GBBSEADHUM0", /* BOATS_TYPE_SEADOG*/
(void *)&_pBoats[10], "GBBCOPBHUM0", /* BOATS_TYPE_COP*/
(void *)&_pBoats[11], "GBBHOVRHUM0", /* BOATS_TYPE_HOVERCRAFT*/
(void *)&_pBoats[12], "GBBTINYHUM0", /* BOATS_TYPE_TINY*/
(void *)&_pYourTime, "GWWTIMEPLH0", /* Your Time*/
(void *)&_pPlayAgain, "GWWPLAYTXH0", /* Play again*/
(void *)&_pFreeGame, "GWWFREEGMH1", /* Free Game*/
NULL, NULL,
};
/*===================*/
/* private prototypes*/
static void _DrawHighScoreEntry( u32 nTime );
static void _DrawIconsAndTime( u32 nTime, BOOL bDrawIcons );
static u32 _Ascii2Index( u8 nAsciiCode );
static void _DrawAnOldTextHighScoreLine( CmosHiScore_t *pHiScore, f32 nX, f32 nY, u32 nPlace );
static void _DrawOldTextHiScoreScreens( f32 fTime );
static BOOL _CreateEntryWorldObs( void );
static void _LetterWork( WorldOb_t *pWorldOb );
static void _InitHiScoreTableWorldObs( BOOL bAttract );
static void _DrawHighScoreDisplay( void );
static void _EndLetterEntry( void );
/*=================*/
/* public functions*/
/* resets all global vars*/
BOOL wpr_hiscore_ModuleInit( void ) {
_nTrack = 0;
_pTrackInfo = NULL;
_nCurrentLetter = _BEGINNING_CHAR_INDEX;
_NewHighScore.cInitials[0] = _NewHighScore.cInitials[1] = _NewHighScore.cInitials[2] = ' ';
_NewHighScore.fTime = 0.0f;
_NewHighScore.nBoat = 0;
_nHighScoreSlot = 0;
_nInitialIndex = 0;
_StageNum = _NOT_INITED_YET;
_bTexturesLoaded = FALSE;
_pCamSector = NULL;
_nCamHeading = _nCamPitch = _nCamRoll = 0;
vec3_Zero( &_CamPos );
_pWLight = NULL;
_nCounter = 0;
_bFlashOn = TRUE;
_nSubState = 0;
_nFrameCount = 0;
_nFirstEnteredWorldObIndex = 0;
_nLastEnteredWorldObIndex = 0;
_paWObs = NULL;
_paMotion = NULL;
_paPhys = NULL;
_bContinueMode = FALSE ;
_bContinueOnlyMode = FALSE;
return TRUE;
}
/* Call when you would like to make wpr_hiscore the active wrapper module*/
/* loads up all of the artwork needed for all stages of hi score mode.*/
/* If everything can't be loaded, all artwork will be turned off and*/
/* will simply use the old text based wrapper system.*/
/* Also resets all variables to their default values.*/
void wptrols_TurnLightsOff( CONTROLS_LIGHT_THROTTLE );
}
/* draw the countdown timer*/
if( nTime > 99 ) {
nTime = 99;
}
if( nTime > 3 && nTime != 0 ) {
nTemp = nTime/10;
mesh3d_DrawOrtho( _pText_Numbers[nTemp], WPR_DEFS_TIME_DIGIT1_X, WPR_DEFS_TIME_DIGIT_Y, WPR_DEFS_LAYER2_Z, 0, 1.0f );
nTemp = nTime - (nTemp * 10);
mesh3d_DrawOrtho( _pText_Numbers[nTemp], WPR_DEFS_TIME_DIGIT2_X, WPR_DEFS_TIME_DIGIT_Y, WPR_DEFS_LAYER2_Z, 0, 1.0f );
} else if( Gameloop_nFrameCounter & 0x8 ) {
nTemp = nTime/10;
mesh3d_DrawOrtho( _pText_Numbers[nTemp], WPR_DEFS_TIME_DIGIT1_X, WPR_DEFS_TIME_DIGIT_Y, WPR_DEFS_LAYER2_Z, 0, 1.0f );
nTemp = nTime - (nTemp * 10);
mesh3d_DrawOrtho( _pText_Numbers[nTemp], WPR_DEFS_TIME_DIGIT2_X, WPR_DEFS_TIME_DIGIT_Y, WPR_DEFS_LAYER2_Z, 0, 1.0f );
}
}
static void _DrawOldTextHiScoreScreens( f32 fTime ) {
u32 i;
f32 fY, fX;
switch( _StageNum )
{
case _NOT_INITED_YET:
/* we have not been inited, don't do shit*/
break;
case _ENTER_NEW_HIGH_SCORE:
/* select our font*/
text_SetFont( TEXT_FONT_LARGE );
/* print out the screen title*/
Text_fScale = 1.10f;
text_PrintF( 150.0f, 25.0f, "ENTER INITIALS\n" );
Text_fScale = 1.0f;
text_PrintChar( 225.0f, 180.0f, _NewHighScore.cInitials[0] );
text_PrintChar( 250.0f, 180.0f, _NewHighScore.cInitials[1] );
text_PrintChar( 275.0f, 180.0f, _NewHighScore.cInitials[2] );
/* select our font*/
text_SetFont( TEXT_FONT_SMALL );
/* draw all of the alphabets, scaling the currently selected letter*/
for( i=0; i < 22; i++ ) {
fX = 25.0f + (i * 18.0f);
if( (s32)i == _nCurrentLetter ) {
Text_fScale = 1.25f;
text_PrintChar( fX, 225.0f, _acLetterEntry[i] );
Text_fScale = 1.0f;
} else {
text_PrintChar( fX, 225.0f, _acLetterEntry[i] );
}
}
for( i=22; i < _NUMBER_CHARS_ACCEPTED; i++ ) {
fX = 25.0f + ( (i-22) * 18.0f );
if( (s32)i == _nCurrentLetter ) {
Text_fScale = 1.25f;
text_PrintChar( fX, 245.0f, _acLetterEntry[i] );
Text_fScale = 1.0f;
} else {
text_PrintChar( fX, 245.0f, _acLetterEntry[i] );
}
}
/* draw instructions at the bottom of the screen*/
text_PrintStr( 10.0f, 333.0f, "Turn wheel to switch letters, hit throttle to select\n" );
/* draw our remaining time*/
text_PrintF( 250.0f, 355.0f, "%f\n", fTime );
break;
case _DISPLAY_HIGH_SCORES_NEW:
/* select our font*/
text_SetFont( TEXT_FONT_LARGE );
/* print out the screen title and track name*/
Text_fScale = 1.10f;
text_PrintF( 15.0f, 15.0f, "HIGH SCORES: %s\n", _pTrackInfo->pszTrackName );
Text_fScale = 1.0f;
/* select our font*/
text_SetFont( TEXT_FONT_SMALL );
/* draw the lines of high scores*/
Text_fScale = 0.80f;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
fY = 65.0f + (i * 20.0f);
if( i == _nHighScoreSlot ) {
if( (Gameloop_nFrameCounter%20) < 12 ) {
Text_fScale = 1.05f;
_DrawAnOldTextHighScoreLine( &Hi_Score_Table.Table[_nTrack][i], 15.0f, fY, i+1 );
Text_fScale = 0.80f;
}
} else {
_DrawAnOldTextHighScoreLine( &Hi_Score_Table.Table[_nTrack][i], 15.0f, fY, i+1 );
}
}
Text_fScale = 1.0f;
/* draw our remaining time*/
text_PrintF( 250.0f, 355.0f, "%f\n", fTime );
break;
case _DISPLAY_HIGH_SCORES_NO_NEW:
/* select our font*/
text_SetFont( TEXT_FONT_LARGE );
/* print out the screen title and track name*/
Text_fScale = 1.10f;
text_PrintF( 15.0f, 15.0f, "HIGH SCORES: %s\n", _pTrackInfo->pszTrackName );
Text_fScale = 1.0f;
/* select our font*/
text_SetFont( TEXT_FONT_SMALL );
/* draw the lines of high scores*/
Text_fScale = 0.80f;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
fY = 65.0f + (i * 20.0f);
_DrawAnOldTextHighScoreLine( &Hi_Score_Table.Table[_nTrack][i], 15.0f, fY, i+1 );
}
Text_fScale = 1.0f;
/* draw our remaining time*/
text_PrintF( 250.0f, 355.0f, "%f\n", fTime );
break;
case _DISPLAY_HIGH_SCORE_ATTRACT:
/* select our font*/
text_SetFont( TEXT_FONT_LARGE );
/* print out the screen title and track name*/
Text_fScale = 1.10f;
text_PrintF( 15.0f, 15.0f, "HIGH SCORES: %s\n", _pTrackInfo->pszTrackName );
Text_fScale = 1.0f;
/* select our font*/
text_SetFont( TEXT_FONT_SMALL );
/* draw the lines of high scores*/
Text_fScale = 0.80f;
for( i=0; i < CMOS_HI_SCORES_PER_TRACK; i++ ) {
fY = 65.0f + (i * 20.0f);
_DrawAnOldTextHighScoreLine( &Hi_Score_Table.Table[_nTrack][i], 15.0f, fY, i+1 );
}
Text_fScale = 1.0f;
break;
default:
XASSERT_NOW;
break;
}
}
/* will draw one line of a high score starting at nX, nY using the defined spacing*/
/* output will look like:*/
/* 1. MRS RazorBack 03:15.56*/
/* routine assumes that a font has already been selected*/
static void _DrawAnOldTextHighScoreLine( CmosHiScore_t *pHiScore, f32 fX, f32 fY, u32 nPlace ) {
char pszInitials[4];
s32 nMin, nSecs, nCSecs;
/* draw the place*/
text_PrintF( fX, fY, "%d.\n", nPlace );
/* draw the initials*/
fX += _OFFSET_FROM_PLACE;
pszInitials[0] = pHiScore->cInitials[0];
pszInitials[1] = pHiScore->cInitials[1];
pszInitials[2] = pHiScore->cInitials[2];
pszInitials[3] = 0;
text_PrintF( fX, fY, "%s", pszInitials );
/* draw the boat name*/
fX += _OFFSET_FROM_INITIALS;
text_PrintStr( fX, fY, Boats_Info[pHiScore->nBoat].pszBoatName );
/* draw the time*/
fX += _OFFSET_FROM_BOAT_NAME;
xmath_ConvertAFloatSecs2NumOfMinSecCSec( pHiScore->fTime, &nMin, &nSecs, &nCSecs );
XMATH_CLAMPMAX( nMin, 99 );
XMATH_CLAMPMAX( nSecs, 59 );
XMATH_CLAMPMAX( nCSecs, 99 );
text_PrintF( fX, fY, "%02d:%02d.%02d\n", nMin, nSecs, nCSecs );
}
static void _InitHiScoreTableWorldObs( BOOL bAttract ) {
#if !_WATER_SEAM_TEST
char acLineOText[_NUM_CHARS_PER_LINE_WITH_SPACES];
CmosHiScore_t *pLine;
s32 nMin, nSecs, nCSecs;
f32 fZ;
u32 nTemp, i;
WorldOb_t *pWOb;
Motion_t *pMotion;
Phys_t *pPhys;
BOOL bReturn;
for( i=0; i < 10; i++ ) {
pLine = &Hi_Score_Table.Table[_nTrack][i];
if( i < 9 ) {
acLineOText[0] = ' ';
acLineOText[1] = _INT_2_ASCII(i+1);
} else {
acLineOText[0] = _INT_2_ASCII(1);
acLineOText[1] = _INT_2_ASCII(0);
}
acLineOText[2] = ' ';
acLineOText[3] = pLine->cInitials[0];
acLineOText[4] = pLine->cInitials[1];
acLineOText[5] = pLine->cInitials[2];
acLineOText[6] = ' ';
acLineOText[7] = ' ';
acLineOText[8] = ' ';
xmath_ConvertAFloatSecs2NumOfMinSecCSec( pLine->fTime, &nMin, &nSecs, &nCSecs );
XMATH_CLAMPMAX( nMin, 99 );
XMATH_CLAMPMAX( nSecs, 59 );
XMATH_CLAMPMAX( nCSecs, 99 );
nTemp = (u32)(nMin/10);
acLineOText[9] = _INT_2_ASCII(nTemp);
nMin -= (nTemp * 10);
acLineOText[10] = _INT_2_ASCII(nMin);
acLineOText[11] = ':';
nTemp = (u32)(nSecs/10);
acLineOText[12] = _INT_2_ASCII(nTemp);
nSecs -= (nTemp * 10);
acLineOText[13] = _INT_2_ASCII(nSecs);
acLineOText[14] = '.';
nTemp = (u32)(nCSecs/10);
acLineOText[15] = _INT_2_ASCII(nTemp);
nCSecs -= (nTemp * 10);
acLineOText[16] = _INT_2_ASCII(nCSecs);
if( bAttract ) {
fZ = _ATTRACT_DISPLAY_Z - (i * _ATTRACT_DISPLAY_Z_STEP);
if( i >= 5 ) {
fZ -= 17.0f;
}
wpr_floatingfont_PrintStr( acLineOText, _NUM_CHARS_PER_LINE_WITH_SPACES, _ATTRACT_DISPLAY_X, fZ, _ATTRACT_DISPLAY_X_STEP, 0.77f );
} else {
fZ = _DISPLAY_Z - (i * _DISPLAY_Z_STEP);
if( i >= 5 ) {
fZ -= 73.0f;
}
wpr_floatingfont_PrintStr( acLineOText, _NUM_CHARS_PER_LINE_WITH_SPACES, _DISPLAY_X, fZ, _DISPLAY_X_STEP, 0.77f );
}
pWOb = &_paWObs[i];
pMotion = &_paMotion[i];
pPhys = &_paPhys[i];
worldob_InitMesh( pWOb, _pBoats[pLine->nBoat] );
pWOb->fScale = _afBoatScale[pLine->nBoat];
/* set the boat's worldob flags*/
pWOb->nFlags |= ( WORLDOB_FLAG_OFFWORLDPERSIST |
WORLDOB_FLAG_SPECIAL_PHYS );
/* put the boat on the water*/
pWOb->Orient.Pos.p[0] = 830.0f;
pWOb->Orient.Pos.p[2] = fZ;
pWOb->Orient.Pos.p[1] = water_GetHeight( NULL, pWOb->Orient.Pos.p[0], pWOb->Orient.Pos.p[2] );
orient_BuildRotYXZ( &pWOb->Orient, XMATH_270_BRADIANS, 0,
_SILENT |
PHYS_CONTROLFLAG_STARTINGLINE_321GO |
PHYS_CONTROLFLAG_NO_BOOSTER |
PHYS_CONTROLFLAG_NO_HOVER |
PHYS_CONTROLFLAG_NO_STUNTS |
PHYS_CONTROLFLAG_NO_FLYSTEER );
XASSERT( bReturn );
#if 0
if( pPhys->pWaterShadow ) {
pPhys->pWaterShadow->nFlags |= WATER_SHADOW_FLAG_MANDITORY;
}
#endif
pPhys->fSteer = 0.0f;
pPhys->fSteerNoDeadZone = 0.0f; /* SER: Added 980923*/
pPhys->fThrottle = 0.0f;
pPhys->bHydroBoostersOn = FALSE;
}
#endif
}
/* tie up all lose end with the letter entry mode,*/
/* goto the new score display mode*/
static void _EndLetterEntry( void ) {
u32 i;
_nInitialIndex = 3;
_StageNum = _DISPLAY_HIGH_SCORES_NEW;
_nFrameCount = 0;
if( _nHighScoreSlot < 5 ) {
_nSubState = 2;
} else {
_nSubState = 0;
}
if( _bTexturesLoaded ) {
/* put the camera on the end char*/
_CamPos.p[0] = _END_X_POS;
/* setup the font's coloring*/
wpr_floatingfont_SetPrimaryColor( 0.0f, 0.4f, 0.8f, 0.05f );
wpr_floatingfont_TurnOffHighLite();
/* create the display worldobs and put the boats into the world*/
_InitHiScoreTableWorldObs( FALSE );
/* count all chars before our new line*/
_nFirstEnteredWorldObIndex = _NUMBER_CHARS_ACCEPTED;
for( i=0; i < _nHighScoreSlot; i++ ) {
_nFirstEnteredWorldObIndex += 9;
if( Hi_Score_Table.Table[_nTrack][i].cInitials[0] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][i].cInitials[1] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][i].cInitials[2] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
}
_nLastEnteredWorldObIndex = 9;
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[0] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[1] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[2] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( _nHighScoreSlot >= 9 ) {
_nLastEnteredWorldObIndex++;
}
/* flash the newly entered line of text*/
if( Gameloop_nFrameCounter & 0x8 ) {
wpr_floatingfont_HighLiteLetters( _nFirstEnteredWorldObIndex, _nLastEnteredWorldObIndex, 0.0f, 0.4f, 0.8f, 0.05f );
} else {
wpr_floatingfont_HighLiteLetters( _nFirstEnteredWorldObIndex, _nLastEnteredWorldObIndex, 0.6f, 1.0f, 1.0f, 0.05f );
}
}
controls_SetSteeringFeedback( 0.0f );
audio_Trigger( WPR_DEFS_END_INITIALS_ENTRY, WPR_DEFS_SELECTION_VOLUME, 80, AUDIO_TYPE_MUSIC, AUDIO_PRIORITY_MUSIC );
}
_SILENT |
PHYS_CONTROLFLAG_STARTINGLINE_321GO |
PHYS_CONTROLFLAG_NO_BOOSTER |
PHYS_CONTROLFLAG_NO_HOVER |
PHYS_CONTROLFLAG_NO_STUNTS |
PHYS_CONTROLFLAG_NO_FLYSTEER );
XASSERT( bReturn );
#if 0
if( pPhys->pWaterShadow ) {
pPhys->pWaterShadow->nFlags |= WATER_SHADOW_FLAG_MANDITORY;
}
#endif
pPhys->fSteer = 0.0f;
pPhys->fSteerNoDeadZone = 0.0f; /* SER: Added 980923*/
pPhys->fThrottle = 0.0f;
pPhys->bHydroBoostersOn = FALSE;
}
#endif
}
/* tie up all lose end with the letter entry mode,*/
/* goto the new score display mode*/
static void _EndLetterEntry( void ) {
u32 i;
_nInitialIndex = 3;
_StageNum = _DISPLAY_HIGH_SCORES_NEW;
_nFrameCount = 0;
if( _nHighScoreSlot < 5 ) {
_nSubState = 2;
} else {
_nSubState = 0;
}
if( _bTexturesLoaded ) {
/* put the camera on the end char*/
_CamPos.p[0] = _END_X_POS;
/* setup the font's coloring*/
wpr_floatingfont_SetPrimaryColor( 0.0f, 0.4f, 0.8f, 0.05f );
wpr_floatingfont_TurnOffHighLite();
/* create the display worldobs and put the boats into the world*/
_InitHiScoreTableWorldObs( FALSE );
/* count all chars before our new line*/
_nFirstEnteredWorldObIndex = _NUMBER_CHARS_ACCEPTED;
for( i=0; i < _nHighScoreSlot; i++ ) {
_nFirstEnteredWorldObIndex += 9;
if( Hi_Score_Table.Table[_nTrack][i].cInitials[0] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][i].cInitials[1] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][i].cInitials[2] != ' ' ) {
_nFirstEnteredWorldObIndex++;
}
}
_nLastEnteredWorldObIndex = 9;
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[0] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[1] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( Hi_Score_Table.Table[_nTrack][_nHighScoreSlot].cInitials[2] != ' ' ) {
_nLastEnteredWorldObIndex++;
}
if( _nHighScoreSlot >= 9 ) {
_nLastEnteredWorldObIndex++;
}
/* flash the newly entered line of text*/
if( Gameloop_nFrameCounter & 0x8 ) {
wpr_floatingfont_HighLiteLetters( _nFirstEnteredWorldObIndex, _nLastEnteredWorldObIndex, 0.0f, 0.4f, 0.8f, 0.05f );
} else {
wpr_floatingfont_HighLiteLetters( _nFirstEnteredWorldObIndex, _nLastEnteredWorldObIndex, 0.6f, 1.0f, 1.0f, 0.05f );
}
}
controls_SetSteeringFeedback( 0.0f );
audio_Trigger( WPR_DEFS_END_INITIALS_ENTRY, WPR_DEFS_SELECTION_VOLUME, 80, AUDIO_TYPE_MUSIC, AUDIO_PRIORITY_MUSIC
� we could purchase a race if we wanted to*/
if( _bDraw ) {
_DrawPressBoostButton();
}
_QuicklyFlashThrottleButton();
} else {
/* we can't purchase a race yet*/
if( _bDraw ) {
switch( _nDrawState )
{
case 0:
_DrawInsertCoins();
break;
case 1:
_DrawXCredits2Start();
break;
case 2:
_DrawCoinInfoStrings();
break;
}
}
_SlowlyFlashThrottleButton();
}
} else {
/* we must be on the hiscore/continue screen*/
if( nCredits >= _nContinueCost ) {
/* we could continue if we wanted to*/
if( _bDraw ) {
_DrawPressBoostButton();
}
_QuicklyFlashThrottleButton();
} else {
/* we can't continue yet*/
if( _bDraw ) {
switch( _nDrawState )
{
case 0:
_DrawInsertCoins();
break;
case 1:
_DrawXCredits2Continue();
break;
case 2:
_DrawCoinInfoStrings();
break;
}
}
_SlowlyFlashThrottleButton();
}
}
} else {
/* we won a free game, alternate "free game" and "press boost button"*/
if( _bDraw ) {
if( _bEveryOtherDraw ) {
_DrawPressBoostButton();
} else {
_DrawFreeGame();
}
}
_QuicklyFlashThrottleButton();
}
/* always draw the credits in paying mode*/
text_SetStyle( FSTYLE_PITCHED | FSTYLE_RIGHTJUST );
_DrawDepositedCredits();
text_SetStyle( FSTYLE_CENTER | FSTYLE_PITCHED );
}
}
void wpr_banker_ResetFlashTime( void ) {
_bEveryOtherDraw = FALSE;
_bDraw = FALSE;
_fTimer = 0.0f;
_nDrawState = 0;
}
f32 wpr_banker_CurrentCreditBalance( void ) {
int nFull, nNum, nDen, nTemp;
f32 fTemp;
nFull = coins_GetCurrentFullCredits();
coins_GetCurrentPartialCreditsFraction( &nNum, &nDen );
if( nDen ) {
nTemp = (nFull * nDen) + nDen;
fTemp = (f32)(nTemp) / (f32)(nDen);
} else {
fTemp = (f32)(nFull);
}
return fTemp;
}
/* draw the coin balance only, used in relink mode so that we don't lose coin deposits*/
void wpr_banker_DrawCoinBalanceOnly( void ) {
if( !OperatorSettings.bFreePlay ) {
text_SetFont( TEXT_FONT_SMALL );
text_SetStyle( FSTYLE_CENTER | FSTYLE_PITCHED );
Text_fScale = 1.0f;
_DrawDepositedCredits();
}
controls_TurnLightsOff( CONTROLS_LIGHT_THROTTLE );
}
BOOL wpr_banker_AreTheInstructionsCurrentlyDisplayed( void ) {
return _bDraw;
}
/* handles the throttle button being pressed*/
void wpr_banker_ThrottleButton_ISR( void ) {
u32 nCurrentState;
int nBalance;
BOOL bGameCouldBePurchased;
/* copy several vars so that threads don't bite us in the ass*/
nCurrentState = Statemgr_pLocalData->nCurrentState;
nBalance = coins_GetCurrentFullCredits();
bGameCouldBePurchased = _CouldGameBePurchased( nCurrentState == STATEMGR_HISCORE, nBalance );
if( bGameCouldBePurchased ) {
obsys_AbortLoad_ISR();
#if TARGET!=ULTRA64 && TARGET!=DREAMCAST
__asm cli
#endif /*ULTRA64*/
_bButtonISRCalled = TRUE;
#if TARGET!=ULTRA64 && TARGET!=DREAMCAST
__asm sti
#endif /*ULTRA64*/
}
}
void wpr_banker_AwardAServiceCredit( void ) {
coins_AwardAServiceCredit();
audio_Trigger( SOUNDCALL_GCOM_BUYIN_SOUND, AUDIO_VOLUME_MAX, AUDIO_PAN_CABINET, AUDIO_TYPE_COINDROP, AUDIO_PRIORITY_COINDROP );
}
/*==================*/
/* private functions*/
static void _CoinDropCallbackFcn( u32 nCoinSlotNum ) {
coins_CoinDrop( nCoinSlotNum );
wpr_attract_DrawCoinUpdateDuringLargeLoad();
audio_Trigger( SOUNDCALL_GCOM_BUYIN_SOUND, AUDIO_VOLUME_MAX, AUDIO_PAN_CABINET, AUDIO_TYPE_COINDROP, AUDIO_PRIORITY_COINDROP );
OperatorSettings.nCurrentCredits = coins_GetCurrentFullCredits();
}
static BOOL _CouldGameBePurchased( BOOL bContinue, int nBalance ) {
int nCost;
if( OperatorSettings.bFreePlay ) {
/* we can always purchase a game in free play mode*/
return TRUE;
}
if( Player_bHumanWonFreeRace ) {
/* we can always purchase a free game*/
return TRUE;
}
nCost = ( bContinue ) ? _nContinueCost : _nFirstTimeCost;
if( nBalance >= nCost ) {
/* the old fashioned way to play a game, buying it...*/
return TRUE;
}
return FALSE;
}
/* assumes font has been selected and only sets scale*/
static void _DrawPressBoostButton( void ) {
Text_fScale = 0.825f;
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - 30.0f, "PRESS BOOST\n" );
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - 14.0f, "BUTTON TO START\n" );
}
/* assumes font has been selected and only sets scale*/
static void _DrawInsertCoins( void ) {
Text_fScale = 1.0f;
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET, "INSERT COINS\n" );
}
/* assumes font has been selected and only sets scale*/
static void _DrawFreePlay( void ) {
Text_fScale = 1.0f;
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET, "FREE PLAY\n" );
}
/* assumes font has been selected and only sets scale*/
static void _DrawFreeGame( void ) {
Text_fScale = 1.0f;
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET, "FREE GAME!\n" );
}
/* assumes font has been selected and only sets scale*/
static void _DrawDepositedCredits( void ) {
int nFull, nNum, nDen;
Text_fScale = 1.0f;
nFull = coins_GetCurrentFullCredits();
if( coins_GetShowFractionsSetting() ) {
/* display fractions, only display something if there are credits or units*/
coins_GetCurrentPartialCreditsFraction( &nNum, &nDen );
if( nFull && nNum ) {
/* draw both full and fractional number*/
text_PrintF( Viewport_hres_f - _COIN_COLUMN_OFFSET,
Viewport_vres_f - _COIN_ROW_OFFSET,
"%d %d/%d\n", nFull, nNum, nDen );
} else if( nFull ) {
/* only whole credits exist, don't draw fractions until there is a fractional part*/
text_PrintF( Viewport_hres_f - _COIN_COLUMN_OFFSET, Viewport_vres_f - _COIN_ROW_OFFSET, "%d\n", nFull );
} else if( nNum ) {
/* only fractional credits exist*/
text_PrintF( Viewport_hres_f - _COIN_COLUMN_OFFSET,
Viewport_vres_f - _COIN_ROW_OFFSET,
"%d/%d\n", nNum, nDen );
}
} else if( nFull ) {
/* no fractions*/
text_PrintF( Viewport_hres_f - _COIN_COLUMN_OFFSET, Viewport_vres_f - _COIN_ROW_OFFSET, "%d\n", nFull );
}
}
/* assumes font has been selected and only sets scale*/
static void _DrawCoinInfoStrings( void ) {
f32 fY;
u32 i;
if( !_nNumLinesCoinInfo ) {
/* nothing to draw*/
return;
}
i = _nNumLinesCoinInfo - 1;
fY = Viewport_vres_f - _INFO_STRING_BOTTOM_OFFSET;
while( i ) {
fY -= _INFO_STRING_HEIGHT;
--i;
}
Text_fScale = 0.925f;
for( i=0; i < _nNumLinesCoinInfo; i++ ) {
text_PrintStr( Viewport_half_hres_f, fY, &_pszCoinInfoStrings[i][0] );
fY += _INFO_STRING_HEIGHT;
}
}
/* assumes font has been selected and only sets scale*/
static void _DrawXCredits2Start( void ) {
Text_fScale = 1.0f;
if( _nFirstTimeCost > 1 ) {
text_PrintF( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET,
"%d CREDITS TO START\n", _nFirstTimeCost );
} else {
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET,
"1 CREDIT TO START\n" );
}
}
/* assumes font has been selected and only sets scale*/
static void _DrawXCredits2Continue( void ) {
Text_fScale = 1.0f;
if( _nContinueCost > 1 ) {
text_PrintF( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET,
"%d CREDITS TO CONTINUE\n", _nContinueCost );
} else {
text_PrintStr( Viewport_half_hres_f, Viewport_vres_f - _BOTTOM_ROW_OFFSET,
"1 CREDIT TO CONTINUE\n" );
}
}
/* assumes font has been selected and only sets scale*/
static void _SlowlyFlashThrottleButton( void ) {
if( _nFlashCounter & 0x8 ) {
controls_TurnLightsOn( CONTROLS_LIGHT_THROTTLE );
} else {
controls_TurnLightsOff( CONTROLS_LIGHT_THROTTLE );
}
}
/* assumes font has been selected and only sets scale*/
static void _QuicklyFlashThrottleButton( void ) {
if( _nFlashCounter & 0x4 ) {
controls_TurnLightsOn( CONTROLS_LIGHT_THROTTLE );
} else {
controls_TurnLightsOff( CONTROLS_LIGHT_THROTTLE );
}
}
race.c
Found at 1x985EA00.
500
#define _MAX_SCREEN_AREA_SUM (512.0f*400.0f * 6.0f) /* <== SER: changed on 10/21/98 from (512.0f*400.0f * 7.0f)*/
#if TARGET==ULTRA64 /*Reduce max water spray polygons during race to 10*/
#define _MAX_SPRAY_PARTICLES 10
#elif TARGET==DREAMCAST /*ULTRA64*/
#define _MAX_SPRAY_PARTICLES 40
#else /* DREAMCAST */
#define _MAX_SPRAY_PARTICLES 200
#endif
/*=================*/
/* public variables*/
/*==================*/
/* private variables*/
static void *_pSysmemFrame;
static ObsysFrame_t _ObsysFrame;
static float _afRandomTable[_RANDOM_TABLE_COUNT];
static f32 _fRandomSeed;
static BOOL _bUpDateRank;
static BOOL _bUseGameCamSystem;
static BOOL _bLastCameraView;
/*===================*/
/* private prototypes*/
static void _Work (int nParm);
static void _Draw (int nParm);
static void _SplitScreenDraw (int nParm);
static void _Deallocate (void);
static void _DisplayLoadingScreen (void);
static void _LoadRaceObjects (void);
static void _MoveAllRacers( void );
static void _UpdateCamView( void );
static u8 *_pTrackBlit, *_pBoatBlit;
static u32 _nTrackBlit, _nBoatBlit;
/*=================*/
/* public functions*/
BOOL race_ModuleInit (void)
{
u32 i;
for (i = 0; i < _RANDOM_TABLE_COUNT; i++)
{
_afRandomTable[i] = xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
xmath_RandomFloat ();
}
race_SeedRandom( 1.0f );
_bLa4
audits.c
Found at 1x1929800.
}
void audits_LogAFreeGameWin( void ) {
_nLastRaceBuyCode = _FREE_RACE;
}
void audits_LogANewRacePurchase( void ) {
_nLastRaceBuyCode = _START;
}
void audits_LogALostLinkDuringARace( void ) {
if( !_bLostLinkDuringARace ) {
_bLostLinkDuringARace = TRUE;
++Audits_Data.nNumLostLinksDuringARace;
}
}
void audits_LogAnOutOfSyncGame( void ) {
++Audits_Data.nOutOfSyncGames;
}
void audits_LogAWatchDogReset( void ) {
++Audits_Data.nNumWatchDogResets;
audits_PeriodicAttractModeUpdate();
}
void audits_LogARelinkSession( void ) {
++Audits_Data.nNumRelinks;
}
void audits_LogACoinDroppedInTheLeftSlot( void ) {
++Audits_Data.nLeftCoinCount;
}
void audits_LogACoinDroppedInTheRightSlot( void ) {
++Audits_Data.nRightCoinCount;
}
void audits_LogACoinDroppedInThe3rdSlot( void ) {
++Audits_Data.nThirdCoinCount;
}
void audits_LogACoinDroppedInThe4thSlot( void ) {
++Audits_Data.nFourthCoinCount;
}
void audits_LogADollarBill( void ) {
++Audits_Data.nBillCount;
}
void audits_PeriodicAttractModeUpdate( void ) {
u32 nTime;
/* update our time vars*/
nTime = timer_ElapsedTicks( _nPowerOnTimer );
Audits_Data.nPowerOnTime = _nOldPowerOnTime + nTime;
Audits_Data.nTimeInARace = _nOldTimeInARace + Audits_Data.nTimeInARaceSinceLastReset;
Audits_Data.nPowerOnTimeSinceLastReset = nTime;
/* write out the cmos stuff to disk*/
cmos_CopyAllGlobalStructs2Cmos();
}
void audits_LogAServiceCredit( void ) {
++Audits_Data.nServiceCoinCount;
}
/*==================*/
/* private functions*/
static void _UpdateAuditObject( AuditObject_t *pPtr, u32 nPlace, u32 nTrackNum, u32 nBoatNum, BOOL bFinish, BOOL bTimeExpired, u32 nNumPlayers ) {
if( !pPtr ) {
return;
}
++pPtr->nNumGamesPlayed;
/* how did it end*/
if( bFinish ) {
++pPtr->nNumFinishes;
} else if( bTimeExpired ) {
++pPtr->nNumTimeExpires;
} else {
++pPtr->nNumDidNotFinish;
}
/* what type of start was this race*/
switch( _nLastRaceBuyCode )
{
case _NO_TYPE:
break;
case _START:
++pPtr->nNumStarts;
break;
case _CONTINUE:
++pPtr->nNumContinues;
break;
case _FREE_RACE:
++pPtr->nNumFreeGamesWon;
break;
default:
break;
}
/* how many players were in the race*/
switch( nNumPlayers )
{
case 1:
++pPtr->nNum1PlayerRaces;
break;
case 2:
++pPtr->nNum2PlayerRaces;
break;
case 3:
++pPtr->nNum3PlayerRaces;
break;
case 4:
++pPtr->nNum4PlayerRaces;
break;
default:
break;
}
}
static AuditObject_t *_GetTrackAuditOb( u32 nTrack ) {
switch( nTrack )
{
case TRACKS_SHIPGRAVEYARD:
return &Audits_Data.ShipGraveyardStats;
break;
case TRACKS_AMAZON:
return &Audits_Data.AmazonStats;
break;
case TRACKS_VENICE:
return &Audits_Data.VeniceStats;
break;
case TRACKS_LAKEPOWELL:
return &Audits_Data.LakePowellStats;
break;
case TRACKS_ARTIC:
return &Audits_Data.ArticStats;
break;
case TRACKS_NILE:
return &Audits_Data.NileStats;
break;
case TRACKS_NY:
return &Audits_Data.NYStats;
break;
case TRACKS_GREECE:
return &Audits_Data.GreeceStats;
break;
case TRACKS_CHINA:
return &Audits_Data.ChinaStats;
break;
case TRACKS_LOOP1:
return &Audits_Data.Loop1Stats;
break;
case TRACKS_LOOP2:
return &Audits_Data.Loop2Stats;
break;
case TRACKS_LOOP3:
return &Audits_Data.Loop3Stats;
break;
default:
break;
}
return NULL;
}
static AuditObject_t *_GetBoatAuditOb( u32 nBoat ) {
switch( nBoat )
{
case BOATS_TYPE_BANSHEE:
return &Audits_Data.BansheeStats;
break;
case BOATS_TYPE_TIDAL_BLADE:
return &Audits_Data.TidalBladeStats;
break;
case BOATS_TYPE_RAD_HAZARD:
return &Audits_Data.RadHazardStats;
break;
case BOATS_TYPE_MISS_BEHAVE:
return &Audits_Data.MissBehaveStats;
break;
case BOATS_TYPE_DAMN_THE_TORPEDOES:
return &Audits_Data.DamnTheTorpedoesStats;
break;
case BOATS_TYPE_CUT_THROAT:
return &Audits_Data.CutThroatStats;
break;
case BOATS_TYPE_RAZORBACK:
return &Audits_Data.RazorBackStats;
break;
case BOATS_TYPE_THRESHER:
return &Audits_Data.ThresherStats;
break;
case BOATS_TYPE_MIDWAY:
return &Audits_Data.MidwayStats;
break;
#if TARGET!=ULTRA64 /*Don't allow secret boats*/
case BOATS_TYPE_SEADOG:
return &Audits_Data.SeadogStats;
break;
case BOATS_TYPE_COP:
return &Audits_Data.CopStats;
break;
case BOATS_TYPE_HOVERCRAFT:
return &Audits_Data.HovercraftStats;
break;
case BOATS_TYPE_TINY:
return &Audits_Data.TinyTanicStats;
break;
#endif /*ULTRA64*/
default:
break;
}
return NULL;
Sg_gd.mak
At 1x0E42800 is a makefile for the game.
#------------------------------------------------------------------------------
# Sg_gd.mak
#------------------------------------------------------------------------------
PROJECT = Hydro
PROJECT_OBJS = "$(OBJDIR)\audio.obj"\
"$(OBJDIR)\audio_spkr.obj"\
"$(OBJDIR)\audio_mgr.obj"\
"$(OBJDIR)\audio_driver.obj"\
"$(OBJDIR)\audits.obj"\
"$(OBJDIR)\ai_craft.obj" \
"$(OBJDIR)\ai_player.obj" \
"$(OBJDIR)\ai_drive.obj" \
"$(OBJDIR)\ai_rabbit.obj" \
"$(OBJDIR)\ai_chase_acop.obj" \
"$(OBJDIR)\ai_chase_ccop.obj" \
"$(OBJDIR)\ai_chase_gcop.obj" \
"$(OBJDIR)\ai_chase_icop.obj" \
"$(OBJDIR)\ai_chase_mcop.obj" \
"$(OBJDIR)\ai_chase_ncop.obj" \
"$(OBJDIR)\ai_chase_whal.obj" \
"$(OBJDIR)\ai_chase_jucr.obj" \
"$(OBJDIR)\ai_params.obj" \
"$(OBJDIR)\anim.obj" \
"$(OBJDIR)\anim3d.obj" \
"$(OBJDIR)\anim_air.obj" \
"$(OBJDIR)\anim_birds.obj" \
"$(OBJDIR)\anim_fish.obj" \
"$(OBJDIR)\anim_land.obj" \
"$(OBJDIR)\anim_water.obj" \
"$(OBJDIR)\anim_nile.obj"\
"$(OBJDIR)\anim_sarc.obj"\
"$(OBJDIR)\anim_zarhis.obj"\
"$(OBJDIR)\anim_loop2.obj"\
"$(OBJDIR)\blit.obj" \
"$(OBJDIR)\boats.obj" \
"$(OBJDIR)\bonuskeys.obj"\
"$(OBJDIR)\bt_banshee.obj" \
"$(OBJDIR)\bt_cut.obj" \
"$(OBJDIR)\bt_damn.obj" \
"$(OBJDIR)\bt_mbehave.obj" \
"$(OBJDIR)\bt_midway.obj" \
"$(OBJDIR)\bt_rad.obj" \
"$(OBJDIR)\bt_razor.obj" \
"$(OBJDIR)\bt_seadog.obj" \
"$(OBJDIR)\bt_cop.obj" \
"$(OBJDIR)\bt_tiny.obj" \
"$(OBJDIR)\bt_hovercraft.obj" \
"$(OBJDIR)\bt_tblade.obj" \
"$(OBJDIR)\bt_thresher.obj" \
"$(OBJDIR)\cam_mgr.obj"\
"$(OBJDIR)\cmos_driver.obj" \
"$(OBJDIR)\cmos.obj" \
"$(OBJDIR)\collide.obj" \
"$(OBJDIR)\controls.obj" \
"$(OBJDIR)\control_driver.obj" \
"$(OBJDIR)\diagnos.obj" \
"$(OBJDIR)\drawqueue.obj" \
"$(OBJDIR)\coins.obj" \
"$(OBJDIR)\floatation.obj" \
"$(OBJDIR)\fog.obj" \
"$(OBJDIR)\fx.obj" \
"$(OBJDIR)\fx_smoke.obj" \
"$(OBJDIR)\fx_splash.obj" \
"$(OBJDIR)\fx_particles.obj" \
"$(OBJDIR)\gamecam.obj" \
"$(OBJDIR)\gamecoll.obj" \
"$(OBJDIR)\gameheap.obj" \
"$(OBJDIR)\gameinit.obj" \
"$(OBJDIR)\gameloop.obj" \
"$(OBJDIR)\gerr.obj" \
"$(OBJDIR)\gfxdefs.obj" \
"$(OBJDIR)\glcount.obj" \
"$(OBJDIR)\glide.obj" \
"$(OBJDIR)\gutil.obj" \
"$(OBJDIR)\hi_score.obj" \
"$(OBJDIR)\hud.obj" \
"$(OBJDIR)\hud_radar.obj" \
"$(OBJDIR)\hud_text.obj" \
"$(OBJDIR)\hud_wrongway.obj" \
"$(OBJDIR)\init3dfx.obj"\
"$(OBJDIR)\light.obj" \
"$(OBJDIR)\linklist.obj" \
"$(OBJDIR)\leader_lights.obj" \
"$(OBJDIR)\main.obj" \
"$(OBJDIR)\material.obj" \
"$(OBJDIR)\mem_driver.obj"\
"$(OBJDIR)\motion.obj" \
"$(OBJDIR)\mtx3.obj" \
"$(OBJDIR)\Mtx4.obj" \
"$(OBJDIR)\network_driver.obj" \
"$(OBJDIR)\net_comm.obj" \
"$(OBJDIR)\net_link.obj" \
"$(OBJDIR)\objectid.obj" \
"$(OBJDIR)\obsys.obj" \
"$(OBJDIR)\operator.obj" \
"$(OBJDIR)\orient.obj" \
"$(OBJDIR)\particle.obj" \
"$(OBJDIR)\paths.obj" \
"$(OBJDIR)\phys.obj" \
"$(OBJDIR)\physcoll.obj" \
"$(OBJDIR)\phys_lite.obj" \
"$(OBJDIR)\physdata.obj" \
"$(OBJDIR)\player.obj" \
"$(OBJDIR)\powerup.obj" \
"$(OBJDIR)\quat.obj" \
"$(OBJDIR)\r2file.obj" \
"$(OBJDIR)\race.obj" \
"$(OBJDIR)\report.obj" \
"$(OBJDIR)\scissor.obj" \
"$(OBJDIR)\Ss.obj" \
"$(OBJDIR)\Gdda.obj" \
"$(OBJDIR)\Sintbl.obj" \
"$(OBJDIR)\sky.obj" \
"$(OBJDIR)\statemgr.obj" \
"$(OBJDIR)\sysmem.obj" \
"$(OBJDIR)\sysmsg.obj" \
"$(OBJDIR)\sysfont.obj" \
"$(OBJDIR)\temp.obj" \
"$(OBJDIR)\terrain.obj" \
"$(OBJDIR)\tesla.obj" \
"$(OBJDIR)\text.obj" \
"$(OBJDIR)\timer.obj" \
"$(OBJDIR)\timer_driver.obj" \
"$(OBJDIR)\tmem.obj" \
"$(OBJDIR)\tracks.obj" \
"$(OBJDIR)\tripwire.obj" \
"$(OBJDIR)\tws.obj" \
"$(OBJDIR)\Viewport.obj" \
"$(OBJDIR)\water.obj" \
"$(OBJDIR)\watchdog.obj" \
"$(OBJDIR)\waterfall.obj" \
"$(OBJDIR)\waterspray.obj" \
"$(OBJDIR)\world.obj" \
"$(OBJDIR)\worldcoll.obj" \
"$(OBJDIR)\worldlt.obj" \
"$(OBJDIR)\worldob.obj" \
"$(OBJDIR)\wpr_attract.obj" \
"$(OBJDIR)\wpr_banker.obj" \
"$(OBJDIR)\wpr_defs.obj" \
"$(OBJDIR)\wpr_floatingfont.obj" \
"$(OBJDIR)\wpr_hiscore.obj" \
"$(OBJDIR)\wpr_memmgr.obj" \
"$(OBJDIR)\wpr_select.obj" \
"$(OBJDIR)\vec2.obj" \
"$(OBJDIR)\vec3.obj" \
"$(OBJDIR)\xclib.obj" \
"$(OBJDIR)\xfile.obj" \
"$(OBJDIR)\Xfm.obj" \
"$(OBJDIR)\Xmath.obj"\
"$(OBJDIR)\dcInit.obj"\
"$(OBJDIR)\dcDebug.obj"\
"$(OBJDIR)\dcTexture.obj"\
"$(OBJDIR)\dcDispStr.obj"\
"$(OBJDIR)\dcTexChar.obj"\
"$(OBJDIR)\dcFile.obj"\
"$(OBJDIR)\dcDraw.obj"\
"$(OBJDIR)\dcHydro.obj"\
"$(OBJDIR)\dcFog.obj"\
"$(OBJDIR)\runavg_binary.obj"\
"$(OBJDIR)\runavg_float.obj"\
"$(OBJDIR)\aMesh3d.obj"\
# "$(OBJDIR)\Mesh3dasm.obj"
"$(OBJDIR)\Mesh3d.obj"
DEBUG = TRUE
#LIST = TRUE
#BIN = TRUE
!include katana.inc
Website Fragments
At 1x17BE800 in track 36 is the homepage for the website AltaVista.
<html><head> <title>AltaVista HOME </title> <META http-equiv=Refresh content=1800> <META http-equiv="PICS-Label" content='(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.altavista.com/" on "1998.05.18T13:30-0800" r (n 0 s 0 v 0 l 0))'> <META http-equiv="PICS-Label" content='(PICS-1.1 "http://www.classify.org/safesurf/" l by "suggestions.altavista@pa.dec.com" r (SS~~000 1))'> </head><body bgcolor=#ffffff text=#000000 link=#000099 vlink=#663366 alink=#ff0000> <CENTER><table border=0 cellspacing=0 cellpadding=0> <tr valign=bottom><td><A HREF="/"><IMG SRC="/av/gifs/new/front_hdr.gif" ALT="AltaVista" BORDER=0 HEIGHT=60 WIDTH=480></A></td> <td width=120 height=60> <A HREF="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage_upperright;sz=120x60"><IMG SRC="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage_upperright;sz=120x60" ALT="Click Here" WIDTH=120 HEIGHT=60 BORDER=0></A></td></tr> <tr><td colspan=2 bgcolor=#003399><img src="/av/gifs/pixel.gif" width=1 height=2 border=0></td></tr> </table> <table border=0 bgcolor=#ffcc66 width=600 cellspacing=0 cellpadding=4><tr> <td width=5><br></td> <td><table width=100% border=0 bgcolor=#ffcc66 cellspacing=0 cellpadding=2> <FORM name=mfrm method=GET action="/cgi-bin/query"> <INPUT TYPE=hidden NAME=pg VALUE=q> <tr><td valign=top><table cellspacing=0 cellpadding=0 width=100% border=0><tr><td align=left><font face=arial size=-1><B>Ask AltaVista<sup><small>TM</small></sup> a question.</B> Or enter a few words in <SELECT NAME=kl><OPTION VALUE=XX SELECTED>any language <OPTION VALUE=zh>Chinese <OPTION VALUE=cs>Czech <OPTION VALUE=da>Danish <OPTION VALUE=nl>Dutch <OPTION VALUE=en>English <OPTION VALUE=et>Estonian <OPTION VALUE=fi>Finnish <OPTION VALUE=fr>French <OPTION VALUE=de>German <OPTION VALUE=el>Greek <OPTION VALUE=he>Hebrew <OPTION VALUE=hu>Hungarian <OPTION VALUE=is>Icelandic <OPTION VALUE=it>Italian <OPTION VALUE=ja>Japanese <OPTION VALUE=ko>Korean <OPTION VALUE=lv>Latvian <OPTION VALUE=lt>Lithuanian <OPTION VALUE=no>Norwegian <OPTION VALUE=pl>Polish <OPTION VALUE=pt>Portuguese <OPTION VALUE=ro>Romanian <OPTION VALUE=ru>Russian <OPTION VALUE=es>Spanish <OPTION VALUE=sv>Swedish </SELECT></font></td><td align=right><font face=arial size=-1><a href="/av/content/help.htm">Help</a> - <a href="/cgi-bin/query?pg=aq&what=web">Advanced</a></font></td></tr></table></td></tr> <tr><td><INPUT NAME=q size=50 maxlength=800 VALUE=""> <input type=submit name=search value="Search"></td></tr> <tr><td> <font face=arial,helvetica size=-1>Example: <b>How can I find Harvard's web site?</b></font><br> </td></tr> </FORM> </table></td></tr></table> <table width=600 border=0 cellspacing=0 cellpadding=0> <tr><td colspan=2 BGCOLOR=#003399><img src="/av/gifs/pixel.gif" border=0 width=0 height=2></td></tr> </table> <table width=600 cellpadding=0 cellspacing=0 border=0> <tr><td><img src="/av/gifs/pixel.gif" width=1 height=5 border=0></td></tr> <tr><td align=center><table cellpadding=0 cellspacing=0 border=0> <tr><td align=left valign=middle><font face=arial,helvetica color=#003399><b>Specialty<BR>Searches</b></font></td> <td width=40><br></td> <td align=left valign=middle><font size=-1 face="arial,Helvetica"> <a href="http://jump.altavista.com/cgi-bin/FF"><b>AV Family Filter</b></a> - <a href="http://jump.altavista.com/image"><b>AV Photo & Media Finder</b></a> - <a href="http://jump.altavista.com/gadgets">AV Tools & Gadgets</a> <br><a href="http://jump.altavista.com/shopping">Online Shopping</a> - <a href="http://jump.altavista.com/finance">AV Finance</a> - <a href="http://jump.altavista.com/health">Health</a> - <a href="http://jump.altavista.com/vertical">Industrial Communities</a> - <a href="http://jump.altavista.com/career">Careers</a> <br><a href="http://jump.altavista.com/maps">Maps</a> - <a href="http://jump.altavista.com/people">People Finder</a> - <a href="http://jump.altavista.com/travel">Travel</a> - <a href="/cgi-bin/query?what=news">Usenet<!-- Discussion Groups--></a> - <a href="http://jump.altavista.com/business">Yellow Pages</a> - <a href="http://jump.altavista.com/getwild">Entertainment</a> </font></td></tr></table></td></tr> <tr><td bgcolor=WHITE><img src="/av/gifs/pixel.gif" width=1 height=5 border=0></td></tr> <tr><td bgcolor=#003399><img src="/av/gifs/pixel.gif" width=1 height=2 border=0></td></tr> </table> <BR><table width=600 border=0 cellpadding=0 cellspacing=0> <tr><td width=175 valign=top><font face="arial,helvetica" size=-1><font size=+1>C</font><B>ATEGORIES</B><br> <table width=100% cellpadding=0 bgcolor=#FFCC66 cellspacing=0 border=0><tr><td valign=bottom align=right><img src="/av/gifs/pixel.gif" height=3 width=0></td></tr></table> <table cellpadding=0 cellspacing=0 border=0><tr><td width=8><BR></td><td align=left valign=top><font face="arial,helvetica" size=-1> <B><a href="http://jump.altavista.com/cat/auto">Automotive</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/busn">Business & Finance</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/comp">Computers & Internet</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/hlth">Health & Fitness</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/hobb">Hobbies & Interests</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/home">Home & Family</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/entr">Media & Amusements</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/peop">People & Chat</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/refr">Reference & Education</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/shop">Shopping & Services</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/pol">Society & Politics</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/sprt">Sports & Recreation</a><BR> <img src="/av/gifs/pixel.gif" height=7 width=0><BR><a href="http://jump.altavista.com/cat/trav">Travel & Vacations</a></B></font></td></tr></table></font></td><td width=17><br></td> <td width=265 valign=top><font face="arial,helvetica" size=-1><font size=+1>N</font><B>EWS BY <FONT COLOR=#3131CE>ABC</FONT><FONT COLOR=#21219C>NEWS.com</FONT></B><br> <table width=100% cellpadding=0 bgcolor=#FFCC66 cellspacing=0 border=0><tr><td valign=bottom align=right><img src="/av/gifs/pixel.gif" height=3 width=0></td></tr></table> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://jump.altavista.com/news/sections/world/index.html">NATO Forces Meet Resistance</a><br> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://jump.altavista.com/news/sections/world/index.html">India-Pakistan Fighting Escalates</a><br> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://jump.altavista.com/news/sections/politics/index.html">Bush Announces Candidacy</a><br> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://jump.altavista.com/news/sections/business/index.html">Qwest Bids for Two Telecoms</a><br> <br> <table border=0 cellpadding=0 cellspacing=0 width=100%><tr><td align=right><font face="arial,helvetica" size=-1><font size=+1>A</font><B>LTA</b><font size=+1>V</font><b>ISTA</b> <font size=+1>H</font><b>IGHLIGHTS</B></font></td></tr></table> <table width=100% cellpadding=0 bgcolor=#FFCC66 cellspacing=0 border=0><tr><td valign=bottom align=right><img src="/av/gifs/pixel.gif" height=3 width=0></td></tr></table> <table border=0 cellpadding=0 cellspacing=0><tr><td width=8><br></td> <td><font face="arial,helvetica" size=-1><img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href=http://jump.altavista.com/highlight.go?www.wildweb.com/av/article/0,1048,1_1_3839,00.html>Silverchair Lead's Battle With Anorexia</a><br> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://www.trip.com/home/0,1311,1-4,00.html">Travel with TRIP.com -- Simply Brilliant</a><br> <img src=/av/gifs/dart.gif width=8 height=9 border=0> <a href="http://www.altavista.com/av/content/jobs.htm"><b><font color="CC0000">Great</font> Jobs at AltaVista</b></a><br></font></td></tr></table> <br><font size=+1>O</font><B>THER</b> <font size=+1>S</font><b>ERVICES</B><br> <table width=100% cellpadding=0 bgcolor=#FFCC66 cellspacing=0 border=0><tr><td valign=bottom align=right><img src="/av/gifs/pixel.gif" height=3 width=0></td></tr></table> <table border=0 cellpadding=0 cellspacing=0><tr><td width=8><br></td> <td><font face="arial,helvetica" size=-1><a href="http://jump.altavista.com/avie5/ads/specsearch"><b><font color="CC0000">Get</font> Internet Explorer 5</b></a> - <a href="http://jump.altavista.com/email">Email</a><br> <a href="http://jump.altavista.com/discovery">AltaVista Discovery 1.1</a> <BR><a href="http://video.altavista.com/cgi-bin/avsearch">Video Search Demo</a> - <a href="http://jump.altavista.com/ati">Free Photo Albums</a> <br> <a href="http://jump.altavista.com/translate">AV Translation Services</a> - <a href="/av/oneweb/">Asian Languages</a><br> <a href="http://jump.altavista.com/homepage">Make Us Your Homepage</a> <a href="http://jump.altavista.com/card">Prints, Posters & Cards</a><BR> </font></td></tr></table> </font></td> <td width=18><br></td> <td width=125 valign=top><font face="arial,helvetica" size=-1 color=gray> <table border=0 width=100%><tr><td align=right><A HREF="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage125;sz=125x125"><IMG SRC="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage125;sz=125x125" ALT="Click Here" WIDTH=125 HEIGHT=125 BORDER=0></A></td></tr></table> <br><B>Featured Sponsors</B><br> <table width=100% cellpadding=0 bgcolor=#CCCCCC cellspacing=0 border=0><tr><td><img src="/av/gifs/pixel.gif" height=3 width=0></td></tr></table> <table border=0 cellpadding=0 cellspacing=0><tr><td width=8><br></td> <td><font face="arial,helvetica" size=-1> <a href="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=407841"> <img src="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=407841" alt="Click Here" width=6 height=6 border=0>YardMart! Mowers & Grills up to 20% off</a><br> <img src="http://ad.doubleclick.net/dot.gif" height=6 width=1><br> <a href="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=407879"> <img src="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=407879" alt="Click Here" width=6 height=6 border=0>dsgsports.com $20 off order over $50</a><br> <img src="http://ad.doubleclick.net/dot.gif" height=6 width=1><br> <a href="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=431673"> <img src="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=431673" alt="Click Here" width=6 height=6 border=0>Save Big on Health & Beauty, Fragrances!</a><br> <img src="http://ad.doubleclick.net/dot.gif" height=6 width=1><br> <a href="http://ad.doubleclick.net/jump/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=399941"> <img src="http://ad.doubleclick.net/ad/altavista.digital.com/sponsor-button/homepage_text1;sz=6x6;ad=399941" alt="Click Here" width=6 height=6 border=0>Lowest MuZic & Movie prices on the planet</a><br> </font></td></tr></table> </font></td></tr></table><BR><table width=600 cellpadding=0 cellspacing=0 border=0> <tr><td bgcolor=#003399><img src="/av/gifs/pixel.gif" border=0 width=0 height=2></td></tr></table> <table width=600 cellpadding=0 cellspacing=0 border=0> <tr><td valign=top><font size=-2 face="arial,helvetica" color=#003399> <br> <a href="/">AltaVista Home</a> | <a href="/av/content/help.htm">Help</a> | <a href="/av/content/questions.htm">Feedback</a> | <a href="http://jump.altavista.com/DoubleClick">Advertising Info</a> | <a href="/cgi-bin/query?pg=tmpl&v=pref.html">Set your Preferences</a> | <a href="/cgi-bin/query?text">Text-Only Version</a> <BR> <a href="http://www.compaq.com/">COMPAQ</a> | <a href="/av/content/disclaimer.htm">Disclaimer</a> | <a href="/av/content/privacy.htm">Privacy</a> | <a href="/av/content/av_network.html">Our Search Network</a> | <a href="/av/content/about.htm">About AltaVista</a> | <a href="/av/content/addurl.htm">Add a Page</a> </font></td><td align=right><a href="http://jump.altavista.com/avie5/ads/getie"><img src="/av/gifs/ie_horiz.gif" hspace=0 vspace=8 border=0 height=32 width=88></a> </td></tr> </table> </BODY></HTML>
At 0xDE92200 is a fragment of some search results generated by the same website.
v=|-1|-1|-1|-1|-1&x=cgi-bin">Daily specials below cost</a> </font></td></tr></table></td></tr> </table> <dl><dt><b>41. </b><a href="http://www.geocities.com/SiliconValley/1669/self.htm"><b>About Myself...</b></a><dd> Here is me. Not much to say, I guess, so I'll just state the obvious a few times to take up a little space. If you can think of anything else I can add...<br><b>URL:</b> <font color=gray>www.geocities.com/SiliconValley/1669/self.htm<br> Last modified 24-Oct-98 - page size 3K - in English</font> [ <a href="http://jump.altavista.com/trans.go?urltext=http%3a%2f%2fwww%2egeocities%2ecom%2fSiliconValley%2f1669%2fself%2ehtm&language=en">Translate</a> ]</dl> <dl><dt><b>42. </b><a href="http://www-mugc.cc.monash.edu.au/~wgmag1/home/alternative_frames_index1.html"><b>Sideframe</b></a><dd> About Me About This Page Art Australia Books Computer games Credit F.A.Q. Form Feedback Genealogy Guestbook NEXT FRAME....<br><b>URL:</b> <font color=gray>www-mugc.cc.monash.edu.au/~wgmag1/home/a...mes_index1.html<br> Last modified 12-Dec-98 - page size 3K - in English</font> [ <a href="http://jump.altavista.com/trans.go?urltext=http%3a%2f%2fwww%2dmugc%2ecc%2emonash%2eedu%2eau%2f%7ewgmag1%2fhome%2falternative%5fframes%5findex1%2ehtml&language=en">Translate</a> ]</dl> <dl><dt><b>43. </b><a href="http://www.geocities.com/SiliconValley/Lab/2072/audio.htm"><b>audio video</b></a><dd> FRONT PAGE MENU INDONESIA AUSTRALIA COMPUTER GAMES TAFE SEARCH ENGINE AUDIO-VIDEO MIDI. Audio Video. Adcom - high-end audio an4
Beginning at 1x3B2F200 is a job listing for an Account Manager position.
ilding……Selling knowledge of (Oracle, SQL Server, DB2) Databases,……A must: Fluent in Spanish, Conversational in Portuguese</font></td> <td valign="top" bgcolor="FFFFCC" width="18%"><font face="arial" size="2">Management Recruiters of Pittsburgh-North</font></td> <td valign="top" bgcolor="FFFFCC" width="15%"><font face="arial" size="2"> <br>Accustomed to 6 figures <br><font size="2" color="fc0000">Permanent</font> </font> </td> <td valign="top" bgcolor="FFFFCC" width="18%"><font face="arial" size="2">Any, </font></td> <td valign="top" bgcolor="FFFFCC" width="14%"><font face="arial" size="2">Jun-03-99</font></td> <td width="1%" bgcolor="FFFFCC"> </td> </tr> <tr><td colspan=7 bgcolor="FFFFCC"> </td></tr> </table> <table border=0 width="100%" cellpadding=5 cellspacing=0 bgcolor="ffffcc"> <tr> <td width="1%" bgcolor="FFFFCC"> </td> <td width="98%" colspan="5" valign="top" bgcolor="CCCC99"><font face="arial" size="2"><b> <a href="../../guest/job_display.dbm?jobID=316440"> Account Manager </a> <font size="1"> - Looking for an energetic outside sales person to grow sales with existing and new customers. Will manage Fortune 500 accounts in local area. </font></font></td> <td width="1%" bgcolor="FFFFCC"> </td> </tr> <tr> <td width="1%" bgcolor="FFFFCC"> </td> <td valign="top" colspan=1 <img src="/ci/left_end_blank.gif" border=0 alt="View Prior Page"><img src="/ci/page_back.gif" border=0 alt="View Prior Page"><img src="/ci/page_01_b.gif" border=0><a href="/guest/job_drilldown_results.dbm?page=2&url_qID=1806435&other=0&state=ZZ&state_title=in%20Outside%20U%2ES%2E"><img src="/ci/page_02_a.gif" border=0></a><a href="/guest/job_drilldown_results.dbm?page=3&url_qID=1806435&other=0&state=ZZ&state_title=in%20Outside%20U%2ES%2E"><img src="/ci/page_03_a.gif" border=0></a><a href="/guest/job_drilldown_results.dbm?page=2&url_qID=1806435&other=0&state=ZZ&state_title=in%20Outside%20U%2ES%2E"><img src="/ci/page_next.gif" border=0 alt="View Next Page"></a><a href="/guest/job_drilldown_results.dbm?page=all&url_qID=1806435&other=0&state=ZZ&state_title=in%20Outside%20U%2ES%2E"><img src="/ci/page_alla.gif" border=0 alt="View All Jobs"></a><a href="/guest/paging_help.cfm"><img src="/ci/page_helpa.gif" border=0 alt="Help"></a><img src="/ci/active_space.gif" border=0><img src="/ci/summaryb.gif" border=0 alt=