From 64020b2902c8e4c9599ac102f306dac40754da0e Mon Sep 17 00:00:00 2001 From: Sergey Galushko Date: Wed, 30 Mar 2022 00:39:04 +0300 Subject: [PATCH 01/84] PSP Port initial --- .gitmodules | 2 +- common/backends.h | 13 +- common/com_model.h | 17 +- common/defaults.h | 42 +- common/port.h | 23 +- common/xash3d_types.h | 4 + engine/client/cl_game.c | 20 +- engine/client/cl_netgraph.c | 6 +- engine/client/cl_render.c | 4 + engine/client/client.h | 9 + engine/client/console.c | 9 +- engine/client/in_touch.c | 20 + engine/client/input.c | 18 +- engine/client/keys.c | 5 +- engine/client/ref_common.c | 8 + engine/client/s_vox.c | 8 +- engine/common/base_cmd.c | 3 + engine/common/build.c | 6 +- engine/common/common.h | 15 +- engine/common/filesystem.c | 442 ++- engine/common/host.c | 10 +- engine/common/imagelib/img_utils.c | 19 +- engine/common/launcher.c | 29 + engine/common/lib_common.c | 6 +- engine/common/net_buffer.c | 7 +- engine/common/net_buffer.h | 19 + engine/common/net_encode.c | 120 +- engine/common/net_ws.c | 3 +- engine/common/netchan.h | 15 +- engine/common/protocol.h | 25 +- engine/common/soundlib/snd_main.c | 4 +- engine/common/soundlib/snd_mp3.c | 5 +- engine/common/soundlib/snd_wav.c | 4 + engine/common/system.c | 9 + engine/common/system.h | 4 + engine/platform/platform.h | 6 +- engine/platform/psp/dll_psp.c | 259 ++ engine/platform/psp/dll_psp.h | 38 + engine/platform/psp/in_psp.c | 182 ++ engine/platform/psp/lib_psp.c | 145 + engine/platform/psp/lib_psp.h | 0 engine/platform/psp/s_psp.c | 252 ++ engine/platform/psp/sys_psp.c | 281 ++ engine/platform/psp/vid_psp.c | 538 ++++ engine/platform/psp/vram_psp.c | 259 ++ engine/platform/psp/vram_psp.h | 39 + engine/server/server.h | 23 +- engine/server/sv_game.c | 7 +- engine/server/sv_init.c | 7 + engine/server/sv_phys.c | 41 +- engine/server/sv_save.c | 31 +- engine/sprite.h | 6 + engine/wscript | 11 +- mainui | 2 +- public/build.h | 8 +- public/matrixlib.c | 631 ++++- public/xash3d_mathlib.c | 324 ++- ref_gu/exports.txt | 2 + ref_gu/gu_alias.c | 1545 +++++++++++ ref_gu/gu_backend.c | 663 +++++ ref_gu/gu_beams.c | 1544 +++++++++++ ref_gu/gu_clipping.c | 416 +++ ref_gu/gu_context.c | 515 ++++ ref_gu/gu_cull.c | 149 + ref_gu/gu_dbghulls.c | 124 + ref_gu/gu_decals.c | 1268 +++++++++ ref_gu/gu_draw.c | 308 +++ ref_gu/gu_extension.c | 79 + ref_gu/gu_extension.h | 23 + ref_gu/gu_frustum.c | 355 +++ ref_gu/gu_frustum.h | 52 + ref_gu/gu_helper.h | 74 + ref_gu/gu_image.c | 2499 +++++++++++++++++ ref_gu/gu_init.c | 349 +++ ref_gu/gu_local.h | 809 ++++++ ref_gu/gu_rlight.c | 496 ++++ ref_gu/gu_rmain.c | 1361 +++++++++ ref_gu/gu_rmath.c | 267 ++ ref_gu/gu_rmisc.c | 190 ++ ref_gu/gu_rpart.c | 405 +++ ref_gu/gu_rsurf.c | 2352 ++++++++++++++++ ref_gu/gu_sprite.c | 1026 +++++++ ref_gu/gu_studio.c | 4142 ++++++++++++++++++++++++++++ ref_gu/gu_triapi.c | 577 ++++ ref_gu/gu_vgui.c | 309 +++ ref_gu/gu_warp.c | 871 ++++++ ref_gu/vram_psp.h | 39 + ref_gu/wscript | 58 + ref_soft/exports.txt | 2 + scripts/waifulib/xcompile.py | 160 +- wscript | 93 +- 91 files changed, 26988 insertions(+), 177 deletions(-) create mode 100644 engine/platform/psp/dll_psp.c create mode 100644 engine/platform/psp/dll_psp.h create mode 100644 engine/platform/psp/in_psp.c create mode 100644 engine/platform/psp/lib_psp.c create mode 100644 engine/platform/psp/lib_psp.h create mode 100644 engine/platform/psp/s_psp.c create mode 100644 engine/platform/psp/sys_psp.c create mode 100644 engine/platform/psp/vid_psp.c create mode 100644 engine/platform/psp/vram_psp.c create mode 100644 engine/platform/psp/vram_psp.h create mode 100644 ref_gu/exports.txt create mode 100644 ref_gu/gu_alias.c create mode 100644 ref_gu/gu_backend.c create mode 100644 ref_gu/gu_beams.c create mode 100644 ref_gu/gu_clipping.c create mode 100644 ref_gu/gu_context.c create mode 100644 ref_gu/gu_cull.c create mode 100644 ref_gu/gu_dbghulls.c create mode 100644 ref_gu/gu_decals.c create mode 100644 ref_gu/gu_draw.c create mode 100644 ref_gu/gu_extension.c create mode 100644 ref_gu/gu_extension.h create mode 100644 ref_gu/gu_frustum.c create mode 100644 ref_gu/gu_frustum.h create mode 100644 ref_gu/gu_helper.h create mode 100644 ref_gu/gu_image.c create mode 100644 ref_gu/gu_init.c create mode 100644 ref_gu/gu_local.h create mode 100644 ref_gu/gu_rlight.c create mode 100644 ref_gu/gu_rmain.c create mode 100644 ref_gu/gu_rmath.c create mode 100644 ref_gu/gu_rmisc.c create mode 100644 ref_gu/gu_rpart.c create mode 100644 ref_gu/gu_rsurf.c create mode 100644 ref_gu/gu_sprite.c create mode 100644 ref_gu/gu_studio.c create mode 100644 ref_gu/gu_triapi.c create mode 100644 ref_gu/gu_vgui.c create mode 100644 ref_gu/gu_warp.c create mode 100644 ref_gu/vram_psp.h create mode 100644 ref_gu/wscript create mode 100644 ref_soft/exports.txt diff --git a/.gitmodules b/.gitmodules index fc29b8c4..def188dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "mainui"] path = mainui - url = https://github.com/FWGS/mainui_cpp + url = https://github.com/Crow-bar/mainui_cpp [submodule "ref_gl/nanogl"] path = ref_gl/nanogl url = https://github.com/FWGS/nanogl diff --git a/common/backends.h b/common/backends.h index 34c0f097..3896f8b1 100644 --- a/common/backends.h +++ b/common/backends.h @@ -21,6 +21,7 @@ GNU General Public License for more details. #define VIDEO_ANDROID 2 #define VIDEO_FBDEV 3 #define VIDEO_DOS 4 +#define VIDEO_PSP 5 // audio backends (XASH_SOUND) @@ -28,6 +29,7 @@ GNU General Public License for more details. #define SOUND_SDL 1 #define SOUND_OPENSLES 2 #define SOUND_ALSA 3 +#define SOUND_PSP 4 // crash handler (XASH_CRASHHANDLER) #define CRASHHANDLER_NULL 0 @@ -40,6 +42,7 @@ GNU General Public License for more details. #define INPUT_SDL 1 #define INPUT_ANDROID 2 #define INPUT_EVDEV 3 +#define INPUT_PSP 4 // timer (XASH_TIMER) #define TIMER_NULL 0 // not used @@ -47,19 +50,21 @@ GNU General Public License for more details. #define TIMER_LINUX 2 #define TIMER_WIN32 3 #define TIMER_DOS 4 +#define TIMER_PSP 5 // messageboxes (XASH_MESSAGEBOX) #define MSGBOX_STDERR 0 #define MSGBOX_SDL 1 #define MSGBOX_ANDROID 2 #define MSGBOX_WIN32 3 - +#define MSGBOX_PSP 4 // library loading (XASH_LIB) -#define LIB_NULL 0 -#define LIB_POSIX 1 -#define LIB_WIN32 2 +#define LIB_NULL 0 +#define LIB_POSIX 1 +#define LIB_WIN32 2 #define LIB_STATIC 3 +#define LIB_PSP 4 #endif /* BACKENDS_H */ diff --git a/common/com_model.h b/common/com_model.h index 1372cd07..dacbe525 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -126,6 +126,21 @@ typedef struct int flags; // sky or slime, no lightmap or 256 subdivision } mtexinfo_t; +#if XASH_PSP +typedef struct +{ + float uv[2]; + float xyz[3]; +}gu_vert_t; +typedef struct glpoly_s +{ + struct glpoly_s *next; + struct glpoly_s *chain; + int numverts; + int flags; // for SURF_UNDERWATER + gu_vert_t verts[1]; // variable sized (xyz s1t1 + lm(xyz s2t2)) +} glpoly_t; +#else typedef struct glpoly_s { struct glpoly_s *next; @@ -134,7 +149,7 @@ typedef struct glpoly_s int flags; // for SURF_UNDERWATER float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) } glpoly_t; - +#endif typedef struct mnode_s { // common with leaf diff --git a/common/defaults.h b/common/defaults.h index e31d093c..71d7e885 100644 --- a/common/defaults.h +++ b/common/defaults.h @@ -95,6 +95,29 @@ SETUP BACKENDS DEFINITIONS // usually only 10-20 fds availiable #define XASH_REDUCE_FD + #elif XASH_PSP + #ifndef XASH_VIDEO + #define XASH_VIDEO VIDEO_PSP + #endif + + #ifndef XASH_TIMER + #define XASH_TIMER TIMER_PSP + #endif + + #ifndef XASH_INPUT + #define XASH_INPUT INPUT_PSP + #endif + + #ifndef XASH_SOUND + #define XASH_SOUND SOUND_PSP + #endif // XASH_SOUND + + #ifndef XASH_MESSAGEBOX + #define XASH_MESSAGEBOX MSGBOX_PSP + #endif // XASH_MESSAGEBOX + + #define XASH_REDUCE_FD + #define XASH_NO_TOUCH #endif #endif // XASH_DEDICATED @@ -132,7 +155,7 @@ SETUP BACKENDS DEFINITIONS #endif // !XASH_WIN32 #endif -#ifdef XASH_STATIC_LIBS +#if defined(XASH_STATIC_LIBS) && !defined(XASH_PSP) #define XASH_LIB LIB_STATIC #define XASH_INTERNAL_GAMELIBS #define XASH_ALLOW_SAVERESTORE_OFFSETS @@ -140,6 +163,9 @@ SETUP BACKENDS DEFINITIONS #define XASH_LIB LIB_WIN32 #elif XASH_POSIX #define XASH_LIB LIB_POSIX +#elif XASH_PSP +#define XASH_ALLOW_SAVERESTORE_OFFSETS +#define XASH_LIB LIB_PSP #endif // @@ -193,11 +219,15 @@ Default build-depended cvar and constant values #endif // DEFAULT_FULLSCREEN #ifndef DEFAULT_ACCELERATED_RENDERER - #if XASH_MOBILE_PLATFORM - #define DEFAULT_ACCELERATED_RENDERER "gles1" - #else // !XASH_MOBILE_PLATFORM - #define DEFAULT_ACCELERATED_RENDERER "gl" - #endif // !XASH_MOBILE_PLATFORM + #ifdef XASH_PSP + #define DEFAULT_ACCELERATED_RENDERER "gu" + #else + #if XASH_MOBILE_PLATFORM + #define DEFAULT_ACCELERATED_RENDERER "gles1" + #else // !XASH_MOBILE_PLATFORM + #define DEFAULT_ACCELERATED_RENDERER "gl" + #endif // !XASH_MOBILE_PLATFORM + #endif #endif // DEFAULT_ACCELERATED_RENDERER #ifndef DEFAULT_SOFTWARE_RENDERER diff --git a/common/port.h b/common/port.h index 102b6dff..233335b9 100644 --- a/common/port.h +++ b/common/port.h @@ -26,7 +26,9 @@ GNU General Public License for more details. #include #define OS_LIB_EXT "dylib" #define OPEN_COMMAND "open" - #else + #elif XASH_PSP + #define OS_LIB_EXT "prx" + #else #define OS_LIB_EXT "so" #define OPEN_COMMAND "xdg-open" #endif @@ -74,6 +76,25 @@ GNU General Public License for more details. #define FreeLibrary( x ) (0) #define SetCurrentDirectory( x ) (!chdir( x )) #endif + +#if XASH_PSP + #include + #include + #include "../engine/platform/psp/dll_psp.h" + #define PATH_MAX 1024 + #define PATH_SPLITTER "/" + #define O_BINARY 0 + #define O_TEXT 0 + #define _mkdir( x ) sceIoMkdir( x, FIO_S_IRWXU | FIO_S_IRWXG | FIO_S_IROTH | FIO_S_IXOTH ) + #define SetCurrentDirectory( x ) ( !sceIoChdir( x ) ) + #define LoadLibrary( x ) ( 0 ) + #define GetProcAddress( x, y ) ( 0 ) + #define FreeLibrary( x ) ( 0 ) +// #define LoadLibrary( x ) dlopen( x, RTLD_NOW ) +// #define GetProcAddress( x, y ) dlsym( x, y ) +// #define FreeLibrary( x ) dlclose( x ) +#endif + //#define MAKEWORD( a, b ) ((short int)(((unsigned char)(a))|(((short int)((unsigned char)(b)))<<8))) #define max( a, b ) (((a) > (b)) ? (a) : (b)) #define min( a, b ) (((a) < (b)) ? (a) : (b)) diff --git a/common/xash3d_types.h b/common/xash3d_types.h index 7f979601..e6c9824c 100644 --- a/common/xash3d_types.h +++ b/common/xash3d_types.h @@ -136,6 +136,9 @@ typedef void (*setpair_t)( const char *key, const void *value, void *buffer, voi // config strings are a general means of communication from // the server to all connected clients. // each config string can be at most CS_SIZE characters. +#if XASH_PSP +#define MAX_QPATH 48 +#else #if XASH_LOW_MEMORY == 0 #define MAX_QPATH 64 // max length of a game pathname #elif XASH_LOW_MEMORY == 2 @@ -143,6 +146,7 @@ typedef void (*setpair_t)( const char *key, const void *value, void *buffer, voi #elif XASH_LOW_MEMORY == 1 #define MAX_QPATH 48 #endif +#endif #define MAX_OSPATH 260 // max length of a filesystem pathname #define CS_SIZE 64 // size of one config string #define CS_TIME 16 // size of time string diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 707bc27b..baa4b749 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -103,6 +103,12 @@ CL_GetEntityByIndex Render callback for studio models ==================== */ +#if XASH_OPT +cl_entity_t *pfnCL_GetEntityByIndex( int index ) +{ + return CL_GetEntityByIndex( index ); +} +#else cl_entity_t *CL_GetEntityByIndex( int index ) { if( !clgame.entities ) // not in game yet @@ -116,7 +122,7 @@ cl_entity_t *CL_GetEntityByIndex( int index ) return CL_EDICT_NUM( index ); } - +#endif /* ================ CL_ModelHandle @@ -124,13 +130,19 @@ CL_ModelHandle get model handle by index ================ */ +#if XASH_OPT +model_t *pfnCL_ModelHandle( int modelindex ) +{ + return CL_ModelHandle( modelindex ); +} +#else model_t *CL_ModelHandle( int modelindex ) { if( modelindex < 0 || modelindex >= MAX_MODELS ) return NULL; return cl.models[modelindex]; } - +#endif /* ==================== CL_IsThirdPerson @@ -3807,7 +3819,11 @@ static cl_enginefunc_t gEngfuncs = pfnIsNoClipping, CL_GetLocalPlayer, CL_GetViewModel, +#if XASH_OPT + pfnCL_GetEntityByIndex, +#else CL_GetEntityByIndex, +#endif pfnGetClientTime, pfnCalcShake, pfnApplyShake, diff --git a/engine/client/cl_netgraph.c b/engine/client/cl_netgraph.c index ed40ed5a..3aa51ce0 100644 --- a/engine/client/cl_netgraph.c +++ b/engine/client/cl_netgraph.c @@ -16,9 +16,11 @@ GNU General Public License for more details. #include "common.h" #include "client.h" -#if XASH_LOW_MEMORY +#if XASH_LOW_MEMORY == 0 #define NET_TIMINGS 1024 -#else +#elif XASH_LOW_MEMORY == 1 +#define NET_TIMINGS 256 +#elif XASH_LOW_MEMORY == 2 #define NET_TIMINGS 64 #endif #define NET_TIMINGS_MASK (NET_TIMINGS - 1) diff --git a/engine/client/cl_render.c b/engine/client/cl_render.c index 88a25f69..8c645f46 100644 --- a/engine/client/cl_render.c +++ b/engine/client/cl_render.c @@ -271,7 +271,11 @@ static render_api_t gRenderAPI = pfnFileBufferCRC32, COM_CompareFileTime, Host_Error, +#if XASH_OPT + (void*)pfnCL_ModelHandle, +#else (void*)CL_ModelHandle, +#endif pfnTime, Cvar_Set, S_FadeMusicVolume, diff --git a/engine/client/client.h b/engine/client/client.h index c219f70b..9de00b29 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -709,7 +709,11 @@ dlight_t *CL_GetEntityLight( int number ); // // cl_cmds.c // +#ifdef XASH_PSP +void CL_Quit_f( void ); +#else void CL_Quit_f( void ) NORETURN; +#endif void CL_ScreenShot_f( void ); void CL_SnapShot_f( void ); void CL_PlayCDTrack_f( void ); @@ -821,7 +825,12 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize ); client_textmessage_t *CL_TextMessageGet( const char *pName ); int pfnDecalIndexFromName( const char *szDecalName ); int pfnIndexFromTrace( struct pmtrace_s *pTrace ); +#if XASH_OPT +#define CL_ModelHandle( modelindex ) ( ( ( modelindex ) < 0 || ( modelindex ) >= MAX_MODELS ) ? NULL : cl.models[( modelindex )] ) +model_t *pfnCL_ModelHandle( int modelindex ); +#else model_t *CL_ModelHandle( int modelindex ); +#endif void NetAPI_CancelAllRequests( void ); int CL_FindModelIndex( const char *m ); cl_entity_t *CL_GetLocalPlayer( void ); diff --git a/engine/client/console.c b/engine/client/console.c index 1d4f3177..1cfe1277 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1788,13 +1788,20 @@ void Key_Console( int key ) } // console scrolling +#if XASH_PSP + if( key == K_JOY2 ) +#else if( key == K_PGUP ) +#endif { Con_PageUp( 1 ); return; } - +#if XASH_PSP + if( key == K_JOY1 ) +#else if( key == K_PGDN ) +#endif { Con_PageDown( 1 ); return; diff --git a/engine/client/in_touch.c b/engine/client/in_touch.c index c42ea954..cf754f87 100644 --- a/engine/client/in_touch.c +++ b/engine/client/in_touch.c @@ -19,6 +19,24 @@ GNU General Public License for more details. #include "vgui_draw.h" #include "mobility_int.h" +#ifdef XASH_NO_TOUCH + +void Touch_WriteConfig( void ) {} +void Touch_SetClientOnly( qboolean state ) {} +void Touch_RemoveButton( const char *name ) {} +void Touch_HideButtons( const char *name, byte hide ) {} +void Touch_AddClientButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags ) {} +void Touch_AddDefaultButton( const char *name, const char *texturefile, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags ) {} +void Touch_ResetDefaultButtons( void ){} +void Touch_Init( void ) {} +void Touch_Draw( void ) {} +int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy ) { return 0; } +void Touch_GetMove( float *forward, float *side, float *yaw, float *pitch ) {} +void Touch_KeyEvent( int key, int down ) {} +void Touch_Shutdown( void ) {} + +#else /* XASH_NO_TOUCH */ + typedef enum { touch_command, // just tap a button @@ -1973,3 +1991,5 @@ void Touch_Shutdown( void ) touch.initialized = false; Mem_FreePool( &touch.mempool ); } + +#endif /* XASH_NO_TOUCH */ diff --git a/engine/client/input.c b/engine/client/input.c index 744ba6e0..62874174 100644 --- a/engine/client/input.c +++ b/engine/client/input.c @@ -61,10 +61,10 @@ uint IN_CollectInputDevices( void ) if( !m_ignore->value ) // no way to check is mouse connected, so use cvar only ret |= INPUT_DEVICE_MOUSE; - +#ifndef XASH_NO_TOUCH if( CVAR_TO_BOOL(touch_enable) ) ret |= INPUT_DEVICE_TOUCH; - +#endif if( Joy_IsActive() ) // connected or enabled ret |= INPUT_DEVICE_JOYSTICK; @@ -93,13 +93,17 @@ void IN_LockInputDevices( qboolean lock ) { SetBits( m_ignore->flags, FCVAR_READ_ONLY ); SetBits( joy_enable->flags, FCVAR_READ_ONLY ); +#ifndef XASH_NO_TOUCH SetBits( touch_enable->flags, FCVAR_READ_ONLY ); +#endif } else { ClearBits( m_ignore->flags, FCVAR_READ_ONLY ); ClearBits( joy_enable->flags, FCVAR_READ_ONLY ); +#ifndef XASH_NO_TOUCH ClearBits( touch_enable->flags, FCVAR_READ_ONLY ); +#endif } } @@ -196,7 +200,7 @@ void IN_ToggleClientMouse( int newstate, int oldstate ) else if( newstate == key_game ) { // reset mouse pos, so cancel effect in game -#if SDL_VERSION_ATLEAST( 2, 0, 0 ) +#if SDL_VERSION_ATLEAST( 2, 0, 0 ) && !defined( XASH_NO_TOUCH ) if( CVAR_TO_BOOL( touch_enable ) ) { SDL_SetRelativeMouseMode( SDL_FALSE ); @@ -277,7 +281,7 @@ void IN_ActivateMouse( qboolean force ) { if( in_mouse_suspended ) { -#ifdef XASH_SDL +#if defined( XASH_SDL ) && !defined( XASH_NO_TOUCH ) /// TODO: Platform_ShowCursor if( !touch_emulate ) SDL_ShowCursor( SDL_FALSE ); @@ -372,6 +376,7 @@ void IN_MouseEvent( void ) { int i; +#ifndef XASH_NO_TOUCH // touch emu: handle motion if( CVAR_TO_BOOL( touch_emulate )) { @@ -380,7 +385,7 @@ void IN_MouseEvent( void ) else Touch_KeyEvent( K_MOUSE1, 2 ); } - +#endif if( !in_mouseinitialized || !in_mouseactive ) return; @@ -396,9 +401,10 @@ void IN_MouseEvent( void ) Platform_GetMousePos(&x, &y); if( host.mouse_visible ) SDL_ShowCursor( SDL_TRUE ); +#ifndef XASH_NO_TOUCH else if( !CVAR_TO_BOOL( touch_emulate ) ) SDL_ShowCursor( SDL_FALSE ); - +#endif if( x < host.window_center_x / 2 || y < host.window_center_y / 2 || x > host.window_center_x + host.window_center_x / 2 || diff --git a/engine/client/keys.c b/engine/client/keys.c index 9172b97f..c941b286 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -519,8 +519,11 @@ void Key_Init( void ) // setup default binding. "unbindall" from config.cfg will be reset it for( kn = keynames; kn->name; kn++ ) Key_SetBinding( kn->keynum, kn->binding ); - +#if XASH_PSP + osk_enable = Cvar_Get( "osk_enable", "1", FCVAR_ARCHIVE, "enable built-in on-screen keyboard" ); +#else osk_enable = Cvar_Get( "osk_enable", "0", FCVAR_ARCHIVE, "enable built-in on-screen keyboard" ); +#endif key_rotate = Cvar_Get( "key_rotate", "0", FCVAR_ARCHIVE, "rotate arrow keys (0-3)" ); } diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index 4a63b438..93fd07ec 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -268,7 +268,11 @@ static ref_api_t gEngfuncs = CL_GetLocalPlayer, CL_GetViewModel, +#if XASH_OPT + pfnCL_GetEntityByIndex, +#else CL_GetEntityByIndex, +#endif R_BeamGetEntity, CL_GetWaterEntity, CL_AddVisibleEntity, @@ -295,7 +299,11 @@ static ref_api_t gEngfuncs = Mod_ForName, pfnMod_Extradata, +#if XASH_OPT + pfnCL_ModelHandle, +#else CL_ModelHandle, +#endif pfnMod_GetCurrentLoadingModel, pfnMod_SetCurrentLoadingModel, diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 38047960..745b7cb0 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -466,8 +466,14 @@ void VOX_LoadSound( channel_t *pchan, const char *pszin ) // lookup actual string in g_Sentences, // set pointer to string data +#ifdef XASH_PSP + if( pszin[0] == '#' ) + psz = VOX_LookupString( pszin + 1, NULL ); + else + psz = VOX_LookupString( pszin, NULL ); +#else psz = VOX_LookupString( pszin, NULL ); - +#endif if( !psz ) { Con_DPrintf( S_ERROR "VOX_LoadSound: no such sentence %s\n", pszin ); diff --git a/engine/common/base_cmd.c b/engine/common/base_cmd.c index b1685626..745f6624 100644 --- a/engine/common/base_cmd.c +++ b/engine/common/base_cmd.c @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "base_cmd.h" #include "cdll_int.h" +#ifdef XASH_HASHED_VARS // TODO: use another hash function, as COM_HashKey depends on string length #define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes static base_command_hashmap_t *hashed_cmds[HASH_SIZE]; @@ -285,3 +286,5 @@ void BaseCmd_Test_f( void ) Con_Printf( "BaseCmd is valid\n" ); } } + +#endif // XASH_HASHED_VARS diff --git a/engine/common/build.c b/engine/common/build.c index 78f9c8f9..d9bcca82 100644 --- a/engine/common/build.c +++ b/engine/common/build.c @@ -93,6 +93,8 @@ const char *Q_buildos( void ) osname = "emscripten"; #elif XASH_DOS4GW osname = "DOS4GW"; +#elif XASH_PSP + osname = "psp"; #else #error "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug" #endif @@ -136,9 +138,9 @@ const char *Q_buildarch( void ) #else "l"; #endif -#elif XASH_MIPS && XASH_BIG_ENDIAN +#elif XASH_MIPS && defined XASH_BIG_ENDIAN archname = "mips"; -#elif XASH_MIPS && XASH_LITTLE_ENDIAN +#elif XASH_MIPS && defined XASH_LITTLE_ENDIAN archname = "mipsel"; #elif XASH_JS archname = "javascript"; diff --git a/engine/common/common.h b/engine/common/common.h index b23e3147..7a02284a 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -138,10 +138,13 @@ typedef enum #define CIN_MAIN 0 #define CIN_LOGO 1 +#if XASH_PSP +#define MAX_DECALS 256 // touching TE_DECAL messages, etc +#define MAX_STATIC_ENTITIES 256 // static entities that moved on the client when level is spawn +#else #if XASH_LOW_MEMORY == 0 #define MAX_DECALS 512 // touching TE_DECAL messages, etc #define MAX_STATIC_ENTITIES 3096 // static entities that moved on the client when level is spawn - #elif XASH_LOW_MEMORY == 2 #define MAX_DECALS 256 // touching TE_DECAL messages, etc #define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn @@ -149,6 +152,7 @@ typedef enum #define MAX_DECALS 512 // touching TE_DECAL messages, etc #define MAX_STATIC_ENTITIES 128 // static entities that moved on the client when level is spawn #endif +#endif // filesystem flags #define FS_STATIC_PATH ( 1U << 0 ) // FS_ClearSearchPath will be ignore this path @@ -240,7 +244,9 @@ typedef struct gameinfo_s int max_tents; // min temp ents is 300, max is 2048 int max_beams; // min beams is 64, max beams is 512 int max_particles; // min particles is 4096, max particles is 32768 - +#ifdef XASH_PSP + char game_dll_psp[64]; +#endif char game_dll_linux[64]; // custom path for game.dll char game_dll_osx[64]; // custom path for game.dll @@ -871,7 +877,12 @@ int R_CreateDecalList( struct decallist_s *pList ); void R_ClearAllDecals( void ); void CL_ClearStaticEntities( void ); qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position ); +#if XASH_OPT +#define CL_GetEntityByIndex( index ) ( ( !clgame.entities ) ? NULL : ( ( ( index ) < 0 || ( index ) >= clgame.maxEntities ) ? NULL : ( ( ( index ) == 0 ) ? clgame.entities : ( clgame.entities + ( index ) ) ) ) ) +struct cl_entity_s *pfnCL_GetEntityByIndex( int index ); +#else struct cl_entity_s *CL_GetEntityByIndex( int index ); +#endif struct player_info_s *CL_GetPlayerInfo( int playerIndex ); void CL_ServerCommand( qboolean reliable, char *fmt, ... ) _format( 2 ); void CL_HudMessage( const char *pMessage ); diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index 946e2fed..c38919a9 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -23,6 +23,10 @@ GNU General Public License for more details. #elif XASH_DOS4GW #include #include +#elif XASH_PSP +#include +#include +#include #else #include #include @@ -80,16 +84,25 @@ typedef struct wadtype_s struct file_s { +#if XASH_PSP + SceUID handle; // psp file descriptor +#else int handle; // file descriptor +#endif fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode) fs_offset_t position; // current position in the file fs_offset_t offset; // offset into the package (0 if external file) int ungetc; // single stored character from ungetc, cleared to EOF when read +#if !XASH_PSP /* unused */ time_t filetime; // pak, wad or real filetime +#endif // contents buffer fs_offset_t buff_ind, buff_len; // buffer current index and length byte buff[FILE_BUFF_SIZE]; // intermediate buffer #ifdef XASH_REDUCE_FD +#if XASH_PSP + qboolean backup_hold; +#endif const char *backup_path; fs_offset_t backup_position; uint backup_options; @@ -110,7 +123,11 @@ struct wfile_s typedef struct pack_s { string filename; +#if XASH_PSP + SceUID handle; +#else int handle; +#endif int numfiles; time_t filetime; // common for all packed files dpackfile_t *files; @@ -128,7 +145,11 @@ typedef struct zipfile_s typedef struct zip_s { string filename; +#if XASH_PSP + SceUID handle; +#else int handle; +#endif int numfiles; time_t filetime; zipfile_t *files; @@ -168,7 +189,20 @@ static void FS_EnsureOpenFile( file_t *file ) if( file && !file->backup_path ) return; - +#if XASH_PSP + if( fs_last_readfile && (fs_last_readfile->handle != -1) && (fs_last_readfile->backup_hold == false) ) + { + fs_last_readfile->backup_position = sceIoLseek( fs_last_readfile->handle, 0, PSP_SEEK_CUR ); + sceIoClose( fs_last_readfile->handle ); + fs_last_readfile->handle = -1; + } + fs_last_readfile = file; + if( file && (file->handle == -1) ) + { + file->handle = sceIoOpen( file->backup_path, file->backup_options, 0666 ); + sceIoLseek( file->handle, file->backup_position, PSP_SEEK_SET ); + } +#else if( fs_last_readfile && (fs_last_readfile->handle != -1) ) { fs_last_readfile->backup_position = lseek( fs_last_readfile->handle, 0, SEEK_CUR ); @@ -181,13 +215,23 @@ static void FS_EnsureOpenFile( file_t *file ) file->handle = open( file->backup_path, file->backup_options ); lseek( file->handle, file->backup_position, SEEK_SET ); } +#endif } static void FS_EnsureOpenZip( zip_t *zip ) { if( fs_last_zip == zip ) return; - +#if XASH_PSP + if( fs_last_zip && (fs_last_zip->handle != -1) ) + { + sceIoClose( fs_last_zip->handle ); + fs_last_zip->handle = -1; + } + fs_last_zip = zip; + if( zip && (zip->handle == -1) ) + zip->handle = sceIoOpen( zip->filename, PSP_O_RDONLY, 0666 ); +#else if( fs_last_zip && (fs_last_zip->handle != -1) ) { close( fs_last_zip->handle ); @@ -196,6 +240,7 @@ static void FS_EnsureOpenZip( zip_t *zip ) fs_last_zip = zip; if( zip && (zip->handle == -1) ) zip->handle = open( zip->filename, O_RDONLY|O_BINARY ); +#endif } static void FS_BackupFileName( file_t *file, const char *path, uint options ) @@ -207,7 +252,11 @@ static void FS_BackupFileName( file_t *file, const char *path, uint options ) if( file == fs_last_readfile ) FS_EnsureOpenFile( NULL ); } +#if XASH_PSP + else if( options == PSP_O_RDONLY ) +#else else if( options == O_RDONLY || options == (O_RDONLY|O_BINARY) ) +#endif { file->backup_path = copystring( path ); file->backup_options = options; @@ -325,6 +374,9 @@ static void listdirectory( stringlist_t *list, const char *path, qboolean lowerc char pattern[4096]; struct _finddata_t n_file; int hFile; +#elif XASH_PSP + SceUID dir; + SceIoDirent entry; #else DIR *dir; struct dirent *entry; @@ -343,6 +395,20 @@ static void listdirectory( stringlist_t *list, const char *path, qboolean lowerc while( _findnext( hFile, &n_file ) == 0 ) stringlistappend( list, n_file.name ); _findclose( hFile ); +#elif XASH_PSP + if( ( dir = sceIoDopen( path ) ) < 0 ) + return; + + // iterate through the directory + while( 1 ) + { + // zero the dirent, to avoid possible problems with sceIoDread + memset( &entry, 0, sizeof( SceIoDirent ) ); + if( !sceIoDread( dir, &entry ) ) + break; + stringlistappend( list, entry.d_name ); + } + sceIoDclose( dir ); #else if( !( dir = opendir( path ) ) ) return; @@ -405,7 +471,7 @@ static const char *FS_FixFileCase( const char *path ) out[i] = 0; return out; -#elif !XASH_WIN32 && !XASH_IOS // assume case insensitive +#elif !XASH_WIN32 && !XASH_IOS && !XASH_PSP // assume case insensitive DIR *dir; struct dirent *entry; char path2[PATH_MAX], *fname; @@ -524,7 +590,11 @@ void FS_CreatePath( char *path ) // create the directory save = *ofs; *ofs = 0; +#if XASH_PSP + sceIoMkdir( path, 0777 ); +#else _mkdir( path ); +#endif *ofs = save; } } @@ -585,14 +655,20 @@ of the list so they override previous pack files. pack_t *FS_LoadPackPAK( const char *packfile, int *error ) { dpackheader_t header; +#if XASH_PSP + SceUID packhandle; +#else int packhandle; +#endif int i, numpackfiles; pack_t *pack; dpackfile_t *info; - +#if XASH_PSP + packhandle = sceIoOpen( packfile, PSP_O_RDONLY, 0666 ); +#else packhandle = open( packfile, O_RDONLY|O_BINARY ); - -#if !XASH_WIN32 +#endif +#if !XASH_WIN32 && !XASH_PSP if( packhandle < 0 ) { const char *fpackfile = FS_FixFileCase( packfile ); @@ -607,14 +683,20 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) if( error ) *error = PAK_LOAD_COULDNT_OPEN; return NULL; } - +#if XASH_PSP + sceIoRead( packhandle, (void *)&header, sizeof( header )); +#else read( packhandle, (void *)&header, sizeof( header )); - +#endif if( header.ident != IDPACKV1HEADER ) { Con_Reportf( "%s is not a packfile. Ignored.\n", packfile ); if( error ) *error = PAK_LOAD_BAD_HEADER; +#if XASH_PSP + sceIoClose( packhandle ); +#else close( packhandle ); +#endif return NULL; } @@ -622,7 +704,11 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) { Con_Reportf( S_ERROR "%s has an invalid directory size. Ignored.\n", packfile ); if( error ) *error = PAK_LOAD_BAD_FOLDERS; +#if XASH_PSP + sceIoClose( packhandle ); +#else close( packhandle ); +#endif return NULL; } @@ -632,7 +718,11 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) { Con_Reportf( S_ERROR "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles ); if( error ) *error = PAK_LOAD_TOO_MANY_FILES; +#if XASH_PSP + sceIoClose( packhandle ); +#else close( packhandle ); +#endif return NULL; } @@ -640,18 +730,33 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) { Con_Reportf( "%s has no files. Ignored.\n", packfile ); if( error ) *error = PAK_LOAD_NO_FILES; +#if XASH_PSP + sceIoClose( packhandle ); +#else close( packhandle ); +#endif return NULL; } info = (dpackfile_t *)Mem_Malloc( fs_mempool, sizeof( *info ) * numpackfiles ); +#if XASH_PSP + sceIoLseek( packhandle, header.dirofs, PSP_SEEK_SET ); +#else lseek( packhandle, header.dirofs, SEEK_SET ); - +#endif +#if XASH_PSP + if( header.dirlen != sceIoRead( packhandle, (void *)info, header.dirlen ) ) +#else if( header.dirlen != read( packhandle, (void *)info, header.dirlen )) +#endif { Con_Reportf( "%s is an incomplete PAK, not loading\n", packfile ); if( error ) *error = PAK_LOAD_CORRUPTED; +#if XASH_PSP + sceIoClose( packhandle ); +#else close( packhandle ); +#endif Mem_Free( info ); return NULL; } @@ -669,7 +774,11 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) #ifdef XASH_REDUCE_FD // will reopen when needed - close(pack->handle); +#if XASH_PSP + sceIoClose( packhandle ); +#else + close( packhandle ); +#endif pack->handle = -1; #endif @@ -689,10 +798,12 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) zipfile_t *info = NULL; char filename_buffer[MAX_SYSPATH]; zip_t *zip = (zip_t *)Mem_Calloc( fs_mempool, sizeof( zip_t ) ); - +#if XASH_PSP + zip->handle = sceIoOpen( zipfile, PSP_O_RDONLY, 0666 ); +#else zip->handle = open( zipfile, O_RDONLY|O_BINARY ); - -#if !XASH_WIN32 +#endif +#if !XASH_WIN32 && !XASH_PSP if( zip->handle < 0 ) { const char *fzipfile = FS_FixFileCase( zipfile ); @@ -711,9 +822,11 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) Zip_Close( zip ); return NULL; } - +#if XASH_PSP + length = sceIoLseek( zip->handle, 0, PSP_SEEK_END ); +#else length = lseek( zip->handle, 0, SEEK_END ); - +#endif if( length > UINT_MAX ) { Con_Reportf( S_ERROR "%s bigger than 4GB.\n", zipfile ); @@ -724,11 +837,13 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) Zip_Close( zip ); return NULL; } - +#if XASH_PSP + sceIoLseek( zip->handle, 0, PSP_SEEK_SET ); + sceIoRead( zip->handle, &signature, sizeof( signature ) ); +#else lseek( zip->handle, 0, SEEK_SET ); - read( zip->handle, &signature, sizeof( signature ) ); - +#endif if( signature == ZIP_HEADER_EOCD ) { Con_Reportf( S_WARN "%s has no files. Ignored.\n", zipfile ); @@ -752,14 +867,22 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) } // Find oecd +#if XASH_PSP + sceIoLseek( zip->handle, 0, PSP_SEEK_SET ); +#else lseek( zip->handle, 0, SEEK_SET ); +#endif filepos = length; while ( filepos > 0 ) { +#if XASH_PSP + sceIoLseek( zip->handle, filepos, PSP_SEEK_SET ); + sceIoRead( zip->handle, &signature, sizeof( signature ) ); +#else lseek( zip->handle, filepos, SEEK_SET ); read( zip->handle, &signature, sizeof( signature ) ); - +#endif if( signature == ZIP_HEADER_EOCD ) break; @@ -776,19 +899,27 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) Zip_Close( zip ); return NULL; } +#if XASH_PSP + sceIoRead( zip->handle, &header_eocd, sizeof( zip_header_eocd_t ) ); + // Move to CDF start + sceIoLseek( zip->handle, header_eocd.central_directory_offset, PSP_SEEK_SET ); +#else read( zip->handle, &header_eocd, sizeof( zip_header_eocd_t ) ); // Move to CDF start lseek( zip->handle, header_eocd.central_directory_offset, SEEK_SET ); - +#endif // Calc count of files in archive info = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * header_eocd.total_central_directory_record ); for( i = 0; i < header_eocd.total_central_directory_record; i++ ) { +#if XASH_PSP + sceIoRead( zip->handle, &header_cdf, sizeof( header_cdf ) ); +#else read( zip->handle, &header_cdf, sizeof( header_cdf ) ); - +#endif if( header_cdf.signature != ZIP_HEADER_CDF ) { Con_Reportf( S_ERROR "CDF signature mismatch in %s. Zip file corrupted.\n", zipfile ); @@ -804,7 +935,11 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) if( header_cdf.uncompressed_size && header_cdf.filename_len && ( header_cdf.filename_len < MAX_SYSPATH ) ) { memset( &filename_buffer, '\0', MAX_SYSPATH ); +#if XASH_PSP + sceIoRead( zip->handle, &filename_buffer, header_cdf.filename_len ); +#else read( zip->handle, &filename_buffer, header_cdf.filename_len ); +#endif Q_strncpy( info[numpackfiles].name, filename_buffer, MAX_SYSPATH ); info[numpackfiles].size = header_cdf.uncompressed_size; @@ -813,6 +948,15 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) numpackfiles++; } else +#if XASH_PSP + sceIoLseek( zip->handle, header_cdf.filename_len, PSP_SEEK_CUR ); + + if( header_cdf.extrafield_len ) + sceIoLseek( zip->handle, header_cdf.extrafield_len, PSP_SEEK_CUR ); + + if( header_cdf.file_commentary_len ) + sceIoLseek( zip->handle, header_cdf.file_commentary_len, PSP_SEEK_CUR ); +#else lseek( zip->handle, header_cdf.filename_len, SEEK_CUR ); if( header_cdf.extrafield_len ) @@ -820,15 +964,20 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) if( header_cdf.file_commentary_len ) lseek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR ); +#endif } // recalculate offsets for( i = 0; i < numpackfiles; i++ ) { zip_header_t header; - +#if XASH_PSP + sceIoLseek( zip->handle, info[i].offset, PSP_SEEK_SET ); + sceIoRead( zip->handle, &header, sizeof( header ) ); +#else lseek( zip->handle, info[i].offset, SEEK_SET ); read( zip->handle, &header, sizeof( header ) ); +#endif info[i].flags = header.compression_flags; info[i].offset = info[i].offset + header.filename_len + header.extrafield_len + sizeof( header ); } @@ -840,8 +989,13 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error ) #ifdef XASH_REDUCE_FD // will reopen when needed - close(zip->handle); +#if XASH_PSP + sceIoClose( zip->handle ); zip->handle = -1; +#else + close( zip->handle ); + zip->handle = -1; +#endif #endif if( error ) @@ -858,10 +1012,13 @@ void Zip_Close( zip_t *zip ) Mem_Free( zip->files ); FS_EnsureOpenZip( NULL ); - +#if XASH_PSP + if( zip->handle >= 0 ) + sceIoClose( zip->handle ); +#else if( zip->handle >= 0 ) close( zip->handle ); - +#endif Mem_Free( zip ); } @@ -885,10 +1042,13 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game file = &search->zip->files[index]; FS_EnsureOpenZip( search->zip ); - +#if XASH_PSP + if( sceIoLseek( search->zip->handle, file->offset, PSP_SEEK_SET ) == -1 ) + return NULL; +#else if( lseek( search->zip->handle, file->offset, SEEK_SET ) == -1 ) return NULL; - +#endif /*if( read( search->zip->handle, &header, sizeof( header ) ) < 0 ) return NULL; @@ -902,8 +1062,11 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game { decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 ); decompressed_buffer[file->size] = '\0'; - +#if XASH_PSP + sceIoRead( search->zip->handle, decompressed_buffer, file->size ); +#else read( search->zip->handle, decompressed_buffer, file->size ); +#endif #if 0 CRC32_Init( &test_crc ); CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size ); @@ -927,9 +1090,11 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 ); decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 ); decompressed_buffer[file->size] = '\0'; - +#if XASH_PSP + sceIoRead( search->zip->handle, compressed_buffer, file->compressed_size ); +#else read( search->zip->handle, compressed_buffer, file->compressed_size ); - +#endif memset( &decompress_stream, 0, sizeof( decompress_stream ) ); decompress_stream.total_in = decompress_stream.avail_in = file->compressed_size; @@ -1268,12 +1433,15 @@ void FS_AddGameHierarchy( const char *dir, uint flags ) FS_AddGameDirectory( va( "%s/%s/", host.rodir, dir ), newFlags ); FS_AllowDirectPaths( false ); } - +#if !XASH_PSP if( isGameDir ) FS_AddGameDirectory( va( "%s/downloaded/", dir ), FS_NOWRITE_PATH | FS_CUSTOM_PATH ); +#endif FS_AddGameDirectory( va( "%s/", dir ), flags ); +#if !XASH_PSP if( isGameDir ) FS_AddGameDirectory( va( "%s/custom/", dir ), FS_NOWRITE_PATH | FS_CUSTOM_PATH ); +#endif } /* @@ -1302,8 +1470,13 @@ void FS_ClearSearchPath( void ) { if( search->pack->files ) Mem_Free( search->pack->files ); +#if XASH_PSP + if( search->pack->handle >= 0 ) + sceIoClose( search->pack->handle ); +#else if( search->pack->handle >= 0 ) close( search->pack->handle ); +#endif Mem_Free( search->pack ); } @@ -1477,8 +1650,10 @@ static void FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) if( Q_strlen( GameInfo->game_dll_osx )) FS_Printf( f, "gamedll_osx\t\t\"%s\"\n", GameInfo->game_dll_osx ); - - +#if XASH_PSP + if( Q_strlen( GameInfo->game_dll_psp )) + FS_Printf( f, "gamedll_psp\t\t\"%s\"\n", GameInfo->game_dll_psp ); +#endif if( Q_strlen( GameInfo->iconpath )) FS_Printf( f, "icon\t\t\"%s\"\n", GameInfo->iconpath ); @@ -1545,7 +1720,9 @@ void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir ) Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux )); Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx )); - +#if XASH_PSP + Q_strncpy( GameInfo->game_dll_psp, "dlls/server.prx", sizeof( GameInfo->game_dll_psp )); +#endif // .ico path Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath )); @@ -1562,6 +1739,9 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool { char *pfile = (char*) buf; qboolean found_linux = false, found_osx = false; +#if XASH_PSP + qboolean found_psp = false; +#endif string token; while(( pfile = COM_ParseFile( pfile, token )) != NULL ) @@ -1617,6 +1797,14 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool pfile = COM_ParseFile( pfile, GameInfo->game_dll_osx ); found_osx = true; } +#if XASH_PSP + // valid for both + else if( !Q_stricmp( token, "gamedll_psp" )) + { + pfile = COM_ParseFile( pfile, GameInfo->game_dll_psp ); + found_psp = true; + } +#endif // valid for both else if( !Q_stricmp( token, "icon" )) { @@ -1759,7 +1947,8 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool } } } - + +#if XASH_PSP if( !found_linux || !found_osx ) { // just replace extension from dll to so/dylib @@ -1773,7 +1962,10 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool if( !found_osx ) Q_snprintf( GameInfo->game_dll_osx, sizeof( GameInfo->game_dll_osx ), "%s.dylib", gamedll ); } - +#else + if( !found_psp ) + Q_snprintf( GameInfo->game_dll_psp, sizeof( GameInfo->game_dll_psp ), "dlls/server.prx" ); // force set +#endif // make sure what gamedir is really exist if( !FS_SysFolderExists( va( "%s"PATH_SPLITTER"%s", host.rootdir, GameInfo->falldir ))) GameInfo->falldir[0] = '\0'; @@ -2027,7 +2219,7 @@ void FS_Init( void ) Cmd_AddCommand( "fs_path", FS_Path_f, "show filesystem search pathes" ); Cmd_AddCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" ); -#if !XASH_WIN32 +#if !XASH_WIN32 && !XASH_PSP if( Sys_CheckParm( "-casesensitive" ) ) fs_caseinsensitive = false; @@ -2156,12 +2348,30 @@ Internal function used to determine filetime */ static int FS_SysFileTime( const char *filename ) { +#if XASH_PSP + SceIoStat buf; + struct tm libc_tm; + + if ( sceIoGetstat( filename, &buf ) < 0 ) + return -1; + + libc_tm.tm_year = buf.st_mtime.year; + libc_tm.tm_mon = buf.st_mtime.month; + libc_tm.tm_mday = buf.st_mtime.day; + libc_tm.tm_hour = buf.st_mtime.hour; + libc_tm.tm_min = buf.st_mtime.minute; + libc_tm.tm_sec = buf.st_mtime.second; + libc_tm.tm_isdst = -1; + + return mktime( &libc_tm ); +#else struct stat buf; if( stat( filename, &buf ) == -1 ) return -1; return buf.st_mtime; +#endif } /* @@ -2176,7 +2386,53 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) file_t *file; int mod, opt; uint ind; +#if XASH_PSP + qboolean backup_hold = false; + // Hold file in open state + if( mode[0] == '*' ) + { + backup_hold = true; + mode++; + } + + // Parse the mode string + switch( mode[0] ) + { + case 'r': // read + mod = PSP_O_RDONLY; + opt = 0; + break; + case 'w': // write + mod = PSP_O_WRONLY; + opt = PSP_O_CREAT | PSP_O_TRUNC; + break; + case 'a': // append + mod = PSP_O_WRONLY; + opt = PSP_O_CREAT | PSP_O_APPEND; + break; + case 'e': // edit + mod = PSP_O_WRONLY; + opt = PSP_O_CREAT; + break; + default: + return NULL; + } + + for( ind = 1; mode[ind] != '\0'; ind++ ) + { + switch( mode[ind] ) + { + case '+': + mod = PSP_O_RDWR; + break; + case 'b': // not used + break; + default: + break; + } + } +#else // Parse the mode string switch( mode[0] ) { @@ -2214,14 +2470,23 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) break; } } - +#endif file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file )); +#if !XASH_PSP file->filetime = FS_SysFileTime( filepath ); +#endif file->ungetc = EOF; - +#if XASH_PSP + file->handle = sceIoOpen( filepath, mod|opt, 0666 ); +#else file->handle = open( filepath, mod|opt, 0666 ); +#endif -#if !XASH_WIN32 +#if XASH_PSP + file->backup_hold = backup_hold; + if( file->handle >= 0 ) + FS_BackupFileName( file, filepath, mod|opt ); +#elif !XASH_WIN32 if( file->handle < 0 ) { const char *ffilepath = FS_FixFileCase( filepath ); @@ -2234,22 +2499,29 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) FS_BackupFileName( file, filepath, mod|opt ); #endif + if( file->handle < 0 ) { Mem_Free( file ); return NULL; } - +#if XASH_PSP + file->real_length = sceIoLseek( file->handle, 0, PSP_SEEK_END ); +#else file->real_length = lseek( file->handle, 0, SEEK_END ); - +#endif // uncomment do disable write //if( opt & O_CREAT ) // return NULL; // For files opened in append mode, we start at the end of the file if( opt & O_APPEND ) file->position = file->real_length; +#if XASH_PSP + else sceIoLseek( file->handle, 0, PSP_SEEK_SET ); +#else else lseek( file->handle, 0, SEEK_SET ); +#endif return file; } @@ -2270,6 +2542,15 @@ static file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offse { file_t *file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t )); #ifndef XASH_REDUCE_FD +#if XASH_PSP + file->handle = sceIoOpen( syspath, PSP_O_RDONLY, 0666 ); + + if( sceIoLseek( file->handle, offset, SEEK_SET ) == -1 ) + { + Mem_Free( file ); + return NULL; + } +#else /* XASH_PSP */ #ifdef HAVE_DUP file->handle = dup( handle ); #else @@ -2281,13 +2562,18 @@ static file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offse Mem_Free( file ); return NULL; } - -#else +#endif /* XASH_PSP */ +#else /* XASH_REDUCE_FD */ file->backup_position = offset; file->backup_path = copystring( syspath ); +#if XASH_PSP + file->backup_hold = false; + file->backup_options = PSP_O_RDONLY; +#else file->backup_options = O_RDONLY|O_BINARY; - file->handle = -1; #endif + file->handle = -1; +#endif /* XASH_REDUCE_FD */ file->real_length = len; file->offset = offset; @@ -2349,6 +2635,11 @@ qboolean FS_SysFileExists( const char *path, qboolean caseinsensitive ) close( desc ); return true; +#elif XASH_PSP + SceIoStat buf; + if ( sceIoGetstat( path, &buf ) < 0 ) + return false; + return FIO_S_ISREG( buf.st_mode ); #else int ret; struct stat buf; @@ -2383,6 +2674,23 @@ qboolean FS_SysFolderExists( const char *path ) DWORD dwFlags = GetFileAttributes( path ); return ( dwFlags != -1 ) && ( dwFlags & FILE_ATTRIBUTE_DIRECTORY ); +#elif XASH_PSP + SceUID dir = sceIoDopen( path ); + + if( dir >= 0 ) + { + sceIoDclose( dir ); + return true; + } + else if( ( dir == 0x80010002 ) || ( dir == 0x80010014 ) ) + { + return false; + } + else + { + Con_Reportf( S_ERROR "FS_SysFolderExists: problem while opening dir: %#010x\n", dir ); + return false; + } #else DIR *dir = opendir( path ); @@ -2640,7 +2948,11 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly ) char real_path[MAX_SYSPATH]; // open the file on disk directly +#if XASH_PSP /* Fixed double slashes */ + Q_sprintf( real_path, "%s%s", fs_writedir, filepath ); +#else Q_sprintf( real_path, "%s/%s", fs_writedir, filepath ); +#endif FS_CreatePath( real_path );// Create directories up to the file return FS_SysOpen( real_path, mode ); } @@ -2663,7 +2975,11 @@ int FS_Close( file_t *file ) FS_BackupFileName( file, NULL, 0 ); if( file->handle >= 0 ) +#if XASH_PSP + if( sceIoClose( file->handle ) ) +#else if( close( file->handle )) +#endif return EOF; Mem_Free( file ); @@ -2685,15 +3001,22 @@ fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize ) // if necessary, seek to the exact file position we're supposed to be if( file->buff_ind != file->buff_len ) +#if XASH_PSP + sceIoLseek( file->handle, file->buff_ind - file->buff_len, PSP_SEEK_CUR ); +#else lseek( file->handle, file->buff_ind - file->buff_len, SEEK_CUR ); - +#endif // purge cached data FS_Purge( file ); - +#if XASH_PSP + // write the buffer and update the position + result = sceIoWrite( file->handle, data, (fs_offset_t)datasize ); + file->position = sceIoLseek( file->handle, 0, PSP_SEEK_CUR ); +#else // write the buffer and update the position result = write( file->handle, data, (fs_offset_t)datasize ); file->position = lseek( file->handle, 0, SEEK_CUR ); - +#endif if( file->real_length < file->position ) file->real_length = file->position; @@ -2752,9 +3075,13 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) { if( count > (fs_offset_t)buffersize ) count = (fs_offset_t)buffersize; +#if XASH_PSP + sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); + nb = sceIoRead (file->handle, &((byte *)buffer)[done], count ); +#else lseek( file->handle, file->offset + file->position, SEEK_SET ); nb = read (file->handle, &((byte *)buffer)[done], count ); - +#endif if( nb > 0 ) { done += nb; @@ -2767,9 +3094,13 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) { if( count > (fs_offset_t)sizeof( file->buff )) count = (fs_offset_t)sizeof( file->buff ); +#if XASH_PSP + sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); + nb = sceIoRead( file->handle, file->buff, count ); +#else lseek( file->handle, file->offset + file->position, SEEK_SET ); nb = read( file->handle, file->buff, count ); - +#endif if( nb > 0 ) { file->buff_len = nb; @@ -2843,8 +3174,11 @@ int FS_VPrintf( file_t *file, const char *format, va_list ap ) Mem_Free( tempbuff ); buff_size *= 2; } - +#if XASH_PSP + len = sceIoWrite( file->handle, tempbuff, len ); +#else len = write( file->handle, tempbuff, len ); +#endif Mem_Free( tempbuff ); return len; @@ -2956,9 +3290,13 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence ) FS_EnsureOpenFile( file ); // Purge cached data FS_Purge( file ); - +#if XASH_PSP + if( sceIoLseek( file->handle, file->offset + offset, PSP_SEEK_SET ) == -1 ) + return -1; +#else if( lseek( file->handle, file->offset + offset, SEEK_SET ) == -1 ) return -1; +#endif file->position = offset; return 0; diff --git a/engine/common/host.c b/engine/common/host.c index aa6df9c6..1e8fe3c6 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -874,10 +874,10 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha // init host state machine COM_InitHostState(); - +#ifdef XASH_HASHED_VARS // init hashed commands BaseCmd_Init(); - +#endif // startup cmds and cvars subsystem Cmd_Init(); Cvar_Init(); @@ -908,6 +908,8 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha #if TARGET_OS_IOS const char *IOS_GetDocsDir(); Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) ); +#elif XASH_PSP + COM_ExtractFilePath( argv[0], host.rootdir ); #elif XASH_SDL == 2 char *szBasePath; @@ -1009,7 +1011,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa host_serverstate = Cvar_Get( "host_serverstate", "0", FCVAR_READ_ONLY, "displays current server state" ); host_maxfps = Cvar_Get( "fps_max", "72", FCVAR_ARCHIVE, "host fps upper limit" ); host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" ); +#if XASH_PSP + host_sleeptime = Cvar_Get( "sleeptime", "0", FCVAR_ARCHIVE, "milliseconds to sleep for each frame. higher values reduce fps accuracy" ); +#else host_sleeptime = Cvar_Get( "sleeptime", "1", FCVAR_ARCHIVE, "milliseconds to sleep for each frame. higher values reduce fps accuracy" ); +#endif host_gameloaded = Cvar_Get( "host_gameloaded", "0", FCVAR_READ_ONLY, "inidcates a loaded game.dll" ); host_clientloaded = Cvar_Get( "host_clientloaded", "0", FCVAR_READ_ONLY, "inidcates a loaded client.dll" ); host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" ); diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 358de8e3..08532b3d 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -101,7 +101,22 @@ static const loadpixformat_t load_null[] = { { NULL, NULL, NULL, IL_HINT_NO } }; - +#if XASH_PSP +static const loadpixformat_t load_game[] = +{ +{ "%s%s.%s", "mip", Image_LoadMIP, IL_HINT_NO }, // hl textures from wad or buffer +//{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models +{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus +{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images +//{ "%s%s.%s", "png", Image_LoadPNG, IL_HINT_NO }, // NightFire 007 menus +{ "%s%s.%s", "mdl", Image_LoadMDL, IL_HINT_HL }, // hl studio model skins +{ "%s%s.%s", "spr", Image_LoadSPR, IL_HINT_HL }, // hl sprite frames +{ "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc) +{ "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc) +{ "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette +{ NULL, NULL, NULL, IL_HINT_NO } +}; +#else static const loadpixformat_t load_game[] = { { "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models @@ -116,7 +131,7 @@ static const loadpixformat_t load_game[] = { "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette { NULL, NULL, NULL, IL_HINT_NO } }; - +#endif /* ============================================================================= diff --git a/engine/common/launcher.c b/engine/common/launcher.c index 08fedf6b..b37968eb 100644 --- a/engine/common/launcher.c +++ b/engine/common/launcher.c @@ -34,6 +34,11 @@ GNU General Public License for more details. static char szGameDir[128]; // safe place to keep gamedir static int g_iArgc; static char **g_pszArgv; +#if XASH_PSP +#define MAX_NARGVS 50 +static int g_fArgc; +static char *g_fArgv[MAX_NARGVS]; +#endif void Launcher_ChangeGame( const char *progname ) { @@ -70,6 +75,7 @@ int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int n free( szArgv ); } #endif + int main( int argc, char** argv ) { char gamedir_buf[32] = ""; @@ -102,15 +108,38 @@ int main( int argc, char** argv ) #endif #endif +#if XASH_PSP + g_iArgc = argc; + g_pszArgv = argv; + if(argc <= 1) + { + g_fArgc = 0; + g_fArgv[g_fArgc++] = argv[0]; // for get root directory path + Platform_ReadCmd( "start.cmd", &g_fArgc, g_fArgv ); + if(g_fArgc > 1) + { + g_iArgc = g_fArgc; + g_pszArgv = g_fArgv; + } + } +#else g_iArgc = argc; g_pszArgv = argv; +#endif #if XASH_IOS { void IOS_LaunchDialog( void ); IOS_LaunchDialog(); } #endif + +#if XASH_PSP + Host_Main( g_iArgc, g_pszArgv, gamedir, 0, &Launcher_ChangeGame ); + Sys_Quit( ); + return 0; +#else return Host_Main( g_iArgc, g_pszArgv, gamedir, 0, &Launcher_ChangeGame ); +#endif } #endif diff --git a/engine/common/lib_common.c b/engine/common/lib_common.c index 76080657..9788053b 100644 --- a/engine/common/lib_common.c +++ b/engine/common/lib_common.c @@ -63,7 +63,7 @@ const char *COM_OffsetNameForFunction( void *function ) static void COM_GenerateCommonLibraryName( const char *name, const char *ext, char *out, size_t size ) { -#if ( XASH_WIN32 || XASH_LINUX || XASH_APPLE ) && XASH_X86 +#if (( XASH_WIN32 || XASH_LINUX || XASH_APPLE ) && XASH_X86) || XASH_PSP Q_snprintf( out, size, "%s.%s", name, ext ); #elif ( XASH_WIN32 || XASH_LINUX || XASH_APPLE ) Q_snprintf( out, size, "%s_%s.%s", name, Q_buildarch(), ext ); @@ -110,6 +110,8 @@ static void COM_GenerateServerLibraryPath( char *out, size_t size ) Q_strncpy( out, GI->game_dll, size ); #elif XASH_APPLE Q_strncpy( out, GI->game_dll_osx, size ); +#elif XASH_PSP + Q_strncpy( out, GI->game_dll_psp, size ); #else // XASH_LINUX Q_strncpy( out, GI->game_dll_linux, size ); #endif @@ -122,6 +124,8 @@ static void COM_GenerateServerLibraryPath( char *out, size_t size ) Q_strncpy( dllpath, GI->game_dll, sizeof( dllpath ) ); #elif XASH_APPLE Q_strncpy( dllpath, GI->game_dll_osx, sizeof( dllpath ) ); +#elif XASH_PSP + Q_strncpy( dllpath, GI->game_dll_psp, sizeof( dllpath ) ); #else // XASH_APPLE Q_strncpy( dllpath, GI->game_dll_linux, sizeof( dllpath ) ); #endif diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index 53a2f981..0fa02ed1 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -94,13 +94,14 @@ void MSG_Clear( sizebuf_t *sb ) sb->bOverflow = false; } +#if !XASH_PSP static qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) { if( sb->iCurBit + nBits > sb->nDataBits ) sb->bOverflow = true; return sb->bOverflow; } - +#endif qboolean MSG_CheckOverflow( sizebuf_t *sb ) { return MSG_Overflow( sb, 0 ); @@ -135,7 +136,7 @@ void MSG_SeekToByte( sizebuf_t *sb, int bytePos ) { sb->iCurBit = bytePos << 3; } - +#if !XASH_PSP void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) { if( !MSG_Overflow( sb, 1 )) @@ -146,7 +147,7 @@ void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) sb->iCurBit++; } } - +#endif void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits ) { Assert( numbits >= 0 && numbits <= 32 ); diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 0d0af632..848c1d78 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -70,7 +70,26 @@ void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, in void MSG_Clear( sizebuf_t *sb ); // Bit-write functions +#if XASH_PSP +_inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) +{ + if( sb->iCurBit + nBits > sb->nDataBits ) + sb->bOverflow = true; + return sb->bOverflow; +} +_inline void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) +{ + if( !MSG_Overflow( sb, 1 )) + { + if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 ); + else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 ); + + sb->iCurBit++; + } +} +#else void MSG_WriteOneBit( sizebuf_t *sb, int nValue ); +#endif void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits ); void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits ); void MSG_WriteBitLong( sizebuf_t *sb, int data, int numbits, qboolean bSigned ); diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index c132b1bd..5f73818f 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -295,6 +295,17 @@ static const delta_field_t ent_fields[] = { NULL }, }; +#if XASH_OPT /* Direct access */ +#define D_event_t 0 +#define D_movevars_t 1 +#define D_usercmd_t 2 +#define D_clientdata_t 3 +#define D_weapon_data_t 4 +#define D_entity_state_t 5 +#define D_entity_state_player_t 6 +#define D_custom_entity_state_t 7 +#endif + static delta_info_t dt_info[] = { { "event_t", ev_fields, NUM_FIELDS( ev_fields ) }, @@ -799,9 +810,11 @@ void Delta_Init( void ) Delta_InitFields (); // initialize fields delta_init = true; - +#if XASH_OPT + dt = &dt_info[D_movevars_t]; +#else dt = Delta_FindStruct( "movevars_t" ); - +#endif Assert( dt != NULL ); if( dt->bInitialized ) return; // "movevars_t" already specified by user @@ -894,7 +907,11 @@ Delta_ClampIntegerField prevent data to out of range ===================== */ +#if XASH_OPT +_inline int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits ) +#else int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits ) +#endif { #ifdef _DEBUG if( numbits < 32 && abs( iValue ) >= (uint)BIT( numbits )) @@ -989,7 +1006,6 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba #if defined __GNUC__ && __GNUC_MAJOR < 9 && !defined __clang__ #pragma GCC diagnostic pop #endif - fromF = Delta_ClampIntegerField( pField, fromF, bSigned, pField->bits ); toF = Delta_ClampIntegerField( pField, toF, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; @@ -1065,13 +1081,20 @@ int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean playe if( from == NULL ) return 0; return countBits; } - +#if XASH_OPT + dt = &dt_info[D_weapon_data_t]; + if( FBitSet( to->entityType, ENTITY_BEAM )) + dt = &dt_info[D_custom_entity_state_t]; + else if( player ) + dt = &dt_info[D_entity_state_player_t]; + else dt = &dt_info[D_entity_state_t]; +#else if( FBitSet( to->entityType, ENTITY_BEAM )) dt = Delta_FindStruct( "custom_entity_state_t" ); else if( player ) dt = Delta_FindStruct( "entity_state_player_t" ); else dt = Delta_FindStruct( "entity_state_t" ); - +#endif Assert( dt && dt->bInitialized ); countBits++; // entityType flag @@ -1109,7 +1132,11 @@ write fields by offsets assume from and to is valid ===================== */ +#if XASH_OPT +_inline qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) +#else qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) +#endif { qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false; float flValue, flAngle, flTime; @@ -1332,8 +1359,11 @@ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to ) delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_usercmd_t]; +#else dt = Delta_FindStruct( "usercmd_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1359,8 +1389,11 @@ void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to ) delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_usercmd_t]; +#else dt = Delta_FindStruct( "usercmd_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1394,8 +1427,11 @@ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_event_t]; +#else dt = Delta_FindStruct( "event_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1421,8 +1457,11 @@ void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_event_t]; +#else dt = Delta_FindStruct( "event_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1450,8 +1489,11 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t delta_info_t *dt; int i, startBit; int numChanges = 0; - +#if XASH_OPT + dt = &dt_info[D_movevars_t]; +#else dt = Delta_FindStruct( "movevars_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1485,8 +1527,11 @@ void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to ) delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_movevars_t]; +#else dt = Delta_FindStruct( "movevars_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1522,8 +1567,11 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, delta_info_t *dt; int i, startBit; int numChanges = 0; - +#if XASH_OPT + dt = &dt_info[D_clientdata_t]; +#else dt = Delta_FindStruct( "clientdata_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1562,8 +1610,11 @@ void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, f delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_clientdata_t]; +#else dt = Delta_FindStruct( "clientdata_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1603,8 +1654,11 @@ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to delta_info_t *dt; int i, startBit; int numChanges = 0; - +#if XASH_OPT + dt = &dt_info[D_weapon_data_t]; +#else dt = Delta_FindStruct( "weapon_data_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1641,8 +1695,11 @@ void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, delta_t *pField; delta_info_t *dt; int i; - +#if XASH_OPT + dt = &dt_info[D_weapon_data_t]; +#else dt = Delta_FindStruct( "weapon_data_t" ); +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1724,7 +1781,20 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t * numChanges++; } else MSG_WriteOneBit( msg, 0 ); - +#if XASH_OPT + if( FBitSet( to->entityType, ENTITY_BEAM )) + { + dt = &dt_info[D_custom_entity_state_t]; + } + else if( delta_type == DELTA_PLAYER ) + { + dt = &dt_info[D_entity_state_player_t]; + } + else + { + dt = &dt_info[D_entity_state_t]; + } +#else if( FBitSet( to->entityType, ENTITY_BEAM )) { dt = Delta_FindStruct( "custom_entity_state_t" ); @@ -1737,7 +1807,7 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t * { dt = Delta_FindStruct( "entity_state_t" ); } - +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; @@ -1843,6 +1913,20 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state to->entityType = MSG_ReadUBitLong( msg, 2 ); to->number = number; +#if XASH_OPT + if( cls.legacymode ? ( to->entityType == ENTITY_BEAM ) : FBitSet( to->entityType, ENTITY_BEAM )) + { + dt = &dt_info[D_custom_entity_state_t]; + } + else if( delta_type == DELTA_PLAYER ) + { + dt = &dt_info[D_entity_state_player_t]; + } + else + { + dt = &dt_info[D_entity_state_t]; + } +#else if( cls.legacymode ? ( to->entityType == ENTITY_BEAM ) : FBitSet( to->entityType, ENTITY_BEAM )) { dt = Delta_FindStruct( "custom_entity_state_t" ); @@ -1855,7 +1939,7 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state { dt = Delta_FindStruct( "entity_state_t" ); } - +#endif Assert( dt && dt->bInitialized ); pField = dt->pFields; diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c index b372c133..719821cb 100644 --- a/engine/common/net_ws.c +++ b/engine/common/net_ws.c @@ -93,6 +93,7 @@ static int ioctl_stub( int d, unsigned long r, ... ) #define SOCKET int typedef int WSAsize_t; #else +#include //GSA #include "platform/stub/net_stub.h" #endif @@ -340,7 +341,7 @@ int NET_GetHostByName( const char *hostname ) #endif } -#if !defined XASH_NO_ASYNC_NS_RESOLVE && ( XASH_WIN32 || !(XASH_EMSCRIPTEN || XASH_DOS4GW) ) +#if !defined XASH_NO_ASYNC_NS_RESOLVE && ( XASH_WIN32 || !(XASH_EMSCRIPTEN || XASH_DOS4GW || XASH_PSP) ) #define CAN_ASYNC_NS_RESOLVE #endif diff --git a/engine/common/netchan.h b/engine/common/netchan.h index 0ccb4236..2d5b3278 100644 --- a/engine/common/netchan.h +++ b/engine/common/netchan.h @@ -87,7 +87,18 @@ GNU General Public License for more details. #define NETSPLIT_BACKUP 8 #define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1) #define NETSPLIT_HEADER_SIZE 18 - +#if XASH_PSP + #undef MULTIPLAYER_BACKUP + #undef SINGLEPLAYER_BACKUP + #undef NUM_PACKET_ENTITIES + #undef MAX_CUSTOM_BASELINES + #undef NET_MAX_FRAGMENT + #define MULTIPLAYER_BACKUP 16 + #define SINGLEPLAYER_BACKUP 16 + #define NUM_PACKET_ENTITIES 32 + #define MAX_CUSTOM_BASELINES 8 + #define NET_MAX_FRAGMENT 32768 +#else #if XASH_LOW_MEMORY == 2 #undef MULTIPLAYER_BACKUP #undef SINGLEPLAYER_BACKUP @@ -109,7 +120,7 @@ GNU General Public License for more details. #define MAX_CUSTOM_BASELINES 8 #define NET_MAX_FRAGMENT 32768 #endif - +#endif /* XASH_PSP */ typedef struct netsplit_chain_packet_s { // bool vector diff --git a/engine/common/protocol.h b/engine/common/protocol.h index d43e6aec..06336c30 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -182,6 +182,29 @@ GNU General Public License for more details. #define FRAGMENT_MAX_SIZE 64000 // maximal fragment size #define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection +#if XASH_PSP + +#undef MAX_VISIBLE_PACKET +#undef MAX_VISIBLE_PACKET_VIS_BYTES +#undef MAX_EVENTS +#undef MAX_SUPPORTED_MODELS +#undef MAX_MODELS +#undef MAX_SOUNDS +#undef MAX_CUSTOM +#undef MAX_RENDER_DECALS +#undef MAX_RESOURCES + +#define MAX_VISIBLE_PACKET 256 +#define MAX_VISIBLE_PACKET_VIS_BYTES ((MAX_VISIBLE_PACKET + 7) / 8) +#define MAX_EVENTS 256 +#define MAX_SUPPORTED_MODELS 512 +#define MAX_MODELS MAX_SUPPORTED_MODELS +#define MAX_SOUNDS 512 +#define MAX_CUSTOM 32 +#define MAX_RENDER_DECALS 256 +#define MAX_RESOURCES (MAX_MODELS+MAX_SOUNDS+MAX_CUSTOM+MAX_EVENTS) + +#else #if XASH_LOW_MEMORY == 2 #undef MAX_VISIBLE_PACKET #undef MAX_VISIBLE_PACKET_VIS_BYTES @@ -234,7 +257,7 @@ GNU General Public License for more details. #define MAX_RENDER_DECALS 128 #define MAX_RESOURCES 1024 #endif - +#endif /* XASH_PSP */ // Quake1 Protocol #define PROTOCOL_VERSION_QUAKE 15 diff --git a/engine/common/soundlib/snd_main.c b/engine/common/soundlib/snd_main.c index c68c14a1..704d5765 100644 --- a/engine/common/soundlib/snd_main.c +++ b/engine/common/soundlib/snd_main.c @@ -62,10 +62,10 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) fs_offset_t filesize = 0; const loadwavfmt_t *format; byte *f; - + Sound_Reset(); // clear old sounddata Q_strncpy( loadname, filename, sizeof( loadname )); - + if( Q_stricmp( ext, "" )) { // we needs to compare file extension with list of supported formats diff --git a/engine/common/soundlib/snd_mp3.c b/engine/common/soundlib/snd_mp3.c index e8f44661..1f42bc32 100644 --- a/engine/common/soundlib/snd_mp3.c +++ b/engine/common/soundlib/snd_mp3.c @@ -117,8 +117,11 @@ stream_t *Stream_OpenMPG( const char *filename ) file_t *file; int ret; wavinfo_t sc; - +#if XASH_PSP // hold mode + file = FS_Open( filename, "*rb", false ); +#else file = FS_Open( filename, "rb", false ); +#endif if( !file ) return NULL; // at this point we have valid stream diff --git a/engine/common/soundlib/snd_wav.c b/engine/common/soundlib/snd_wav.c index 7b53d460..22fe6681 100644 --- a/engine/common/soundlib/snd_wav.c +++ b/engine/common/soundlib/snd_wav.c @@ -320,7 +320,11 @@ stream_t *Stream_OpenWAV( const char *filename ) return NULL; // open +#if XASH_PSP // hold mode + file = FS_Open( filename, "*rb", false ); +#else file = FS_Open( filename, "rb", false ); +#endif if( !file ) return NULL; // find "RIFF" chunk diff --git a/engine/common/system.c b/engine/common/system.c index 43f8201e..d61acfa1 100644 --- a/engine/common/system.c +++ b/engine/common/system.c @@ -32,6 +32,10 @@ GNU General Public License for more details. #endif #endif +#if XASH_PSP +#include +#endif + #include "menu_int.h" // _UPDATE_PAGE macro qboolean error_on_exit = false; // arg for exit(); @@ -472,7 +476,12 @@ Sys_Quit void Sys_Quit( void ) { Host_Shutdown(); +#if XASH_PSP + sceKernelDelayThread( 50 * 1000 ); + sceKernelExitGame(); +#else exit( error_on_exit ); +#endif } /* diff --git a/engine/common/system.h b/engine/common/system.h index 2096e6e0..48b8c198 100644 --- a/engine/common/system.h +++ b/engine/common/system.h @@ -68,7 +68,11 @@ void Sys_Print( const char *pMsg ); void Sys_PrintLog( const char *pMsg ); void Sys_InitLog( void ); void Sys_CloseLog( void ); +#ifdef XASH_PSP +void Sys_Quit( void ); +#else void Sys_Quit( void ) NORETURN; +#endif // // sys_con.c diff --git a/engine/platform/platform.h b/engine/platform/platform.h index 134a2563..e40fe461 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -38,7 +38,11 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren // commented out, as this is an optional feature or maybe implemented in system API directly // see system.c // qboolean Sys_DebuggerPresent( void ); - +#if XASH_PSP +void Platform_ReadCmd( const char *fname, int *argc, char **argv ); +SceUID Platform_LoadModule( const char *filename, int mpid, SceSize argsize, void *argp ); +int Platform_UnloadModule( SceUID modid, int *sce_code ); +#endif #if XASH_ANDROID const char *Android_GetAndroidID( void ); const char *Android_LoadID( void ); diff --git a/engine/platform/psp/dll_psp.c b/engine/platform/psp/dll_psp.c new file mode 100644 index 00000000..7a78b279 --- /dev/null +++ b/engine/platform/psp/dll_psp.c @@ -0,0 +1,259 @@ +/* + From the vitaXash3D by fgsfdsfgs. +*/ +#include "common.h" +#include "dll_psp.h" +#include +#include +#include + +#define MAX_DLNAMELEN 256 + +#if 1 +typedef struct table_s +{ + const char *name; + void *pointer; +} table_t; + +#include "generated_library_tables.h" +#endif + +typedef struct dll_s +{ + SceUID handle; + char name[MAX_DLNAMELEN]; + int refcnt; + dllexport_t *exp; + struct dll_s *next; +} dll_t; + +static dll_t *dll_list; +static char *dll_err = NULL; +static char dll_err_buf[1024]; + +static void *dlfind( const char *name ) +{ + dll_t *d = NULL; + for( d = dll_list; d; d = d->next ) + if( !Q_strcmp( d->name, name ) ) + break; + return d; +} + +static const char *dlname( void *handle ) +{ + dll_t *d = NULL; + // iterate through all dll_ts to check if the handle is actually in the list + // and not some bogus pointer from god knows where + for( d = dll_list; d; d = d->next ) if( d == handle ) break; + return d ? d->name : NULL; +} + +void *dlopen( const char *name, int flag ) +{ + dll_t *old, *new; + char fullpath[MAX_SYSPATH]; + char static_name[16]; + void *static_exp; + void *dynamic_exp; + void *exp_p; + SceUID h; + + if( !name ) + return NULL; + + old = dlfind( name ); + if( old ) + { + old->refcnt++; + return old; + } + + Q_snprintf( fullpath, sizeof( fullpath ), "%s", name ); + + exp_p = &dynamic_exp; + static_exp = NULL; + memset( static_name, 0x00, sizeof( static_name ) ); + + h = Platform_LoadModule( fullpath, 0, sizeof( exp_p ), &exp_p ); + if( h < 0 ) + { + snprintf( dll_err_buf, sizeof( dll_err_buf ), "dlopen( %s ): error %#010x\n", name, h ); + dll_err = dll_err_buf; + + COM_FileBase( name, static_name ); + + if( !Q_strncmp( static_name, "lib", 3 ) ) + Q_sprintf( static_name, "%s", &static_name[3] ); + + table_t* tbl = ( table_t* )libs; + while( tbl->name ) + { + if( !Q_strcmp( tbl->name, static_name) ) + { + static_exp = tbl->pointer; + break; + } + tbl++; + } + + if( static_exp == NULL ) + return NULL; + + Con_Printf ( "dlopen( %s ): ( static ) success!\n", fullpath ); + } + else + { + Con_Printf ( "dlopen( %s ): ( dynamic ) success!\n", fullpath ); + } + + new = calloc( 1, sizeof( dll_t ) ); + if( !new ) + { + dll_err = "dlopen(): out of memory"; + return NULL; + } + snprintf( new->name, MAX_DLNAMELEN, name ); + + if( static_exp != NULL ) + { + new->handle = -1; + new->exp = static_exp; + } + else + { + new->handle = h; + new->exp = dynamic_exp; + } + + new->refcnt = 1; + + new->next = dll_list; + dll_list = new; + + return new; +} + +void *dlsym( void *handle, const char *symbol ) +{ + if( !handle || !symbol ) + { + dll_err = "dlsym(): NULL args"; + return NULL; + } + + if( !dlname( handle ) ) + { + dll_err = "dlsym(): unknown handle"; + return NULL; + } + + dll_t *d = handle; + if( !d->refcnt ) + { + dll_err = "dlsym(): call dlopen() first"; + return NULL; + } + + dllexport_t *f = NULL; + for( f = d->exp; f && f->func; f++ ) + { + if( !Q_strcmp( f->name, symbol ) ) + break; + } + + if( f && f->func ) + { + return f->func; + } + else + { + dll_err = "dlsym(): symbol not found in dll"; + return NULL; + } +} + +int dlclose( void *handle ) +{ + int result, sce_code; + dll_t *d; + + if( !handle ) + { + dll_err = "dlclose(): NULL arg"; + return -1; + } + + if( !dlname( handle ) ) + { + dll_err = "dlclose(): unknown handle"; + return -2; + } + + d = handle; + d->refcnt--; + if( d->refcnt <= 0 ) + { + if( d->handle != -1 ) + { + result = Platform_UnloadModule( d->handle, &sce_code ); + if( result < 0 ) + { + if( result == -1 ) + { + dll_err = "dlclose(): module doesn't want to stop"; + return -3; + } + + snprintf( dll_err_buf, sizeof( dll_err_buf ), "dlclose( %s ): error %#010x", d->name, sce_code ); + dll_err = dll_err_buf; + } + } + + if( d == dll_list ) + dll_list = NULL; + else + { + dll_t *pd; + for( pd = dll_list; pd; pd = pd->next ) + { + if( pd->next == d ) + { + pd->next = d->next; + break; + } + } + } + free( d ); + } + return 0; +} + +char *dlerror( void ) +{ + char *err = dll_err; + dll_err = NULL; + return err; +} + +int dladdr( const void *addr, Dl_info *info ) +{ + dll_t *d = NULL; + dllexport_t *f = NULL; + for( d = dll_list; d; d = d->next ) + for( f = d->exp; f && f->func; f++ ) + if( f->func == addr ) goto for_end; +for_end: + if( d && f && f->func ) + { + if( info ) + { + info->dli_fhandle = d; + info->dli_sname = f->name; + info->dli_saddr = addr; + } + return 1; + } + return 0; +} \ No newline at end of file diff --git a/engine/platform/psp/dll_psp.h b/engine/platform/psp/dll_psp.h new file mode 100644 index 00000000..4fc7766e --- /dev/null +++ b/engine/platform/psp/dll_psp.h @@ -0,0 +1,38 @@ +#ifndef DLL_PSP_H +#define DLL_PSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define RTLD_LAZY 0x0001 +#define RTLD_NOW 0x0002 + +typedef struct dllexport_s +{ + const char *name; + void *func; +} dllexport_t; + +typedef struct Dl_info_s +{ + void *dli_fhandle; + const char *dli_sname; + const void *dli_saddr; +} Dl_info; + +void *dlsym(void *handle, const char *symbol ); +void *dlopen(const char *name, int flag ); +int dlclose(void *handle); +char *dlerror( void ); +int dladdr( const void *addr, Dl_info *info ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c new file mode 100644 index 00000000..befa200e --- /dev/null +++ b/engine/platform/psp/in_psp.c @@ -0,0 +1,182 @@ +/* +in_psp.c - PSP input component +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "common.h" +#include "keydefs.h" +#include "input.h" +#include "client.h" + +#if XASH_INPUT == INPUT_PSP +#include + +#define PSP_MAX_KEYS 12 + +extern convar_t *psp_deadzone_min; +extern convar_t *psp_deadzone_max; + +static struct psp_keymap_s +{ + unsigned int srckey; + int dstkey; +}psp_keymap[] = +{ +#if 1 + { PSP_CTRL_SELECT, '~' }, + { PSP_CTRL_START, K_ESCAPE }, + { PSP_CTRL_UP, K_UPARROW }, + { PSP_CTRL_RIGHT, K_RIGHTARROW }, + { PSP_CTRL_DOWN, K_DOWNARROW }, + { PSP_CTRL_LEFT, K_LEFTARROW }, + { PSP_CTRL_LTRIGGER, K_JOY1 }, + { PSP_CTRL_RTRIGGER, K_JOY2 }, + { PSP_CTRL_TRIANGLE, K_SHIFT }, + { PSP_CTRL_CIRCLE, K_SPACE }, + { PSP_CTRL_CROSS, K_ENTER }, + { PSP_CTRL_SQUARE, K_BACKSPACE }, +#else + { PSP_CTRL_SELECT, K_MODE_BUTTON }, + { PSP_CTRL_START, K_START_BUTTON }, + { PSP_CTRL_UP, K_UPARROW }, + { PSP_CTRL_RIGHT, K_RIGHTARROW }, + { PSP_CTRL_DOWN, K_DOWNARROW }, + { PSP_CTRL_LEFT, K_LEFTARROW }, + { PSP_CTRL_LTRIGGER, K_L1_BUTTON }, + { PSP_CTRL_RTRIGGER, K_R1_BUTTON }, + { PSP_CTRL_TRIANGLE, K_Y_BUTTON }, + { PSP_CTRL_CIRCLE, K_B_BUTTON }, + { PSP_CTRL_CROSS, K_A_BUTTON }, + { PSP_CTRL_SQUARE, K_X_BUTTON }, +#endif +#if 0 + PSP_CTRL_HOME, + PSP_CTRL_HOLD, + PSP_CTRL_NOTE, + PSP_CTRL_SCREEN, + PSP_CTRL_VOLUP, + PSP_CTRL_VOLDOWN, + PSP_CTRL_WLAN_UP, + PSP_CTRL_REMOTE, + PSP_CTRL_DISC, + PSP_CTRL_MS, +#endif +}; +static signed short psp_joymap[256]; /* -32768 <> 32767 */ + +static float Platform_JoyRescale( float axis, float deadzone_min, float deadzone_max ) +{ + float abs_axis, scale, r_deadzone_max; + int flip_axis = 0; + + // (-127) - (0) - (+127) + abs_axis = axis - 128.0f; + if( abs_axis < 0.0f ) + { + abs_axis = -abs_axis - 1.0f; + flip_axis = 1; + } + if( abs_axis <= deadzone_min ) return 0.0f; + r_deadzone_max = 127.0f - deadzone_max; + if( abs_axis >= r_deadzone_max ) return ( flip_axis ? -127.0f : 127.0f ); + + scale = 127.0f / ( r_deadzone_max - deadzone_min ); + abs_axis -= deadzone_min; + abs_axis *= scale; + + return ( flip_axis ? -abs_axis : abs_axis ); +} + +void Platform_RunEvents( void ) +{ + int i; + SceCtrlData buf; + signed short curr_X, curr_Y; + static unsigned int last_buttons; + static signed short last_X, last_Y; + + sceCtrlReadBufferPositive( &buf, 1 ); + + for( i = 0; i < PSP_MAX_KEYS; i++ ) + { + if( ( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) + Key_Event( psp_keymap[i].dstkey, buf.Buttons & psp_keymap[i].srckey ); + } + last_buttons = buf.Buttons; + + if( FBitSet( psp_deadzone_min->flags, FCVAR_CHANGED ) || FBitSet( psp_deadzone_max->flags, FCVAR_CHANGED ) ) + { + for ( i = 0; i < 256; i++ ) + { + psp_joymap[i] = Platform_JoyRescale( i, psp_deadzone_min->value, psp_deadzone_max->value ); + psp_joymap[i] *= 256; + } + + ClearBits( psp_deadzone_min->flags, FCVAR_CHANGED ); + ClearBits( psp_deadzone_max->flags, FCVAR_CHANGED ); + } + + curr_X = psp_joymap[buf.Lx]; + curr_Y = psp_joymap[buf.Ly]; + + if( last_X != curr_X ) + Joy_AxisMotionEvent( 2, -curr_X ); + + if( last_Y != curr_Y ) + Joy_AxisMotionEvent( 3, -curr_Y ); + + last_X = curr_X; + last_Y = curr_Y; +} + +void Platform_GetMousePos( int *x, int *y ) +{ + *x = *y = 0; +} + +void Platform_SetMousePos( int x, int y ) +{ + +} + +void Platform_EnableTextInput( qboolean enable ) +{ + +} + +int Platform_JoyInit( int numjoy ) +{ + int i; + + // set up the controller. + sceCtrlSetSamplingCycle( 0 ); + sceCtrlSetSamplingMode( PSP_CTRL_MODE_ANALOG ); + + // building a joystick map + for ( i = 0; i < 256; i++ ) + { + psp_joymap[i] = Platform_JoyRescale( i, psp_deadzone_min->value, psp_deadzone_max->value ); + psp_joymap[i] *= 256; + } + return 1; +} + +void Platform_MouseMove( float *x, float *y ) +{ + +} + +void Platform_PreCreateMove( void ) +{ + +} +#endif /* XASH_INPUT */ \ No newline at end of file diff --git a/engine/platform/psp/lib_psp.c b/engine/platform/psp/lib_psp.c new file mode 100644 index 00000000..9d343f8d --- /dev/null +++ b/engine/platform/psp/lib_psp.c @@ -0,0 +1,145 @@ +/* +lib_psp.c - dynamic library code for Sony PSP system +Copyright (C) 2018 Flying With Gauss + +This program is free software: you can redistribute it and/sor modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "platform/platform.h" +#if XASH_LIB == LIB_PSP + + +#include "common.h" +#include "library.h" +#include "filesystem.h" +#include "server.h" +#include "platform/psp/lib_psp.h" + +#ifdef XASH_NO_LIBDL +#ifndef XASH_DLL_LOADER +#error Enable at least one dll backend!!! +#endif // XASH_DLL_LOADER + +void *dlsym(void *handle, const char *symbol ) +{ + Con_DPrintf( "dlsym( %p, \"%s\" ): stub\n", handle, symbol ); + return NULL; +} + +void *dlopen(const char *name, int flag ) +{ + Con_DPrintf( "dlopen( \"%s\", %d ): stub\n", name, flag ); + return NULL; +} + +int dlclose(void *handle) +{ + Con_DPrintf( "dlsym( %p ): stub\n", handle ); + return 0; +} + +char *dlerror( void ) +{ + return "Loading ELF libraries not supported in this build!\n"; +} + +int dladdr( const void *addr, Dl_info *info ) +{ + return 0; +} +#endif // XASH_NO_LIBDL + +qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname, qboolean directpath ) +{ + // TODO: implement + return true; +} + +void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath ) +{ + dll_user_t *hInst = NULL; + void *pHandle = NULL; + + COM_ResetLibraryError(); + + // platforms where gameinfo mechanism is working goes here + // and use FS_FindLibrary + hInst = FS_FindLibrary( dllname, directpath ); + if( !hInst ) + { + // try to find by linker(LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, LD_32_LIBRARY_PATH and so on...) + if( !pHandle ) + { + pHandle = dlopen( dllname, RTLD_LAZY ); + if( pHandle ) + return pHandle; + + COM_PushLibraryError( va( "Failed to find library %s", dllname )); + COM_PushLibraryError( dlerror() ); + return NULL; + } + } + + if( hInst->custom_loader ) + { + COM_PushLibraryError( va( "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath )); + Mem_Free( hInst ); + return NULL; + } + + if( !( hInst->hInstance = dlopen( hInst->fullPath, RTLD_LAZY ) ) ) + { + COM_PushLibraryError( dlerror() ); + Mem_Free( hInst ); + return NULL; + } + + pHandle = hInst->hInstance; + + Mem_Free( hInst ); + + return pHandle; +} + +void COM_FreeLibrary( void *hInstance ) +{ + dlclose( hInstance ); +} + +void *COM_GetProcAddress( void *hInstance, const char *name ) +{ + return dlsym( hInstance, name ); +} + +void *COM_FunctionFromName( void *hInstance, const char *pName ) +{ + void *function; + if( !( function = COM_GetProcAddress( hInstance, pName ) ) ) + { + Con_Reportf( S_ERROR "FunctionFromName: Can't get symbol %s: %s\n", pName, dlerror()); + } + return function; +} + +const char *COM_NameForFunction( void *hInstance, void *function ) +{ + // NOTE: dladdr() is a glibc extension + Dl_info info = {0}; + dladdr((void*)function, &info); + if(info.dli_sname) + return info.dli_sname; +#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS + return COM_OffsetNameForFunction( function ); +#else + return NULL; +#endif +} + +#endif // _WIN32 diff --git a/engine/platform/psp/lib_psp.h b/engine/platform/psp/lib_psp.h new file mode 100644 index 00000000..e69de29b diff --git a/engine/platform/psp/s_psp.c b/engine/platform/psp/s_psp.c new file mode 100644 index 00000000..eaf3f82f --- /dev/null +++ b/engine/platform/psp/s_psp.c @@ -0,0 +1,252 @@ +/* +s_psp.c - sound hardware output +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + + +#ifndef XASH_DEDICATED +#include "common.h" +#if XASH_SOUND == SOUND_PSP + +#include +#include +#include + +#include "sound.h" + +#define SAMPLE_16BIT_SHIFT 1 +#define SECONDARY_BUFFER_SIZE 0x10000 + +#define SND_CHANELS 2 +#define SND_FREQ 44100 +#define SND_BUF_SIZE 16384 + +typedef struct +{ + short left; + short right; +}sample_t; + +static sample_t snd_buffer[SND_BUF_SIZE] __attribute__( ( aligned( 64 ) ) ); +static volatile unsigned int snd_sampleread; + +/* +======================================================================= +Global variables. Must be visible to window-procedure function +so it can unlock and free the data block after it has been played. +======================================================================= +*/ + +dma_t dma; + +void S_Activate( qboolean active ) +{ + +} + +/* From PSP Quake */ +static void PSP_SoundCallback( void* buffer, unsigned int samplesToWrite, void* userData ) +{ + // Where are we writing to? + sample_t* const dest = ( sample_t* )buffer; + + // Where are we reading from? + const sample_t* const src = &snd_buffer[snd_sampleread]; + + // How many samples to read? + const unsigned int samplesToRead = samplesToWrite; // 44100 + + // Going to wrap past the end of the input buffer? + const unsigned int samplesBeforeEndOfInput = SND_BUF_SIZE - snd_sampleread; + if ( samplesToRead > samplesBeforeEndOfInput ) + { + // Yes, so write the first chunk from the end of the input buffer. + memcpy( dest, src, samplesBeforeEndOfInput * sizeof( sample_t ) ); + + // Write the second chunk from the start of the input buffer. + const unsigned int samplesToReadFromBeginning = samplesToRead - samplesBeforeEndOfInput; + + memcpy( &dest[samplesBeforeEndOfInput], src, samplesToReadFromBeginning * sizeof( sample_t ) ); + } + else + { + // No wrapping, just copy. + memcpy( &dest[0], src, samplesToRead * sizeof( sample_t ) ); + } + + // Update the read offset. + snd_sampleread = ( snd_sampleread + samplesToRead ) % SND_BUF_SIZE; +} + +/* +================== +SNDDMA_Init + +Try to find a sound device to mix for. +Returns false if nothing is found. +================== +*/ +qboolean SNDDMA_Init( void ) +{ + dma.format.speed = SND_FREQ; + dma.format.channels = SND_CHANELS; + dma.format.width = 2; + dma.samples = SND_BUF_SIZE * SND_CHANELS; + dma.buffer = ( unsigned char * )snd_buffer; + dma.samplepos = 0; + + // Initialise the audio system. This initialises it for the CD audio module + // too. + pspAudioInit(); + + // Set the channel callback. + // Sound effects use channel 0, CD audio uses channel 1. + pspAudioSetChannelCallback( 0, PSP_SoundCallback, 0 ); + + Con_Printf( "Using PSP audio driver: %d Hz\n", dma.format.speed ); + + //SNDDMA_Activate( true ); + + dma.initialized = true; +#if 0 /* libmp3 */ + // load modules + int status = sceUtilityLoadModule( PSP_MODULE_AV_AVCODEC ); + if ( status < 0 ) + { + Con_Printf( "Error - PSP_MODULE_AV_AVCODEC returned 0x%08X\n", status ); + }else printf("PSP_MODULE_AV_AVCODEC - OK\n"); + + status = sceUtilityLoadModule( PSP_MODULE_AV_MP3 ); + if ( status < 0 ) + { + Con_Printf( "Error - PSP_MODULE_AV_MP3 returned 0x%08X\n", status ); + }else printf("PSP_MODULE_AV_MP3 - OK\n"); + + // init mp3 resources + status = sceMp3InitResource(); + if ( status < 0 ) + { + Con_Printf("Error - sceMp3InitResource returned 0x%08X\n", status); + }else printf("sceMp3InitResource - OK\n"); +#endif + return true; +} + +/* +============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos( void ) +{ + dma.samplepos = snd_sampleread * SND_CHANELS; + return dma.samplepos; +} + +/* +============== +SNDDMA_GetSoundtime + +update global soundtime +=============== +*/ +int SNDDMA_GetSoundtime( void ) +{ + static int buffers, oldsamplepos; + int samplepos, fullsamples; + + fullsamples = dma.samples / 2; + + // it is possible to miscount buffers + // if it has wrapped twice between + // calls to S_Update. Oh well. + samplepos = SNDDMA_GetDMAPos(); + + if( samplepos < oldsamplepos ) + { + buffers++; // buffer wrapped + + if( paintedtime > 0x40000000 ) + { + // time to chop things off to avoid 32 bit limits + buffers = 0; + paintedtime = fullsamples; + S_StopAllSounds( true ); + } + } + + oldsamplepos = samplepos; + + return (buffers * fullsamples + samplepos / 2); +} + +/* +============== +SNDDMA_BeginPainting + +Makes sure dma.buffer is valid +=============== +*/ +void SNDDMA_BeginPainting( void ) +{ + +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +Also unlocks the dsound buffer +=============== +*/ +void SNDDMA_Submit( void ) +{ + +} + +/* +============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown( void ) +{ + Con_Printf("Shutting down audio.\n"); + + // Clear the mixing buffer so we don't get any noise during cleanup. + memset(snd_buffer, 0, sizeof(snd_buffer)); + + // Clear the channel callback. + pspAudioSetChannelCallback(0, 0, 0); + + // Stop the audio system? + pspAudioEndPre(); + + // Insert a false delay so the thread can be cleaned up. + sceKernelDelayThread(50 * 1000); + + // Shut down the audio system. + pspAudioEnd(); + + dma.initialized = false; +} + +#endif +#endif diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c new file mode 100644 index 00000000..8c835496 --- /dev/null +++ b/engine/platform/psp/sys_psp.c @@ -0,0 +1,281 @@ +/* +sys_psp.c - PSP System utils +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "platform/platform.h" +#include +#include +#include +#include +#include +#include + +#include + + +PSP_MODULE_INFO( "Xash3D", PSP_MODULE_USER, 1, 0 ); +PSP_MAIN_THREAD_ATTR( PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_VFPU ); +PSP_MAIN_THREAD_STACK_SIZE_KB( 512 ); +PSP_HEAP_SIZE_KB( -3 * 1024 ); /* 3 MB for prx modules */ + +convar_t *psp_deadzone_min; +convar_t *psp_deadzone_max; + +/* Exit callback */ +static int exit_callback( int arg1, int arg2, void *common ) +{ + host.crashed = true; + return 0; +} + +/* Callback thread */ +static int CallbackThread( SceSize args, void *argp ) +{ + int cbid; + + cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL); + sceKernelRegisterExitCallback(cbid); + sceKernelSleepThreadCB(); + + return 0; +} + +/* Sets up the callback thread and returns its thread id */ +static int SetupCallbacks( void ) +{ + int thid = 0; + + thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0); + if(thid >= 0) + { + sceKernelStartThread(thid, 0, 0); + } + return thid; +} + +#if XASH_TIMER == TIMER_PSP +double Platform_DoubleTime( void ) +{ +/* + static u64 start_ticks; + static qboolean timer_init = false; + u64 current_ticks; + + if ( !timer_init ) + { + sceRtcGetCurrentTick( &start_ticks ); + timer_init = true; + } + sceRtcGetCurrentTick( ¤t_ticks ); + + return ( current_ticks - start_ticks ) * 0.000001; +*/ + u64 current_ticks; + sceRtcGetCurrentTick( ¤t_ticks ); + + return ( double )current_ticks * 0.000001; +} + +void Platform_Sleep( int msec ) +{ + sceKernelDelayThread( msec * 1000 ); +} +#endif + +void *Platform_GetNativeObject( const char *name ) +{ + return NULL; +} + +void Platform_Vibrate( float life, char flags ) +{ + +} + +void Platform_GetClipboardText( char *buffer, size_t size ) +{ + +} + +void Platform_SetClipboardText( const char *buffer, size_t size ) +{ + +} + +void Platform_ShellExecute( const char *path, const char *parms ) +{ + +} + +#if XASH_MESSAGEBOX == MSGBOX_PSP +void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow ) +{ + static qboolean g_dbgscreen = false; + + // Clear the sound buffer. + S_StopAllSounds( true ); + + // Print message to the debug screen. + if ( !g_dbgscreen ) + { + pspDebugScreenInit(); + g_dbgscreen = true; + } + pspDebugScreenSetTextColor( 0x0080ff ); + pspDebugScreenPrintf( "\n\n\n\n%s:\n", title ); + pspDebugScreenSetTextColor( 0x0000ff ); + pspDebugScreenPrintData( message, Q_strlen( message ) ); + pspDebugScreenSetTextColor( 0xffffff ); + pspDebugScreenPrintf( "\n\nPress X to continue.\n" ); + + // Wait for a X button press. + SceCtrlData pad; + do + { + sceCtrlReadBufferPositive( &pad, 1 ); + } + while( !( pad.Buttons & PSP_CTRL_CROSS ) ); + pspDebugScreenClear(); +} +#endif // XASH_MESSAGEBOX == MSGBOX_PSP + +void Platform_ReadCmd( const char *fname, int *argc, char **argv ) +{ + int cmd_fd; + size_t cmd_fsize; + byte *cmd_buff; + int i, j = 0; + + cmd_fd = sceIoOpen( fname, PSP_O_RDONLY, 0777 ); + if( cmd_fd > 0 ) + { + cmd_fsize = sceIoLseek( cmd_fd, 0, PSP_SEEK_END ); + sceIoLseek( cmd_fd, 0, PSP_SEEK_SET ); + + printf( "CMD FILE(%s) Size: %i\n", fname, cmd_fsize ); + + if( cmd_fsize == 0 ) return; + + cmd_buff = malloc( cmd_fsize ); + if( !cmd_buff ) + { + printf( "CMD FILE(%s) Memory allocation error!\n", fname ); + sceIoClose(cmd_fd); + return; + } + + if( sceIoRead(cmd_fd, cmd_buff, cmd_fsize) >= 0 ) + { + for( i = 0; i < cmd_fsize; i++ ) + { + if( isspace( cmd_buff[i] ) != 0 ) + { + if( j == 0 ) continue; + + argv[*argc] = malloc( j + 1 ); + if( !argv[*argc] ) + { + printf( "CMD FILE(%s) Memory allocation error!\n", fname ); + free( cmd_buff ); + sceIoClose( cmd_fd ); + return; + } + memcpy( argv[*argc], &cmd_buff[i - j], j ); + argv[*argc][j] = 0x00; + ( int )( *argc )++; + j = 0; + } + else j++; + + } + if( j != 0 ) + { + argv[*argc] = malloc( j + 1 ); + if( !argv[*argc] ) + { + printf( "CMD FILE(%s) Memory allocation error!\n", fname ); + free( cmd_buff ); + sceIoClose( cmd_fd ); + return; + } + memcpy( argv[*argc], &cmd_buff[i - j], j ); + argv[*argc][j] = 0x00; + ( int )( *argc )++; + j = 0; + } + } + else printf( "CMD FILE(%s) Read error!\n", fname ); + + free( cmd_buff ); + sceIoClose(cmd_fd); + } +} + +SceUID Platform_LoadModule( const char *filename, int mpid, SceSize argsize, void *argp ) +{ + SceKernelLMOption option; + SceUID modid = 0; + int retVal = 0, mresult; + + memset( &option, 0, sizeof( option ) ); + option.size = sizeof( option ); + option.mpidtext = mpid; + option.mpiddata = mpid; + option.position = 0; + option.access = 1; + + retVal = sceKernelLoadModule( filename, 0, &option ); + if(retVal < 0) + return retVal; + + modid = retVal; + + retVal = sceKernelStartModule( modid, argsize, argp, &mresult, NULL ); + if( retVal < 0 ) + return retVal; + + return modid; +} + +int Platform_UnloadModule( SceUID modid, int *sce_code ) +{ + int status; + *sce_code = sceKernelStopModule( modid, 0, NULL, &status, NULL); + + if( ( *sce_code ) < 0 ) + return -2; + else if( status == SCE_KERNEL_ERROR_NOT_STOPPED ) + return -1; + + *sce_code = sceKernelUnloadModule( modid ); + return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); +} + +void Platform_Init( void ) +{ + pspSdkDisableFPUExceptions(); + + SetupCallbacks(); + scePowerSetClockFrequency( 333, 333, 166 ); + + psp_deadzone_min = Cvar_Get( "psp_deadzone_min", "20", FCVAR_ARCHIVE, "Joy deadzone min (0 - 127)" ); + psp_deadzone_max = Cvar_Get( "psp_deadzone_max", "0", FCVAR_ARCHIVE, "Joy deadzone max (0 - 127)" ); +} + +void Platform_Shutdown( void ) +{ +#if XASH_PROFILING + gprof_cleanup(); +#endif +} \ No newline at end of file diff --git a/engine/platform/psp/vid_psp.c b/engine/platform/psp/vid_psp.c new file mode 100644 index 00000000..e29eeab5 --- /dev/null +++ b/engine/platform/psp/vid_psp.c @@ -0,0 +1,538 @@ +/* +vid_psp.c - PSP video component +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#if XASH_VIDEO == VIDEO_PSP + +#if !XASH_DEDICATED +#include +#include +#include +#include +#include "vram_psp.h" + +#include "common.h" +#include "client.h" +#include "mod_local.h" +#include "input.h" +#include "vid_common.h" + +// Set gu list +#define PSP_GU_STATIC_LIST 1 +#define PSP_GU_LIST_SIZE 0x40000 + +// Set frame buffer +#define PSP_FB_WIDTH 480 +#define PSP_FB_HEIGHT 272 +#define PSP_FB_BWIDTH 512 +#define PSP_FB_FORMAT 5650 //4444,5551,5650,8888 + +#if PSP_FB_FORMAT == 4444 +#define PSP_FB_HW_FORMAT GU_PSM_4444 +#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_4444 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == 5551 +#define PSP_FB_HW_FORMAT GU_PSM_5551 +#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_5551 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == 5650 +#define PSP_FB_HW_FORMAT GU_PSM_5650 +#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == 8888 +#define PSP_FB_HW_FORMAT GU_PSM_8888 +#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_8888 +#define PSP_FB_BPP 4 +#endif + +#if 0 +// Set up screen scaling +#define PSP_WIDTH_AR 30 +#define PSP_HEIGHT_AR 17 +#define PSP_MIN_MAR 12 +#define PSP_MAX_MAR 16 +#define PSP_MIN_MAR_W (PSP_WIDTH_AR * PSP_MIN_MAR) +#define PSP_MIN_MAR_H (PSP_HEIGHT_AR * PSP_MIN_MAR) +#define PSP_MAX_MAR_W (PSP_WIDTH_AR * PSP_MAX_MAR) +#define PSP_MAX_MAR_H (PSP_HEIGHT_AR * PSP_MAX_MAR) +#endif + + +static qboolean vsync; +#if 1 +static vidmode_t vidmodes[] = { "480x272", PSP_FB_WIDTH, PSP_FB_HEIGHT}; +static int num_vidmodes = 1; +#else +static vidmode_t *vidmodes = NULL; +static int num_vidmodes = 0; +#endif +static struct +{ +#if 0 + int in_width, in_height; + int out_width, out_height; +#endif + void *draw_buffer; + void *disp_buffer; + void *depth_buffer; +#if PSP_GU_STATIC_LIST + unsigned int gu_list[PSP_GU_LIST_SIZE] __attribute__( ( aligned( 64 ) ) ); +#else + unsigned int *gu_list; +#endif +}vid_psp; + +qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b ) +{ + *stride = PSP_FB_BWIDTH; + *r = 31; + *g = 63 << 5; + *b = 31 << 11; + *bpp = 2; + + vid_psp.draw_buffer = (void*)valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.draw_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); + + vid_psp.disp_buffer = (void*)valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.disp_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); + + sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_SW_FORMAT, 1); + + return true; +} + +void *SW_LockBuffer( void ) +{ + return vid_psp.draw_buffer; +} + +void SW_UnlockBuffer( void ) +{ + void* p_swap = vid_psp.disp_buffer; + vid_psp.disp_buffer = vid_psp.draw_buffer; + vid_psp.draw_buffer = p_swap; + + sceKernelDcacheWritebackInvalidateAll(); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_SW_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME); + + if ( vsync ) + { + sceDisplayWaitVblankStart(); + } +} + +_inline void GU_Init( void ) +{ + vid_psp.draw_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.draw_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); + + vid_psp.disp_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.disp_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); + + vid_psp.depth_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.depth_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.depth_buffer)\n"); + +#if !PSP_GU_STATIC_LIST + vid_psp.gu_list = ( unsigned int* )valloc( PSP_GU_LIST_SIZE * sizeof ( unsigned int ) ); + if( !vid_psp.gu_list ) + Host_Error( "Memory allocation failled! (vid_psp.gu_list)\n"); +#endif + + // Initialise the GU. + sceGuInit(); + + // Set up the GU. + sceGuStart( GU_DIRECT, vid_psp.gu_list ); + + sceGuDrawBuffer( PSP_FB_HW_FORMAT, vrelptr( vid_psp.draw_buffer ), PSP_FB_BWIDTH); + sceGuDispBuffer( PSP_FB_WIDTH, PSP_FB_HEIGHT, vrelptr( vid_psp.disp_buffer ), PSP_FB_BWIDTH); + sceGuDepthBuffer( vrelptr( vid_psp.depth_buffer ), PSP_FB_BWIDTH); + + // Set the rendering offset and viewport. + sceGuOffset( 2048 - ( PSP_FB_WIDTH / 2 ), 2048 - ( PSP_FB_HEIGHT / 2 ) ); + sceGuViewport( 2048, 2048, PSP_FB_WIDTH, PSP_FB_HEIGHT ); + + // Set up scissoring. + sceGuEnable( GU_SCISSOR_TEST ); + sceGuScissor( 0, 0, PSP_FB_WIDTH, PSP_FB_HEIGHT ); + + // Set up texturing. + sceGuEnable( GU_TEXTURE_2D ); + + // Set up clearing. + sceGuClearDepth( 65535 ); + sceGuClearColor( GU_RGBA( 0x10, 0x20, 0x40, 0xff ) ); + + // Set up depth. + sceGuDepthOffset( 0 ); + sceGuDepthRange( 0, 65535 ); + sceGuDepthFunc( GU_LEQUAL ); + sceGuEnable( GU_DEPTH_TEST ); + + // Set up fog +// sceGuFog( 100.0f, 500.0f, 0xffffffff ); +// sceGuDisable( GU_FOG ); + + // Set the default matrices. + sceGumMatrixMode( GU_PROJECTION ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_VIEW ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_MODEL ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_TEXTURE ); + sceGumLoadIdentity(); + + sceGumUpdateMatrix(); + + // Set up culling. + sceGuFrontFace( GU_CW ); + sceGuEnable( GU_CULL_FACE ); + sceGuEnable( GU_CLIP_PLANES ); + + // Set up blending. + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + + sceGuFinish(); + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); + + // Turn on the display. + sceDisplayWaitVblankStart(); + sceGuDisplay(GU_TRUE); + + // Start a new render. + sceGuStart( GU_DIRECT, vid_psp.gu_list ); + + Con_Printf( "Vram available: %i\n", vmemavail() ); +} + +_inline void GU_Shutdown( void ) +{ + // Finish rendering. + sceGuFinish(); + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); + + // Shut down the display. + sceGuTerm(); + + // Free the buffers. + vfree( vid_psp.draw_buffer ); + vid_psp.draw_buffer = NULL; + vfree( vid_psp.disp_buffer ); + vid_psp.disp_buffer = NULL; + vfree( vid_psp.depth_buffer ); + vid_psp.depth_buffer = NULL; +#if !PSP_GU_STATIC_LIST + vfree( vid_psp.gu_list ); + vid_psp.gu_list = NULL; +#endif +} + +_inline void GU_SwapBuffers( void ) +{ +/* + // Don't forget writeback the cache + sceKernelDcacheWritebackAll(); +*/ + // Finish rendering. + size_t list_size = sceGuFinish(); +/* + if( list_size > sizeof( gu_list ) - 1000 ) + printf( "Display list size (%i) %i!\n", list_size, sizeof( gu_list ) ); +*/ + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); + + if ( vsync ) + { + sceDisplayWaitVblankStart(); + } + + // Swap the buffers. + sceGuSwapBuffers(); + + void* p_swap = vid_psp.disp_buffer; + vid_psp.disp_buffer = vid_psp.draw_buffer; + vid_psp.draw_buffer = p_swap; + + // Start a new render. + sceGuStart( GU_DIRECT, vid_psp.gu_list ); +} + +int R_MaxVideoModes( void ) +{ + return num_vidmodes; +} + +vidmode_t *R_GetVideoMode( int num ) +{ + if( !vidmodes || num < 0 || num >= R_MaxVideoModes() ) + { + return NULL; + } + + return vidmodes + num; +} +#if 0 +static void R_InitVideoModes( void ) +{ + int i; + + vidmodes = Mem_Malloc( host.mempool, (PSP_MAX_MAR - PSP_MIN_MAR) * sizeof( vidmode_t ) ); + + // from smallest to largest + for(i = PSP_MIN_MAR ; i <= PSP_MAX_MAR; i++ ) + { + vidmodes[num_vidmodes].width = PSP_WIDTH_AR * i; + vidmodes[num_vidmodes].height = PSP_HEIGHT_AR * i; + vidmodes[num_vidmodes].desc = + copystring( va( "%ix%i", vidmodes[num_vidmodes].width, vidmodes[num_vidmodes].height )); + + num_vidmodes++; + } +} + +static void R_FreeVideoModes( void ) +{ + int i; + + if(!vidmodes) + return; + + for( i = 0; i < num_vidmodes; i++ ) + Mem_Free( (char*)vidmodes[i].desc ); + Mem_Free( vidmodes ); + + vidmodes = NULL; +} +#endif +/* +================= +GL_GetProcAddress +================= +*/ +void *GL_GetProcAddress( const char *name ) +{ + return NULL; +} + +/* +=============== +GL_UpdateSwapInterval +=============== +*/ +void GL_UpdateSwapInterval( void ) +{ + // disable VSync while level is loading + if( cls.state < ca_active ) + { + // setup vsync here + vsync = false; + SetBits( gl_vsync->flags, FCVAR_CHANGED ); + } + else if( FBitSet( gl_vsync->flags, FCVAR_CHANGED )) + { + ClearBits( gl_vsync->flags, FCVAR_CHANGED ); + vsync = (gl_vsync->value > 0) ? true : false; + } +} + +static qboolean VID_SetScreenResolution( int width, int height ) +{ + int render_w = width, render_h = height; + uint rotate = vid_rotate->value; + + if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) ) + { + if( rotate & 1 ) + { + int swap = render_w; + + render_w = render_h; + render_h = swap; + } + + render_h /= vid_scale->value; + render_w /= vid_scale->value; + } + else + { + Con_Printf( S_WARN "failed to setup screen transform\n" ); + } + + + + R_SaveVideoMode( width, height, render_w, render_h ); + + return true; +} + +void GL_SwapBuffers( void ) +{ + GU_SwapBuffers(); +} + +int GL_SetAttribute( int attr, int val ) +{ + return 0; +} + +int GL_GetAttribute( int attr, int *val ) +{ + return 0; +} + +/* +================== +R_Init_Video +================== +*/ +qboolean R_Init_Video( const int type ) +{ + string safe; + qboolean retval; + + refState.desktopBitsPixel = ( PSP_FB_BPP * 8 ); + + VID_StartupGamma(); + + switch( type ) + { + case REF_SOFTWARE: + glw_state.software = true; + break; + case REF_GL: + if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) ) + glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE ); + break; + default: + Host_Error( "Can't initialize unknown context type %d!\n", type ); + break; + } + + if( !(retval = VID_SetMode()) ) + { + return retval; + } + + switch( type ) + { + case REF_GL: + // refdll also can check extensions + ref.dllFuncs.GL_InitExtensions(); + GU_Init(); + break; + case REF_SOFTWARE: + default: + break; + } +#if 0 + R_InitVideoModes(); +#endif + host.renderinfo_changed = false; + + return true; +} + +rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen ) +{ + Con_Reportf( "R_ChangeDisplaySettings: Setting video mode to %dx%d %s\n", width, height, fullscreen ? "fullscreen" : "windowed" ); + + refState.fullScreen = fullscreen; + + if( !VID_SetScreenResolution( width, height ) ) + return rserr_invalid_fullscreen; + + return rserr_ok; +} + +/* +================== +VID_SetMode + +Set the described video mode +================== +*/ +qboolean VID_SetMode( void ) +{ + qboolean fullscreen = false; + int iScreenWidth, iScreenHeight; + rserr_t err; + +#if 1 + iScreenWidth = PSP_FB_WIDTH; + iScreenHeight = PSP_FB_HEIGHT; +#else + vid_psp.out_width = PSP_FB_WIDTH; + vid_psp.out_height = PSP_FB_HEIGHT; + + iScreenWidth = Cvar_VariableInteger( "width" ); + iScreenHeight = Cvar_VariableInteger( "height" ); + + if( iScreenWidth < PSP_MIN_MAR_W || + iScreenHeight < PSP_MIN_MAR_H ) // trying to get resolution automatically by default + { + iScreenWidth = PSP_MIN_MAR_W; + iScreenHeight = PSP_MIN_MAR_H; + } + + if( iScreenWidth > PSP_MAX_MAR_W || + iScreenHeight > PSP_MAX_MAR_H ) // trying to get resolution automatically by default + { + iScreenWidth = PSP_MAX_MAR_W; + iScreenHeight = PSP_MAX_MAR_H; + } +#endif + if( !FBitSet( vid_fullscreen->flags, FCVAR_CHANGED ) ) + Cvar_SetValue( "fullscreen", DEFAULT_FULLSCREEN ); + else + ClearBits( vid_fullscreen->flags, FCVAR_CHANGED ); + + SetBits( gl_vsync->flags, FCVAR_CHANGED ); + fullscreen = true;//Cvar_VariableInteger("fullscreen") != 0; + + if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, fullscreen )) == rserr_ok ) + { +#if 0 + vid_psp.in_width = iScreenWidth; + vid_psp.in_height = iScreenHeight; +#endif + } + else + return false; + + return true; +} + +/* +================== +R_Free_Video +================== +*/ +void R_Free_Video( void ) +{ +#if 0 + R_FreeVideoModes(); +#endif + ref.dllFuncs.GL_ClearExtensions(); + if( !glw_state.software ) + GU_Shutdown(); +} + +#endif // XASH_DEDICATED +#endif // XASH_VIDEO \ No newline at end of file diff --git a/engine/platform/psp/vram_psp.c b/engine/platform/psp/vram_psp.c new file mode 100644 index 00000000..a9a520dd --- /dev/null +++ b/engine/platform/psp/vram_psp.c @@ -0,0 +1,259 @@ +/* + * Helper for use with the PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed as 'free to use and modify as long as credited appropriately' + * + * vram.c - Standard C high performance VRAM allocation routines. + * + * Copyright (c) 2007 Alexander Berl 'Raphael' + * http://wordpress.fx-world.org + */ +#include "vram.h" +#include + +// Configure the memory to be managed +#define __MEM_SIZE 0x00200000 +#define __MEM_START 0x04000000 + +// Configure the block size the memory gets subdivided into (page size) +// __MEM_SIZE/__BLOCK_SIZE may not exceed 2^16-1 = 65535 +// The block size also defines the alignment of allocations +// Larger block sizes perform better, because the blocktable is smaller and therefore fits better into cache +// however the overhead is also bigger and more memory is wasted +#define __BLOCK_SIZE 512 +#define __MEM_BLOCKS (__MEM_SIZE/__BLOCK_SIZE) +#define __BLOCKS(x) ((x+__BLOCK_SIZE-1)/__BLOCK_SIZE) +#define __BLOCKSIZE(x) ((x+__BLOCK_SIZE-1)&~(__BLOCK_SIZE-1)) + + +// A MEMORY BLOCK ENTRY IS MADE UP LIKE THAT: +// bit: 31 30 29 - 15 14-0 +// free block prev size +// +// bit 31: free bit, indicating if block is allocated or not +// bit 30: blocked bit, indicating if block is part of a larger block (0) - used for error resilience +// bit 29-15: block index of previous block +// bit 14- 0: size of current block +// +// This management can handle a max amount of 2^16-1 = 65535 blocks, which resolves to 64MB at blocksize of 1024 bytes +// +#define __BLOCK_GET_SIZE(x) ((x & 0x7FFF)) +#define __BLOCK_GET_PREV(x) ((x >> 15) & 0x7FFF) +#define __BLOCK_GET_FREE(x) ((x >> 31)) +#define __BLOCK_GET_BLOCK(x) ((x >> 30) & 0x1) +#define __BLOCK_SET_SIZE(x,y) x=((x & ~0x7FFF) | ((y) & 0x7FFF)) +#define __BLOCK_ADD_SIZE(x,y) x=((x & ~0x7FFF) | (((x & 0x7FFF)+((y) & 0x7FFF)) & 0x7FFF)) +#define __BLOCK_SET_PREV(x,y) x=((x & ~0x3FFF8000) | (((y) & 0x7FFF)<<15)) +#define __BLOCK_SET_FREE(x,y) x=((x & 0x7FFFFFFF) | (((y) & 0x1)<<31)) +#define __BLOCK_SET_BLOCK(x,y) x=((x & 0xBFFFFFFF) | (((y) & 0x1)<<30)) +#define __BLOCK_MAKE(s,p,f,n) (((f & 0x1)<<31) | ((n & 0x1)<<30) | (((p) & 0x7FFF)<<15) | ((s) & 0x7FFF)) +#define __BLOCK_GET_FREEBLOCK(x) ((x>>30) & 0x3) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change) +#define __BLOCK0 ((__MEM_BLOCKS) | (1<<31) | (1<<30)) + + +unsigned int __mem_blocks[__MEM_BLOCKS] = { 0 }; + + +static int __largest_update = 0; +static int __largest_block = __MEM_BLOCKS; +static int __mem_free = __MEM_BLOCKS; + + +inline void* vrelptr( void *ptr ) +{ + return (void*)((unsigned int)ptr & ~__MEM_START); +} + +inline void* vabsptr( void *ptr ) +{ + return (void*)((unsigned int)ptr | __MEM_START); +} + + +static void __find_largest_block( void ) +{ + int i = 0; + __largest_block = 0; + while (i<__MEM_BLOCKS) + { + int csize = __BLOCK_GET_SIZE(__mem_blocks[i]); + if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>__largest_block) + __largest_block = csize; + i += csize; + } + __largest_update = 0; +} + +#ifdef _DEBUG +void __memwalk( void ) +{ + int i = 0; + if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0; + while (i<__MEM_BLOCKS) + { + printf("BLOCK %i:\n", i); + printf(" free: %i\n", __BLOCK_GET_FREEBLOCK(__mem_blocks[i])); + printf(" size: %i\n", __BLOCK_GET_SIZE(__mem_blocks[i])); + printf(" prev: %i\n", __BLOCK_GET_PREV(__mem_blocks[i])); + i+=__BLOCK_GET_SIZE(__mem_blocks[i]); + } +} +#endif + +void* valloc( size_t size ) +{ + // Initialize memory block, if not yet done + if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0; + + int i = 0; + int j = 0; + int bsize = __BLOCKS(size); + + if (__largest_update==0 && __largest_block=bsize) + { + if (csizebsize && next<__MEM_BLOCKS) + { + __mem_blocks[next] = __BLOCK_MAKE(csize-bsize,i,1,1); + int nextnext = i+csize; + if (nextnext<__MEM_BLOCKS) + { + __BLOCK_SET_PREV(__mem_blocks[nextnext], next); + } + } + + __mem_free -= bsize; + if (__largest_block==csize) // if we just allocated from one of the largest blocks + { + if ((csize-bsize)>(__mem_free/2)) + __largest_block = (csize-bsize); // there can't be another largest block + else + __largest_update = 1; + } + return ((void*)(__MEM_START + (i*__BLOCK_SIZE))); +} + + +void vfree( void* ptr ) +{ + if (ptr==0) return; + + int block = ((unsigned int)ptr - __MEM_START)/__BLOCK_SIZE; + if (block<0 || block>__MEM_BLOCKS) + { + #ifdef _DEBUG + printf("Block is out of range: %i (0x%x)\n", block, (int)ptr); + #endif + return; + } + int csize = __BLOCK_GET_SIZE(__mem_blocks[block]); + #ifdef _DEBUG + printf("freeing block %i (0x%x), size: %i\n", block, (int)ptr, csize); + #endif + + if (__BLOCK_GET_FREEBLOCK(__mem_blocks[block])!=1 || csize==0) + { + #ifdef _DEBUG + printf("Block was not allocated!\n"); + #endif + return; + } + + // Mark block as free + __BLOCK_SET_FREE(__mem_blocks[block],1); + __mem_free += csize; + + int next = block+csize; + // Merge with previous block if possible + int prev = __BLOCK_GET_PREV(__mem_blocks[block]); + if (prev + * http://wordpress.fx-world.org + */ +#ifndef vram_h__ +#define vram_h__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void* vrelptr( void *ptr ); // make a pointer relative to memory base address (ATTENTION: A NULL rel ptr is not illegal/invalid!) +void* vabsptr( void *ptr ); // make a pointer absolute (default return type of valloc) + +void* valloc( size_t size ); +void vfree( void* ptr ); +size_t vmemavail(); +size_t vlargestblock(); + + +#ifdef _DEBUG +// Debug printf (to stdout) a trace of the current Memblocks +void __memwalk(); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif // ifdef vram_h__ diff --git a/engine/server/server.h b/engine/server/server.h index 47fbf173..7098b5b4 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -54,13 +54,17 @@ extern int SV_UPDATE_BACKUP; #define GROUP_OP_AND 0 #define GROUP_OP_NAND 1 -#ifdef NDEBUG +#if defined( NDEBUG ) || XASH_OPT #define SV_IsValidEdict( e ) ( e && !e->free ) #else #define SV_IsValidEdict( e ) SV_CheckEdict( e, __FILE__, __LINE__ ) #endif #define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - svgame.edicts)) +#if XASH_OPT +#define EDICT_NUM( num ) ( ( ( ( num ) >= 0 ) && ( ( num ) < GI->max_edicts) ) ? svgame.edicts + ( num ) : NULL ) +#else #define EDICT_NUM( num ) SV_EdictNum( num ) +#endif #define STRING( offset ) SV_GetString( offset ) #define ALLOC_STRING(str) SV_AllocString( str ) #define MAKE_STRING(str) SV_MakeString( str ) @@ -476,7 +480,12 @@ void Master_Packet( void ); // void SV_ActivateServer( int runPhysics ); qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background ); +#if XASH_OPT +#define SV_ModelHandle( modelindex ) ( ( modelindex < 0 || modelindex >= MAX_MODELS ) ? NULL : sv.models[( modelindex )] ) +model_t *pfnSV_ModelHandle( int modelindex ); +#else model_t *SV_ModelHandle( int modelindex ); +#endif void SV_DeactivateServer( void ); // @@ -490,7 +499,17 @@ qboolean SV_RunThink( edict_t *ent ); qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time ); qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker ); void SV_Impact( edict_t *e1, edict_t *e2, trace_t *trace ); +#if XASH_OPT +// filter movetypes to collide with +#define SV_CanPushed( ent ) ( ( ent )->v.movetype == MOVETYPE_NONE || \ + ( ent )->v.movetype == MOVETYPE_PUSH || \ + ( ent )->v.movetype == MOVETYPE_FOLLOW || \ + ( ent )->v.movetype == MOVETYPE_NOCLIP || \ + ( ent )->v.movetype == MOVETYPE_COMPOUND ) ? false : true +qboolean pfnSV_CanPushed( edict_t *ent ); +#else qboolean SV_CanPushed( edict_t *ent ); +#endif void SV_FreeOldEntities( void ); void SV_CheckAllEnts( void ); @@ -633,7 +652,9 @@ void SV_RestartAmbientSounds( void ); void SV_RestartDecals( void ); void SV_RestartStaticEnts( void ); int pfnGetCurrentPlayer( void ); +#if !XASH_OPT edict_t *SV_EdictNum( int n ); +#endif char *SV_Localinfo( void ); // // sv_log.c diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index c6d41c42..0a72ed88 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -35,7 +35,7 @@ static vec3_t viewPoint[MAX_CLIENTS]; // exports typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev ); typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals ); - +#if !XASH_OPT edict_t *SV_EdictNum( int n ) { if(( n >= 0 ) && ( n < GI->max_edicts )) @@ -59,7 +59,7 @@ qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line ) return false; } #endif - +#endif /* ============= EntvarsDescription @@ -2679,7 +2679,8 @@ void GAME_EXPORT pfnMessageEnd( void ) return; } - *(word *)&sv.multicast.pData[svgame.msg_size_index] = svgame.msg_realsize; + /**(word *)&*/ // GSA + sv.multicast.pData[svgame.msg_size_index] = svgame.msg_realsize; } else { diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index e4b05a1c..497aaa2f 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -266,12 +266,19 @@ SV_ModelHandle get model by handle ================ */ +#if XASH_OPT +model_t *pfnSV_ModelHandle( int modelindex ) +{ + return SV_ModelHandle( modelindex ); +} +#else model_t *SV_ModelHandle( int modelindex ) { if( modelindex < 0 || modelindex >= MAX_MODELS ) return NULL; return sv.models[modelindex]; } +#endif void SV_ReadResourceList( const char *filename ) { diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 62efc1de..602b0458 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -842,6 +842,12 @@ SV_CanPushed filter entities for push ============ */ +#if XASH_OPT +qboolean pfnSV_CanPushed( edict_t *ent ) +{ + return SV_CanPushed( ent ); +} +#else qboolean SV_CanPushed( edict_t *ent ) { // filter movetypes to collide with @@ -856,6 +862,7 @@ qboolean SV_CanPushed( edict_t *ent ) } return true; } +#endif /* ============ @@ -864,7 +871,11 @@ SV_CanBlock allow entity to block pusher? ============ */ +#if XASH_PSP +static inline qboolean SV_CanBlock( edict_t *ent ) +#else static qboolean SV_CanBlock( edict_t *ent ) +#endif { if( ent->v.mins[0] == ent->v.maxs[0] ) return false; @@ -936,12 +947,12 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) // filter movetypes to collide with if( !SV_CanPushed( check )) continue; - +#if !XASH_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; - +#endif // if the entity is standing on the pusher, it will definately be moved if( !( FBitSet( check->v.flags, FL_ONGROUND ) && check->v.groundentity == pusher )) { @@ -957,7 +968,12 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) if( !SV_TestEntityPosition( check, NULL )) continue; } - +#if XASH_OPT + pusher->v.solid = SOLID_NOT; + block = SV_TestEntityPosition( check, pusher ); + pusher->v.solid = oldsolid; + if( block ) continue; +#endif // remove the onground flag for non-players if( check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; @@ -1049,18 +1065,19 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); + if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; - +#if !XASH_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; - +#endif // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher )) { @@ -1076,7 +1093,12 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) if( !SV_TestEntityPosition( check, NULL )) continue; } - +#if XASH_OPT + pusher->v.solid = SOLID_NOT; + block = SV_TestEntityPosition( check, pusher ); + pusher->v.solid = oldsolid; + if( block ) continue; +#endif // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); @@ -1092,7 +1114,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) Matrix4x4_VectorITransform( start_l, org, temp ); Matrix4x4_VectorTransform( end_l, temp, org2 ); VectorSubtract( org2, org, lmove ); - + // i can't clear FL_ONGROUND in all cases because many bad things may be happen if( check->v.movetype != MOVETYPE_WALK ) { @@ -1131,7 +1153,6 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) return check; } } - return NULL; } @@ -2018,7 +2039,11 @@ static server_physics_api_t gPhysicsAPI = SV_LinkEdict, SV_GetServerTime, SV_GetFrameTime, +#if XASH_OPT + (void*)pfnSV_ModelHandle, +#else (void*)SV_ModelHandle, +#endif SV_GetHeadNode, SV_ServerState, Host_Error, diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index 6dff96c8..6bfba80a 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -32,8 +32,11 @@ half-life implementation of saverestore system #define SAVEGAME_HEADER (('V'<<24)+('A'<<16)+('S'<<8)+'J') // little-endian "JSAV" #define SAVEGAME_VERSION 0x0071 // Version 0.71 GoldSrc compatible #define CLIENT_SAVEGAME_VERSION 0x0067 // Version 0.67 - +#ifdef XASH_PSP +#define SAVE_HEAPSIZE 0x200000 // reserve 2Mb for now +#else #define SAVE_HEAPSIZE 0x400000 // reserve 4Mb for now +#endif #define SAVE_HASHSTRINGS 0xFFF // 4095 unique strings #define SAVE_AGED_COUNT 2 @@ -2255,10 +2258,19 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) else pTokenList = NULL; // short, short (size, index of field name) +#if XASH_PSP /* FIX Unaligned access! */ + short offpd; + memcpy(&offpd, pData, sizeof( short ) ); + nFieldSize = offpd; + pData += sizeof( short ); + + memcpy(&offpd, pData, sizeof( short )); + pFieldName = pTokenList[offpd]; +#else nFieldSize = *(short *)pData; pData += sizeof( short ); pFieldName = pTokenList[*(short *)pData]; - +#endif if( Q_stricmp( pFieldName, "GameHeader" )) { Q_strncpy( comment, "", MAX_STRING ); @@ -2270,7 +2282,11 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) // int (fieldcount) pData += sizeof( short ); +#if XASH_PSP /* FIX Unaligned access! */ + memcpy(&nNumberOfFields, pData, sizeof(int)); +#else nNumberOfFields = (int)*pData; +#endif pData += nFieldSize; // each field is a short (size), short (index of name), binary string of "size" bytes (data) @@ -2280,12 +2296,21 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) // Size // szName // Actual Data +#if XASH_PSP /* FIX Unaligned access! */ + memcpy(&offpd, pData, sizeof( short ) ); + nFieldSize = offpd; + pData += sizeof( short ); + + memcpy(&offpd, pData, sizeof( short )); + pFieldName = pTokenList[offpd]; + pData += sizeof( short ); +#else nFieldSize = *(short *)pData; pData += sizeof( short ); pFieldName = pTokenList[*(short *)pData]; pData += sizeof( short ); - +#endif if( !Q_stricmp( pFieldName, "comment" )) { Q_strncpy( description, pData, nFieldSize ); diff --git a/engine/sprite.h b/engine/sprite.h index a62a14ed..da0964e3 100644 --- a/engine/sprite.h +++ b/engine/sprite.h @@ -15,6 +15,9 @@ #ifndef SPRITE_H #define SPRITE_H +#ifdef __psp__ // GSA +#pragma pack(push, 1) +#endif /* ============================================================================== @@ -125,4 +128,7 @@ typedef struct frametype_t type; } dframetype_t; +#ifdef __psp__ // GSA +#pragma pack(pop) +#endif #endif//SPRITE_H diff --git a/engine/wscript b/engine/wscript index 847919ab..c230a68b 100644 --- a/engine/wscript +++ b/engine/wscript @@ -44,6 +44,8 @@ def configure(conf): elif conf.env.DEST_OS == 'android': # Android doesn't need SDL2 for i in ['log']: conf.check_cc(lib = i) + elif conf.env.DEST_OS == 'psp': + conf.define('XASH_NO_NETWORK', 1) elif conf.options.FBDEV_SW: # unused, XASH_LINUX without XASH_SDL gives fbdev & alsa support # conf.define('XASH_FBDEV', 1) @@ -66,7 +68,8 @@ def configure(conf): if conf.options.STATIC: conf.env.STATIC = True - conf.define('XASH_NO_LIBDL',1) + if conf.env.DEST_OS != 'psp': + conf.define('XASH_NO_LIBDL',1) if not conf.env.DEST_OS in ['win32', 'android'] and not conf.options.NO_ASYNC_RESOLVE: conf.load('pthreads') @@ -99,7 +102,7 @@ def build(bld): if bld.env.DEST_OS == 'win32': libs += ['USER32', 'SHELL32', 'GDI32', 'ADVAPI32', 'DBGHELP', 'PSAPI', 'WS2_32' ] source += bld.path.ant_glob(['platform/win32/*.c']) - elif bld.env.DEST_OS != 'dos': #posix + elif bld.env.DEST_OS not in ['dos', 'psp']: #posix libs += [ 'M', 'RT', 'PTHREAD', 'ASOUND'] if not bld.env.STATIC: libs += ['DL'] @@ -112,7 +115,6 @@ def build(bld): source += bld.path.ant_glob(['platform/dos/*.c']) source += bld.path.ant_glob(['platform/stub/s_stub.c']) - if bld.get_define('XASH_CUSTOM_SWAP'): source += bld.path.ant_glob(['platform/misc/kmalloc.c', 'platform/misc/sbrk.c']) @@ -133,6 +135,9 @@ def build(bld): libs += ['LOG'] source += bld.path.ant_glob(['platform/android/*.cpp', 'platform/android/*.c', 'platform/linux/*.c']) + if bld.env.DEST_OS == 'psp': + source += bld.path.ant_glob(['platform/psp/*.c']) + # add client files if not bld.env.DEDICATED: source += bld.path.ant_glob([ diff --git a/mainui b/mainui index 6e913551..d3c61e2e 160000 --- a/mainui +++ b/mainui @@ -1 +1 @@ -Subproject commit 6e9135516a9e1c9bcd7e0b1b6a923fc55d4f8eaa +Subproject commit d3c61e2e1486bcac3af9e8d31a7c6b0186d1968a diff --git a/public/build.h b/public/build.h index 043a11cd..2b7ee030 100644 --- a/public/build.h +++ b/public/build.h @@ -70,6 +70,8 @@ For more information, please refer to #undef XASH_WIN32 #undef XASH_WIN64 #undef XASH_X86 +#undef XASH_PSP +#undef XASH_OPT //================================================================ // @@ -115,11 +117,15 @@ For more information, please refer to #elif defined __WATCOMC__ && defined __DOS__ #define XASH_DOS4GW 1 #define XASH_LITTLE_ENDIAN +#elif defined __psp__ + #define XASH_PSP 1 + #define XASH_LITTLE_ENDIAN + #define XASH_OPT 1 #else #error "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug" #endif -#if defined XASH_ANDROID || defined XASH_IOS +#if defined XASH_ANDROID || defined XASH_IOS || defined XASH_PSP #define XASH_MOBILE_PLATFORM 1 #endif diff --git a/public/matrixlib.c b/public/matrixlib.c index f536e4f9..ef4c1415 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -35,13 +35,57 @@ const matrix3x4 matrix3x4_identity = */ void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] + "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] + "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else out[0] = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3]; out[1] = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3]; out[2] = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3]; +#endif } void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vsub.t C130, C130, R103\n" // C130 = v - in[][3] + "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else vec3_t dir; dir[0] = v[0] - in[0][3]; @@ -51,20 +95,74 @@ void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out out[0] = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0]; out[1] = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1]; out[2] = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2]; +#endif } void Matrix3x4_VectorRotate( const matrix3x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] +#if 0 + "vtfm3.t C000, M100, C130\n" // c000 = M100 * C130 +#else + "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] +#endif + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); + +#else out[0] = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2]; out[1] = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2]; out[2] = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2]; +#endif } void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] +#if 0 + "vtfm3.t C000, E100, C130\n" // c000 = E100 * C130 +#else + "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] +#endif + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else out[0] = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0]; out[1] = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1]; out[2] = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2]; +#endif } void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matrix3x4 in2 ) @@ -119,6 +217,30 @@ void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out ) void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin ) { +#if 0//XASH_PSP /* not tested */ + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C130, %1\n" // C130 = quaternion + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "vmov.q C100, C130[ W, Z, -Y, -X]\n" // C100 = ( w, z, -y, -x) + "vmov.q C110, C130[-Z, W, X, -Y]\n" // C110 = (-z, w, x, -y) + "vmov.q C120, C130[ Y, -X, W, -Z]\n" // C120 = ( y, -x, w, -z) + "vmov.q C200, C130[ W, Z, -Y, X]\n" // C200 = ( w, z, -y, x) + "vmov.q C210, C130[-Z, W, X, Y]\n" // C210 = (-z, w, x, y) + "vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z) + "vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w) + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *quaternion ), "m"( *origin ) + ); +#else out[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2]; out[1][0] = 2.0f * quaternion[0] * quaternion[1] + 2.0f * quaternion[3] * quaternion[2]; out[2][0] = 2.0f * quaternion[0] * quaternion[2] - 2.0f * quaternion[3] * quaternion[1]; @@ -134,10 +256,166 @@ void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec out[0][3] = origin[0]; out[1][3] = origin[1]; out[2][3] = origin[2]; +#endif } void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_t origin, float scale ) { +#if XASH_PSP /* performance not tested */ + if( angles[ROLL] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S102, 8 + %1\n" // S102 = angles[ROLL] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + /**/ + "vsin.t C110, C100\n" // C110 = sin( C100 ) P Y R + "vcos.t C120, C100\n" // C120 = cos( C100 ) P Y R + "vneg.t C100, C110\n" // C100 = -C110 = -sin( C100 ) + /**/ + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmul.s S011, S112, S110\n" // S011 = S112 * S110 = ( sr * sp ) + "vmul.s S001, S011, S121\n" // S001 = S011 * S121 = ( sr * sp * cy ) + "vmul.s S103, S122, S101\n" // S001 = S122 * S101 = ( cr * -sy ) + "vadd.s S001, S001, S103\n" // S001 = S001 + S103 = out[0][1] = ( sr * sp * cy + cr * -sy ) + "vmul.s S012, S122, S110\n" // S002 = S122 * S110 = ( cr * sp ) + "vmul.s S002, S012, S121\n" // S002 = S012 * S121 = ( cr * sp * cy ) + "vmul.s S103, S102, S101\n" // S002 = S102 * S101 = ( -sr * -sy ) + "vadd.s S002, S002, S103\n" // S002 = S002 + S103 = out[0][2] = ( cr * sp * cy + -sr * -sy ) + /**/ + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmul.s S011, S011, S111\n" // S001 = S011 * S111 = ( sr * sp * sy ) + "vmul.s S103, S122, S121\n" // S001 = S122 * S121 = ( cr * cy ) + "vadd.s S011, S011, S103\n" // S011 = S011 + S103 = out[1][1] = ( sr * sp * sy + cr * cy ) + "vmul.s S012, S012, S111\n" // S012 = S012 * S111 = ( cr * sp * sy ) + "vmul.s S103, S102, S121\n" // S103 = S102 * S121 = ( -sr * cy ) + "vadd.s S012, S012, S103\n" // S012 = S012 + S103 = out[1][2] = ( cr * sp * sy + -sr * cy ) + /**/ + "vmov.s S020, S101\n" // S020 = S101 = out[2][0] = ( -sp ) + "vmul.s S021, S112, S120\n" // S021 = S112 * S120 = out[2][1] = ( sr * cp ) + "vmul.s S022, S122, S120\n" // S021 = S122 * S120 = out[2][2] = ( cr * cp ) + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else if( angles[PITCH] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + /**/ + "vsin.p C110, C100\n" // C110 = sin( C100 ) P Y + "vcos.p C120, C100\n" // C120 = cos( C100 ) P Y + "vneg.p C100, C110\n" // C100 = -C110 = -sin( C100 ) + /**/ + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmov.s S001, S101\n" // S001 = S101 = out[0][1] = ( -sy ) + "vmul.s S002, S110, S121\n" // S001 = S110 * S121 = out[0][2] = ( sp * cy ) + /**/ + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vmul.s S012, S110, S111\n" // S012 = S110 * S111 = out[1][2] = ( sp * sy ) + /**/ + "vmov.s S020, S100\n" // S020 = S100 = out[2][0] = ( -sp ) + "vzero.s S021\n" // S021 = out[2][1] = 0.0f + "vmov.s S022, S120\n" // S022 = S120 = out[2][2] = ( cp ) + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else if( angles[YAW] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) + /**/ + "vsin.s S111, S101\n" // S111 = sin( S101 ) Y + "vcos.s S121, S101\n" // S121 = cos( S101 ) Y + /**/ + "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f + "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f + "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) + "vneg.s S001, S111\n" // S001 = S111 = out[0][1] = ( -sy ) + "vmov.s S010, S111\n" // S010 = S111 = out[1][0] = ( sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vone.s S022\n" // S022 = out[2][2] = 1.0f + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %2\n" // S130 = scale + /**/ + "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] + "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] + "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] + "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale + "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale + "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *origin ), "m"( scale ) + ); + } +#else float angle, sr, sp, sy, cr, cp, cy; if( angles[ROLL] ) @@ -215,10 +493,39 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ out[2][2] = scale; out[2][3] = origin[2]; } +#endif } void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, float d, vec3_t out, float *dist ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %2\n" // C100 = in[0] + "ulv.q C110, 16 + %2\n" // C110 = in[1] + "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vadd.s S003, S003, S010\n" // S003 = S003 + S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option + : "=m"( *out ), "=m"( *dist ) + : "m"( *in ), "m"( *normal ), "m"( d ) + ); +#else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); float iscale = 1.0f / scale; @@ -226,6 +533,7 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, out[1] = (normal[0] * in[1][0] + normal[1] * in[1][1] + normal[2] * in[1][2]) * iscale; out[2] = (normal[0] * in[2][0] + normal[1] * in[2][1] + normal[2] * in[2][2]) * iscale; *dist = d * scale + ( out[0] * in[0][3] + out[1] * in[1][3] + out[2] * in[2][3] ); +#endif } void Matrix3x4_Invert_Simple( matrix3x4 out, const matrix3x4 in1 ) @@ -312,13 +620,57 @@ const matrix4x4 matrix4x4_identity = */ void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] + "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] + "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else out[0] = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3]; out[1] = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3]; out[2] = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3]; +#endif } void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vsub.t C200, C130, R103\n" // C130 = v - in[][3] + "vdot.t S000, C200, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] + "vdot.t S001, C200, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] + "vdot.t S002, C200, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else vec3_t dir; dir[0] = v[0] - in[0][3]; @@ -328,20 +680,74 @@ void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out out[0] = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0]; out[1] = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1]; out[2] = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2]; +#endif } void Matrix4x4_VectorRotate( const matrix4x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] +#if 0 + "vtfm3.t C000, M100, C130\n" // c000 = M100 * C130 +#else + "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] +#endif + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else out[0] = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2]; out[1] = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2]; out[2] = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2]; +#endif } void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %1\n" // C100 = in[0] + "ulv.q C110, 16 + %1\n" // C110 = in[1] + "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] +#if 0 + "vtfm3.t C000, E100, C130\n" // c000 = E100 * C130 +#else + "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] +#endif + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ), "m"( *v ) + ); +#else out[0] = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0]; out[1] = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1]; out[2] = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2]; +#endif + } void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) @@ -384,6 +790,7 @@ void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec out[1][1] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[2] * quaternion[2]; out[2][1] = 2.0f * quaternion[1] * quaternion[2] + 2.0f * quaternion[3] * quaternion[0]; out[1][3] = origin[1]; + out[0][2] = 2.0f * quaternion[0] * quaternion[2] + 2.0f * quaternion[3] * quaternion[1]; out[1][2] = 2.0f * quaternion[1] * quaternion[2] - 2.0f * quaternion[3] * quaternion[0]; out[2][2] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[1] * quaternion[1]; @@ -396,6 +803,169 @@ void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale ) { +#if XASH_PSP /* performance not tested */ + if( angles[ROLL] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S102, 8 + %1\n" // S102 = angles[ROLL] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + /**/ + "vsin.t C110, C100\n" // C110 = sin( C100 ) P Y R + "vcos.t C120, C100\n" // C120 = cos( C100 ) P Y R + "vneg.t C100, C110\n" // C100 = -C110 = -sin( C100 ) + /**/ + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmul.s S011, S112, S110\n" // S011 = S112 * S110 = ( sr * sp ) + "vmul.s S001, S011, S121\n" // S001 = S011 * S121 = ( sr * sp * cy ) + "vmul.s S103, S122, S101\n" // S001 = S122 * S101 = ( cr * -sy ) + "vadd.s S001, S001, S103\n" // S001 = S001 + S103 = out[0][1] = ( sr * sp * cy + cr * -sy ) + "vmul.s S012, S122, S110\n" // S002 = S122 * S110 = ( cr * sp ) + "vmul.s S002, S012, S121\n" // S002 = S012 * S121 = ( cr * sp * cy ) + "vmul.s S103, S102, S101\n" // S002 = S102 * S101 = ( -sr * -sy ) + "vadd.s S002, S002, S103\n" // S002 = S002 + S103 = out[0][2] = ( cr * sp * cy + -sr * -sy ) + /**/ + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmul.s S011, S011, S111\n" // S001 = S011 * S111 = ( sr * sp * sy ) + "vmul.s S103, S122, S121\n" // S001 = S122 * S121 = ( cr * cy ) + "vadd.s S011, S011, S103\n" // S011 = S011 + S103 = out[1][1] = ( sr * sp * sy + cr * cy ) + "vmul.s S012, S012, S111\n" // S012 = S012 * S111 = ( cr * sp * sy ) + "vmul.s S103, S102, S121\n" // S103 = S102 * S121 = ( -sr * cy ) + "vadd.s S012, S012, S103\n" // S012 = S012 + S103 = out[1][2] = ( cr * sp * sy + -sr * cy ) + /**/ + "vmov.s S020, S101\n" // S020 = S101 = out[2][0] = ( -sp ) + "vmul.s S021, S112, S120\n" // S021 = S112 * S120 = out[2][1] = ( sr * cp ) + "vmul.s S022, S122, S120\n" // S021 = S122 * S120 = out[2][2] = ( cr * cp ) + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + "usv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else if( angles[PITCH] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + /**/ + "vsin.p C110, C100\n" // C110 = sin( C100 ) P Y + "vcos.p C120, C100\n" // C120 = cos( C100 ) P Y + "vneg.p C100, C110\n" // C100 = -C110 = -sin( C100 ) + /**/ + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmov.s S001, S101\n" // S001 = S101 = out[0][1] = ( -sy ) + "vmul.s S002, S110, S121\n" // S001 = S110 * S121 = out[0][2] = ( sp * cy ) + /**/ + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vmul.s S012, S110, S111\n" // S012 = S110 * S111 = out[1][2] = ( sp * sy ) + /**/ + "vmov.s S020, S100\n" // S020 = S100 = out[2][0] = ( -sp ) + "vzero.s S021\n" // S021 = out[2][1] = 0.0f + "vmov.s S022, S120\n" // S022 = S120 = out[2][2] = ( cp ) + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + "usv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else if( angles[YAW] ) + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale + /**/ + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) + /**/ + "vsin.s S111, S101\n" // S111 = sin( S101 ) Y + "vcos.s S121, S101\n" // S121 = cos( S101 ) Y + /**/ + "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f + "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f + "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) + "vneg.s S001, S111\n" // S001 = S111 = out[0][1] = ( -sy ) + "vmov.s S010, S111\n" // S010 = S111 = out[1][0] = ( sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vone.s S022\n" // S022 = out[2][2] = 1.0f + /**/ + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + "usv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *angles ), "m"( *origin ), "m"( scale ) + ); + } + else + { + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %2\n" // S130 = scale + /**/ + "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] + "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] + "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale + "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale + "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale + /**/ + "usv.q C000, 0 + %0\n" // out[0] = C000 + "usv.q C010, 16 + %0\n" // out[1] = C010 + "usv.q C020, 32 + %0\n" // out[2] = C020 + "usv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *origin ), "m"( scale ) + ); + } +#else float angle, sr, sp, sy, cr, cp, cy; if( angles[ROLL] ) @@ -489,6 +1059,7 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ out[3][2] = 0.0f; out[3][3] = 1.0f; } +#endif } void Matrix4x4_ConvertToEntity( const matrix4x4 in, vec3_t angles, vec3_t origin ) @@ -516,6 +1087,34 @@ void Matrix4x4_ConvertToEntity( const matrix4x4 in, vec3_t angles, vec3_t origin void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %2\n" // C100 = in[0] + "ulv.q C110, 16 + %2\n" // C110 = in[1] + "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vadd.s S003, S003, S010\n" // S003 = S003 + S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option + : "=m"( *out ), "=m"( *dist ) + : "m"( *in ), "m"( *normal ), "m"( d ) + ); +#else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); float iscale = 1.0f / scale; @@ -523,10 +1122,39 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, out[1] = (normal[0] * in[1][0] + normal[1] * in[1][1] + normal[2] * in[1][2]) * iscale; out[2] = (normal[0] * in[2][0] + normal[1] * in[2][1] + normal[2] * in[2][2]) * iscale; *dist = d * scale + ( out[0] * in[0][3] + out[1] * in[1][3] + out[2] * in[2][3] ); +#endif } void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C100, 0 + %2\n" // C100 = in[0] + "ulv.q C110, 16 + %2\n" // C110 = in[1] + "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vsub.s S003, S003, S010\n" // S003 = S003 - S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option + : "=m"( *out ), "=m"( *dist ) + : "m"( *in ), "m"( *normal ), "m"( d ) + ); +#else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); float iscale = 1.0f / scale; @@ -534,6 +1162,7 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, out[1] = (normal[0] * in[1][0] + normal[1] * in[1][1] + normal[2] * in[1][2]) * iscale; out[2] = (normal[0] * in[2][0] + normal[1] * in[2][1] + normal[2] * in[2][2]) * iscale; *dist = d * scale - ( out[0] * in[0][3] + out[1] * in[1][3] + out[2] * in[2][3] ); +#endif } void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 ) @@ -635,7 +1264,7 @@ qboolean Matrix4x4_Invert_Full( matrix4x4 out, const matrix4x4 in1 ) r[3][4] = 0.0f; r[3][5] = 0.0f; r[3][6] = 0.0f; - r[3][7] = 1.0f; + r[3][7] = 1.0f; if( fabs( r[3][0] ) > fabs( r[2][0] )) { diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index 39f5d1ba..973bf692 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -34,7 +34,7 @@ int boxpnt[6][4] = { 7, 5, 1, 3 }, // -X { 7, 3, 2, 6 }, // -Y { 7, 6, 4, 5 }, // -Z -}; +}; // pre-quantized table normals from Quake1 const float m_bytenormals[NUMVERTEXNORMALS][3] = @@ -128,7 +128,7 @@ round the hullsize to nearest 'right' value void RoundUpHullSize( vec3_t size ) { int i, j; - + for( i = 0; i < 3; i++) { qboolean negative = false; @@ -149,7 +149,7 @@ void RoundUpHullSize( vec3_t size ) { result = ( value - hull_table[j] ); if( result <= HULL_PRECISION ) - { + { result = -hull_table[j]; break; } @@ -158,7 +158,7 @@ void RoundUpHullSize( vec3_t size ) { result = ( value - hull_table[j] ); if( result <= HULL_PRECISION ) - { + { result = hull_table[j]; break; } @@ -244,6 +244,23 @@ qboolean PlanesGetIntersectionPoint( const mplane_t *plane1, const mplane_t *pla return true; } +/* +================= +PlaneIntersect + +find point where ray +was intersect with plane +================= +*/ +void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, vec3_t out ) +{ + float distToPlane = PlaneDiff( p0, plane ); + float planeDotRay = DotProduct( plane->normal, p1 ); + float sect = -(distToPlane) / planeDotRay; + + VectorMA( p0, sect, p1, out ); +} + /* ================= NearestPOW @@ -289,6 +306,23 @@ rsqrt */ float rsqrt( float number ) { +#if XASH_PSP + float result; + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S000, %1\n" // S000 = number + "vzero.s S001\n" // S111 = 0 + "vcmp.s EZ, S000\n" // CC[0] = ( S000 == 0.0f ) + "vrsq.s S000, S000\n" // S000 = 1.0 / sqrt( S000 ) + "vcmovt.s S000, S001, 0\n" // if ( CC[0] ) S000 = S001 + "sv.s S000, %0\n" // result = S001 + ".set pop\n" // restore assembler option + : "=m"( result ) + : "m"( number ) + ); + return result; +#else int i; float x, y; @@ -302,6 +336,7 @@ float rsqrt( float number ) y = y * (1.5f - (x * y * y)); // first iteration return y; +#endif } /* @@ -311,6 +346,21 @@ SinCos */ void SinCos( float radians, float *sine, float *cosine ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S000, %2\n" // S000 = radians + "vcst.s S001, VFPU_2_PI\n" // S001 = VFPU_2_PI = 2 / PI + "vmul.s S000, S000, S001\n" // S000 = S000 * S001 + "vrot.p C002, S000, [S, C]\n" // S002 = sin( radians ), S003 = cos( radians ) + "sv.s S002, %0\n" // sine = S002 + "sv.s S003, %1\n" // cosine = S003 + ".set pop\n" // restore assembler option + : "=m"( *sine), "=m"( *cosine ) + : "m"( radians ) + ); +#else #if _MSC_VER == 1200 _asm { @@ -327,6 +377,7 @@ void SinCos( float radians, float *sine, float *cosine ) *sine = sin(radians); *cosine = cos(radians); #endif +#endif } /* @@ -451,7 +502,7 @@ void GAME_EXPORT VectorAngles( const float *forward, float *angles ) if( pitch < 0 ) pitch += 360; } - VectorSet( angles, pitch, yaw, 0 ); + VectorSet( angles, pitch, yaw, 0 ); } /* @@ -489,6 +540,7 @@ void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, v // // bounds operations // + /* ================= ClearBounds @@ -585,23 +637,6 @@ qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared return true; } -/* -================= -PlaneIntersect - -find point where ray -was intersect with plane -================= -*/ -void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, vec3_t out ) -{ - float distToPlane = PlaneDiff( p0, plane ); - float planeDotRay = DotProduct( plane->normal, p1 ); - float sect = -(distToPlane) / planeDotRay; - - VectorMA( p0, sect, p1, out ); -} - /* ================= RadiusFromBounds @@ -630,6 +665,42 @@ AngleQuaternion */ void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio ) { +#if 0//XASH_PSP /* performance not tested */ + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + + + + /**/ + "lv.s S000, 8 + %1\n" // S000 = angles[ROLL] + "lv.s S001, 0 + %1\n" // S000 = angles[PITCH] + "lv.s S002, 4 + %1\n" // S000 = angles[YAW] + /**/ + "vcst.s S010, VFPU_1_PI\n" // S010 = VFPU_1_PI = 1 / PI + "vscl.t C000, C000, S010\n" // C000 = C000 * S010 = C000 * 0.5f * ( 2 / PI ) + + /**/ + "vcos.t C010, C000\n" // C010 = cos( *angles * 0.5f ) + "vsin.t C000, C000\n" // C000 = sin( *angles * 0.5f ) + "vcrs.t C020, C010, C010\n" // C020 = ( cp*cy, cy*cr, cr*cp ) + "vcrs.t C030, C000, C000\n" // C030 = ( sp*sy, sy*sr, sr*sp ) + "vmul.s S003, S020, S010\n" // S003 = S020 * S010 = cp*cy*cr + "vmul.s S013, S030, S000\n" // S013 = S030 * S000 = sp*sy*sr + "vmul.t C020, C020, C000\n" // C020 = C020 * C000 = ( cp*cy*sr, cy*cr*sp, cr*cp*sy ) + "vmul.t C030, C030, C010\n" // C030 = C030 * C010 = ( sp*sy*cr, sy*sr*cp, sr*sp*cy ) + "vadd.s S003, S003, S013\n" // S003 = S003 + S013 = cr*cp*cy + sr*sp*sy + "vadd.t C000, C020, C030[-X, Y, -Z]\n" + // S000 = S020 - C030 = cp*cy*sr - sp*sy*cr + // S001 = S021 + C031 = cy*cr*sp + sy*sr*cp + // S002 = S022 - C032 = cr*cp*sy - sr*sp*cy + "usv.q C000, %0\n" // *q = C000 + ".set pop\n" // restore assembler option + : "=m"( *q ) + : "m"( *angles ), "r"( studio ) + ); + + printf("ASM [%f %f %f %f]\n", q[0], q[1], q[2], q[3] ); float sr, sp, sy, cr, cp, cy; if( studio ) @@ -649,6 +720,28 @@ void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio ) q[1] = cr * sp * cy + sr * cp * sy; // Y q[2] = cr * cp * sy - sr * sp * cy; // Z q[3] = cr * cp * cy + sr * sp * sy; // W + printf("C [%f %f %f %f]\n", q[0], q[1], q[2], q[3] ); +#else + float sr, sp, sy, cr, cp, cy; + + if( studio ) + { + SinCos( angles[ROLL] * 0.5f, &sy, &cy ); + SinCos( angles[YAW] * 0.5f, &sp, &cp ); + SinCos( angles[PITCH] * 0.5f, &sr, &cr ); + } + else + { + SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy ); + SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp ); + SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr ); + } + + q[0] = sr * cp * cy - cr * sp * sy; // X + q[1] = cr * sp * cy + sr * cp * sy; // Y + q[2] = cr * cp * sy - sr * sp * cy; // Z + q[3] = cr * cp * cy + sr * sp * sy; // W +#endif } /* @@ -679,20 +772,20 @@ void QuaternionAlign( const vec4_t p, const vec4_t q, vec4_t qt ) float b = 0.0f; int i; - for( i = 0; i < 4; i++ ) + for( i = 0; i < 4; i++ ) { a += (p[i] - q[i]) * (p[i] - q[i]); b += (p[i] + q[i]) * (p[i] + q[i]); } - if( a > b ) + if( a > b ) { - for( i = 0; i < 4; i++ ) + for( i = 0; i < 4; i++ ) qt[i] = -q[i]; } else { - for( i = 0; i < 4; i++ ) + for( i = 0; i < 4; i++ ) qt[i] = q[i]; } } @@ -820,8 +913,184 @@ Returns 1, 2, or 1 + 2 */ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) { - float dist1, dist2; +#if XASH_PSP + int sides; + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S000, 0 + %[normal]\n" // S000 = p->normal[0] + "lv.s S001, 4 + %[normal]\n" // S001 = p->normal[1] + "lv.s S002, 8 + %[normal]\n" // S002 = p->normal[2] + "vzero.p C030\n" // C030 = [0.0f, 0.0f] + "lv.s S032, %[dist]\n" // S032 = p->dist + "move $8, $0\n" // $8 = 0 + "beq %[signbits], $8, 0f\n" // jump to 0 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 1f\n" // jump to 1 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 2f\n" // jump to 2 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 3f\n" // jump to 3 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 4f\n" // jump to 4 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 5f\n" // jump to 5 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 6f\n" // jump to 6 + "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) + "beq %[signbits], $8, 7f\n" // jump to 7 + "nop\n" // ( delay slot ) + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "0:\n" +/* + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +*/ + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "1:\n" +/* + dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +*/ + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "2:\n" +/* + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +*/ + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "3:\n" +/* + dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +*/ + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "4:\n" +/* + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +*/ + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "5:\n" +/* + dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +*/ + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "6:\n" +/* + dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +*/ + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "j 8f\n" // jump to SetSides + "nop\n" // ( delay slot ) + "7:\n" +/* + dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +*/ + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "vdot.t S030, C000, C010\n" // S030 = C000 * C010 + "vdot.t S031, C000, C020\n" // S030 = C000 * C020 + "8:\n" // SetSides +/* + if( dist1 >= p->dist ) + sides = 1; + if( dist2 < p->dist ) + sides |= 2; +*/ + "addiu %[sides], $0, 0\n" // sides = 0 + "vcmp.s LT, S030, S032\n" // S030 < S032 + "bvt 0, 9f\n" // if ( CC[0] == 1 ) jump to 9 + "nop\n" // ( delay slot ) + "addiu %[sides], %[sides], 1\n"// sides = 1 + "9:\n" + "vcmp.s GE, S031, S032\n" // S031 >= S032 + "bvt 0, 10f\n" // if ( CC[0] == 1 ) jump to 10 + "nop\n" // ( delay slot ) + "addiu %[sides], %[sides], 2\n"// sides = sides + 2 + "10:\n" + ".set pop\n" // restore assembler option + : [sides] "=r" ( sides ) + : [normal] "m" ( p->normal ), + [emaxs] "m" ( *emaxs ), + [emins] "m" ( *emins ), + [signbits] "r" ( p->signbits ), + [dist] "m" ( p->dist ) + : "$8" + ); + return sides; +#else int sides = 0; + float dist1, dist2; // general case switch( p->signbits ) @@ -870,5 +1139,6 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) sides |= 2; return sides; +#endif } diff --git a/ref_gu/exports.txt b/ref_gu/exports.txt new file mode 100644 index 00000000..b79f9600 --- /dev/null +++ b/ref_gu/exports.txt @@ -0,0 +1,2 @@ +GetRefAPI +GetRefHumanReadableName \ No newline at end of file diff --git a/ref_gu/gu_alias.c b/ref_gu/gu_alias.c new file mode 100644 index 00000000..69271ba8 --- /dev/null +++ b/ref_gu/gu_alias.c @@ -0,0 +1,1545 @@ +/* +gu_alias.c - alias model renderer +Copyright (C) 2017 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "gu_local.h" +#include "xash3d_mathlib.h" +#include "const.h" +#include "r_studioint.h" +#include "triangleapi.h" +#include "alias.h" +#include "pm_local.h" +#include "pmtrace.h" + +extern cvar_t r_shadows; + +typedef struct +{ + double time; + double frametime; + int framecount; // alias framecount + qboolean interpolate; + + float ambientlight; + float shadelight; + vec3_t lightvec; // averaging light direction + vec3_t lightvec_local; // light direction in local space + vec3_t lightspot; // shadow spot + vec3_t lightcolor; // averaging lightcolor + int oldpose; // shadow used + int newpose; // shadow used + float lerpfrac; // lerp frames +} alias_draw_state_t; + +static alias_draw_state_t g_alias; // global alias state + +/* +================================================================= + +ALIAS MODEL DISPLAY LIST GENERATION + +================================================================= +*/ +static qboolean m_fDoRemap; +static aliashdr_t *m_pAliasHeader; +static trivertex_t *g_poseverts[MAXALIASFRAMES]; +static dtriangle_t g_triangles[MAXALIASTRIS]; +static stvert_t g_stverts[MAXALIASVERTS]; +static int g_used[8192]; + +// a pose is a single set of vertexes. a frame may be +// an animating sequence of poses +int g_posenum; + +// the command list holds counts and s/t values that are valid for +// every frame +static int g_commands[8192]; +static int g_numcommands; + +// all frames will have their vertexes rearranged and expanded +// so they are in the order expected by the command list +static int g_vertexorder[8192]; +static int g_numorder; + +static int g_stripverts[128]; +static int g_striptris[128]; +static int g_stripcount; + +/* +==================== +R_StudioInit + +==================== +*/ +void R_AliasInit( void ) +{ + g_alias.interpolate = true; + m_fDoRemap = false; +} + +/* +================ +StripLength +================ +*/ +static int StripLength( int starttri, int startv ) +{ + int m1, m2, j, k; + dtriangle_t *last, *check; + + g_used[starttri] = 2; + + last = &g_triangles[starttri]; + + g_stripverts[0] = last->vertindex[(startv+0) % 3]; + g_stripverts[1] = last->vertindex[(startv+1) % 3]; + g_stripverts[2] = last->vertindex[(startv+2) % 3]; + + g_striptris[0] = starttri; + g_stripcount = 1; + + m1 = last->vertindex[(startv+2)%3]; + m2 = last->vertindex[(startv+1)%3]; +nexttri: + // look for a matching triangle + for( j = starttri + 1, check = &g_triangles[starttri + 1]; j < m_pAliasHeader->numtris; j++, check++ ) + { + if( check->facesfront != last->facesfront ) + continue; + + for( k = 0; k < 3; k++ ) + { + if( check->vertindex[k] != m1 ) + continue; + if( check->vertindex[(k+1) % 3] != m2 ) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if( g_used[j] ) goto done; + + // the new edge + if( g_stripcount & 1 ) + m2 = check->vertindex[(k+2) % 3]; + else m1 = check->vertindex[(k+2) % 3]; + + g_stripverts[g_stripcount+2] = check->vertindex[(k+2) % 3]; + g_striptris[g_stripcount] = j; + g_stripcount++; + + g_used[j] = 2; + goto nexttri; + } + } +done: + // clear the temp used flags + for( j = starttri + 1; j < m_pAliasHeader->numtris; j++ ) + { + if( g_used[j] == 2 ) + g_used[j] = 0; + } + + return g_stripcount; +} + +/* +=========== +FanLength +=========== +*/ +static int FanLength( int starttri, int startv ) +{ + int m1, m2, j, k; + dtriangle_t *last, *check; + + g_used[starttri] = 2; + + last = &g_triangles[starttri]; + + g_stripverts[0] = last->vertindex[(startv+0) % 3]; + g_stripverts[1] = last->vertindex[(startv+1) % 3]; + g_stripverts[2] = last->vertindex[(startv+2) % 3]; + + g_striptris[0] = starttri; + g_stripcount = 1; + + m1 = last->vertindex[(startv+0) % 3]; + m2 = last->vertindex[(startv+2) % 3]; + +nexttri: + // look for a matching triangle + for( j = starttri + 1, check = &g_triangles[starttri + 1]; j < m_pAliasHeader->numtris; j++, check++ ) + { + if( check->facesfront != last->facesfront ) + continue; + + for( k = 0; k < 3; k++ ) + { + if( check->vertindex[k] != m1 ) + continue; + if( check->vertindex[(k+1) % 3] != m2 ) + continue; + + // this is the next part of the fan + // if we can't use this triangle, this tristrip is done + if( g_used[j] ) goto done; + + // the new edge + m2 = check->vertindex[(k+2) % 3]; + + g_stripverts[g_stripcount + 2] = m2; + g_striptris[g_stripcount] = j; + g_stripcount++; + + g_used[j] = 2; + goto nexttri; + } + } +done: + // clear the temp used flags + for( j = starttri + 1; j < m_pAliasHeader->numtris; j++ ) + { + if( g_used[j] == 2 ) + g_used[j] = 0; + } + + return g_stripcount; +} + +/* +================ +BuildTris + +Generate a list of trifans or strips +for the model, which holds for all frames +================ +*/ +void BuildTris( void ) +{ + int len, bestlen, besttype = 0; + int bestverts[1024]; + int besttris[1024]; + int type, startv; + int i, j, k; + float s, t; + + // + // build tristrips + // + memset( g_used, 0, sizeof( g_used )); + g_numcommands = 0; + g_numorder = 0; + + for( i = 0; i < m_pAliasHeader->numtris; i++ ) + { + // pick an unused triangle and start the trifan + if( g_used[i] ) continue; + + bestlen = 0; + for( type = 0; type < 2; type++ ) + { + for( startv = 0; startv < 3; startv++ ) + { + if( type == 1 ) len = StripLength( i, startv ); + else len = FanLength( i, startv ); + + if( len > bestlen ) + { + besttype = type; + bestlen = len; + + for( j = 0; j < bestlen + 2; j++ ) + bestverts[j] = g_stripverts[j]; + + for( j = 0; j < bestlen; j++ ) + besttris[j] = g_striptris[j]; + } + } + } + + // mark the tris on the best strip as used + for( j = 0; j < bestlen; j++ ) + g_used[besttris[j]] = 1; + + if( besttype == 1 ) + g_commands[g_numcommands++] = (bestlen + 2); + else g_commands[g_numcommands++] = -(bestlen + 2); + + for( j = 0; j < bestlen + 2; j++ ) + { + // emit a vertex into the reorder buffer + k = bestverts[j]; + g_vertexorder[g_numorder++] = k; + + // emit s/t coords into the commands stream + s = g_stverts[k].s; + t = g_stverts[k].t; + + if( !g_triangles[besttris[0]].facesfront && g_stverts[k].onseam ) + s += m_pAliasHeader->skinwidth / 2; // on back side + s = (s + 0.5f) / m_pAliasHeader->skinwidth; + t = (t + 0.5f) / m_pAliasHeader->skinheight; + + // Carmack use floats and Valve use shorts here... + *(float *)&g_commands[g_numcommands++] = s; + *(float *)&g_commands[g_numcommands++] = t; + } + } + + g_commands[g_numcommands++] = 0; // end of list marker +} + +/* +================ +GL_MakeAliasModelDisplayLists +================ +*/ +void GL_MakeAliasModelDisplayLists( model_t *m ) +{ + trivertex_t *verts; + int i, j; + + BuildTris( ); + + // save the data out + m_pAliasHeader->poseverts = g_numorder; + + m_pAliasHeader->commands = Mem_Malloc( m->mempool, g_numcommands * 4 ); + memcpy( m_pAliasHeader->commands, g_commands, g_numcommands * 4 ); + + m_pAliasHeader->posedata = Mem_Malloc( m->mempool, m_pAliasHeader->numposes * m_pAliasHeader->poseverts * sizeof( trivertex_t )); + verts = m_pAliasHeader->posedata; + + for( i = 0; i < m_pAliasHeader->numposes; i++ ) + { + for( j = 0; j < g_numorder; j++ ) + *verts++ = g_poseverts[i][g_vertexorder[j]]; + } +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ +/* +================= +Mod_LoadAliasFrame +================= +*/ +void *Mod_LoadAliasFrame( void *pin, maliasframedesc_t *frame ) +{ + daliasframe_t *pdaliasframe; + trivertex_t *pinframe; + int i; + + pdaliasframe = (daliasframe_t *)pin; + + Q_strncpy( frame->name, pdaliasframe->name, sizeof( frame->name )); + frame->firstpose = g_posenum; + frame->numposes = 1; + + for( i = 0; i < 3; i++ ) + { + frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i]; + frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i]; + } + + pinframe = (trivertex_t *)(pdaliasframe + 1); + + g_poseverts[g_posenum] = (trivertex_t *)pinframe; + pinframe += m_pAliasHeader->numverts; + g_posenum++; + + return (void *)pinframe; +} + +/* +================= +Mod_LoadAliasGroup +================= +*/ +void *Mod_LoadAliasGroup( void *pin, maliasframedesc_t *frame ) +{ + daliasgroup_t *pingroup; + int i, numframes; + daliasinterval_t *pin_intervals; + void *ptemp; + + pingroup = (daliasgroup_t *)pin; + numframes = pingroup->numframes; + + frame->firstpose = g_posenum; + frame->numposes = numframes; + + for( i = 0; i < 3; i++ ) + { + frame->bboxmin.v[i] = pingroup->bboxmin.v[i]; + frame->bboxmax.v[i] = pingroup->bboxmax.v[i]; + } + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + + // all the intervals are always equal 0.1 so we don't care about them + frame->interval = pin_intervals->interval; + pin_intervals += numframes; + ptemp = (void *)pin_intervals; + + for( i = 0; i < numframes; i++ ) + { + g_poseverts[g_posenum] = (trivertex_t *)((daliasframe_t *)ptemp + 1); + ptemp = (trivertex_t *)((daliasframe_t *)ptemp + 1) + m_pAliasHeader->numverts; + g_posenum++; + } + + return ptemp; +} + +/* +=============== +Mod_CreateSkinData +=============== +*/ +rgbdata_t *Mod_CreateSkinData( model_t *mod, byte *data, int width, int height ) +{ + static rgbdata_t skin; + char name[MAX_QPATH]; + int i; + model_t *loadmodel = gEngfuncs.Mod_GetCurrentLoadingModel(); + + skin.width = width; + skin.height = height; + skin.depth = 1; + skin.type = PF_INDEXED_24; + skin.flags = IMAGE_HAS_COLOR|IMAGE_QUAKEPAL; + skin.encode = DXT_ENCODE_DEFAULT; + skin.numMips = 1; + skin.buffer = data; + skin.palette = (byte *)gEngfuncs.CL_GetPaletteColor( 0 ); + skin.size = width * height; + + if( !gEngfuncs.Image_CustomPalette() ) + { + for( i = 0; i < skin.width * skin.height; i++ ) + { + if( data[i] > 224 && data[i] != 255 ) + { + SetBits( skin.flags, IMAGE_HAS_LUMA ); + break; + } + } + } + + COM_FileBase( loadmodel->name, name ); + + // for alias models only player can have remap textures + if( mod != NULL && !Q_stricmp( name, "player" )) + { + texture_t *tx = NULL; + int i, size; + + i = mod->numtextures; + mod->textures = (texture_t **)Mem_Realloc( mod->mempool, mod->textures, ( i + 1 ) * sizeof( texture_t* )); + size = width * height + 768; + tx = Mem_Calloc( mod->mempool, sizeof( *tx ) + size ); + mod->textures[i] = tx; + + Q_strncpy( tx->name, "DM_Skin", sizeof( tx->name )); + tx->anim_min = SHIRT_HUE_START; // topcolor start + tx->anim_max = SHIRT_HUE_END; // topcolor end + // bottomcolor start always equal is (topcolor end + 1) + tx->anim_total = PANTS_HUE_END;// bottomcolor end + + tx->width = width; + tx->height = height; + + // the pixels immediately follow the structures + memcpy( (tx+1), data, width * height ); + memcpy( ((byte *)(tx+1)+(width * height)), skin.palette, 768 ); + mod->numtextures++; // done + } + + // make an copy + return gEngfuncs.FS_CopyImage( &skin ); +} + +void *Mod_LoadSingleSkin( daliasskintype_t *pskintype, int skinnum, int size ) +{ + string name, lumaname; + string checkname; + rgbdata_t *pic; + model_t *loadmodel = gEngfuncs.Mod_GetCurrentLoadingModel(); + + Q_snprintf( name, sizeof( name ), "%s:frame%i", loadmodel->name, skinnum ); + Q_snprintf( lumaname, sizeof( lumaname ), "%s:luma%i", loadmodel->name, skinnum ); + Q_snprintf( checkname, sizeof( checkname ), "%s_%i.tga", loadmodel->name, skinnum ); + if( !gEngfuncs.FS_FileExists( checkname, false ) || ( pic = gEngfuncs.FS_LoadImage( checkname, NULL, 0 )) == NULL ) + pic = Mod_CreateSkinData( loadmodel, (byte *)(pskintype + 1), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight ); + + m_pAliasHeader->gl_texturenum[skinnum][0] = + m_pAliasHeader->gl_texturenum[skinnum][1] = + m_pAliasHeader->gl_texturenum[skinnum][2] = + m_pAliasHeader->gl_texturenum[skinnum][3] = GL_LoadTextureInternal( name, pic, 0 ); + gEngfuncs.FS_FreeImage( pic ); + + if( R_GetTexture( m_pAliasHeader->gl_texturenum[skinnum][0] )->flags & TF_HAS_LUMA ) + { + pic = Mod_CreateSkinData( NULL, (byte *)(pskintype + 1), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight ); + m_pAliasHeader->fb_texturenum[skinnum][0] = + m_pAliasHeader->fb_texturenum[skinnum][1] = + m_pAliasHeader->fb_texturenum[skinnum][2] = + m_pAliasHeader->fb_texturenum[skinnum][3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA ); + gEngfuncs.FS_FreeImage( pic ); + } + + return ((byte *)(pskintype + 1) + size); +} + +void *Mod_LoadGroupSkin( daliasskintype_t *pskintype, int skinnum, int size ) +{ + daliasskininterval_t *pinskinintervals; + daliasskingroup_t *pinskingroup; + string name, lumaname; + rgbdata_t *pic; + int i, j; + model_t *loadmodel = gEngfuncs.Mod_GetCurrentLoadingModel(); + + // animating skin group. yuck. + pskintype++; + pinskingroup = (daliasskingroup_t *)pskintype; + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + pskintype = (void *)(pinskinintervals + pinskingroup->numskins); + + for( i = 0; i < pinskingroup->numskins; i++ ) + { + Q_snprintf( name, sizeof( name ), "%s_%i_%i", loadmodel->name, skinnum, i ); + pic = Mod_CreateSkinData( loadmodel, (byte *)(pskintype), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight ); + m_pAliasHeader->gl_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( name, pic, 0 ); + gEngfuncs.FS_FreeImage( pic ); + + if( R_GetTexture( m_pAliasHeader->gl_texturenum[skinnum][i & 3] )->flags & TF_HAS_LUMA ) + { + Q_snprintf( lumaname, sizeof( lumaname ), "%s_%i_%i_luma", loadmodel->name, skinnum, i ); + pic = Mod_CreateSkinData( NULL, (byte *)(pskintype), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight ); + m_pAliasHeader->fb_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA ); + gEngfuncs.FS_FreeImage( pic ); + } + + pskintype = (daliasskintype_t *)((byte *)(pskintype) + size); + } + + for( j = i; i < 4; i++ ) + { + m_pAliasHeader->gl_texturenum[skinnum][i & 3] = m_pAliasHeader->gl_texturenum[skinnum][i - j]; + m_pAliasHeader->fb_texturenum[skinnum][i & 3] = m_pAliasHeader->fb_texturenum[skinnum][i - j]; + } + + return pskintype; +} + +/* +=============== +Mod_LoadAllSkins +=============== +*/ +void *Mod_LoadAllSkins( int numskins, daliasskintype_t *pskintype ) +{ + int i, size; + + if( numskins < 1 || numskins > MAX_SKINS ) + gEngfuncs.Host_Error( "Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins ); + + size = m_pAliasHeader->skinwidth * m_pAliasHeader->skinheight; + + for( i = 0; i < numskins; i++ ) + { + if( pskintype->type == ALIAS_SKIN_SINGLE ) + { + pskintype = (daliasskintype_t *)Mod_LoadSingleSkin( pskintype, i, size ); + } + else + { + pskintype = (daliasskintype_t *)Mod_LoadGroupSkin( pskintype, i, size ); + } + } + + return (void *)pskintype; +} + +//========================================================================= +/* +================= +Mod_CalcAliasBounds +================= +*/ +void Mod_CalcAliasBounds( model_t *mod ) +{ + int i, j, k; + float radius; + float dist; + vec3_t v; + + ClearBounds( mod->mins, mod->maxs ); + radius = 0.0f; + + // process verts + for( i = 0; i < m_pAliasHeader->numposes; i++ ) + { + for( j = 0; j < m_pAliasHeader->numverts; j++ ) + { + for( k = 0; k < 3; k++ ) + v[k] = g_poseverts[i][j].v[k] * m_pAliasHeader->scale[k] + m_pAliasHeader->scale_origin[k]; + + AddPointToBounds( v, mod->mins, mod->maxs ); + dist = DotProduct( v, v ); + + if( radius < dist ) + radius = dist; + } + } + + mod->radius = sqrt( radius ); +} + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded ) +{ + daliashdr_t *pinmodel; + stvert_t *pinstverts; + dtriangle_t *pintriangles; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + int i, j, size; + + if( loaded ) *loaded = false; + pinmodel = (daliashdr_t *)buffer; + i = pinmodel->version; + + if( i != ALIAS_VERSION ) + { + gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION ); + return; + } + + if( pinmodel->numverts <= 0 || pinmodel->numtris <= 0 || pinmodel->numframes <= 0 ) + return; // how to possible is make that? + + mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name )); + + // allocate space for a working header, plus all the data except the frames, + // skin and group info + size = sizeof( aliashdr_t ) + (pinmodel->numframes - 1) * sizeof( maliasframedesc_t ); + + m_pAliasHeader = Mem_Calloc( mod->mempool, size ); + mod->flags = pinmodel->flags; // share effects flags + + // endian-adjust and copy the data, starting with the alias model header + m_pAliasHeader->boundingradius = pinmodel->boundingradius; + m_pAliasHeader->numskins = pinmodel->numskins; + m_pAliasHeader->skinwidth = pinmodel->skinwidth; + m_pAliasHeader->skinheight = pinmodel->skinheight; + m_pAliasHeader->numverts = pinmodel->numverts; + m_pAliasHeader->numtris = pinmodel->numtris; + m_pAliasHeader->numframes = pinmodel->numframes; + + if( m_pAliasHeader->numverts > MAXALIASVERTS ) + { + gEngfuncs.Con_DPrintf( S_ERROR "model %s has too many vertices\n", mod->name ); + return; + } + + m_pAliasHeader->size = pinmodel->size; +// mod->synctype = pinmodel->synctype; + mod->numframes = m_pAliasHeader->numframes; + + for( i = 0; i < 3; i++ ) + { + m_pAliasHeader->scale[i] = pinmodel->scale[i]; + m_pAliasHeader->scale_origin[i] = pinmodel->scale_origin[i]; + m_pAliasHeader->eyeposition[i] = pinmodel->eyeposition[i]; + } + + // load the skins + pskintype = (daliasskintype_t *)&pinmodel[1]; + pskintype = Mod_LoadAllSkins( m_pAliasHeader->numskins, pskintype ); + + // load base s and t vertices + pinstverts = (stvert_t *)pskintype; + + for( i = 0; i < m_pAliasHeader->numverts; i++ ) + { + g_stverts[i].onseam = pinstverts[i].onseam; + g_stverts[i].s = pinstverts[i].s; + g_stverts[i].t = pinstverts[i].t; + } + + // load triangle lists + pintriangles = (dtriangle_t *)&pinstverts[m_pAliasHeader->numverts]; + + for( i = 0; i < m_pAliasHeader->numtris; i++ ) + { + g_triangles[i].facesfront = pintriangles[i].facesfront; + + for( j = 0; j < 3; j++ ) + g_triangles[i].vertindex[j] = pintriangles[i].vertindex[j]; + } + + // load the frames + pframetype = (daliasframetype_t *)&pintriangles[m_pAliasHeader->numtris]; + g_posenum = 0; + + for( i = 0; i < m_pAliasHeader->numframes; i++ ) + { + aliasframetype_t frametype = pframetype->type; + + if( frametype == ALIAS_SINGLE ) + pframetype = (daliasframetype_t *)Mod_LoadAliasFrame( pframetype + 1, &m_pAliasHeader->frames[i] ); + else pframetype = (daliasframetype_t *)Mod_LoadAliasGroup( pframetype + 1, &m_pAliasHeader->frames[i] ); + } + + m_pAliasHeader->numposes = g_posenum; + + Mod_CalcAliasBounds( mod ); + mod->type = mod_alias; + + // build the draw lists + GL_MakeAliasModelDisplayLists( mod ); + + // move the complete, relocatable alias model to the cache + gEngfuncs.Mod_GetCurrentLoadingModel()->cache.data = m_pAliasHeader; + + if( loaded ) *loaded = true; // done +} + +void Mod_AliasUnloadTextures( void *data ) +{ + aliashdr_t *palias; + int i, j; + + palias = data; + if( !palias ) return; // already freed + + for( i = 0; i < MAX_SKINS; i++ ) + { + if( !palias->gl_texturenum[i][0] ) + break; + + for( j = 0; j < 4; j++ ) + { + GL_FreeTexture( palias->gl_texturenum[i][j] ); + GL_FreeTexture( palias->fb_texturenum[i][j] ); + } + } +} + +/* +============================================================= + + ALIAS MODELS + +============================================================= +*/ + +/* +=============== +R_AliasDynamicLight + +similar to R_StudioDynamicLight +=============== +*/ +void R_AliasDynamicLight( cl_entity_t *ent, alight_t *plight ) +{ + movevars_t *mv = gEngfuncs.pfnGetMoveVars(); + vec3_t lightDir, vecSrc, vecEnd; + vec3_t origin, dist, finalLight; + float add, radius, total; + colorVec light; + uint lnum; + dlight_t *dl; + + if( !plight || !ent ) + return; + + if( !RI.drawWorld || r_fullbright->value || FBitSet( ent->curstate.effects, EF_FULLBRIGHT )) + { + plight->shadelight = 0; + plight->ambientlight = 192; + + VectorSet( plight->plightvec, 0.0f, 0.0f, -1.0f ); + VectorSet( plight->color, 1.0f, 1.0f, 1.0f ); + return; + } + + // determine plane to get lightvalues from: ceil or floor + if( FBitSet( ent->curstate.effects, EF_INVLIGHT )) + VectorSet( lightDir, 0.0f, 0.0f, 1.0f ); + else VectorSet( lightDir, 0.0f, 0.0f, -1.0f ); + + VectorCopy( ent->origin, origin ); + + VectorSet( vecSrc, origin[0], origin[1], origin[2] - lightDir[2] * 8.0f ); + light.r = light.g = light.b = light.a = 0; + + if(( mv->skycolor_r + mv->skycolor_g + mv->skycolor_b ) != 0 ) + { + msurface_t *psurf = NULL; + pmtrace_t trace; + + if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_WRITE_LARGE_COORD )) + { + vecEnd[0] = origin[0] - mv->skyvec_x * 65536.0f; + vecEnd[1] = origin[1] - mv->skyvec_y * 65536.0f; + vecEnd[2] = origin[2] - mv->skyvec_z * 65536.0f; + } + else + { + vecEnd[0] = origin[0] - mv->skyvec_x * 8192.0f; + vecEnd[1] = origin[1] - mv->skyvec_y * 8192.0f; + vecEnd[2] = origin[2] - mv->skyvec_z * 8192.0f; + } + + trace = gEngfuncs.CL_TraceLine( vecSrc, vecEnd, PM_STUDIO_IGNORE ); + if( trace.ent > 0 ) psurf = gEngfuncs.EV_TraceSurface( trace.ent, vecSrc, vecEnd ); + else psurf = gEngfuncs.EV_TraceSurface( 0, vecSrc, vecEnd ); + + if( psurf && FBitSet( psurf->flags, SURF_DRAWSKY )) + { + VectorSet( lightDir, mv->skyvec_x, mv->skyvec_y, mv->skyvec_z ); + + light.r = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_r, 255 )); + light.g = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_g, 255 )); + light.b = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_b, 255 )); + } + } + + if(( light.r + light.g + light.b ) == 0 ) + { + colorVec gcolor; + float grad[4]; + + VectorScale( lightDir, 2048.0f, vecEnd ); + VectorAdd( vecEnd, vecSrc, vecEnd ); + + light = R_LightVec( vecSrc, vecEnd, g_alias.lightspot, g_alias.lightvec ); + + if( VectorIsNull( g_alias.lightvec )) + { + vecSrc[0] -= 16.0f; + vecSrc[1] -= 16.0f; + vecEnd[0] -= 16.0f; + vecEnd[1] -= 16.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[0] += 32.0f; + vecEnd[0] += 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[1] += 32.0f; + vecEnd[1] += 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[0] -= 32.0f; + vecEnd[0] -= 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3]; + lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3]; + VectorNormalize( lightDir ); + } + else + { + VectorCopy( g_alias.lightvec, lightDir ); + } + } + + VectorSet( finalLight, light.r, light.g, light.b ); + ent->cvFloorColor = light; + + total = Q_max( Q_max( light.r, light.g ), light.b ); + if( total == 0.0f ) total = 1.0f; + + // scale lightdir by light intentsity + VectorScale( lightDir, total, lightDir ); + + for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + { + dl = gEngfuncs.GetDynamicLight( lnum ); + + if( dl->die < g_alias.time || !r_dynamic->value ) + continue; + + VectorSubtract( origin, dl->origin, dist ); + + radius = VectorLength( dist ); + add = dl->radius - radius; + + if( add > 0.0f ) + { + total += add; + + if( radius > 1.0f ) + VectorScale( dist, ( add / radius ), dist ); + else VectorScale( dist, add, dist ); + + VectorAdd( lightDir, dist, lightDir ); + + finalLight[0] += gEngfuncs.LightToTexGamma( dl->color.r ) * ( add / 256.0f ) * 2.0f; + finalLight[1] += gEngfuncs.LightToTexGamma( dl->color.g ) * ( add / 256.0f ) * 2.0f; + finalLight[2] += gEngfuncs.LightToTexGamma( dl->color.b ) * ( add / 256.0f ) * 2.0f; + } + } + + VectorScale( lightDir, 0.9f, lightDir ); + + plight->shadelight = VectorLength( lightDir ); + plight->ambientlight = total - plight->shadelight; + + total = Q_max( Q_max( finalLight[0], finalLight[1] ), finalLight[2] ); + + if( total > 0.0f ) + { + plight->color[0] = finalLight[0] * ( 1.0f / total ); + plight->color[1] = finalLight[1] * ( 1.0f / total ); + plight->color[2] = finalLight[2] * ( 1.0f / total ); + } + else VectorSet( plight->color, 1.0f, 1.0f, 1.0f ); + + if( plight->ambientlight > 128 ) + plight->ambientlight = 128; + + if( plight->ambientlight + plight->shadelight > 255 ) + plight->shadelight = 255 - plight->ambientlight; + + VectorNormalize2( lightDir, plight->plightvec ); +} + +/* +=============== +R_AliasSetupLighting + +=============== +*/ +void R_AliasSetupLighting( alight_t *plight ) +{ + if( !m_pAliasHeader || !plight ) + return; + + g_alias.ambientlight = plight->ambientlight; + g_alias.shadelight = plight->shadelight; + VectorCopy( plight->plightvec, g_alias.lightvec ); + VectorCopy( plight->color, g_alias.lightcolor ); + + // transform back to local space + Matrix4x4_VectorIRotate( RI.objectMatrix, g_alias.lightvec, g_alias.lightvec_local ); + VectorNormalize( g_alias.lightvec_local ); +} + +/* +=============== +R_AliasLighting + +=============== +*/ +void R_AliasLighting( float *lv, const vec3_t normal ) +{ + float illum = g_alias.ambientlight; + float r, lightcos; + + lightcos = DotProduct( normal, g_alias.lightvec_local ); // -1 colinear, 1 opposite + if( lightcos > 1.0f ) lightcos = 1.0f; + + illum += g_alias.shadelight; + + r = SHADE_LAMBERT; + + // do modified hemispherical lighting + if( r <= 1.0f ) + { + r += 1.0f; + lightcos = (( r - 1.0f ) - lightcos) / r; + if( lightcos > 0.0f ) + illum += g_alias.shadelight * lightcos; + } + else + { + lightcos = (lightcos + ( r - 1.0f )) / r; + if( lightcos > 0.0f ) + illum -= g_alias.shadelight * lightcos; + } + + illum = Q_max( illum, 0.0f ); + illum = Q_min( illum, 255.0f ); + *lv = illum * (1.0f / 255.0f); +} + +/* +=============== +R_AliasSetRemapColors + +=============== +*/ +void R_AliasSetRemapColors( int newTop, int newBottom ) +{ + gEngfuncs.CL_AllocRemapInfo( RI.currententity, newTop, newBottom ); + + if( gEngfuncs.CL_GetRemapInfoForEntity( RI.currententity )) + { + gEngfuncs.CL_UpdateRemapInfo( RI.currententity, newTop, newBottom ); + m_fDoRemap = true; + } +} + +/* +============= +GL_DrawAliasFrame +============= +*/ +void GL_DrawAliasFrame( aliashdr_t *paliashdr ) +{ + float lv_tmp; + trivertex_t *verts0; + trivertex_t *verts1; + vec3_t vert, norm; + int *order; + int count; + + verts0 = verts1 = paliashdr->posedata; + verts0 += g_alias.oldpose * paliashdr->poseverts; + verts1 += g_alias.newpose * paliashdr->poseverts; + order = paliashdr->commands; + + while( 1 ) + { + // get the vertex count and primitive type + count = *order++; + if( !count ) break; // done + + int prim; + if( count < 0 ) + { + prim = GU_TRIANGLE_FAN; + count = -count; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )sceGuGetMemory( sizeof( gu_vert_ftcv_t ) * count ); + for( int index = 0; index < count; index++ ) + { + out[index].u = ((float *)order)[0]; + out[index].v = ((float *)order)[1]; + order += 2; + + VectorLerp( m_bytenormals[verts0->lightnormalindex], g_alias.lerpfrac, m_bytenormals[verts1->lightnormalindex], norm ); + VectorNormalize( norm ); + R_AliasLighting( &lv_tmp, norm ); + out[index].c = GUCOLOR4F( g_alias.lightcolor[0] * lv_tmp, g_alias.lightcolor[1] * lv_tmp, g_alias.lightcolor[2] * lv_tmp, tr.blend ); + VectorLerp( verts0->v, g_alias.lerpfrac, verts1->v, vert ); + out[index].x = vert[0]; + out[index].y = vert[1]; + out[index].z = vert[2]; + verts0++, verts1++; + } + sceGuDrawArray( prim, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, count, 0, out ); + } +} + +/* +============= +GL_DrawAliasShadow +============= +*/ +void GL_DrawAliasShadow( aliashdr_t *paliashdr ) +{ + trivertex_t *verts0; + trivertex_t *verts1; + float vec_x, vec_y; + vec3_t av, point; + int *order; + float height; + int count; + + if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW )) + return; + + if( glState.stencilEnabled ) + sceGuEnable( GU_STENCIL_TEST ); + + height = g_alias.lightspot[2] + 1.0f; + vec_x = -g_alias.lightvec[0] * 8.0f; + vec_y = -g_alias.lightvec[1] * 8.0f; + + r_stats.c_alias_polys += paliashdr->numtris; + + verts0 = verts1 = paliashdr->posedata; + verts0 += g_alias.oldpose * paliashdr->poseverts; + verts1 += g_alias.newpose * paliashdr->poseverts; + order = paliashdr->commands; + + while( 1 ) + { + // get the vertex count and primitive type + count = *order++; + if( !count ) break; // done + + int prim; + if( count < 0 ) + { + prim = GU_TRIANGLE_FAN; + count = -count; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * count ); + for( int index = 0; index < count; index++ ) + { + // texture coordinates come from the draw list + // (skipped for shadows) pglTexCoord2fv ((float *)order); + order += 2; + + // normals and vertexes come from the frame list + VectorLerp( verts0->v, g_alias.lerpfrac, verts1->v, av ); + point[0] = av[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; + point[1] = av[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; + point[2] = av[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; + Matrix3x4_VectorTransform( RI.objectMatrix, point, av ); + + point[0] = av[0] - (vec_x * ( av[2] - g_alias.lightspot[2] )); + point[1] = av[1] - (vec_y * ( av[2] - g_alias.lightspot[2] )); + point[2] = g_alias.lightspot[2] + 1.0f; + + out[index].x = point[0]; + out[index].y = point[1]; + out[index].z = point[2]; + + verts0++, verts1++; + } + sceGuDrawArray( prim, GU_VERTEX_32BITF, count, 0, out ); + } + + if( glState.stencilEnabled ) + sceGuDisable( GU_STENCIL_TEST ); +} + +/* +==================== +R_AliasLerpMovement + +==================== +*/ +void R_AliasLerpMovement( cl_entity_t *e ) +{ + float f = 1.0f; + + // don't do it if the goalstarttime hasn't updated in a while. + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + if( g_alias.interpolate && ( g_alias.time < e->curstate.animtime + 1.0f ) && ( e->curstate.animtime != e->latched.prevanimtime )) + f = ( g_alias.time - e->curstate.animtime ) / ( e->curstate.animtime - e->latched.prevanimtime ); + + if( ENGINE_GET_PARM( PARM_PLAYING_DEMO ) == DEMO_QUAKE1 ) + f = f + 1.0f; + + g_alias.lerpfrac = bound( 0.0f, f, 1.0f ); + + if( e->player || e->curstate.movetype != MOVETYPE_STEP ) + return; // monsters only + + // Con_Printf( "%4.2f %.2f %.2f\n", f, e->curstate.animtime, g_alias.time ); + VectorLerp( e->latched.prevorigin, f, e->curstate.origin, e->origin ); + + if( !VectorCompareEpsilon( e->curstate.angles, e->latched.prevangles, ON_EPSILON )) + { + vec4_t q, q1, q2; + + AngleQuaternion( e->curstate.angles, q1, false ); + AngleQuaternion( e->latched.prevangles, q2, false ); + QuaternionSlerp( q2, q1, f, q ); + QuaternionAngle( q, e->angles ); + } + else VectorCopy( e->curstate.angles, e->angles ); + + // NOTE: this completely over control about angles and don't broke interpolation + if( FBitSet( e->model->flags, ALIAS_ROTATE )) + e->angles[1] = anglemod( 100.0f * g_alias.time ); +} + +/* +================= +R_SetupAliasFrame + +================= +*/ +void R_SetupAliasFrame( cl_entity_t *e, aliashdr_t *paliashdr ) +{ + int newpose, oldpose; + int newframe, oldframe; + int numposes, cycle; + float interval; + + oldframe = e->latched.prevframe; + newframe = e->curstate.frame; + + if( newframe < 0 ) + { + newframe = 0; + } + else if( newframe >= paliashdr->numframes ) + { + if( newframe > paliashdr->numframes ) + gEngfuncs.Con_Reportf( S_WARN "R_GetAliasFrame: no such frame %d (%s)\n", newframe, e->model->name ); + newframe = paliashdr->numframes - 1; + } + + if(( oldframe >= paliashdr->numframes ) || ( oldframe < 0 )) + oldframe = newframe; + + numposes = paliashdr->frames[newframe].numposes; + + if( numposes > 1 ) + { + oldpose = newpose = paliashdr->frames[newframe].firstpose; + interval = 1.0f / paliashdr->frames[newframe].interval; + cycle = (int)(g_alias.time * interval); + oldpose += (cycle + 0) % numposes; // lerpframe from + newpose += (cycle + 1) % numposes; // lerpframe to + g_alias.lerpfrac = ( g_alias.time * interval ); + g_alias.lerpfrac -= (int)g_alias.lerpfrac; + } + else + { + oldpose = paliashdr->frames[oldframe].firstpose; + newpose = paliashdr->frames[newframe].firstpose; + } + + g_alias.oldpose = oldpose; + g_alias.newpose = newpose; + + GL_DrawAliasFrame( paliashdr ); +} + +/* +=============== +R_StudioDrawAbsBBox + +=============== +*/ +static void R_AliasDrawAbsBBox( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax ) +{ + vec3_t p[8]; + int i; + + // looks ugly, skip + if( r_drawentities->value != 5 || e == gEngfuncs.GetViewModel() ) + return; + + // compute a full bounding box + for( i = 0; i < 8; i++ ) + { + p[i][0] = ( i & 1 ) ? absmin[0] : absmax[0]; + p[i][1] = ( i & 2 ) ? absmin[1] : absmax[1]; + p[i][2] = ( i & 4 ) ? absmin[2] : absmax[2]; + } + + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + sceGuColor( GUCOLOR4F( 0.5f, 0.5f, 1.0f, 0.5f ) ); + TriRenderMode( kRenderTransAdd ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + unsigned int color = getTriBrightness( g_alias.shadelight / 255.0f ); + + gu_vert_fcv_t* const out = ( gu_vert_fcv_t* )sceGuGetMemory( sizeof( gu_vert_fcv_t ) * 24 ); + for( i = 0; i < 6; i++ ) + { + out[i * 4 + 0].c = color; + out[i * 4 + 0].x = p[boxpnt[i][0]][0]; + out[i * 4 + 0].y = p[boxpnt[i][0]][1]; + out[i * 4 + 0].z = p[boxpnt[i][0]][2]; + out[i * 4 + 1].c = color; + out[i * 4 + 1].x = p[boxpnt[i][1]][0]; + out[i * 4 + 1].y = p[boxpnt[i][1]][1]; + out[i * 4 + 1].z = p[boxpnt[i][1]][2]; + out[i * 4 + 2].c = color; + out[i * 4 + 2].x = p[boxpnt[i][2]][0]; + out[i * 4 + 2].y = p[boxpnt[i][2]][1]; + out[i * 4 + 2].z = p[boxpnt[i][2]][2]; + out[i * 4 + 3].c = color; + out[i * 4 + 3].x = p[boxpnt[i][3]][0]; + out[i * 4 + 3].y = p[boxpnt[i][3]][1]; + out[i * 4 + 3].z = p[boxpnt[i][3]][2]; + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 24, 0, out ); + + TriRenderMode( kRenderNormal ); +} + +static void R_AliasDrawLightTrace( cl_entity_t *e ) +{ + if( r_drawentities->value == 7 ) + { + vec3_t origin; + + sceGuDisable( GU_TEXTURE_2D ); + sceGuDisable( GU_DEPTH_TEST ); + + gu_vert_fcv_t* out = ( gu_vert_fcv_t* )sceGuGetMemory( sizeof( gu_vert_fcv_t ) * 4 ); + out[0].c = GU_COLOR( 1.0f, 0.5f, 0.0f, 1.0f ); + out[0].x = e->origin[0]; + out[0].y = e->origin[1]; + out[0].z = e->origin[2]; + out[1].c = out[0].c; + out[1].x = g_alias.lightspot[0]; + out[1].y = g_alias.lightspot[1]; + out[1].z = g_alias.lightspot[2]; + VectorMA( g_alias.lightspot, -64.0f, g_alias.lightvec, origin ); + out[2].c = GU_COLOR( 0.0f, 0.5f, 1.0f, 1.0f ); + out[2].x = g_alias.lightspot[0]; + out[2].y = g_alias.lightspot[1]; + out[2].z = g_alias.lightspot[2]; + out[3].c = out[2].c; + out[3].x = origin[0]; + out[3].y = origin[1]; + out[3].z = origin[2]; + sceGuDrawArray( GU_LINES, GU_COLOR_8888 | GU_VERTEX_32BITF, 4, 0, out ); + + out = ( gu_vert_fcv_t* )sceGuGetMemory( sizeof( gu_vert_fcv_t ) ); + out->c = GU_COLOR( 1.0f, 0.0f, 0.0f, 1.0f ); + out->x = g_alias.lightspot[0]; + out->y = g_alias.lightspot[1]; + out->z = g_alias.lightspot[2]; + sceGuDrawArray( GU_POINTS, GU_COLOR_8888 | GU_VERTEX_32BITF, 1, 0, out ); + + sceGuEnable( GU_DEPTH_TEST ); + sceGuEnable( GU_TEXTURE_2D ); + } +} + +/* +================ +R_AliasSetupTimings + +init current time for a given model +================ +*/ +static void R_AliasSetupTimings( void ) +{ + if( RI.drawWorld ) + { + // synchronize with server time + g_alias.time = gpGlobals->time; + } + else + { + // menu stuff + g_alias.time = gpGlobals->realtime; + } + + m_fDoRemap = false; +} + +/* +================= +R_DrawAliasModel + +================= +*/ +void R_DrawAliasModel( cl_entity_t *e ) +{ + model_t *clmodel; + vec3_t absmin, absmax; + remap_info_t *pinfo = NULL; + int anim, skin; + alight_t lighting; + player_info_t *playerinfo; + vec3_t dir, angles; + + clmodel = RI.currententity->model; + + VectorAdd( e->origin, clmodel->mins, absmin ); + VectorAdd( e->origin, clmodel->maxs, absmax ); + + if( R_CullModel( e, absmin, absmax )) + return; + + // + // locate the proper data + // + m_pAliasHeader = (aliashdr_t *)gEngfuncs.Mod_Extradata( mod_alias, RI.currententity->model ); + if( !m_pAliasHeader ) return; + + // init time + R_AliasSetupTimings(); + + // angles will be modify below keep original + VectorCopy( e->angles, angles ); + + R_AliasLerpMovement( e ); + + if( !FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_COMPENSATE_QUAKE_BUG )) + e->angles[PITCH] = -e->angles[PITCH]; // stupid quake bug + + // don't rotate clients, only aim + if( e->player ) e->angles[PITCH] = 0.0f; + + // + // get lighting information + // + lighting.plightvec = dir; + R_AliasDynamicLight( e, &lighting ); + + r_stats.c_alias_polys += m_pAliasHeader->numtris; + r_stats.c_alias_models_drawn++; + + // + // draw all the triangles + // + + R_RotateForEntity( e ); + + // model and frame independant + R_AliasSetupLighting( &lighting ); + GL_SetRenderMode( e->curstate.rendermode ); + + // setup remapping only for players + if( e->player && ( playerinfo = pfnPlayerInfo( e->curstate.number - 1 )) != NULL ) + { + // get remap colors + int topcolor = bound( 0, playerinfo->topcolor, 13 ); + int bottomcolor = bound( 0, playerinfo->bottomcolor, 13 ); + R_AliasSetRemapColors( topcolor, bottomcolor ); + } + + if( tr.fFlipViewModel ) + { + const ScePspFVector3 translation = + { + m_pAliasHeader->scale_origin[0], + -m_pAliasHeader->scale_origin[1], + m_pAliasHeader->scale_origin[2] + }; + sceGumTranslate( &translation ); + + const ScePspFVector3 scaling = + { + m_pAliasHeader->scale[0], + -m_pAliasHeader->scale[1], + m_pAliasHeader->scale[2] + }; + sceGumScale( &scaling ); + } + else + { + const ScePspFVector3 translation = + { + m_pAliasHeader->scale_origin[0], + m_pAliasHeader->scale_origin[1], + m_pAliasHeader->scale_origin[2] + }; + sceGumTranslate( &translation ); + + const ScePspFVector3 scaling = + { + m_pAliasHeader->scale[0], + m_pAliasHeader->scale[1], + m_pAliasHeader->scale[2] + }; + sceGumScale( &scaling ); + } + + + anim = (int)( g_alias.time * 10 ) & 3; + skin = bound( 0, RI.currententity->curstate.skin, m_pAliasHeader->numskins - 1 ); + if( m_fDoRemap ) pinfo = gEngfuncs.CL_GetRemapInfoForEntity( e ); + + if( r_lightmap->value && !r_fullbright->value ) + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + else if( pinfo != NULL && pinfo->textures[skin] != 0 ) + GL_Bind( XASH_TEXTURE0, pinfo->textures[skin] ); // FIXME: allow remapping for skingroups someday + else + { + GL_Bind( XASH_TEXTURE0, m_pAliasHeader->gl_texturenum[skin][anim] ); + + if( FBitSet( R_GetTexture( m_pAliasHeader->gl_texturenum[skin][anim] )->flags, TF_HAS_ALPHA )) + { + sceGuEnable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, 0x00, 0xff ); + tr.blend = 1.0f; + } + } + + sceGumUpdateMatrix(); //Apply a matrix transformation + + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + sceGuShadeModel( GU_SMOOTH ); + R_SetupAliasFrame( e, m_pAliasHeader ); + + sceGuShadeModel( GU_FLAT ); + + R_LoadIdentity(); + + // get lerped origin + VectorAdd( e->origin, clmodel->mins, absmin ); + VectorAdd( e->origin, clmodel->maxs, absmax ); + + R_AliasDrawAbsBBox( e, absmin, absmax ); + R_AliasDrawLightTrace( e ); + + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuDisable( GU_ALPHA_TEST ); + if( r_shadows.value ) + { + // need to compute transformation matrix + Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f ); + sceGuDisable( GU_TEXTURE_2D ); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + sceGuColor( GUCOLOR4F( 0.0f, 0.0f, 0.0f, 0.5f ) ); + sceGuDepthFunc( GU_LESS ); + + GL_DrawAliasShadow( m_pAliasHeader ); + + sceGuDepthFunc( GU_LEQUAL ); + sceGuEnable( GU_TEXTURE_2D ); + sceGuDisable( GU_BLEND ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, 1.0f ) ); + R_LoadIdentity(); + } + + // restore original angles + VectorCopy( angles, e->angles ); +} + +//================================================================================== diff --git a/ref_gu/gu_backend.c b/ref_gu/gu_backend.c new file mode 100644 index 00000000..b8c34cea --- /dev/null +++ b/ref_gu/gu_backend.c @@ -0,0 +1,663 @@ +/* +gl_backend.c - rendering backend +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + + +#include "gu_local.h" +#include "xash3d_mathlib.h" + +char r_speeds_msg[MAX_SYSPATH]; +ref_speeds_t r_stats; // r_speeds counters + +/* +=============== +R_SpeedsMessage +=============== +*/ +qboolean R_SpeedsMessage( char *out, size_t size ) +{ + if( gEngfuncs.drawFuncs->R_SpeedsMessage != NULL ) + { + if( gEngfuncs.drawFuncs->R_SpeedsMessage( out, size )) + return true; + // otherwise pass to default handler + } + + if( r_speeds->value <= 0 ) return false; + if( !out || !size ) return false; + + Q_strncpy( out, r_speeds_msg, size ); + + return true; +} + +/* +============== +R_Speeds_Printf + +helper to print into r_speeds message +============== +*/ +void R_Speeds_Printf( const char *msg, ... ) +{ + va_list argptr; + char text[2048]; + + va_start( argptr, msg ); + Q_vsprintf( text, msg, argptr ); + va_end( argptr ); + + Q_strncat( r_speeds_msg, text, sizeof( r_speeds_msg )); +} + +/* +============== +GL_BackendStartFrame +============== +*/ +void GL_BackendStartFrame( void ) +{ + r_speeds_msg[0] = '\0'; +} + +/* +============== +GL_BackendEndFrame +============== +*/ +void GL_BackendEndFrame( void ) +{ + mleaf_t *curleaf; + + if( r_speeds->value <= 0 || !RI.drawWorld ) + return; + + if( !RI.viewleaf ) + curleaf = WORLDMODEL->leafs; + else curleaf = RI.viewleaf; + + R_Speeds_Printf( "Renderer: ^1Engine^7\n\n" ); + + switch( (int)r_speeds->value ) + { + case 1: + Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i wpoly, %3i apoly\n%3i epoly, %3i spoly", + r_stats.c_world_polys, r_stats.c_alias_polys, r_stats.c_studio_polys, r_stats.c_sprite_polys ); + break; + case 2: + R_Speeds_Printf( "visible leafs:\n%3i leafs\ncurrent leaf %3i\n", r_stats.c_world_leafs, curleaf - WORLDMODEL->leafs ); + R_Speeds_Printf( "ReciusiveWorldNode: %3lf secs\nDrawTextureChains %lf\n", r_stats.t_world_node, r_stats.t_world_draw ); + break; + case 3: + Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i alias models drawn\n%3i studio models drawn\n%3i sprites drawn", + r_stats.c_alias_models_drawn, r_stats.c_studio_models_drawn, r_stats.c_sprite_models_drawn ); + break; + case 4: + Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i static entities\n%3i normal entities\n%3i server entities", + r_numStatics, r_numEntities - r_numStatics, ENGINE_GET_PARM( PARM_NUMENTITIES )); + break; + case 5: + Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i tempents\n%3i viewbeams\n%3i particles", + r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count ); + break; + } + + memset( &r_stats, 0, sizeof( r_stats )); +} + +/* +================= +GL_LoadTexMatrix +================= +*/ +void GL_LoadTexMatrix( const matrix4x4 m ) +{ + sceGumMatrixMode( GU_TEXTURE ); + GL_LoadMatrix( m ); + sceGumUpdateMatrix(); + + glState.texIdentityMatrix = false; +} + +/* +================= +GL_LoadTexMatrixExt +================= +*/ +void GL_LoadTexMatrixExt( const float *glmatrix ) +{ + Assert( glmatrix != NULL ); + + sceGumMatrixMode( GU_TEXTURE ); + sceGumLoadMatrix( ( const ScePspFMatrix4 * ) glmatrix ); + sceGumUpdateMatrix(); + + glState.texIdentityMatrix = false; +} + +/* +================= +GL_LoadMatrix +================= +*/ +void GL_LoadMatrix( const matrix4x4 source ) +{ + float dest[16]; + + Matrix4x4_ToArrayFloatGL( source, dest ); + sceGumLoadMatrix( ( const ScePspFMatrix4 * ) dest ); +} + +/* +================= +GL_LoadIdentityTexMatrix +================= +*/ +void GL_LoadIdentityTexMatrix( void ) +{ + if( glState.texIdentityMatrix ) + return; + + sceGumMatrixMode( GU_TEXTURE ); + sceGumLoadIdentity(); + sceGumUpdateMatrix(); + + glState.texIdentityMatrix = true; +} + +/* +================= +GL_SelectTexture +================= +*/ +void GL_SelectTexture( GLint tmu ) +{ + +} + +/* +============== +GL_DisableAllTexGens +============== +*/ +void GL_DisableAllTexGens( void ) +{ + +} + +/* +============== +GL_CleanUpTextureUnits +============== +*/ +void GL_CleanUpTextureUnits( int last ) +{ + +} + +/* +============== +GL_CleanupAllTextureUnits +============== +*/ +void GL_CleanupAllTextureUnits( void ) +{ + +} + +/* +================= +GL_MultiTexCoord2f +================= +*/ +void GL_MultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t ) +{ + +} + +/* +================= +GL_TextureTarget +================= +*/ +void GL_TextureTarget( uint target ) +{ + +} + +/* +================= +GL_TexGen +================= +*/ +void GL_TexGen( GLenum coord, GLenum mode ) +{ + +} + +/* +================= +GL_SetTexCoordArrayMode +================= +*/ +void GL_SetTexCoordArrayMode( GLenum mode ) +{ + +} + +/* +================= +GL_Cull +================= +*/ +void GL_Cull( GLenum cull ) +{ + if( glState.faceCull == cull ) + return; + + if( !cull ) + { + sceGuDisable( GU_CULL_FACE ); + glState.faceCull = 0; + return; + } + + sceGuEnable( GU_CULL_FACE ); + sceGuFrontFace( cull - 1 ); + glState.faceCull = cull; +} + +void GL_SetRenderMode( int mode ) +{ + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + switch( mode ) + { + case kRenderNormal: + default: + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + break; + case kRenderTransColor: + case kRenderTransTexture: + sceGuEnable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + break; + case kRenderTransAlpha: + sceGuDisable( GU_BLEND ); + sceGuEnable( GU_ALPHA_TEST ); + break; + case kRenderGlow: + case kRenderTransAdd: + sceGuEnable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + break; + } +} + +/* +============================================================================== + +SCREEN SHOTS + +============================================================================== +*/ +// used for 'env' and 'sky' shots +typedef struct envmap_s +{ + vec3_t angles; + int flags; +} envmap_t; + +const envmap_t r_skyBoxInfo[6] = +{ +{{ 0, 270, 180}, IMAGE_FLIP_X }, +{{ 0, 90, 180}, IMAGE_FLIP_X }, +{{ -90, 0, 180}, IMAGE_FLIP_X }, +{{ 90, 0, 180}, IMAGE_FLIP_X }, +{{ 0, 0, 180}, IMAGE_FLIP_X }, +{{ 0, 180, 180}, IMAGE_FLIP_X }, +}; + +const envmap_t r_envMapInfo[6] = +{ +{{ 0, 0, 90}, 0 }, +{{ 0, 180, -90}, 0 }, +{{ 0, 90, 0}, 0 }, +{{ 0, 270, 180}, 0 }, +{{-90, 180, -90}, 0 }, +{{ 90, 0, 90}, 0 } +}; + +qboolean VID_ScreenShot( const char *filename, int shot_type ) +{ +#if 0 + rgbdata_t *r_shot; + uint flags = IMAGE_FLIP_Y; + int width = 0, height = 0; + qboolean result; + + r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t )); + r_shot->width = (gpGlobals->width + 3) & ~3; + r_shot->height = (gpGlobals->height + 3) & ~3; + r_shot->flags = IMAGE_HAS_COLOR; + r_shot->type = PF_RGB_24; + r_shot->size = r_shot->width * r_shot->height * gEngfuncs.Image_GetPFDesc( r_shot->type )->bpp; + r_shot->palette = NULL; + r_shot->buffer = Mem_Malloc( r_temppool, r_shot->size ); + + // get screen frame + pglReadPixels( 0, 0, r_shot->width, r_shot->height, GL_RGB, GL_UNSIGNED_BYTE, r_shot->buffer ); + + switch( shot_type ) + { + case VID_SCREENSHOT: + break; + case VID_SNAPSHOT: + gEngfuncs.FS_AllowDirectPaths( true ); + break; + case VID_LEVELSHOT: + flags |= IMAGE_RESAMPLE; + if( gpGlobals->wideScreen ) + { + height = 480; + width = 800; + } + else + { + height = 480; + width = 640; + } + break; + case VID_MINISHOT: + flags |= IMAGE_RESAMPLE; + height = 200; + width = 320; + break; + case VID_MAPSHOT: + flags |= IMAGE_RESAMPLE|IMAGE_QUANTIZE; // GoldSrc request overviews in 8-bit format + height = 768; + width = 1024; + break; + } + + gEngfuncs.Image_Process( &r_shot, width, height, flags, 0.0f ); + + // write image + result = gEngfuncs.FS_SaveImage( filename, r_shot ); + gEngfuncs.FS_AllowDirectPaths( false ); // always reset after store screenshot + gEngfuncs.FS_FreeImage( r_shot ); + + return result; +#else + return 0; +#endif +} + +/* +================= +VID_CubemapShot +================= +*/ +qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot ) +{ +#if 0 + rgbdata_t *r_shot, *r_side; + byte *temp = NULL; + byte *buffer = NULL; + string basename; + int i = 1, flags, result; + + if( !RI.drawWorld || !WORLDMODEL ) + return false; + + // make sure the specified size is valid + while( i < size ) i<<=1; + + if( i != size ) return false; + if( size > gpGlobals->width || size > gpGlobals->height ) + return false; + + // alloc space + temp = Mem_Malloc( r_temppool, size * size * 3 ); + buffer = Mem_Malloc( r_temppool, size * size * 3 * 6 ); + r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t )); + r_side = Mem_Calloc( r_temppool, sizeof( rgbdata_t )); + + // use client vieworg + if( !vieworg ) vieworg = RI.vieworg; + + R_CheckGamma(); + + for( i = 0; i < 6; i++ ) + { + // go into 3d mode + R_Set2DMode( false ); + + if( skyshot ) + { + R_DrawCubemapView( vieworg, r_skyBoxInfo[i].angles, size ); + flags = r_skyBoxInfo[i].flags; + } + else + { + R_DrawCubemapView( vieworg, r_envMapInfo[i].angles, size ); + flags = r_envMapInfo[i].flags; + } + + pglReadPixels( 0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, temp ); + r_side->flags = IMAGE_HAS_COLOR; + r_side->width = r_side->height = size; + r_side->type = PF_RGB_24; + r_side->size = r_side->width * r_side->height * 3; + r_side->buffer = temp; + + if( flags ) gEngfuncs.Image_Process( &r_side, 0, 0, flags, 0.0f ); + memcpy( buffer + (size * size * 3 * i), r_side->buffer, size * size * 3 ); + } + + r_shot->flags = IMAGE_HAS_COLOR; + r_shot->flags |= (skyshot) ? IMAGE_SKYBOX : IMAGE_CUBEMAP; + r_shot->width = size; + r_shot->height = size; + r_shot->type = PF_RGB_24; + r_shot->size = r_shot->width * r_shot->height * 3 * 6; + r_shot->palette = NULL; + r_shot->buffer = buffer; + + // make sure what we have right extension + Q_strncpy( basename, base, MAX_STRING ); + COM_StripExtension( basename ); + COM_DefaultExtension( basename, ".tga" ); + + // write image as 6 sides + result = gEngfuncs.FS_SaveImage( basename, r_shot ); + gEngfuncs.FS_FreeImage( r_shot ); + gEngfuncs.FS_FreeImage( r_side ); + + return result; +#else + return 0; +#endif +} + +//======================================================= + +/* +=============== +R_ShowTextures + +Draw all the images to the screen, on top of whatever +was there. This is used to test for texture thrashing. +=============== +*/ +void R_ShowTextures( void ) +{ +#if 0 + gl_texture_t *image; + float x, y, w, h; + int total, start, end; + int i, j, k, base_w, base_h; + rgba_t color = { 192, 192, 192, 255 }; + int charHeight, numTries = 0; + static qboolean showHelp = true; + string shortname; + + if( !CVAR_TO_BOOL( gl_showtextures )) + return; + + if( showHelp ) + { + gEngfuncs.CL_CenterPrint( "use '<-' and '->' keys to change atlas page, ESC to quit", 0.25f ); + showHelp = false; + } + + GL_SetRenderMode( kRenderNormal ); + pglClear( GL_COLOR_BUFFER_BIT ); + pglFinish(); + + base_w = 8; // textures view by horizontal + base_h = 6; // textures view by vertical + +rebuild_page: + total = base_w * base_h; + start = total * (gl_showtextures->value - 1); + end = total * gl_showtextures->value; + if( end > MAX_TEXTURES ) end = MAX_TEXTURES; + + w = gpGlobals->width / base_w; + h = gpGlobals->height / base_h; + + gEngfuncs.Con_DrawStringLen( NULL, NULL, &charHeight ); + + for( i = j = 0; i < MAX_TEXTURES; i++ ) + { + image = R_GetTexture( i ); + if( j == start ) break; // found start + if( pglIsTexture( image->texnum )) j++; + } + + if( i == MAX_TEXTURES && gl_showtextures->value != 1 ) + { + // bad case, rewind to one and try again + gEngfuncs.Cvar_SetValue( "r_showtextures", max( 1, gl_showtextures->value - 1 )); + if( ++numTries < 2 ) goto rebuild_page; // to prevent infinite loop + } + + for( k = 0; i < MAX_TEXTURES; i++ ) + { + if( j == end ) break; // page is full + + image = R_GetTexture( i ); + if( !pglIsTexture( image->texnum )) + continue; + + x = k % base_w * w; + y = k / base_w * h; + + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + GL_Bind( XASH_TEXTURE0, i ); // NOTE: don't use image->texnum here, because skybox has a 'wrong' indexes + + if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE )) + pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); + + pglBegin( GL_QUADS ); + pglTexCoord2f( 0, 0 ); + pglVertex2f( x, y ); + if( image->target == GL_TEXTURE_RECTANGLE_EXT ) + pglTexCoord2f( image->width, 0 ); + else pglTexCoord2f( 1, 0 ); + pglVertex2f( x + w, y ); + if( image->target == GL_TEXTURE_RECTANGLE_EXT ) + pglTexCoord2f( image->width, image->height ); + else pglTexCoord2f( 1, 1 ); + pglVertex2f( x + w, y + h ); + if( image->target == GL_TEXTURE_RECTANGLE_EXT ) + pglTexCoord2f( 0, image->height ); + else pglTexCoord2f( 0, 1 ); + pglVertex2f( x, y + h ); + pglEnd(); + + if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE )) + pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB ); + + COM_FileBase( image->name, shortname ); + if( Q_strlen( shortname ) > 18 ) + { + // cutoff too long names, it looks ugly + shortname[16] = '.'; + shortname[17] = '.'; + shortname[18] = '\0'; + } + gEngfuncs.Con_DrawString( x + 1, y + h - charHeight, shortname, color ); + j++, k++; + } + + gEngfuncs.CL_DrawCenterPrint (); + pglFinish(); +#endif +} + +/* +================ +SCR_TimeRefresh_f + +timerefresh [noflip] +================ +*/ +void SCR_TimeRefresh_f( void ) +{ + int i; + double start, stop; + double time; + + if( ENGINE_GET_PARM( PARM_CONNSTATE ) != ca_active ) + return; + + start = gEngfuncs.pfnTime(); + + // run without page flipping like GoldSrc + if( gEngfuncs.Cmd_Argc() == 1 ) + { +#if 0 + pglDrawBuffer( GL_FRONT ); +#endif + for( i = 0; i < 128; i++ ) + { + gpGlobals->viewangles[1] = i / 128.0f * 360.0f; + R_RenderScene(); + } +#if 0 + pglFinish(); +#endif + R_EndFrame(); + } + else + { + for( i = 0; i < 128; i++ ) + { + R_BeginFrame( true ); + gpGlobals->viewangles[1] = i / 128.0f * 360.0f; + R_RenderScene(); + R_EndFrame(); + } + } + + stop = gEngfuncs.pfnTime (); + time = (stop - start); + gEngfuncs.Con_Printf( "%f seconds (%f fps)\n", time, 128 / time ); +} diff --git a/ref_gu/gu_beams.c b/ref_gu/gu_beams.c new file mode 100644 index 00000000..aedbde39 --- /dev/null +++ b/ref_gu/gu_beams.c @@ -0,0 +1,1544 @@ +/* +gl_beams.c - beams rendering +Copyright (C) 2009 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "r_efx.h" +#include "event_flags.h" +#include "entity_types.h" +#include "triangleapi.h" +#include "customentity.h" +#include "cl_tent.h" +#include "pm_local.h" +#include "studio.h" + +#define NOISE_DIVISIONS 64 // don't touch - many tripmines cause the crash when it equal 128 + +typedef struct +{ + vec3_t pos; + float texcoord; // Y texture coordinate + float width; +} beamseg_t; + +/* +============================================================== + +FRACTAL NOISE + +============================================================== +*/ +static float rgNoise[NOISE_DIVISIONS+1]; // global noise array + +// freq2 += step * 0.1; +// Fractal noise generator, power of 2 wavelength +static void FracNoise( float *noise, int divs ) +{ + int div2; + + div2 = divs >> 1; + if( divs < 2 ) return; + + // noise is normalized to +/- scale + noise[div2] = ( noise[0] + noise[divs] ) * 0.5f + divs * gEngfuncs.COM_RandomFloat( -0.125f, 0.125f ); + + if( div2 > 1 ) + { + FracNoise( &noise[div2], div2 ); + FracNoise( noise, div2 ); + } +} + +static void SineNoise( float *noise, int divs ) +{ + float freq = 0; + float step = M_PI_F / (float)divs; + int i; + + for( i = 0; i < divs; i++ ) + { + noise[i] = sin( freq ); + freq += step; + } +} + + +/* +============================================================== + +BEAM MATHLIB + +============================================================== +*/ +static void R_BeamComputePerpendicular( const vec3_t vecBeamDelta, vec3_t pPerp ) +{ + // direction in worldspace of the center of the beam + vec3_t vecBeamCenter; + + VectorNormalize2( vecBeamDelta, vecBeamCenter ); + CrossProduct( RI.vforward, vecBeamCenter, pPerp ); + VectorNormalize( pPerp ); +} + +static void R_BeamComputeNormal( const vec3_t vStartPos, const vec3_t vNextPos, vec3_t pNormal ) +{ + // vTangentY = line vector for beam + vec3_t vTangentY, vDirToBeam; + + VectorSubtract( vStartPos, vNextPos, vTangentY ); + + // vDirToBeam = vector from viewer origin to beam + VectorSubtract( vStartPos, RI.vieworg, vDirToBeam ); + + // get a vector that is perpendicular to us and perpendicular to the beam. + // this is used to fatten the beam. + CrossProduct( vTangentY, vDirToBeam, pNormal ); + VectorNormalizeFast( pNormal ); +} + + +/* +============== +R_BeamCull + +Cull the beam by bbox +============== +*/ +qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly ) +{ + vec3_t mins, maxs; + int i; + + for( i = 0; i < 3; i++ ) + { + if( start[i] < end[i] ) + { + mins[i] = start[i]; + maxs[i] = end[i]; + } + else + { + mins[i] = end[i]; + maxs[i] = start[i]; + } + + // don't let it be zero sized + if( mins[i] == maxs[i] ) + maxs[i] += 1.0f; + } + + // check bbox + if( gEngfuncs.Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( ))) + { + if( pvsOnly || !R_CullBox( mins, maxs )) + { + // beam is visible + return false; + } + } + + // beam is culled + return true; +} + +/* +================ +CL_AddCustomBeam + +Add the beam that encoded as custom entity +================ +*/ +void CL_AddCustomBeam( cl_entity_t *pEnvBeam ) +{ + if( tr.draw_list->num_beam_entities >= MAX_VISIBLE_PACKET ) + { + gEngfuncs.Con_Printf( S_ERROR "Too many beams %d!\n", tr.draw_list->num_beam_entities ); + return; + } + + if( pEnvBeam ) + { + tr.draw_list->beam_entities[tr.draw_list->num_beam_entities] = pEnvBeam; + tr.draw_list->num_beam_entities++; + } +} + + +/* +============================================================== + +BEAM DRAW METHODS + +============================================================== +*/ +/* +================ +R_DrawSegs + +general code for drawing beams +================ +*/ +static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments, int flags ) +{ + int noiseIndex, noiseStep; + int i, total_segs, segs_drawn; + float div, length, fraction, factor; + float flMaxWidth, vLast, vStep, brightness; + vec3_t perp1, vLastNormal; + beamseg_t curSeg; + + if( segments < 2 ) return; + + length = VectorLength( delta ); + flMaxWidth = width * 0.5f; + div = 1.0f / ( segments - 1 ); + + if( length * div < flMaxWidth * 1.414f ) + { + // here, we have too many segments; we could get overlap... so lets have less segments + segments = (int)( length / ( flMaxWidth * 1.414f )) + 1.0f; + if( segments < 2 ) segments = 2; + } + + if( segments > NOISE_DIVISIONS ) + segments = NOISE_DIVISIONS; + + div = 1.0f / (segments - 1); + length *= 0.01f; + vStep = length * div; // Texture length texels per space pixel + + // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) + vLast = fmod( freq * speed, 1 ); + + if( flags & FBEAM_SINENOISE ) + { + if( segments < 16 ) + { + segments = 16; + div = 1.0f / ( segments - 1 ); + } + scale *= 100.0f; + length = segments * 0.1f; + } + else + { + scale *= length * 2.0f; + } + + // Iterator to resample noise waveform (it needs to be generated in powers of 2) + noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f ); + brightness = 1.0f; + noiseIndex = 0; + + if( FBitSet( flags, FBEAM_SHADEIN )) + brightness = 0; + + // Choose two vectors that are perpendicular to the beam + R_BeamComputePerpendicular( delta, perp1 ); + + total_segs = segments; + segs_drawn = 0; +#if 1 + gu_vert_ftcnv_t* const out = ( gu_vert_ftcnv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; + unsigned int vert_color = 0; +#endif + // specify all the segments. + for( i = 0; i < segments; i++ ) + { + beamseg_t nextSeg; + vec3_t vPoint1, vPoint2; + + Assert( noiseIndex < ( NOISE_DIVISIONS << 16 )); + + fraction = i * div; + + VectorMA( source, fraction, delta, nextSeg.pos ); + + // distort using noise + if( scale != 0 ) + { + factor = rgNoise[noiseIndex>>16] * scale; + + if( FBitSet( flags, FBEAM_SINENOISE )) + { + float s, c; + + SinCos( fraction * M_PI_F * length + freq, &s, &c ); + VectorMA( nextSeg.pos, (factor * s), RI.vup, nextSeg.pos ); + + // rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal + VectorMA( nextSeg.pos, (factor * c), RI.vright, nextSeg.pos ); + } + else + { + VectorMA( nextSeg.pos, factor, perp1, nextSeg.pos ); + } + } + + // specify the next segment. + nextSeg.width = width * 2.0f; + nextSeg.texcoord = vLast; + + if( segs_drawn > 0 ) + { + // Get a vector that is perpendicular to us and perpendicular to the beam. + // This is used to fatten the beam. + vec3_t vNormal, vAveNormal; + + R_BeamComputeNormal( curSeg.pos, nextSeg.pos, vNormal ); + + if( segs_drawn > 1 ) + { + // Average this with the previous normal + VectorAdd( vNormal, vLastNormal, vAveNormal ); + VectorScale( vAveNormal, 0.5f, vAveNormal ); + VectorNormalizeFast( vAveNormal ); + } + else + { + VectorCopy( vNormal, vAveNormal ); + } + + VectorCopy( vNormal, vLastNormal ); + + // draw regular segment + VectorMA( curSeg.pos, ( curSeg.width * 0.5f ), vAveNormal, vPoint1 ); + VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vAveNormal, vPoint2 ); +#if 1 + vert_color = getTriBrightness( brightness ); + out[vert_size].u = 0.0f; + out[vert_size].v = curSeg.texcoord; + out[vert_size].c = vert_color; + out[vert_size].nx = vAveNormal[0]; + out[vert_size].ny = vAveNormal[1]; + out[vert_size].nz = vAveNormal[2]; + out[vert_size].x = vPoint1[0]; + out[vert_size].y = vPoint1[1]; + out[vert_size].z = vPoint1[2]; + vert_size++; + out[vert_size].u = 1.0f; + out[vert_size].v = curSeg.texcoord; + out[vert_size].c = vert_color; + out[vert_size].nx = vAveNormal[0]; + out[vert_size].ny = vAveNormal[1]; + out[vert_size].nz = vAveNormal[2]; + out[vert_size].x = vPoint2[0]; + out[vert_size].y = vPoint2[1]; + out[vert_size].z = vPoint2[2]; + vert_size++; +#else + pglTexCoord2f( 0.0f, curSeg.texcoord ); + TriBrightness( brightness ); + pglNormal3fv( vAveNormal ); + pglVertex3fv( vPoint1 ); + + pglTexCoord2f( 1.0f, curSeg.texcoord ); + TriBrightness( brightness ); + pglNormal3fv( vAveNormal ); + pglVertex3fv( vPoint2 ); +#endif + } + + curSeg = nextSeg; + segs_drawn++; + + if( FBitSet( flags, FBEAM_SHADEIN ) && FBitSet( flags, FBEAM_SHADEOUT )) + { + if( fraction < 0.5f ) brightness = fraction; + else brightness = ( 1.0f - fraction ); + } + else if( FBitSet( flags, FBEAM_SHADEIN )) + { + brightness = fraction; + } + else if( FBitSet( flags, FBEAM_SHADEOUT )) + { + brightness = 1.0f - fraction; + } + + if( segs_drawn == total_segs ) + { + // draw the last segment + VectorMA( curSeg.pos, ( curSeg.width * 0.5f ), vLastNormal, vPoint1 ); + VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vLastNormal, vPoint2 ); + + // specify the points. +#if 1 + vert_color = getTriBrightness( brightness ); + out[vert_size].u = 0.0f; + out[vert_size].v = curSeg.texcoord; + out[vert_size].c = vert_color; + out[vert_size].nx = vLastNormal[0]; + out[vert_size].ny = vLastNormal[1]; + out[vert_size].nz = vLastNormal[2]; + out[vert_size].x = vPoint1[0]; + out[vert_size].y = vPoint1[1]; + out[vert_size].z = vPoint1[2]; + vert_size++; + out[vert_size].u = 1.0f; + out[vert_size].v = curSeg.texcoord; + out[vert_size].c = vert_color; + out[vert_size].nx = vLastNormal[0]; + out[vert_size].ny = vLastNormal[1]; + out[vert_size].nz = vLastNormal[2]; + out[vert_size].x = vPoint2[0]; + out[vert_size].y = vPoint2[1]; + out[vert_size].z = vPoint2[2]; + vert_size++; +#else + pglTexCoord2f( 0.0f, curSeg.texcoord ); + TriBrightness( brightness ); + pglNormal3fv( vLastNormal ); + pglVertex3fv( vPoint1 ); + + pglTexCoord2f( 1.0f, curSeg.texcoord ); + TriBrightness( brightness ); + pglNormal3fv( vLastNormal ); + pglVertex3fv( vPoint2 ); +#endif + } + + vLast += vStep; // Advance texture scroll (v axis only) + noiseIndex += noiseStep; + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_NORMAL_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif +} + +/* +================ +R_DrawTorus + +Draw beamtours +================ +*/ +void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +{ + int i, noiseIndex, noiseStep; + float div, length, fraction, factor, vLast, vStep; + vec3_t last1, last2, point, screen, screenLast, tmp, normal; + + if( segments < 2 ) + return; + + if( segments > NOISE_DIVISIONS ) + segments = NOISE_DIVISIONS; + + length = VectorLength( delta ) * 0.01f; + if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams + + div = 1.0f / (segments - 1); + + vStep = length * div; // Texture length texels per space pixel + + // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) + vLast = fmod( freq * speed, 1 ); + scale = scale * length; + + // Iterator to resample noise waveform (it needs to be generated in powers of 2) + noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f ); + noiseIndex = 0; +#if 1 + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; +#endif + for( i = 0; i < segments; i++ ) + { + float s, c; + + fraction = i * div; + SinCos( fraction * M_PI2_F, &s, &c ); + + point[0] = s * freq * delta[2] + source[0]; + point[1] = c * freq * delta[2] + source[1]; + point[2] = source[2]; + + // distort using noise + if( scale != 0 ) + { + if(( noiseIndex >> 16 ) < NOISE_DIVISIONS ) + { + factor = rgNoise[noiseIndex>>16] * scale; + VectorMA( point, factor, RI.vup, point ); + + // rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal + factor = rgNoise[noiseIndex>>16] * scale * cos( fraction * M_PI_F * 3 + freq ); + VectorMA( point, factor, RI.vright, point ); + } + } + + // Transform point into screen space + TriWorldToScreen( point, screen ); + + if( i != 0 ) + { + // build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + VectorScale( RI.vup, -tmp[0], normal ); // Build point along noraml line (normal is -y, x) + VectorMA( normal, tmp[1], RI.vright, normal ); + + // Make a wide line + VectorMA( point, width, normal, last1 ); + VectorMA( point, -width, normal, last2 ); + + vLast += vStep; // advance texture scroll (v axis only) +#if 1 + out[vert_size].u = 1.0f; + out[vert_size].v = vLast; + out[vert_size].x = last2[0]; + out[vert_size].y = last2[1]; + out[vert_size].z = last2[2]; + vert_size++; + out[vert_size].u = 0.0f; + out[vert_size].v = vLast; + out[vert_size].x = last1[0]; + out[vert_size].y = last1[1]; + out[vert_size].z = last1[2]; + vert_size++; +#else + TriTexCoord2f( 1, vLast ); + TriVertex3fv( last2 ); + TriTexCoord2f( 0, vLast ); + TriVertex3fv( last1 ); +#endif + } + + VectorCopy( screen, screenLast ); + noiseIndex += noiseStep; + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif +} + +/* +================ +R_DrawDisk + +Draw beamdisk +================ +*/ +void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +{ + float div, length, fraction; + float w, vLast, vStep; + vec3_t point; + int i; + + if( segments < 2 ) + return; + + if( segments > NOISE_DIVISIONS ) // UNDONE: Allow more segments? + segments = NOISE_DIVISIONS; + + length = VectorLength( delta ) * 0.01f; + if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams + + div = 1.0f / (segments - 1); + vStep = length * div; // Texture length texels per space pixel + + // scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) + vLast = fmod( freq * speed, 1 ); + scale = scale * length; + + // clamp the beam width + w = fmod( freq, width * 0.1f ) * delta[2]; +#if 1 + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; + unsigned int vert_color = getTriBrightness( 1.0f ); +#endif + // NOTE: we must force the degenerate triangles to be on the edge + for( i = 0; i < segments; i++ ) + { + float s, c; + + fraction = i * div; + VectorCopy( source, point ); +#if 1 + out[vert_size].u = 1.0f; + out[vert_size].v = vLast; + out[vert_size].c = vert_color; + out[vert_size].x = point[0]; + out[vert_size].y = point[1]; + out[vert_size].z = point[2]; + vert_size++; + + SinCos( fraction * M_PI2_F, &s, &c ); + point[0] = s * w + source[0]; + point[1] = c * w + source[1]; + point[2] = source[2]; + + out[vert_size].u = 0.0f; + out[vert_size].v = vLast; + out[vert_size].c = vert_color; + out[vert_size].x = point[0]; + out[vert_size].y = point[1]; + out[vert_size].z = point[2]; + vert_size++; +#else + TriBrightness( 1.0f ); + TriTexCoord2f( 1.0f, vLast ); + TriVertex3fv( point ); + + SinCos( fraction * M_PI2_F, &s, &c ); + point[0] = s * w + source[0]; + point[1] = c * w + source[1]; + point[2] = source[2]; + + TriBrightness( 1.0f ); + TriTexCoord2f( 0.0f, vLast ); + TriVertex3fv( point ); +#endif + vLast += vStep; // advance texture scroll (v axis only) + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif +} + +/* +================ +R_DrawCylinder + +Draw beam cylinder +================ +*/ +void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +{ + float div, length, fraction; + float vLast, vStep; + vec3_t point; + int i; + + if( segments < 2 ) + return; + + if( segments > NOISE_DIVISIONS ) + segments = NOISE_DIVISIONS; + + length = VectorLength( delta ) * 0.01f; + if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams + + div = 1.0f / (segments - 1); + vStep = length * div; // texture length texels per space pixel + + // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) + vLast = fmod( freq * speed, 1 ); + scale = scale * length; +#if 1 + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; + unsigned int vert_color0 = getTriBrightness( 0.0f ); + unsigned int vert_color1 = getTriBrightness( 1.0f ); +#endif + for ( i = 0; i < segments; i++ ) + { + float s, c; + + fraction = i * div; + SinCos( fraction * M_PI2_F, &s, &c ); + + point[0] = s * freq * delta[2] + source[0]; + point[1] = c * freq * delta[2] + source[1]; + point[2] = source[2] + width; +#if 1 + out[vert_size].u = 1.0f; + out[vert_size].v = vLast; + out[vert_size].c = vert_color0; + out[vert_size].x = point[0]; + out[vert_size].y = point[1]; + out[vert_size].z = point[2]; + vert_size++; + + point[0] = s * freq * ( delta[2] + width ) + source[0]; + point[1] = c * freq * ( delta[2] + width ) + source[1]; + point[2] = source[2] - width; + + out[vert_size].u = 0.0f; + out[vert_size].v = vLast; + out[vert_size].c = vert_color1; + out[vert_size].x = point[0]; + out[vert_size].y = point[1]; + out[vert_size].z = point[2]; + vert_size++; +#else + TriBrightness( 0 ); + TriTexCoord2f( 1, vLast ); + TriVertex3fv( point ); + + point[0] = s * freq * ( delta[2] + width ) + source[0]; + point[1] = c * freq * ( delta[2] + width ) + source[1]; + point[2] = source[2] - width; + + TriBrightness( 1 ); + TriTexCoord2f( 0, vLast ); + TriVertex3fv( point ); +#endif + vLast += vStep; // Advance texture scroll (v axis only) + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif +} + +/* +============== +R_DrawBeamFollow + +drawi followed beam +============== +*/ +void R_DrawBeamFollow( BEAM *pbeam, float frametime ) +{ + particle_t *pnew, *particles; + float fraction, div, vLast, vStep; + vec3_t last1, last2, tmp, screen; + vec3_t delta, screenLast, normal; + + gEngfuncs.R_FreeDeadParticles( &pbeam->particles ); + + particles = pbeam->particles; + pnew = NULL; + + div = 0; + if( FBitSet( pbeam->flags, FBEAM_STARTENTITY )) + { + if( particles ) + { + VectorSubtract( particles->org, pbeam->source, delta ); + div = VectorLength( delta ); + + if( div >= 32 ) + { + pnew = gEngfuncs.CL_AllocParticleFast(); + } + } + else + { + pnew = gEngfuncs.CL_AllocParticleFast(); + } + } + + if( pnew ) + { + VectorCopy( pbeam->source, pnew->org ); + pnew->die = gpGlobals->time + pbeam->amplitude; + VectorClear( pnew->vel ); + + pnew->next = particles; + pbeam->particles = pnew; + particles = pnew; + } + + // nothing to draw + if( !particles ) return; + + if( !pnew && div != 0 ) + { + VectorCopy( pbeam->source, delta ); + TriWorldToScreen( pbeam->source, screenLast ); + TriWorldToScreen( particles->org, screen ); + } + else if( particles && particles->next ) + { + VectorCopy( particles->org, delta ); + TriWorldToScreen( particles->org, screenLast ); + TriWorldToScreen( particles->next->org, screen ); + particles = particles->next; + } + else + { + return; + } + + // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the + // first beam segment for this trail + + // build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + + // Build point along noraml line (normal is -y, x) + VectorScale( RI.vup, tmp[0], normal ); // Build point along normal line (normal is -y, x) + VectorMA( normal, tmp[1], RI.vright, normal ); + + // Make a wide line + VectorMA( delta, pbeam->width, normal, last1 ); + VectorMA( delta, -pbeam->width, normal, last2 ); + + div = 1.0f / pbeam->amplitude; + fraction = ( pbeam->die - gpGlobals->time ) * div; + + vLast = 0.0f; + vStep = 1.0f; + +#if 1 + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; + unsigned int vert_color = 0; + gu_vert_ftcv_t* saved_ptr; +#endif + + while( particles ) + { +#if 1 + vert_color = getTriBrightness( fraction ); + out[vert_size].u = 1.0f; + out[vert_size].v = 1.0f; + out[vert_size].c = vert_color; + out[vert_size].x = last2[0]; + out[vert_size].y = last2[1]; + out[vert_size].z = last2[2]; + saved_ptr = &out[vert_size]; + vert_size++; + out[vert_size].u = 0.0f; + out[vert_size].v = 1.0f; + out[vert_size].c = vert_color; + out[vert_size].x = last1[0]; + out[vert_size].y = last1[1]; + out[vert_size].z = last1[2]; + vert_size++; +#else + TriBrightness( fraction ); + TriTexCoord2f( 1, 1 ); + TriVertex3fv( last2 ); + TriBrightness( fraction ); + TriTexCoord2f( 0, 1 ); + TriVertex3fv( last1 ); +#endif + // Transform point into screen space + TriWorldToScreen( particles->org, screen ); + // Build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + VectorScale( RI.vup, tmp[0], normal ); // Build point along noraml line (normal is -y, x) + VectorMA( normal, tmp[1], RI.vright, normal ); + + // Make a wide line + VectorMA( particles->org, pbeam->width, normal, last1 ); + VectorMA( particles->org, -pbeam->width, normal, last2 ); + + vLast += vStep; // Advance texture scroll (v axis only) + + if( particles->next != NULL ) + { + fraction = (particles->die - gpGlobals->time) * div; + } + else + { + fraction = 0.0; + } +#if 1 + vert_color = getTriBrightness( fraction ); + out[vert_size].u = 0.0f; + out[vert_size].v = 0.0f; + out[vert_size].c = vert_color; + out[vert_size].x = last1[0]; + out[vert_size].y = last1[1]; + out[vert_size].z = last1[2]; + vert_size++; + + out[vert_size].u = saved_ptr->u; + out[vert_size].v = saved_ptr->v; + out[vert_size].c = saved_ptr->c; + out[vert_size].x = saved_ptr->x; + out[vert_size].y = saved_ptr->y; + out[vert_size].z = saved_ptr->z; + vert_size++; + + out[vert_size].u = 0.0f; + out[vert_size].v = 0.0f; + out[vert_size].c = vert_color; + out[vert_size].x = last1[0]; + out[vert_size].y = last1[1]; + out[vert_size].z = last1[2]; + vert_size++; + + out[vert_size].u = 1.0f; + out[vert_size].v = 0.0f; + out[vert_size].c = vert_color; + out[vert_size].x = last2[0]; + out[vert_size].y = last2[1]; + out[vert_size].z = last2[2]; + vert_size++; +#else + TriBrightness( fraction ); + TriTexCoord2f( 0, 0 ); + TriVertex3fv( last1 ); + TriBrightness( fraction ); + TriTexCoord2f( 1, 0 ); + TriVertex3fv( last2 ); +#endif + VectorCopy( screen, screenLast ); + + particles = particles->next; + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif + // drift popcorn trail if there is a velocity + particles = pbeam->particles; + + while( particles ) + { + VectorMA( particles->org, frametime, particles->vel, particles->org ); + particles = particles->next; + } +} + +/* +================ +R_DrawRing + +Draw beamring +================ +*/ +void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, float freq, float speed, int segments ) +{ + int i, j, noiseIndex, noiseStep; + float div, length, fraction, factor, vLast, vStep; + vec3_t last1, last2, point, screen, screenLast; + vec3_t tmp, normal, center, xaxis, yaxis; + float radius, x, y, scale; + + if( segments < 2 ) + return; + + VectorClear( screenLast ); + segments = segments * M_PI_F; + + if( segments > NOISE_DIVISIONS * 8 ) + segments = NOISE_DIVISIONS * 8; + + length = VectorLength( delta ) * 0.01f * M_PI_F; + if( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams + + div = 1.0f / ( segments - 1 ); + + vStep = length * div / 8.0f; // texture length texels per space pixel + + // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) + vLast = fmod( freq * speed, 1.0f ); + scale = amplitude * length / 8.0f; + + // Iterator to resample noise waveform (it needs to be generated in powers of 2) + noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f ) * 8; + noiseIndex = 0; + + VectorScale( delta, 0.5f, delta ); + VectorAdd( source, delta, center ); + + VectorCopy( delta, xaxis ); + radius = VectorLength( xaxis ); + + // cull beamring + // -------------------------------- + // Compute box center +/- radius + VectorSet( last1, radius, radius, scale ); + VectorAdd( center, last1, tmp ); // maxs + VectorSubtract( center, last1, screen ); // mins + + if( !WORLDMODEL ) + return; + + // is that box in PVS && frustum? + if( !gEngfuncs.Mod_BoxVisible( screen, tmp, Mod_GetCurrentVis( )) || R_CullBox( screen, tmp )) + { + return; + } + + VectorSet( yaxis, xaxis[1], -xaxis[0], 0.0f ); + VectorNormalize( yaxis ); + VectorScale( yaxis, radius, yaxis ); + + j = segments / 8; +#if 1 + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; +#endif + for( i = 0; i < segments + 1; i++ ) + { + fraction = i * div; + SinCos( fraction * M_PI2_F, &x, &y ); + + VectorMAMAM( x, xaxis, y, yaxis, 1.0f, center, point ); + + // distort using noise + factor = rgNoise[(noiseIndex >> 16) & (NOISE_DIVISIONS - 1)] * scale; + VectorMA( point, factor, RI.vup, point ); + + // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal + factor = rgNoise[(noiseIndex >> 16) & (NOISE_DIVISIONS - 1)] * scale; + factor *= cos( fraction * M_PI_F * 24 + freq ); + VectorMA( point, factor, RI.vright, point ); + + // Transform point into screen space + TriWorldToScreen( point, screen ); + + if( i != 0 ) + { + // build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + + // Build point along normal line (normal is -y, x) + VectorScale( RI.vup, tmp[0], normal ); + VectorMA( normal, tmp[1], RI.vright, normal ); + + // Make a wide line + VectorMA( point, width, normal, last1 ); + VectorMA( point, -width, normal, last2 ); + + vLast += vStep; // Advance texture scroll (v axis only) +#if 1 + out[vert_size].u = 1.0f; + out[vert_size].v = vLast; + out[vert_size].x = last2[0]; + out[vert_size].y = last2[1]; + out[vert_size].z = last2[2]; + vert_size++; + out[vert_size].u = 0.0f; + out[vert_size].v = vLast; + out[vert_size].x = last1[0]; + out[vert_size].y = last1[1]; + out[vert_size].z = last1[2]; + vert_size++; +#else + TriTexCoord2f( 1.0f, vLast ); + TriVertex3fv( last2 ); + TriTexCoord2f( 0.0f, vLast ); + TriVertex3fv( last1 ); +#endif + } + + VectorCopy( screen, screenLast ); + noiseIndex += noiseStep; + j--; + + if( j == 0 && amplitude != 0 ) + { + j = segments / 8; + FracNoise( rgNoise, NOISE_DIVISIONS ); + } + } +#if 1 + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); +#endif +} + +/* +============== +R_BeamComputePoint + +compute attachment point for beam +============== +*/ +static qboolean R_BeamComputePoint( int beamEnt, vec3_t pt ) +{ + cl_entity_t *ent; + int attach; + + ent = gEngfuncs.R_BeamGetEntity( beamEnt ); + + if( beamEnt < 0 ) + attach = BEAMENT_ATTACHMENT( -beamEnt ); + else attach = BEAMENT_ATTACHMENT( beamEnt ); + + if( !ent ) + { + gEngfuncs.Con_DPrintf( S_ERROR "R_BeamComputePoint: invalid entity %i\n", BEAMENT_ENTITY( beamEnt )); + VectorClear( pt ); + return false; + } + + // get attachment + if( attach > 0 ) + VectorCopy( ent->attachment[attach - 1], pt ); + else if( ent->index == ENGINE_GET_PARM( PARM_PLAYER_INDEX ) ) + { + vec3_t simorg; + gEngfuncs.GetPredictedOrigin( simorg ); + VectorCopy( simorg, pt ); + } + else VectorCopy( ent->origin, pt ); + + return true; +} + +/* +============== +R_BeamRecomputeEndpoints + +Recomputes beam endpoints.. +============== +*/ +qboolean R_BeamRecomputeEndpoints( BEAM *pbeam ) +{ + if( FBitSet( pbeam->flags, FBEAM_STARTENTITY )) + { + cl_entity_t *start = gEngfuncs.R_BeamGetEntity( pbeam->startEntity ); + + if( R_BeamComputePoint( pbeam->startEntity, pbeam->source )) + { + if( !pbeam->pFollowModel ) + pbeam->pFollowModel = start->model; + SetBits( pbeam->flags, FBEAM_STARTVISIBLE ); + } + else if( !FBitSet( pbeam->flags, FBEAM_FOREVER )) + { + ClearBits( pbeam->flags, FBEAM_STARTENTITY ); + } + } + + if( FBitSet( pbeam->flags, FBEAM_ENDENTITY )) + { + cl_entity_t *end = gEngfuncs.R_BeamGetEntity( pbeam->endEntity ); + + if( R_BeamComputePoint( pbeam->endEntity, pbeam->target )) + { + if( !pbeam->pFollowModel ) + pbeam->pFollowModel = end->model; + SetBits( pbeam->flags, FBEAM_ENDVISIBLE ); + } + else if( !FBitSet( pbeam->flags, FBEAM_FOREVER )) + { + ClearBits( pbeam->flags, FBEAM_ENDENTITY ); + pbeam->die = gpGlobals->time; + return false; + } + else + { + return false; + } + } + + if( FBitSet( pbeam->flags, FBEAM_STARTENTITY ) && !FBitSet( pbeam->flags, FBEAM_STARTVISIBLE )) + return false; + return true; +} + + +/* +============== +R_BeamDraw + +Update beam vars and draw it +============== +*/ +void R_BeamDraw( BEAM *pbeam, float frametime ) +{ + model_t *model; + vec3_t delta; + + model = gEngfuncs.pfnGetModelByIndex( pbeam->modelIndex ); + SetBits( pbeam->flags, FBEAM_ISACTIVE ); + + if( !model || model->type != mod_sprite ) + { + pbeam->flags &= ~FBEAM_ISACTIVE; // force to ignore + pbeam->die = gpGlobals->time; + return; + } + + // update frequency + pbeam->freq += frametime; + + // generate fractal noise + if( frametime != 0.0f ) + { + rgNoise[0] = 0; + rgNoise[NOISE_DIVISIONS] = 0; + } + + if( pbeam->amplitude != 0 && frametime != 0.0f ) + { + if( FBitSet( pbeam->flags, FBEAM_SINENOISE )) + SineNoise( rgNoise, NOISE_DIVISIONS ); + else FracNoise( rgNoise, NOISE_DIVISIONS ); + } + + // update end points + if( FBitSet( pbeam->flags, FBEAM_STARTENTITY|FBEAM_ENDENTITY )) + { + // makes sure attachment[0] + attachment[1] are valid + if( !R_BeamRecomputeEndpoints( pbeam )) + { + ClearBits( pbeam->flags, FBEAM_ISACTIVE ); // force to ignore + return; + } + + // compute segments from the new endpoints + VectorSubtract( pbeam->target, pbeam->source, delta ); + VectorClear( pbeam->delta ); + + if( VectorLength( delta ) > 0.0000001f ) + VectorCopy( delta, pbeam->delta ); + + if( pbeam->amplitude >= 0.50f ) + pbeam->segments = VectorLength( pbeam->delta ) * 0.25f + 3.0f; // one per 4 pixels + else pbeam->segments = VectorLength( pbeam->delta ) * 0.075f + 3.0f; // one per 16 pixels + } + + if( pbeam->type == TE_BEAMPOINTS && R_BeamCull( pbeam->source, pbeam->target, 0 )) + { + ClearBits( pbeam->flags, FBEAM_ISACTIVE ); + return; + } + + // don't draw really short or inactive beams + if( !FBitSet( pbeam->flags, FBEAM_ISACTIVE ) || VectorLength( pbeam->delta ) < 0.1f ) + { + return; + } + + if( pbeam->flags & ( FBEAM_FADEIN|FBEAM_FADEOUT )) + { + // update life cycle + pbeam->t = pbeam->freq + ( pbeam->die - gpGlobals->time ); + if( pbeam->t != 0.0f ) pbeam->t = 1.0f - pbeam->freq / pbeam->t; + } + + if( pbeam->type == TE_BEAMHOSE ) + { + float flDot; + + VectorSubtract( pbeam->target, pbeam->source, delta ); + VectorNormalize( delta ); + + flDot = DotProduct( delta, RI.vforward ); + + // abort if the player's looking along it away from the source + if( flDot > 0 ) + { + return; + } + else + { + float flFade = pow( flDot, 10 ); + vec3_t localDir, vecProjection, tmp; + float flDistance; + + // fade the beam if the player's not looking at the source + VectorSubtract( RI.vieworg, pbeam->source, localDir ); + flDot = DotProduct( delta, localDir ); + VectorScale( delta, flDot, vecProjection ); + VectorSubtract( localDir, vecProjection, tmp ); + flDistance = VectorLength( tmp ); + + if( flDistance > 30 ) + { + flDistance = 1.0f - (( flDistance - 30.0f ) / 64.0f ); + if( flDistance <= 0 ) flFade = 0; + else flFade *= pow( flDistance, 3 ); + } + + if( flFade < ( 1.0f / 255.0f )) + return; + + // FIXME: needs to be testing + pbeam->brightness *= flFade; + } + } + + TriRenderMode( FBitSet( pbeam->flags, FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd ); + + if( !TriSpriteTexture( model, (int)(pbeam->frame + pbeam->frameRate * gpGlobals->time) % pbeam->frameCount )) + { + ClearBits( pbeam->flags, FBEAM_ISACTIVE ); + return; + } + + if( pbeam->type == TE_BEAMFOLLOW ) + { + cl_entity_t *pStart; + + // XASH SPECIFIC: get brightness from head entity + pStart = gEngfuncs.R_BeamGetEntity( pbeam->startEntity ); + if( pStart && pStart->curstate.rendermode != kRenderNormal ) + pbeam->brightness = CL_FxBlend( pStart ) / 255.0f; + } + + if( FBitSet( pbeam->flags, FBEAM_FADEIN )) + TriColor4f( pbeam->r, pbeam->g, pbeam->b, pbeam->t * pbeam->brightness ); + else if( FBitSet( pbeam->flags, FBEAM_FADEOUT )) + TriColor4f( pbeam->r, pbeam->g, pbeam->b, ( 1.0f - pbeam->t ) * pbeam->brightness ); + else TriColor4f( pbeam->r, pbeam->g, pbeam->b, pbeam->brightness ); + + switch( pbeam->type ) + { + case TE_BEAMTORUS: + GL_Cull( GL_NONE ); +#if 0 + TriBegin( TRI_TRIANGLE_STRIP ); +#endif + R_DrawTorus( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); +#if 0 + TriEnd(); +#endif + break; + case TE_BEAMDISK: + GL_Cull( GL_NONE ); +#if 0 + TriBegin( TRI_TRIANGLE_STRIP ); +#endif + R_DrawDisk( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); +#if 0 + TriEnd(); +#endif + break; + case TE_BEAMCYLINDER: + GL_Cull( GL_NONE ); +#if 0 + TriBegin( TRI_TRIANGLE_STRIP ); +#endif + R_DrawCylinder( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); +#if 0 + TriEnd(); +#endif + break; + case TE_BEAMPOINTS: + case TE_BEAMHOSE: +#if 0 + TriBegin( TRI_TRIANGLE_STRIP ); +#endif + R_DrawSegs( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags ); +#if 0 + TriEnd(); +#endif + break; + case TE_BEAMFOLLOW: +#if 0 + TriBegin( TRI_QUADS ); +#endif + R_DrawBeamFollow( pbeam, frametime ); +#if 0 + TriEnd(); +#endif + break; + case TE_BEAMRING: + GL_Cull( GL_NONE ); +#if 0 + TriBegin( TRI_TRIANGLE_STRIP ); +#endif + R_DrawRing( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); +#if 0 + TriEnd(); +#endif + break; + } + + GL_Cull( GL_FRONT ); + r_stats.c_view_beams_count++; +} + +/* +============== +R_BeamSetAttributes + +set beam attributes +============== +*/ +static void R_BeamSetAttributes( BEAM *pbeam, float r, float g, float b, float framerate, int startFrame ) +{ + pbeam->frame = (float)startFrame; + pbeam->frameRate = framerate; + pbeam->r = r; + pbeam->g = g; + pbeam->b = b; +} + +/* +============== +R_BeamSetup + +generic function. all beams must be +passed through this +============== +*/ +static void R_BeamSetup( BEAM *pbeam, vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ) +{ + model_t *sprite = gEngfuncs.pfnGetModelByIndex( modelIndex ); + + if( !sprite ) return; + + pbeam->type = BEAM_POINTS; + pbeam->modelIndex = modelIndex; + pbeam->frame = 0; + pbeam->frameRate = 0; + pbeam->frameCount = sprite->numframes; + + VectorCopy( start, pbeam->source ); + VectorCopy( end, pbeam->target ); + VectorSubtract( end, start, pbeam->delta ); + + pbeam->freq = speed * gpGlobals->time; + pbeam->die = life + gpGlobals->time; + pbeam->amplitude = amplitude; + pbeam->brightness = brightness; + pbeam->width = width; + pbeam->speed = speed; + + if( amplitude >= 0.50f ) + pbeam->segments = VectorLength( pbeam->delta ) * 0.25f + 3.0f; // one per 4 pixels + else pbeam->segments = VectorLength( pbeam->delta ) * 0.075f + 3.0f; // one per 16 pixels + + pbeam->pFollowModel = NULL; + pbeam->flags = 0; +} + + + +/* +============== +R_BeamDrawCustomEntity + +initialize beam from server entity +============== +*/ +void R_BeamDrawCustomEntity( cl_entity_t *ent ) +{ + BEAM beam; + float amp = ent->curstate.body / 100.0f; + float blend = CL_FxBlend( ent ) / 255.0f; + float r, g, b; + int beamFlags; + + r = ent->curstate.rendercolor.r / 255.0f; + g = ent->curstate.rendercolor.g / 255.0f; + b = ent->curstate.rendercolor.b / 255.0f; + + R_BeamSetup( &beam, ent->origin, ent->angles, ent->curstate.modelindex, 0, ent->curstate.scale, amp, blend, ent->curstate.animtime ); + R_BeamSetAttributes( &beam, r, g, b, ent->curstate.framerate, ent->curstate.frame ); + beam.pFollowModel = NULL; + + switch( ent->curstate.rendermode & 0x0F ) + { + case BEAM_ENTPOINT: + beam.type = TE_BEAMPOINTS; + if( ent->curstate.sequence ) + { + SetBits( beam.flags, FBEAM_STARTENTITY ); + beam.startEntity = ent->curstate.sequence; + } + if( ent->curstate.skin ) + { + SetBits( beam.flags, FBEAM_ENDENTITY ); + beam.endEntity = ent->curstate.skin; + } + break; + case BEAM_ENTS: + beam.type = TE_BEAMPOINTS; + SetBits( beam.flags, FBEAM_STARTENTITY | FBEAM_ENDENTITY ); + beam.startEntity = ent->curstate.sequence; + beam.endEntity = ent->curstate.skin; + break; + case BEAM_HOSE: + beam.type = TE_BEAMHOSE; + break; + case BEAM_POINTS: + // already set up + break; + } + + beamFlags = ( ent->curstate.rendermode & 0xF0 ); + + if( FBitSet( beamFlags, BEAM_FSINE )) + SetBits( beam.flags, FBEAM_SINENOISE ); + + if( FBitSet( beamFlags, BEAM_FSOLID )) + SetBits( beam.flags, FBEAM_SOLID ); + + if( FBitSet( beamFlags, BEAM_FSHADEIN )) + SetBits( beam.flags, FBEAM_SHADEIN ); + + if( FBitSet( beamFlags, BEAM_FSHADEOUT )) + SetBits( beam.flags, FBEAM_SHADEOUT ); + + // draw it + R_BeamDraw( &beam, tr.frametime ); +} + + +/* +============== +CL_DrawBeams + +draw beam loop +============== +*/ +void CL_DrawBeams( int fTrans, BEAM *active_beams ) +{ + BEAM *pBeam; + int i, flags; + + sceGuShadeModel( GU_SMOOTH ); + sceGuDepthMask( fTrans ? GU_TRUE : GU_FALSE ); + + // server beams don't allocate beam chains + // all params are stored in cl_entity_t + for( i = 0; i < tr.draw_list->num_beam_entities; i++ ) + { + RI.currentbeam = tr.draw_list->beam_entities[i]; + flags = RI.currentbeam->curstate.rendermode & 0xF0; + + if( fTrans && FBitSet( flags, FBEAM_SOLID )) + continue; + + if( !fTrans && !FBitSet( flags, FBEAM_SOLID )) + continue; + + R_BeamDrawCustomEntity( RI.currentbeam ); + r_stats.c_view_beams_count++; + } + + RI.currentbeam = NULL; + + // draw temporary entity beams + for( pBeam = active_beams; pBeam; pBeam = pBeam->next ) + { + if( fTrans && FBitSet( pBeam->flags, FBEAM_SOLID )) + continue; + + if( !fTrans && !FBitSet( pBeam->flags, FBEAM_SOLID )) + continue; + + R_BeamDraw( pBeam, gpGlobals->time - gpGlobals->oldtime ); + } + + sceGuShadeModel( GU_FLAT ); + sceGuDepthMask( GU_FALSE ); + +} diff --git a/ref_gu/gu_clipping.c b/ref_gu/gu_clipping.c new file mode 100644 index 00000000..536a8665 --- /dev/null +++ b/ref_gu/gu_clipping.c @@ -0,0 +1,416 @@ +/* +gu_clipping.c - software clipping implimentation +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +/* + +Based on clipping system from PSP Quake by Peter Mackay and Chris Swindle. + +*/ + +#include "gu_local.h" + +#define MAX_CLIPPED_VERTICES 32 + +#define CPLANE_BOTTOM 0 +#define CPLANE_LEFT 1 +#define CPLANE_RIGHT 2 +#define CPLANE_TOP 3 +#define MAX_CPLANES 4 + +// Types. +typedef ScePspFVector4 plane_type; +typedef plane_type frustum_t[MAX_CPLANES]; + +// Transformed frustum. +static ScePspFMatrix4 projection_view_matrix __attribute__( ( aligned( 16 ) ) ); +static frustum_t projection_view_frustum __attribute__( ( aligned( 16 ) ) ); +static frustum_t clipping_frustum __attribute__( ( aligned( 16 ) ) ); + +// The temporary working buffers. +static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__( ( aligned( 16 ) ) ); + +/* +================= +GU_ClipGetFrustum +================= +*/ +_inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) +{ + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0(%4)\n" // C000 = matrix->x + "lv.q C110, 16(%4)\n" // C010 = matrix->y + "lv.q C120, 32(%4)\n" // C020 = matrix->z + "lv.q C130, 48(%4)\n" // C030 = matrix->w + "vzero.q C210\n" // C000 = 0 + "vadd.q C000, R103, R101\n" // C000 = R103 + R101 ( BOTTOM ) + "vdot.q S200, C000, C000\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( BOTTOM ) + "vadd.q C010, R103, R100\n" // C010 = R103 + R100 ( LEFT ) + "vdot.q S201, C010, C010\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( LEFT ) + "vsub.q C020, R103, R100\n" // C020 = R103 - R100 ( RIGHT ) + "vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT ) + "vsub.q C030, R103, R101\n" // C030 = R103 - R101 ( TOP ) + "vdot.q S203, C030, C030\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( TOP ) + "vcmp.q EZ, C200\n" // CC[0] = ( C200 == 0.0f ) + "vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 ) + "vcmovt.q C200, C210, 0\n" // if ( CC[*] ) C200 = C210 + "vscl.q C000, C000, S200\n" // C000 = C000 * S200 ( BOTTOM ) + "vscl.q C010, C010, S201\n" // C010 = C010 * S201 ( LEFT ) + "vscl.q C020, C020, S202\n" // C020 = C020 * S202 ( RIGHT ) + "vscl.q C030, C030, S203\n" // C030 = C030 * S203 ( TOP ) + "sv.q C000, %0\n" // Store plane from register + "sv.q C010, %1\n" // Store plane from register + "sv.q C020, %2\n" // Store plane from register + "sv.q C030, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option + : "=m"( ( *frustum )[CPLANE_BOTTOM] ), + "=m"( ( *frustum )[CPLANE_LEFT] ), + "=m"( ( *frustum )[CPLANE_RIGHT] ), + "=m"( ( *frustum )[CPLANE_TOP] ) + : "r"( matrix ) /* addr */ + ); +} + +/* +================= +GU_ClipBeginFrame + +Calculate the clipping frustum for static objects +================= +*/ +void GU_ClipBeginFrame( void ) +{ + // Get the projection matrix. + sceGumMatrixMode( GU_PROJECTION ); + ScePspFMatrix4 proj; + sceGumStoreMatrix( &proj ); + + // Get the view matrix. + sceGumMatrixMode( GU_VIEW ); + ScePspFMatrix4 view; + sceGumStoreMatrix( &view ); + + // Restore matrix mode. + sceGumMatrixMode( GU_MODEL ); + + // Combine the two matrices (multiply projection by view). + gumMultMatrix( &projection_view_matrix, &proj, &view ); + + // Calculate and cache the clipping frustum. + GU_ClipGetFrustum( &projection_view_matrix, &projection_view_frustum ); + + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C700, %4\n" // Load plane into register + "lv.q C710, %5\n" // Load plane into register + "lv.q C720, %6\n" // Load plane into register + "lv.q C730, %7\n" // Load plane into register + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option + : "=m"( clipping_frustum[CPLANE_BOTTOM] ), + "=m"( clipping_frustum[CPLANE_LEFT] ), + "=m"( clipping_frustum[CPLANE_RIGHT] ), + "=m"( clipping_frustum[CPLANE_TOP] ) + : "m"( projection_view_frustum[CPLANE_BOTTOM] ), + "m"( projection_view_frustum[CPLANE_LEFT] ), + "m"( projection_view_frustum[CPLANE_RIGHT] ), + "m"( projection_view_frustum[CPLANE_TOP] ) + ); +} + +/* +================= +GU_ClipBeginBrush + +Calculate the clipping frustum for dynamic objects +================= +*/ +void GU_ClipBeginBrush( void ) +{ + // Get the model matrix. + ScePspFMatrix4 model_matrix; + sceGumStoreMatrix( &model_matrix ); + + // Combine the matrices (multiply projection-view by model). + ScePspFMatrix4 projection_view_model_matrix; + gumMultMatrix( &projection_view_model_matrix, &projection_view_matrix, &model_matrix ); + + // Calculate the clipping frustum. + GU_ClipGetFrustum( &projection_view_model_matrix, &clipping_frustum ); + + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C700, %0\n" // Load plane into register + "lv.q C710, %1\n" // Load plane into register + "lv.q C720, %2\n" // Load plane into register + "lv.q C730, %3\n" // Load plane into register + ".set pop\n" // Restore assembler option + :: "m"( clipping_frustum[CPLANE_BOTTOM] ), + "m"( clipping_frustum[CPLANE_LEFT] ), + "m"( clipping_frustum[CPLANE_RIGHT] ), + "m"( clipping_frustum[CPLANE_TOP] ) + ); +} + +/* +================= +GU_ClipEndBrush + +Restore the clipping frustum +================= +*/ +void GU_ClipEndBrush( void ) +{ + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C700, %4\n" // Load plane into register + "lv.q C710, %5\n" // Load plane into register + "lv.q C720, %6\n" // Load plane into register + "lv.q C730, %7\n" // Load plane into register + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option + : "=m"( clipping_frustum[CPLANE_BOTTOM] ), + "=m"( clipping_frustum[CPLANE_LEFT] ), + "=m"( clipping_frustum[CPLANE_RIGHT] ), + "=m"( clipping_frustum[CPLANE_TOP] ) + : "m"( projection_view_frustum[CPLANE_BOTTOM] ), + "m"( projection_view_frustum[CPLANE_LEFT] ), + "m"( projection_view_frustum[CPLANE_RIGHT] ), + "m"( projection_view_frustum[CPLANE_TOP] ) + ); +} + +/* +================= +GU_ClipLoadFrustum + +Load the clipping frustum ( native ) +================= +*/ +#if 0 +void GU_ClipLoadFrustum( const mplane_t *plane ) +{ + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "ulv.q C700, %4\n" // Load plane into register + "ulv.q C710, %5\n" // Load plane into register + "ulv.q C720, %6\n" // Load plane into register + "ulv.q C730, %7\n" // Load plane into register + "vneg.q R703, R703\n" // R703 = -R703 = -dist + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option + : "=m"( clipping_frustum[CPLANE_BOTTOM] ), + "=m"( clipping_frustum[CPLANE_LEFT] ), + "=m"( clipping_frustum[CPLANE_RIGHT] ), + "=m"( clipping_frustum[CPLANE_TOP] ) + : "m"( plane[FRUSTUM_BOTTOM] ), + "m"( plane[FRUSTUM_LEFT] ), + "m"( plane[FRUSTUM_RIGHT] ), + "m"( plane[FRUSTUM_TOP] ) + + ); +} +#endif + +/* +================= +GU_ClipIsRequired + +Is clipping required? +================= +*/ +qboolean GU_ClipIsRequired( const gu_vert_t* v, size_t vc ) +{ + int res; + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "move $8, %1\n" // $8 = &v[0] + "move $9, %2\n" // $9 = vc + "li $10, 20\n" // $10 = 20( sizeof( gu_vert_t ) ) + "mul $10, $10, $9\n" // $10 = $10 * $9 + "addu $10, $10, $8\n" // $10 = $10 + $8 + "addiu %0, $0, 1\n" // res = 1 + "vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f] + "0:\n" // loop + "lv.s S610, 8($8)\n" // S610 = v[i].xyz[0] + "lv.s S611, 12($8)\n" // S611 = v[i].xyz[1] + "lv.s S612, 16($8)\n" // S612 = v[i].xyz[2] + "vhtfm4.q C620, M700, C610\n" // C620 = frustrum * v[i].xyz + "vcmp.q LT, C620, C600\n" // S620 < 0.0f || S621 < 0.0f || S622 < 0.0f || S623 < 0.0f + "bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit + "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) ( delay slot ) + "bne $10, $8, 0b\n" // if ( $10 != $8 ) jump to loop + "nop\n" // ( delay slot ) + "move %0, $0\n" // res = 0 + "1:\n" // exit + ".set pop\n" // Restore assembler option + : "=r"( res ) + : "r"( v ), "r"( vc ) + : "$8", "$9", "$10" + ); + return res; +} + +/* +================= +GU_Clip2Plane + +Clips a polygon against a plane. +================= +*/ +_inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_vert_t *cv, size_t *cvc ) +{ + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "move $8, %1\n" // $8 = uv[0] is S + "addiu $9, $8, 20\n" // $9 = uv[1] is P + "move $10, %2\n" // $10 = uvc + "li $11, 20\n" // $11 = 20( sizeof( gu_vert_t ) ) + "mul $11, $11, $10\n" // $11 = $11 * $10 + "addu $11, $11, $8\n" // $11 = $11 + $8 + "move $12, %3\n" // $12 = &cv[0] + "move %0, $0\n" // cvc = 0 + "ulv.q C100, %4\n" // Load plane into register + "vzero.s S110\n" // Set zero for cmp + "0:\n" // loop + "lv.s S000, 0($8)\n" // Load vertex S TEX(4b) U into register + "lv.s S001, 4($8)\n" // Load vertex S TEX(4b) V into register + "lv.s S010, 8($8)\n" // Load vertex S XYZ(4b) X into register + "lv.s S011, 12($8)\n" // Load vertex S XYZ(4b) Y into register + "lv.s S012, 16($8)\n" // Load vertex S XYZ(4b) Z into register + "lv.s S020, 0($9)\n" // Load vertex P TEX(4b) U into register + "lv.s S021, 4($9)\n" // Load vertex P TEX(4b) V into register + "lv.s S030, 8($9)\n" // Load vertex P XYZ(4b) X into register + "lv.s S031, 12($9)\n" // Load vertex P XYZ(4b) Y into register + "lv.s S032, 16($9)\n" // Load vertex P XYZ(4b) Z into register + "vhdp.q S111, C010, C100\n" // S111 = plane * S (S DIST) + "vhdp.q S112, C030, C100\n" // S112 = plane * P (P DIST) + "vcmp.s LE, S111, S110\n" // (S dist <= 0.0f) + "bvt 0, 2f\n" // if ( CC[0] == 1 ) jump to 2f + "nop\n" // ( delay slot ) + "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) + "bvt 0, 1f\n" // if ( CC[0] == 1 ) jump to 1f + "nop\n" // ( delay slot ) + "sv.s S020, 0($12)\n" // cv->uv[0] = C020 TEX U + "sv.s S021, 4($12)\n" // cv->uv[1] = C021 TEX V + "sv.s S030, 8($12)\n" // cv->xyz[0] = C030 XYZ X + "sv.s S031, 12($12)\n" // cv->xyz[1] = C031 XYZ Y + "sv.s S032, 16($12)\n" // cv->xyz[2] = C032 XYZ Z + "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) + "j 3f\n" // jump to next + "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) + "1:\n" + "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) + "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 + "vsub.p C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX) + "vsub.t C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ) + "vscl.p C120, C120, S112\n" // C120 = C020 * S112 + "vscl.t C130, C130, S112\n" // C130 = C030 * S112 + "vadd.p C120, C120, C000\n" // C120 = C120 + C000(S TEX) + "vadd.t C130, C130, C010\n" // C130 = C130 + C010(S XYZ) + "sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U + "sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V + "sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X + "sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y + "sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z + "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) + "j 3f\n" // jump to next + "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) + "2:\n" + "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) + "bvt 0, 3f\n" // if ( CC[0] == 1 ) jump to next + "nop\n" // ( delay slot ) + "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) + "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 + "vsub.p C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX) + "vsub.t C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ) + "vscl.p C120, C120, S112\n" // C120 = C020 * S112 + "vscl.t C130, C130, S112\n" // C130 = C030 * S112 + "vadd.p C120, C120, C000\n" // C120 = C120 + C000(S TEX) + "vadd.t C130, C130, C010\n" // C130 = C130 + C010(S XYZ) + "sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U + "sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V + "sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X + "sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y + "sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z + "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) + "addiu %0, %0, 1\n" // cvc += 1 + "sv.s S020, 0($12)\n" // cv->uv[0] = S020 TEX U + "sv.s S021, 4($12)\n" // cv->uv[1] = S021 TEX V + "sv.s S030, 8($12)\n" // cv->xyz[0] = S030 XYZ X + "sv.s S031, 12($12)\n" // cv->xyz[1] = S031 XYZ Y + "sv.s S032, 16($12)\n" // cv->xyz[2] = S032 XYZ Z + "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) + "addiu %0, %0, 1\n" // cvc += 1 + "3:\n" // next + "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) + "addiu $9, $8, 20\n" // $9 = $8 + 20( sizeof( gu_vert_t ) ) + "bne $9, $11, 4f\n" // if ( $11 != $9 ) jump to next + "nop\n" + "move $9, %1\n" // $9 = &uv[0] set P + "4:\n" + "bne $11, $8, 0b\n" // if ( $11 != $8 ) jump to loop + "nop\n" // ( delay slot ) + ".set pop\n" // Restore assembler option + : "+r"( *cvc ) + : "r"( uv ), "r"( uvc ), "r"( cv ), "m"( *plane ) + : "$8", "$9", "$10", "$11", "$12" + ); +} + +/* +================= +GU_Clip + +Clips a polygon against the frustum +================= +*/ +void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ) +{ + size_t vc; + + if ( !uvc ) // no vertices to clip? + gEngfuncs.Host_Error( "GU_Clip: calling clip with zero vertices!" ); + + vc = uvc; + *cvc = 0; + + GU_Clip2Plane( &clipping_frustum[CPLANE_BOTTOM], uv, vc, work_buffer[0], &vc ); + if ( !vc ) return; + GU_Clip2Plane( &clipping_frustum[CPLANE_LEFT], work_buffer[0], vc, work_buffer[1], &vc ); + if ( !vc ) return; + GU_Clip2Plane( &clipping_frustum[CPLANE_RIGHT], work_buffer[1], vc, work_buffer[0], &vc ); + if ( !vc ) return; + *cv = extGuBeginPacket( NULL ); // uncached + GU_Clip2Plane( &clipping_frustum[CPLANE_TOP], work_buffer[0], vc, *cv, cvc ); + if ( !cvc ) return; + extGuEndPacket( ( void * )( *cv + *cvc ) ); +} \ No newline at end of file diff --git a/ref_gu/gu_context.c b/ref_gu/gu_context.c new file mode 100644 index 00000000..32d3a1fc --- /dev/null +++ b/ref_gu/gu_context.c @@ -0,0 +1,515 @@ +/* +vid_sdl.c - SDL vid component +Copyright (C) 2018 a1batross +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +// GL API function pointers, if any, reside in this translation unit +#define APIENTRY_LINKAGE +#include "gu_local.h" + +ref_api_t gEngfuncs; +ref_globals_t *gpGlobals; + +static void R_ClearScreen( void ) +{ + sceGuClearColor( 0x00000000 ); + sceGuClear( GU_COLOR_BUFFER_BIT ); +} + +static const byte *R_GetTextureOriginalBuffer( unsigned int idx ) +{ + gl_texture_t *glt = R_GetTexture( idx ); + + if( !glt || !glt->original || !glt->original->buffer ) + return NULL; + + return glt->original->buffer; +} + +/* +============= +CL_FillRGBA + +============= +*/ +static void CL_FillRGBA( float _x, float _y, float _w, float _h, int r, int g, int b, int a ) +{ + sceGuDisable( GU_TEXTURE_2D ); + sceGuEnable( GU_BLEND ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + sceGuColor( GUCOLOR4UB( r, g, b, a ) ); + + gu_vert_hv_t* const out = ( gu_vert_hv_t* )sceGuGetMemory( sizeof( gu_vert_hv_t ) * 2 ); + out[0].x = _x; + out[0].y = _y; + out[0].z = 0; + out[1].x = _x + _w; + out[1].y = _y + _h; + out[1].z = 0; + sceGuDrawArray( GU_SPRITES, GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out ); + + sceGuColor( 0xffffffff ); + sceGuEnable( GU_TEXTURE_2D ); + sceGuDisable( GU_BLEND ); +} + +/* +============= +pfnFillRGBABlend + +============= +*/ +static void GAME_EXPORT CL_FillRGBABlend( float _x, float _y, float _w, float _h, int r, int g, int b, int a ) +{ + sceGuDisable( GU_TEXTURE_2D ); + sceGuEnable( GU_BLEND ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_DST_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4UB( r, g, b, a ) ); + + gu_vert_hv_t* const out = ( gu_vert_hv_t* )sceGuGetMemory( sizeof( gu_vert_hv_t ) * 2 ); + out[0].x = _x; + out[0].y = _y; + out[0].z = 0; + out[1].x = _x + _w; + out[1].y = _y + _h; + out[1].z = 0; + sceGuDrawArray( GU_SPRITES, GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out ); + + sceGuColor( 0xffffffff ); + sceGuEnable( GU_TEXTURE_2D ); + sceGuDisable( GU_BLEND ); +} + +void Mod_BrushUnloadTextures( model_t *mod ) +{ + int i; + + for( i = 0; i < mod->numtextures; i++ ) + { + texture_t *tx = mod->textures[i]; + if( !tx || tx->gl_texturenum == tr.defaultTexture ) + continue; // free slot + + GL_FreeTexture( tx->gl_texturenum ); // main texture + GL_FreeTexture( tx->fb_texturenum ); // luma texture + } +} + +void Mod_UnloadTextures( model_t *mod ) +{ + Assert( mod != NULL ); + + switch( mod->type ) + { + case mod_studio: + Mod_StudioUnloadTextures( mod->cache.data ); + break; + case mod_alias: + Mod_AliasUnloadTextures( mod->cache.data ); + break; + case mod_brush: + Mod_BrushUnloadTextures( mod ); + break; + case mod_sprite: + Mod_SpriteUnloadTextures( mod->cache.data ); + break; + default: + ASSERT( 0 ); + break; + } +} + +qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf ) +{ + qboolean loaded = true; + + if( create ) + { + switch( mod->type ) + { + case mod_studio: + // Mod_LoadStudioModel( mod, buf, loaded ); + break; + case mod_sprite: + Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo ); + break; + case mod_alias: + Mod_LoadAliasModel( mod, buf, &loaded ); + break; + case mod_brush: + // Mod_LoadBrushModel( mod, buf, loaded ); + break; + default: gEngfuncs.Host_Error( "Mod_LoadModel: unsupported type %d\n", mod->type ); + } + } + + if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData ) + gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf ); + + if( !create ) + Mod_UnloadTextures( mod ); + + return loaded; +} + +static int GL_RefGetParm( int parm, int arg ) +{ + gl_texture_t *glt; + + switch( parm ) + { + case PARM_TEX_WIDTH: + glt = R_GetTexture( arg ); + return glt->width; + case PARM_TEX_HEIGHT: + glt = R_GetTexture( arg ); + return glt->height; + case PARM_TEX_SRC_WIDTH: + glt = R_GetTexture( arg ); + return glt->srcWidth; + case PARM_TEX_SRC_HEIGHT: + glt = R_GetTexture( arg ); + return glt->srcHeight; + case PARM_TEX_GLFORMAT: + glt = R_GetTexture( arg ); + return glt->format; + case PARM_TEX_ENCODE: + glt = R_GetTexture( arg ); + return glt->encode; + case PARM_TEX_MIPCOUNT: + glt = R_GetTexture( arg ); + return glt->numMips; + case PARM_TEX_DEPTH: + glt = R_GetTexture( arg ); + return glt->depth; + case PARM_TEX_SKYBOX: + Assert( arg >= 0 && arg < 6 ); + return tr.skyboxTextures[arg]; + case PARM_TEX_SKYTEXNUM: + return tr.skytexturenum; + case PARM_TEX_LIGHTMAP: + arg = bound( 0, arg, MAX_LIGHTMAPS - 1 ); + return tr.lightmapTextures[arg]; + case PARM_WIDESCREEN: + return gpGlobals->wideScreen; + case PARM_FULLSCREEN: + return gpGlobals->fullScreen; + case PARM_SCREEN_WIDTH: + return gpGlobals->width; + case PARM_SCREEN_HEIGHT: + return gpGlobals->height; + case PARM_TEX_TARGET: + /*glt = R_GetTexture( arg );*/ + return /*glt->target*/0; + case PARM_TEX_TEXNUM: + /*glt = R_GetTexture( arg );*/ + return /*glt->texnum*/0; + case PARM_TEX_FLAGS: + glt = R_GetTexture( arg ); + return glt->flags; + case PARM_ACTIVE_TMU: + return 0; + case PARM_LIGHTSTYLEVALUE: + arg = bound( 0, arg, MAX_LIGHTSTYLES - 1 ); + return tr.lightstylevalue[arg]; + case PARM_MAX_IMAGE_UNITS: + return 1; + case PARM_REBUILD_GAMMA: + return glConfig.softwareGammaUpdate; + case PARM_SURF_SAMPLESIZE: + if( arg >= 0 && arg < WORLDMODEL->numsurfaces ) + return gEngfuncs.Mod_SampleSizeForFace( &WORLDMODEL->surfaces[arg] ); + return LM_SAMPLE_SIZE; + case PARM_GL_CONTEXT_TYPE: + return CONTEXT_TYPE_GL; + case PARM_GLES_WRAPPER: + return GLES_WRAPPER_NONE; + case PARM_STENCIL_ACTIVE: + return glState.stencilEnabled; + case PARM_SKY_SPHERE: + return ENGINE_GET_PARM_( parm, arg ) && !tr.fCustomSkybox; + default: + return ENGINE_GET_PARM_( parm, arg ); + } + return 0; +} + +static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale ) +{ + gl_texture_t *glt = R_GetTexture( texture ); + + if( xScale ) *xScale = glt->xscale; + if( yScale ) *yScale = glt->yscale; +} + +static void R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density ) +{ + gl_texture_t *glt = R_GetTexture( texture ); + + if( red ) *red = glt->fogParams[0]; + if( green ) *green = glt->fogParams[1]; + if( blue ) *blue = glt->fogParams[2]; + if( density ) *density = glt->fogParams[3]; +} + + +static void R_SetCurrentEntity( cl_entity_t *ent ) +{ + RI.currententity = ent; + + // set model also + if( RI.currententity != NULL ) + { + RI.currentmodel = RI.currententity->model; + } +} + +static void R_SetCurrentModel( model_t *mod ) +{ + RI.currentmodel = mod; +} + +static float R_GetFrameTime( void ) +{ + return tr.frametime; +} + +static const char *GL_TextureName( unsigned int texnum ) +{ + return R_GetTexture( texnum )->name; +} + +const byte *GL_TextureData( unsigned int texnum ) +{ + rgbdata_t *pic = R_GetTexture( texnum )->original; + + if( pic != NULL ) + return pic->buffer; + return NULL; +} + +void R_ProcessEntData( qboolean allocate ) +{ + if( !allocate ) + { + tr.draw_list->num_solid_entities = 0; + tr.draw_list->num_trans_entities = 0; + tr.draw_list->num_beam_entities = 0; + } + + if( gEngfuncs.drawFuncs->R_ProcessEntData ) + gEngfuncs.drawFuncs->R_ProcessEntData( allocate ); +} + +qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int offset_x, int offset_y, float scale_x, float scale_y ) +{ + qboolean ret = true; + if( rotate > 0 ) + { + gEngfuncs.Con_Printf("rotation transform not supported\n"); + ret = false; + } + + if( offset_x || offset_y ) + { + gEngfuncs.Con_Printf("offset transform not supported\n"); + ret = false; + } + + if( scale_x != 1.0f || scale_y != 1.0f ) + { + gEngfuncs.Con_Printf("scale transform not supported\n"); + ret = false; + } + + return ret; +} + +static void* GAME_EXPORT R_GetProcAddress( const char *name ) +{ + return gEngfuncs.GL_GetProcAddress( name ); +} + +static const char *R_GetConfigName( void ) +{ + return "ref_gu"; +} + +ref_interface_t gReffuncs = +{ + R_Init, + R_Shutdown, + R_GetConfigName, + R_SetDisplayTransform, + + GL_SetupAttributes, + GL_InitExtensions, + GL_ClearExtensions, + + R_BeginFrame, + R_RenderScene, + R_EndFrame, + R_PushScene, + R_PopScene, + GL_BackendStartFrame, + GL_BackendEndFrame, + + R_ClearScreen, + R_AllowFog, + GL_SetRenderMode, + + R_AddEntity, + CL_AddCustomBeam, + R_ProcessEntData, + + R_ShowTextures, + + R_GetTextureOriginalBuffer, + GL_LoadTextureFromBuffer, + GL_ProcessTexture, + R_SetupSky, + + R_Set2DMode, + R_DrawStretchRaw, + R_DrawStretchPic, + R_DrawTileClear, + CL_FillRGBA, + CL_FillRGBABlend, + + VID_ScreenShot, + VID_CubemapShot, + + R_LightPoint, + + R_DecalShoot, + R_DecalRemoveAll, + R_CreateDecalList, + R_ClearAllDecals, + + R_StudioEstimateFrame, + R_StudioLerpMovement, + CL_InitStudioAPI, + + R_InitSkyClouds, + GL_SubdivideSurface, + CL_RunLightStyles, + + R_GetSpriteParms, + R_GetSpriteTexture, + + Mod_LoadMapSprite, + Mod_ProcessRenderData, + Mod_StudioLoadTextures, + + CL_DrawParticles, + CL_DrawTracers, + CL_DrawBeams, + R_BeamCull, + + GL_RefGetParm, + R_GetDetailScaleForTexture, + R_GetExtraParmsForTexture, + R_GetFrameTime, + + R_SetCurrentEntity, + R_SetCurrentModel, + + GL_FindTexture, + GL_TextureName, + GL_TextureData, + GL_LoadTexture, + GL_CreateTexture, + GL_LoadTextureArray, + GL_CreateTextureArray, + GL_FreeTexture, + + DrawSingleDecal, + R_DecalSetupVerts, + R_EntityRemoveDecals, + + R_UploadStretchRaw, + + GL_Bind, + GL_SelectTexture, + GL_LoadTexMatrixExt, + GL_LoadIdentityTexMatrix, + GL_CleanUpTextureUnits, + GL_TexGen, + GL_TextureTarget, + GL_SetTexCoordArrayMode, + GL_UpdateTexSize, + NULL, + NULL, + + CL_DrawParticlesExternal, + R_LightVec, + R_StudioGetTexture, + + R_RenderFrame, + Mod_SetOrthoBounds, + R_SpeedsMessage, + Mod_GetCurrentVis, + R_NewMap, + R_ClearScene, + R_GetProcAddress, + + TriRenderMode, + TriBegin, + TriEnd, + _TriColor4f, + _TriColor4ub, + TriTexCoord2f, + TriVertex3fv, + TriVertex3f, + TriWorldToScreen, + TriFog, + R_ScreenToWorld, + TriGetMatrix, + TriFogParams, + TriCullFace, + + VGUI_DrawInit, + VGUI_DrawShutdown, + VGUI_SetupDrawingText, + VGUI_SetupDrawingRect, + VGUI_SetupDrawingImage, + VGUI_BindTexture, + VGUI_EnableTexture, + VGUI_CreateTexture, + VGUI_UploadTexture, + VGUI_UploadTextureBlock, + VGUI_DrawQuad, + VGUI_GetTextureSizes, + VGUI_GenerateTexture, +}; + +int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals ) +{ + if( version != REF_API_VERSION ) + return 0; + + // fill in our callbacks + memcpy( funcs, &gReffuncs, sizeof( ref_interface_t )); + memcpy( &gEngfuncs, engfuncs, sizeof( ref_api_t )); + gpGlobals = globals; + + return REF_API_VERSION; +} + +void EXPORT GetRefHumanReadableName( char *out, size_t size ) +{ + Q_strncpy( out, "sceGu", size ); +} diff --git a/ref_gu/gu_cull.c b/ref_gu/gu_cull.c new file mode 100644 index 00000000..782ba4e5 --- /dev/null +++ b/ref_gu/gu_cull.c @@ -0,0 +1,149 @@ +/* +gl_cull.c - render culling routines +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "entity_types.h" + +/* +============================================================= + +FRUSTUM AND PVS CULLING + +============================================================= +*/ +/* +================= +R_CullBox + +Returns true if the box is completely outside the frustum +================= +*/ +qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ) +{ + return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 ); +} + +/* +================= +R_CullSphere + +Returns true if the sphere is completely outside the frustum +================= +*/ +qboolean R_CullSphere( const vec3_t centre, const float radius ) +{ + return GL_FrustumCullSphere( &RI.frustum, centre, radius, 0 ); +} + +/* +============= +R_CullModel +============= +*/ +int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax ) +{ + if( e == gEngfuncs.GetViewModel() ) + { + if( ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) + return 1; + + if( RP_NORMALPASS() && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer()) + return 0; + + return 1; + } + + // local client can't view himself if camera or thirdperson is not active + if( RP_LOCALCLIENT( e ) && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer()) + return 1; + + if( R_CullBox( absmin, absmax )) + return 1; + + return 0; +} + +/* +================= +R_CullSurface + +cull invisible surfaces +================= +*/ +int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags ) +{ + cl_entity_t *e = RI.currententity; + + if( !surf || !surf->texinfo || !surf->texinfo->texture ) + return CULL_OTHER; + + if( r_nocull->value ) + return CULL_VISIBLE; + + // world surfaces can be culled by vis frame too + if( RI.currententity == gEngfuncs.GetEntityByIndex( 0 ) && surf->visframe != tr.framecount ) + return CULL_VISFRAME; + + // only static ents can be culled by frustum + if( !R_StaticEntity( e )) frustum = NULL; + + if( !VectorIsNull( surf->plane->normal )) + { + float dist; + + // can use normal.z for world (optimisation) + if( RI.drawOrtho ) + { + vec3_t orthonormal; + + if( e == gEngfuncs.GetEntityByIndex( 0 ) ) orthonormal[2] = surf->plane->normal[2]; + else Matrix4x4_VectorRotate( RI.objectMatrix, surf->plane->normal, orthonormal ); + dist = orthonormal[2]; + } + else dist = PlaneDiff( tr.modelorg, surf->plane ); + + if( glState.faceCull == GL_FRONT ) + { + if( FBitSet( surf->flags, SURF_PLANEBACK )) + { + if( dist >= -BACKFACE_EPSILON ) + return CULL_BACKSIDE; // wrong side + } + else + { + if( dist <= BACKFACE_EPSILON ) + return CULL_BACKSIDE; // wrong side + } + } + else if( glState.faceCull == GL_BACK ) + { + if( FBitSet( surf->flags, SURF_PLANEBACK )) + { + if( dist <= BACKFACE_EPSILON ) + return CULL_BACKSIDE; // wrong side + } + else + { + if( dist >= -BACKFACE_EPSILON ) + return CULL_BACKSIDE; // wrong side + } + } + } + + if( frustum && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags )) + return CULL_FRUSTUM; + + return CULL_VISIBLE; +} diff --git a/ref_gu/gu_dbghulls.c b/ref_gu/gu_dbghulls.c new file mode 100644 index 00000000..5d340ff7 --- /dev/null +++ b/ref_gu/gu_dbghulls.c @@ -0,0 +1,124 @@ +/* +gl_dbghulls.c - loading & handling world and brushmodels +Copyright (C) 2016 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "mod_local.h" + +#define list_entry( ptr, type, member ) \ + ((type *)((char *)(ptr) - (size_t)(&((type *)0)->member))) + +// iterate over each entry in the list +#define list_for_each_entry( pos, head, member ) \ + for( pos = list_entry( (head)->next, winding_t, member ); \ + &pos->member != (head); \ + pos = list_entry( pos->member.next, winding_t, member )) + +// REFTODO: rewrite in triapi +void R_DrawWorldHull( void ) +{ + hull_model_t *hull = &WORLD->hull_models[0]; + winding_t *poly; + int i; + + if( FBitSet( r_showhull->flags, FCVAR_CHANGED )) + { + int val = bound( 0, (int)r_showhull->value, 3 ); + if( val ) gEngfuncs.Mod_CreatePolygonsForHull( val ); + ClearBits( r_showhull->flags, FCVAR_CHANGED ); + } + + if( !CVAR_TO_BOOL( r_showhull )) + return; +#if 1 + sceGuDisable( GU_TEXTURE_2D ); + list_for_each_entry( poly, &hull->polys, chain ) + { + srand((unsigned int)poly); + sceGuColor( GU_RGBA(rand() % 256, rand() % 256, rand() % 256, rand() % 256) ); + gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * poly->numpoints ); + for( i = 0; i < poly->numpoints; i++ ) + { + out[i].x = poly->p[i][0]; + out[i].y = poly->p[i][1]; + out[i].z = poly->p[i][2]; + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_VERTEX_32BITF, poly->numpoints, 0, out ); + } + sceGuEnable( GU_TEXTURE_2D ); +#else + pglDisable( GL_TEXTURE_2D ); + list_for_each_entry( poly, &hull->polys, chain ) + { + srand((unsigned int)poly); + pglColor3f( rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0 ); + pglBegin( GL_POLYGON ); + for( i = 0; i < poly->numpoints; i++ ) + pglVertex3fv( poly->p[i] ); + pglEnd(); + } + pglEnable( GL_TEXTURE_2D ); +#endif +} + +void R_DrawModelHull( void ) +{ + hull_model_t *hull; + winding_t *poly; + int i; + + if( !CVAR_TO_BOOL( r_showhull )) + return; + + if( !RI.currentmodel || RI.currentmodel->name[0] != '*' ) + return; + + i = atoi( RI.currentmodel->name + 1 ); + if( i < 1 || i >= WORLD->num_hull_models ) + return; + + hull = &WORLD->hull_models[i]; +#if 1 + sceGuDisable( GU_TEXTURE_2D ); + list_for_each_entry( poly, &hull->polys, chain ) + { + srand((unsigned int)poly); + sceGuColor( GU_RGBA(rand() % 256, rand() % 256, rand() % 256, rand() % 256) ); + gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * poly->numpoints ); + for( i = 0; i < poly->numpoints; i++ ) + { + out[i].x = poly->p[i][0]; + out[i].y = poly->p[i][1]; + out[i].z = poly->p[i][2]; + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_VERTEX_32BITF, poly->numpoints, 0, out ); + } + sceGuEnable( GU_TEXTURE_2D ); +#else + pglPolygonOffset( 1.0f, 2.0 ); + pglEnable( GL_POLYGON_OFFSET_FILL ); + pglDisable( GL_TEXTURE_2D ); + list_for_each_entry( poly, &hull->polys, chain ) + { + srand((unsigned int)poly); + pglColor3f( rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0 ); + pglBegin( GL_POLYGON ); + for( i = 0; i < poly->numpoints; i++ ) + pglVertex3fv( poly->p[i] ); + pglEnd(); + } + pglEnable( GL_TEXTURE_2D ); + pglDisable( GL_POLYGON_OFFSET_FILL ); +#endif +} diff --git a/ref_gu/gu_decals.c b/ref_gu/gu_decals.c new file mode 100644 index 00000000..a3e52985 --- /dev/null +++ b/ref_gu/gu_decals.c @@ -0,0 +1,1268 @@ +/* +gl_decals.c - decal paste and rendering +Copyright (C) 2010 Uncle Mike +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "cl_tent.h" + +#define DECAL_OVERLAP_DISTANCE 2 +#define DECAL_DISTANCE 4 // too big values produce more clipped polygons +#define MAX_DECALCLIPVERT 32 // produced vertexes of fragmented decal +#define DECAL_CACHEENTRY 256 // MUST BE POWER OF 2 or code below needs to change! +#define DECAL_TRANSPARENT_THRESHOLD 230 // transparent decals draw with GL_MODULATE + +// empirically determined constants for minimizing overalpping decals +#define MAX_OVERLAP_DECALS 6 +#define DECAL_OVERLAP_DIST 8 +#define MIN_DECAL_SCALE 0.01f +#define MAX_DECAL_SCALE 16.0f + +// clip edges +#define LEFT_EDGE 0 +#define RIGHT_EDGE 1 +#define TOP_EDGE 2 +#define BOTTOM_EDGE 3 + +// This structure contains the information used to create new decals +typedef struct +{ + vec3_t m_Position; // world coordinates of the decal center + model_t *m_pModel; // the model the decal is going to be applied in + int m_iTexture; // The decal material + int m_Size; // Size of the decal (in world coords) + int m_Flags; + int m_Entity; // Entity the decal is applied to. + float m_scale; + int m_decalWidth; + int m_decalHeight; + vec3_t m_Basis[3]; +} decalinfo_t; + +static float g_DecalClipVerts[MAX_DECALCLIPVERT][VERTEXSIZE]; +static float g_DecalClipVerts2[MAX_DECALCLIPVERT][VERTEXSIZE]; + +decal_t gDecalPool[MAX_RENDER_DECALS]; +static int gDecalCount; + +void R_ClearDecals( void ) +{ + memset( gDecalPool, 0, sizeof( gDecalPool )); + gDecalCount = 0; +} + +// unlink pdecal from any surface it's attached to +static void R_DecalUnlink( decal_t *pdecal ) +{ + decal_t *tmp; + + if( pdecal->psurface ) + { + if( pdecal->psurface->pdecals == pdecal ) + { + pdecal->psurface->pdecals = pdecal->pnext; + } + else + { + tmp = pdecal->psurface->pdecals; + if( !tmp ) gEngfuncs.Host_Error( "R_DecalUnlink: bad decal list\n" ); + + while( tmp->pnext ) + { + if( tmp->pnext == pdecal ) + { + tmp->pnext = pdecal->pnext; + break; + } + tmp = tmp->pnext; + } + } + } + + if( pdecal->polys ) + Mem_Free( pdecal->polys ); + + pdecal->psurface = NULL; + pdecal->polys = NULL; +} + +// Just reuse next decal in list +// A decal that spans multiple surfaces will use multiple decal_t pool entries, +// as each surface needs it's own. +static decal_t *R_DecalAlloc( decal_t *pdecal ) +{ + int limit = MAX_RENDER_DECALS; + + if( r_decals->value < limit ) + limit = r_decals->value; + + if( !limit ) return NULL; + + if( !pdecal ) + { + int count = 0; + + // check for the odd possiblity of infinte loop + do + { + if( gDecalCount >= limit ) + gDecalCount = 0; + + pdecal = &gDecalPool[gDecalCount]; // reuse next decal + gDecalCount++; + count++; + } while( FBitSet( pdecal->flags, FDECAL_PERMANENT ) && count < limit ); + } + + // if decal is already linked to a surface, unlink it. + R_DecalUnlink( pdecal ); + + return pdecal; +} + +//----------------------------------------------------------------------------- +// find decal image and grab size from it +//----------------------------------------------------------------------------- +static void R_GetDecalDimensions( int texture, int *width, int *height ) +{ + if( width ) *width = 1; // to avoid divide by zero + if( height ) *height = 1; + + R_GetTextureParms( width, height, texture ); +} + +//----------------------------------------------------------------------------- +// compute the decal basis based on surface normal +//----------------------------------------------------------------------------- +void R_DecalComputeBasis( msurface_t *surf, int flags, vec3_t textureSpaceBasis[3] ) +{ + vec3_t surfaceNormal; + + // setup normal + if( surf->flags & SURF_PLANEBACK ) + VectorNegate( surf->plane->normal, surfaceNormal ); + else VectorCopy( surf->plane->normal, surfaceNormal ); + + VectorNormalize2( surfaceNormal, textureSpaceBasis[2] ); +#if 0 + if( FBitSet( flags, FDECAL_CUSTOM )) + { + vec3_t pSAxis = { 1, 0, 0 }; + + // T = S cross N + CrossProduct( pSAxis, textureSpaceBasis[2], textureSpaceBasis[1] ); + + // Name sure they aren't parallel or antiparallel + // In that case, fall back to the normal algorithm. + if( DotProduct( textureSpaceBasis[1], textureSpaceBasis[1] ) > 1e-6 ) + { + // S = N cross T + CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] ); + + VectorNormalizeFast( textureSpaceBasis[0] ); + VectorNormalizeFast( textureSpaceBasis[1] ); + return; + } + // Fall through to the standard algorithm for parallel or antiparallel + } +#endif + VectorNormalize2( surf->texinfo->vecs[0], textureSpaceBasis[0] ); + VectorNormalize2( surf->texinfo->vecs[1], textureSpaceBasis[1] ); +} + +void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] ) +{ + int width, height; + + // Compute the non-scaled decal basis + R_DecalComputeBasis( surf, pDecal->flags, textureSpaceBasis ); + R_GetDecalDimensions( texture, &width, &height ); + + // world width of decal = ptexture->width / pDecal->scale + // world height of decal = ptexture->height / pDecal->scale + // scale is inverse, scales world space to decal u/v space [0,1] + // OPTIMIZE: Get rid of these divides + decalWorldScale[0] = (float)pDecal->scale / width; + decalWorldScale[1] = (float)pDecal->scale / height; + + VectorScale( textureSpaceBasis[0], decalWorldScale[0], textureSpaceBasis[0] ); + VectorScale( textureSpaceBasis[1], decalWorldScale[1], textureSpaceBasis[1] ); +} + +// Build the initial list of vertices from the surface verts into the global array, 'verts'. +void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t textureSpaceBasis[3], float *verts ) +{ + float *v; + int i; + + for( i = 0; i < surf->polys->numverts; i++, verts += VERTEXSIZE ) + { + VectorCopy( surf->polys->verts[i].xyz, verts ); // copy model space coordinates + verts[3] = DotProduct( verts, textureSpaceBasis[0] ) - pDecal->dx + 0.5f; + verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - pDecal->dy + 0.5f; + verts[5] = verts[6] = 0.0f; + } +} + +// Figure out where the decal maps onto the surface. +void R_SetupDecalClip( decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] ) +{ + R_SetupDecalTextureSpaceBasis( pDecal, surf, texture, textureSpaceBasis, decalWorldScale ); + + // Generate texture coordinates for each vertex in decal s,t space + // probably should pre-generate this, store it and use it for decal-decal collisions + // as in R_DecalsIntersect() + pDecal->dx = DotProduct( pDecal->position, textureSpaceBasis[0] ); + pDecal->dy = DotProduct( pDecal->position, textureSpaceBasis[1] ); +} + +// Quick and dirty sutherland Hodgman clipper +// Clip polygon to decal in texture space +// JAY: This code is lame, change it later. It does way too much work per frame +// It can be made to recursively call the clipping code and only copy the vertex list once +int R_ClipInside( float *vert, int edge ) +{ + switch( edge ) + { + case LEFT_EDGE: + if( vert[3] > 0.0f ) + return 1; + return 0; + case RIGHT_EDGE: + if( vert[3] < 1.0f ) + return 1; + return 0; + case TOP_EDGE: + if( vert[4] > 0.0f ) + return 1; + return 0; + case BOTTOM_EDGE: + if( vert[4] < 1.0f ) + return 1; + return 0; + } + return 0; +} + +void R_ClipIntersect( float *one, float *two, float *out, int edge ) +{ + float t; + + // t is the parameter of the line between one and two clipped to the edge + // or the fraction of the clipped point between one & two + // vert[0], vert[1], vert[2] is X, Y, Z + // vert[3] is u + // vert[4] is v + // vert[5] is lightmap u + // vert[6] is lightmap v + + if( edge < TOP_EDGE ) + { + if( edge == LEFT_EDGE ) + { + // left + t = ((one[3] - 0.0f) / (one[3] - two[3])); + out[3] = out[5] = 0.0f; + } + else + { + // right + t = ((one[3] - 1.0f) / (one[3] - two[3])); + out[3] = out[5] = 1.0f; + } + + out[4] = one[4] + (two[4] - one[4]) * t; + out[6] = one[6] + (two[6] - one[6]) * t; + } + else + { + if( edge == TOP_EDGE ) + { + // top + t = ((one[4] - 0.0f) / (one[4] - two[4])); + out[4] = out[6] = 0.0f; + } + else + { + // bottom + t = ((one[4] - 1.0f) / (one[4] - two[4])); + out[4] = out[6] = 1.0f; + } + + out[3] = one[3] + (two[3] - one[3]) * t; + out[5] = one[5] + (two[4] - one[5]) * t; + } + + VectorLerp( one, t, two, out ); +} + +static int SHClip( float *vert, int vertCount, float *out, int edge ) +{ + int j, outCount; + float *s, *p; + + outCount = 0; + + s = &vert[(vertCount - 1) * VERTEXSIZE]; + + for( j = 0; j < vertCount; j++ ) + { + p = &vert[j * VERTEXSIZE]; + + if( R_ClipInside( p, edge )) + { + if( R_ClipInside( s, edge )) + { + // Add a vertex and advance out to next vertex + memcpy( out, p, sizeof( float ) * VERTEXSIZE ); + out += VERTEXSIZE; + outCount++; + } + else + { + R_ClipIntersect( s, p, out, edge ); + out += VERTEXSIZE; + outCount++; + + memcpy( out, p, sizeof( float ) * VERTEXSIZE ); + out += VERTEXSIZE; + outCount++; + } + } + else + { + if( R_ClipInside( s, edge )) + { + R_ClipIntersect( p, s, out, edge ); + out += VERTEXSIZE; + outCount++; + } + } + + s = p; + } + + return outCount; +} + +float *R_DoDecalSHClip( float *pInVerts, decal_t *pDecal, int nStartVerts, int *pVertCount ) +{ + float *pOutVerts = g_DecalClipVerts[0]; + int outCount; + + // clip the polygon to the decal texture space + outCount = SHClip( pInVerts, nStartVerts, g_DecalClipVerts2[0], LEFT_EDGE ); + outCount = SHClip( g_DecalClipVerts2[0], outCount, g_DecalClipVerts[0], RIGHT_EDGE ); + outCount = SHClip( g_DecalClipVerts[0], outCount, g_DecalClipVerts2[0], TOP_EDGE ); + outCount = SHClip( g_DecalClipVerts2[0], outCount, pOutVerts, BOTTOM_EDGE ); + + if( pVertCount ) + *pVertCount = outCount; + + return pOutVerts; +} + +//----------------------------------------------------------------------------- +// Generate clipped vertex list for decal pdecal projected onto polygon psurf +//----------------------------------------------------------------------------- +float *R_DecalVertsClip( decal_t *pDecal, msurface_t *surf, int texture, int *pVertCount ) +{ + float decalWorldScale[2]; + vec3_t textureSpaceBasis[3]; + + // figure out where the decal maps onto the surface. + R_SetupDecalClip( pDecal, surf, texture, textureSpaceBasis, decalWorldScale ); + + // build the initial list of vertices from the surface verts. + R_SetupDecalVertsForMSurface( pDecal, surf, textureSpaceBasis, g_DecalClipVerts[0] ); + + return R_DoDecalSHClip( g_DecalClipVerts[0], pDecal, surf->polys->numverts, pVertCount ); +} + +// Generate lighting coordinates at each vertex for decal vertices v[] on surface psurf +static void R_DecalVertsLight( float *v, msurface_t *surf, int vertCount ) +{ + float s, t; + mtexinfo_t *tex; + mextrasurf_t *info = surf->info; + float sample_size; + int j; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + tex = surf->texinfo; + + for( j = 0; j < vertCount; j++, v += VERTEXSIZE ) + { + // lightmap texture coordinates + s = DotProduct( v, info->lmvecs[0] ) + info->lmvecs[0][3] - info->lightmapmins[0]; + s += surf->light_s * sample_size; + s += sample_size * 0.5f; + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width; + + t = DotProduct( v, info->lmvecs[1] ) + info->lmvecs[1][3] - info->lightmapmins[1]; + t += surf->light_t * sample_size; + t += sample_size * 0.5f; + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height; + + v[5] = s; + v[6] = t; + } +} + +// Check for intersecting decals on this surface +static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int *pcount ) +{ + int texture; + decal_t *plast, *pDecal; + vec3_t decalExtents[2]; + float lastArea = 2; + int mapSize[2]; + + plast = NULL; + *pcount = 0; + + // (Same as R_SetupDecalClip). + texture = decalinfo->m_iTexture; + + // precalculate the extents of decalinfo's decal in world space. + R_GetDecalDimensions( texture, &mapSize[0], &mapSize[1] ); + VectorScale( decalinfo->m_Basis[0], ((mapSize[0] / decalinfo->m_scale) * 0.5f), decalExtents[0] ); + VectorScale( decalinfo->m_Basis[1], ((mapSize[1] / decalinfo->m_scale) * 0.5f), decalExtents[1] ); + + pDecal = surf->pdecals; + + while( pDecal ) + { + texture = pDecal->texture; + + // Don't steal bigger decals and replace them with smaller decals + // Don't steal permanent decals + if( !FBitSet( pDecal->flags, FDECAL_PERMANENT )) + { + vec3_t testBasis[3]; + vec3_t testPosition[2]; + float testWorldScale[2]; + vec2_t vDecalMin, vDecalMax; + vec2_t vUnionMin, vUnionMax; + + R_SetupDecalTextureSpaceBasis( pDecal, surf, texture, testBasis, testWorldScale ); + + VectorSubtract( decalinfo->m_Position, decalExtents[0], testPosition[0] ); + VectorSubtract( decalinfo->m_Position, decalExtents[1], testPosition[1] ); + + // Here, we project the min and max extents of the decal that got passed in into + // this decal's (pDecal's) [0,0,1,1] clip space, just like we would if we were + // clipping a triangle into pDecal's clip space. + Vector2Set( vDecalMin, + DotProduct( testPosition[0], testBasis[0] ) - pDecal->dx + 0.5f, + DotProduct( testPosition[1], testBasis[1] ) - pDecal->dy + 0.5f ); + + VectorAdd( decalinfo->m_Position, decalExtents[0], testPosition[0] ); + VectorAdd( decalinfo->m_Position, decalExtents[1], testPosition[1] ); + + Vector2Set( vDecalMax, + DotProduct( testPosition[0], testBasis[0] ) - pDecal->dx + 0.5f, + DotProduct( testPosition[1], testBasis[1] ) - pDecal->dy + 0.5f ); + + // Now figure out the part of the projection that intersects pDecal's + // clip box [0,0,1,1]. + Vector2Set( vUnionMin, max( vDecalMin[0], 0 ), max( vDecalMin[1], 0 )); + Vector2Set( vUnionMax, min( vDecalMax[0], 1 ), min( vDecalMax[1], 1 )); + + if( vUnionMin[0] < 1 && vUnionMin[1] < 1 && vUnionMax[0] > 0 && vUnionMax[1] > 0 ) + { + // Figure out how much of this intersects the (0,0) - (1,1) bbox. + float flArea = (vUnionMax[0] - vUnionMin[1]) * (vUnionMax[1] - vUnionMin[1]); + + if( flArea > 0.6f ) + { + *pcount += 1; + + if( !plast || flArea <= lastArea ) + { + plast = pDecal; + lastArea = flArea; + } + } + } + } + pDecal = pDecal->pnext; + } + return plast; +} + +/* +==================== +R_DecalCreatePoly + +creates mesh for decal on first rendering +==================== +*/ +glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t *surf ) +{ + int lnumverts; + glpoly_t *poly; + float *v; + int i; + + if( pdecal->polys ) // already created? + return pdecal->polys; + + v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &lnumverts ); + if( !lnumverts ) return NULL; // probably this never happens + + // allocate glpoly + // REFTODO: com_studiocache pool! + poly = Mem_Calloc( r_temppool, sizeof( glpoly_t ) + ( lnumverts * 2 - 1 ) * sizeof( gu_vert_t )); + poly->next = pdecal->polys; + poly->flags = surf->flags; + pdecal->polys = poly; + poly->numverts = lnumverts; + + for( i = 0; i < lnumverts; i++, v += VERTEXSIZE ) + { + poly->verts[i].uv[0] = v[3]; + poly->verts[i].uv[1] = v[4]; + VectorCopy( v, poly->verts[i].xyz ); + + poly->verts[i + lnumverts].uv[0] = v[5]; + poly->verts[i + lnumverts].uv[1] = v[6]; + VectorCopy( v, poly->verts[i + lnumverts].xyz ); + } + + return poly; +} + +// Add the decal to the surface's list of decals. +static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t *decalinfo ) +{ + decal_t *pold; + + pdecal->pnext = NULL; + pold = surf->pdecals; + + if( pold ) + { + while( pold->pnext ) + pold = pold->pnext; + pold->pnext = pdecal; + } + else + { + surf->pdecals = pdecal; + } + + // tag surface + pdecal->psurface = surf; + + // at this point decal are linked with surface + // and will be culled, drawing and sorting + // together with surface + + // alloc clipped poly for decal + R_DecalCreatePoly( decalinfo, pdecal, surf ); +} + +static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, float y ) +{ + decal_t *pdecal, *pold; + int count, vertCount; + + if( !surf ) return; // ??? + + pold = R_DecalIntersect( decalinfo, surf, &count ); + if( count < MAX_OVERLAP_DECALS ) pold = NULL; + + pdecal = R_DecalAlloc( pold ); + if( !pdecal ) return; // r_decals == 0 ??? + + pdecal->flags = decalinfo->m_Flags; + + VectorCopy( decalinfo->m_Position, pdecal->position ); + + pdecal->dx = x; + pdecal->dy = y; + + // set scaling + pdecal->scale = decalinfo->m_scale; + pdecal->entityIndex = decalinfo->m_Entity; + pdecal->texture = decalinfo->m_iTexture; + + // check to see if the decal actually intersects the surface + // if not, then remove the decal + R_DecalVertsClip( pdecal, surf, decalinfo->m_iTexture, &vertCount ); + + if( !vertCount ) + { + R_DecalUnlink( pdecal ); + return; + } + + // add to the surface's list + R_AddDecalToSurface( pdecal, surf, decalinfo ); +} + +void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo ) +{ + // get the texture associated with this surface + mtexinfo_t *tex = surf->texinfo; + decal_t *decal = surf->pdecals; + vec4_t textureU, textureV; + float s, t, w, h; + connstate_t state = ENGINE_GET_PARM( PARM_CONNSTATE ); + + // we in restore mode + if( state == ca_connected || state == ca_validate ) + { + // NOTE: we may have the decal on this surface that come from another level. + // check duplicate with same position and texture + while( decal != NULL ) + { + if( VectorCompare( decal->position, decalinfo->m_Position ) && decal->texture == decalinfo->m_iTexture ) + return; // decal already exists, don't place it again + decal = decal->pnext; + } + } + + Vector4Copy( tex->vecs[0], textureU ); + Vector4Copy( tex->vecs[1], textureV ); + + // project decal center into the texture space of the surface + s = DotProduct( decalinfo->m_Position, textureU ) + textureU[3] - surf->texturemins[0]; + t = DotProduct( decalinfo->m_Position, textureV ) + textureV[3] - surf->texturemins[1]; + + // Determine the decal basis (measured in world space) + // Note that the decal basis vectors 0 and 1 will always lie in the same + // plane as the texture space basis vectorstextureVecsTexelsPerWorldUnits. + R_DecalComputeBasis( surf, decalinfo->m_Flags, decalinfo->m_Basis ); + + // Compute an effective width and height (axis aligned) in the parent texture space + // How does this work? decalBasis[0] represents the u-direction (width) + // of the decal measured in world space, decalBasis[1] represents the + // v-direction (height) measured in world space. + // textureVecsTexelsPerWorldUnits[0] represents the u direction of + // the surface's texture space measured in world space (with the appropriate + // scale factor folded in), and textureVecsTexelsPerWorldUnits[1] + // represents the texture space v direction. We want to find the dimensions (w,h) + // of a square measured in texture space, axis aligned to that coordinate system. + // All we need to do is to find the components of the decal edge vectors + // (decalWidth * decalBasis[0], decalHeight * decalBasis[1]) + // in texture coordinates: + + w = fabs( decalinfo->m_decalWidth * DotProduct( textureU, decalinfo->m_Basis[0] )) + + fabs( decalinfo->m_decalHeight * DotProduct( textureU, decalinfo->m_Basis[1] )); + + h = fabs( decalinfo->m_decalWidth * DotProduct( textureV, decalinfo->m_Basis[0] )) + + fabs( decalinfo->m_decalHeight * DotProduct( textureV, decalinfo->m_Basis[1] )); + + // move s,t to upper left corner + s -= ( w * 0.5f ); + t -= ( h * 0.5f ); + + // Is this rect within the surface? -- tex width & height are unsigned + if( s <= -w || t <= -h || s > (surf->extents[0] + w) || t > (surf->extents[1] + h)) + { + return; // nope + } + + // stamp it + R_DecalCreate( decalinfo, surf, s, t ); +} + +//----------------------------------------------------------------------------- +// iterate over all surfaces on a node, looking for surfaces to decal +//----------------------------------------------------------------------------- +static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) +{ + // iterate over all surfaces in the node + msurface_t *surf; + int i; + + surf = model->surfaces + node->firstsurface; + + for( i = 0; i < node->numsurfaces; i++, surf++ ) + { + // never apply decals on the water or sky surfaces + if( surf->flags & (SURF_DRAWTURB|SURF_DRAWSKY|SURF_CONVEYOR)) + continue; + + if( surf->flags & SURF_TRANSPARENT && !glState.stencilEnabled ) + continue; + + R_DecalSurface( surf, decalinfo ); + } +} + +//----------------------------------------------------------------------------- +// Recursive routine to find surface to apply a decal to. World coordinates of +// the decal are passed in r_recalpos like the rest of the engine. This should +// be called through R_DecalShoot() +//----------------------------------------------------------------------------- +static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) +{ + mplane_t *splitplane; + float dist; + + Assert( node != NULL ); + + if( node->contents < 0 ) + { + // hit a leaf + return; + } + + splitplane = node->plane; + dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist; + + // This is arbitrarily set to 10 right now. In an ideal world we'd have the + // exact surface but we don't so, this tells me which planes are "sort of + // close" to the gunshot -- the gunshot is actually 4 units in front of the + // wall (see dlls\weapons.cpp). We also need to check to see if the decal + // actually intersects the texture space of the surface, as this method tags + // parallel surfaces in the same node always. + // JAY: This still tags faces that aren't correct at edges because we don't + // have a surface normal + if( dist > decalinfo->m_Size ) + { + R_DecalNode( model, node->children[0], decalinfo ); + } + else if( dist < -decalinfo->m_Size ) + { + R_DecalNode( model, node->children[1], decalinfo ); + } + else + { + if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE ) + R_DecalNodeSurfaces( model, node, decalinfo ); + + R_DecalNode( model, node->children[0], decalinfo ); + R_DecalNode( model, node->children[1], decalinfo ); + } +} + +// Shoots a decal onto the surface of the BSP. position is the center of the decal in world coords +void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale ) +{ + decalinfo_t decalInfo; + cl_entity_t *ent = NULL; + model_t *model = NULL; + int width, height; + hull_t *hull; + + if( textureIndex <= 0 || textureIndex >= MAX_TEXTURES ) + { + gEngfuncs.Con_Printf( S_ERROR "Decal has invalid texture!\n" ); + return; + } + + if( entityIndex > 0 ) + { + ent = gEngfuncs.GetEntityByIndex( entityIndex ); + + if( modelIndex > 0 ) model = gEngfuncs.pfnGetModelByIndex( modelIndex ); + else if( ent != NULL ) model = gEngfuncs.pfnGetModelByIndex( ent->curstate.modelindex ); + else return; + } + else if( modelIndex > 0 ) + model = gEngfuncs.pfnGetModelByIndex( modelIndex ); + else model = WORLDMODEL; + + if( !model ) return; + + if( model->type != mod_brush ) + { + gEngfuncs.Con_Printf( S_ERROR "Decals must hit mod_brush!\n" ); + return; + } + + decalInfo.m_pModel = model; + hull = &model->hulls[0]; // always use #0 hull + + // NOTE: all the decals at 'first shoot' placed into local space of parent entity + // and won't transform again on a next restore, levelchange etc + if( ent && !FBitSet( flags, FDECAL_LOCAL_SPACE )) + { + vec3_t pos_l; + + // transform decal position in local bmodel space + if( !VectorIsNull( ent->angles )) + { + matrix4x4 matrix; + + Matrix4x4_CreateFromEntity( matrix, ent->angles, ent->origin, 1.0f ); + Matrix4x4_VectorITransform( matrix, pos, pos_l ); + } + else + { + VectorSubtract( pos, ent->origin, pos_l ); + } + + VectorCopy( pos_l, decalInfo.m_Position ); + // decal position moved into local space + SetBits( flags, FDECAL_LOCAL_SPACE ); + } + else + { + // already in local space + VectorCopy( pos, decalInfo.m_Position ); + } + + // this decal must use landmark for correct transition + // because their model exist only in world-space + if( !FBitSet( model->flags, MODEL_HAS_ORIGIN )) + SetBits( flags, FDECAL_USE_LANDMARK ); + + // more state used by R_DecalNode() + decalInfo.m_iTexture = textureIndex; + decalInfo.m_Entity = entityIndex; + decalInfo.m_Flags = flags; + + R_GetDecalDimensions( textureIndex, &width, &height ); + decalInfo.m_Size = width >> 1; + if(( height >> 1 ) > decalInfo.m_Size ) + decalInfo.m_Size = height >> 1; + + decalInfo.m_scale = bound( MIN_DECAL_SCALE, scale, MAX_DECAL_SCALE ); + + // compute the decal dimensions in world space + decalInfo.m_decalWidth = width / decalInfo.m_scale; + decalInfo.m_decalHeight = height / decalInfo.m_scale; + + R_DecalNode( model, &model->nodes[hull->firstclipnode], &decalInfo ); +} + +// Build the vertex list for a decal on a surface and clip it to the surface. +// This is a template so it can work on world surfaces and dynamic displacement +// triangles the same way. +float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount ) +{ + glpoly_t *p = pDecal->polys; + int i, count; + float *v; + + if( p ) + { + v = g_DecalClipVerts[0]; + count = p->numverts; + + // if we have mesh so skip clipping and just copy vertexes out (perf) + for( i = 0; i < count; i++, v += VERTEXSIZE ) + { + VectorCopy( p->verts[i].xyz, v ); + v[3] = p->verts[i].uv[0]; + v[4] = p->verts[i].uv[1]; + v[5] = p->verts[i + count].uv[0]; + v[6] = p->verts[i + count].uv[1]; + } + + // restore pointer + v = g_DecalClipVerts[0]; + } + else + { + v = R_DecalVertsClip( pDecal, surf, texture, &count ); + R_DecalVertsLight( v, surf, count ); + } + + if( outCount ) + *outCount = count; + + return v; +} + +void DrawSingleDecal( decal_t *pDecal, msurface_t *fa ) +{ + float *v; + int i, numVerts; + + v = R_DecalSetupVerts( pDecal, fa, pDecal->texture, &numVerts ); + if( !numVerts ) return; + + GL_Bind( XASH_TEXTURE0, pDecal->texture ); + + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * numVerts ); + for( i = 0; i < numVerts; i++, v += VERTEXSIZE ) + { + out[i].uv[0] = v[3]; + out[i].uv[1] = v[4]; + VectorCopy( v, out[i].xyz ); + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, numVerts, 0, out ); +} + +void DrawSurfaceDecals( msurface_t *fa, qboolean single, qboolean reverse ) +{ + decal_t *p; + cl_entity_t *e; + + if( !fa->pdecals ) return; + + e = RI.currententity; + Assert( e != NULL ); + + if( single ) + { + if( e->curstate.rendermode == kRenderNormal || e->curstate.rendermode == kRenderTransAlpha ) + { + sceGuDepthMask( GU_TRUE ); + sceGuEnable( GU_BLEND ); + + if( e->curstate.rendermode == kRenderTransAlpha ) + sceGuDisable( GU_ALPHA_TEST ); + } + + if( e->curstate.rendermode == kRenderTransColor ) + sceGuEnable( GU_TEXTURE_2D ); + + if( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd ) + GL_Cull( GL_NONE ); + + if( gl_depthoffset->value ) + sceGuDepthOffset( ( int )-gl_depthoffset->value ); + } + + if( FBitSet( fa->flags, SURF_TRANSPARENT ) && glState.stencilEnabled ) + { + mtexinfo_t *tex = fa->texinfo; + + for( p = fa->pdecals; p; p = p->pnext ) + { + if( p->texture ) + { + float *o, *v; + int i, numVerts; + o = R_DecalSetupVerts( p, fa, p->texture, &numVerts ); + + sceGuEnable( GU_STENCIL_TEST ); + sceGuStencilFunc( GU_ALWAYS, 1, 0xffffffff ); + sceGuPixelMask( 0xffffffff ); + + sceGuStencilOp( GU_KEEP, GU_KEEP, GU_REPLACE ); + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * numVerts ); + for( i = 0, v = o; i < numVerts; i++, v += VERTEXSIZE ) + { + out[i].uv[0] = ( DotProduct( v, tex->vecs[0] ) + tex->vecs[0][3] ) / tex->texture->width; + out[i].uv[1] = ( DotProduct( v, tex->vecs[1] ) + tex->vecs[1][3] ) / tex->texture->height; + VectorCopy( v, out[i].xyz ); + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, numVerts, 0, out ); +#if 0 /* two layer ??? */ + sceGuStencilOp( GU_KEEP, GU_KEEP, GU_DECR ); + sceGuEnable( GU_ALPHA_TEST ); + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, numVerts, 0, out ); + sceGuDisable( GU_ALPHA_TEST ); +#endif + sceGuPixelMask( 0x00000000 ); + sceGuStencilFunc( GU_EQUAL, 0, 0xffffffff ); + sceGuStencilOp( GU_KEEP, GU_KEEP, GU_KEEP ); + } + } + } + + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + + if( reverse && e->curstate.rendermode == kRenderTransTexture ) + { + decal_t *list[1024]; + int i, count; + + for( p = fa->pdecals, count = 0; p && count < 1024; p = p->pnext ) + if( p->texture ) list[count++] = p; + + for( i = count - 1; i >= 0; i-- ) + DrawSingleDecal( list[i], fa ); + } + else + { + for( p = fa->pdecals; p; p = p->pnext ) + { + if( !p->texture ) continue; + DrawSingleDecal( p, fa ); + } + } + + if( FBitSet( fa->flags, SURF_TRANSPARENT ) && glState.stencilEnabled ) + sceGuDisable( GU_STENCIL_TEST ); + + if( single ) + { + if( e->curstate.rendermode == kRenderNormal || e->curstate.rendermode == kRenderTransAlpha ) + { + sceGuDepthMask( GU_FALSE ); + sceGuDisable( GU_BLEND ); + + if( e->curstate.rendermode == kRenderTransAlpha ) + sceGuEnable( GU_ALPHA_TEST ); + } + + if( gl_depthoffset->value ) + sceGuDepthOffset( 0 ); + + if( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd ) + GL_Cull( GL_FRONT ); + + if( e->curstate.rendermode == kRenderTransColor ) + sceGuDisable( GU_TEXTURE_2D ); + + // restore blendfunc here + if( e->curstate.rendermode == kRenderTransAdd || e->curstate.rendermode == kRenderGlow ) + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + } +} + +void DrawDecalsBatch( void ) +{ + cl_entity_t *e; + int i; + + if( !tr.num_draw_decals ) + return; + + e = RI.currententity; + Assert( e != NULL ); + + if( e->curstate.rendermode != kRenderTransTexture ) + { + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuDepthMask( GU_TRUE ); + } + + if( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd ) + GL_Cull( GL_NONE ); + + if( gl_depthoffset->value ) + sceGuDepthOffset( ( int )-gl_depthoffset->value ); + + for( i = 0; i < tr.num_draw_decals; i++ ) + { + DrawSurfaceDecals( tr.draw_decals[i], false, false ); + } + + if( e->curstate.rendermode != kRenderTransTexture ) + { + sceGuDepthMask( GU_FALSE ); + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + } + + if( gl_depthoffset->value ) + sceGuDepthOffset( 0 ); + + if( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd ) + GL_Cull( GL_FRONT ); + + tr.num_draw_decals = 0; +} + +/* +============================================================= + + DECALS SERIALIZATION + +============================================================= +*/ +static qboolean R_DecalUnProject( decal_t *pdecal, decallist_t *entry ) +{ + if( !pdecal || !( pdecal->psurface )) + return false; + + VectorCopy( pdecal->position, entry->position ); + entry->entityIndex = pdecal->entityIndex; + + // Grab surface plane equation + if( pdecal->psurface->flags & SURF_PLANEBACK ) + VectorNegate( pdecal->psurface->plane->normal, entry->impactPlaneNormal ); + else VectorCopy( pdecal->psurface->plane->normal, entry->impactPlaneNormal ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pList - +// count - +// Output : static int +//----------------------------------------------------------------------------- +static int DecalListAdd( decallist_t *pList, int count ) +{ + vec3_t tmp; + decallist_t *pdecal; + int i; + + pdecal = pList + count; + + for( i = 0; i < count; i++ ) + { + if( !Q_strcmp( pdecal->name, pList[i].name ) && pdecal->entityIndex == pList[i].entityIndex ) + { + VectorSubtract( pdecal->position, pList[i].position, tmp ); // Merge + + if( VectorLength( tmp ) < DECAL_OVERLAP_DISTANCE ) + return count; + } + } + + // this is a new decal + return count + 1; +} + +static int DecalDepthCompare( const void *a, const void *b ) +{ + const decallist_t *elem1, *elem2; + + elem1 = (const decallist_t *)a; + elem2 = (const decallist_t *)b; + + if( elem1->depth > elem2->depth ) + return 1; + if( elem1->depth < elem2->depth ) + return -1; + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Called by CSaveRestore::SaveClientState +// Input : *pList - +// Output : int +//----------------------------------------------------------------------------- +int R_CreateDecalList( decallist_t *pList ) +{ + int total = 0; + int i, depth; + + if( WORLDMODEL ) + { + for( i = 0; i < MAX_RENDER_DECALS; i++ ) + { + decal_t *decal = &gDecalPool[i]; + decal_t *pdecals; + + // decal is in use and is not a custom decal + if( decal->psurface == NULL || FBitSet( decal->flags, FDECAL_DONTSAVE )) + continue; + + // compute depth + depth = 0; + pdecals = decal->psurface->pdecals; + + while( pdecals && pdecals != decal ) + { + depth++; + pdecals = pdecals->pnext; + } + + pList[total].depth = depth; + pList[total].flags = decal->flags; + pList[total].scale = decal->scale; + + R_DecalUnProject( decal, &pList[total] ); + COM_FileBase( R_GetTexture( decal->texture )->name, pList[total].name ); + + // check to see if the decal should be added + total = DecalListAdd( pList, total ); + } + + if( gEngfuncs.drawFuncs->R_CreateStudioDecalList ) + { + total += gEngfuncs.drawFuncs->R_CreateStudioDecalList( pList, total ); + } + } + + // sort the decals lowest depth first, so they can be re-applied in order + qsort( pList, total, sizeof( decallist_t ), DecalDepthCompare ); + + return total; +} + +/* +=============== +R_DecalRemoveAll + +remove all decals with specified texture +=============== +*/ +void R_DecalRemoveAll( int textureIndex ) +{ + decal_t *pdecal; + int i; + + if( textureIndex < 0 || textureIndex >= MAX_TEXTURES ) + return; // out of bounds + + for( i = 0; i < gDecalCount; i++ ) + { + pdecal = &gDecalPool[i]; + + // don't remove permanent decals + if( !textureIndex && FBitSet( pdecal->flags, FDECAL_PERMANENT )) + continue; + + if( !textureIndex || ( pdecal->texture == textureIndex )) + R_DecalUnlink( pdecal ); + } +} + +/* +=============== +R_EntityRemoveDecals + +remove all decals from specified entity +=============== +*/ +void R_EntityRemoveDecals( model_t *mod ) +{ + msurface_t *psurf; + decal_t *p; + int i; + + if( !mod || mod->type != mod_brush ) + return; + + psurf = &mod->surfaces[mod->firstmodelsurface]; + for( i = 0; i < mod->nummodelsurfaces; i++, psurf++ ) + { + for( p = psurf->pdecals; p; p = p->pnext ) + R_DecalUnlink( p ); + } +} + +/* +=============== +R_ClearAllDecals + +remove all decals from anything +used for full decals restart +=============== +*/ +void R_ClearAllDecals( void ) +{ + decal_t *pdecal; + int i; + + // because gDecalCount may be zeroed after recach the decal limit + for( i = 0; i < MAX_RENDER_DECALS; i++ ) + { + pdecal = &gDecalPool[i]; + R_DecalUnlink( pdecal ); + } + + if( gEngfuncs.drawFuncs->R_ClearStudioDecals ) + { + gEngfuncs.drawFuncs->R_ClearStudioDecals(); + } +} diff --git a/ref_gu/gu_draw.c b/ref_gu/gu_draw.c new file mode 100644 index 00000000..1646f37c --- /dev/null +++ b/ref_gu/gu_draw.c @@ -0,0 +1,308 @@ +/* +gu_draw.c - orthogonal drawing stuff +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" + +/* +============= +R_GetImageParms +============= +*/ +void R_GetTextureParms( int *w, int *h, int texnum ) +{ + gl_texture_t *glt; + + glt = R_GetTexture( texnum ); + if( w ) *w = glt->srcWidth; + if( h ) *h = glt->srcHeight; +} + +/* +============= +R_GetSpriteParms + +same as GetImageParms but used +for sprite models +============= +*/ +void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite ) +{ + mspriteframe_t *pFrame; + + if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ? + pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f ); + + if( frameWidth ) *frameWidth = pFrame->width; + if( frameHeight ) *frameHeight = pFrame->height; + if( numFrames ) *numFrames = pSprite->numframes; +} + +int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame ) +{ + if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data ) + return 0; + + return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum; +} + +/* +============= +R_DrawStretchPic +============= +*/ +void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum ) +{ + float uw, uh; + gl_texture_t *glt; + + GL_Bind( XASH_TEXTURE0, texnum ); + + glt = R_GetTexture( texnum ); + + gu_vert_htv_t* const out = ( gu_vert_htv_t* )sceGuGetMemory( sizeof( gu_vert_htv_t ) * 2 ); + out[0].u = s1 * glt->width; + out[0].v = t1 * glt->height; + out[0].x = x; + out[0].y = y; + out[0].z = 0; + out[1].u = s2 * glt->width; + out[1].v = t2 * glt->height; + out[1].x = x + w; + out[1].y = y + h; + out[1].z = 0; + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_16BIT | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out ); +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void R_DrawTileClear( int texnum, int x, int y, int w, int h ) +{ + float tw, th; + gl_texture_t *glt; + + GL_SetRenderMode( kRenderNormal ); + + sceGuColor( 0xffffffff ); + + GL_Bind( XASH_TEXTURE0, texnum ); + + glt = R_GetTexture( texnum ); + tw = glt->srcWidth; + th = glt->srcHeight; + + gu_vert_htv_t* const out = ( gu_vert_htv_t* )sceGuGetMemory( sizeof( gu_vert_ftv_t ) * 2 ); + out[0].u = x / tw * glt->width; + out[0].v = y / th * glt->height; + out[0].x = x; + out[0].y = y; + out[0].z = 0; + out[1].u = ( x + w ) / tw * glt->width; + out[1].v = ( y + h ) / th * glt->height; + out[1].x = x + w; + out[1].y = y + h; + out[1].z = 0; + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_16BIT | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out ); +} + +/* +============= +R_DrawStretchRaw +============= +*/ +void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty ) +{ +#if 0 + byte *raw = NULL; + gl_texture_t *tex; + + if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) + { + int width = 1, height = 1; + + // check the dimensions + width = NearestPOW( cols, true ); + height = NearestPOW( rows, false ); + + if( cols != width || rows != height ) + { + raw = GL_ResampleTexture( data, cols, rows, width, height, false ); + cols = width; + rows = height; + } + } + else + { + raw = (byte *)data; + } + + if( cols > glConfig.max_2d_texture_size ) + gEngfuncs.Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", cols ); + if( rows > glConfig.max_2d_texture_size ) + gEngfuncs.Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", rows ); + + pglDisable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); + + tex = R_GetTexture( tr.cinTexture ); + GL_Bind( XASH_TEXTURE0, tr.cinTexture ); + + if( cols == tex->width && rows == tex->height ) + { + if( dirty ) + { + pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw ); + } + } + else + { + tex->size = cols * rows * 4; + tex->width = cols; + tex->height = rows; + if( dirty ) + { + pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw ); + } + } + + pglBegin( GL_QUADS ); + pglTexCoord2f( 0, 0 ); + pglVertex2f( x, y ); + pglTexCoord2f( 1, 0 ); + pglVertex2f( x + w, y ); + pglTexCoord2f( 1, 1 ); + pglVertex2f( x + w, y + h ); + pglTexCoord2f( 0, 1 ); + pglVertex2f( x, y + h ); + pglEnd(); +#endif +} + +/* +============= +R_UploadStretchRaw +============= +*/ +void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data ) +{ +#if 0 + byte *raw = NULL; + gl_texture_t *tex; + + if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) + { + // check the dimensions + width = NearestPOW( width, true ); + height = NearestPOW( height, false ); + } + else + { + width = bound( 128, width, glConfig.max_2d_texture_size ); + height = bound( 128, height, glConfig.max_2d_texture_size ); + } + + if( cols != width || rows != height ) + { + raw = GL_ResampleTexture( data, cols, rows, width, height, false ); + cols = width; + rows = height; + } + else + { + raw = (byte *)data; + } + + if( cols > glConfig.max_2d_texture_size ) + gEngfuncs.Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", cols ); + if( rows > glConfig.max_2d_texture_size ) + gEngfuncs.Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", rows ); + + tex = R_GetTexture( texture ); + GL_Bind( GL_KEEP_UNIT, texture ); + tex->width = cols; + tex->height = rows; + + pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw ); + GL_ApplyTextureParams( tex ); +#endif +} + +/* +=============== +R_Set2DMode +=============== +*/ +void R_Set2DMode( qboolean enable ) +{ + if( enable ) + { + if( glState.in2DMode ) + return; + + // set 2D virtual screen size +#if 1 // through mode + sceGuViewport( 2048, 2048, gpGlobals->width, gpGlobals->width ); + sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); +#else + pglViewport( 0, 0, gpGlobals->width, gpGlobals->height ); + pglMatrixMode( GL_PROJECTION ); + pglLoadIdentity(); + pglOrtho( 0, gpGlobals->width, gpGlobals->height, 0, -99999, 99999 ); + pglMatrixMode( GL_MODELVIEW ); + pglLoadIdentity(); +#endif + GL_Cull( GL_NONE ); +#if 1 + sceGuDepthMask( GU_TRUE ); + sceGuDisable( GU_DEPTH_TEST ); + sceGuEnable( GU_ALPHA_TEST ); + sceGuColor( 0xffffffff ); +#else + pglDepthMask( GL_FALSE ); + pglDisable( GL_DEPTH_TEST ); + pglEnable( GL_ALPHA_TEST ); + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); +#endif + glState.in2DMode = true; + RI.currententity = NULL; + RI.currentmodel = NULL; + } + else + { +#if 1 + sceGuDepthMask( GU_FALSE ); + sceGuEnable( GU_DEPTH_TEST ); + glState.in2DMode = false; +#else + pglDepthMask( GL_TRUE ); + pglEnable( GL_DEPTH_TEST ); + glState.in2DMode = false; + + pglMatrixMode( GL_PROJECTION ); + GL_LoadMatrix( RI.projectionMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.worldviewMatrix ); +#endif + GL_Cull( GL_FRONT ); + } +} diff --git a/ref_gu/gu_extension.c b/ref_gu/gu_extension.c new file mode 100644 index 00000000..260783dc --- /dev/null +++ b/ref_gu/gu_extension.c @@ -0,0 +1,79 @@ +/* +gu_extension.c - PSP Graphic Unit extensions +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include +#include +#include +#include +#include "gu_extension.h" + +/* from guInternal.h */ +typedef struct +{ + unsigned int* start; + unsigned int* current; + int parent_context; +} GuDisplayList; +extern GuDisplayList* gu_list; +extern int gu_curr_context; +extern int ge_list_executed[]; + +static unsigned int gu_list_size; + + +void extGuStart(int cid, void* list, int size) +{ + gu_list_size = size; + sceGuStart( cid, list ); +} + +/* Begin user packet */ +void *extGuBeginPacket( unsigned int *maxsize ) +{ + unsigned int* current_ptr = gu_list->current; + if( maxsize != NULL ) + { + unsigned int size = ( ( unsigned int )gu_list->current ) - ( ( unsigned int )gu_list->start ); + *maxsize = ( ( unsigned int )gu_list_size ) - ( ( unsigned int )size ); + } + return current_ptr + 2; +} + +/* End user packet */ +void extGuEndPacket( void *eaddr ) +{ + unsigned int* current_ptr = gu_list->current; + unsigned int size = ( ( unsigned int ) eaddr ) - ( ( unsigned int )current_ptr ); + + if( size > 0 ) + { + size += 3; + size += ( ( unsigned int )( size >> 31 ) ) >> 30; + size = ( size >> 2 ) << 2; + + unsigned int* new_ptr = ( unsigned int* )( ( ( unsigned int ) current_ptr ) + size + 8 ); + + int lo = ( 8 << 24 ) | ( ( ( unsigned int )new_ptr ) & 0xffffff ); + int hi = ( 16 << 24 ) | ( ( ( ( unsigned int )new_ptr ) >> 8 ) & 0xf0000 ); + + current_ptr[0] = hi; + current_ptr[1] = lo; + + gu_list->current = new_ptr; + + if ( !gu_curr_context ) + sceGeListUpdateStallAddr( ge_list_executed[0], new_ptr ); + } +} \ No newline at end of file diff --git a/ref_gu/gu_extension.h b/ref_gu/gu_extension.h new file mode 100644 index 00000000..7273870e --- /dev/null +++ b/ref_gu/gu_extension.h @@ -0,0 +1,23 @@ +/* +gu_extension.h - PSP Graphic Unit extensions header +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GU_EXTENSION_H +#define GU_EXTENSION_H + +void extGuStart(int cid, void* list, int size); +void *extGuBeginPacket( unsigned int *maxsize ); +void extGuEndPacket( void *eaddr ); + +#endif//GU_EXTENSION_H diff --git a/ref_gu/gu_frustum.c b/ref_gu/gu_frustum.c new file mode 100644 index 00000000..a52a8fb1 --- /dev/null +++ b/ref_gu/gu_frustum.c @@ -0,0 +1,355 @@ +/* +gu_frustum.cpp - frustum test implementation +Copyright (C) 2016 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "xash3d_mathlib.h" + +void GL_FrustumEnablePlane( gl_frustum_t *out, int side ) +{ + Assert( side >= 0 && side < FRUSTUM_PLANES ); + + // make sure what plane is ready + if( !VectorIsNull( out->planes[side].normal )) + SetBits( out->clipFlags, BIT( side )); +} + +void GL_FrustumDisablePlane( gl_frustum_t *out, int side ) +{ + Assert( side >= 0 && side < FRUSTUM_PLANES ); + ClearBits( out->clipFlags, BIT( side )); +} + +void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist ) +{ + Assert( side >= 0 && side < FRUSTUM_PLANES ); + + out->planes[side].type = PlaneTypeForNormal( vecNormal ); + out->planes[side].signbits = SignbitsForPlane( vecNormal ); + VectorCopy( vecNormal, out->planes[side].normal ); + out->planes[side].dist = flDist; + + SetBits( out->clipFlags, BIT( side )); +} + +void GL_FrustumNormalizePlane( gl_frustum_t *out, int side ) +{ + float length; + + Assert( side >= 0 && side < FRUSTUM_PLANES ); + + // normalize + length = VectorLength( out->planes[side].normal ); + + if( length ) + { + float ilength = (1.0f / length); + out->planes[side].normal[0] *= ilength; + out->planes[side].normal[1] *= ilength; + out->planes[side].normal[2] *= ilength; + out->planes[side].dist *= ilength; + } + + out->planes[side].type = PlaneTypeForNormal( out->planes[side].normal ); + out->planes[side].signbits = SignbitsForPlane( out->planes[side].normal ); + + SetBits( out->clipFlags, BIT( side )); +} + +void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY ) +{ + float xs, xc; + vec3_t farpoint, nearpoint; + vec3_t normal, iforward; + + // horizontal fov used for left and right planes + SinCos( DEG2RAD( flFovX ) * 0.5f, &xs, &xc ); + + // setup left plane + VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vright, normal ); + GL_FrustumSetPlane( out, FRUSTUM_LEFT, normal, DotProduct( RI.cullorigin, normal )); + + // setup right plane + VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vright, normal ); + GL_FrustumSetPlane( out, FRUSTUM_RIGHT, normal, DotProduct( RI.cullorigin, normal )); + + // vertical fov used for top and bottom planes + SinCos( DEG2RAD( flFovY ) * 0.5f, &xs, &xc ); + VectorNegate( RI.cull_vforward, iforward ); + + // setup bottom plane + VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vup, normal ); + GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, normal, DotProduct( RI.cullorigin, normal )); + + // setup top plane + VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vup, normal ); + GL_FrustumSetPlane( out, FRUSTUM_TOP, normal, DotProduct( RI.cullorigin, normal )); + + // setup far plane + VectorMA( RI.cullorigin, flZFar, RI.cull_vforward, farpoint ); + GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, DotProduct( iforward, farpoint )); + + // no need to setup backplane for general view. + if( flZNear == 0.0f ) return; + + // setup near plane + VectorMA( RI.cullorigin, flZNear, RI.cull_vforward, nearpoint ); + GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, DotProduct( RI.cull_vforward, nearpoint )); +} + +void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar ) +{ + vec3_t iforward, iright, iup; + + // setup the near and far planes + float orgOffset = DotProduct( RI.cullorigin, RI.cull_vforward ); + VectorNegate( RI.cull_vforward, iforward ); + + // because quake ortho is inverted and far and near should be swaped + GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, -flZNear - orgOffset ); + GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, flZFar + orgOffset ); + + // setup left and right planes + orgOffset = DotProduct( RI.cullorigin, RI.cull_vright ); + VectorNegate( RI.cull_vright, iright ); + + GL_FrustumSetPlane( out, FRUSTUM_LEFT, RI.cull_vright, xLeft + orgOffset ); + GL_FrustumSetPlane( out, FRUSTUM_RIGHT, iright, -xRight - orgOffset ); + + // setup top and buttom planes + orgOffset = DotProduct( RI.cullorigin, RI.cull_vup ); + VectorNegate( RI.cull_vup, iup ); + + GL_FrustumSetPlane( out, FRUSTUM_TOP, RI.cull_vup, yTop + orgOffset ); + GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, iup, -yBottom - orgOffset ); +} + +void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius ) +{ + vec3_t normal; + int i; + + for( i = 0; i < FRUSTUM_PLANES; i++ ) + { + // setup normal for each direction + VectorClear( normal ); + normal[((i >> 1) + 1) % 3] = (i & 1) ? 1.0f : -1.0f; + GL_FrustumSetPlane( out, i, normal, DotProduct( org, normal ) - radius ); + } +} + +void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection ) +{ + int i; + + // left + out->planes[FRUSTUM_LEFT].normal[0] = projection[0][3] + projection[0][0]; + out->planes[FRUSTUM_LEFT].normal[1] = projection[1][3] + projection[1][0]; + out->planes[FRUSTUM_LEFT].normal[2] = projection[2][3] + projection[2][0]; + out->planes[FRUSTUM_LEFT].dist = -(projection[3][3] + projection[3][0]); + + // right + out->planes[FRUSTUM_RIGHT].normal[0] = projection[0][3] - projection[0][0]; + out->planes[FRUSTUM_RIGHT].normal[1] = projection[1][3] - projection[1][0]; + out->planes[FRUSTUM_RIGHT].normal[2] = projection[2][3] - projection[2][0]; + out->planes[FRUSTUM_RIGHT].dist = -(projection[3][3] - projection[3][0]); + + // bottom + out->planes[FRUSTUM_BOTTOM].normal[0] = projection[0][3] + projection[0][1]; + out->planes[FRUSTUM_BOTTOM].normal[1] = projection[1][3] + projection[1][1]; + out->planes[FRUSTUM_BOTTOM].normal[2] = projection[2][3] + projection[2][1]; + out->planes[FRUSTUM_BOTTOM].dist = -(projection[3][3] + projection[3][1]); + + // top + out->planes[FRUSTUM_TOP].normal[0] = projection[0][3] - projection[0][1]; + out->planes[FRUSTUM_TOP].normal[1] = projection[1][3] - projection[1][1]; + out->planes[FRUSTUM_TOP].normal[2] = projection[2][3] - projection[2][1]; + out->planes[FRUSTUM_TOP].dist = -(projection[3][3] - projection[3][1]); + + // near + out->planes[FRUSTUM_NEAR].normal[0] = projection[0][3] + projection[0][2]; + out->planes[FRUSTUM_NEAR].normal[1] = projection[1][3] + projection[1][2]; + out->planes[FRUSTUM_NEAR].normal[2] = projection[2][3] + projection[2][2]; + out->planes[FRUSTUM_NEAR].dist = -(projection[3][3] + projection[3][2]); + + // far + out->planes[FRUSTUM_FAR].normal[0] = projection[0][3] - projection[0][2]; + out->planes[FRUSTUM_FAR].normal[1] = projection[1][3] - projection[1][2]; + out->planes[FRUSTUM_FAR].normal[2] = projection[2][3] - projection[2][2]; + out->planes[FRUSTUM_FAR].dist = -(projection[3][3] - projection[3][2]); + + for( i = 0; i < FRUSTUM_PLANES; i++ ) + { + GL_FrustumNormalizePlane( out, i ); + } +} + +void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t corners[8] ) +{ + memset( corners, 0, sizeof( vec3_t ) * 8 ); + + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[0] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[1] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[2] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[3] ); + + if( FBitSet( out->clipFlags, BIT( FRUSTUM_NEAR ))) + { + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[4] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[5] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[6] ); + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[7] ); + } + else + { + PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], corners[4] ); + VectorCopy( corners[4], corners[5] ); + VectorCopy( corners[4], corners[6] ); + VectorCopy( corners[4], corners[7] ); + } +} + +void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs ) +{ + vec3_t corners[8]; + int i; + + GL_FrustumComputeCorners( out, corners ); + + ClearBounds( mins, maxs ); + + for( i = 0; i < 8; i++ ) + AddPointToBounds( corners[i], mins, maxs ); +} + +void GL_FrustumDrawDebug( gl_frustum_t *out ) +{ + vec3_t bbox[8]; + int i; + + GL_FrustumComputeCorners( out, bbox ); +/* + // g-cont. frustum must be yellow :-) + pglColor4f( 1.0f, 1.0f, 0.0f, 1.0f ); + pglDisable( GL_TEXTURE_2D ); + pglBegin( GL_LINES ); + + for( i = 0; i < 2; i += 1 ) + { + pglVertex3fv( bbox[i+0] ); + pglVertex3fv( bbox[i+2] ); + pglVertex3fv( bbox[i+4] ); + pglVertex3fv( bbox[i+6] ); + pglVertex3fv( bbox[i+0] ); + pglVertex3fv( bbox[i+4] ); + pglVertex3fv( bbox[i+2] ); + pglVertex3fv( bbox[i+6] ); + pglVertex3fv( bbox[i*2+0] ); + pglVertex3fv( bbox[i*2+1] ); + pglVertex3fv( bbox[i*2+4] ); + pglVertex3fv( bbox[i*2+5] ); + } + + pglEnd(); + pglEnable( GL_TEXTURE_2D ); +*/ +} + +// cull methods +qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags ) +{ + int iClipFlags; + int i, bit; + + if( r_nocull->value ) + return false; + + if( userClipFlags != 0 ) + iClipFlags = userClipFlags; + else iClipFlags = out->clipFlags; + + for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) + { + const mplane_t *p = &out->planes[FRUSTUM_PLANES - i]; + + if( !FBitSet( iClipFlags, bit )) + continue; + + switch( p->signbits ) + { + case 0: + if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist ) + return true; + break; + case 1: + if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist ) + return true; + break; + case 2: + if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist ) + return true; + break; + case 3: + if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist ) + return true; + break; + case 4: + if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist ) + return true; + break; + case 5: + if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist ) + return true; + break; + case 6: + if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist ) + return true; + break; + case 7: + if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist ) + return true; + break; + default: + return false; + } + } + + return false; +} + +qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags ) +{ + int iClipFlags; + int i, bit; + + if( r_nocull->value ) + return false; + + if( userClipFlags != 0 ) + iClipFlags = userClipFlags; + else iClipFlags = out->clipFlags; + + for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) + { + const mplane_t *p = &out->planes[FRUSTUM_PLANES - i]; + + if( !FBitSet( iClipFlags, bit )) + continue; + + if( DotProduct( center, p->normal ) - p->dist <= -radius ) + return true; + } + + return false; +} diff --git a/ref_gu/gu_frustum.h b/ref_gu/gu_frustum.h new file mode 100644 index 00000000..f48793b5 --- /dev/null +++ b/ref_gu/gu_frustum.h @@ -0,0 +1,52 @@ +/* +gl_frustum.cpp - frustum test implementation +Copyright (C) 2016 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GL_FRUSTUM_H +#define GL_FRUSTUM_H + +// don't change this order +#define FRUSTUM_LEFT 0 +#define FRUSTUM_RIGHT 1 +#define FRUSTUM_BOTTOM 2 +#define FRUSTUM_TOP 3 +#define FRUSTUM_FAR 4 +#define FRUSTUM_NEAR 5 +#define FRUSTUM_PLANES 6 + +typedef struct gl_frustum_s +{ + mplane_t planes[FRUSTUM_PLANES]; + unsigned int clipFlags; +} gl_frustum_t; + +void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY ); +void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar ); +void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius ); // used for pointlights +void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection ); +void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist ); +void GL_FrustumNormalizePlane( gl_frustum_t *out, int side ); +void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs ); +void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t bbox[8] ); +void GL_FrustumDrawDebug( gl_frustum_t *out ); + +// cull methods +qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags ); +qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t centre, float radius, int userClipFlags ); + +// plane manipulating +void GL_FrustumEnablePlane( gl_frustum_t *out, int side ); +void GL_FrustumDisablePlane( gl_frustum_t *out, int side ); + +#endif//GL_FRUSTUM_H diff --git a/ref_gu/gu_helper.h b/ref_gu/gu_helper.h new file mode 100644 index 00000000..588a6693 --- /dev/null +++ b/ref_gu/gu_helper.h @@ -0,0 +1,74 @@ +/* +gl_helper.h - gu helper +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GU_HELPER_H +#define GU_HELPER_H +#ifndef APIENTRY +#define APIENTRY +#endif + +#ifndef APIENTRY_LINKAGE +#define APIENTRY_LINKAGE extern +#endif + +// GL types wrapping +typedef uint GLenum; +typedef byte GLboolean; +typedef uint GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef byte GLubyte; +typedef word GLushort; +typedef uint GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef int GLintptrARB; +typedef int GLsizeiptrARB; +typedef char GLcharARB; +typedef uint GLhandleARB; +typedef float GLmatrix[16]; + +// GL_Cull wrapping +#define GL_NONE 0 +#define GL_FRONT GU_CW + 1 +#define GL_BACK GU_CCW + 1 + +// color functions wrapping +#define GUCOLOR4F( r, g, b, a ) GU_COLOR( ( r ), ( g ), ( b ), ( a ) ) +#define GUCOLOR4FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) +#define GUCOLOR4UB( r, g, b, a ) GU_RGBA( ( r ), ( g ), ( b ), ( a ) ) +#define GUCOLOR4UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) +#define GUCOLOR3F( r, g, b ) GU_COLOR( ( r ), ( g ), ( b ), 1.0f ) +#define GUCOLOR3FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], 1.0f ) +#define GUCOLOR3UB( r, g, b ) GU_RGBA( ( r ), ( g ), ( b ), 255 ) +#define GUCOLOR3UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], 255 ) + +// blend function wrapping +#define GUBLEND1 0xffffff +#define GUBLEND0 0x000000 + +// texture flags +#define GUFLAGTEXNONE 0x00 +#define GUFLAGTEXUSED 0x01 +#define GUFLAGTEXSWIZZLED 0x02 +#define GUFLAGTEXINVRAM 0x04 +/*#define GUFLAGMIP 0x08*/ + +#endif // GU_HELPER_H diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c new file mode 100644 index 00000000..46296beb --- /dev/null +++ b/ref_gu/gu_image.c @@ -0,0 +1,2499 @@ +/* +gu_image.c - texture uploading and processing +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include +#include +#include "vram_psp.h" +#include "gu_local.h" +#include "crclib.h" + +#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2) + +static gl_texture_t gl_textures[MAX_TEXTURES]; +static gl_texture_t* gl_texturesHashTable[TEXTURES_HASH_SIZE]; +static uint gl_numTextures; + + +/* + num_colors = PALETTE_BLOCKS x 16 (16-bit CLUT) + num_colors = PALETTE_BLOCKS x 8 (32-bit CLUT) +*/ +#define PALETTE_FORMAT GU_PSM_4444 +#if (PALETTE_FORMAT == GU_PSM_4444) || (PALETTE_FORMAT == GU_PSM_5551) || (PALETTE_FORMAT == GU_PSM_5650) +#define PALETTE_SIZE 2 * 256 +#define PALETTE_BLOCKS 16 +#elif PALETTE_FORMAT == GU_PSM_8888 +#define PALETTE_SIZE 4 * 256 +#define PALETTE_BLOCKS 32 +#else +#error Current PALETTE_FORMAT not supported! +#endif + + + +#define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE )) +/* +================= +R_GetTexture + +acess to array elem +================= +*/ +gl_texture_t *R_GetTexture( GLenum texnum ) +{ + ASSERT( texnum >= 0 && texnum < MAX_TEXTURES ); + return &gl_textures[texnum]; +} + +/* +================= +GL_Bind +================= +*/ +void GL_Bind( GLint tmu, GLenum texnum ) +{ + gl_texture_t *texture; +#if 1 + int i; +#else + GLuint glTarget; +#endif + // missed or invalid texture? + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + { + if( texnum != 0 ) + gEngfuncs.Con_DPrintf( S_ERROR "GL_Bind: invalid texturenum %d\n", texnum ); + texnum = tr.defaultTexture; + } + + texture = &gl_textures[texnum]; +#if 1 + if( glState.currentTexture == texnum ) + return; + + // Set palette + if(texture->format == GU_PSM_T8 && texture->dstPalette) + { + sceGuClutMode( PALETTE_FORMAT, 0, 0xff, 0 ); + sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ); + } + + // Set texture parameters + sceGuTexMode( texture->format, texture->numMips, 0, FBitSet(texture->guFlags, GUFLAGTEXSWIZZLED) ? GU_TRUE : GU_FALSE ); + if(texture->numMips > 0) + { + sceGuTexFilter( GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR_MIPMAP_LINEAR ); + sceGuTexLevelMode( gl_texture_lodfunc->value, gl_texture_lodbias->value ); + sceGuTexSlope( gl_texture_lodslope->value ); + } + else + { + sceGuTexFilter( GU_LINEAR, GU_LINEAR ); + } + + // Set base texture + sceGuTexImage(0, texture->width, texture->height, texture->width, texture->dstTexture); + + // Set mip textures + if( texture->numMips > 0 ) + { + int offset = texture->width * texture->height; + int width, height; + for ( i = 1; i <= texture->numMips; i++ ) + { + width = Q_max( 1, ( texture->width >> i ) ); + height = Q_max( 1, ( texture->height >> i ) ); + sceGuTexImage( i, width, height, width, &texture->dstTexture[offset] ); + offset += width * height; + } + } + + glState.currentTexture = texnum; +#else + glTarget = texture->target; + + if( glTarget == GL_TEXTURE_2D_ARRAY_EXT ) + glTarget = GL_TEXTURE_2D; + + if( glState.currentTextureTargets[tmu] != glTarget ) + { + if( glState.currentTextureTargets[tmu] != GL_NONE ) + pglDisable( glState.currentTextureTargets[tmu] ); + glState.currentTextureTargets[tmu] = glTarget; + pglEnable( glState.currentTextureTargets[tmu] ); + } + + if( glState.currentTextures[tmu] == texture->texnum ) + return; + + pglBindTexture( texture->target, texture->texnum ); + + glState.currentTextures[tmu] = texture->texnum; +#endif +} + +/* +================= +GL_ApplyTextureParams +================= +*/ +void GL_ApplyTextureParams( gl_texture_t *tex ) +{ +#if 0 + vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f }; + + if( !glw_state.initialized ) + return; + + Assert( tex != NULL ); + + // set texture filter + if( FBitSet( tex->flags, TF_DEPTHMAP )) + { + if( !FBitSet( tex->flags, TF_NOCOMPARE )) + { + pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB ); + pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); + } + + if( FBitSet( tex->flags, TF_LUMINANCE )) + pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE ); + else pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY ); + + if( FBitSet( tex->flags, TF_NEAREST )) + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + + // allow max anisotropy as 1.0f on depth textures + if( GL_Support( GL_ANISOTROPY_EXT )) + pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f ); + } + else if( FBitSet( tex->flags, TF_NOMIPMAP ) || tex->numMips <= 1 ) + { + if( FBitSet( tex->flags, TF_NEAREST ) || ( IsLightMap( tex ) && gl_lightmap_nearest->value )) + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + } + else + { + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->value ) + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + + // set texture anisotropy if available + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_ALPHACONTRAST )) + pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value ); + + // set texture LOD bias if available + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 )) + pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value ); + } + + // check if border is not supported + if( FBitSet( tex->flags, TF_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT )) + { + ClearBits( tex->flags, TF_BORDER ); + SetBits( tex->flags, TF_CLAMP ); + } + + // only seamless cubemaps allows wrap 'clamp_to_border" + if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && FBitSet( tex->flags, TF_BORDER )) + ClearBits( tex->flags, TF_BORDER ); + + // set texture wrap + if( FBitSet( tex->flags, TF_BORDER )) + { + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + + if( tex->target != GL_TEXTURE_1D ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER ); + + pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, border ); + } + else if( FBitSet( tex->flags, TF_CLAMP )) + { + if( GL_Support( GL_CLAMPTOEDGE_EXT )) + { + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + + if( tex->target != GL_TEXTURE_1D ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP ); + + if( tex->target != GL_TEXTURE_1D ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP ); + + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP ); + } + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_REPEAT ); + + if( tex->target != GL_TEXTURE_1D ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_REPEAT ); + + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_REPEAT ); + } +#endif +} + +/* +================= +GL_UpdateTextureParams +================= +*/ +static void GL_UpdateTextureParams( int iTexture ) +{ +#if 0 + gl_texture_t *tex = &gl_textures[iTexture]; + + Assert( tex != NULL ); + + if( !tex->texnum ) return; // free slot + + GL_Bind( XASH_TEXTURE0, iTexture ); + + // set texture anisotropy if available + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP|TF_ALPHACONTRAST )) + pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value ); + + // set texture LOD bias if available + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP )) + pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value ); + + if( IsLightMap( tex )) + { + if( gl_lightmap_nearest->value ) + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + } + + if( tex->numMips <= 1 ) return; + + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->value ) + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + else + { + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } +#endif +} + +/* +================= +R_SetTextureParameters +================= +*/ +void R_SetTextureParameters( void ) +{ +#if 0 + int i; + + if( GL_Support( GL_ANISOTROPY_EXT )) + { + if( gl_texture_anisotropy->value > glConfig.max_texture_anisotropy ) + gEngfuncs.Cvar_SetValue( "gl_anisotropy", glConfig.max_texture_anisotropy ); + else if( gl_texture_anisotropy->value < 1.0f ) + gEngfuncs.Cvar_SetValue( "gl_anisotropy", 1.0f ); + } + + if( GL_Support( GL_TEXTURE_LOD_BIAS )) + { + if( gl_texture_lodbias->value < -glConfig.max_texture_lod_bias ) + gEngfuncs.Cvar_SetValue( "gl_texture_lodbias", -glConfig.max_texture_lod_bias ); + else if( gl_texture_lodbias->value > glConfig.max_texture_lod_bias ) + gEngfuncs.Cvar_SetValue( "gl_texture_lodbias", glConfig.max_texture_lod_bias ); + } + + ClearBits( gl_texture_anisotropy->flags, FCVAR_CHANGED ); + ClearBits( gl_texture_lodbias->flags, FCVAR_CHANGED ); + ClearBits( gl_texture_nearest->flags, FCVAR_CHANGED ); + ClearBits( gl_lightmap_nearest->flags, FCVAR_CHANGED ); + + // change all the existing mipmapped texture objects + for( i = 0; i < gl_numTextures; i++ ) + GL_UpdateTextureParams( i ); +#endif +} + +/* +================ +GL_CalcTextureSamples +================ +*/ +static int GL_CalcTextureSamples( int flags ) +{ + if( FBitSet( flags, IMAGE_HAS_COLOR )) + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 4 : 3; + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 2 : 1; +} + +/* +================== +GL_CalcImageSize +================== +*/ +static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int depth ) +{ + size_t size = 0; + + // check the depth error + depth = Q_max( 1, depth ); + + switch( format ) + { + case PF_INDEXED_24: + case PF_INDEXED_32: + case PF_LUMINANCE: + size = width * height * depth; + break; + case PF_RGB_24: + case PF_BGR_24: + size = width * height * depth * 3; + break; + case PF_BGRA_32: + case PF_RGBA_32: + size = width * height * depth * 4; + break; + case PF_DXT1: + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth; + break; + case PF_DXT3: + case PF_DXT5: + case PF_ATI2: + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth; + break; + } + + return size; +} + +/* +================== +GL_CalcTextureSize +================== +*/ +static size_t GL_CalcTextureSize( int format, int width, int height ) +{ + size_t size = 0; + + switch( format ) + { + case GU_PSM_T4: + case GU_PSM_DXT1: + size = ( ( width * height ) >> 1 ); + break; + case GU_PSM_T8: + case GU_PSM_DXT3: + case GU_PSM_DXT5: + size = width * height; + break; + case GU_PSM_T16: + case GU_PSM_4444: + case GU_PSM_5551: + case GU_PSM_5650: + size = width * height * 2; + break; + case GU_PSM_T32: + case GU_PSM_8888: + size = width * height * 4; + break; + default: + gEngfuncs.Host_Error( "GL_CalcTextureSize: bad texture internal format (%u)\n", format ); + break; + } + return size; +} + +static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer ) +{ + int width, height; +#if 1 + int i, mipcount; +#endif + Assert( tex != NULL ); + + if( !haveBuffer ) + return 1; +#if 1 // brush model only + if( !FBitSet( tex->flags, TF_ALLOW_EMBOSS ) ) + return 1; +#endif + // generate mip-levels by user request + if( FBitSet( tex->flags, TF_NOMIPMAP )) + return 1; + + // mip-maps can't exceeds 16 +#if 1 // 8 mipmaps for GU + for( i = 0; i < 8; i++ ) +#else + for( mipcount = 0; mipcount < 16; mipcount++ ) +#endif + { + width = Q_max( 1, ( tex->width >> i )); + height = Q_max( 1, ( tex->height >> i )); +#if 1 + if( ( width > 16 ) && ( height > 16 ) ) + mipcount = i; + else break; +#else + if( width == 1 && height == 1 ) + break; +#endif + } + + return mipcount + 1; +} + +/* +================ +GL_SetTextureDimensions +================ +*/ +static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height, int depth ) +{ +#if 1 + int maxTextureSize = glConfig.max_texture_size; + + Assert( tex != NULL ); + + // store original sizes + tex->srcWidth = width; + tex->srcHeight = height; + + if( width > maxTextureSize || height > maxTextureSize ) + { + while( width > maxTextureSize || height > maxTextureSize ) + { + width >>= 1; + height >>= 1; + } + } + + float calc_w = ceilf( logf( width ) * 1.0f / logf( 2.0f ) ); + float calc_h = ceilf( logf( height ) * 1.0f / logf( 2.0f ) ); + width = ( 1 << ( int ) calc_w ); + height = ( 1 << ( int ) calc_h ); + + // set the texture dimensions + tex->width = Q_max( 32, width ); + tex->height = Q_max( 32, height ); + tex->depth = Q_max( 1, depth ); +#else + int maxTextureSize = 0; + int maxDepthSize = 1; + + Assert( tex != NULL ); + + switch( tex->target ) + { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + maxTextureSize = glConfig.max_2d_texture_size; + break; + case GL_TEXTURE_2D_ARRAY_EXT: + maxDepthSize = glConfig.max_2d_texture_layers; + maxTextureSize = glConfig.max_2d_texture_size; + break; + case GL_TEXTURE_RECTANGLE_EXT: + maxTextureSize = glConfig.max_2d_rectangle_size; + break; + case GL_TEXTURE_CUBE_MAP_ARB: + maxTextureSize = glConfig.max_cubemap_size; + break; + case GL_TEXTURE_3D: + maxDepthSize = glConfig.max_3d_texture_size; + maxTextureSize = glConfig.max_3d_texture_size; + break; + default: + Assert( false ); + } + + // store original sizes + tex->srcWidth = width; + tex->srcHeight = height; + + if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) + { + int step = (int)gl_round_down->value; + int scaled_width, scaled_height; + + for( scaled_width = 1; scaled_width < width; scaled_width <<= 1 ); + + if( step > 0 && width < scaled_width && ( step == 1 || ( scaled_width - width ) > ( scaled_width >> step ))) + scaled_width >>= 1; + + for( scaled_height = 1; scaled_height < height; scaled_height <<= 1 ); + + if( step > 0 && height < scaled_height && ( step == 1 || ( scaled_height - height ) > ( scaled_height >> step ))) + scaled_height >>= 1; + + width = scaled_width; + height = scaled_height; + } + + if( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize ) + { + if( tex->target == GL_TEXTURE_1D ) + { + while( width > maxTextureSize ) + width >>= 1; + } + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT ) + { + while( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize ) + { + width >>= 1; + height >>= 1; + depth >>= 1; + } + } + else // all remaining cases + { + while( width > maxTextureSize || height > maxTextureSize ) + { + width >>= 1; + height >>= 1; + } + } + } + + // set the texture dimensions + tex->width = Q_max( 1, width ); + tex->height = Q_max( 1, height ); + tex->depth = Q_max( 1, depth ); +#endif +} + +/* +=============== +GL_SetTextureFormat +=============== +*/ +static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int channelMask ) +{ + qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR ); + qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA ); + + Assert( tex != NULL ); +#if 1 + if( ImageDXT( format )) + { + switch( format ) + { + case PF_DXT1: tex->format = GU_PSM_DXT1; break; // never use DXT1 with 1-bit alpha + case PF_DXT3: tex->format = GU_PSM_DXT3; break; + case PF_DXT5: tex->format = GU_PSM_DXT5; break; + } + } + /* + else if( FBitSet( tex->flags, TF_DEPTHMAP )) + { + if( FBitSet( tex->flags, TF_ARB_16BIT )) + tex->format = GL_DEPTH_COMPONENT16; + else if( FBitSet( tex->flags, TF_ARB_FLOAT )) + tex->format = GL_DEPTH_COMPONENT32F; + else tex->format = GL_DEPTH_COMPONENT24; + }*/ + else + { + if( format == PF_INDEXED_24 || format == PF_INDEXED_32 ) + { + tex->format = GU_PSM_T8; + } + else + { + if ( IsLightMap( tex ) ) + tex->format = GU_PSM_5650; + else if( haveAlpha ) + tex->format = GU_PSM_4444; + else + tex->format = GU_PSM_5650; + } + } +#endif +#if 0 + qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR ); + qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA ); + + Assert( tex != NULL ); + + if( ImageDXT( format )) + { + switch( format ) + { + case PF_DXT1: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; // never use DXT1 with 1-bit alpha + case PF_DXT3: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case PF_DXT5: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case PF_ATI2: + if( glConfig.hardware_type == GLHW_RADEON ) + tex->format = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; + else tex->format = GL_COMPRESSED_RED_GREEN_RGTC2_EXT; + break; + } + return; + } + else if( FBitSet( tex->flags, TF_DEPTHMAP )) + { + if( FBitSet( tex->flags, TF_ARB_16BIT )) + tex->format = GL_DEPTH_COMPONENT16; + else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_DEPTH_FLOAT_EXT )) + tex->format = GL_DEPTH_COMPONENT32F; + else tex->format = GL_DEPTH_COMPONENT24; + } + else if( FBitSet( tex->flags, TF_ARB_FLOAT|TF_ARB_16BIT ) && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT )) + { + if( haveColor && haveAlpha ) + { + if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) + tex->format = GL_RGBA16F_ARB; + else tex->format = GL_RGBA32F_ARB; + } + else if( haveColor ) + { + if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) + tex->format = GL_RGB16F_ARB; + else tex->format = GL_RGB32F_ARB; + } + else if( haveAlpha ) + { + if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) + tex->format = GL_RG16F; + else tex->format = GL_RG32F; + } + else + { + if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) + tex->format = GL_LUMINANCE16F_ARB; + else tex->format = GL_LUMINANCE32F_ARB; + } + } + else + { + // NOTE: not all the types will be compressed + int bits = gpGlobals->desktopBitsPixel; + + switch( GL_CalcTextureSamples( channelMask )) + { + case 1: + if( FBitSet( tex->flags, TF_ALPHACONTRAST )) + tex->format = GL_INTENSITY8; + else tex->format = GL_LUMINANCE8; + break; + case 2: tex->format = GL_LUMINANCE8_ALPHA8; break; + case 3: + switch( bits ) + { + case 16: tex->format = GL_RGB5; break; + case 32: tex->format = GL_RGB8; break; + default: tex->format = GL_RGB; break; + } + break; + case 4: + default: + switch( bits ) + { + case 16: tex->format = GL_RGBA4; break; + case 32: tex->format = GL_RGBA8; break; + default: tex->format = GL_RGBA; break; + } + break; + } + } +#endif +} + +/* +================= +GL_ResampleTexture32 + +Assume input buffer is RGBA +================= +*/ +void GL_ResampleTexture32( const byte *source, int inWidth, int inHeight, byte *dest, int outWidth, int outHeight, qboolean isNormalMap ) +{ + uint frac, fracStep; + uint *in = (uint *)source; + uint p1[0x1000], p2[0x1000]; + byte *pix1, *pix2, *pix3, *pix4; + uint *out, *inRow1, *inRow2; + vec3_t normal; + int i, x, y; + + if( !source ) + return; + + fracStep = inWidth * 0x10000 / outWidth; + out = (uint *)dest; + + frac = fracStep >> 2; + for( i = 0; i < outWidth; i++ ) + { + p1[i] = 4 * (frac >> 16); + frac += fracStep; + } + + frac = (fracStep >> 2) * 3; + for( i = 0; i < outWidth; i++ ) + { + p2[i] = 4 * (frac >> 16); + frac += fracStep; + } + + if( isNormalMap ) + { + for( y = 0; y < outHeight; y++, out += outWidth ) + { + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight); + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight); + + for( x = 0; x < outWidth; x++ ) + { + pix1 = (byte *)inRow1 + p1[x]; + pix2 = (byte *)inRow1 + p2[x]; + pix3 = (byte *)inRow2 + p1[x]; + pix4 = (byte *)inRow2 + p2[x]; + + normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] ); + normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] ); + normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] ); + + if( !VectorNormalizeLength( normal )) + VectorSet( normal, 0.5f, 0.5f, 1.0f ); + + ((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]); + ((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]); + ((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]); + ((byte *)(out+x))[3] = 255; + } + } + } + else + { + for( y = 0; y < outHeight; y++, out += outWidth ) + { + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight); + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight); + + for( x = 0; x < outWidth; x++ ) + { + pix1 = (byte *)inRow1 + p1[x]; + pix2 = (byte *)inRow1 + p2[x]; + pix3 = (byte *)inRow2 + p1[x]; + pix4 = (byte *)inRow2 + p2[x]; + + ((byte *)(out+x))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2; + ((byte *)(out+x))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2; + ((byte *)(out+x))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2; + ((byte *)(out+x))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2; + } + } + } +} + +/* +================= +GL_ResampleTexture8 + +For indexed textures +================= +*/ +void GL_ResampleTexture8(const byte *source, int inWidth, int inHeight, byte *dest, int outWidth, int outHeight) +{ + uint fracstep; + byte *out; + const byte *inrow; + uint frac; + int i, j; + + if( !source ) + return; + + fracstep = inWidth * 0x10000 / outWidth; + out = dest; + + for (i = 0; i < outHeight ; ++i, out += outWidth) + { + inrow = source + inWidth * (i * inHeight / outHeight); + frac = fracstep >> 1; + for (j = 0; j < outWidth; ++j, frac += fracstep) + { + out[j] = inrow[frac >> 16]; + } + } +} +/* +================= +GL_BoxFilter3x3 + +box filter 3x3 +================= +*/ +void GL_BoxFilter3x3( byte *out, const byte *in, int w, int h, int x, int y ) +{ + int r = 0, g = 0, b = 0, a = 0; + int count = 0, acount = 0; + int i, j, u, v; + const byte *pixel; + + for( i = 0; i < 3; i++ ) + { + u = ( i - 1 ) + x; + + for( j = 0; j < 3; j++ ) + { + v = ( j - 1 ) + y; + + if( u >= 0 && u < w && v >= 0 && v < h ) + { + pixel = &in[( u + v * w ) * 4]; + + if( pixel[3] != 0 ) + { + r += pixel[0]; + g += pixel[1]; + b += pixel[2]; + a += pixel[3]; + acount++; + } + } + } + } + + if( acount == 0 ) + acount = 1; + + out[0] = r / acount; + out[1] = g / acount; + out[2] = b / acount; +// out[3] = (int)( SimpleSpline( ( a / 12.0f ) / 255.0f ) * 255 ); +} + +/* +================= +GL_ApplyFilter + +Apply box-filter to 1-bit alpha +================= +*/ +byte *GL_ApplyFilter( const byte *source, int width, int height ) +{ + byte *in = (byte *)source; + byte *out = (byte *)source; + int i; + + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) ) + return in; + + for( i = 0; source && i < width * height; i++, in += 4 ) + { + if( in[0] == 0 && in[1] == 0 && in[2] == 0 && in[3] == 0 ) + GL_BoxFilter3x3( in, source, width, height, i % width, i / width ); + } + + return out; +} + +/* +================= +GL_BuildMipMap + +Operates in place, quartering the size of the texture +================= +*/ +static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, int flags ) +{ + byte *out = in; + int instride = ALIGN( srcWidth * 4, 1 ); + int mipWidth, mipHeight, outpadding; + int row, x, y, z; + vec3_t normal; + + if( !in ) return; + + mipWidth = Q_max( 1, ( srcWidth >> 1 )); + mipHeight = Q_max( 1, ( srcHeight >> 1 )); + outpadding = ALIGN( mipWidth * 4, 1 ) - mipWidth * 4; + row = srcWidth << 2; + + if( FBitSet( flags, TF_ALPHACONTRAST )) + { + memset( in, mipWidth, mipWidth * mipHeight * 4 ); + return; + } + + // move through all layers + for( z = 0; z < srcDepth; z++ ) + { + if( FBitSet( flags, TF_NORMALMAP )) + { + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding ) + { + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in; + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 ) + { + if((( x << 1 ) + 1 ) < srcWidth ) + { + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( in[row+4] ) + + MAKE_SIGNED( next[row+0] ) + MAKE_SIGNED( next[row+4] ); + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( in[row+5] ) + + MAKE_SIGNED( next[row+1] ) + MAKE_SIGNED( next[row+5] ); + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( in[row+6] ) + + MAKE_SIGNED( next[row+2] ) + MAKE_SIGNED( next[row+6] ); + } + else + { + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( next[row+0] ); + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( next[row+1] ); + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( next[row+2] ); + } + + if( !VectorNormalizeLength( normal )) + VectorSet( normal, 0.5f, 0.5f, 1.0f ); + + out[0] = 128 + (byte)(127.0f * normal[0]); + out[1] = 128 + (byte)(127.0f * normal[1]); + out[2] = 128 + (byte)(127.0f * normal[2]); + out[3] = 255; + } + } + } + else + { + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding ) + { + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in; + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 ) + { + if((( x << 1 ) + 1 ) < srcWidth ) + { + out[0] = (in[row+0] + in[row+4] + next[row+0] + next[row+4]) >> 2; + out[1] = (in[row+1] + in[row+5] + next[row+1] + next[row+5]) >> 2; + out[2] = (in[row+2] + in[row+6] + next[row+2] + next[row+6]) >> 2; + out[3] = (in[row+3] + in[row+7] + next[row+3] + next[row+7]) >> 2; + } + else + { + out[0] = (in[row+0] + next[row+0]) >> 1; + out[1] = (in[row+1] + next[row+1]) >> 1; + out[2] = (in[row+2] + next[row+2]) >> 1; + out[3] = (in[row+3] + next[row+3]) >> 1; + } + } + } + } + } +} + +static void GL_TextureImageRAW( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, GLint type, const void *data ) +{ +#if 0 + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; + qboolean subImage = FBitSet( tex->flags, TF_IMG_UPLOADED ); + GLenum inFormat = gEngfuncs.Image_GetPFDesc(type)->glFormat; + GLint dataType = GL_UNSIGNED_BYTE; + + Assert( tex != NULL ); +#endif +} +#if 0 +static void GL_TextureImageDXT( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data ) +{ + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; + qboolean subImage = FBitSet( tex->flags, TF_IMG_UPLOADED ); + + Assert( tex != NULL ); + +#ifndef XASH_GLES + if( tex->target == GL_TEXTURE_1D ) + { + if( subImage ) pglCompressedTexSubImage1DARB( tex->target, level, 0, width, tex->format, size, data ); + else pglCompressedTexImage1DARB( tex->target, level, tex->format, width, 0, size, data ); + } + else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB ) + { + if( subImage ) pglCompressedTexSubImage2DARB( cubeTarget + side, level, 0, 0, width, height, tex->format, size, data ); + else pglCompressedTexImage2DARB( cubeTarget + side, level, tex->format, width, height, 0, size, data ); + } + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT ) + { + if( subImage ) pglCompressedTexSubImage3DARB( tex->target, level, 0, 0, 0, width, height, depth, tex->format, size, data ); + else pglCompressedTexImage3DARB( tex->target, level, tex->format, width, height, depth, 0, size, data ); + } + else // 2D or RECT + { + if( subImage ) pglCompressedTexSubImage2DARB( tex->target, level, 0, 0, width, height, tex->format, size, data ); + else pglCompressedTexImage2DARB( tex->target, level, tex->format, width, height, 0, size, data ); + } +#endif +} +#endif +/* +=============== +GL_PixelConverter +=============== +*/ +static void GL_PixelConverter( byte *dst, const byte *src, int size, qboolean alpha, int format ) +{ +#if 0 // undone + if(alpha) + { + __asm__ volatile ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "move $8, %0\n" // $8 = &dst[0] + "move $9, %1\n" // $9 = &src[0] + "move $10, %2\n" // $10 = size + "0:\n" + + "ulv.q C000, 0($8)\n" // Load 4 pixels from src + + "vt4444.q C010, C000\n" // Convert 4 -> 2 + + "sv.s S010, 0($9)\n" + "sv.s S010, 8($9)\n" + "addiu $8, $8, 16\n" // $8 = $8 + 16 + "addiu $9, $9, 8\n" // $9 = $9 + 8 + + "bne $10, $8, 0b\n" // if ( $11 != $8 ) jump to loop + "addiu $10, $10, -4\n" // $10 = $10 - 4 ( delay slot ) + ".set pop\n" // Restore assembler option + : "r"( dst ), "r"( src ), "r"( size ), "r"( format ) + : "$8", "$9", "$10" + ); + } + else + { + + } +#else + int i; + byte color[4]; + + for( i = 0; i < size; i++ ) + { + switch( format ) + { + case GU_PSM_4444: + color[0] = *src; src++; + color[1] = *src; src++; + color[2] = *src; src++; + color[3] = alpha ? *src : 0xff; if( alpha ) src++; + *dst = ( color[0] >> 4 ) & 0x0f; + *dst |= ( color[1] ) & 0xf0; dst++; + *dst = ( color[2] >> 4 ) & 0x0f; + *dst |= ( color[3] ) & 0xf0; dst++; + break; + case GU_PSM_5551: + color[0] = ( *src >> 3 ) & 0x1f; src++; + color[1] = ( *src >> 3 ) & 0x1f; src++; + color[2] = ( *src >> 3 ) & 0x1f; src++; + color[3] = alpha ? ( ( *src >> 7 ) & 0x01 ) : 0xff; if( alpha ) src++; + *dst = color[0]; + *dst |= ( color[1] << 5 ) & 0xe0; dst++; + *dst = ( color[1] >> 3 ) & 0x03; + *dst |= ( color[2] << 2 ) & 0x7c; + *dst |= ( color[3] << 7 ) & 0x80; dst++; + break; + case GU_PSM_5650: + color[0] = ( *src >> 3 ) & 0x1f; src++; + color[1] = ( *src >> 2 ) & 0x3f; src++; + color[2] = ( *src >> 3 ) & 0x1f; src++; if( alpha ) src++; + *dst = color[0]; + *dst |= ( color[1] << 5 ) & 0xe0; dst++; + *dst = ( color[1] >> 3 ) & 0x07; + *dst |= ( color[2] << 3 ) & 0xf8; dst++; + break; + case GU_PSM_8888: + *dst = *src; src++; dst++; + *dst = *src; src++; dst++; + *dst = *src; src++; dst++; + *dst = alpha ? *src : 0xff; if( alpha ) src++; dst++; + break; + default: + break; + } + } +#endif +} +/* +=============== +GL_TextureSwizzle + +fast swizzling +=============== +*/ +static void GL_TextureSwizzle(byte *dst, const byte *src, uint width, uint height) +{ + uint blockx, blocky; + uint j; + uint width_blocks = ( width / 16 ); + uint height_blocks = ( height / 8 ); + uint src_pitch = ( width - 16 ) / 4; + uint src_row = width * 8; + const byte* ysrc = src; + uint* dst32 = ( uint* )dst; + + for (blocky = 0; blocky < height_blocks; ++blocky) + { + const byte* xsrc = ysrc; + for (blockx = 0; blockx < width_blocks; ++blockx) + { + const int* src32 = ( uint* )xsrc; + for (j = 0; j < 8; ++j) + { + *(dst32++) = *(src32++); + *(dst32++) = *(src32++); + *(dst32++) = *(src32++); + *(dst32++) = *(src32++); + src32 += src_pitch; + } + xsrc += 16; + } + ysrc += src_row; + } +} + +/* +=============== +GL_UploadTexture + +upload texture into memory +=============== +*/ +static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) +{ + byte *buf, *data; + size_t texsize, size; + uint width, height; + uint i, j, numSides; + uint offset = 0; + qboolean normalMap; + const byte *bufend; + void *volBuff; + unsigned int volSize; + int volUid; + + // dedicated server + if( !glw_state.initialized ) + return true; + + Assert( pic != NULL ); + Assert( tex != NULL ); + + GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth ); + GL_SetTextureFormat( tex, pic->type, pic->flags ); + + tex->fogParams[0] = pic->fogParams[0]; + tex->fogParams[1] = pic->fogParams[1]; + tex->fogParams[2] = pic->fogParams[2]; + tex->fogParams[3] = pic->fogParams[3]; + + if(( pic->width * pic->height ) & 3 ) + { + // will be resampled, just tell me for debug targets + gEngfuncs.Con_Reportf( "GL_UploadTexture: %s s&3 [%d x %d]\n", tex->name, pic->width, pic->height ); + } + + if( !pic->buffer ) + return true; + + buf = pic->buffer; + bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps + + offset = GL_CalcImageSize( pic->type, pic->width, pic->height, pic->depth ); + texsize = GL_CalcTextureSize( tex->format, tex->width, tex->height ); + normalMap = FBitSet( tex->flags, TF_NORMALMAP ) ? true : false; + tex->numMips = 0; + + volUid = sceKernelVolatileMemLock( 0, &volBuff, &volSize ); + if( volUid != 0) + gEngfuncs.Host_Error( "GL_AllocTexture: volatile memory lock error 0x%08x ! \n", volUid); + + if( ImageDXT( pic->type ) ) + { + memcpy(tex->dstTexture, buf, texsize); + } + else if( pic->type == PF_INDEXED_32 ) + { + int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL )); + + // Calc mip size + texsize = 0; + for(j = 0; j < mipCount; j++ ) + { + width = Q_max( 1, ( tex->width >> j ) ); + height = Q_max( 1, ( tex->height >> j ) ); + texsize += GL_CalcTextureSize( tex->format, width, height ); + } + + // Check allocation size + if( tex->dstTexture && ( tex->size != texsize ) ) + { + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + + // Already allocated? + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )valloc( texsize ); + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )memalign( 16, texsize ); + if ( !tex->dstTexture ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); + } + } + else + { + SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + } + + // Load palette + tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !tex->dstPalette ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); + } + GL_PixelConverter( tex->dstPalette, pic->palette, 256, true, PALETTE_FORMAT ); + sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); + + int mip_offset = 0; + for( j = 0; j < mipCount; j++ ) + { + width = Q_max( 1, ( tex->width >> j ) ); + height = Q_max( 1, ( tex->height >> j ) ); + + if( ( pic->width != width ) || ( pic->height != height ) ) + GL_ResampleTexture8( buf, pic->width, pic->height, volBuff, width, height ); + else memcpy(volBuff, buf, offset); + GL_TextureSwizzle( tex->dstTexture + mip_offset, volBuff, width, height ); + mip_offset += GL_CalcTextureSize( tex->format, width, height ); + tex->numMips = j; + } + SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + } + else if( pic->type == PF_INDEXED_24 ) + { + // Check allocation + if( tex->dstTexture && ( tex->size != texsize ) ) + { + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + // Already allocated + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )valloc( texsize ); + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )memalign( 16, texsize ); + if ( !tex->dstTexture ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); + } + } + else + { + SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + } + + if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) + GL_ResampleTexture8( buf, pic->width, pic->height, volBuff, tex->width, tex->height ); + else + memcpy(volBuff, buf, offset); + + tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !tex->dstPalette ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); + } + GL_PixelConverter( tex->dstPalette, pic->palette, 256, false, PALETTE_FORMAT ); + sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); + GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width, tex->height ); + SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + } + else // RGBA32 + { + // Check allocation + if( tex->dstTexture && ( tex->size != texsize ) ) + { + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + // Already allocated + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )valloc( texsize ); + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )memalign( 16, texsize ); + if ( !tex->dstTexture ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); + } + } + else + { + SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + } + + if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) + { + GL_ResampleTexture32( buf, pic->width, pic->height, volBuff, tex->width, tex->height, normalMap ); + offset = tex->width * tex->height * 4; + } + else + { + memcpy( volBuff, buf, offset ); + } + + if( tex->format == GU_PSM_8888 ) + { + memcpy( tex->dstTexture, volBuff, texsize ); + } + else + { + if ( IsLightMap( tex ) ) + { + GL_PixelConverter( tex->dstTexture, volBuff, tex->width * tex->height, true, tex->format ); + } + else + { +/* + if( !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + volBuff = GL_ApplyFilter( volBuff, tex->width, tex->height ); +*/ + GL_PixelConverter( volBuff + offset, volBuff, tex->width * tex->height, true, tex->format ); + GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * 2, tex->height ); + SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + } + } + } + sceKernelVolatileMemUnlock( 0 ); + sceKernelDcacheWritebackRange( tex->dstTexture, texsize ); + tex->size = texsize; + + SetBits( tex->flags, TF_IMG_UPLOADED ); // done + + return true; +} + +/* +=============== +GL_UpdateDlightTexture + +=============== +*/ +qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ) +{ + gl_texture_t *tex; + size_t texsize; + + // missed or invalid texture? + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + { + if( texnum != 0 ) + { + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid texturenum %d\n", texnum ); + return false; + } + } + tex = &gl_textures[texnum]; + + if(tex->width < width || tex->height < height ) + { + + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid update area size %s\n", tex->name ); + return false; + } + + if(tex->width < xoff || tex->height < yoff ) + { + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid position cord %s\n", tex->name ); + return false; + } + tex->numMips = 0; + tex->dstPalette = NULL; + tex->format = GU_PSM_5650; + + texsize = tex->width * tex->height * 2; + if( tex->size != texsize ) + { + if( tex->dstTexture ) + { + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + + tex->dstTexture = NULL; + ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + } + + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )valloc( texsize ); + if( !tex->dstTexture ) + { + tex->dstTexture = ( byte* )memalign( 16, texsize ); + if ( !tex->dstTexture ) + gEngfuncs.Host_Error( "GL_UpdateDlightTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); + } + else + { + SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + memset( tex->dstTexture, 0x00, texsize ); + SetBits( tex->flags, TF_IMG_UPLOADED ); // done + } + + tex->size = texsize; + byte *src = ( byte* )buffer; + byte *dst = tex->dstTexture; + + dst += ( yoff * tex->width + xoff ) * 2; + while( height-- ) + { + GL_PixelConverter( dst, src, width, true, tex->format ); + dst += tex->width * 2; + src += width * 4; + } + sceKernelDcacheWritebackRange( tex->dstTexture, texsize ); + return true; +} + +/* +=============== +GL_ProcessImage + +do specified actions on pixels +=============== +*/ +static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) +{ + float emboss_scale = 0.0f; + uint img_flags = 0; + + // force upload texture as RGB or RGBA (detail textures requires this) + if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; + if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA; + + tex->encode = pic->encode; // share encode method + + if( ImageDXT( pic->type )) + { + if( !pic->numMips ) + tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request + + // clear all the unsupported flags + tex->flags &= ~TF_KEEP_SOURCE; + } + else + { + // copy flag about luma pixels + if( pic->flags & IMAGE_HAS_LUMA ) + tex->flags |= TF_HAS_LUMA; + + if( pic->flags & IMAGE_QUAKEPAL ) + tex->flags |= TF_QUAKEPAL; + + // create luma texture from quake texture + if( tex->flags & TF_MAKELUMA ) + { + img_flags |= IMAGE_MAKE_LUMA; + tex->flags &= ~TF_MAKELUMA; + } + + if( tex->flags & TF_ALLOW_EMBOSS ) + { + img_flags |= IMAGE_EMBOSS; + //tex->flags &= ~TF_ALLOW_EMBOSS; + } + + if( !FBitSet( tex->flags, TF_IMG_UPLOADED ) && FBitSet( tex->flags, TF_KEEP_SOURCE )) + tex->original = gEngfuncs.FS_CopyImage( pic ); // because current pic will be expanded to rgba +#if 0 // forced indexed textures + // we need to expand image into RGBA buffer + if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 ) + img_flags |= IMAGE_FORCE_RGBA; +#endif + // dedicated server doesn't register this variable + if( gl_emboss_scale != NULL ) + emboss_scale = gl_emboss_scale->value; + + // processing image before uploading (force to rgba, make luma etc) + if( pic->buffer ) gEngfuncs.Image_Process( &pic, 0, 0, img_flags, emboss_scale ); + + if( FBitSet( tex->flags, TF_LUMINANCE )) + ClearBits( pic->flags, IMAGE_HAS_COLOR ); + } +} + +/* +================ +GL_CheckTexName +================ +*/ +qboolean GL_CheckTexName( const char *name ) +{ + if( !COM_CheckString( name )) + return false; + + // because multi-layered textures can exceed name string + if( Q_strlen( name ) >= sizeof( gl_textures->name )) + { + gEngfuncs.Con_Printf( S_ERROR "LoadTexture: too long name %s (%d)\n", name, Q_strlen( name )); + return false; + } + + return true; +} + +/* +================ +GL_TextureForName +================ +*/ +static gl_texture_t *GL_TextureForName( const char *name ) +{ + gl_texture_t *tex; + uint hash; + + // find the texture in array + hash = COM_HashKey( name, TEXTURES_HASH_SIZE ); + + for( tex = gl_texturesHashTable[hash]; tex != NULL; tex = tex->nextHash ) + { + if( !Q_stricmp( tex->name, name )) + return tex; + } + + return NULL; +} + +/* +================ +GL_AllocTexture +================ +*/ +static gl_texture_t *GL_AllocTexture( const char *name, texFlags_t flags ) +{ + gl_texture_t *tex; + uint i; + + // find a free texture_t slot + for( i = 0, tex = gl_textures; i < gl_numTextures; i++, tex++ ) + if( !tex->name[0] ) break; + + if( i == gl_numTextures ) + { + if( gl_numTextures == MAX_TEXTURES ) + gEngfuncs.Host_Error( "GL_AllocTexture: MAX_TEXTURES limit exceeds\n" ); + gl_numTextures++; + } + + tex = &gl_textures[i]; + + // copy initial params + Q_strncpy( tex->name, name, sizeof( tex->name )); +#if 0 + if( FBitSet( flags, TF_SKYSIDE )) + tex->texnum = tr.skyboxbasenum++; + else tex->texnum = i; // texnum is used for fast acess into gl_textures array too +#endif + tex->flags = flags; + + // add to hash table + tex->hashValue = COM_HashKey( name, TEXTURES_HASH_SIZE ); + tex->nextHash = gl_texturesHashTable[tex->hashValue]; + gl_texturesHashTable[tex->hashValue] = tex; + + return tex; +} + +/* +================ +GL_DeleteTexture +================ +*/ +static void GL_DeleteTexture( gl_texture_t *tex ) +{ + gl_texture_t **prev; + gl_texture_t *cur; + + ASSERT( tex != NULL ); + + // already freed? + if( !tex->dstTexture && !tex->name[0] ) return; + + // debug + if( !tex->name[0] ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_DeleteTexture: trying to free unnamed texture\n"); + return; + } + + // remove from hash table + prev = &gl_texturesHashTable[tex->hashValue]; + while( 1 ) + { + cur = *prev; + if( !cur ) break; + + if( cur == tex ) + { + *prev = cur->nextHash; + break; + } + prev = &cur->nextHash; + } + + // release source + if( tex->original ) + gEngfuncs.FS_FreeImage( tex->original ); + + if( tex->dstPalette ) + free( tex->dstPalette ); + + if( tex->dstTexture ) + { + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + } + memset( tex, 0, sizeof( *tex )); +} + +/* +================ +GL_UpdateTexSize + +recalc image room +================ +*/ +void GL_UpdateTexSize( int texnum, int width, int height, int depth ) +{ + int i, j, texsize; + int numSides; + gl_texture_t *tex; + + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + return; + + tex = &gl_textures[texnum]; + numSides = FBitSet( tex->flags, TF_CUBEMAP ) ? 6 : 1; + GL_SetTextureDimensions( tex, width, height, depth ); + tex->size = 0; // recompute now + + for( i = 0; i < numSides; i++ ) + { + for( j = 0; j < Q_max( 1, tex->numMips ); j++ ) + { + width = Q_max( 1, ( tex->width >> j )); + height = Q_max( 1, ( tex->height >> j )); +#if 1 + texsize = GL_CalcTextureSize( tex->format, width, height ); +#else + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); +#endif + tex->size += texsize; + } + } +} + +/* +================ +GL_LoadTexture +================ +*/ +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) +{ + gl_texture_t *tex; + rgbdata_t *pic; + uint picFlags = 0; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name ))) + return (tex - gl_textures); + + if( FBitSet( flags, TF_NOFLIP_TGA )) + SetBits( picFlags, IL_DONTFLIP_TGA ); +#if 1 + SetBits( picFlags, IL_KEEP_8BIT ); +#else + if( FBitSet( flags, TF_KEEP_SOURCE ) && !FBitSet( flags, TF_EXPAND_SOURCE )) + SetBits( picFlags, IL_KEEP_8BIT ); +#endif + // set some image flags + gEngfuncs.Image_SetForceFlags( picFlags ); + + pic = gEngfuncs.FS_LoadImage( name, buf, size ); + if( !pic ) return 0; // couldn't loading image + + // allocate the new one + tex = GL_AllocTexture( name, flags ); + GL_ProcessImage( tex, pic ); + + if( !GL_UploadTexture( tex, pic )) + { + memset( tex, 0, sizeof( gl_texture_t )); + gEngfuncs.FS_FreeImage( pic ); // release source texture + return 0; + } + + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc + gEngfuncs.FS_FreeImage( pic ); // release source texture + + // NOTE: always return texnum as index in array or engine will stop work !!! + return tex - gl_textures; +} + +/* +================ +GL_LoadTextureArray +================ +*/ +int GL_LoadTextureArray( const char **names, int flags ) +{ +#if 1 + return 0; +#else + rgbdata_t *pic, *src; + char basename[256]; + uint numLayers = 0; + uint picFlags = 0; + char name[256]; + gl_texture_t *tex; + uint i, j; + + if( !names || !names[0] || !glw_state.initialized ) + return 0; + + // count layers (g-cont. this is pontentially unsafe loop) + for( i = 0; i < glConfig.max_2d_texture_layers && ( *names[i] != '\0' ); i++ ) + numLayers++; + name[0] = '\0'; + + if( numLayers <= 0 ) return 0; + + // create complexname from layer names + for( i = 0; i < numLayers; i++ ) + { + COM_FileBase( names[i], basename ); + Q_strncat( name, va( "%s", basename ), sizeof( name )); + if( i != ( numLayers - 1 )) Q_strncat( name, "|", sizeof( name )); + } + + Q_strncat( name, va( "[%i]", numLayers ), sizeof( name )); + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name ))) + return (tex - gl_textures); + + // load all the images and pack it into single image + for( i = 0, pic = NULL; i < numLayers; i++ ) + { + size_t srcsize, dstsize, mipsize; + + src = gEngfuncs.FS_LoadImage( names[i], NULL, 0 ); + if( !src ) break; // coldn't find layer + + if( pic ) + { + // mixed mode: DXT + RGB + if( pic->type != src->type ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_LoadTextureArray: mismatch image format for %s and %s\n", names[0], names[i] ); + break; + } + + // different mipcount + if( pic->numMips != src->numMips ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_LoadTextureArray: mismatch mip count for %s and %s\n", names[0], names[i] ); + break; + } + + if( pic->encode != src->encode ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_LoadTextureArray: mismatch custom encoding for %s and %s\n", names[0], names[i] ); + break; + } + + // but allow to rescale raw images + if( ImageRAW( pic->type ) && ImageRAW( src->type ) && ( pic->width != src->width || pic->height != src->height )) + gEngfuncs.Image_Process( &src, pic->width, pic->height, IMAGE_RESAMPLE, 0.0f ); + + if( pic->size != src->size ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_LoadTextureArray: mismatch image size for %s and %s\n", names[0], names[i] ); + break; + } + } + else + { + // create new image + pic = Mem_Malloc( gEngfuncs.Image_GetPool(), sizeof( rgbdata_t )); + memcpy( pic, src, sizeof( rgbdata_t )); + + // expand pic buffer for all layers + pic->buffer = Mem_Malloc( gEngfuncs.Image_GetPool(), pic->size * numLayers ); + pic->depth = 0; + } + + mipsize = srcsize = dstsize = 0; + + for( j = 0; j < max( 1, pic->numMips ); j++ ) + { + int width = Q_max( 1, ( pic->width >> j )); + int height = Q_max( 1, ( pic->height >> j )); + mipsize = GL_CalcImageSize( pic->type, width, height, 1 ); + memcpy( pic->buffer + dstsize + mipsize * i, src->buffer + srcsize, mipsize ); + dstsize += mipsize * numLayers; + srcsize += mipsize; + } + + gEngfuncs.FS_FreeImage( src ); + + // increase layers + pic->depth++; + } + + // there were errors + if( !pic || ( pic->depth != numLayers )) + { + gEngfuncs.Con_Printf( S_ERROR "GL_LoadTextureArray: not all layers were loaded. Texture array is not created\n" ); + if( pic ) gEngfuncs.FS_FreeImage( pic ); + return 0; + } + + // it's multilayer image! + SetBits( pic->flags, IMAGE_MULTILAYER ); + pic->size *= numLayers; + + // allocate the new one + tex = GL_AllocTexture( name, flags ); + GL_ProcessImage( tex, pic ); + + if( !GL_UploadTexture( tex, pic )) + { + memset( tex, 0, sizeof( gl_texture_t )); + gEngfuncs.FS_FreeImage( pic ); // release source texture + return 0; + } + + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc + gEngfuncs.FS_FreeImage( pic ); // release source texture + + // NOTE: always return texnum as index in array or engine will stop work !!! + return tex - gl_textures; +#endif +} + +/* +================ +GL_LoadTextureFromBuffer +================ +*/ +int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ) +{ + gl_texture_t *tex; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name )) && !update ) + return (tex - gl_textures); + + // couldn't loading image + if( !pic ) return 0; + + if( update ) + { + if( tex == NULL ) + gEngfuncs.Host_Error( "GL_LoadTextureFromBuffer: couldn't find texture %s for update\n", name ); + SetBits( tex->flags, flags ); + } + else + { + // allocate the new one + tex = GL_AllocTexture( name, flags ); + } + + GL_ProcessImage( tex, pic ); + + if( !GL_UploadTexture( tex, pic )) + { + memset( tex, 0, sizeof( gl_texture_t )); + return 0; + } + + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc + return (tex - gl_textures); +} + +/* +================ +GL_CreateTexture + +creates texture from buffer +================ +*/ +int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ) +{ + qboolean update = FBitSet( flags, TF_UPDATE ) ? true : false; + int datasize = 1; + rgbdata_t r_empty; + + if( FBitSet( flags, TF_ARB_16BIT )) + datasize = 2; + else if( FBitSet( flags, TF_ARB_FLOAT )) + datasize = 4; + + ClearBits( flags, TF_UPDATE ); + memset( &r_empty, 0, sizeof( r_empty )); + r_empty.width = width; + r_empty.height = height; + r_empty.type = PF_RGBA_32; + r_empty.size = r_empty.width * r_empty.height * datasize * 4; + r_empty.buffer = (byte *)buffer; + + // clear invalid combinations + ClearBits( flags, TF_TEXTURE_3D ); + + // if image not luminance and not alphacontrast it will have color + if( !FBitSet( flags, TF_LUMINANCE ) && !FBitSet( flags, TF_ALPHACONTRAST )) + SetBits( r_empty.flags, IMAGE_HAS_COLOR ); + + if( FBitSet( flags, TF_HAS_ALPHA )) + SetBits( r_empty.flags, IMAGE_HAS_ALPHA ); +#if 0 + if( FBitSet( flags, TF_CUBEMAP )) + { + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT )) + return 0; + SetBits( r_empty.flags, IMAGE_CUBEMAP ); + r_empty.size *= 6; + } +#endif + return GL_LoadTextureFromBuffer( name, &r_empty, flags, update ); +} + +/* +================ +GL_CreateTextureArray + +creates texture array from buffer +================ +*/ +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ) +{ +#if 1 + return 0; +#else + rgbdata_t r_empty; + + memset( &r_empty, 0, sizeof( r_empty )); + r_empty.width = Q_max( width, 1 ); + r_empty.height = Q_max( height, 1 ); + r_empty.depth = Q_max( depth, 1 ); + r_empty.type = PF_RGBA_32; + r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4; + r_empty.buffer = (byte *)buffer; + + // clear invalid combinations + ClearBits( flags, TF_CUBEMAP|TF_SKYSIDE|TF_HAS_LUMA|TF_MAKELUMA|TF_ALPHACONTRAST ); + + // if image not luminance it will have color + if( !FBitSet( flags, TF_LUMINANCE )) + SetBits( r_empty.flags, IMAGE_HAS_COLOR ); + + if( FBitSet( flags, TF_HAS_ALPHA )) + SetBits( r_empty.flags, IMAGE_HAS_ALPHA ); + + if( FBitSet( flags, TF_TEXTURE_3D )) + { + if( !GL_Support( GL_TEXTURE_3D_EXT )) + return 0; + } + else + { + if( !GL_Support( GL_TEXTURE_ARRAY_EXT )) + return 0; + SetBits( r_empty.flags, IMAGE_MULTILAYER ); + } + + return GL_LoadTextureInternal( name, &r_empty, flags ); +#endif +} + +/* +================ +GL_FindTexture +================ +*/ +int GL_FindTexture( const char *name ) +{ + gl_texture_t *tex; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name ))) + return (tex - gl_textures); + + return 0; +} + +/* +================ +GL_FreeTexture +================ +*/ +void GL_FreeTexture( GLenum texnum ) +{ + // number 0 it's already freed + if( texnum <= 0 ) return; + + GL_DeleteTexture( &gl_textures[texnum] ); +} + +/* +================ +GL_ProcessTexture +================ +*/ +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) +{ + gl_texture_t *image; + rgbdata_t *pic; + int flags = 0; + + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + return; // missed image + image = &gl_textures[texnum]; + + // select mode + if( gamma != -1.0f ) + { + flags = IMAGE_LIGHTGAMMA; + } + else if( topColor != -1 && bottomColor != -1 ) + { + flags = IMAGE_REMAP; + } + else + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: bad operation for %s\n", image->name ); + return; + } + + if( !image->original ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: no input data for %s\n", image->name ); + return; + } + + if( ImageDXT( image->original->type )) + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: can't process compressed texture %s\n", image->name ); + return; + } + + // all the operations makes over the image copy not an original + pic = gEngfuncs.FS_CopyImage( image->original ); + gEngfuncs.Image_Process( &pic, topColor, bottomColor, flags, 0.0f ); + + GL_UploadTexture( image, pic ); + GL_ApplyTextureParams( image ); // update texture filter, wrap etc + + gEngfuncs.FS_FreeImage( pic ); +} + +/* +================ +GL_TexMemory + +return size of all uploaded textures +================ +*/ +int GL_TexMemory( void ) +{ + int i, total = 0; + + for( i = 0; i < gl_numTextures; i++ ) + total += gl_textures[i].size; + + return total; +} + +/* +============================================================================== + +INTERNAL TEXTURES + +============================================================================== +*/ +/* +================== +GL_FakeImage +================== +*/ +static rgbdata_t *GL_FakeImage( int width, int height, int depth, int flags ) +{ + static byte data2D[1024]; // 16x16x4 + static rgbdata_t r_image; + + // also use this for bad textures, but without alpha + r_image.width = Q_max( 1, width ); + r_image.height = Q_max( 1, height ); + r_image.depth = Q_max( 1, depth ); + r_image.flags = flags; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * r_image.depth * 4; + r_image.buffer = (r_image.size > sizeof( data2D )) ? NULL : data2D; + r_image.palette = NULL; + r_image.numMips = 1; + r_image.encode = 0; + + if( FBitSet( r_image.flags, IMAGE_CUBEMAP )) + r_image.size *= 6; + memset( data2D, 0xFF, sizeof( data2D )); + + return &r_image; +} + +/* +================== +R_InitDlightTexture +================== +*/ +void R_InitDlightTexture( void ) +{ + rgbdata_t r_image; + + if( tr.dlightTexture != 0 ) + return; // already initialized + + memset( &r_image, 0, sizeof( r_image )); + r_image.width = BLOCK_SIZE; + r_image.height = BLOCK_SIZE; + r_image.flags = IMAGE_HAS_COLOR; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + + tr.dlightTexture = GL_LoadTextureInternal( "*dlight", &r_image, TF_NOMIPMAP|TF_CLAMP|TF_ATLAS_PAGE ); +} + +/* +================== +GL_CreateInternalTextures +================== +*/ +static void GL_CreateInternalTextures( void ) +{ + int dx2, dy, d; + int x, y; + rgbdata_t *pic; + + // emo-texture from quake1 + pic = GL_FakeImage( 16, 16, 1, IMAGE_HAS_COLOR ); + + for( y = 0; y < 16; y++ ) + { + for( x = 0; x < 16; x++ ) + { + if(( y < 8 ) ^ ( x < 8 )) + ((uint *)pic->buffer)[y*16+x] = 0xFFFF00FF; + else ((uint *)pic->buffer)[y*16+x] = 0xFF000000; + } + } + + tr.defaultTexture = GL_LoadTextureInternal( REF_DEFAULT_TEXTURE, pic, TF_COLORMAP ); + + // particle texture from quake1 + pic = GL_FakeImage( 16, 16, 1, IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA ); + + for( x = 0; x < 16; x++ ) + { + dx2 = x - 8; + dx2 = dx2 * dx2; + + for( y = 0; y < 16; y++ ) + { + dy = y - 8; + d = 255 - 35 * sqrt( dx2 + dy * dy ); + pic->buffer[( y * 16 + x ) * 4 + 3] = bound( 0, d, 255 ); + } + } + + tr.particleTexture = GL_LoadTextureInternal( REF_PARTICLE_TEXTURE, pic, TF_CLAMP ); + + // white texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFFFFFFFF; + tr.whiteTexture = GL_LoadTextureInternal( REF_WHITE_TEXTURE, pic, TF_COLORMAP ); + + // gray texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFF7F7F7F; + tr.grayTexture = GL_LoadTextureInternal( REF_GRAY_TEXTURE, pic, TF_COLORMAP ); + + // black texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFF000000; + tr.blackTexture = GL_LoadTextureInternal( REF_BLACK_TEXTURE, pic, TF_COLORMAP ); + + // cinematic dummy + pic = GL_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR ); + tr.cinTexture = GL_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP ); +} + +/* +=============== +R_TextureList_f +=============== +*/ +void R_TextureList_f( void ) +{ + gl_texture_t *image; + int i, texCount, ram_bytes = 0, vram_bytes = 0; + + gEngfuncs.Con_Printf( "\n" ); + gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -type- -encode- -wrap- -depth- -name--------\n" ); + + for( i = texCount = 0, image = gl_textures; i < gl_numTextures; i++, image++ ) + { + if( !image->dstTexture ) continue; + + if( image->dstPalette ) ram_bytes += PALETTE_SIZE; + + vram_bytes += ( FBitSet( image->guFlags, GUFLAGTEXINVRAM ) ) ? image->size : 0; + ram_bytes += ( FBitSet( image->guFlags, GUFLAGTEXINVRAM ) ) ? 0 : image->size; + texCount++; + + gEngfuncs.Con_Printf( "%4i: ", i ); + gEngfuncs.Con_Printf( "%4i %4i ", image->width, image->height ); + gEngfuncs.Con_Printf( "%12s ", Q_memprint( image->size )); + + switch( image->format ) + { + case GU_PSM_T4: + gEngfuncs.Con_Printf( "T4 " ); + break; + case GU_PSM_T8: + gEngfuncs.Con_Printf( "T8 " ); + break; + case GU_PSM_T16: + gEngfuncs.Con_Printf( "T16 " ); + break; + case GU_PSM_T32: + gEngfuncs.Con_Printf( "T32 " ); + break; + case GU_PSM_DXT1: + gEngfuncs.Con_Printf( "DXT1 " ); + break; + case GU_PSM_DXT3: + gEngfuncs.Con_Printf( "DXT3 " ); + break; + case GU_PSM_DXT5: + gEngfuncs.Con_Printf( "DXT5 " ); + break; + case GU_PSM_4444: + gEngfuncs.Con_Printf( "4444 " ); + break; + case GU_PSM_5551: + gEngfuncs.Con_Printf( "5551 " ); + break; + case GU_PSM_5650: + gEngfuncs.Con_Printf( "5650 " ); + break; + case GU_PSM_8888: + gEngfuncs.Con_Printf( "8888 " ); + break; + default: + gEngfuncs.Con_Printf( " ^1ERROR^7 " ); + break; + } + + if( image->flags & TF_NORMALMAP ) + gEngfuncs.Con_Printf( "normal " ); + else gEngfuncs.Con_Printf( "diffuse " ); + + switch( image->encode ) + { + case DXT_ENCODE_COLOR_YCoCg: + gEngfuncs.Con_Printf( "YCoCg " ); + break; + case DXT_ENCODE_NORMAL_AG_ORTHO: + gEngfuncs.Con_Printf( "ortho " ); + break; + case DXT_ENCODE_NORMAL_AG_STEREO: + gEngfuncs.Con_Printf( "stereo " ); + break; + case DXT_ENCODE_NORMAL_AG_PARABOLOID: + gEngfuncs.Con_Printf( "parabolic " ); + break; + case DXT_ENCODE_NORMAL_AG_QUARTIC: + gEngfuncs.Con_Printf( "quartic " ); + break; + case DXT_ENCODE_NORMAL_AG_AZIMUTHAL: + gEngfuncs.Con_Printf( "azimuthal " ); + break; + default: + gEngfuncs.Con_Printf( "default " ); + break; + } + + if( image->flags & TF_CLAMP ) + gEngfuncs.Con_Printf( "clamp " ); + else if( image->flags & TF_BORDER ) + gEngfuncs.Con_Printf( "border " ); + else gEngfuncs.Con_Printf( "repeat " ); + gEngfuncs.Con_Printf( " %d ", image->depth ); + gEngfuncs.Con_Printf( " %s\n", image->name ); + } + + gEngfuncs.Con_Printf( "---------------------------------------------------------\n" ); + gEngfuncs.Con_Printf( "%i total textures\n", texCount ); + gEngfuncs.Con_Printf( "%i max index\n", gl_numTextures ); + gEngfuncs.Con_Printf( "%s total ram memory used\n", Q_memprint( ram_bytes )); + gEngfuncs.Con_Printf( "%s total vram memory used\n", Q_memprint( vram_bytes )); + gEngfuncs.Con_Printf( "\n" ); +} + +/* +=============== +R_InitImages +=============== +*/ +void R_InitImages( void ) +{ + memset( gl_textures, 0, sizeof( gl_textures )); + memset( gl_texturesHashTable, 0, sizeof( gl_texturesHashTable )); + gl_numTextures = 0; + + // create unused 0-entry + Q_strncpy( gl_textures->name, "*unused*", sizeof( gl_textures->name )); + gl_textures->hashValue = COM_HashKey( gl_textures->name, TEXTURES_HASH_SIZE ); + gl_textures->nextHash = gl_texturesHashTable[gl_textures->hashValue]; + gl_texturesHashTable[gl_textures->hashValue] = gl_textures; + gl_numTextures = 1; + + // validate cvars + R_SetTextureParameters(); + GL_CreateInternalTextures(); + + gEngfuncs.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" ); +} + +/* +=============== +R_ShutdownImages +=============== +*/ +void R_ShutdownImages( void ) +{ + gl_texture_t *tex; + int i; + + gEngfuncs.Cmd_RemoveCommand( "texturelist" ); + GL_CleanupAllTextureUnits(); + + for( i = 0, tex = gl_textures; i < gl_numTextures; i++, tex++ ) + GL_DeleteTexture( tex ); + + memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); + memset( gl_texturesHashTable, 0, sizeof( gl_texturesHashTable )); + memset( gl_textures, 0, sizeof( gl_textures )); + gl_numTextures = 0; +} diff --git a/ref_gu/gu_init.c b/ref_gu/gu_init.c new file mode 100644 index 00000000..d30b8481 --- /dev/null +++ b/ref_gu/gu_init.c @@ -0,0 +1,349 @@ + +#include "gu_local.h" + +cvar_t *gl_texture_lodfunc; +cvar_t *gl_texture_lodbias; +cvar_t *gl_texture_lodslope; + +cvar_t *gl_texture_nearest; +cvar_t *gl_lightmap_nearest; +cvar_t *gl_keeptjunctions; +cvar_t *gl_emboss_scale; +cvar_t *gl_detailscale; +cvar_t *gl_depthoffset; +cvar_t *gl_wireframe; +cvar_t *gl_finish; +cvar_t *gl_nosort; +cvar_t *gl_vsync; +cvar_t *gl_clear; +cvar_t *gl_test; +cvar_t *gl_stencilbits; +cvar_t *gl_subdivide_size; +cvar_t *r_speeds; +cvar_t *r_fullbright; +cvar_t *r_norefresh; +cvar_t *r_lighting_extended; +cvar_t *r_lighting_modulate; +cvar_t *r_lighting_ambient; +cvar_t *r_detailtextures; +cvar_t *r_drawentities; +cvar_t *r_adjust_fov; +cvar_t *r_decals; +cvar_t *r_novis; +cvar_t *r_nocull; +cvar_t *r_lockpvs; +cvar_t *r_lockfrustum; +cvar_t *r_traceglow; +cvar_t *r_dynamic; +cvar_t *r_lightmap; +cvar_t *r_showhull; +cvar_t *gl_round_down; +cvar_t *gl_showtextures; +cvar_t *cl_lightstyle_lerping; + +cvar_t *vid_brightness; +cvar_t *vid_gamma; +cvar_t *tracerred; +cvar_t *tracergreen; +cvar_t *tracerblue; +cvar_t *traceralpha; + +byte *r_temppool; + +gl_globals_t tr; +glconfig_t glConfig; +glstate_t glState; +glwstate_t glw_state; + +/* +============== +GL_GetProcAddress + +defined just for nanogl/glwes, so it don't link to SDL2 directly, nor use dlsym +============== +*/ +void GAME_EXPORT *GL_GetProcAddress( const char *name ) +{ + return gEngfuncs.GL_GetProcAddress( name ); +} + +/* +=============== +GL_SetDefaultState +=============== +*/ +static void GL_SetDefaultState( void ) +{ + memset( &glState, 0, sizeof( glState )); + + // init draw stack + tr.draw_list = &tr.draw_stack[0]; + tr.draw_stack_pos = 0; + + // init glState struct + glState.currentTexture = -1; + glState.texIdentityMatrix = true; + glState.fogColor = 0; + glState.fogDensity = 0; + glState.fogStart = 100.0f; + glState.fogEnd = 1000.0f; +} + +/* +=============== +GL_SetDefaults +=============== +*/ +static void GL_SetDefaults( void ) +{ +#if 1 +/* + sceGuFinish(); + sceGuSync(0,0); +*/ + sceGuClearColor( GU_COLOR( 0.5f, 0.5f, 0.5f, 1.0f ) ); + + sceGuDisable( GU_DEPTH_TEST ); + sceGuDisable( GU_CULL_FACE ); + //sceGuDisable( GU_SCISSOR_TEST ); + sceGuDepthFunc( GU_LEQUAL ); + sceGuColor( 0xffffffff ); + + if( glState.stencilEnabled ) + { + sceGuDisable( GU_STENCIL_TEST ); + /*pglStencilMask( ( GLuint ) ~0 );*/ + sceGuStencilFunc( GU_EQUAL, 0, ~0 ); + sceGuStencilOp( GU_KEEP, GU_INCR, GU_INCR ); + } + sceGuDepthOffset( 0 ); + + GL_CleanupAllTextureUnits(); + + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuEnable( GU_TEXTURE_2D ); + sceGuShadeModel( GU_SMOOTH ); + sceGuFrontFace( GU_CCW ); +#else + pglFinish(); + + pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f ); + + pglDisable( GL_DEPTH_TEST ); + pglDisable( GL_CULL_FACE ); + pglDisable( GL_SCISSOR_TEST ); + pglDepthFunc( GL_LEQUAL ); + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + + if( glState.stencilEnabled ) + { + pglDisable( GL_STENCIL_TEST ); + pglStencilMask( ( GLuint ) ~0 ); + pglStencilFunc( GL_EQUAL, 0, ~0 ); + pglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); + } + + pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + pglPolygonOffset( -1.0f, -2.0f ); + + GL_CleanupAllTextureUnits(); + + pglDisable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglDisable( GL_POLYGON_OFFSET_FILL ); + pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST ); + pglEnable( GL_TEXTURE_2D ); + pglShadeModel( GL_SMOOTH ); + pglFrontFace( GL_CCW ); + + pglPointSize( 1.2f ); + pglLineWidth( 1.2f ); +#endif + GL_Cull( GL_NONE ); +} + + +/* +================= +R_RenderInfo_f +================= +*/ +void R_RenderInfo_f( void ) +{ + gEngfuncs.Con_Printf( "\n" ); + gEngfuncs.Con_Printf( "HARDWARE RENDER\n"); + gEngfuncs.Con_Printf( "MAX_TEXTURE_SIZE: %i\n", glConfig.max_texture_size ); + gEngfuncs.Con_Printf( "MODE: %ix%i\n", gpGlobals->width, gpGlobals->height ); + gEngfuncs.Con_Printf( "VERTICAL SYNC: %s\n", gl_vsync->value ? "enabled" : "disabled" ); + gEngfuncs.Con_Printf( "Color %d bits, Alpha %d bits, Depth %d bits, Stencil %d bits\n", glConfig.color_bits, + glConfig.alpha_bits, glConfig.depth_bits, glConfig.stencil_bits ); +} + +void GL_InitExtensions( void ) +{ +// int colorBits[3]; + + glConfig.color_bits = 5 + 5 + 5; + glConfig.alpha_bits = 1; + glConfig.stencil_bits = ( int )gl_stencilbits->value; + glState.stencilEnabled = true; + glConfig.max_texture_size = 256; + + // get our various GL strings + gEngfuncs.Con_Reportf( "^3Video^7: PSP HW\n" ); + + gEngfuncs.Cvar_Get( "gl_max_size", va( "%i", glConfig.max_texture_size ), 0, "opengl texture max dims" ); +/* + gEngfuncs.Image_AddCmdFlags( IL_DDS_HARDWARE ); +*/ + R_RenderInfo_f(); + + tr.framecount = tr.visframecount = 1; + glw_state.initialized = true; +} + +void GL_ClearExtensions( void ) +{ + // now all extensions are disabled + glw_state.initialized = false; +} + +//======================================================================= + +/* +================= +GL_InitCommands +================= +*/ +void GL_InitCommands( void ) +{ + r_speeds = gEngfuncs.Cvar_Get( "r_speeds", "0", FCVAR_ARCHIVE, "shows renderer speeds" ); + r_fullbright = gEngfuncs.Cvar_Get( "r_fullbright", "0", FCVAR_CHEAT, "disable lightmaps, get fullbright for entities" ); + r_norefresh = gEngfuncs.Cvar_Get( "r_norefresh", "0", 0, "disable 3D rendering (use with caution)" ); + r_lighting_extended = gEngfuncs.Cvar_Get( "r_lighting_extended", "0", FCVAR_ARCHIVE, "allow to get lighting from world and bmodels" ); // disabled + r_lighting_modulate = gEngfuncs.Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "lightstyles modulate scale" ); + r_lighting_ambient = gEngfuncs.Cvar_Get( "r_lighting_ambient", "0.3", FCVAR_ARCHIVE, "map ambient lighting scale" ); + r_novis = gEngfuncs.Cvar_Get( "r_novis", "0", 0, "ignore vis information (perfomance test)" ); + r_nocull = gEngfuncs.Cvar_Get( "r_nocull", "0", 0, "ignore frustrum culling (perfomance test)" ); + r_detailtextures = gEngfuncs.Cvar_Get( "r_detailtextures", "0", FCVAR_ARCHIVE, "enable detail textures support, use '2' for autogenerate detail.txt" ); // disabled + r_lockpvs = gEngfuncs.Cvar_Get( "r_lockpvs", "0", FCVAR_CHEAT, "lockpvs area at current point (pvs test)" ); + r_lockfrustum = gEngfuncs.Cvar_Get( "r_lockfrustum", "0", FCVAR_CHEAT, "lock frustrum area at current point (cull test)" ); + r_dynamic = gEngfuncs.Cvar_Get( "r_dynamic", "1", FCVAR_ARCHIVE, "allow dynamic lighting (dlights, lightstyles)" ); + r_traceglow = gEngfuncs.Cvar_Get( "r_traceglow", "0", FCVAR_ARCHIVE, "cull flares behind models" ); // disabled + r_lightmap = gEngfuncs.Cvar_Get( "r_lightmap", "0", FCVAR_CHEAT, "lightmap debugging tool" ); + r_drawentities = gEngfuncs.Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" ); + r_decals = gEngfuncs.pfnGetCvarPointer( "r_decals", 0 ); + r_showhull = gEngfuncs.pfnGetCvarPointer( "r_showhull", 0 ); + + gl_texture_nearest = gEngfuncs.Cvar_Get( "gl_texture_nearest", "0", FCVAR_GLCONFIG, "disable texture filter" ); + gl_lightmap_nearest = gEngfuncs.Cvar_Get( "gl_lightmap_nearest", "0", FCVAR_GLCONFIG, "disable lightmap filter" ); + gl_vsync = gEngfuncs.pfnGetCvarPointer( "gl_vsync", 0 ); + gl_detailscale = gEngfuncs.Cvar_Get( "gl_detailscale", "4.0", FCVAR_GLCONFIG, "default scale applies while auto-generate list of detail textures" ); + gl_texture_lodfunc = gEngfuncs.Cvar_Get( "gl_texture_lodfunc", "2", FCVAR_GLCONFIG, "LOD func for mipmapped textures" ); + gl_texture_lodbias = gEngfuncs.Cvar_Get( "gl_texture_lodbias", "-5.0", FCVAR_GLCONFIG, "LOD bias for mipmapped textures (perfomance|quality)" ); + gl_texture_lodslope = gEngfuncs.Cvar_Get( "gl_texture_lodslope", "0.3", FCVAR_GLCONFIG, "LOD slope for mipmapped textures" ); + gl_keeptjunctions = gEngfuncs.Cvar_Get( "gl_keeptjunctions", "1", FCVAR_GLCONFIG, "removing tjuncs causes blinking pixels" ); + gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_GLCONFIG|FCVAR_LATCH, "fake bumpmapping scale" ); + gl_showtextures = gEngfuncs.pfnGetCvarPointer( "r_showtextures", 0 ); + gl_finish = gEngfuncs.Cvar_Get( "gl_finish", "0", FCVAR_GLCONFIG, "use glFinish instead of glFlush" ); + gl_nosort = gEngfuncs.Cvar_Get( "gl_nosort", "1", FCVAR_GLCONFIG, "disable sorting of translucent surfaces" ); + gl_clear = gEngfuncs.pfnGetCvarPointer( "gl_clear", 0 ); + gl_test = gEngfuncs.Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" ); + gl_wireframe = gEngfuncs.Cvar_Get( "gl_wireframe", "0", FCVAR_GLCONFIG|FCVAR_SPONLY, "show wireframe overlay" ); + gl_stencilbits = gEngfuncs.Cvar_Get( "gl_stencilbits", "8", FCVAR_GLCONFIG, "pixelformat stencil bits (0 - auto)" ); + gl_subdivide_size = gEngfuncs.Cvar_Get( "gl_subdivide_size", "256.0", FCVAR_GLCONFIG, "the division value for the sky brushes" ); + gl_round_down = gEngfuncs.Cvar_Get( "gl_round_down", "2", FCVAR_GLCONFIG, "round texture sizes to nearest POT value" ); + // these cvar not used by engine but some mods requires this + gl_depthoffset = gEngfuncs.Cvar_Get( "gl_depthoffset", "256.0", FCVAR_GLCONFIG, "depth offset for decals" ); + + // make sure gl_vsync is checked after vid_restart + SetBits( gl_vsync->flags, FCVAR_CHANGED ); + + vid_gamma = gEngfuncs.pfnGetCvarPointer( "gamma", 0 ); + vid_brightness = gEngfuncs.pfnGetCvarPointer( "brightness", 0 ); + + tracerred = gEngfuncs.Cvar_Get( "tracerred", "0.8", 0, "tracer red component weight ( 0 - 1.0 )" ); + tracergreen = gEngfuncs.Cvar_Get( "tracergreen", "0.8", 0, "tracer green component weight ( 0 - 1.0 )" ); + tracerblue = gEngfuncs.Cvar_Get( "tracerblue", "0.4", 0, "tracer blue component weight ( 0 - 1.0 )" ); + traceralpha = gEngfuncs.Cvar_Get( "traceralpha", "0.5", 0, "tracer alpha amount ( 0 - 1.0 )" ); + + cl_lightstyle_lerping = gEngfuncs.pfnGetCvarPointer( "cl_lightstyle_lerping", 0 ); + + gEngfuncs.Cmd_AddCommand( "r_info", R_RenderInfo_f, "display renderer info" ); + gEngfuncs.Cmd_AddCommand( "timerefresh", SCR_TimeRefresh_f, "turn quickly and print rendering statistcs" ); +} + +/* +================= +GL_RemoveCommands +================= +*/ +void GL_RemoveCommands( void ) +{ + gEngfuncs.Cmd_RemoveCommand( "r_info" ); +} + +/* +=============== +R_Init +=============== +*/ +qboolean R_Init( void ) +{ + if( glw_state.initialized ) + return true; + + GL_InitCommands(); + GL_InitRandomTable(); + + GL_SetDefaultState(); + + // create the window and set up the context + if( !gEngfuncs.R_Init_Video( REF_GL )) // request GL context + { + GL_RemoveCommands(); + gEngfuncs.R_Free_Video(); +// Why? Host_Error again??? +// gEngfuncs.Host_Error( "Can't initialize video subsystem\nProbably driver was not installed" ); + return false; + } + + r_temppool = Mem_AllocPool( "Render Zone" ); + + GL_SetDefaults(); + R_InitImages(); + R_SpriteInit(); + R_StudioInit(); + R_AliasInit(); + R_ClearDecals(); + R_ClearScene(); + + return true; +} + +/* +=============== +R_Shutdown +=============== +*/ +void R_Shutdown( void ) +{ + if( !glw_state.initialized ) + return; + + GL_RemoveCommands(); + R_ShutdownImages(); + + Mem_FreePool( &r_temppool ); + + // shut down OS specific OpenGL stuff like contexts, etc. + gEngfuncs.R_Free_Video(); +} + +void GL_SetupAttributes( int safegl ) +{ + +} diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h new file mode 100644 index 00000000..6355af0b --- /dev/null +++ b/ref_gu/gu_local.h @@ -0,0 +1,809 @@ +/* +gu_local.h - renderer local declarations +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GL_LOCAL_H +#define GL_LOCAL_H +#if 1 +#include +#include +#include +#endif +#include "port.h" +#include "xash3d_types.h" +#include "cvardef.h" +#include "const.h" +#include "com_model.h" +#include "cl_entity.h" +#include "render_api.h" +#include "protocol.h" +#include "dlight.h" +#include "gu_frustum.h" +#include "ref_api.h" +#include "xash3d_mathlib.h" +#include "ref_params.h" +#include "enginefeatures.h" +#include "com_strings.h" +#include "pm_movevars.h" +//#include "cvar.h" +#include "gu_helper.h" +#include "gu_extension.h" +#include "wadfile.h" + +#ifndef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif // offsetof + +#define ASSERT(x) if(!( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ ) +#define Assert(x) if(!( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ ) + +#include + +#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) cvar_t cv = { cvname, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc } +#define CVAR_DEFINE_AUTO( cv, cvstr, cvflags, cvdesc ) cvar_t cv = { #cv, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc } +#define CVAR_TO_BOOL( x ) ((x) && ((x)->value != 0.0f) ? true : false ) + +#define WORLD (gEngfuncs.GetWorld()) +#define WORLDMODEL (gEngfuncs.pfnGetModelByIndex( 1 )) +#define MOVEVARS (gEngfuncs.pfnGetMoveVars()) + +// make mod_ref.h? +#define LM_SAMPLE_SIZE 16 + + +extern byte *r_temppool; +#if 1 + +#define BLOCK_SIZE tr.block_size // lightmap blocksize +#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility +#define BLOCK_SIZE_MAX 128 + +#define MAX_TEXTURES 1536 +#define MAX_DETAIL_TEXTURES 64 +#define MAX_LIGHTMAPS 64 +#define SUBDIVIDE_SIZE 64 +#define MAX_DECAL_SURFS 256 +#define MAX_DRAW_STACK 2 // normal view and menu view + +#else + +#define BLOCK_SIZE tr.block_size // lightmap blocksize +#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility +#define BLOCK_SIZE_MAX 1024 + +#define MAX_TEXTURES 4096 +#define MAX_DETAIL_TEXTURES 256 +#define MAX_LIGHTMAPS 256 +#define SUBDIVIDE_SIZE 64 +#define MAX_DECAL_SURFS 4096 +#define MAX_DRAW_STACK 2 // normal view and menu view + +#endif + +#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles +#define SHADE_LAMBERT 1.495f + +#if 1 +#define DEFAULT_ALPHATEST 0x00 +#else +#define DEFAULT_ALPHATEST 0.0f +#endif + +// refparams +#define RP_NONE 0 +#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot +#define RP_OLDVIEWLEAF BIT( 1 ) +#define RP_CLIPPLANE BIT( 2 ) + +#define RP_NONVIEWERREF (RP_ENVVIEW) +#define R_ModelOpaque( rm ) ( rm == kRenderNormal ) +#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles )) +#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ENGINE_GET_PARM( PARM_PLAYER_INDEX ) && e->player ) +#define RP_NORMALPASS() ( FBitSet( RI.params, RP_NONVIEWERREF ) == 0 ) + +#define CL_IsViewEntityLocalPlayer() ( ENGINE_GET_PARM( PARM_VIEWENT_INDEX ) == ENGINE_GET_PARM( PARM_PLAYER_INDEX ) ) + +#define CULL_VISIBLE 0 // not culled +#define CULL_BACKSIDE 1 // backside of transparent wall +#define CULL_FRUSTUM 2 // culled by frustum +#define CULL_VISFRAME 3 // culled by PVS +#define CULL_OTHER 4 // culled by other reason + +typedef struct gltexture_s +{ + + char name[128]; // game path, including extension (can be store image programs) + short srcWidth; // keep unscaled sizes + short srcHeight; + short width; // upload width\height + short height; + short depth; // texture depth or count of layers for 2D_ARRAY + byte numMips; // mipmap count + byte *dstTexture; // texture pointer + byte *dstPalette; + byte guFlags; + int format; // uploaded format + GLint encode; // using GLSL decoder + texFlags_t flags; + + rgba_t fogParams; // some water textures + // contain info about underwater fog + + rgbdata_t *original; // keep original image + + // debug info + size_t size; // upload size for debug targets + + // detail textures stuff + float xscale; + float yscale; +#if 0 + int servercount; +#endif + uint hashValue; + struct gltexture_s *nextHash; +} gl_texture_t; + +#if 1 +typedef struct +{ + float x, y, z; +}gu_vert_fv_t; + +typedef struct +{ + unsigned int c; + float x, y, z; +}gu_vert_fcv_t; + +typedef struct +{ + float u, v; + float x, y, z; +}gu_vert_ftv_t; + +typedef struct +{ + float u, v; + unsigned int c; + float x, y, z; +}gu_vert_ftcv_t; + +typedef struct +{ + float u, v; + unsigned int c; + float nx, ny, nz; + float x, y, z; +}gu_vert_ftcnv_t; + +typedef struct +{ + short x, y, z; +}gu_vert_hv_t; + +typedef struct +{ + short u, v; + short x, y, z; +}gu_vert_htv_t; + +typedef struct +{ + short u, v; + unsigned int c; + short x, y, z; +}gu_vert_htcv_t; +#endif + +typedef struct +{ + int params; // rendering parameters + + qboolean drawWorld; // ignore world for drawing PlayerModel + qboolean isSkyVisible; // sky is visible + qboolean onlyClientDraw; // disabled by client request + qboolean drawOrtho; // draw world as orthogonal projection + + float fov_x, fov_y; // current view fov + + cl_entity_t *currententity; + model_t *currentmodel; + cl_entity_t *currentbeam; // same as above but for beams + + int viewport[4]; + gl_frustum_t frustum; + + mleaf_t *viewleaf; + mleaf_t *oldviewleaf; + vec3_t pvsorigin; + vec3_t vieworg; // locked vieworigin + vec3_t viewangles; + vec3_t vforward; + vec3_t vright; + vec3_t vup; + + vec3_t cullorigin; + vec3_t cull_vforward; + vec3_t cull_vright; + vec3_t cull_vup; + + float farClip; + + qboolean fogCustom; + qboolean fogEnabled; + qboolean fogSkybox; + vec4_t fogColor; + float fogDensity; + float fogStart; + float fogEnd; + int cached_contents; // in water + int cached_waterlevel; // was in water + + float skyMins[2][6]; + float skyMaxs[2][6]; + + matrix4x4 objectMatrix; // currententity matrix + matrix4x4 worldviewMatrix; // modelview for world + matrix4x4 modelviewMatrix; // worldviewMatrix * objectMatrix + + matrix4x4 projectionMatrix; + matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix + byte visbytes[(MAX_MAP_LEAFS+7)/8];// actual PVS for current frame + + float viewplanedist; + mplane_t clipPlane; +} ref_instance_t; + +typedef struct +{ + cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes + cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes + cl_entity_t *beam_entities[MAX_VISIBLE_PACKET]; + uint num_solid_entities; + uint num_trans_entities; + uint num_beam_entities; +} draw_list_t; + +typedef struct +{ + int defaultTexture; // use for bad textures + int particleTexture; + int whiteTexture; + int grayTexture; + int blackTexture; + int solidskyTexture; // quake1 solid-sky layer + int alphaskyTexture; // quake1 alpha-sky layer + int lightmapTextures[MAX_LIGHTMAPS]; + int dlightTexture; // custom dlight texture + int skyboxTextures[6]; // skybox sides + int cinTexture; // cinematic texture + + int skytexturenum; // this not a gl_texturenum! +#if 0 + int skyboxbasenum; // start with 5800 +#endif + // entity lists + draw_list_t draw_stack[MAX_DRAW_STACK]; + int draw_stack_pos; + draw_list_t *draw_list; + + msurface_t *draw_decals[MAX_DECAL_SURFS]; + int num_draw_decals; + + // OpenGL matrix states + qboolean modelviewIdentity; + + int visframecount; // PVS frame + int dlightframecount; // dynamic light frame + int realframecount; // not including viewpasses + int framecount; + + qboolean ignore_lightgamma; + qboolean fCustomRendering; + qboolean fResetVis; + qboolean fFlipViewModel; + + byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS + int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536 + int block_size; // lightmap blocksize + + double frametime; // special frametime for multipass rendering (will set to 0 on a nextview) + float blend; // global blend value + + // cull info + vec3_t modelorg; // relative to viewpoint + + qboolean fCustomSkybox; +} gl_globals_t; + +typedef struct +{ + uint c_world_polys; + uint c_studio_polys; + uint c_sprite_polys; + uint c_alias_polys; + uint c_world_leafs; + + uint c_view_beams_count; + uint c_active_tents_count; + uint c_alias_models_drawn; + uint c_studio_models_drawn; + uint c_sprite_models_drawn; + uint c_particle_count; + + uint c_client_ents; // entities that moved to client + double t_world_node; + double t_world_draw; +} ref_speeds_t; + +extern ref_speeds_t r_stats; +extern ref_instance_t RI; +extern gl_globals_t tr; + +extern float gldepthmin, gldepthmax; +#define r_numEntities (tr.draw_list->num_solid_entities + tr.draw_list->num_trans_entities) +#define r_numStatics (r_stats.c_client_ents) + +// +// gu_backend.c +// +void GL_BackendStartFrame( void ); +void GL_BackendEndFrame( void ); +void GL_CleanUpTextureUnits( int last ); +void GL_Bind( GLint tmu, GLenum texnum ); +void GL_MultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t ); +void GL_SetTexCoordArrayMode( GLenum mode ); +void GL_LoadTexMatrix( const matrix4x4 m ); +void GL_LoadTexMatrixExt( const float *glmatrix ); +void GL_LoadMatrix( const matrix4x4 source ); +void GL_TexGen( GLenum coord, GLenum mode ); +void GL_SelectTexture( GLint texture ); +void GL_CleanupAllTextureUnits( void ); +void GL_LoadIdentityTexMatrix( void ); +void GL_DisableAllTexGens( void ); +void GL_SetRenderMode( int mode ); +void GL_TextureTarget( uint target ); +void GL_Cull( GLenum cull ); +void R_ShowTextures( void ); +void SCR_TimeRefresh_f( void ); + +// +// gu_beams.c +// +void CL_DrawBeams( int fTrans, BEAM *active_beams ); +qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly ); + +// +// gu_cull.c +// +int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax ); +qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ); +qboolean R_CullSphere( const vec3_t centre, const float radius ); +int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags ); + +// +// gu_decals.c +// +void DrawSurfaceDecals( msurface_t *fa, qboolean single, qboolean reverse ); +float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount ); +void DrawSingleDecal( decal_t *pDecal, msurface_t *fa ); +void R_EntityRemoveDecals( model_t *mod ); +void DrawDecalsBatch( void ); +void R_ClearDecals( void ); + +// +// gu_draw.c +// +void R_Set2DMode( qboolean enable ); +void R_DrawTileClear( int texnum, int x, int y, int w, int h ); +void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data ); + +// +// gu_drawhulls.c +// +void R_DrawWorldHull( void ); +void R_DrawModelHull( void ); + +// +// gu_image.c +// +void R_SetTextureParameters( void ); +gl_texture_t *R_GetTexture( GLenum texnum ); +#define GL_LoadTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, false ) +#define GL_UpdateTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, true ) +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); +int GL_LoadTextureArray( const char **names, int flags ); +int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ); +byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap ); +int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ); +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ); +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); +qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ); +void GL_UpdateTexSize( int texnum, int width, int height, int depth ); +void GL_ApplyTextureParams( gl_texture_t *tex ); +int GL_FindTexture( const char *name ); +void GL_FreeTexture( GLenum texnum ); +const char *GL_Target( GLenum target ); +void R_InitDlightTexture( void ); +void R_TextureList_f( void ); +void R_InitImages( void ); +void R_ShutdownImages( void ); +int GL_TexMemory( void ); + +// +// gu_rlight.c +// +void CL_RunLightStyles( void ); +void R_PushDlights( void ); +void R_AnimateLight( void ); +void R_GetLightSpot( vec3_t lightspot ); +void R_MarkLights( dlight_t *light, int bit, mnode_t *node ); +colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec ); +int R_CountSurfaceDlights( msurface_t *surf ); +colorVec R_LightPoint( const vec3_t p0 ); +int R_CountDlights( void ); + +// +// gu_rmain.c +// +void R_ClearScene( void ); +void R_LoadIdentity( void ); +void R_RenderScene( void ); +void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size ); +void R_SetupRefParams( const struct ref_viewpass_s *rvp ); +void R_TranslateForEntity( cl_entity_t *e ); +void R_RotateForEntity( cl_entity_t *e ); +void R_SetupGL( qboolean set_gl_state ); +void R_AllowFog( qboolean allowed ); +void R_SetupFrustum( void ); +void R_FindViewLeaf( void ); +void R_CheckGamma( void ); +void R_PushScene( void ); +void R_PopScene( void ); +void R_DrawFog( void ); +int CL_FxBlend( cl_entity_t *e ); + +// +// gu_rmath.c +// +void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] ); +void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] ); +void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ); +void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z ); +void Matrix4x4_ConcatScale( matrix4x4 out, float x ); +void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z ); +void Matrix4x4_CreateScale( matrix4x4 out, float x ); +void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar); +void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar); +void Matrix4x4_CreateModelview( matrix4x4 out ); + +// +// gu_rmisc.c +// +void R_ClearStaticEntities( void ); + +// +// gu_rsurf.c +// +void R_MarkLeaves( void ); +void R_DrawWorld( void ); +void R_DrawWaterSurfaces( void ); +void R_DrawBrushModel( cl_entity_t *e ); +void GL_SubdivideSurface( msurface_t *fa ); +void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa ); +void DrawGLPoly( glpoly_t *p, float xScale, float yScale ); +texture_t *R_TextureAnimation( msurface_t *s ); +void GL_SetupFogColorForSurfaces( void ); +void R_DrawAlphaTextureChains( void ); +void GL_RebuildLightmaps( void ); +void GL_InitRandomTable( void ); +void GL_BuildLightmaps( void ); +void GL_ResetFogColor( void ); +void R_GenerateVBO( void ); +void R_ClearVBO( void ); +void R_AddDecalVBO( decal_t *pdecal, msurface_t *surf ); + +// +// gu_rpart.c +// +void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime ); +void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float partsize ); +void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ); + + +// +// gu_sprite.c +// +void R_SpriteInit( void ); +void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags ); +mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw ); +void R_DrawSpriteModel( cl_entity_t *e ); + +// +// gu_studio.c +// +void R_StudioInit( void ); +void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded ); +void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles ); +float CL_GetSequenceDuration( cl_entity_t *ent, int sequence ); +struct mstudiotex_s *R_StudioGetTexture( cl_entity_t *e ); +float CL_GetStudioEstimatedFrame( cl_entity_t *ent ); +int R_GetEntityRenderMode( cl_entity_t *ent ); +void R_DrawStudioModel( cl_entity_t *e ); +player_info_t *pfnPlayerInfo( int index ); +void R_GatherPlayerLight( void ); +float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc ); +void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles ); +void R_StudioResetPlayerModels( void ); +void CL_InitStudioAPI( void ); +void Mod_StudioLoadTextures( model_t *mod, void *data ); +void Mod_StudioUnloadTextures( void *data ); + +// +// gu_alias.c +// +void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded ); +void R_DrawAliasModel( cl_entity_t *e ); +void R_AliasInit( void ); + +// +// gu_warp.c +// +void R_InitSkyClouds( mip_t *mt, struct texture_s *tx, qboolean custom_palette ); +void R_AddSkyBoxSurface( msurface_t *fa ); +void R_ClearSkyBox( void ); +void R_DrawSkyBox( void ); +void R_DrawClouds( void ); +void EmitWaterPolys( msurface_t *warp, qboolean reverse ); + +// +// gu_vgui.c +// +void VGUI_DrawInit( void ); +void VGUI_DrawShutdown( void ); +void VGUI_SetupDrawingText( int *pColor ); +void VGUI_SetupDrawingRect( int *pColor ); +void VGUI_SetupDrawingImage( int *pColor ); +void VGUI_BindTexture( int id ); +void VGUI_EnableTexture( qboolean enable ); +void VGUI_CreateTexture( int id, int width, int height ); +void VGUI_UploadTexture( int id, const char *buffer, int width, int height ); +void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight ); +void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr ); +void VGUI_GetTextureSizes( int *width, int *height ); +int VGUI_GenerateTexture( void ); + +//#include "vid_common.h" + +// +// renderer exports +// +qboolean R_Init( void ); +void R_Shutdown( void ); +void GL_SetupAttributes( int safegl ); +void GL_OnContextCreated( void ); +void GL_InitExtensions( void ); +void GL_ClearExtensions( void ); +void VID_CheckChanges( void ); +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); +void GL_FreeImage( const char *name ); +qboolean VID_ScreenShot( const char *filename, int shot_type ); +qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot ); +void R_BeginFrame( qboolean clearScene ); +void R_RenderFrame( const struct ref_viewpass_s *vp ); +void R_EndFrame( void ); +void R_ClearScene( void ); +void R_GetTextureParms( int *w, int *h, int texnum ); +void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int curFrame, const struct model_s *pSprite ); +void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty ); +void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum ); +qboolean R_SpeedsMessage( char *out, size_t size ); +void R_SetupSky( const char *skyboxname ); +qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ); +int R_WorldToScreen( const vec3_t point, vec3_t screen ); +void R_ScreenToWorld( const vec3_t screen, vec3_t point ); +qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType ); +void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size, qboolean *loaded ); +void Mod_SpriteUnloadTextures( void *data ); +void Mod_UnloadAliasModel( struct model_s *mod ); +void Mod_AliasUnloadTextures( void *data ); +void GL_SetRenderMode( int mode ); +void R_RunViewmodelEvents( void ); +void R_DrawViewModel( void ); +int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame ); +void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale ); +void R_RemoveEfrags( struct cl_entity_s *ent ); +void R_AddEfrags( struct cl_entity_s *ent ); +void R_DecalRemoveAll( int texture ); +int R_CreateDecalList( decallist_t *pList ); +void R_ClearAllDecals( void ); +byte *Mod_GetCurrentVis( void ); +void Mod_SetOrthoBounds( const float *mins, const float *maxs ); +void R_NewMap( void ); +void CL_AddCustomBeam( cl_entity_t *pEnvBeam ); + +// +// gu_opengl.c +// + +// +// gu_triapi.c +// +void TriRenderMode( int mode ); +void TriBegin( int mode ); +void TriEnd( void ); +void TriTexCoord2f( float u, float v ); +void TriVertex3fv( const float *v ); +void TriVertex3f( float x, float y, float z ); +void _TriColor4f( float r, float g, float b, float a ); +void _TriColor4ub( byte r, byte g, byte b, byte a ); +void TriColor4f( float r, float g, float b, float a ); +void TriColor4ub( byte r, byte g, byte b, byte a ); +void TriBrightness( float brightness ); +int TriWorldToScreen( const float *world, float *screen ); +int TriSpriteTexture( model_t *pSpriteModel, int frame ); +void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ); +void TriGetMatrix( const int pname, float *matrix ); +void TriFogParams( float flDensity, int iFogSkybox ); +void TriCullFace( TRICULLSTYLE mode ); +#if 1 +/* Needs for psp */ +unsigned int getTriBrightness( float brightness ); +#endif + +// +// gu_clipping.c +// +#define CLIPPING_DEBUGGING 0 +void GU_ClipBeginFrame( void ); +void GU_ClipBeginBrush( void ); +void GU_ClipEndBrush( void ); +void GU_ClipLoadFrustum( const mplane_t *plane ); // Experimental +qboolean GU_ClipIsRequired( const gu_vert_t* v, size_t vc ); +void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ); + +/* +======================================================================= + + GL STATE MACHINE + +======================================================================= +*/ +typedef struct +{ + int max_texture_size; + int color_bits; + int alpha_bits; + int depth_bits; + int stencil_bits; + + gl_context_type_t context; + gles_wrapper_t wrapper; + + qboolean softwareGammaUpdate; + qboolean fCustomRenderer; + int prev_width; + int prev_height; +} glconfig_t; + +typedef struct +{ + + int width, height; + int activeTMU; + GLint currentTexture; + GLboolean texIdentityMatrix; + GLint isFogEnabled; + + int faceCull; + + qboolean stencilEnabled; + qboolean in2DMode; + + uint fogColor; + float fogDensity; + float fogStart; + float fogEnd; +} glstate_t; + + +typedef struct +{ + qboolean initialized; // OpenGL subsystem started + qboolean extended; // extended context allows to GL_Debug +} glwstate_t; + +extern glconfig_t glConfig; +extern glstate_t glState; +// move to engine +extern glwstate_t glw_state; +extern ref_api_t gEngfuncs; +extern ref_globals_t *gpGlobals; + +#define ENGINE_GET_PARM_ (*gEngfuncs.EngineGetParm) +#define ENGINE_GET_PARM( parm ) ENGINE_GET_PARM_( ( parm ), 0 ) + +// +// renderer cvars +// +extern cvar_t *gl_texture_lodfunc; +extern cvar_t *gl_texture_lodbias; +extern cvar_t *gl_texture_lodslope; +extern cvar_t *gl_texture_nearest; +extern cvar_t *gl_lightmap_nearest; +extern cvar_t *gl_keeptjunctions; +extern cvar_t *gl_emboss_scale; +extern cvar_t *gl_round_down; +extern cvar_t *gl_detailscale; +extern cvar_t *gl_wireframe; +extern cvar_t *gl_depthoffset; +extern cvar_t *gl_finish; +extern cvar_t *gl_nosort; +extern cvar_t *gl_clear; +extern cvar_t *gl_test; // cvar to testify new effects +extern cvar_t *gl_stencilbits; +extern cvar_t *gl_subdivide_size; + +extern cvar_t *r_speeds; +extern cvar_t *r_fullbright; +extern cvar_t *r_norefresh; +extern cvar_t *r_lighting_extended; +extern cvar_t *r_lighting_modulate; +extern cvar_t *r_lighting_ambient; +extern cvar_t *r_studio_lambert; +extern cvar_t *r_detailtextures; +extern cvar_t *r_drawentities; +extern cvar_t *r_decals; +extern cvar_t *r_novis; +extern cvar_t *r_nocull; +extern cvar_t *r_lockpvs; +extern cvar_t *r_lockfrustum; +extern cvar_t *r_traceglow; +extern cvar_t *r_dynamic; +extern cvar_t *r_lightmap; + +extern cvar_t *vid_brightness; +extern cvar_t *vid_gamma; + +// +// engine shared convars +// +extern cvar_t *gl_showtextures; +extern cvar_t *tracerred; +extern cvar_t *tracergreen; +extern cvar_t *tracerblue; +extern cvar_t *traceralpha; +extern cvar_t *cl_lightstyle_lerping; +extern cvar_t *r_showhull; + +// +// engine callbacks +// +#include "crtlib.h" + +#define Mem_Malloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ ) +#define Mem_Calloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ ) +#define Mem_Realloc( pool, ptr, size ) gEngfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ ) +#define Mem_Free( mem ) gEngfuncs._Mem_Free( mem, __FILE__, __LINE__ ) +#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ ) +#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ ) +#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ ) + +#endif // GL_LOCAL_H diff --git a/ref_gu/gu_rlight.c b/ref_gu/gu_rlight.c new file mode 100644 index 00000000..b212c328 --- /dev/null +++ b/ref_gu/gu_rlight.c @@ -0,0 +1,496 @@ +/* +gl_rlight.c - dynamic and static lights +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "pm_local.h" +#include "studio.h" +#include "xash3d_mathlib.h" +#include "ref_params.h" + +/* +============================================================================= + +DYNAMIC LIGHTS + +============================================================================= +*/ +/* +================== +CL_RunLightStyles + +================== +*/ +void CL_RunLightStyles( void ) +{ + int i, k, flight, clight; + float l, lerpfrac, backlerp; + float frametime = (gpGlobals->time - gpGlobals->oldtime); + float scale; + lightstyle_t *ls; + + if( !WORLDMODEL ) return; + + scale = r_lighting_modulate->value; + + // light animations + // 'm' is normal light, 'a' is no light, 'z' is double bright + for( i = 0; i < MAX_LIGHTSTYLES; i++ ) + { + ls = gEngfuncs.GetLightStyle( i ); + if( !WORLDMODEL->lightdata ) + { + tr.lightstylevalue[i] = 256 * 256; + continue; + } + + if( !ENGINE_GET_PARM( PARAM_GAMEPAUSED ) && frametime <= 0.1f ) + ls->time += frametime; // evaluate local time + + flight = (int)Q_floor( ls->time * 10 ); + clight = (int)Q_ceil( ls->time * 10 ); + lerpfrac = ( ls->time * 10 ) - flight; + backlerp = 1.0f - lerpfrac; + + if( !ls->length ) + { + tr.lightstylevalue[i] = 256 * scale; + continue; + } + else if( ls->length == 1 ) + { + // single length style so don't bother interpolating + tr.lightstylevalue[i] = ls->map[0] * 22 * scale; + continue; + } + else if( !ls->interp || !CVAR_TO_BOOL( cl_lightstyle_lerping )) + { + tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale; + continue; + } + + // interpolate animating light + // frame just gone + k = ls->map[flight % ls->length]; + l = (float)( k * 22.0f ) * backlerp; + + // upcoming frame + k = ls->map[clight % ls->length]; + l += (float)( k * 22.0f ) * lerpfrac; + + tr.lightstylevalue[i] = (int)l * scale; + } +} + +/* +============= +R_MarkLights +============= +*/ +void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) +{ + float dist; + msurface_t *surf; + int i; + + if( !node || node->contents < 0 ) + return; + + dist = PlaneDiff( light->origin, node->plane ); + + if( dist > light->radius ) + { + R_MarkLights( light, bit, node->children[0] ); + return; + } + if( dist < -light->radius ) + { + R_MarkLights( light, bit, node->children[1] ); + return; + } + + // mark the polygons + surf = RI.currentmodel->surfaces + node->firstsurface; + + for( i = 0; i < node->numsurfaces; i++, surf++ ) + { + if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius )) + continue; // no intersection + + if( surf->dlightframe != tr.dlightframecount ) + { + surf->dlightbits = 0; + surf->dlightframe = tr.dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLights( light, bit, node->children[0] ); + R_MarkLights( light, bit, node->children[1] ); +} + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights( void ) +{ + dlight_t *l; + int i; + + tr.dlightframecount = tr.framecount; + + RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); + RI.currentmodel = RI.currententity->model; + + for( i = 0; i < MAX_DLIGHTS; i++, l++ ) + { + l = gEngfuncs.GetDynamicLight( i ); + + if( l->die < gpGlobals->time || !l->radius ) + continue; + + if( GL_FrustumCullSphere( &RI.frustum, l->origin, l->radius, 15 )) + continue; + + R_MarkLights( l, 1<nodes ); + } +} + +/* +============= +R_CountDlights +============= +*/ +int R_CountDlights( void ) +{ + dlight_t *l; + int i, numDlights = 0; + + for( i = 0; i < MAX_DLIGHTS; i++ ) + { + l = gEngfuncs.GetDynamicLight( i ); + + if( l->die < gpGlobals->time || !l->radius ) + continue; + + numDlights++; + } + + return numDlights; +} + +/* +============= +R_CountSurfaceDlights +============= +*/ +int R_CountSurfaceDlights( msurface_t *surf ) +{ + int i, numDlights = 0; + + for( i = 0; i < MAX_DLIGHTS; i++ ) + { + if(!( surf->dlightbits & BIT( i ))) + continue; // not lit by this light + + numDlights++; + } + + return numDlights; +} + +/* +======================================================================= + + AMBIENT LIGHTING + +======================================================================= +*/ +static vec3_t g_trace_lightspot; +static vec3_t g_trace_lightvec; +static float g_trace_fraction; + +/* +================= +R_RecursiveLightPoint +================= +*/ +static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end ) +{ + float front, back, frac, midf; + int i, map, side, size; + float ds, dt, s, t; + int sample_size; + color24 *lm, *dm; + mextrasurf_t *info; + msurface_t *surf; + mtexinfo_t *tex; + matrix3x4 tbn; + vec3_t mid; + + // didn't hit anything + if( !node || node->contents < 0 ) + { + cv->r = cv->g = cv->b = cv->a = 0; + return false; + } + + // calculate mid point + front = PlaneDiff( start, node->plane ); + back = PlaneDiff( end, node->plane ); + + side = front < 0; + if(( back < 0 ) == side ) + return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end ); + + frac = front / ( front - back ); + + VectorLerp( start, frac, end, mid ); + midf = p1f + ( p2f - p1f ) * frac; + + // co down front side + if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid )) + return true; // hit something + + if(( back < 0 ) == side ) + { + cv->r = cv->g = cv->b = cv->a = 0; + return false; // didn't hit anything + } + + // check for impact on this node + surf = model->surfaces + node->firstsurface; + VectorCopy( mid, g_trace_lightspot ); + + for( i = 0; i < node->numsurfaces; i++, surf++ ) + { + int smax, tmax; + + tex = surf->texinfo; + info = surf->info; + + if( FBitSet( surf->flags, SURF_DRAWTILED )) + continue; // no lightmaps + + s = DotProduct( mid, info->lmvecs[0] ) + info->lmvecs[0][3]; + t = DotProduct( mid, info->lmvecs[1] ) + info->lmvecs[1][3]; + + if( s < info->lightmapmins[0] || t < info->lightmapmins[1] ) + continue; + + ds = s - info->lightmapmins[0]; + dt = t - info->lightmapmins[1]; + + if ( ds > info->lightextents[0] || dt > info->lightextents[1] ) + continue; + + cv->r = cv->g = cv->b = cv->a = 0; + + if( !surf->samples ) + return true; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + smax = (info->lightextents[0] / sample_size) + 1; + tmax = (info->lightextents[1] / sample_size) + 1; + ds /= sample_size; + dt /= sample_size; + + lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds ); + g_trace_fraction = midf; + size = smax * tmax; + dm = NULL; + + if( surf->info->deluxemap ) + { + vec3_t faceNormal; + + if( FBitSet( surf->flags, SURF_PLANEBACK )) + VectorNegate( surf->plane->normal, faceNormal ); + else VectorCopy( surf->plane->normal, faceNormal ); + + // compute face TBN +#if 1 + Vector4Set( tbn[0], surf->info->lmvecs[0][0], surf->info->lmvecs[0][1], surf->info->lmvecs[0][2], 0.0f ); + Vector4Set( tbn[1], -surf->info->lmvecs[1][0], -surf->info->lmvecs[1][1], -surf->info->lmvecs[1][2], 0.0f ); + Vector4Set( tbn[2], faceNormal[0], faceNormal[1], faceNormal[2], 0.0f ); +#else + Vector4Set( tbn[0], surf->info->lmvecs[0][0], -surf->info->lmvecs[1][0], faceNormal[0], 0.0f ); + Vector4Set( tbn[1], surf->info->lmvecs[0][1], -surf->info->lmvecs[1][1], faceNormal[1], 0.0f ); + Vector4Set( tbn[2], surf->info->lmvecs[0][2], -surf->info->lmvecs[1][2], faceNormal[2], 0.0f ); +#endif + VectorNormalize( tbn[0] ); + VectorNormalize( tbn[1] ); + VectorNormalize( tbn[2] ); + dm = surf->info->deluxemap + Q_rint( dt ) * smax + Q_rint( ds ); + } + + for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ ) + { + uint scale = tr.lightstylevalue[surf->styles[map]]; + + if( tr.ignore_lightgamma ) + { + cv->r += lm->r * scale; + cv->g += lm->g * scale; + cv->b += lm->b * scale; + } + else + { + cv->r += gEngfuncs.LightToTexGamma( lm->r ) * scale; + cv->g += gEngfuncs.LightToTexGamma( lm->g ) * scale; + cv->b += gEngfuncs.LightToTexGamma( lm->b ) * scale; + } + lm += size; // skip to next lightmap + + if( dm != NULL ) + { + vec3_t srcNormal, lightNormal; + float f = (1.0f / 128.0f); + + VectorSet( srcNormal, ((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f ); + Matrix3x4_VectorIRotate( tbn, srcNormal, lightNormal ); // turn to world space + VectorScale( lightNormal, (float)scale * -1.0f, lightNormal ); // turn direction from light + VectorAdd( g_trace_lightvec, lightNormal, g_trace_lightvec ); + dm += size; // skip to next deluxmap + } + } + + return true; + } + + // go down back side + return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end ); +} + +/* +================= +R_LightVec + +check bspmodels to get light from +================= +*/ +colorVec R_LightVecInternal( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec ) +{ + float last_fraction; + int i, maxEnts = 1; + colorVec light, cv; + + if( lspot ) VectorClear( lspot ); + if( lvec ) VectorClear( lvec ); + + if( WORLDMODEL && WORLDMODEL->lightdata ) + { + light.r = light.g = light.b = light.a = 0; + last_fraction = 1.0f; + + // get light from bmodels too + if( CVAR_TO_BOOL( r_lighting_extended )) + maxEnts = MAX_PHYSENTS; + + // check all the bsp-models + for( i = 0; i < maxEnts; i++ ) + { + physent_t *pe = gEngfuncs.EV_GetPhysent( i ); + vec3_t offset, start_l, end_l; + mnode_t *pnodes; + matrix4x4 matrix; + + if( !pe ) + break; + + if( !pe->model || pe->model->type != mod_brush ) + continue; // skip non-bsp models + + pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode]; + VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset ); + VectorAdd( offset, pe->origin, offset ); + VectorSubtract( start, offset, start_l ); + VectorSubtract( end, offset, end_l ); + + // rotate start and end into the models frame of reference + if( !VectorIsNull( pe->angles )) + { + Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f ); + Matrix4x4_VectorITransform( matrix, start, start_l ); + Matrix4x4_VectorITransform( matrix, end, end_l ); + } + + VectorClear( g_trace_lightspot ); + VectorClear( g_trace_lightvec ); + g_trace_fraction = 1.0f; + + if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l )) + continue; // didn't hit anything + + if( g_trace_fraction < last_fraction ) + { + if( lspot ) VectorCopy( g_trace_lightspot, lspot ); + if( lvec ) VectorNormalize2( g_trace_lightvec, lvec ); + light.r = Q_min(( cv.r >> 7 ), 255 ); + light.g = Q_min(( cv.g >> 7 ), 255 ); + light.b = Q_min(( cv.b >> 7 ), 255 ); + last_fraction = g_trace_fraction; + + if(( light.r + light.g + light.b ) != 0 ) + break; // we get light now + } + } + } + else + { + light.r = light.g = light.b = 255; + light.a = 0; + } + + return light; +} + +/* +================= +R_LightVec + +check bspmodels to get light from +================= +*/ +colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec ) +{ + colorVec light = R_LightVecInternal( start, end, lspot, lvec ); + + if( CVAR_TO_BOOL( r_lighting_extended ) && lspot != NULL && lvec != NULL ) + { + // trying to get light from ceiling (but ignore gradient analyze) + if(( light.r + light.g + light.b ) == 0 ) + return R_LightVecInternal( end, start, lspot, lvec ); + } + + return light; +} + +/* +================= +R_LightPoint + +light from floor +================= +*/ +colorVec R_LightPoint( const vec3_t p0 ) +{ + vec3_t p1; + + VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f ); + + return R_LightVec( p0, p1, NULL, NULL ); +} diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c new file mode 100644 index 00000000..ca2bdd3b --- /dev/null +++ b/ref_gu/gu_rmain.c @@ -0,0 +1,1361 @@ +/* +gu_rmain.c - renderer main loop +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "xash3d_mathlib.h" +#include "library.h" +#include "beamdef.h" +#include "particledef.h" +#include "entity_types.h" + +#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA ) +float gldepthmin, gldepthmax; + +ref_instance_t RI; + +static int R_RankForRenderMode( int rendermode ) +{ + switch( rendermode ) + { + case kRenderTransTexture: + return 1; // draw second + case kRenderTransAdd: + return 2; // draw third + case kRenderGlow: + return 3; // must be last! + } + return 0; +} + +void R_AllowFog( qboolean allowed ) +{ +#if 1 + if( allowed ) + { + if( glState.isFogEnabled ) + sceGuEnable( GU_FOG ); + } + else + { + if( glState.isFogEnabled ) + sceGuDisable( GU_FOG ); + } +#else + if( allowed ) + { + if( glState.isFogEnabled ) + pglEnable( GL_FOG ); + } + else + { + if( glState.isFogEnabled ) + pglDisable( GL_FOG ); + } +#endif +} + +/* +=============== +R_OpaqueEntity + +Opaque entity can be brush or studio model but sprite +=============== +*/ +static qboolean R_OpaqueEntity( cl_entity_t *ent ) +{ + if( R_GetEntityRenderMode( ent ) == kRenderNormal ) + return true; + return false; +} + +/* +=============== +R_TransEntityCompare + +Sorting translucent entities by rendermode then by distance +=============== +*/ +static int R_TransEntityCompare( const void *a, const void *b ) +{ + cl_entity_t *ent1, *ent2; + vec3_t vecLen, org; + float dist1, dist2; + int rendermode1; + int rendermode2; + + ent1 = *(cl_entity_t **)a; + ent2 = *(cl_entity_t **)b; + rendermode1 = R_GetEntityRenderMode( ent1 ); + rendermode2 = R_GetEntityRenderMode( ent2 ); + + // sort by distance + if( ent1->model->type != mod_brush || rendermode1 != kRenderTransAlpha ) + { + VectorAverage( ent1->model->mins, ent1->model->maxs, org ); + VectorAdd( ent1->origin, org, org ); + VectorSubtract( RI.vieworg, org, vecLen ); + dist1 = DotProduct( vecLen, vecLen ); + } + else dist1 = 1000000000; + + if( ent2->model->type != mod_brush || rendermode2 != kRenderTransAlpha ) + { + VectorAverage( ent2->model->mins, ent2->model->maxs, org ); + VectorAdd( ent2->origin, org, org ); + VectorSubtract( RI.vieworg, org, vecLen ); + dist2 = DotProduct( vecLen, vecLen ); + } + else dist2 = 1000000000; + + if( dist1 > dist2 ) + return -1; + if( dist1 < dist2 ) + return 1; + + // then sort by rendermode + if( R_RankForRenderMode( rendermode1 ) > R_RankForRenderMode( rendermode2 )) + return 1; + if( R_RankForRenderMode( rendermode1 ) < R_RankForRenderMode( rendermode2 )) + return -1; + + return 0; +} + +/* +=============== +R_WorldToScreen + +Convert a given point from world into screen space +Returns true if we behind to screen +=============== +*/ +int R_WorldToScreen( const vec3_t point, vec3_t screen ) +{ + matrix4x4 worldToScreen; + qboolean behind; + float w; + + if( !point || !screen ) + return true; + + Matrix4x4_Copy( worldToScreen, RI.worldviewProjectionMatrix ); + screen[0] = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3]; + screen[1] = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3]; + w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3]; + screen[2] = 0.0f; // just so we have something valid here + + if( w < 0.001f ) + { + screen[0] *= 100000; + screen[1] *= 100000; + behind = true; + } + else + { + float invw = 1.0f / w; + screen[0] *= invw; + screen[1] *= invw; + behind = false; + } + + return behind; +} + +/* +=============== +R_ScreenToWorld + +Convert a given point from screen into world space +=============== +*/ +void R_ScreenToWorld( const vec3_t screen, vec3_t point ) +{ + matrix4x4 screenToWorld; + float w; + + if( !point || !screen ) + return; + + Matrix4x4_Invert_Full( screenToWorld, RI.worldviewProjectionMatrix ); + + point[0] = screen[0] * screenToWorld[0][0] + screen[1] * screenToWorld[0][1] + screen[2] * screenToWorld[0][2] + screenToWorld[0][3]; + point[1] = screen[0] * screenToWorld[1][0] + screen[1] * screenToWorld[1][1] + screen[2] * screenToWorld[1][2] + screenToWorld[1][3]; + point[2] = screen[0] * screenToWorld[2][0] + screen[1] * screenToWorld[2][1] + screen[2] * screenToWorld[2][2] + screenToWorld[2][3]; + w = screen[0] * screenToWorld[3][0] + screen[1] * screenToWorld[3][1] + screen[2] * screenToWorld[3][2] + screenToWorld[3][3]; + if( w != 0.0f ) VectorScale( point, ( 1.0f / w ), point ); +} + +/* +=============== +R_PushScene +=============== +*/ +void R_PushScene( void ) +{ + if( ++tr.draw_stack_pos >= MAX_DRAW_STACK ) + gEngfuncs.Host_Error( "draw stack overflow\n" ); + + tr.draw_list = &tr.draw_stack[tr.draw_stack_pos]; +} + +/* +=============== +R_PopScene +=============== +*/ +void R_PopScene( void ) +{ + if( --tr.draw_stack_pos < 0 ) + gEngfuncs.Host_Error( "draw stack underflow\n" ); + tr.draw_list = &tr.draw_stack[tr.draw_stack_pos]; +} + +/* +=============== +R_ClearScene +=============== +*/ +void R_ClearScene( void ) +{ + tr.draw_list->num_solid_entities = 0; + tr.draw_list->num_trans_entities = 0; + tr.draw_list->num_beam_entities = 0; + + // clear the scene befor start new frame + if( gEngfuncs.drawFuncs->R_ClearScene != NULL ) + gEngfuncs.drawFuncs->R_ClearScene(); + +} + +/* +=============== +R_AddEntity +=============== +*/ +qboolean R_AddEntity( struct cl_entity_s *clent, int type ) +{ + if( !r_drawentities->value ) + return false; // not allow to drawing + + if( !clent || !clent->model ) + return false; // if set to invisible, skip + + if( FBitSet( clent->curstate.effects, EF_NODRAW )) + return false; // done + + if( !R_ModelOpaque( clent->curstate.rendermode ) && CL_FxBlend( clent ) <= 0 ) + return true; // invisible + + switch( type ) + { + case ET_FRAGMENTED: + r_stats.c_client_ents++; + break; + case ET_TEMPENTITY: + r_stats.c_active_tents_count++; + break; + default: break; + } + + if( R_OpaqueEntity( clent )) + { + // opaque + if( tr.draw_list->num_solid_entities >= MAX_VISIBLE_PACKET ) + return false; + + tr.draw_list->solid_entities[tr.draw_list->num_solid_entities] = clent; + tr.draw_list->num_solid_entities++; + } + else + { + // translucent + if( tr.draw_list->num_trans_entities >= MAX_VISIBLE_PACKET ) + return false; + + tr.draw_list->trans_entities[tr.draw_list->num_trans_entities] = clent; + tr.draw_list->num_trans_entities++; + } + + return true; +} + +/* +============= +R_Clear +============= +*/ +static void R_Clear( int bitMask ) +{ + int bits; + + if( ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) + sceGuClearColor( 0xff00ff00 ); // green background (Valve rules) + else sceGuClearColor( 0xff7f7f7f ); + + bits = GU_DEPTH_BUFFER_BIT; + + if( glState.stencilEnabled ) + bits |= GU_STENCIL_BUFFER_BIT; + + bits &= bitMask; + + sceGuClear( bits ); + + // change ordering for overview + if( RI.drawOrtho ) + { + gldepthmin = 65535.0f; + gldepthmax = 0.0f; + } + else + { + gldepthmin = 0.0f; + gldepthmax = 65535.0f; + } + + sceGuDepthFunc( GU_LEQUAL ); + sceGuDepthRange( ( int )gldepthmin, ( int )gldepthmax ); +} + +//============================================================================= +/* +=============== +R_GetFarClip +=============== +*/ +static float R_GetFarClip( void ) +{ + if( WORLDMODEL && RI.drawWorld ) + return MOVEVARS->zmax * 1.73f; + return 2048.0f; +} + +/* +=============== +R_SetupFrustum +=============== +*/ +void R_SetupFrustum( void ) +{ + const ref_overview_t *ov = gEngfuncs.GetOverviewParms(); + + if( RP_NORMALPASS() && ( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 )) + { + RI.fov_x = atan( tan( DEG2RAD( RI.fov_x ) / 2 ) * ( 0.97f + sin( gpGlobals->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f); + RI.fov_y = atan( tan( DEG2RAD( RI.fov_y ) / 2 ) * ( 1.03f - sin( gpGlobals->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f); + } + + // build the transformation matrix for the given view angles + AngleVectors( RI.viewangles, RI.vforward, RI.vright, RI.vup ); + + if( !r_lockfrustum->value ) + { + VectorCopy( RI.vieworg, RI.cullorigin ); + VectorCopy( RI.vforward, RI.cull_vforward ); + VectorCopy( RI.vright, RI.cull_vright ); + VectorCopy( RI.vup, RI.cull_vup ); + } + + if( RI.drawOrtho ) + GL_FrustumInitOrtho( &RI.frustum, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar ); + else GL_FrustumInitProj( &RI.frustum, 0.0f, R_GetFarClip(), RI.fov_x, RI.fov_y ); // NOTE: we ignore nearplane here (mirrors only) +} + +/* +============= +R_SetupProjectionMatrix +============= +*/ +static void R_SetupProjectionMatrix( matrix4x4 m ) +{ + GLfloat xMin, xMax, yMin, yMax, zNear, zFar; + + if( RI.drawOrtho ) + { + const ref_overview_t *ov = gEngfuncs.GetOverviewParms(); + Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar ); + return; + } + + RI.farClip = R_GetFarClip(); + + zNear = 4.0f; + zFar = max( 256.0f, RI.farClip ); + + yMax = zNear * tan( RI.fov_y * M_PI_F / 360.0f ); + yMin = -yMax; + + xMax = zNear * tan( RI.fov_x * M_PI_F / 360.0f ); + xMin = -xMax; + + Matrix4x4_CreateProjection( m, xMax, xMin, yMax, yMin, zNear, zFar ); +} + +/* +============= +R_SetupModelviewMatrix +============= +*/ +static void R_SetupModelviewMatrix( matrix4x4 m ) +{ + Matrix4x4_CreateModelview( m ); + Matrix4x4_ConcatRotate( m, -RI.viewangles[2], 1, 0, 0 ); + Matrix4x4_ConcatRotate( m, -RI.viewangles[0], 0, 1, 0 ); + Matrix4x4_ConcatRotate( m, -RI.viewangles[1], 0, 0, 1 ); + Matrix4x4_ConcatTranslate( m, -RI.vieworg[0], -RI.vieworg[1], -RI.vieworg[2] ); +} + +/* +============= +R_LoadIdentity +============= +*/ +void R_LoadIdentity( void ) +{ + if( tr.modelviewIdentity ) + return; + + Matrix4x4_LoadIdentity( RI.objectMatrix ); +#if 1 + sceGumMatrixMode( GU_MODEL ); + GL_LoadMatrix( RI.objectMatrix ); + sceGumUpdateMatrix(); +#else + Matrix4x4_Copy( RI.modelviewMatrix, RI.worldviewMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.modelviewMatrix ); +#endif + tr.modelviewIdentity = true; +} + +/* +============= +R_RotateForEntity +============= +*/ +void R_RotateForEntity( cl_entity_t *e ) +{ + float scale = 1.0f; + + if( e == gEngfuncs.GetEntityByIndex( 0 ) ) + { + R_LoadIdentity(); + return; + } + + if( e->model->type != mod_brush && e->curstate.scale > 0.0f ) + scale = e->curstate.scale; + + Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, scale ); +#if 1 + sceGumMatrixMode( GU_MODEL ); + GL_LoadMatrix( RI.objectMatrix ); + sceGumUpdateMatrix(); +#else + Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.modelviewMatrix ); +#endif + tr.modelviewIdentity = false; +} + +/* +============= +R_TranslateForEntity +============= +*/ +void R_TranslateForEntity( cl_entity_t *e ) +{ + float scale = 1.0f; + + if( e == gEngfuncs.GetEntityByIndex( 0 ) ) + { + printf("e == gEngfuncs.GetEntityByIndex\n"); + R_LoadIdentity(); + return; + } + + if( e->model->type != mod_brush && e->curstate.scale > 0.0f ) + scale = e->curstate.scale; + + Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, scale ); +#if 1 + sceGumMatrixMode( GU_MODEL ); + GL_LoadMatrix( RI.objectMatrix ); + sceGumUpdateMatrix(); +#else + Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.modelviewMatrix ); +#endif + tr.modelviewIdentity = false; +} + +/* +=============== +R_FindViewLeaf +=============== +*/ +void R_FindViewLeaf( void ) +{ + RI.oldviewleaf = RI.viewleaf; + RI.viewleaf = gEngfuncs.Mod_PointInLeaf( RI.pvsorigin, WORLDMODEL->nodes ); +} + +/* +=============== +R_SetupFrame +=============== +*/ +static void R_SetupFrame( void ) +{ + // setup viewplane dist + RI.viewplanedist = DotProduct( RI.vieworg, RI.vforward ); + + // NOTE: this request is the fps-killer on some NVidia drivers +#if 1 + glState.isFogEnabled = sceGuGetStatus( GU_FOG ); +#else + glState.isFogEnabled = pglIsEnabled( GL_FOG ); +#endif + + if( !gl_nosort->value ) + { + // sort translucents entities by rendermode and distance + qsort( tr.draw_list->trans_entities, tr.draw_list->num_trans_entities, sizeof( cl_entity_t* ), R_TransEntityCompare ); + } + + // current viewleaf + if( RI.drawWorld ) + { + RI.isSkyVisible = false; // unknown at this moment + R_FindViewLeaf(); + } +} + +/* +============= +R_SetupGL +============= +*/ +void R_SetupGL( qboolean set_gl_state ) +{ + R_SetupModelviewMatrix( RI.worldviewMatrix ); + R_SetupProjectionMatrix( RI.projectionMatrix ); + + Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix ); + + if( !set_gl_state ) return; + + if( RP_NORMALPASS( )) + { + int x, x2, y, y2; + + // set up viewport (main, playersetup) + x = floor( RI.viewport[0] * gpGlobals->width / gpGlobals->width ); + x2 = ceil(( RI.viewport[0] + RI.viewport[2] ) * gpGlobals->width / gpGlobals->width ); + y = floor( gpGlobals->height - RI.viewport[1] * gpGlobals->height / gpGlobals->height ); + y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] ) * gpGlobals->height / gpGlobals->height ); +#if 1 + sceGuViewport( 2048, 2048, x2 - x, y - y2 ); /* psp center viewport 2048x2048 PSPFIXME*/ + sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); + /*sceGuViewport( + 2048, + 2048 + (gpGlobals->height / 2) - y2 - ((y - y2) / 2), + x2 - x, y - y2); + sceGuScissor(x, gpGlobals->height - y2 - (y - y2), x + (x2 - x), gpGlobals->height - y2);*/ +#else + pglViewport( x, y2, x2 - x, y - y2 ); +#endif + } + else + { + // envpass, mirrorpass +#if 1 + sceGuViewport( 2048, 2048, RI.viewport[2], RI.viewport[3] ); /* psp center viewport 2048x2048 PSPFIXME */ + sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); +#else + pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); +#endif + } +#if 1 + sceGumMatrixMode( GU_PROJECTION ); + GL_LoadMatrix( RI.projectionMatrix ); + + sceGumMatrixMode( GU_VIEW ); + GL_LoadMatrix( RI.worldviewMatrix ); + + sceGumUpdateMatrix(); //Apply a matrix transformation + sceGumMatrixMode( GU_MODEL ); + +/* not supported + if( FBitSet( RI.params, RP_CLIPPLANE )) + { + GLdouble clip[4]; + mplane_t *p = &RI.clipPlane; + + clip[0] = p->normal[0]; + clip[1] = p->normal[1]; + clip[2] = p->normal[2]; + clip[3] = -p->dist; + + pglClipPlane( GL_CLIP_PLANE0, clip ); + pglEnable( GL_CLIP_PLANE0 ); + } +*/ + GL_Cull( GL_FRONT ); + + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, 1.0f ) ); + + GU_ClipBeginFrame(); +#else + pglMatrixMode( GL_PROJECTION ); + GL_LoadMatrix( RI.projectionMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.worldviewMatrix ); + + if( FBitSet( RI.params, RP_CLIPPLANE )) + { + GLdouble clip[4]; + mplane_t *p = &RI.clipPlane; + + clip[0] = p->normal[0]; + clip[1] = p->normal[1]; + clip[2] = p->normal[2]; + clip[3] = -p->dist; + + pglClipPlane( GL_CLIP_PLANE0, clip ); + pglEnable( GL_CLIP_PLANE0 ); + } + + GL_Cull( GL_FRONT ); + + pglDisable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); +#endif +} + +/* +============= +R_EndGL +============= +*/ +static void R_EndGL( void ) +{ +#if 0 + if( RI.params & RP_CLIPPLANE ) + pglDisable( GL_CLIP_PLANE0 ); +#endif +} + +/* +============= +R_RecursiveFindWaterTexture + +using to find source waterleaf with +watertexture to grab fog values from it +============= +*/ +static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down ) +{ + gl_texture_t *tex = NULL; + + // assure the initial node is not null + // we could check it here, but we would rather check it + // outside the call to get rid of one additional recursion level + Assert( node != NULL ); + + // ignore solid nodes + if( node->contents == CONTENTS_SOLID ) + return NULL; + + if( node->contents < 0 ) + { + mleaf_t *pleaf; + msurface_t **mark; + int i, c; + + // ignore non-liquid leaves + if( node->contents != CONTENTS_WATER && node->contents != CONTENTS_LAVA && node->contents != CONTENTS_SLIME ) + return NULL; + + // find texture + pleaf = (mleaf_t *)node; + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + for( i = 0; i < c; i++, mark++ ) + { + if( (*mark)->flags & SURF_DRAWTURB && (*mark)->texinfo && (*mark)->texinfo->texture ) + return R_GetTexture( (*mark)->texinfo->texture->gl_texturenum ); + } + + // texture not found + return NULL; + } + + // this is a regular node + // traverse children + if( node->children[0] && ( node->children[0] != ignore )) + { + tex = R_RecursiveFindWaterTexture( node->children[0], node, true ); + if( tex ) return tex; + } + + if( node->children[1] && ( node->children[1] != ignore )) + { + tex = R_RecursiveFindWaterTexture( node->children[1], node, true ); + if( tex ) return tex; + } + + // for down recursion, return immediately + if( down ) return NULL; + + // texture not found, step up if any + if( node->parent ) + return R_RecursiveFindWaterTexture( node->parent, node, false ); + + // top-level node, bail out + return NULL; +} + +/* +============= +R_CheckFog + +check for underwater fog +Using backward recursion to find waterline leaf +from underwater leaf (idea: XaeroX) +============= +*/ +static void R_CheckFog( void ) +{ + cl_entity_t *ent; + gl_texture_t *tex; + int i, cnt, count; + + // quake global fog + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + { + if( !MOVEVARS->fog_settings ) + { +#if 1 + if( sceGuGetStatus( GU_FOG ) ) + sceGuDisable( GU_FOG ); +#else + if( pglIsEnabled( GL_FOG ) ) + pglDisable( GL_FOG ); +#endif + RI.fogEnabled = false; + return; + } + + // quake-style global fog + RI.fogColor[0] = ((MOVEVARS->fog_settings & 0xFF000000) >> 24) / 255.0f; + RI.fogColor[1] = ((MOVEVARS->fog_settings & 0xFF0000) >> 16) / 255.0f; + RI.fogColor[2] = ((MOVEVARS->fog_settings & 0xFF00) >> 8) / 255.0f; + RI.fogDensity = ((MOVEVARS->fog_settings & 0xFF) / 255.0f) * 0.01f; + RI.fogStart = RI.fogEnd = 0.0f; + RI.fogColor[3] = 1.0f; + RI.fogCustom = false; + RI.fogEnabled = true; + RI.fogSkybox = true; + return; + } + + RI.fogEnabled = false; + + if( RI.onlyClientDraw || ENGINE_GET_PARM( PARM_WATER_LEVEL ) < 3 || !RI.drawWorld || !RI.viewleaf ) + { + if( RI.cached_waterlevel == 3 ) + { + // in some cases waterlevel jumps from 3 to 1. Catch it + RI.cached_waterlevel = ENGINE_GET_PARM( PARM_WATER_LEVEL ); + RI.cached_contents = CONTENTS_EMPTY; + if( !RI.fogCustom ) + { + glState.isFogEnabled = false; +#if 1 + sceGuDisable( GU_FOG ); +#else + pglDisable( GL_FOG ); +#endif + } + } + return; + } + + ent = gEngfuncs.CL_GetWaterEntity( RI.vieworg ); + if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 ) + cnt = ent->curstate.skin; + else cnt = RI.viewleaf->contents; + + RI.cached_waterlevel = ENGINE_GET_PARM( PARM_WATER_LEVEL ); + + if( !IsLiquidContents( RI.cached_contents ) && IsLiquidContents( cnt )) + { + tex = NULL; + + // check for water texture + if( ent && ent->model && ent->model->type == mod_brush ) + { + msurface_t *surf; + + count = ent->model->nummodelsurfaces; + + for( i = 0, surf = &ent->model->surfaces[ent->model->firstmodelsurface]; i < count; i++, surf++ ) + { + if( surf->flags & SURF_DRAWTURB && surf->texinfo && surf->texinfo->texture ) + { + tex = R_GetTexture( surf->texinfo->texture->gl_texturenum ); + RI.cached_contents = ent->curstate.skin; + break; + } + } + } + else + { + tex = R_RecursiveFindWaterTexture( RI.viewleaf->parent, NULL, false ); + if( tex ) RI.cached_contents = RI.viewleaf->contents; + } + + if( !tex ) return; // no valid fogs + + // copy fog params + RI.fogColor[0] = tex->fogParams[0] / 255.0f; + RI.fogColor[1] = tex->fogParams[1] / 255.0f; + RI.fogColor[2] = tex->fogParams[2] / 255.0f; + RI.fogDensity = tex->fogParams[3] * 0.000025f; + RI.fogStart = RI.fogEnd = 0.0f; + RI.fogColor[3] = 1.0f; + RI.fogCustom = false; + RI.fogEnabled = true; + RI.fogSkybox = true; + } + else + { + RI.fogCustom = false; + RI.fogEnabled = true; + RI.fogSkybox = true; + } +} + +/* +============= +R_CheckGLFog + +special condition for Spirit 1.9 +that used direct calls of glFog-functions +============= +*/ +static void R_CheckGLFog( void ) +{ +#ifdef HACKS_RELATED_HLMODS + if(( !RI.fogEnabled && !RI.fogCustom ) && pglIsEnabled( GL_FOG ) && VectorIsNull( RI.fogColor )) + { + // fill the fog color from GL-state machine +#if 0 + pglGetFloatv( GL_FOG_COLOR, RI.fogColor ); +#endif + RI.fogSkybox = true; + } +#endif +} + +/* +============= +R_DrawFog + +============= +*/ +void R_DrawFog( void ) +{ + if( !RI.fogEnabled ) return; +#if 1 + sceGuEnable( GU_FOG ); + glState.fogDensity = RI.fogDensity; + glState.fogColor = GUCOLOR4F( RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], glState.fogDensity ); + sceGuFog( glState.fogStart, glState.fogEnd, glState.fogColor ); +#else + pglEnable( GL_FOG ); + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + pglFogi( GL_FOG_MODE, GL_EXP2 ); + else pglFogi( GL_FOG_MODE, GL_EXP ); + pglFogf( GL_FOG_DENSITY, RI.fogDensity ); + pglFogfv( GL_FOG_COLOR, RI.fogColor ); + pglHint( GL_FOG_HINT, GL_NICEST ); +#endif +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList( void ) +{ + int i; + + tr.blend = 1.0f; + + // first draw solid entities + for( i = 0; i < tr.draw_list->num_solid_entities && !RI.onlyClientDraw; i++ ) + { + RI.currententity = tr.draw_list->solid_entities[i]; + RI.currentmodel = RI.currententity->model; + + Assert( RI.currententity != NULL ); + Assert( RI.currentmodel != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_brush: + R_DrawBrushModel( RI.currententity ); + break; + case mod_alias: + R_DrawAliasModel( RI.currententity ); + break; + case mod_studio: + R_DrawStudioModel( RI.currententity ); + break; + default: + break; + } + } + + // quake-specific feature + R_DrawAlphaTextureChains(); + + // draw sprites seperately, because of alpha blending + for( i = 0; i < tr.draw_list->num_solid_entities && !RI.onlyClientDraw; i++ ) + { + RI.currententity = tr.draw_list->solid_entities[i]; + RI.currentmodel = RI.currententity->model; + + Assert( RI.currententity != NULL ); + Assert( RI.currentmodel != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_sprite: + R_DrawSpriteModel( RI.currententity ); + break; + } + } + + if( !RI.onlyClientDraw ) + { + gEngfuncs.CL_DrawEFX( tr.frametime, false ); + } + + if( RI.drawWorld ) + gEngfuncs.pfnDrawNormalTriangles(); + + // then draw translucent entities + for( i = 0; i < tr.draw_list->num_trans_entities && !RI.onlyClientDraw; i++ ) + { + RI.currententity = tr.draw_list->trans_entities[i]; + RI.currentmodel = RI.currententity->model; + + // handle studiomodels with custom rendermodes on texture + if( RI.currententity->curstate.rendermode != kRenderNormal ) + tr.blend = CL_FxBlend( RI.currententity ) / 255.0f; + else tr.blend = 1.0f; // draw as solid but sorted by distance + + if( tr.blend <= 0.0f ) continue; + + Assert( RI.currententity != NULL ); + Assert( RI.currentmodel != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_brush: + R_DrawBrushModel( RI.currententity ); + break; + case mod_alias: + R_DrawAliasModel( RI.currententity ); + break; + case mod_studio: + R_DrawStudioModel( RI.currententity ); + break; + case mod_sprite: + R_DrawSpriteModel( RI.currententity ); + break; + default: + break; + } + } + + if( RI.drawWorld ) + { + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + gEngfuncs.pfnDrawTransparentTriangles (); + } + + if( !RI.onlyClientDraw ) + { + R_AllowFog( false ); + gEngfuncs.CL_DrawEFX( tr.frametime, true ); + R_AllowFog( true ); + } + + sceGuDisable( GU_BLEND ); // Trinity Render issues + + if( !RI.onlyClientDraw ) + R_DrawViewModel(); + gEngfuncs.CL_ExtraUpdate(); +} + +/* +================ +R_RenderScene + +R_SetupRefParams must be called right before +================ +*/ +void R_RenderScene( void ) +{ + if( !WORLDMODEL && RI.drawWorld ) + gEngfuncs.Host_Error( "R_RenderView: NULL worldmodel\n" ); + + // frametime is valid only for normal pass + if( RP_NORMALPASS( )) + tr.frametime = gpGlobals->time - gpGlobals->oldtime; + else tr.frametime = 0.0; + + // begin a new frame + tr.framecount++; + + R_PushDlights(); + + R_SetupFrustum(); + R_SetupFrame(); + R_SetupGL( true ); + R_Clear( ~0 ); + + R_MarkLeaves(); + R_DrawFog (); + + R_CheckGLFog(); + R_DrawWorld(); + R_CheckFog(); + + gEngfuncs.CL_ExtraUpdate (); // don't let sound get messed up if going slow + + R_DrawEntitiesOnList(); + + R_DrawWaterSurfaces(); + + R_EndGL(); +} + +/* +=============== +R_CheckGamma +=============== +*/ +void R_CheckGamma( void ) +{ + if( gEngfuncs.R_DoResetGamma( )) + { + // paranoia cubemaps uses this + gEngfuncs.BuildGammaTable( 1.8f, 0.0f ); + + // paranoia cubemap rendering + if( gEngfuncs.drawFuncs->GL_BuildLightmaps ) + gEngfuncs.drawFuncs->GL_BuildLightmaps( ); + } + else if( FBitSet( vid_gamma->flags, FCVAR_CHANGED ) || FBitSet( vid_brightness->flags, FCVAR_CHANGED )) + { + gEngfuncs.BuildGammaTable( vid_gamma->value, vid_brightness->value ); + glConfig.softwareGammaUpdate = true; + GL_RebuildLightmaps(); + glConfig.softwareGammaUpdate = false; + } +} + +/* +=============== +R_BeginFrame +=============== +*/ +void R_BeginFrame( qboolean clearScene ) +{ + glConfig.softwareGammaUpdate = false; // in case of possible fails + + if(( gl_clear->value || ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) && + clearScene && ENGINE_GET_PARM( PARM_CONNSTATE ) != ca_cinematic ) + { +#if 1 + sceGuClear( GU_COLOR_BUFFER_BIT ); +#else + pglClear( GL_COLOR_BUFFER_BIT ); +#endif + } + + R_CheckGamma(); + + R_Set2DMode( true ); + // draw buffer stuff +#if 0 + pglDrawBuffer( GL_BACK ); + + // update texture parameters + if( FBitSet( gl_texture_nearest->flags|gl_lightmap_nearest->flags|gl_texture_anisotropy->flags|gl_texture_lodbias->flags, FCVAR_CHANGED )) + R_SetTextureParameters(); +#endif + gEngfuncs.CL_ExtraUpdate (); +} + +/* +=============== +R_SetupRefParams + +set initial params for renderer +=============== +*/ +void R_SetupRefParams( const ref_viewpass_t *rvp ) +{ + RI.params = RP_NONE; + RI.drawWorld = FBitSet( rvp->flags, RF_DRAW_WORLD ); + RI.onlyClientDraw = FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW ); + RI.farClip = 0; + + if( !FBitSet( rvp->flags, RF_DRAW_CUBEMAP )) + RI.drawOrtho = FBitSet( rvp->flags, RF_DRAW_OVERVIEW ); + else RI.drawOrtho = false; + + // setup viewport + RI.viewport[0] = rvp->viewport[0]; + RI.viewport[1] = rvp->viewport[1]; + RI.viewport[2] = rvp->viewport[2]; + RI.viewport[3] = rvp->viewport[3]; + + // calc FOV + RI.fov_x = rvp->fov_x; + RI.fov_y = rvp->fov_y; + + VectorCopy( rvp->vieworigin, RI.vieworg ); + VectorCopy( rvp->viewangles, RI.viewangles ); + VectorCopy( rvp->vieworigin, RI.pvsorigin ); +} + +/* +=============== +R_RenderFrame +=============== +*/ +void R_RenderFrame( const ref_viewpass_t *rvp ) +{ + if( r_norefresh->value ) + return; + + // setup the initial render params + R_SetupRefParams( rvp ); +#if 0 + if( gl_finish->value && RI.drawWorld ) + pglFinish(); +#endif + + // completely override rendering + if( gEngfuncs.drawFuncs->GL_RenderFrame != NULL ) + { + tr.fCustomRendering = true; + + if( gEngfuncs.drawFuncs->GL_RenderFrame( rvp )) + { + R_GatherPlayerLight(); + tr.realframecount++; + tr.fResetVis = true; + return; + } + } + + tr.fCustomRendering = false; + if( !RI.onlyClientDraw ) + R_RunViewmodelEvents(); + + tr.realframecount++; // right called after viewmodel events + R_RenderScene(); + + return; +} + +/* +=============== +R_EndFrame +=============== +*/ +void R_EndFrame( void ) +{ + // flush any remaining 2D bits + R_Set2DMode( false ); + gEngfuncs.GL_SwapBuffers(); +} + +/* +=============== +R_DrawCubemapView +=============== +*/ +void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size ) +{ + ref_viewpass_t rvp; + + // basic params + rvp.flags = rvp.viewentity = 0; + SetBits( rvp.flags, RF_DRAW_WORLD ); + SetBits( rvp.flags, RF_DRAW_CUBEMAP ); + + rvp.viewport[0] = rvp.viewport[1] = 0; + rvp.viewport[2] = rvp.viewport[3] = size; + rvp.fov_x = rvp.fov_y = 90.0f; // this is a final fov value + + // setup origin & angles + VectorCopy( origin, rvp.vieworigin ); + VectorCopy( angles, rvp.viewangles ); + + R_RenderFrame( &rvp ); + + RI.viewleaf = NULL; // force markleafs next frame +} + +/* +=============== +CL_FxBlend +=============== +*/ +int CL_FxBlend( cl_entity_t *e ) +{ + int blend = 0; + float offset, dist; + vec3_t tmp; + + offset = ((int)e->index ) * 363.0f; // Use ent index to de-sync these fx + + switch( e->curstate.renderfx ) + { + case kRenderFxPulseSlowWide: + blend = e->curstate.renderamt + 0x40 * sin( gpGlobals->time * 2 + offset ); + break; + case kRenderFxPulseFastWide: + blend = e->curstate.renderamt + 0x40 * sin( gpGlobals->time * 8 + offset ); + break; + case kRenderFxPulseSlow: + blend = e->curstate.renderamt + 0x10 * sin( gpGlobals->time * 2 + offset ); + break; + case kRenderFxPulseFast: + blend = e->curstate.renderamt + 0x10 * sin( gpGlobals->time * 8 + offset ); + break; + case kRenderFxFadeSlow: + if( RP_NORMALPASS( )) + { + if( e->curstate.renderamt > 0 ) + e->curstate.renderamt -= 1; + else e->curstate.renderamt = 0; + } + blend = e->curstate.renderamt; + break; + case kRenderFxFadeFast: + if( RP_NORMALPASS( )) + { + if( e->curstate.renderamt > 3 ) + e->curstate.renderamt -= 4; + else e->curstate.renderamt = 0; + } + blend = e->curstate.renderamt; + break; + case kRenderFxSolidSlow: + if( RP_NORMALPASS( )) + { + if( e->curstate.renderamt < 255 ) + e->curstate.renderamt += 1; + else e->curstate.renderamt = 255; + } + blend = e->curstate.renderamt; + break; + case kRenderFxSolidFast: + if( RP_NORMALPASS( )) + { + if( e->curstate.renderamt < 252 ) + e->curstate.renderamt += 4; + else e->curstate.renderamt = 255; + } + blend = e->curstate.renderamt; + break; + case kRenderFxStrobeSlow: + blend = 20 * sin( gpGlobals->time * 4 + offset ); + if( blend < 0 ) blend = 0; + else blend = e->curstate.renderamt; + break; + case kRenderFxStrobeFast: + blend = 20 * sin( gpGlobals->time * 16 + offset ); + if( blend < 0 ) blend = 0; + else blend = e->curstate.renderamt; + break; + case kRenderFxStrobeFaster: + blend = 20 * sin( gpGlobals->time * 36 + offset ); + if( blend < 0 ) blend = 0; + else blend = e->curstate.renderamt; + break; + case kRenderFxFlickerSlow: + blend = 20 * (sin( gpGlobals->time * 2 ) + sin( gpGlobals->time * 17 + offset )); + if( blend < 0 ) blend = 0; + else blend = e->curstate.renderamt; + break; + case kRenderFxFlickerFast: + blend = 20 * (sin( gpGlobals->time * 16 ) + sin( gpGlobals->time * 23 + offset )); + if( blend < 0 ) blend = 0; + else blend = e->curstate.renderamt; + break; + case kRenderFxHologram: + case kRenderFxDistort: + VectorCopy( e->origin, tmp ); + VectorSubtract( tmp, RI.vieworg, tmp ); + dist = DotProduct( tmp, RI.vforward ); + + // turn off distance fade + if( e->curstate.renderfx == kRenderFxDistort ) + dist = 1; + + if( dist <= 0 ) + { + blend = 0; + } + else + { + e->curstate.renderamt = 180; + if( dist <= 100 ) blend = e->curstate.renderamt; + else blend = (int) ((1.0f - ( dist - 100 ) * ( 1.0f / 400.0f )) * e->curstate.renderamt ); + blend += gEngfuncs.COM_RandomLong( -32, 31 ); + } + break; + default: + blend = e->curstate.renderamt; + break; + } + + blend = bound( 0, blend, 255 ); + + return blend; +} diff --git a/ref_gu/gu_rmath.c b/ref_gu/gu_rmath.c new file mode 100644 index 00000000..c3a3db24 --- /dev/null +++ b/ref_gu/gu_rmath.c @@ -0,0 +1,267 @@ +/* +gl_rmath.c - renderer mathlib +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "xash3d_mathlib.h" + +/* +======================================================================== + + Matrix4x4 operations (private to renderer) + +======================================================================== +*/ +void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3] * in2[3][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0] + in1[1][3] * in2[3][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1] + in1[1][3] * in2[3][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2] + in1[1][3] * in2[3][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3] * in2[3][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0] + in1[2][3] * in2[3][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1] + in1[2][3] * in2[3][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2] + in1[2][3] * in2[3][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3] * in2[3][3]; + out[3][0] = in1[3][0] * in2[0][0] + in1[3][1] * in2[1][0] + in1[3][2] * in2[2][0] + in1[3][3] * in2[3][0]; + out[3][1] = in1[3][0] * in2[0][1] + in1[3][1] * in2[1][1] + in1[3][2] * in2[2][1] + in1[3][3] * in2[3][1]; + out[3][2] = in1[3][0] * in2[0][2] + in1[3][1] * in2[1][2] + in1[3][2] * in2[2][2] + in1[3][3] * in2[3][2]; + out[3][3] = in1[3][0] * in2[0][3] + in1[3][1] * in2[1][3] + in1[3][2] * in2[2][3] + in1[3][3] * in2[3][3]; +} + +/* +================ +Matrix4x4_CreateProjection + +NOTE: produce quake style world orientation +================ +*/ +void Matrix4x4_CreateProjection( matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar ) +{ + out[0][0] = ( 2.0f * zNear ) / ( xMax - xMin ); + out[1][1] = ( 2.0f * zNear ) / ( yMax - yMin ); + out[2][2] = -( zFar + zNear ) / ( zFar - zNear ); + out[3][3] = out[0][1] = out[1][0] = out[3][0] = out[0][3] = out[3][1] = out[1][3] = 0.0f; + + out[2][0] = 0.0f; + out[2][1] = 0.0f; + out[0][2] = ( xMax + xMin ) / ( xMax - xMin ); + out[1][2] = ( yMax + yMin ) / ( yMax - yMin ); + out[3][2] = -1.0f; + out[2][3] = -( 2.0f * zFar * zNear ) / ( zFar - zNear ); +} + +void Matrix4x4_CreateOrtho( matrix4x4 out, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar ) +{ + out[0][0] = 2.0f / (xRight - xLeft); + out[1][1] = 2.0f / (yTop - yBottom); + out[2][2] = -2.0f / (zFar - zNear); + out[3][3] = 1.0f; + out[0][1] = out[0][2] = out[1][0] = out[1][2] = out[3][0] = out[3][1] = out[3][2] = 0.0f; + + out[2][0] = 0.0f; + out[2][1] = 0.0f; + out[0][3] = -(xRight + xLeft) / (xRight - xLeft); + out[1][3] = -(yTop + yBottom) / (yTop - yBottom); + out[2][3] = -(zFar + zNear) / (zFar - zNear); +} + +/* +================ +Matrix4x4_CreateModelview + +NOTE: produce quake style world orientation +================ +*/ +void Matrix4x4_CreateModelview( matrix4x4 out ) +{ + out[0][0] = out[1][1] = out[2][2] = 0.0f; + out[3][0] = out[0][3] = 0.0f; + out[3][1] = out[1][3] = 0.0f; + out[3][2] = out[2][3] = 0.0f; + out[3][3] = 1.0f; + out[1][0] = out[0][2] = out[2][1] = 0.0f; + out[2][0] = out[0][1] = -1.0f; + out[1][2] = 1.0f; +} + +void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] ) +{ + out[ 0] = in[0][0]; + out[ 1] = in[1][0]; + out[ 2] = in[2][0]; + out[ 3] = in[3][0]; + out[ 4] = in[0][1]; + out[ 5] = in[1][1]; + out[ 6] = in[2][1]; + out[ 7] = in[3][1]; + out[ 8] = in[0][2]; + out[ 9] = in[1][2]; + out[10] = in[2][2]; + out[11] = in[3][2]; + out[12] = in[0][3]; + out[13] = in[1][3]; + out[14] = in[2][3]; + out[15] = in[3][3]; +} + +void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] ) +{ + out[0][0] = in[0]; + out[1][0] = in[1]; + out[2][0] = in[2]; + out[3][0] = in[3]; + out[0][1] = in[4]; + out[1][1] = in[5]; + out[2][1] = in[6]; + out[3][1] = in[7]; + out[0][2] = in[8]; + out[1][2] = in[9]; + out[2][2] = in[10]; + out[3][2] = in[11]; + out[0][3] = in[12]; + out[1][3] = in[13]; + out[2][3] = in[14]; + out[3][3] = in[15]; +} + +void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z ) +{ + out[0][0] = 1.0f; + out[0][1] = 0.0f; + out[0][2] = 0.0f; + out[0][3] = x; + out[1][0] = 0.0f; + out[1][1] = 1.0f; + out[1][2] = 0.0f; + out[1][3] = y; + out[2][0] = 0.0f; + out[2][1] = 0.0f; + out[2][2] = 1.0f; + out[2][3] = z; + out[3][0] = 0.0f; + out[3][1] = 0.0f; + out[3][2] = 0.0f; + out[3][3] = 1.0f; +} + +void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z ) +{ + float len, c, s; + + len = x * x + y * y + z * z; + if( len != 0.0f ) len = 1.0f / sqrt( len ); + x *= len; + y *= len; + z *= len; + + angle *= (-M_PI_F / 180.0f); + SinCos( angle, &s, &c ); + + out[0][0]=x * x + c * (1 - x * x); + out[0][1]=x * y * (1 - c) + z * s; + out[0][2]=z * x * (1 - c) - y * s; + out[0][3]=0.0f; + out[1][0]=x * y * (1 - c) - z * s; + out[1][1]=y * y + c * (1 - y * y); + out[1][2]=y * z * (1 - c) + x * s; + out[1][3]=0.0f; + out[2][0]=z * x * (1 - c) + y * s; + out[2][1]=y * z * (1 - c) - x * s; + out[2][2]=z * z + c * (1 - z * z); + out[2][3]=0.0f; + out[3][0]=0.0f; + out[3][1]=0.0f; + out[3][2]=0.0f; + out[3][3]=1.0f; +} + +void Matrix4x4_CreateScale( matrix4x4 out, float x ) +{ + out[0][0] = x; + out[0][1] = 0.0f; + out[0][2] = 0.0f; + out[0][3] = 0.0f; + out[1][0] = 0.0f; + out[1][1] = x; + out[1][2] = 0.0f; + out[1][3] = 0.0f; + out[2][0] = 0.0f; + out[2][1] = 0.0f; + out[2][2] = x; + out[2][3] = 0.0f; + out[3][0] = 0.0f; + out[3][1] = 0.0f; + out[3][2] = 0.0f; + out[3][3] = 1.0f; +} + +void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z ) +{ + out[0][0] = x; + out[0][1] = 0.0f; + out[0][2] = 0.0f; + out[0][3] = 0.0f; + out[1][0] = 0.0f; + out[1][1] = y; + out[1][2] = 0.0f; + out[1][3] = 0.0f; + out[2][0] = 0.0f; + out[2][1] = 0.0f; + out[2][2] = z; + out[2][3] = 0.0f; + out[3][0] = 0.0f; + out[3][1] = 0.0f; + out[3][2] = 0.0f; + out[3][3] = 1.0f; +} + +void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z ) +{ + matrix4x4 base, temp; + + Matrix4x4_Copy( base, out ); + Matrix4x4_CreateTranslate( temp, x, y, z ); + Matrix4x4_Concat( out, base, temp ); +} + +void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z ) +{ + matrix4x4 base, temp; + + Matrix4x4_Copy( base, out ); + Matrix4x4_CreateRotate( temp, angle, x, y, z ); + Matrix4x4_Concat( out, base, temp ); +} + +void Matrix4x4_ConcatScale( matrix4x4 out, float x ) +{ + matrix4x4 base, temp; + + Matrix4x4_Copy( base, out ); + Matrix4x4_CreateScale( temp, x ); + Matrix4x4_Concat( out, base, temp ); +} + +void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z ) +{ + matrix4x4 base, temp; + + Matrix4x4_Copy( base, out ); + Matrix4x4_CreateScale3( temp, x, y, z ); + Matrix4x4_Concat( out, base, temp ); +} diff --git a/ref_gu/gu_rmisc.c b/ref_gu/gu_rmisc.c new file mode 100644 index 00000000..3c2bc692 --- /dev/null +++ b/ref_gu/gu_rmisc.c @@ -0,0 +1,190 @@ +/* +gl_rmisc.c - renderer misceallaneous +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "shake.h" +#include "screenfade.h" +#include "cdll_int.h" + +static void R_ParseDetailTextures( const char *filename ) +{ + byte *afile; + char *pfile; + string token, texname; + string detail_texname; + string detail_path; + float xScale, yScale; + texture_t *tex; + int i; + + afile = gEngfuncs.COM_LoadFile( filename, NULL, false ); + if( !afile ) return; + + pfile = (char *)afile; + + // format: 'texturename' 'detailtexture' 'xScale' 'yScale' + while(( pfile = gEngfuncs.COM_ParseFile( pfile, token )) != NULL ) + { + texname[0] = '\0'; + detail_texname[0] = '\0'; + + // read texname + if( token[0] == '{' ) + { + // NOTE: COM_ParseFile handled some symbols seperately + // this code will be fix it + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + Q_strncat( texname, "{", sizeof( texname )); + Q_strncat( texname, token, sizeof( texname )); + } + else Q_strncpy( texname, token, sizeof( texname )); + + // read detailtexture name + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + Q_strncat( detail_texname, token, sizeof( detail_texname )); + + // trying the scales or '{' + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + + // read second part of detailtexture name + if( token[0] == '{' ) + { + Q_strncat( detail_texname, token, sizeof( detail_texname )); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); // read scales + Q_strncat( detail_texname, token, sizeof( detail_texname )); + pfile = gEngfuncs.COM_ParseFile( pfile, token ); // parse scales + } + + Q_snprintf( detail_path, sizeof( detail_path ), "gfx/%s", detail_texname ); + + // read scales + xScale = Q_atof( token ); + + pfile = gEngfuncs.COM_ParseFile( pfile, token ); + yScale = Q_atof( token ); + + if( xScale <= 0.0f || yScale <= 0.0f ) + continue; + + // search for existing texture and uploading detail texture + for( i = 0; i < WORLDMODEL->numtextures; i++ ) + { + tex = WORLDMODEL->textures[i]; + + if( Q_stricmp( tex->name, texname )) + continue; + + tex->dt_texturenum = GL_LoadTexture( detail_path, NULL, 0, TF_FORCE_COLOR ); + + // texture is loaded + if( tex->dt_texturenum ) + { + gl_texture_t *glt; + + glt = R_GetTexture( tex->gl_texturenum ); + glt->xscale = xScale; + glt->yscale = yScale; + } + break; + } + } + + Mem_Free( afile ); +} + +void R_NewMap( void ) +{ + texture_t *tx; + int i; + + R_ClearDecals(); // clear all level decals + + R_StudioResetPlayerModels(); + + // upload detailtextures + if( CVAR_TO_BOOL( r_detailtextures )) + { + string mapname, filepath; + + Q_strncpy( mapname, WORLDMODEL->name, sizeof( mapname )); + COM_StripExtension( mapname ); + Q_sprintf( filepath, "%s_detail.txt", mapname ); + + R_ParseDetailTextures( filepath ); + } + + if( gEngfuncs.pfnGetCvarFloat( "v_dark" )) + { + screenfade_t *sf = gEngfuncs.GetScreenFade(); + float fadetime = 5.0f; + client_textmessage_t *title; + + title = gEngfuncs.pfnTextMessageGet( "GAMETITLE" ); + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + fadetime = 1.0f; + + if( title ) + { + // get settings from titles.txt + sf->fadeEnd = title->holdtime + title->fadeout; + sf->fadeReset = title->fadeout; + } + else sf->fadeEnd = sf->fadeReset = fadetime; + + sf->fadeFlags = FFADE_IN; + sf->fader = sf->fadeg = sf->fadeb = 0; + sf->fadealpha = 255; + sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset; + sf->fadeReset += gpGlobals->time; + sf->fadeEnd += sf->fadeReset; + + gEngfuncs.Cvar_SetValue( "v_dark", 0.0f ); + } + + // clear out efrags in case the level hasn't been reloaded + for( i = 0; i < WORLDMODEL->numleafs; i++ ) + WORLDMODEL->leafs[i+1].efrags = NULL; + + glState.isFogEnabled = false; + tr.skytexturenum = -1; +#if 1 + sceGuDisable( GU_FOG ); +#else + pglDisable( GL_FOG ); +#endif + // clearing texture chains + for( i = 0; i < WORLDMODEL->numtextures; i++ ) + { + if( !WORLDMODEL->textures[i] ) + continue; + + tx = WORLDMODEL->textures[i]; + + if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == ( tx->height * 2 )) + tr.skytexturenum = i; + + tx->texturechain = NULL; + } + + R_SetupSky( MOVEVARS->skyName ); + + GL_BuildLightmaps (); +#if 0 + R_GenerateVBO(); +#endif + if( gEngfuncs.drawFuncs->R_NewMap != NULL ) + gEngfuncs.drawFuncs->R_NewMap(); + +} diff --git a/ref_gu/gu_rpart.c b/ref_gu/gu_rpart.c new file mode 100644 index 00000000..095ebea2 --- /dev/null +++ b/ref_gu/gu_rpart.c @@ -0,0 +1,405 @@ +/* +gu_rpart.c - particles and tracers +Copyright (C) 2010 Uncle Mike +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "r_efx.h" +#include "event_flags.h" +#include "entity_types.h" +#include "triangleapi.h" +#include "pm_local.h" +#include "cl_tent.h" +#include "studio.h" + +static float gTracerSize[11] = { 1.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; +static color24 gTracerColors[] = +{ +{ 255, 255, 255 }, // White +{ 255, 0, 0 }, // Red +{ 0, 255, 0 }, // Green +{ 0, 0, 255 }, // Blue +{ 0, 0, 0 }, // Tracer default, filled in from cvars, etc. +{ 255, 167, 17 }, // Yellow-orange sparks +{ 255, 130, 90 }, // Yellowish streaks (garg) +{ 55, 60, 144 }, // Blue egon streak +{ 255, 130, 90 }, // More Yellowish streaks (garg) +{ 255, 140, 90 }, // More Yellowish streaks (garg) +{ 200, 130, 90 }, // More red streaks (garg) +{ 255, 120, 70 }, // Darker red streaks (garg) +}; + +/* +================ +CL_DrawParticles + +update particle color, position, free expired and draw it +================ +*/ +void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float partsize ) +{ + particle_t *p; + vec3_t right, up; + color24 *pColor; + int alpha; + float size; + + if( !cl_active_particles ) + return; // nothing to draw? +#if 1 + sceGuEnable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + + GL_Bind( XASH_TEXTURE0, tr.particleTexture ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuDepthMask( GU_TRUE ); + + for( p = cl_active_particles; p; p = p->next ) + { + if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + { + size = partsize; // get initial size of particle + + // scale up to keep particles from disappearing + size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0]; + size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1]; + size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2]; + + if( size < 20.0f ) size = partsize; + else size = partsize + size * 0.002f; + + // scale the axes by radius + VectorScale( RI.cull_vright, size, right ); + VectorScale( RI.cull_vup, size, up ); + + p->color = bound( 0, p->color, 255 ); + pColor = gEngfuncs.CL_GetPaletteColor( p->color ); + + alpha = 255 * (p->die - gpGlobals->time) * 16.0f; + if( alpha > 255 || p->type == pt_static ) + alpha = 255; + + sceGuColor( GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), + gEngfuncs.LightToTexGamma( pColor->g ), + gEngfuncs.LightToTexGamma( pColor->b ), alpha ) ); + + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )sceGuGetMemory( sizeof( gu_vert_ftv_t ) * 4 ); + + out[0].u = 0.0f; + out[0].v = 1.0f; + out[0].x = p->org[0] - right[0] + up[0]; + out[0].y = p->org[1] - right[1] + up[1]; + out[0].z = p->org[2] - right[2] + up[2]; + out[1].u = 0.0f; + out[1].v = 0.0f; + out[1].x = p->org[0] + right[0] + up[0]; + out[1].y = p->org[1] + right[1] + up[1]; + out[1].z = p->org[2] + right[2] + up[2]; + out[2].u = 1.0f; + out[2].v = 0.0f; + out[2].x = p->org[0] + right[0] - up[0]; + out[2].y = p->org[1] + right[1] - up[1]; + out[2].z = p->org[2] + right[2] - up[2]; + out[3].u = 1.0f; + out[3].v = 1.0f; + out[3].x = p->org[0] - right[0] - up[0]; + out[3].y = p->org[1] - right[1] - up[1]; + out[3].z = p->org[2] - right[2] - up[2]; + + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); + + r_stats.c_particle_count++; + } + + gEngfuncs.CL_ThinkParticle( frametime, p ); + } + + sceGuDepthMask( GU_FALSE ); +#else + pglEnable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + GL_Bind( XASH_TEXTURE0, tr.particleTexture ); + pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglDepthMask( GL_FALSE ); + + pglBegin( GL_QUADS ); + + for( p = cl_active_particles; p; p = p->next ) + { + if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + { + size = partsize; // get initial size of particle + + // scale up to keep particles from disappearing + size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0]; + size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1]; + size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2]; + + if( size < 20.0f ) size = partsize; + else size = partsize + size * 0.002f; + + // scale the axes by radius + VectorScale( RI.cull_vright, size, right ); + VectorScale( RI.cull_vup, size, up ); + + p->color = bound( 0, p->color, 255 ); + pColor = gEngfuncs.CL_GetPaletteColor( p->color ); + + alpha = 255 * (p->die - gpGlobals->time) * 16.0f; + if( alpha > 255 || p->type == pt_static ) + alpha = 255; + + pglColor4ub( gEngfuncs.LightToTexGamma( pColor->r ), + gEngfuncs.LightToTexGamma( pColor->g ), + gEngfuncs.LightToTexGamma( pColor->b ), alpha ); + + pglTexCoord2f( 0.0f, 1.0f ); + pglVertex3f( p->org[0] - right[0] + up[0], p->org[1] - right[1] + up[1], p->org[2] - right[2] + up[2] ); + pglTexCoord2f( 0.0f, 0.0f ); + pglVertex3f( p->org[0] + right[0] + up[0], p->org[1] + right[1] + up[1], p->org[2] + right[2] + up[2] ); + pglTexCoord2f( 1.0f, 0.0f ); + pglVertex3f( p->org[0] + right[0] - up[0], p->org[1] + right[1] - up[1], p->org[2] + right[2] - up[2] ); + pglTexCoord2f( 1.0f, 1.0f ); + pglVertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] ); + r_stats.c_particle_count++; + } + + gEngfuncs.CL_ThinkParticle( frametime, p ); + } + + pglEnd(); + pglDepthMask( GL_TRUE ); +#endif +} + +/* +================ +CL_CullTracer + +check tracer bbox +================ +*/ +static qboolean CL_CullTracer( particle_t *p, const vec3_t start, const vec3_t end ) +{ + vec3_t mins, maxs; + int i; + + // compute the bounding box + for( i = 0; i < 3; i++ ) + { + if( start[i] < end[i] ) + { + mins[i] = start[i]; + maxs[i] = end[i]; + } + else + { + mins[i] = end[i]; + maxs[i] = start[i]; + } + + // don't let it be zero sized + if( mins[i] == maxs[i] ) + { + maxs[i] += gTracerSize[p->type] * 2.0f; + } + } + + // check bbox + return R_CullBox( mins, maxs ); +} + +/* +================ +CL_DrawTracers + +update tracer color, position, free expired and draw it +================ +*/ +void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) +{ + float scale, atten, gravity; + vec3_t screenLast, screen; + vec3_t start, end, delta; + particle_t *p; + + // update tracer color if this is changed + if( FBitSet( tracerred->flags|tracergreen->flags|tracerblue->flags|traceralpha->flags, FCVAR_CHANGED )) + { + color24 *customColors = &gTracerColors[4]; + customColors->r = (byte)(tracerred->value * traceralpha->value * 255); + customColors->g = (byte)(tracergreen->value * traceralpha->value * 255); + customColors->b = (byte)(tracerblue->value * traceralpha->value * 255); + ClearBits( tracerred->flags, FCVAR_CHANGED ); + ClearBits( tracergreen->flags, FCVAR_CHANGED ); + ClearBits( tracerblue->flags, FCVAR_CHANGED ); + ClearBits( traceralpha->flags, FCVAR_CHANGED ); + } + + if( !cl_active_tracers ) + return; // nothing to draw? + + if( !TriSpriteTexture( gEngfuncs.GetDefaultSprite( REF_DOT_SPRITE ), 0 )) + return; +#if 1 + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuDepthMask( GU_TRUE ); +#else + pglEnable( GL_BLEND ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); + pglDisable( GL_ALPHA_TEST ); + pglDepthMask( GL_FALSE ); +#endif + gravity = frametime * MOVEVARS->gravity; + scale = 1.0 - (frametime * 0.9); + if( scale < 0.0f ) scale = 0.0f; + + for( p = cl_active_tracers; p; p = p->next ) + { + atten = (p->die - gpGlobals->time); + if( atten > 0.1f ) atten = 0.1f; + + VectorScale( p->vel, ( p->ramp * atten ), delta ); + VectorAdd( p->org, delta, end ); + VectorCopy( p->org, start ); + + if( !CL_CullTracer( p, start, end )) + { + vec3_t verts[4], tmp2; + vec3_t tmp, normal; + color24 *pColor; + + // Transform point into screen space + TriWorldToScreen( start, screen ); + TriWorldToScreen( end, screenLast ); + + // build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + + // build point along noraml line (normal is -y, x) + VectorScale( RI.cull_vup, tmp[0] * gTracerSize[p->type], normal ); + VectorScale( RI.cull_vright, -tmp[1] * gTracerSize[p->type], tmp2 ); + VectorSubtract( normal, tmp2, normal ); + + // compute four vertexes + VectorSubtract( start, normal, verts[0] ); + VectorAdd( start, normal, verts[1] ); + VectorAdd( verts[0], delta, verts[2] ); + VectorAdd( verts[1], delta, verts[3] ); + + if( p->color > sizeof( gTracerColors ) / sizeof( color24 ) ) + { + gEngfuncs.Con_Printf( S_ERROR "UserTracer with color > %d\n", sizeof( gTracerColors ) / sizeof( color24 )); + p->color = 0; + } + + pColor = &gTracerColors[p->color]; +#if 1 + sceGuColor( GUCOLOR4UB( pColor->r, pColor->g, pColor->b, p->packedColor ) ); + + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )sceGuGetMemory( sizeof( gu_vert_ftv_t ) * 4 ); + + out[0].u = 0.0f; + out[0].v = 0.8f; + out[0].x = verts[2][0]; + out[0].y = verts[2][1]; + out[0].z = verts[2][2]; + out[1].u = 1.0f; + out[1].v = 0.8f; + out[1].x = verts[3][0]; + out[1].y = verts[3][1]; + out[1].z = verts[3][2]; + out[2].u = 1.0f; + out[2].v = 0.0f; + out[2].x = verts[1][0]; + out[2].y = verts[1][1]; + out[2].z = verts[1][2]; + out[3].u = 0.0f; + out[3].v = 0.0f; + out[3].x = verts[0][0]; + out[3].y = verts[0][1]; + out[3].z = verts[0][2]; + + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); +#else + pglColor4ub( pColor->r, pColor->g, pColor->b, p->packedColor ); + + pglBegin( GL_QUADS ); + pglTexCoord2f( 0.0f, 0.8f ); + pglVertex3fv( verts[2] ); + pglTexCoord2f( 1.0f, 0.8f ); + pglVertex3fv( verts[3] ); + pglTexCoord2f( 1.0f, 0.0f ); + pglVertex3fv( verts[1] ); + pglTexCoord2f( 0.0f, 0.0f ); + pglVertex3fv( verts[0] ); + pglEnd(); +#endif + } + + // evaluate position + VectorMA( p->org, frametime, p->vel, p->org ); + + if( p->type == pt_grav ) + { + p->vel[0] *= scale; + p->vel[1] *= scale; + p->vel[2] -= gravity; + + p->packedColor = 255 * (p->die - gpGlobals->time) * 2; + if( p->packedColor > 255 ) p->packedColor = 255; + } + else if( p->type == pt_slowgrav ) + { + p->vel[2] = gravity * 0.05f; + } + } +#if 1 + sceGuDepthMask( GU_FALSE ); +#else + pglDepthMask( GL_TRUE ); +#endif +} + +/* +=============== +CL_DrawParticlesExternal + +allow to draw effects from custom renderer +=============== +*/ +void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime ) +{ + ref_instance_t oldRI = RI; + + memcpy( &oldRI, &RI, sizeof( ref_instance_t )); + R_SetupRefParams( rvp ); + R_SetupFrustum(); + R_SetupGL( false ); // don't touch GL-states + tr.frametime = frametime; + + gEngfuncs.CL_DrawEFX( frametime, trans_pass ); + + // restore internal state + memcpy( &RI, &oldRI, sizeof( ref_instance_t )); +} diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c new file mode 100644 index 00000000..c546a707 --- /dev/null +++ b/ref_gu/gu_rsurf.c @@ -0,0 +1,2352 @@ +/* +gu_rsurf.c - surface-related refresh code +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "xash3d_mathlib.h" +#include "mod_local.h" + +typedef struct +{ + int allocated[BLOCK_SIZE_MAX]; + int current_lightmap_texture; + msurface_t *dynamic_surfaces; + msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; + byte lightmap_buffer[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; +} gllightmapstate_t; + +static int nColinElim; // stats +static vec2_t world_orthocenter; +static vec2_t world_orthohalf; +static uint r_blocklights[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*3]; +static mextrasurf_t *fullbright_surfaces[MAX_TEXTURES]; +static mextrasurf_t *detail_surfaces[MAX_TEXTURES]; +static int rtable[MOD_FRAMES][MOD_FRAMES]; +static qboolean draw_alpha_surfaces = false; +static qboolean draw_fullbrights = false; +static qboolean draw_details = false; +static msurface_t *skychain = NULL; +static gllightmapstate_t gl_lms; +static void LM_UploadBlock( qboolean dynamic ); + +byte *Mod_GetCurrentVis( void ) +{ + if( gEngfuncs.drawFuncs->Mod_GetCurrentVis && tr.fCustomRendering ) + return gEngfuncs.drawFuncs->Mod_GetCurrentVis(); + return RI.visbytes; +} + +void Mod_SetOrthoBounds( const float *mins, const float *maxs ) +{ + if( gEngfuncs.drawFuncs->GL_OrthoBounds ) + { + gEngfuncs.drawFuncs->GL_OrthoBounds( mins, maxs ); + } + + Vector2Average( maxs, mins, world_orthocenter ); + Vector2Subtract( maxs, world_orthocenter, world_orthohalf ); +} + +static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs ) +{ + int i, j; + float *v; + + ClearBounds( mins, maxs ); + + for( i = 0, v = verts; i < numverts; i++ ) + { + for( j = 0; j < 3; j++, v++ ) + { + if( *v < mins[j] ) mins[j] = *v; + if( *v > maxs[j] ) maxs[j] = *v; + } + } +} + +static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts ) +{ + vec3_t front[SUBDIVIDE_SIZE], back[SUBDIVIDE_SIZE]; + mextrasurf_t *warpinfo = warpface->info; + float dist[SUBDIVIDE_SIZE]; + float m, frac, s, t, *v; + int i, j, k, f, b; + float sample_size; + vec3_t mins, maxs; + glpoly_t *poly; + model_t *loadmodel = gEngfuncs.Mod_GetCurrentLoadingModel(); + + if( numverts > ( SUBDIVIDE_SIZE - 4 )) + gEngfuncs.Host_Error( "Mod_SubdividePolygon: too many vertexes on face ( %i )\n", numverts ); + + sample_size = gEngfuncs.Mod_SampleSizeForFace( warpface ); + BoundPoly( numverts, verts, mins, maxs ); + + for( i = 0; i < 3; i++ ) + { + m = ( mins[i] + maxs[i] ) * 0.5f; + m = gl_subdivide_size->value * floor( m / gl_subdivide_size->value + 0.5f ); + if( maxs[i] - m < 8 ) continue; + if( m - mins[i] < 8 ) continue; + + // cut it + v = verts + i; + for( j = 0; j < numverts; j++, v += 3 ) + dist[j] = *v - m; + + // wrap cases + dist[j] = dist[0]; + v -= i; + VectorCopy( verts, v ); + + f = b = 0; + v = verts; + for( j = 0; j < numverts; j++, v += 3 ) + { + if( dist[j] >= 0 ) + { + VectorCopy( v, front[f] ); + f++; + } + + if( dist[j] <= 0 ) + { + VectorCopy (v, back[b]); + b++; + } + + if( dist[j] == 0 || dist[j+1] == 0 ) + continue; + + if(( dist[j] > 0 ) != ( dist[j+1] > 0 )) + { + // clip point + frac = dist[j] / ( dist[j] - dist[j+1] ); + for( k = 0; k < 3; k++ ) + front[f][k] = back[b][k] = v[k] + frac * (v[3+k] - v[k]); + f++; + b++; + } + } + + SubdividePolygon_r( warpface, f, front[0] ); + SubdividePolygon_r( warpface, b, back[0] ); + return; + } + + if( numverts != 4 ) + ClearBits( warpface->flags, SURF_DRAWTURB_QUADS ); + + // add a point in the center to help keep warp valid + poly = Mem_Calloc( loadmodel->mempool, sizeof( glpoly_t ) + ( numverts * 2 - 1 ) * sizeof( gu_vert_t ) ); + poly->next = warpface->polys; + poly->flags = warpface->flags; + warpface->polys = poly; + poly->numverts = numverts; + + for( i = 0; i < numverts; i++, verts += 3 ) + { + if( FBitSet( warpface->flags, SURF_DRAWTURB )) + { + s = DotProduct( verts, warpface->texinfo->vecs[0] ); + t = DotProduct( verts, warpface->texinfo->vecs[1] ); + } + else + { + s = DotProduct( verts, warpface->texinfo->vecs[0] ) + warpface->texinfo->vecs[0][3]; + t = DotProduct( verts, warpface->texinfo->vecs[1] ) + warpface->texinfo->vecs[1][3]; + s /= warpface->texinfo->texture->width; + t /= warpface->texinfo->texture->height; + } + + poly->verts[i].uv[0] = s; + poly->verts[i].uv[1] = t; + VectorCopy( verts, poly->verts[i].xyz ); + + // for speed reasons + if( !FBitSet( warpface->flags, SURF_DRAWTURB )) + { + // lightmap texture coordinates + s = DotProduct( verts, warpinfo->lmvecs[0] ) + warpinfo->lmvecs[0][3]; + s -= warpinfo->lightmapmins[0]; + s += warpface->light_s * sample_size; + s += sample_size * 0.5f; + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width; + + t = DotProduct( verts, warpinfo->lmvecs[1] ) + warpinfo->lmvecs[1][3]; + t -= warpinfo->lightmapmins[1]; + t += warpface->light_t * sample_size; + t += sample_size * 0.5f; + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height; + + poly->verts[i + numverts].uv[0] = s; + poly->verts[i + numverts].uv[1] = t; + VectorCopy( verts, poly->verts[i + numverts].xyz ); + } + } +} + +void GL_SetupFogColorForSurfaces( void ) +{ + vec3_t fogColor; + float factor, div; + + if( !glState.isFogEnabled) + return; + + if( RI.currententity && RI.currententity->curstate.rendermode == kRenderTransTexture ) + { +#if 1 + glState.fogColor = GUCOLOR4F( RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], glState.fogDensity ); + sceGuFog( glState.fogStart, glState.fogEnd, glState.fogColor ); +#else + pglFogfv( GL_FOG_COLOR, RI.fogColor ); +#endif + return; + } + + div = (r_detailtextures->value) ? 2.0f : 1.0f; + factor = (r_detailtextures->value) ? 3.0f : 2.0f; + fogColor[0] = pow( RI.fogColor[0] / div, ( 1.0f / factor )); + fogColor[1] = pow( RI.fogColor[1] / div, ( 1.0f / factor )); + fogColor[2] = pow( RI.fogColor[2] / div, ( 1.0f / factor )); +#if 1 + glState.fogColor = GUCOLOR4F( fogColor[0], fogColor[1], fogColor[2], glState.fogDensity ); + sceGuFog( glState.fogStart, glState.fogEnd, glState.fogColor ); +#else + pglFogfv( GL_FOG_COLOR, fogColor ); +#endif +} + +void GL_ResetFogColor( void ) +{ + // restore fog here +#if 1 + if( !glState.isFogEnabled ) + return; + + glState.fogColor = GUCOLOR4F( RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], glState.fogDensity ); + sceGuFog( glState.fogStart, glState.fogEnd, glState.fogColor ); +#else + if( glState.isFogEnabled ) + pglFogfv( GL_FOG_COLOR, RI.fogColor ); +#endif +} + +/* +================ +GL_SubdivideSurface + +Breaks a polygon up along axial 64 unit +boundaries so that turbulent and sky warps +can be done reasonably. +================ +*/ +void GL_SubdivideSurface( msurface_t *fa ) +{ + vec3_t verts[SUBDIVIDE_SIZE]; + int numverts; + int i, lindex; + float *vec; + model_t *loadmodel = gEngfuncs.Mod_GetCurrentLoadingModel(); + + // convert edges back to a normal polygon + numverts = 0; + for( i = 0; i < fa->numedges; i++ ) + { + lindex = loadmodel->surfedges[fa->firstedge + i]; + + if( lindex > 0 ) vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + else vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + VectorCopy( vec, verts[numverts] ); + numverts++; + } + + SetBits( fa->flags, SURF_DRAWTURB_QUADS ); // predict state + + // do subdivide + SubdividePolygon_r( fa, numverts, verts[0] ); +} + +/* +================ +GL_BuildPolygonFromSurface +================ +*/ +void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa ) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + mextrasurf_t *info = fa->info; + float sample_size; + texture_t *tex; + gl_texture_t *glt; + float *vec; + float s, t; + glpoly_t *poly; + int num_removed = 0; + + if( !mod || !fa->texinfo || !fa->texinfo->texture ) + return; // bad polygon ? + + if( FBitSet( fa->flags, SURF_CONVEYOR ) && fa->texinfo->texture->gl_texturenum != 0 ) + { + glt = R_GetTexture( fa->texinfo->texture->gl_texturenum ); + tex = fa->texinfo->texture; + Assert( glt != NULL && tex != NULL ); + + // update conveyor widths for keep properly speed of scrolling + glt->srcWidth = tex->width; + glt->srcHeight = tex->height; + } + + sample_size = gEngfuncs.Mod_SampleSizeForFace( fa ); + + // reconstruct the polygon + pedges = mod->edges; + lnumverts = fa->numedges; + + // detach if already created, reconstruct again + poly = fa->polys; + fa->polys = NULL; + + // quake simple models (healthkits etc) need to be reconstructed their polys because LM coords has changed after the map change + // PSP GU-friendly format s1t1 xyz s2t2 xyz (Idea from PSP Quake) + poly = Mem_Realloc( mod->mempool, poly, sizeof( glpoly_t ) + ( lnumverts * 2 - 1 ) * sizeof( gu_vert_t )); + poly->next = fa->polys; + poly->flags = fa->flags; + fa->polys = poly; + poly->numverts = lnumverts; + + for( i = 0; i < lnumverts; i++ ) + { + lindex = mod->surfedges[fa->firstedge + i]; + + if( lindex > 0 ) + { + r_pedge = &pedges[lindex]; + vec = mod->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = mod->vertexes[r_pedge->v[1]].position; + } + + s = DotProduct( vec, fa->texinfo->vecs[0] ) + fa->texinfo->vecs[0][3]; + s /= fa->texinfo->texture->width; + + t = DotProduct( vec, fa->texinfo->vecs[1] ) + fa->texinfo->vecs[1][3]; + t /= fa->texinfo->texture->height; + + poly->verts[i].uv[0] = s; + poly->verts[i].uv[1] = t; + VectorCopy( vec, poly->verts[i].xyz ); + + // lightmap texture coordinates + s = DotProduct( vec, info->lmvecs[0] ) + info->lmvecs[0][3]; + s -= info->lightmapmins[0]; + s += fa->light_s * sample_size; + s += sample_size * 0.5f; + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width; + + t = DotProduct( vec, info->lmvecs[1] ) + info->lmvecs[1][3]; + t -= info->lightmapmins[1]; + t += fa->light_t * sample_size; + t += sample_size * 0.5f; + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height; + + poly->verts[i + poly->numverts].uv[0] = s; + poly->verts[i + poly->numverts].uv[1] = t; + VectorCopy( vec, poly->verts[i + poly->numverts].xyz ); + } + + // remove co-linear points - Ed + if( !CVAR_TO_BOOL( gl_keeptjunctions ) && !FBitSet( fa->flags, SURF_UNDERWATER )) + { + for( i = 0; i < lnumverts; i++ ) + { + vec3_t v1, v2; + gu_vert_t *prev, *this, *next; + + prev = &poly->verts[(i + lnumverts - 1) % lnumverts]; + next = &poly->verts[(i + 1) % lnumverts]; + this = &poly->verts[i]; + + VectorSubtract( this->xyz, prev->xyz, v1 ); + VectorNormalize( v1 ); + VectorSubtract( next->xyz, prev->xyz, v2 ); + VectorNormalize( v2 ); + + // skip co-linear points + if(( fabs( v1[0] - v2[0] ) <= 0.001f) && (fabs( v1[1] - v2[1] ) <= 0.001f) && (fabs( v1[2] - v2[2] ) <= 0.001f)) + { + int j, k; + + for( j = i + 1; j < lnumverts; j++ ) + { + poly->verts[j - 1] = poly->verts[j]; + poly->verts[poly->numverts + j - 1] = poly->verts[poly->numverts + j]; + } + + // retry next vertex next time, which is now current vertex + lnumverts--; + nColinElim++; + num_removed++; + i--; + } + } + + if (num_removed > 0) + { + for (i = poly->numverts; i < poly->numverts + lnumverts; i++) + poly->verts[i - num_removed] = poly->verts[i]; + } + } + + poly->numverts = lnumverts; +} + + +/* +=============== +R_TextureAnim + +Returns the proper texture for a given time and base texture, do not process random tiling +=============== +*/ +texture_t *R_TextureAnim( texture_t *b ) +{ + texture_t *base = b; + int count, reletive; + + if( RI.currententity->curstate.frame ) + { + if( base->alternate_anims ) + base = base->alternate_anims; + } + + if( !base->anim_total ) + return base; + if( base->name[0] == '-' ) + { + return b; // already tiled + } + else + { + int speed; + + // Quake1 textures uses 10 frames per second + if( FBitSet( R_GetTexture( base->gl_texturenum )->flags, TF_QUAKEPAL )) + speed = 10; + else speed = 20; + + reletive = (int)(gpGlobals->time * speed) % base->anim_total; + } + + + count = 0; + + while( base->anim_min > reletive || base->anim_max <= reletive ) + { + base = base->anim_next; + + if( !base || ++count > MOD_FRAMES ) + return b; + } + + return base; +} + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and surface +=============== +*/ +texture_t *R_TextureAnimation( msurface_t *s ) +{ + texture_t *base = s->texinfo->texture; + int count, reletive; + + if( RI.currententity && RI.currententity->curstate.frame ) + { + if( base->alternate_anims ) + base = base->alternate_anims; + } + + if( !base->anim_total ) + return base; + + if( base->name[0] == '-' ) + { + int tx = (int)((s->texturemins[0] + (base->width << 16)) / base->width) % MOD_FRAMES; + int ty = (int)((s->texturemins[1] + (base->height << 16)) / base->height) % MOD_FRAMES; + + reletive = rtable[tx][ty] % base->anim_total; + } + else + { + int speed; + + // Quake1 textures uses 10 frames per second + if( FBitSet( R_GetTexture( base->gl_texturenum )->flags, TF_QUAKEPAL )) + speed = 10; + else speed = 20; + + reletive = (int)(gpGlobals->time * speed) % base->anim_total; + } + + count = 0; + + while( base->anim_min > reletive || base->anim_max <= reletive ) + { + base = base->anim_next; + + if( !base || ++count > MOD_FRAMES ) + return s->texinfo->texture; + } + + return base; +} + +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights( msurface_t *surf ) +{ + float dist, rad, minlight; + int lnum, s, t, sd, td, smax, tmax; + float sl, tl, sacc, tacc; + vec3_t impact, origin_l; + mextrasurf_t *info = surf->info; + int sample_frac = 1.0; + float sample_size; + mtexinfo_t *tex; + dlight_t *dl; + uint *bl; + + // no dlighted surfaces here + if( !R_CountSurfaceDlights( surf )) return; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + smax = (info->lightextents[0] / sample_size) + 1; + tmax = (info->lightextents[1] / sample_size) + 1; + tex = surf->texinfo; + + if( FBitSet( tex->flags, TEX_WORLD_LUXELS )) + { + if( surf->texinfo->faceinfo ) + sample_frac = surf->texinfo->faceinfo->texture_step; + else if( FBitSet( surf->texinfo->flags, TEX_EXTRA_LIGHTMAP )) + sample_frac = LM_SAMPLE_EXTRASIZE; + else sample_frac = LM_SAMPLE_SIZE; + } + + for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + { + if( !FBitSet( surf->dlightbits, BIT( lnum ))) + continue; // not lit by this light + + dl = gEngfuncs.GetDynamicLight( lnum ); + + // transform light origin to local bmodel space + if( !tr.modelviewIdentity ) + Matrix4x4_VectorITransform( RI.objectMatrix, dl->origin, origin_l ); + else VectorCopy( dl->origin, origin_l ); + + rad = dl->radius; + dist = PlaneDiff( origin_l, surf->plane ); + rad -= fabs( dist ); + + // rad is now the highest intensity on the plane + minlight = dl->minlight; + if( rad < minlight ) + continue; + + minlight = rad - minlight; + + if( surf->plane->type < 3 ) + { + VectorCopy( origin_l, impact ); + impact[surf->plane->type] -= dist; + } + else VectorMA( origin_l, -dist, surf->plane->normal, impact ); + + sl = DotProduct( impact, info->lmvecs[0] ) + info->lmvecs[0][3] - info->lightmapmins[0]; + tl = DotProduct( impact, info->lmvecs[1] ) + info->lmvecs[1][3] - info->lightmapmins[1]; + bl = r_blocklights; + + for( t = 0, tacc = 0; t < tmax; t++, tacc += sample_size ) + { + td = (tl - tacc) * sample_frac; + if( td < 0 ) td = -td; + + for( s = 0, sacc = 0; s < smax; s++, sacc += sample_size, bl += 3 ) + { + sd = (sl - sacc) * sample_frac; + if( sd < 0 ) sd = -sd; + + if( sd > td ) dist = sd + (td >> 1); + else dist = td + (sd >> 1); + + if( dist < minlight ) + { + bl[0] += ((int)((rad - dist) * 256) * gEngfuncs.LightToTexGamma( dl->color.r )) / 256; + bl[1] += ((int)((rad - dist) * 256) * gEngfuncs.LightToTexGamma( dl->color.g )) / 256; + bl[2] += ((int)((rad - dist) * 256) * gEngfuncs.LightToTexGamma( dl->color.b )) / 256; + } + } + } + } +} + +/* +================ +R_SetCacheState +================ +*/ +void R_SetCacheState( msurface_t *surf ) +{ + int maps; + + for( maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++ ) + { + surf->cached_light[maps] = tr.lightstylevalue[surf->styles[maps]]; + } +} + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ +static void LM_InitBlock( void ) +{ + memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated )); +} + +static int LM_AllocBlock( int w, int h, int *x, int *y ) +{ + int i, j; + int best, best2; + + best = BLOCK_SIZE; + + for( i = 0; i < BLOCK_SIZE - w; i++ ) + { + best2 = 0; + + for( j = 0; j < w; j++ ) + { + if( gl_lms.allocated[i+j] >= best ) + break; + if( gl_lms.allocated[i+j] > best2 ) + best2 = gl_lms.allocated[i+j]; + } + + if( j == w ) + { + // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if( best + h > BLOCK_SIZE ) + return false; + + for( i = 0; i < w; i++ ) + gl_lms.allocated[*x + i] = best + h; + + return true; +} + +static void LM_UploadBlock( qboolean dynamic ) +{ + int i; + + if( dynamic ) + { + int height = 0; + + for( i = 0; i < BLOCK_SIZE; i++ ) + { + if( gl_lms.allocated[i] > height ) + height = gl_lms.allocated[i]; + } + + GL_UpdateDlightTexture( tr.dlightTexture, 0, 0, BLOCK_SIZE, height, gl_lms.lightmap_buffer ); + GL_Bind( XASH_TEXTURE0, tr.dlightTexture ); + } + else + { + rgbdata_t r_lightmap; + char lmName[16]; + + i = gl_lms.current_lightmap_texture; + + // upload static lightmaps only during loading + memset( &r_lightmap, 0, sizeof( r_lightmap )); + Q_snprintf( lmName, sizeof( lmName ), "*lightmap%i", i ); + + r_lightmap.width = BLOCK_SIZE; + r_lightmap.height = BLOCK_SIZE; + r_lightmap.type = PF_RGBA_32; + r_lightmap.size = r_lightmap.width * r_lightmap.height * 4; + r_lightmap.flags = IMAGE_HAS_COLOR; + r_lightmap.buffer = gl_lms.lightmap_buffer; + tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE ); + + if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS ) + gEngfuncs.Host_Error( "AllocBlock: full\n" ); + } +} + +/* +================= +R_BuildLightmap + +Combine and scale multiple lightmaps into the floating +format in r_blocklights +================= +*/ +static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean dynamic ) +{ + int smax, tmax; + uint *bl, scale; + int i, map, size, s, t; + int sample_size; + mextrasurf_t *info = surf->info; + color24 *lm; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + smax = ( info->lightextents[0] / sample_size ) + 1; + tmax = ( info->lightextents[1] / sample_size ) + 1; + size = smax * tmax; + + lm = surf->samples; + + memset( r_blocklights, 0, sizeof( uint ) * size * 3 ); + + // add all the lightmaps + for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255 && lm; map++ ) + { + scale = tr.lightstylevalue[surf->styles[map]]; + + for( i = 0, bl = r_blocklights; i < size; i++, bl += 3, lm++ ) + { + bl[0] += gEngfuncs.LightToTexGamma( lm->r ) * scale; + bl[1] += gEngfuncs.LightToTexGamma( lm->g ) * scale; + bl[2] += gEngfuncs.LightToTexGamma( lm->b ) * scale; + } + } + + // add all the dynamic lights + if( surf->dlightframe == tr.framecount && dynamic ) + R_AddDynamicLights( surf ); + + // Put into texture format + stride -= (smax << 2); + bl = r_blocklights; + + for( t = 0; t < tmax; t++, dest += stride ) + { + for( s = 0; s < smax; s++ ) + { + dest[0] = Q_min((bl[0] >> 7), 255 ); + dest[1] = Q_min((bl[1] >> 7), 255 ); + dest[2] = Q_min((bl[2] >> 7), 255 ); + dest[3] = 255; + + bl += 3; + dest += 4; + } + } +} + +/* +================ +DrawGLPoly +================ +*/ +void DrawGLPoly( glpoly_t *p, float xScale, float yScale ) +{ + float *v; + float sOffset, sy; + float tOffset, cy; + cl_entity_t *e = RI.currententity; + int i; + qboolean hasScale = false; + qboolean hasOffset = false; + + if( !p ) return; + + if( FBitSet( p->flags, SURF_DRAWTILED )) + GL_ResetFogColor(); + + if( p->flags & SURF_CONVEYOR ) + { + float flConveyorSpeed = 0.0f; + float flRate, flAngle; + gl_texture_t *texture; + + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && RI.currententity == gEngfuncs.GetEntityByIndex( 0 ) ) + { + // same as doom speed + flConveyorSpeed = -35.0f; + } + else + { + flConveyorSpeed = (e->curstate.rendercolor.g<<8|e->curstate.rendercolor.b) / 16.0f; + if( e->curstate.rendercolor.r ) flConveyorSpeed = -flConveyorSpeed; + } + + texture = R_GetTexture( glState.currentTexture ); + + flRate = fabs( flConveyorSpeed ) / (float)texture->srcWidth; + flAngle = ( flConveyorSpeed >= 0 ) ? 180 : 0; + + SinCos( flAngle * ( M_PI_F / 180.0f ), &sy, &cy ); + sOffset = gpGlobals->time * cy * flRate; + tOffset = gpGlobals->time * sy * flRate; + + // make sure that we are positive + if( sOffset < 0.0f ) sOffset += 1.0f + -(int)sOffset; + if( tOffset < 0.0f ) tOffset += 1.0f + -(int)tOffset; + + // make sure that we are in a [0,1] range + sOffset = sOffset - (int)sOffset; + tOffset = tOffset - (int)tOffset; + + hasOffset = true; + } + + if( xScale != 0.0f && yScale != 0.0f ) + hasScale = true; + + if( hasScale ) sceGuTexScale( xScale, yScale ); + if( hasOffset ) sceGuTexOffset( sOffset, tOffset ); + + if ( GU_ClipIsRequired( &p->verts[0], p->numverts ) ) + { + // clip the polygon. + gu_vert_t* cv; + size_t cvc; + + GU_Clip( &p->verts[0], p->numverts, &cv, &cvc ); + if( cvc ) + { +#if CLIPPING_DEBUGGING + sceGuDisable(GU_TEXTURE_2D); + sceGuColor( 0xff0000ff ); +#endif + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); +#if CLIPPING_DEBUGGING + sceGuEnable(GU_TEXTURE_2D); + sceGuColor( 0xffffffff ); +#endif + } + } + else sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, &p->verts[0] ); + + if( hasScale ) sceGuTexScale( 1.0f, 1.0f ); + if( hasOffset ) sceGuTexOffset( 0.0f, 0.0f ); + + if( FBitSet( p->flags, SURF_DRAWTILED )) + GL_SetupFogColorForSurfaces(); +} + +/* +================ +DrawGLPolyChain + +Render lightmaps +================ +*/ +void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset ) +{ + qboolean dynamic = true; + + if( soffset == 0.0f && toffset == 0.0f ) + dynamic = false; + + if( dynamic ) sceGuTexOffset( -soffset, -toffset ); + + for( ; p != NULL; p = p->chain ) + { + float *v; + int i; + + if ( GU_ClipIsRequired( &p->verts[p->numverts], p->numverts ) ) + { + // clip the polygon. + gu_vert_t* cv; + size_t cvc; + + GU_Clip( &p->verts[p->numverts], p->numverts, &cv, &cvc ); + if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); + } + else sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, &p->verts[p->numverts] ); + } + + if( dynamic ) sceGuTexOffset( 0.0f, 0.0f ); +} + +_inline qboolean R_HasLightmap( void ) +{ + if( CVAR_TO_BOOL( r_fullbright ) || !WORLDMODEL->lightdata ) + return false; + + if( RI.currententity ) + { + if( RI.currententity->curstate.effects & EF_FULLBRIGHT ) + return false; // disabled by user + + // check for rendermode + switch( RI.currententity->curstate.rendermode ) + { + case kRenderTransTexture: + case kRenderTransColor: + case kRenderTransAdd: + case kRenderGlow: + return false; // no lightmaps + } + } + + return true; +} + +/* +================ +R_BlendLightmaps +================ +*/ +void R_BlendLightmaps( void ) +{ + msurface_t *surf, *newsurf = NULL; + int i; + + if( !R_HasLightmap() ) + return; + + GL_SetupFogColorForSurfaces (); + + if( !CVAR_TO_BOOL( r_lightmap )) + sceGuEnable( GU_BLEND ); + else sceGuDisable( GU_BLEND ); + + // lightmapped solid surfaces + sceGuDepthMask( GU_TRUE ); + sceGuDepthFunc( GU_EQUAL ); + + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, GUBLEND0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + // render static lightmaps first + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + if( gl_lms.lightmap_surfaces[i] ) + { + GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[i] ); + + for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->info->lightmapchain ) + { + if( surf->polys ) DrawGLPolyChain( surf->polys, 0.0f, 0.0f ); + } + } + } + + // render dynamic lightmaps + if( CVAR_TO_BOOL( r_dynamic )) + { + LM_InitBlock(); +#if 0 + GL_Bind( XASH_TEXTURE0, tr.dlightTexture ); +#endif + newsurf = gl_lms.dynamic_surfaces; + + for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->info->lightmapchain ) + { + int smax, tmax; + int sample_size; + mextrasurf_t *info = surf->info; + byte *base; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + smax = ( info->lightextents[0] / sample_size ) + 1; + tmax = ( info->lightextents[1] / sample_size ) + 1; + + if( LM_AllocBlock( smax, tmax, &surf->info->dlight_s, &surf->info->dlight_t )) + { + base = gl_lms.lightmap_buffer; + base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4; + + R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true ); + } + else + { + msurface_t *drawsurf; + + // upload what we have so far + LM_UploadBlock( true ); + + // draw all surfaces that use this lightmap + for( drawsurf = newsurf; drawsurf != surf; drawsurf = drawsurf->info->lightmapchain ) + { + if( drawsurf->polys ) + { + DrawGLPolyChain( drawsurf->polys, + ( drawsurf->light_s - drawsurf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ), + ( drawsurf->light_t - drawsurf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE )); + } + } + + newsurf = drawsurf; + + // clear the block + LM_InitBlock(); + + // try uploading the block now + if( !LM_AllocBlock( smax, tmax, &surf->info->dlight_s, &surf->info->dlight_t )) + gEngfuncs.Host_Error( "AllocBlock: full\n" ); + + base = gl_lms.lightmap_buffer; + base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4; + + R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true ); + } + } + + // draw remainder of dynamic lightmaps that haven't been uploaded yet + if( newsurf ) LM_UploadBlock( true ); + + for( surf = newsurf; surf != NULL; surf = surf->info->lightmapchain ) + { + if( surf->polys ) + { + DrawGLPolyChain( surf->polys, + ( surf->light_s - surf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ), + ( surf->light_t - surf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE )); + } + } + } + + sceGuDisable( GU_BLEND ); + sceGuDepthMask( GU_FALSE ); + sceGuDepthFunc( GU_LEQUAL ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + sceGuColor( 0xffffffff ); + + // restore fog here + GL_ResetFogColor(); +} + +/* +================ +R_RenderFullbrights +================ +*/ +void R_RenderFullbrights( void ) +{ + mextrasurf_t *es, *p; + int i; + + if( !draw_fullbrights ) + return; + + R_AllowFog( false ); + + sceGuEnable( GU_BLEND ); + sceGuDepthMask( GU_TRUE ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_FIX, GU_FIX, GUBLEND1, GUBLEND1 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + for( i = 1; i < MAX_TEXTURES; i++ ) + { + es = fullbright_surfaces[i]; + if( !es ) continue; + + GL_Bind( XASH_TEXTURE0, i ); + + for( p = es; p; p = p->lumachain ) + DrawGLPoly( p->surf->polys, 0.0f, 0.0f ); + + fullbright_surfaces[i] = NULL; + es->lumachain = NULL; + } + + sceGuDisable( GU_BLEND ); + sceGuDepthMask( GU_FALSE ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + + draw_fullbrights = false; + R_AllowFog( true ); +} + +/* +================ +R_RenderDetails +================ +*/ +void R_RenderDetails( void ) +{ + gl_texture_t *glt; + mextrasurf_t *es, *p; + msurface_t *fa; + int i; + + if( !draw_details ) + return; + + GL_SetupFogColorForSurfaces(); + + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_DST_COLOR, GU_SRC_COLOR, 0, 0 ); + sceGuTexFunc( GU_TFX_DECAL, GU_TCC_RGBA ); + sceGuDepthFunc( GU_EQUAL ); + + for( i = 1; i < MAX_TEXTURES; i++ ) + { + es = detail_surfaces[i]; + if( !es ) continue; + + GL_Bind( XASH_TEXTURE0, i ); + + for( p = es; p; p = p->detailchain ) + { + fa = p->surf; + glt = R_GetTexture( fa->texinfo->texture->gl_texturenum ); // get texture scale + + DrawGLPoly( fa->polys, glt->xscale, glt->yscale ); + } + + detail_surfaces[i] = NULL; + es->detailchain = NULL; + } + + sceGuDisable( GU_BLEND ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + sceGuDepthFunc( GU_LEQUAL ); + + draw_details = false; + + // restore fog here + GL_ResetFogColor(); +} + +/* +================ +R_RenderBrushPoly +================ +*/ +void R_RenderBrushPoly( msurface_t *fa, int cull_type ) +{ + qboolean is_dynamic = false; + int maps; + texture_t *t; + + r_stats.c_world_polys++; + + if( fa->flags & SURF_DRAWSKY ) + return; // already handled + + t = R_TextureAnimation( fa ); + + GL_Bind( XASH_TEXTURE0, t->gl_texturenum ); + + if( FBitSet( fa->flags, SURF_DRAWTURB )) + { + // warp texture, no lightmaps + EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE)); + return; + } + + if( t->fb_texturenum ) + { + fa->info->lumachain = fullbright_surfaces[t->fb_texturenum]; + fullbright_surfaces[t->fb_texturenum] = fa->info; + draw_fullbrights = true; + } + + if( CVAR_TO_BOOL( r_detailtextures )) + { + if( glState.isFogEnabled ) + { + // don't apply detail textures for windows in the fog + if( RI.currententity->curstate.rendermode != kRenderTransTexture ) + { + if( t->dt_texturenum ) + { + fa->info->detailchain = detail_surfaces[t->dt_texturenum]; + detail_surfaces[t->dt_texturenum] = fa->info; + } + else + { + // draw stub detail texture for underwater surfaces + fa->info->detailchain = detail_surfaces[tr.grayTexture]; + detail_surfaces[tr.grayTexture] = fa->info; + } + draw_details = true; + } + } + else if( t->dt_texturenum ) + { + fa->info->detailchain = detail_surfaces[t->dt_texturenum]; + detail_surfaces[t->dt_texturenum] = fa->info; + draw_details = true; + } + } + + DrawGLPoly( fa->polys, 0.0f, 0.0f ); + + if( RI.currententity->curstate.rendermode == kRenderNormal ) + { + // batch decals to draw later + if( tr.num_draw_decals < MAX_DECAL_SURFS && fa->pdecals ) + tr.draw_decals[tr.num_draw_decals++] = fa; + } + else + { + // if rendermode != kRenderNormal draw decals sequentially + DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE)); + } + + if( FBitSet( fa->flags, SURF_DRAWTILED )) + return; // no lightmaps anyway + + // check for lightmap modification + for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) + { + if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] ) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if( fa->dlightframe == tr.framecount ) + { +dynamic: + // NOTE: at this point we have only valid textures + if( r_dynamic->value ) is_dynamic = true; + } + + if( is_dynamic ) + { + if(( fa->styles[maps] >= 32 || fa->styles[maps] == 0 || fa->styles[maps] == 20 ) && ( fa->dlightframe != tr.framecount )) + { + byte temp[132*132*4]; + mextrasurf_t *info = fa->info; + int sample_size; + int smax, tmax; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( fa ); + smax = ( info->lightextents[0] / sample_size ) + 1; + tmax = ( info->lightextents[1] / sample_size ) + 1; + + R_BuildLightMap( fa, temp, smax * 4, true ); + R_SetCacheState( fa ); + +#if 1 + GL_UpdateDlightTexture( tr.lightmapTextures[fa->lightmaptexturenum], fa->light_s, fa->light_t, smax, tmax, temp ); +#else + GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] ); + + pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, + GL_RGBA, GL_UNSIGNED_BYTE, temp ); +#endif + fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } + else + { + fa->info->lightmapchain = gl_lms.dynamic_surfaces; + gl_lms.dynamic_surfaces = fa; + } + } + else + { + fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } +} + +/* +================ +R_DrawTextureChains +================ +*/ +void R_DrawTextureChains( void ) +{ + int i; + msurface_t *s; + texture_t *t; + + // make sure what color is reset + sceGuColor( 0xffffffff ); + + R_LoadIdentity(); // set identity matrix + + GL_SetupFogColorForSurfaces(); + + // restore worldmodel + RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); + RI.currentmodel = RI.currententity->model; + + if( ENGINE_GET_PARM( PARM_SKY_SPHERE ) ) + { + sceGuDisable( GU_TEXTURE_2D ); + sceGuColor( 0xffffffff ); + } + + // clip skybox surfaces + for( s = skychain; s != NULL; s = s->texturechain ) + R_AddSkyBoxSurface( s ); + + if( ENGINE_GET_PARM( PARM_SKY_SPHERE ) ) + { + sceGuEnable( GU_TEXTURE_2D ); + if( skychain ) + R_DrawClouds(); + skychain = NULL; + } + + for( i = 0; i < WORLDMODEL->numtextures; i++ ) + { + t = WORLDMODEL->textures[i]; + if( !t ) continue; + + s = t->texturechain; + + if( !s || ( i == tr.skytexturenum )) + continue; + + if(( s->flags & SURF_DRAWTURB ) && MOVEVARS->wateralpha < 1.0f ) + continue; // draw translucent water later + + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT )) + { + draw_alpha_surfaces = true; + continue; // draw transparent surfaces later + } + + for( ; s != NULL; s = s->texturechain ) + R_RenderBrushPoly( s, CULL_VISIBLE ); + t->texturechain = NULL; + } +} + +/* +================ +R_DrawAlphaTextureChains +================ +*/ +void R_DrawAlphaTextureChains( void ) +{ + int i; + msurface_t *s; + texture_t *t; + + if( !draw_alpha_surfaces ) + return; + + memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces )); + gl_lms.dynamic_surfaces = NULL; + + // make sure what color is reset + sceGuColor( 0xffffffff ); + + R_LoadIdentity(); // set identity matrix + + sceGuDisable( GU_BLEND ); + sceGuEnable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, 0x40, 0xff ); + + GL_SetupFogColorForSurfaces(); + + // restore worldmodel + RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); + RI.currentmodel = RI.currententity->model; + RI.currententity->curstate.rendermode = kRenderTransAlpha; + draw_alpha_surfaces = false; + + for( i = 0; i < WORLDMODEL->numtextures; i++ ) + { + t = WORLDMODEL->textures[i]; + if( !t ) continue; + + s = t->texturechain; + + if( !s || !FBitSet( s->flags, SURF_TRANSPARENT )) + continue; + + for( ; s != NULL; s = s->texturechain ) + R_RenderBrushPoly( s, CULL_VISIBLE ); + t->texturechain = NULL; + } + + GL_ResetFogColor(); + R_BlendLightmaps(); + RI.currententity->curstate.rendermode = kRenderNormal; // restore world rendermode + + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); +} + +/* +================ +R_DrawWaterSurfaces +================ +*/ +void R_DrawWaterSurfaces( void ) +{ + int i; + msurface_t *s; + texture_t *t; + + if( !RI.drawWorld || RI.onlyClientDraw ) + return; + + // non-transparent water is already drawed + if( MOVEVARS->wateralpha >= 1.0f ) + return; + + // restore worldmodel + RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); + RI.currentmodel = RI.currententity->model; + + // go back to the world matrix + R_LoadIdentity(); + + sceGuEnable( GU_BLEND ); + sceGuDepthMask( GU_TRUE ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, MOVEVARS->wateralpha ) ); + + for( i = 0; i < WORLDMODEL->numtextures; i++ ) + { + t = WORLDMODEL->textures[i]; + if( !t ) continue; + + s = t->texturechain; + if( !s ) continue; + + if( !FBitSet( s->flags, SURF_DRAWTURB )) + continue; + + // set modulate mode explicitly + GL_Bind( XASH_TEXTURE0, t->gl_texturenum ); + + for( ; s; s = s->texturechain ) + EmitWaterPolys( s, false ); + + t->texturechain = NULL; + } + + sceGuDisable( GU_BLEND ); + sceGuDepthMask( GU_FALSE ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + sceGuColor( 0xffffffff ); +} + +/* +================= +R_SurfaceCompare + +compare translucent surfaces +================= +*/ +static int R_SurfaceCompare( const void *a, const void *b ) +{ + msurface_t *surf1, *surf2; + vec3_t org1, org2; + float len1, len2; + + surf1 = (msurface_t *)((sortedface_t *)a)->surf; + surf2 = (msurface_t *)((sortedface_t *)b)->surf; + + VectorAdd( RI.currententity->origin, surf1->info->origin, org1 ); + VectorAdd( RI.currententity->origin, surf2->info->origin, org2 ); + + // compare by plane dists + len1 = DotProduct( org1, RI.vforward ) - RI.viewplanedist; + len2 = DotProduct( org2, RI.vforward ) - RI.viewplanedist; + + if( len1 > len2 ) + return -1; + if( len1 < len2 ) + return 1; + + return 0; +} + +void R_SetRenderMode( cl_entity_t *e ) +{ + switch( e->curstate.rendermode ) + { + case kRenderNormal: + sceGuColor( 0xffffffff ); + break; + case kRenderTransColor: + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4UB( e->curstate.rendercolor.r, e->curstate.rendercolor.g, e->curstate.rendercolor.b, e->curstate.renderamt ) ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuDisable( GU_TEXTURE_2D ); + sceGuEnable( GU_BLEND ); + break; + case kRenderTransAdd: + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuColor( GUCOLOR4F( tr.blend, tr.blend, tr.blend, 1.0f ) ); + sceGuBlendFunc( GU_ADD, GU_FIX, GU_FIX, GUBLEND1, GUBLEND1 ); + sceGuDepthMask( GU_TRUE ); + sceGuEnable( GU_BLEND ); + break; + case kRenderTransAlpha: + sceGuEnable( GU_ALPHA_TEST ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + { + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, tr.blend ) ); + sceGuEnable( GU_BLEND ); + } + else + { + sceGuColor( 0xffffffff ); + sceGuDisable( GU_BLEND ); + } + sceGuAlphaFunc( GU_GREATER, 0x40, 0xff ); + break; + default: + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, tr.blend ) ); + sceGuDepthMask( GU_TRUE ); + sceGuEnable( GU_BLEND ); + break; + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel( cl_entity_t *e ) +{ + int i, k, num_sorted; + vec3_t origin_l, oldorigin; + int old_rendermode; + vec3_t mins, maxs; + int cull_type; + msurface_t *psurf; + model_t *clmodel; + qboolean rotated; + dlight_t *l; + + if( !RI.drawWorld ) return; + + clmodel = e->model; + + if( !VectorIsNull( e->angles )) + { + for( i = 0; i < 3; i++ ) + { + mins[i] = e->origin[i] - clmodel->radius; + maxs[i] = e->origin[i] + clmodel->radius; + } + rotated = true; + } + else + { + VectorAdd( e->origin, clmodel->mins, mins ); + VectorAdd( e->origin, clmodel->maxs, maxs ); + rotated = false; + } + + if( R_CullBox( mins, maxs )) + return; + + memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces )); + old_rendermode = e->curstate.rendermode; + gl_lms.dynamic_surfaces = NULL; + + if( rotated ) R_RotateForEntity( e ); + else R_TranslateForEntity( e ); + + if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT )) + e->curstate.rendermode = kRenderTransAlpha; + + e->visframe = tr.realframecount; // visible + + if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg ); + else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); + + // calculate dynamic lighting for bmodel + for( k = 0; k < MAX_DLIGHTS; k++ ) + { + l = gEngfuncs.GetDynamicLight( k ); + + if( l->die < gpGlobals->time || !l->radius ) + continue; + + VectorCopy( l->origin, oldorigin ); // save lightorigin + Matrix4x4_VectorITransform( RI.objectMatrix, l->origin, origin_l ); + VectorCopy( origin_l, l->origin ); // move light in bmodel space + R_MarkLights( l, 1<nodes + clmodel->hulls[0].firstclipnode ); + VectorCopy( oldorigin, l->origin ); // restore lightorigin + } + + // setup the rendermode + R_SetRenderMode( e ); + GL_SetupFogColorForSurfaces (); + + if( e->curstate.rendermode == kRenderTransAdd ) + { + R_AllowFog( false ); + } + + psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; +#if 1 /* no sorting */ + GU_ClipBeginBrush(); + for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) + { + if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + { + if( psurf->plane->type != PLANE_Z && !FBitSet( e->curstate.effects, EF_WATERSIDES )) + continue; + if( mins[2] + 1.0f >= psurf->plane->dist ) + continue; + } + + cull_type = R_CullSurface( psurf, &RI.frustum, RI.frustum.clipFlags ); + + if( cull_type >= CULL_FRUSTUM ) + continue; + + if( cull_type == CULL_BACKSIDE ) + { + if( !FBitSet( psurf->flags, SURF_DRAWTURB ) && !( psurf->pdecals && e->curstate.rendermode == kRenderTransTexture )) + continue; + } + R_RenderBrushPoly( psurf, cull_type ); + } + + if( e->curstate.rendermode == kRenderTransColor ) + sceGuEnable( GU_TEXTURE_2D ); +#else + num_sorted = 0; + for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) + { + if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) + { + if( psurf->plane->type != PLANE_Z && !FBitSet( e->curstate.effects, EF_WATERSIDES )) + continue; + if( mins[2] + 1.0f >= psurf->plane->dist ) + continue; + } + + cull_type = R_CullSurface( psurf, &RI.frustum, RI.frustum.clipFlags ); + + if( cull_type >= CULL_FRUSTUM ) + continue; + + if( cull_type == CULL_BACKSIDE ) + { + if( !FBitSet( psurf->flags, SURF_DRAWTURB ) && !( psurf->pdecals && e->curstate.rendermode == kRenderTransTexture )) + continue; + } + + if( num_sorted < gpGlobals->max_surfaces ) + { + gpGlobals->draw_surfaces[num_sorted].surf = psurf; + gpGlobals->draw_surfaces[num_sorted].cull = cull_type; + num_sorted++; + } + } + + // sort faces if needs + if( !FBitSet( clmodel->flags, MODEL_LIQUID ) && e->curstate.rendermode == kRenderTransTexture && !CVAR_TO_BOOL( gl_nosort )) + qsort( gpGlobals->draw_surfaces, num_sorted, sizeof( sortedface_t ), R_SurfaceCompare ); + + // draw sorted translucent surfaces + GU_ClipBeginBrush(); + for( i = 0; i < num_sorted; i++ ) + R_RenderBrushPoly( gpGlobals->draw_surfaces[i].surf, gpGlobals->draw_surfaces[i].cull ); + if( e->curstate.rendermode == kRenderTransColor ) + sceGuEnable( GU_TEXTURE_2D ); +#endif + DrawDecalsBatch(); + GL_ResetFogColor(); + R_BlendLightmaps(); + R_RenderFullbrights(); + R_RenderDetails(); + GU_ClipEndBrush(); + + // restore fog here + if( e->curstate.rendermode == kRenderTransAdd ) + R_AllowFog( true ); + + e->curstate.rendermode = old_rendermode; + + sceGuDisable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuDisable( GU_BLEND ); + sceGuDepthMask( GU_FALSE ); + + R_DrawModelHull(); // draw before restore + R_LoadIdentity(); // restore worldmatrix +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) +{ + int i, clipped; + msurface_t *surf, **mark; + mleaf_t *pleaf; + int c, side; + float dot; +loc0: + if( node->contents == CONTENTS_SOLID ) + return; // hit a solid leaf + + if( node->visframe != tr.visframecount ) + return; + + if( clipflags && !CVAR_TO_BOOL( r_nocull )) + { + for( i = 0; i < 6; i++ ) + { + const mplane_t *p = &RI.frustum.planes[i]; + + if( !FBitSet( clipflags, BIT( i ))) + continue; + + clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p ); + if( clipped == 2 ) return; + if( clipped == 1 ) ClearBits( clipflags, BIT( i )); + } + } + + // if a leaf node, draw stuff + if( node->contents < 0 ) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if( c ) + { + do + { + (*mark)->visframe = tr.framecount; + mark++; + } while( --c ); + } + + // deal with model fragments in this leaf + if( pleaf->efrags ) + gEngfuncs.R_StoreEfrags( &pleaf->efrags, tr.realframecount ); + + r_stats.c_world_leafs++; + return; + } + + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + dot = PlaneDiff( tr.modelorg, node->plane ); + side = (dot >= 0.0f) ? 0 : 1; + + // recurse down the children, front side first + R_RecursiveWorldNode( node->children[side], clipflags ); + + // draw stuff + for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ ) + { + if( R_CullSurface( surf, &RI.frustum, clipflags )) + continue; + + if( surf->flags & SURF_DRAWSKY ) + { + // make sky chain to right clip the skybox + surf->texturechain = skychain; + skychain = surf; + } + else + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + + // recurse down the back side + node = node->children[!side]; + goto loc0; +} + +/* +================ +R_CullNodeTopView + +cull node by user rectangle (simple scissor) +================ +*/ +qboolean R_CullNodeTopView( mnode_t *node ) +{ + vec2_t delta, size; + vec3_t center, half; + + // build the node center and half-diagonal + VectorAverage( node->minmaxs, node->minmaxs + 3, center ); + VectorSubtract( node->minmaxs + 3, center, half ); + + // cull against the screen frustum or the appropriate area's frustum. + Vector2Subtract( center, world_orthocenter, delta ); + Vector2Add( half, world_orthohalf, size ); + + return ( fabs( delta[0] ) > size[0] ) || ( fabs( delta[1] ) > size[1] ); +} + +/* +================ +R_DrawTopViewLeaf +================ +*/ +static void R_DrawTopViewLeaf( mleaf_t *pleaf, uint clipflags ) +{ + msurface_t **mark, *surf; + int i; + + for( i = 0, mark = pleaf->firstmarksurface; i < pleaf->nummarksurfaces; i++, mark++ ) + { + surf = *mark; + + // don't process the same surface twice + if( surf->visframe == tr.framecount ) + continue; + + surf->visframe = tr.framecount; + + if( R_CullSurface( surf, &RI.frustum, clipflags )) + continue; + + if(!( surf->flags & SURF_DRAWSKY )) + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + + // deal with model fragments in this leaf + if( pleaf->efrags ) + gEngfuncs.R_StoreEfrags( &pleaf->efrags, tr.realframecount ); + + r_stats.c_world_leafs++; +} + +/* +================ +R_DrawWorldTopView +================ +*/ +void R_DrawWorldTopView( mnode_t *node, uint clipflags ) +{ + int i, c, clipped; + msurface_t *surf; + + do + { + if( node->contents == CONTENTS_SOLID ) + return; // hit a solid leaf + + if( node->visframe != tr.visframecount ) + return; + + if( clipflags && !r_nocull->value ) + { + for( i = 0; i < 6; i++ ) + { + const mplane_t *p = &RI.frustum.planes[i]; + + if( !FBitSet( clipflags, BIT( i ))) + continue; + + clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p ); + if( clipped == 2 ) return; + if( clipped == 1 ) ClearBits( clipflags, BIT( i )); + } + } + + // cull against the screen frustum or the appropriate area's frustum. + if( R_CullNodeTopView( node )) + return; + + // if a leaf node, draw stuff + if( node->contents < 0 ) + { + R_DrawTopViewLeaf( (mleaf_t *)node, clipflags ); + return; + } + + // draw stuff + for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ ) + { + // don't process the same surface twice + if( surf->visframe == tr.framecount ) + continue; + + surf->visframe = tr.framecount; + + if( R_CullSurface( surf, &RI.frustum, clipflags )) + continue; + + if(!( surf->flags & SURF_DRAWSKY )) + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + + // recurse down both children, we don't care the order... + R_DrawWorldTopView( node->children[0], clipflags ); + node = node->children[1]; + + } while( node ); +} + +/* +============= +R_DrawTriangleOutlines +============= +*/ +void R_DrawTriangleOutlines( void ) +{ +#if 0 + int i, j; + msurface_t *surf; + glpoly_t *p; + float *v; + + if( !gl_wireframe->value ) + return; + + pglDisable( GL_TEXTURE_2D ); + pglDisable( GL_DEPTH_TEST ); + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + pglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + // render static surfaces first + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->info->lightmapchain ) + { + p = surf->polys; + for( ; p != NULL; p = p->chain ) + { + pglBegin( GL_POLYGON ); + v = p->verts[0]; + for( j = 0; j < p->numverts; j++, v += VERTEXSIZE ) + pglVertex3fv( v ); + pglEnd (); + } + } + } + + // render surfaces with dynamic lightmaps + for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->info->lightmapchain ) + { + p = surf->polys; + + for( ; p != NULL; p = p->chain ) + { + pglBegin( GL_POLYGON ); + v = p->verts[0]; + for( j = 0; j < p->numverts; j++, v += VERTEXSIZE ) + pglVertex3fv( v ); + pglEnd (); + } + } + + pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + pglEnable( GL_DEPTH_TEST ); + pglEnable( GL_TEXTURE_2D ); +#endif +} + +/* +============= +R_DrawWorld +============= +*/ +void R_DrawWorld( void ) +{ + double start, end; + + // paranoia issues: when gl_renderer is "0" we need have something valid for currententity + // to prevent crashing until HeadShield drawing. + RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); + RI.currentmodel = RI.currententity->model; + + if( !RI.drawWorld || RI.onlyClientDraw ) + return; + + VectorCopy( RI.cullorigin, tr.modelorg ); + memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces )); + memset( fullbright_surfaces, 0, sizeof( fullbright_surfaces )); + memset( detail_surfaces, 0, sizeof( detail_surfaces )); + + gl_lms.dynamic_surfaces = NULL; + + sceGuDisable( GU_ALPHA_TEST ); + sceGuDisable( GU_BLEND ); + + tr.blend = 1.0f; + + R_ClearSkyBox (); + + start = gEngfuncs.pfnTime(); + if( RI.drawOrtho ) + R_DrawWorldTopView( WORLDMODEL->nodes, RI.frustum.clipFlags ); + else R_RecursiveWorldNode( WORLDMODEL->nodes, RI.frustum.clipFlags ); + end = gEngfuncs.pfnTime(); + + r_stats.t_world_node = end - start; + + start = gEngfuncs.pfnTime(); + + R_DrawTextureChains(); + + if( !ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) + { + DrawDecalsBatch(); + GL_ResetFogColor(); + R_BlendLightmaps(); + R_RenderFullbrights(); + R_RenderDetails(); + + if( skychain ) + R_DrawSkyBox(); + } + + end = gEngfuncs.pfnTime(); + + r_stats.t_world_draw = end - start; + tr.num_draw_decals = 0; + skychain = NULL; + + R_DrawTriangleOutlines (); + + R_DrawWorldHull(); +} + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current leaf +=============== +*/ +void R_MarkLeaves( void ) +{ + qboolean novis = false; + qboolean force = false; + mleaf_t *leaf = NULL; + mnode_t *node; + vec3_t test; + int i; + + if( !RI.drawWorld ) return; + + if( FBitSet( r_novis->flags, FCVAR_CHANGED ) || tr.fResetVis ) + { + // force recalc viewleaf + ClearBits( r_novis->flags, FCVAR_CHANGED ); + tr.fResetVis = false; + RI.viewleaf = NULL; + } + + VectorCopy( RI.pvsorigin, test ); + + if( RI.viewleaf != NULL ) + { + // merge two leafs that can be a crossed-line contents + if( RI.viewleaf->contents == CONTENTS_EMPTY ) + { + VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] - 16.0f ); + leaf = gEngfuncs.Mod_PointInLeaf( test, WORLDMODEL->nodes ); + } + else + { + VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] + 16.0f ); + leaf = gEngfuncs.Mod_PointInLeaf( test, WORLDMODEL->nodes ); + } + + if(( leaf->contents != CONTENTS_SOLID ) && ( RI.viewleaf != leaf )) + force = true; + } + + if( RI.viewleaf == RI.oldviewleaf && RI.viewleaf != NULL && !force ) + return; + + // development aid to let you run around + // and see exactly where the pvs ends + if( r_lockpvs->value ) return; + + RI.oldviewleaf = RI.viewleaf; + tr.visframecount++; + + if( r_novis->value || RI.drawOrtho || !RI.viewleaf || !WORLDMODEL->visdata ) + novis = true; + + gEngfuncs.R_FatPVS( RI.pvsorigin, REFPVS_RADIUS, RI.visbytes, FBitSet( RI.params, RP_OLDVIEWLEAF ), novis ); + if( force && !novis ) gEngfuncs.R_FatPVS( test, REFPVS_RADIUS, RI.visbytes, true, novis ); + + for( i = 0; i < WORLDMODEL->numleafs; i++ ) + { + if( CHECKVISBIT( RI.visbytes, i )) + { + node = (mnode_t *)&WORLDMODEL->leafs[i+1]; + do + { + if( node->visframe == tr.visframecount ) + break; + node->visframe = tr.visframecount; + node = node->parent; + } while( node ); + } + } +} + +/* +======================== +GL_CreateSurfaceLightmap +======================== +*/ +void GL_CreateSurfaceLightmap( msurface_t *surf, model_t *loadmodel ) +{ + int smax, tmax; + int sample_size; + mextrasurf_t *info = surf->info; + byte *base; + + if( !loadmodel->lightdata ) + return; + + if( FBitSet( surf->flags, SURF_DRAWTILED ) ) + return; + + sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); + smax = ( info->lightextents[0] / sample_size ) + 1; + tmax = ( info->lightextents[1] / sample_size ) + 1; + + if( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + LM_UploadBlock( false ); + LM_InitBlock(); + + if( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + gEngfuncs.Host_Error( "AllocBlock: full\n" ); + } + + surf->lightmaptexturenum = gl_lms.current_lightmap_texture; + + base = gl_lms.lightmap_buffer; + base += ( surf->light_t * BLOCK_SIZE + surf->light_s ) * 4; + + R_SetCacheState( surf ); + R_BuildLightMap( surf, base, BLOCK_SIZE * 4, false ); +} + +/* +================== +GL_RebuildLightmaps + +Rebuilds the lightmap texture +when gamma is changed +================== +*/ +void GL_RebuildLightmaps( void ) +{ + int i, j; + model_t *m; + + if( !ENGINE_GET_PARM( PARM_CLIENT_ACTIVE ) ) + return; // wait for worldmodel + + ClearBits( vid_brightness->flags, FCVAR_CHANGED ); + ClearBits( vid_gamma->flags, FCVAR_CHANGED ); + + // release old lightmaps + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + if( !tr.lightmapTextures[i] ) break; + GL_FreeTexture( tr.lightmapTextures[i] ); + } + + memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ) ); + gl_lms.current_lightmap_texture = 0; + + // setup all the lightstyles + CL_RunLightStyles(); + + LM_InitBlock(); + + for( i = 0; i < ENGINE_GET_PARM( PARM_NUMMODELS ); i++ ) + { + if( ( m = gEngfuncs.pfnGetModelByIndex( i + 1 ) ) == NULL ) + continue; + + if( m->name[0] == '*' || m->type != mod_brush ) + continue; + + for( j = 0; j < m->numsurfaces; j++ ) + GL_CreateSurfaceLightmap( m->surfaces + j, m ); + } + LM_UploadBlock( false ); + + if( gEngfuncs.drawFuncs->GL_BuildLightmaps ) + { + // build lightmaps on the client-side + gEngfuncs.drawFuncs->GL_BuildLightmaps( ); + } +} + +/* +================== +GL_BuildLightmaps + +Builds the lightmap texture +with all the surfaces from all brush models +================== +*/ +void GL_BuildLightmaps( void ) +{ + int i, j; + model_t *m; + + // release old lightmaps + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + if( !tr.lightmapTextures[i] ) break; + GL_FreeTexture( tr.lightmapTextures[i] ); + } + + memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); + memset( &RI, 0, sizeof( RI )); +#if 1 + tr.block_size = BLOCK_SIZE_DEFAULT; +#else + // update the lightmap blocksize + if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_LARGE_LIGHTMAPS )) + tr.block_size = BLOCK_SIZE_MAX; + else tr.block_size = BLOCK_SIZE_DEFAULT; +#endif + skychain = NULL; + + tr.framecount = tr.visframecount = 1; // no dlight cache + gl_lms.current_lightmap_texture = 0; + tr.modelviewIdentity = false; + tr.realframecount = 1; + nColinElim = 0; + + // setup the texture for dlights + R_InitDlightTexture(); + + // setup all the lightstyles + CL_RunLightStyles(); + + LM_InitBlock(); + + for( i = 0; i < ENGINE_GET_PARM( PARM_NUMMODELS ); i++ ) + { + if( ( m = gEngfuncs.pfnGetModelByIndex( i + 1 ) ) == NULL ) + continue; + + if( m->name[0] == '*' || m->type != mod_brush ) + continue; + + for( j = 0; j < m->numsurfaces; j++ ) + { + // clearing all decal chains + m->surfaces[j].pdecals = NULL; + m->surfaces[j].visframe = 0; + + GL_CreateSurfaceLightmap( m->surfaces + j, m ); + + if( m->surfaces[j].flags & SURF_DRAWTURB ) + continue; + + GL_BuildPolygonFromSurface( m, m->surfaces + j ); + } + + // clearing visframe + for( j = 0; j < m->numleafs; j++ ) + m->leafs[j+1].visframe = 0; + for( j = 0; j < m->numnodes; j++ ) + m->nodes[j].visframe = 0; + } + + LM_UploadBlock( false ); + + if( gEngfuncs.drawFuncs->GL_BuildLightmaps ) + { + // build lightmaps on the client-side + gEngfuncs.drawFuncs->GL_BuildLightmaps( ); + } + + // now gamma and brightness are valid + ClearBits( vid_brightness->flags, FCVAR_CHANGED ); + ClearBits( vid_gamma->flags, FCVAR_CHANGED ); +} + +void GL_InitRandomTable( void ) +{ + int tu, tv; + + // make random predictable + gEngfuncs.COM_SetRandomSeed( 255 ); + + for( tu = 0; tu < MOD_FRAMES; tu++ ) + { + for( tv = 0; tv < MOD_FRAMES; tv++ ) + { + rtable[tu][tv] = gEngfuncs.COM_RandomLong( 0, 0x7FFF ); + } + } + + gEngfuncs.COM_SetRandomSeed( 0 ); +} diff --git a/ref_gu/gu_sprite.c b/ref_gu/gu_sprite.c new file mode 100644 index 00000000..1958ebaa --- /dev/null +++ b/ref_gu/gu_sprite.c @@ -0,0 +1,1026 @@ +/* +gu_sprite.c - sprite rendering +Copyright (C) 2010 Uncle Mike +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "pm_local.h" +#include "sprite.h" +#include "studio.h" +#include "entity_types.h" +#include "cl_tent.h" + +// it's a Valve default value for LoadMapSprite (probably must be power of two) +#define MAPSPRITE_SIZE 128 +#define GLARE_FALLOFF 19000.0f + +cvar_t *r_sprite_lerping; +cvar_t *r_sprite_lighting; +char sprite_name[MAX_QPATH]; +char group_suffix[8]; +static uint r_texFlags = 0; +static int sprite_version; +float sprite_radius; + +/* +==================== +R_SpriteInit + +==================== +*/ +void R_SpriteInit( void ) +{ + r_sprite_lerping = gEngfuncs.Cvar_Get( "r_sprite_lerping", "1", FCVAR_ARCHIVE, "enables sprite animation lerping" ); + r_sprite_lighting = gEngfuncs.Cvar_Get( "r_sprite_lighting", "1", FCVAR_ARCHIVE, "enables sprite lighting (blood etc)" ); +} + +/* +==================== +R_SpriteLoadFrame + +upload a single frame +==================== +*/ +static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num ) +{ + dspriteframe_t pinframe; + mspriteframe_t *pspriteframe; + int gl_texturenum = 0; + char texname[128]; + int bytes = 1; + + memcpy( &pinframe, pin, sizeof(dspriteframe_t)); + + if( sprite_version == SPRITE_VERSION_32 ) + bytes = 4; + + // build uinque frame name + if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite + { + Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 ); + gl_texturenum = GL_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, r_texFlags ); + } + else + { + Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 ); + gl_texturenum = GL_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, r_texFlags ); + } + + // setup frame description + pspriteframe = Mem_Malloc( mod->mempool, sizeof( mspriteframe_t )); + pspriteframe->width = pinframe.width; + pspriteframe->height = pinframe.height; + pspriteframe->up = pinframe.origin[1]; + pspriteframe->left = pinframe.origin[0]; + pspriteframe->down = pinframe.origin[1] - pinframe.height; + pspriteframe->right = pinframe.width + pinframe.origin[0]; + pspriteframe->gl_texturenum = gl_texturenum; + *ppframe = pspriteframe; + + return ( const dframetype_t* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes ); +} + +/* +==================== +R_SpriteLoadGroup + +upload a group frames +==================== +*/ +static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum ) +{ + const dspritegroup_t *pingroup; + mspritegroup_t *pspritegroup; + const dspriteinterval_t *pin_intervals; + float *poutintervals; + int i, groupsize, numframes; + const void *ptemp; + + pingroup = (const dspritegroup_t *)pin; + numframes = pingroup->numframes; + + groupsize = sizeof( mspritegroup_t ) + (numframes - 1) * sizeof( pspritegroup->frames[0] ); + pspritegroup = Mem_Calloc( mod->mempool, groupsize ); + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_t *)pspritegroup; + pin_intervals = (const dspriteinterval_t *)(pingroup + 1); + poutintervals = Mem_Calloc( mod->mempool, numframes * sizeof( float )); + pspritegroup->intervals = poutintervals; + + for( i = 0; i < numframes; i++ ) + { + *poutintervals = pin_intervals->interval; + if( *poutintervals <= 0.0f ) + *poutintervals = 1.0f; // set error value + poutintervals++; + pin_intervals++; + } + + ptemp = (const void *)pin_intervals; + for( i = 0; i < numframes; i++ ) + { + ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i ); + } + + return (const dframetype_t *)ptemp; +} + +/* +==================== +Mod_LoadSpriteModel + +load sprite model +==================== +*/ +void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags ) +{ + const dsprite_t *pin; + const short *numi = NULL; + const dframetype_t *pframetype; + msprite_t *psprite; + int i; + + pin = buffer; + psprite = mod->cache.data; + + if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 ) + numi = NULL; + else if( pin->version == SPRITE_VERSION_HL ) + numi = (const short *)((const byte*)buffer + sizeof( dsprite_hl_t )); + + r_texFlags = texFlags; + sprite_version = pin->version; + Q_strncpy( sprite_name, mod->name, sizeof( sprite_name )); + COM_StripExtension( sprite_name ); + + if( numi == NULL ) + { + rgbdata_t *pal; + + pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 ); + pframetype = (const dframetype_t *)((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1 + gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data + } + else if( *numi == 256 ) + { + const byte *src = (const byte *)(numi+1); + rgbdata_t *pal; + + // install palette + switch( psprite->texFormat ) + { + case SPR_INDEXALPHA: + pal = gEngfuncs.FS_LoadImage( "#gradient.pal", src, 768 ); + break; + case SPR_ALPHTEST: + pal = gEngfuncs.FS_LoadImage( "#masked.pal", src, 768 ); + break; + default: + pal = gEngfuncs.FS_LoadImage( "#normal.pal", src, 768 ); + break; + } + + pframetype = (const dframetype_t *)(src + 768); + gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data + } + else + { + gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi ); + return; + } + + if( mod->numframes < 1 ) + return; + + for( i = 0; i < mod->numframes; i++ ) + { + frametype_t frametype = pframetype->type; + psprite->frames[i].type = (spriteframetype_t)frametype; + + switch( frametype ) + { + case FRAME_SINGLE: + Q_strncpy( group_suffix, "frame", sizeof( group_suffix )); + pframetype = R_SpriteLoadFrame( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + break; + case FRAME_GROUP: + Q_strncpy( group_suffix, "group", sizeof( group_suffix )); + pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + break; + case FRAME_ANGLED: + Q_strncpy( group_suffix, "angle", sizeof( group_suffix )); + pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i ); + break; + } + if( pframetype == NULL ) break; // technically an error + } + + if( loaded ) *loaded = true; // done +} + +/* +==================== +Mod_LoadMapSprite + +Loading a bitmap image as sprite with multiple frames +as pieces of input image +==================== +*/ +void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean *loaded ) +{ + byte *src, *dst; + rgbdata_t *pix, temp; + char texname[128]; + int i, j, x, y, w, h; + int xl, yl, xh, yh; + int linedelta, numframes; + mspriteframe_t *pspriteframe; + msprite_t *psprite; + + if( loaded ) *loaded = false; + Q_snprintf( texname, sizeof( texname ), "#%s", mod->name ); + gEngfuncs.Image_SetForceFlags( IL_OVERVIEW ); + pix = gEngfuncs.FS_LoadImage( texname, buffer, size ); + gEngfuncs.Image_ClearForceFlags(); + if( !pix ) return; // bad image or something else + + mod->type = mod_sprite; + r_texFlags = 0; // no custom flags for map sprites + + if( pix->width % MAPSPRITE_SIZE ) + w = pix->width - ( pix->width % MAPSPRITE_SIZE ); + else w = pix->width; + + if( pix->height % MAPSPRITE_SIZE ) + h = pix->height - ( pix->height % MAPSPRITE_SIZE ); + else h = pix->height; + + if( w < MAPSPRITE_SIZE ) w = MAPSPRITE_SIZE; + if( h < MAPSPRITE_SIZE ) h = MAPSPRITE_SIZE; + + // resample image if needed + gEngfuncs.Image_Process( &pix, w, h, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE, 0.0f ); + + w = h = MAPSPRITE_SIZE; + + // check range + if( w > pix->width ) w = pix->width; + if( h > pix->height ) h = pix->height; + + // determine how many frames we needs + numframes = (pix->width * pix->height) / (w * h); + mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name )); + psprite = Mem_Calloc( mod->mempool, sizeof( msprite_t ) + ( numframes - 1 ) * sizeof( psprite->frames )); + mod->cache.data = psprite; // make link to extradata + + psprite->type = SPR_FWD_PARALLEL_ORIENTED; + psprite->texFormat = SPR_ALPHTEST; + psprite->numframes = mod->numframes = numframes; + psprite->radius = sqrt(((w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1))); + + mod->mins[0] = mod->mins[1] = -w / 2; + mod->maxs[0] = mod->maxs[1] = w / 2; + mod->mins[2] = -h / 2; + mod->maxs[2] = h / 2; + + // create a temporary pic + memset( &temp, 0, sizeof( temp )); + temp.width = w; + temp.height = h; + temp.type = pix->type; + temp.flags = pix->flags; + temp.size = w * h * gEngfuncs.Image_GetPFDesc(temp.type)->bpp; + temp.buffer = Mem_Malloc( r_temppool, temp.size ); + temp.palette = NULL; + + // chop the image and upload into video memory + for( i = xl = yl = 0; i < numframes; i++ ) + { + xh = xl + w; + yh = yl + h; + + src = pix->buffer + ( yl * pix->width + xl ) * 4; + linedelta = ( pix->width - w ) * 4; + dst = temp.buffer; + + // cut block from source + for( y = yl; y < yh; y++ ) + { + for( x = xl; x < xh; x++ ) + for( j = 0; j < 4; j++ ) + *dst++ = *src++; + src += linedelta; + } + + // build uinque frame name + Q_snprintf( texname, sizeof( texname ), "#MAP/%s_%i%i.spr", mod->name, i / 10, i % 10 ); + + psprite->frames[i].frameptr = Mem_Calloc( mod->mempool, sizeof( mspriteframe_t )); + pspriteframe = psprite->frames[i].frameptr; + pspriteframe->width = w; + pspriteframe->height = h; + pspriteframe->up = ( h >> 1 ); + pspriteframe->left = -( w >> 1 ); + pspriteframe->down = ( h >> 1 ) - h; + pspriteframe->right = w + -( w >> 1 ); + pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE ); + + xl += w; + if( xl >= pix->width ) + { + xl = 0; + yl += h; + } + } + + gEngfuncs.FS_FreeImage( pix ); + Mem_Free( temp.buffer ); + + if( loaded ) *loaded = true; +} + +/* +==================== +Mod_UnloadSpriteModel + +release sprite model and frames +==================== +*/ +void Mod_SpriteUnloadTextures( void *data ) +{ + msprite_t *psprite; + mspritegroup_t *pspritegroup; + mspriteframe_t *pspriteframe; + int i, j; + + psprite = data; + + if( psprite ) + { + // release all textures + for( i = 0; i < psprite->numframes; i++ ) + { + if( psprite->frames[i].type == SPR_SINGLE ) + { + pspriteframe = psprite->frames[i].frameptr; + GL_FreeTexture( pspriteframe->gl_texturenum ); + } + else + { + pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr; + + for( j = 0; j < pspritegroup->numframes; j++ ) + { + pspriteframe = pspritegroup->frames[i]; + GL_FreeTexture( pspriteframe->gl_texturenum ); + } + } + } + } +} + +/* +================ +R_GetSpriteFrame + +assume pModel is valid +================ +*/ +mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw ) +{ + msprite_t *psprite; + mspritegroup_t *pspritegroup; + mspriteframe_t *pspriteframe = NULL; + float *pintervals, fullinterval; + int i, numframes; + float targettime; + + Assert( pModel != NULL ); + psprite = pModel->cache.data; + + if( frame < 0 ) + { + frame = 0; + } + else if( frame >= psprite->numframes ) + { + if( frame > psprite->numframes ) + gEngfuncs.Con_Printf( S_WARN "R_GetSpriteFrame: no such frame %d (%s)\n", frame, pModel->name ); + frame = psprite->numframes - 1; + } + + if( psprite->frames[frame].type == SPR_SINGLE ) + { + pspriteframe = psprite->frames[frame].frameptr; + } + else if( psprite->frames[frame].type == SPR_GROUP ) + { + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by zero + targettime = gpGlobals->time - ((int)( gpGlobals->time / fullinterval )) * fullinterval; + + for( i = 0; i < (numframes - 1); i++ ) + { + if( pintervals[i] > targettime ) + break; + } + pspriteframe = pspritegroup->frames[i]; + } + else if( psprite->frames[frame].type == FRAME_ANGLED ) + { + int angleframe = (int)(Q_rint(( RI.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7; + + // e.g. doom-style sprite monsters + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pspriteframe = pspritegroup->frames[angleframe]; + } + + return pspriteframe; +} + +/* +================ +R_GetSpriteFrameInterpolant + +NOTE: we using prevblending[0] and [1] for holds interval +between frames where are we lerping +================ +*/ +float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe, mspriteframe_t **curframe ) +{ + msprite_t *psprite; + mspritegroup_t *pspritegroup; + int i, j, numframes, frame; + float lerpFrac, time, jtime, jinterval; + float *pintervals, fullinterval, targettime; + int m_fDoInterp; + + psprite = ent->model->cache.data; + frame = (int)ent->curstate.frame; + lerpFrac = 1.0f; + + // misc info + m_fDoInterp = (ent->curstate.effects & EF_NOINTERP) ? false : true; + + if( frame < 0 ) + { + frame = 0; + } + else if( frame >= psprite->numframes ) + { + gEngfuncs.Con_Reportf( S_WARN "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name ); + frame = psprite->numframes - 1; + } + + if( psprite->frames[frame].type == FRAME_SINGLE ) + { + if( m_fDoInterp ) + { + if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_SINGLE ) + { + // this can be happens when rendering switched between single and angled frames + // or change model on replace delta-entity + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 1.0f; + } + + if( ent->latched.sequencetime < gpGlobals->time ) + { + if( frame != ent->latched.prevblending[1] ) + { + ent->latched.prevblending[0] = ent->latched.prevblending[1]; + ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 0.0f; + } + else lerpFrac = (gpGlobals->time - ent->latched.sequencetime) * 11.0f; + } + else + { + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 0.0f; + } + } + else + { + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + lerpFrac = 1.0f; + } + + if( ent->latched.prevblending[0] >= psprite->numframes ) + { + // reset interpolation on change model + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 0.0f; + } + + // get the interpolated frames + if( oldframe ) *oldframe = psprite->frames[ent->latched.prevblending[0]].frameptr; + if( curframe ) *curframe = psprite->frames[frame].frameptr; + } + else if( psprite->frames[frame].type == FRAME_GROUP ) + { + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + jinterval = pintervals[1] - pintervals[0]; + time = gpGlobals->time; + jtime = 0.0f; + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by zero + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + // LordHavoc: since I can't measure the time properly when it loops from numframes - 1 to 0, + // i instead measure the time of the first frame, hoping it is consistent + for( i = 0, j = numframes - 1; i < (numframes - 1); i++ ) + { + if( pintervals[i] > targettime ) + break; + j = i; + jinterval = pintervals[i] - jtime; + jtime = pintervals[i]; + } + + if( m_fDoInterp ) + lerpFrac = (targettime - jtime) / jinterval; + else j = i; // no lerping + + // get the interpolated frames + if( oldframe ) *oldframe = pspritegroup->frames[j]; + if( curframe ) *curframe = pspritegroup->frames[i]; + } + else if( psprite->frames[frame].type == FRAME_ANGLED ) + { + // e.g. doom-style sprite monsters + float yaw = ent->angles[YAW]; + int angleframe = (int)(Q_rint(( RI.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7; + + if( m_fDoInterp ) + { + if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_ANGLED ) + { + // this can be happens when rendering switched between single and angled frames + // or change model on replace delta-entity + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 1.0f; + } + + if( ent->latched.sequencetime < gpGlobals->time ) + { + if( frame != ent->latched.prevblending[1] ) + { + ent->latched.prevblending[0] = ent->latched.prevblending[1]; + ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 0.0f; + } + else lerpFrac = (gpGlobals->time - ent->latched.sequencetime) * ent->curstate.framerate; + } + else + { + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + ent->latched.sequencetime = gpGlobals->time; + lerpFrac = 0.0f; + } + } + else + { + ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame; + lerpFrac = 1.0f; + } + + pspritegroup = (mspritegroup_t *)psprite->frames[ent->latched.prevblending[0]].frameptr; + if( oldframe ) *oldframe = pspritegroup->frames[angleframe]; + + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + if( curframe ) *curframe = pspritegroup->frames[angleframe]; + } + + return lerpFrac; +} + +/* +================ +R_CullSpriteModel + +Cull sprite model by bbox +================ +*/ +qboolean R_CullSpriteModel( cl_entity_t *e, vec3_t origin ) +{ + vec3_t sprite_mins, sprite_maxs; + float scale = 1.0f; + + if( !e->model->cache.data ) + return true; + + if( e->curstate.scale > 0.0f ) + scale = e->curstate.scale; + + // scale original bbox (no rotation for sprites) + VectorScale( e->model->mins, scale, sprite_mins ); + VectorScale( e->model->maxs, scale, sprite_maxs ); + + sprite_radius = RadiusFromBounds( sprite_mins, sprite_maxs ); + + VectorAdd( sprite_mins, origin, sprite_mins ); + VectorAdd( sprite_maxs, origin, sprite_maxs ); + + return R_CullModel( e, sprite_mins, sprite_maxs ); +} + +/* +================ +R_GlowSightDistance + +Set sprite brightness factor +================ +*/ +static float R_SpriteGlowBlend( vec3_t origin, int rendermode, int renderfx, float *pscale ) +{ + float dist, brightness; + vec3_t glowDist; + pmtrace_t *tr; + + VectorSubtract( origin, RI.vieworg, glowDist ); + dist = VectorLength( glowDist ); + + if( RP_NORMALPASS( )) + { + tr = gEngfuncs.EV_VisTraceLine( RI.vieworg, origin, r_traceglow->value ? PM_GLASS_IGNORE : (PM_GLASS_IGNORE|PM_STUDIO_IGNORE)); + + if(( 1.0f - tr->fraction ) * dist > 8.0f ) + return 0.0f; + } + + if( renderfx == kRenderFxNoDissipation ) + return 1.0f; + + brightness = GLARE_FALLOFF / ( dist * dist ); + brightness = bound( 0.05f, brightness, 1.0f ); + *pscale *= dist * ( 1.0f / 200.0f ); + + return brightness; +} + +/* +================ +R_SpriteOccluded + +Do occlusion test for glow-sprites +================ +*/ +qboolean R_SpriteOccluded( cl_entity_t *e, vec3_t origin, float *pscale ) +{ + if( e->curstate.rendermode == kRenderGlow ) + { + float blend; + vec3_t v; + + TriWorldToScreen( origin, v ); + + if( v[0] < RI.viewport[0] || v[0] > RI.viewport[0] + RI.viewport[2] ) + return true; // do scissor + if( v[1] < RI.viewport[1] || v[1] > RI.viewport[1] + RI.viewport[3] ) + return true; // do scissor + + blend = R_SpriteGlowBlend( origin, e->curstate.rendermode, e->curstate.renderfx, pscale ); + tr.blend *= blend; + + if( blend <= 0.01f ) + return true; // faded + } + else + { + if( R_CullSpriteModel( e, origin )) + return true; + } + + return false; +} + +/* +================= +R_DrawSpriteQuad +================= +*/ +static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right, vec3_t v_up, float scale ) +{ + vec3_t point; + + r_stats.c_sprite_polys++; + + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); + VectorMA( org, frame->down * scale, v_up, point ); + VectorMA( point, frame->left * scale, v_right, point ); + out[0].uv[0] = 0.0f; + out[0].uv[1] = 1.0f; + VectorCopy( point, out[0].xyz ); + VectorMA( org, frame->up * scale, v_up, point ); + VectorMA( point, frame->left * scale, v_right, point ); + out[1].uv[0] = 0.0f; + out[1].uv[1] = 0.0f; + VectorCopy( point, out[1].xyz ); + VectorMA( org, frame->up * scale, v_up, point ); + VectorMA( point, frame->right * scale, v_right, point ); + out[2].uv[0] = 1.0f; + out[2].uv[1] = 0.0f; + VectorCopy( point, out[2].xyz ); + VectorMA( org, frame->down * scale, v_up, point ); + VectorMA( point, frame->right * scale, v_right, point ); + out[3].uv[0] = 1.0f; + out[3].uv[1] = 1.0f; + VectorCopy( point, out[3].xyz ); + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); +} + +static qboolean R_SpriteHasLightmap( cl_entity_t *e, int texFormat ) +{ + if( !r_sprite_lighting->value ) + return false; + + if( texFormat != SPR_ALPHTEST ) + return false; + + if( e->curstate.effects & EF_FULLBRIGHT ) + return false; + + if( e->curstate.renderamt <= 127 ) + return false; + + switch( e->curstate.rendermode ) + { + case kRenderNormal: + case kRenderTransAlpha: + case kRenderTransTexture: + break; + default: + return false; + } + + return true; +} + +/* +================= +R_SpriteAllowLerping +================= +*/ +static qboolean R_SpriteAllowLerping( cl_entity_t *e, msprite_t *psprite ) +{ + if( !r_sprite_lerping->value ) + return false; + + if( psprite->numframes <= 1 ) + return false; + + if( psprite->texFormat != SPR_ADDITIVE ) + return false; + + if( e->curstate.rendermode == kRenderNormal || e->curstate.rendermode == kRenderTransAlpha ) + return false; + + return true; +} + +/* +================= +R_DrawSpriteModel +================= +*/ +void R_DrawSpriteModel( cl_entity_t *e ) +{ + mspriteframe_t *frame, *oldframe; + msprite_t *psprite; + model_t *model; + int i, type; + float angle, dot, sr, cr; + float lerp = 1.0f, ilerp, scale; + vec3_t v_forward, v_right, v_up; + vec3_t origin, color, color2 = { 0.0f }; + + if( RI.params & RP_ENVVIEW ) + return; + + model = e->model; + psprite = (msprite_t * )model->cache.data; + VectorCopy( e->origin, origin ); // set render origin + + // do movewith + if( e->curstate.aiment > 0 && e->curstate.movetype == MOVETYPE_FOLLOW ) + { + cl_entity_t *parent; + + parent = gEngfuncs.GetEntityByIndex( e->curstate.aiment ); + + if( parent && parent->model ) + { + if( parent->model->type == mod_studio && e->curstate.body > 0 ) + { + int num = bound( 1, e->curstate.body, MAXSTUDIOATTACHMENTS ); + VectorCopy( parent->attachment[num-1], origin ); + } + else VectorCopy( parent->origin, origin ); + } + } + + scale = e->curstate.scale; + if( !scale ) scale = 1.0f; + + if( R_SpriteOccluded( e, origin, &scale )) + return; // sprite culled + + r_stats.c_sprite_models_drawn++; + + if( e->curstate.rendermode == kRenderGlow || e->curstate.rendermode == kRenderTransAdd ) + R_AllowFog( false ); + + // select properly rendermode + switch( e->curstate.rendermode ) + { + case kRenderTransAlpha: + sceGuDepthMask( GU_TRUE ); + // fallthrough + case kRenderTransColor: + case kRenderTransTexture: + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + break; + case kRenderGlow: + sceGuDisable( GU_DEPTH_TEST ); + // fallthrough + case kRenderTransAdd: + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + sceGuDepthMask( GU_TRUE ); + break; + case kRenderNormal: + default: + sceGuDisable( GU_BLEND ); + break; + } + + // all sprites can have color + sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); + sceGuEnable( GU_ALPHA_TEST ); + + // NOTE: never pass sprites with rendercolor '0 0 0' it's a stupid Valve Hammer Editor bug + if( e->curstate.rendercolor.r || e->curstate.rendercolor.g || e->curstate.rendercolor.b ) + { + color[0] = (float)e->curstate.rendercolor.r * ( 1.0f / 255.0f ); + color[1] = (float)e->curstate.rendercolor.g * ( 1.0f / 255.0f ); + color[2] = (float)e->curstate.rendercolor.b * ( 1.0f / 255.0f ); + } + else + { + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 1.0f; + } + + if( R_SpriteHasLightmap( e, psprite->texFormat )) + { + colorVec lightColor = R_LightPoint( origin ); + // FIXME: collect light from dlights? + color2[0] = (float)lightColor.r * ( 1.0f / 255.0f ); + color2[1] = (float)lightColor.g * ( 1.0f / 255.0f ); + color2[2] = (float)lightColor.b * ( 1.0f / 255.0f ); + + // NOTE: sprites with 'lightmap' looks ugly when alpha func is GL_GREATER 0.0 + sceGuAlphaFunc( GU_GREATER, 0x7f, 0xff ); + } + + if( R_SpriteAllowLerping( e, psprite )) + lerp = R_GetSpriteFrameInterpolant( e, &oldframe, &frame ); + else frame = oldframe = R_GetSpriteFrame( model, e->curstate.frame, e->angles[YAW] ); + + type = psprite->type; + + // automatically roll parallel sprites if requested + if( e->angles[ROLL] != 0.0f && type == SPR_FWD_PARALLEL ) + type = SPR_FWD_PARALLEL_ORIENTED; + + switch( type ) + { + case SPR_ORIENTED: + AngleVectors( e->angles, v_forward, v_right, v_up ); + VectorScale( v_forward, 0.01f, v_forward ); // to avoid z-fighting + VectorSubtract( origin, v_forward, origin ); + break; + case SPR_FACING_UPRIGHT: + VectorSet( v_right, origin[1] - RI.vieworg[1], -(origin[0] - RI.vieworg[0]), 0.0f ); + VectorSet( v_up, 0.0f, 0.0f, 1.0f ); + VectorNormalize( v_right ); + break; + case SPR_FWD_PARALLEL_UPRIGHT: + dot = RI.vforward[2]; + if(( dot > 0.999848f ) || ( dot < -0.999848f )) // cos(1 degree) = 0.999848 + return; // invisible + VectorSet( v_up, 0.0f, 0.0f, 1.0f ); + VectorSet( v_right, RI.vforward[1], -RI.vforward[0], 0.0f ); + VectorNormalize( v_right ); + break; + case SPR_FWD_PARALLEL_ORIENTED: + angle = e->angles[ROLL] * (M_PI2 / 360.0f); + SinCos( angle, &sr, &cr ); + for( i = 0; i < 3; i++ ) + { + v_right[i] = (RI.vright[i] * cr + RI.vup[i] * sr); + v_up[i] = RI.vright[i] * -sr + RI.vup[i] * cr; + } + break; + case SPR_FWD_PARALLEL: // normal sprite + default: + VectorCopy( RI.vright, v_right ); + VectorCopy( RI.vup, v_up ); + break; + } + + if( psprite->facecull == SPR_CULL_NONE ) + GL_Cull( GL_NONE ); + + if( oldframe == frame ) + { + // draw the single non-lerped frame + sceGuColor( GUCOLOR4F( color[0], color[1], color[2], tr.blend) ); + GL_Bind( XASH_TEXTURE0, frame->gl_texturenum ); + R_DrawSpriteQuad( frame, origin, v_right, v_up, scale ); + } + else + { + // draw two combined lerped frames + lerp = bound( 0.0f, lerp, 1.0f ); + ilerp = 1.0f - lerp; + + if( ilerp != 0.0f ) + { + sceGuColor( GUCOLOR4F( color[0], color[1], color[2], tr.blend * ilerp ) ); + GL_Bind( XASH_TEXTURE0, oldframe->gl_texturenum ); + R_DrawSpriteQuad( oldframe, origin, v_right, v_up, scale ); + } + + if( lerp != 0.0f ) + { + sceGuColor( GUCOLOR4F( color[0], color[1], color[2], tr.blend * ilerp ) ); + GL_Bind( XASH_TEXTURE0, frame->gl_texturenum ); + R_DrawSpriteQuad( frame, origin, v_right, v_up, scale ); + } + } + + // draw the sprite 'lightmap' :-) + if( R_SpriteHasLightmap( e, psprite->texFormat )) + { + if( !r_lightmap->value ) + sceGuEnable( GU_BLEND ); + else sceGuDisable( GU_BLEND ); + sceGuDepthFunc( GU_EQUAL ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, GUBLEND0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE , GU_TCC_RGBA ); + + sceGuColor( GUCOLOR4F( color2[0], color2[1], color2[2], tr.blend ) ); + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + R_DrawSpriteQuad( frame, origin, v_right, v_up, scale ); + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuDepthFunc( GU_LEQUAL ); + } + + if( psprite->facecull == SPR_CULL_NONE ) + GL_Cull( GL_FRONT ); + + sceGuDisable( GU_ALPHA_TEST ); + sceGuDepthMask( GU_FALSE ); + + if( e->curstate.rendermode == kRenderGlow || e->curstate.rendermode == kRenderTransAdd ) + R_AllowFog( true ); + + if( e->curstate.rendermode != kRenderNormal ) + { + sceGuDisable( GU_BLEND ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + sceGuEnable( GU_DEPTH_TEST ); + } +} diff --git a/ref_gu/gu_studio.c b/ref_gu/gu_studio.c new file mode 100644 index 00000000..9aba3679 --- /dev/null +++ b/ref_gu/gu_studio.c @@ -0,0 +1,4142 @@ +/* +gu_studio.c - studio model renderer +Copyright (C) 2010 Uncle Mike +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "xash3d_mathlib.h" +#include "const.h" +#include "r_studioint.h" +#include "triangleapi.h" +#include "studio.h" +#include "pm_local.h" +#include "cl_tent.h" +//#include "client.h" +#include "pmtrace.h" + +#define EVENT_CLIENT 5000 // less than this value it's a server-side studio events +#define MAX_LOCALLIGHTS 4 + +typedef struct +{ + char name[MAX_OSPATH]; + char modelname[MAX_OSPATH]; + model_t *model; +} player_model_t; + +cvar_t *r_glowshellfreq; + +cvar_t r_shadows = { "r_shadows", "0", 0 }; + +static vec3_t hullcolor[8] = +{ +{ 1.0f, 1.0f, 1.0f }, +{ 1.0f, 0.5f, 0.5f }, +{ 0.5f, 1.0f, 0.5f }, +{ 1.0f, 1.0f, 0.5f }, +{ 0.5f, 0.5f, 1.0f }, +{ 1.0f, 0.5f, 1.0f }, +{ 0.5f, 1.0f, 1.0f }, +{ 1.0f, 1.0f, 1.0f }, +}; + +typedef struct sortedmesh_s +{ + mstudiomesh_t *mesh; + int flags; // face flags +} sortedmesh_t; + +#if XASH_LOW_MEMORY + #undef MAXSTUDIOVERTS + #define MAXSTUDIOVERTS 1024 +#endif + +typedef struct +{ + double time; + double frametime; + int framecount; // studio framecount + qboolean interpolate; + int rendermode; + float blend; // blend value + + // bones + matrix3x4 rotationmatrix; + matrix3x4 bonestransform[MAXSTUDIOBONES]; + matrix3x4 lighttransform[MAXSTUDIOBONES]; + + // boneweighting stuff + matrix3x4 worldtransform[MAXSTUDIOBONES]; + + // cached bones + matrix3x4 cached_bonestransform[MAXSTUDIOBONES]; + matrix3x4 cached_lighttransform[MAXSTUDIOBONES]; + char cached_bonenames[MAXSTUDIOBONES][32]; + int cached_numbones; // number of bones in cache + + sortedmesh_t meshes[MAXSTUDIOMESHES]; // sorted meshes + vec3_t verts[MAXSTUDIOVERTS]; + vec3_t norms[MAXSTUDIOVERTS]; + + // lighting state + float ambientlight; + float shadelight; + vec3_t lightvec; // averaging light direction + vec3_t lightspot; // shadow spot + vec3_t lightcolor; // averaging lightcolor + vec3_t blightvec[MAXSTUDIOBONES]; // bone light vecs + vec3_t lightvalues[MAXSTUDIOVERTS]; // precomputed lightvalues per each shared vertex of submodel + + // chrome stuff + vec3_t chrome_origin; + vec2_t chrome[MAXSTUDIOVERTS]; // texture coords for surface normals + vec3_t chromeright[MAXSTUDIOBONES]; // chrome vector "right" in bone reference frames + vec3_t chromeup[MAXSTUDIOBONES]; // chrome vector "up" in bone reference frames + int chromeage[MAXSTUDIOBONES]; // last time chrome vectors were updated + + // glowshell stuff + int normaltable[MAXSTUDIOVERTS]; // glowshell uses this + + // elights cache + int numlocallights; + int lightage[MAXSTUDIOBONES]; + dlight_t *locallight[MAX_LOCALLIGHTS]; + color24 locallightcolor[MAX_LOCALLIGHTS]; + vec4_t lightpos[MAXSTUDIOVERTS][MAX_LOCALLIGHTS]; + vec3_t lightbonepos[MAXSTUDIOBONES][MAX_LOCALLIGHTS]; + float locallightR2[MAX_LOCALLIGHTS]; + + // playermodels + player_model_t player_models[MAX_CLIENTS]; + + // drawelements renderer + gu_vert_ftcv_t arrayverts[MAXSTUDIOVERTS]; + unsigned short arrayelems[MAXSTUDIOVERTS * 6]; + uint numverts; + uint numelems; +} studio_draw_state_t; + +// studio-related cvars +static cvar_t *r_studio_sort_textures; +static cvar_t *r_drawviewmodel; +cvar_t *cl_righthand = NULL; +static cvar_t *cl_himodels; +static cvar_t *r_studio_drawelements; + +static r_studio_interface_t *pStudioDraw; +static studio_draw_state_t g_studio; // global studio state + +// global variables +static qboolean m_fDoRemap; +mstudiomodel_t *m_pSubModel; +mstudiobodyparts_t *m_pBodyPart; +player_info_t *m_pPlayerInfo; +studiohdr_t *m_pStudioHeader; +float m_flGaitMovement; +int g_iBackFaceCull; +int g_nTopColor, g_nBottomColor; // remap colors +int g_nFaceFlags, g_nForceFaceFlags; + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + cl_himodels = gEngfuncs.Cvar_Get( "cl_himodels", "0", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" ); + r_studio_sort_textures = gEngfuncs.Cvar_Get( "r_studio_sort_textures", "0", FCVAR_ARCHIVE, "change draw order for additive meshes" ); + r_drawviewmodel = gEngfuncs.Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" ); + r_studio_drawelements = gEngfuncs.Cvar_Get( "r_studio_drawelements", "0", FCVAR_ARCHIVE, "use glDrawElements for studiomodels" ); + + Matrix3x4_LoadIdentity( g_studio.rotationmatrix ); + r_glowshellfreq = gEngfuncs.Cvar_Get( "r_glowshellfreq", "2.2", 0, "glowing shell frequency update" ); + + // g-cont. cvar disabled by Valve +// gEngfuncs.Cvar_RegisterVariable( &r_shadows ); + + g_studio.interpolate = true; + + g_studio.framecount = 0; + m_fDoRemap = false; +} + +/* +================ +R_StudioSetupTimings + +init current time for a given model +================ +*/ +_inline void R_StudioSetupTimings( void ) +{ + if( RI.drawWorld ) + { + // synchronize with server time + g_studio.time = gpGlobals->time; + g_studio.frametime = gpGlobals->time - gpGlobals->oldtime; + } + else + { + // menu stuff + g_studio.time = gpGlobals->realtime; + g_studio.frametime = gpGlobals->frametime; + } +} + +/* +================ +R_AllowFlipViewModel + +should a flip the viewmodel if cl_righthand is set to 1 +================ +*/ +_inline qboolean R_AllowFlipViewModel( cl_entity_t *e ) +{ + if( cl_righthand && cl_righthand->value > 0 ) + { + if( e == gEngfuncs.GetViewModel() ) + return true; + } + + return false; +} + +/* +================ +R_StudioComputeBBox + +Compute a full bounding box for current sequence +================ +*/ +_inline qboolean R_StudioComputeBBox( vec3_t bbox[8] ) +{ + vec3_t studio_mins, studio_maxs; + vec3_t mins, maxs, p1, p2; + cl_entity_t *e = RI.currententity; + mstudioseqdesc_t *pseqdesc; + int i; + + if( !m_pStudioHeader ) + return false; + + // check if we have valid mins\maxs + if( !VectorCompare( vec3_origin, RI.currentmodel->mins )) + { + // clipping bounding box + VectorCopy( RI.currentmodel->mins, mins ); + VectorCopy( RI.currentmodel->maxs, maxs ); + } + else + { + ClearBounds( mins, maxs ); + } + + // check sequence range + if( e->curstate.sequence < 0 || e->curstate.sequence >= m_pStudioHeader->numseq ) + e->curstate.sequence = 0; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->curstate.sequence; + + // add sequence box to the model box + AddPointToBounds( pseqdesc->bbmin, mins, maxs ); + AddPointToBounds( pseqdesc->bbmax, mins, maxs ); + ClearBounds( studio_mins, studio_maxs ); + + // compute a full bounding box + for( i = 0; i < 8; i++ ) + { + p1[0] = ( i & 1 ) ? mins[0] : maxs[0]; + p1[1] = ( i & 2 ) ? mins[1] : maxs[1]; + p1[2] = ( i & 4 ) ? mins[2] : maxs[2]; + + Matrix3x4_VectorTransform( g_studio.rotationmatrix, p1, p2 ); + AddPointToBounds( p2, studio_mins, studio_maxs ); + if( bbox ) VectorCopy( p2, bbox[i] ); + } + + if( !bbox && R_CullModel( e, studio_mins, studio_maxs )) + return false; // model culled + return true; // visible +} + +void R_StudioComputeSkinMatrix( mstudioboneweight_t *boneweights, matrix3x4 result ) +{ + vec4_t flWeight; + int i, numbones = 0; + float flTotal; + + for( i = 0; i < MAXSTUDIOBONEWEIGHTS; i++ ) + { + if( boneweights->bone[i] != -1 ) + numbones++; + } + + if( numbones == 4 ) + { + vec4_t *boneMat0 = (vec4_t *)g_studio.worldtransform[boneweights->bone[0]]; + vec4_t *boneMat1 = (vec4_t *)g_studio.worldtransform[boneweights->bone[1]]; + vec4_t *boneMat2 = (vec4_t *)g_studio.worldtransform[boneweights->bone[2]]; + vec4_t *boneMat3 = (vec4_t *)g_studio.worldtransform[boneweights->bone[3]]; + flWeight[0] = boneweights->weight[0] / 255.0f; + flWeight[1] = boneweights->weight[1] / 255.0f; + flWeight[2] = boneweights->weight[2] / 255.0f; + flWeight[3] = boneweights->weight[3] / 255.0f; + flTotal = flWeight[0] + flWeight[1] + flWeight[2] + flWeight[3]; + + if( flTotal < 1.0f ) flWeight[0] += 1.0f - flTotal; // compensate rounding error + + result[0][0] = boneMat0[0][0] * flWeight[0] + boneMat1[0][0] * flWeight[1] + boneMat2[0][0] * flWeight[2] + boneMat3[0][0] * flWeight[3]; + result[0][1] = boneMat0[0][1] * flWeight[0] + boneMat1[0][1] * flWeight[1] + boneMat2[0][1] * flWeight[2] + boneMat3[0][1] * flWeight[3]; + result[0][2] = boneMat0[0][2] * flWeight[0] + boneMat1[0][2] * flWeight[1] + boneMat2[0][2] * flWeight[2] + boneMat3[0][2] * flWeight[3]; + result[0][3] = boneMat0[0][3] * flWeight[0] + boneMat1[0][3] * flWeight[1] + boneMat2[0][3] * flWeight[2] + boneMat3[0][3] * flWeight[3]; + result[1][0] = boneMat0[1][0] * flWeight[0] + boneMat1[1][0] * flWeight[1] + boneMat2[1][0] * flWeight[2] + boneMat3[1][0] * flWeight[3]; + result[1][1] = boneMat0[1][1] * flWeight[0] + boneMat1[1][1] * flWeight[1] + boneMat2[1][1] * flWeight[2] + boneMat3[1][1] * flWeight[3]; + result[1][2] = boneMat0[1][2] * flWeight[0] + boneMat1[1][2] * flWeight[1] + boneMat2[1][2] * flWeight[2] + boneMat3[1][2] * flWeight[3]; + result[1][3] = boneMat0[1][3] * flWeight[0] + boneMat1[1][3] * flWeight[1] + boneMat2[1][3] * flWeight[2] + boneMat3[1][3] * flWeight[3]; + result[2][0] = boneMat0[2][0] * flWeight[0] + boneMat1[2][0] * flWeight[1] + boneMat2[2][0] * flWeight[2] + boneMat3[2][0] * flWeight[3]; + result[2][1] = boneMat0[2][1] * flWeight[0] + boneMat1[2][1] * flWeight[1] + boneMat2[2][1] * flWeight[2] + boneMat3[2][1] * flWeight[3]; + result[2][2] = boneMat0[2][2] * flWeight[0] + boneMat1[2][2] * flWeight[1] + boneMat2[2][2] * flWeight[2] + boneMat3[2][2] * flWeight[3]; + result[2][3] = boneMat0[2][3] * flWeight[0] + boneMat1[2][3] * flWeight[1] + boneMat2[2][3] * flWeight[2] + boneMat3[2][3] * flWeight[3]; + } + else if( numbones == 3 ) + { + vec4_t *boneMat0 = (vec4_t *)g_studio.worldtransform[boneweights->bone[0]]; + vec4_t *boneMat1 = (vec4_t *)g_studio.worldtransform[boneweights->bone[1]]; + vec4_t *boneMat2 = (vec4_t *)g_studio.worldtransform[boneweights->bone[2]]; + flWeight[0] = boneweights->weight[0] / 255.0f; + flWeight[1] = boneweights->weight[1] / 255.0f; + flWeight[2] = boneweights->weight[2] / 255.0f; + flTotal = flWeight[0] + flWeight[1] + flWeight[2]; + + if( flTotal < 1.0f ) flWeight[0] += 1.0f - flTotal; // compensate rounding error + + result[0][0] = boneMat0[0][0] * flWeight[0] + boneMat1[0][0] * flWeight[1] + boneMat2[0][0] * flWeight[2]; + result[0][1] = boneMat0[0][1] * flWeight[0] + boneMat1[0][1] * flWeight[1] + boneMat2[0][1] * flWeight[2]; + result[0][2] = boneMat0[0][2] * flWeight[0] + boneMat1[0][2] * flWeight[1] + boneMat2[0][2] * flWeight[2]; + result[0][3] = boneMat0[0][3] * flWeight[0] + boneMat1[0][3] * flWeight[1] + boneMat2[0][3] * flWeight[2]; + result[1][0] = boneMat0[1][0] * flWeight[0] + boneMat1[1][0] * flWeight[1] + boneMat2[1][0] * flWeight[2]; + result[1][1] = boneMat0[1][1] * flWeight[0] + boneMat1[1][1] * flWeight[1] + boneMat2[1][1] * flWeight[2]; + result[1][2] = boneMat0[1][2] * flWeight[0] + boneMat1[1][2] * flWeight[1] + boneMat2[1][2] * flWeight[2]; + result[1][3] = boneMat0[1][3] * flWeight[0] + boneMat1[1][3] * flWeight[1] + boneMat2[1][3] * flWeight[2]; + result[2][0] = boneMat0[2][0] * flWeight[0] + boneMat1[2][0] * flWeight[1] + boneMat2[2][0] * flWeight[2]; + result[2][1] = boneMat0[2][1] * flWeight[0] + boneMat1[2][1] * flWeight[1] + boneMat2[2][1] * flWeight[2]; + result[2][2] = boneMat0[2][2] * flWeight[0] + boneMat1[2][2] * flWeight[1] + boneMat2[2][2] * flWeight[2]; + result[2][3] = boneMat0[2][3] * flWeight[0] + boneMat1[2][3] * flWeight[1] + boneMat2[2][3] * flWeight[2]; + } + else if( numbones == 2 ) + { + vec4_t *boneMat0 = (vec4_t *)g_studio.worldtransform[boneweights->bone[0]]; + vec4_t *boneMat1 = (vec4_t *)g_studio.worldtransform[boneweights->bone[1]]; + flWeight[0] = boneweights->weight[0] / 255.0f; + flWeight[1] = boneweights->weight[1] / 255.0f; + flTotal = flWeight[0] + flWeight[1]; + + if( flTotal < 1.0f ) flWeight[0] += 1.0f - flTotal; // compensate rounding error + + result[0][0] = boneMat0[0][0] * flWeight[0] + boneMat1[0][0] * flWeight[1]; + result[0][1] = boneMat0[0][1] * flWeight[0] + boneMat1[0][1] * flWeight[1]; + result[0][2] = boneMat0[0][2] * flWeight[0] + boneMat1[0][2] * flWeight[1]; + result[0][3] = boneMat0[0][3] * flWeight[0] + boneMat1[0][3] * flWeight[1]; + result[1][0] = boneMat0[1][0] * flWeight[0] + boneMat1[1][0] * flWeight[1]; + result[1][1] = boneMat0[1][1] * flWeight[0] + boneMat1[1][1] * flWeight[1]; + result[1][2] = boneMat0[1][2] * flWeight[0] + boneMat1[1][2] * flWeight[1]; + result[1][3] = boneMat0[1][3] * flWeight[0] + boneMat1[1][3] * flWeight[1]; + result[2][0] = boneMat0[2][0] * flWeight[0] + boneMat1[2][0] * flWeight[1]; + result[2][1] = boneMat0[2][1] * flWeight[0] + boneMat1[2][1] * flWeight[1]; + result[2][2] = boneMat0[2][2] * flWeight[0] + boneMat1[2][2] * flWeight[1]; + result[2][3] = boneMat0[2][3] * flWeight[0] + boneMat1[2][3] * flWeight[1]; + } + else + { + Matrix3x4_Copy( result, g_studio.worldtransform[boneweights->bone[0]] ); + } +} + +/* +=============== +pfnGetCurrentEntity + +=============== +*/ +static cl_entity_t *pfnGetCurrentEntity( void ) +{ + return RI.currententity; +} + +/* +=============== +pfnPlayerInfo + +=============== +*/ +player_info_t *pfnPlayerInfo( int index ) +{ + if( !RI.drawWorld ) + index = -1; + + return gEngfuncs.pfnPlayerInfo( index ); +} + +/* +=============== +pfnMod_ForName + +=============== +*/ +static model_t *pfnMod_ForName( const char *model, int crash ) +{ + return gEngfuncs.Mod_ForName( model, crash, false ); +} + +/* +=============== +pfnGetPlayerState + +=============== +*/ +entity_state_t *R_StudioGetPlayerState( int index ) +{ + if( !RI.drawWorld ) + return &RI.currententity->curstate; + + return gEngfuncs.pfnGetPlayerState( index ); +} + +/* +=============== +pfnGetViewEntity + +=============== +*/ +static cl_entity_t *pfnGetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +/* +=============== +pfnGetEngineTimes + +=============== +*/ +static void pfnGetEngineTimes( int *framecount, double *current, double *old ) +{ + if( framecount ) *framecount = tr.realframecount; + if( current ) *current = gpGlobals->time; + if( old ) *old = gpGlobals->oldtime; +} + +/* +=============== +pfnGetViewInfo + +=============== +*/ +static void pfnGetViewInfo( float *origin, float *upv, float *rightv, float *forwardv ) +{ + if( origin ) VectorCopy( RI.vieworg, origin ); + if( forwardv ) VectorCopy( RI.vforward, forwardv ); + if( rightv ) VectorCopy( RI.vright, rightv ); + if( upv ) VectorCopy( RI.vup, upv ); +} + +/* +=============== +R_GetChromeSprite + +=============== +*/ +static model_t *R_GetChromeSprite( void ) +{ + return gEngfuncs.GetDefaultSprite( REF_CHROME_SPRITE ); +} + +/* +=============== +pfnGetModelCounters + +=============== +*/ +static void pfnGetModelCounters( int **s, int **a ) +{ + *s = &g_studio.framecount; + *a = &r_stats.c_studio_models_drawn; +} + +/* +=============== +pfnGetAliasScale + +=============== +*/ +static void pfnGetAliasScale( float *x, float *y ) +{ + if( x ) *x = 1.0f; + if( y ) *y = 1.0f; +} + +/* +=============== +pfnStudioGetBoneTransform + +=============== +*/ +static float ****pfnStudioGetBoneTransform( void ) +{ + return (float ****)g_studio.bonestransform; +} + +/* +=============== +pfnStudioGetLightTransform + +=============== +*/ +static float ****pfnStudioGetLightTransform( void ) +{ + return (float ****)g_studio.lighttransform; +} + +/* +=============== +pfnStudioGetAliasTransform + +=============== +*/ +static float ***pfnStudioGetAliasTransform( void ) +{ + return NULL; +} + +/* +=============== +pfnStudioGetRotationMatrix + +=============== +*/ +static float ***pfnStudioGetRotationMatrix( void ) +{ + return (float ***)g_studio.rotationmatrix; +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +_inline void R_StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3.0f); + + if( *pBlend < pseqdesc->blendstart[0] ) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0f; + *pBlend = 0; + } + else if( *pBlend > pseqdesc->blendend[0] ) + { + *pPitch -= pseqdesc->blendend[0] / 3.0f; + *pBlend = 255; + } + else + { + if( pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1f ) // catch qc error + *pBlend = 127; + else *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0.0f; + } +} + +/* +==================== +R_StudioLerpMovement + +==================== +*/ +void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles ) +{ + float f = 1.0f; + + // don't do it if the goalstarttime hasn't updated in a while. + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + if( g_studio.interpolate && ( time < e->curstate.animtime + 1.0f ) && ( e->curstate.animtime != e->latched.prevanimtime )) + f = ( time - e->curstate.animtime ) / ( e->curstate.animtime - e->latched.prevanimtime ); + + // Con_Printf( "%4.2f %.2f %.2f\n", f, e->curstate.animtime, g_studio.time ); + VectorLerp( e->latched.prevorigin, f, e->curstate.origin, origin ); + + if( !VectorCompareEpsilon( e->curstate.angles, e->latched.prevangles, ON_EPSILON )) + { + vec4_t q, q1, q2; + + AngleQuaternion( e->curstate.angles, q1, false ); + AngleQuaternion( e->latched.prevangles, q2, false ); + QuaternionSlerp( q2, q1, f, q ); + QuaternionAngle( q, angles ); + } + else VectorCopy( e->curstate.angles, angles ); +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void R_StudioSetUpTransform( cl_entity_t *e ) +{ + vec3_t origin, angles; + + VectorCopy( e->origin, origin ); + VectorCopy( e->angles, angles ); + + // interpolate monsters position (moved into UpdateEntityFields by user request) + if( e->curstate.movetype == MOVETYPE_STEP && !FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_COMPUTE_STUDIO_LERP )) + { + R_StudioLerpMovement( e, g_studio.time, origin, angles ); + } + + if( !FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_COMPENSATE_QUAKE_BUG )) + angles[PITCH] = -angles[PITCH]; // stupid quake bug + + // don't rotate clients, only aim + if( e->player ) angles[PITCH] = 0.0f; + + Matrix3x4_CreateFromEntity( g_studio.rotationmatrix, angles, origin, 1.0f ); + + if( tr.fFlipViewModel ) + { + g_studio.rotationmatrix[0][1] = -g_studio.rotationmatrix[0][1]; + g_studio.rotationmatrix[1][1] = -g_studio.rotationmatrix[1][1]; + g_studio.rotationmatrix[2][1] = -g_studio.rotationmatrix[2][1]; + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if( g_studio.interpolate ) + { + if( g_studio.time < e->curstate.animtime ) dfdt = 0.0; + else dfdt = (g_studio.time - e->curstate.animtime) * e->curstate.framerate * pseqdesc->fps; + } + else dfdt = 0; + + if( pseqdesc->numframes <= 1 ) f = 0.0; + else f = (e->curstate.frame * (pseqdesc->numframes - 1)) / 256.0f; + + f += dfdt; + + if( pseqdesc->flags & STUDIO_LOOPING ) + { + if( pseqdesc->numframes > 1 ) + f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + if( f < 0 ) f += (pseqdesc->numframes - 1); + } + else + { + if( f >= pseqdesc->numframes - 1.001 ) + f = pseqdesc->numframes - 1.001; + if( f < 0.0 ) f = 0.0; + } + return f; +} + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float R_StudioEstimateInterpolant( cl_entity_t *e ) +{ + float dadt = 1.0f; + + if( g_studio.interpolate && ( e->curstate.animtime >= e->latched.prevanimtime + 0.01f )) + { + dadt = ( g_studio.time - e->curstate.animtime ) / 0.1f; + if( dadt > 2.0f ) dadt = 2.0f; + } + + return dadt; +} + +/* +==================== +CL_GetSequenceDuration + +==================== +*/ +float CL_GetSequenceDuration( cl_entity_t *ent, int sequence ) +{ + studiohdr_t *pstudiohdr; + mstudioseqdesc_t *pseqdesc; + + if( ent->model != NULL && ent->model->type == mod_studio ) + { + pstudiohdr = (studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, ent->model ); + + if( pstudiohdr ) + { + sequence = bound( 0, sequence, pstudiohdr->numseq - 1 ); + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; + + if( pseqdesc->numframes > 1 && pseqdesc->fps > 0 ) + return (float)pseqdesc->numframes / (float)pseqdesc->fps; + } + } + + return 0.1f; +} + + +/* +==================== +StudioFxTransform + +==================== +*/ +_inline void R_StudioFxTransform( cl_entity_t *ent, matrix3x4 transform ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if( !gEngfuncs.COM_RandomLong( 0, 49 )) + { + int axis = gEngfuncs.COM_RandomLong( 0, 1 ); + + if( axis == 1 ) axis = 2; // choose between x & z + VectorScale( transform[axis], gEngfuncs.COM_RandomFloat( 1.0f, 1.484f ), transform[axis] ); + } + else if( !gEngfuncs.COM_RandomLong( 0, 49 )) + { + float offset; + int axis = gEngfuncs.COM_RandomLong( 0, 1 ); + + if( axis == 1 ) axis = 2; // choose between x & z + offset = gEngfuncs.COM_RandomFloat( -10.0f, 10.0f ); + transform[gEngfuncs.COM_RandomLong( 0, 2 )][3] += offset; + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0f + ( g_studio.time - ent->curstate.animtime ) * 10.0f; + if( scale > 2.0f ) scale = 2.0f; // don't blow up more than 200% + + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; + } + break; + } +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +_inline void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) +{ + mstudiobonecontroller_t *pbonecontroller; + float value = 0.0f; + int i, j; + + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for( j = 0; j < m_pStudioHeader->numbonecontrollers; j++ ) + { + i = pbonecontroller[j].index; + + if( i == STUDIO_MOUTH ) + { + // mouth hardcoded at controller 4 + value = (float)mouthopen / 64.0f; + value = bound( 0.0f, value, 1.0f ); + value = (1.0f - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + else if( i < 4 ) + { + // check for 360% wrapping + if( FBitSet( pbonecontroller[j].type, STUDIO_RLOOP )) + { + if( abs( pcontroller1[i] - pcontroller2[i] ) > 128 ) + { + int a = (pcontroller1[i] + 128) % 256; + int b = (pcontroller2[i] + 128) % 256; + value = (( a * dadt ) + ( b * ( 1.0f - dadt )) - 128) * (360.0f / 256.0f) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0f - dadt))) * (360.0f / 256.0f) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0f - dadt)) / 255.0f; + value = bound( 0.0f, value, 1.0f ); + value = (1.0f - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + } + + switch( pbonecontroller[j].type & STUDIO_TYPES ) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = DEG2RAD( value ); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + +/* +==================== +StudioCalcRotations + +==================== +*/ +void R_StudioCalcRotations( cl_entity_t *e, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +{ + int i, frame; + float adj[MAXSTUDIOCONTROLLERS]; + float s, dadt; + mstudiobone_t *pbone; + + // bah, fix this bug with changing sequences too fast + if( f > pseqdesc->numframes - 1 ) + { + f = 0.0f; + } + else if( f < -0.01f ) + { + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + f = -0.01f; + } + + frame = (int)f; + + dadt = R_StudioEstimateInterpolant( e ); + s = (f - frame); + + // add in programtic controllers + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + R_StudioCalcBoneAdj( dadt, adj, e->curstate.controller, e->latched.prevcontroller, e->mouth.mouthopen ); + + for( i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++ ) + { + gEngfuncs.R_StudioCalcBoneQuaternion( frame, s, pbone, panim, adj, q[i] ); + gEngfuncs.R_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + } + + if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f; + if( pseqdesc->motiontype & STUDIO_Y ) pos[pseqdesc->motionbone][1] = 0.0f; + if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f; +} + +/* +==================== +StudioMergeBones + +==================== +*/ +_inline void R_StudioMergeBones( cl_entity_t *e, model_t *m_pSubModel ) +{ + int i, j; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + matrix3x4 bonematrix; + static vec4_t q[MAXSTUDIOBONES]; + static float pos[MAXSTUDIOBONES][3]; + float f; + + if( e->curstate.sequence >= m_pStudioHeader->numseq ) + e->curstate.sequence = 0; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->curstate.sequence; + + f = R_StudioEstimateFrame( e, pseqdesc ); + + panim = gEngfuncs.R_StudioGetAnim( m_pStudioHeader, m_pSubModel, pseqdesc ); + R_StudioCalcRotations( e, pos, q, pseqdesc, panim, f ); + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + for( j = 0; j < g_studio.cached_numbones; j++ ) + { + if( !Q_stricmp( pbones[i].name, g_studio.cached_bonenames[j] )) + { + Matrix3x4_Copy( g_studio.bonestransform[i], g_studio.cached_bonestransform[j] ); + Matrix3x4_Copy( g_studio.lighttransform[i], g_studio.cached_lighttransform[j] ); + break; + } + } + + if( j >= g_studio.cached_numbones ) + { + Matrix3x4_FromOriginQuat( bonematrix, q[i], pos[i] ); + if( pbones[i].parent == -1 ) + { + Matrix3x4_ConcatTransforms( g_studio.bonestransform[i], g_studio.rotationmatrix, bonematrix ); + Matrix3x4_Copy( g_studio.lighttransform[i], g_studio.bonestransform[i] ); + + // apply client-side effects to the transformation matrix + R_StudioFxTransform( e, g_studio.bonestransform[i] ); + } + else + { + Matrix3x4_ConcatTransforms( g_studio.bonestransform[i], g_studio.bonestransform[pbones[i].parent], bonematrix ); + Matrix3x4_ConcatTransforms( g_studio.lighttransform[i], g_studio.lighttransform[pbones[i].parent], bonematrix ); + } + } + } +} + +/* +==================== +StudioSetupBones + +==================== +*/ +_inline void R_StudioSetupBones( cl_entity_t *e ) +{ + float f; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + matrix3x4 bonematrix; + static vec3_t pos[MAXSTUDIOBONES]; + static vec4_t q[MAXSTUDIOBONES]; + static vec3_t pos2[MAXSTUDIOBONES]; + static vec4_t q2[MAXSTUDIOBONES]; + static vec3_t pos3[MAXSTUDIOBONES]; + static vec4_t q3[MAXSTUDIOBONES]; + static vec3_t pos4[MAXSTUDIOBONES]; + static vec4_t q4[MAXSTUDIOBONES]; + int i; + + if( e->curstate.sequence >= m_pStudioHeader->numseq ) + e->curstate.sequence = 0; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->curstate.sequence; + + f = R_StudioEstimateFrame( e, pseqdesc ); + + panim = gEngfuncs.R_StudioGetAnim( m_pStudioHeader, RI.currentmodel, pseqdesc ); + R_StudioCalcRotations( e, pos, q, pseqdesc, panim, f ); + + if( pseqdesc->numblends > 1 ) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos2, q2, pseqdesc, panim, f ); + + dadt = R_StudioEstimateInterpolant( e ); + s = (e->curstate.blending[0] * dadt + e->latched.prevblending[0] * (1.0f - dadt)) / 255.0f; + + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q, pos, q2, pos2, s ); + + if( pseqdesc->numblends == 4 ) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos4, q4, pseqdesc, panim, f ); + + s = (e->curstate.blending[0] * dadt + e->latched.prevblending[0] * (1.0f - dadt)) / 255.0f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q3, pos3, q4, pos4, s ); + + s = (e->curstate.blending[1] * dadt + e->latched.prevblending[1] * (1.0f - dadt)) / 255.0f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q, pos, q3, pos3, s ); + } + } + + if( g_studio.interpolate && e->latched.sequencetime && ( e->latched.sequencetime + 0.2f > g_studio.time ) && ( e->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static vec3_t pos1b[MAXSTUDIOBONES]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->latched.prevsequence; + panim = gEngfuncs.R_StudioGetAnim( m_pStudioHeader, RI.currentmodel, pseqdesc ); + + // clip prevframe + R_StudioCalcRotations( e, pos1b, q1b, pseqdesc, panim, e->latched.prevframe ); + + if( pseqdesc->numblends > 1 ) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos2, q2, pseqdesc, panim, e->latched.prevframe ); + + s = (e->latched.prevseqblending[0]) / 255.0f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q1b, pos1b, q2, pos2, s ); + + if( pseqdesc->numblends == 4 ) + { + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos3, q3, pseqdesc, panim, e->latched.prevframe ); + + panim += m_pStudioHeader->numbones; + R_StudioCalcRotations( e, pos4, q4, pseqdesc, panim, e->latched.prevframe ); + + s = (e->latched.prevseqblending[0]) / 255.0f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q3, pos3, q4, pos4, s ); + + s = (e->latched.prevseqblending[1]) / 255.0f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0f - ( g_studio.time - e->latched.sequencetime ) / 0.2f; + gEngfuncs.R_StudioSlerpBones( m_pStudioHeader->numbones, q, pos, q1b, pos1b, s ); + } + else + { + // store prevframe otherwise + e->latched.prevframe = f; + } + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) + { + qboolean copy_bones = true; + + if( m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq ) + m_pPlayerInfo->gaitsequence = 0; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + + panim = gEngfuncs.R_StudioGetAnim( m_pStudioHeader, RI.currentmodel, pseqdesc ); + R_StudioCalcRotations( e, pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + if( !Q_strcmp( pbones[i].name, "Bip01 Spine" )) + copy_bones = false; + else if( !Q_strcmp( pbones[pbones[i].parent].name, "Bip01 Pelvis" )) + copy_bones = true; + + if( !copy_bones ) continue; + + VectorCopy( pos2[i], pos[i] ); + Vector4Copy( q2[i], q[i] ); + } + } + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + Matrix3x4_FromOriginQuat( bonematrix, q[i], pos[i] ); + + if( pbones[i].parent == -1 ) + { + Matrix3x4_ConcatTransforms( g_studio.bonestransform[i], g_studio.rotationmatrix, bonematrix ); + Matrix3x4_Copy( g_studio.lighttransform[i], g_studio.bonestransform[i] ); + + // apply client-side effects to the transformation matrix + R_StudioFxTransform( e, g_studio.bonestransform[i] ); + } + else + { + Matrix3x4_ConcatTransforms( g_studio.bonestransform[i], g_studio.bonestransform[pbones[i].parent], bonematrix ); + Matrix3x4_ConcatTransforms( g_studio.lighttransform[i], g_studio.lighttransform[pbones[i].parent], bonematrix ); + } + } +} + +/* +==================== +StudioSaveBones + +==================== +*/ +_inline void R_StudioSaveBones( void ) +{ + mstudiobone_t *pbones; + int i; + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + g_studio.cached_numbones = m_pStudioHeader->numbones; + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + Matrix3x4_Copy( g_studio.cached_bonestransform[i], g_studio.bonestransform[i] ); + Matrix3x4_Copy( g_studio.cached_lighttransform[i], g_studio.lighttransform[i] ); + Q_strncpy( g_studio.cached_bonenames[i], pbones[i].name, 32 ); + } +} + +/* +==================== +StudioBuildNormalTable + +NOTE: m_pSubModel must be set +==================== +*/ +_inline void R_StudioBuildNormalTable( void ) +{ + cl_entity_t *e = RI.currententity; + mstudiomesh_t *pmesh; + int i, j; + + Assert( m_pSubModel != NULL ); + + // reset chrome cache + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + g_studio.chromeage[i] = 0; + + for( i = 0; i < m_pSubModel->numverts; i++ ) + g_studio.normaltable[i] = -1; + + for( j = 0; j < m_pSubModel->nummesh; j++ ) + { + short *ptricmds; + + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; + ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + + while(( i = *( ptricmds++ ))) + { + if( i < 0 ) i = -i; + + for( ; i > 0; i--, ptricmds += 4 ) + { + if( g_studio.normaltable[ptricmds[0]] < 0 ) + g_studio.normaltable[ptricmds[0]] = ptricmds[1]; + } + } + } + + g_studio.chrome_origin[0] = cos( r_glowshellfreq->value * g_studio.time ) * 4000.0f; + g_studio.chrome_origin[1] = sin( r_glowshellfreq->value * g_studio.time ) * 4000.0f; + g_studio.chrome_origin[2] = cos( r_glowshellfreq->value * g_studio.time * 0.33f ) * 4000.0f; + + if( e->curstate.rendercolor.r || e->curstate.rendercolor.g || e->curstate.rendercolor.b ) + TriColor4ub( e->curstate.rendercolor.r, e->curstate.rendercolor.g, e->curstate.rendercolor.b, 255 ); + else TriColor4ub( 255, 255, 255, 255 ); +} + +/* +==================== +StudioGenerateNormals + +NOTE: m_pSubModel must be set +g_studio.verts must be computed +==================== +*/ +_inline void R_StudioGenerateNormals( void ) +{ + int v0, v1, v2; + vec3_t e0, e1, norm; + mstudiomesh_t *pmesh; + int i, j; + + Assert( m_pSubModel != NULL ); + + for( i = 0; i < m_pSubModel->numverts; i++ ) + VectorClear( g_studio.norms[i] ); + + for( j = 0; j < m_pSubModel->nummesh; j++ ) + { + short *ptricmds; + + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + j; + ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + + while(( i = *( ptricmds++ ))) + { + if( i < 0 ) + { + i = -i; + + if( i > 2 ) + { + v0 = ptricmds[0]; ptricmds += 4; + v1 = ptricmds[0]; ptricmds += 4; + + for( i -= 2; i > 0; i--, ptricmds += 4 ) + { + v2 = ptricmds[0]; + + VectorSubtract( g_studio.verts[v1], g_studio.verts[v0], e0 ); + VectorSubtract( g_studio.verts[v2], g_studio.verts[v0], e1 ); + CrossProduct( e1, e0, norm ); + + VectorAdd( g_studio.norms[v0], norm, g_studio.norms[v0] ); + VectorAdd( g_studio.norms[v1], norm, g_studio.norms[v1] ); + VectorAdd( g_studio.norms[v2], norm, g_studio.norms[v2] ); + + v1 = v2; + } + } + else + { + ptricmds += i; + } + } + else + { + if( i > 2 ) + { + qboolean odd = false; + + v0 = ptricmds[0]; ptricmds += 4; + v1 = ptricmds[0]; ptricmds += 4; + + for( i -= 2; i > 0; i--, ptricmds += 4 ) + { + v2 = ptricmds[0]; + + VectorSubtract( g_studio.verts[v1], g_studio.verts[v0], e0 ); + VectorSubtract( g_studio.verts[v2], g_studio.verts[v0], e1 ); + CrossProduct( e1, e0, norm ); + + VectorAdd( g_studio.norms[v0], norm, g_studio.norms[v0] ); + VectorAdd( g_studio.norms[v1], norm, g_studio.norms[v1] ); + VectorAdd( g_studio.norms[v2], norm, g_studio.norms[v2] ); + + if( odd ) v1 = v2; + else v0 = v2; + + odd = !odd; + } + } + else + { + ptricmds += i; + } + } + } + } + + for( i = 0; i < m_pSubModel->numverts; i++ ) + VectorNormalize( g_studio.norms[i] ); +} + +/* +==================== +StudioSetupChrome + +==================== +*/ +_inline void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal ) +{ + float n; + + if( g_studio.chromeage[bone] != g_studio.framecount ) + { + // calculate vectors from the viewer to the bone. This roughly adjusts for position + vec3_t chromeupvec; // g_studio.chrome t vector in world reference frame + vec3_t chromerightvec; // g_studio.chrome s vector in world reference frame + vec3_t tmp; // vector pointing at bone in world reference frame + + VectorNegate( g_studio.chrome_origin, tmp ); + tmp[0] += g_studio.bonestransform[bone][0][3]; + tmp[1] += g_studio.bonestransform[bone][1][3]; + tmp[2] += g_studio.bonestransform[bone][2][3]; + + VectorNormalize( tmp ); + CrossProduct( tmp, RI.vright, chromeupvec ); + VectorNormalize( chromeupvec ); + CrossProduct( tmp, chromeupvec, chromerightvec ); + VectorNormalize( chromerightvec ); + + Matrix3x4_VectorIRotate( g_studio.bonestransform[bone], chromeupvec, g_studio.chromeup[bone] ); + Matrix3x4_VectorIRotate( g_studio.bonestransform[bone], chromerightvec, g_studio.chromeright[bone] ); + + g_studio.chromeage[bone] = g_studio.framecount; + } + + // calc s coord + n = DotProduct( normal, g_studio.chromeright[bone] ); + pchrome[0] = (n + 1.0f) * 32.0f; + + // calc t coord + n = DotProduct( normal, g_studio.chromeup[bone] ); + pchrome[1] = (n + 1.0f) * 32.0f; +} + +/* +==================== +StudioCalcAttachments + +==================== +*/ +_inline void R_StudioCalcAttachments( void ) +{ + mstudioattachment_t *pAtt; + int i; + + // calculate attachment points + pAtt = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + + for( i = 0; i < Q_min( MAXSTUDIOATTACHMENTS, m_pStudioHeader->numattachments ); i++ ) + { + Matrix3x4_VectorTransform( g_studio.lighttransform[pAtt[i].bone], pAtt[i].org, RI.currententity->attachment[i] ); + } +} + +/* +=============== +pfnStudioSetupModel + +=============== +*/ +static void R_StudioSetupModel( int bodypart, void **ppbodypart, void **ppsubmodel ) +{ + int index; + + if( bodypart > m_pStudioHeader->numbodyparts ) + bodypart = 0; + + m_pBodyPart = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex) + bodypart; + + index = RI.currententity->curstate.body / m_pBodyPart->base; + index = index % m_pBodyPart->nummodels; + + m_pSubModel = (mstudiomodel_t *)((byte *)m_pStudioHeader + m_pBodyPart->modelindex) + index; + + if( ppbodypart ) *ppbodypart = m_pBodyPart; + if( ppsubmodel ) *ppsubmodel = m_pSubModel; +} + +/* +=============== +R_StudioCheckBBox + +=============== +*/ +static int R_StudioCheckBBox( void ) +{ + if( !RI.currententity || !RI.currentmodel ) + return false; + + return R_StudioComputeBBox( NULL ); +} + +/* +=============== +R_StudioDynamicLight + +=============== +*/ +void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight ) +{ + movevars_t *mv = gEngfuncs.pfnGetMoveVars(); + vec3_t lightDir, vecSrc, vecEnd; + vec3_t origin, dist, finalLight; + float add, radius, total; + colorVec light; + uint lnum; + dlight_t *dl; + + if( !plight || !ent || !ent->model ) + return; + + if( !RI.drawWorld || r_fullbright->value || FBitSet( ent->curstate.effects, EF_FULLBRIGHT )) + { + plight->shadelight = 0; + plight->ambientlight = 192; + + VectorSet( plight->plightvec, 0.0f, 0.0f, -1.0f ); + VectorSet( plight->color, 1.0f, 1.0f, 1.0f ); + return; + } + + // determine plane to get lightvalues from: ceil or floor + if( FBitSet( ent->curstate.effects, EF_INVLIGHT )) + VectorSet( lightDir, 0.0f, 0.0f, 1.0f ); + else VectorSet( lightDir, 0.0f, 0.0f, -1.0f ); + + VectorCopy( ent->origin, origin ); + + VectorSet( vecSrc, origin[0], origin[1], origin[2] - lightDir[2] * 8.0f ); + light.r = light.g = light.b = light.a = 0; + + if(( mv->skycolor_r + mv->skycolor_g + mv->skycolor_b ) != 0 ) + { + msurface_t *psurf = NULL; + pmtrace_t trace; + + if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_WRITE_LARGE_COORD )) + { + vecEnd[0] = origin[0] - mv->skyvec_x * 65536.0f; + vecEnd[1] = origin[1] - mv->skyvec_y * 65536.0f; + vecEnd[2] = origin[2] - mv->skyvec_z * 65536.0f; + } + else + { + vecEnd[0] = origin[0] - mv->skyvec_x * 8192.0f; + vecEnd[1] = origin[1] - mv->skyvec_y * 8192.0f; + vecEnd[2] = origin[2] - mv->skyvec_z * 8192.0f; + } + + trace = gEngfuncs.CL_TraceLine( vecSrc, vecEnd, PM_WORLD_ONLY ); + if( trace.ent > 0 ) psurf = gEngfuncs.EV_TraceSurface( trace.ent, vecSrc, vecEnd ); + else psurf = gEngfuncs.EV_TraceSurface( 0, vecSrc, vecEnd ); + + if( FBitSet( ent->model->flags, STUDIO_FORCE_SKYLIGHT ) || ( psurf && FBitSet( psurf->flags, SURF_DRAWSKY ))) + { + VectorSet( lightDir, mv->skyvec_x, mv->skyvec_y, mv->skyvec_z ); + + light.r = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_r, 255 )); + light.g = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_g, 255 )); + light.b = gEngfuncs.LightToTexGamma( bound( 0, mv->skycolor_b, 255 )); + } + } + + if(( light.r + light.g + light.b ) < 16 ) // TESTTEST + { + colorVec gcolor; + float grad[4]; + + VectorScale( lightDir, 2048.0f, vecEnd ); + VectorAdd( vecEnd, vecSrc, vecEnd ); + + light = R_LightVec( vecSrc, vecEnd, g_studio.lightspot, g_studio.lightvec ); + + if( VectorIsNull( g_studio.lightvec )) + { + vecSrc[0] -= 16.0f; + vecSrc[1] -= 16.0f; + vecEnd[0] -= 16.0f; + vecEnd[1] -= 16.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[0] += 32.0f; + vecEnd[0] += 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[1] += 32.0f; + vecEnd[1] += 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + vecSrc[0] -= 32.0f; + vecEnd[0] -= 32.0f; + + gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL ); + grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f; + + lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3]; + lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3]; + VectorNormalize( lightDir ); + } + else + { + VectorCopy( g_studio.lightvec, lightDir ); + } + } + + VectorSet( finalLight, light.r, light.g, light.b ); + ent->cvFloorColor = light; + + total = Q_max( Q_max( light.r, light.g ), light.b ); + if( total == 0.0f ) total = 1.0f; + + // scale lightdir by light intentsity + VectorScale( lightDir, total, lightDir ); + + for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + { + dl = gEngfuncs.GetDynamicLight( lnum ); + + if( dl->die < g_studio.time || !r_dynamic->value ) + continue; + + VectorSubtract( ent->origin, dl->origin, dist ); + + radius = VectorLength( dist ); + add = (dl->radius - radius); + + if( add > 0.0f ) + { + total += add; + + if( radius > 1.0f ) + VectorScale( dist, ( add / radius ), dist ); + else VectorScale( dist, add, dist ); + + VectorAdd( lightDir, dist, lightDir ); + + finalLight[0] += gEngfuncs.LightToTexGamma( dl->color.r ) * ( add / 256.0f ) * 2.0f; + finalLight[1] += gEngfuncs.LightToTexGamma( dl->color.g ) * ( add / 256.0f ) * 2.0f; + finalLight[2] += gEngfuncs.LightToTexGamma( dl->color.b ) * ( add / 256.0f ) * 2.0f; + } + } + + if( FBitSet( ent->model->flags, STUDIO_AMBIENT_LIGHT )) + add = 0.6f; + else add = 0.9f; + + VectorScale( lightDir, add, lightDir ); + + plight->shadelight = VectorLength( lightDir ); + plight->ambientlight = total - plight->shadelight; + + total = Q_max( Q_max( finalLight[0], finalLight[1] ), finalLight[2] ); + + if( total > 0.0f ) + { + plight->color[0] = finalLight[0] * ( 1.0f / total ); + plight->color[1] = finalLight[1] * ( 1.0f / total ); + plight->color[2] = finalLight[2] * ( 1.0f / total ); + } + else VectorSet( plight->color, 1.0f, 1.0f, 1.0f ); + + if( plight->ambientlight > 128 ) + plight->ambientlight = 128; + + if( plight->ambientlight + plight->shadelight > 255 ) + plight->shadelight = 255 - plight->ambientlight; + + VectorNormalize2( lightDir, plight->plightvec ); +} + +/* +=============== +pfnStudioEntityLight + +=============== +*/ +void R_StudioEntityLight( alight_t *lightinfo ) +{ + int lnum, i, j, k; + float minstrength, dist2, f, r2; + float lstrength[MAX_LOCALLIGHTS]; + cl_entity_t *ent = RI.currententity; + vec3_t mid, origin, pos; + dlight_t *el; + + g_studio.numlocallights = 0; + + if( !ent || !r_dynamic->value ) + return; + + for( i = 0; i < MAX_LOCALLIGHTS; i++ ) + lstrength[i] = 0; + + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, origin ); + dist2 = 1000000.0f; + k = 0; + + for( lnum = 0; lnum < MAX_ELIGHTS; lnum++ ) + { + el = gEngfuncs.GetEntityLight( lnum ); + + if( el->die < g_studio.time || el->radius <= 0.0f ) + continue; + + if(( el->key & 0xFFF ) == ent->index ) + { + int att = (el->key >> 12) & 0xF; + + if( att ) VectorCopy( ent->attachment[att], el->origin ); + else VectorCopy( ent->origin, el->origin ); + } + + VectorCopy( el->origin, pos ); + VectorSubtract( origin, el->origin, mid ); + + f = DotProduct( mid, mid ); + r2 = el->radius * el->radius; + + if( f > r2 ) minstrength = r2 / f; + else minstrength = 1.0f; + + if( minstrength > 0.05f ) + { + if( g_studio.numlocallights >= MAX_LOCALLIGHTS ) + { + for( j = 0, k = -1; j < g_studio.numlocallights; j++ ) + { + if( lstrength[j] < dist2 && lstrength[j] < minstrength ) + { + dist2 = lstrength[j]; + k = j; + } + } + } + else k = g_studio.numlocallights; + + if( k != -1 ) + { + g_studio.locallightcolor[k].r = gEngfuncs.LightToTexGamma( el->color.r ); + g_studio.locallightcolor[k].g = gEngfuncs.LightToTexGamma( el->color.g ); + g_studio.locallightcolor[k].b = gEngfuncs.LightToTexGamma( el->color.b ); + g_studio.locallightR2[k] = r2; + g_studio.locallight[k] = el; + lstrength[k] = minstrength; + + if( k >= g_studio.numlocallights ) + g_studio.numlocallights = k + 1; + } + } + } +} + +/* +=============== +R_StudioSetupLighting + +=============== +*/ +void R_StudioSetupLighting( alight_t *plight ) +{ + float scale = 1.0f; + int i; + + if( !m_pStudioHeader || !plight ) + return; + + if( RI.currententity != NULL ) + scale = RI.currententity->curstate.scale; + + g_studio.ambientlight = plight->ambientlight; + g_studio.shadelight = plight->shadelight; + VectorCopy( plight->plightvec, g_studio.lightvec ); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + Matrix3x4_VectorIRotate( g_studio.lighttransform[i], plight->plightvec, g_studio.blightvec[i] ); + if( scale > 1.0f ) VectorNormalize( g_studio.blightvec[i] ); // in case model may be scaled + } + + VectorCopy( plight->color, g_studio.lightcolor ); +} + +/* +=============== +R_StudioLighting + +=============== +*/ +_inline void R_StudioLighting( float *lv, int bone, int flags, vec3_t normal ) +{ + float illum; + + if( FBitSet( flags, STUDIO_NF_FULLBRIGHT )) + { + *lv = 1.0f; + return; + } + + illum = g_studio.ambientlight; + + if( FBitSet( flags, STUDIO_NF_FLATSHADE )) + { + illum += g_studio.shadelight * 0.8f; + } + else + { + float r, lightcos; + + if( bone != -1 ) lightcos = DotProduct( normal, g_studio.blightvec[bone] ); + else lightcos = DotProduct( normal, g_studio.lightvec ); // -1 colinear, 1 opposite + if( lightcos > 1.0f ) lightcos = 1.0f; + + illum += g_studio.shadelight; + + r = SHADE_LAMBERT; + + // do modified hemispherical lighting + if( r <= 1.0f ) + { + r += 1.0f; + lightcos = (( r - 1.0f ) - lightcos) / r; + if( lightcos > 0.0f ) + illum += g_studio.shadelight * lightcos; + } + else + { + lightcos = (lightcos + ( r - 1.0f )) / r; + if( lightcos > 0.0f ) + illum -= g_studio.shadelight * lightcos; + } + + illum = Q_max( illum, 0.0f ); + } + + illum = Q_min( illum, 255.0f ); + *lv = illum * ( 1.0f / 255.0f ); +} + +/* +==================== +R_LightLambert + +==================== +*/ +_inline void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color, byte *out ) +{ + vec3_t finalLight; + vec3_t localLight; + int i; + + VectorCopy( color, finalLight ); + + for( i = 0; i < g_studio.numlocallights; i++ ) + { + float r, r2; + + if( tr.fFlipViewModel ) + r = DotProduct( normal, light[i] ); + else r = -DotProduct( normal, light[i] ); + + if( r > 0.0f ) + { + if( light[i][3] == 0.0f ) + { + r2 = DotProduct( light[i], light[i] ); + + if( r2 > 0.0f ) + light[i][3] = g_studio.locallightR2[i] / ( r2 * sqrt( r2 )); + else light[i][3] = 0.0001f; + } + + localLight[0] = Q_min( g_studio.locallightcolor[i].r * r * light[i][3], 255.0f ); + localLight[1] = Q_min( g_studio.locallightcolor[i].g * r * light[i][3], 255.0f ); + localLight[2] = Q_min( g_studio.locallightcolor[i].b * r * light[i][3], 255.0f ); + VectorScale( localLight, ( 1.0f / 255.0f ), localLight ); + + finalLight[0] = Q_min( finalLight[0] + localLight[0], 1.0f ); + finalLight[1] = Q_min( finalLight[1] + localLight[1], 1.0f ); + finalLight[2] = Q_min( finalLight[2] + localLight[2], 1.0f ); + } + } + + out[0] = finalLight[0] * 255; + out[1] = finalLight[1] * 255; + out[2] = finalLight[2] * 255; +} + +#if 0 /* R_StudioSetColorArray used */ +static void R_StudioSetColorBegin(short *ptricmds, vec3_t *pstudionorms ) +{ + float *lv = (float *)g_studio.lightvalues[ptricmds[1]]; + rgba_t color; + + if( g_studio.numlocallights ) + { + color[3] = tr.blend * 255; + R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color ); + pglColor4ubv( color ); + } + else + { + if( RI.currententity->curstate.rendermode == kRenderTransColor ) + { + color[3] = tr.blend * 255; + VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color ); + pglColor4ubv( color ); + } + else pglColor4f( lv[0], lv[1], lv[2], tr.blend ); + } +} +#endif + +_inline void R_StudioSetColorArray(short *ptricmds, vec3_t *pstudionorms, byte *color ) +{ + float *lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + color[3] = tr.blend * 255; + + if( g_studio.numlocallights ) + R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color ); + else + { + if( RI.currententity->curstate.rendermode == kRenderTransColor ) + VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color ); + else + { + color[0] = lv[0] * 255; + color[1] = lv[1] * 255; + color[2] = lv[2] * 255; + } + } +} + +/* +==================== +R_LightStrength + +==================== +*/ +_inline void R_LightStrength( int bone, vec3_t localpos, vec4_t light[MAX_LOCALLIGHTS] ) +{ + int i; + + if( g_studio.lightage[bone] != g_studio.framecount ) + { + for( i = 0; i < g_studio.numlocallights; i++ ) + { + dlight_t *el = g_studio.locallight[i]; + Matrix3x4_VectorITransform( g_studio.lighttransform[bone], el->origin, g_studio.lightbonepos[bone][i] ); + } + + g_studio.lightage[bone] = g_studio.framecount; + } + + for( i = 0; i < g_studio.numlocallights; i++ ) + { + VectorSubtract( localpos, g_studio.lightbonepos[bone][i], light[i] ); + light[i][3] = 0.0f; + } +} + +/* +=============== +R_StudioSetupSkin + +=============== +*/ +static void R_StudioSetupSkin( studiohdr_t *ptexturehdr, int index ) +{ + mstudiotexture_t *ptexture = NULL; + + if( FBitSet( g_nForceFaceFlags, STUDIO_NF_CHROME )) + return; + + if( ptexturehdr == NULL ) + return; + + // NOTE: user may ignore to call StudioRemapColors and remap_info will be unavailable + if( m_fDoRemap ) ptexture = gEngfuncs.CL_GetRemapInfoForEntity( RI.currententity )->ptexture; + if( !ptexture ) ptexture = (mstudiotexture_t *)((byte *)ptexturehdr + ptexturehdr->textureindex); // fallback + + if( r_lightmap->value && !r_fullbright->value ) + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + else GL_Bind( XASH_TEXTURE0, ptexture[index].index ); +} + +/* +=============== +R_StudioGetTexture + +Doesn't changes studio global state at all +=============== +*/ +mstudiotexture_t *R_StudioGetTexture( cl_entity_t *e ) +{ + mstudiotexture_t *ptexture; + studiohdr_t *phdr, *thdr; + + if(( phdr = gEngfuncs.Mod_Extradata( mod_studio, e->model )) == NULL ) + return NULL; + + thdr = m_pStudioHeader; + if( !thdr ) return NULL; + + if( m_fDoRemap ) ptexture = gEngfuncs.CL_GetRemapInfoForEntity( e )->ptexture; + else ptexture = (mstudiotexture_t *)((byte *)thdr + thdr->textureindex); + + return ptexture; +} + +void R_StudioSetRenderamt( int iRenderamt ) +{ + if( !RI.currententity ) return; + + RI.currententity->curstate.renderamt = iRenderamt; + tr.blend = CL_FxBlend( RI.currententity ) / 255.0f; +} + +/* +=============== +R_StudioSetCullState + +sets true for enable backculling (for left-hand viewmodel) +=============== +*/ +void R_StudioSetCullState( int iCull ) +{ + g_iBackFaceCull = iCull; +} + +/* +=============== +R_StudioRenderShadow + +just a prefab for render shadow +=============== +*/ +void R_StudioRenderShadow( int iSprite, float *p1, float *p2, float *p3, float *p4 ) +{ + if( !p1 || !p2 || !p3 || !p4 ) + return; + + if( TriSpriteTexture( gEngfuncs.pfnGetModelByIndex( iSprite ), 0 )) + { + TriRenderMode( kRenderTransAlpha ); + TriColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); +#if 1 + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); + out[0].uv[0] = 0.0f; + out[0].uv[1] = 0.0f; + VectorCopy( p1, out[0].xyz ); + out[1].uv[0] = 0.0f; + out[1].uv[1] = 0.1f; + VectorCopy( p2, out[1].xyz ); + out[2].uv[0] = 1.0f; + out[2].uv[1] = 1.0f; + VectorCopy( p3, out[2].xyz ); + out[3].uv[0] = 1.0f; + out[3].uv[1] = 0.0f; + VectorCopy( p4, out[3].xyz ); + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); +#else + pglBegin( GL_QUADS ); + pglTexCoord2f( 0.0f, 0.0f ); + pglVertex3fv( p1 ); + pglTexCoord2f( 0.0f, 1.0f ); + pglVertex3fv( p2 ); + pglTexCoord2f( 1.0f, 1.0f ); + pglVertex3fv( p3 ); + pglTexCoord2f( 1.0f, 0.0f ); + pglVertex3fv( p4 ); + pglEnd(); +#endif + TriRenderMode( kRenderNormal ); + } +} + +/* +=============== +R_StudioMeshCompare + +Sorting opaque entities by model type +=============== +*/ +static int R_StudioMeshCompare( const void *a, const void *b ) +{ + if( FBitSet( ((const sortedmesh_t*)a)->flags, STUDIO_NF_ADDITIVE )) + return 1; + + if( FBitSet( ((const sortedmesh_t*)a)->flags, STUDIO_NF_MASKED )) + return -1; + + return 0; +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t ) +{ + float *lv; + int i, prim, index; + + while(( i = *( ptricmds++ ))) + { + if( i < 0 ) + { + prim = GU_TRIANGLE_FAN; + i = -i; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )sceGuGetMemory( sizeof( gu_vert_ftcv_t ) * i ); + + for( index = 0; index < i; index++, ptricmds += 4 ) + { + byte color[4]; + R_StudioSetColorArray( ptricmds, pstudionorms, color ); + out[index].u = ptricmds[2] * s; + out[index].v = ptricmds[3] * t; + out[index].c = GUCOLOR4UBV( color ); + out[index].x = g_studio.verts[ptricmds[0]][0]; + out[index].y = g_studio.verts[ptricmds[0]][1]; + out[index].z = g_studio.verts[ptricmds[0]][2]; + } + sceGuDrawArray( prim, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, i, 0, out ); + } +} + +/* +=============== +R_StudioDrawFloatMesh + +generic path +=============== +*/ +_inline void R_StudioDrawFloatMesh( short *ptricmds, vec3_t *pstudionorms ) +{ + float *lv; + int i, prim, index; + + while(( i = *( ptricmds++ ))) + { + if( i < 0 ) + { + prim = GU_TRIANGLE_FAN; + i = -i; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )sceGuGetMemory( sizeof( gu_vert_ftcv_t ) * i ); + + for( index = 0; index < i; index++, ptricmds += 4 ) + { + byte color[4]; + R_StudioSetColorArray( ptricmds, pstudionorms, color ); + out[index].u = HalfToFloat( ptricmds[2] ); + out[index].u = HalfToFloat( ptricmds[3] ); + out[index].c = GUCOLOR4UBV( color ); + out[index].x = g_studio.verts[ptricmds[0]][0]; + out[index].y = g_studio.verts[ptricmds[0]][1]; + out[index].z = g_studio.verts[ptricmds[0]][2]; + } + sceGuDrawArray( prim, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, i, 0, out ); + } +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t, float scale ) +{ + float *lv, *av; + int i, idx, prim, index; + qboolean glowShell = (scale > 0.0f) ? true : false; + vec3_t vert; + byte color[4]; + + while(( i = *( ptricmds++ ))) + { + if( i < 0 ) + { + prim = GU_TRIANGLE_FAN; + i = -i; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )sceGuGetMemory( sizeof( gu_vert_ftcv_t ) * i ); + + for( index = 0; index < i; index++, ptricmds += 4 ) + { + if( glowShell ) + { + color24 *clr = &RI.currententity->curstate.rendercolor; + + idx = g_studio.normaltable[ptricmds[0]]; + av = g_studio.verts[ptricmds[0]]; + lv = g_studio.norms[ptricmds[0]]; + VectorMA( av, scale, lv, vert ); + out[index].u = g_studio.chrome[idx][0] * s; + out[index].v = g_studio.chrome[idx][1] * t; + out[index].c = GUCOLOR4UB( clr->r, clr->g, clr->b, 255 ); + out[index].x = vert[0]; + out[index].y = vert[1]; + out[index].z = vert[2]; + } + else + { + idx = ptricmds[1]; + //lv = (float *)g_studio.lightvalues[ptricmds[1]]; //unused + R_StudioSetColorArray( ptricmds, pstudionorms, color ); + out[index].u = g_studio.chrome[idx][0] * s; + out[index].v = g_studio.chrome[idx][1] * t; + out[index].c = GUCOLOR4UBV( color ); + out[index].x = g_studio.verts[ptricmds[0]][0]; + out[index].y = g_studio.verts[ptricmds[0]][1]; + out[index].z = g_studio.verts[ptricmds[0]][2]; + } + } + sceGuDrawArray( prim, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, i, 0, out ); + } +} + + +_inline int R_StudioBuildIndices( qboolean tri_strip, int vertexState ) +{ + // build in indices + if( vertexState++ < 3 ) + { + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + else if( tri_strip ) + { + // flip triangles between clockwise and counter clockwise + if( vertexState & 1 ) + { + // draw triangle [n-2 n-1 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + else + { + // draw triangle [n-1 n-2 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + } + else + { + // draw triangle fan [0 n-1 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - ( vertexState - 1 ); + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + + return vertexState; +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayNormalMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t ) +{ + float *lv; + int i; + float alpha = tr.blend; + + while(( i = *( ptricmds++ ))) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { +#if 1 + byte cl[4]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; /* unused */ + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arrayverts[g_studio.numverts].u = ptricmds[2] * s; + g_studio.arrayverts[g_studio.numverts].v = ptricmds[3] * t; + g_studio.arrayverts[g_studio.numverts].c = GUCOLOR4UBV( cl ); + g_studio.arrayverts[g_studio.numverts].x = g_studio.verts[ptricmds[0]][0]; + g_studio.arrayverts[g_studio.numverts].y = g_studio.verts[ptricmds[0]][1]; + g_studio.arrayverts[g_studio.numverts].z = g_studio.verts[ptricmds[0]][2]; + g_studio.numverts++; +#else + GLubyte *cl; + + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arraycoord[g_studio.numverts][0] = ptricmds[2] * s; + g_studio.arraycoord[g_studio.numverts][1] = ptricmds[3] * t; + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + g_studio.numverts++; +#endif + } + } +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayFloatMesh( short *ptricmds, vec3_t *pstudionorms ) +{ + float *lv; + int i; + float alpha = tr.blend; + + while(( i = *( ptricmds++ ))) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { +#if 1 + byte cl[4]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; /* unused */ + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); +#if 0 + __asm__ volatile ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S000, 4(%0)\n" // S000 = ptricmds[2], S001 = ptricmds[3] + "vh2f.s C000, S000\n" // S000 = ptricmds[2], S001 = ptricmds[3] + "sv.s S000, 0(%1)\n" // out[index].u = S000 = ptricmds[2] + "sv.s S001, 4(%1)\n" // out[index].v = S001 = ptricmds[3] + ".set pop\n" // restore assembler option + :: "r"( ptricmds ), "r"( &g_studio.arrayverts[g_studio.numverts] ) + ); +#else + g_studio.arrayverts[g_studio.numverts].u = HalfToFloat( ptricmds[2] ); + g_studio.arrayverts[g_studio.numverts].v = HalfToFloat( ptricmds[3] ); /* Error fixed */ +#endif + g_studio.arrayverts[g_studio.numverts].u = HalfToFloat( ptricmds[2] ); + g_studio.arrayverts[g_studio.numverts].v = HalfToFloat( ptricmds[3] ); /* Error fixed */ + g_studio.arrayverts[g_studio.numverts].c = GUCOLOR4UBV( cl ); + g_studio.arrayverts[g_studio.numverts].x = g_studio.verts[ptricmds[0]][0]; + g_studio.arrayverts[g_studio.numverts].y = g_studio.verts[ptricmds[0]][1]; + g_studio.arrayverts[g_studio.numverts].z = g_studio.verts[ptricmds[0]][2]; + g_studio.numverts++; +#else + GLubyte *cl; + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arraycoord[g_studio.numverts][0] = HalfToFloat( ptricmds[2] ); + g_studio.arraycoord[g_studio.numverts][1] = HalfToFloat( ptricmds[2] ); + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + g_studio.numverts++; +#endif + } + } +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayChromeMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t, float scale ) +{ + float *lv, *av; + int i, idx; + qboolean glowShell = (scale > 0.0f) ? true : false; + vec3_t vert; + float alpha = tr.blend; + + while(( i = *( ptricmds++ ))) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { +#if 1 + byte cl[4]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; /* unused */ + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + if( glowShell ) + { + idx = g_studio.normaltable[ptricmds[0]]; + av = g_studio.verts[ptricmds[0]]; + lv = g_studio.norms[ptricmds[0]]; + + cl[0] = RI.currententity->curstate.rendercolor.r; + cl[1] = RI.currententity->curstate.rendercolor.g; + cl[2] = RI.currententity->curstate.rendercolor.b; + cl[3] = 255; + + VectorMA( av, scale, lv, vert ); + + g_studio.arrayverts[g_studio.numverts].x = vert[0]; + g_studio.arrayverts[g_studio.numverts].y = vert[1]; + g_studio.arrayverts[g_studio.numverts].z = vert[2]; + } + else + { + idx = ptricmds[1]; + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arrayverts[g_studio.numverts].x = g_studio.verts[ptricmds[0]][0]; + g_studio.arrayverts[g_studio.numverts].y = g_studio.verts[ptricmds[0]][1]; + g_studio.arrayverts[g_studio.numverts].z = g_studio.verts[ptricmds[0]][2]; + } + + g_studio.arrayverts[g_studio.numverts].u = g_studio.chrome[idx][0] * s; + g_studio.arrayverts[g_studio.numverts].v = g_studio.chrome[idx][1] * t; + g_studio.arrayverts[g_studio.numverts].c = GUCOLOR4UBV( cl ); + g_studio.numverts++; +#else + GLubyte *cl; + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + if( glowShell ) + { + idx = g_studio.normaltable[ptricmds[0]]; + av = g_studio.verts[ptricmds[0]]; + lv = g_studio.norms[ptricmds[0]]; + + cl[0] = RI.currententity->curstate.rendercolor.r; + cl[1] = RI.currententity->curstate.rendercolor.g; + cl[2] = RI.currententity->curstate.rendercolor.b; + cl[3] = 255; + + VectorMA( av, scale, lv, vert ); + VectorCopy( vert, g_studio.arrayverts[g_studio.numverts] ); + } + else + { + idx = ptricmds[1]; + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + } + + g_studio.arraycoord[g_studio.numverts][0] = g_studio.chrome[idx][0] * s; + g_studio.arraycoord[g_studio.numverts][1] = g_studio.chrome[idx][1] * t; + + g_studio.numverts++; +#endif + } + } +} + +_inline void R_StudioDrawArrays( uint startverts, uint startelems ) +{ + sceKernelDcacheWritebackAll(); // writeback cache + sceGuDrawArray( GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | + GU_VERTEX_32BITF | GU_INDEX_16BIT, g_studio.numelems - startelems, + &g_studio.arrayelems[startelems], g_studio.arrayverts ); +} + +/* +=============== +R_StudioDrawPoints + +=============== +*/ +static void R_StudioDrawPoints( void ) +{ + int i, j, k, m_skinnum; + float shellscale = 0.0f; + qboolean need_sort = false; + byte *pvertbone; + byte *pnormbone; + vec3_t *pstudioverts; + vec3_t *pstudionorms; + mstudiotexture_t *ptexture; + mstudiomesh_t *pmesh; + short *pskinref; + float lv_tmp; + + if( !m_pStudioHeader ) return; + + + g_studio.numverts = g_studio.numelems = 0; + + // safety bounding the skinnum + m_skinnum = bound( 0, RI.currententity->curstate.skin, ( m_pStudioHeader->numskinfamilies - 1 )); + ptexture = (mstudiotexture_t *)((byte *)m_pStudioHeader + m_pStudioHeader->textureindex); + pvertbone = ((byte *)m_pStudioHeader + m_pSubModel->vertinfoindex); + pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex); + + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex); + pstudioverts = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->vertindex); + pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); + + pskinref = (short *)((byte *)m_pStudioHeader + m_pStudioHeader->skinindex); + if( m_skinnum != 0 ) pskinref += (m_skinnum * m_pStudioHeader->numskinref); + + if( FBitSet( m_pStudioHeader->flags, STUDIO_HAS_BONEWEIGHTS ) && m_pSubModel->blendvertinfoindex != 0 && m_pSubModel->blendnorminfoindex != 0 ) + { + mstudioboneweight_t *pvertweight = (mstudioboneweight_t *)((byte *)m_pStudioHeader + m_pSubModel->blendvertinfoindex); + mstudioboneweight_t *pnormweight = (mstudioboneweight_t *)((byte *)m_pStudioHeader + m_pSubModel->blendnorminfoindex); + matrix3x4 skinMat __attribute__( (aligned( 16 ) ) ); + + for( i = 0; i < m_pSubModel->numverts; i++ ) + { + R_StudioComputeSkinMatrix( &pvertweight[i], skinMat ); + Matrix3x4_VectorTransform( skinMat, pstudioverts[i], g_studio.verts[i] ); + R_LightStrength( pvertbone[i], pstudioverts[i], g_studio.lightpos[i] ); + } + + for( i = 0; i < m_pSubModel->numnorms; i++ ) + { + R_StudioComputeSkinMatrix( &pnormweight[i], skinMat ); + Matrix3x4_VectorRotate( skinMat, pstudionorms[i], g_studio.norms[i] ); + } + } + else + { + for( i = 0; i < m_pSubModel->numverts; i++ ) + { + Matrix3x4_VectorTransform( g_studio.bonestransform[pvertbone[i]], pstudioverts[i], g_studio.verts[i] ); + R_LightStrength( pvertbone[i], pstudioverts[i], g_studio.lightpos[i] ); + } + } + + // generate shared normals for properly scaling glowing shell + if( RI.currententity->curstate.renderfx == kRenderFxGlowShell ) + { + float factor = (1.0f / 128.0f); + shellscale = Q_max( factor, RI.currententity->curstate.renderamt * factor ); + R_StudioBuildNormalTable(); + R_StudioGenerateNormals(); + } + + for( j = k = 0; j < m_pSubModel->nummesh; j++ ) + { + g_nFaceFlags = ptexture[pskinref[pmesh[j].skinref]].flags | g_nForceFaceFlags; + + // fill in sortedmesh info + g_studio.meshes[j].flags = g_nFaceFlags; + g_studio.meshes[j].mesh = &pmesh[j]; + + if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED|STUDIO_NF_ADDITIVE )) + need_sort = true; + + if( RI.currententity->curstate.rendermode == kRenderTransAdd ) + { + for( i = 0; i < pmesh[j].numnorms; i++, k++, pstudionorms++, pnormbone++ ) + { + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioSetupChrome( g_studio.chrome[k], *pnormbone, (float *)pstudionorms ); + VectorSet( g_studio.lightvalues[k], tr.blend, tr.blend, tr.blend ); + } + } + else + { + for( i = 0; i < pmesh[j].numnorms; i++, k++, pstudionorms++, pnormbone++ ) + { + if( FBitSet( m_pStudioHeader->flags, STUDIO_HAS_BONEWEIGHTS )) + R_StudioLighting( &lv_tmp, -1, g_nFaceFlags, g_studio.norms[k] ); + else R_StudioLighting( &lv_tmp, *pnormbone, g_nFaceFlags, (float *)pstudionorms ); + + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioSetupChrome( g_studio.chrome[k], *pnormbone, (float *)pstudionorms ); + VectorScale( g_studio.lightcolor, lv_tmp, g_studio.lightvalues[k] ); + } + } + } + + if( r_studio_sort_textures->value && need_sort ) + { + // resort opaque and translucent meshes draw order + qsort( g_studio.meshes, m_pSubModel->nummesh, sizeof( sortedmesh_t ), R_StudioMeshCompare ); + } + + // NOTE: rewind normals at start + pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); + + for( j = 0; j < m_pSubModel->nummesh; j++ ) + { + float oldblend = tr.blend; + uint startArrayVerts = g_studio.numverts; + uint startArrayElems = g_studio.numelems; + short *ptricmds; + float s, t; + + pmesh = g_studio.meshes[j].mesh; + ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + + g_nFaceFlags = ptexture[pskinref[pmesh->skinref]].flags | g_nForceFaceFlags; + + s = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width; + t = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height; + + if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED )) + { + sceGuEnable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, 0x7f, 0xff ); + sceGuDepthMask( GU_FALSE ); + + if( R_ModelOpaque( RI.currententity->curstate.rendermode )) + tr.blend = 1.0f; + } + else if( FBitSet( g_nFaceFlags, STUDIO_NF_ADDITIVE )) + { + if( R_ModelOpaque( RI.currententity->curstate.rendermode )) + { + sceGuBlendFunc( GU_ADD, GU_FIX, GU_FIX, GUBLEND1, GUBLEND1 ); + sceGuDepthMask( GU_TRUE ); + sceGuEnable( GU_BLEND ); + + R_AllowFog( false ); + } + else sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + } + + R_StudioSetupSkin( m_pStudioHeader, pskinref[pmesh->skinref] ); + + if( CVAR_TO_BOOL(r_studio_drawelements) ) + { + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioBuildArrayChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); + else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS )) + R_StudioBuildArrayFloatMesh( ptricmds, pstudionorms ); + else R_StudioBuildArrayNormalMesh( ptricmds, pstudionorms, s, t ); + + R_StudioDrawArrays( startArrayVerts, startArrayElems ); + } + else + { + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); + else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS )) + R_StudioDrawFloatMesh( ptricmds, pstudionorms ); + else R_StudioDrawNormalMesh( ptricmds, pstudionorms, s, t ); + } + + if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED )) + { + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuDisable( GU_ALPHA_TEST ); + } + else if( FBitSet( g_nFaceFlags, STUDIO_NF_ADDITIVE ) && R_ModelOpaque( RI.currententity->curstate.rendermode )) + { + sceGuDepthMask( GU_FALSE ); + sceGuDisable( GU_BLEND ); + + R_AllowFog( true ); + } + + r_stats.c_studio_polys += pmesh->numtris; + tr.blend = oldblend; + } +} + +/* +=============== +R_StudioDrawHulls + +=============== +*/ +static void R_StudioDrawHulls( void ) +{ +#if 0 + float alpha, lv; + int i, j; + + if( r_drawentities->value == 4 ) + alpha = 0.5f; + else alpha = 1.0f; + + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); + + for( i = 0; i < m_pStudioHeader->numhitboxes; i++ ) + { + mstudiobbox_t *pbbox = (mstudiobbox_t *)((byte *)m_pStudioHeader + m_pStudioHeader->hitboxindex); + vec3_t tmp, p[8]; + + for( j = 0; j < 8; j++ ) + { + tmp[0] = (j & 1) ? pbbox[i].bbmin[0] : pbbox[i].bbmax[0]; + tmp[1] = (j & 2) ? pbbox[i].bbmin[1] : pbbox[i].bbmax[1]; + tmp[2] = (j & 4) ? pbbox[i].bbmin[2] : pbbox[i].bbmax[2]; + + Matrix3x4_VectorTransform( g_studio.bonestransform[pbbox[i].bone], tmp, p[j] ); + } + + j = (pbbox[i].group % 8); + + TriBegin( TRI_QUADS ); + TriColor4f( hullcolor[j][0], hullcolor[j][1], hullcolor[j][2], alpha ); + + for( j = 0; j < 6; j++ ) + { + VectorClear( tmp ); + tmp[j % 3] = (j < 3) ? 1.0f : -1.0f; + R_StudioLighting( &lv, pbbox[i].bone, 0, tmp ); + + TriBrightness( lv ); + TriVertex3fv( p[boxpnt[j][0]] ); + TriVertex3fv( p[boxpnt[j][1]] ); + TriVertex3fv( p[boxpnt[j][2]] ); + TriVertex3fv( p[boxpnt[j][3]] ); + } + TriEnd(); + } +#endif +} + +/* +=============== +R_StudioDrawAbsBBox + +=============== +*/ +static void R_StudioDrawAbsBBox( void ) +{ +#if 0 + vec3_t p[8], tmp; + float lv; + int i; + + // looks ugly, skip + if( RI.currententity == gEngfuncs.GetViewModel() ) + return; + + if( !R_StudioComputeBBox( p )) + return; + + GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); + TriColor4f( 0.5f, 0.5f, 1.0f, 0.5f ); + TriRenderMode( kRenderTransAdd ); + + TriBegin( TRI_QUADS ); + for( i = 0; i < 6; i++ ) + { + VectorClear( tmp ); + tmp[i % 3] = (i < 3) ? 1.0f : -1.0f; + R_StudioLighting( &lv, -1, 0, tmp ); + + TriBrightness( lv ); + TriVertex3fv( p[boxpnt[i][0]] ); + TriVertex3fv( p[boxpnt[i][1]] ); + TriVertex3fv( p[boxpnt[i][2]] ); + TriVertex3fv( p[boxpnt[i][3]] ); + } + TriEnd(); + TriRenderMode( kRenderNormal ); +#endif +} + +/* +=============== +R_StudioDrawBones + +=============== +*/ +static void R_StudioDrawBones( void ) +{ +#if 0 + mstudiobone_t *pbones = (mstudiobone_t *) ((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + vec3_t point; + int i; + + pglDisable( GL_TEXTURE_2D ); + + for( i = 0; i < m_pStudioHeader->numbones; i++ ) + { + if( pbones[i].parent >= 0 ) + { + pglPointSize( 3.0f ); + pglColor3f( 1, 0.7f, 0 ); + pglBegin( GL_LINES ); + + Matrix3x4_OriginFromMatrix( g_studio.bonestransform[pbones[i].parent], point ); + pglVertex3fv( point ); + Matrix3x4_OriginFromMatrix( g_studio.bonestransform[i], point ); + pglVertex3fv( point ); + + pglEnd(); + + pglColor3f( 0, 0, 0.8f ); + pglBegin( GL_POINTS ); + if( pbones[pbones[i].parent].parent != -1 ) + { + Matrix3x4_OriginFromMatrix( g_studio.bonestransform[pbones[i].parent], point ); + pglVertex3fv( point ); + } + Matrix3x4_OriginFromMatrix( g_studio.bonestransform[i], point ); + pglVertex3fv( point ); + pglEnd(); + } + else + { + // draw parent bone node + pglPointSize( 5.0f ); + pglColor3f( 0.8f, 0, 0 ); + pglBegin( GL_POINTS ); + Matrix3x4_OriginFromMatrix( g_studio.bonestransform[i], point ); + pglVertex3fv( point ); + pglEnd(); + } + } + + pglPointSize( 1.0f ); + pglEnable( GL_TEXTURE_2D ); +#endif +} + +static void R_StudioDrawAttachments( void ) +{ +#if 0 + int i; + + pglDisable( GL_TEXTURE_2D ); + pglDisable( GL_DEPTH_TEST ); + + for( i = 0; i < m_pStudioHeader->numattachments; i++ ) + { + mstudioattachment_t *pattachments; + vec3_t v[4]; + + pattachments = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + Matrix3x4_VectorTransform( g_studio.bonestransform[pattachments[i].bone], pattachments[i].org, v[0] ); + Matrix3x4_VectorTransform( g_studio.bonestransform[pattachments[i].bone], pattachments[i].vectors[0], v[1] ); + Matrix3x4_VectorTransform( g_studio.bonestransform[pattachments[i].bone], pattachments[i].vectors[1], v[2] ); + Matrix3x4_VectorTransform( g_studio.bonestransform[pattachments[i].bone], pattachments[i].vectors[2], v[3] ); + + pglBegin( GL_LINES ); + pglColor3f( 1, 0, 0 ); + pglVertex3fv( v[0] ); + pglColor3f( 1, 1, 1 ); + pglVertex3fv (v[1] ); + pglColor3f( 1, 0, 0 ); + pglVertex3fv (v[0] ); + pglColor3f( 1, 1, 1 ); + pglVertex3fv (v[2] ); + pglColor3f( 1, 0, 0 ); + pglVertex3fv (v[0] ); + pglColor3f( 1, 1, 1 ); + pglVertex3fv( v[3] ); + pglEnd(); + + pglPointSize( 5.0f ); + pglColor3f( 0, 1, 0 ); + pglBegin( GL_POINTS ); + pglVertex3fv( v[0] ); + pglEnd(); + pglPointSize( 1.0f ); + } + + pglEnable( GL_TEXTURE_2D ); + pglEnable( GL_DEPTH_TEST ); +#endif +} + +/* +=============== +R_StudioSetRemapColors + +=============== +*/ +static void R_StudioSetRemapColors( int newTop, int newBottom ) +{ + gEngfuncs.CL_AllocRemapInfo( RI.currententity, newTop, newBottom ); + + if( gEngfuncs.CL_GetRemapInfoForEntity( RI.currententity )) + { + gEngfuncs.CL_UpdateRemapInfo( RI.currententity, newTop, newBottom ); + m_fDoRemap = true; + } +} + +void R_StudioResetPlayerModels( void ) +{ + memset( g_studio.player_models, 0, sizeof( g_studio.player_models )); +} + +/* +=============== +R_StudioSetupPlayerModel + +=============== +*/ +static model_t *R_StudioSetupPlayerModel( int index ) +{ + player_info_t *info = gEngfuncs.pfnPlayerInfo( index ); + player_model_t *state; + + state = &g_studio.player_models[index]; + + // g-cont: force for "dev-mode", non-local games and menu preview + if(( gpGlobals->developer || !ENGINE_GET_PARM( PARM_LOCAL_GAME ) || !RI.drawWorld ) && info->model[0] ) + { + if( Q_strcmp( state->name, info->model )) + { + Q_strncpy( state->name, info->model, sizeof( state->name )); + state->name[sizeof( state->name ) - 1] = 0; + + Q_snprintf( state->modelname, sizeof( state->modelname ), "models/player/%s/%s.mdl", info->model, info->model ); + + if( gEngfuncs.FS_FileExists( state->modelname, false )) + state->model = gEngfuncs.Mod_ForName( state->modelname, false, true ); + else state->model = NULL; + + if( !state->model ) + state->model = RI.currententity->model; + } + } + else + { + if( state->model != RI.currententity->model ) + state->model = RI.currententity->model; + state->name[0] = 0; + } + + return state->model; +} + +/* +================ +R_GetEntityRenderMode + +check for texture flags +================ +*/ +int R_GetEntityRenderMode( cl_entity_t *ent ) +{ + int i, opaque, trans; + mstudiotexture_t *ptexture; + cl_entity_t *oldent; + model_t *model; + studiohdr_t *phdr; + + oldent = RI.currententity; + RI.currententity = ent; + + if( ent->player ) // check it for real playermodel + model = R_StudioSetupPlayerModel( ent->curstate.number - 1 ); + else model = ent->model; + + RI.currententity = oldent; + + if(( phdr = gEngfuncs.Mod_Extradata( mod_studio, model )) == NULL ) + { + if( R_ModelOpaque( ent->curstate.rendermode )) + { + // forcing to choose right sorting type + if(( model && model->type == mod_brush ) && FBitSet( model->flags, MODEL_TRANSPARENT )) + return kRenderTransAlpha; + } + return ent->curstate.rendermode; + } + ptexture = (mstudiotexture_t *)((byte *)phdr + phdr->textureindex); + + for( opaque = trans = i = 0; i < phdr->numtextures; i++, ptexture++ ) + { + // ignore chrome & additive it's just a specular-like effect + if( FBitSet( ptexture->flags, STUDIO_NF_ADDITIVE ) && !FBitSet( ptexture->flags, STUDIO_NF_CHROME )) + trans++; + else opaque++; + } + + // if model is more additive than opaque + if( trans > opaque ) + return kRenderTransAdd; + return ent->curstate.rendermode; +} + +/* +=============== +R_StudioClientEvents + +=============== +*/ +static void R_StudioClientEvents( void ) +{ + mstudioseqdesc_t *pseqdesc; + mstudioevent_t *pevent; + cl_entity_t *e = RI.currententity; + int i, sequence; + float end, start; + + if( g_studio.frametime == 0.0 ) + return; // gamepaused + + // fill attachments with interpolated origin + if( m_pStudioHeader->numattachments <= 0 ) + { + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, e->attachment[0] ); + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, e->attachment[1] ); + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, e->attachment[2] ); + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, e->attachment[3] ); + } + + if( FBitSet( e->curstate.effects, EF_MUZZLEFLASH )) + { + dlight_t *el = gEngfuncs.CL_AllocElight( 0 ); + + ClearBits( e->curstate.effects, EF_MUZZLEFLASH ); + VectorCopy( e->attachment[0], el->origin ); + el->die = gpGlobals->time + 0.05f; + el->color.r = 255; + el->color.g = 192; + el->color.b = 64; + el->decay = 320; + el->radius = 24; + } + + sequence = bound( 0, e->curstate.sequence, m_pStudioHeader->numseq - 1 ); + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + sequence; + + // no events for this animation + if( pseqdesc->numevents == 0 ) + return; + + end = R_StudioEstimateFrame( e, pseqdesc ); + start = end - e->curstate.framerate * gpGlobals->frametime * pseqdesc->fps; + pevent = (mstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex); + + if( e->latched.sequencetime == e->curstate.animtime ) + { + if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING )) + start = -0.01f; + } + + for( i = 0; i < pseqdesc->numevents; i++ ) + { + // ignore all non-client-side events + if( pevent[i].event < EVENT_CLIENT ) + continue; + + if( (float)pevent[i].frame > start && pevent[i].frame <= end ) + gEngfuncs.pfnStudioEvent( &pevent[i], e ); + } +} + +/* +=============== +R_StudioGetForceFaceFlags + +=============== +*/ +int R_StudioGetForceFaceFlags( void ) +{ + return g_nForceFaceFlags; +} + +/* +=============== +R_StudioSetForceFaceFlags + +=============== +*/ +void R_StudioSetForceFaceFlags( int flags ) +{ + g_nForceFaceFlags = flags; +} + +/* +=============== +pfnStudioSetHeader + +=============== +*/ +void R_StudioSetHeader( studiohdr_t *pheader ) +{ + m_pStudioHeader = pheader; + m_fDoRemap = false; +} + +/* +=============== +R_StudioSetRenderModel + +=============== +*/ +void R_StudioSetRenderModel( model_t *model ) +{ + RI.currentmodel = model; +} + +/* +=============== +R_StudioSetupRenderer + +=============== +*/ +static void R_StudioSetupRenderer( int rendermode ) +{ + studiohdr_t *phdr = m_pStudioHeader; + int i; + + if( rendermode > kRenderTransAdd ) rendermode = 0; + g_studio.rendermode = bound( 0, rendermode, kRenderTransAdd ); + + sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); + sceGuDisable( GU_ALPHA_TEST ); + sceGuShadeModel( GU_SMOOTH ); + + // a point to setup local to world transform for boneweighted models + if( phdr && FBitSet( phdr->flags, STUDIO_HAS_BONEINFO )) + { + // NOTE: extended boneinfo goes immediately after bones + mstudioboneinfo_t *boneinfo = (mstudioboneinfo_t *)((byte *)phdr + phdr->boneindex + phdr->numbones * sizeof( mstudiobone_t )); + + for( i = 0; i < phdr->numbones; i++ ) + Matrix3x4_ConcatTransforms( g_studio.worldtransform[i], g_studio.bonestransform[i], boneinfo[i].poseToBone ); + } +} + +/* +=============== +R_StudioRestoreRenderer + +=============== +*/ +static void R_StudioRestoreRenderer( void ) +{ + if( g_studio.rendermode != kRenderNormal ) + sceGuDisable( GU_BLEND ); + + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + sceGuShadeModel( GU_FLAT ); + + m_fDoRemap = false; +} + +/* +=============== +R_StudioSetChromeOrigin + +=============== +*/ +void R_StudioSetChromeOrigin( void ) +{ + VectorCopy( RI.vieworg, g_studio.chrome_origin ); +} + +/* +=============== +pfnIsHardware + +Xash3D is always works in hardware mode +=============== +*/ +static int pfnIsHardware( void ) +{ + return 1; // 0 is Software, 1 is OpenGL, 2 is Direct3D +} + +/* +=============== +R_StudioDrawPointsShadow + +=============== +*/ +static void R_StudioDrawPointsShadow( void ) +{ + float *av, height; + float vec_x, vec_y; + mstudiomesh_t *pmesh; + vec3_t point; + int i, k; + + if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW )) + return; + + if( glState.stencilEnabled ) + sceGuEnable( GU_STENCIL_TEST ); + + height = g_studio.lightspot[2] + 1.0f; + vec_x = -g_studio.lightvec[0] * 8.0f; + vec_y = -g_studio.lightvec[1] * 8.0f; + + for( k = 0; k < m_pSubModel->nummesh; k++ ) + { + short *ptricmds; + + pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + k; + ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); + + r_stats.c_studio_polys += pmesh->numtris; + + while( ( i = *( ptricmds++ ) ) ) + { + int prim; + if( i < 0 ) + { + prim = GU_TRIANGLE_FAN; + i = -i; + } + else + { + prim = GU_TRIANGLE_STRIP; + } + + gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * i ); + + for(int index = 0; index < i; index++, ptricmds += 4) + { + av = g_studio.verts[ptricmds[0]]; + point[0] = av[0] - (vec_x * ( av[2] - g_studio.lightspot[2] )); + point[1] = av[1] - (vec_y * ( av[2] - g_studio.lightspot[2] )); + point[2] = g_studio.lightspot[2] + 1.0f; + + out[index].x = point[0]; + out[index].y = point[1]; + out[index].z = point[2]; + } + sceGuDrawArray( prim, GU_VERTEX_32BITF, i, 0, out ); + } + } + if( glState.stencilEnabled ) + sceGuDisable( GU_STENCIL_TEST ); +} + +/* +=============== +GL_StudioSetRenderMode + +set rendermode for studiomodel +=============== +*/ +void GL_StudioSetRenderMode( int rendermode ) +{ + switch( rendermode ) + { + case kRenderNormal: + break; + case kRenderTransColor: + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuEnable( GU_BLEND ); + break; + case kRenderTransAdd: + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuColor( GUCOLOR4F( tr.blend, tr.blend, tr.blend, 1.0f ) ); + sceGuBlendFunc( GU_ADD, GU_FIX, GU_FIX, GUBLEND1, GUBLEND1 ); + sceGuDepthMask( GU_TRUE ); + sceGuEnable( GU_BLEND ); + break; + default: + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, tr.blend ) ); + sceGuDepthMask( GU_FALSE ); + sceGuEnable( GU_BLEND ); + break; + } +} + +/* +=============== +GL_StudioDrawShadow + +g-cont: don't modify this code it's 100% matched with +original GoldSrc code and used in some mods to enable +studio shadows with some asm tricks +=============== +*/ +static void GL_StudioDrawShadow( void ) +{ + sceGuDepthMask( GU_FALSE ); + + if( r_shadows.value && g_studio.rendermode != kRenderTransAdd && !FBitSet( RI.currentmodel->flags, STUDIO_AMBIENT_LIGHT )) + { + float color = 1.0f - (tr.blend * 0.5f); + + sceGuDisable( GU_TEXTURE_2D ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuEnable( GU_BLEND ); + sceGuColor( GUCOLOR4F( 0.0f, 0.0f, 0.0f, 1.0f - color ) ); + + sceGuDepthFunc( GU_LESS ); + R_StudioDrawPointsShadow(); + sceGuDepthFunc( GU_LEQUAL ); + + sceGuEnable( GU_TEXTURE_2D ); + sceGuDisable( GU_BLEND ); + sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, 1.0f ) ); + sceGuShadeModel( GU_SMOOTH ); + } +} + +/* +==================== +StudioRenderFinal + +==================== +*/ +void R_StudioRenderFinal( void ) +{ + int i, rendermode; + + rendermode = R_StudioGetForceFaceFlags() ? kRenderTransAdd : RI.currententity->curstate.rendermode; + R_StudioSetupRenderer( rendermode ); + + if( r_drawentities->value == 2 ) + { + R_StudioDrawBones(); + } + else if( r_drawentities->value == 3 ) + { + R_StudioDrawHulls(); + } + else + { + for( i = 0; i < m_pStudioHeader->numbodyparts; i++ ) + { + R_StudioSetupModel( i, (void**)&m_pBodyPart, (void**)&m_pSubModel ); + + GL_StudioSetRenderMode( rendermode ); + R_StudioDrawPoints(); + GL_StudioDrawShadow(); + } + } + + if( r_drawentities->value == 4 ) + { + TriRenderMode( kRenderTransAdd ); + R_StudioDrawHulls( ); + TriRenderMode( kRenderNormal ); + } + + if( r_drawentities->value == 5 ) + { + R_StudioDrawAbsBBox( ); + } + + if( r_drawentities->value == 6 ) + { + R_StudioDrawAttachments(); + } + + if( r_drawentities->value == 7 ) + { + vec3_t origin; +#if 1 +#else + pglDisable( GL_TEXTURE_2D ); + pglDisable( GL_DEPTH_TEST ); + + Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, origin ); + + pglBegin( GL_LINES ); + pglColor3f( 1, 0.5, 0 ); + pglVertex3fv( origin ); + pglVertex3fv( g_studio.lightspot ); + pglEnd(); + + pglBegin( GL_LINES ); + pglColor3f( 0, 0.5, 1 ); + VectorMA( g_studio.lightspot, -64.0f, g_studio.lightvec, origin ); + pglVertex3fv( g_studio.lightspot ); + pglVertex3fv( origin ); + pglEnd(); + + pglPointSize( 5.0f ); + pglColor3f( 1, 0, 0 ); + pglBegin( GL_POINTS ); + pglVertex3fv( g_studio.lightspot ); + pglEnd(); + pglPointSize( 1.0f ); + + pglEnable( GL_DEPTH_TEST ); + pglEnable( GL_TEXTURE_2D ); +#endif + } + + R_StudioRestoreRenderer(); +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void R_StudioRenderModel( void ) +{ + R_StudioSetChromeOrigin(); + R_StudioSetForceFaceFlags( 0 ); + + if( RI.currententity->curstate.renderfx == kRenderFxGlowShell ) + { + RI.currententity->curstate.renderfx = kRenderFxNone; + + R_StudioRenderFinal( ); + + R_StudioSetForceFaceFlags( STUDIO_NF_CHROME ); + TriSpriteTexture( R_GetChromeSprite(), 0 ); + RI.currententity->curstate.renderfx = kRenderFxGlowShell; + + R_StudioRenderFinal( ); + } + else + { + R_StudioRenderFinal( ); + } +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void R_StudioEstimateGait( entity_state_t *pplayer ) +{ + vec3_t est_velocity; + float dt; + + dt = bound( 0.0f, g_studio.frametime, 1.0f ); + + if( dt == 0.0f || m_pPlayerInfo->renderframe == tr.realframecount ) + { + m_flGaitMovement = 0; + return; + } + + VectorSubtract( RI.currententity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( RI.currententity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = VectorLength( est_velocity ); + + if( dt <= 0.0f || m_flGaitMovement / dt < 5.0f ) + { + m_flGaitMovement = 0.0f; + est_velocity[0] = 0.0f; + est_velocity[1] = 0.0f; + } + + if( est_velocity[1] == 0.0f && est_velocity[0] == 0.0f ) + { + float flYawDiff = RI.currententity->angles[YAW] - m_pPlayerInfo->gaityaw; + + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if( flYawDiff > 180.0f ) flYawDiff -= 360.0f; + if( flYawDiff < -180.0f ) flYawDiff += 360.0f; + + if( dt < 0.25f ) + flYawDiff *= dt * 4.0f; + else flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0.0f; + } + else + { + m_pPlayerInfo->gaityaw = ( atan2( est_velocity[1], est_velocity[0] ) * 180 / M_PI_F ); + if( m_pPlayerInfo->gaityaw > 180.0f ) m_pPlayerInfo->gaityaw = 180.0f; + if( m_pPlayerInfo->gaityaw < -180.0f ) m_pPlayerInfo->gaityaw = -180.0f; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void R_StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + int iBlend; + float dt, flYaw; // view direction relative to movement + + if( RI.currententity->curstate.sequence >= m_pStudioHeader->numseq ) + RI.currententity->curstate.sequence = 0; + + dt = bound( 0.0f, g_studio.frametime, 1.0f ); + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + RI.currententity->curstate.sequence; + + R_StudioPlayerBlend( pseqdesc, &iBlend, &RI.currententity->angles[PITCH] ); + + RI.currententity->latched.prevangles[PITCH] = RI.currententity->angles[PITCH]; + RI.currententity->curstate.blending[0] = iBlend; + RI.currententity->latched.prevblending[0] = RI.currententity->curstate.blending[0]; + RI.currententity->latched.prevseqblending[0] = RI.currententity->curstate.blending[0]; + R_StudioEstimateGait( pplayer ); + + // calc side to side turning + flYaw = RI.currententity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if( flYaw < -180.0f ) flYaw = flYaw + 360.0f; + if( flYaw > 180.0f ) flYaw = flYaw - 360.0f; + + if( flYaw > 120.0f ) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180.0f; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180.0f; + } + else if( flYaw < -120.0f ) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180.0f; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180.0f; + } + + // adjust torso + RI.currententity->curstate.controller[0] = ((flYaw / 4.0f) + 30.0f) / (60.0f / 255.0f); + RI.currententity->curstate.controller[1] = ((flYaw / 4.0f) + 30.0f) / (60.0f / 255.0f); + RI.currententity->curstate.controller[2] = ((flYaw / 4.0f) + 30.0f) / (60.0f / 255.0f); + RI.currententity->curstate.controller[3] = ((flYaw / 4.0f) + 30.0f) / (60.0f / 255.0f); + RI.currententity->latched.prevcontroller[0] = RI.currententity->curstate.controller[0]; + RI.currententity->latched.prevcontroller[1] = RI.currententity->curstate.controller[1]; + RI.currententity->latched.prevcontroller[2] = RI.currententity->curstate.controller[2]; + RI.currententity->latched.prevcontroller[3] = RI.currententity->curstate.controller[3]; + + RI.currententity->angles[YAW] = m_pPlayerInfo->gaityaw; + if( RI.currententity->angles[YAW] < -0 ) RI.currententity->angles[YAW] += 360.0f; + RI.currententity->latched.prevangles[YAW] = RI.currententity->angles[YAW]; + + if( pplayer->gaitsequence >= m_pStudioHeader->numseq ) + pplayer->gaitsequence = 0; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // calc gait frame + if( pseqdesc->linearmovement[0] > 0 ) + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + else m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; + + // do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if( m_pPlayerInfo->gaitframe < 0 ) m_pPlayerInfo->gaitframe += pseqdesc->numframes; +} + +/* +=============== +R_StudioDrawPlayer + +=============== +*/ +static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + int m_nPlayerIndex; + alight_t lighting; + vec3_t dir; + + m_nPlayerIndex = pplayer->number - 1; + + if( m_nPlayerIndex < 0 || m_nPlayerIndex >= ENGINE_GET_PARM( PARM_MAX_CLIENTS ) ) + return 0; + + RI.currentmodel = R_StudioSetupPlayerModel( m_nPlayerIndex ); + if( RI.currentmodel == NULL ) + return 0; + + R_StudioSetHeader((studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, RI.currentmodel )); + + if( pplayer->gaitsequence ) + { + vec3_t orig_angles; + + m_pPlayerInfo = pfnPlayerInfo( m_nPlayerIndex ); + VectorCopy( RI.currententity->angles, orig_angles ); + + R_StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + R_StudioSetUpTransform( RI.currententity ); + VectorCopy( orig_angles, RI.currententity->angles ); + } + else + { + RI.currententity->curstate.controller[0] = 127; + RI.currententity->curstate.controller[1] = 127; + RI.currententity->curstate.controller[2] = 127; + RI.currententity->curstate.controller[3] = 127; + RI.currententity->latched.prevcontroller[0] = RI.currententity->curstate.controller[0]; + RI.currententity->latched.prevcontroller[1] = RI.currententity->curstate.controller[1]; + RI.currententity->latched.prevcontroller[2] = RI.currententity->curstate.controller[2]; + RI.currententity->latched.prevcontroller[3] = RI.currententity->curstate.controller[3]; + + m_pPlayerInfo = pfnPlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + R_StudioSetUpTransform( RI.currententity ); + } + + if( flags & STUDIO_RENDER ) + { + // see if the bounding box lets us trivially reject, also sets + if( !R_StudioCheckBBox( )) + return 0; + + r_stats.c_studio_models_drawn++; + g_studio.framecount++; // render data cache cookie + + if( m_pStudioHeader->numbodyparts == 0 ) + return 1; + } + + m_pPlayerInfo = pfnPlayerInfo( m_nPlayerIndex ); + R_StudioSetupBones( RI.currententity ); + R_StudioSaveBones( ); + + m_pPlayerInfo->renderframe = tr.realframecount; + m_pPlayerInfo = NULL; + + if( flags & STUDIO_EVENTS ) + { + R_StudioCalcAttachments( ); + R_StudioClientEvents( ); + + // copy attachments into global entity array + if( RI.currententity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( RI.currententity->index ); + memcpy( ent->attachment, RI.currententity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if( flags & STUDIO_RENDER ) + { + if( cl_himodels->value && RI.currentmodel != RI.currententity->model ) + { + // show highest resolution multiplayer model + RI.currententity->curstate.body = 255; + } + + if( !( !gpGlobals->developer && ENGINE_GET_PARM( PARM_MAX_CLIENTS ) == 1 ) && ( RI.currentmodel == RI.currententity->model )) + RI.currententity->curstate.body = 1; // force helmet + + lighting.plightvec = dir; + R_StudioDynamicLight( RI.currententity, &lighting ); + + R_StudioEntityLight( &lighting ); + + // model and frame independant + R_StudioSetupLighting( &lighting ); + + m_pPlayerInfo = pfnPlayerInfo( m_nPlayerIndex ); + + // get remap colors + g_nTopColor = m_pPlayerInfo->topcolor; + g_nBottomColor = m_pPlayerInfo->bottomcolor; + + if( g_nTopColor < 0 ) g_nTopColor = 0; + if( g_nTopColor > 360 ) g_nTopColor = 360; + if( g_nBottomColor < 0 ) g_nBottomColor = 0; + if( g_nBottomColor > 360 ) g_nBottomColor = 360; + + R_StudioSetRemapColors( g_nTopColor, g_nBottomColor ); + + R_StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if( pplayer->weaponmodel ) + { + cl_entity_t saveent = *RI.currententity; + model_t *pweaponmodel = gEngfuncs.pfnGetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, pweaponmodel ); + + R_StudioMergeBones( RI.currententity, pweaponmodel ); + R_StudioSetupLighting( &lighting ); + R_StudioRenderModel( ); + R_StudioCalcAttachments( ); + + *RI.currententity = saveent; + } + } + + return 1; +} + +/* +=============== +R_StudioDrawModel + +=============== +*/ +static int R_StudioDrawModel( int flags ) +{ + alight_t lighting; + vec3_t dir; + + if( RI.currententity->curstate.renderfx == kRenderFxDeadPlayer ) + { + qboolean save_interpolate; + entity_state_t deadplayer; + int result; + + if( RI.currententity->curstate.renderamt <= 0 || + RI.currententity->curstate.renderamt > ENGINE_GET_PARM( PARM_MAX_CLIENTS ) ) + return 0; + + // get copy of player + deadplayer = *R_StudioGetPlayerState( RI.currententity->curstate.renderamt - 1 ); + + // clear weapon, movement state + deadplayer.number = RI.currententity->curstate.renderamt; + deadplayer.weaponmodel = 0; + deadplayer.gaitsequence = 0; + + deadplayer.movetype = MOVETYPE_NONE; + VectorCopy( RI.currententity->curstate.angles, deadplayer.angles ); + VectorCopy( RI.currententity->curstate.origin, deadplayer.origin ); + + save_interpolate = g_studio.interpolate; + g_studio.interpolate = false; + result = R_StudioDrawPlayer( flags, &deadplayer ); // draw as though it were a player + g_studio.interpolate = save_interpolate; + + return result; + } + + R_StudioSetHeader((studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, RI.currentmodel )); + + R_StudioSetUpTransform( RI.currententity ); + + if( flags & STUDIO_RENDER ) + { + // see if the bounding box lets us trivially reject, also sets + if( !R_StudioCheckBBox( )) + return 0; + + r_stats.c_studio_models_drawn++; + g_studio.framecount++; // render data cache cookie + + if( m_pStudioHeader->numbodyparts == 0 ) + return 1; + } + + if( RI.currententity->curstate.movetype == MOVETYPE_FOLLOW ) + R_StudioMergeBones( RI.currententity, RI.currentmodel ); + else R_StudioSetupBones( RI.currententity ); + + R_StudioSaveBones(); + + if( flags & STUDIO_EVENTS ) + { + R_StudioCalcAttachments( ); + R_StudioClientEvents( ); + + // copy attachments into global entity array + if( RI.currententity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( RI.currententity->index ); + memcpy( ent->attachment, RI.currententity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if( flags & STUDIO_RENDER ) + { + lighting.plightvec = dir; + R_StudioDynamicLight( RI.currententity, &lighting ); + + R_StudioEntityLight( &lighting ); + + // model and frame independant + R_StudioSetupLighting( &lighting ); + + // get remap colors + g_nTopColor = RI.currententity->curstate.colormap & 0xFF; + g_nBottomColor = (RI.currententity->curstate.colormap & 0xFF00) >> 8; + + R_StudioSetRemapColors( g_nTopColor, g_nBottomColor ); + + R_StudioRenderModel(); + } + + return 1; +} + +/* +================= +R_StudioDrawModelInternal +================= +*/ +void R_StudioDrawModelInternal( cl_entity_t *e, int flags ) +{ + if( !RI.drawWorld ) + { + if( e->player ) + R_StudioDrawPlayer( flags, &e->curstate ); + else R_StudioDrawModel( flags ); + } + else + { + // select the properly method + if( e->player ) + pStudioDraw->StudioDrawPlayer( flags, R_StudioGetPlayerState( e->index - 1 )); + else pStudioDraw->StudioDrawModel( flags ); + } +} + +/* +================= +R_DrawStudioModel +================= +*/ +void R_DrawStudioModel( cl_entity_t *e ) +{ + if( FBitSet( RI.params, RP_ENVVIEW )) + return; + + R_StudioSetupTimings(); + + if( e->player ) + { + R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); + } + else + { + if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 ) + { + cl_entity_t *parent = gEngfuncs.GetEntityByIndex( e->curstate.aiment ); + + if( parent && parent->model && parent->model->type == mod_studio ) + { + RI.currententity = parent; + R_StudioDrawModelInternal( RI.currententity, 0 ); + VectorCopy( parent->curstate.origin, e->curstate.origin ); + VectorCopy( parent->origin, e->origin ); + RI.currententity = e; + } + } + + R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); + } +} + +/* +================= +R_RunViewmodelEvents +================= +*/ +void R_RunViewmodelEvents( void ) +{ + int i; + vec3_t simorg; + + if( r_drawviewmodel->value == 0 ) + return; + + if( ENGINE_GET_PARM( PARM_THIRDPERSON )) + return; + + // ignore in thirdperson, camera view or client is died + if( !RP_NORMALPASS() || ENGINE_GET_PARM( PARM_LOCAL_HEALTH ) <= 0 || !CL_IsViewEntityLocalPlayer()) + return; + + RI.currententity = gEngfuncs.GetViewModel(); + + if( !RI.currententity->model || RI.currententity->model->type != mod_studio ) + return; + + R_StudioSetupTimings(); + + gEngfuncs.GetPredictedOrigin( simorg ); + for( i = 0; i < 4; i++ ) + VectorCopy( simorg, RI.currententity->attachment[i] ); + RI.currentmodel = RI.currententity->model; + + R_StudioDrawModelInternal( RI.currententity, STUDIO_EVENTS ); +} + +/* +================= +R_GatherPlayerLight +================= +*/ +void R_GatherPlayerLight( void ) +{ + cl_entity_t *view = gEngfuncs.GetViewModel(); + colorVec c; + + tr.ignore_lightgamma = true; + c = R_LightPoint( view->origin ); + tr.ignore_lightgamma = false; + gEngfuncs.SetLocalLightLevel( ( c.r + c.g + c.b ) / 3 ); +} + +/* +================= +R_DrawViewModel +================= +*/ +void R_DrawViewModel( void ) +{ + qboolean m_flip; + + cl_entity_t *view = gEngfuncs.GetViewModel(); + + R_GatherPlayerLight(); + + if( r_drawviewmodel->value == 0 ) + return; + + if( ENGINE_GET_PARM( PARM_THIRDPERSON )) + return; + + // ignore in thirdperson, camera view or client is died + if( !RP_NORMALPASS() || ENGINE_GET_PARM( PARM_LOCAL_HEALTH ) <= 0 || !CL_IsViewEntityLocalPlayer()) + return; + + tr.blend = CL_FxBlend( view ) / 255.0f; + if( !R_ModelOpaque( view->curstate.rendermode ) && tr.blend <= 0.0f ) + return; // invisible ? + + RI.currententity = view; + + if( !RI.currententity->model ) + return; + + // adjust the depth range to prevent view model from poking into walls + sceGuDepthRange( ( int )gldepthmin, ( int )( gldepthmin + 0.3f * ( gldepthmax - gldepthmin ) ) ); + + RI.currentmodel = RI.currententity->model; + + m_flip = R_AllowFlipViewModel( RI.currententity ); + + // backface culling for left-handed weapons + if( m_flip || g_iBackFaceCull ) + { + tr.fFlipViewModel = true; + GL_Cull( GL_FRONT ); + } + + switch( RI.currententity->model->type ) + { + case mod_alias: + R_DrawAliasModel( RI.currententity ); + break; + case mod_studio: + R_StudioSetupTimings(); + R_StudioDrawModelInternal( RI.currententity, STUDIO_RENDER ); + break; + } + + // restore depth range + sceGuDepthRange( ( int )gldepthmin, ( int )gldepthmax ); + + // backface culling for left-handed weapons + if( m_flip || g_iBackFaceCull ) + { + tr.fFlipViewModel = false; + GL_Cull( GL_BACK ); + } +} + +/* +==================== +R_StudioLoadTexture + +load model texture with unique name +==================== +*/ +static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture_t *ptexture ) +{ + size_t size; + int flags = 0; + char texname[128], name[128], mdlname[128]; + texture_t *tx = NULL; + + if( ptexture->flags & STUDIO_NF_NORMALMAP ) + flags |= (TF_NORMALMAP); + + // store some textures for remapping + if( !Q_strnicmp( ptexture->name, "DM_Base", 7 ) || !Q_strnicmp( ptexture->name, "remap", 5 )) + { + int i, size; + char val[6]; + byte *pixels; + + i = mod->numtextures; + mod->textures = (texture_t **)Mem_Realloc( mod->mempool, mod->textures, ( i + 1 ) * sizeof( texture_t* )); + size = ptexture->width * ptexture->height + 768; + tx = Mem_Calloc( mod->mempool, sizeof( *tx ) + size ); + mod->textures[i] = tx; + + // store ranges into anim_min, anim_max etc + if( !Q_strnicmp( ptexture->name, "DM_Base", 7 )) + { + Q_strncpy( tx->name, "DM_Base", sizeof( tx->name )); + tx->anim_min = PLATE_HUE_START; // topcolor start + tx->anim_max = PLATE_HUE_END; // topcolor end + // bottomcolor start always equal is (topcolor end + 1) + tx->anim_total = SUIT_HUE_END;// bottomcolor end + } + else + { + Q_strncpy( tx->name, "DM_User", sizeof( tx->name )); // custom remapped + Q_strncpy( val, ptexture->name + 7, 4 ); + tx->anim_min = bound( 0, Q_atoi( val ), 255 ); // topcolor start + Q_strncpy( val, ptexture->name + 11, 4 ); + tx->anim_max = bound( 0, Q_atoi( val ), 255 ); // topcolor end + // bottomcolor start always equal is (topcolor end + 1) + Q_strncpy( val, ptexture->name + 15, 4 ); + tx->anim_total = bound( 0, Q_atoi( val ), 255 ); // bottomcolor end + } + + tx->width = ptexture->width; + tx->height = ptexture->height; + + // the pixels immediately follow the structures + pixels = (byte *)phdr + ptexture->index; + memcpy( tx+1, pixels, size ); + + ptexture->flags |= STUDIO_NF_COLORMAP; // yes, this is colormap image + flags |= TF_FORCE_COLOR; + + mod->numtextures++; // done + } + + Q_strncpy( mdlname, mod->name, sizeof( mdlname )); + COM_FileBase( ptexture->name, name ); + COM_StripExtension( mdlname ); + + if( FBitSet( ptexture->flags, STUDIO_NF_NOMIPS )) + SetBits( flags, TF_NOMIPMAP ); + + // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it + //ptexture->index = (int)((byte *)phdr) + ptexture->index; + gEngfuncs.Image_SetMDLPointer((byte *)phdr + ptexture->index); + size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768; + + if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_IMPROVED_LINETRACE ) && FBitSet( ptexture->flags, STUDIO_NF_MASKED )) + flags |= TF_KEEP_SOURCE; // Paranoia2 texture alpha-tracing + + // build the texname + Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name ); + ptexture->index = GL_LoadTexture( texname, (byte *)ptexture, size, flags ); + + if( !ptexture->index ) + { + ptexture->index = tr.defaultTexture; + } + else if( tx ) + { + // duplicate texnum for easy acess + tx->gl_texturenum = ptexture->index; + } +} + +/* +================= +Mod_StudioLoadTextures +================= +*/ +void Mod_StudioLoadTextures( model_t *mod, void *data ) +{ + studiohdr_t *phdr = (studiohdr_t *)data; + mstudiotexture_t *ptexture; + int i; + + if( !phdr ) + return; + + ptexture = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); + if( phdr->textureindex > 0 && phdr->numtextures <= MAXSTUDIOSKINS ) + { + for( i = 0; i < phdr->numtextures; i++ ) + R_StudioLoadTexture( mod, phdr, &ptexture[i] ); + } +} + +/* +================= +Mod_StudioUnloadTextures +================= +*/ +void Mod_StudioUnloadTextures( void *data ) +{ + studiohdr_t *phdr = (studiohdr_t *)data; + mstudiotexture_t *ptexture; + int i; + + if( !phdr ) + return; + + ptexture = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex); + + // release all textures + for( i = 0; i < phdr->numtextures; i++ ) + { + if( ptexture[i].index == tr.defaultTexture ) + continue; + GL_FreeTexture( ptexture[i].index ); + } +} + +static model_t *pfnModelHandle( int modelindex ) +{ + return gEngfuncs.pfnGetModelByIndex( modelindex ); +} + +static void *pfnMod_CacheCheck( struct cache_user_s *c ) +{ + return gEngfuncs.Mod_CacheCheck( c ); +} + +static void *pfnMod_StudioExtradata( model_t *mod ) +{ + return gEngfuncs.Mod_Extradata( mod_studio, mod ); +} + +static void pfnMod_LoadCacheFile( const char *path, struct cache_user_s *cu ) +{ + gEngfuncs.Mod_LoadCacheFile( path, cu ); +} + +static cvar_t *pfnGetCvarPointer( const char *name ) +{ + return (cvar_t*)gEngfuncs.pfnGetCvarPointer( name, 0 ); +} + +static void *pfnMod_Calloc( int number, size_t size ) +{ + return gEngfuncs.Mod_Calloc( number, size ); +} + +static engine_studio_api_t gStudioAPI = +{ + pfnMod_Calloc, + pfnMod_CacheCheck, + pfnMod_LoadCacheFile, + pfnMod_ForName, + pfnMod_StudioExtradata, + pfnModelHandle, + pfnGetCurrentEntity, + pfnPlayerInfo, + R_StudioGetPlayerState, + pfnGetViewEntity, + pfnGetEngineTimes, + pfnGetCvarPointer, + pfnGetViewInfo, + R_GetChromeSprite, + pfnGetModelCounters, + pfnGetAliasScale, + pfnStudioGetBoneTransform, + pfnStudioGetLightTransform, + pfnStudioGetAliasTransform, + pfnStudioGetRotationMatrix, + R_StudioSetupModel, + R_StudioCheckBBox, + R_StudioDynamicLight, + R_StudioEntityLight, + R_StudioSetupLighting, + R_StudioDrawPoints, + R_StudioDrawHulls, + R_StudioDrawAbsBBox, + R_StudioDrawBones, + (void*)R_StudioSetupSkin, + R_StudioSetRemapColors, + R_StudioSetupPlayerModel, + R_StudioClientEvents, + R_StudioGetForceFaceFlags, + R_StudioSetForceFaceFlags, + (void*)R_StudioSetHeader, + R_StudioSetRenderModel, + R_StudioSetupRenderer, + R_StudioRestoreRenderer, + R_StudioSetChromeOrigin, + pfnIsHardware, + GL_StudioDrawShadow, + GL_StudioSetRenderMode, + R_StudioSetRenderamt, + R_StudioSetCullState, + R_StudioRenderShadow, +}; + +static r_studio_interface_t gStudioDraw = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +=============== +CL_InitStudioAPI + +Initialize client studio +=============== +*/ +void CL_InitStudioAPI( void ) +{ + pStudioDraw = &gStudioDraw; + + // trying to grab them from client.dll + cl_righthand = gEngfuncs.pfnGetCvarPointer( "cl_righthand", 0 ); + + if( cl_righthand == NULL ) + cl_righthand = gEngfuncs.Cvar_Get( "cl_righthand", "0", FCVAR_ARCHIVE, "flip viewmodel (left to right)" ); + + // Xash will be used internal StudioModelRenderer + if( gEngfuncs.pfnGetStudioModelInterface( STUDIO_INTERFACE_VERSION, &pStudioDraw, &gStudioAPI )) + return; + + // NOTE: we always return true even if game interface was not correct + // because we need Draw our StudioModels + // just restore pointer to builtin function + pStudioDraw = &gStudioDraw; +} diff --git a/ref_gu/gu_triapi.c b/ref_gu/gu_triapi.c new file mode 100644 index 00000000..caff6115 --- /dev/null +++ b/ref_gu/gu_triapi.c @@ -0,0 +1,577 @@ +/* +gu_triapi.c - TriAPI draw methods +Copyright (C) 2011 Uncle Mike +Copyright (C) 2019 a1batross +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" +#include "const.h" + +static struct +{ + int renderMode; // override kRenderMode from TriAPI + vec4_t triRGBA; +} ds; + +/* +=============================================================== + + TRIAPI IMPLEMENTATION + +=============================================================== +*/ +#if 1 +static struct +{ + void *start; + gu_vert_ftcv_t *list; + qboolean begin; + int count; + int prim; + unsigned int flags; +}tri_gucontext = +{ + .start = NULL, + .list = NULL, + .begin = false, + .count = 0, + .prim = 0, + .flags = 0 +}; +#endif + +/* +============= +TriRenderMode + +set rendermode +============= +*/ +void TriRenderMode( int mode ) +{ +#if 1 + ds.renderMode = mode; + switch( mode ) + { + case kRenderNormal: + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuDisable( GU_BLEND ); + sceGuDepthMask( GU_FALSE ); + break; + case kRenderTransAlpha: + sceGuEnable( GU_BLEND ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuDepthMask( GU_TRUE ); + break; + case kRenderTransColor: + case kRenderTransTexture: + sceGuEnable( GU_BLEND ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + break; + case kRenderGlow: + case kRenderTransAdd: + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); + sceGuEnable( GU_BLEND ); + sceGuDepthMask( GU_TRUE ); + break; + } +#else + ds.renderMode = mode; + switch( mode ) + { + case kRenderNormal: + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglDisable( GL_BLEND ); + pglDepthMask( GL_TRUE ); + break; + case kRenderTransAlpha: + pglEnable( GL_BLEND ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglDepthMask( GL_FALSE ); + break; + case kRenderTransColor: + case kRenderTransTexture: + pglEnable( GL_BLEND ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + break; + case kRenderGlow: + case kRenderTransAdd: + pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); + pglEnable( GL_BLEND ); + pglDepthMask( GL_FALSE ); + break; + } +#endif +} + +/* +============= +TriBegin + +begin triangle sequence +============= +*/ +void TriBegin( int mode ) +{ +#if 1 + switch( mode ) + { + case TRI_POINTS: + tri_gucontext.prim = GU_POINTS; + break; + case TRI_TRIANGLES: + tri_gucontext.prim = GU_TRIANGLES; + break; + case TRI_TRIANGLE_FAN: + tri_gucontext.prim = GU_TRIANGLE_FAN; + break; + case TRI_QUADS: + tri_gucontext.prim = GU_TRIANGLE_FAN; + break; + case TRI_LINES: + tri_gucontext.prim = GU_LINES; + break; + case TRI_TRIANGLE_STRIP: + tri_gucontext.prim = GU_TRIANGLE_STRIP; + break; + case TRI_QUAD_STRIP: + tri_gucontext.prim = GU_TRIANGLE_STRIP; + break; + case TRI_POLYGON: + default: + tri_gucontext.prim = GU_TRIANGLE_FAN; + break; + } + tri_gucontext.start = extGuBeginPacket( NULL ); + tri_gucontext.list = ( gu_vert_ftcv_t* )tri_gucontext.start; + tri_gucontext.begin = true; + tri_gucontext.count = 0; + tri_gucontext.flags = 0; +#else + switch( mode ) + { + case TRI_POINTS: + mode = GL_POINTS; + break; + case TRI_TRIANGLES: + mode = GL_TRIANGLES; + break; + case TRI_TRIANGLE_FAN: + mode = GL_TRIANGLE_FAN; + break; + case TRI_QUADS: + mode = GL_QUADS; + break; + case TRI_LINES: + mode = GL_LINES; + break; + case TRI_TRIANGLE_STRIP: + mode = GL_TRIANGLE_STRIP; + break; + case TRI_QUAD_STRIP: + mode = GL_QUAD_STRIP; + break; + case TRI_POLYGON: + default: + mode = GL_POLYGON; + break; + } + + pglBegin( mode ); +#endif +} + +/* +============= +TriEnd + +draw triangle sequence +============= +*/ +void TriEnd( void ) +{ +#if 1 + unsigned int vert_size; + + if( !tri_gucontext.begin ) + return; + + extGuEndPacket( ( void* )tri_gucontext.list ); + sceGuDrawArray( tri_gucontext.prim, tri_gucontext.flags, tri_gucontext.count, 0, tri_gucontext.start ); + + tri_gucontext.begin = false; +#else + pglEnd( ); +#endif +} + +/* +============= +_TriColor4f + +============= +*/ +void _TriColor4f( float r, float g, float b, float a ) +{ +#if 1 + if( tri_gucontext.begin ) + { + tri_gucontext.flags |= GU_COLOR_8888; + tri_gucontext.list->c = GUCOLOR4F( r, g, b, a ); + } + else + { + sceGuColor( GUCOLOR4F( r, g, b, a ) ); + } +#else + pglColor4f( r, g, b, a ); +#endif +} + +/* +============= +_TriColor4ub + +============= +*/ +void _TriColor4ub( byte r, byte g, byte b, byte a ) +{ +#if 1 + if( tri_gucontext.begin ) + { + tri_gucontext.flags |= GU_COLOR_8888; + tri_gucontext.list->c = GUCOLOR4UB( r, g, b, a ); + } + else + { + sceGuColor( GUCOLOR4UB( r, g, b, a ) ); + } +#else + pglColor4ub( r, g, b, a ); +#endif +} + + +/* +============= +TriColor4ub + +============= +*/ +void TriColor4ub( byte r, byte g, byte b, byte a ) +{ + ds.triRGBA[0] = r * (1.0f / 255.0f); + ds.triRGBA[1] = g * (1.0f / 255.0f); + ds.triRGBA[2] = b * (1.0f / 255.0f); + ds.triRGBA[3] = a * (1.0f / 255.0f); + + _TriColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f ); +} + +/* +================= +TriColor4f +================= +*/ +void TriColor4f( float r, float g, float b, float a ) +{ + if( ds.renderMode == kRenderTransAlpha ) + TriColor4ub( r * 255.0f, g * 255.0f, b * 255.0f, a * 255.0f ); + else _TriColor4f( r * a, g * a, b * a, 1.0 ); + + ds.triRGBA[0] = r; + ds.triRGBA[1] = g; + ds.triRGBA[2] = b; + ds.triRGBA[3] = a; +} + +/* +============= +TriTexCoord2f + +============= +*/ +void TriTexCoord2f( float u, float v ) +{ +#if 1 + if( !tri_gucontext.begin ) + return; + + tri_gucontext.flags |= GU_TEXTURE_32BITF; + tri_gucontext.list->u = u; + tri_gucontext.list->v = v; +#else + pglTexCoord2f( u, v ); +#endif +} + +/* +============= +TriVertex3fv + +============= +*/ +void TriVertex3fv( const float *v ) +{ +#if 1 + if( !tri_gucontext.begin ) + return; + + if( !(tri_gucontext.flags & GU_TEXTURE_32BITF) ) + { + tri_gucontext.list->u = 0; + tri_gucontext.list->v = 0; + } + + if( !(tri_gucontext.flags & GU_COLOR_8888) ) + { + tri_gucontext.list->c = 0xffffffff; + } + + tri_gucontext.flags |= GU_VERTEX_32BITF; + tri_gucontext.list->x = v[0]; + tri_gucontext.list->y = v[1]; + tri_gucontext.list->z = v[2]; + tri_gucontext.list++; + + tri_gucontext.count++; +#else + pglVertex3fv( v ); +#endif +} + +/* +============= +TriVertex3f + +============= +*/ +void TriVertex3f( float x, float y, float z ) +{ +#if 1 + if( !tri_gucontext.begin ) + return; + + if( !(tri_gucontext.flags & GU_TEXTURE_32BITF) ) + { + tri_gucontext.list->u = 0; + tri_gucontext.list->v = 0; + } + + if( !(tri_gucontext.flags & GU_COLOR_8888) ) + { + tri_gucontext.list->c = 0xffffffff; + } + + tri_gucontext.flags |= GU_VERTEX_32BITF; + tri_gucontext.list->x = x; + tri_gucontext.list->y = y; + tri_gucontext.list->z = z; + tri_gucontext.list++; + + tri_gucontext.count++; +#else + pglVertex3f( x, y, z ); +#endif +} + +/* +============= +TriWorldToScreen + +convert world coordinates (x,y,z) into screen (x, y) +============= +*/ +int TriWorldToScreen( const float *world, float *screen ) +{ + int retval; + + retval = R_WorldToScreen( world, screen ); + + screen[0] = 0.5f * screen[0] * (float)RI.viewport[2]; + screen[1] = -0.5f * screen[1] * (float)RI.viewport[3]; + screen[0] += 0.5f * (float)RI.viewport[2]; + screen[1] += 0.5f * (float)RI.viewport[3]; + + return retval; +} + +/* +============= +TriSpriteTexture + +bind current texture +============= +*/ +int TriSpriteTexture( model_t *pSpriteModel, int frame ) +{ + int gl_texturenum; + + if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) == 0 ) + return 0; + + if( gl_texturenum <= 0 || gl_texturenum > MAX_TEXTURES ) + gl_texturenum = tr.defaultTexture; + + GL_Bind( XASH_TEXTURE0, gl_texturenum ); + + return 1; +} + +/* +============= +TriFog + +enables global fog on the level +============= +*/ +void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) +{ + // overrided by internal fog + if( RI.fogEnabled ) return; + RI.fogCustom = bOn; + + // check for invalid parms + if( flEnd <= flStart ) + { + glState.isFogEnabled = RI.fogCustom = false; +#if 1 + sceGuDisable( GU_FOG ); +#else + pglDisable( GL_FOG ); +#endif + return; + } +#if 1 + if( RI.fogCustom ) + sceGuEnable( GU_FOG ); + else sceGuDisable( GU_FOG ); +#else + if( RI.fogCustom ) + pglEnable( GL_FOG ); + else pglDisable( GL_FOG ); +#endif + // copy fog params + RI.fogColor[0] = flFogColor[0] / 255.0f; + RI.fogColor[1] = flFogColor[1] / 255.0f; + RI.fogColor[2] = flFogColor[2] / 255.0f; + RI.fogStart = flStart; + RI.fogColor[3] = 1.0f; + RI.fogDensity = 0.0f; + RI.fogSkybox = true; + RI.fogEnd = flEnd; + +#if 1 + printf("TRI FOG: s %f e %f c %f %f %f %f \n", RI.fogStart, RI.fogEnd, + RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], RI.fogColor[3] ); + + //glState.fogDensity = RI.fogDensity + glState.fogColor = GUCOLOR4F( RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], glState.fogDensity ); + glState.fogStart = RI.fogStart; + glState.fogEnd = RI.fogEnd; + + sceGuFog( glState.fogStart, glState.fogEnd, glState.fogColor ); +#else + pglFogi( GL_FOG_MODE, GL_LINEAR ); + pglFogfv( GL_FOG_COLOR, RI.fogColor ); + pglFogf( GL_FOG_START, RI.fogStart ); + pglFogf( GL_FOG_END, RI.fogEnd ); + pglHint( GL_FOG_HINT, GL_NICEST ); +#endif +} + +/* +============= +TriGetMatrix + +very strange export +============= +*/ +void TriGetMatrix( const int pname, float *matrix ) +{ +#if 1 + printf("%s:%i:%s - Not implemented\n", __FILE__, __LINE__, __FUNCTION__ ); +#else + pglGetFloatv( pname, matrix ); +#endif +} + +/* +============= +TriForParams + +============= +*/ +void TriFogParams( float flDensity, int iFogSkybox ) +{ + RI.fogDensity = flDensity; + RI.fogSkybox = iFogSkybox; +} + +/* +============= +TriCullFace + +============= +*/ +void TriCullFace( TRICULLSTYLE mode ) +{ + int glMode; + + switch( mode ) + { + case TRI_FRONT: + glMode = GL_FRONT; + break; + default: + glMode = GL_NONE; + break; + } + + GL_Cull( mode ); +} + +/* +============= +TriBrightness +============= +*/ +void TriBrightness( float brightness ) +{ + float r, g, b; + + r = ds.triRGBA[0] * ds.triRGBA[3] * brightness; + g = ds.triRGBA[1] * ds.triRGBA[3] * brightness; + b = ds.triRGBA[2] * ds.triRGBA[3] * brightness; + + _TriColor4f( r, g, b, 1.0f ); +} + +unsigned int getTriBrightness( float brightness ) +{ + vec3_t color; + + if(brightness < 0.0f) return 0; + + color[0] = ds.triRGBA[0] * ds.triRGBA[3] * brightness; + color[1] = ds.triRGBA[1] * ds.triRGBA[3] * brightness; + color[2] = ds.triRGBA[2] * ds.triRGBA[3] * brightness; + + VectorNormalizeFast( color ); + + return GUCOLOR3FV( color ); +} + diff --git a/ref_gu/gu_vgui.c b/ref_gu/gu_vgui.c new file mode 100644 index 00000000..e9f7a354 --- /dev/null +++ b/ref_gu/gu_vgui.c @@ -0,0 +1,309 @@ +/* +gl_vgui.c - OpenGL vgui draw methods +Copyright (C) 2011 Uncle Mike +Copyright (C) 2019 a1batross +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "gu_local.h" + +#define VGUI_MAX_TEXTURES ( MAX_TEXTURES / 2 ) // a half of total textures count +#if 1 +static short g_textures[VGUI_MAX_TEXTURES]; +#else +static int g_textures[VGUI_MAX_TEXTURES]; +#endif +static int g_textureId = 0; +static int g_iBoundTexture; + +/* +================ +VGUI_DrawInit + +Startup VGUI backend +================ +*/ +void GAME_EXPORT VGUI_DrawInit( void ) +{ + memset( g_textures, 0, sizeof( g_textures )); + g_textureId = g_iBoundTexture = 0; +} + +/* +================ +VGUI_DrawShutdown + +Release all textures +================ +*/ +void GAME_EXPORT VGUI_DrawShutdown( void ) +{ + int i; + + for( i = 1; i < g_textureId; i++ ) + { + GL_FreeTexture( g_textures[i] ); + } +} + +/* +================ +VGUI_GenerateTexture + +generate unique texture number +================ +*/ +int GAME_EXPORT VGUI_GenerateTexture( void ) +{ + if( ++g_textureId >= VGUI_MAX_TEXTURES ) + gEngfuncs.Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" ); + return g_textureId; +} + +/* +================ +VGUI_UploadTexture + +Upload texture into video memory +================ +*/ +void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int height ) +{ + rgbdata_t r_image; + char texName[32]; + + if( id <= 0 || id >= VGUI_MAX_TEXTURES ) + { + gEngfuncs.Con_DPrintf( S_ERROR "VGUI_UploadTexture: bad texture %i. Ignored\n", id ); + return; + } + + Q_snprintf( texName, sizeof( texName ), "*vgui%i", id ); + memset( &r_image, 0, sizeof( r_image )); + + r_image.width = width; + r_image.height = height; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA; + r_image.buffer = (byte *)buffer; + + g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE ); +} + +/* +================ +VGUI_CreateTexture + +Create empty rgba texture and upload them into video memory +================ +*/ +void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height ) +{ + rgbdata_t r_image; + char texName[32]; + + if( id <= 0 || id >= VGUI_MAX_TEXTURES ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGUI_CreateTexture: bad texture %i. Ignored\n", id ); + return; + } + + Q_snprintf( texName, sizeof( texName ), "*vgui%i", id ); + memset( &r_image, 0, sizeof( r_image )); + + r_image.width = width; + r_image.height = height; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + r_image.flags = IMAGE_HAS_ALPHA; + r_image.buffer = NULL; + + g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST ); + g_iBoundTexture = id; +} + +void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight ) +{ + if( id <= 0 || id >= VGUI_MAX_TEXTURES || g_textures[id] == 0 || g_textures[id] == tr.whiteTexture ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGUI_UploadTextureBlock: bad texture %i. Ignored\n", id ); + return; + } +#if 1 + +#else + pglTexSubImage2D( GL_TEXTURE_2D, 0, drawX, drawY, blockWidth, blockHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgba ); +#endif + g_iBoundTexture = id; +} + +void GAME_EXPORT VGUI_SetupDrawingRect( int *pColor ) +{ +#if 1 + sceGuEnable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuColor( GUCOLOR4UB( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ) ); +#else + pglEnable( GL_BLEND ); + pglDisable( GL_ALPHA_TEST ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglColor4ub( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ); +#endif +} + +void GAME_EXPORT VGUI_SetupDrawingText( int *pColor ) +{ +#if 1 + sceGuEnable( GU_BLEND ); + sceGuEnable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, 0x00, 0xff ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuColor( GUCOLOR4UB( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ) ); +#else + pglEnable( GL_BLEND ); + pglEnable( GL_ALPHA_TEST ); + pglAlphaFunc( GL_GREATER, 0.0f ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglColor4ub( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ); +#endif +} + +void GAME_EXPORT VGUI_SetupDrawingImage( int *pColor ) +{ +#if 1 + sceGuEnable( GU_BLEND ); + sceGuEnable( GU_ALPHA_TEST ); + sceGuAlphaFunc( GU_GREATER, 0x00, 0xff ); + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + sceGuColor( GUCOLOR4UB( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ) ); +#else + pglEnable( GL_BLEND ); + pglEnable( GL_ALPHA_TEST ); + pglAlphaFunc( GL_GREATER, 0.0f ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglColor4ub( pColor[0], pColor[1], pColor[2], 255 - pColor[3] ); +#endif +} + +void GAME_EXPORT VGUI_BindTexture( int id ) +{ + if( id > 0 && id < VGUI_MAX_TEXTURES && g_textures[id] ) + { + GL_Bind( XASH_TEXTURE0, g_textures[id] ); + g_iBoundTexture = id; + } + else + { + // NOTE: same as bogus index 2700 in GoldSrc + id = g_iBoundTexture = 1; + GL_Bind( XASH_TEXTURE0, g_textures[id] ); + } +} + +/* +================ +VGUI_GetTextureSizes + +returns wide and tall for currently binded texture +================ +*/ +void GAME_EXPORT VGUI_GetTextureSizes( int *width, int *height ) +{ + gl_texture_t *glt; + int texnum; + + if( g_iBoundTexture ) + texnum = g_textures[g_iBoundTexture]; + else texnum = tr.defaultTexture; + + glt = R_GetTexture( texnum ); + if( width ) *width = glt->srcWidth; + if( height ) *height = glt->srcHeight; +} + +/* +================ +VGUI_EnableTexture + +disable texturemode for fill rectangle +================ +*/ +void GAME_EXPORT VGUI_EnableTexture( qboolean enable ) +{ +#if 1 + if( enable ) sceGuEnable( GU_TEXTURE_2D ); + else sceGuDisable( GU_TEXTURE_2D ); +#else + if( enable ) pglEnable( GL_TEXTURE_2D ); + else pglDisable( GL_TEXTURE_2D ); +#endif +} + +/* +================ +VGUI_DrawQuad + +generic method to fill rectangle +================ +*/ +void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr ) +{ + int width, height; + float xscale, yscale; +#if 1 + gl_texture_t *glt; + float twidth, theight; +#endif + gEngfuncs.CL_GetScreenInfo( &width, &height ); + + xscale = gpGlobals->width / (float)width; + yscale = gpGlobals->height / (float)height; + + ASSERT( ul != NULL && lr != NULL ); +#if 1 + glt = R_GetTexture( g_iBoundTexture ? g_textures[g_iBoundTexture] : tr.defaultTexture ); + + gu_vert_htv_t* const out = ( gu_vert_htv_t* )sceGuGetMemory( sizeof( gu_vert_htv_t ) * 2 ); + out[0].u = ul->coord[0] * glt->width; + out[0].v = ul->coord[1] * glt->height; + out[0].x = ul->point[0] * xscale; + out[0].y = ul->point[1] * yscale; + out[0].z = 0; + out[1].u = lr->coord[0] * glt->width; + out[1].v = lr->coord[1] * glt->height; + out[1].x = lr->point[0] * xscale; + out[1].y = lr->point[1] * yscale; + out[1].z = 0; + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_16BIT | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out ); +#else + pglBegin( GL_QUADS ); + pglTexCoord2f( ul->coord[0], ul->coord[1] ); + pglVertex2f( ul->point[0] * xscale, ul->point[1] * yscale ); + + pglTexCoord2f( lr->coord[0], ul->coord[1] ); + pglVertex2f( lr->point[0] * xscale, ul->point[1] * yscale ); + + pglTexCoord2f( lr->coord[0], lr->coord[1] ); + pglVertex2f( lr->point[0] * xscale, lr->point[1] * yscale ); + + pglTexCoord2f( ul->coord[0], lr->coord[1] ); + pglVertex2f( ul->point[0] * xscale, lr->point[1] * yscale ); + pglEnd(); +#endif +} diff --git a/ref_gu/gu_warp.c b/ref_gu/gu_warp.c new file mode 100644 index 00000000..ad60361e --- /dev/null +++ b/ref_gu/gu_warp.c @@ -0,0 +1,871 @@ +/* +gl_warp.c - sky and water polygons +Copyright (C) 2010 Uncle Mike +Copyright (C) 2020 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + + +#include "gu_local.h" +#include "wadfile.h" +#define SKYCLOUDS_QUALITY 12 +#define MAX_CLIP_VERTS 128 // skybox clip vertices +#define TURBSCALE ( 256.0f / ( M_PI2 )) +const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" }; +static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 }; + +static const vec3_t skyclip[6] = +{ +{ 1, 1, 0 }, +{ 1, -1, 0 }, +{ 0, -1, 1 }, +{ 0, 1, 1 }, +{ 1, 0, 1 }, +{ -1, 0, 1 } +}; + +// 1 = s, 2 = t, 3 = 2048 +static const int st_to_vec[6][3] = +{ +{ 3, -1, 2 }, +{ -3, 1, 2 }, +{ 1, 3, 2 }, +{ -1, -3, 2 }, +{ -2, -1, 3 }, // 0 degrees yaw, look straight up +{ 2, -1, -3 } // look straight down +}; + +// s = [0]/[2], t = [1]/[2] +static const int vec_to_st[6][3] = +{ +{ -2, 3, 1 }, +{ 2, 3, -1 }, +{ 1, 3, 2 }, +{ -1, 3, -2 }, +{ -2, -1, 3 }, +{ -2, 1, -3 } +}; + +// speed up sin calculations +float r_turbsin[] = +{ + #include "warpsin.h" +}; + +#define SKYBOX_MISSED 0 +#define SKYBOX_HLSTYLE 1 +#define SKYBOX_Q1STYLE 2 + +static int CheckSkybox( const char *name ) +{ + const char *skybox_ext[3] = { "dds", "tga", "bmp" }; + int i, j, num_checked_sides; + const char *sidename; + + // search for skybox images + for( i = 0; i < 3; i++ ) + { + num_checked_sides = 0; + for( j = 0; j < 6; j++ ) + { + // build side name + sidename = va( "%s%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] ); + if( gEngfuncs.FS_FileExists( sidename, false )) + num_checked_sides++; + + } + + if( num_checked_sides == 6 ) + return SKYBOX_HLSTYLE; // image exists + + for( j = 0; j < 6; j++ ) + { + // build side name + sidename = va( "%s_%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] ); + if( gEngfuncs.FS_FileExists( sidename, false )) + num_checked_sides++; + } + + if( num_checked_sides == 6 ) + return SKYBOX_Q1STYLE; // images exists + } + + return SKYBOX_MISSED; +} + +void DrawSkyPolygon( int nump, vec3_t vecs ) +{ + int i, j, axis; + float s, t, dv, *vp; + vec3_t v, av; + + // decide which face it maps to + VectorClear( v ); + + for( i = 0, vp = vecs; i < nump; i++, vp += 3 ) + VectorAdd( vp, v, v ); + + av[0] = fabs( v[0] ); + av[1] = fabs( v[1] ); + av[2] = fabs( v[2] ); + + if( av[0] > av[1] && av[0] > av[2] ) + axis = (v[0] < 0) ? 1 : 0; + else if( av[1] > av[2] && av[1] > av[0] ) + axis = (v[1] < 0) ? 3 : 2; + else axis = (v[2] < 0) ? 5 : 4; + + // project new texture coords + for( i = 0; i < nump; i++, vecs += 3 ) + { + j = vec_to_st[axis][2]; + dv = (j > 0) ? vecs[j-1] : -vecs[-j-1]; + + if( dv == 0.0f ) continue; + + j = vec_to_st[axis][0]; + s = (j < 0) ? -vecs[-j-1] / dv : vecs[j-1] / dv; + + j = vec_to_st[axis][1]; + t = (j < 0) ? -vecs[-j-1] / dv : vecs[j-1] / dv; + + if( s < RI.skyMins[0][axis] ) RI.skyMins[0][axis] = s; + if( t < RI.skyMins[1][axis] ) RI.skyMins[1][axis] = t; + if( s > RI.skyMaxs[0][axis] ) RI.skyMaxs[0][axis] = s; + if( t > RI.skyMaxs[1][axis] ) RI.skyMaxs[1][axis] = t; + } +} + +/* +============== +ClipSkyPolygon +============== +*/ +void ClipSkyPolygon( int nump, vec3_t vecs, int stage ) +{ + const float *norm; + float *v, d, e; + qboolean front, back; + float dists[MAX_CLIP_VERTS + 1]; + int sides[MAX_CLIP_VERTS + 1]; + vec3_t newv[2][MAX_CLIP_VERTS + 1]; + int newc[2]; + int i, j; + + if( nump > MAX_CLIP_VERTS ) + gEngfuncs.Host_Error( "ClipSkyPolygon: MAX_CLIP_VERTS\n" ); +loc1: + if( stage == 6 ) + { + // fully clipped, so draw it + DrawSkyPolygon( nump, vecs ); + return; + } + + front = back = false; + norm = skyclip[stage]; + for( i = 0, v = vecs; i < nump; i++, v += 3 ) + { + d = DotProduct( v, norm ); + if( d > ON_EPSILON ) + { + front = true; + sides[i] = SIDE_FRONT; + } + else if( d < -ON_EPSILON ) + { + back = true; + sides[i] = SIDE_BACK; + } + else + { + sides[i] = SIDE_ON; + } + dists[i] = d; + } + + if( !front || !back ) + { + // not clipped + stage++; + goto loc1; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy( vecs, ( vecs + ( i * 3 ))); + newc[0] = newc[1] = 0; + + for( i = 0, v = vecs; i < nump; i++, v += 3 ) + { + switch( sides[i] ) + { + case SIDE_FRONT: + VectorCopy( v, newv[0][newc[0]] ); + newc[0]++; + break; + case SIDE_BACK: + VectorCopy( v, newv[1][newc[1]] ); + newc[1]++; + break; + case SIDE_ON: + VectorCopy( v, newv[0][newc[0]] ); + newc[0]++; + VectorCopy( v, newv[1][newc[1]] ); + newc[1]++; + break; + } + + if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) + continue; + + d = dists[i] / ( dists[i] - dists[i+1] ); + for( j = 0; j < 3; j++ ) + { + e = v[j] + d * ( v[j+3] - v[j] ); + newv[0][newc[0]][j] = e; + newv[1][newc[1]][j] = e; + } + newc[0]++; + newc[1]++; + } + + // continue + ClipSkyPolygon( newc[0], newv[0][0], stage + 1 ); + ClipSkyPolygon( newc[1], newv[1][0], stage + 1 ); +} +#if 1 +_inline void MakeSkyVec( float s, float t, int axis, gu_vert_t *out ) +{ + int j, k, farclip; + vec3_t v, b; + + farclip = RI.farClip; + + b[0] = s * (farclip >> 1); + b[1] = t * (farclip >> 1); + b[2] = (farclip >> 1); + + for( j = 0; j < 3; j++ ) + { + k = st_to_vec[axis][j]; + v[j] = (k < 0) ? -b[-k-1] : b[k-1]; + v[j] += RI.cullorigin[j]; + } + + // avoid bilerp seam + s = (s + 1.0f) * 0.5f; + t = (t + 1.0f) * 0.5f; + + if( s < 1.0f / 512.0f ) + s = 1.0f / 512.0f; + else if( s > 511.0f / 512.0f ) + s = 511.0f / 512.0f; + if( t < 1.0f / 512.0f ) + t = 1.0f / 512.0f; + else if( t > 511.0f / 512.0f ) + t = 511.0f / 512.0f; + + t = 1.0f - t; + + out->uv[0] = s; + out->uv[1] = t; + VectorCopy( v, out->xyz ); +} +#else +void MakeSkyVec( float s, float t, int axis ) +{ + int j, k, farclip; + vec3_t v, b; + + farclip = RI.farClip; + + b[0] = s * (farclip >> 1); + b[1] = t * (farclip >> 1); + b[2] = (farclip >> 1); + + for( j = 0; j < 3; j++ ) + { + k = st_to_vec[axis][j]; + v[j] = (k < 0) ? -b[-k-1] : b[k-1]; + v[j] += RI.cullorigin[j]; + } + + // avoid bilerp seam + s = (s + 1.0f) * 0.5f; + t = (t + 1.0f) * 0.5f; + + if( s < 1.0f / 512.0f ) + s = 1.0f / 512.0f; + else if( s > 511.0f / 512.0f ) + s = 511.0f / 512.0f; + if( t < 1.0f / 512.0f ) + t = 1.0f / 512.0f; + else if( t > 511.0f / 512.0f ) + t = 511.0f / 512.0f; + + t = 1.0f - t; + + pglTexCoord2f( s, t ); + pglVertex3fv( v ); +} +#endif +/* +============== +R_ClearSkyBox +============== +*/ +void R_ClearSkyBox( void ) +{ + int i; + + for( i = 0; i < 6; i++ ) + { + RI.skyMins[0][i] = RI.skyMins[1][i] = 9999999.0f; + RI.skyMaxs[0][i] = RI.skyMaxs[1][i] = -9999999.0f; + } +} + +/* +================= +R_AddSkyBoxSurface +================= +*/ +void R_AddSkyBoxSurface( msurface_t *fa ) +{ + vec3_t verts[MAX_CLIP_VERTS]; + glpoly_t *p; + float *v; + int i; + + if( ENGINE_GET_PARM( PARM_SKY_SPHERE ) && fa->polys && !tr.fCustomSkybox ) + { + glpoly_t *p = fa->polys; + + // draw the sky poly + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, p->verts ); + } + + // calculate vertex values for sky box + for( p = fa->polys; p; p = p->next ) + { + for( i = 0; i < p->numverts; i++ ) + VectorSubtract( p->verts[i].xyz, RI.cullorigin, verts[i] ); + ClipSkyPolygon( p->numverts, verts[0], 0 ); + } +} + +/* +============== +R_UnloadSkybox + +Unload previous skybox +============== +*/ +void R_UnloadSkybox( void ) +{ + int i; + + // release old skybox + for( i = 0; i < 6; i++ ) + { + if( !tr.skyboxTextures[i] ) continue; + GL_FreeTexture( tr.skyboxTextures[i] ); + } +#if 0 + tr.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes) +#endif + memset( tr.skyboxTextures, 0, sizeof( tr.skyboxTextures )); + tr.fCustomSkybox = false; +} + +/* +============== +R_DrawSkybox +============== +*/ +void R_DrawSkyBox( void ) +{ + int i; + RI.isSkyVisible = true; + + // don't fogging skybox (this fix old Half-Life bug) + if( !RI.fogSkybox ) R_AllowFog( false ); + +/* + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity * 0.5f ); +*/ + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + sceGuTexFunc( GU_TFX_REPLACE, GU_TCC_RGBA ); + + for( i = 0; i < 6; i++ ) + { + if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] ) + continue; + + if( tr.skyboxTextures[r_skyTexOrder[i]] ) + GL_Bind( XASH_TEXTURE0, tr.skyboxTextures[r_skyTexOrder[i]] ); + else GL_Bind( XASH_TEXTURE0, tr.grayTexture ); // stub + + //gu_vert_t uv[4] __attribute__( ( aligned( 16 ) ) ); // dcache writeback required! + gu_vert_t* const uv = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); + MakeSkyVec( RI.skyMins[0][i], RI.skyMins[1][i], i, &uv[0] ); + MakeSkyVec( RI.skyMins[0][i], RI.skyMaxs[1][i], i, &uv[1] ); + MakeSkyVec( RI.skyMaxs[0][i], RI.skyMaxs[1][i], i, &uv[2] ); + MakeSkyVec( RI.skyMaxs[0][i], RI.skyMins[1][i], i, &uv[3] ); + + if ( GU_ClipIsRequired( uv, 4 ) ) + { + gu_vert_t* cv; + size_t cvc; + + GU_Clip( uv, 4, &cv, &cvc ); + if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); + } + else sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, uv ); + } + + if( !RI.fogSkybox ) + R_AllowFog( true ); +/* + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity ); +*/ + R_LoadIdentity(); +} + +/* +=============== +R_SetupSky +=============== +*/ +void R_SetupSky( const char *skyboxname ) +{ + char loadname[MAX_STRING]; + char sidename[MAX_STRING]; + int i, result; + + if( !COM_CheckString( skyboxname )) + { + R_UnloadSkybox(); + return; // clear old skybox + } + + Q_snprintf( loadname, sizeof( loadname ), "gfx/env/%s", skyboxname ); + COM_StripExtension( loadname ); + + // kill the underline suffix to find them manually later + if( loadname[Q_strlen( loadname ) - 1] == '_' ) + loadname[Q_strlen( loadname ) - 1] = '\0'; + result = CheckSkybox( loadname ); + + // to prevent infinite recursion if default skybox was missed + if( result == SKYBOX_MISSED && Q_stricmp( loadname, DEFAULT_SKYBOX_PATH )) + { + gEngfuncs.Con_Reportf( S_WARN "missed or incomplete skybox '%s'\n", skyboxname ); + R_SetupSky( "desert" ); // force to default + return; + } + + // release old skybox + R_UnloadSkybox(); + gEngfuncs.Con_DPrintf( "SKY: " ); + + for( i = 0; i < 6; i++ ) + { + if( result == SKYBOX_HLSTYLE ) + Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] ); + else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] ); + + tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY ); + if( !tr.skyboxTextures[i] ) break; + gEngfuncs.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " ); + } + + if( i == 6 ) + { + tr.fCustomSkybox = true; + gEngfuncs.Con_DPrintf( "done\n" ); + return; // loaded + } + + gEngfuncs.Con_DPrintf( "^2failed\n" ); + R_UnloadSkybox(); +} + +//============================================================================== +// +// RENDER CLOUDS +// +//============================================================================== +/* +============== +R_CloudVertex +============== +*/ +void R_CloudVertex( float s, float t, int axis, vec3_t v ) +{ + int j, k, farclip; + vec3_t b; + + farclip = RI.farClip; + + b[0] = s * (farclip >> 1); + b[1] = t * (farclip >> 1); + b[2] = (farclip >> 1); + + for( j = 0; j < 3; j++ ) + { + k = st_to_vec[axis][j]; + v[j] = (k < 0) ? -b[-k-1] : b[k-1]; + v[j] += RI.cullorigin[j]; + } +} + +/* +============= +R_CloudTexCoord +============= +*/ +#if 1 +_inline void R_CloudTexCoord( vec3_t v, float speed, float *s, float *t ) +#else +void R_CloudTexCoord( vec3_t v, float speed, float *s, float *t ) +#endif +{ + float length, speedscale; + vec3_t dir; + + speedscale = gpGlobals->time * speed; + speedscale -= (int)speedscale & ~127; + + VectorSubtract( v, RI.vieworg, dir ); + dir[2] *= 3.0f; // flatten the sphere + + length = VectorLength( dir ); + length = 6.0f * 63.0f / length; + + *s = ( speedscale + dir[0] * length ) * (1.0f / 128.0f); + *t = ( speedscale + dir[1] * length ) * (1.0f / 128.0f); +} + +/* +=============== +R_CloudDrawPoly +=============== +*/ +void R_CloudDrawPoly( glpoly_t *p ) +{ + float *v; + int i; + + GL_SetRenderMode( kRenderNormal ); + GL_Bind( XASH_TEXTURE0, tr.solidskyTexture ); + + gu_vert_t* out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); + for( i = 0; i < 4; i++ ) + { + R_CloudTexCoord( p->verts[i].xyz, 8.0f, &out[i].uv[0], &out[i].uv[1] ); + VectorCopy( p->verts[i].xyz, out[i].xyz ); + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); + + GL_SetRenderMode( kRenderTransTexture ); + GL_Bind( XASH_TEXTURE0, tr.alphaskyTexture ); + + out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); + for( i = 0; i < 4; i++ ) + { + R_CloudTexCoord( p->verts[i].xyz, 16.0f, &out[i].uv[0], &out[i].uv[1] ); + VectorCopy( p->verts[i].xyz, out[i].xyz ); + } + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); + + sceGuDisable( GU_BLEND ); +} + +/* +============== +R_CloudRenderSide +============== +*/ +void R_CloudRenderSide( int axis ) +{ + vec3_t verts[4]; + float di, qi, dj, qj; + vec3_t vup, vright; + vec3_t temp, temp2; + glpoly_t p[1]; + int i, j; + + R_CloudVertex( -1.0f, -1.0f, axis, verts[0] ); + R_CloudVertex( -1.0f, 1.0f, axis, verts[1] ); + R_CloudVertex( 1.0f, 1.0f, axis, verts[2] ); + R_CloudVertex( 1.0f, -1.0f, axis, verts[3] ); + + VectorSubtract( verts[2], verts[3], vup ); + VectorSubtract( verts[2], verts[1], vright ); + + p->numverts = 4; + di = SKYCLOUDS_QUALITY; + qi = 1.0f / di; + dj = (axis < 4) ? di * 2 : di; //subdivide vertically more than horizontally on skybox sides + qj = 1.0f / dj; + + for( i = 0; i < di; i++ ) + { + for( j = 0; j < dj; j++ ) + { + if( i * qi < RI.skyMins[0][axis] / 2 + 0.5f - qi + || i * qi > RI.skyMaxs[0][axis] / 2 + 0.5f + || j * qj < RI.skyMins[1][axis] / 2 + 0.5f - qj + || j * qj > RI.skyMaxs[1][axis] / 2 + 0.5f ) + continue; + + VectorScale( vright, qi * i, temp ); + VectorScale( vup, qj * j, temp2 ); + VectorAdd( temp, temp2, temp ); + VectorAdd( verts[0], temp, p->verts[0].xyz ); + + VectorScale( vup, qj, temp ); + VectorAdd( p->verts[0].xyz, temp, p->verts[1].xyz ); + + VectorScale( vright, qi, temp ); + VectorAdd( p->verts[1].xyz, temp, p->verts[2].xyz ); + + VectorAdd( p->verts[0].xyz, temp, p->verts[3].xyz ); + + R_CloudDrawPoly( p ); + } + } +} + +/* +============== +R_DrawClouds + +Quake-style clouds +============== +*/ +void R_DrawClouds( void ) +{ + int i; + + RI.isSkyVisible = true; + +/* + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity * 0.25f ); +*/ + sceGuDepthFunc( GU_GEQUAL ); + sceGuDepthMask( GU_TRUE ); + + for( i = 0; i < 6; i++ ) + { + if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] ) + continue; + R_CloudRenderSide( i ); + } + + sceGuDepthFunc( GU_LEQUAL ); + sceGuDepthMask( GU_FALSE ); +/* + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity ); +*/ +} + +/* +============= +R_InitSkyClouds + +A sky texture is 256*128, with the right side being a masked overlay +============== +*/ +void R_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette ) +{ + rgbdata_t r_temp, *r_sky; + uint *trans, *rgba; + uint transpix; + int r, g, b; + int i, j, p; + char texname[32]; + + if( !glw_state.initialized ) + return; + + Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", tx->name ); + + if( mt->offsets[0] > 0 ) + { + int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6); + + if( custom_palette ) size += sizeof( short ) + 768; + r_sky = gEngfuncs.FS_LoadImage( texname, (byte *)mt, size ); + } + else + { + // okay, loading it from wad + r_sky = gEngfuncs.FS_LoadImage( texname, NULL, 0 ); + } + + // make sure what sky image is valid + if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 || r_sky->height == 0 ) + { + gEngfuncs.Con_Reportf( S_ERROR "R_InitSky: unable to load sky texture %s\n", tx->name ); + if( r_sky ) gEngfuncs.FS_FreeImage( r_sky ); + return; + } + + // make an average value for the back to avoid + // a fringe on the top level + trans = Mem_Malloc( r_temppool, r_sky->height * r_sky->height * sizeof( *trans )); + r = g = b = 0; + + for( i = 0; i < r_sky->width >> 1; i++ ) + { + for( j = 0; j < r_sky->height; j++ ) + { + p = r_sky->buffer[i * r_sky->width + j + r_sky->height]; + rgba = (uint *)r_sky->palette + p; + trans[(i * r_sky->height) + j] = *rgba; + r += ((byte *)rgba)[0]; + g += ((byte *)rgba)[1]; + b += ((byte *)rgba)[2]; + } + } + + ((byte *)&transpix)[0] = r / ( r_sky->height * r_sky->height ); + ((byte *)&transpix)[1] = g / ( r_sky->height * r_sky->height ); + ((byte *)&transpix)[2] = b / ( r_sky->height * r_sky->height ); + ((byte *)&transpix)[3] = 0; + + // build a temporary image + r_temp = *r_sky; + r_temp.width = r_sky->width >> 1; + r_temp.height = r_sky->height; + r_temp.type = PF_RGBA_32; + r_temp.flags = IMAGE_HAS_COLOR; + r_temp.size = r_temp.width * r_temp.height * 4; + r_temp.buffer = (byte *)trans; + r_temp.palette = NULL; + + // load it in + tr.solidskyTexture = GL_LoadTextureInternal( REF_SOLIDSKY_TEXTURE, &r_temp, TF_NOMIPMAP ); + + for( i = 0; i < r_sky->width >> 1; i++ ) + { + for( j = 0; j < r_sky->height; j++ ) + { + p = r_sky->buffer[i * r_sky->width + j]; + + if( p == 0 ) + { + trans[(i * r_sky->height) + j] = transpix; + } + else + { + rgba = (uint *)r_sky->palette + p; + trans[(i * r_sky->height) + j] = *rgba; + } + } + } + + r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA; + + // load it in + tr.alphaskyTexture = GL_LoadTextureInternal( REF_ALPHASKY_TEXTURE, &r_temp, TF_NOMIPMAP ); + + // clean up + gEngfuncs.FS_FreeImage( r_sky ); + Mem_Free( trans ); +} + +/* +============= +EmitWaterPolys + +Does a water warp on the pre-fragmented glpoly_t chain +============= +*/ +void EmitWaterPolys( msurface_t *warp, qboolean reverse ) +{ + gu_vert_t *verts; + float *v, nv, waveHeight; + float s, t, os, ot; + glpoly_t *p; + int i; + + if( !warp->polys ) return; + + // set the current waveheight + if( warp->polys->verts[0].xyz[2] >= RI.vieworg[2] ) + waveHeight = -RI.currententity->curstate.scale; + else waveHeight = RI.currententity->curstate.scale; + + // reset fog color for nonlightmapped water + GL_ResetFogColor(); + + for( p = warp->polys; p; p = p->next ) + { + if( reverse ) + verts = &p->verts[p->numverts - 1]; + else verts = &p->verts[0]; + + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * p->numverts ); + for( i = 0; i < p->numverts; i++ ) + { + if( waveHeight ) + { + nv = r_turbsin[( int )( gpGlobals->time * 160.0f + verts->xyz[1] + verts->xyz[0]) & 255] + 8.0f; + nv = (r_turbsin[( int )( verts->xyz[0] * 5.0f + gpGlobals->time * 171.0f - verts->xyz[1]) & 255] + 8.0f ) * 0.8f + nv; + nv = nv * waveHeight + verts->xyz[2]; + } + else nv = verts->xyz[2]; + + os = verts->uv[0]; + ot = verts->uv[1]; + + s = os + r_turbsin[(int)((ot * 0.125f + gpGlobals->time) * TURBSCALE) & 255]; + s *= ( 1.0f / SUBDIVIDE_SIZE ); + + t = ot + r_turbsin[(int)((os * 0.125f + gpGlobals->time) * TURBSCALE) & 255]; + t *= ( 1.0f / SUBDIVIDE_SIZE ); + + out[i].uv[0] = s; + out[i].uv[1] = t; + out[i].xyz[0] = verts->xyz[0]; + out[i].xyz[1] = verts->xyz[1]; + out[i].xyz[2] = nv; + + if( reverse ) + verts -= 1; + else verts += 1; + } + if ( GU_ClipIsRequired( out, p->numverts ) ) + { + // Clip the polygon. + gu_vert_t* cv; + size_t cvc; + + GU_Clip( out, p->numverts, &cv, &cvc ); + if( cvc ) + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); + } + else + sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, out ); + } + GL_SetupFogColorForSurfaces(); +} diff --git a/ref_gu/vram_psp.h b/ref_gu/vram_psp.h new file mode 100644 index 00000000..0b974f99 --- /dev/null +++ b/ref_gu/vram_psp.h @@ -0,0 +1,39 @@ +/* + * Helper for use with the PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed as 'free to use and modify as long as credited appropriately' + * + * vram.h - Standard C high performance VRAM allocation routines. + * + * Copyright (c) 2007 Alexander Berl 'Raphael' + * http://wordpress.fx-world.org + */ +#ifndef vram_h__ +#define vram_h__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void* vrelptr( void *ptr ); // make a pointer relative to memory base address (ATTENTION: A NULL rel ptr is not illegal/invalid!) +void* vabsptr( void *ptr ); // make a pointer absolute (default return type of valloc) + +void* valloc( size_t size ); +void vfree( void* ptr ); +size_t vmemavail(); +size_t vlargestblock(); + + +#ifdef _DEBUG +// Debug printf (to stdout) a trace of the current Memblocks +void __memwalk(); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif // ifdef vram_h__ diff --git a/ref_gu/wscript b/ref_gu/wscript new file mode 100644 index 00000000..7c05884b --- /dev/null +++ b/ref_gu/wscript @@ -0,0 +1,58 @@ +#! /usr/bin/env python +# encoding: utf-8 +# mittorn, 2018 + +from waflib import Logs +import os + +top = '.' + +def options(opt): + grp = opt.add_option_group('ref_gu options') + + grp.add_option('--enable-static-gl', action='store_true', dest='GL_STATIC', default=False, + help = 'enable direct linking to opengl [default: %default]') + + grp.add_option('--disable-gl', action='store_false', dest='GL', default=True, + help = 'disable opengl [default: %default]') + + # stub + return + +def configure(conf): + # check for dedicated server build + if conf.options.DEDICATED: + return + + conf.define_cond('SUPPORT_BSP2_FORMAT', conf.options.SUPPORT_BSP2_FORMAT) + + conf.env.GL = conf.options.GL + conf.env.GL_STATIC = conf.options.GL_STATIC + + conf.define('REF_DLL', 1) + +def build(bld): + libs = [ 'public', 'M' ] + + source = bld.path.ant_glob(['*.c']) + + includes = ['.', + '../engine', + '../engine/common', + '../engine/server', + '../engine/client', + '../public', + '../common', + '../pm_shared' ] + + if bld.env.GL: + bld.shlib( + source = source, + target = 'ref_gu', + features = 'c', + includes = includes, + use = libs + (['GL'] if bld.env.GL_STATIC else []), + defines = ['XASH_GL_STATIC'] if bld.env.GL_STATIC else [], + install_path = bld.env.LIBDIR, + subsystem = bld.env.MSVC_SUBSYSTEM + ) diff --git a/ref_soft/exports.txt b/ref_soft/exports.txt new file mode 100644 index 00000000..b79f9600 --- /dev/null +++ b/ref_soft/exports.txt @@ -0,0 +1,2 @@ +GetRefAPI +GetRefHumanReadableName \ No newline at end of file diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 3f0be086..06a53c32 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -28,6 +28,8 @@ ANDROID_NDK_SYSROOT_FLAG_MAX = 19 # latest NDK that need --sysroot flag ANDROID_NDK_API_MIN = { 10: 3, 19: 16, 20: 16 } # minimal API level ndk revision supports ANDROID_64BIT_API_MIN = 21 # minimal API level that supports 64-bit targets +PSP_SDK_ENVVARS = ['PSPDEV', 'PSPSDK', 'PSPTOOLCHAIN'] + # This class does support ONLY r10e and r19c/r20 NDK class Android: ctx = None # waf context @@ -320,11 +322,80 @@ class Android: ldflags += ['-march=armv5te'] return ldflags + + +class PSP: + ctx = None # waf context + sdk_home = None + psptoolchain_path = None + pspsdk_path = None + binutils_path = None + module_type = None + fw_version = None + render_type = None + + def __init__(self, ctx, moduletype, fwversion, rendertype): + self.ctx = ctx + self.module_type = moduletype + self.fw_version = fwversion + self.render_type = rendertype + + for i in PSP_SDK_ENVVARS: + self.sdk_home = os.getenv(i) + if self.sdk_home != None: + break + else: + ctx.fatal('Set %s environment variable pointing to the root of PSP SDK!' % + ' or '.join(PSP_SDK_ENVVARS)) + + self.psptoolchain_path = os.path.join(self.sdk_home, 'psp') + self.pspsdk_path = os.path.join(self.psptoolchain_path, 'sdk') + self.binutils_path = os.path.join(self.sdk_home, 'bin') + + def cflags(self, cxx = False): + cflags = [] + cflags += ['-I%s' % (os.path.join(self.pspsdk_path, 'include'))] +# cflags += ['-I%s' % (os.path.join(self.psptoolchain_path, 'include'))] + cflags += ['-I.'] + cflags += ['-D_PSP_FW_VERSION=%s' % self.fw_version, '-G0'] + return cflags + # they go before object list + def linkflags(self): + linkflags = [] +# if self.module_type == 'prx': +# linkflags += ['-specs=%s' % os.path.join(self.pspsdk_path, 'lib/prxspecs')] +# linkflags += ['-Wl,-q,-T%s' % os.path.join(self.pspsdk_path, 'lib/linkfile.prx')] +# linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined', '-no-canonical-prefixes'] + return linkflags + + def ldflags(self): + ldflags = [] + if self.module_type == 'prx': + ldflags += ['-specs=%s' % os.path.join(self.pspsdk_path, 'lib/prxspecs')] + ldflags += ['-Wl,-q,-T%s' % os.path.join(self.pspsdk_path, 'lib/linkfile.prx')] + ldflags += ['-L%s' % os.path.join(self.pspsdk_path, 'lib')] +# ldflags += ['-L%s' % os.path.join(self.psptoolchain_path, 'lib')] + ldflags += ['-L.'] +# ldflags += ['-lgcc', '-no-canonical-prefixes'] + return ldflags + + def stdlibs(self): + stdlibs = [] + stdlibs += ['-lpspdisplay', '-lpspgum_vfpu', '-lpspgu','-lpspge', '-lpspvfpu'] + stdlibs += ['-lpspaudiolib', '-lpspaudio'] + stdlibs += ['-lstdc++', '-lc', '-lm', '-lpspdebug', '-lpspctrl', '-lpspsdk', '-lpsprtc'] + stdlibs += ['-lpspnet', '-lpspnet_inet', '-lpspnet_apctl', '-lpspnet_resolver', '-lpsputility', '-lpspuser', '-lpspkernel', '-lpsppower'] + return stdlibs + def options(opt): android = opt.add_option_group('Android options') android.add_option('--android', action='store', dest='ANDROID_OPTS', default=None, help='enable building for android, format: --android=,,, example: --android=armeabi-v7a-hard,4.9,9') + psp = opt.add_option_group('Sony PSP options') + psp.add_option('--psp', action='store', dest='PSP_OPTS', default=None, + help='enable building for Sony PSP, format: --psp=,, example: --psp=prx,660,HW') + def configure(conf): if conf.options.ANDROID_OPTS: values = conf.options.ANDROID_OPTS.split(',') @@ -361,11 +432,98 @@ def configure(conf): # conf.env.ANDROID_OPTS = android conf.env.DEST_OS2 = 'android' - MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android' }) + if conf.options.PSP_OPTS: + values = conf.options.PSP_OPTS.split(',') + if len(values) != 3: + conf.fatal('Invalid --psp paramater value!') + + valid_module_type = ['elf', 'prx'] + valid_render_type = ['SW', 'HW', 'ALL'] + + if values[0] not in valid_module_type: + conf.fatal('Unknown module type: %s. Supported: %r' % (values[0], ', '.join(valid_module_type))) + if values[2] not in valid_render_type: + conf.fatal('Unknown render type: %s. Supported: %r' % (values[2], ', '.join(valid_render_type))) + + conf.psp = psp = PSP(conf, values[0], values[1], values[2]) + conf.environ['CC'] = os.path.join(psp.binutils_path, 'psp-gcc') + conf.environ['CXX'] = os.path.join(psp.binutils_path, 'psp-gcc') + conf.environ['AS'] = os.path.join(psp.binutils_path, 'psp-gcc') + conf.environ['STRIP'] = os.path.join(psp.binutils_path, 'psp-strip') + conf.environ['LD'] = os.path.join(psp.binutils_path, 'psp-gcc') + conf.environ['AR'] = os.path.join(psp.binutils_path, 'psp-ar') + conf.environ['RANLIB'] = os.path.join(psp.binutils_path, 'psp-ranlib') + conf.environ['OBJCOPY'] = os.path.join(psp.binutils_path, 'psp-objcopy') + +# conf.environ['PRXGEN'] = os.path.join(psp.binutils_path, 'prxgen') +# conf.environ['MKSFO'] = os.path.join(psp.binutils_path, 'mksfoex') +# conf.environ['PACK_PBP'] = os.path.join(psp.binutils_path, 'pack-pbp') +# conf.environ['FIXUP'] = os.path.join(psp.binutils_path, 'psp-fixup-imports') + + conf.env.PRXGEN = conf.find_program('psp-prxgen', path_list = psp.binutils_path) + conf.env.MKSFO = conf.find_program('mksfoex', path_list = psp.binutils_path) + conf.env.PACK_PBP = conf.find_program('pack-pbp', path_list = psp.binutils_path) + conf.env.FIXUP = conf.find_program('psp-fixup-imports', path_list = psp.binutils_path) + + conf.env.CFLAGS += psp.cflags() + conf.env.CXXFLAGS += psp.cflags() + conf.env.LINKFLAGS += psp.linkflags() + conf.env.LDFLAGS += psp.ldflags() + + conf.env.PREFIX = '/lib' + + conf.msg('Selected PSPSDK', '%s' % (psp.sdk_home)) + # no need to print C/C++ compiler, as it would be printed by compiler_c/cxx + conf.msg('... C/C++ flags', ' '.join(psp.cflags()).replace(psp.sdk_home, '$PSPSDK')) + conf.msg('... link flags', ' '.join(psp.linkflags()).replace(psp.sdk_home, '$PSPSDK')) + conf.msg('... ld flags', ' '.join(psp.ldflags()).replace(psp.sdk_home, '$PSPSDK')) + + if conf.options.PROFILING: + conf.env.LDFLAGS += ['-lpspprof'] + conf.env.CFLAGS += ['-pg'] + conf.env.LDFLAGS += psp.stdlibs() + + conf.env.DEST_OS2 = 'psp' + conf.env.PSP_RENDER_TYPE = psp.render_type + conf.env.PSP_PATTERN_program = '%s' + conf.env.PSP_PATTERN_stlib = 'lib%s.a' + conf.env.PSP_PATTERN_shlib = '%s.elf' + + if psp.module_type == 'prx': + conf.env.PSP_BUILD_PRX = True + + MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android', '__psp__' : 'psp'}) for k in c_config.MACRO_TO_DESTOS: MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS +def build(bld): + if bld.env.DEST_OS == 'psp': + bld(rule='${FIXUP} -o ${TGT} ${SRC}', source='engine/xash', target='xash.elf') + if bld.env.PSP_BUILD_PRX: + bld(rule='${PRXGEN} ${SRC} ${TGT}', source='xash.elf', target='xash.prx') + bld(rule='${MKSFO} -d MEMSIZE=1 Xash3D ${TGT}', source='xash.prx', target='PARAM.SFO') + bld(rule='${PACK_PBP} ${TGT} ${SRC[1]} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0]} ${PSP_EBOOT_PSAR}', source='xash.prx PARAM.SFO', target='EBOOT.PBP') + else: + bld(rule='${STRIP} -o ${TGT} ${SRC}', source='xash.elf', target='xash_strip.elf') + bld(rule='${MKSFO} -d MEMSIZE=1 Xash3D ${TGT}', source='xash_strip.elf', target='PARAM.SFO') + bld(rule='${PACK_PBP} ${TGT} ${SRC[1]} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0]} ${PSP_EBOOT_PSAR}', source='xash_strip.elf PARAM.SFO', target='EBOOT.PBP') +# source_target = os.path.join('engine', bld.env.PSP_BUILD_TARGET) +# Logs.info(source_target) +# Logs.info(bld.env.PSP_BUILD_TARGET) +# bld(rule='${FIXUP} -o ${PSP_BUILD_TARGET}.elf ${SRC}', source=source_target, always=True) +# if bld.env.PSP_BUILD_PRX: +# bld(rule='${PRXGEN} ${PSP_BUILD_TARGET}.elf ${PSP_BUILD_TARGET}.prx', always=True) +# if bld.env.PSP_BUILD_EBOOT: +# bld(rule='${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${PSP_EBOOT_SFO}', always=True) +# bld(rule='${PACK_PBP} ${PSP_EBOOT} ${PSP_EBOOT_SFO} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${PSP_BUILD_TARGET}.prx ${PSP_EBOOT_PSAR}', always=True) +# else: +# if bld.env.PSP_BUILD_EBOOT: +# bld(rule='${STRIP} -o ${PSP_BUILD_TARGET}.elf ${PSP_BUILD_TARGET}_strip.elf', always=True) +# bld(rule='${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${PSP_EBOOT_SFO}', always=True) +# bld(rule='${PACK_PBP} ${PSP_EBOOT} ${PSP_EBOOT_SFO} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${PSP_BUILD_TARGET}_strip.elf ${PSP_EBOOT_PSAR}', always=True) +# bld(rule='rm -f ${PSP_BUILD_TARGET}_strip.elf', always=True) + def post_compiler_cxx_configure(conf): conf.msg('Target OS', conf.env.DEST_OS) conf.msg('Target CPU', conf.env.DEST_CPU) diff --git a/wscript b/wscript index 259f6baf..575edb56 100644 --- a/wscript +++ b/wscript @@ -49,11 +49,12 @@ SUBDIRS = [ Subproject('public', dedicated=False, mandatory = True), Subproject('game_launch', singlebin=True), Subproject('ref_gl',), + Subproject('ref_gu',), Subproject('ref_soft'), Subproject('mainui'), Subproject('vgui_support'), - Subproject('stub/server', dedicated=False), - Subproject('stub/client'), + Subproject('stubserver/server', dedicated=False), + Subproject('stubserver/client'), Subproject('dllemu'), Subproject('engine', dedicated=False), ] @@ -92,7 +93,10 @@ def options(opt): help = 'enable low memory mode (only for devices have <128 ram)') grp.add_option('--enable-magx', action = 'store_true', dest = 'MAGX', default = False, - help = 'enable targetting for MotoMAGX phones [default: %default]') + help = 'enable targeting for MotoMAGX phones [default: %default]') + + grp.add_option('--enable-profiling', action = 'store_true', dest = 'PROFILING', default = False, + help = 'enable building with GNU profiling tools') grp.add_option('--ignore-projects', action = 'store', dest = 'IGNORE_PROJECTS', default = None, help = 'disable selected projects from build [default: %default]') @@ -116,6 +120,7 @@ def configure(conf): enforce_pic = True # modern defaults valid_build_types = ['fastnative', 'fast', 'release', 'debug', 'nooptimize', 'sanitize', 'none'] conf.load('fwgslib reconfigure') + if conf.options.IGNORE_PROJECTS: conf.env.IGNORE_PROJECTS = conf.options.IGNORE_PROJECTS.split(',') @@ -139,7 +144,7 @@ def configure(conf): conf.env.MSVC_TARGETS = ['x86'] # explicitly request x86 target for MSVC if sys.platform == 'win32': conf.load('msvc msvc_pdb msdev msvs') - conf.load('xshlib subproject xcompile compiler_c compiler_cxx gitversion clang_compilation_database strip_on_install waf_unit_test') + conf.load('xshlib subproject xcompile gas compiler_c compiler_cxx gitversion clang_compilation_database strip_on_install waf_unit_test') try: conf.env.CC_VERSION[0] @@ -153,6 +158,58 @@ def configure(conf): conf.options.GLWES = True conf.options.GL = False + if conf.env.DEST_OS == 'psp': + conf.options.NO_VGUI= True # skip vgui + conf.options.SINGLE_BINARY = True + conf.options.NO_ASYNC_RESOLVE = True + conf.options.LOW_MEMORY = 2 + conf.options.GL = True + conf.options.GL_STATIC = True + conf.options.STATIC = True + enforce_pic = False + + # rewrite compile patterns + conf.env.cprogram_PATTERN = conf.env.PSP_PATTERN_program + conf.env.cxxprogram_PATTERN = conf.env.PSP_PATTERN_program + conf.env.cshlib_PATTERN = conf.env.PSP_PATTERN_shlib + conf.env.cxxshlib_PATTERN = conf.env.PSP_PATTERN_shlib + conf.env.cstlib_PATTERN = conf.env.PSP_PATTERN_stlib + conf.env.cxxstlib_PATTERN = conf.env.PSP_PATTERN_stlib + + # set EBOOT.PBP generation parameters + conf.env.PSP_EBOOT_TITLE = 'Xash3D' + conf.env.PSP_EBOOT_SFO = 'PARAM.SFO' + conf.env.PSP_EBOOT_ICON = 'NULL' + conf.env.PSP_EBOOT_ICON1 = 'NULL' + conf.env.PSP_EBOOT_UNKPNG = 'NULL' + conf.env.PSP_EBOOT_PIC1 = 'NULL' + conf.env.PSP_EBOOT_SND0 = 'NULL' + conf.env.PSP_EBOOT_PSAR = 'NULL' + conf.env.PSP_EBOOT = 'EBOOT.PBP' + + # set target parameters + conf.env.PSP_BUILD_TARGET = 'xash' + conf.env.PSP_BUILD_EBOOT = True + + if conf.options.SINGLE_BINARY: + conf.options.IGNORE_PROJECTS = 'ref_gl,stub/server,stub/client' + conf.options.STATIC_LINKING = 'menu' + if conf.env.PSP_RENDER_TYPE == 'SW': + conf.options.STATIC_LINKING += ',ref_soft' + else: + conf.options.IGNORE_PROJECTS += ',ref_soft' + + if conf.env.PSP_RENDER_TYPE == 'HW': + conf.options.STATIC_LINKING += ',ref_gu' + else: + conf.options.IGNORE_PROJECTS += ',ref_gu' + + if conf.env.PSP_RENDER_TYPE == 'ALL': + conf.options.STATIC_LINKING += 'ref_soft,ref_gu' + + conf.env.IGNORE_PROJECTS = conf.options.IGNORE_PROJECTS.split(',') + conf.load('xshlib') # for set linking + if conf.env.STATIC_LINKING: enforce_pic = False # PIC may break static linking @@ -244,7 +301,7 @@ def configure(conf): }, 'debug': { 'msvc': ['/O1'], - 'gcc': ['-Og'], + 'gcc': ['-Og', '-fno-omit-frame-pointer', '-funwind-tables'], 'owcc': ['-O0', '-fno-omit-frame-pointer', '-funwind-tables', '-fno-omit-leaf-frame-pointer'], 'default': ['-O1'] }, @@ -268,12 +325,12 @@ def configure(conf): '-Werror=vla', '-Werror=tautological-compare', '-Werror=duplicated-cond', - '-Werror=duplicated-branches', # BEWARE: buggy +# '-Werror=duplicated-branches', # BEWARE: buggy '-Werror=bool-compare', '-Werror=bool-operation', - '-Werror=cast-align', +# '-Werror=cast-align', '-Werror=cast-align=strict', # =strict is for GCC >=8 - '-Werror=packed', +# '-Werror=packed', '-Werror=packed-not-aligned', '-Wuninitialized', # older GCC versions have -Wmaybe-uninitialized enabled by this switch, which is not accurate # so just warn, not error @@ -288,10 +345,10 @@ def configure(conf): '-Werror=implicit-function-declaration', '-Werror=int-conversion', '-Werror=implicit-int', - '-Werror=strict-prototypes', +# '-Werror=strict-prototypes', '-Werror=old-style-declaration', '-Werror=old-style-definition', - '-Werror=declaration-after-statement', +# '-Werror=declaration-after-statement', '-Werror=enum-conversion', '-fnonconst-initializers' # owcc ] @@ -299,6 +356,13 @@ def configure(conf): linkflags = conf.get_flags_by_type(linker_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0]) cflags = conf.get_flags_by_type(compiler_c_cxx_flags, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0]) + # Profiling +# if conf.options.PROFILING: +# prof_cflags = { +# 'gcc': ['-pg'] +# } +# cflags += conf.get_flags_by_compiler(prof_cflags, conf.env.COMPILER_CC) + # Here we don't differentiate C or C++ flags if conf.options.LTO: lto_cflags = { @@ -323,7 +387,7 @@ def configure(conf): } cflags += conf.get_flags_by_compiler(polly_cflags, conf.env.COMPILER_CC) - + # And here C++ flags starts to be treated separately cxxflags = list(cflags) if conf.env.COMPILER_CC != 'msvc': @@ -359,7 +423,8 @@ def configure(conf): else: # include portable stdint by Paul Hsich conf.define('STDINT_H', 'pstdint.h') - + + conf.env.PROFILING = conf.options.PROFILING conf.env.DEDICATED = conf.options.DEDICATED conf.env.SINGLE_BINARY = conf.options.SINGLE_BINARY or conf.env.DEDICATED if conf.env.DEST_OS == 'dos': @@ -407,6 +472,9 @@ def configure(conf): if conf.options.LOW_MEMORY: conf.define('XASH_LOW_MEMORY', conf.options.LOW_MEMORY) + if conf.options.PROFILING: + conf.define('XASH_PROFILING', 1) + for i in SUBDIRS: if not i.is_enabled(conf): continue @@ -420,3 +488,4 @@ def build(bld): continue bld.add_subproject(i.name) + bld.load('xcompile') From cd37d866c28336df586aabc51f9cdaab4b69d7c9 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sun, 3 Apr 2022 18:00:12 +0300 Subject: [PATCH 02/84] code cleanup --- common/port.h | 8 +-- engine/client/cl_game.c | 6 +- engine/client/cl_render.c | 2 +- engine/client/client.h | 4 +- engine/client/ref_common.c | 4 +- engine/client/s_vox.c | 2 +- engine/common/common.h | 2 +- engine/common/imagelib/img_utils.c | 10 ++-- engine/common/launcher.c | 11 ++-- engine/common/net_buffer.c | 4 +- engine/common/net_buffer.h | 2 +- engine/common/net_encode.c | 94 +++++++++++++++--------------- engine/common/net_ws.c | 2 +- engine/common/system.h | 2 +- engine/platform/psp/dll_psp.c | 2 +- engine/platform/psp/in_psp.c | 12 ++-- engine/platform/psp/lib_psp.c | 2 +- engine/platform/psp/lib_psp.h | 0 engine/platform/psp/s_psp.c | 9 +-- engine/platform/psp/sys_psp.c | 14 ++--- engine/server/server.h | 10 ++-- engine/server/sv_game.c | 6 +- engine/server/sv_init.c | 2 +- engine/server/sv_phys.c | 12 ++-- engine/server/sv_save.c | 2 +- engine/sprite.h | 4 +- public/build.h | 2 - public/xash3d_mathlib.c | 2 +- ref_soft/r_decals.c | 49 +++++++++++++++- scripts/waifulib/xcompile.py | 12 ++-- wscript | 7 +++ 31 files changed, 172 insertions(+), 128 deletions(-) delete mode 100644 engine/platform/psp/lib_psp.h diff --git a/common/port.h b/common/port.h index 233335b9..0756fe7e 100644 --- a/common/port.h +++ b/common/port.h @@ -80,7 +80,6 @@ GNU General Public License for more details. #if XASH_PSP #include #include - #include "../engine/platform/psp/dll_psp.h" #define PATH_MAX 1024 #define PATH_SPLITTER "/" #define O_BINARY 0 @@ -90,9 +89,6 @@ GNU General Public License for more details. #define LoadLibrary( x ) ( 0 ) #define GetProcAddress( x, y ) ( 0 ) #define FreeLibrary( x ) ( 0 ) -// #define LoadLibrary( x ) dlopen( x, RTLD_NOW ) -// #define GetProcAddress( x, y ) dlsym( x, y ) -// #define FreeLibrary( x ) dlclose( x ) #endif //#define MAKEWORD( a, b ) ((short int)(((unsigned char)(a))|(((short int)((unsigned char)(b)))<<8))) @@ -164,6 +160,10 @@ GNU General Public License for more details. #define XASH_LOW_MEMORY 0 #endif +#ifndef XASH_EXT_OPT +#define XASH_EXT_OPT 0 +#endif + #include #include #include diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index baa4b749..c8397b7a 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -103,7 +103,7 @@ CL_GetEntityByIndex Render callback for studio models ==================== */ -#if XASH_OPT +#if XASH_EXT_OPT == 2 cl_entity_t *pfnCL_GetEntityByIndex( int index ) { return CL_GetEntityByIndex( index ); @@ -130,7 +130,7 @@ CL_ModelHandle get model handle by index ================ */ -#if XASH_OPT +#if XASH_EXT_OPT == 2 model_t *pfnCL_ModelHandle( int modelindex ) { return CL_ModelHandle( modelindex ); @@ -3819,7 +3819,7 @@ static cl_enginefunc_t gEngfuncs = pfnIsNoClipping, CL_GetLocalPlayer, CL_GetViewModel, -#if XASH_OPT +#if XASH_EXT_OPT == 2 pfnCL_GetEntityByIndex, #else CL_GetEntityByIndex, diff --git a/engine/client/cl_render.c b/engine/client/cl_render.c index 8c645f46..1677b90c 100644 --- a/engine/client/cl_render.c +++ b/engine/client/cl_render.c @@ -271,7 +271,7 @@ static render_api_t gRenderAPI = pfnFileBufferCRC32, COM_CompareFileTime, Host_Error, -#if XASH_OPT +#if XASH_EXT_OPT == 2 (void*)pfnCL_ModelHandle, #else (void*)CL_ModelHandle, diff --git a/engine/client/client.h b/engine/client/client.h index 9de00b29..36d3d1bf 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -709,7 +709,7 @@ dlight_t *CL_GetEntityLight( int number ); // // cl_cmds.c // -#ifdef XASH_PSP +#if XASH_PSP void CL_Quit_f( void ); #else void CL_Quit_f( void ) NORETURN; @@ -825,7 +825,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize ); client_textmessage_t *CL_TextMessageGet( const char *pName ); int pfnDecalIndexFromName( const char *szDecalName ); int pfnIndexFromTrace( struct pmtrace_s *pTrace ); -#if XASH_OPT +#if XASH_EXT_OPT == 2 #define CL_ModelHandle( modelindex ) ( ( ( modelindex ) < 0 || ( modelindex ) >= MAX_MODELS ) ? NULL : cl.models[( modelindex )] ) model_t *pfnCL_ModelHandle( int modelindex ); #else diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index 93fd07ec..be32ca7c 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -268,7 +268,7 @@ static ref_api_t gEngfuncs = CL_GetLocalPlayer, CL_GetViewModel, -#if XASH_OPT +#if XASH_EXT_OPT == 2 pfnCL_GetEntityByIndex, #else CL_GetEntityByIndex, @@ -299,7 +299,7 @@ static ref_api_t gEngfuncs = Mod_ForName, pfnMod_Extradata, -#if XASH_OPT +#if XASH_EXT_OPT == 2 pfnCL_ModelHandle, #else CL_ModelHandle, diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 745b7cb0..1554a140 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -466,7 +466,7 @@ void VOX_LoadSound( channel_t *pchan, const char *pszin ) // lookup actual string in g_Sentences, // set pointer to string data -#ifdef XASH_PSP +#if XASH_PSP if( pszin[0] == '#' ) psz = VOX_LookupString( pszin + 1, NULL ); else diff --git a/engine/common/common.h b/engine/common/common.h index 7a02284a..69c081bc 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -877,7 +877,7 @@ int R_CreateDecalList( struct decallist_s *pList ); void R_ClearAllDecals( void ); void CL_ClearStaticEntities( void ); qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position ); -#if XASH_OPT +#if XASH_EXT_OPT == 2 #define CL_GetEntityByIndex( index ) ( ( !clgame.entities ) ? NULL : ( ( ( index ) < 0 || ( index ) >= clgame.maxEntities ) ? NULL : ( ( ( index ) == 0 ) ? clgame.entities : ( clgame.entities + ( index ) ) ) ) ) struct cl_entity_s *pfnCL_GetEntityByIndex( int index ); #else diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 08532b3d..c834c386 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -101,19 +101,19 @@ static const loadpixformat_t load_null[] = { { NULL, NULL, NULL, IL_HINT_NO } }; -#if XASH_PSP +#if XASH_EXT_OPT static const loadpixformat_t load_game[] = { { "%s%s.%s", "mip", Image_LoadMIP, IL_HINT_NO }, // hl textures from wad or buffer -//{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models -{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus -{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images -//{ "%s%s.%s", "png", Image_LoadPNG, IL_HINT_NO }, // NightFire 007 menus { "%s%s.%s", "mdl", Image_LoadMDL, IL_HINT_HL }, // hl studio model skins { "%s%s.%s", "spr", Image_LoadSPR, IL_HINT_HL }, // hl sprite frames { "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc) { "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc) { "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette +{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models +{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus +{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images +{ "%s%s.%s", "png", Image_LoadPNG, IL_HINT_NO }, // NightFire 007 menus { NULL, NULL, NULL, IL_HINT_NO } }; #else diff --git a/engine/common/launcher.c b/engine/common/launcher.c index b37968eb..ef2179ce 100644 --- a/engine/common/launcher.c +++ b/engine/common/launcher.c @@ -108,13 +108,14 @@ int main( int argc, char** argv ) #endif #endif -#if XASH_PSP g_iArgc = argc; - g_pszArgv = argv; + g_pszArgv = argv; + +#if XASH_PSP if(argc <= 1) { g_fArgc = 0; - g_fArgv[g_fArgc++] = argv[0]; // for get root directory path + g_fArgv[g_fArgc++] = argv[0]; // cwd path Platform_ReadCmd( "start.cmd", &g_fArgc, g_fArgv ); if(g_fArgc > 1) { @@ -122,10 +123,8 @@ int main( int argc, char** argv ) g_pszArgv = g_fArgv; } } -#else - g_iArgc = argc; - g_pszArgv = argv; #endif + #if XASH_IOS { void IOS_LaunchDialog( void ); diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index 0fa02ed1..653e3a7a 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -94,7 +94,7 @@ void MSG_Clear( sizebuf_t *sb ) sb->bOverflow = false; } -#if !XASH_PSP +#if XASH_EXT_OPT != 2 static qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) { if( sb->iCurBit + nBits > sb->nDataBits ) @@ -136,7 +136,7 @@ void MSG_SeekToByte( sizebuf_t *sb, int bytePos ) { sb->iCurBit = bytePos << 3; } -#if !XASH_PSP +#if XASH_EXT_OPT != 2 void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) { if( !MSG_Overflow( sb, 1 )) diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 848c1d78..0ad16130 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -70,7 +70,7 @@ void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, in void MSG_Clear( sizebuf_t *sb ); // Bit-write functions -#if XASH_PSP +#if XASH_EXT_OPT == 2 _inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) { if( sb->iCurBit + nBits > sb->nDataBits ) diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 5f73818f..af7274a4 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -295,15 +295,18 @@ static const delta_field_t ent_fields[] = { NULL }, }; -#if XASH_OPT /* Direct access */ -#define D_event_t 0 -#define D_movevars_t 1 -#define D_usercmd_t 2 -#define D_clientdata_t 3 -#define D_weapon_data_t 4 -#define D_entity_state_t 5 -#define D_entity_state_player_t 6 -#define D_custom_entity_state_t 7 +#if XASH_EXT_OPT /* Direct access */ +enum +{ + E_EVENT = 0, + E_MOVEVARS, + E_USERCMD, + E_CLIENTDATA, + E_WEAPON_DATA, + E_ENTITY_STATE, + E_ENTITY_STATE_PLAYER, + E_CUSTOM_ENTITY_STATE +}; #endif static delta_info_t dt_info[] = @@ -810,8 +813,8 @@ void Delta_Init( void ) Delta_InitFields (); // initialize fields delta_init = true; -#if XASH_OPT - dt = &dt_info[D_movevars_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_MOVEVARS]; #else dt = Delta_FindStruct( "movevars_t" ); #endif @@ -907,7 +910,7 @@ Delta_ClampIntegerField prevent data to out of range ===================== */ -#if XASH_OPT +#if XASH_EXT_OPT == 2 _inline int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits ) #else int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits ) @@ -1081,13 +1084,12 @@ int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean playe if( from == NULL ) return 0; return countBits; } -#if XASH_OPT - dt = &dt_info[D_weapon_data_t]; +#if XASH_EXT_OPT if( FBitSet( to->entityType, ENTITY_BEAM )) - dt = &dt_info[D_custom_entity_state_t]; + dt = &dt_info[E_CUSTOM_ENTITY_STATE]; else if( player ) - dt = &dt_info[D_entity_state_player_t]; - else dt = &dt_info[D_entity_state_t]; + dt = &dt_info[E_ENTITY_STATE_PLAYER]; + else dt = &dt_info[E_ENTITY_STATE]; #else if( FBitSet( to->entityType, ENTITY_BEAM )) dt = Delta_FindStruct( "custom_entity_state_t" ); @@ -1132,7 +1134,7 @@ write fields by offsets assume from and to is valid ===================== */ -#if XASH_OPT +#if XASH_EXT_OPT == 2 _inline qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) #else qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) @@ -1359,8 +1361,8 @@ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to ) delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_usercmd_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_USERCMD]; #else dt = Delta_FindStruct( "usercmd_t" ); #endif @@ -1389,8 +1391,8 @@ void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to ) delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_usercmd_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_USERCMD]; #else dt = Delta_FindStruct( "usercmd_t" ); #endif @@ -1427,8 +1429,8 @@ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_event_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_EVENT]; #else dt = Delta_FindStruct( "event_t" ); #endif @@ -1457,8 +1459,8 @@ void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_event_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_EVENT]; #else dt = Delta_FindStruct( "event_t" ); #endif @@ -1489,8 +1491,8 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t delta_info_t *dt; int i, startBit; int numChanges = 0; -#if XASH_OPT - dt = &dt_info[D_movevars_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_MOVEVARS]; #else dt = Delta_FindStruct( "movevars_t" ); #endif @@ -1527,8 +1529,8 @@ void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to ) delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_movevars_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_MOVEVARS]; #else dt = Delta_FindStruct( "movevars_t" ); #endif @@ -1567,8 +1569,8 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, delta_info_t *dt; int i, startBit; int numChanges = 0; -#if XASH_OPT - dt = &dt_info[D_clientdata_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_CLIENTDATA]; #else dt = Delta_FindStruct( "clientdata_t" ); #endif @@ -1610,8 +1612,8 @@ void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, f delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_clientdata_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_CLIENTDATA]; #else dt = Delta_FindStruct( "clientdata_t" ); #endif @@ -1654,8 +1656,8 @@ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to delta_info_t *dt; int i, startBit; int numChanges = 0; -#if XASH_OPT - dt = &dt_info[D_weapon_data_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_WEAPON_DATA]; #else dt = Delta_FindStruct( "weapon_data_t" ); #endif @@ -1695,8 +1697,8 @@ void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, delta_t *pField; delta_info_t *dt; int i; -#if XASH_OPT - dt = &dt_info[D_weapon_data_t]; +#if XASH_EXT_OPT + dt = &dt_info[E_WEAPON_DATA]; #else dt = Delta_FindStruct( "weapon_data_t" ); #endif @@ -1781,18 +1783,18 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t * numChanges++; } else MSG_WriteOneBit( msg, 0 ); -#if XASH_OPT +#if XASH_EXT_OPT if( FBitSet( to->entityType, ENTITY_BEAM )) { - dt = &dt_info[D_custom_entity_state_t]; + dt = &dt_info[E_CUSTOM_ENTITY_STATE]; } else if( delta_type == DELTA_PLAYER ) { - dt = &dt_info[D_entity_state_player_t]; + dt = &dt_info[E_ENTITY_STATE_PLAYER]; } else { - dt = &dt_info[D_entity_state_t]; + dt = &dt_info[E_ENTITY_STATE]; } #else if( FBitSet( to->entityType, ENTITY_BEAM )) @@ -1913,18 +1915,18 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state to->entityType = MSG_ReadUBitLong( msg, 2 ); to->number = number; -#if XASH_OPT +#if XASH_EXT_OPT if( cls.legacymode ? ( to->entityType == ENTITY_BEAM ) : FBitSet( to->entityType, ENTITY_BEAM )) { - dt = &dt_info[D_custom_entity_state_t]; + dt = &dt_info[E_CUSTOM_ENTITY_STATE]; } else if( delta_type == DELTA_PLAYER ) { - dt = &dt_info[D_entity_state_player_t]; + dt = &dt_info[E_ENTITY_STATE_PLAYER]; } else { - dt = &dt_info[D_entity_state_t]; + dt = &dt_info[E_ENTITY_STATE]; } #else if( cls.legacymode ? ( to->entityType == ENTITY_BEAM ) : FBitSet( to->entityType, ENTITY_BEAM )) diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c index 719821cb..ec33af08 100644 --- a/engine/common/net_ws.c +++ b/engine/common/net_ws.c @@ -93,7 +93,7 @@ static int ioctl_stub( int d, unsigned long r, ... ) #define SOCKET int typedef int WSAsize_t; #else -#include //GSA +#include // @Crow-bar #include "platform/stub/net_stub.h" #endif diff --git a/engine/common/system.h b/engine/common/system.h index 48b8c198..8730e918 100644 --- a/engine/common/system.h +++ b/engine/common/system.h @@ -68,7 +68,7 @@ void Sys_Print( const char *pMsg ); void Sys_PrintLog( const char *pMsg ); void Sys_InitLog( void ); void Sys_CloseLog( void ); -#ifdef XASH_PSP +#if XASH_PSP void Sys_Quit( void ); #else void Sys_Quit( void ) NORETURN; diff --git a/engine/platform/psp/dll_psp.c b/engine/platform/psp/dll_psp.c index 7a78b279..3e82252a 100644 --- a/engine/platform/psp/dll_psp.c +++ b/engine/platform/psp/dll_psp.c @@ -256,4 +256,4 @@ for_end: return 1; } return 0; -} \ No newline at end of file +} diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c index befa200e..14fdaf42 100644 --- a/engine/platform/psp/in_psp.c +++ b/engine/platform/psp/in_psp.c @@ -22,8 +22,8 @@ GNU General Public License for more details. #define PSP_MAX_KEYS 12 -extern convar_t *psp_deadzone_min; -extern convar_t *psp_deadzone_max; +convar_t *psp_deadzone_min; +convar_t *psp_deadzone_max; static struct psp_keymap_s { @@ -108,7 +108,7 @@ void Platform_RunEvents( void ) for( i = 0; i < PSP_MAX_KEYS; i++ ) { - if( ( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) + if( ( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) Key_Event( psp_keymap[i].dstkey, buf.Buttons & psp_keymap[i].srckey ); } last_buttons = buf.Buttons; @@ -156,6 +156,10 @@ void Platform_EnableTextInput( qboolean enable ) int Platform_JoyInit( int numjoy ) { int i; + + // set up cvars + psp_deadzone_min = Cvar_Get( "psp_deadzone_min", "20", FCVAR_ARCHIVE, "Joy deadzone min (0 - 127)" ); + psp_deadzone_max = Cvar_Get( "psp_deadzone_max", "0", FCVAR_ARCHIVE, "Joy deadzone max (0 - 127)" ); // set up the controller. sceCtrlSetSamplingCycle( 0 ); @@ -179,4 +183,4 @@ void Platform_PreCreateMove( void ) { } -#endif /* XASH_INPUT */ \ No newline at end of file +#endif /* XASH_INPUT */ diff --git a/engine/platform/psp/lib_psp.c b/engine/platform/psp/lib_psp.c index 9d343f8d..6274ecfe 100644 --- a/engine/platform/psp/lib_psp.c +++ b/engine/platform/psp/lib_psp.c @@ -20,7 +20,7 @@ GNU General Public License for more details. #include "library.h" #include "filesystem.h" #include "server.h" -#include "platform/psp/lib_psp.h" +#include "platform/psp/dll_psp.h" #ifdef XASH_NO_LIBDL #ifndef XASH_DLL_LOADER diff --git a/engine/platform/psp/lib_psp.h b/engine/platform/psp/lib_psp.h deleted file mode 100644 index e69de29b..00000000 diff --git a/engine/platform/psp/s_psp.c b/engine/platform/psp/s_psp.c index eaf3f82f..7e29f858 100644 --- a/engine/platform/psp/s_psp.c +++ b/engine/platform/psp/s_psp.c @@ -13,9 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ - -#ifndef XASH_DEDICATED -#include "common.h" +#include "platform/platform.h" #if XASH_SOUND == SOUND_PSP #include @@ -47,8 +45,6 @@ so it can unlock and free the data block after it has been played. ======================================================================= */ -dma_t dma; - void S_Activate( qboolean active ) { @@ -248,5 +244,4 @@ void SNDDMA_Shutdown( void ) dma.initialized = false; } -#endif -#endif +#endif // XASH_SOUND == SOUND_PSP diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index 8c835496..561fb739 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -29,9 +29,6 @@ PSP_MAIN_THREAD_ATTR( PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_VFPU ); PSP_MAIN_THREAD_STACK_SIZE_KB( 512 ); PSP_HEAP_SIZE_KB( -3 * 1024 ); /* 3 MB for prx modules */ -convar_t *psp_deadzone_min; -convar_t *psp_deadzone_max; - /* Exit callback */ static int exit_callback( int arg1, int arg2, void *common ) { @@ -218,7 +215,7 @@ void Platform_ReadCmd( const char *fname, int *argc, char **argv ) else printf( "CMD FILE(%s) Read error!\n", fname ); free( cmd_buff ); - sceIoClose(cmd_fd); + sceIoClose( cmd_fd ); } } @@ -264,13 +261,14 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) void Platform_Init( void ) { + // disable fpu exceptions (division by zero and etc...) pspSdkDisableFPUExceptions(); + // exit callback thread SetupCallbacks(); - scePowerSetClockFrequency( 333, 333, 166 ); - psp_deadzone_min = Cvar_Get( "psp_deadzone_min", "20", FCVAR_ARCHIVE, "Joy deadzone min (0 - 127)" ); - psp_deadzone_max = Cvar_Get( "psp_deadzone_max", "0", FCVAR_ARCHIVE, "Joy deadzone max (0 - 127)" ); + // set max cpu/gpu frequency + scePowerSetClockFrequency( 333, 333, 166 ); } void Platform_Shutdown( void ) @@ -278,4 +276,4 @@ void Platform_Shutdown( void ) #if XASH_PROFILING gprof_cleanup(); #endif -} \ No newline at end of file +} diff --git a/engine/server/server.h b/engine/server/server.h index 7098b5b4..20ff633f 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -54,13 +54,13 @@ extern int SV_UPDATE_BACKUP; #define GROUP_OP_AND 0 #define GROUP_OP_NAND 1 -#if defined( NDEBUG ) || XASH_OPT +#if defined( NDEBUG ) #define SV_IsValidEdict( e ) ( e && !e->free ) #else #define SV_IsValidEdict( e ) SV_CheckEdict( e, __FILE__, __LINE__ ) #endif #define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - svgame.edicts)) -#if XASH_OPT +#if XASH_EXT_OPT == 2 #define EDICT_NUM( num ) ( ( ( ( num ) >= 0 ) && ( ( num ) < GI->max_edicts) ) ? svgame.edicts + ( num ) : NULL ) #else #define EDICT_NUM( num ) SV_EdictNum( num ) @@ -480,7 +480,7 @@ void Master_Packet( void ); // void SV_ActivateServer( int runPhysics ); qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background ); -#if XASH_OPT +#if XASH_EXT_OPT == 2 #define SV_ModelHandle( modelindex ) ( ( modelindex < 0 || modelindex >= MAX_MODELS ) ? NULL : sv.models[( modelindex )] ) model_t *pfnSV_ModelHandle( int modelindex ); #else @@ -499,7 +499,7 @@ qboolean SV_RunThink( edict_t *ent ); qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time ); qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker ); void SV_Impact( edict_t *e1, edict_t *e2, trace_t *trace ); -#if XASH_OPT +#if XASH_EXT_OPT == 2 // filter movetypes to collide with #define SV_CanPushed( ent ) ( ( ent )->v.movetype == MOVETYPE_NONE || \ ( ent )->v.movetype == MOVETYPE_PUSH || \ @@ -652,7 +652,7 @@ void SV_RestartAmbientSounds( void ); void SV_RestartDecals( void ); void SV_RestartStaticEnts( void ); int pfnGetCurrentPlayer( void ); -#if !XASH_OPT +#if XASH_EXT_OPT != 2 edict_t *SV_EdictNum( int n ); #endif char *SV_Localinfo( void ); diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 0a72ed88..6fee369b 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -35,14 +35,14 @@ static vec3_t viewPoint[MAX_CLIENTS]; // exports typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev ); typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals ); -#if !XASH_OPT +#if XASH_EXT_OPT != 2 edict_t *SV_EdictNum( int n ) { if(( n >= 0 ) && ( n < GI->max_edicts )) return svgame.edicts + n; return NULL; } - +#endif #ifndef NDEBUG qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line ) { @@ -59,7 +59,7 @@ qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line ) return false; } #endif -#endif + /* ============= EntvarsDescription diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 497aaa2f..7d7f410e 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -266,7 +266,7 @@ SV_ModelHandle get model by handle ================ */ -#if XASH_OPT +#if XASH_EXT_OPT > 1 model_t *pfnSV_ModelHandle( int modelindex ) { return SV_ModelHandle( modelindex ); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 602b0458..a57ef84e 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -842,7 +842,7 @@ SV_CanPushed filter entities for push ============ */ -#if XASH_OPT +#if XASH_EXT_OPT > 1 qboolean pfnSV_CanPushed( edict_t *ent ) { return SV_CanPushed( ent ); @@ -947,7 +947,7 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) // filter movetypes to collide with if( !SV_CanPushed( check )) continue; -#if !XASH_OPT +#if !XASH_EXT_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; @@ -968,7 +968,7 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) if( !SV_TestEntityPosition( check, NULL )) continue; } -#if XASH_OPT +#if XASH_EXT_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; @@ -1072,7 +1072,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) // filter movetypes to collide with if( !SV_CanPushed( check )) continue; -#if !XASH_OPT +#if !XASH_EXT_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; @@ -1093,7 +1093,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) if( !SV_TestEntityPosition( check, NULL )) continue; } -#if XASH_OPT +#if XASH_EXT_OPT pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; @@ -2039,7 +2039,7 @@ static server_physics_api_t gPhysicsAPI = SV_LinkEdict, SV_GetServerTime, SV_GetFrameTime, -#if XASH_OPT +#if XASH_EXT_OPT > 1 (void*)pfnSV_ModelHandle, #else (void*)SV_ModelHandle, diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index 6bfba80a..0a82412b 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -32,7 +32,7 @@ half-life implementation of saverestore system #define SAVEGAME_HEADER (('V'<<24)+('A'<<16)+('S'<<8)+'J') // little-endian "JSAV" #define SAVEGAME_VERSION 0x0071 // Version 0.71 GoldSrc compatible #define CLIENT_SAVEGAME_VERSION 0x0067 // Version 0.67 -#ifdef XASH_PSP +#if XASH_PSP #define SAVE_HEAPSIZE 0x200000 // reserve 2Mb for now #else #define SAVE_HEAPSIZE 0x400000 // reserve 4Mb for now diff --git a/engine/sprite.h b/engine/sprite.h index da0964e3..e49d3424 100644 --- a/engine/sprite.h +++ b/engine/sprite.h @@ -15,7 +15,7 @@ #ifndef SPRITE_H #define SPRITE_H -#ifdef __psp__ // GSA +#if XASH_PSP #pragma pack(push, 1) #endif @@ -128,7 +128,7 @@ typedef struct frametype_t type; } dframetype_t; -#ifdef __psp__ // GSA +#if XASH_PSP #pragma pack(pop) #endif #endif//SPRITE_H diff --git a/public/build.h b/public/build.h index 2b7ee030..6d016c8f 100644 --- a/public/build.h +++ b/public/build.h @@ -71,7 +71,6 @@ For more information, please refer to #undef XASH_WIN64 #undef XASH_X86 #undef XASH_PSP -#undef XASH_OPT //================================================================ // @@ -120,7 +119,6 @@ For more information, please refer to #elif defined __psp__ #define XASH_PSP 1 #define XASH_LITTLE_ENDIAN - #define XASH_OPT 1 #else #error "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug" #endif diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index 973bf692..e465f4a5 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -353,7 +353,7 @@ void SinCos( float radians, float *sine, float *cosine ) "lv.s S000, %2\n" // S000 = radians "vcst.s S001, VFPU_2_PI\n" // S001 = VFPU_2_PI = 2 / PI "vmul.s S000, S000, S001\n" // S000 = S000 * S001 - "vrot.p C002, S000, [S, C]\n" // S002 = sin( radians ), S003 = cos( radians ) + "vrot.p C002, S000, [s, c]\n" // S002 = sin( radians ), S003 = cos( radians ) "sv.s S002, %0\n" // sine = S002 "sv.s S003, %1\n" // cosine = S003 ".set pop\n" // restore assembler option diff --git a/ref_soft/r_decals.c b/ref_soft/r_decals.c index 436d9fbb..c69792fa 100644 --- a/ref_soft/r_decals.c +++ b/ref_soft/r_decals.c @@ -202,6 +202,19 @@ void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int textu // Build the initial list of vertices from the surface verts into the global array, 'verts'. void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t textureSpaceBasis[3], float *verts ) { +#if XASH_PSP + int i; + + if( !surf->polys ) + return; + for( i = 0; i < surf->polys->numverts; i++, verts += VERTEXSIZE ) + { + VectorCopy( surf->polys->verts[i].xyz, verts ); // copy model space coordinates + verts[3] = DotProduct( verts, textureSpaceBasis[0] ) - pDecal->dx + 0.5f; + verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - pDecal->dy + 0.5f; + verts[5] = verts[6] = 0.0f; + } +#else float *v; int i; @@ -214,6 +227,7 @@ void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t tex verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - pDecal->dy + 0.5f; verts[5] = verts[6] = 0.0f; } +#endif } // Figure out where the decal maps onto the surface. @@ -525,7 +539,26 @@ glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &lnumverts ); if( !lnumverts ) return NULL; // probably this never happens +#if XASH_PSP + // allocate glpoly + // REFTODO: com_studiocache pool! + poly = Mem_Calloc( r_temppool, sizeof( glpoly_t ) + ( lnumverts * 2 - 1 ) * sizeof( gu_vert_t )); + poly->next = pdecal->polys; + poly->flags = surf->flags; + pdecal->polys = poly; + poly->numverts = lnumverts; + for( i = 0; i < lnumverts; i++, v += VERTEXSIZE ) + { + poly->verts[i].uv[0] = v[3]; + poly->verts[i].uv[1] = v[4]; + VectorCopy( v, poly->verts[i].xyz ); + + poly->verts[i + lnumverts].uv[0] = v[5]; + poly->verts[i + lnumverts].uv[1] = v[6]; + VectorCopy( v, poly->verts[i + lnumverts].xyz ); + } +#else // allocate glpoly // REFTODO: com_studiocache pool! poly = Mem_Calloc( r_temppool, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float )); @@ -542,7 +575,7 @@ glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t poly->verts[i][5] = v[5]; poly->verts[i][6] = v[6]; } - +#endif return poly; } @@ -862,8 +895,18 @@ float * GAME_EXPORT R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int te { v = g_DecalClipVerts[0]; count = p->numverts; +#if XASH_PSP + // if we have mesh so skip clipping and just copy vertexes out (perf) + for( i = 0; i < count; i++, v += VERTEXSIZE ) + { + VectorCopy( p->verts[i].xyz, v ); + v[3] = p->verts[i].uv[0]; + v[4] = p->verts[i].uv[1]; + v[5] = p->verts[i + count].uv[0]; + v[6] = p->verts[i + count].uv[1]; + } +#else v2 = p->verts[0]; - // if we have mesh so skip clipping and just copy vertexes out (perf) for( i = 0; i < count; i++, v += VERTEXSIZE, v2 += VERTEXSIZE ) { @@ -873,7 +916,7 @@ float * GAME_EXPORT R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int te v[5] = v2[5]; v[6] = v2[6]; } - +#endif // restore pointer v = g_DecalClipVerts[0]; } diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 06a53c32..174c3f33 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -355,9 +355,8 @@ class PSP: def cflags(self, cxx = False): cflags = [] cflags += ['-I%s' % (os.path.join(self.pspsdk_path, 'include'))] -# cflags += ['-I%s' % (os.path.join(self.psptoolchain_path, 'include'))] cflags += ['-I.'] - cflags += ['-D_PSP_FW_VERSION=%s' % self.fw_version, '-G0'] + cflags += ['-DNDEBUG', '-D_PSP_FW_VERSION=%s' % self.fw_version, '-G0'] return cflags # they go before object list def linkflags(self): @@ -374,17 +373,16 @@ class PSP: ldflags += ['-specs=%s' % os.path.join(self.pspsdk_path, 'lib/prxspecs')] ldflags += ['-Wl,-q,-T%s' % os.path.join(self.pspsdk_path, 'lib/linkfile.prx')] ldflags += ['-L%s' % os.path.join(self.pspsdk_path, 'lib')] -# ldflags += ['-L%s' % os.path.join(self.psptoolchain_path, 'lib')] ldflags += ['-L.'] -# ldflags += ['-lgcc', '-no-canonical-prefixes'] return ldflags def stdlibs(self): stdlibs = [] stdlibs += ['-lpspdisplay', '-lpspgum_vfpu', '-lpspgu','-lpspge', '-lpspvfpu'] - stdlibs += ['-lpspaudiolib', '-lpspaudio'] - stdlibs += ['-lstdc++', '-lc', '-lm', '-lpspdebug', '-lpspctrl', '-lpspsdk', '-lpsprtc'] - stdlibs += ['-lpspnet', '-lpspnet_inet', '-lpspnet_apctl', '-lpspnet_resolver', '-lpsputility', '-lpspuser', '-lpspkernel', '-lpsppower'] + stdlibs += ['-lpspaudiolib', '-lpspaudio'] + stdlibs += ['-lstdc++', '-lc', '-lm'] + stdlibs += ['-lpspctrl', '-lpspdebug', '-lpsppower', '-lpspsdk', '-lpsprtc'] + stdlibs += ['-lpspuser', '-lpspkernel'] return stdlibs def options(opt): diff --git a/wscript b/wscript index 575edb56..d495dfd2 100644 --- a/wscript +++ b/wscript @@ -92,6 +92,9 @@ def options(opt): grp.add_option('--low-memory-mode', action = 'store', dest = 'LOW_MEMORY', default = 0, type = 'int', help = 'enable low memory mode (only for devices have <128 ram)') + grp.add_option('--ext-opt-mode', action = 'store', dest = 'EXT_OPT', default = 0, type = 'int', + help = 'enable extended optimization mode (only for weak devices)') + grp.add_option('--enable-magx', action = 'store_true', dest = 'MAGX', default = False, help = 'enable targeting for MotoMAGX phones [default: %default]') @@ -163,6 +166,7 @@ def configure(conf): conf.options.SINGLE_BINARY = True conf.options.NO_ASYNC_RESOLVE = True conf.options.LOW_MEMORY = 2 + conf.options.EXT_OPT = 2 conf.options.GL = True conf.options.GL_STATIC = True conf.options.STATIC = True @@ -472,6 +476,9 @@ def configure(conf): if conf.options.LOW_MEMORY: conf.define('XASH_LOW_MEMORY', conf.options.LOW_MEMORY) + if conf.options.EXT_OPT: + conf.define('XASH_EXT_OPT', conf.options.EXT_OPT) + if conf.options.PROFILING: conf.define('XASH_PROFILING', 1) From f5aaa58ff9dad77b314098c3029f3fe97f3f506d Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sun, 3 Apr 2022 18:10:58 +0300 Subject: [PATCH 03/84] readme: update --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 1def0067..d0786004 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,10 @@ Even if Xash3D FWGS does support targetting 64-bit, you can't load games without * Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs` +#### PSP +* Build pspsdk(GCC 9.3) from https://github.com/pspdev +* Clone this repository: `git clone --recursive https://github.com/Crow-bar/xash3d-fwgs`. + ### Building #### Windows(Visual Studio) 0) Open command line @@ -79,6 +83,12 @@ Even if Xash3D FWGS does support targetting 64-bit, you can't load games without 2) Compile: `./waf build` 3) Install(optional): `./waf install` +#### PSP +0) Navigate to `xash3d-fwgs` directory. +1) Examine which build options are available: `./waf --help` +2) Configure build: `./waf configure -T fast --psp=prx,660,HW --prefix=/path/to/any/output/directory` +3) Compile: `./waf build` + ## Running 0) Copy libraries and main executable somewhere, if you're skipped installation stage. 1) Copy game files to same directory From 190279c11710ce20a66bafd97b8e451f9081490b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 5 Apr 2022 22:35:13 +0300 Subject: [PATCH 04/84] system user name --- engine/common/system.c | 5 +++++ scripts/waifulib/xcompile.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/engine/common/system.c b/engine/common/system.c index d61acfa1..2268a8f0 100644 --- a/engine/common/system.c +++ b/engine/common/system.c @@ -34,6 +34,7 @@ GNU General Public License for more details. #if XASH_PSP #include +#include #endif #include "menu_int.h" // _UPDATE_PAGE macro @@ -136,6 +137,10 @@ char *Sys_GetCurrentUser( void ) if( pw ) return pw->pw_name; +#elif XASH_PSP + static char sys_nickname[128]; + if (sceUtilityGetSystemParamString(PSP_SYSTEMPARAM_ID_STRING_NICKNAME, sys_nickname, sizeof(sys_nickname)) == 0) + return sys_nickname; #endif return "Player"; } diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 174c3f33..6d3e1a5a 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -381,7 +381,7 @@ class PSP: stdlibs += ['-lpspdisplay', '-lpspgum_vfpu', '-lpspgu','-lpspge', '-lpspvfpu'] stdlibs += ['-lpspaudiolib', '-lpspaudio'] stdlibs += ['-lstdc++', '-lc', '-lm'] - stdlibs += ['-lpspctrl', '-lpspdebug', '-lpsppower', '-lpspsdk', '-lpsprtc'] + stdlibs += ['-lpspctrl', '-lpspdebug', '-lpsppower', '-lpsputility', '-lpspsdk', '-lpsprtc'] stdlibs += ['-lpspuser', '-lpspkernel'] return stdlibs From 32e175311ba29de3378cd997d2bf9f79b2cf2a8b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 7 Apr 2022 11:12:33 +0300 Subject: [PATCH 05/84] mainui update --- mainui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mainui b/mainui index d3c61e2e..37e4c7cb 160000 --- a/mainui +++ b/mainui @@ -1 +1 @@ -Subproject commit d3c61e2e1486bcac3af9e8d31a7c6b0186d1968a +Subproject commit 37e4c7cb817403f59edb9babbfdf3435ea2ba1ab From cab187618d7230f681e051d4d1d2616087668c01 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sat, 9 Apr 2022 17:26:42 +0300 Subject: [PATCH 06/84] FCVAR_GLCONFIG permission update --- engine/common/cvar.c | 5 ++++- ref_gu/gu_init.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 89c39ab6..cfcbd5ea 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -509,8 +509,11 @@ void Cvar_DirectSet( convar_t *var, const char *value ) // lookup for registration again if( var != Cvar_FindVar( var->name )) return; // how this possible? - +#if XASH_PSP + if( FBitSet( var->flags, FCVAR_READ_ONLY )) +#else if( FBitSet( var->flags, FCVAR_READ_ONLY|FCVAR_GLCONFIG )) +#endif { Con_Printf( "%s is read-only.\n", var->name ); return; diff --git a/ref_gu/gu_init.c b/ref_gu/gu_init.c index d30b8481..67198c7b 100644 --- a/ref_gu/gu_init.c +++ b/ref_gu/gu_init.c @@ -253,9 +253,9 @@ void GL_InitCommands( void ) gl_clear = gEngfuncs.pfnGetCvarPointer( "gl_clear", 0 ); gl_test = gEngfuncs.Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" ); gl_wireframe = gEngfuncs.Cvar_Get( "gl_wireframe", "0", FCVAR_GLCONFIG|FCVAR_SPONLY, "show wireframe overlay" ); - gl_stencilbits = gEngfuncs.Cvar_Get( "gl_stencilbits", "8", FCVAR_GLCONFIG, "pixelformat stencil bits (0 - auto)" ); + gl_stencilbits = gEngfuncs.Cvar_Get( "gl_stencilbits", "8", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "pixelformat stencil bits (0 - auto)" ); gl_subdivide_size = gEngfuncs.Cvar_Get( "gl_subdivide_size", "256.0", FCVAR_GLCONFIG, "the division value for the sky brushes" ); - gl_round_down = gEngfuncs.Cvar_Get( "gl_round_down", "2", FCVAR_GLCONFIG, "round texture sizes to nearest POT value" ); + gl_round_down = gEngfuncs.Cvar_Get( "gl_round_down", "2", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "round texture sizes to nearest POT value" ); // these cvar not used by engine but some mods requires this gl_depthoffset = gEngfuncs.Cvar_Get( "gl_depthoffset", "256.0", FCVAR_GLCONFIG, "depth offset for decals" ); From eea17a4e32eb72dcfea76a8f55f0e7f3d67ed473 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sat, 9 Apr 2022 17:28:09 +0300 Subject: [PATCH 07/84] Matrix_CreateFromEntity ASM BUG --- public/matrixlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/matrixlib.c b/public/matrixlib.c index ef4c1415..49f710f0 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -261,7 +261,7 @@ void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_t origin, float scale ) { -#if XASH_PSP /* performance not tested */ +#if 0/*XASH_PSP*/ /* performance not tested */ /* BUG */ if( angles[ROLL] ) { __asm__ ( @@ -803,7 +803,7 @@ void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale ) { -#if XASH_PSP /* performance not tested */ +#if 0/*XASH_PSP*/ /* performance not tested */ /* BUG */ if( angles[ROLL] ) { __asm__ ( From a308ce2f483d276f1cc6e9a03d0657c530fcf97d Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sat, 9 Apr 2022 17:34:42 +0300 Subject: [PATCH 08/84] ref_gu: texture loader update --- common/com_image.h | 1 + ref_gu/gu_image.c | 616 +++++++++++---------------------------------- ref_gu/gu_init.c | 2 +- ref_gu/gu_rsurf.c | 2 +- 4 files changed, 146 insertions(+), 475 deletions(-) diff --git a/common/com_image.h b/common/com_image.h index 33a0f812..e5182d38 100644 --- a/common/com_image.h +++ b/common/com_image.h @@ -10,6 +10,7 @@ NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == */ #define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE) #define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2) +#define ImageIND( type ) (type == PF_INDEXED_32 || type == PF_INDEXED_24) // @Crow_bar typedef enum { diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 46296beb..6f1d5975 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -25,7 +25,6 @@ static gl_texture_t gl_textures[MAX_TEXTURES]; static gl_texture_t* gl_texturesHashTable[TEXTURES_HASH_SIZE]; static uint gl_numTextures; - /* num_colors = PALETTE_BLOCKS x 16 (16-bit CLUT) num_colors = PALETTE_BLOCKS x 8 (32-bit CLUT) @@ -41,9 +40,10 @@ static uint gl_numTextures; #error Current PALETTE_FORMAT not supported! #endif - +#define TEXTURE_SIZE_MIN 8 #define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE )) + /* ================= R_GetTexture @@ -65,11 +65,8 @@ GL_Bind void GL_Bind( GLint tmu, GLenum texnum ) { gl_texture_t *texture; -#if 1 - int i; -#else - GLuint glTarget; -#endif + int i, offset, width, height; + // missed or invalid texture? if( texnum <= 0 || texnum >= MAX_TEXTURES ) { @@ -78,21 +75,21 @@ void GL_Bind( GLint tmu, GLenum texnum ) texnum = tr.defaultTexture; } - texture = &gl_textures[texnum]; -#if 1 if( glState.currentTexture == texnum ) return; + + texture = &gl_textures[texnum]; // Set palette - if(texture->format == GU_PSM_T8 && texture->dstPalette) + if( texture->format == GU_PSM_T8 && texture->dstPalette ) { sceGuClutMode( PALETTE_FORMAT, 0, 0xff, 0 ); sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ); } // Set texture parameters - sceGuTexMode( texture->format, texture->numMips, 0, FBitSet(texture->guFlags, GUFLAGTEXSWIZZLED) ? GU_TRUE : GU_FALSE ); - if(texture->numMips > 0) + sceGuTexMode( texture->format, texture->numMips - 1, 0, FBitSet( texture->guFlags, GUFLAGTEXSWIZZLED ) ? GU_TRUE : GU_FALSE ); + if( texture->numMips > 1 ) { sceGuTexFilter( GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR_MIPMAP_LINEAR ); sceGuTexLevelMode( gl_texture_lodfunc->value, gl_texture_lodbias->value ); @@ -104,44 +101,21 @@ void GL_Bind( GLint tmu, GLenum texnum ) } // Set base texture - sceGuTexImage(0, texture->width, texture->height, texture->width, texture->dstTexture); + sceGuTexImage( 0, texture->width, texture->height, texture->width, texture->dstTexture ); // Set mip textures - if( texture->numMips > 0 ) + if( texture->numMips > 1 ) { - int offset = texture->width * texture->height; - int width, height; - for ( i = 1; i <= texture->numMips; i++ ) + offset = texture->width * texture->height; + for ( i = 1; i < texture->numMips; i++ ) { - width = Q_max( 1, ( texture->width >> i ) ); - height = Q_max( 1, ( texture->height >> i ) ); + width = Q_max( TEXTURE_SIZE_MIN, ( texture->width >> i ) ); + height = Q_max( TEXTURE_SIZE_MIN, ( texture->height >> i ) ); sceGuTexImage( i, width, height, width, &texture->dstTexture[offset] ); offset += width * height; } } - glState.currentTexture = texnum; -#else - glTarget = texture->target; - - if( glTarget == GL_TEXTURE_2D_ARRAY_EXT ) - glTarget = GL_TEXTURE_2D; - - if( glState.currentTextureTargets[tmu] != glTarget ) - { - if( glState.currentTextureTargets[tmu] != GL_NONE ) - pglDisable( glState.currentTextureTargets[tmu] ); - glState.currentTextureTargets[tmu] = glTarget; - pglEnable( glState.currentTextureTargets[tmu] ); - } - - if( glState.currentTextures[tmu] == texture->texnum ) - return; - - pglBindTexture( texture->target, texture->texnum ); - - glState.currentTextures[tmu] = texture->texnum; -#endif } /* @@ -372,18 +346,6 @@ void R_SetTextureParameters( void ) #endif } -/* -================ -GL_CalcTextureSamples -================ -*/ -static int GL_CalcTextureSamples( int flags ) -{ - if( FBitSet( flags, IMAGE_HAS_COLOR )) - return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 4 : 3; - return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 2 : 1; -} - /* ================== GL_CalcImageSize @@ -461,44 +423,40 @@ static size_t GL_CalcTextureSize( int format, int width, int height ) return size; } -static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer ) +static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *mipsize ) { int width, height; -#if 1 - int i, mipcount; -#endif + int mipcount; + Assert( tex != NULL ); if( !haveBuffer ) return 1; -#if 1 // brush model only + +#if 0 + // brush model only if( !FBitSet( tex->flags, TF_ALLOW_EMBOSS ) ) return 1; #endif + // generate mip-levels by user request - if( FBitSet( tex->flags, TF_NOMIPMAP )) + if( FBitSet( tex->flags, TF_NOMIPMAP ) ) return 1; - // mip-maps can't exceeds 16 -#if 1 // 8 mipmaps for GU - for( i = 0; i < 8; i++ ) -#else - for( mipcount = 0; mipcount < 16; mipcount++ ) -#endif + // 8 levels - 7 + 1 base + for( mipcount = 1; mipcount < 8; mipcount++ ) { - width = Q_max( 1, ( tex->width >> i )); - height = Q_max( 1, ( tex->height >> i )); -#if 1 - if( ( width > 16 ) && ( height > 16 ) ) - mipcount = i; - else break; -#else - if( width == 1 && height == 1 ) - break; -#endif - } + width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> mipcount ) ); + height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> mipcount ) ); - return mipcount + 1; + if( width == TEXTURE_SIZE_MIN && height == TEXTURE_SIZE_MIN ) + break; + + // calc without base size + if( mipsize != NULL ) + *mipsize += GL_CalcTextureSize( tex->format, width, height ); + } + return mipcount; } /* @@ -506,16 +464,28 @@ static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer ) GL_SetTextureDimensions ================ */ -static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height, int depth ) +static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height ) { -#if 1 - int maxTextureSize = glConfig.max_texture_size; + int maxTextureSize; + int stepWidth, stepHeight; Assert( tex != NULL ); + + maxTextureSize = glConfig.max_texture_size; // store original sizes tex->srcWidth = width; tex->srcHeight = height; + +#if 0 // scale up + stepWidth = ( int )ceilf( logf( width ) * 1.0f / logf( 2.0f ) ); + stepHeight = ( int )ceilf( logf( height ) * 1.0f / logf( 2.0f ) ); +#else // scale down + stepWidth = ( int )floorf( logf( width ) * 1.0f / logf( 2.0f ) ); + stepHeight = ( int )floorf( logf( height ) * 1.0f / logf( 2.0f ) ); +#endif + width = ( 1 << stepWidth ); + height = ( 1 << stepHeight ); if( width > maxTextureSize || height > maxTextureSize ) { @@ -526,99 +496,9 @@ static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height, i } } - float calc_w = ceilf( logf( width ) * 1.0f / logf( 2.0f ) ); - float calc_h = ceilf( logf( height ) * 1.0f / logf( 2.0f ) ); - width = ( 1 << ( int ) calc_w ); - height = ( 1 << ( int ) calc_h ); - // set the texture dimensions - tex->width = Q_max( 32, width ); - tex->height = Q_max( 32, height ); - tex->depth = Q_max( 1, depth ); -#else - int maxTextureSize = 0; - int maxDepthSize = 1; - - Assert( tex != NULL ); - - switch( tex->target ) - { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - maxTextureSize = glConfig.max_2d_texture_size; - break; - case GL_TEXTURE_2D_ARRAY_EXT: - maxDepthSize = glConfig.max_2d_texture_layers; - maxTextureSize = glConfig.max_2d_texture_size; - break; - case GL_TEXTURE_RECTANGLE_EXT: - maxTextureSize = glConfig.max_2d_rectangle_size; - break; - case GL_TEXTURE_CUBE_MAP_ARB: - maxTextureSize = glConfig.max_cubemap_size; - break; - case GL_TEXTURE_3D: - maxDepthSize = glConfig.max_3d_texture_size; - maxTextureSize = glConfig.max_3d_texture_size; - break; - default: - Assert( false ); - } - - // store original sizes - tex->srcWidth = width; - tex->srcHeight = height; - - if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) - { - int step = (int)gl_round_down->value; - int scaled_width, scaled_height; - - for( scaled_width = 1; scaled_width < width; scaled_width <<= 1 ); - - if( step > 0 && width < scaled_width && ( step == 1 || ( scaled_width - width ) > ( scaled_width >> step ))) - scaled_width >>= 1; - - for( scaled_height = 1; scaled_height < height; scaled_height <<= 1 ); - - if( step > 0 && height < scaled_height && ( step == 1 || ( scaled_height - height ) > ( scaled_height >> step ))) - scaled_height >>= 1; - - width = scaled_width; - height = scaled_height; - } - - if( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize ) - { - if( tex->target == GL_TEXTURE_1D ) - { - while( width > maxTextureSize ) - width >>= 1; - } - else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT ) - { - while( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize ) - { - width >>= 1; - height >>= 1; - depth >>= 1; - } - } - else // all remaining cases - { - while( width > maxTextureSize || height > maxTextureSize ) - { - width >>= 1; - height >>= 1; - } - } - } - - // set the texture dimensions - tex->width = Q_max( 1, width ); - tex->height = Q_max( 1, height ); - tex->depth = Q_max( 1, depth ); -#endif + tex->width = Q_max( TEXTURE_SIZE_MIN, width ); + tex->height = Q_max( TEXTURE_SIZE_MIN, height ); } /* @@ -632,8 +512,8 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA ); Assert( tex != NULL ); -#if 1 - if( ImageDXT( format )) + + if( ImageDXT( format ) ) { switch( format ) { @@ -651,112 +531,19 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan tex->format = GL_DEPTH_COMPONENT32F; else tex->format = GL_DEPTH_COMPONENT24; }*/ + else if( ImageIND( format ) ) + { + tex->format = GU_PSM_T8; + } else { - if( format == PF_INDEXED_24 || format == PF_INDEXED_32 ) - { - tex->format = GU_PSM_T8; - } - else - { - if ( IsLightMap( tex ) ) - tex->format = GU_PSM_5650; - else if( haveAlpha ) - tex->format = GU_PSM_4444; - else - tex->format = GU_PSM_5650; - } - } -#endif -#if 0 - qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR ); - qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA ); - - Assert( tex != NULL ); - - if( ImageDXT( format )) - { - switch( format ) - { - case PF_DXT1: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; // never use DXT1 with 1-bit alpha - case PF_DXT3: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case PF_DXT5: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case PF_ATI2: - if( glConfig.hardware_type == GLHW_RADEON ) - tex->format = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; - else tex->format = GL_COMPRESSED_RED_GREEN_RGTC2_EXT; - break; - } - return; - } - else if( FBitSet( tex->flags, TF_DEPTHMAP )) - { - if( FBitSet( tex->flags, TF_ARB_16BIT )) - tex->format = GL_DEPTH_COMPONENT16; - else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_DEPTH_FLOAT_EXT )) - tex->format = GL_DEPTH_COMPONENT32F; - else tex->format = GL_DEPTH_COMPONENT24; - } - else if( FBitSet( tex->flags, TF_ARB_FLOAT|TF_ARB_16BIT ) && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT )) - { - if( haveColor && haveAlpha ) - { - if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) - tex->format = GL_RGBA16F_ARB; - else tex->format = GL_RGBA32F_ARB; - } - else if( haveColor ) - { - if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) - tex->format = GL_RGB16F_ARB; - else tex->format = GL_RGB32F_ARB; - } + if ( IsLightMap( tex ) ) + tex->format = GU_PSM_5650; else if( haveAlpha ) - { - if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) - tex->format = GL_RG16F; - else tex->format = GL_RG32F; - } + tex->format = GU_PSM_4444; else - { - if( FBitSet( tex->flags, TF_ARB_16BIT ) || gpGlobals->desktopBitsPixel == 16 ) - tex->format = GL_LUMINANCE16F_ARB; - else tex->format = GL_LUMINANCE32F_ARB; - } + tex->format = GU_PSM_5650; } - else - { - // NOTE: not all the types will be compressed - int bits = gpGlobals->desktopBitsPixel; - - switch( GL_CalcTextureSamples( channelMask )) - { - case 1: - if( FBitSet( tex->flags, TF_ALPHACONTRAST )) - tex->format = GL_INTENSITY8; - else tex->format = GL_LUMINANCE8; - break; - case 2: tex->format = GL_LUMINANCE8_ALPHA8; break; - case 3: - switch( bits ) - { - case 16: tex->format = GL_RGB5; break; - case 32: tex->format = GL_RGB8; break; - default: tex->format = GL_RGB; break; - } - break; - case 4: - default: - switch( bits ) - { - case 16: tex->format = GL_RGBA4; break; - case 32: tex->format = GL_RGBA8; break; - default: tex->format = GL_RGBA; break; - } - break; - } - } -#endif } /* @@ -1041,49 +828,6 @@ static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, } } -static void GL_TextureImageRAW( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, GLint type, const void *data ) -{ -#if 0 - GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; - qboolean subImage = FBitSet( tex->flags, TF_IMG_UPLOADED ); - GLenum inFormat = gEngfuncs.Image_GetPFDesc(type)->glFormat; - GLint dataType = GL_UNSIGNED_BYTE; - - Assert( tex != NULL ); -#endif -} -#if 0 -static void GL_TextureImageDXT( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data ) -{ - GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; - qboolean subImage = FBitSet( tex->flags, TF_IMG_UPLOADED ); - - Assert( tex != NULL ); - -#ifndef XASH_GLES - if( tex->target == GL_TEXTURE_1D ) - { - if( subImage ) pglCompressedTexSubImage1DARB( tex->target, level, 0, width, tex->format, size, data ); - else pglCompressedTexImage1DARB( tex->target, level, tex->format, width, 0, size, data ); - } - else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB ) - { - if( subImage ) pglCompressedTexSubImage2DARB( cubeTarget + side, level, 0, 0, width, height, tex->format, size, data ); - else pglCompressedTexImage2DARB( cubeTarget + side, level, tex->format, width, height, 0, size, data ); - } - else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT ) - { - if( subImage ) pglCompressedTexSubImage3DARB( tex->target, level, 0, 0, 0, width, height, depth, tex->format, size, data ); - else pglCompressedTexImage3DARB( tex->target, level, tex->format, width, height, depth, 0, size, data ); - } - else // 2D or RECT - { - if( subImage ) pglCompressedTexSubImage2DARB( tex->target, level, 0, 0, width, height, tex->format, size, data ); - else pglCompressedTexImage2DARB( tex->target, level, tex->format, width, height, 0, size, data ); - } -#endif -} -#endif /* =============== GL_PixelConverter @@ -1179,7 +923,7 @@ GL_TextureSwizzle fast swizzling =============== */ -static void GL_TextureSwizzle(byte *dst, const byte *src, uint width, uint height) +static void GL_TextureSwizzle( byte *dst, const byte *src, uint width, uint height ) { uint blockx, blocky; uint j; @@ -1190,18 +934,18 @@ static void GL_TextureSwizzle(byte *dst, const byte *src, uint width, uint heigh const byte* ysrc = src; uint* dst32 = ( uint* )dst; - for (blocky = 0; blocky < height_blocks; ++blocky) + for ( blocky = 0; blocky < height_blocks; ++blocky ) { const byte* xsrc = ysrc; - for (blockx = 0; blockx < width_blocks; ++blockx) + for ( blockx = 0; blockx < width_blocks; ++blockx ) { const int* src32 = ( uint* )xsrc; - for (j = 0; j < 8; ++j) + for ( j = 0; j < 8; ++j ) { - *(dst32++) = *(src32++); - *(dst32++) = *(src32++); - *(dst32++) = *(src32++); - *(dst32++) = *(src32++); + *( dst32++ ) = *( src32++ ); + *( dst32++ ) = *( src32++ ); + *( dst32++ ) = *( src32++ ); + *( dst32++ ) = *( src32++ ); src32 += src_pitch; } xsrc += 16; @@ -1219,13 +963,11 @@ upload texture into memory */ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { - byte *buf, *data; - size_t texsize, size; + size_t texSize; uint width, height; - uint i, j, numSides; - uint offset = 0; + uint i; + uint offset; qboolean normalMap; - const byte *bufend; void *volBuff; unsigned int volSize; int volUid; @@ -1237,7 +979,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) Assert( pic != NULL ); Assert( tex != NULL ); - GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth ); + GL_SetTextureDimensions( tex, pic->width, pic->height ); GL_SetTextureFormat( tex, pic->type, pic->flags ); tex->fogParams[0] = pic->fogParams[0]; @@ -1253,182 +995,112 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if( !pic->buffer ) return true; - - buf = pic->buffer; - bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps - - offset = GL_CalcImageSize( pic->type, pic->width, pic->height, pic->depth ); - texsize = GL_CalcTextureSize( tex->format, tex->width, tex->height ); + + // Prepare sizes + offset = GL_CalcImageSize( pic->type, pic->width, pic->height, /* pic->depth */ 1 ); + texSize = GL_CalcTextureSize( tex->format, tex->width, tex->height ); normalMap = FBitSet( tex->flags, TF_NORMALMAP ) ? true : false; - tex->numMips = 0; + tex->numMips = ImageIND( pic->type ) ? GL_CalcMipmapCount( tex, ( pic->buffer != NULL ), &texSize) : 1; + // Volatile memory for temporary buffer volUid = sceKernelVolatileMemLock( 0, &volBuff, &volSize ); if( volUid != 0) gEngfuncs.Host_Error( "GL_AllocTexture: volatile memory lock error 0x%08x ! \n", volUid); - if( ImageDXT( pic->type ) ) + // Check allocation size + if( tex->dstTexture && ( tex->size != texSize ) ) { - memcpy(tex->dstTexture, buf, texsize); + if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + vfree( tex->dstTexture ); + else + free( tex->dstTexture ); + + tex->dstTexture = NULL; + ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); } - else if( pic->type == PF_INDEXED_32 ) + + // already allocated? + if( !tex->dstTexture ) { - int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL )); - - // Calc mip size - texsize = 0; - for(j = 0; j < mipCount; j++ ) - { - width = Q_max( 1, ( tex->width >> j ) ); - height = Q_max( 1, ( tex->height >> j ) ); - texsize += GL_CalcTextureSize( tex->format, width, height ); - } - - // Check allocation size - if( tex->dstTexture && ( tex->size != texsize ) ) - { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) - vfree( tex->dstTexture ); - else - free( tex->dstTexture ); - ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); - } - - // Already allocated? + tex->dstTexture = ( byte* )valloc( texSize ); if( !tex->dstTexture ) { - tex->dstTexture = ( byte* )valloc( texsize ); - if( !tex->dstTexture ) + tex->dstTexture = ( byte* )memalign( 16, texSize ); + if ( !tex->dstTexture ) { - tex->dstTexture = ( byte* )memalign( 16, texsize ); - if ( !tex->dstTexture ) - { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); - } + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %lu %s )\n", texSize, tex->name); } - else + } + else + { + SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + } + } + + if( ImageDXT( pic->type ) ) + { + memcpy( tex->dstTexture, pic->buffer, texSize ); + } + else if( ImageIND( pic->type ) ) + { + if( !tex->dstPalette ) + { + tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !tex->dstPalette ) { - SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); } } // Load palette - tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !tex->dstPalette ) - { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); - } - GL_PixelConverter( tex->dstPalette, pic->palette, 256, true, PALETTE_FORMAT ); + GL_PixelConverter( tex->dstPalette, pic->palette, 256, (pic->type == PF_INDEXED_32) ? true : false, PALETTE_FORMAT ); sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); + // Load base + mip texture int mip_offset = 0; - for( j = 0; j < mipCount; j++ ) + for( i = 0; i < tex->numMips; i++ ) { - width = Q_max( 1, ( tex->width >> j ) ); - height = Q_max( 1, ( tex->height >> j ) ); + width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> i ) ); + height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> i ) ); if( ( pic->width != width ) || ( pic->height != height ) ) - GL_ResampleTexture8( buf, pic->width, pic->height, volBuff, width, height ); - else memcpy(volBuff, buf, offset); + GL_ResampleTexture8( pic->buffer, pic->width, pic->height, volBuff, width, height ); + else memcpy(volBuff, pic->buffer, offset); + GL_TextureSwizzle( tex->dstTexture + mip_offset, volBuff, width, height ); mip_offset += GL_CalcTextureSize( tex->format, width, height ); - tex->numMips = j; } SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); } - else if( pic->type == PF_INDEXED_24 ) - { - // Check allocation - if( tex->dstTexture && ( tex->size != texsize ) ) - { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) - vfree( tex->dstTexture ); - else - free( tex->dstTexture ); - ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); - } - // Already allocated - if( !tex->dstTexture ) - { - tex->dstTexture = ( byte* )valloc( texsize ); - if( !tex->dstTexture ) - { - tex->dstTexture = ( byte* )memalign( 16, texsize ); - if ( !tex->dstTexture ) - { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); - } - } - else - { - SetBits( tex->guFlags, GUFLAGTEXINVRAM ); - } - } - - if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) - GL_ResampleTexture8( buf, pic->width, pic->height, volBuff, tex->width, tex->height ); - else - memcpy(volBuff, buf, offset); - - tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !tex->dstPalette ) - { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); - } - GL_PixelConverter( tex->dstPalette, pic->palette, 256, false, PALETTE_FORMAT ); - sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); - GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width, tex->height ); - SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); - } else // RGBA32 { - // Check allocation - if( tex->dstTexture && ( tex->size != texsize ) ) - { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) - vfree( tex->dstTexture ); - else - free( tex->dstTexture ); - ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); - } - // Already allocated - if( !tex->dstTexture ) - { - tex->dstTexture = ( byte* )valloc( texsize ); - if( !tex->dstTexture ) - { - tex->dstTexture = ( byte* )memalign( 16, texsize ); - if ( !tex->dstTexture ) - { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); - } - } - else - { - SetBits( tex->guFlags, GUFLAGTEXINVRAM ); - } - } - if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) { - GL_ResampleTexture32( buf, pic->width, pic->height, volBuff, tex->width, tex->height, normalMap ); + GL_ResampleTexture32( pic->buffer, pic->width, pic->height, volBuff, tex->width, tex->height, normalMap ); offset = tex->width * tex->height * 4; } else { - memcpy( volBuff, buf, offset ); + memcpy( volBuff, pic->buffer, offset ); } if( tex->format == GU_PSM_8888 ) { - memcpy( tex->dstTexture, volBuff, texsize ); + if ( IsLightMap( tex ) ) + { + memcpy( tex->dstTexture, volBuff, texSize ); + } + else + { + GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * 4, tex->height ); + SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + } } else { + // disable swizzling for lightmaps if ( IsLightMap( tex ) ) { GL_PixelConverter( tex->dstTexture, volBuff, tex->width * tex->height, true, tex->format ); @@ -1446,8 +1118,8 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) } } sceKernelVolatileMemUnlock( 0 ); - sceKernelDcacheWritebackRange( tex->dstTexture, texsize ); - tex->size = texsize; + sceKernelDcacheWritebackRange( tex->dstTexture, texSize ); + tex->size = texSize; SetBits( tex->flags, TF_IMG_UPLOADED ); // done @@ -1470,7 +1142,7 @@ qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int { if( texnum != 0 ) { - gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid texturenum %d\n", texnum ); + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid texture num %d\n", texnum ); return false; } } @@ -1485,10 +1157,10 @@ qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int if(tex->width < xoff || tex->height < yoff ) { - gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid position cord %s\n", tex->name ); + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid offset position %s\n", tex->name ); return false; } - tex->numMips = 0; + tex->numMips = 1; tex->dstPalette = NULL; tex->format = GU_PSM_5650; @@ -1751,6 +1423,7 @@ recalc image room */ void GL_UpdateTexSize( int texnum, int width, int height, int depth ) { +#if 0 int i, j, texsize; int numSides; gl_texture_t *tex; @@ -1769,14 +1442,11 @@ void GL_UpdateTexSize( int texnum, int width, int height, int depth ) { width = Q_max( 1, ( tex->width >> j )); height = Q_max( 1, ( tex->height >> j )); -#if 1 - texsize = GL_CalcTextureSize( tex->format, width, height ); -#else texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); -#endif tex->size += texsize; } } +#endif } /* diff --git a/ref_gu/gu_init.c b/ref_gu/gu_init.c index 67198c7b..1732d559 100644 --- a/ref_gu/gu_init.c +++ b/ref_gu/gu_init.c @@ -243,7 +243,7 @@ void GL_InitCommands( void ) gl_vsync = gEngfuncs.pfnGetCvarPointer( "gl_vsync", 0 ); gl_detailscale = gEngfuncs.Cvar_Get( "gl_detailscale", "4.0", FCVAR_GLCONFIG, "default scale applies while auto-generate list of detail textures" ); gl_texture_lodfunc = gEngfuncs.Cvar_Get( "gl_texture_lodfunc", "2", FCVAR_GLCONFIG, "LOD func for mipmapped textures" ); - gl_texture_lodbias = gEngfuncs.Cvar_Get( "gl_texture_lodbias", "-5.0", FCVAR_GLCONFIG, "LOD bias for mipmapped textures (perfomance|quality)" ); + gl_texture_lodbias = gEngfuncs.Cvar_Get( "gl_texture_lodbias", "-6.0", FCVAR_GLCONFIG, "LOD bias for mipmapped textures (perfomance|quality)" ); gl_texture_lodslope = gEngfuncs.Cvar_Get( "gl_texture_lodslope", "0.3", FCVAR_GLCONFIG, "LOD slope for mipmapped textures" ); gl_keeptjunctions = gEngfuncs.Cvar_Get( "gl_keeptjunctions", "1", FCVAR_GLCONFIG, "removing tjuncs causes blinking pixels" ); gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_GLCONFIG|FCVAR_LATCH, "fake bumpmapping scale" ); diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index c546a707..90b238cf 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -713,7 +713,7 @@ static void LM_UploadBlock( qboolean dynamic ) r_lightmap.size = r_lightmap.width * r_lightmap.height * 4; r_lightmap.flags = IMAGE_HAS_COLOR; r_lightmap.buffer = gl_lms.lightmap_buffer; - tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE ); + tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_NOMIPMAP|TF_ATLAS_PAGE ); if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS ) gEngfuncs.Host_Error( "AllocBlock: full\n" ); From e7e10ac8b9f2d630f93bb5e07225bfcaa7c636d2 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sun, 10 Apr 2022 21:34:43 +0300 Subject: [PATCH 09/84] filesystem: hold mode fix --- engine/common/filesystem.c | 17 ++++++++--------- engine/common/soundlib/snd_mp3.c | 5 +++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index c38919a9..035733df 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -2387,19 +2387,13 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) int mod, opt; uint ind; #if XASH_PSP +#ifdef XASH_REDUCE_FD qboolean backup_hold = false; - - // Hold file in open state - if( mode[0] == '*' ) - { - backup_hold = true; - mode++; - } - +#endif // Parse the mode string switch( mode[0] ) { - case 'r': // read + case 'r': // read mod = PSP_O_RDONLY; opt = 0; break; @@ -2428,6 +2422,11 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) break; case 'b': // not used break; +#ifdef XASH_REDUCE_FD + case 'h': // hold + backup_hold = true; + break; +#endif default: break; } diff --git a/engine/common/soundlib/snd_mp3.c b/engine/common/soundlib/snd_mp3.c index 1f42bc32..a512bee7 100644 --- a/engine/common/soundlib/snd_mp3.c +++ b/engine/common/soundlib/snd_mp3.c @@ -117,8 +117,9 @@ stream_t *Stream_OpenMPG( const char *filename ) file_t *file; int ret; wavinfo_t sc; -#if XASH_PSP // hold mode - file = FS_Open( filename, "*rb", false ); +#if XASH_PSP + // h - hold mode + file = FS_Open( filename, "rbh", false ); #else file = FS_Open( filename, "rb", false ); #endif From 5c244b4140164d3b59f9e09d5e784b3e1a686592 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 11 Apr 2022 14:53:01 +0300 Subject: [PATCH 10/84] filesystem: Stream_OpenWAV hold mode fix --- engine/common/soundlib/snd_wav.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/common/soundlib/snd_wav.c b/engine/common/soundlib/snd_wav.c index 22fe6681..f87a3059 100644 --- a/engine/common/soundlib/snd_wav.c +++ b/engine/common/soundlib/snd_wav.c @@ -320,8 +320,9 @@ stream_t *Stream_OpenWAV( const char *filename ) return NULL; // open -#if XASH_PSP // hold mode - file = FS_Open( filename, "*rb", false ); +#if XASH_PSP + // h - hold mode + file = FS_Open( filename, "rbh", false ); #else file = FS_Open( filename, "rb", false ); #endif From dc22f5cbaf58e690a5efb198c5cfbda34a411713 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 14 Apr 2022 10:17:28 +0300 Subject: [PATCH 11/84] vox: MAX_SENTENCES changed to 2048 --- engine/client/vox.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/client/vox.h b/engine/client/vox.h index 8e6e557b..ca2fe552 100644 --- a/engine/client/vox.h +++ b/engine/client/vox.h @@ -18,7 +18,11 @@ GNU General Public License for more details. #define CVOXWORDMAX 64 #define CVOXZEROSCANMAX 255 // scan up to this many samples for next zero crossing +#if XASH_PSP +#define MAX_SENTENCES 2048 +#else #define MAX_SENTENCES 4096 +#endif #define SENTENCE_INDEX -99999 // unique sentence index typedef struct voxword_s From 7be87a913dfe2a15b892ff8f1932a344158c7177 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 14 Apr 2022 14:54:52 +0300 Subject: [PATCH 12/84] filesystem: small changes --- engine/common/filesystem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index 035733df..ddb1a713 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -590,11 +590,7 @@ void FS_CreatePath( char *path ) // create the directory save = *ofs; *ofs = 0; -#if XASH_PSP - sceIoMkdir( path, 0777 ); -#else _mkdir( path ); -#endif *ofs = save; } } @@ -2515,10 +2511,11 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) // return NULL; // For files opened in append mode, we start at the end of the file - if( opt & O_APPEND ) file->position = file->real_length; #if XASH_PSP + if( opt & PSP_O_APPEND ) file->position = file->real_length; else sceIoLseek( file->handle, 0, PSP_SEEK_SET ); #else + if( opt & O_APPEND ) file->position = file->real_length; else lseek( file->handle, 0, SEEK_SET ); #endif From 2eef2cec49c6fee8fc5268ccd0823683a8a404fd Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sat, 16 Apr 2022 12:39:02 +0300 Subject: [PATCH 13/84] sound: psp sound output rewritten --- engine/platform/psp/s_psp.c | 247 ------------------------------ engine/platform/psp/snd_psp.c | 276 ++++++++++++++++++++++++++++++++++ scripts/waifulib/xcompile.py | 2 +- 3 files changed, 277 insertions(+), 248 deletions(-) delete mode 100644 engine/platform/psp/s_psp.c create mode 100644 engine/platform/psp/snd_psp.c diff --git a/engine/platform/psp/s_psp.c b/engine/platform/psp/s_psp.c deleted file mode 100644 index 7e29f858..00000000 --- a/engine/platform/psp/s_psp.c +++ /dev/null @@ -1,247 +0,0 @@ -/* -s_psp.c - sound hardware output -Copyright (C) 2020 Sergey Galushko - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ - -#include "platform/platform.h" -#if XASH_SOUND == SOUND_PSP - -#include -#include -#include - -#include "sound.h" - -#define SAMPLE_16BIT_SHIFT 1 -#define SECONDARY_BUFFER_SIZE 0x10000 - -#define SND_CHANELS 2 -#define SND_FREQ 44100 -#define SND_BUF_SIZE 16384 - -typedef struct -{ - short left; - short right; -}sample_t; - -static sample_t snd_buffer[SND_BUF_SIZE] __attribute__( ( aligned( 64 ) ) ); -static volatile unsigned int snd_sampleread; - -/* -======================================================================= -Global variables. Must be visible to window-procedure function -so it can unlock and free the data block after it has been played. -======================================================================= -*/ - -void S_Activate( qboolean active ) -{ - -} - -/* From PSP Quake */ -static void PSP_SoundCallback( void* buffer, unsigned int samplesToWrite, void* userData ) -{ - // Where are we writing to? - sample_t* const dest = ( sample_t* )buffer; - - // Where are we reading from? - const sample_t* const src = &snd_buffer[snd_sampleread]; - - // How many samples to read? - const unsigned int samplesToRead = samplesToWrite; // 44100 - - // Going to wrap past the end of the input buffer? - const unsigned int samplesBeforeEndOfInput = SND_BUF_SIZE - snd_sampleread; - if ( samplesToRead > samplesBeforeEndOfInput ) - { - // Yes, so write the first chunk from the end of the input buffer. - memcpy( dest, src, samplesBeforeEndOfInput * sizeof( sample_t ) ); - - // Write the second chunk from the start of the input buffer. - const unsigned int samplesToReadFromBeginning = samplesToRead - samplesBeforeEndOfInput; - - memcpy( &dest[samplesBeforeEndOfInput], src, samplesToReadFromBeginning * sizeof( sample_t ) ); - } - else - { - // No wrapping, just copy. - memcpy( &dest[0], src, samplesToRead * sizeof( sample_t ) ); - } - - // Update the read offset. - snd_sampleread = ( snd_sampleread + samplesToRead ) % SND_BUF_SIZE; -} - -/* -================== -SNDDMA_Init - -Try to find a sound device to mix for. -Returns false if nothing is found. -================== -*/ -qboolean SNDDMA_Init( void ) -{ - dma.format.speed = SND_FREQ; - dma.format.channels = SND_CHANELS; - dma.format.width = 2; - dma.samples = SND_BUF_SIZE * SND_CHANELS; - dma.buffer = ( unsigned char * )snd_buffer; - dma.samplepos = 0; - - // Initialise the audio system. This initialises it for the CD audio module - // too. - pspAudioInit(); - - // Set the channel callback. - // Sound effects use channel 0, CD audio uses channel 1. - pspAudioSetChannelCallback( 0, PSP_SoundCallback, 0 ); - - Con_Printf( "Using PSP audio driver: %d Hz\n", dma.format.speed ); - - //SNDDMA_Activate( true ); - - dma.initialized = true; -#if 0 /* libmp3 */ - // load modules - int status = sceUtilityLoadModule( PSP_MODULE_AV_AVCODEC ); - if ( status < 0 ) - { - Con_Printf( "Error - PSP_MODULE_AV_AVCODEC returned 0x%08X\n", status ); - }else printf("PSP_MODULE_AV_AVCODEC - OK\n"); - - status = sceUtilityLoadModule( PSP_MODULE_AV_MP3 ); - if ( status < 0 ) - { - Con_Printf( "Error - PSP_MODULE_AV_MP3 returned 0x%08X\n", status ); - }else printf("PSP_MODULE_AV_MP3 - OK\n"); - - // init mp3 resources - status = sceMp3InitResource(); - if ( status < 0 ) - { - Con_Printf("Error - sceMp3InitResource returned 0x%08X\n", status); - }else printf("sceMp3InitResource - OK\n"); -#endif - return true; -} - -/* -============== -SNDDMA_GetDMAPos - -return the current sample position (in mono samples read) -inside the recirculating dma buffer, so the mixing code will know -how many sample are required to fill it up. -=============== -*/ -int SNDDMA_GetDMAPos( void ) -{ - dma.samplepos = snd_sampleread * SND_CHANELS; - return dma.samplepos; -} - -/* -============== -SNDDMA_GetSoundtime - -update global soundtime -=============== -*/ -int SNDDMA_GetSoundtime( void ) -{ - static int buffers, oldsamplepos; - int samplepos, fullsamples; - - fullsamples = dma.samples / 2; - - // it is possible to miscount buffers - // if it has wrapped twice between - // calls to S_Update. Oh well. - samplepos = SNDDMA_GetDMAPos(); - - if( samplepos < oldsamplepos ) - { - buffers++; // buffer wrapped - - if( paintedtime > 0x40000000 ) - { - // time to chop things off to avoid 32 bit limits - buffers = 0; - paintedtime = fullsamples; - S_StopAllSounds( true ); - } - } - - oldsamplepos = samplepos; - - return (buffers * fullsamples + samplepos / 2); -} - -/* -============== -SNDDMA_BeginPainting - -Makes sure dma.buffer is valid -=============== -*/ -void SNDDMA_BeginPainting( void ) -{ - -} - -/* -============== -SNDDMA_Submit - -Send sound to device if buffer isn't really the dma buffer -Also unlocks the dsound buffer -=============== -*/ -void SNDDMA_Submit( void ) -{ - -} - -/* -============== -SNDDMA_Shutdown - -Reset the sound device for exiting -=============== -*/ -void SNDDMA_Shutdown( void ) -{ - Con_Printf("Shutting down audio.\n"); - - // Clear the mixing buffer so we don't get any noise during cleanup. - memset(snd_buffer, 0, sizeof(snd_buffer)); - - // Clear the channel callback. - pspAudioSetChannelCallback(0, 0, 0); - - // Stop the audio system? - pspAudioEndPre(); - - // Insert a false delay so the thread can be cleaned up. - sceKernelDelayThread(50 * 1000); - - // Shut down the audio system. - pspAudioEnd(); - - dma.initialized = false; -} - -#endif // XASH_SOUND == SOUND_PSP diff --git a/engine/platform/psp/snd_psp.c b/engine/platform/psp/snd_psp.c new file mode 100644 index 00000000..37f55878 --- /dev/null +++ b/engine/platform/psp/snd_psp.c @@ -0,0 +1,276 @@ +/* +snd_psp.c - psp sound hardware output +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "platform/platform.h" +#if XASH_SOUND == SOUND_PSP +#include + +#include +#include +#include + +#include "sound.h" + +#define PSP_NUM_AUDIO_SAMPLES 1024 // must be multiple of 64 +#define PSP_OUTPUT_CHANNELS 2 +#define PSP_OUTPUT_BUFFER_SIZE ( ( PSP_NUM_AUDIO_SAMPLES ) * ( PSP_OUTPUT_CHANNELS ) ) + +static struct +{ + SceUID threadUID; + SceUID semaUID; + int channel; + volatile int volL; + volatile int volR; + volatile int running; +} snd_psp = { -1, -1, -1, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, 1 }; + +static short snd_psp_buff[2][PSP_OUTPUT_BUFFER_SIZE] __attribute__( ( aligned( 64 ) ) ); + +/* +================== +SNDDMA_MainThread + +Copy samples +================== +*/ +static int SNDDMA_MainThread( SceSize args, void *argp ) +{ + int index = 0; + + while( snd_psp.running ) + { + sceKernelWaitSema( snd_psp.semaUID, 1, NULL ); + + int len = PSP_OUTPUT_BUFFER_SIZE; + int size = dma.samples; + int pos = dma.samplepos; + int wrapped = pos + len - size; + + if( wrapped < 0 ) + { + sceDmacMemcpy( snd_psp_buff[index], dma.buffer + ( pos * 2 ), len * 2 ); + dma.samplepos += len; + } + else + { + int remaining = size - pos; + sceDmacMemcpy( snd_psp_buff[index], dma.buffer + ( pos * 2 ), remaining * 2 ); + if( wrapped > 0 ) + sceDmacMemcpy( snd_psp_buff[index] + ( remaining * 2 ), dma.buffer, wrapped * 2 ); + dma.samplepos = wrapped; + } + + sceKernelSignalSema( snd_psp.semaUID, 1 ); + + sceAudioOutputPannedBlocking( snd_psp.channel, snd_psp.volL, snd_psp.volR, snd_psp_buff[index] ); + index = !index; + } + + sceKernelExitThread( 0 ); + return 0; +} + +/* +================== +SNDDMA_Init + +Try to find a sound device to mix for. +Returns false if nothing is found. +================== +*/ +qboolean SNDDMA_Init( void ) +{ + int samplecount; + + dma.format.speed = SOUND_DMA_SPEED; + dma.format.channels = PSP_OUTPUT_CHANNELS; + dma.format.width = 2; + + // must be multiple of 64 + samplecount = s_samplecount->value; + if( !samplecount ) + samplecount = 0x4000; + + dma.samples = samplecount * PSP_OUTPUT_CHANNELS; + dma.samplepos = 0; + dma.buffer = memalign( 64, dma.samples * 2 ); // 16 bit + if( !dma.buffer ) + return false; + + // clearing buffers + memset( dma.buffer, 0, dma.samples * 2 ); + memset( snd_psp_buff, 0, sizeof( snd_psp_buff ) ); + + // allocate and initialize a hardware output channel + snd_psp.channel = sceAudioChReserve( PSP_AUDIO_NEXT_CHANNEL, + PSP_NUM_AUDIO_SAMPLES, + PSP_AUDIO_FORMAT_STEREO ); + if( snd_psp.channel < 0 ) + { + SNDDMA_Shutdown(); + return false; + } + + // create semaphore + snd_psp.semaUID = sceKernelCreateSema( "sound_sema", 0, 1, 255, NULL ); + if( snd_psp.semaUID <= 0 ) + { + SNDDMA_Shutdown(); + return false; + } + + // create audio thread + snd_psp.threadUID = sceKernelCreateThread( "sound_thread", SNDDMA_MainThread, 0x11, 0x8000, 0, 0 ); + if( snd_psp.threadUID < 0 ) + { + SNDDMA_Shutdown(); + return false; + } + + // start audio thread + if( sceKernelStartThread( snd_psp.threadUID, 0, 0 ) < 0 ) + { + SNDDMA_Shutdown(); + return false; + } + + Con_Printf( "Using PSP audio driver: %d Hz\n", dma.format.speed ); + + dma.initialized = true; + + return true; +} + +/* +============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos( void ) +{ + return dma.samplepos; +} + +/* +============== +SNDDMA_GetSoundtime + +update global soundtime +=============== +*/ +int SNDDMA_GetSoundtime( void ) +{ + static int buffers, oldsamplepos; + int samplepos, fullsamples; + + fullsamples = dma.samples / 2; + + // it is possible to miscount buffers + // if it has wrapped twice between + // calls to S_Update. Oh well. + samplepos = SNDDMA_GetDMAPos(); + + if( samplepos < oldsamplepos ) + { + buffers++; // buffer wrapped + + if( paintedtime > 0x40000000 ) + { + // time to chop things off to avoid 32 bit limits + buffers = 0; + paintedtime = fullsamples; + S_StopAllSounds( true ); + } + } + + oldsamplepos = samplepos; + + return (buffers * fullsamples + samplepos / 2); +} + +/* +============== +SNDDMA_BeginPainting + +Makes sure dma.buffer is valid +=============== +*/ +void SNDDMA_BeginPainting( void ) +{ + if( snd_psp.semaUID > 0 ) + sceKernelWaitSema( snd_psp.semaUID, 1, NULL ); +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +Also unlocks the dsound buffer +=============== +*/ +void SNDDMA_Submit( void ) +{ + if( snd_psp.semaUID > 0 ) + sceKernelSignalSema( snd_psp.semaUID, 1 ); +} + +/* +============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown( void ) +{ + Con_Printf("Shutting down audio.\n"); + + snd_psp.running = 0; + + if( snd_psp.threadUID >= 0 ) + { + sceKernelWaitThreadEnd( snd_psp.threadUID, NULL ); + sceKernelDeleteThread( snd_psp.threadUID ); + snd_psp.threadUID = -1; + } + + if( snd_psp.semaUID > 0 ) + { + sceKernelDeleteSema( snd_psp.semaUID ); + snd_psp.semaUID = -1; + } + + if( snd_psp.channel >= 0 ) + { + sceAudioChRelease( snd_psp.channel ); + snd_psp.channel = -1; + } + + if( dma.buffer ) + { + free( dma.buffer ); + dma.buffer = NULL; + } + + dma.initialized = false; +} + +#endif // XASH_SOUND == SOUND_PSP diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 6d3e1a5a..65b0e567 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -379,7 +379,7 @@ class PSP: def stdlibs(self): stdlibs = [] stdlibs += ['-lpspdisplay', '-lpspgum_vfpu', '-lpspgu','-lpspge', '-lpspvfpu'] - stdlibs += ['-lpspaudiolib', '-lpspaudio'] + stdlibs += ['-lpspaudio', '-lpspdmac'] stdlibs += ['-lstdc++', '-lc', '-lm'] stdlibs += ['-lpspctrl', '-lpspdebug', '-lpsppower', '-lpsputility', '-lpspsdk', '-lpsprtc'] stdlibs += ['-lpspuser', '-lpspkernel'] From 13a9c41b0cfb5a0181c236174dea22a2ae6e2f96 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sat, 16 Apr 2022 18:38:11 +0300 Subject: [PATCH 14/84] added .vscode/ to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f1d3f9ef..0d6660b1 100644 --- a/.gitignore +++ b/.gitignore @@ -326,3 +326,6 @@ __pycache__ *.vcproj *.sln *.vcxproj + +# VS Code +.vscode/ From 5eb19c1478b81e2b50432af1540c521f75963622 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sun, 24 Apr 2022 23:34:39 +0300 Subject: [PATCH 15/84] ref_gu: viewport bug fixed --- ref_gu/gu_draw.c | 4 +-- ref_gu/gu_rmain.c | 65 ++++++++++++++++------------------------------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/ref_gu/gu_draw.c b/ref_gu/gu_draw.c index 1646f37c..5b77462a 100644 --- a/ref_gu/gu_draw.c +++ b/ref_gu/gu_draw.c @@ -260,8 +260,8 @@ void R_Set2DMode( qboolean enable ) // set 2D virtual screen size #if 1 // through mode - sceGuViewport( 2048, 2048, gpGlobals->width, gpGlobals->width ); - sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); + sceGuViewport( 2048, 2048, gpGlobals->width, gpGlobals->height ); + sceGuScissor( 0, 0, gpGlobals->width, gpGlobals->height ); #else pglViewport( 0, 0, gpGlobals->width, gpGlobals->height ); pglMatrixMode( GL_PROJECTION ); diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index ca2bdd3b..8828a19e 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -565,36 +565,41 @@ void R_SetupGL( qboolean set_gl_state ) if( RP_NORMALPASS( )) { - int x, x2, y, y2; + int x, x2, y, y2, w, h; // set up viewport (main, playersetup) - x = floor( RI.viewport[0] * gpGlobals->width / gpGlobals->width ); - x2 = ceil(( RI.viewport[0] + RI.viewport[2] ) * gpGlobals->width / gpGlobals->width ); - y = floor( gpGlobals->height - RI.viewport[1] * gpGlobals->height / gpGlobals->height ); - y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] ) * gpGlobals->height / gpGlobals->height ); + x = floor( RI.viewport[0]/* * gpGlobals->width / gpGlobals->width*/ ); + x2 = ceil(( RI.viewport[0] + RI.viewport[2] )/* * gpGlobals->width / gpGlobals->width*/ ); + y = floor( gpGlobals->height - RI.viewport[1]/* * gpGlobals->height / gpGlobals->height*/ ); + y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] )/* * gpGlobals->height / gpGlobals->height*/ ); #if 1 - sceGuViewport( 2048, 2048, x2 - x, y - y2 ); /* psp center viewport 2048x2048 PSPFIXME*/ - sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); - /*sceGuViewport( - 2048, - 2048 + (gpGlobals->height / 2) - y2 - ((y - y2) / 2), - x2 - x, y - y2); - sceGuScissor(x, gpGlobals->height - y2 - (y - y2), x + (x2 - x), gpGlobals->height - y2);*/ + w = x2 - x; + h = y - y2; + + sceGuViewport( 2048 /*- ( gpGlobals->width >> 1 ) + x + ( w >> 1 )*/, + 2048 + ( gpGlobals->height >> 1 ) - y2 - ( h >> 1 ), + w, h ); + sceGuScissor( x, gpGlobals->height - y2 - h, x + w, gpGlobals->height - y2 ); #else - pglViewport( x, y2, x2 - x, y - y2 ); + pglViewport( x, y2, w, h ); #endif } else { // envpass, mirrorpass -#if 1 - sceGuViewport( 2048, 2048, RI.viewport[2], RI.viewport[3] ); /* psp center viewport 2048x2048 PSPFIXME */ - sceGuScissor(0, 0, gpGlobals->width, gpGlobals->height); +#if 1 + // FIXME: + sceGuViewport( 2048 - ( gpGlobals->width >> 1 ) + RI.viewport[0] + ( RI.viewport[2] >> 1 ), + 2048 + ( gpGlobals->height >> 1 ) - RI.viewport[1] - ( RI.viewport[3] >> 1 ), + RI.viewport[2], RI.viewport[3] ); + sceGuViewport( 2048, 2048, RI.viewport[2], RI.viewport[3] ); + sceGuScissor( RI.viewport[0], gpGlobals->height - RI.viewport[1] - RI.viewport[3], + RI.viewport[0] + RI.viewport[2], gpGlobals->height - RI.viewport[1] ); #else pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); #endif } -#if 1 + sceGumMatrixMode( GU_PROJECTION ); GL_LoadMatrix( RI.projectionMatrix ); @@ -626,33 +631,7 @@ void R_SetupGL( qboolean set_gl_state ) sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, 1.0f ) ); GU_ClipBeginFrame(); -#else - pglMatrixMode( GL_PROJECTION ); - GL_LoadMatrix( RI.projectionMatrix ); - pglMatrixMode( GL_MODELVIEW ); - GL_LoadMatrix( RI.worldviewMatrix ); - - if( FBitSet( RI.params, RP_CLIPPLANE )) - { - GLdouble clip[4]; - mplane_t *p = &RI.clipPlane; - - clip[0] = p->normal[0]; - clip[1] = p->normal[1]; - clip[2] = p->normal[2]; - clip[3] = -p->dist; - - pglClipPlane( GL_CLIP_PLANE0, clip ); - pglEnable( GL_CLIP_PLANE0 ); - } - - GL_Cull( GL_FRONT ); - - pglDisable( GL_BLEND ); - pglDisable( GL_ALPHA_TEST ); - pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); -#endif } /* From 4dfdbdd6aa1ac6714fb46261e52aee10382d152a Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 25 Apr 2022 16:44:01 +0300 Subject: [PATCH 16/84] ref_gu: unnecessary operations --- ref_gu/gu_rmain.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 8828a19e..9b5374e4 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -566,12 +566,18 @@ void R_SetupGL( qboolean set_gl_state ) if( RP_NORMALPASS( )) { int x, x2, y, y2, w, h; - // set up viewport (main, playersetup) - x = floor( RI.viewport[0]/* * gpGlobals->width / gpGlobals->width*/ ); - x2 = ceil(( RI.viewport[0] + RI.viewport[2] )/* * gpGlobals->width / gpGlobals->width*/ ); - y = floor( gpGlobals->height - RI.viewport[1]/* * gpGlobals->height / gpGlobals->height*/ ); - y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] )/* * gpGlobals->height / gpGlobals->height*/ ); +#if 1 + x = RI.viewport[0]; + x2 = RI.viewport[0] + RI.viewport[2]; + y = gpGlobals->height - RI.viewport[1]; + y2 = gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] ); +#else + x = floor( RI.viewport[0] * gpGlobals->width / gpGlobals->width ); + x2 = ceil(( RI.viewport[0] + RI.viewport[2] ) * gpGlobals->width / gpGlobals->width ); + y = floor( gpGlobals->height - RI.viewport[1] * gpGlobals->height / gpGlobals->height ); + y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] ) * gpGlobals->height / gpGlobals->height ); +#endif #if 1 w = x2 - x; h = y - y2; From 2885d4459335318dc7bfc9f4b2aed41044e325e2 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 4 May 2022 10:49:07 +0300 Subject: [PATCH 17/84] platform: 60 fps cap fix --- engine/platform/psp/in_psp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c index 14fdaf42..34a04fd2 100644 --- a/engine/platform/psp/in_psp.c +++ b/engine/platform/psp/in_psp.c @@ -104,7 +104,7 @@ void Platform_RunEvents( void ) static unsigned int last_buttons; static signed short last_X, last_Y; - sceCtrlReadBufferPositive( &buf, 1 ); + sceCtrlPeekBufferPositive( &buf, 1 ); for( i = 0; i < PSP_MAX_KEYS; i++ ) { From 90faeb231f932c6da091103969778b8121baf641 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 5 May 2022 21:50:14 +0300 Subject: [PATCH 18/84] optimization: aligned memory access, vfpu math --- common/xash3d_types.h | 10 ++ public/matrixlib.c | 212 +++++++++++++++++++++++++--------------- public/xash3d_mathlib.c | 89 ++++------------- ref_gu/gu_frustum.c | 3 +- ref_gu/gu_rmath.c | 23 +++++ 5 files changed, 186 insertions(+), 151 deletions(-) diff --git a/common/xash3d_types.h b/common/xash3d_types.h index e6c9824c..ac29ea29 100644 --- a/common/xash3d_types.h +++ b/common/xash3d_types.h @@ -14,12 +14,22 @@ typedef int sound_t; typedef float vec_t; typedef vec_t vec2_t[2]; typedef vec_t vec3_t[3]; +#if XASH_PSP +typedef vec_t vec4_t[4] __attribute__( ( aligned( 16 ) ) ); +typedef vec_t quat_t[4] __attribute__( ( aligned( 16 ) ) ); +#else typedef vec_t vec4_t[4]; typedef vec_t quat_t[4]; +#endif typedef byte rgba_t[4]; // unsigned byte colorpack typedef byte rgb_t[3]; // unsigned byte colorpack +#if XASH_PSP +typedef vec_t matrix3x4[3][4] __attribute__( ( aligned( 16 ) ) ); +typedef vec_t matrix4x4[4][4] __attribute__( ( aligned( 16 ) ) ); +#else typedef vec_t matrix3x4[3][4]; typedef vec_t matrix4x4[4][4]; +#endif #undef true #undef false diff --git a/public/matrixlib.c b/public/matrixlib.c index 49f710f0..f56a68fb 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -39,9 +39,9 @@ void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[ __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] @@ -68,16 +68,20 @@ void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] "vsub.t C130, C130, R103\n" // C130 = v - in[][3] +#if 1 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 +#else "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] +#endif "sv.s S000, 0 + %0\n" // out[0] = S000 "sv.s S001, 4 + %0\n" // out[1] = S001 "sv.s S002, 8 + %0\n" // out[2] = S002 @@ -104,14 +108,14 @@ void Matrix3x4_VectorRotate( const matrix3x4 in, const float v[3], float out[3] __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] -#if 0 - "vtfm3.t C000, M100, C130\n" // c000 = M100 * C130 +#if 1 + "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 #else "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] @@ -138,14 +142,14 @@ void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] -#if 0 - "vtfm3.t C000, E100, C130\n" // c000 = E100 * C130 +#if 1 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] @@ -167,6 +171,27 @@ void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matrix3x4 in2 ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "vzero.q C130\n" // C130 = [0, 0, 0, 0] + "lv.q C200, 0 + %2\n" // C100 = in2[0] + "lv.q C210, 16 + %2\n" // C110 = in2[1] + "lv.q C220, 32 + %2\n" // C120 = in2[2] + "vidt.q C230\n" // C230 = [0, 0, 0, 1] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in1 ), "m"( *in2 ) + ); +#else out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; @@ -179,6 +204,7 @@ void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matri out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; +#endif } void Matrix3x4_SetOrigin( matrix3x4 out, float x, float y, float z ) @@ -221,7 +247,7 @@ void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C130, %1\n" // C130 = quaternion + "lv.q C130, %1\n" // C130 = quaternion "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] @@ -233,9 +259,9 @@ void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec "vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z) "vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w) "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *quaternion ), "m"( *origin ) @@ -306,9 +332,9 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -347,9 +373,9 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -382,9 +408,9 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -407,9 +433,9 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *origin ), "m"( scale ) @@ -502,9 +528,9 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %2\n" // C100 = in[0] - "ulv.q C110, 16 + %2\n" // C110 = in[1] - "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] @@ -624,9 +650,9 @@ void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[ __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] @@ -653,16 +679,20 @@ void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] - "vsub.t C200, C130, R103\n" // C130 = v - in[][3] - "vdot.t S000, C200, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] - "vdot.t S001, C200, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] - "vdot.t S002, C200, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] + "vsub.t C130, C130, R103\n" // C130 = v - in[][3] +#if 1 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 +#else + "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] +#endif "sv.s S000, 0 + %0\n" // out[0] = S000 "sv.s S001, 4 + %0\n" // out[1] = S001 "sv.s S002, 8 + %0\n" // out[2] = S002 @@ -689,14 +719,14 @@ void Matrix4x4_VectorRotate( const matrix4x4 in, const float v[3], float out[3] __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] -#if 0 - "vtfm3.t C000, M100, C130\n" // c000 = M100 * C130 +#if 1 + "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 #else "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] @@ -722,14 +752,14 @@ void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %1\n" // C100 = in[0] - "ulv.q C110, 16 + %1\n" // C110 = in[1] - "ulv.q C120, 32 + %1\n" // C120 = in[2] + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] "lv.s S130, 0 + %2\n" // S130 = v[0] "lv.s S131, 4 + %2\n" // S131 = v[1] "lv.s S132, 8 + %2\n" // S132 = v[2] -#if 0 - "vtfm3.t C000, E100, C130\n" // c000 = E100 * C130 +#if 1 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] @@ -752,6 +782,27 @@ void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "vzero.q C130\n" // C130 = [0, 0, 0, 0] + "lv.q C200, 0 + %2\n" // C100 = in2[0] + "lv.q C210, 16 + %2\n" // C110 = in2[1] + "lv.q C220, 32 + %2\n" // C120 = in2[2] + "vidt.q C230\n" // C230 = [0, 0, 0, 1] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in1 ), "m"( *in2 ) + ); +#else out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; @@ -764,6 +815,7 @@ void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matri out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; +#endif } void Matrix4x4_SetOrigin( matrix4x4 out, float x, float y, float z ) @@ -818,7 +870,7 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) /**/ "vsin.t C110, C100\n" // C110 = sin( C100 ) P Y R "vcos.t C120, C100\n" // C120 = cos( C100 ) P Y R @@ -849,10 +901,10 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 - "usv.q C030, 48 + %0\n" // out[3] = C030 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -871,7 +923,7 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) /**/ "vsin.p C110, C100\n" // C110 = sin( C100 ) P Y "vcos.p C120, C100\n" // C120 = cos( C100 ) P Y @@ -892,10 +944,10 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 - "usv.q C030, 48 + %0\n" // out[3] = C030 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -913,7 +965,7 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) + "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) /**/ "vsin.s S111, S101\n" // S111 = sin( S101 ) Y "vcos.s S121, S101\n" // S121 = cos( S101 ) Y @@ -929,10 +981,10 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 - "usv.q C030, 48 + %0\n" // out[3] = C030 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) @@ -956,10 +1008,10 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale /**/ - "usv.q C000, 0 + %0\n" // out[0] = C000 - "usv.q C010, 16 + %0\n" // out[1] = C010 - "usv.q C020, 32 + %0\n" // out[2] = C020 - "usv.q C030, 48 + %0\n" // out[3] = C030 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *origin ), "m"( scale ) @@ -1091,9 +1143,9 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %2\n" // C100 = in[0] - "ulv.q C110, 16 + %2\n" // C110 = in[1] - "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] @@ -1131,9 +1183,9 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C100, 0 + %2\n" // C100 = in[0] - "ulv.q C110, 16 + %2\n" // C110 = in[1] - "ulv.q C120, 32 + %2\n" // C120 = in[2] + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index e465f4a5..d3ba9c57 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -312,11 +312,11 @@ float rsqrt( float number ) ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.s S000, %1\n" // S000 = number - "vzero.s S001\n" // S111 = 0 + "vzero.s S001\n" // S100 = 0 "vcmp.s EZ, S000\n" // CC[0] = ( S000 == 0.0f ) "vrsq.s S000, S000\n" // S000 = 1.0 / sqrt( S000 ) "vcmovt.s S000, S001, 0\n" // if ( CC[0] ) S000 = S001 - "sv.s S000, %0\n" // result = S001 + "sv.s S000, %0\n" // result = S000 ".set pop\n" // restore assembler option : "=m"( result ) : "m"( number ) @@ -940,144 +940,93 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) "beq %[signbits], $8, 7f\n" // jump to 7 "nop\n" // ( delay slot ) - "j 8f\n" // jump to SetSides + "j 9f\n" // jump to SetSides "nop\n" // ( delay slot ) "0:\n" -/* - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -*/ "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "1:\n" -/* - dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -*/ "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "2:\n" -/* - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -*/ "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "3:\n" -/* - dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -*/ "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "4:\n" -/* - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -*/ "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "5:\n" -/* - dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -*/ "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "6:\n" -/* - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -*/ "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "j 8f\n" // jump to SetSides + "j 8f\n" // jump to DotProduct "nop\n" // ( delay slot ) "7:\n" -/* - dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -*/ "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "8:\n" // DotProduct "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S030 = C000 * C020 - "8:\n" // SetSides -/* - if( dist1 >= p->dist ) - sides = 1; - if( dist2 < p->dist ) - sides |= 2; -*/ + "vdot.t S031, C000, C020\n" // S031 = C000 * C020 + "9:\n" // SetSides "addiu %[sides], $0, 0\n" // sides = 0 "vcmp.s LT, S030, S032\n" // S030 < S032 - "bvt 0, 9f\n" // if ( CC[0] == 1 ) jump to 9 - "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 1\n"// sides = 1 - "9:\n" - "vcmp.s GE, S031, S032\n" // S031 >= S032 "bvt 0, 10f\n" // if ( CC[0] == 1 ) jump to 10 "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 2\n"// sides = sides + 2 + "addiu %[sides], %[sides], 1\n"// sides = 1 "10:\n" + "vcmp.s GE, S031, S032\n" // S031 >= S032 + "bvt 0, 11f\n" // if ( CC[0] == 1 ) jump to 11 + "nop\n" // ( delay slot ) + "addiu %[sides], %[sides], 2\n"// sides = sides + 2 + "11:\n" ".set pop\n" // restore assembler option : [sides] "=r" ( sides ) : [normal] "m" ( p->normal ), diff --git a/ref_gu/gu_frustum.c b/ref_gu/gu_frustum.c index a52a8fb1..35c97c69 100644 --- a/ref_gu/gu_frustum.c +++ b/ref_gu/gu_frustum.c @@ -235,11 +235,12 @@ void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs ) void GL_FrustumDrawDebug( gl_frustum_t *out ) { +/* vec3_t bbox[8]; int i; GL_FrustumComputeCorners( out, bbox ); -/* + // g-cont. frustum must be yellow :-) pglColor4f( 1.0f, 1.0f, 0.0f, 1.0f ); pglDisable( GL_TEXTURE_2D ); diff --git a/ref_gu/gu_rmath.c b/ref_gu/gu_rmath.c index c3a3db24..78b91e3e 100644 --- a/ref_gu/gu_rmath.c +++ b/ref_gu/gu_rmath.c @@ -25,6 +25,28 @@ GNU General Public License for more details. */ void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) { +#if 1 + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "lv.q C130, 48 + %1\n" // C130 = in1[3] + "lv.q C200, 0 + %2\n" // C200 = in2[0] + "lv.q C210, 16 + %2\n" // C210 = in2[1] + "lv.q C220, 32 + %2\n" // C220 = in2[2] + "lv.q C230, 48 + %2\n" // C230 = in2[3] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in1 ), "m"( *in2 ) + ); +#else out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2]; @@ -41,6 +63,7 @@ void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) out[3][1] = in1[3][0] * in2[0][1] + in1[3][1] * in2[1][1] + in1[3][2] * in2[2][1] + in1[3][3] * in2[3][1]; out[3][2] = in1[3][0] * in2[0][2] + in1[3][1] * in2[1][2] + in1[3][2] * in2[2][2] + in1[3][3] * in2[3][2]; out[3][3] = in1[3][0] * in2[0][3] + in1[3][1] * in2[1][3] + in1[3][2] * in2[2][3] + in1[3][3] * in2[3][3]; +#endif } /* From 2ab8bce9248af061fb15a639a0c7c7cff4bdd566 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 5 May 2022 21:54:18 +0300 Subject: [PATCH 19/84] ref_gu: texture min size fixed --- ref_gu/gu_image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 6f1d5975..e43df402 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -40,7 +40,7 @@ static uint gl_numTextures; #error Current PALETTE_FORMAT not supported! #endif -#define TEXTURE_SIZE_MIN 8 +#define TEXTURE_SIZE_MIN 16 //8 #define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE )) From fe8fea742da0902e4e47fec6e9b57cc31dd0003d Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 13 May 2022 09:48:54 +0300 Subject: [PATCH 20/84] filesystem: added XASH_NO_ZIP define, 64 byte alignment for file buffer --- common/defaults.h | 1 + engine/common/filesystem.c | 72 ++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/common/defaults.h b/common/defaults.h index 71d7e885..e1f5cc55 100644 --- a/common/defaults.h +++ b/common/defaults.h @@ -118,6 +118,7 @@ SETUP BACKENDS DEFINITIONS #define XASH_REDUCE_FD #define XASH_NO_TOUCH + #define XASH_NO_ZIP #endif #endif // XASH_DEDICATED diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index ddb1a713..d456e5de 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -60,6 +60,7 @@ GNU General Public License for more details. #define WAD_LOAD_NO_FILES 5 #define WAD_LOAD_CORRUPTED 6 +#ifndef XASH_NO_ZIP // ZIP errors #define ZIP_LOAD_OK 0 #define ZIP_LOAD_COULDNT_OPEN 1 @@ -67,6 +68,7 @@ GNU General Public License for more details. #define ZIP_LOAD_BAD_FOLDERS 3 #define ZIP_LOAD_NO_FILES 5 #define ZIP_LOAD_CORRUPTED 6 +#endif // XASH_NO_ZIP typedef struct stringlist_s { @@ -98,7 +100,11 @@ struct file_s #endif // contents buffer fs_offset_t buff_ind, buff_len; // buffer current index and length +#if XASH_PSP + byte *buff; // aligned intermediate buffer +#else byte buff[FILE_BUFF_SIZE]; // intermediate buffer +#endif #ifdef XASH_REDUCE_FD #if XASH_PSP qboolean backup_hold; @@ -133,6 +139,7 @@ typedef struct pack_s dpackfile_t *files; } pack_t; +#ifndef XASH_NO_ZIP typedef struct zipfile_s { char name[MAX_SYSPATH]; @@ -154,13 +161,16 @@ typedef struct zip_s time_t filetime; zipfile_t *files; } zip_t; +#endif // XASH_NO_ZIP typedef struct searchpath_s { string filename; pack_t *pack; wfile_t *wad; +#ifndef XASH_NO_ZIP zip_t *zip; +#endif // XASH_NO_ZIP int flags; struct searchpath_s *next; } searchpath_t; @@ -179,7 +189,9 @@ static qboolean fs_caseinsensitive = true; // try to search missing files #ifdef XASH_REDUCE_FD static file_t *fs_last_readfile; +#ifndef XASH_NO_ZIP static zip_t *fs_last_zip; +#endif // XASH_NO_ZIP static pack_t *fs_last_pak; static void FS_EnsureOpenFile( file_t *file ) @@ -218,6 +230,7 @@ static void FS_EnsureOpenFile( file_t *file ) #endif } +#ifndef XASH_NO_ZIP static void FS_EnsureOpenZip( zip_t *zip ) { if( fs_last_zip == zip ) @@ -242,6 +255,7 @@ static void FS_EnsureOpenZip( zip_t *zip ) zip->handle = open( zip->filename, O_RDONLY|O_BINARY ); #endif } +#endif // XASH_NO_ZIP static void FS_BackupFileName( file_t *file, const char *path, uint options ) { @@ -266,7 +280,9 @@ static void FS_BackupFileName( file_t *file, const char *path, uint options ) #else static void FS_EnsureOpenFile( file_t *file ) {} +#ifndef XASH_NO_ZIP static void FS_EnsureOpenZip( zip_t *zip ) {} +#endif static void FS_BackupFileName( file_t *file, const char *path, uint options ) {} #endif @@ -274,7 +290,9 @@ static void FS_InitMemory( void ); static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly ); static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const signed char matchtype ); static dpackfile_t *FS_AddFileToPack( const char* name, pack_t *pack, fs_offset_t offset, fs_offset_t size ); +#ifndef XASH_NO_ZIP void Zip_Close( zip_t *zip ); +#endif static byte *W_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly ); static wfile_t *W_Open( const char *filename, int *errorcode ); static qboolean FS_SysFolderExists( const char *path ); @@ -613,7 +631,9 @@ void FS_Path_f( void ) { if( s->pack ) Con_Printf( "%s (%i files)", s->pack->filename, s->pack->numfiles ); else if( s->wad ) Con_Printf( "%s (%i files)", s->wad->filename, s->wad->numlumps ); +#ifndef XASH_NO_ZIP else if( s->zip ) Con_Printf( "%s (%i files)", s->zip->filename, s->zip->numfiles ); +#endif else Con_Printf( "%s", s->filename ); if( s->flags & FS_GAMERODIR_PATH ) Con_Printf( " ^2rodir^7" ); @@ -784,6 +804,7 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) return pack; } +#ifndef XASH_NO_ZIP static zip_t *FS_LoadZip( const char *zipfile, int *error ) { int numpackfiles = 0, i; @@ -1152,6 +1173,7 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game FS_EnsureOpenZip( NULL ); return NULL; } +#endif // XASH_NO_ZIP /* ==================== @@ -1267,6 +1289,7 @@ static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loade } } +#ifndef XASH_NO_ZIP qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int flags ) { searchpath_t *search; @@ -1319,6 +1342,7 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int return false; } } +#endif // XASH_NO_ZIP /* ================ @@ -1351,6 +1375,7 @@ void FS_AddGameDirectory( const char *dir, uint flags ) } } +#ifndef XASH_NO_ZIP // add any Zip package in the directory for( i = 0; i < list.numstrings; i++ ) { @@ -1359,7 +1384,8 @@ void FS_AddGameDirectory( const char *dir, uint flags ) Q_sprintf( fullpath, "%s%s", dir, list.strings[i] ); FS_AddZip_Fullpath( fullpath, NULL, flags ); } - } + } +#endif FS_AllowDirectPaths( true ); @@ -1481,10 +1507,12 @@ void FS_ClearSearchPath( void ) W_Close( search->wad ); } +#ifndef XASH_NO_ZIP if( search->zip ) { Zip_Close(search->zip); } +#endif // XASH_NO_ZIP Mem_Free( search ); } @@ -1945,6 +1973,9 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool } #if XASH_PSP + if( !found_psp ) + Q_snprintf( GameInfo->game_dll_psp, sizeof( GameInfo->game_dll_psp ), "dlls/server.prx" ); +#else if( !found_linux || !found_osx ) { // just replace extension from dll to so/dylib @@ -1958,9 +1989,6 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool if( !found_osx ) Q_snprintf( GameInfo->game_dll_osx, sizeof( GameInfo->game_dll_osx ), "%s.dylib", gamedll ); } -#else - if( !found_psp ) - Q_snprintf( GameInfo->game_dll_psp, sizeof( GameInfo->game_dll_psp ), "dlls/server.prx" ); // force set #endif // make sure what gamedir is really exist if( !FS_SysFolderExists( va( "%s"PATH_SPLITTER"%s", host.rootdir, GameInfo->falldir ))) @@ -2466,7 +2494,12 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) } } #endif +#if XASH_PSP + file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t ) + FILE_BUFF_SIZE + 64 ); + file->buff = (byte *)( ( ( ( u32 )file + sizeof( file_t ) ) & ( ~( 64 - 1 ) ) ) + 64 ); +#else file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file )); +#endif #if !XASH_PSP file->filetime = FS_SysFileTime( filepath ); #endif @@ -2536,7 +2569,12 @@ static int FS_DuplicateHandle( const char *filename, int handle, fs_offset_t pos static file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len ) { +#if XASH_PSP + file_t *file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t ) + FILE_BUFF_SIZE + 64 ); + file->buff = (byte *)( ( ( ( u32 )file + sizeof( file_t ) ) & ( ~( 64 - 1 ) ) ) + 64 ); +#else file_t *file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t )); +#endif #ifndef XASH_REDUCE_FD #if XASH_PSP file->handle = sceIoOpen( syspath, PSP_O_RDONLY, 0666 ); @@ -2602,6 +2640,7 @@ FS_OpenZipFile Open a packed file using its package file descriptor =========== */ +#ifndef XASH_NO_ZIP file_t *FS_OpenZipFile( zip_t *zip, int pack_ind ) { zipfile_t *pfile; @@ -2613,6 +2652,7 @@ file_t *FS_OpenZipFile( zip_t *zip, int pack_ind ) return FS_OpenHandle( zip->filename, zip->handle, pfile->offset, pfile->size ); } +#endif // XASH_NO_ZIP /* ================== @@ -2801,6 +2841,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir return search; } } +#ifndef XASH_NO_ZIP else if( search->zip ) { int i; @@ -2814,6 +2855,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir } } } +#endif // XASH_NO_ZIP else { char netpath[MAX_SYSPATH]; @@ -2898,8 +2940,10 @@ file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedi return FS_OpenPackedFile( search->pack, pack_ind ); else if( search->wad ) return NULL; // let W_LoadFile get lump correctly +#ifndef XASH_NO_ZIP else if( search->zip ) return FS_OpenZipFile( search->zip, pack_ind ); +#endif // XASH_NO_ZIP else if( pack_ind < 0 ) { char path [MAX_SYSPATH]; @@ -3067,7 +3111,11 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) count = file->real_length - file->position; // if we have a lot of data to get, put them directly into "buffer" +#if XASH_PSP + if( buffersize > FILE_BUFF_SIZE / 2 ) +#else if( buffersize > sizeof( file->buff ) / 2 ) +#endif { if( count > (fs_offset_t)buffersize ) count = (fs_offset_t)buffersize; @@ -3088,12 +3136,19 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) } else { - if( count > (fs_offset_t)sizeof( file->buff )) - count = (fs_offset_t)sizeof( file->buff ); #if XASH_PSP + if( count > FILE_BUFF_SIZE ) + count = FILE_BUFF_SIZE; + + if( count == 0 ) + return done; + sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); nb = sceIoRead( file->handle, file->buff, count ); #else + if( count > (fs_offset_t)sizeof( file->buff )) + count = (fs_offset_t)sizeof( file->buff ); + lseek( file->handle, file->offset + file->position, SEEK_SET ); nb = read( file->handle, file->buff, count ); #endif @@ -3366,9 +3421,10 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro else { buf = W_LoadFile( path, &filesize, gamedironly ); - +#ifndef XASH_NO_ZIP if( !buf ) buf = Zip_LoadFile( path, &filesize, gamedironly ); +#endif // XASH_NO_ZIP } @@ -3700,8 +3756,10 @@ int FS_FileTime( const char *filename, qboolean gamedironly ) return search->pack->filetime; else if( search->wad ) // grab wad filetime return search->wad->filetime; +#ifndef XASH_NO_ZIP else if( search->zip ) return search->zip->filetime; +#endif // XASH_NO_ZIP else if( pack_ind < 0 ) { // found in the filesystem? From 89ec7122fe5fe2f9f3853b27104e2639554e92e6 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 17 May 2022 11:50:04 +0300 Subject: [PATCH 21/84] ref_gu: cleanup, added texture wrap mode in GL_Bind --- common/render_api.h | 4 + ref_gu/gu_context.c | 8 +- ref_gu/gu_helper.h | 141 +++++++++---------- ref_gu/gu_image.c | 329 ++++++-------------------------------------- ref_gu/gu_local.h | 7 +- 5 files changed, 119 insertions(+), 370 deletions(-) diff --git a/common/render_api.h b/common/render_api.h index 5ba549f8..850256c5 100644 --- a/common/render_api.h +++ b/common/render_api.h @@ -107,6 +107,10 @@ typedef enum TF_ARB_FLOAT = (1<<26), // float textures TF_NOCOMPARE = (1<<27), // disable comparing for depth textures TF_ARB_16BIT = (1<<28), // keep image as 16-bit (not 24) +#if XASH_PSP + TF_IMG_SWIZZLED = (1<<29), + TF_IMG_INVRAM = (1<<30), +#endif } texFlags_t; typedef enum diff --git a/ref_gu/gu_context.c b/ref_gu/gu_context.c index 32d3a1fc..0e0e8e2d 100644 --- a/ref_gu/gu_context.c +++ b/ref_gu/gu_context.c @@ -187,14 +187,14 @@ static int GL_RefGetParm( int parm, int arg ) glt = R_GetTexture( arg ); return glt->format; case PARM_TEX_ENCODE: - glt = R_GetTexture( arg ); - return glt->encode; + /*glt = R_GetTexture( arg );*/ + return /*glt->encode*/0; case PARM_TEX_MIPCOUNT: glt = R_GetTexture( arg ); return glt->numMips; case PARM_TEX_DEPTH: - glt = R_GetTexture( arg ); - return glt->depth; + /*glt = R_GetTexture( arg );*/ + return /*glt->depth*/1; case PARM_TEX_SKYBOX: Assert( arg >= 0 && arg < 6 ); return tr.skyboxTextures[arg]; diff --git a/ref_gu/gu_helper.h b/ref_gu/gu_helper.h index 588a6693..acc94c32 100644 --- a/ref_gu/gu_helper.h +++ b/ref_gu/gu_helper.h @@ -1,74 +1,67 @@ -/* -gl_helper.h - gu helper -Copyright (C) 2021 Sergey Galushko - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ - -#ifndef GU_HELPER_H -#define GU_HELPER_H -#ifndef APIENTRY -#define APIENTRY -#endif - -#ifndef APIENTRY_LINKAGE -#define APIENTRY_LINKAGE extern -#endif - -// GL types wrapping -typedef uint GLenum; -typedef byte GLboolean; -typedef uint GLbitfield; -typedef void GLvoid; -typedef signed char GLbyte; -typedef short GLshort; -typedef int GLint; -typedef byte GLubyte; -typedef word GLushort; -typedef uint GLuint; -typedef int GLsizei; -typedef float GLfloat; -typedef float GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef int GLintptrARB; -typedef int GLsizeiptrARB; -typedef char GLcharARB; -typedef uint GLhandleARB; -typedef float GLmatrix[16]; - -// GL_Cull wrapping -#define GL_NONE 0 -#define GL_FRONT GU_CW + 1 -#define GL_BACK GU_CCW + 1 - -// color functions wrapping -#define GUCOLOR4F( r, g, b, a ) GU_COLOR( ( r ), ( g ), ( b ), ( a ) ) -#define GUCOLOR4FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) -#define GUCOLOR4UB( r, g, b, a ) GU_RGBA( ( r ), ( g ), ( b ), ( a ) ) -#define GUCOLOR4UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) -#define GUCOLOR3F( r, g, b ) GU_COLOR( ( r ), ( g ), ( b ), 1.0f ) -#define GUCOLOR3FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], 1.0f ) -#define GUCOLOR3UB( r, g, b ) GU_RGBA( ( r ), ( g ), ( b ), 255 ) -#define GUCOLOR3UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], 255 ) - -// blend function wrapping -#define GUBLEND1 0xffffff -#define GUBLEND0 0x000000 - -// texture flags -#define GUFLAGTEXNONE 0x00 -#define GUFLAGTEXUSED 0x01 -#define GUFLAGTEXSWIZZLED 0x02 -#define GUFLAGTEXINVRAM 0x04 -/*#define GUFLAGMIP 0x08*/ - -#endif // GU_HELPER_H +/* +gl_helper.h - gu helper +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GU_HELPER_H +#define GU_HELPER_H +#ifndef APIENTRY +#define APIENTRY +#endif + +#ifndef APIENTRY_LINKAGE +#define APIENTRY_LINKAGE extern +#endif + +// GL types wrapping +typedef uint GLenum; +typedef byte GLboolean; +typedef uint GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef byte GLubyte; +typedef word GLushort; +typedef uint GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef int GLintptrARB; +typedef int GLsizeiptrARB; +typedef char GLcharARB; +typedef uint GLhandleARB; +typedef float GLmatrix[16]; + +// GL_Cull wrapping +#define GL_NONE 0 +#define GL_FRONT GU_CW + 1 +#define GL_BACK GU_CCW + 1 + +// color functions wrapping +#define GUCOLOR4F( r, g, b, a ) GU_COLOR( ( r ), ( g ), ( b ), ( a ) ) +#define GUCOLOR4FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) +#define GUCOLOR4UB( r, g, b, a ) GU_RGBA( ( r ), ( g ), ( b ), ( a ) ) +#define GUCOLOR4UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], ( v )[3] ) +#define GUCOLOR3F( r, g, b ) GU_COLOR( ( r ), ( g ), ( b ), 1.0f ) +#define GUCOLOR3FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], 1.0f ) +#define GUCOLOR3UB( r, g, b ) GU_RGBA( ( r ), ( g ), ( b ), 255 ) +#define GUCOLOR3UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], 255 ) + +// blend function wrapping +#define GUBLEND1 0xffffff +#define GUBLEND0 0x000000 + +#endif // GU_HELPER_H diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index e43df402..20448df5 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -77,7 +77,7 @@ void GL_Bind( GLint tmu, GLenum texnum ) if( glState.currentTexture == texnum ) return; - + texture = &gl_textures[texnum]; // Set palette @@ -88,18 +88,31 @@ void GL_Bind( GLint tmu, GLenum texnum ) } // Set texture parameters - sceGuTexMode( texture->format, texture->numMips - 1, 0, FBitSet( texture->guFlags, GUFLAGTEXSWIZZLED ) ? GU_TRUE : GU_FALSE ); + sceGuTexMode( texture->format, texture->numMips - 1, 0, FBitSet( texture->flags, TF_IMG_SWIZZLED ) ? GU_TRUE : GU_FALSE ); if( texture->numMips > 1 ) { - sceGuTexFilter( GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR_MIPMAP_LINEAR ); + //sceGuTexFilter( GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR_MIPMAP_LINEAR ); + if( FBitSet( texture->flags, TF_NEAREST ) || gl_texture_nearest->value ) + sceGuTexFilter( GU_NEAREST_MIPMAP_NEAREST, GU_NEAREST ); + else + sceGuTexFilter( GU_LINEAR_MIPMAP_LINEAR, GU_LINEAR ); + sceGuTexLevelMode( gl_texture_lodfunc->value, gl_texture_lodbias->value ); sceGuTexSlope( gl_texture_lodslope->value ); } else { - sceGuTexFilter( GU_LINEAR, GU_LINEAR ); + if( FBitSet( texture->flags, TF_NEAREST ) || ( IsLightMap( texture ) && gl_lightmap_nearest->value )) + sceGuTexFilter( GU_NEAREST, GU_NEAREST ); + else + sceGuTexFilter( GU_LINEAR, GU_LINEAR ); } + if( FBitSet( texture->flags, TF_CLAMP ) || FBitSet( texture->flags, TF_BORDER ) ) + sceGuTexWrap( GU_CLAMP, GU_CLAMP ); + else + sceGuTexWrap( GU_REPEAT, GU_REPEAT ); + // Set base texture sceGuTexImage( 0, texture->width, texture->height, texture->width, texture->dstTexture ); @@ -118,234 +131,6 @@ void GL_Bind( GLint tmu, GLenum texnum ) glState.currentTexture = texnum; } -/* -================= -GL_ApplyTextureParams -================= -*/ -void GL_ApplyTextureParams( gl_texture_t *tex ) -{ -#if 0 - vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f }; - - if( !glw_state.initialized ) - return; - - Assert( tex != NULL ); - - // set texture filter - if( FBitSet( tex->flags, TF_DEPTHMAP )) - { - if( !FBitSet( tex->flags, TF_NOCOMPARE )) - { - pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB ); - pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL ); - } - - if( FBitSet( tex->flags, TF_LUMINANCE )) - pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE ); - else pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY ); - - if( FBitSet( tex->flags, TF_NEAREST )) - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - // allow max anisotropy as 1.0f on depth textures - if( GL_Support( GL_ANISOTROPY_EXT )) - pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f ); - } - else if( FBitSet( tex->flags, TF_NOMIPMAP ) || tex->numMips <= 1 ) - { - if( FBitSet( tex->flags, TF_NEAREST ) || ( IsLightMap( tex ) && gl_lightmap_nearest->value )) - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - } - else - { - if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->value ) - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - // set texture anisotropy if available - if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_ALPHACONTRAST )) - pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value ); - - // set texture LOD bias if available - if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 )) - pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value ); - } - - // check if border is not supported - if( FBitSet( tex->flags, TF_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT )) - { - ClearBits( tex->flags, TF_BORDER ); - SetBits( tex->flags, TF_CLAMP ); - } - - // only seamless cubemaps allows wrap 'clamp_to_border" - if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && FBitSet( tex->flags, TF_BORDER )) - ClearBits( tex->flags, TF_BORDER ); - - // set texture wrap - if( FBitSet( tex->flags, TF_BORDER )) - { - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - - if( tex->target != GL_TEXTURE_1D ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER ); - - pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, border ); - } - else if( FBitSet( tex->flags, TF_CLAMP )) - { - if( GL_Support( GL_CLAMPTOEDGE_EXT )) - { - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - - if( tex->target != GL_TEXTURE_1D ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP ); - - if( tex->target != GL_TEXTURE_1D ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP ); - - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP ); - } - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_REPEAT ); - - if( tex->target != GL_TEXTURE_1D ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_REPEAT ); - - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB ) - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_REPEAT ); - } -#endif -} - -/* -================= -GL_UpdateTextureParams -================= -*/ -static void GL_UpdateTextureParams( int iTexture ) -{ -#if 0 - gl_texture_t *tex = &gl_textures[iTexture]; - - Assert( tex != NULL ); - - if( !tex->texnum ) return; // free slot - - GL_Bind( XASH_TEXTURE0, iTexture ); - - // set texture anisotropy if available - if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP|TF_ALPHACONTRAST )) - pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value ); - - // set texture LOD bias if available - if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP )) - pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value ); - - if( IsLightMap( tex )) - { - if( gl_lightmap_nearest->value ) - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - } - - if( tex->numMips <= 1 ) return; - - if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->value ) - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - else - { - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } -#endif -} - -/* -================= -R_SetTextureParameters -================= -*/ -void R_SetTextureParameters( void ) -{ -#if 0 - int i; - - if( GL_Support( GL_ANISOTROPY_EXT )) - { - if( gl_texture_anisotropy->value > glConfig.max_texture_anisotropy ) - gEngfuncs.Cvar_SetValue( "gl_anisotropy", glConfig.max_texture_anisotropy ); - else if( gl_texture_anisotropy->value < 1.0f ) - gEngfuncs.Cvar_SetValue( "gl_anisotropy", 1.0f ); - } - - if( GL_Support( GL_TEXTURE_LOD_BIAS )) - { - if( gl_texture_lodbias->value < -glConfig.max_texture_lod_bias ) - gEngfuncs.Cvar_SetValue( "gl_texture_lodbias", -glConfig.max_texture_lod_bias ); - else if( gl_texture_lodbias->value > glConfig.max_texture_lod_bias ) - gEngfuncs.Cvar_SetValue( "gl_texture_lodbias", glConfig.max_texture_lod_bias ); - } - - ClearBits( gl_texture_anisotropy->flags, FCVAR_CHANGED ); - ClearBits( gl_texture_lodbias->flags, FCVAR_CHANGED ); - ClearBits( gl_texture_nearest->flags, FCVAR_CHANGED ); - ClearBits( gl_lightmap_nearest->flags, FCVAR_CHANGED ); - - // change all the existing mipmapped texture objects - for( i = 0; i < gl_numTextures; i++ ) - GL_UpdateTextureParams( i ); -#endif -} - /* ================== GL_CalcImageSize @@ -433,7 +218,7 @@ static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *m if( !haveBuffer ) return 1; -#if 0 +#if 0 // brush model only if( !FBitSet( tex->flags, TF_ALLOW_EMBOSS ) ) return 1; @@ -470,13 +255,13 @@ static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height ) int stepWidth, stepHeight; Assert( tex != NULL ); - + maxTextureSize = glConfig.max_texture_size; // store original sizes tex->srcWidth = width; tex->srcHeight = height; - + #if 0 // scale up stepWidth = ( int )ceilf( logf( width ) * 1.0f / logf( 2.0f ) ); stepHeight = ( int )ceilf( logf( height ) * 1.0f / logf( 2.0f ) ); @@ -995,14 +780,14 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if( !pic->buffer ) return true; - + // Prepare sizes offset = GL_CalcImageSize( pic->type, pic->width, pic->height, /* pic->depth */ 1 ); texSize = GL_CalcTextureSize( tex->format, tex->width, tex->height ); normalMap = FBitSet( tex->flags, TF_NORMALMAP ) ? true : false; tex->numMips = ImageIND( pic->type ) ? GL_CalcMipmapCount( tex, ( pic->buffer != NULL ), &texSize) : 1; - // Volatile memory for temporary buffer + // Volatile memory for temporary buffer volUid = sceKernelVolatileMemLock( 0, &volBuff, &volSize ); if( volUid != 0) gEngfuncs.Host_Error( "GL_AllocTexture: volatile memory lock error 0x%08x ! \n", volUid); @@ -1010,13 +795,13 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) // Check allocation size if( tex->dstTexture && ( tex->size != texSize ) ) { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + if( FBitSet( tex->flags, TF_IMG_INVRAM ) ) vfree( tex->dstTexture ); else free( tex->dstTexture ); - + tex->dstTexture = NULL; - ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + ClearBits( tex->flags, TF_IMG_INVRAM ); } // already allocated? @@ -1034,7 +819,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) } else { - SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + SetBits( tex->flags, TF_IMG_INVRAM ); } } @@ -1072,7 +857,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) GL_TextureSwizzle( tex->dstTexture + mip_offset, volBuff, width, height ); mip_offset += GL_CalcTextureSize( tex->format, width, height ); } - SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + SetBits( tex->flags, TF_IMG_SWIZZLED ); } else // RGBA32 { @@ -1095,7 +880,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) else { GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * 4, tex->height ); - SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + SetBits( tex->flags, TF_IMG_SWIZZLED ); } } else @@ -1113,7 +898,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) */ GL_PixelConverter( volBuff + offset, volBuff, tex->width * tex->height, true, tex->format ); GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * 2, tex->height ); - SetBits( tex->guFlags, GUFLAGTEXSWIZZLED ); + SetBits( tex->flags, TF_IMG_SWIZZLED ); } } } @@ -1169,13 +954,13 @@ qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int { if( tex->dstTexture ) { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + if( FBitSet( tex->flags, TF_IMG_INVRAM ) ) vfree( tex->dstTexture ); else free( tex->dstTexture ); tex->dstTexture = NULL; - ClearBits( tex->guFlags, GUFLAGTEXINVRAM ); + ClearBits( tex->flags, TF_IMG_INVRAM ); } } @@ -1190,7 +975,7 @@ qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int } else { - SetBits( tex->guFlags, GUFLAGTEXINVRAM ); + SetBits( tex->flags, TF_IMG_INVRAM ); } memset( tex->dstTexture, 0x00, texsize ); SetBits( tex->flags, TF_IMG_UPLOADED ); // done @@ -1226,9 +1011,9 @@ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) // force upload texture as RGB or RGBA (detail textures requires this) if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA; - +#if 0 tex->encode = pic->encode; // share encode method - +#endif if( ImageDXT( pic->type )) { if( !pic->numMips ) @@ -1406,7 +1191,7 @@ static void GL_DeleteTexture( gl_texture_t *tex ) if( tex->dstTexture ) { - if( FBitSet( tex->guFlags, GUFLAGTEXINVRAM ) ) + if( FBitSet( tex->flags, TF_IMG_INVRAM ) ) vfree( tex->dstTexture ); else free( tex->dstTexture ); @@ -1492,7 +1277,6 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) return 0; } - GL_ApplyTextureParams( tex ); // update texture filter, wrap etc gEngfuncs.FS_FreeImage( pic ); // release source texture // NOTE: always return texnum as index in array or engine will stop work !!! @@ -1683,7 +1467,6 @@ int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags return 0; } - GL_ApplyTextureParams( tex ); // update texture filter, wrap etc return (tex - gl_textures); } @@ -1730,6 +1513,9 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe SetBits( r_empty.flags, IMAGE_CUBEMAP ); r_empty.size *= 6; } +#else + if( FBitSet( flags, TF_CUBEMAP )) + return 0; #endif return GL_LoadTextureFromBuffer( name, &r_empty, flags, update ); } @@ -1861,7 +1647,6 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) gEngfuncs.Image_Process( &pic, topColor, bottomColor, flags, 0.0f ); GL_UploadTexture( image, pic ); - GL_ApplyTextureParams( image ); // update texture filter, wrap etc gEngfuncs.FS_FreeImage( pic ); } @@ -2019,7 +1804,7 @@ void R_TextureList_f( void ) int i, texCount, ram_bytes = 0, vram_bytes = 0; gEngfuncs.Con_Printf( "\n" ); - gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -type- -encode- -wrap- -depth- -name--------\n" ); + gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -type- -wrap- -name--------\n" ); for( i = texCount = 0, image = gl_textures; i < gl_numTextures; i++, image++ ) { @@ -2027,8 +1812,8 @@ void R_TextureList_f( void ) if( image->dstPalette ) ram_bytes += PALETTE_SIZE; - vram_bytes += ( FBitSet( image->guFlags, GUFLAGTEXINVRAM ) ) ? image->size : 0; - ram_bytes += ( FBitSet( image->guFlags, GUFLAGTEXINVRAM ) ) ? 0 : image->size; + vram_bytes += ( FBitSet( image->flags, TF_IMG_INVRAM ) ) ? image->size : 0; + ram_bytes += ( FBitSet( image->flags, TF_IMG_INVRAM ) ) ? 0 : image->size; texCount++; gEngfuncs.Con_Printf( "%4i: ", i ); @@ -2075,41 +1860,12 @@ void R_TextureList_f( void ) break; } - if( image->flags & TF_NORMALMAP ) - gEngfuncs.Con_Printf( "normal " ); - else gEngfuncs.Con_Printf( "diffuse " ); - - switch( image->encode ) - { - case DXT_ENCODE_COLOR_YCoCg: - gEngfuncs.Con_Printf( "YCoCg " ); - break; - case DXT_ENCODE_NORMAL_AG_ORTHO: - gEngfuncs.Con_Printf( "ortho " ); - break; - case DXT_ENCODE_NORMAL_AG_STEREO: - gEngfuncs.Con_Printf( "stereo " ); - break; - case DXT_ENCODE_NORMAL_AG_PARABOLOID: - gEngfuncs.Con_Printf( "parabolic " ); - break; - case DXT_ENCODE_NORMAL_AG_QUARTIC: - gEngfuncs.Con_Printf( "quartic " ); - break; - case DXT_ENCODE_NORMAL_AG_AZIMUTHAL: - gEngfuncs.Con_Printf( "azimuthal " ); - break; - default: - gEngfuncs.Con_Printf( "default " ); - break; - } - if( image->flags & TF_CLAMP ) gEngfuncs.Con_Printf( "clamp " ); else if( image->flags & TF_BORDER ) gEngfuncs.Con_Printf( "border " ); else gEngfuncs.Con_Printf( "repeat " ); - gEngfuncs.Con_Printf( " %d ", image->depth ); + gEngfuncs.Con_Printf( " %s\n", image->name ); } @@ -2140,7 +1896,6 @@ void R_InitImages( void ) gl_numTextures = 1; // validate cvars - R_SetTextureParameters(); GL_CreateInternalTextures(); gEngfuncs.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" ); diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 6355af0b..e6930dd4 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -129,13 +129,12 @@ typedef struct gltexture_s short srcHeight; short width; // upload width\height short height; - short depth; // texture depth or count of layers for 2D_ARRAY + //short depth; // texture depth or count of layers for 2D_ARRAY byte numMips; // mipmap count byte *dstTexture; // texture pointer byte *dstPalette; - byte guFlags; int format; // uploaded format - GLint encode; // using GLSL decoder + //GLint encode; // using GLSL decoder texFlags_t flags; rgba_t fogParams; // some water textures @@ -420,7 +419,6 @@ void R_DrawModelHull( void ); // // gu_image.c // -void R_SetTextureParameters( void ); gl_texture_t *R_GetTexture( GLenum texnum ); #define GL_LoadTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, false ) #define GL_UpdateTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, true ) @@ -433,7 +431,6 @@ int GL_CreateTextureArray( const char *name, int width, int height, int depth, c void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ); void GL_UpdateTexSize( int texnum, int width, int height, int depth ); -void GL_ApplyTextureParams( gl_texture_t *tex ); int GL_FindTexture( const char *name ); void GL_FreeTexture( GLenum texnum ); const char *GL_Target( GLenum target ); From 07e29771a100c2be1da5626016233f26f1cd70d0 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 24 May 2022 08:35:13 +0300 Subject: [PATCH 22/84] ref_gu: refactoring --- engine/platform/psp/vid_psp.c | 194 ++------------- ref_gu/gu_image.c | 29 +-- ref_gu/gu_local.h | 34 +-- ref_gu/{gu_init.c => gu_render.c} | 220 ++++++++++++++---- ref_gu/gu_rmain.c | 25 +- .../psp/vram_psp.c => ref_gu/gu_vram.c | 2 +- .../psp/vram_psp.h => ref_gu/gu_vram.h | 0 ref_gu/vram_psp.h | 39 ---- 8 files changed, 242 insertions(+), 301 deletions(-) rename ref_gu/{gu_init.c => gu_render.c} (69%) rename engine/platform/psp/vram_psp.c => ref_gu/gu_vram.c (99%) rename engine/platform/psp/vram_psp.h => ref_gu/gu_vram.h (100%) delete mode 100644 ref_gu/vram_psp.h diff --git a/engine/platform/psp/vid_psp.c b/engine/platform/psp/vid_psp.c index e29eeab5..08438a84 100644 --- a/engine/platform/psp/vid_psp.c +++ b/engine/platform/psp/vid_psp.c @@ -17,9 +17,6 @@ GNU General Public License for more details. #if !XASH_DEDICATED #include #include -#include -#include -#include "vram_psp.h" #include "common.h" #include "client.h" @@ -27,31 +24,19 @@ GNU General Public License for more details. #include "input.h" #include "vid_common.h" -// Set gu list -#define PSP_GU_STATIC_LIST 1 -#define PSP_GU_LIST_SIZE 0x40000 - // Set frame buffer #define PSP_FB_WIDTH 480 #define PSP_FB_HEIGHT 272 #define PSP_FB_BWIDTH 512 -#define PSP_FB_FORMAT 5650 //4444,5551,5650,8888 +#define PSP_FB_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 //4444,5551,565,8888 -#if PSP_FB_FORMAT == 4444 -#define PSP_FB_HW_FORMAT GU_PSM_4444 -#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_4444 +#if PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_4444 #define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == 5551 -#define PSP_FB_HW_FORMAT GU_PSM_5551 -#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_5551 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_5551 #define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == 5650 -#define PSP_FB_HW_FORMAT GU_PSM_5650 -#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_565 #define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == 8888 -#define PSP_FB_HW_FORMAT GU_PSM_8888 -#define PSP_FB_SW_FORMAT PSP_DISPLAY_PIXEL_FORMAT_8888 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_8888 #define PSP_FB_BPP 4 #endif @@ -84,12 +69,6 @@ static struct #endif void *draw_buffer; void *disp_buffer; - void *depth_buffer; -#if PSP_GU_STATIC_LIST - unsigned int gu_list[PSP_GU_LIST_SIZE] __attribute__( ( aligned( 64 ) ) ); -#else - unsigned int *gu_list; -#endif }vid_psp; qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b ) @@ -100,16 +79,16 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint * *b = 31 << 11; *bpp = 2; - vid_psp.draw_buffer = (void*)valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + vid_psp.draw_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); if( !vid_psp.draw_buffer ) Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); - vid_psp.disp_buffer = (void*)valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + vid_psp.disp_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); if( !vid_psp.disp_buffer ) Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT); - sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_SW_FORMAT, 1); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_FORMAT, 1); return true; } @@ -126,7 +105,7 @@ void SW_UnlockBuffer( void ) vid_psp.draw_buffer = p_swap; sceKernelDcacheWritebackInvalidateAll(); - sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_SW_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME); if ( vsync ) { @@ -134,146 +113,6 @@ void SW_UnlockBuffer( void ) } } -_inline void GU_Init( void ) -{ - vid_psp.draw_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); - if( !vid_psp.draw_buffer ) - Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); - - vid_psp.disp_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); - if( !vid_psp.disp_buffer ) - Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); - - vid_psp.depth_buffer = ( void* )valloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); - if( !vid_psp.depth_buffer ) - Host_Error( "Memory allocation failled! (vid_psp.depth_buffer)\n"); - -#if !PSP_GU_STATIC_LIST - vid_psp.gu_list = ( unsigned int* )valloc( PSP_GU_LIST_SIZE * sizeof ( unsigned int ) ); - if( !vid_psp.gu_list ) - Host_Error( "Memory allocation failled! (vid_psp.gu_list)\n"); -#endif - - // Initialise the GU. - sceGuInit(); - - // Set up the GU. - sceGuStart( GU_DIRECT, vid_psp.gu_list ); - - sceGuDrawBuffer( PSP_FB_HW_FORMAT, vrelptr( vid_psp.draw_buffer ), PSP_FB_BWIDTH); - sceGuDispBuffer( PSP_FB_WIDTH, PSP_FB_HEIGHT, vrelptr( vid_psp.disp_buffer ), PSP_FB_BWIDTH); - sceGuDepthBuffer( vrelptr( vid_psp.depth_buffer ), PSP_FB_BWIDTH); - - // Set the rendering offset and viewport. - sceGuOffset( 2048 - ( PSP_FB_WIDTH / 2 ), 2048 - ( PSP_FB_HEIGHT / 2 ) ); - sceGuViewport( 2048, 2048, PSP_FB_WIDTH, PSP_FB_HEIGHT ); - - // Set up scissoring. - sceGuEnable( GU_SCISSOR_TEST ); - sceGuScissor( 0, 0, PSP_FB_WIDTH, PSP_FB_HEIGHT ); - - // Set up texturing. - sceGuEnable( GU_TEXTURE_2D ); - - // Set up clearing. - sceGuClearDepth( 65535 ); - sceGuClearColor( GU_RGBA( 0x10, 0x20, 0x40, 0xff ) ); - - // Set up depth. - sceGuDepthOffset( 0 ); - sceGuDepthRange( 0, 65535 ); - sceGuDepthFunc( GU_LEQUAL ); - sceGuEnable( GU_DEPTH_TEST ); - - // Set up fog -// sceGuFog( 100.0f, 500.0f, 0xffffffff ); -// sceGuDisable( GU_FOG ); - - // Set the default matrices. - sceGumMatrixMode( GU_PROJECTION ); - sceGumLoadIdentity(); - sceGumMatrixMode( GU_VIEW ); - sceGumLoadIdentity(); - sceGumMatrixMode( GU_MODEL ); - sceGumLoadIdentity(); - sceGumMatrixMode( GU_TEXTURE ); - sceGumLoadIdentity(); - - sceGumUpdateMatrix(); - - // Set up culling. - sceGuFrontFace( GU_CW ); - sceGuEnable( GU_CULL_FACE ); - sceGuEnable( GU_CLIP_PLANES ); - - // Set up blending. - sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); - - sceGuFinish(); - sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); - - // Turn on the display. - sceDisplayWaitVblankStart(); - sceGuDisplay(GU_TRUE); - - // Start a new render. - sceGuStart( GU_DIRECT, vid_psp.gu_list ); - - Con_Printf( "Vram available: %i\n", vmemavail() ); -} - -_inline void GU_Shutdown( void ) -{ - // Finish rendering. - sceGuFinish(); - sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); - - // Shut down the display. - sceGuTerm(); - - // Free the buffers. - vfree( vid_psp.draw_buffer ); - vid_psp.draw_buffer = NULL; - vfree( vid_psp.disp_buffer ); - vid_psp.disp_buffer = NULL; - vfree( vid_psp.depth_buffer ); - vid_psp.depth_buffer = NULL; -#if !PSP_GU_STATIC_LIST - vfree( vid_psp.gu_list ); - vid_psp.gu_list = NULL; -#endif -} - -_inline void GU_SwapBuffers( void ) -{ -/* - // Don't forget writeback the cache - sceKernelDcacheWritebackAll(); -*/ - // Finish rendering. - size_t list_size = sceGuFinish(); -/* - if( list_size > sizeof( gu_list ) - 1000 ) - printf( "Display list size (%i) %i!\n", list_size, sizeof( gu_list ) ); -*/ - sceGuSync( GU_SYNC_FINISH, GU_SYNC_WHAT_DONE ); - - if ( vsync ) - { - sceDisplayWaitVblankStart(); - } - - // Swap the buffers. - sceGuSwapBuffers(); - - void* p_swap = vid_psp.disp_buffer; - vid_psp.disp_buffer = vid_psp.draw_buffer; - vid_psp.draw_buffer = p_swap; - - // Start a new render. - sceGuStart( GU_DIRECT, vid_psp.gu_list ); -} - int R_MaxVideoModes( void ) { return num_vidmodes; @@ -384,7 +223,7 @@ static qboolean VID_SetScreenResolution( int width, int height ) void GL_SwapBuffers( void ) { - GU_SwapBuffers(); + if ( vsync ) sceDisplayWaitVblankStart(); } int GL_SetAttribute( int attr, int val ) @@ -435,7 +274,6 @@ qboolean R_Init_Video( const int type ) case REF_GL: // refdll also can check extensions ref.dllFuncs.GL_InitExtensions(); - GU_Init(); break; case REF_SOFTWARE: default: @@ -530,8 +368,16 @@ void R_Free_Video( void ) R_FreeVideoModes(); #endif ref.dllFuncs.GL_ClearExtensions(); - if( !glw_state.software ) - GU_Shutdown(); + if( glw_state.software ) + { + if( vid_psp.draw_buffer ) + free( vid_psp.draw_buffer ); + if( vid_psp.disp_buffer ) + free( vid_psp.disp_buffer ); + + vid_psp.draw_buffer = NULL; + vid_psp.disp_buffer = NULL; + } } #endif // XASH_DEDICATED diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 20448df5..2066fdbd 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -15,7 +15,6 @@ GNU General Public License for more details. */ #include #include -#include "vram_psp.h" #include "gu_local.h" #include "crclib.h" @@ -251,26 +250,28 @@ GL_SetTextureDimensions */ static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height ) { - int maxTextureSize; - int stepWidth, stepHeight; + int maxTextureSize = glConfig.max_texture_size; + int step = (int)gl_round_down->value; + int scaled_width, scaled_height; Assert( tex != NULL ); - maxTextureSize = glConfig.max_texture_size; - // store original sizes tex->srcWidth = width; tex->srcHeight = height; -#if 0 // scale up - stepWidth = ( int )ceilf( logf( width ) * 1.0f / logf( 2.0f ) ); - stepHeight = ( int )ceilf( logf( height ) * 1.0f / logf( 2.0f ) ); -#else // scale down - stepWidth = ( int )floorf( logf( width ) * 1.0f / logf( 2.0f ) ); - stepHeight = ( int )floorf( logf( height ) * 1.0f / logf( 2.0f ) ); -#endif - width = ( 1 << stepWidth ); - height = ( 1 << stepHeight ); + for( scaled_width = 1; scaled_width < width; scaled_width <<= 1 ); + + if( step > 0 && width < scaled_width && ( step == 1 || ( scaled_width - width ) > ( scaled_width >> step ) ) ) + scaled_width >>= 1; + + for( scaled_height = 1; scaled_height < height; scaled_height <<= 1 ); + + if( step > 0 && height < scaled_height && ( step == 1 || ( scaled_height - height ) > ( scaled_height >> step ) ) ) + scaled_height >>= 1; + + width = scaled_width; + height = scaled_height; if( width > maxTextureSize || height > maxTextureSize ) { diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index e6930dd4..9064e367 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -16,11 +16,12 @@ GNU General Public License for more details. #ifndef GL_LOCAL_H #define GL_LOCAL_H -#if 1 + #include +#include #include #include -#endif + #include "port.h" #include "xash3d_types.h" #include "cvardef.h" @@ -40,6 +41,7 @@ GNU General Public License for more details. //#include "cvar.h" #include "gu_helper.h" #include "gu_extension.h" +#include "gu_vram.h" #include "wadfile.h" #ifndef offsetof @@ -686,18 +688,7 @@ void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ); typedef struct { int max_texture_size; - int color_bits; - int alpha_bits; - int depth_bits; - int stencil_bits; - - gl_context_type_t context; - gles_wrapper_t wrapper; - qboolean softwareGammaUpdate; - qboolean fCustomRenderer; - int prev_width; - int prev_height; } glconfig_t; typedef struct @@ -727,8 +718,23 @@ typedef struct qboolean extended; // extended context allows to GL_Debug } glwstate_t; +typedef struct +{ + int screen_width; + int screen_height; + int buffer_width; + int buffer_format; + int buffer_bpp; + void *draw_buffer; + void *disp_buffer; + void *depth_buffer; + void *context_list; + size_t context_list_size; +}gurender_t; + extern glconfig_t glConfig; extern glstate_t glState; +extern gurender_t guRender; // move to engine extern glwstate_t glw_state; extern ref_api_t gEngfuncs; @@ -751,11 +757,9 @@ extern cvar_t *gl_round_down; extern cvar_t *gl_detailscale; extern cvar_t *gl_wireframe; extern cvar_t *gl_depthoffset; -extern cvar_t *gl_finish; extern cvar_t *gl_nosort; extern cvar_t *gl_clear; extern cvar_t *gl_test; // cvar to testify new effects -extern cvar_t *gl_stencilbits; extern cvar_t *gl_subdivide_size; extern cvar_t *r_speeds; diff --git a/ref_gu/gu_init.c b/ref_gu/gu_render.c similarity index 69% rename from ref_gu/gu_init.c rename to ref_gu/gu_render.c index 1732d559..57312499 100644 --- a/ref_gu/gu_init.c +++ b/ref_gu/gu_render.c @@ -1,4 +1,18 @@ +/* +gu_render.c - render initialization +Copyright (C) 2010 Uncle Mike +Copyright (C) 2022 Sergey Galushko +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ #include "gu_local.h" cvar_t *gl_texture_lodfunc; @@ -12,12 +26,10 @@ cvar_t *gl_emboss_scale; cvar_t *gl_detailscale; cvar_t *gl_depthoffset; cvar_t *gl_wireframe; -cvar_t *gl_finish; cvar_t *gl_nosort; cvar_t *gl_vsync; cvar_t *gl_clear; cvar_t *gl_test; -cvar_t *gl_stencilbits; cvar_t *gl_subdivide_size; cvar_t *r_speeds; cvar_t *r_fullbright; @@ -54,6 +66,155 @@ gl_globals_t tr; glconfig_t glConfig; glstate_t glState; glwstate_t glw_state; +gurender_t guRender; + +// Set frame buffer +#define PSP_FB_WIDTH 480 +#define PSP_FB_HEIGHT 272 +#define PSP_FB_BWIDTH 512 +#define PSP_FB_FORMAT GU_PSM_5650 //4444,5551,5650,8888 + +#if PSP_FB_FORMAT == GU_PSM_4444 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == GU_PSM_5551 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == GU_PSM_5650 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == GU_PSM_8888 +#define PSP_FB_BPP 4 +#endif + +#define PSP_GU_LIST_SIZE 0x100000 // 1Mb + +static byte context_list[PSP_GU_LIST_SIZE] __attribute__( ( aligned( 64 ) ) ); + +/* +=============== +GU_Init +=============== +*/ +static void GU_Init( void ) +{ + memset( &guRender, 0, sizeof( guRender )); + + guRender.screen_width = PSP_FB_WIDTH; + guRender.screen_height = PSP_FB_HEIGHT; + guRender.buffer_width = PSP_FB_BWIDTH; + guRender.buffer_format = PSP_FB_FORMAT; + guRender.buffer_bpp = PSP_FB_BPP; + + guRender.draw_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp ); + if( !guRender.draw_buffer ) + gEngfuncs.Host_Error( "Memory allocation failled! (guRender.draw_buffer)\n" ); + + guRender.disp_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp ); + if( !guRender.disp_buffer ) + gEngfuncs.Host_Error( "Memory allocation failled! (guRender.disp_buffer)\n" ); + + guRender.depth_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp ); + if( !guRender.depth_buffer ) + gEngfuncs.Host_Error( "Memory allocation failled! (guRender.depth_buffer)\n" ); + + guRender.context_list = context_list; + guRender.context_list_size = sizeof( context_list ); + + // Initialise the GU. + sceGuInit(); + + // Set up the GU. + sceGuStart( GU_DIRECT, guRender.context_list ); + + sceGuDrawBuffer( guRender.buffer_format, vrelptr( guRender.draw_buffer ), guRender.buffer_width ); + sceGuDispBuffer( guRender.screen_width, guRender.screen_height, vrelptr( guRender.disp_buffer ), guRender.buffer_width ); + sceGuDepthBuffer( vrelptr( guRender.depth_buffer ), guRender.buffer_width ); + + // Set the rendering offset and viewport. + sceGuOffset( 2048 - ( guRender.screen_width / 2 ), 2048 - ( guRender.screen_height / 2 ) ); + sceGuViewport( 2048, 2048, guRender.screen_width, guRender.screen_height ); + + // Set up scissoring. + sceGuEnable( GU_SCISSOR_TEST ); + sceGuScissor( 0, 0, guRender.screen_width, guRender.screen_height ); + + // Xash default + sceGuClearColor( GU_COLOR( 0.5f, 0.5f, 0.5f, 1.0f ) ); + + sceGuDisable( GU_DEPTH_TEST ); + sceGuDisable( GU_CULL_FACE ); + sceGuEnable( GU_CLIP_PLANES ); + sceGuDepthFunc( GU_LEQUAL ); + sceGuColor( 0xffffffff ); + + // Set up stencil + if( glState.stencilEnabled ) + { + sceGuDisable( GU_STENCIL_TEST ); + /*pglStencilMask( ( GLuint ) ~0 );*/ // alpha color sceGuPixelMask + sceGuStencilFunc( GU_EQUAL, 0, ~0 ); + sceGuStencilOp( GU_KEEP, GU_INCR, GU_INCR ); + } + + sceGuDepthRange( 0, 65535 ); + sceGuDepthOffset( 0 ); + + sceGuDisable( GU_BLEND ); + sceGuDisable( GU_ALPHA_TEST ); + + sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); + sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); + sceGuEnable( GU_TEXTURE_2D ); + sceGuShadeModel( GU_SMOOTH ); + sceGuFrontFace( GU_CW ); // reversed + + // Set the default matrices. + sceGumMatrixMode( GU_PROJECTION ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_VIEW ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_MODEL ); + sceGumLoadIdentity(); + sceGumMatrixMode( GU_TEXTURE ); + sceGumLoadIdentity(); + + sceGumUpdateMatrix(); + + sceGuFinish(); + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT ); + + // Turn on the display. + sceDisplayWaitVblankStart(); + sceGuDisplay(GU_TRUE); + + // Start a new render. + sceGuStart( GU_DIRECT, guRender.context_list ); +} + +/* +=============== +GU_Shutdown +=============== +*/ +static void GU_Shutdown( void ) +{ + // Finish rendering. + sceGuFinish(); + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT ); + + // Shut down the display. + sceGuTerm(); + + // Free the buffers. + if( guRender.draw_buffer ) + vfree( guRender.draw_buffer ); + if( guRender.disp_buffer ) + vfree( guRender.disp_buffer ); + if( guRender.depth_buffer ) + vfree( guRender.depth_buffer ); + + guRender.draw_buffer = NULL; + guRender.disp_buffer = NULL; + guRender.depth_buffer = NULL; +} /* ============== @@ -88,46 +249,14 @@ static void GL_SetDefaultState( void ) glState.fogStart = 100.0f; glState.fogEnd = 1000.0f; } - +#if 0 /* =============== GL_SetDefaults =============== */ -static void GL_SetDefaults( void ) +static void GU_SetDefaults( void ) { -#if 1 -/* - sceGuFinish(); - sceGuSync(0,0); -*/ - sceGuClearColor( GU_COLOR( 0.5f, 0.5f, 0.5f, 1.0f ) ); - - sceGuDisable( GU_DEPTH_TEST ); - sceGuDisable( GU_CULL_FACE ); - //sceGuDisable( GU_SCISSOR_TEST ); - sceGuDepthFunc( GU_LEQUAL ); - sceGuColor( 0xffffffff ); - - if( glState.stencilEnabled ) - { - sceGuDisable( GU_STENCIL_TEST ); - /*pglStencilMask( ( GLuint ) ~0 );*/ - sceGuStencilFunc( GU_EQUAL, 0, ~0 ); - sceGuStencilOp( GU_KEEP, GU_INCR, GU_INCR ); - } - sceGuDepthOffset( 0 ); - - GL_CleanupAllTextureUnits(); - - sceGuDisable( GU_BLEND ); - sceGuDisable( GU_ALPHA_TEST ); - - sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); - sceGuEnable( GU_TEXTURE_2D ); - sceGuShadeModel( GU_SMOOTH ); - sceGuFrontFace( GU_CCW ); -#else pglFinish(); pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f ); @@ -161,10 +290,10 @@ static void GL_SetDefaults( void ) pglPointSize( 1.2f ); pglLineWidth( 1.2f ); -#endif + GL_Cull( GL_NONE ); } - +#endif /* ================= @@ -178,17 +307,11 @@ void R_RenderInfo_f( void ) gEngfuncs.Con_Printf( "MAX_TEXTURE_SIZE: %i\n", glConfig.max_texture_size ); gEngfuncs.Con_Printf( "MODE: %ix%i\n", gpGlobals->width, gpGlobals->height ); gEngfuncs.Con_Printf( "VERTICAL SYNC: %s\n", gl_vsync->value ? "enabled" : "disabled" ); - gEngfuncs.Con_Printf( "Color %d bits, Alpha %d bits, Depth %d bits, Stencil %d bits\n", glConfig.color_bits, - glConfig.alpha_bits, glConfig.depth_bits, glConfig.stencil_bits ); + gEngfuncs.Con_Printf( "VRAM AVAILABLE: %i\n", vmemavail() ); } void GL_InitExtensions( void ) { -// int colorBits[3]; - - glConfig.color_bits = 5 + 5 + 5; - glConfig.alpha_bits = 1; - glConfig.stencil_bits = ( int )gl_stencilbits->value; glState.stencilEnabled = true; glConfig.max_texture_size = 256; @@ -248,14 +371,12 @@ void GL_InitCommands( void ) gl_keeptjunctions = gEngfuncs.Cvar_Get( "gl_keeptjunctions", "1", FCVAR_GLCONFIG, "removing tjuncs causes blinking pixels" ); gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_GLCONFIG|FCVAR_LATCH, "fake bumpmapping scale" ); gl_showtextures = gEngfuncs.pfnGetCvarPointer( "r_showtextures", 0 ); - gl_finish = gEngfuncs.Cvar_Get( "gl_finish", "0", FCVAR_GLCONFIG, "use glFinish instead of glFlush" ); gl_nosort = gEngfuncs.Cvar_Get( "gl_nosort", "1", FCVAR_GLCONFIG, "disable sorting of translucent surfaces" ); gl_clear = gEngfuncs.pfnGetCvarPointer( "gl_clear", 0 ); gl_test = gEngfuncs.Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" ); gl_wireframe = gEngfuncs.Cvar_Get( "gl_wireframe", "0", FCVAR_GLCONFIG|FCVAR_SPONLY, "show wireframe overlay" ); - gl_stencilbits = gEngfuncs.Cvar_Get( "gl_stencilbits", "8", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "pixelformat stencil bits (0 - auto)" ); gl_subdivide_size = gEngfuncs.Cvar_Get( "gl_subdivide_size", "256.0", FCVAR_GLCONFIG, "the division value for the sky brushes" ); - gl_round_down = gEngfuncs.Cvar_Get( "gl_round_down", "2", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "round texture sizes to nearest POT value" ); + gl_round_down = gEngfuncs.Cvar_Get( "gl_round_down", "1", FCVAR_GLCONFIG, "round texture sizes to nearest POT value" ); // these cvar not used by engine but some mods requires this gl_depthoffset = gEngfuncs.Cvar_Get( "gl_depthoffset", "256.0", FCVAR_GLCONFIG, "depth offset for decals" ); @@ -313,7 +434,7 @@ qboolean R_Init( void ) r_temppool = Mem_AllocPool( "Render Zone" ); - GL_SetDefaults(); + GU_Init(); R_InitImages(); R_SpriteInit(); R_StudioInit(); @@ -336,6 +457,7 @@ void R_Shutdown( void ) GL_RemoveCommands(); R_ShutdownImages(); + GU_Shutdown(); Mem_FreePool( &r_temppool ); diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 9b5374e4..7c3a41ea 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -1091,11 +1091,7 @@ void R_BeginFrame( qboolean clearScene ) if(( gl_clear->value || ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) && clearScene && ENGINE_GET_PARM( PARM_CONNSTATE ) != ca_cinematic ) { -#if 1 sceGuClear( GU_COLOR_BUFFER_BIT ); -#else - pglClear( GL_COLOR_BUFFER_BIT ); -#endif } R_CheckGamma(); @@ -1157,10 +1153,6 @@ void R_RenderFrame( const ref_viewpass_t *rvp ) // setup the initial render params R_SetupRefParams( rvp ); -#if 0 - if( gl_finish->value && RI.drawWorld ) - pglFinish(); -#endif // completely override rendering if( gEngfuncs.drawFuncs->GL_RenderFrame != NULL ) @@ -1195,7 +1187,22 @@ void R_EndFrame( void ) { // flush any remaining 2D bits R_Set2DMode( false ); - gEngfuncs.GL_SwapBuffers(); + + // finish rendering. + sceGuFinish(); + sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT ); + + // swap the buffers. + sceGuSwapBuffers(); + + void* p_swap = guRender.disp_buffer; + guRender.disp_buffer = guRender.draw_buffer; + guRender.draw_buffer = p_swap; + + gEngfuncs.GL_SwapBuffers(); // vsync + + // start a new render. + sceGuStart( GU_DIRECT, guRender.context_list ); } /* diff --git a/engine/platform/psp/vram_psp.c b/ref_gu/gu_vram.c similarity index 99% rename from engine/platform/psp/vram_psp.c rename to ref_gu/gu_vram.c index a9a520dd..ee8ac5e8 100644 --- a/engine/platform/psp/vram_psp.c +++ b/ref_gu/gu_vram.c @@ -8,7 +8,7 @@ * Copyright (c) 2007 Alexander Berl 'Raphael' * http://wordpress.fx-world.org */ -#include "vram.h" +#include "gu_vram.h" #include // Configure the memory to be managed diff --git a/engine/platform/psp/vram_psp.h b/ref_gu/gu_vram.h similarity index 100% rename from engine/platform/psp/vram_psp.h rename to ref_gu/gu_vram.h diff --git a/ref_gu/vram_psp.h b/ref_gu/vram_psp.h deleted file mode 100644 index 0b974f99..00000000 --- a/ref_gu/vram_psp.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Helper for use with the PSP Software Development Kit - http://www.pspdev.org - * ----------------------------------------------------------------------- - * Licensed as 'free to use and modify as long as credited appropriately' - * - * vram.h - Standard C high performance VRAM allocation routines. - * - * Copyright (c) 2007 Alexander Berl 'Raphael' - * http://wordpress.fx-world.org - */ -#ifndef vram_h__ -#define vram_h__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void* vrelptr( void *ptr ); // make a pointer relative to memory base address (ATTENTION: A NULL rel ptr is not illegal/invalid!) -void* vabsptr( void *ptr ); // make a pointer absolute (default return type of valloc) - -void* valloc( size_t size ); -void vfree( void* ptr ); -size_t vmemavail(); -size_t vlargestblock(); - - -#ifdef _DEBUG -// Debug printf (to stdout) a trace of the current Memblocks -void __memwalk(); -#endif - - -#ifdef __cplusplus -} -#endif - -#endif // ifdef vram_h__ From 1d7176751ccb56b0d9609f84205432a063e5ec28 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 25 May 2022 16:56:53 +0300 Subject: [PATCH 23/84] ref_gu: pixel converter update --- ref_gu/gu_backend.c | 44 +++++++----- ref_gu/gu_image.c | 170 +++++++++++++++++++++++++++----------------- ref_gu/gu_local.h | 3 + 3 files changed, 136 insertions(+), 81 deletions(-) diff --git a/ref_gu/gu_backend.c b/ref_gu/gu_backend.c index b8c34cea..88c0ed2f 100644 --- a/ref_gu/gu_backend.c +++ b/ref_gu/gu_backend.c @@ -95,7 +95,7 @@ void GL_BackendEndFrame( void ) case 1: Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i wpoly, %3i apoly\n%3i epoly, %3i spoly", r_stats.c_world_polys, r_stats.c_alias_polys, r_stats.c_studio_polys, r_stats.c_sprite_polys ); - break; + break; case 2: R_Speeds_Printf( "visible leafs:\n%3i leafs\ncurrent leaf %3i\n", r_stats.c_world_leafs, curleaf - WORLDMODEL->leafs ); R_Speeds_Printf( "ReciusiveWorldNode: %3lf secs\nDrawTextureChains %lf\n", r_stats.t_world_node, r_stats.t_world_draw ); @@ -127,7 +127,7 @@ void GL_LoadTexMatrix( const matrix4x4 m ) sceGumMatrixMode( GU_TEXTURE ); GL_LoadMatrix( m ); sceGumUpdateMatrix(); - + glState.texIdentityMatrix = false; } @@ -143,7 +143,7 @@ void GL_LoadTexMatrixExt( const float *glmatrix ) sceGumMatrixMode( GU_TEXTURE ); sceGumLoadMatrix( ( const ScePspFMatrix4 * ) glmatrix ); sceGumUpdateMatrix(); - + glState.texIdentityMatrix = false; } @@ -169,11 +169,11 @@ void GL_LoadIdentityTexMatrix( void ) { if( glState.texIdentityMatrix ) return; - + sceGumMatrixMode( GU_TEXTURE ); - sceGumLoadIdentity(); + sceGumLoadIdentity(); sceGumUpdateMatrix(); - + glState.texIdentityMatrix = true; } @@ -282,7 +282,7 @@ void GL_Cull( GLenum cull ) void GL_SetRenderMode( int mode ) { sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); - + switch( mode ) { case kRenderNormal: @@ -343,25 +343,38 @@ const envmap_t r_envMapInfo[6] = {{ 90, 0, 90}, 0 } }; + + qboolean VID_ScreenShot( const char *filename, int shot_type ) { -#if 0 rgbdata_t *r_shot; - uint flags = IMAGE_FLIP_Y; + uint flags = 0; int width = 0, height = 0; qboolean result; + int bpp; r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t )); r_shot->width = (gpGlobals->width + 3) & ~3; r_shot->height = (gpGlobals->height + 3) & ~3; r_shot->flags = IMAGE_HAS_COLOR; r_shot->type = PF_RGB_24; - r_shot->size = r_shot->width * r_shot->height * gEngfuncs.Image_GetPFDesc( r_shot->type )->bpp; + bpp = gEngfuncs.Image_GetPFDesc( r_shot->type )->bpp; + r_shot->size = r_shot->width * r_shot->height * bpp; r_shot->palette = NULL; r_shot->buffer = Mem_Malloc( r_temppool, r_shot->size ); // get screen frame - pglReadPixels( 0, 0, r_shot->width, r_shot->height, GL_RGB, GL_UNSIGNED_BYTE, r_shot->buffer ); + byte *src = ( byte* )guRender.disp_buffer; + byte *dst = r_shot->buffer; + int cheight = r_shot->height; + + // stride copy + while( cheight-- ) + { + GL_PixelConverter( dst, src, r_shot->width, PC_HWF( guRender.buffer_format ), PC_SWF( r_shot->type ) ); + dst += r_shot->width * bpp; + src += guRender.buffer_width * guRender.buffer_bpp; + } switch( shot_type ) { @@ -403,9 +416,6 @@ qboolean VID_ScreenShot( const char *filename, int shot_type ) gEngfuncs.FS_FreeImage( r_shot ); return result; -#else - return 0; -#endif } /* @@ -507,7 +517,7 @@ was there. This is used to test for texture thrashing. */ void R_ShowTextures( void ) { -#if 0 +#if 0 gl_texture_t *image; float x, y, w, h; int total, start, end; @@ -609,7 +619,7 @@ rebuild_page: gEngfuncs.CL_DrawCenterPrint (); pglFinish(); -#endif +#endif } /* @@ -641,7 +651,7 @@ void SCR_TimeRefresh_f( void ) gpGlobals->viewangles[1] = i / 128.0f * 360.0f; R_RenderScene(); } -#if 0 +#if 0 pglFinish(); #endif R_EndFrame(); diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 2066fdbd..d69e22ac 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -617,91 +617,133 @@ static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, /* =============== GL_PixelConverter + +32 <-> 16 bit Image converter + +Macro for inFormat/outFormat: +PC_HWF - PSP Hardware format mask +PC_SWF - Xash3d Software format mask =============== */ -static void GL_PixelConverter( byte *dst, const byte *src, int size, qboolean alpha, int format ) +void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int outFormat ) { -#if 0 // undone - if(alpha) - { - __asm__ volatile ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "move $8, %0\n" // $8 = &dst[0] - "move $9, %1\n" // $9 = &src[0] - "move $10, %2\n" // $10 = size - "0:\n" - - "ulv.q C000, 0($8)\n" // Load 4 pixels from src - - "vt4444.q C010, C000\n" // Convert 4 -> 2 - - "sv.s S010, 0($9)\n" - "sv.s S010, 8($9)\n" - "addiu $8, $8, 16\n" // $8 = $8 + 16 - "addiu $9, $9, 8\n" // $9 = $9 + 8 - - "bne $10, $8, 0b\n" // if ( $11 != $8 ) jump to loop - "addiu $10, $10, -4\n" // $10 = $10 - 4 ( delay slot ) - ".set pop\n" // Restore assembler option - : "r"( dst ), "r"( src ), "r"( size ), "r"( format ) - : "$8", "$9", "$10" - ); - } - else - { - - } -#else int i; byte color[4]; + color[0] = color[1] = color[2] = color[3] = 0xff; + for( i = 0; i < size; i++ ) { - switch( format ) + // unpack + switch( inFormat ) { - case GU_PSM_4444: + case PC_HWF( GU_PSM_5650 ): + color[0] = ( *src & 0x1f ) << 3; + color[1] = ( *src & 0xe0 ) >> 3; src++; + color[1] |= ( *src & 0x07 ) << 5; + color[2] = ( *src & 0xf8 ); src++; + color[3] = 0xff; + break; + case PC_HWF( GU_PSM_5551 ): + color[0] = ( *src & 0x1f ) << 3; + color[1] = ( *src & 0xe0 ) >> 2; src++; + color[1] |= ( *src & 0x03 ) << 6; + color[2] = ( *src & 0x7c ) << 1; + color[3] = ( *src & 0x80 ) ? 0xff : 0x00; src++; + break; + case PC_HWF( GU_PSM_4444 ): + color[0] = ( *src & 0x0f ) << 4; + color[1] = ( *src & 0xf0 ); src++; + color[2] = ( *src & 0x0f ) << 4; + color[3] = ( *src & 0xf0 ); src++; + break; + case PC_SWF( PF_INDEXED_24 ): // palette !!! + case PC_SWF( PF_RGB_24 ): color[0] = *src; src++; color[1] = *src; src++; color[2] = *src; src++; - color[3] = alpha ? *src : 0xff; if( alpha ) src++; + color[3] = 0xff; + break; + case PC_SWF( PF_BGR_24 ): + color[2] = *src; src++; + color[1] = *src; src++; + color[0] = *src; src++; + color[3] = 0xff; + src += 3; + break; + case PC_SWF( PF_INDEXED_32 ): // palette !!! + case PC_SWF( PF_RGBA_32 ): + case PC_HWF( GU_PSM_8888 ): + color[0] = *src; src++; + color[1] = *src; src++; + color[2] = *src; src++; + color[3] = *src; src++; + break; + case PC_SWF( PF_BGRA_32 ): + color[2] = *src; src++; + color[1] = *src; src++; + color[0] = *src; src++; + color[3] = *src; src++; + break; + default: + gEngfuncs.Host_Error( "GL_PixelConverter: unknown input format\n"); + break; + } + + // pack + switch( outFormat ) + { + case PC_HWF( GU_PSM_5650 ): + *dst = ( color[0] >> 3 ) & 0x1f; + *dst |= ( color[1] << 3 ) & 0xe0; dst++; + *dst = ( color[1] >> 5 ) & 0x07; + *dst |= ( color[2] ) & 0xf8; dst++; + break; + case PC_HWF( GU_PSM_5551 ): + *dst = ( color[0] >> 3 ); + *dst |= ( color[1] << 2 ) & 0xe0; dst++; + *dst = ( color[1] >> 6 ) & 0x03; + *dst |= ( color[2] >> 1 ) & 0x7c; + *dst |= ( color[3] ) & 0x80; dst++; + break; + case PC_HWF( GU_PSM_4444 ): *dst = ( color[0] >> 4 ) & 0x0f; *dst |= ( color[1] ) & 0xf0; dst++; *dst = ( color[2] >> 4 ) & 0x0f; *dst |= ( color[3] ) & 0xf0; dst++; break; - case GU_PSM_5551: - color[0] = ( *src >> 3 ) & 0x1f; src++; - color[1] = ( *src >> 3 ) & 0x1f; src++; - color[2] = ( *src >> 3 ) & 0x1f; src++; - color[3] = alpha ? ( ( *src >> 7 ) & 0x01 ) : 0xff; if( alpha ) src++; - *dst = color[0]; - *dst |= ( color[1] << 5 ) & 0xe0; dst++; - *dst = ( color[1] >> 3 ) & 0x03; - *dst |= ( color[2] << 2 ) & 0x7c; - *dst |= ( color[3] << 7 ) & 0x80; dst++; + case PC_SWF( PF_INDEXED_24 ): // palette !!! + case PC_SWF( PF_RGB_24 ): + *dst = color[0]; dst++; + *dst = color[1]; dst++; + *dst = color[2]; dst++; break; - case GU_PSM_5650: - color[0] = ( *src >> 3 ) & 0x1f; src++; - color[1] = ( *src >> 2 ) & 0x3f; src++; - color[2] = ( *src >> 3 ) & 0x1f; src++; if( alpha ) src++; - *dst = color[0]; - *dst |= ( color[1] << 5 ) & 0xe0; dst++; - *dst = ( color[1] >> 3 ) & 0x07; - *dst |= ( color[2] << 3 ) & 0xf8; dst++; + case PC_SWF( PF_BGR_24 ): + *dst = color[2]; dst++; + *dst = color[1]; dst++; + *dst = color[0]; dst++; break; - case GU_PSM_8888: - *dst = *src; src++; dst++; - *dst = *src; src++; dst++; - *dst = *src; src++; dst++; - *dst = alpha ? *src : 0xff; if( alpha ) src++; dst++; + case PC_SWF( PF_INDEXED_32 ): // palette !!! + case PC_SWF( PF_RGBA_32 ): + case PC_HWF( GU_PSM_8888 ): + *dst = color[0]; dst++; + *dst = color[1]; dst++; + *dst = color[2]; dst++; + *dst = color[3]; dst++; + break; + case PC_SWF( PF_BGRA_32 ): + *dst = color[3]; dst++; + *dst = color[2]; dst++; + *dst = color[1]; dst++; + *dst = color[0]; dst++; break; default: + gEngfuncs.Host_Error( "GL_PixelConverter: unknown output format\n"); break; } } -#endif } + /* =============== GL_TextureSwizzle @@ -841,7 +883,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) } // Load palette - GL_PixelConverter( tex->dstPalette, pic->palette, 256, (pic->type == PF_INDEXED_32) ? true : false, PALETTE_FORMAT ); + GL_PixelConverter( tex->dstPalette, pic->palette, 256, PC_SWF( pic->type ), PC_HWF( PALETTE_FORMAT ) ); sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); // Load base + mip texture @@ -889,7 +931,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) // disable swizzling for lightmaps if ( IsLightMap( tex ) ) { - GL_PixelConverter( tex->dstTexture, volBuff, tex->width * tex->height, true, tex->format ); + GL_PixelConverter( tex->dstTexture, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); } else { @@ -897,7 +939,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if( !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) volBuff = GL_ApplyFilter( volBuff, tex->width, tex->height ); */ - GL_PixelConverter( volBuff + offset, volBuff, tex->width * tex->height, true, tex->format ); + GL_PixelConverter( volBuff + offset, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * 2, tex->height ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } @@ -989,7 +1031,7 @@ qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int dst += ( yoff * tex->width + xoff ) * 2; while( height-- ) { - GL_PixelConverter( dst, src, width, true, tex->format ); + GL_PixelConverter( dst, src, width, PC_SWF( PF_RGBA_32 ), PC_HWF( tex->format ) ); dst += tex->width * 2; src += width * 4; } diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 9064e367..6291e213 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -428,6 +428,9 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); int GL_LoadTextureArray( const char **names, int flags ); int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ); byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap ); +#define PC_SWF( X ) ( ( X ) | ( 1 << 15 ) ) +#define PC_HWF( X ) ( X ) +void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int outFormat ); int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ); int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ); void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); From 8e8a0e49087c79fb33fefdc13a7841b075122c5b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 26 May 2022 15:53:31 +0300 Subject: [PATCH 24/84] ref_gu: optimized sprites and particles --- ref_gu/gu_rpart.c | 72 ++++++++++++++++++++++------------------------ ref_gu/gu_sprite.c | 16 ++++++++++- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/ref_gu/gu_rpart.c b/ref_gu/gu_rpart.c index 095ebea2..3709834d 100644 --- a/ref_gu/gu_rpart.c +++ b/ref_gu/gu_rpart.c @@ -66,6 +66,10 @@ void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); sceGuDepthMask( GU_TRUE ); + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + unsigned int vert_size = 0; + unsigned int vert_color = 0; + for( p = cl_active_particles; p; p = p->next ) { if(( p->type != pt_blob ) || ( p->packedColor == 255 )) @@ -90,43 +94,37 @@ void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float alpha = 255 * (p->die - gpGlobals->time) * 16.0f; if( alpha > 255 || p->type == pt_static ) alpha = 255; - - sceGuColor( GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), + vert_color = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), gEngfuncs.LightToTexGamma( pColor->g ), - gEngfuncs.LightToTexGamma( pColor->b ), alpha ) ); + gEngfuncs.LightToTexGamma( pColor->b ), alpha ); - gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )sceGuGetMemory( sizeof( gu_vert_ftv_t ) * 4 ); - - out[0].u = 0.0f; - out[0].v = 1.0f; - out[0].x = p->org[0] - right[0] + up[0]; - out[0].y = p->org[1] - right[1] + up[1]; - out[0].z = p->org[2] - right[2] + up[2]; - out[1].u = 0.0f; - out[1].v = 0.0f; - out[1].x = p->org[0] + right[0] + up[0]; - out[1].y = p->org[1] + right[1] + up[1]; - out[1].z = p->org[2] + right[2] + up[2]; - out[2].u = 1.0f; - out[2].v = 0.0f; - out[2].x = p->org[0] + right[0] - up[0]; - out[2].y = p->org[1] + right[1] - up[1]; - out[2].z = p->org[2] + right[2] - up[2]; - out[3].u = 1.0f; - out[3].v = 1.0f; - out[3].x = p->org[0] - right[0] - up[0]; - out[3].y = p->org[1] - right[1] - up[1]; - out[3].z = p->org[2] - right[2] - up[2]; - - sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); + out[vert_size].u = 0.0f; + out[vert_size].v = 0.0f; + out[vert_size].c = vert_color; + out[vert_size].x = p->org[0] + right[0] + up[0]; + out[vert_size].y = p->org[1] + right[1] + up[1]; + out[vert_size].z = p->org[2] + right[2] + up[2]; + vert_size++; + out[vert_size].u = 1.0f; + out[vert_size].v = 1.0f; + out[vert_size].c = vert_color; + out[vert_size].x = p->org[0] - right[0] - up[0]; + out[vert_size].y = p->org[1] - right[1] - up[1]; + out[vert_size].z = p->org[2] - right[2] - up[2]; + vert_size++; r_stats.c_particle_count++; } gEngfuncs.CL_ThinkParticle( frametime, p ); } - - sceGuDepthMask( GU_FALSE ); + + if( vert_size ) + { + extGuEndPacket( ( void * )( out + vert_size ) ); + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); + } + sceGuDepthMask( GU_FALSE ); #else pglEnable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); @@ -211,7 +209,7 @@ static qboolean CL_CullTracer( particle_t *p, const vec3_t start, const vec3_t e mins[i] = end[i]; maxs[i] = start[i]; } - + // don't let it be zero sized if( mins[i] == maxs[i] ) { @@ -302,10 +300,10 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) VectorSubtract( normal, tmp2, normal ); // compute four vertexes - VectorSubtract( start, normal, verts[0] ); - VectorAdd( start, normal, verts[1] ); - VectorAdd( verts[0], delta, verts[2] ); - VectorAdd( verts[1], delta, verts[3] ); + VectorSubtract( start, normal, verts[0] ); + VectorAdd( start, normal, verts[1] ); + VectorAdd( verts[0], delta, verts[2] ); + VectorAdd( verts[1], delta, verts[3] ); if( p->color > sizeof( gTracerColors ) / sizeof( color24 ) ) { @@ -321,12 +319,12 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) out[0].u = 0.0f; out[0].v = 0.8f; - out[0].x = verts[2][0]; + out[0].x = verts[2][0]; out[0].y = verts[2][1]; - out[0].z = verts[2][2]; + out[0].z = verts[2][2]; out[1].u = 1.0f; out[1].v = 0.8f; - out[1].x = verts[3][0]; + out[1].x = verts[3][0]; out[1].y = verts[3][1]; out[1].z = verts[3][2]; out[2].u = 1.0f; diff --git a/ref_gu/gu_sprite.c b/ref_gu/gu_sprite.c index 1958ebaa..6b8fb918 100644 --- a/ref_gu/gu_sprite.c +++ b/ref_gu/gu_sprite.c @@ -732,7 +732,7 @@ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right, vec3_t point; r_stats.c_sprite_polys++; - +#if 0 gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); VectorMA( org, frame->down * scale, v_up, point ); VectorMA( point, frame->left * scale, v_right, point ); @@ -755,6 +755,20 @@ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right, out[3].uv[1] = 1.0f; VectorCopy( point, out[3].xyz ); sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); +#else + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 2 ); + VectorMA( org, frame->up * scale, v_up, point ); + VectorMA( point, frame->left * scale, v_right, point ); + out[0].uv[0] = 0.0f; + out[0].uv[1] = 0.0f; + VectorCopy( point, out[0].xyz ); + VectorMA( org, frame->down * scale, v_up, point ); + VectorMA( point, frame->right * scale, v_right, point ); + out[1].uv[0] = 1.0f; + out[1].uv[1] = 1.0f; + VectorCopy( point, out[1].xyz ); + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 2, 0, out ); +#endif } static qboolean R_SpriteHasLightmap( cl_entity_t *e, int texFormat ) From 6073e35bfcbffb937e98b7408ea0488a958d1d2a Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 27 May 2022 14:58:47 +0300 Subject: [PATCH 25/84] vid_psp.c: CRLF -> LF --- engine/platform/psp/vid_psp.c | 766 +++++++++++++++++----------------- 1 file changed, 383 insertions(+), 383 deletions(-) diff --git a/engine/platform/psp/vid_psp.c b/engine/platform/psp/vid_psp.c index 08438a84..c680aa71 100644 --- a/engine/platform/psp/vid_psp.c +++ b/engine/platform/psp/vid_psp.c @@ -1,384 +1,384 @@ -/* -vid_psp.c - PSP video component -Copyright (C) 2021 Sergey Galushko - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ -#if XASH_VIDEO == VIDEO_PSP - -#if !XASH_DEDICATED -#include -#include - -#include "common.h" -#include "client.h" -#include "mod_local.h" -#include "input.h" -#include "vid_common.h" - -// Set frame buffer -#define PSP_FB_WIDTH 480 -#define PSP_FB_HEIGHT 272 -#define PSP_FB_BWIDTH 512 -#define PSP_FB_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 //4444,5551,565,8888 - -#if PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_4444 -#define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_5551 -#define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_565 -#define PSP_FB_BPP 2 -#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_8888 -#define PSP_FB_BPP 4 -#endif - -#if 0 -// Set up screen scaling -#define PSP_WIDTH_AR 30 -#define PSP_HEIGHT_AR 17 -#define PSP_MIN_MAR 12 -#define PSP_MAX_MAR 16 -#define PSP_MIN_MAR_W (PSP_WIDTH_AR * PSP_MIN_MAR) -#define PSP_MIN_MAR_H (PSP_HEIGHT_AR * PSP_MIN_MAR) -#define PSP_MAX_MAR_W (PSP_WIDTH_AR * PSP_MAX_MAR) -#define PSP_MAX_MAR_H (PSP_HEIGHT_AR * PSP_MAX_MAR) -#endif - - -static qboolean vsync; -#if 1 -static vidmode_t vidmodes[] = { "480x272", PSP_FB_WIDTH, PSP_FB_HEIGHT}; -static int num_vidmodes = 1; -#else -static vidmode_t *vidmodes = NULL; -static int num_vidmodes = 0; -#endif -static struct -{ -#if 0 - int in_width, in_height; - int out_width, out_height; -#endif - void *draw_buffer; - void *disp_buffer; -}vid_psp; - -qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b ) -{ - *stride = PSP_FB_BWIDTH; - *r = 31; - *g = 63 << 5; - *b = 31 << 11; - *bpp = 2; - - vid_psp.draw_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); - if( !vid_psp.draw_buffer ) - Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); - - vid_psp.disp_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); - if( !vid_psp.disp_buffer ) - Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); - - sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT); - sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_FORMAT, 1); - - return true; -} - -void *SW_LockBuffer( void ) -{ - return vid_psp.draw_buffer; -} - -void SW_UnlockBuffer( void ) -{ - void* p_swap = vid_psp.disp_buffer; - vid_psp.disp_buffer = vid_psp.draw_buffer; - vid_psp.draw_buffer = p_swap; - - sceKernelDcacheWritebackInvalidateAll(); - sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME); - - if ( vsync ) - { - sceDisplayWaitVblankStart(); - } -} - -int R_MaxVideoModes( void ) -{ - return num_vidmodes; -} - -vidmode_t *R_GetVideoMode( int num ) -{ - if( !vidmodes || num < 0 || num >= R_MaxVideoModes() ) - { - return NULL; - } - - return vidmodes + num; -} -#if 0 -static void R_InitVideoModes( void ) -{ - int i; - - vidmodes = Mem_Malloc( host.mempool, (PSP_MAX_MAR - PSP_MIN_MAR) * sizeof( vidmode_t ) ); - - // from smallest to largest - for(i = PSP_MIN_MAR ; i <= PSP_MAX_MAR; i++ ) - { - vidmodes[num_vidmodes].width = PSP_WIDTH_AR * i; - vidmodes[num_vidmodes].height = PSP_HEIGHT_AR * i; - vidmodes[num_vidmodes].desc = - copystring( va( "%ix%i", vidmodes[num_vidmodes].width, vidmodes[num_vidmodes].height )); - - num_vidmodes++; - } -} - -static void R_FreeVideoModes( void ) -{ - int i; - - if(!vidmodes) - return; - - for( i = 0; i < num_vidmodes; i++ ) - Mem_Free( (char*)vidmodes[i].desc ); - Mem_Free( vidmodes ); - - vidmodes = NULL; -} -#endif -/* -================= -GL_GetProcAddress -================= -*/ -void *GL_GetProcAddress( const char *name ) -{ - return NULL; -} - -/* -=============== -GL_UpdateSwapInterval -=============== -*/ -void GL_UpdateSwapInterval( void ) -{ - // disable VSync while level is loading - if( cls.state < ca_active ) - { - // setup vsync here - vsync = false; - SetBits( gl_vsync->flags, FCVAR_CHANGED ); - } - else if( FBitSet( gl_vsync->flags, FCVAR_CHANGED )) - { - ClearBits( gl_vsync->flags, FCVAR_CHANGED ); - vsync = (gl_vsync->value > 0) ? true : false; - } -} - -static qboolean VID_SetScreenResolution( int width, int height ) -{ - int render_w = width, render_h = height; - uint rotate = vid_rotate->value; - - if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) ) - { - if( rotate & 1 ) - { - int swap = render_w; - - render_w = render_h; - render_h = swap; - } - - render_h /= vid_scale->value; - render_w /= vid_scale->value; - } - else - { - Con_Printf( S_WARN "failed to setup screen transform\n" ); - } - - - - R_SaveVideoMode( width, height, render_w, render_h ); - - return true; -} - -void GL_SwapBuffers( void ) -{ - if ( vsync ) sceDisplayWaitVblankStart(); -} - -int GL_SetAttribute( int attr, int val ) -{ - return 0; -} - -int GL_GetAttribute( int attr, int *val ) -{ - return 0; -} - -/* -================== -R_Init_Video -================== -*/ -qboolean R_Init_Video( const int type ) -{ - string safe; - qboolean retval; - - refState.desktopBitsPixel = ( PSP_FB_BPP * 8 ); - - VID_StartupGamma(); - - switch( type ) - { - case REF_SOFTWARE: - glw_state.software = true; - break; - case REF_GL: - if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) ) - glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE ); - break; - default: - Host_Error( "Can't initialize unknown context type %d!\n", type ); - break; - } - - if( !(retval = VID_SetMode()) ) - { - return retval; - } - - switch( type ) - { - case REF_GL: - // refdll also can check extensions - ref.dllFuncs.GL_InitExtensions(); - break; - case REF_SOFTWARE: - default: - break; - } -#if 0 - R_InitVideoModes(); -#endif - host.renderinfo_changed = false; - - return true; -} - -rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen ) -{ - Con_Reportf( "R_ChangeDisplaySettings: Setting video mode to %dx%d %s\n", width, height, fullscreen ? "fullscreen" : "windowed" ); - - refState.fullScreen = fullscreen; - - if( !VID_SetScreenResolution( width, height ) ) - return rserr_invalid_fullscreen; - - return rserr_ok; -} - -/* -================== -VID_SetMode - -Set the described video mode -================== -*/ -qboolean VID_SetMode( void ) -{ - qboolean fullscreen = false; - int iScreenWidth, iScreenHeight; - rserr_t err; - -#if 1 - iScreenWidth = PSP_FB_WIDTH; - iScreenHeight = PSP_FB_HEIGHT; -#else - vid_psp.out_width = PSP_FB_WIDTH; - vid_psp.out_height = PSP_FB_HEIGHT; - - iScreenWidth = Cvar_VariableInteger( "width" ); - iScreenHeight = Cvar_VariableInteger( "height" ); - - if( iScreenWidth < PSP_MIN_MAR_W || - iScreenHeight < PSP_MIN_MAR_H ) // trying to get resolution automatically by default - { - iScreenWidth = PSP_MIN_MAR_W; - iScreenHeight = PSP_MIN_MAR_H; - } - - if( iScreenWidth > PSP_MAX_MAR_W || - iScreenHeight > PSP_MAX_MAR_H ) // trying to get resolution automatically by default - { - iScreenWidth = PSP_MAX_MAR_W; - iScreenHeight = PSP_MAX_MAR_H; - } -#endif - if( !FBitSet( vid_fullscreen->flags, FCVAR_CHANGED ) ) - Cvar_SetValue( "fullscreen", DEFAULT_FULLSCREEN ); - else - ClearBits( vid_fullscreen->flags, FCVAR_CHANGED ); - - SetBits( gl_vsync->flags, FCVAR_CHANGED ); - fullscreen = true;//Cvar_VariableInteger("fullscreen") != 0; - - if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, fullscreen )) == rserr_ok ) - { -#if 0 - vid_psp.in_width = iScreenWidth; - vid_psp.in_height = iScreenHeight; -#endif - } - else - return false; - - return true; -} - -/* -================== -R_Free_Video -================== -*/ -void R_Free_Video( void ) -{ -#if 0 - R_FreeVideoModes(); -#endif - ref.dllFuncs.GL_ClearExtensions(); - if( glw_state.software ) - { - if( vid_psp.draw_buffer ) - free( vid_psp.draw_buffer ); - if( vid_psp.disp_buffer ) - free( vid_psp.disp_buffer ); - - vid_psp.draw_buffer = NULL; - vid_psp.disp_buffer = NULL; - } -} - -#endif // XASH_DEDICATED +/* +vid_psp.c - PSP video component +Copyright (C) 2021 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#if XASH_VIDEO == VIDEO_PSP + +#if !XASH_DEDICATED +#include +#include + +#include "common.h" +#include "client.h" +#include "mod_local.h" +#include "input.h" +#include "vid_common.h" + +// Set frame buffer +#define PSP_FB_WIDTH 480 +#define PSP_FB_HEIGHT 272 +#define PSP_FB_BWIDTH 512 +#define PSP_FB_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 //4444,5551,565,8888 + +#if PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_4444 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_5551 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_565 +#define PSP_FB_BPP 2 +#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_8888 +#define PSP_FB_BPP 4 +#endif + +#if 0 +// Set up screen scaling +#define PSP_WIDTH_AR 30 +#define PSP_HEIGHT_AR 17 +#define PSP_MIN_MAR 12 +#define PSP_MAX_MAR 16 +#define PSP_MIN_MAR_W (PSP_WIDTH_AR * PSP_MIN_MAR) +#define PSP_MIN_MAR_H (PSP_HEIGHT_AR * PSP_MIN_MAR) +#define PSP_MAX_MAR_W (PSP_WIDTH_AR * PSP_MAX_MAR) +#define PSP_MAX_MAR_H (PSP_HEIGHT_AR * PSP_MAX_MAR) +#endif + + +static qboolean vsync; +#if 1 +static vidmode_t vidmodes[] = { "480x272", PSP_FB_WIDTH, PSP_FB_HEIGHT}; +static int num_vidmodes = 1; +#else +static vidmode_t *vidmodes = NULL; +static int num_vidmodes = 0; +#endif +static struct +{ +#if 0 + int in_width, in_height; + int out_width, out_height; +#endif + void *draw_buffer; + void *disp_buffer; +}vid_psp; + +qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b ) +{ + *stride = PSP_FB_BWIDTH; + *r = 31; + *g = 63 << 5; + *b = 31 << 11; + *bpp = 2; + + vid_psp.draw_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.draw_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n"); + + vid_psp.disp_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP ); + if( !vid_psp.disp_buffer ) + Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); + + sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_FORMAT, 1); + + return true; +} + +void *SW_LockBuffer( void ) +{ + return vid_psp.draw_buffer; +} + +void SW_UnlockBuffer( void ) +{ + void* p_swap = vid_psp.disp_buffer; + vid_psp.disp_buffer = vid_psp.draw_buffer; + vid_psp.draw_buffer = p_swap; + + sceKernelDcacheWritebackInvalidateAll(); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME); + + if ( vsync ) + { + sceDisplayWaitVblankStart(); + } +} + +int R_MaxVideoModes( void ) +{ + return num_vidmodes; +} + +vidmode_t *R_GetVideoMode( int num ) +{ + if( !vidmodes || num < 0 || num >= R_MaxVideoModes() ) + { + return NULL; + } + + return vidmodes + num; +} +#if 0 +static void R_InitVideoModes( void ) +{ + int i; + + vidmodes = Mem_Malloc( host.mempool, (PSP_MAX_MAR - PSP_MIN_MAR) * sizeof( vidmode_t ) ); + + // from smallest to largest + for(i = PSP_MIN_MAR ; i <= PSP_MAX_MAR; i++ ) + { + vidmodes[num_vidmodes].width = PSP_WIDTH_AR * i; + vidmodes[num_vidmodes].height = PSP_HEIGHT_AR * i; + vidmodes[num_vidmodes].desc = + copystring( va( "%ix%i", vidmodes[num_vidmodes].width, vidmodes[num_vidmodes].height )); + + num_vidmodes++; + } +} + +static void R_FreeVideoModes( void ) +{ + int i; + + if(!vidmodes) + return; + + for( i = 0; i < num_vidmodes; i++ ) + Mem_Free( (char*)vidmodes[i].desc ); + Mem_Free( vidmodes ); + + vidmodes = NULL; +} +#endif +/* +================= +GL_GetProcAddress +================= +*/ +void *GL_GetProcAddress( const char *name ) +{ + return NULL; +} + +/* +=============== +GL_UpdateSwapInterval +=============== +*/ +void GL_UpdateSwapInterval( void ) +{ + // disable VSync while level is loading + if( cls.state < ca_active ) + { + // setup vsync here + vsync = false; + SetBits( gl_vsync->flags, FCVAR_CHANGED ); + } + else if( FBitSet( gl_vsync->flags, FCVAR_CHANGED )) + { + ClearBits( gl_vsync->flags, FCVAR_CHANGED ); + vsync = (gl_vsync->value > 0) ? true : false; + } +} + +static qboolean VID_SetScreenResolution( int width, int height ) +{ + int render_w = width, render_h = height; + uint rotate = vid_rotate->value; + + if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) ) + { + if( rotate & 1 ) + { + int swap = render_w; + + render_w = render_h; + render_h = swap; + } + + render_h /= vid_scale->value; + render_w /= vid_scale->value; + } + else + { + Con_Printf( S_WARN "failed to setup screen transform\n" ); + } + + + + R_SaveVideoMode( width, height, render_w, render_h ); + + return true; +} + +void GL_SwapBuffers( void ) +{ + if ( vsync ) sceDisplayWaitVblankStart(); +} + +int GL_SetAttribute( int attr, int val ) +{ + return 0; +} + +int GL_GetAttribute( int attr, int *val ) +{ + return 0; +} + +/* +================== +R_Init_Video +================== +*/ +qboolean R_Init_Video( const int type ) +{ + string safe; + qboolean retval; + + refState.desktopBitsPixel = ( PSP_FB_BPP * 8 ); + + VID_StartupGamma(); + + switch( type ) + { + case REF_SOFTWARE: + glw_state.software = true; + break; + case REF_GL: + if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) ) + glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE ); + break; + default: + Host_Error( "Can't initialize unknown context type %d!\n", type ); + break; + } + + if( !(retval = VID_SetMode()) ) + { + return retval; + } + + switch( type ) + { + case REF_GL: + // refdll also can check extensions + ref.dllFuncs.GL_InitExtensions(); + break; + case REF_SOFTWARE: + default: + break; + } +#if 0 + R_InitVideoModes(); +#endif + host.renderinfo_changed = false; + + return true; +} + +rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen ) +{ + Con_Reportf( "R_ChangeDisplaySettings: Setting video mode to %dx%d %s\n", width, height, fullscreen ? "fullscreen" : "windowed" ); + + refState.fullScreen = fullscreen; + + if( !VID_SetScreenResolution( width, height ) ) + return rserr_invalid_fullscreen; + + return rserr_ok; +} + +/* +================== +VID_SetMode + +Set the described video mode +================== +*/ +qboolean VID_SetMode( void ) +{ + qboolean fullscreen = false; + int iScreenWidth, iScreenHeight; + rserr_t err; + +#if 1 + iScreenWidth = PSP_FB_WIDTH; + iScreenHeight = PSP_FB_HEIGHT; +#else + vid_psp.out_width = PSP_FB_WIDTH; + vid_psp.out_height = PSP_FB_HEIGHT; + + iScreenWidth = Cvar_VariableInteger( "width" ); + iScreenHeight = Cvar_VariableInteger( "height" ); + + if( iScreenWidth < PSP_MIN_MAR_W || + iScreenHeight < PSP_MIN_MAR_H ) // trying to get resolution automatically by default + { + iScreenWidth = PSP_MIN_MAR_W; + iScreenHeight = PSP_MIN_MAR_H; + } + + if( iScreenWidth > PSP_MAX_MAR_W || + iScreenHeight > PSP_MAX_MAR_H ) // trying to get resolution automatically by default + { + iScreenWidth = PSP_MAX_MAR_W; + iScreenHeight = PSP_MAX_MAR_H; + } +#endif + if( !FBitSet( vid_fullscreen->flags, FCVAR_CHANGED ) ) + Cvar_SetValue( "fullscreen", DEFAULT_FULLSCREEN ); + else + ClearBits( vid_fullscreen->flags, FCVAR_CHANGED ); + + SetBits( gl_vsync->flags, FCVAR_CHANGED ); + fullscreen = true;//Cvar_VariableInteger("fullscreen") != 0; + + if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, fullscreen )) == rserr_ok ) + { +#if 0 + vid_psp.in_width = iScreenWidth; + vid_psp.in_height = iScreenHeight; +#endif + } + else + return false; + + return true; +} + +/* +================== +R_Free_Video +================== +*/ +void R_Free_Video( void ) +{ +#if 0 + R_FreeVideoModes(); +#endif + ref.dllFuncs.GL_ClearExtensions(); + if( glw_state.software ) + { + if( vid_psp.draw_buffer ) + free( vid_psp.draw_buffer ); + if( vid_psp.disp_buffer ) + free( vid_psp.disp_buffer ); + + vid_psp.draw_buffer = NULL; + vid_psp.disp_buffer = NULL; + } +} + +#endif // XASH_DEDICATED #endif // XASH_VIDEO \ No newline at end of file From 8071355d6847b219cee36cf68023ebc398bea71a Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 27 May 2022 15:00:30 +0300 Subject: [PATCH 26/84] ref_soft: framebuffer width fix --- engine/platform/psp/vid_psp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/platform/psp/vid_psp.c b/engine/platform/psp/vid_psp.c index c680aa71..d14f37e8 100644 --- a/engine/platform/psp/vid_psp.c +++ b/engine/platform/psp/vid_psp.c @@ -88,7 +88,7 @@ qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint * Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n"); sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT); - sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_WIDTH, PSP_FB_FORMAT, 1); + sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, 1); return true; } From c07c1357e5880bc21ec344c79eaaa0e8e9a857c7 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 27 May 2022 15:11:38 +0300 Subject: [PATCH 27/84] platform: buttons layout update --- engine/client/console.c | 20 ++++++++++++++++++-- engine/client/keys.c | 26 ++++++++++++++++++++++++++ engine/platform/psp/in_psp.c | 2 +- mainui | 2 +- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/engine/client/console.c b/engine/client/console.c index 1cfe1277..89f85a2d 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1508,7 +1508,11 @@ void Field_KeyDownEvent( field_t *edit, int key ) return; } +#if XASH_PSP + if( key == K_BACKSPACE || key == K_X_BUTTON ) +#else if( key == K_BACKSPACE ) +#endif { if( edit->cursor > 0 ) { @@ -1718,7 +1722,11 @@ void Key_Console( int key ) } // enter finishes the line +#if XASH_PSP + if( key == K_ENTER || key == K_KP_ENTER || key == K_A_BUTTON ) +#else if( key == K_ENTER || key == K_KP_ENTER ) +#endif { // if not in the game explicitly prepent a slash if needed if( cls.state != ca_active && con.input.buffer[0] != '\\' && con.input.buffer[0] != '/' ) @@ -1789,7 +1797,7 @@ void Key_Console( int key ) // console scrolling #if XASH_PSP - if( key == K_JOY2 ) + if( key == K_PGUP || key == K_R1_BUTTON ) #else if( key == K_PGUP ) #endif @@ -1798,7 +1806,7 @@ void Key_Console( int key ) return; } #if XASH_PSP - if( key == K_JOY1 ) + if( key == K_PGDN || key == K_L1_BUTTON ) #else if( key == K_PGDN ) #endif @@ -1852,14 +1860,22 @@ void Key_Message( int key ) { char buffer[MAX_SYSPATH]; +#if XASH_PSP + if( key == K_ESCAPE || key == K_START_BUTTON ) +#else if( key == K_ESCAPE ) +#endif { Key_SetKeyDest( key_game ); Con_ClearField( &con.chat ); return; } +#if XASH_PSP + if( key == K_ENTER || key == K_KP_ENTER || key == K_A_BUTTON ) +#else if( key == K_ENTER || key == K_KP_ENTER ) +#endif { if( con.chat.buffer[0] && cls.state == ca_active ) { diff --git a/engine/client/keys.c b/engine/client/keys.c index c941b286..0bb61e6c 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -106,7 +106,11 @@ keyname_t keynames[] = {"R1_BUTTON", K_R1_BUTTON, ""}, {"BACK", K_BACK_BUTTON, ""}, {"MODE", K_MODE_BUTTON, ""}, +#if XASH_PSP +{"START", K_START_BUTTON, "escape"}, // hardcoded +#else {"START", K_START_BUTTON, ""}, +#endif {"STICK1", K_LSTICK, ""}, {"STICK2", K_RSTICK, ""}, {"L2_BUTTON", K_L2_BUTTON, ""}, // in case... @@ -380,6 +384,9 @@ void Key_Unbindall_f( void ) // set some defaults Key_SetBinding( K_ESCAPE, "escape" ); +#if XASH_PSP + Key_SetBinding( K_START_BUTTON, "escape" ); +#endif } /* @@ -714,7 +721,11 @@ void GAME_EXPORT Key_Event( int key, int down ) Touch_KeyEvent( key, down ); // console key is hardcoded, so the user can never unbind it +#if XASH_PSP + if( key == '`' || key == '~' || key == K_MODE_BUTTON ) +#else if( key == '`' || key == '~' ) +#endif { // we are in typing mode, so don't switch to console if( cls.key_dest == key_message || !down ) @@ -725,7 +736,11 @@ void GAME_EXPORT Key_Event( int key, int down ) } // escape is always handled special +#if XASH_PSP + if( ( key == K_ESCAPE || key == K_START_BUTTON ) && down ) +#else if( key == K_ESCAPE && down ) +#endif { switch( cls.key_dest ) { @@ -890,7 +905,11 @@ Normal keyboard characters, already shifted / capslocked / etc void CL_CharEvent( int key ) { // the console key should never be used as a char +#if XASH_PSP + if( key == '`' || key == '~' || key == K_MODE_BUTTON ) return; +#else if( key == '`' || key == '~' ) return; +#endif if( cls.key_dest == key_console && !Con_Visible( )) { @@ -1015,7 +1034,11 @@ static qboolean OSK_KeyEvent( int key, int down ) if( osk.curbutton.val == 0 ) { +#if XASH_PSP + if( key == K_ENTER || key == K_A_BUTTON ) +#else if( key == K_ENTER ) +#endif { osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x]; return true; @@ -1026,6 +1049,9 @@ static qboolean OSK_KeyEvent( int key, int down ) switch ( key ) { +#if XASH_PSP + case K_A_BUTTON: +#endif case K_ENTER: switch( osk.curbutton.val ) { diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c index 34a04fd2..dcd5e1a2 100644 --- a/engine/platform/psp/in_psp.c +++ b/engine/platform/psp/in_psp.c @@ -31,7 +31,7 @@ static struct psp_keymap_s int dstkey; }psp_keymap[] = { -#if 1 +#if 0 { PSP_CTRL_SELECT, '~' }, { PSP_CTRL_START, K_ESCAPE }, { PSP_CTRL_UP, K_UPARROW }, diff --git a/mainui b/mainui index 37e4c7cb..0cd109c0 160000 --- a/mainui +++ b/mainui @@ -1 +1 @@ -Subproject commit 37e4c7cb817403f59edb9babbfdf3435ea2ba1ab +Subproject commit 0cd109c0463c1d5fd4f84055fa4f21e49f2d901f From d35330cd557cce7a6c4f08f359ec55001989f842 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 1 Jun 2022 14:55:43 +0300 Subject: [PATCH 28/84] psp: enabled console background image --- engine/client/console.c | 2 +- mainui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/client/console.c b/engine/client/console.c index 89f85a2d..bafbcfb6 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -2394,7 +2394,7 @@ void Con_VidInit( void ) { Con_LoadConchars(); Con_CheckResize(); -#if XASH_LOW_MEMORY +#if XASH_LOW_MEMORY && !XASH_PSP con.background = R_GetBuiltinTexture( REF_BLACK_TEXTURE ); #else // loading console image diff --git a/mainui b/mainui index 0cd109c0..5ad02202 160000 --- a/mainui +++ b/mainui @@ -1 +1 @@ -Subproject commit 0cd109c0463c1d5fd4f84055fa4f21e49f2d901f +Subproject commit 5ad0220211016dbb9535e2d637377f161aa32a25 From 1e132bf29ef280f6f56d270f1800d839e58f9ab1 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 1 Jun 2022 16:16:51 +0300 Subject: [PATCH 29/84] ref_gu: added rgb 332 format; changeable output format in R_BuildLightMap --- common/com_image.h | 6 + ref_gu/gu_image.c | 352 +++++++++++++++++++++++++++------------------ ref_gu/gu_local.h | 18 ++- ref_gu/gu_rsurf.c | 64 +++++++-- 4 files changed, 284 insertions(+), 156 deletions(-) diff --git a/common/com_image.h b/common/com_image.h index e5182d38..32569733 100644 --- a/common/com_image.h +++ b/common/com_image.h @@ -21,6 +21,12 @@ typedef enum PF_BGRA_32, // big endian RGBA (MacOS) PF_RGB_24, // uncompressed dds or another 24-bit image PF_BGR_24, // big-endian RGB (MacOS) +#if XASH_PSP + PF_RGB_332, // 8-bit R3 G3 B2 + PF_RGB_5650, // 16-bit R5 G6 B5 + PF_RGBA_5551, // 16-bit R5 G5 B5 A1 + PF_RGBA_4444, // 16-bit R4 G4 B4 A4 +#endif PF_LUMINANCE, PF_DXT1, // s3tc DXT1 format PF_DXT3, // s3tc DXT3 format diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index d69e22ac..b00cc9b9 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -22,24 +22,25 @@ GNU General Public License for more details. static gl_texture_t gl_textures[MAX_TEXTURES]; static gl_texture_t* gl_texturesHashTable[TEXTURES_HASH_SIZE]; -static uint gl_numTextures; +static uint gl_numTextures; +static byte *palette_332 = NULL; /* num_colors = PALETTE_BLOCKS x 16 (16-bit CLUT) num_colors = PALETTE_BLOCKS x 8 (32-bit CLUT) */ -#define PALETTE_FORMAT GU_PSM_4444 +#define PALETTE_FORMAT GU_PSM_4444 #if (PALETTE_FORMAT == GU_PSM_4444) || (PALETTE_FORMAT == GU_PSM_5551) || (PALETTE_FORMAT == GU_PSM_5650) -#define PALETTE_SIZE 2 * 256 -#define PALETTE_BLOCKS 16 +#define PALETTE_SIZE 2 * 256 +#define PALETTE_BLOCKS 16 #elif PALETTE_FORMAT == GU_PSM_8888 -#define PALETTE_SIZE 4 * 256 -#define PALETTE_BLOCKS 32 +#define PALETTE_SIZE 4 * 256 +#define PALETTE_BLOCKS 32 #else #error Current PALETTE_FORMAT not supported! #endif -#define TEXTURE_SIZE_MIN 16 //8 +#define TEXTURE_SIZE_MIN 16 #define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE )) @@ -80,10 +81,10 @@ void GL_Bind( GLint tmu, GLenum texnum ) texture = &gl_textures[texnum]; // Set palette - if( texture->format == GU_PSM_T8 && texture->dstPalette ) + if( texture->format == GU_PSM_T8 ) { sceGuClutMode( PALETTE_FORMAT, 0, 0xff, 0 ); - sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ); + sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ? texture->dstPalette : palette_332 ); } // Set texture parameters @@ -118,13 +119,13 @@ void GL_Bind( GLint tmu, GLenum texnum ) // Set mip textures if( texture->numMips > 1 ) { - offset = texture->width * texture->height; + offset = texture->width * texture->height * texture->bpp; for ( i = 1; i < texture->numMips; i++ ) { width = Q_max( TEXTURE_SIZE_MIN, ( texture->width >> i ) ); height = Q_max( TEXTURE_SIZE_MIN, ( texture->height >> i ) ); sceGuTexImage( i, width, height, width, &texture->dstTexture[offset] ); - offset += width * height; + offset += width * height * texture->bpp; } } glState.currentTexture = texnum; @@ -147,8 +148,14 @@ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int d case PF_INDEXED_24: case PF_INDEXED_32: case PF_LUMINANCE: + case PF_RGB_332: size = width * height * depth; break; + case PF_RGB_5650: + case PF_RGBA_5551: + case PF_RGBA_4444: + size = width * height * depth * 2; + break; case PF_RGB_24: case PF_BGR_24: size = width * height * depth * 3; @@ -175,9 +182,10 @@ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int d GL_CalcTextureSize ================== */ -static size_t GL_CalcTextureSize( int format, int width, int height ) +static size_t GL_CalcTextureSize( int format, int width, int height, byte *outBpp ) { size_t size = 0; + byte bpp = 0; switch( format ) { @@ -188,29 +196,35 @@ static size_t GL_CalcTextureSize( int format, int width, int height ) case GU_PSM_T8: case GU_PSM_DXT3: case GU_PSM_DXT5: + bpp = 1; size = width * height; break; case GU_PSM_T16: case GU_PSM_4444: case GU_PSM_5551: case GU_PSM_5650: + bpp = 2; size = width * height * 2; break; case GU_PSM_T32: case GU_PSM_8888: + bpp = 4; size = width * height * 4; break; default: gEngfuncs.Host_Error( "GL_CalcTextureSize: bad texture internal format (%u)\n", format ); break; } + + if(outBpp != NULL) *outBpp = bpp; + return size; } -static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *mipsize ) +static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *mipSize ) { int width, height; - int mipcount; + int mipCount; Assert( tex != NULL ); @@ -228,19 +242,19 @@ static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *m return 1; // 8 levels - 7 + 1 base - for( mipcount = 1; mipcount < 8; mipcount++ ) + for( mipCount = 1; mipCount < 8; mipCount++ ) { - width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> mipcount ) ); - height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> mipcount ) ); + width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> mipCount ) ); + height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> mipCount ) ); if( width == TEXTURE_SIZE_MIN && height == TEXTURE_SIZE_MIN ) break; // calc without base size - if( mipsize != NULL ) - *mipsize += GL_CalcTextureSize( tex->format, width, height ); + if( mipSize != NULL ) + *mipSize += GL_CalcTextureSize( tex->format, width, height, NULL ); } - return mipcount; + return mipCount; } /* @@ -299,17 +313,47 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan Assert( tex != NULL ); - if( ImageDXT( format ) ) + switch( format ) { - switch( format ) - { - case PF_DXT1: tex->format = GU_PSM_DXT1; break; // never use DXT1 with 1-bit alpha - case PF_DXT3: tex->format = GU_PSM_DXT3; break; - case PF_DXT5: tex->format = GU_PSM_DXT5; break; - } + case PF_DXT1: // never use DXT1 with 1-bit alpha + tex->format = GU_PSM_DXT1; + break; + case PF_DXT3: + tex->format = GU_PSM_DXT3; + break; + case PF_DXT5: + tex->format = GU_PSM_DXT5; + break; + case PF_INDEXED_24: + case PF_INDEXED_32: + case PF_RGB_332: + tex->format = GU_PSM_T8; + break; + case PF_RGB_5650: + tex->format = GU_PSM_5650; + break; + case PF_RGBA_5551: + tex->format = GU_PSM_5551; + break; + case PF_RGBA_4444: + tex->format = GU_PSM_4444; + break; + case PF_RGBA_32: + case PF_BGRA_32: + case PF_RGB_24: + case PF_BGR_24: + if ( IsLightMap( tex ) ) + tex->format = GU_PSM_8888; + else if( haveAlpha ) + tex->format = GU_PSM_4444; + else + tex->format = GU_PSM_T8; // rgb332 + break; + default: + gEngfuncs.Host_Error( "GL_SetTextureFormat: unknown format %i\n", format ); + break; } - /* - else if( FBitSet( tex->flags, TF_DEPTHMAP )) + /*if( FBitSet( tex->flags, TF_DEPTHMAP )) { if( FBitSet( tex->flags, TF_ARB_16BIT )) tex->format = GL_DEPTH_COMPONENT16; @@ -317,19 +361,6 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan tex->format = GL_DEPTH_COMPONENT32F; else tex->format = GL_DEPTH_COMPONENT24; }*/ - else if( ImageIND( format ) ) - { - tex->format = GU_PSM_T8; - } - else - { - if ( IsLightMap( tex ) ) - tex->format = GU_PSM_5650; - else if( haveAlpha ) - tex->format = GU_PSM_4444; - else - tex->format = GU_PSM_5650; - } } /* @@ -693,6 +724,11 @@ void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int // pack switch( outFormat ) { + case PC_HWF( GU_PSM_T8 ): // 332, indexing + *dst = ( color[0] >> 5 ) & 0x07; + *dst |= ( color[1] >> 2 ) & 0x38; + *dst |= ( color[2] ) & 0xc0; dst++; + break; case PC_HWF( GU_PSM_5650 ): *dst = ( color[0] >> 3 ) & 0x1f; *dst |= ( color[1] << 3 ) & 0xe0; dst++; @@ -794,8 +830,9 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) size_t texSize; uint width, height; uint i; - uint offset; + uint offset, mipOffset; qboolean normalMap; + qboolean swizzle; void *volBuff; unsigned int volSize; int volUid; @@ -826,14 +863,16 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) // Prepare sizes offset = GL_CalcImageSize( pic->type, pic->width, pic->height, /* pic->depth */ 1 ); - texSize = GL_CalcTextureSize( tex->format, tex->width, tex->height ); + texSize = GL_CalcTextureSize( tex->format, tex->width, tex->height, &tex->bpp ); normalMap = FBitSet( tex->flags, TF_NORMALMAP ) ? true : false; - tex->numMips = ImageIND( pic->type ) ? GL_CalcMipmapCount( tex, ( pic->buffer != NULL ), &texSize) : 1; + tex->numMips = ImageIND( pic->type ) ? GL_CalcMipmapCount( tex, ( pic->buffer != NULL ), &texSize ) : 1; + swizzle = IsLightMap( tex ) ? false : true; + mipOffset = 0; // Volatile memory for temporary buffer volUid = sceKernelVolatileMemLock( 0, &volBuff, &volSize ); if( volUid != 0) - gEngfuncs.Host_Error( "GL_AllocTexture: volatile memory lock error 0x%08x ! \n", volUid); + gEngfuncs.Host_Error( "GL_UploadTexture: volatile memory lock error ( 0x%08x )\n", volUid ); // Check allocation size if( tex->dstTexture && ( tex->size != texSize ) ) @@ -857,94 +896,100 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if ( !tex->dstTexture ) { sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( texture: %lu %s )\n", texSize, tex->name); + gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for texture ( %lu )\n", tex->name, texSize ); } } - else - { - SetBits( tex->flags, TF_IMG_INVRAM ); - } + else SetBits( tex->flags, TF_IMG_INVRAM ); } if( ImageDXT( pic->type ) ) { memcpy( tex->dstTexture, pic->buffer, texSize ); } - else if( ImageIND( pic->type ) ) + else if( ImageIND( pic->type ) || pic->type == PF_RGB_332 ) { - if( !tex->dstPalette ) + if( pic->type != PF_RGB_332 ) { - tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !tex->dstPalette ) + if( !tex->dstPalette ) { - sceKernelVolatileMemUnlock( 0 ); - gEngfuncs.Host_Error( "GL_AllocTexture: out of memory! ( palette: %s )\n", tex->name); + tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !tex->dstPalette ) + { + sceKernelVolatileMemUnlock( 0 ); + gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for palette ( %lu )\n", tex->name, PALETTE_SIZE ); + } } + + // Load palette + GL_PixelConverter( tex->dstPalette, pic->palette, 256, PC_SWF( pic->type ), PC_HWF( PALETTE_FORMAT ) ); + sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); } - // Load palette - GL_PixelConverter( tex->dstPalette, pic->palette, 256, PC_SWF( pic->type ), PC_HWF( PALETTE_FORMAT ) ); - sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); - // Load base + mip texture - int mip_offset = 0; for( i = 0; i < tex->numMips; i++ ) { width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> i ) ); height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> i ) ); if( ( pic->width != width ) || ( pic->height != height ) ) - GL_ResampleTexture8( pic->buffer, pic->width, pic->height, volBuff, width, height ); - else memcpy(volBuff, pic->buffer, offset); + GL_ResampleTexture8( pic->buffer, pic->width, pic->height, swizzle ? volBuff : ( tex->dstTexture + mipOffset ), width, height ); + else memcpy( swizzle ? volBuff : ( tex->dstTexture + mipOffset ), pic->buffer, offset ); - GL_TextureSwizzle( tex->dstTexture + mip_offset, volBuff, width, height ); - mip_offset += GL_CalcTextureSize( tex->format, width, height ); + if(swizzle) GL_TextureSwizzle( tex->dstTexture + mipOffset, volBuff, width, height ); + mipOffset += GL_CalcTextureSize( tex->format, width, height, NULL ); + } + if(swizzle) SetBits( tex->flags, TF_IMG_SWIZZLED ); + } + else if( pic->type == PF_RGB_5650 || pic->type == PF_RGBA_5551 || pic->type == PF_RGBA_4444 ) + { + if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) + { + for( i = 0; i < tex->height; i++ ) + { + memcpy( swizzle ? ( volBuff + tex->width * tex->bpp * i ) : ( tex->dstTexture + tex->width * tex->bpp * i ), + ( pic->buffer + pic->width * tex->bpp * i ), pic->width * tex->bpp ); + } + } + else memcpy( swizzle ? volBuff : tex->dstTexture, pic->buffer, offset ); + + if( swizzle ) + { + GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * tex->bpp, tex->height ); + SetBits( tex->flags, TF_IMG_SWIZZLED ); } - SetBits( tex->flags, TF_IMG_SWIZZLED ); } else // RGBA32 { if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) { GL_ResampleTexture32( pic->buffer, pic->width, pic->height, volBuff, tex->width, tex->height, normalMap ); - offset = tex->width * tex->height * 4; + offset = tex->width * tex->height * 4; // 4 src bpp } - else - { - memcpy( volBuff, pic->buffer, offset ); - } - + else memcpy( volBuff, pic->buffer, offset ); +/* + if( !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + volBuff = GL_ApplyFilter( volBuff, tex->width, tex->height ); +*/ if( tex->format == GU_PSM_8888 ) { - if ( IsLightMap( tex ) ) + if ( swizzle ) { - memcpy( tex->dstTexture, volBuff, texSize ); - } - else - { - GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * 4, tex->height ); + GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * tex->bpp, tex->height ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } + else memcpy( tex->dstTexture, volBuff, texSize ); } else { - // disable swizzling for lightmaps - if ( IsLightMap( tex ) ) + GL_PixelConverter( swizzle ? (volBuff + offset) : tex->dstTexture, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); + if( swizzle ) { - GL_PixelConverter( tex->dstTexture, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); - } - else - { -/* - if( !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) - volBuff = GL_ApplyFilter( volBuff, tex->width, tex->height ); -*/ - GL_PixelConverter( volBuff + offset, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); - GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * 2, tex->height ); + GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * tex->bpp, tex->height ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } } } + sceKernelVolatileMemUnlock( 0 ); sceKernelDcacheWritebackRange( tex->dstTexture, texSize ); tex->size = texSize; @@ -956,86 +1001,62 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) /* =============== -GL_UpdateDlightTexture +GL_UpdateTexture =============== */ -qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ) +qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ) { gl_texture_t *tex; size_t texsize; + byte *dst, *src; // missed or invalid texture? - if( texnum <= 0 || texnum >= MAX_TEXTURES ) + if(( texnum <= 0 ) || ( texnum >= MAX_TEXTURES )) { if( texnum != 0 ) { - gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid texture num %d\n", texnum ); + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateTexture: invalid texture num %d\n", texnum ); return false; } } tex = &gl_textures[texnum]; - if(tex->width < width || tex->height < height ) + if(( tex->width < width + xoff ) || ( tex->height < height + yoff )) { - - gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid update area size %s\n", tex->name ); + gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateTexture: %s invalid update area size XY[%d x %d] WH[%d x %d]\n", tex->name, width, height, xoff, yoff ); return false; } - if(tex->width < xoff || tex->height < yoff ) + if( !FBitSet( tex->flags, TF_IMG_UPLOADED ) ) { - gEngfuncs.Con_DPrintf( S_ERROR "GL_UpdateDlightTexture: invalid offset position %s\n", tex->name ); - return false; - } - tex->numMips = 1; - tex->dstPalette = NULL; - tex->format = GU_PSM_5650; + tex->size = GL_CalcTextureSize( tex->format, tex->width, tex->height, &tex->bpp ); + tex->numMips = 1; + tex->dstPalette = NULL; - texsize = tex->width * tex->height * 2; - if( tex->size != texsize ) - { - if( tex->dstTexture ) - { - if( FBitSet( tex->flags, TF_IMG_INVRAM ) ) - vfree( tex->dstTexture ); - else - free( tex->dstTexture ); - - tex->dstTexture = NULL; - ClearBits( tex->flags, TF_IMG_INVRAM ); - } - } - - if( !tex->dstTexture ) - { - tex->dstTexture = ( byte* )valloc( texsize ); + tex->dstTexture = ( byte* )valloc( tex->size ); if( !tex->dstTexture ) { - tex->dstTexture = ( byte* )memalign( 16, texsize ); + tex->dstTexture = ( byte* )memalign( 16, tex->size ); if ( !tex->dstTexture ) - gEngfuncs.Host_Error( "GL_UpdateDlightTexture: out of memory! ( texture: %i %s )\n", texsize, tex->name); + gEngfuncs.Host_Error( "GL_UpdateTexture: out of memory! ( texture: %i %s )\n", tex->size, tex->name ); } - else - { - SetBits( tex->flags, TF_IMG_INVRAM ); - } - memset( tex->dstTexture, 0x00, texsize ); + else SetBits( tex->flags, TF_IMG_INVRAM ); + + memset( tex->dstTexture, 0x00, tex->size ); SetBits( tex->flags, TF_IMG_UPLOADED ); // done } - tex->size = texsize; - byte *src = ( byte* )buffer; - byte *dst = tex->dstTexture; - - dst += ( yoff * tex->width + xoff ) * 2; + src = ( byte* )buffer; + dst = tex->dstTexture + ( yoff * tex->width + xoff ) * tex->bpp; while( height-- ) { - GL_PixelConverter( dst, src, width, PC_SWF( PF_RGBA_32 ), PC_HWF( tex->format ) ); - dst += tex->width * 2; - src += width * 4; + memcpy( dst, src, width * tex->bpp ); + dst += tex->width * tex->bpp; + src += width * tex->bpp; } - sceKernelDcacheWritebackRange( tex->dstTexture, texsize ); + + sceKernelDcacheWritebackRange( tex->dstTexture, tex->size ); return true; } @@ -1763,8 +1784,8 @@ void R_InitDlightTexture( void ) r_image.width = BLOCK_SIZE; r_image.height = BLOCK_SIZE; r_image.flags = IMAGE_HAS_COLOR; - r_image.type = PF_RGBA_32; - r_image.size = r_image.width * r_image.height * 4; + r_image.type = LIGHTMAP_FORMAT; + r_image.size = r_image.width * r_image.height * LIGHTMAP_BPP; tr.dlightTexture = GL_LoadTextureInternal( "*dlight", &r_image, TF_NOMIPMAP|TF_CLAMP|TF_ATLAS_PAGE ); } @@ -1836,6 +1857,45 @@ static void GL_CreateInternalTextures( void ) tr.cinTexture = GL_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP ); } +/* +================== +GL_Create332Palette +================== +*/ +static void GL_Create332Palette( void ) +{ + palette_332 = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !palette_332 ) + gEngfuncs.Host_Error( "GL_Create332Palette: out of memory!\n" ); + + for(int i = 0; i < 256; i++) + { +#if PALETTE_FORMAT == GU_PSM_5650 + palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; + palette_332[i * 2 + 1] = ( i & 0x38 ) >> 3; + palette_332[i * 2 + 1] |= ( i & 0xc0 ); +#elif PALETTE_FORMAT == GU_PSM_5551 + palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; + palette_332[i * 2 + 0] |= ( i & 0x08 ) << 4; + palette_332[i * 2 + 1] = ( i & 0x30 ) >> 4; + palette_332[i * 2 + 1] |= ( i & 0xc0 ) >> 1; + palette_332[i * 2 + 1] |= 0x80; +#elif PALETTE_FORMAT == GU_PSM_4444 + palette_332[i * 2 + 0] = ( i & 0x07 ) << 1; + palette_332[i * 2 + 0] |= ( i & 0x38 ) << 2; + palette_332[i * 2 + 1] = ( i & 0xc0 ) >> 4; + palette_332[i * 2 + 1] |= 0xf0; +#elif PALETTE_FORMAT == GU_PSM_8888 + palette_332[i * 4 + 0] = ( i & 0x07 ) << 5; + palette_332[i * 4 + 1] = ( i & 0x38 ) << 2; + palette_332[i * 4 + 2] = ( i & 0xc0 ); + palette_332[i * 4 + 3] = 0xff; +#endif + } + sceKernelDcacheWritebackRange( palette_332, PALETTE_SIZE ); +} + + /* =============== R_TextureList_f @@ -1847,7 +1907,7 @@ void R_TextureList_f( void ) int i, texCount, ram_bytes = 0, vram_bytes = 0; gEngfuncs.Con_Printf( "\n" ); - gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -type- -wrap- -name--------\n" ); + gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -s- -wrap- -name--------\n" ); for( i = texCount = 0, image = gl_textures; i < gl_numTextures; i++, image++ ) { @@ -1903,6 +1963,8 @@ void R_TextureList_f( void ) break; } + gEngfuncs.Con_Printf( "%s ", FBitSet( image->flags, TF_IMG_SWIZZLED ) ? "Y" : "N" ); + if( image->flags & TF_CLAMP ) gEngfuncs.Con_Printf( "clamp " ); else if( image->flags & TF_BORDER ) @@ -1938,6 +2000,9 @@ void R_InitImages( void ) gl_texturesHashTable[gl_textures->hashValue] = gl_textures; gl_numTextures = 1; + // create 332 palette + GL_Create332Palette(); + // validate cvars GL_CreateInternalTextures(); @@ -1960,6 +2025,9 @@ void R_ShutdownImages( void ) for( i = 0, tex = gl_textures; i < gl_numTextures; i++, tex++ ) GL_DeleteTexture( tex ); + if( palette_332 ) + free( palette_332 ); + memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); memset( gl_texturesHashTable, 0, sizeof( gl_texturesHashTable )); memset( gl_textures, 0, sizeof( gl_textures )); diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 6291e213..28f09ddd 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -66,6 +66,21 @@ GNU General Public License for more details. extern byte *r_temppool; + +#define LIGHTMAP_BPP 2 //1 2 3 4 + +#if LIGHTMAP_BPP == 1 +#define LIGHTMAP_FORMAT PF_RGB_332 +#elif LIGHTMAP_BPP == 2 +#define LIGHTMAP_FORMAT PF_RGB_5650 +#elif LIGHTMAP_BPP == 3 +#define LIGHTMAP_FORMAT PF_RGB_24 +#elif LIGHTMAP_BPP == 4 +#define LIGHTMAP_FORMAT PF_RGBA_32 +#else +#error (1 > LIGHTMAP_BPP > 4) +#endif + #if 1 #define BLOCK_SIZE tr.block_size // lightmap blocksize @@ -135,6 +150,7 @@ typedef struct gltexture_s byte numMips; // mipmap count byte *dstTexture; // texture pointer byte *dstPalette; + byte bpp; int format; // uploaded format //GLint encode; // using GLSL decoder texFlags_t flags; @@ -434,7 +450,7 @@ void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ); int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ); void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); -qboolean GL_UpdateDlightTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ); +qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ); void GL_UpdateTexSize( int texnum, int width, int height, int depth ); int GL_FindTexture( const char *name ); void GL_FreeTexture( GLenum texnum ); diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index 90b238cf..70d7fd03 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -24,7 +24,7 @@ typedef struct int current_lightmap_texture; msurface_t *dynamic_surfaces; msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; - byte lightmap_buffer[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; + byte lightmap_buffer[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*LIGHTMAP_BPP]; } gllightmapstate_t; static int nColinElim; // stats @@ -693,7 +693,7 @@ static void LM_UploadBlock( qboolean dynamic ) height = gl_lms.allocated[i]; } - GL_UpdateDlightTexture( tr.dlightTexture, 0, 0, BLOCK_SIZE, height, gl_lms.lightmap_buffer ); + GL_UpdateTexture( tr.dlightTexture, 0, 0, BLOCK_SIZE, height, gl_lms.lightmap_buffer ); GL_Bind( XASH_TEXTURE0, tr.dlightTexture ); } else @@ -709,8 +709,8 @@ static void LM_UploadBlock( qboolean dynamic ) r_lightmap.width = BLOCK_SIZE; r_lightmap.height = BLOCK_SIZE; - r_lightmap.type = PF_RGBA_32; - r_lightmap.size = r_lightmap.width * r_lightmap.height * 4; + r_lightmap.type = LIGHTMAP_FORMAT; + r_lightmap.size = r_lightmap.width * r_lightmap.height * LIGHTMAP_BPP; r_lightmap.flags = IMAGE_HAS_COLOR; r_lightmap.buffer = gl_lms.lightmap_buffer; tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_NOMIPMAP|TF_ATLAS_PAGE ); @@ -736,6 +736,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean int sample_size; mextrasurf_t *info = surf->info; color24 *lm; + byte color[3]; sample_size = gEngfuncs.Mod_SampleSizeForFace( surf ); smax = ( info->lightextents[0] / sample_size ) + 1; @@ -764,6 +765,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean R_AddDynamicLights( surf ); // Put into texture format +#if 0 stride -= (smax << 2); bl = r_blocklights; @@ -780,6 +782,42 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean dest += 4; } } +#else + stride -= smax * LIGHTMAP_BPP; + bl = r_blocklights; + + for( t = 0; t < tmax; t++, dest += stride ) + { + for( s = 0; s < smax; s++ ) + { + color[0] = Q_min((bl[0] >> 7), 255 ); + color[1] = Q_min((bl[1] >> 7), 255 ); + color[2] = Q_min((bl[2] >> 7), 255 ); + color[3] = 255; +#if LIGHTMAP_BPP == 1 + dest[0] = ( color[0] >> 5 ) & 0x07; + dest[0] |= ( color[1] >> 2 ) & 0x38; + dest[0] |= ( color[2] ) & 0xc0; +#elif LIGHTMAP_BPP == 2 + dest[0] = ( color[0] >> 3 ) & 0x1f; + dest[0] |= ( color[1] << 3 ) & 0xe0; + dest[1] = ( color[1] >> 5 ) & 0x07; + dest[1] |= ( color[2] ) & 0xf8; +#elif LIGHTMAP_BPP == 3 + dest[0] = color[0]; + dest[1] = color[1]; + dest[2] = color[2]; +#else + dest[0] = color[0]; + dest[1] = color[1]; + dest[2] = color[2]; + dest[3] = 255; +#endif + bl += 3; + dest += LIGHTMAP_BPP; + } + } +#endif } /* @@ -998,9 +1036,9 @@ void R_BlendLightmaps( void ) if( LM_AllocBlock( smax, tmax, &surf->info->dlight_s, &surf->info->dlight_t )) { base = gl_lms.lightmap_buffer; - base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4; + base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * LIGHTMAP_BPP; - R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true ); + R_BuildLightMap( surf, base, BLOCK_SIZE * LIGHTMAP_BPP, true ); } else { @@ -1030,9 +1068,9 @@ void R_BlendLightmaps( void ) gEngfuncs.Host_Error( "AllocBlock: full\n" ); base = gl_lms.lightmap_buffer; - base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4; + base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * LIGHTMAP_BPP; - R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true ); + R_BuildLightMap( surf, base, BLOCK_SIZE * LIGHTMAP_BPP, true ); } } @@ -1254,7 +1292,7 @@ dynamic: { if(( fa->styles[maps] >= 32 || fa->styles[maps] == 0 || fa->styles[maps] == 20 ) && ( fa->dlightframe != tr.framecount )) { - byte temp[132*132*4]; + byte temp[132*132*LIGHTMAP_BPP]; mextrasurf_t *info = fa->info; int sample_size; int smax, tmax; @@ -1263,11 +1301,11 @@ dynamic: smax = ( info->lightextents[0] / sample_size ) + 1; tmax = ( info->lightextents[1] / sample_size ) + 1; - R_BuildLightMap( fa, temp, smax * 4, true ); + R_BuildLightMap( fa, temp, smax * LIGHTMAP_BPP, true ); R_SetCacheState( fa ); #if 1 - GL_UpdateDlightTexture( tr.lightmapTextures[fa->lightmaptexturenum], fa->light_s, fa->light_t, smax, tmax, temp ); + GL_UpdateTexture( tr.lightmapTextures[fa->lightmaptexturenum], fa->light_s, fa->light_t, smax, tmax, temp ); #else GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] ); @@ -2185,10 +2223,10 @@ void GL_CreateSurfaceLightmap( msurface_t *surf, model_t *loadmodel ) surf->lightmaptexturenum = gl_lms.current_lightmap_texture; base = gl_lms.lightmap_buffer; - base += ( surf->light_t * BLOCK_SIZE + surf->light_s ) * 4; + base += ( surf->light_t * BLOCK_SIZE + surf->light_s ) * LIGHTMAP_BPP; R_SetCacheState( surf ); - R_BuildLightMap( surf, base, BLOCK_SIZE * 4, false ); + R_BuildLightMap( surf, base, BLOCK_SIZE * LIGHTMAP_BPP, false ); } /* From 3a3b8e2c4ae4e1b765bb3dad4d688bb3f8e37b7b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 8 Jun 2022 16:15:38 +0300 Subject: [PATCH 30/84] ref_gu: triapi update --- ref_gu/gu_triapi.c | 278 ++++++++++++++++----------------------------- 1 file changed, 98 insertions(+), 180 deletions(-) diff --git a/ref_gu/gu_triapi.c b/ref_gu/gu_triapi.c index caff6115..9cf25f76 100644 --- a/ref_gu/gu_triapi.c +++ b/ref_gu/gu_triapi.c @@ -24,6 +24,17 @@ static struct vec4_t triRGBA; } ds; +static struct +{ + byte *start; + byte *end; + int count; + int prim; + uint flags; + float lastTexCord[2]; + uint lastColor; +}triContext = { 0 }; + /* =============================================================== @@ -31,25 +42,6 @@ static struct =============================================================== */ -#if 1 -static struct -{ - void *start; - gu_vert_ftcv_t *list; - qboolean begin; - int count; - int prim; - unsigned int flags; -}tri_gucontext = -{ - .start = NULL, - .list = NULL, - .begin = false, - .count = 0, - .prim = 0, - .flags = 0 -}; -#endif /* ============= @@ -60,7 +52,6 @@ set rendermode */ void TriRenderMode( int mode ) { -#if 1 ds.renderMode = mode; switch( mode ) { @@ -87,34 +78,6 @@ void TriRenderMode( int mode ) sceGuDepthMask( GU_TRUE ); break; } -#else - ds.renderMode = mode; - switch( mode ) - { - case kRenderNormal: - pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - pglDisable( GL_BLEND ); - pglDepthMask( GL_TRUE ); - break; - case kRenderTransAlpha: - pglEnable( GL_BLEND ); - pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - pglDepthMask( GL_FALSE ); - break; - case kRenderTransColor: - case kRenderTransTexture: - pglEnable( GL_BLEND ); - pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - break; - case kRenderGlow: - case kRenderTransAdd: - pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); - pglEnable( GL_BLEND ); - pglDepthMask( GL_FALSE ); - break; - } -#endif } /* @@ -126,72 +89,39 @@ begin triangle sequence */ void TriBegin( int mode ) { -#if 1 switch( mode ) { case TRI_POINTS: - tri_gucontext.prim = GU_POINTS; + triContext.prim = GU_POINTS; break; case TRI_TRIANGLES: - tri_gucontext.prim = GU_TRIANGLES; + triContext.prim = GU_TRIANGLES; break; case TRI_TRIANGLE_FAN: - tri_gucontext.prim = GU_TRIANGLE_FAN; + triContext.prim = GU_TRIANGLE_FAN; break; case TRI_QUADS: - tri_gucontext.prim = GU_TRIANGLE_FAN; + triContext.prim = GU_TRIANGLE_FAN; break; case TRI_LINES: - tri_gucontext.prim = GU_LINES; + triContext.prim = GU_LINES; break; case TRI_TRIANGLE_STRIP: - tri_gucontext.prim = GU_TRIANGLE_STRIP; + triContext.prim = GU_TRIANGLE_STRIP; break; case TRI_QUAD_STRIP: - tri_gucontext.prim = GU_TRIANGLE_STRIP; + triContext.prim = GU_TRIANGLE_STRIP; break; case TRI_POLYGON: default: - tri_gucontext.prim = GU_TRIANGLE_FAN; - break; - } - tri_gucontext.start = extGuBeginPacket( NULL ); - tri_gucontext.list = ( gu_vert_ftcv_t* )tri_gucontext.start; - tri_gucontext.begin = true; - tri_gucontext.count = 0; - tri_gucontext.flags = 0; -#else - switch( mode ) - { - case TRI_POINTS: - mode = GL_POINTS; - break; - case TRI_TRIANGLES: - mode = GL_TRIANGLES; - break; - case TRI_TRIANGLE_FAN: - mode = GL_TRIANGLE_FAN; - break; - case TRI_QUADS: - mode = GL_QUADS; - break; - case TRI_LINES: - mode = GL_LINES; - break; - case TRI_TRIANGLE_STRIP: - mode = GL_TRIANGLE_STRIP; - break; - case TRI_QUAD_STRIP: - mode = GL_QUAD_STRIP; - break; - case TRI_POLYGON: - default: - mode = GL_POLYGON; + triContext.prim = GU_TRIANGLE_FAN; break; } - pglBegin( mode ); -#endif + triContext.start = extGuBeginPacket( NULL ); + triContext.end = triContext.start; + triContext.count = 0; + triContext.flags = 0; } /* @@ -203,19 +133,15 @@ draw triangle sequence */ void TriEnd( void ) { -#if 1 - unsigned int vert_size; - - if( !tri_gucontext.begin ) + if( !triContext.start || triContext.count == 0 ) return; - extGuEndPacket( ( void* )tri_gucontext.list ); - sceGuDrawArray( tri_gucontext.prim, tri_gucontext.flags, tri_gucontext.count, 0, tri_gucontext.start ); - - tri_gucontext.begin = false; -#else - pglEnd( ); -#endif + extGuEndPacket(( void* )triContext.end ); + sceGuDrawArray( triContext.prim, triContext.flags, triContext.count, 0, triContext.start ); + + triContext.start = NULL; + triContext.end = NULL; + triContext.count = 0; } /* @@ -226,19 +152,15 @@ _TriColor4f */ void _TriColor4f( float r, float g, float b, float a ) { -#if 1 - if( tri_gucontext.begin ) + if( triContext.start ) { - tri_gucontext.flags |= GU_COLOR_8888; - tri_gucontext.list->c = GUCOLOR4F( r, g, b, a ); + if( triContext.count > 0 && !( triContext.flags & GU_COLOR_8888 )) + return; + + triContext.flags |= GU_COLOR_8888; + triContext.lastColor = GUCOLOR4F( r, g, b, a ); } - else - { - sceGuColor( GUCOLOR4F( r, g, b, a ) ); - } -#else - pglColor4f( r, g, b, a ); -#endif + else sceGuColor( GUCOLOR4F( r, g, b, a )); } /* @@ -249,19 +171,15 @@ _TriColor4ub */ void _TriColor4ub( byte r, byte g, byte b, byte a ) { -#if 1 - if( tri_gucontext.begin ) + if( triContext.start ) { - tri_gucontext.flags |= GU_COLOR_8888; - tri_gucontext.list->c = GUCOLOR4UB( r, g, b, a ); + if( triContext.count > 0 && !( triContext.flags & GU_COLOR_8888 )) + return; + + triContext.flags |= GU_COLOR_8888; + triContext.lastColor = GUCOLOR4UB( r, g, b, a ); } - else - { - sceGuColor( GUCOLOR4UB( r, g, b, a ) ); - } -#else - pglColor4ub( r, g, b, a ); -#endif + else sceGuColor( GUCOLOR4UB( r, g, b, a )); } @@ -306,16 +224,15 @@ TriTexCoord2f */ void TriTexCoord2f( float u, float v ) { -#if 1 - if( !tri_gucontext.begin ) + if( !triContext.start ) return; - tri_gucontext.flags |= GU_TEXTURE_32BITF; - tri_gucontext.list->u = u; - tri_gucontext.list->v = v; -#else - pglTexCoord2f( u, v ); -#endif + if( triContext.count > 0 && !( triContext.flags & GU_TEXTURE_32BITF )) + return; + + triContext.flags |= GU_TEXTURE_32BITF; + triContext.lastTexCord[0] = u; + triContext.lastTexCord[1] = v; } /* @@ -326,31 +243,32 @@ TriVertex3fv */ void TriVertex3fv( const float *v ) { -#if 1 - if( !tri_gucontext.begin ) + if( !triContext.start ) return; - if( !(tri_gucontext.flags & GU_TEXTURE_32BITF) ) + if( triContext.flags & GU_TEXTURE_32BITF ) { - tri_gucontext.list->u = 0; - tri_gucontext.list->v = 0; - } - - if( !(tri_gucontext.flags & GU_COLOR_8888) ) - { - tri_gucontext.list->c = 0xffffffff; + *( float* )triContext.end = triContext.lastTexCord[0]; + triContext.end += sizeof( float ); + *( float* )triContext.end = triContext.lastTexCord[1]; + triContext.end += sizeof( float ); } - tri_gucontext.flags |= GU_VERTEX_32BITF; - tri_gucontext.list->x = v[0]; - tri_gucontext.list->y = v[1]; - tri_gucontext.list->z = v[2]; - tri_gucontext.list++; - - tri_gucontext.count++; -#else - pglVertex3fv( v ); -#endif + if( triContext.flags & GU_COLOR_8888 ) + { + *( uint* )triContext.end = triContext.lastColor; + triContext.end += sizeof( uint ); + } + + triContext.flags |= GU_VERTEX_32BITF; + *( float* )triContext.end = v[0]; + triContext.end += sizeof( float ); + *( float* )triContext.end = v[1]; + triContext.end += sizeof( float ); + *( float* )triContext.end = v[2]; + triContext.end += sizeof( float ); + + triContext.count++; } /* @@ -361,31 +279,32 @@ TriVertex3f */ void TriVertex3f( float x, float y, float z ) { -#if 1 - if( !tri_gucontext.begin ) + if( !triContext.start ) return; - - if( !(tri_gucontext.flags & GU_TEXTURE_32BITF) ) + + if( triContext.flags & GU_TEXTURE_32BITF ) { - tri_gucontext.list->u = 0; - tri_gucontext.list->v = 0; - } - - if( !(tri_gucontext.flags & GU_COLOR_8888) ) - { - tri_gucontext.list->c = 0xffffffff; + *( float* )triContext.end = triContext.lastTexCord[0]; + triContext.end += sizeof( float ); + *( float* )triContext.end = triContext.lastTexCord[1]; + triContext.end += sizeof( float ); } - tri_gucontext.flags |= GU_VERTEX_32BITF; - tri_gucontext.list->x = x; - tri_gucontext.list->y = y; - tri_gucontext.list->z = z; - tri_gucontext.list++; + if( triContext.flags & GU_COLOR_8888 ) + { + *( uint* )triContext.end = triContext.lastColor; + triContext.end += sizeof( uint ); + } - tri_gucontext.count++; -#else - pglVertex3f( x, y, z ); -#endif + triContext.flags |= GU_VERTEX_32BITF; + *( float* )triContext.end = x; + triContext.end += sizeof( float ); + *( float* )triContext.end = y; + triContext.end += sizeof( float ); + *( float* )triContext.end = z; + triContext.end += sizeof( float ); + + triContext.count++; } /* @@ -449,7 +368,7 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) { glState.isFogEnabled = RI.fogCustom = false; #if 1 - sceGuDisable( GU_FOG ); + sceGuDisable( GU_FOG ); #else pglDisable( GL_FOG ); #endif @@ -473,11 +392,11 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) RI.fogDensity = 0.0f; RI.fogSkybox = true; RI.fogEnd = flEnd; - + #if 1 - printf("TRI FOG: s %f e %f c %f %f %f %f \n", RI.fogStart, RI.fogEnd, + printf("TRI FOG: s %f e %f c %f %f %f %f \n", RI.fogStart, RI.fogEnd, RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], RI.fogColor[3] ); - + //glState.fogDensity = RI.fogDensity glState.fogColor = GUCOLOR4F( RI.fogColor[0], RI.fogColor[1], RI.fogColor[2], glState.fogDensity ); glState.fogStart = RI.fogStart; @@ -572,6 +491,5 @@ unsigned int getTriBrightness( float brightness ) VectorNormalizeFast( color ); - return GUCOLOR3FV( color ); + return GUCOLOR3FV( color ); } - From f2d59eb7f820de45ef5ca08fb15313e8e127d04b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 9 Jun 2022 11:13:29 +0300 Subject: [PATCH 31/84] ref_gu: studio model optimization --- public/xash3d_mathlib.c | 51 +++++++++++------------------------------ ref_gu/gu_studio.c | 16 +++++++------ 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index d3ba9c57..2908e0e9 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -665,62 +665,37 @@ AngleQuaternion */ void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio ) { -#if 0//XASH_PSP /* performance not tested */ +#if XASH_PSP + vec4_t dst_angles; + + dst_angles[0] = studio ? angles[PITCH] : DEG2RAD( angles[ROLL] ); + dst_angles[1] = studio ? angles[YAW] : DEG2RAD( angles[PITCH] ); + dst_angles[2] = studio ? angles[ROLL] : DEG2RAD( angles[YAW] ); + __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - - - - /**/ - "lv.s S000, 8 + %1\n" // S000 = angles[ROLL] - "lv.s S001, 0 + %1\n" // S000 = angles[PITCH] - "lv.s S002, 4 + %1\n" // S000 = angles[YAW] - /**/ + "lv.q C000, %1\n" // C000 = [PITCH, YAW, ROLL] "vcst.s S010, VFPU_1_PI\n" // S010 = VFPU_1_PI = 1 / PI "vscl.t C000, C000, S010\n" // C000 = C000 * S010 = C000 * 0.5f * ( 2 / PI ) - - /**/ - "vcos.t C010, C000\n" // C010 = cos( *angles * 0.5f ) - "vsin.t C000, C000\n" // C000 = sin( *angles * 0.5f ) + "vcos.t C010, C000\n" // C010 = cos( C000 * 0.5f ) + "vsin.t C000, C000\n" // C000 = sin( C000 * 0.5f ) "vcrs.t C020, C010, C010\n" // C020 = ( cp*cy, cy*cr, cr*cp ) "vcrs.t C030, C000, C000\n" // C030 = ( sp*sy, sy*sr, sr*sp ) "vmul.s S003, S020, S010\n" // S003 = S020 * S010 = cp*cy*cr "vmul.s S013, S030, S000\n" // S013 = S030 * S000 = sp*sy*sr "vmul.t C020, C020, C000\n" // C020 = C020 * C000 = ( cp*cy*sr, cy*cr*sp, cr*cp*sy ) "vmul.t C030, C030, C010\n" // C030 = C030 * C010 = ( sp*sy*cr, sy*sr*cp, sr*sp*cy ) - "vadd.s S003, S003, S013\n" // S003 = S003 + S013 = cr*cp*cy + sr*sp*sy + "vadd.s S003, S003, S013\n" // S003 = S003 + S013 = cp*cy*cr + cp*cy*cr "vadd.t C000, C020, C030[-X, Y, -Z]\n" // S000 = S020 - C030 = cp*cy*sr - sp*sy*cr // S001 = S021 + C031 = cy*cr*sp + sy*sr*cp // S002 = S022 - C032 = cr*cp*sy - sr*sp*cy - "usv.q C000, %0\n" // *q = C000 + "sv.q C000, %0\n" // *q = C000 ".set pop\n" // restore assembler option : "=m"( *q ) - : "m"( *angles ), "r"( studio ) + : "m"( dst_angles ) ); - - printf("ASM [%f %f %f %f]\n", q[0], q[1], q[2], q[3] ); - float sr, sp, sy, cr, cp, cy; - - if( studio ) - { - SinCos( angles[ROLL] * 0.5f, &sy, &cy ); - SinCos( angles[YAW] * 0.5f, &sp, &cp ); - SinCos( angles[PITCH] * 0.5f, &sr, &cr ); - } - else - { - SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy ); - SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp ); - SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr ); - } - - q[0] = sr * cp * cy - cr * sp * sy; // X - q[1] = cr * sp * cy + sr * cp * sy; // Y - q[2] = cr * cp * sy - sr * sp * cy; // Z - q[3] = cr * cp * cy + sr * sp * sy; // W - printf("C [%f %f %f %f]\n", q[0], q[1], q[2], q[3] ); #else float sr, sp, sy, cr, cp, cy; diff --git a/ref_gu/gu_studio.c b/ref_gu/gu_studio.c index 9aba3679..e49a6b46 100644 --- a/ref_gu/gu_studio.c +++ b/ref_gu/gu_studio.c @@ -28,6 +28,8 @@ GNU General Public License for more details. #define EVENT_CLIENT 5000 // less than this value it's a server-side studio events #define MAX_LOCALLIGHTS 4 +#define STUDIOEXTRADATA( mod ) ((( mod ) && ( mod )->type == mod_studio ) ? ( mod )->cache.data : NULL ) + typedef struct { char name[MAX_OSPATH]; @@ -697,7 +699,7 @@ float CL_GetSequenceDuration( cl_entity_t *ent, int sequence ) if( ent->model != NULL && ent->model->type == mod_studio ) { - pstudiohdr = (studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, ent->model ); + pstudiohdr = (studiohdr_t *)STUDIOEXTRADATA( ent->model ); if( pstudiohdr ) { @@ -1868,7 +1870,7 @@ mstudiotexture_t *R_StudioGetTexture( cl_entity_t *e ) mstudiotexture_t *ptexture; studiohdr_t *phdr, *thdr; - if(( phdr = gEngfuncs.Mod_Extradata( mod_studio, e->model )) == NULL ) + if(( phdr = STUDIOEXTRADATA( e->model )) == NULL ) return NULL; thdr = m_pStudioHeader; @@ -2878,7 +2880,7 @@ int R_GetEntityRenderMode( cl_entity_t *ent ) RI.currententity = oldent; - if(( phdr = gEngfuncs.Mod_Extradata( mod_studio, model )) == NULL ) + if(( phdr = STUDIOEXTRADATA( model )) == NULL ) { if( R_ModelOpaque( ent->curstate.rendermode )) { @@ -3489,7 +3491,7 @@ static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) if( RI.currentmodel == NULL ) return 0; - R_StudioSetHeader((studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, RI.currentmodel )); + R_StudioSetHeader((studiohdr_t *)STUDIOEXTRADATA( RI.currentmodel )); if( pplayer->gaitsequence ) { @@ -3596,7 +3598,7 @@ static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) cl_entity_t saveent = *RI.currententity; model_t *pweaponmodel = gEngfuncs.pfnGetModelByIndex( pplayer->weaponmodel ); - m_pStudioHeader = (studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, pweaponmodel ); + m_pStudioHeader = (studiohdr_t *)STUDIOEXTRADATA( pweaponmodel ); R_StudioMergeBones( RI.currententity, pweaponmodel ); R_StudioSetupLighting( &lighting ); @@ -3651,7 +3653,7 @@ static int R_StudioDrawModel( int flags ) return result; } - R_StudioSetHeader((studiohdr_t *)gEngfuncs.Mod_Extradata( mod_studio, RI.currentmodel )); + R_StudioSetHeader((studiohdr_t *)STUDIOEXTRADATA( RI.currentmodel )); R_StudioSetUpTransform( RI.currententity ); @@ -4039,7 +4041,7 @@ static void *pfnMod_CacheCheck( struct cache_user_s *c ) static void *pfnMod_StudioExtradata( model_t *mod ) { - return gEngfuncs.Mod_Extradata( mod_studio, mod ); + return STUDIOEXTRADATA( mod ); } static void pfnMod_LoadCacheFile( const char *path, struct cache_user_s *cu ) From 12889494e0224385110b59dcf617ae7deaa23a01 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 10 Jun 2022 10:49:07 +0300 Subject: [PATCH 32/84] ref_gu: reducing the number of calls to CL_GetEntityLight and CL_GetDynamicLight --- ref_gu/gu_alias.c | 4 +--- ref_gu/gu_rlight.c | 8 ++------ ref_gu/gu_rsurf.c | 8 ++------ ref_gu/gu_studio.c | 8 ++------ 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/ref_gu/gu_alias.c b/ref_gu/gu_alias.c index 69271ba8..0fa0693e 100644 --- a/ref_gu/gu_alias.c +++ b/ref_gu/gu_alias.c @@ -887,10 +887,8 @@ void R_AliasDynamicLight( cl_entity_t *ent, alight_t *plight ) // scale lightdir by light intentsity VectorScale( lightDir, total, lightDir ); - for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + for( lnum = 0, dl = gEngfuncs.GetDynamicLight( 0 ); lnum < MAX_DLIGHTS; lnum++, dl++ ) { - dl = gEngfuncs.GetDynamicLight( lnum ); - if( dl->die < g_alias.time || !r_dynamic->value ) continue; diff --git a/ref_gu/gu_rlight.c b/ref_gu/gu_rlight.c index b212c328..b4ccd2a3 100644 --- a/ref_gu/gu_rlight.c +++ b/ref_gu/gu_rlight.c @@ -155,10 +155,8 @@ void R_PushDlights( void ) RI.currententity = gEngfuncs.GetEntityByIndex( 0 ); RI.currentmodel = RI.currententity->model; - for( i = 0; i < MAX_DLIGHTS; i++, l++ ) + for( i = 0, l = gEngfuncs.GetDynamicLight( 0 ); i < MAX_DLIGHTS; i++, l++ ) { - l = gEngfuncs.GetDynamicLight( i ); - if( l->die < gpGlobals->time || !l->radius ) continue; @@ -179,10 +177,8 @@ int R_CountDlights( void ) dlight_t *l; int i, numDlights = 0; - for( i = 0; i < MAX_DLIGHTS; i++ ) + for( i = 0, l = gEngfuncs.GetDynamicLight( 0 ); i < MAX_DLIGHTS; i++, l++ ) { - l = gEngfuncs.GetDynamicLight( i ); - if( l->die < gpGlobals->time || !l->radius ) continue; diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index 70d7fd03..6b22c484 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -558,13 +558,11 @@ void R_AddDynamicLights( msurface_t *surf ) else sample_frac = LM_SAMPLE_SIZE; } - for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + for( lnum = 0, dl = gEngfuncs.GetDynamicLight( 0 ); lnum < MAX_DLIGHTS; lnum++, dl++ ) { if( !FBitSet( surf->dlightbits, BIT( lnum ))) continue; // not lit by this light - dl = gEngfuncs.GetDynamicLight( lnum ); - // transform light origin to local bmodel space if( !tr.modelviewIdentity ) Matrix4x4_VectorITransform( RI.objectMatrix, dl->origin, origin_l ); @@ -1642,10 +1640,8 @@ void R_DrawBrushModel( cl_entity_t *e ) else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); // calculate dynamic lighting for bmodel - for( k = 0; k < MAX_DLIGHTS; k++ ) + for( k = 0, l = gEngfuncs.GetDynamicLight( 0 ); k < MAX_DLIGHTS; k++, l++ ) { - l = gEngfuncs.GetDynamicLight( k ); - if( l->die < gpGlobals->time || !l->radius ) continue; diff --git a/ref_gu/gu_studio.c b/ref_gu/gu_studio.c index e49a6b46..3f51e662 100644 --- a/ref_gu/gu_studio.c +++ b/ref_gu/gu_studio.c @@ -1486,10 +1486,8 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight ) // scale lightdir by light intentsity VectorScale( lightDir, total, lightDir ); - for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ ) + for( lnum = 0, dl = gEngfuncs.GetDynamicLight( 0 ); lnum < MAX_DLIGHTS; lnum++, dl++ ) { - dl = gEngfuncs.GetDynamicLight( lnum ); - if( dl->die < g_studio.time || !r_dynamic->value ) continue; @@ -1569,10 +1567,8 @@ void R_StudioEntityLight( alight_t *lightinfo ) dist2 = 1000000.0f; k = 0; - for( lnum = 0; lnum < MAX_ELIGHTS; lnum++ ) + for( lnum = 0, el = gEngfuncs.GetEntityLight( 0 ); lnum < MAX_ELIGHTS; lnum++, el++ ) { - el = gEngfuncs.GetEntityLight( lnum ); - if( el->die < g_studio.time || el->radius <= 0.0f ) continue; From db9e82cdecb24f9b924c8a0969a46def8299b7c4 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 10 Jun 2022 11:19:16 +0300 Subject: [PATCH 33/84] engine: CL_IsPlayerIndex macro --- engine/client/cl_frame.c | 2 ++ engine/client/client.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 625f193d..d2ef6f06 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -33,10 +33,12 @@ CL_IsPlayerIndex detect player entity ================== */ +#if XASH_EXT_OPT != 2 qboolean CL_IsPlayerIndex( int idx ) { return ( idx >= 1 && idx <= cl.maxclients ); } +#endif /* ========================================================================= diff --git a/engine/client/client.h b/engine/client/client.h index 36d3d1bf..25bea5de 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -954,7 +954,11 @@ void CL_ProcessPlayerState( int playerindex, entity_state_t *state ); void CL_ComputePlayerOrigin( cl_entity_t *clent ); void CL_ProcessPacket( frame_t *frame ); void CL_MoveThirdpersonCamera( void ); +#if XASH_EXT_OPT == 2 +#define CL_IsPlayerIndex( idx ) (( idx ) >= 1 && ( idx ) <= cl.maxclients ) +#else qboolean CL_IsPlayerIndex( int idx ); +#endif void CL_SetIdealPitch( void ); void CL_EmitEntities( void ); From cbfb43f05b29224b24df23b39d73380c6edbf32b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 10 Jun 2022 13:32:03 +0300 Subject: [PATCH 34/84] engine: NORETURN macro disabled for PSP --- engine/client/client.h | 4 ---- engine/common/system.h | 4 ---- public/crtlib.h | 4 ++++ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/engine/client/client.h b/engine/client/client.h index 25bea5de..b8bb14a6 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -709,11 +709,7 @@ dlight_t *CL_GetEntityLight( int number ); // // cl_cmds.c // -#if XASH_PSP -void CL_Quit_f( void ); -#else void CL_Quit_f( void ) NORETURN; -#endif void CL_ScreenShot_f( void ); void CL_SnapShot_f( void ); void CL_PlayCDTrack_f( void ); diff --git a/engine/common/system.h b/engine/common/system.h index 8730e918..2096e6e0 100644 --- a/engine/common/system.h +++ b/engine/common/system.h @@ -68,11 +68,7 @@ void Sys_Print( const char *pMsg ); void Sys_PrintLog( const char *pMsg ); void Sys_InitLog( void ); void Sys_CloseLog( void ); -#if XASH_PSP -void Sys_Quit( void ); -#else void Sys_Quit( void ) NORETURN; -#endif // // sys_con.c diff --git a/public/crtlib.h b/public/crtlib.h index f64db6f2..9220e488 100644 --- a/public/crtlib.h +++ b/public/crtlib.h @@ -21,7 +21,11 @@ GNU General Public License for more details. #ifdef __GNUC__ #define _format(x) __attribute__((format(printf, x, x+1))) +#if XASH_PSP +#define NORETURN +#else #define NORETURN __attribute__((noreturn)) +#endif #else #define _format(x) #define NORETURN From 1b4bc7f5ec536a1c6b9ca27eac1317478e278b20 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 16 Jun 2022 09:59:01 +0300 Subject: [PATCH 35/84] platform: module loader refactoring --- common/defaults.h | 3 +- engine/common/lib_common.c | 2 + engine/platform/psp/dll_psp.c | 259 -------------- engine/platform/psp/lib_psp.c | 627 ++++++++++++++++++++++++++-------- 4 files changed, 485 insertions(+), 406 deletions(-) delete mode 100644 engine/platform/psp/dll_psp.c diff --git a/common/defaults.h b/common/defaults.h index e1f5cc55..f4ce186e 100644 --- a/common/defaults.h +++ b/common/defaults.h @@ -156,7 +156,7 @@ SETUP BACKENDS DEFINITIONS #endif // !XASH_WIN32 #endif -#if defined(XASH_STATIC_LIBS) && !defined(XASH_PSP) +#if defined(XASH_STATIC_LIBS) && !XASH_PSP #define XASH_LIB LIB_STATIC #define XASH_INTERNAL_GAMELIBS #define XASH_ALLOW_SAVERESTORE_OFFSETS @@ -165,7 +165,6 @@ SETUP BACKENDS DEFINITIONS #elif XASH_POSIX #define XASH_LIB LIB_POSIX #elif XASH_PSP -#define XASH_ALLOW_SAVERESTORE_OFFSETS #define XASH_LIB LIB_PSP #endif diff --git a/engine/common/lib_common.c b/engine/common/lib_common.c index 9788053b..b2a95319 100644 --- a/engine/common/lib_common.c +++ b/engine/common/lib_common.c @@ -36,6 +36,7 @@ void COM_PushLibraryError( const char *error ) Q_strncat( s_szLastError, "\n", sizeof( s_szLastError ) ); } +#if !XASH_PSP void *COM_FunctionFromName_SR( void *hInstance, const char *pName ) { #ifdef XASH_ALLOW_SAVERESTORE_OFFSETS @@ -52,6 +53,7 @@ const char *COM_OffsetNameForFunction( void *function ) Con_Reportf( "COM_OffsetNameForFunction %s\n", sname ); return sname; } +#endif /* ============================================================================= diff --git a/engine/platform/psp/dll_psp.c b/engine/platform/psp/dll_psp.c deleted file mode 100644 index 3e82252a..00000000 --- a/engine/platform/psp/dll_psp.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - From the vitaXash3D by fgsfdsfgs. -*/ -#include "common.h" -#include "dll_psp.h" -#include -#include -#include - -#define MAX_DLNAMELEN 256 - -#if 1 -typedef struct table_s -{ - const char *name; - void *pointer; -} table_t; - -#include "generated_library_tables.h" -#endif - -typedef struct dll_s -{ - SceUID handle; - char name[MAX_DLNAMELEN]; - int refcnt; - dllexport_t *exp; - struct dll_s *next; -} dll_t; - -static dll_t *dll_list; -static char *dll_err = NULL; -static char dll_err_buf[1024]; - -static void *dlfind( const char *name ) -{ - dll_t *d = NULL; - for( d = dll_list; d; d = d->next ) - if( !Q_strcmp( d->name, name ) ) - break; - return d; -} - -static const char *dlname( void *handle ) -{ - dll_t *d = NULL; - // iterate through all dll_ts to check if the handle is actually in the list - // and not some bogus pointer from god knows where - for( d = dll_list; d; d = d->next ) if( d == handle ) break; - return d ? d->name : NULL; -} - -void *dlopen( const char *name, int flag ) -{ - dll_t *old, *new; - char fullpath[MAX_SYSPATH]; - char static_name[16]; - void *static_exp; - void *dynamic_exp; - void *exp_p; - SceUID h; - - if( !name ) - return NULL; - - old = dlfind( name ); - if( old ) - { - old->refcnt++; - return old; - } - - Q_snprintf( fullpath, sizeof( fullpath ), "%s", name ); - - exp_p = &dynamic_exp; - static_exp = NULL; - memset( static_name, 0x00, sizeof( static_name ) ); - - h = Platform_LoadModule( fullpath, 0, sizeof( exp_p ), &exp_p ); - if( h < 0 ) - { - snprintf( dll_err_buf, sizeof( dll_err_buf ), "dlopen( %s ): error %#010x\n", name, h ); - dll_err = dll_err_buf; - - COM_FileBase( name, static_name ); - - if( !Q_strncmp( static_name, "lib", 3 ) ) - Q_sprintf( static_name, "%s", &static_name[3] ); - - table_t* tbl = ( table_t* )libs; - while( tbl->name ) - { - if( !Q_strcmp( tbl->name, static_name) ) - { - static_exp = tbl->pointer; - break; - } - tbl++; - } - - if( static_exp == NULL ) - return NULL; - - Con_Printf ( "dlopen( %s ): ( static ) success!\n", fullpath ); - } - else - { - Con_Printf ( "dlopen( %s ): ( dynamic ) success!\n", fullpath ); - } - - new = calloc( 1, sizeof( dll_t ) ); - if( !new ) - { - dll_err = "dlopen(): out of memory"; - return NULL; - } - snprintf( new->name, MAX_DLNAMELEN, name ); - - if( static_exp != NULL ) - { - new->handle = -1; - new->exp = static_exp; - } - else - { - new->handle = h; - new->exp = dynamic_exp; - } - - new->refcnt = 1; - - new->next = dll_list; - dll_list = new; - - return new; -} - -void *dlsym( void *handle, const char *symbol ) -{ - if( !handle || !symbol ) - { - dll_err = "dlsym(): NULL args"; - return NULL; - } - - if( !dlname( handle ) ) - { - dll_err = "dlsym(): unknown handle"; - return NULL; - } - - dll_t *d = handle; - if( !d->refcnt ) - { - dll_err = "dlsym(): call dlopen() first"; - return NULL; - } - - dllexport_t *f = NULL; - for( f = d->exp; f && f->func; f++ ) - { - if( !Q_strcmp( f->name, symbol ) ) - break; - } - - if( f && f->func ) - { - return f->func; - } - else - { - dll_err = "dlsym(): symbol not found in dll"; - return NULL; - } -} - -int dlclose( void *handle ) -{ - int result, sce_code; - dll_t *d; - - if( !handle ) - { - dll_err = "dlclose(): NULL arg"; - return -1; - } - - if( !dlname( handle ) ) - { - dll_err = "dlclose(): unknown handle"; - return -2; - } - - d = handle; - d->refcnt--; - if( d->refcnt <= 0 ) - { - if( d->handle != -1 ) - { - result = Platform_UnloadModule( d->handle, &sce_code ); - if( result < 0 ) - { - if( result == -1 ) - { - dll_err = "dlclose(): module doesn't want to stop"; - return -3; - } - - snprintf( dll_err_buf, sizeof( dll_err_buf ), "dlclose( %s ): error %#010x", d->name, sce_code ); - dll_err = dll_err_buf; - } - } - - if( d == dll_list ) - dll_list = NULL; - else - { - dll_t *pd; - for( pd = dll_list; pd; pd = pd->next ) - { - if( pd->next == d ) - { - pd->next = d->next; - break; - } - } - } - free( d ); - } - return 0; -} - -char *dlerror( void ) -{ - char *err = dll_err; - dll_err = NULL; - return err; -} - -int dladdr( const void *addr, Dl_info *info ) -{ - dll_t *d = NULL; - dllexport_t *f = NULL; - for( d = dll_list; d; d = d->next ) - for( f = d->exp; f && f->func; f++ ) - if( f->func == addr ) goto for_end; -for_end: - if( d && f && f->func ) - { - if( info ) - { - info->dli_fhandle = d; - info->dli_sname = f->name; - info->dli_saddr = addr; - } - return 1; - } - return 0; -} diff --git a/engine/platform/psp/lib_psp.c b/engine/platform/psp/lib_psp.c index 6274ecfe..910eaa7f 100644 --- a/engine/platform/psp/lib_psp.c +++ b/engine/platform/psp/lib_psp.c @@ -1,145 +1,482 @@ -/* -lib_psp.c - dynamic library code for Sony PSP system -Copyright (C) 2018 Flying With Gauss - -This program is free software: you can redistribute it and/sor modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -*/ -#include "platform/platform.h" -#if XASH_LIB == LIB_PSP - - -#include "common.h" -#include "library.h" -#include "filesystem.h" -#include "server.h" -#include "platform/psp/dll_psp.h" - -#ifdef XASH_NO_LIBDL -#ifndef XASH_DLL_LOADER -#error Enable at least one dll backend!!! -#endif // XASH_DLL_LOADER - -void *dlsym(void *handle, const char *symbol ) -{ - Con_DPrintf( "dlsym( %p, \"%s\" ): stub\n", handle, symbol ); - return NULL; -} - -void *dlopen(const char *name, int flag ) -{ - Con_DPrintf( "dlopen( \"%s\", %d ): stub\n", name, flag ); - return NULL; -} - -int dlclose(void *handle) -{ - Con_DPrintf( "dlsym( %p ): stub\n", handle ); - return 0; -} - -char *dlerror( void ) -{ - return "Loading ELF libraries not supported in this build!\n"; -} - -int dladdr( const void *addr, Dl_info *info ) -{ - return 0; -} -#endif // XASH_NO_LIBDL - -qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname, qboolean directpath ) -{ - // TODO: implement - return true; -} - -void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath ) -{ - dll_user_t *hInst = NULL; - void *pHandle = NULL; - - COM_ResetLibraryError(); - - // platforms where gameinfo mechanism is working goes here - // and use FS_FindLibrary - hInst = FS_FindLibrary( dllname, directpath ); - if( !hInst ) - { - // try to find by linker(LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, LD_32_LIBRARY_PATH and so on...) - if( !pHandle ) - { - pHandle = dlopen( dllname, RTLD_LAZY ); - if( pHandle ) - return pHandle; - - COM_PushLibraryError( va( "Failed to find library %s", dllname )); - COM_PushLibraryError( dlerror() ); - return NULL; - } - } - - if( hInst->custom_loader ) - { - COM_PushLibraryError( va( "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath )); - Mem_Free( hInst ); - return NULL; - } - - if( !( hInst->hInstance = dlopen( hInst->fullPath, RTLD_LAZY ) ) ) - { - COM_PushLibraryError( dlerror() ); - Mem_Free( hInst ); - return NULL; - } - - pHandle = hInst->hInstance; - - Mem_Free( hInst ); - - return pHandle; -} - -void COM_FreeLibrary( void *hInstance ) -{ - dlclose( hInstance ); -} - -void *COM_GetProcAddress( void *hInstance, const char *name ) -{ - return dlsym( hInstance, name ); -} - -void *COM_FunctionFromName( void *hInstance, const char *pName ) -{ - void *function; - if( !( function = COM_GetProcAddress( hInstance, pName ) ) ) - { - Con_Reportf( S_ERROR "FunctionFromName: Can't get symbol %s: %s\n", pName, dlerror()); - } - return function; -} - -const char *COM_NameForFunction( void *hInstance, void *function ) -{ - // NOTE: dladdr() is a glibc extension - Dl_info info = {0}; - dladdr((void*)function, &info); - if(info.dli_sname) - return info.dli_sname; -#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS - return COM_OffsetNameForFunction( function ); -#else - return NULL; -#endif -} - -#endif // _WIN32 +/* +lib_psp.c - dynamic library code for Sony PSP system +Copyright (C) 2018 Flying With Gauss +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/sor modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "platform/platform.h" + +#if XASH_LIB == LIB_PSP +#include +#include "common.h" +#include "library.h" +#include "filesystem.h" +#include "server.h" + +#define MOD_MAXNAMELEN 256 + +typedef struct table_s +{ + const char *name; + void *pointer; +} table_t; +#include "generated_library_tables.h" + +typedef struct mod_func_s +{ + const char *name; + void *addr; +} mod_func_t; + +typedef struct mod_handle_s +{ + SceUID uid; + char name[MOD_MAXNAMELEN]; + uint segAddr; + uint segSize; + mod_func_t *func; + struct mod_handle_s *next; +} mod_handle_t; + +static mod_handle_t *modList = NULL; +static char *modErrorPtr = NULL; +static char modErrorBuf[1024]; + +#define Module_Error( fmt, ... ) Module_SetError( "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ ) + +int Module_SetError( const char *fmt, ... ) +{ + va_list args; + int result; + + va_start( args, fmt ); + result = Q_vsnprintf( modErrorBuf, sizeof( modErrorBuf ), fmt, args ); + va_end( args ); + + modErrorPtr = modErrorBuf; + + return result; +} + +char *Module_GetError( void ) +{ + char *errPtr = modErrorPtr; + modErrorPtr = NULL; + return errPtr; +} + +static mod_handle_t *Module_Find( const char *name ) +{ + mod_handle_t *modHandle; + + if( !name ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + for( modHandle = modList; modHandle; modHandle = modHandle->next ) + { + if( !Q_strcmp( modHandle->name, name )) + return modHandle; + } + + return NULL; +} + +static const char *Module_Name( void *handle ) +{ + mod_handle_t *modHandle; + + if( !handle ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + for( modHandle = modList; modHandle; modHandle = modHandle->next ) + { + if( modHandle == handle ) + return modHandle->name; + } + + return NULL; +} + +static mod_func_t *Module_LoadStatic( const char *name ) +{ + table_t *staticLib; + + if( !name ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + for( staticLib = ( table_t* )libs; staticLib->pointer && staticLib->name; staticLib++ ) + { + if( !Q_strcmp( staticLib->name, name )) + return staticLib->pointer; + } + + return NULL; +} + +mod_handle_t *Module_Load( const char *name ) +{ + mod_handle_t *modHandle; + mod_func_t *modFunc; + qboolean skipPrefix; + char modStaticName[32]; + void *modArg; + SceUID modUid; + uint modSegAddr, modSegSize; + SceKernelModuleInfo info; + + if( !name ) + return NULL; + + modHandle = Module_Find( name ); + if( modHandle ) + return modHandle; + + skipPrefix = false; + modSegAddr = modSegSize = 0; + + modArg = &modFunc; + modUid = Platform_LoadModule( name, 0, sizeof( modArg ), &modArg ); + if( modUid < 0 ) + { + COM_FileBase( name, modStaticName ); + + if( !Q_strncmp( modStaticName, "lib", 3 ) ) + skipPrefix = true; + + modFunc = Module_LoadStatic( skipPrefix ? &modStaticName[3] : modStaticName ); + if( !modFunc ) + { + Module_Error( "module %s error ( %#010x )", name, modUid ); + return NULL; + } + + modUid = -1; + + Con_Reportf( "Module_Load( %s ): ( static ) success!\n", name ); + } + else + { + info.size = sizeof( info ); + if ( sceKernelQueryModuleInfo( modUid, &info ) >= 0 ) + { + if( info.nsegment > 0 ) + { + modSegAddr = info.segmentaddr[0]; + modSegSize = info.segmentsize[0]; + } + } + + Con_Reportf( "Module_Load( %s ): ( dynamic ) success!\n", name ); + } + + modHandle = calloc( 1, sizeof( mod_handle_t )); + if( !modHandle ) + { + Module_Error( "out of memory" ); + return NULL; + } + + Q_strncpy( modHandle->name, name, MOD_MAXNAMELEN ); + + modHandle->uid = modUid; + modHandle->func = modFunc; + modHandle->segAddr = modSegAddr; + modHandle->segSize = modSegSize; + modHandle->next = modList; + + modList = modHandle; + + return modHandle; +} + +void *Module_GetAddrByName( mod_handle_t *handle, const char *name ) +{ + mod_func_t *modFunc; + + if( !handle || !name ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + if( !Module_Name( handle )) + { + Module_SetError( "unknown handle" ); + return NULL; + } + + if( !handle->func ) + { + Module_SetError( "call Module_Load() first" ); + return NULL; + } + + for( modFunc = handle->func; modFunc->addr && modFunc->name; modFunc++ ) + { + if( !Q_strcmp( modFunc->name, name )) + return modFunc->addr; + } + + Module_Error( "func %s not found in %s", name, handle->name ); + + return NULL; +} + +const char *Module_GetNameByAddr( mod_handle_t *handle, const void *addr ) +{ + mod_func_t *modFunc; + + if( !handle || !addr ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + if( !Module_Name( handle )) + { + Module_SetError( "unknown handle" ); + return NULL; + } + + if( !handle->func ) + { + Module_SetError( "call Module_Load() first" ); + return NULL; + } + + for( modFunc = handle->func; modFunc->addr && modFunc->name; modFunc++ ) + { + if( modFunc->addr == addr ) + return modFunc->name; + } + + Module_Error( "addr %#010x not found in %s", addr, handle->name ); + + return NULL; +} + +uint Module_GetOffsetByAddr( mod_handle_t *handle, const void *addr ) +{ + uint addrUInt; + + if( !handle || !addr ) + { + Module_Error( "input mismatch" ); + return 0; + } + + if( !Module_Name( handle )) + { + Module_SetError( "unknown handle" ); + return 0; + } + + if( !handle->segAddr ) + { + Module_SetError( "unknown segment" ); + return 0; + } + + addrUInt = ( uint )addr; + if( addrUInt < handle->segAddr || addrUInt >= ( handle->segAddr + handle->segSize )) + { + Module_SetError( "addr %#010x is out of range", addrUInt ); + return 0; + } + + return addrUInt - handle->segAddr; +} + +void *Module_GetAddrByOffset( mod_handle_t *handle, uint offset ) +{ + if( !handle || !offset ) + { + Module_Error( "input mismatch" ); + return NULL; + } + + if( !Module_Name( handle )) + { + Module_SetError( "unknown handle" ); + return NULL; + } + + if( !handle->segAddr ) + { + Module_SetError( "unknown segment" ); + return NULL; + } + + if( offset >= handle->segSize ) + { + Module_SetError( "offset %#010x is out of range", offset ); + return NULL; + } + + return ( void* )( offset + handle->segAddr ); +} + +int Module_Unload( mod_handle_t *handle ) +{ + mod_handle_t *modHandle; + int result, sceCode; + + if( !handle ) + { + Module_Error( "input mismatch" ); + return -1; + } + + if( !Module_Name( handle )) + { + Module_Error( "unknown handle" ); + return -2; + } + + if( handle->uid != -1 ) + { + result = Platform_UnloadModule( handle->uid, &sceCode ); + if( result < 0 ) + { + if( result == -1 ) + Module_Error( "module %s doesn't want to stop", handle->name ); + else + Module_Error( "module %s error ( %#010x )", handle->name, sceCode ); + + return -3; + } + } + + if( handle != modList ) + { + for( modHandle = modList; modHandle; modHandle = modHandle->next ) + { + if( modHandle->next == handle ) + { + modHandle->next = handle->next; + break; + } + } + } + else modList = handle->next; + + free( handle ); + + return 0; +} + +qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname, qboolean directpath ) +{ + // TODO: implement + return true; +} + +void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath ) +{ + dll_user_t *hInst = NULL; + void *pHandle = NULL; + + COM_ResetLibraryError(); + + // platforms where gameinfo mechanism is working goes here + // and use FS_FindLibrary + hInst = FS_FindLibrary( dllname, directpath ); + if( !hInst ) + { + // try to find by linker(LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, LD_32_LIBRARY_PATH and so on...) + if( !pHandle ) + { + pHandle = Module_Load( dllname ); + if( pHandle ) + return pHandle; + + COM_PushLibraryError( va( "Failed to find library %s", dllname )); + COM_PushLibraryError( Module_GetError() ); + return NULL; + } + } + + if( hInst->custom_loader ) + { + COM_PushLibraryError( va( "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath )); + Mem_Free( hInst ); + return NULL; + } + + if( !( hInst->hInstance = Module_Load( hInst->fullPath ))) + { + COM_PushLibraryError( Module_GetError() ); + Mem_Free( hInst ); + return NULL; + } + + pHandle = hInst->hInstance; + + Mem_Free( hInst ); + + return pHandle; +} + +void COM_FreeLibrary( void *hInstance ) +{ + Module_Unload( hInstance ); +} + +void *COM_GetProcAddress( void *hInstance, const char *name ) +{ + return Module_GetAddrByName( hInstance, name ); +} + +void *COM_FunctionFromName_SR( void *hInstance, const char *pName ) +{ + void *funcAddr; + + if( !memcmp( pName, "ofs:", 4 )) + funcAddr = Module_GetAddrByOffset( hInstance, Q_atoi( &pName[4] )); + else + funcAddr = Module_GetAddrByName( hInstance, pName ); + + if( !funcAddr ) + Con_Reportf( S_ERROR "FunctionFromName: Can't get symbol %s: %s\n", pName, Module_GetError() ); + + return funcAddr; +} + +const char *COM_NameForFunction( void *hInstance, void *function ) +{ + static char offsetName[16]; + const char *funcName; + uint addrOffset; + + funcName = Module_GetNameByAddr( hInstance, function ); + if( funcName ) + return funcName; + + addrOffset = Module_GetOffsetByAddr( hInstance, function ); + if( !addrOffset ) + return NULL; + + Q_snprintf( offsetName, sizeof( offsetName ), "ofs:%u", addrOffset ); + Con_Reportf( "COM_NameForFunction: %s\n", offsetName ); + + return offsetName; +} +#endif // XASH_LIB == LIB_PSP From da695b75c42f0dc2cdd86d49d4d90dae346447bc Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 16 Jun 2022 14:08:01 +0300 Subject: [PATCH 36/84] engine: using MSGBOX in developer mode (Sys_Error) --- engine/common/system.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engine/common/system.c b/engine/common/system.c index 2268a8f0..cbd4de47 100644 --- a/engine/common/system.c +++ b/engine/common/system.c @@ -138,9 +138,9 @@ char *Sys_GetCurrentUser( void ) if( pw ) return pw->pw_name; #elif XASH_PSP - static char sys_nickname[128]; - if (sceUtilityGetSystemParamString(PSP_SYSTEMPARAM_ID_STRING_NICKNAME, sys_nickname, sizeof(sys_nickname)) == 0) - return sys_nickname; + static string s_userName; + if( sceUtilityGetSystemParamString( PSP_SYSTEMPARAM_ID_STRING_NICKNAME, s_userName, sizeof( s_userName )) == 0 ) + return s_userName; #endif return "Player"; } @@ -438,6 +438,7 @@ void Sys_Error( const char *error, ... ) #endif } +#if !XASH_PSP if( host_developer.value ) { #if XASH_WIN32 @@ -448,6 +449,7 @@ void Sys_Error( const char *error, ... ) Sys_WaitForQuit(); } else +#endif // XASH_PSP { #if XASH_WIN32 Wcon_ShowConsole( false ); From da68591f0345f0caeb2803671f8bc6694d0eea7c Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 16 Jun 2022 14:14:55 +0300 Subject: [PATCH 37/84] ref_gu: .bss size reduction --- ref_gu/gu_alias.c | 10 +++++++++- ref_gu/gu_studio.c | 39 ++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/ref_gu/gu_alias.c b/ref_gu/gu_alias.c index 0fa0693e..8ee371fa 100644 --- a/ref_gu/gu_alias.c +++ b/ref_gu/gu_alias.c @@ -22,6 +22,14 @@ GNU General Public License for more details. #include "pm_local.h" #include "pmtrace.h" +// Quake 1 +#undef MAXALIASVERTS +#undef MAXALIASFRAMES +#undef MAXALIASTRIS +#define MAXALIASVERTS 1024 +#define MAXALIASFRAMES 256 +#define MAXALIASTRIS 2048 + extern cvar_t r_shadows; typedef struct @@ -56,7 +64,7 @@ static aliashdr_t *m_pAliasHeader; static trivertex_t *g_poseverts[MAXALIASFRAMES]; static dtriangle_t g_triangles[MAXALIASTRIS]; static stvert_t g_stverts[MAXALIASVERTS]; -static int g_used[8192]; +static byte g_used[8192]; // a pose is a single set of vertexes. a frame may be // an animating sequence of poses diff --git a/ref_gu/gu_studio.c b/ref_gu/gu_studio.c index 3f51e662..1b8f6eaf 100644 --- a/ref_gu/gu_studio.c +++ b/ref_gu/gu_studio.c @@ -25,6 +25,11 @@ GNU General Public License for more details. //#include "client.h" #include "pmtrace.h" +//#define STUDIO_DRAWELEMENTS + +#undef MAXSTUDIOVERTS +#define MAXSTUDIOVERTS 1024 + #define EVENT_CLIENT 5000 // less than this value it's a server-side studio events #define MAX_LOCALLIGHTS 4 @@ -59,11 +64,6 @@ typedef struct sortedmesh_s int flags; // face flags } sortedmesh_t; -#if XASH_LOW_MEMORY - #undef MAXSTUDIOVERTS - #define MAXSTUDIOVERTS 1024 -#endif - typedef struct { double time; @@ -122,11 +122,14 @@ typedef struct // playermodels player_model_t player_models[MAX_CLIENTS]; +#ifdef STUDIO_DRAWELEMENTS // drawelements renderer gu_vert_ftcv_t arrayverts[MAXSTUDIOVERTS]; unsigned short arrayelems[MAXSTUDIOVERTS * 6]; uint numverts; uint numelems; +#endif // STUDIO_DRAWELEMENTS + } studio_draw_state_t; // studio-related cvars @@ -1914,7 +1917,7 @@ void R_StudioRenderShadow( int iSprite, float *p1, float *p2, float *p3, float * { TriRenderMode( kRenderTransAlpha ); TriColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); -#if 1 + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); out[0].uv[0] = 0.0f; out[0].uv[1] = 0.0f; @@ -1929,18 +1932,7 @@ void R_StudioRenderShadow( int iSprite, float *p1, float *p2, float *p3, float * out[3].uv[1] = 0.0f; VectorCopy( p4, out[3].xyz ); sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); -#else - pglBegin( GL_QUADS ); - pglTexCoord2f( 0.0f, 0.0f ); - pglVertex3fv( p1 ); - pglTexCoord2f( 0.0f, 1.0f ); - pglVertex3fv( p2 ); - pglTexCoord2f( 1.0f, 1.0f ); - pglVertex3fv( p3 ); - pglTexCoord2f( 1.0f, 0.0f ); - pglVertex3fv( p4 ); - pglEnd(); -#endif + TriRenderMode( kRenderNormal ); } } @@ -2108,7 +2100,7 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa } } - +#ifdef STUDIO_DRAWELEMENTS _inline int R_StudioBuildIndices( qboolean tri_strip, int vertexState ) { // build in indices @@ -2390,6 +2382,7 @@ _inline void R_StudioDrawArrays( uint startverts, uint startelems ) GU_VERTEX_32BITF | GU_INDEX_16BIT, g_studio.numelems - startelems, &g_studio.arrayelems[startelems], g_studio.arrayverts ); } +#endif // STUDIO_DRAWELEMENTS /* =============== @@ -2413,8 +2406,9 @@ static void R_StudioDrawPoints( void ) if( !m_pStudioHeader ) return; - +#ifdef STUDIO_DRAWELEMENTS g_studio.numverts = g_studio.numelems = 0; +#endif // STUDIO_DRAWELEMENTS // safety bounding the skinnum m_skinnum = bound( 0, RI.currententity->curstate.skin, ( m_pStudioHeader->numskinfamilies - 1 )); @@ -2513,8 +2507,10 @@ static void R_StudioDrawPoints( void ) for( j = 0; j < m_pSubModel->nummesh; j++ ) { float oldblend = tr.blend; +#ifdef STUDIO_DRAWELEMENTS uint startArrayVerts = g_studio.numverts; uint startArrayElems = g_studio.numelems; +#endif // STUDIO_DRAWELEMENTS short *ptricmds; float s, t; @@ -2549,7 +2545,7 @@ static void R_StudioDrawPoints( void ) } R_StudioSetupSkin( m_pStudioHeader, pskinref[pmesh->skinref] ); - +#ifdef STUDIO_DRAWELEMENTS if( CVAR_TO_BOOL(r_studio_drawelements) ) { if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) @@ -2561,6 +2557,7 @@ static void R_StudioDrawPoints( void ) R_StudioDrawArrays( startArrayVerts, startArrayElems ); } else +#endif // STUDIO_DRAWELEMENTS { if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); From 0277700977e4190412968d7fbed1a9281b7ed152 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 8 Jan 2021 00:25:14 +0300 Subject: [PATCH 38/84] gitignore: fix waf ignores --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0d6660b1..991ca01d 100644 --- a/.gitignore +++ b/.gitignore @@ -314,8 +314,8 @@ build-* # Waf build_current -\.?waf-*/ -\.?waf3-*/ +*waf-*/ +*waf3-*/ .lock-waf* *.lastbuildstate *.unsuccessfulbuild From b8ff41eac9989d5df14de6dfdeda2dd7ee3496a7 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 10 Aug 2022 16:49:49 +0300 Subject: [PATCH 39/84] psp: removed dll_psp.h --- engine/platform/psp/dll_psp.h | 38 ----------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 engine/platform/psp/dll_psp.h diff --git a/engine/platform/psp/dll_psp.h b/engine/platform/psp/dll_psp.h deleted file mode 100644 index 4fc7766e..00000000 --- a/engine/platform/psp/dll_psp.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DLL_PSP_H -#define DLL_PSP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#define RTLD_LAZY 0x0001 -#define RTLD_NOW 0x0002 - -typedef struct dllexport_s -{ - const char *name; - void *func; -} dllexport_t; - -typedef struct Dl_info_s -{ - void *dli_fhandle; - const char *dli_sname; - const void *dli_saddr; -} Dl_info; - -void *dlsym(void *handle, const char *symbol ); -void *dlopen(const char *name, int flag ); -int dlclose(void *handle); -char *dlerror( void ); -int dladdr( const void *addr, Dl_info *info ); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file From 91d6fdd190bfbbccbc17ecedda6d124fda5095c9 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 10 Aug 2022 16:58:20 +0300 Subject: [PATCH 40/84] psp: using the maximum amount of VRAM --- engine/platform/psp/ka/KernelAccess.S | 8 + engine/platform/psp/ka/ka.h | 30 +++ engine/platform/psp/sys_psp.c | 16 +- engine/wscript | 1 + ref_gu/gu_render.c | 6 + ref_gu/gu_vram.c | 255 +++++++++++++++----------- ref_gu/gu_vram.h | 2 + scripts/waifulib/xcompile.py | 1 + 8 files changed, 208 insertions(+), 111 deletions(-) create mode 100644 engine/platform/psp/ka/KernelAccess.S create mode 100644 engine/platform/psp/ka/ka.h diff --git a/engine/platform/psp/ka/KernelAccess.S b/engine/platform/psp/ka/KernelAccess.S new file mode 100644 index 00000000..44023056 --- /dev/null +++ b/engine/platform/psp/ka/KernelAccess.S @@ -0,0 +1,8 @@ + .set noreorder + +#include "pspstub.s" + + STUB_START "KernelAccess",0x40090000,0x00020005 + STUB_FUNC 0x8A5C745F,kaGeEdramSetSize + STUB_FUNC 0x71570ECF,kaGeEdramGetHwSize + STUB_END diff --git a/engine/platform/psp/ka/ka.h b/engine/platform/psp/ka/ka.h new file mode 100644 index 00000000..2e2238f9 --- /dev/null +++ b/engine/platform/psp/ka/ka.h @@ -0,0 +1,30 @@ +/* +kamod.h - kernel access module header +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef KAMOD_H +#define KAMOD_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int kaGeEdramSetSize(int size); +int kaGeEdramGetHwSize(void); + +#ifdef __cplusplus +} +#endif + +#endif // KAMOD_H diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index 561fb739..9c56ecc4 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -14,6 +14,7 @@ GNU General Public License for more details. */ #include "platform/platform.h" +#include "platform/psp/ka/ka.h" #include #include #include @@ -256,11 +257,14 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) return -1; *sce_code = sceKernelUnloadModule( modid ); - return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); + return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); } void Platform_Init( void ) { + SceUID kamID; + int result; + // disable fpu exceptions (division by zero and etc...) pspSdkDisableFPUExceptions(); @@ -269,6 +273,16 @@ void Platform_Init( void ) // set max cpu/gpu frequency scePowerSetClockFrequency( 333, 333, 166 ); + + // set max VRAM + kamID = Platform_LoadModule( "ka.prx", 1, 0, NULL ); + if( kamID >= 0 ) + { + result = kaGeEdramGetHwSize(); + if( result > 0 ) + result = kaGeEdramSetSize( result ); + Platform_UnloadModule( kamID, &result ); + } } void Platform_Shutdown( void ) diff --git a/engine/wscript b/engine/wscript index c230a68b..18e26531 100644 --- a/engine/wscript +++ b/engine/wscript @@ -137,6 +137,7 @@ def build(bld): if bld.env.DEST_OS == 'psp': source += bld.path.ant_glob(['platform/psp/*.c']) + source += bld.path.ant_glob(['platform/psp/*/*.S']) # add client files if not bld.env.DEDICATED: diff --git a/ref_gu/gu_render.c b/ref_gu/gu_render.c index 57312499..3727fcd1 100644 --- a/ref_gu/gu_render.c +++ b/ref_gu/gu_render.c @@ -417,6 +417,12 @@ qboolean R_Init( void ) if( glw_state.initialized ) return true; + if( vinit() < 0 ) + { + gEngfuncs.Host_Error( "Can't initialize video subsystem\nVRam unavailable" ); + return false; + } + GL_InitCommands(); GL_InitRandomTable(); diff --git a/ref_gu/gu_vram.c b/ref_gu/gu_vram.c index ee8ac5e8..d589eef4 100644 --- a/ref_gu/gu_vram.c +++ b/ref_gu/gu_vram.c @@ -10,20 +10,31 @@ */ #include "gu_vram.h" #include +#include +#include + +#define _MBEINVRAM +//#define _DEBUG // Configure the memory to be managed -#define __MEM_SIZE 0x00200000 -#define __MEM_START 0x04000000 +static unsigned int __mem_size = 0; +static unsigned int __mem_start = 0; +static int __mem_num_blocks = 0; + +static unsigned int *__mem_blocks; + +static int __largest_update = 0; +static int __largest_block = 0; +static int __mem_free = 0; // Configure the block size the memory gets subdivided into (page size) -// __MEM_SIZE/__BLOCK_SIZE may not exceed 2^16-1 = 65535 +// __mem_size/__BLOCK_SIZE may not exceed 2^16-1 = 65535 // The block size also defines the alignment of allocations // Larger block sizes perform better, because the blocktable is smaller and therefore fits better into cache // however the overhead is also bigger and more memory is wasted -#define __BLOCK_SIZE 512 -#define __MEM_BLOCKS (__MEM_SIZE/__BLOCK_SIZE) -#define __BLOCKS(x) ((x+__BLOCK_SIZE-1)/__BLOCK_SIZE) -#define __BLOCKSIZE(x) ((x+__BLOCK_SIZE-1)&~(__BLOCK_SIZE-1)) +#define __BLOCK_SIZE 512 +#define __BLOCKS(x) (( x + __BLOCK_SIZE - 1 ) / __BLOCK_SIZE ) +#define __BLOCKSIZE(x) (( x + __BLOCK_SIZE - 1 ) & ~( __BLOCK_SIZE - 1 )) // A MEMORY BLOCK ENTRY IS MADE UP LIKE THAT: @@ -37,36 +48,56 @@ // // This management can handle a max amount of 2^16-1 = 65535 blocks, which resolves to 64MB at blocksize of 1024 bytes // -#define __BLOCK_GET_SIZE(x) ((x & 0x7FFF)) -#define __BLOCK_GET_PREV(x) ((x >> 15) & 0x7FFF) -#define __BLOCK_GET_FREE(x) ((x >> 31)) -#define __BLOCK_GET_BLOCK(x) ((x >> 30) & 0x1) -#define __BLOCK_SET_SIZE(x,y) x=((x & ~0x7FFF) | ((y) & 0x7FFF)) -#define __BLOCK_ADD_SIZE(x,y) x=((x & ~0x7FFF) | (((x & 0x7FFF)+((y) & 0x7FFF)) & 0x7FFF)) -#define __BLOCK_SET_PREV(x,y) x=((x & ~0x3FFF8000) | (((y) & 0x7FFF)<<15)) -#define __BLOCK_SET_FREE(x,y) x=((x & 0x7FFFFFFF) | (((y) & 0x1)<<31)) -#define __BLOCK_SET_BLOCK(x,y) x=((x & 0xBFFFFFFF) | (((y) & 0x1)<<30)) -#define __BLOCK_MAKE(s,p,f,n) (((f & 0x1)<<31) | ((n & 0x1)<<30) | (((p) & 0x7FFF)<<15) | ((s) & 0x7FFF)) -#define __BLOCK_GET_FREEBLOCK(x) ((x>>30) & 0x3) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change) -#define __BLOCK0 ((__MEM_BLOCKS) | (1<<31) | (1<<30)) +#define __BLOCK_GET_SIZE( x ) (( x & 0x7FFF )) +#define __BLOCK_GET_PREV( x ) (( x >> 15 ) & 0x7FFF ) +#define __BLOCK_GET_FREE( x ) (( x >> 31 )) +#define __BLOCK_GET_BLOCK( x ) (( x >> 30) & 0x1 ) +#define __BLOCK_SET_SIZE( x, y ) x = (( x & ~0x7FFF ) | (( y ) & 0x7FFF )) +#define __BLOCK_ADD_SIZE( x, y ) x = (( x & ~0x7FFF ) | ((( x & 0x7FFF ) + (( y ) & 0x7FFF )) & 0x7FFF )) +#define __BLOCK_SET_PREV( x, y ) x = (( x & ~0x3FFF8000 ) | ((( y ) & 0x7FFF ) << 15 )) +#define __BLOCK_SET_FREE( x, y ) x = (( x & 0x7FFFFFFF ) | ((( y ) & 0x1 ) << 31 )) +#define __BLOCK_SET_BLOCK( x, y ) x = (( x & 0xBFFFFFFF ) | ((( y ) & 0x1 ) << 30 )) +#define __BLOCK_MAKE( s, p, f, n ) ((( f & 0x1 ) << 31 ) | (( n & 0x1 ) << 30 ) | ((( p ) & 0x7FFF ) << 15 ) | (( s ) & 0x7FFF )) +#define __BLOCK_GET_FREEBLOCK( x ) (( x >> 30 ) & 0x3 ) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change) +#define __BLOCK0 (( __mem_num_blocks ) | ( 1 << 31 ) | ( 1 << 30 )) +int vinit( void ) +{ + if( __mem_start ) return 0; -unsigned int __mem_blocks[__MEM_BLOCKS] = { 0 }; + __mem_size = sceGeEdramGetSize(); + __mem_start = ( unsigned int )sceGeEdramGetAddr(); +#ifdef _MBEINVRAM + __mem_num_blocks = __mem_size / ( __BLOCK_SIZE + sizeof( unsigned int )); + __mem_size = __mem_num_blocks * __BLOCK_SIZE; + __mem_blocks = ( unsigned int* )( __mem_start + __mem_size ); // to end +#else + __mem_num_blocks = __mem_size / __BLOCK_SIZE; + __mem_blocks = ( unsigned int* )calloc( __mem_num_blocks, sizeof( unsigned int )); + if( !__mem_blocks ) + { + __mem_size = 0; + __mem_start = 0; + return -1; + } +#endif + __largest_block = __mem_num_blocks; + __mem_free = __mem_num_blocks; - -static int __largest_update = 0; -static int __largest_block = __MEM_BLOCKS; -static int __mem_free = __MEM_BLOCKS; + return 0; +} inline void* vrelptr( void *ptr ) { - return (void*)((unsigned int)ptr & ~__MEM_START); + if( !__mem_start ) return NULL; + return ( void* )(( unsigned int )ptr & ~__mem_start ); } inline void* vabsptr( void *ptr ) { - return (void*)((unsigned int)ptr | __MEM_START); + if( !__mem_start ) return NULL; + return ( void* )(( unsigned int )ptr | __mem_start ); } @@ -74,10 +105,10 @@ static void __find_largest_block( void ) { int i = 0; __largest_block = 0; - while (i<__MEM_BLOCKS) + while( i < __mem_num_blocks ) { - int csize = __BLOCK_GET_SIZE(__mem_blocks[i]); - if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>__largest_block) + int csize = __BLOCK_GET_SIZE( __mem_blocks[i] ); + if( __BLOCK_GET_FREEBLOCK( __mem_blocks[i] ) == 3 && csize > __largest_block ) __largest_block = csize; i += csize; } @@ -88,158 +119,161 @@ static void __find_largest_block( void ) void __memwalk( void ) { int i = 0; - if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0; - while (i<__MEM_BLOCKS) + if( !__mem_start ) return; + if( __mem_blocks[0] == 0 ) __mem_blocks[0] = __BLOCK0; + while( i < __mem_num_blocks ) { - printf("BLOCK %i:\n", i); - printf(" free: %i\n", __BLOCK_GET_FREEBLOCK(__mem_blocks[i])); - printf(" size: %i\n", __BLOCK_GET_SIZE(__mem_blocks[i])); - printf(" prev: %i\n", __BLOCK_GET_PREV(__mem_blocks[i])); - i+=__BLOCK_GET_SIZE(__mem_blocks[i]); + printf( "BLOCK %i:\n", i ); + printf( " free: %i\n", __BLOCK_GET_FREEBLOCK( __mem_blocks[i] )); + printf( " size: %i\n", __BLOCK_GET_SIZE( __mem_blocks[i] )); + printf( " prev: %i\n", __BLOCK_GET_PREV( __mem_blocks[i] )); + i += __BLOCK_GET_SIZE( __mem_blocks[i] ); } } #endif void* valloc( size_t size ) { + if( !__mem_start ) return NULL; + // Initialize memory block, if not yet done - if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0; - + if( __mem_blocks[0] == 0 ) __mem_blocks[0] = __BLOCK0; + int i = 0; int j = 0; - int bsize = __BLOCKS(size); - - if (__largest_update==0 && __largest_block=bsize) + int csize = __BLOCK_GET_SIZE( __mem_blocks[i] ); + if( __BLOCK_GET_FREEBLOCK( __mem_blocks[i] ) == 3 && csize >= bsize ) { - if (csizebsize && next<__MEM_BLOCKS) + __mem_blocks[i] = __BLOCK_MAKE( bsize, j, 0, 1 ); + + int next = i + bsize; + if( csize > bsize && next < __mem_num_blocks ) { - __mem_blocks[next] = __BLOCK_MAKE(csize-bsize,i,1,1); - int nextnext = i+csize; - if (nextnext<__MEM_BLOCKS) + __mem_blocks[next] = __BLOCK_MAKE( csize - bsize, i, 1, 1 ); + int nextnext = i + csize; + if ( nextnext < __mem_num_blocks ) { - __BLOCK_SET_PREV(__mem_blocks[nextnext], next); + __BLOCK_SET_PREV( __mem_blocks[nextnext], next ); } } __mem_free -= bsize; - if (__largest_block==csize) // if we just allocated from one of the largest blocks + if( __largest_block == csize ) // if we just allocated from one of the largest blocks { - if ((csize-bsize)>(__mem_free/2)) - __largest_block = (csize-bsize); // there can't be another largest block + if(( csize - bsize ) > ( __mem_free / 2 )) + __largest_block = ( csize - bsize ); // there can't be another largest block else __largest_update = 1; } - return ((void*)(__MEM_START + (i*__BLOCK_SIZE))); + return (( void* )( __mem_start + ( i * __BLOCK_SIZE ))); } void vfree( void* ptr ) { - if (ptr==0) return; + if( ptr == 0 ) return; - int block = ((unsigned int)ptr - __MEM_START)/__BLOCK_SIZE; - if (block<0 || block>__MEM_BLOCKS) + int block = (( unsigned int )ptr - __mem_start ) / __BLOCK_SIZE; + if( block < 0 || block > __mem_num_blocks ) { - #ifdef _DEBUG - printf("Block is out of range: %i (0x%x)\n", block, (int)ptr); - #endif +#ifdef _DEBUG + printf( "Block is out of range: %i (0x%x)\n", block, (int)ptr ); +#endif return; } - int csize = __BLOCK_GET_SIZE(__mem_blocks[block]); - #ifdef _DEBUG + int csize = __BLOCK_GET_SIZE( __mem_blocks[block] ); +#ifdef _DEBUG printf("freeing block %i (0x%x), size: %i\n", block, (int)ptr, csize); - #endif +#endif - if (__BLOCK_GET_FREEBLOCK(__mem_blocks[block])!=1 || csize==0) + if( __BLOCK_GET_FREEBLOCK( __mem_blocks[block] ) != 1 || csize == 0 ) { - #ifdef _DEBUG - printf("Block was not allocated!\n"); - #endif +#ifdef _DEBUG + printf( "Block was not allocated!\n" ); +#endif return; } - + // Mark block as free - __BLOCK_SET_FREE(__mem_blocks[block],1); + __BLOCK_SET_FREE( __mem_blocks[block], 1 ); __mem_free += csize; - - int next = block+csize; + + int next = block + csize; // Merge with previous block if possible - int prev = __BLOCK_GET_PREV(__mem_blocks[block]); - if (prev Date: Tue, 30 Aug 2022 16:47:03 +0300 Subject: [PATCH 41/84] engine: .bss size reduction for PSP --- engine/client/s_load.c | 4 ++++ engine/client/sound.h | 5 +++++ ref_gu/gu_local.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/engine/client/s_load.c b/engine/client/s_load.c index cb4573bf..e319da39 100644 --- a/engine/client/s_load.c +++ b/engine/client/s_load.c @@ -20,7 +20,11 @@ GNU General Public License for more details. // than could actually be referenced during gameplay, // because we don't want to free anything until we are // sure we won't need it. +#if XASH_PSP +#define MAX_SFX 2048 +#else #define MAX_SFX 8192 +#endif #define MAX_SFX_HASH (MAX_SFX/4) static int s_numSfx = 0; diff --git a/engine/client/sound.h b/engine/client/sound.h index fba869f7..09f75213 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -201,8 +201,13 @@ typedef struct //==================================================================== +#if XASH_PSP +#define MAX_DYNAMIC_CHANNELS (20 + NUM_AMBIENTS) +#define MAX_CHANNELS (128 + MAX_DYNAMIC_CHANNELS) +#else #define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS) #define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp +#endif #define MAX_RAW_CHANNELS 16 #define MAX_RAW_SAMPLES 8192 diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 28f09ddd..200282b8 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -67,7 +67,7 @@ GNU General Public License for more details. extern byte *r_temppool; -#define LIGHTMAP_BPP 2 //1 2 3 4 +#define LIGHTMAP_BPP 1 //1 2 3 4 #if LIGHTMAP_BPP == 1 #define LIGHTMAP_FORMAT PF_RGB_332 From 3afc7134abaadd18e583e119062d06da53d9dc12 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 5 Sep 2022 11:57:37 +0300 Subject: [PATCH 42/84] ref_gu: efx optimization --- ref_gu/gu_beams.c | 550 +++++++++++++++++---------------------------- ref_gu/gu_local.h | 1 + ref_gu/gu_render.c | 2 + ref_gu/gu_rpart.c | 254 +++++++++------------ ref_gu/gu_sprite.c | 40 +--- 5 files changed, 326 insertions(+), 521 deletions(-) diff --git a/ref_gu/gu_beams.c b/ref_gu/gu_beams.c index aedbde39..7e9d8357 100644 --- a/ref_gu/gu_beams.c +++ b/ref_gu/gu_beams.c @@ -47,7 +47,7 @@ static float rgNoise[NOISE_DIVISIONS+1]; // global noise array static void FracNoise( float *noise, int divs ) { int div2; - + div2 = divs >> 1; if( divs < 2 ) return; @@ -198,7 +198,9 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f float flMaxWidth, vLast, vStep, brightness; vec3_t perp1, vLastNormal; beamseg_t curSeg; - + uint vert_count; + uint vert_color; + if( segments < 2 ) return; length = VectorLength( delta ); @@ -250,17 +252,18 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f total_segs = segments; segs_drawn = 0; -#if 1 - gu_vert_ftcnv_t* const out = ( gu_vert_ftcnv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; - unsigned int vert_color = 0; -#endif + + gu_vert_ftcnv_t* const out = ( gu_vert_ftcnv_t* )extGuBeginPacket( NULL ); + + vert_count = 0; + vert_color = 0; + // specify all the segments. for( i = 0; i < segments; i++ ) { beamseg_t nextSeg; vec3_t vPoint1, vPoint2; - + Assert( noiseIndex < ( NOISE_DIVISIONS << 16 )); fraction = i * div; @@ -317,39 +320,28 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f // draw regular segment VectorMA( curSeg.pos, ( curSeg.width * 0.5f ), vAveNormal, vPoint1 ); VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vAveNormal, vPoint2 ); -#if 1 - vert_color = getTriBrightness( brightness ); - out[vert_size].u = 0.0f; - out[vert_size].v = curSeg.texcoord; - out[vert_size].c = vert_color; - out[vert_size].nx = vAveNormal[0]; - out[vert_size].ny = vAveNormal[1]; - out[vert_size].nz = vAveNormal[2]; - out[vert_size].x = vPoint1[0]; - out[vert_size].y = vPoint1[1]; - out[vert_size].z = vPoint1[2]; - vert_size++; - out[vert_size].u = 1.0f; - out[vert_size].v = curSeg.texcoord; - out[vert_size].c = vert_color; - out[vert_size].nx = vAveNormal[0]; - out[vert_size].ny = vAveNormal[1]; - out[vert_size].nz = vAveNormal[2]; - out[vert_size].x = vPoint2[0]; - out[vert_size].y = vPoint2[1]; - out[vert_size].z = vPoint2[2]; - vert_size++; -#else - pglTexCoord2f( 0.0f, curSeg.texcoord ); - TriBrightness( brightness ); - pglNormal3fv( vAveNormal ); - pglVertex3fv( vPoint1 ); - pglTexCoord2f( 1.0f, curSeg.texcoord ); - TriBrightness( brightness ); - pglNormal3fv( vAveNormal ); - pglVertex3fv( vPoint2 ); -#endif + vert_color = getTriBrightness( brightness ); + out[vert_count].u = 0.0f; + out[vert_count].v = curSeg.texcoord; + out[vert_count].c = vert_color; + out[vert_count].nx = vAveNormal[0]; + out[vert_count].ny = vAveNormal[1]; + out[vert_count].nz = vAveNormal[2]; + out[vert_count].x = vPoint1[0]; + out[vert_count].y = vPoint1[1]; + out[vert_count].z = vPoint1[2]; + vert_count++; + out[vert_count].u = 1.0f; + out[vert_count].v = curSeg.texcoord; + out[vert_count].c = vert_color; + out[vert_count].nx = vAveNormal[0]; + out[vert_count].ny = vAveNormal[1]; + out[vert_count].nz = vAveNormal[2]; + out[vert_count].x = vPoint2[0]; + out[vert_count].y = vPoint2[1]; + out[vert_count].z = vPoint2[2]; + vert_count++; } curSeg = nextSeg; @@ -376,48 +368,35 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vLastNormal, vPoint2 ); // specify the points. -#if 1 vert_color = getTriBrightness( brightness ); - out[vert_size].u = 0.0f; - out[vert_size].v = curSeg.texcoord; - out[vert_size].c = vert_color; - out[vert_size].nx = vLastNormal[0]; - out[vert_size].ny = vLastNormal[1]; - out[vert_size].nz = vLastNormal[2]; - out[vert_size].x = vPoint1[0]; - out[vert_size].y = vPoint1[1]; - out[vert_size].z = vPoint1[2]; - vert_size++; - out[vert_size].u = 1.0f; - out[vert_size].v = curSeg.texcoord; - out[vert_size].c = vert_color; - out[vert_size].nx = vLastNormal[0]; - out[vert_size].ny = vLastNormal[1]; - out[vert_size].nz = vLastNormal[2]; - out[vert_size].x = vPoint2[0]; - out[vert_size].y = vPoint2[1]; - out[vert_size].z = vPoint2[2]; - vert_size++; -#else - pglTexCoord2f( 0.0f, curSeg.texcoord ); - TriBrightness( brightness ); - pglNormal3fv( vLastNormal ); - pglVertex3fv( vPoint1 ); - - pglTexCoord2f( 1.0f, curSeg.texcoord ); - TriBrightness( brightness ); - pglNormal3fv( vLastNormal ); - pglVertex3fv( vPoint2 ); -#endif + out[vert_count].u = 0.0f; + out[vert_count].v = curSeg.texcoord; + out[vert_count].c = vert_color; + out[vert_count].nx = vLastNormal[0]; + out[vert_count].ny = vLastNormal[1]; + out[vert_count].nz = vLastNormal[2]; + out[vert_count].x = vPoint1[0]; + out[vert_count].y = vPoint1[1]; + out[vert_count].z = vPoint1[2]; + vert_count++; + out[vert_count].u = 1.0f; + out[vert_count].v = curSeg.texcoord; + out[vert_count].c = vert_color; + out[vert_count].nx = vLastNormal[0]; + out[vert_count].ny = vLastNormal[1]; + out[vert_count].nz = vLastNormal[2]; + out[vert_count].x = vPoint2[0]; + out[vert_count].y = vPoint2[1]; + out[vert_count].z = vPoint2[2]; + vert_count++; } vLast += vStep; // Advance texture scroll (v axis only) noiseIndex += noiseStep; } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_NORMAL_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_NORMAL_32BITF | GU_VERTEX_32BITF, vert_count, 0, out ); } /* @@ -432,6 +411,7 @@ void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float f int i, noiseIndex, noiseStep; float div, length, fraction, factor, vLast, vStep; vec3_t last1, last2, point, screen, screenLast, tmp, normal; + uint vert_count = 0; if( segments < 2 ) return; @@ -453,10 +433,11 @@ void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float f // Iterator to resample noise waveform (it needs to be generated in powers of 2) noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f ); noiseIndex = 0; -#if 1 - gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; -#endif + + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )extGuBeginPacket( NULL ); + + vert_count = 0; + for( i = 0; i < segments; i++ ) { float s, c; @@ -481,7 +462,7 @@ void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float f VectorMA( point, factor, RI.vright, point ); } } - + // Transform point into screen space TriWorldToScreen( point, screen ); @@ -495,40 +476,33 @@ void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float f VectorNormalize( tmp ); VectorScale( RI.vup, -tmp[0], normal ); // Build point along noraml line (normal is -y, x) VectorMA( normal, tmp[1], RI.vright, normal ); - + // Make a wide line VectorMA( point, width, normal, last1 ); VectorMA( point, -width, normal, last2 ); vLast += vStep; // advance texture scroll (v axis only) -#if 1 - out[vert_size].u = 1.0f; - out[vert_size].v = vLast; - out[vert_size].x = last2[0]; - out[vert_size].y = last2[1]; - out[vert_size].z = last2[2]; - vert_size++; - out[vert_size].u = 0.0f; - out[vert_size].v = vLast; - out[vert_size].x = last1[0]; - out[vert_size].y = last1[1]; - out[vert_size].z = last1[2]; - vert_size++; -#else - TriTexCoord2f( 1, vLast ); - TriVertex3fv( last2 ); - TriTexCoord2f( 0, vLast ); - TriVertex3fv( last1 ); -#endif + + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].x = last2[0]; + out[vert_count].y = last2[1]; + out[vert_count].z = last2[2]; + vert_count++; + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].x = last1[0]; + out[vert_count].y = last1[1]; + out[vert_count].z = last1[2]; + vert_count++; } VectorCopy( screen, screenLast ); noiseIndex += noiseStep; } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_count, 0, out ); } /* @@ -542,8 +516,9 @@ void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float fr { float div, length, fraction; float w, vLast, vStep; - vec3_t point; int i; + uint vert_count; + uint vert_color; if( segments < 2 ) return; @@ -553,69 +528,52 @@ void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float fr length = VectorLength( delta ) * 0.01f; if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams - + div = 1.0f / (segments - 1); vStep = length * div; // Texture length texels per space pixel - + // scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1 ); scale = scale * length; // clamp the beam width w = fmod( freq, width * 0.1f ) * delta[2]; -#if 1 - gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; - unsigned int vert_color = getTriBrightness( 1.0f ); -#endif + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + + vert_count = 0; + vert_color = getTriBrightness( 1.0f ); + // NOTE: we must force the degenerate triangles to be on the edge for( i = 0; i < segments; i++ ) { float s, c; fraction = i * div; - VectorCopy( source, point ); -#if 1 - out[vert_size].u = 1.0f; - out[vert_size].v = vLast; - out[vert_size].c = vert_color; - out[vert_size].x = point[0]; - out[vert_size].y = point[1]; - out[vert_size].z = point[2]; - vert_size++; + + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = source[0]; + out[vert_count].y = source[1]; + out[vert_count].z = source[2]; + vert_count++; SinCos( fraction * M_PI2_F, &s, &c ); - point[0] = s * w + source[0]; - point[1] = c * w + source[1]; - point[2] = source[2]; - out[vert_size].u = 0.0f; - out[vert_size].v = vLast; - out[vert_size].c = vert_color; - out[vert_size].x = point[0]; - out[vert_size].y = point[1]; - out[vert_size].z = point[2]; - vert_size++; -#else - TriBrightness( 1.0f ); - TriTexCoord2f( 1.0f, vLast ); - TriVertex3fv( point ); + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = s * w + source[0]; + out[vert_count].y = c * w + source[1]; + out[vert_count].z = source[2]; + vert_count++; - SinCos( fraction * M_PI2_F, &s, &c ); - point[0] = s * w + source[0]; - point[1] = c * w + source[1]; - point[2] = source[2]; - - TriBrightness( 1.0f ); - TriTexCoord2f( 0.0f, vLast ); - TriVertex3fv( point ); -#endif vLast += vStep; // advance texture scroll (v axis only) } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out ); } /* @@ -629,8 +587,10 @@ void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, floa { float div, length, fraction; float vLast, vStep; - vec3_t point; int i; + uint vert_count; + uint vert_color0; + uint vert_color1; if( segments < 2 ) return; @@ -640,19 +600,20 @@ void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, floa length = VectorLength( delta ) * 0.01f; if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams - + div = 1.0f / (segments - 1); vStep = length * div; // texture length texels per space pixel - + // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1 ); scale = scale * length; -#if 1 + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; - unsigned int vert_color0 = getTriBrightness( 0.0f ); - unsigned int vert_color1 = getTriBrightness( 1.0f ); -#endif + + vert_count = 0; + vert_color0 = getTriBrightness( 0.0f ); + vert_color1 = getTriBrightness( 1.0f ); + for ( i = 0; i < segments; i++ ) { float s, c; @@ -660,48 +621,26 @@ void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, floa fraction = i * div; SinCos( fraction * M_PI2_F, &s, &c ); - point[0] = s * freq * delta[2] + source[0]; - point[1] = c * freq * delta[2] + source[1]; - point[2] = source[2] + width; -#if 1 - out[vert_size].u = 1.0f; - out[vert_size].v = vLast; - out[vert_size].c = vert_color0; - out[vert_size].x = point[0]; - out[vert_size].y = point[1]; - out[vert_size].z = point[2]; - vert_size++; - - point[0] = s * freq * ( delta[2] + width ) + source[0]; - point[1] = c * freq * ( delta[2] + width ) + source[1]; - point[2] = source[2] - width; + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color0; + out[vert_count].x = s * freq * delta[2] + source[0]; + out[vert_count].y = c * freq * delta[2] + source[1]; + out[vert_count].z = source[2] + width; + vert_count++; + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color1; + out[vert_count].x = s * freq * ( delta[2] + width ) + source[0]; + out[vert_count].y = c * freq * ( delta[2] + width ) + source[1]; + out[vert_count].z = source[2] - width; + vert_count++; - out[vert_size].u = 0.0f; - out[vert_size].v = vLast; - out[vert_size].c = vert_color1; - out[vert_size].x = point[0]; - out[vert_size].y = point[1]; - out[vert_size].z = point[2]; - vert_size++; -#else - TriBrightness( 0 ); - TriTexCoord2f( 1, vLast ); - TriVertex3fv( point ); - - point[0] = s * freq * ( delta[2] + width ) + source[0]; - point[1] = c * freq * ( delta[2] + width ) + source[1]; - point[2] = source[2] - width; - - TriBrightness( 1 ); - TriTexCoord2f( 0, vLast ); - TriVertex3fv( point ); -#endif vLast += vStep; // Advance texture scroll (v axis only) } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out ); } /* @@ -717,6 +656,8 @@ void R_DrawBeamFollow( BEAM *pbeam, float frametime ) float fraction, div, vLast, vStep; vec3_t last1, last2, tmp, screen; vec3_t delta, screenLast, normal; + uint vert_count; + uint vert_color; gEngfuncs.R_FreeDeadParticles( &pbeam->particles ); @@ -786,7 +727,7 @@ void R_DrawBeamFollow( BEAM *pbeam, float frametime ) // Build point along noraml line (normal is -y, x) VectorScale( RI.vup, tmp[0], normal ); // Build point along normal line (normal is -y, x) VectorMA( normal, tmp[1], RI.vright, normal ); - + // Make a wide line VectorMA( delta, pbeam->width, normal, last1 ); VectorMA( delta, -pbeam->width, normal, last2 ); @@ -796,41 +737,30 @@ void R_DrawBeamFollow( BEAM *pbeam, float frametime ) vLast = 0.0f; vStep = 1.0f; - -#if 1 + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; - unsigned int vert_color = 0; - gu_vert_ftcv_t* saved_ptr; -#endif + + vert_count = 0; + vert_color = 0; + + vert_color = getTriBrightness( fraction ); + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = last2[0]; + out[vert_count].y = last2[1]; + out[vert_count].z = last2[2]; + vert_count++; + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = last1[0]; + out[vert_count].y = last1[1]; + out[vert_count].z = last1[2]; + vert_count++; while( particles ) { -#if 1 - vert_color = getTriBrightness( fraction ); - out[vert_size].u = 1.0f; - out[vert_size].v = 1.0f; - out[vert_size].c = vert_color; - out[vert_size].x = last2[0]; - out[vert_size].y = last2[1]; - out[vert_size].z = last2[2]; - saved_ptr = &out[vert_size]; - vert_size++; - out[vert_size].u = 0.0f; - out[vert_size].v = 1.0f; - out[vert_size].c = vert_color; - out[vert_size].x = last1[0]; - out[vert_size].y = last1[1]; - out[vert_size].z = last1[2]; - vert_size++; -#else - TriBrightness( fraction ); - TriTexCoord2f( 1, 1 ); - TriVertex3fv( last2 ); - TriBrightness( fraction ); - TriTexCoord2f( 0, 1 ); - TriVertex3fv( last1 ); -#endif // Transform point into screen space TriWorldToScreen( particles->org, screen ); // Build world-space normal to screen-space direction vector @@ -845,7 +775,7 @@ void R_DrawBeamFollow( BEAM *pbeam, float frametime ) // Make a wide line VectorMA( particles->org, pbeam->width, normal, last1 ); VectorMA( particles->org, -pbeam->width, normal, last2 ); - + vLast += vStep; // Advance texture scroll (v axis only) if( particles->next != NULL ) @@ -856,55 +786,31 @@ void R_DrawBeamFollow( BEAM *pbeam, float frametime ) { fraction = 0.0; } -#if 1 - vert_color = getTriBrightness( fraction ); - out[vert_size].u = 0.0f; - out[vert_size].v = 0.0f; - out[vert_size].c = vert_color; - out[vert_size].x = last1[0]; - out[vert_size].y = last1[1]; - out[vert_size].z = last1[2]; - vert_size++; - - out[vert_size].u = saved_ptr->u; - out[vert_size].v = saved_ptr->v; - out[vert_size].c = saved_ptr->c; - out[vert_size].x = saved_ptr->x; - out[vert_size].y = saved_ptr->y; - out[vert_size].z = saved_ptr->z; - vert_size++; - out[vert_size].u = 0.0f; - out[vert_size].v = 0.0f; - out[vert_size].c = vert_color; - out[vert_size].x = last1[0]; - out[vert_size].y = last1[1]; - out[vert_size].z = last1[2]; - vert_size++; - - out[vert_size].u = 1.0f; - out[vert_size].v = 0.0f; - out[vert_size].c = vert_color; - out[vert_size].x = last2[0]; - out[vert_size].y = last2[1]; - out[vert_size].z = last2[2]; - vert_size++; -#else - TriBrightness( fraction ); - TriTexCoord2f( 0, 0 ); - TriVertex3fv( last1 ); - TriBrightness( fraction ); - TriTexCoord2f( 1, 0 ); - TriVertex3fv( last2 ); -#endif + vert_color = getTriBrightness( fraction ); + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = last2[0]; + out[vert_count].y = last2[1]; + out[vert_count].z = last2[2]; + vert_count++; + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].c = vert_color; + out[vert_count].x = last1[0]; + out[vert_count].y = last1[1]; + out[vert_count].z = last1[2]; + vert_count++; + VectorCopy( screen, screenLast ); particles = particles->next; } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out ); + // drift popcorn trail if there is a velocity particles = pbeam->particles; @@ -929,19 +835,20 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa vec3_t last1, last2, point, screen, screenLast; vec3_t tmp, normal, center, xaxis, yaxis; float radius, x, y, scale; + uint vert_count; if( segments < 2 ) return; VectorClear( screenLast ); segments = segments * M_PI_F; - + if( segments > NOISE_DIVISIONS * 8 ) segments = NOISE_DIVISIONS * 8; length = VectorLength( delta ) * 0.01f * M_PI_F; if( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams - + div = 1.0f / ( segments - 1 ); vStep = length * div / 8.0f; // texture length texels per space pixel @@ -959,7 +866,7 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa VectorCopy( delta, xaxis ); radius = VectorLength( xaxis ); - + // cull beamring // -------------------------------- // Compute box center +/- radius @@ -976,21 +883,22 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa return; } - VectorSet( yaxis, xaxis[1], -xaxis[0], 0.0f ); + VectorSet( yaxis, xaxis[1], -xaxis[0], 0.0f ); VectorNormalize( yaxis ); VectorScale( yaxis, radius, yaxis ); j = segments / 8; -#if 1 + gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; -#endif + + vert_count = 0; + for( i = 0; i < segments + 1; i++ ) { fraction = i * div; SinCos( fraction * M_PI2_F, &x, &y ); - VectorMAMAM( x, xaxis, y, yaxis, 1.0f, center, point ); + VectorMAMAM( x, xaxis, y, yaxis, 1.0f, center, point ); // distort using noise factor = rgNoise[(noiseIndex >> 16) & (NOISE_DIVISIONS - 1)] * scale; @@ -1000,7 +908,7 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa factor = rgNoise[(noiseIndex >> 16) & (NOISE_DIVISIONS - 1)] * scale; factor *= cos( fraction * M_PI_F * 24 + freq ); VectorMA( point, factor, RI.vright, point ); - + // Transform point into screen space TriWorldToScreen( point, screen ); @@ -1016,31 +924,25 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa // Build point along normal line (normal is -y, x) VectorScale( RI.vup, tmp[0], normal ); VectorMA( normal, tmp[1], RI.vright, normal ); - + // Make a wide line VectorMA( point, width, normal, last1 ); VectorMA( point, -width, normal, last2 ); vLast += vStep; // Advance texture scroll (v axis only) -#if 1 - out[vert_size].u = 1.0f; - out[vert_size].v = vLast; - out[vert_size].x = last2[0]; - out[vert_size].y = last2[1]; - out[vert_size].z = last2[2]; - vert_size++; - out[vert_size].u = 0.0f; - out[vert_size].v = vLast; - out[vert_size].x = last1[0]; - out[vert_size].y = last1[1]; - out[vert_size].z = last1[2]; - vert_size++; -#else - TriTexCoord2f( 1.0f, vLast ); - TriVertex3fv( last2 ); - TriTexCoord2f( 0.0f, vLast ); - TriVertex3fv( last1 ); -#endif + + out[vert_count].u = 1.0f; + out[vert_count].v = vLast; + out[vert_count].x = last2[0]; + out[vert_count].y = last2[1]; + out[vert_count].z = last2[2]; + vert_count++; + out[vert_count].u = 0.0f; + out[vert_count].v = vLast; + out[vert_count].x = last1[0]; + out[vert_count].y = last1[1]; + out[vert_count].z = last1[2]; + vert_count++; } VectorCopy( screen, screenLast ); @@ -1053,10 +955,10 @@ void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, floa FracNoise( rgNoise, NOISE_DIVISIONS ); } } -#if 1 - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_size, 0, out ); -#endif + + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, vert_count, 0, out ); + } /* @@ -1301,62 +1203,26 @@ void R_BeamDraw( BEAM *pbeam, float frametime ) { case TE_BEAMTORUS: GL_Cull( GL_NONE ); -#if 0 - TriBegin( TRI_TRIANGLE_STRIP ); -#endif R_DrawTorus( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); -#if 0 - TriEnd(); -#endif break; case TE_BEAMDISK: GL_Cull( GL_NONE ); -#if 0 - TriBegin( TRI_TRIANGLE_STRIP ); -#endif R_DrawDisk( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); -#if 0 - TriEnd(); -#endif break; case TE_BEAMCYLINDER: GL_Cull( GL_NONE ); -#if 0 - TriBegin( TRI_TRIANGLE_STRIP ); -#endif R_DrawCylinder( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); -#if 0 - TriEnd(); -#endif break; case TE_BEAMPOINTS: case TE_BEAMHOSE: -#if 0 - TriBegin( TRI_TRIANGLE_STRIP ); -#endif R_DrawSegs( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags ); -#if 0 - TriEnd(); -#endif break; case TE_BEAMFOLLOW: -#if 0 - TriBegin( TRI_QUADS ); -#endif R_DrawBeamFollow( pbeam, frametime ); -#if 0 - TriEnd(); -#endif break; case TE_BEAMRING: GL_Cull( GL_NONE ); -#if 0 - TriBegin( TRI_TRIANGLE_STRIP ); -#endif R_DrawRing( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); -#if 0 - TriEnd(); -#endif break; } diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 200282b8..b973cfeb 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -812,6 +812,7 @@ extern cvar_t *tracerblue; extern cvar_t *traceralpha; extern cvar_t *cl_lightstyle_lerping; extern cvar_t *r_showhull; +extern cvar_t *r_fast_particles; // // engine callbacks diff --git a/ref_gu/gu_render.c b/ref_gu/gu_render.c index 3727fcd1..def3e776 100644 --- a/ref_gu/gu_render.c +++ b/ref_gu/gu_render.c @@ -49,6 +49,7 @@ cvar_t *r_traceglow; cvar_t *r_dynamic; cvar_t *r_lightmap; cvar_t *r_showhull; +cvar_t *r_fast_particles; cvar_t *gl_round_down; cvar_t *gl_showtextures; cvar_t *cl_lightstyle_lerping; @@ -360,6 +361,7 @@ void GL_InitCommands( void ) r_drawentities = gEngfuncs.Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" ); r_decals = gEngfuncs.pfnGetCvarPointer( "r_decals", 0 ); r_showhull = gEngfuncs.pfnGetCvarPointer( "r_showhull", 0 ); + r_fast_particles = gEngfuncs.Cvar_Get( "r_fast_particles", "1", FCVAR_ARCHIVE, "use GU_POINTS for particles" ); gl_texture_nearest = gEngfuncs.Cvar_Get( "gl_texture_nearest", "0", FCVAR_GLCONFIG, "disable texture filter" ); gl_lightmap_nearest = gEngfuncs.Cvar_Get( "gl_lightmap_nearest", "0", FCVAR_GLCONFIG, "disable lightmap filter" ); diff --git a/ref_gu/gu_rpart.c b/ref_gu/gu_rpart.c index 3709834d..40b80ec9 100644 --- a/ref_gu/gu_rpart.c +++ b/ref_gu/gu_rpart.c @@ -54,134 +54,124 @@ void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float color24 *pColor; int alpha; float size; + uint vert_count; + uint vert_color; if( !cl_active_particles ) return; // nothing to draw? -#if 1 + + vert_count = 0; + vert_color = 0; + sceGuEnable( GU_BLEND ); sceGuDisable( GU_ALPHA_TEST ); sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); - GL_Bind( XASH_TEXTURE0, tr.particleTexture ); - sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); sceGuDepthMask( GU_TRUE ); - gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); - unsigned int vert_size = 0; - unsigned int vert_color = 0; - - for( p = cl_active_particles; p; p = p->next ) + if( r_fast_particles->value ) { - if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + gu_vert_fcv_t* const out = ( gu_vert_fcv_t* )extGuBeginPacket( NULL ); + + sceGuDisable( GU_TEXTURE_2D ); + + for( p = cl_active_particles; p; p = p->next ) { - size = partsize; // get initial size of particle + if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + { + p->color = bound( 0, p->color, 255 ); + pColor = gEngfuncs.CL_GetPaletteColor( p->color ); - // scale up to keep particles from disappearing - size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0]; - size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1]; - size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2]; + alpha = 255 * (p->die - gpGlobals->time) * 16.0f; + if( alpha > 255 || p->type == pt_static ) + alpha = 255; - if( size < 20.0f ) size = partsize; - else size = partsize + size * 0.002f; + out[vert_count].c = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), + gEngfuncs.LightToTexGamma( pColor->g ), + gEngfuncs.LightToTexGamma( pColor->b ), alpha ); + out[vert_count].x = p->org[0]; + out[vert_count].y = p->org[1]; + out[vert_count].z = p->org[2]; + vert_count++; - // scale the axes by radius - VectorScale( RI.cull_vright, size, right ); - VectorScale( RI.cull_vup, size, up ); + r_stats.c_particle_count++; + } - p->color = bound( 0, p->color, 255 ); - pColor = gEngfuncs.CL_GetPaletteColor( p->color ); - - alpha = 255 * (p->die - gpGlobals->time) * 16.0f; - if( alpha > 255 || p->type == pt_static ) - alpha = 255; - vert_color = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), - gEngfuncs.LightToTexGamma( pColor->g ), - gEngfuncs.LightToTexGamma( pColor->b ), alpha ); - - out[vert_size].u = 0.0f; - out[vert_size].v = 0.0f; - out[vert_size].c = vert_color; - out[vert_size].x = p->org[0] + right[0] + up[0]; - out[vert_size].y = p->org[1] + right[1] + up[1]; - out[vert_size].z = p->org[2] + right[2] + up[2]; - vert_size++; - out[vert_size].u = 1.0f; - out[vert_size].v = 1.0f; - out[vert_size].c = vert_color; - out[vert_size].x = p->org[0] - right[0] - up[0]; - out[vert_size].y = p->org[1] - right[1] - up[1]; - out[vert_size].z = p->org[2] - right[2] - up[2]; - vert_size++; - - r_stats.c_particle_count++; + gEngfuncs.CL_ThinkParticle( frametime, p ); } - gEngfuncs.CL_ThinkParticle( frametime, p ); + if( vert_count ) + { + extGuEndPacket( ( void * )( out + vert_count ) ); + sceGuDrawArray( GU_POINTS, GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out ); + } + + sceGuEnable( GU_TEXTURE_2D ); + } + else + { + GL_Bind( XASH_TEXTURE0, tr.particleTexture ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); + + gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL ); + + for( p = cl_active_particles; p; p = p->next ) + { + if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + { + size = partsize; // get initial size of particle + + // scale up to keep particles from disappearing + size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0]; + size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1]; + size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2]; + + if( size < 20.0f ) size = partsize; + else size = partsize + size * 0.002f; + + // scale the axes by radius + VectorScale( RI.cull_vright, size, right ); + VectorScale( RI.cull_vup, size, up ); + + p->color = bound( 0, p->color, 255 ); + pColor = gEngfuncs.CL_GetPaletteColor( p->color ); + + alpha = 255 * (p->die - gpGlobals->time) * 16.0f; + if( alpha > 255 || p->type == pt_static ) + alpha = 255; + vert_color = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ), + gEngfuncs.LightToTexGamma( pColor->g ), + gEngfuncs.LightToTexGamma( pColor->b ), alpha ); + + out[vert_count].u = 0.0f; + out[vert_count].v = 0.0f; + out[vert_count].c = vert_color; + out[vert_count].x = p->org[0] + right[0] + up[0]; + out[vert_count].y = p->org[1] + right[1] + up[1]; + out[vert_count].z = p->org[2] + right[2] + up[2]; + vert_count++; + out[vert_count].u = 1.0f; + out[vert_count].v = 1.0f; + out[vert_count].c = vert_color; + out[vert_count].x = p->org[0] - right[0] - up[0]; + out[vert_count].y = p->org[1] - right[1] - up[1]; + out[vert_count].z = p->org[2] - right[2] - up[2]; + vert_count++; + + r_stats.c_particle_count++; + } + + gEngfuncs.CL_ThinkParticle( frametime, p ); + } + + if( vert_count ) + { + extGuEndPacket(( void * )( out + vert_count )); + sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out ); + } } - if( vert_size ) - { - extGuEndPacket( ( void * )( out + vert_size ) ); - sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_size, 0, out ); - } sceGuDepthMask( GU_FALSE ); -#else - pglEnable( GL_BLEND ); - pglDisable( GL_ALPHA_TEST ); - pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - - GL_Bind( XASH_TEXTURE0, tr.particleTexture ); - pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - pglDepthMask( GL_FALSE ); - - pglBegin( GL_QUADS ); - - for( p = cl_active_particles; p; p = p->next ) - { - if(( p->type != pt_blob ) || ( p->packedColor == 255 )) - { - size = partsize; // get initial size of particle - - // scale up to keep particles from disappearing - size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0]; - size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1]; - size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2]; - - if( size < 20.0f ) size = partsize; - else size = partsize + size * 0.002f; - - // scale the axes by radius - VectorScale( RI.cull_vright, size, right ); - VectorScale( RI.cull_vup, size, up ); - - p->color = bound( 0, p->color, 255 ); - pColor = gEngfuncs.CL_GetPaletteColor( p->color ); - - alpha = 255 * (p->die - gpGlobals->time) * 16.0f; - if( alpha > 255 || p->type == pt_static ) - alpha = 255; - - pglColor4ub( gEngfuncs.LightToTexGamma( pColor->r ), - gEngfuncs.LightToTexGamma( pColor->g ), - gEngfuncs.LightToTexGamma( pColor->b ), alpha ); - - pglTexCoord2f( 0.0f, 1.0f ); - pglVertex3f( p->org[0] - right[0] + up[0], p->org[1] - right[1] + up[1], p->org[2] - right[2] + up[2] ); - pglTexCoord2f( 0.0f, 0.0f ); - pglVertex3f( p->org[0] + right[0] + up[0], p->org[1] + right[1] + up[1], p->org[2] + right[2] + up[2] ); - pglTexCoord2f( 1.0f, 0.0f ); - pglVertex3f( p->org[0] + right[0] - up[0], p->org[1] + right[1] - up[1], p->org[2] + right[2] - up[2] ); - pglTexCoord2f( 1.0f, 1.0f ); - pglVertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] ); - r_stats.c_particle_count++; - } - - gEngfuncs.CL_ThinkParticle( frametime, p ); - } - - pglEnd(); - pglDepthMask( GL_TRUE ); -#endif } /* @@ -251,19 +241,12 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) if( !cl_active_tracers ) return; // nothing to draw? - if( !TriSpriteTexture( gEngfuncs.GetDefaultSprite( REF_DOT_SPRITE ), 0 )) - return; -#if 1 sceGuEnable( GU_BLEND ); sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 ); sceGuDisable( GU_ALPHA_TEST ); sceGuDepthMask( GU_TRUE ); -#else - pglEnable( GL_BLEND ); - pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); - pglDisable( GL_ALPHA_TEST ); - pglDepthMask( GL_FALSE ); -#endif + sceGuDisable( GU_TEXTURE_2D ); + gravity = frametime * MOVEVARS->gravity; scale = 1.0 - (frametime * 0.9); if( scale < 0.0f ) scale = 0.0f; @@ -312,47 +295,22 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) } pColor = &gTracerColors[p->color]; -#if 1 - sceGuColor( GUCOLOR4UB( pColor->r, pColor->g, pColor->b, p->packedColor ) ); + sceGuColor( GUCOLOR4UB( pColor->r, pColor->g, pColor->b, p->packedColor )); - gu_vert_ftv_t* const out = ( gu_vert_ftv_t* )sceGuGetMemory( sizeof( gu_vert_ftv_t ) * 4 ); - - out[0].u = 0.0f; - out[0].v = 0.8f; + gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * 4 ); out[0].x = verts[2][0]; out[0].y = verts[2][1]; out[0].z = verts[2][2]; - out[1].u = 1.0f; - out[1].v = 0.8f; out[1].x = verts[3][0]; out[1].y = verts[3][1]; out[1].z = verts[3][2]; - out[2].u = 1.0f; - out[2].v = 0.0f; out[2].x = verts[1][0]; out[2].y = verts[1][1]; out[2].z = verts[1][2]; - out[3].u = 0.0f; - out[3].v = 0.0f; out[3].x = verts[0][0]; out[3].y = verts[0][1]; out[3].z = verts[0][2]; - - sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); -#else - pglColor4ub( pColor->r, pColor->g, pColor->b, p->packedColor ); - - pglBegin( GL_QUADS ); - pglTexCoord2f( 0.0f, 0.8f ); - pglVertex3fv( verts[2] ); - pglTexCoord2f( 1.0f, 0.8f ); - pglVertex3fv( verts[3] ); - pglTexCoord2f( 1.0f, 0.0f ); - pglVertex3fv( verts[1] ); - pglTexCoord2f( 0.0f, 0.0f ); - pglVertex3fv( verts[0] ); - pglEnd(); -#endif + sceGuDrawArray( GU_TRIANGLE_FAN, GU_VERTEX_32BITF, 4, 0, out ); } // evaluate position @@ -372,11 +330,9 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) p->vel[2] = gravity * 0.05f; } } -#if 1 + + sceGuEnable( GU_TEXTURE_2D ); sceGuDepthMask( GU_FALSE ); -#else - pglDepthMask( GL_TRUE ); -#endif } /* diff --git a/ref_gu/gu_sprite.c b/ref_gu/gu_sprite.c index 6b8fb918..1e7881b6 100644 --- a/ref_gu/gu_sprite.c +++ b/ref_gu/gu_sprite.c @@ -729,46 +729,26 @@ R_DrawSpriteQuad */ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right, vec3_t v_up, float scale ) { - vec3_t point; - r_stats.c_sprite_polys++; -#if 0 + gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); - VectorMA( org, frame->down * scale, v_up, point ); - VectorMA( point, frame->left * scale, v_right, point ); out[0].uv[0] = 0.0f; out[0].uv[1] = 1.0f; - VectorCopy( point, out[0].xyz ); - VectorMA( org, frame->up * scale, v_up, point ); - VectorMA( point, frame->left * scale, v_right, point ); + VectorMA( org, frame->down * scale, v_up, out[0].xyz ); + VectorMA( out[0].xyz, frame->left * scale, v_right, out[0].xyz ); out[1].uv[0] = 0.0f; out[1].uv[1] = 0.0f; - VectorCopy( point, out[1].xyz ); - VectorMA( org, frame->up * scale, v_up, point ); - VectorMA( point, frame->right * scale, v_right, point ); + VectorMA( org, frame->up * scale, v_up, out[1].xyz ); + VectorMA( out[1].xyz, frame->left * scale, v_right, out[1].xyz ); out[2].uv[0] = 1.0f; out[2].uv[1] = 0.0f; - VectorCopy( point, out[2].xyz ); - VectorMA( org, frame->down * scale, v_up, point ); - VectorMA( point, frame->right * scale, v_right, point ); + VectorMA( org, frame->up * scale, v_up, out[2].xyz ); + VectorMA( out[2].xyz, frame->right * scale, v_right, out[2].xyz ); out[3].uv[0] = 1.0f; out[3].uv[1] = 1.0f; - VectorCopy( point, out[3].xyz ); + VectorMA( org, frame->down * scale, v_up, out[3].xyz ); + VectorMA( out[3].xyz, frame->right * scale, v_right, out[3].xyz ); sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 4, 0, out ); -#else - gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 2 ); - VectorMA( org, frame->up * scale, v_up, point ); - VectorMA( point, frame->left * scale, v_right, point ); - out[0].uv[0] = 0.0f; - out[0].uv[1] = 0.0f; - VectorCopy( point, out[0].xyz ); - VectorMA( org, frame->down * scale, v_up, point ); - VectorMA( point, frame->right * scale, v_right, point ); - out[1].uv[0] = 1.0f; - out[1].uv[1] = 1.0f; - VectorCopy( point, out[1].xyz ); - sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, 2, 0, out ); -#endif } static qboolean R_SpriteHasLightmap( cl_entity_t *e, int texFormat ) @@ -1014,7 +994,7 @@ void R_DrawSpriteModel( cl_entity_t *e ) sceGuDisable( GU_ALPHA_TEST ); sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, GUBLEND0, 0 ); sceGuTexFunc( GU_TFX_MODULATE , GU_TCC_RGBA ); - + sceGuColor( GUCOLOR4F( color2[0], color2[1], color2[2], tr.blend ) ); GL_Bind( XASH_TEXTURE0, tr.whiteTexture ); R_DrawSpriteQuad( frame, origin, v_right, v_up, scale ); From 9c61941e5258e8f3add591f5930726913b493349 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 9 Sep 2022 10:18:29 +0300 Subject: [PATCH 43/84] ref_gu: code cleanup, fix spaces and tabs, asm Matrix_FromOriginQuat --- public/matrixlib.c | 795 +++++++++++++++++++++------------------- public/xash3d_mathlib.c | 231 ++++++------ ref_gu/gu_clipping.c | 178 ++++----- ref_gu/gu_local.h | 32 +- ref_gu/gu_rlight.c | 3 +- ref_gu/gu_rmain.c | 16 +- ref_gu/gu_warp.c | 72 ++-- 7 files changed, 672 insertions(+), 655 deletions(-) diff --git a/public/matrixlib.c b/public/matrixlib.c index f56a68fb..ccc2bb84 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -37,21 +37,21 @@ void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[ { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] - "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] - "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] - "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] + "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] + "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -66,26 +66,26 @@ void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] - "vsub.t C130, C130, R103\n" // C130 = v - in[][3] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vsub.t C130, C130, R103\n" // C130 = v - in[][3] #if 1 - "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else - "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] - "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] - "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] + "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -106,25 +106,25 @@ void Matrix3x4_VectorRotate( const matrix3x4 in, const float v[3], float out[3] { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] #if 1 - "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 + "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 #else - "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] - "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] - "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -140,25 +140,25 @@ void Matrix3x4_VectorIRotate( const matrix3x4 in, const float v[3], float out[3] { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] #if 1 - "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else - "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] - "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] - "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] + "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -173,21 +173,21 @@ void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matri { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in1[0] - "lv.q C110, 16 + %1\n" // C110 = in1[1] - "lv.q C120, 32 + %1\n" // C120 = in1[2] - "vzero.q C130\n" // C130 = [0, 0, 0, 0] - "lv.q C200, 0 + %2\n" // C100 = in2[0] - "lv.q C210, 16 + %2\n" // C110 = in2[1] - "lv.q C220, 32 + %2\n" // C120 = in2[2] - "vidt.q C230\n" // C230 = [0, 0, 0, 1] - "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "vzero.q C130\n" // C130 = [0, 0, 0, 0] + "lv.q C200, 0 + %2\n" // C100 = in2[0] + "lv.q C210, 16 + %2\n" // C110 = in2[1] + "lv.q C220, 32 + %2\n" // C120 = in2[2] + "vidt.q C230\n" // C230 = [0, 0, 0, 1] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in1 ), "m"( *in2 ) ); @@ -243,28 +243,29 @@ void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out ) void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin ) { -#if 0//XASH_PSP /* not tested */ +#if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C130, %1\n" // C130 = quaternion - "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] - "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] - "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "vmov.q C100, C130[ W, Z, -Y, -X]\n" // C100 = ( w, z, -y, -x) - "vmov.q C110, C130[-Z, W, X, -Y]\n" // C110 = (-z, w, x, -y) - "vmov.q C120, C130[ Y, -X, W, -Z]\n" // C120 = ( y, -x, w, -z) - "vmov.q C200, C130[ W, Z, -Y, X]\n" // C200 = ( w, z, -y, x) - "vmov.q C210, C130[-Z, W, X, Y]\n" // C210 = (-z, w, x, y) - "vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z) - "vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w) - "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C130, %1\n" // C130 = quaternion + "lv.s S300, 0 + %2\n" // S300 = origin[0] + "lv.s S301, 4 + %2\n" // S301 = origin[1] + "lv.s S302, 8 + %2\n" // S302 = origin[2] + "vmov.q C100, C130[ W, Z, -Y, -X]\n" // C100 = ( w, z, -y, -x) + "vmov.q C110, C130[-Z, W, X, -Y]\n" // C110 = (-z, w, x, -y) + "vmov.q C120, C130[ Y, -X, W, -Z]\n" // C120 = ( y, -x, w, -z) + "vmov.q C200, C130[ W, Z, -Y, X]\n" // C200 = ( w, z, -y, x) + "vmov.q C210, C130[-Z, W, X, Y]\n" // C210 = (-z, w, x, y) + "vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z) + "vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w) + "vmmul.q M000, E100, E200\n" // M000 = E100 * E200 + "vmov.t R003, C300\n" // out[x][3] = origin[x] + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) - : "m"( *quaternion ), "m"( *origin ) + : "m"( *quaternion ), "m"( *origin ) ); #else out[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2]; @@ -290,153 +291,153 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_ #if 0/*XASH_PSP*/ /* performance not tested */ /* BUG */ if( angles[ROLL] ) { - __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] - "lv.s S101, 4 + %1\n" // S101 = angles[YAW] - "lv.s S102, 8 + %1\n" // S102 = angles[ROLL] - "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] - "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] - "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S102, 8 + %1\n" // S102 = angles[ROLL] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale /**/ - "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) /**/ - "vsin.t C110, C100\n" // C110 = sin( C100 ) P Y R - "vcos.t C120, C100\n" // C120 = cos( C100 ) P Y R - "vneg.t C100, C110\n" // C100 = -C110 = -sin( C100 ) + "vsin.t C110, C100\n" // C110 = sin( C100 ) P Y R + "vcos.t C120, C100\n" // C120 = cos( C100 ) P Y R + "vneg.t C100, C110\n" // C100 = -C110 = -sin( C100 ) /**/ - "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) - "vmul.s S011, S112, S110\n" // S011 = S112 * S110 = ( sr * sp ) - "vmul.s S001, S011, S121\n" // S001 = S011 * S121 = ( sr * sp * cy ) - "vmul.s S103, S122, S101\n" // S001 = S122 * S101 = ( cr * -sy ) - "vadd.s S001, S001, S103\n" // S001 = S001 + S103 = out[0][1] = ( sr * sp * cy + cr * -sy ) - "vmul.s S012, S122, S110\n" // S002 = S122 * S110 = ( cr * sp ) - "vmul.s S002, S012, S121\n" // S002 = S012 * S121 = ( cr * sp * cy ) - "vmul.s S103, S102, S101\n" // S002 = S102 * S101 = ( -sr * -sy ) - "vadd.s S002, S002, S103\n" // S002 = S002 + S103 = out[0][2] = ( cr * sp * cy + -sr * -sy ) + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmul.s S011, S112, S110\n" // S011 = S112 * S110 = ( sr * sp ) + "vmul.s S001, S011, S121\n" // S001 = S011 * S121 = ( sr * sp * cy ) + "vmul.s S103, S122, S101\n" // S001 = S122 * S101 = ( cr * -sy ) + "vadd.s S001, S001, S103\n" // S001 = S001 + S103 = out[0][1] = ( sr * sp * cy + cr * -sy ) + "vmul.s S012, S122, S110\n" // S002 = S122 * S110 = ( cr * sp ) + "vmul.s S002, S012, S121\n" // S002 = S012 * S121 = ( cr * sp * cy ) + "vmul.s S103, S102, S101\n" // S002 = S102 * S101 = ( -sr * -sy ) + "vadd.s S002, S002, S103\n" // S002 = S002 + S103 = out[0][2] = ( cr * sp * cy + -sr * -sy ) /**/ - "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) - "vmul.s S011, S011, S111\n" // S001 = S011 * S111 = ( sr * sp * sy ) - "vmul.s S103, S122, S121\n" // S001 = S122 * S121 = ( cr * cy ) - "vadd.s S011, S011, S103\n" // S011 = S011 + S103 = out[1][1] = ( sr * sp * sy + cr * cy ) - "vmul.s S012, S012, S111\n" // S012 = S012 * S111 = ( cr * sp * sy ) - "vmul.s S103, S102, S121\n" // S103 = S102 * S121 = ( -sr * cy ) - "vadd.s S012, S012, S103\n" // S012 = S012 + S103 = out[1][2] = ( cr * sp * sy + -sr * cy ) + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmul.s S011, S011, S111\n" // S001 = S011 * S111 = ( sr * sp * sy ) + "vmul.s S103, S122, S121\n" // S001 = S122 * S121 = ( cr * cy ) + "vadd.s S011, S011, S103\n" // S011 = S011 + S103 = out[1][1] = ( sr * sp * sy + cr * cy ) + "vmul.s S012, S012, S111\n" // S012 = S012 * S111 = ( cr * sp * sy ) + "vmul.s S103, S102, S121\n" // S103 = S102 * S121 = ( -sr * cy ) + "vadd.s S012, S012, S103\n" // S012 = S012 + S103 = out[1][2] = ( cr * sp * sy + -sr * cy ) /**/ - "vmov.s S020, S101\n" // S020 = S101 = out[2][0] = ( -sp ) - "vmul.s S021, S112, S120\n" // S021 = S112 * S120 = out[2][1] = ( sr * cp ) - "vmul.s S022, S122, S120\n" // S021 = S122 * S120 = out[2][2] = ( cr * cp ) + "vmov.s S020, S101\n" // S020 = S101 = out[2][0] = ( -sp ) + "vmul.s S021, S112, S120\n" // S021 = S112 * S120 = out[2][1] = ( sr * cp ) + "vmul.s S022, S122, S120\n" // S021 = S122 * S120 = out[2][2] = ( cr * cp ) /**/ - "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) ); } else if( angles[PITCH] ) { - __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] - "lv.s S101, 4 + %1\n" // S101 = angles[YAW] - "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] - "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] - "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale /**/ - "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) /**/ - "vsin.p C110, C100\n" // C110 = sin( C100 ) P Y - "vcos.p C120, C100\n" // C120 = cos( C100 ) P Y - "vneg.p C100, C110\n" // C100 = -C110 = -sin( C100 ) + "vsin.p C110, C100\n" // C110 = sin( C100 ) P Y + "vcos.p C120, C100\n" // C120 = cos( C100 ) P Y + "vneg.p C100, C110\n" // C100 = -C110 = -sin( C100 ) /**/ - "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) - "vmov.s S001, S101\n" // S001 = S101 = out[0][1] = ( -sy ) - "vmul.s S002, S110, S121\n" // S001 = S110 * S121 = out[0][2] = ( sp * cy ) + "vmul.s S000, S120, S121\n" // S000 = S120 * S121 = out[0][0] = ( cp * cy ) + "vmov.s S001, S101\n" // S001 = S101 = out[0][1] = ( -sy ) + "vmul.s S002, S110, S121\n" // S001 = S110 * S121 = out[0][2] = ( sp * cy ) /**/ - "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) - "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) - "vmul.s S012, S110, S111\n" // S012 = S110 * S111 = out[1][2] = ( sp * sy ) + "vmul.s S010, S120, S111\n" // S010 = S120 * S111 = out[1][0] = ( cp * sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vmul.s S012, S110, S111\n" // S012 = S110 * S111 = out[1][2] = ( sp * sy ) /**/ - "vmov.s S020, S100\n" // S020 = S100 = out[2][0] = ( -sp ) - "vzero.s S021\n" // S021 = out[2][1] = 0.0f - "vmov.s S022, S120\n" // S022 = S120 = out[2][2] = ( cp ) + "vmov.s S020, S100\n" // S020 = S100 = out[2][0] = ( -sp ) + "vzero.s S021\n" // S021 = out[2][1] = 0.0f + "vmov.s S022, S120\n" // S022 = S120 = out[2][2] = ( cp ) /**/ - "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) ); } else if( angles[YAW] ) { - __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.s S101, 4 + %1\n" // S101 = angles[YAW] - "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] - "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] - "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S101, 4 + %1\n" // S101 = angles[YAW] + "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %3\n" // S130 = scale /**/ - "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) - "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) + "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) + "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) /**/ - "vsin.s S111, S101\n" // S111 = sin( S101 ) Y - "vcos.s S121, S101\n" // S121 = cos( S101 ) Y + "vsin.s S111, S101\n" // S111 = sin( S101 ) Y + "vcos.s S121, S101\n" // S121 = cos( S101 ) Y /**/ - "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f - "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f - "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) - "vneg.s S001, S111\n" // S001 = S111 = out[0][1] = ( -sy ) - "vmov.s S010, S111\n" // S010 = S111 = out[1][0] = ( sy ) - "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) - "vone.s S022\n" // S022 = out[2][2] = 1.0f + "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f + "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f + "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) + "vneg.s S001, S111\n" // S001 = S111 = out[0][1] = ( -sy ) + "vmov.s S010, S111\n" // S010 = S111 = out[1][0] = ( sy ) + "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) + "vone.s S022\n" // S022 = out[2][2] = 1.0f /**/ - "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale + "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale /**/ - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) ); } else { - __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0] - "lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1] - "lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %2\n" // S130 = scale + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0] + "lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1] + "lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2] + "lv.s S130, %2\n" // S130 = scale /**/ - "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] - "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] - "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] - "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale - "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale - "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale + "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] + "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] + "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] + "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale + "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale + "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale /**/ - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *origin ), "m"( scale ) ); @@ -526,28 +527,28 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %2\n" // C100 = in[0] - "lv.q C110, 16 + %2\n" // C110 = in[1] - "lv.q C120, 32 + %2\n" // C120 = in[2] - "lv.s S200, 0 + %3\n" // S200 = normal[0] - "lv.s S201, 4 + %3\n" // S201 = normal[1] - "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d - "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 - "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 - "vscl.t C000, C000, S212\n" // C000 = C000 * S211 - "vmul.s S003, S210, S211\n" // S003 = S210 * S211 - "vdot.t S010, R103, C000\n" // S010 = R103 * C000 - "vadd.s S003, S003, S010\n" // S003 = S003 + S010 - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - "sv.s S003, %1\n" // dist = S003 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vadd.s S003, S003, S010\n" // S003 = S003 + S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) : "m"( *in ), "m"( *normal ), "m"( d ) ); @@ -648,21 +649,21 @@ void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[ { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] - "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] - "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] - "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3] + "vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3] + "vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3] + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -677,26 +678,26 @@ void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] - "vsub.t C130, C130, R103\n" // C130 = v - in[][3] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] + "vsub.t C130, C130, R103\n" // C130 = v - in[][3] #if 1 - "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else - "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] - "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] - "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] + "vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -717,25 +718,25 @@ void Matrix4x4_VectorRotate( const matrix4x4 in, const float v[3], float out[3] { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] #if 1 - "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 + "vtfm3.t C000, M100, C130\n" // C000 = M100 * C130 #else - "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] - "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] - "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + "vdot.t S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + "vdot.t S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + "vdot.t S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -750,25 +751,25 @@ void Matrix4x4_VectorIRotate( const matrix4x4 in, const float v[3], float out[3] { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in[0] - "lv.q C110, 16 + %1\n" // C110 = in[1] - "lv.q C120, 32 + %1\n" // C120 = in[2] - "lv.s S130, 0 + %2\n" // S130 = v[0] - "lv.s S131, 4 + %2\n" // S131 = v[1] - "lv.s S132, 8 + %2\n" // S132 = v[2] + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in[0] + "lv.q C110, 16 + %1\n" // C110 = in[1] + "lv.q C120, 32 + %1\n" // C120 = in[2] + "lv.s S130, 0 + %2\n" // S130 = v[0] + "lv.s S131, 4 + %2\n" // S131 = v[1] + "lv.s S132, 8 + %2\n" // S132 = v[2] #if 1 - "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 + "vtfm3.t C000, E100, C130\n" // C000 = E100 * C130 #else - "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] - "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] - "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] + "vdot.t S000, C130, R100\n" // S000 = v[0] * in[0][0] + v[1] * in[1][0] + v[2] * in[2][0] + "vdot.t S001, C130, R101\n" // S001 = v[0] * in[0][1] + v[1] * in[1][1] + v[2] * in[2][1] + "vdot.t S002, C130, R102\n" // S002 = v[0] * in[0][2] + v[1] * in[1][2] + v[2] * in[2][2] #endif - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - ".set pop\n" // restore assembler option + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in ), "m"( *v ) ); @@ -784,21 +785,21 @@ void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matri { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in1[0] - "lv.q C110, 16 + %1\n" // C110 = in1[1] - "lv.q C120, 32 + %1\n" // C120 = in1[2] - "vzero.q C130\n" // C130 = [0, 0, 0, 0] - "lv.q C200, 0 + %2\n" // C100 = in2[0] - "lv.q C210, 16 + %2\n" // C110 = in2[1] - "lv.q C220, 32 + %2\n" // C120 = in2[2] - "vidt.q C230\n" // C230 = [0, 0, 0, 1] - "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "vzero.q C130\n" // C130 = [0, 0, 0, 0] + "lv.q C200, 0 + %2\n" // C100 = in2[0] + "lv.q C210, 16 + %2\n" // C110 = in2[1] + "lv.q C220, 32 + %2\n" // C120 = in2[2] + "vidt.q C230\n" // C230 = [0, 0, 0, 1] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in1 ), "m"( *in2 ) ); @@ -834,6 +835,33 @@ void Matrix4x4_OriginFromMatrix( const matrix4x4 in, float *out ) void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec3_t origin ) { +#if XASH_PSP + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C130, %1\n" // C130 = quaternion + "lv.s S300, 0 + %2\n" // S300 = origin[0] + "lv.s S301, 4 + %2\n" // S301 = origin[1] + "lv.s S302, 8 + %2\n" // S302 = origin[2] + "vmov.q C100, C130[ W, Z, -Y, -X]\n" // C100 = ( w, z, -y, -x) + "vmov.q C110, C130[-Z, W, X, -Y]\n" // C110 = (-z, w, x, -y) + "vmov.q C120, C130[ Y, -X, W, -Z]\n" // C120 = ( y, -x, w, -z) + "vmov.q C200, C130[ W, Z, -Y, X]\n" // C200 = ( w, z, -y, x) + "vmov.q C210, C130[-Z, W, X, Y]\n" // C210 = (-z, w, x, y) + "vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z) + "vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w) + "vmmul.q M000, E100, E200\n" // M000 = E100 * E200 + "vmov.t R003, C300\n" // out[x][3] = origin[x] + "vidt.q C030\n" // C030 = [0, 0, 0, 1] + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *quaternion ), "m"( *origin ) + ); +#else out[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2]; out[1][0] = 2.0f * quaternion[0] * quaternion[1] + 2.0f * quaternion[3] * quaternion[2]; out[2][0] = 2.0f * quaternion[0] * quaternion[2] - 2.0f * quaternion[3] * quaternion[1]; @@ -842,7 +870,7 @@ void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec out[1][1] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[2] * quaternion[2]; out[2][1] = 2.0f * quaternion[1] * quaternion[2] + 2.0f * quaternion[3] * quaternion[0]; out[1][3] = origin[1]; - + out[0][2] = 2.0f * quaternion[0] * quaternion[2] + 2.0f * quaternion[3] * quaternion[1]; out[1][2] = 2.0f * quaternion[1] * quaternion[2] - 2.0f * quaternion[3] * quaternion[0]; out[2][2] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[1] * quaternion[1]; @@ -851,6 +879,7 @@ void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec out[3][1] = 0.0f; out[3][2] = 0.0f; out[3][3] = 1.0f; +#endif } void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale ) @@ -858,8 +887,8 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ #if 0/*XASH_PSP*/ /* performance not tested */ /* BUG */ if( angles[ROLL] ) { - __asm__ ( - ".set push\n" // save assembler option + __asm__ ( + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] "lv.s S101, 4 + %1\n" // S101 = angles[YAW] @@ -867,7 +896,7 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) "vscl.t C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) @@ -899,28 +928,28 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmul.s S022, S122, S120\n" // S021 = S122 * S120 = out[2][2] = ( cr * cp ) /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale - "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ "sv.q C000, 0 + %0\n" // out[0] = C000 "sv.q C010, 16 + %0\n" // out[1] = C010 "sv.q C020, 32 + %0\n" // out[2] = C020 "sv.q C030, 48 + %0\n" // out[3] = C030 - ".set pop\n" // restore assembler option + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) ); } else if( angles[PITCH] ) { - __asm__ ( - ".set push\n" // save assembler option + __asm__ ( + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.s S100, 0 + %1\n" // S100 = angles[PITCH] "lv.s S101, 4 + %1\n" // S101 = angles[YAW] "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) "vscl.p C100, C100, S120\n" // C100 = C100 * S120 = angles * ( 2 / 180 ) @@ -938,31 +967,31 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vmul.s S012, S110, S111\n" // S012 = S110 * S111 = out[1][2] = ( sp * sy ) /**/ "vmov.s S020, S100\n" // S020 = S100 = out[2][0] = ( -sp ) - "vzero.s S021\n" // S021 = out[2][1] = 0.0f + "vzero.s S021\n" // S021 = out[2][1] = 0.0f "vmov.s S022, S120\n" // S022 = S120 = out[2][2] = ( cp ) /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale - "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ "sv.q C000, 0 + %0\n" // out[0] = C000 "sv.q C010, 16 + %0\n" // out[1] = C010 "sv.q C020, 32 + %0\n" // out[2] = C020 "sv.q C030, 48 + %0\n" // out[3] = C030 - ".set pop\n" // restore assembler option + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *angles ), "m"( *origin ), "m"( scale ) ); } else if( angles[YAW] ) { - __asm__ ( - ".set push\n" // save assembler option + __asm__ ( + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.s S101, 4 + %1\n" // S101 = angles[YAW] "lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0] "lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1] "lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %3\n" // S130 = scale + "lv.s S130, %3\n" // S130 = scale /**/ "vfim.s S120, 0.0111111111111111\n" // S121 = 0.0111111111111111 const ( 2 / 180 ) "vmul.s S101, S101, S120\n" // S101 = S101 * S120 = angles[YAW] * ( 2 / 180 ) @@ -970,16 +999,16 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ "vsin.s S111, S101\n" // S111 = sin( S101 ) Y "vcos.s S121, S101\n" // S121 = cos( S101 ) Y /**/ - "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f - "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f - "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) + "vzero.p R002\n" // S002 = 0.0f S012 = 0.0f + "vzero.p C020\n" // S020 = 0.0f S021 = 0.0f + "vmov.s S000, S121\n" // S000 = S121 = out[0][0] = ( cy ) "vneg.s S001, S111\n" // S001 = S111 = out[0][1] = ( -sy ) "vmov.s S010, S111\n" // S010 = S111 = out[1][0] = ( sy ) "vmov.s S011, S121\n" // S011 = S121 = out[1][1] = ( cy ) - "vone.s S022\n" // S022 = out[2][2] = 1.0f + "vone.s S022\n" // S022 = out[2][2] = 1.0f /**/ "vmscl.t E000, E000, S130\n" // E000 = E000 * S103 = out(3) * scale - "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] /**/ "sv.q C000, 0 + %0\n" // out[0] = C000 "sv.q C010, 16 + %0\n" // out[1] = C010 @@ -992,27 +1021,27 @@ void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_ } else { - __asm__ ( - ".set push\n" // save assembler option + __asm__ ( + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0] "lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1] "lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2] - "lv.s S130, %2\n" // S130 = scale + "lv.s S130, %2\n" // S130 = scale /**/ - "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] - "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] - "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] - "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] - "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale - "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale - "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale + "vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f] + "vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f] + "vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f] + "vidt.q C030\n" // C030 = [0.0f, 0.0f, 0.0f, 1.0f] + "vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale + "vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale + "vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale /**/ "sv.q C000, 0 + %0\n" // out[0] = C000 "sv.q C010, 16 + %0\n" // out[1] = C010 "sv.q C020, 32 + %0\n" // out[2] = C020 "sv.q C030, 48 + %0\n" // out[3] = C030 - ".set pop\n" // restore assembler option + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *origin ), "m"( scale ) ); @@ -1141,28 +1170,28 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %2\n" // C100 = in[0] - "lv.q C110, 16 + %2\n" // C110 = in[1] - "lv.q C120, 32 + %2\n" // C120 = in[2] - "lv.s S200, 0 + %3\n" // S200 = normal[0] - "lv.s S201, 4 + %3\n" // S201 = normal[1] - "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d - "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 - "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 - "vscl.t C000, C000, S212\n" // C000 = C000 * S211 - "vmul.s S003, S210, S211\n" // S003 = S210 * S211 - "vdot.t S010, R103, C000\n" // S010 = R103 * C000 - "vadd.s S003, S003, S010\n" // S003 = S003 + S010 - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - "sv.s S003, %1\n" // dist = S003 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vadd.s S003, S003, S010\n" // S003 = S003 + S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) : "m"( *in ), "m"( *normal ), "m"( d ) ); @@ -1181,28 +1210,28 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %2\n" // C100 = in[0] - "lv.q C110, 16 + %2\n" // C110 = in[1] - "lv.q C120, 32 + %2\n" // C120 = in[2] - "lv.s S200, 0 + %3\n" // S200 = normal[0] - "lv.s S201, 4 + %3\n" // S201 = normal[1] - "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d - "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 - "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 - "vscl.t C000, C000, S212\n" // C000 = C000 * S211 - "vmul.s S003, S210, S211\n" // S003 = S210 * S211 - "vdot.t S010, R103, C000\n" // S010 = R103 * C000 - "vsub.s S003, S003, S010\n" // S003 = S003 - S010 - "sv.s S000, 0 + %0\n" // out[0] = S000 - "sv.s S001, 4 + %0\n" // out[1] = S001 - "sv.s S002, 8 + %0\n" // out[2] = S002 - "sv.s S003, %1\n" // dist = S003 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %2\n" // C100 = in[0] + "lv.q C110, 16 + %2\n" // C110 = in[1] + "lv.q C120, 32 + %2\n" // C120 = in[2] + "lv.s S200, 0 + %3\n" // S200 = normal[0] + "lv.s S201, 4 + %3\n" // S201 = normal[1] + "lv.s S202, 8 + %3\n" // S202 = normal[2] + "lv.s S210, %4\n" // S210 = d + "vdot.t S211, C100, C100\n" // S211 = C100 * C100 + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 + "vscl.t C000, C000, S212\n" // C000 = C000 * S211 + "vmul.s S003, S210, S211\n" // S003 = S210 * S211 + "vdot.t S010, R103, C000\n" // S010 = R103 * C000 + "vsub.s S003, S003, S010\n" // S003 = S003 - S010 + "sv.s S000, 0 + %0\n" // out[0] = S000 + "sv.s S001, 4 + %0\n" // out[1] = S001 + "sv.s S002, 8 + %0\n" // out[2] = S002 + "sv.s S003, %1\n" // dist = S003 + ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) : "m"( *in ), "m"( *normal ), "m"( d ) ); diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index 2908e0e9..cf1d2e9f 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -307,21 +307,26 @@ rsqrt float rsqrt( float number ) { #if XASH_PSP +#if 0 /* experimental */ + if( number == 0.0f ) return 0.0f; + return ( 1.0 / __builtin_allegrex_sqrt_s( number )); +#else float result; __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.s S000, %1\n" // S000 = number - "vzero.s S001\n" // S100 = 0 + "lv.s S000, %1\n" // S000 = number + "vzero.s S001\n" // S100 = 0 "vcmp.s EZ, S000\n" // CC[0] = ( S000 == 0.0f ) "vrsq.s S000, S000\n" // S000 = 1.0 / sqrt( S000 ) "vcmovt.s S000, S001, 0\n" // if ( CC[0] ) S000 = S001 - "sv.s S000, %0\n" // result = S000 - ".set pop\n" // restore assembler option + "sv.s S000, %0\n" // result = S000 + ".set pop\n" // restore assembler option : "=m"( result ) : "m"( number ) ); return result; +#endif #else int i; float x, y; @@ -348,15 +353,15 @@ void SinCos( float radians, float *sine, float *cosine ) { #if XASH_PSP __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.s S000, %2\n" // S000 = radians + "lv.s S000, %2\n" // S000 = radians "vcst.s S001, VFPU_2_PI\n" // S001 = VFPU_2_PI = 2 / PI "vmul.s S000, S000, S001\n" // S000 = S000 * S001 - "vrot.p C002, S000, [s, c]\n" // S002 = sin( radians ), S003 = cos( radians ) - "sv.s S002, %0\n" // sine = S002 - "sv.s S003, %1\n" // cosine = S003 - ".set pop\n" // restore assembler option + "vrot.p C002, S000, [s, c]\n" // S002 = sin( radians ), S003 = cos( radians ) + "sv.s S002, %0\n" // sine = S002 + "sv.s S003, %1\n" // cosine = S003 + ".set pop\n" // restore assembler option : "=m"( *sine), "=m"( *cosine ) : "m"( radians ) ); @@ -666,16 +671,24 @@ AngleQuaternion void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio ) { #if XASH_PSP - vec4_t dst_angles; - - dst_angles[0] = studio ? angles[PITCH] : DEG2RAD( angles[ROLL] ); - dst_angles[1] = studio ? angles[YAW] : DEG2RAD( angles[PITCH] ); - dst_angles[2] = studio ? angles[ROLL] : DEG2RAD( angles[YAW] ); + vec4_t dst_angles; + if( studio ) + { + dst_angles[0] = angles[PITCH]; + dst_angles[1] = angles[YAW]; + dst_angles[2] = angles[ROLL]; + } + else + { + dst_angles[0] = DEG2RAD( angles[ROLL] ); + dst_angles[1] = DEG2RAD( angles[PITCH] ); + dst_angles[2] = DEG2RAD( angles[YAW] ); + } __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C000, %1\n" // C000 = [PITCH, YAW, ROLL] + "lv.q C000, %1\n" // C000 = [PITCH, YAW, ROLL] "vcst.s S010, VFPU_1_PI\n" // S010 = VFPU_1_PI = 1 / PI "vscl.t C000, C000, S010\n" // C000 = C000 * S010 = C000 * 0.5f * ( 2 / PI ) "vcos.t C010, C000\n" // C010 = cos( C000 * 0.5f ) @@ -688,11 +701,11 @@ void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio ) "vmul.t C030, C030, C010\n" // C030 = C030 * C010 = ( sp*sy*cr, sy*sr*cp, sr*sp*cy ) "vadd.s S003, S003, S013\n" // S003 = S003 + S013 = cp*cy*cr + cp*cy*cr "vadd.t C000, C020, C030[-X, Y, -Z]\n" - // S000 = S020 - C030 = cp*cy*sr - sp*sy*cr - // S001 = S021 + C031 = cy*cr*sp + sy*sr*cp - // S002 = S022 - C032 = cr*cp*sy - sr*sp*cy - "sv.q C000, %0\n" // *q = C000 - ".set pop\n" // restore assembler option + // S000 = S020 - C030 = cp*cy*sr - sp*sy*cr + // S001 = S021 + C031 = cy*cr*sp + sy*sr*cp + // S002 = S022 - C032 = cr*cp*sy - sr*sp*cy + "sv.q C000, %0\n" // *q = C000 + ".set pop\n" // restore assembler option : "=m"( *q ) : "m"( dst_angles ) ); @@ -891,118 +904,118 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) #if XASH_PSP int sides; __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.s S000, 0 + %[normal]\n" // S000 = p->normal[0] - "lv.s S001, 4 + %[normal]\n" // S001 = p->normal[1] - "lv.s S002, 8 + %[normal]\n" // S002 = p->normal[2] - "vzero.p C030\n" // C030 = [0.0f, 0.0f] + "lv.s S000, 0 + %[normal]\n" // S000 = p->normal[0] + "lv.s S001, 4 + %[normal]\n" // S001 = p->normal[1] + "lv.s S002, 8 + %[normal]\n" // S002 = p->normal[2] + "vzero.p C030\n" // C030 = [0.0f, 0.0f] "lv.s S032, %[dist]\n" // S032 = p->dist - "move $8, $0\n" // $8 = 0 - "beq %[signbits], $8, 0f\n" // jump to 0 + "move $8, $0\n" // $8 = 0 + "beq %[signbits], $8, 0f\n" // jump to 0 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 1f\n" // jump to 1 + "beq %[signbits], $8, 1f\n" // jump to 1 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 2f\n" // jump to 2 + "beq %[signbits], $8, 2f\n" // jump to 2 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 3f\n" // jump to 3 + "beq %[signbits], $8, 3f\n" // jump to 3 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 4f\n" // jump to 4 + "beq %[signbits], $8, 4f\n" // jump to 4 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 5f\n" // jump to 5 + "beq %[signbits], $8, 5f\n" // jump to 5 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 6f\n" // jump to 6 + "beq %[signbits], $8, 6f\n" // jump to 6 "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 7f\n" // jump to 7 - "nop\n" // ( delay slot ) - "j 9f\n" // jump to SetSides - "nop\n" // ( delay slot ) + "beq %[signbits], $8, 7f\n" // jump to 7 + "nop\n" // ( delay slot ) + "j 9f\n" // jump to SetSides + "nop\n" // ( delay slot ) "0:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "1:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "2:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "3:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "4:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "5:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "6:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) + "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "j 8f\n" // jump to DotProduct + "nop\n" // ( delay slot ) "7:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "8:\n" // DotProduct + "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] + "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] + "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] + "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] + "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] + "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] + "8:\n" // DotProduct "vdot.t S030, C000, C010\n" // S030 = C000 * C010 "vdot.t S031, C000, C020\n" // S031 = C000 * C020 - "9:\n" // SetSides + "9:\n" // SetSides "addiu %[sides], $0, 0\n" // sides = 0 "vcmp.s LT, S030, S032\n" // S030 < S032 "bvt 0, 10f\n" // if ( CC[0] == 1 ) jump to 10 - "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 1\n"// sides = 1 + "nop\n" // ( delay slot ) + "addiu %[sides], %[sides], 1\n" // sides = 1 "10:\n" "vcmp.s GE, S031, S032\n" // S031 >= S032 "bvt 0, 11f\n" // if ( CC[0] == 1 ) jump to 11 - "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 2\n"// sides = sides + 2 + "nop\n" // ( delay slot ) + "addiu %[sides], %[sides], 2\n" // sides = sides + 2 "11:\n" - ".set pop\n" // restore assembler option + ".set pop\n" // restore assembler option : [sides] "=r" ( sides ) : [normal] "m" ( p->normal ), [emaxs] "m" ( *emaxs ), diff --git a/ref_gu/gu_clipping.c b/ref_gu/gu_clipping.c index 536a8665..ba602120 100644 --- a/ref_gu/gu_clipping.c +++ b/ref_gu/gu_clipping.c @@ -23,23 +23,23 @@ Based on clipping system from PSP Quake by Peter Mackay and Chris Swindle. #define MAX_CLIPPED_VERTICES 32 -#define CPLANE_BOTTOM 0 +#define CPLANE_BOTTOM 0 #define CPLANE_LEFT 1 -#define CPLANE_RIGHT 2 +#define CPLANE_RIGHT 2 #define CPLANE_TOP 3 #define MAX_CPLANES 4 // Types. -typedef ScePspFVector4 plane_type; -typedef plane_type frustum_t[MAX_CPLANES]; +typedef ScePspFVector4 plane_type; +typedef plane_type frustum_t[MAX_CPLANES]; // Transformed frustum. -static ScePspFMatrix4 projection_view_matrix __attribute__( ( aligned( 16 ) ) ); -static frustum_t projection_view_frustum __attribute__( ( aligned( 16 ) ) ); -static frustum_t clipping_frustum __attribute__( ( aligned( 16 ) ) ); +static ScePspFMatrix4 projection_view_matrix __attribute__( ( aligned( 16 ) ) ); +static frustum_t projection_view_frustum __attribute__( ( aligned( 16 ) ) ); +static frustum_t clipping_frustum __attribute__( ( aligned( 16 ) ) ); // The temporary working buffers. -static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__( ( aligned( 16 ) ) ); +static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__( ( aligned( 16 ) ) ); /* ================= @@ -49,13 +49,13 @@ GU_ClipGetFrustum _inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) { __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "lv.q C100, 0(%4)\n" // C000 = matrix->x "lv.q C110, 16(%4)\n" // C010 = matrix->y "lv.q C120, 32(%4)\n" // C020 = matrix->z "lv.q C130, 48(%4)\n" // C030 = matrix->w - "vzero.q C210\n" // C000 = 0 + "vzero.q C210\n" // C000 = 0 "vadd.q C000, R103, R101\n" // C000 = R103 + R101 ( BOTTOM ) "vdot.q S200, C000, C000\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( BOTTOM ) "vadd.q C010, R103, R100\n" // C010 = R103 + R100 ( LEFT ) @@ -64,18 +64,18 @@ _inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) "vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT ) "vsub.q C030, R103, R101\n" // C030 = R103 - R101 ( TOP ) "vdot.q S203, C030, C030\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( TOP ) - "vcmp.q EZ, C200\n" // CC[0] = ( C200 == 0.0f ) - "vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 ) + "vcmp.q EZ, C200\n" // CC[0] = ( C200 == 0.0f ) + "vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 ) "vcmovt.q C200, C210, 0\n" // if ( CC[*] ) C200 = C210 - "vscl.q C000, C000, S200\n" // C000 = C000 * S200 ( BOTTOM ) + "vscl.q C000, C000, S200\n" // C000 = C000 * S200 ( BOTTOM ) "vscl.q C010, C010, S201\n" // C010 = C010 * S201 ( LEFT ) "vscl.q C020, C020, S202\n" // C020 = C020 * S202 ( RIGHT ) "vscl.q C030, C030, S203\n" // C030 = C030 * S203 ( TOP ) - "sv.q C000, %0\n" // Store plane from register - "sv.q C010, %1\n" // Store plane from register - "sv.q C020, %2\n" // Store plane from register - "sv.q C030, %3\n" // Store plane from register - ".set pop\n" // Restore assembler option + "sv.q C000, %0\n" // Store plane from register + "sv.q C010, %1\n" // Store plane from register + "sv.q C020, %2\n" // Store plane from register + "sv.q C030, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option : "=m"( ( *frustum )[CPLANE_BOTTOM] ), "=m"( ( *frustum )[CPLANE_LEFT] ), "=m"( ( *frustum )[CPLANE_RIGHT] ), @@ -113,17 +113,17 @@ void GU_ClipBeginFrame( void ) GU_ClipGetFrustum( &projection_view_matrix, &projection_view_frustum ); __asm__ volatile( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C700, %4\n" // Load plane into register - "lv.q C710, %5\n" // Load plane into register - "lv.q C720, %6\n" // Load plane into register - "lv.q C730, %7\n" // Load plane into register - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register - ".set pop\n" // Restore assembler option + "lv.q C700, %4\n" // Load plane into register + "lv.q C710, %5\n" // Load plane into register + "lv.q C720, %6\n" // Load plane into register + "lv.q C730, %7\n" // Load plane into register + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option : "=m"( clipping_frustum[CPLANE_BOTTOM] ), "=m"( clipping_frustum[CPLANE_LEFT] ), "=m"( clipping_frustum[CPLANE_RIGHT] ), @@ -156,13 +156,13 @@ void GU_ClipBeginBrush( void ) GU_ClipGetFrustum( &projection_view_model_matrix, &clipping_frustum ); __asm__ volatile( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C700, %0\n" // Load plane into register - "lv.q C710, %1\n" // Load plane into register - "lv.q C720, %2\n" // Load plane into register - "lv.q C730, %3\n" // Load plane into register - ".set pop\n" // Restore assembler option + "lv.q C700, %0\n" // Load plane into register + "lv.q C710, %1\n" // Load plane into register + "lv.q C720, %2\n" // Load plane into register + "lv.q C730, %3\n" // Load plane into register + ".set pop\n" // Restore assembler option :: "m"( clipping_frustum[CPLANE_BOTTOM] ), "m"( clipping_frustum[CPLANE_LEFT] ), "m"( clipping_frustum[CPLANE_RIGHT] ), @@ -180,17 +180,17 @@ Restore the clipping frustum void GU_ClipEndBrush( void ) { __asm__ volatile( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C700, %4\n" // Load plane into register - "lv.q C710, %5\n" // Load plane into register - "lv.q C720, %6\n" // Load plane into register - "lv.q C730, %7\n" // Load plane into register - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register - ".set pop\n" // Restore assembler option + "lv.q C700, %4\n" // Load plane into register + "lv.q C710, %5\n" // Load plane into register + "lv.q C720, %6\n" // Load plane into register + "lv.q C730, %7\n" // Load plane into register + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option : "=m"( clipping_frustum[CPLANE_BOTTOM] ), "=m"( clipping_frustum[CPLANE_LEFT] ), "=m"( clipping_frustum[CPLANE_RIGHT] ), @@ -213,18 +213,18 @@ Load the clipping frustum ( native ) void GU_ClipLoadFrustum( const mplane_t *plane ) { __asm__ volatile( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C700, %4\n" // Load plane into register - "ulv.q C710, %5\n" // Load plane into register - "ulv.q C720, %6\n" // Load plane into register - "ulv.q C730, %7\n" // Load plane into register + "ulv.q C700, %4\n" // Load plane into register + "ulv.q C710, %5\n" // Load plane into register + "ulv.q C720, %6\n" // Load plane into register + "ulv.q C730, %7\n" // Load plane into register "vneg.q R703, R703\n" // R703 = -R703 = -dist - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register - ".set pop\n" // Restore assembler option + "sv.q C700, %0\n" // Store plane from register + "sv.q C710, %1\n" // Store plane from register + "sv.q C720, %2\n" // Store plane from register + "sv.q C730, %3\n" // Store plane from register + ".set pop\n" // Restore assembler option : "=m"( clipping_frustum[CPLANE_BOTTOM] ), "=m"( clipping_frustum[CPLANE_LEFT] ), "=m"( clipping_frustum[CPLANE_RIGHT] ), @@ -249,28 +249,28 @@ qboolean GU_ClipIsRequired( const gu_vert_t* v, size_t vc ) { int res; __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "move $8, %1\n" // $8 = &v[0] - "move $9, %2\n" // $9 = vc - "li $10, 20\n" // $10 = 20( sizeof( gu_vert_t ) ) + "move $8, %1\n" // $8 = &v[0] + "move $9, %2\n" // $9 = vc + "li $10, 20\n" // $10 = 20( sizeof( gu_vert_t ) ) "mul $10, $10, $9\n" // $10 = $10 * $9 "addu $10, $10, $8\n" // $10 = $10 + $8 "addiu %0, $0, 1\n" // res = 1 - "vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f] - "0:\n" // loop + "vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f] + "0:\n" // loop "lv.s S610, 8($8)\n" // S610 = v[i].xyz[0] "lv.s S611, 12($8)\n" // S611 = v[i].xyz[1] "lv.s S612, 16($8)\n" // S612 = v[i].xyz[2] "vhtfm4.q C620, M700, C610\n" // C620 = frustrum * v[i].xyz "vcmp.q LT, C620, C600\n" // S620 < 0.0f || S621 < 0.0f || S622 < 0.0f || S623 < 0.0f - "bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit + "bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) ( delay slot ) "bne $10, $8, 0b\n" // if ( $10 != $8 ) jump to loop - "nop\n" // ( delay slot ) - "move %0, $0\n" // res = 0 - "1:\n" // exit - ".set pop\n" // Restore assembler option + "nop\n" // ( delay slot ) + "move %0, $0\n" // res = 0 + "1:\n" // exit + ".set pop\n" // Restore assembler option : "=r"( res ) : "r"( v ), "r"( vc ) : "$8", "$9", "$10" @@ -288,19 +288,19 @@ Clips a polygon against a plane. _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_vert_t *cv, size_t *cvc ) { __asm__ ( - ".set push\n" // save assembler option + ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "move $8, %1\n" // $8 = uv[0] is S + "move $8, %1\n" // $8 = uv[0] is S "addiu $9, $8, 20\n" // $9 = uv[1] is P - "move $10, %2\n" // $10 = uvc - "li $11, 20\n" // $11 = 20( sizeof( gu_vert_t ) ) + "move $10, %2\n" // $10 = uvc + "li $11, 20\n" // $11 = 20( sizeof( gu_vert_t ) ) "mul $11, $11, $10\n" // $11 = $11 * $10 "addu $11, $11, $8\n" // $11 = $11 + $8 - "move $12, %3\n" // $12 = &cv[0] - "move %0, $0\n" // cvc = 0 - "ulv.q C100, %4\n" // Load plane into register - "vzero.s S110\n" // Set zero for cmp - "0:\n" // loop + "move $12, %3\n" // $12 = &cv[0] + "move %0, $0\n" // cvc = 0 + "ulv.q C100, %4\n" // Load plane into register + "vzero.s S110\n" // Set zero for cmp + "0:\n" // loop "lv.s S000, 0($8)\n" // Load vertex S TEX(4b) U into register "lv.s S001, 4($8)\n" // Load vertex S TEX(4b) V into register "lv.s S010, 8($8)\n" // Load vertex S XYZ(4b) X into register @@ -314,19 +314,19 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_ver "vhdp.q S111, C010, C100\n" // S111 = plane * S (S DIST) "vhdp.q S112, C030, C100\n" // S112 = plane * P (P DIST) "vcmp.s LE, S111, S110\n" // (S dist <= 0.0f) - "bvt 0, 2f\n" // if ( CC[0] == 1 ) jump to 2f - "nop\n" // ( delay slot ) + "bvt 0, 2f\n" // if ( CC[0] == 1 ) jump to 2f + "nop\n" // ( delay slot ) "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) - "bvt 0, 1f\n" // if ( CC[0] == 1 ) jump to 1f - "nop\n" // ( delay slot ) + "bvt 0, 1f\n" // if ( CC[0] == 1 ) jump to 1f + "nop\n" // ( delay slot ) "sv.s S020, 0($12)\n" // cv->uv[0] = C020 TEX U "sv.s S021, 4($12)\n" // cv->uv[1] = C021 TEX V "sv.s S030, 8($12)\n" // cv->xyz[0] = C030 XYZ X "sv.s S031, 12($12)\n" // cv->xyz[1] = C031 XYZ Y "sv.s S032, 16($12)\n" // cv->xyz[2] = C032 XYZ Z "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "j 3f\n" // jump to next - "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) + "j 3f\n" // jump to next + "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) "1:\n" "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 @@ -342,12 +342,12 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_ver "sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y "sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "j 3f\n" // jump to next - "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) + "j 3f\n" // jump to next + "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) "2:\n" "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) - "bvt 0, 3f\n" // if ( CC[0] == 1 ) jump to next - "nop\n" // ( delay slot ) + "bvt 0, 3f\n" // if ( CC[0] == 1 ) jump to next + "nop\n" // ( delay slot ) "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 "vsub.p C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX) @@ -370,16 +370,16 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_ver "sv.s S032, 16($12)\n" // cv->xyz[2] = S032 XYZ Z "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) "addiu %0, %0, 1\n" // cvc += 1 - "3:\n" // next + "3:\n" // next "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) "addiu $9, $8, 20\n" // $9 = $8 + 20( sizeof( gu_vert_t ) ) "bne $9, $11, 4f\n" // if ( $11 != $9 ) jump to next "nop\n" - "move $9, %1\n" // $9 = &uv[0] set P + "move $9, %1\n" // $9 = &uv[0] set P "4:\n" "bne $11, $8, 0b\n" // if ( $11 != $8 ) jump to loop - "nop\n" // ( delay slot ) - ".set pop\n" // Restore assembler option + "nop\n" // ( delay slot ) + ".set pop\n" // Restore assembler option : "+r"( *cvc ) : "r"( uv ), "r"( uvc ), "r"( cv ), "m"( *plane ) : "$8", "$9", "$10", "$11", "$12" @@ -412,5 +412,5 @@ void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ) *cv = extGuBeginPacket( NULL ); // uncached GU_Clip2Plane( &clipping_frustum[CPLANE_TOP], work_buffer[0], vc, *cv, cvc ); if ( !cvc ) return; - extGuEndPacket( ( void * )( *cv + *cvc ) ); + extGuEndPacket(( void * )( *cv + *cvc )); } \ No newline at end of file diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index b973cfeb..81e6ae24 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -706,20 +706,20 @@ void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ); */ typedef struct { - int max_texture_size; + int max_texture_size; qboolean softwareGammaUpdate; } glconfig_t; typedef struct { - int width, height; - int activeTMU; + int width, height; + int activeTMU; GLint currentTexture; GLboolean texIdentityMatrix; GLint isFogEnabled; - int faceCull; + int faceCull; qboolean stencilEnabled; qboolean in2DMode; @@ -733,8 +733,8 @@ typedef struct typedef struct { - qboolean initialized; // OpenGL subsystem started - qboolean extended; // extended context allows to GL_Debug + qboolean initialized; // OpenGL subsystem started + qboolean extended; // extended context allows to GL_Debug } glwstate_t; typedef struct @@ -744,19 +744,19 @@ typedef struct int buffer_width; int buffer_format; int buffer_bpp; - void *draw_buffer; - void *disp_buffer; - void *depth_buffer; - void *context_list; - size_t context_list_size; + void *draw_buffer; + void *disp_buffer; + void *depth_buffer; + void *context_list; + size_t context_list_size; }gurender_t; -extern glconfig_t glConfig; -extern glstate_t glState; -extern gurender_t guRender; +extern glconfig_t glConfig; +extern glstate_t glState; +extern gurender_t guRender; // move to engine -extern glwstate_t glw_state; -extern ref_api_t gEngfuncs; +extern glwstate_t glw_state; +extern ref_api_t gEngfuncs; extern ref_globals_t *gpGlobals; #define ENGINE_GET_PARM_ (*gEngfuncs.EngineGetParm) diff --git a/ref_gu/gu_rlight.c b/ref_gu/gu_rlight.c index b4ccd2a3..c1820e1c 100644 --- a/ref_gu/gu_rlight.c +++ b/ref_gu/gu_rlight.c @@ -46,9 +46,8 @@ void CL_RunLightStyles( void ) // light animations // 'm' is normal light, 'a' is no light, 'z' is double bright - for( i = 0; i < MAX_LIGHTSTYLES; i++ ) + for( i = 0, ls = gEngfuncs.GetLightStyle( 0 ); i < MAX_LIGHTSTYLES; i++, ls++ ) { - ls = gEngfuncs.GetLightStyle( i ); if( !WORLDMODEL->lightdata ) { tr.lightstylevalue[i] = 256 * 256; diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 7c3a41ea..903611d7 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -578,7 +578,6 @@ void R_SetupGL( qboolean set_gl_state ) y = floor( gpGlobals->height - RI.viewport[1] * gpGlobals->height / gpGlobals->height ); y2 = ceil( gpGlobals->height - ( RI.viewport[1] + RI.viewport[3] ) * gpGlobals->height / gpGlobals->height ); #endif -#if 1 w = x2 - x; h = y - y2; @@ -586,24 +585,15 @@ void R_SetupGL( qboolean set_gl_state ) 2048 + ( gpGlobals->height >> 1 ) - y2 - ( h >> 1 ), w, h ); sceGuScissor( x, gpGlobals->height - y2 - h, x + w, gpGlobals->height - y2 ); -#else - pglViewport( x, y2, w, h ); -#endif } else { // envpass, mirrorpass -#if 1 - // FIXME: - sceGuViewport( 2048 - ( gpGlobals->width >> 1 ) + RI.viewport[0] + ( RI.viewport[2] >> 1 ), - 2048 + ( gpGlobals->height >> 1 ) - RI.viewport[1] - ( RI.viewport[3] >> 1 ), - RI.viewport[2], RI.viewport[3] ); - sceGuViewport( 2048, 2048, RI.viewport[2], RI.viewport[3] ); + sceGuViewport(2048 - ( gpGlobals->width >> 1 ) + RI.viewport[0] + ( RI.viewport[2] >> 1 ), + 2048 + ( gpGlobals->height >> 1 ) - RI.viewport[1] - ( RI.viewport[3] >> 1 ), + RI.viewport[2], RI.viewport[3] ); sceGuScissor( RI.viewport[0], gpGlobals->height - RI.viewport[1] - RI.viewport[3], RI.viewport[0] + RI.viewport[2], gpGlobals->height - RI.viewport[1] ); -#else - pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); -#endif } sceGumMatrixMode( GU_PROJECTION ); diff --git a/ref_gu/gu_warp.c b/ref_gu/gu_warp.c index ad60361e..e62fad0f 100644 --- a/ref_gu/gu_warp.c +++ b/ref_gu/gu_warp.c @@ -18,9 +18,9 @@ GNU General Public License for more details. #include "gu_local.h" #include "wadfile.h" #define SKYCLOUDS_QUALITY 12 -#define MAX_CLIP_VERTS 128 // skybox clip vertices +#define MAX_CLIP_VERTS 128 // skybox clip vertices #define TURBSCALE ( 256.0f / ( M_PI2 )) -const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" }; +const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" }; static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 }; static const vec3_t skyclip[6] = @@ -154,7 +154,7 @@ void ClipSkyPolygon( int nump, vec3_t vecs, int stage ) { const float *norm; float *v, d, e; - qboolean front, back; + qboolean front, back; float dists[MAX_CLIP_VERTS + 1]; int sides[MAX_CLIP_VERTS + 1]; vec3_t newv[2][MAX_CLIP_VERTS + 1]; @@ -248,7 +248,7 @@ loc1: _inline void MakeSkyVec( float s, float t, int axis, gu_vert_t *out ) { int j, k, farclip; - vec3_t v, b; + vec3_t b; farclip = RI.farClip; @@ -259,8 +259,8 @@ _inline void MakeSkyVec( float s, float t, int axis, gu_vert_t *out ) for( j = 0; j < 3; j++ ) { k = st_to_vec[axis][j]; - v[j] = (k < 0) ? -b[-k-1] : b[k-1]; - v[j] += RI.cullorigin[j]; + out->xyz[j] = (k < 0) ? -b[-k-1] : b[k-1]; + out->xyz[j] += RI.cullorigin[j]; } // avoid bilerp seam @@ -280,7 +280,6 @@ _inline void MakeSkyVec( float s, float t, int axis, gu_vert_t *out ) out->uv[0] = s; out->uv[1] = t; - VectorCopy( v, out->xyz ); } #else void MakeSkyVec( float s, float t, int axis ) @@ -343,10 +342,10 @@ R_AddSkyBoxSurface */ void R_AddSkyBoxSurface( msurface_t *fa ) { - vec3_t verts[MAX_CLIP_VERTS]; + vec3_t verts[MAX_CLIP_VERTS]; glpoly_t *p; - float *v; - int i; + float *v; + int i; if( ENGINE_GET_PARM( PARM_SKY_SPHERE ) && fa->polys && !tr.fCustomSkybox ) { @@ -419,7 +418,6 @@ void R_DrawSkyBox( void ) GL_Bind( XASH_TEXTURE0, tr.skyboxTextures[r_skyTexOrder[i]] ); else GL_Bind( XASH_TEXTURE0, tr.grayTexture ); // stub - //gu_vert_t uv[4] __attribute__( ( aligned( 16 ) ) ); // dcache writeback required! gu_vert_t* const uv = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * 4 ); MakeSkyVec( RI.skyMins[0][i], RI.skyMins[1][i], i, &uv[0] ); MakeSkyVec( RI.skyMins[0][i], RI.skyMaxs[1][i], i, &uv[1] ); @@ -802,11 +800,10 @@ Does a water warp on the pre-fragmented glpoly_t chain */ void EmitWaterPolys( msurface_t *warp, qboolean reverse ) { - gu_vert_t *verts; - float *v, nv, waveHeight; - float s, t, os, ot; + gu_vert_t *verts; + float waveHeight; glpoly_t *p; - int i; + int i; if( !warp->polys ) return; @@ -820,52 +817,41 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse ) for( p = warp->polys; p; p = p->next ) { - if( reverse ) - verts = &p->verts[p->numverts - 1]; + if( reverse ) verts = &p->verts[p->numverts - 1]; else verts = &p->verts[0]; gu_vert_t* const out = ( gu_vert_t* )sceGuGetMemory( sizeof( gu_vert_t ) * p->numverts ); for( i = 0; i < p->numverts; i++ ) { - if( waveHeight ) - { - nv = r_turbsin[( int )( gpGlobals->time * 160.0f + verts->xyz[1] + verts->xyz[0]) & 255] + 8.0f; - nv = (r_turbsin[( int )( verts->xyz[0] * 5.0f + gpGlobals->time * 171.0f - verts->xyz[1]) & 255] + 8.0f ) * 0.8f + nv; - nv = nv * waveHeight + verts->xyz[2]; - } - else nv = verts->xyz[2]; + out[i].uv[0] = verts->uv[0] + r_turbsin[( int )(( verts->uv[1] * 0.125f + gpGlobals->time ) * TURBSCALE ) & 255]; + out[i].uv[0] *= ( 1.0f / SUBDIVIDE_SIZE ); + out[i].uv[1] = verts->uv[1] + r_turbsin[( int )(( verts->uv[0] * 0.125f + gpGlobals->time ) * TURBSCALE ) & 255]; + out[i].uv[1] *= ( 1.0f / SUBDIVIDE_SIZE ); - os = verts->uv[0]; - ot = verts->uv[1]; - - s = os + r_turbsin[(int)((ot * 0.125f + gpGlobals->time) * TURBSCALE) & 255]; - s *= ( 1.0f / SUBDIVIDE_SIZE ); - - t = ot + r_turbsin[(int)((os * 0.125f + gpGlobals->time) * TURBSCALE) & 255]; - t *= ( 1.0f / SUBDIVIDE_SIZE ); - - out[i].uv[0] = s; - out[i].uv[1] = t; out[i].xyz[0] = verts->xyz[0]; out[i].xyz[1] = verts->xyz[1]; - out[i].xyz[2] = nv; - if( reverse ) - verts -= 1; + if( waveHeight ) + { + out[i].xyz[2] = r_turbsin[( int )( gpGlobals->time * 160.0f + verts->xyz[1] + verts->xyz[0] ) & 255] + 8.0f; + out[i].xyz[2] = ( r_turbsin[( int )( verts->xyz[0] * 5.0f + gpGlobals->time * 171.0f - verts->xyz[1] ) & 255] + 8.0f ) * 0.8f + out[i].xyz[2]; + out[i].xyz[2] = out[i].xyz[2] * waveHeight + verts->xyz[2]; + } + else out[i].xyz[2] = verts->xyz[2]; + + if( reverse ) verts -= 1; else verts += 1; } - if ( GU_ClipIsRequired( out, p->numverts ) ) + if ( GU_ClipIsRequired( out, p->numverts )) { // Clip the polygon. gu_vert_t* cv; size_t cvc; GU_Clip( out, p->numverts, &cv, &cvc ); - if( cvc ) - sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); + if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); } - else - sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, out ); + else sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, p->numverts, 0, out ); } GL_SetupFogColorForSurfaces(); } From b567531cdb25d4fc09bc083cb703acf2bb601a4a Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 21 Sep 2022 08:55:44 +0300 Subject: [PATCH 44/84] platform: PSP volatile(P5) memory allocator --- engine/client/ref_common.c | 4 + engine/platform/platform.h | 2 + engine/platform/psp/p5ram_psp.c | 163 +++++++++++++++++++++ engine/platform/psp/p5ram_psp.h | 38 +++++ engine/platform/psp/sys_psp.c | 32 +++-- engine/ref_api.h | 4 + engine/server/sv_save.c | 35 +++++ ref_gu/gu_image.c | 242 +++++++++++++++++--------------- 8 files changed, 395 insertions(+), 125 deletions(-) create mode 100644 engine/platform/psp/p5ram_psp.c create mode 100644 engine/platform/psp/p5ram_psp.h diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index be32ca7c..8e4aaf81 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -393,6 +393,10 @@ static ref_api_t gEngfuncs = pfnDrawNormalTriangles, pfnDrawTransparentTriangles, &clgame.drawFuncs +#if XASH_PSP + ,P5Ram_Alloc, + P5Ram_Free +#endif }; static void R_UnloadProgs( void ) diff --git a/engine/platform/platform.h b/engine/platform/platform.h index e40fe461..4939e155 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -42,6 +42,8 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren void Platform_ReadCmd( const char *fname, int *argc, char **argv ); SceUID Platform_LoadModule( const char *filename, int mpid, SceSize argsize, void *argp ); int Platform_UnloadModule( SceUID modid, int *sce_code ); + +#include "psp/p5ram_psp.h" #endif #if XASH_ANDROID const char *Android_GetAndroidID( void ); diff --git a/engine/platform/psp/p5ram_psp.c b/engine/platform/psp/p5ram_psp.c new file mode 100644 index 00000000..f2a8cce7 --- /dev/null +++ b/engine/platform/psp/p5ram_psp.c @@ -0,0 +1,163 @@ +/* +p5ram_psp.c - PSP P5 memory allocator +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include +#include +#include + +#include +#include +#include "p5ram_psp.h" + +#define P5RAM_ALIGN( x, a ) ((( x ) + (( typeof( x ))( a ) - 1 )) & ~( typeof( x )( a ) - 1 )) + +#define P5RAM_CHECK( addr ) ((( unsigned int )addr >= ( unsigned int )p5ram_addr) && (( unsigned int )addr < ( unsigned int )p5ram_addr + p5ram_size)) + +#define P5RAM_FLAG_INIT 0x01 +#define P5RAM_FLAG_SUSPENDED 0x02 + +typedef struct p5ram_info_s +{ + SceUID uid; + size_t size; + struct p5ram_info_s *next; +}p5ram_info_t; + +static unsigned char p5ram_flags = 0x00; +static p5ram_info_t *p5ram_poolchain = NULL; +static void *p5ram_addr; +static unsigned int p5ram_size; + +int P5Ram_Init( void ) +{ + int result; + + if( p5ram_flags & P5RAM_FLAG_INIT ) + return -1; + + result = sceKernelVolatileMemLock( 0, &p5ram_addr, &p5ram_size ); + if( result == 0 ) + p5ram_flags |= P5RAM_FLAG_INIT; + + return result; +} + +void *P5Ram_Alloc( size_t size ) +{ + SceUID uid; + void *ptr; + + if(!( p5ram_flags & P5RAM_FLAG_INIT )) + return NULL; + + uid = sceKernelAllocPartitionMemory( 5, "USER P5", PSP_SMEM_Low, size + /*sizeof( p5ram_info_t )*/64, NULL ); + if( uid < 0 ) return NULL; + + ptr = sceKernelGetBlockHeadAddr( uid ); + (( p5ram_info_t* )ptr )->uid = uid; + (( p5ram_info_t* )ptr )->size = size; + (( p5ram_info_t* )ptr )->next = p5ram_poolchain; + + p5ram_poolchain = ptr; + + return ptr + /*sizeof( p5ram_info_t )*/64; +} + +void P5Ram_Free( void *ptr ) +{ + p5ram_info_t *info, *next_ptr; + + if( !( p5ram_flags & P5RAM_FLAG_INIT ) || ptr == NULL ) return; + + info = ( p5ram_info_t* )( ptr - /*sizeof( p5ram_info_t )*/64); + + if( info == p5ram_poolchain ) + { + p5ram_poolchain = p5ram_poolchain->next; + } + else + { + next_ptr = p5ram_poolchain; + while( next_ptr ) + { + if( next_ptr->next == info ) + { + next_ptr->next = info->next; + break; + } + next_ptr = next_ptr->next; + } + } + + sceKernelFreePartitionMemory( info->uid ); +} + +void P5Ram_FreeAll( void ) +{ + p5ram_info_t *next_ptr; + + while( p5ram_poolchain ) + { + next_ptr = p5ram_poolchain->next; + sceKernelFreePartitionMemory( p5ram_poolchain->uid ); + p5ram_poolchain = next_ptr; + } +} + +void P5Ram_Shutdown( void ) +{ + if( !( p5ram_flags & P5RAM_FLAG_INIT )) + return; + + P5Ram_FreeAll(); + sceKernelVolatileMemUnlock( 0 ); + + p5ram_flags &= ~P5RAM_FLAG_INIT; +} + +void P5Ram_PowerCallback( int count, int arg, void *common ) +{ + if( !( p5ram_flags & ( P5RAM_FLAG_INIT | P5RAM_FLAG_SUSPENDED ))) + return; + + if ( arg & PSP_POWER_CB_POWER_SWITCH || arg & PSP_POWER_CB_SUSPENDING ) + { + P5Ram_Shutdown(); + p5ram_flags |= P5RAM_FLAG_SUSPENDED; + } + else if ( arg & PSP_POWER_CB_RESUMING ) + { + } + else if ( arg & PSP_POWER_CB_RESUME_COMPLETE ) + { + P5Ram_Init(); + p5ram_flags &= ~P5RAM_FLAG_SUSPENDED; + } +} + +#ifdef P5RAM_DEBUG +void P5Ram_Print( void ) +{ + p5ram_info_t *next_ptr; + + printf("+++++++++++++++++++++++++++++\n"); + next_ptr = p5ram_poolchain; + while( next_ptr ) + { + printf("P5 ALLOC [ 0x%08X 0x%08X 0x%08X 0x%08X ]\n", next_ptr, next_ptr->uid, next_ptr->size, next_ptr->next ); + next_ptr = next_ptr->next; + } + printf("+++++++++++++++++++++++++++++\n"); +} +#endif diff --git a/engine/platform/psp/p5ram_psp.h b/engine/platform/psp/p5ram_psp.h new file mode 100644 index 00000000..dc424c27 --- /dev/null +++ b/engine/platform/psp/p5ram_psp.h @@ -0,0 +1,38 @@ +/* +p5ram_psp.h - PSP P5 memory allocator header +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#ifndef P5RAM_PSP_H +#define P5RAM_PSP_H + +//#define P5RAM_DEBUG + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int P5Ram_Init( void ); +void *P5Ram_Alloc( size_t size ); +void P5Ram_Free( void *ptr ); +void P5Ram_FreeAll( void ); +void P5Ram_Shutdown( void ); +void P5Ram_PowerCallback( int count, int arg, void *common ); +#ifdef P5RAM_DEBUG +void P5Ram_Print( void ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // P5RAM_PSP_H diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index 9c56ecc4..bdb0b2d5 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -30,31 +30,39 @@ PSP_MAIN_THREAD_ATTR( PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_VFPU ); PSP_MAIN_THREAD_STACK_SIZE_KB( 512 ); PSP_HEAP_SIZE_KB( -3 * 1024 ); /* 3 MB for prx modules */ -/* Exit callback */ -static int exit_callback( int arg1, int arg2, void *common ) +static int Platform_ExitCallback( int count, int arg, void *common ) { host.crashed = true; return 0; } -/* Callback thread */ -static int CallbackThread( SceSize args, void *argp ) +static int Platform_PowerCallback( int count, int arg, void *common ) +{ + P5Ram_PowerCallback( count, arg, common ); + return 0; +} + +static int Platform_CallbackThread( SceSize args, void *argp ) { int cbid; - cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL); - sceKernelRegisterExitCallback(cbid); + cbid = sceKernelCreateCallback( "Exit Callback", Platform_ExitCallback, NULL ); + sceKernelRegisterExitCallback( cbid ); + + cbid = sceKernelCreateCallback( "Power Callback", Platform_PowerCallback, NULL ); + scePowerRegisterCallback( 0, cbid ); + sceKernelSleepThreadCB(); return 0; } /* Sets up the callback thread and returns its thread id */ -static int SetupCallbacks( void ) +static int Platform_SetupCallbacks( void ) { int thid = 0; - thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0); + thid = sceKernelCreateThread("update_thread", Platform_CallbackThread, 0x11, 0xFA0, 0, 0); if(thid >= 0) { sceKernelStartThread(thid, 0, 0); @@ -259,7 +267,7 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) *sce_code = sceKernelUnloadModule( modid ); return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); } - +#include "vfs_psp.h" void Platform_Init( void ) { SceUID kamID; @@ -269,7 +277,7 @@ void Platform_Init( void ) pspSdkDisableFPUExceptions(); // exit callback thread - SetupCallbacks(); + Platform_SetupCallbacks(); // set max cpu/gpu frequency scePowerSetClockFrequency( 333, 333, 166 ); @@ -283,10 +291,14 @@ void Platform_Init( void ) result = kaGeEdramSetSize( result ); Platform_UnloadModule( kamID, &result ); } + + // P5 Ram init + P5Ram_Init(); } void Platform_Shutdown( void ) { + P5Ram_Shutdown(); #if XASH_PROFILING gprof_cleanup(); #endif diff --git a/engine/ref_api.h b/engine/ref_api.h index 3539a2a1..0875c77b 100644 --- a/engine/ref_api.h +++ b/engine/ref_api.h @@ -431,6 +431,10 @@ typedef struct ref_api_s void (*pfnDrawNormalTriangles)( void ); void (*pfnDrawTransparentTriangles)( void ); render_interface_t *drawFuncs; +#if XASH_PSP + void *(*P5Ram_Alloc)( size_t size ); + void (*P5Ram_Free)( void *ptr ); +#endif } ref_api_t; struct mip_s; diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index 0a82412b..eafe5c96 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -291,7 +291,11 @@ static void InitEntityTable( SAVERESTOREDATA *pSaveData, int entityCount ) ENTITYTABLE *pTable; int i; +#if XASH_PSP + pSaveData->pTable = P5Ram_Alloc( sizeof( ENTITYTABLE ) * entityCount ); +#else pSaveData->pTable = Mem_Calloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount ); +#endif pSaveData->tableCount = entityCount; // setup entitytable @@ -607,8 +611,13 @@ static SAVERESTOREDATA *SaveInit( int size, int tokenCount ) { SAVERESTOREDATA *pSaveData; +#if XASH_PSP + pSaveData = P5Ram_Alloc( sizeof( SAVERESTOREDATA ) + size ); + pSaveData->pTokens = (char **)P5Ram_Alloc( tokenCount * sizeof( char* )); +#else pSaveData = Mem_Calloc( host.mempool, sizeof( SAVERESTOREDATA ) + size ); pSaveData->pTokens = (char **)Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); +#endif pSaveData->tokenCount = tokenCount; pSaveData->pBaseData = (char *)(pSaveData + 1); // skip the save structure); @@ -657,20 +666,32 @@ static void SaveFinish( SAVERESTOREDATA *pSaveData ) if( pSaveData->pTokens ) { +#if XASH_PSP + P5Ram_Free( pSaveData->pTokens ); +#else Mem_Free( pSaveData->pTokens ); +#endif pSaveData->pTokens = NULL; pSaveData->tokenCount = 0; } if( pSaveData->pTable ) { +#if XASH_PSP + P5Ram_Free( pSaveData->pTable ); +#else Mem_Free( pSaveData->pTable ); +#endif pSaveData->pTable = NULL; pSaveData->tableCount = 0; } svgame.globals->pSaveData = NULL; +#if XASH_PSP + P5Ram_Free( pSaveData ); +#else Mem_Free( pSaveData ); +#endif } /* @@ -2246,7 +2267,11 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) // allocate a table for the strings, and parse the table if( tokenSize > 0 ) { +#if XASH_PSP + pTokenList = P5Ram_Alloc( tokenCount * sizeof( char* )); +#else pTokenList = Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); +#endif // make sure the token strings pointed to by the pToken hashtable. for( i = 0; i < tokenCount; i++ ) @@ -2274,8 +2299,13 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) if( Q_stricmp( pFieldName, "GameHeader" )) { Q_strncpy( comment, "", MAX_STRING ); +#if XASH_PSP + if( pTokenList ) P5Ram_Free( pTokenList ); + if( pSaveData ) P5Ram_Free( pSaveData ); +#else if( pTokenList ) Mem_Free( pTokenList ); if( pSaveData ) Mem_Free( pSaveData ); +#endif FS_Close( f ); return 0; } @@ -2325,8 +2355,13 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) } // delete the string table we allocated +#if XASH_PSP + if( pTokenList ) P5Ram_Free( pTokenList ); + if( pSaveData ) P5Ram_Free( pSaveData ); +#else if( pTokenList ) Mem_Free( pTokenList ); if( pSaveData ) Mem_Free( pSaveData ); +#endif FS_Close( f ); // at least mapname should be filled diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index b00cc9b9..214405ea 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -20,10 +20,10 @@ GNU General Public License for more details. #define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2) -static gl_texture_t gl_textures[MAX_TEXTURES]; +static gl_texture_t gl_textures[MAX_TEXTURES]; static gl_texture_t* gl_texturesHashTable[TEXTURES_HASH_SIZE]; -static uint gl_numTextures; -static byte *palette_332 = NULL; +static uint gl_numTextures; +static byte* gl_palette_332 = NULL; /* num_colors = PALETTE_BLOCKS x 16 (16-bit CLUT) @@ -65,7 +65,7 @@ GL_Bind void GL_Bind( GLint tmu, GLenum texnum ) { gl_texture_t *texture; - int i, offset, width, height; + int i, offset, width, height; // missed or invalid texture? if( texnum <= 0 || texnum >= MAX_TEXTURES ) @@ -84,7 +84,7 @@ void GL_Bind( GLint tmu, GLenum texnum ) if( texture->format == GU_PSM_T8 ) { sceGuClutMode( PALETTE_FORMAT, 0, 0xff, 0 ); - sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ? texture->dstPalette : palette_332 ); + sceGuClutLoad( PALETTE_BLOCKS, texture->dstPalette ); } // Set texture parameters @@ -108,7 +108,7 @@ void GL_Bind( GLint tmu, GLenum texnum ) sceGuTexFilter( GU_LINEAR, GU_LINEAR ); } - if( FBitSet( texture->flags, TF_CLAMP ) || FBitSet( texture->flags, TF_BORDER ) ) + if( FBitSet( texture->flags, TF_CLAMP ) || FBitSet( texture->flags, TF_BORDER )) sceGuTexWrap( GU_CLAMP, GU_CLAMP ); else sceGuTexWrap( GU_REPEAT, GU_REPEAT ); @@ -122,8 +122,8 @@ void GL_Bind( GLint tmu, GLenum texnum ) offset = texture->width * texture->height * texture->bpp; for ( i = 1; i < texture->numMips; i++ ) { - width = Q_max( TEXTURE_SIZE_MIN, ( texture->width >> i ) ); - height = Q_max( TEXTURE_SIZE_MIN, ( texture->height >> i ) ); + width = Q_max( TEXTURE_SIZE_MIN, ( texture->width >> i )); + height = Q_max( TEXTURE_SIZE_MIN, ( texture->height >> i )); sceGuTexImage( i, width, height, width, &texture->dstTexture[offset] ); offset += width * height * texture->bpp; } @@ -138,7 +138,7 @@ GL_CalcImageSize */ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int depth ) { - size_t size = 0; + size_t size = 0; // check the depth error depth = Q_max( 1, depth ); @@ -184,14 +184,14 @@ GL_CalcTextureSize */ static size_t GL_CalcTextureSize( int format, int width, int height, byte *outBpp ) { - size_t size = 0; - byte bpp = 0; + size_t size = 0; + byte bpp = 0; switch( format ) { case GU_PSM_T4: case GU_PSM_DXT1: - size = ( ( width * height ) >> 1 ); + size = (( width * height ) >> 1 ); break; case GU_PSM_T8: case GU_PSM_DXT3: @@ -223,8 +223,8 @@ static size_t GL_CalcTextureSize( int format, int width, int height, byte *outBp static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *mipSize ) { - int width, height; - int mipCount; + int width, height; + int mipCount; Assert( tex != NULL ); @@ -233,19 +233,19 @@ static int GL_CalcMipmapCount( gl_texture_t *tex, qboolean haveBuffer, size_t *m #if 0 // brush model only - if( !FBitSet( tex->flags, TF_ALLOW_EMBOSS ) ) + if( !FBitSet( tex->flags, TF_ALLOW_EMBOSS )) return 1; #endif // generate mip-levels by user request - if( FBitSet( tex->flags, TF_NOMIPMAP ) ) + if( FBitSet( tex->flags, TF_NOMIPMAP )) return 1; // 8 levels - 7 + 1 base for( mipCount = 1; mipCount < 8; mipCount++ ) { - width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> mipCount ) ); - height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> mipCount ) ); + width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> mipCount )); + height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> mipCount )); if( width == TEXTURE_SIZE_MIN && height == TEXTURE_SIZE_MIN ) break; @@ -264,9 +264,9 @@ GL_SetTextureDimensions */ static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height ) { - int maxTextureSize = glConfig.max_texture_size; - int step = (int)gl_round_down->value; - int scaled_width, scaled_height; + int maxTextureSize = glConfig.max_texture_size; + int step = (int)gl_round_down->value; + int scaled_width, scaled_height; Assert( tex != NULL ); @@ -276,12 +276,12 @@ static void GL_SetTextureDimensions( gl_texture_t *tex, int width, int height ) for( scaled_width = 1; scaled_width < width; scaled_width <<= 1 ); - if( step > 0 && width < scaled_width && ( step == 1 || ( scaled_width - width ) > ( scaled_width >> step ) ) ) + if( step > 0 && width < scaled_width && ( step == 1 || ( scaled_width - width ) > ( scaled_width >> step ))) scaled_width >>= 1; for( scaled_height = 1; scaled_height < height; scaled_height <<= 1 ); - if( step > 0 && height < scaled_height && ( step == 1 || ( scaled_height - height ) > ( scaled_height >> step ) ) ) + if( step > 0 && height < scaled_height && ( step == 1 || ( scaled_height - height ) > ( scaled_height >> step ))) scaled_height >>= 1; width = scaled_width; @@ -342,7 +342,7 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan case PF_BGRA_32: case PF_RGB_24: case PF_BGR_24: - if ( IsLightMap( tex ) ) + if ( IsLightMap( tex )) tex->format = GU_PSM_8888; else if( haveAlpha ) tex->format = GU_PSM_4444; @@ -464,7 +464,7 @@ void GL_ResampleTexture8(const byte *source, int inWidth, int inHeight, byte *de byte *out; const byte *inrow; uint frac; - int i, j; + int i, j; if( !source ) return; @@ -659,7 +659,7 @@ PC_SWF - Xash3d Software format mask void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int outFormat ) { int i; - byte color[4]; + byte color[4]; color[0] = color[1] = color[2] = color[3] = 0xff; @@ -789,14 +789,14 @@ fast swizzling */ static void GL_TextureSwizzle( byte *dst, const byte *src, uint width, uint height ) { - uint blockx, blocky; - uint j; - uint width_blocks = ( width / 16 ); - uint height_blocks = ( height / 8 ); - uint src_pitch = ( width - 16 ) / 4; - uint src_row = width * 8; + uint blockx, blocky; + uint j; + uint width_blocks = ( width / 16 ); + uint height_blocks = ( height / 8 ); + uint src_pitch = ( width - 16 ) / 4; + uint src_row = width * 8; const byte* ysrc = src; - uint* dst32 = ( uint* )dst; + uint* dst32 = ( uint* )dst; for ( blocky = 0; blocky < height_blocks; ++blocky ) { @@ -827,15 +827,13 @@ upload texture into memory */ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { - size_t texSize; - uint width, height; - uint i; - uint offset, mipOffset; - qboolean normalMap; - qboolean swizzle; - void *volBuff; - unsigned int volSize; - int volUid; + size_t texSize; + uint width, height; + uint i; + uint offset, mipOffset; + qboolean normalMap; + qboolean swizzle; + byte *tempBuff; // dedicated server if( !glw_state.initialized ) @@ -869,11 +867,6 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) swizzle = IsLightMap( tex ) ? false : true; mipOffset = 0; - // Volatile memory for temporary buffer - volUid = sceKernelVolatileMemLock( 0, &volBuff, &volSize ); - if( volUid != 0) - gEngfuncs.Host_Error( "GL_UploadTexture: volatile memory lock error ( 0x%08x )\n", volUid ); - // Check allocation size if( tex->dstTexture && ( tex->size != texSize ) ) { @@ -894,10 +887,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { tex->dstTexture = ( byte* )memalign( 16, texSize ); if ( !tex->dstTexture ) - { - sceKernelVolatileMemUnlock( 0 ); gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for texture ( %lu )\n", tex->name, texSize ); - } } else SetBits( tex->flags, TF_IMG_INVRAM ); } @@ -914,16 +904,21 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); if ( !tex->dstPalette ) - { - sceKernelVolatileMemUnlock( 0 ); gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for palette ( %lu )\n", tex->name, PALETTE_SIZE ); - } } // Load palette - GL_PixelConverter( tex->dstPalette, pic->palette, 256, PC_SWF( pic->type ), PC_HWF( PALETTE_FORMAT ) ); + GL_PixelConverter( tex->dstPalette, pic->palette, 256, PC_SWF( pic->type ), PC_HWF( PALETTE_FORMAT )); sceKernelDcacheWritebackRange( tex->dstPalette, PALETTE_SIZE ); } + else tex->dstPalette = gl_palette_332; + + // Volatile memory for temporary buffer + if( swizzle ) + { + tempBuff = gEngfuncs.P5Ram_Alloc( texSize ); + if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); + } // Load base + mip texture for( i = 0; i < tex->numMips; i++ ) @@ -931,66 +926,83 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) width = Q_max( TEXTURE_SIZE_MIN, ( tex->width >> i ) ); height = Q_max( TEXTURE_SIZE_MIN, ( tex->height >> i ) ); - if( ( pic->width != width ) || ( pic->height != height ) ) - GL_ResampleTexture8( pic->buffer, pic->width, pic->height, swizzle ? volBuff : ( tex->dstTexture + mipOffset ), width, height ); - else memcpy( swizzle ? volBuff : ( tex->dstTexture + mipOffset ), pic->buffer, offset ); + if(( pic->width != width ) || ( pic->height != height )) + GL_ResampleTexture8( pic->buffer, pic->width, pic->height, swizzle ? tempBuff : ( tex->dstTexture + mipOffset ), width, height ); + else memcpy( swizzle ? tempBuff : ( tex->dstTexture + mipOffset ), pic->buffer, offset ); - if(swizzle) GL_TextureSwizzle( tex->dstTexture + mipOffset, volBuff, width, height ); + if(swizzle) GL_TextureSwizzle( tex->dstTexture + mipOffset, tempBuff, width, height ); mipOffset += GL_CalcTextureSize( tex->format, width, height, NULL ); } - if(swizzle) SetBits( tex->flags, TF_IMG_SWIZZLED ); - } - else if( pic->type == PF_RGB_5650 || pic->type == PF_RGBA_5551 || pic->type == PF_RGBA_4444 ) - { - if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) - { - for( i = 0; i < tex->height; i++ ) - { - memcpy( swizzle ? ( volBuff + tex->width * tex->bpp * i ) : ( tex->dstTexture + tex->width * tex->bpp * i ), - ( pic->buffer + pic->width * tex->bpp * i ), pic->width * tex->bpp ); - } - } - else memcpy( swizzle ? volBuff : tex->dstTexture, pic->buffer, offset ); if( swizzle ) { - GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * tex->bpp, tex->height ); + gEngfuncs.P5Ram_Free( tempBuff ); + SetBits( tex->flags, TF_IMG_SWIZZLED ); + } + } + else if( pic->type == PF_RGB_5650 || pic->type == PF_RGBA_5551 || pic->type == PF_RGBA_4444 ) + { + if( swizzle ) + { + tempBuff = gEngfuncs.P5Ram_Alloc( texSize ); + if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); + } + + if(( pic->width != tex->width ) || ( pic->height != tex->height )) + { + for( i = 0; i < tex->height; i++ ) + { + memcpy( swizzle ? ( tempBuff + tex->width * tex->bpp * i ) : ( tex->dstTexture + tex->width * tex->bpp * i ), + ( pic->buffer + pic->width * tex->bpp * i ), pic->width * tex->bpp ); + } + } + else memcpy( swizzle ? tempBuff : tex->dstTexture, pic->buffer, offset ); + + if( swizzle ) + { + GL_TextureSwizzle( tex->dstTexture, tempBuff, tex->width * tex->bpp, tex->height ); + gEngfuncs.P5Ram_Free( tempBuff ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } } else // RGBA32 { - if( ( pic->width != tex->width ) || ( pic->height != tex->height ) ) - { - GL_ResampleTexture32( pic->buffer, pic->width, pic->height, volBuff, tex->width, tex->height, normalMap ); - offset = tex->width * tex->height * 4; // 4 src bpp - } - else memcpy( volBuff, pic->buffer, offset ); + if(( pic->width != tex->width ) || ( pic->height != tex->height )) + offset = tex->width * tex->height * 4; // src size + + tempBuff = gEngfuncs.P5Ram_Alloc( swizzle ? ( texSize + offset ) : texSize ); + if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); + + if(( pic->width != tex->width ) || ( pic->height != tex->height )) + GL_ResampleTexture32( pic->buffer, pic->width, pic->height, tempBuff, tex->width, tex->height, normalMap ); + else memcpy( tempBuff, pic->buffer, offset ); /* if( !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) - volBuff = GL_ApplyFilter( volBuff, tex->width, tex->height ); + tempBuff = GL_ApplyFilter( tempBuff, tex->width, tex->height ); */ if( tex->format == GU_PSM_8888 ) { if ( swizzle ) { - GL_TextureSwizzle( tex->dstTexture, volBuff, tex->width * tex->bpp, tex->height ); + GL_TextureSwizzle( tex->dstTexture, tempBuff, tex->width * tex->bpp, tex->height ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } - else memcpy( tex->dstTexture, volBuff, texSize ); + else memcpy( tex->dstTexture, tempBuff, texSize ); } else { - GL_PixelConverter( swizzle ? (volBuff + offset) : tex->dstTexture, volBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); + if( tex->format == GU_PSM_T8 ) tex->dstPalette = gl_palette_332; + + GL_PixelConverter( swizzle ? (tempBuff + offset) : tex->dstTexture, tempBuff, tex->width * tex->height, PC_SWF( pic->type ), PC_HWF( tex->format ) ); if( swizzle ) { - GL_TextureSwizzle( tex->dstTexture, volBuff + offset, tex->width * tex->bpp, tex->height ); + GL_TextureSwizzle( tex->dstTexture, tempBuff + offset, tex->width * tex->bpp, tex->height ); SetBits( tex->flags, TF_IMG_SWIZZLED ); } } + gEngfuncs.P5Ram_Free( tempBuff ); } - sceKernelVolatileMemUnlock( 0 ); sceKernelDcacheWritebackRange( tex->dstTexture, texSize ); tex->size = texSize; @@ -1008,8 +1020,8 @@ GL_UpdateTexture qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer ) { gl_texture_t *tex; - size_t texsize; - byte *dst, *src; + size_t texsize; + byte *dst, *src; // missed or invalid texture? if(( texnum <= 0 ) || ( texnum >= MAX_TEXTURES )) @@ -1030,7 +1042,7 @@ qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height if( !FBitSet( tex->flags, TF_IMG_UPLOADED ) ) { - tex->size = GL_CalcTextureSize( tex->format, tex->width, tex->height, &tex->bpp ); + tex->size = GL_CalcTextureSize( tex->format, tex->width, tex->height, &tex->bpp ); tex->numMips = 1; tex->dstPalette = NULL; @@ -1055,7 +1067,7 @@ qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height dst += tex->width * tex->bpp; src += width * tex->bpp; } - + sceKernelDcacheWritebackRange( tex->dstTexture, tex->size ); return true; } @@ -1069,8 +1081,8 @@ do specified actions on pixels */ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) { - float emboss_scale = 0.0f; - uint img_flags = 0; + float emboss_scale = 0.0f; + uint img_flags = 0; // force upload texture as RGB or RGBA (detail textures requires this) if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; @@ -1250,7 +1262,7 @@ static void GL_DeleteTexture( gl_texture_t *tex ) if( tex->original ) gEngfuncs.FS_FreeImage( tex->original ); - if( tex->dstPalette ) + if( tex->dstPalette && tex->dstPalette != gl_palette_332 ) free( tex->dstPalette ); if( tex->dstTexture ) @@ -1306,7 +1318,7 @@ GL_LoadTexture int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) { gl_texture_t *tex; - rgbdata_t *pic; + rgbdata_t *pic; uint picFlags = 0; if( !GL_CheckTexName( name )) @@ -1357,7 +1369,7 @@ int GL_LoadTextureArray( const char **names, int flags ) #if 1 return 0; #else - rgbdata_t *pic, *src; + rgbdata_t *pic, *src; char basename[256]; uint numLayers = 0; uint picFlags = 0; @@ -1544,7 +1556,7 @@ creates texture from buffer int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ) { qboolean update = FBitSet( flags, TF_UPDATE ) ? true : false; - int datasize = 1; + int datasize = 1; rgbdata_t r_empty; if( FBitSet( flags, TF_ARB_16BIT )) @@ -1864,35 +1876,35 @@ GL_Create332Palette */ static void GL_Create332Palette( void ) { - palette_332 = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !palette_332 ) + gl_palette_332 = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !gl_palette_332 ) gEngfuncs.Host_Error( "GL_Create332Palette: out of memory!\n" ); for(int i = 0; i < 256; i++) { #if PALETTE_FORMAT == GU_PSM_5650 - palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; - palette_332[i * 2 + 1] = ( i & 0x38 ) >> 3; - palette_332[i * 2 + 1] |= ( i & 0xc0 ); + gl_palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; + gl_palette_332[i * 2 + 1] = ( i & 0x38 ) >> 3; + gl_palette_332[i * 2 + 1] |= ( i & 0xc0 ); #elif PALETTE_FORMAT == GU_PSM_5551 - palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; - palette_332[i * 2 + 0] |= ( i & 0x08 ) << 4; - palette_332[i * 2 + 1] = ( i & 0x30 ) >> 4; - palette_332[i * 2 + 1] |= ( i & 0xc0 ) >> 1; - palette_332[i * 2 + 1] |= 0x80; + gl_palette_332[i * 2 + 0] = ( i & 0x07 ) << 2; + gl_palette_332[i * 2 + 0] |= ( i & 0x08 ) << 4; + gl_palette_332[i * 2 + 1] = ( i & 0x30 ) >> 4; + gl_palette_332[i * 2 + 1] |= ( i & 0xc0 ) >> 1; + gl_palette_332[i * 2 + 1] |= 0x80; #elif PALETTE_FORMAT == GU_PSM_4444 - palette_332[i * 2 + 0] = ( i & 0x07 ) << 1; - palette_332[i * 2 + 0] |= ( i & 0x38 ) << 2; - palette_332[i * 2 + 1] = ( i & 0xc0 ) >> 4; - palette_332[i * 2 + 1] |= 0xf0; + gl_palette_332[i * 2 + 0] = ( i & 0x07 ) << 1; + gl_palette_332[i * 2 + 0] |= ( i & 0x38 ) << 2; + gl_palette_332[i * 2 + 1] = ( i & 0xc0 ) >> 4; + gl_palette_332[i * 2 + 1] |= 0xf0; #elif PALETTE_FORMAT == GU_PSM_8888 - palette_332[i * 4 + 0] = ( i & 0x07 ) << 5; - palette_332[i * 4 + 1] = ( i & 0x38 ) << 2; - palette_332[i * 4 + 2] = ( i & 0xc0 ); - palette_332[i * 4 + 3] = 0xff; + gl_palette_332[i * 4 + 0] = ( i & 0x07 ) << 5; + gl_palette_332[i * 4 + 1] = ( i & 0x38 ) << 2; + gl_palette_332[i * 4 + 2] = ( i & 0xc0 ); + gl_palette_332[i * 4 + 3] = 0xff; #endif } - sceKernelDcacheWritebackRange( palette_332, PALETTE_SIZE ); + sceKernelDcacheWritebackRange( gl_palette_332, PALETTE_SIZE ); } @@ -2025,8 +2037,8 @@ void R_ShutdownImages( void ) for( i = 0, tex = gl_textures; i < gl_numTextures; i++, tex++ ) GL_DeleteTexture( tex ); - if( palette_332 ) - free( palette_332 ); + if( gl_palette_332 ) + free( gl_palette_332 ); memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); memset( gl_texturesHashTable, 0, sizeof( gl_texturesHashTable )); From b517019750b91ab6dbf959baa39ffc5be9153ee7 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 21 Sep 2022 15:31:26 +0300 Subject: [PATCH 45/84] platform: p5 allocator fix; ref_gu: using vram for palettes --- engine/platform/psp/p5ram_psp.c | 12 ++++++---- engine/platform/psp/p5ram_psp.h | 2 +- engine/platform/psp/sys_psp.c | 2 +- engine/ref_api.h | 2 +- engine/server/sv_save.c | 8 +++---- ref_gu/gu_image.c | 42 +++++++++++++++++++++++---------- ref_gu/gu_vram.c | 5 ++++ ref_gu/gu_vram.h | 1 + 8 files changed, 49 insertions(+), 25 deletions(-) diff --git a/engine/platform/psp/p5ram_psp.c b/engine/platform/psp/p5ram_psp.c index f2a8cce7..1d58a0aa 100644 --- a/engine/platform/psp/p5ram_psp.c +++ b/engine/platform/psp/p5ram_psp.c @@ -18,6 +18,7 @@ GNU General Public License for more details. #include #include +#include #include "p5ram_psp.h" #define P5RAM_ALIGN( x, a ) ((( x ) + (( typeof( x ))( a ) - 1 )) & ~( typeof( x )( a ) - 1 )) @@ -27,7 +28,7 @@ GNU General Public License for more details. #define P5RAM_FLAG_INIT 0x01 #define P5RAM_FLAG_SUSPENDED 0x02 -typedef struct p5ram_info_s +typedef struct __attribute__(( aligned( 64 ))) p5ram_info_s { SceUID uid; size_t size; @@ -53,7 +54,7 @@ int P5Ram_Init( void ) return result; } -void *P5Ram_Alloc( size_t size ) +void *P5Ram_Alloc( size_t size, int clear ) { SceUID uid; void *ptr; @@ -61,17 +62,18 @@ void *P5Ram_Alloc( size_t size ) if(!( p5ram_flags & P5RAM_FLAG_INIT )) return NULL; - uid = sceKernelAllocPartitionMemory( 5, "USER P5", PSP_SMEM_Low, size + /*sizeof( p5ram_info_t )*/64, NULL ); + uid = sceKernelAllocPartitionMemory( 5, "USER P5", PSP_SMEM_Low, size + sizeof( p5ram_info_t ), NULL ); if( uid < 0 ) return NULL; ptr = sceKernelGetBlockHeadAddr( uid ); (( p5ram_info_t* )ptr )->uid = uid; (( p5ram_info_t* )ptr )->size = size; (( p5ram_info_t* )ptr )->next = p5ram_poolchain; + if( clear ) memset(( unsigned char* )ptr + sizeof( p5ram_info_t ), 0, size ); p5ram_poolchain = ptr; - return ptr + /*sizeof( p5ram_info_t )*/64; + return ( void* )(( unsigned char* )ptr + sizeof( p5ram_info_t )); } void P5Ram_Free( void *ptr ) @@ -80,7 +82,7 @@ void P5Ram_Free( void *ptr ) if( !( p5ram_flags & P5RAM_FLAG_INIT ) || ptr == NULL ) return; - info = ( p5ram_info_t* )( ptr - /*sizeof( p5ram_info_t )*/64); + info = ( p5ram_info_t* )((unsigned char*)ptr - sizeof( p5ram_info_t )); if( info == p5ram_poolchain ) { diff --git a/engine/platform/psp/p5ram_psp.h b/engine/platform/psp/p5ram_psp.h index dc424c27..9f73f051 100644 --- a/engine/platform/psp/p5ram_psp.h +++ b/engine/platform/psp/p5ram_psp.h @@ -22,7 +22,7 @@ extern "C" { #endif // __cplusplus int P5Ram_Init( void ); -void *P5Ram_Alloc( size_t size ); +void *P5Ram_Alloc( size_t size, int clear ); void P5Ram_Free( void *ptr ); void P5Ram_FreeAll( void ); void P5Ram_Shutdown( void ); diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index bdb0b2d5..5e2cc518 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -267,7 +267,7 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) *sce_code = sceKernelUnloadModule( modid ); return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); } -#include "vfs_psp.h" + void Platform_Init( void ) { SceUID kamID; diff --git a/engine/ref_api.h b/engine/ref_api.h index 0875c77b..6abbf799 100644 --- a/engine/ref_api.h +++ b/engine/ref_api.h @@ -432,7 +432,7 @@ typedef struct ref_api_s void (*pfnDrawTransparentTriangles)( void ); render_interface_t *drawFuncs; #if XASH_PSP - void *(*P5Ram_Alloc)( size_t size ); + void *(*P5Ram_Alloc)( size_t size, int clear ); void (*P5Ram_Free)( void *ptr ); #endif } ref_api_t; diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index eafe5c96..f6dc900c 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -292,7 +292,7 @@ static void InitEntityTable( SAVERESTOREDATA *pSaveData, int entityCount ) int i; #if XASH_PSP - pSaveData->pTable = P5Ram_Alloc( sizeof( ENTITYTABLE ) * entityCount ); + pSaveData->pTable = P5Ram_Alloc( sizeof( ENTITYTABLE ) * entityCount, 1 ); #else pSaveData->pTable = Mem_Calloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount ); #endif @@ -612,8 +612,8 @@ static SAVERESTOREDATA *SaveInit( int size, int tokenCount ) SAVERESTOREDATA *pSaveData; #if XASH_PSP - pSaveData = P5Ram_Alloc( sizeof( SAVERESTOREDATA ) + size ); - pSaveData->pTokens = (char **)P5Ram_Alloc( tokenCount * sizeof( char* )); + pSaveData = P5Ram_Alloc( sizeof( SAVERESTOREDATA ) + size, 1 ); + pSaveData->pTokens = (char **)P5Ram_Alloc( tokenCount * sizeof( char* ), 1 ); #else pSaveData = Mem_Calloc( host.mempool, sizeof( SAVERESTOREDATA ) + size ); pSaveData->pTokens = (char **)Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); @@ -2268,7 +2268,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) if( tokenSize > 0 ) { #if XASH_PSP - pTokenList = P5Ram_Alloc( tokenCount * sizeof( char* )); + pTokenList = P5Ram_Alloc( tokenCount * sizeof( char* ), 1 ); #else pTokenList = Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); #endif diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 214405ea..561c389f 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -902,9 +902,13 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { if( !tex->dstPalette ) { - tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !tex->dstPalette ) - gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for palette ( %lu )\n", tex->name, PALETTE_SIZE ); + tex->dstPalette = ( byte* )valloc( PALETTE_SIZE ); + if( !tex->dstPalette ) + { + tex->dstPalette = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !tex->dstPalette ) + gEngfuncs.Host_Error( "GL_UploadTexture: %s out of memory for palette ( %lu )\n", tex->name, PALETTE_SIZE ); + } } // Load palette @@ -916,7 +920,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) // Volatile memory for temporary buffer if( swizzle ) { - tempBuff = gEngfuncs.P5Ram_Alloc( texSize ); + tempBuff = gEngfuncs.P5Ram_Alloc( texSize, 0 ); if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); } @@ -944,7 +948,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) { if( swizzle ) { - tempBuff = gEngfuncs.P5Ram_Alloc( texSize ); + tempBuff = gEngfuncs.P5Ram_Alloc( texSize, 0 ); if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); } @@ -970,7 +974,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if(( pic->width != tex->width ) || ( pic->height != tex->height )) offset = tex->width * tex->height * 4; // src size - tempBuff = gEngfuncs.P5Ram_Alloc( swizzle ? ( texSize + offset ) : texSize ); + tempBuff = gEngfuncs.P5Ram_Alloc( swizzle ? ( texSize + offset ) : texSize, 0 ); if( !tempBuff ) gEngfuncs.Host_Error( "GL_UploadTexture: temporary memory error\n" ); if(( pic->width != tex->width ) || ( pic->height != tex->height )) @@ -1040,11 +1044,11 @@ qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height return false; } - if( !FBitSet( tex->flags, TF_IMG_UPLOADED ) ) + if( !FBitSet( tex->flags, TF_IMG_UPLOADED )) { tex->size = GL_CalcTextureSize( tex->format, tex->width, tex->height, &tex->bpp ); tex->numMips = 1; - tex->dstPalette = NULL; + tex->dstPalette = ( tex->format == GU_PSM_T8 ) ? gl_palette_332 : NULL; // default tex->dstTexture = ( byte* )valloc( tex->size ); if( !tex->dstTexture ) @@ -1263,7 +1267,11 @@ static void GL_DeleteTexture( gl_texture_t *tex ) gEngfuncs.FS_FreeImage( tex->original ); if( tex->dstPalette && tex->dstPalette != gl_palette_332 ) - free( tex->dstPalette ); + { + if( vchkptr( tex->dstPalette )) + vfree( tex->dstPalette ); + else free( tex->dstPalette ); + } if( tex->dstTexture ) { @@ -1876,9 +1884,13 @@ GL_Create332Palette */ static void GL_Create332Palette( void ) { - gl_palette_332 = ( byte* )memalign( 16, PALETTE_SIZE ); - if ( !gl_palette_332 ) - gEngfuncs.Host_Error( "GL_Create332Palette: out of memory!\n" ); + gl_palette_332 = ( byte* )valloc( PALETTE_SIZE ); + if( !gl_palette_332 ) + { + gl_palette_332 = ( byte* )memalign( 16, PALETTE_SIZE ); + if ( !gl_palette_332 ) + gEngfuncs.Host_Error( "GL_Create332Palette: out of memory!\n" ); + } for(int i = 0; i < 256; i++) { @@ -2038,7 +2050,11 @@ void R_ShutdownImages( void ) GL_DeleteTexture( tex ); if( gl_palette_332 ) - free( gl_palette_332 ); + { + if( vchkptr( gl_palette_332 )) + vfree( gl_palette_332 ); + else free( gl_palette_332 ); + } memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); memset( gl_texturesHashTable, 0, sizeof( gl_texturesHashTable )); diff --git a/ref_gu/gu_vram.c b/ref_gu/gu_vram.c index d589eef4..2f54de5d 100644 --- a/ref_gu/gu_vram.c +++ b/ref_gu/gu_vram.c @@ -292,3 +292,8 @@ size_t vlargestblock( void ) if( __largest_update ) __find_largest_block(); return __largest_block * __BLOCK_SIZE; } + +int vchkptr( void *ptr ) +{ + return ((( unsigned int )ptr >= __mem_start ) && (( unsigned int )ptr < __mem_start + __mem_size )); +} diff --git a/ref_gu/gu_vram.h b/ref_gu/gu_vram.h index 0602ab56..3c75f001 100644 --- a/ref_gu/gu_vram.h +++ b/ref_gu/gu_vram.h @@ -26,6 +26,7 @@ void* valloc( size_t size ); void vfree( void* ptr ); size_t vmemavail(); size_t vlargestblock(); +int vchkptr( void *ptr ); #ifdef _DEBUG From 21ed285da72572b1b6f11938585904e134808b9f Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 21 Sep 2022 17:01:14 +0300 Subject: [PATCH 46/84] engine: psp filetime fix --- engine/common/filesystem.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index d456e5de..e93f2bb6 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -25,6 +25,7 @@ GNU General Public License for more details. #include #elif XASH_PSP #include +#include #include #include #else @@ -2373,21 +2374,16 @@ Internal function used to determine filetime static int FS_SysFileTime( const char *filename ) { #if XASH_PSP - SceIoStat buf; - struct tm libc_tm; + SceIoStat buf; + time_t fileTime; - if ( sceIoGetstat( filename, &buf ) < 0 ) + if( sceIoGetstat( filename, &buf ) < 0 ) return -1; - libc_tm.tm_year = buf.st_mtime.year; - libc_tm.tm_mon = buf.st_mtime.month; - libc_tm.tm_mday = buf.st_mtime.day; - libc_tm.tm_hour = buf.st_mtime.hour; - libc_tm.tm_min = buf.st_mtime.minute; - libc_tm.tm_sec = buf.st_mtime.second; - libc_tm.tm_isdst = -1; + if( sceRtcGetTime_t(( pspTime* )&buf.st_mtime, &fileTime ) < 0 ) // typedef pspTime! wft? ( pspsdk bug ) + return -1; - return mktime( &libc_tm ); + return fileTime; #else struct stat buf; From d98330adcad06f770b979aef7f299c82c9bb7fc9 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 30 Sep 2022 11:51:57 +0300 Subject: [PATCH 47/84] psp: asm code optimization --- public/matrixlib.c | 27 +++-- public/wscript | 1 + public/xash3d_mathlib.c | 141 ++---------------------- public/xash3d_mathlib_asm.S | 132 ++++++++++++++++++++++ ref_gu/gu_clipping.c | 214 ++++++++++++++++-------------------- ref_gu/gu_local.h | 4 +- ref_gu/gu_rsurf.c | 4 +- ref_gu/gu_warp.c | 4 +- 8 files changed, 256 insertions(+), 271 deletions(-) create mode 100644 public/xash3d_mathlib_asm.S diff --git a/public/matrixlib.c b/public/matrixlib.c index ccc2bb84..4e4e3fe6 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -529,16 +529,16 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering + "mfc1 $8, %4\n" // FPU->CPU + "mtv $8, S210\n" // CPU->VFPU S210 = d "lv.q C100, 0 + %2\n" // C100 = in[0] "lv.q C110, 16 + %2\n" // C110 = in[1] "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 @@ -550,7 +550,8 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, "sv.s S003, %1\n" // dist = S003 ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) - : "m"( *in ), "m"( *normal ), "m"( d ) + : "m"( *in ), "m"( *normal ), "f"( d ) + : "$8" ); #else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); @@ -1172,16 +1173,16 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering + "mfc1 $8, %4\n" // FPU->CPU + "mtv $8, S210\n" // CPU->VFPU S210 = d "lv.q C100, 0 + %2\n" // C100 = in[0] "lv.q C110, 16 + %2\n" // C110 = in[1] "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 @@ -1193,7 +1194,8 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, "sv.s S003, %1\n" // dist = S003 ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) - : "m"( *in ), "m"( *normal ), "m"( d ) + : "m"( *in ), "m"( *normal ), "f"( d ) + : "$8" ); #else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); @@ -1212,16 +1214,16 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering + "mfc1 $8, %4\n" // FPU->CPU + "mtv $8, S210\n" // CPU->VFPU S210 = d "lv.q C100, 0 + %2\n" // C100 = in[0] "lv.q C110, 16 + %2\n" // C110 = in[1] "lv.q C120, 32 + %2\n" // C120 = in[2] "lv.s S200, 0 + %3\n" // S200 = normal[0] "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] - "lv.s S210, %4\n" // S210 = d "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) - "vrcp.s S212, S211\n" // S212 = 1 / S211 + "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 @@ -1233,7 +1235,8 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, "sv.s S003, %1\n" // dist = S003 ".set pop\n" // restore assembler option : "=m"( *out ), "=m"( *dist ) - : "m"( *in ), "m"( *normal ), "m"( d ) + : "m"( *in ), "m"( *normal ), "f"( d ) + : "$8" ); #else float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); diff --git a/public/wscript b/public/wscript index d2ad2ea8..63fa3da5 100644 --- a/public/wscript +++ b/public/wscript @@ -17,6 +17,7 @@ def configure(conf): def build(bld): source = bld.path.ant_glob(['*.c']) + source += bld.path.ant_glob(['*.S']) libs = [] includes = [ '.', '../common', '../engine' ] diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index cf1d2e9f..05de993d 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -315,7 +315,8 @@ float rsqrt( float number ) __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.s S000, %1\n" // S000 = number + "mfc1 $8, %1\n" // FPU->CPU + "mtv $8, S000\n" // CPU->VFPU S000 = number "vzero.s S001\n" // S100 = 0 "vcmp.s EZ, S000\n" // CC[0] = ( S000 == 0.0f ) "vrsq.s S000, S000\n" // S000 = 1.0 / sqrt( S000 ) @@ -323,7 +324,8 @@ float rsqrt( float number ) "sv.s S000, %0\n" // result = S000 ".set pop\n" // restore assembler option : "=m"( result ) - : "m"( number ) + : "f"( number ) + : "$8" ); return result; #endif @@ -355,7 +357,8 @@ void SinCos( float radians, float *sine, float *cosine ) __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.s S000, %2\n" // S000 = radians + "mfc1 $8, %2\n" // FPU->CPU + "mtv $8, S000\n" // CPU->VFPU S000 = radians "vcst.s S001, VFPU_2_PI\n" // S001 = VFPU_2_PI = 2 / PI "vmul.s S000, S000, S001\n" // S000 = S000 * S001 "vrot.p C002, S000, [s, c]\n" // S002 = sin( radians ), S003 = cos( radians ) @@ -363,7 +366,8 @@ void SinCos( float radians, float *sine, float *cosine ) "sv.s S003, %1\n" // cosine = S003 ".set pop\n" // restore assembler option : "=m"( *sine), "=m"( *cosine ) - : "m"( radians ) + : "f"( radians ) + : "$8" ); #else #if _MSC_VER == 1200 @@ -899,133 +903,9 @@ BoxOnPlaneSide Returns 1, 2, or 1 + 2 ================== */ +#if !XASH_PSP int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) { -#if XASH_PSP - int sides; - __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.s S000, 0 + %[normal]\n" // S000 = p->normal[0] - "lv.s S001, 4 + %[normal]\n" // S001 = p->normal[1] - "lv.s S002, 8 + %[normal]\n" // S002 = p->normal[2] - "vzero.p C030\n" // C030 = [0.0f, 0.0f] - "lv.s S032, %[dist]\n" // S032 = p->dist - "move $8, $0\n" // $8 = 0 - "beq %[signbits], $8, 0f\n" // jump to 0 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 1f\n" // jump to 1 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 2f\n" // jump to 2 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 3f\n" // jump to 3 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 4f\n" // jump to 4 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 5f\n" // jump to 5 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 6f\n" // jump to 6 - "addiu $8, $8, 1\n" // $8 = $8 + 1 ( delay slot ) - "beq %[signbits], $8, 7f\n" // jump to 7 - "nop\n" // ( delay slot ) - "j 9f\n" // jump to SetSides - "nop\n" // ( delay slot ) - "0:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "1:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "2:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "3:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emaxs]\n" // S012 = emaxs[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emins]\n" // S022 = emins[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "4:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "5:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emaxs]\n" // S011 = emaxs[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emins]\n" // S021 = emins[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "6:\n" - "lv.s S010, 0 + %[emaxs]\n" // S010 = emaxs[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emins]\n" // S020 = emins[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "j 8f\n" // jump to DotProduct - "nop\n" // ( delay slot ) - "7:\n" - "lv.s S010, 0 + %[emins]\n" // S010 = emins[0] - "lv.s S011, 4 + %[emins]\n" // S011 = emins[1] - "lv.s S012, 8 + %[emins]\n" // S012 = emins[2] - "lv.s S020, 0 + %[emaxs]\n" // S020 = emaxs[0] - "lv.s S021, 4 + %[emaxs]\n" // S021 = emaxs[1] - "lv.s S022, 8 + %[emaxs]\n" // S022 = emaxs[2] - "8:\n" // DotProduct - "vdot.t S030, C000, C010\n" // S030 = C000 * C010 - "vdot.t S031, C000, C020\n" // S031 = C000 * C020 - "9:\n" // SetSides - "addiu %[sides], $0, 0\n" // sides = 0 - "vcmp.s LT, S030, S032\n" // S030 < S032 - "bvt 0, 10f\n" // if ( CC[0] == 1 ) jump to 10 - "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 1\n" // sides = 1 - "10:\n" - "vcmp.s GE, S031, S032\n" // S031 >= S032 - "bvt 0, 11f\n" // if ( CC[0] == 1 ) jump to 11 - "nop\n" // ( delay slot ) - "addiu %[sides], %[sides], 2\n" // sides = sides + 2 - "11:\n" - ".set pop\n" // restore assembler option - : [sides] "=r" ( sides ) - : [normal] "m" ( p->normal ), - [emaxs] "m" ( *emaxs ), - [emins] "m" ( *emins ), - [signbits] "r" ( p->signbits ), - [dist] "m" ( p->dist ) - : "$8" - ); - return sides; -#else int sides = 0; float dist1, dist2; @@ -1076,6 +956,5 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p ) sides |= 2; return sides; -#endif } - +#endif diff --git a/public/xash3d_mathlib_asm.S b/public/xash3d_mathlib_asm.S new file mode 100644 index 00000000..901e39e6 --- /dev/null +++ b/public/xash3d_mathlib_asm.S @@ -0,0 +1,132 @@ +/* +xash3d_mathlib_asm.S - internal mathlib ASM ver. +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include "build.h" +#if XASH_PSP +#include "as_reg_compat.h" + .set noreorder + .set noat + + .text + .align 4 + .global BoxOnPlaneSide + +// int BoxOnPlaneSide( vec3_t emins, vec3_t emaxs, mplane_t *p ); + .ent BoxOnPlaneSide +BoxOnPlaneSide: + ############################ + # a0 - IN emins # + # a1 - IN emaxs # + # a2 - IN p # + # v0 - OUT sides # + ############################ + lbu $v0, 17($a2) // p->signbits + sltiu $v1, $v0, 8 // if(signbits > 8) + beq $v1, $zero, LSetSides // jump to LSetSides + vzero.p C030 // set zero vector + sll $v1, $v0, 2 + la $v0, Ljmptab + addu $v0, $v0, $v1 + lw $v0, 0($v0) + lv.s S000, 0($a2) // p->normal[0] + lv.s S001, 4($a2) // p->normal[1] + jr $v0 + lv.s S002, 8($a2) // p->normal[2] +Lcase0: + lv.s S010, 0($a1) // emaxs[0] + lv.s S011, 4($a1) // emaxs[1] + lv.s S012, 8($a1) // emaxs[2] + lv.s S020, 0($a0) // emins[0] + lv.s S021, 4($a0) // emins[1] + b LDotProduct + lv.s S022, 8($a0) // emins[2] +Lcase1: + lv.s S010, 0($a0) // emins[0] + lv.s S011, 4($a1) // emaxs[1] + lv.s S012, 8($a1) // emaxs[2] + lv.s S020, 0($a1) // emaxs[0] + lv.s S021, 4($a0) // emins[1] + b LDotProduct + lv.s S022, 8($a0) // emins[2] +Lcase2: + lv.s S010, 0($a1) // emaxs[0] + lv.s S011, 4($a0) // emins[1] + lv.s S012, 8($a1) // emaxs[2] + lv.s S020, 0($a0) // emins[0] + lv.s S021, 4($a1) // emaxs[1] + b LDotProduct + lv.s S022, 8($a0) // emins[2] +Lcase3: + lv.s S010, 0($a0) // emins[0] + lv.s S011, 4($a0) // emins[1] + lv.s S012, 8($a1) // emaxs[2] + lv.s S020, 0($a1) // emaxs[0] + lv.s S021, 4($a1) // emaxs[1] + b LDotProduct + lv.s S022, 8($a0) // emins[2] +Lcase4: + lv.s S010, 0($a1) // emaxs[0] + lv.s S011, 4($a1) // emaxs[1] + lv.s S012, 8($a0) // emins[2] + lv.s S020, 0($a0) // emins[0] + lv.s S021, 4($a0) // emins[1] + b LDotProduct + lv.s S022, 8($a1) // emaxs[2] +Lcase5: + lv.s S010, 0($a0) // emins[0] + lv.s S011, 4($a1) // emaxs[1] + lv.s S012, 8($a0) // emins[2] + lv.s S020, 0($a1) // emaxs[0] + lv.s S021, 4($a0) // emins[1] + b LDotProduct + lv.s S022, 8($a1) // emaxs[2] +Lcase6: + lv.s S010, 0($a1) // emaxs[0] + lv.s S011, 4($a0) // emins[1] + lv.s S012, 8($a0) // emins[2] + lv.s S020, 0($a0) // emins[0] + lv.s S021, 4($a1) // emaxs[1] + b LDotProduct + lv.s S022, 8($a1) // emaxs[2] +Lcase7: + lv.s S010, 0($a0) // emins[0] + lv.s S011, 4($a0) // emins[1] + lv.s S012, 8($a0) // emins[2] + lv.s S020, 0($a1) // emaxs[0] + lv.s S021, 4($a1) // emaxs[1] + lv.s S022, 8($a1) // emaxs[2] +LDotProduct: + vdot.t S030, C000, C010 // S030 = C000 * C010 + vdot.t S031, C000, C020 // S031 = C000 * C020 +LSetSides: + lv.s S013, 12($a2) // p->dist + vcmp.s LT, S030, S013 // S030 < S013 + bvt 0, LDist2 // if ( CC[0] == 1 ) jump to LDist2 + li $v0, 0 // sides = 0 + li $v0, 1 // sides = 1 +LDist2: + vcmp.s GE, S031, S013 // S031 >= S013 + bvt 0, LEnd // if ( CC[0] == 1 ) jump to LEnd + nop + ori $v0, $v0, 2 +LEnd: + jr $ra + nop + .end BoxOnPlaneSide + + .section .rodata + .align 4 +Ljmptab: + .word Lcase0, Lcase1, Lcase2, Lcase3, Lcase4, Lcase5, Lcase6, Lcase7 +#endif // XASH_PSP diff --git a/ref_gu/gu_clipping.c b/ref_gu/gu_clipping.c index ba602120..eb92c09d 100644 --- a/ref_gu/gu_clipping.c +++ b/ref_gu/gu_clipping.c @@ -34,12 +34,12 @@ typedef ScePspFVector4 plane_type; typedef plane_type frustum_t[MAX_CPLANES]; // Transformed frustum. -static ScePspFMatrix4 projection_view_matrix __attribute__( ( aligned( 16 ) ) ); -static frustum_t projection_view_frustum __attribute__( ( aligned( 16 ) ) ); -static frustum_t clipping_frustum __attribute__( ( aligned( 16 ) ) ); +static ScePspFMatrix4 projection_view_matrix __attribute__(( aligned( 16 ))); +static frustum_t projection_view_frustum __attribute__(( aligned( 16 ))); +static frustum_t clipping_frustum __attribute__(( aligned( 16 ))); // The temporary working buffers. -static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__( ( aligned( 16 ) ) ); +static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__(( aligned( 16 ))); /* ================= @@ -51,18 +51,18 @@ _inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering + "vzero.q C210\n" // set zero vector "lv.q C100, 0(%4)\n" // C000 = matrix->x "lv.q C110, 16(%4)\n" // C010 = matrix->y "lv.q C120, 32(%4)\n" // C020 = matrix->z "lv.q C130, 48(%4)\n" // C030 = matrix->w - "vzero.q C210\n" // C000 = 0 "vadd.q C000, R103, R101\n" // C000 = R103 + R101 ( BOTTOM ) - "vdot.q S200, C000, C000\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( BOTTOM ) "vadd.q C010, R103, R100\n" // C010 = R103 + R100 ( LEFT ) - "vdot.q S201, C010, C010\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( LEFT ) "vsub.q C020, R103, R100\n" // C020 = R103 - R100 ( RIGHT ) - "vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT ) "vsub.q C030, R103, R101\n" // C030 = R103 - R101 ( TOP ) + "vdot.q S200, C000, C000\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( BOTTOM ) + "vdot.q S201, C010, C010\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( LEFT ) + "vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT ) "vdot.q S203, C030, C030\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( TOP ) "vcmp.q EZ, C200\n" // CC[0] = ( C200 == 0.0f ) "vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 ) @@ -245,37 +245,34 @@ GU_ClipIsRequired Is clipping required? ================= */ -qboolean GU_ClipIsRequired( const gu_vert_t* v, size_t vc ) +int GU_ClipIsRequired( gu_vert_t* uv, int uvc ) { - int res; + int result = 1; + gu_vert_t *uv_end = uv + ( uvc - 1 ); + __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "move $8, %1\n" // $8 = &v[0] - "move $9, %2\n" // $9 = vc - "li $10, 20\n" // $10 = 20( sizeof( gu_vert_t ) ) - "mul $10, $10, $9\n" // $10 = $10 * $9 - "addu $10, $10, $8\n" // $10 = $10 + $8 - "addiu %0, $0, 1\n" // res = 1 "vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f] "0:\n" // loop - "lv.s S610, 8($8)\n" // S610 = v[i].xyz[0] - "lv.s S611, 12($8)\n" // S611 = v[i].xyz[1] - "lv.s S612, 16($8)\n" // S612 = v[i].xyz[2] + "lv.s S610, 8(%1)\n" // S610 = v[i].xyz[0] + "lv.s S611, 12(%1)\n" // S611 = v[i].xyz[1] + "lv.s S612, 16(%1)\n" // S612 = v[i].xyz[2] "vhtfm4.q C620, M700, C610\n" // C620 = frustrum * v[i].xyz "vcmp.q LT, C620, C600\n" // S620 < 0.0f || S621 < 0.0f || S622 < 0.0f || S623 < 0.0f "bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit - "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) ( delay slot ) - "bne $10, $8, 0b\n" // if ( $10 != $8 ) jump to loop "nop\n" // ( delay slot ) + "bne %1, %2, 0b\n" // if ( $10 != $8 ) jump to loop + "addiu %1, %1, %3\n" // $8 = $8 + sizeof( gu_vert_t ) ( delay slot ) "move %0, $0\n" // res = 0 "1:\n" // exit ".set pop\n" // Restore assembler option - : "=r"( res ) - : "r"( v ), "r"( vc ) - : "$8", "$9", "$10" + : "=r"( result ), "+r"( uv ) + : "r"( uv_end ), + "n"(sizeof( gu_vert_t )) + : "$8" ); - return res; + return result; } /* @@ -285,105 +282,78 @@ GU_Clip2Plane Clips a polygon against a plane. ================= */ -_inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, size_t uvc, gu_vert_t *cv, size_t *cvc ) +_inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, int uvc, gu_vert_t *cv, int *cvc ) { + gu_vert_t *uv_end = uv + ( uvc - 1 ); + gu_vert_t *cv_start = cv; + __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "move $8, %1\n" // $8 = uv[0] is S - "addiu $9, $8, 20\n" // $9 = uv[1] is P - "move $10, %2\n" // $10 = uvc - "li $11, 20\n" // $11 = 20( sizeof( gu_vert_t ) ) - "mul $11, $11, $10\n" // $11 = $11 * $10 - "addu $11, $11, $8\n" // $11 = $11 + $8 - "move $12, %3\n" // $12 = &cv[0] - "move %0, $0\n" // cvc = 0 - "ulv.q C100, %4\n" // Load plane into register - "vzero.s S110\n" // Set zero for cmp - "0:\n" // loop - "lv.s S000, 0($8)\n" // Load vertex S TEX(4b) U into register - "lv.s S001, 4($8)\n" // Load vertex S TEX(4b) V into register - "lv.s S010, 8($8)\n" // Load vertex S XYZ(4b) X into register - "lv.s S011, 12($8)\n" // Load vertex S XYZ(4b) Y into register - "lv.s S012, 16($8)\n" // Load vertex S XYZ(4b) Z into register - "lv.s S020, 0($9)\n" // Load vertex P TEX(4b) U into register - "lv.s S021, 4($9)\n" // Load vertex P TEX(4b) V into register - "lv.s S030, 8($9)\n" // Load vertex P XYZ(4b) X into register - "lv.s S031, 12($9)\n" // Load vertex P XYZ(4b) Y into register - "lv.s S032, 16($9)\n" // Load vertex P XYZ(4b) Z into register - "vhdp.q S111, C010, C100\n" // S111 = plane * S (S DIST) - "vhdp.q S112, C030, C100\n" // S112 = plane * P (P DIST) - "vcmp.s LE, S111, S110\n" // (S dist <= 0.0f) - "bvt 0, 2f\n" // if ( CC[0] == 1 ) jump to 2f - "nop\n" // ( delay slot ) - "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) - "bvt 0, 1f\n" // if ( CC[0] == 1 ) jump to 1f - "nop\n" // ( delay slot ) - "sv.s S020, 0($12)\n" // cv->uv[0] = C020 TEX U - "sv.s S021, 4($12)\n" // cv->uv[1] = C021 TEX V - "sv.s S030, 8($12)\n" // cv->xyz[0] = C030 XYZ X - "sv.s S031, 12($12)\n" // cv->xyz[1] = C031 XYZ Y - "sv.s S032, 16($12)\n" // cv->xyz[2] = C032 XYZ Z - "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "j 3f\n" // jump to next - "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) - "1:\n" - "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) - "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 - "vsub.p C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX) - "vsub.t C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ) - "vscl.p C120, C120, S112\n" // C120 = C020 * S112 - "vscl.t C130, C130, S112\n" // C130 = C030 * S112 - "vadd.p C120, C120, C000\n" // C120 = C120 + C000(S TEX) - "vadd.t C130, C130, C010\n" // C130 = C130 + C010(S XYZ) - "sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U - "sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V - "sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X - "sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y - "sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z - "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "j 3f\n" // jump to next - "addiu %0, %0, 1\n" // cvc += 1 ( delay slot ) - "2:\n" - "vcmp.s LE, S112, S110\n" // (P dist <= 0.0f) - "bvt 0, 3f\n" // if ( CC[0] == 1 ) jump to next - "nop\n" // ( delay slot ) - "vsub.s S112, S111, S112\n" // S112 = ( S dist - P dist ) - "vdiv.s S112, S111, S112\n" // S112 = S111 / S112 - "vsub.p C120, C020, C000\n" // C120 = C020(P TEX) - C000(S TEX) - "vsub.t C130, C030, C010\n" // C130 = C030(P XYZ) - C010(S XYZ) - "vscl.p C120, C120, S112\n" // C120 = C020 * S112 - "vscl.t C130, C130, S112\n" // C130 = C030 * S112 - "vadd.p C120, C120, C000\n" // C120 = C120 + C000(S TEX) - "vadd.t C130, C130, C010\n" // C130 = C130 + C010(S XYZ) - "sv.s S120, 0($12)\n" // cv->uv[0] = S120 TEX U - "sv.s S121, 4($12)\n" // cv->uv[1] = S121 TEX V - "sv.s S130, 8($12)\n" // cv->xyz[0] = S130 XYZ X - "sv.s S131, 12($12)\n" // cv->xyz[1] = S131 XYZ Y - "sv.s S132, 16($12)\n" // cv->xyz[2] = S132 XYZ Z - "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "addiu %0, %0, 1\n" // cvc += 1 - "sv.s S020, 0($12)\n" // cv->uv[0] = S020 TEX U - "sv.s S021, 4($12)\n" // cv->uv[1] = S021 TEX V - "sv.s S030, 8($12)\n" // cv->xyz[0] = S030 XYZ X - "sv.s S031, 12($12)\n" // cv->xyz[1] = S031 XYZ Y - "sv.s S032, 16($12)\n" // cv->xyz[2] = S032 XYZ Z - "addiu $12, $12, 20\n" // $12 = $12 + 20( sizeof( gu_vert_t ) ) - "addiu %0, %0, 1\n" // cvc += 1 - "3:\n" // next - "addiu $8, $8, 20\n" // $8 = $8 + 20( sizeof( gu_vert_t ) ) - "addiu $9, $8, 20\n" // $9 = $8 + 20( sizeof( gu_vert_t ) ) - "bne $9, $11, 4f\n" // if ( $11 != $9 ) jump to next + "vzero.q C000\n" // set zero vector + "lv.q C010, 0(%3)\n" // plane + "lv.s S200, 8(%2)\n" // Load vertex P XYZ(4b) X into register + "lv.s S201, 12(%2)\n" // Load vertex P XYZ(4b) Y into register + "lv.s S202, 16(%2)\n" // Load vertex P XYZ(4b) Z into register + "lv.s S210, 0(%2)\n" // Load vertex P TEX(4b) U into register + "lv.s S211, 4(%2)\n" // Load vertex P TEX(4b) V into register + "vhdp.q S212, C200, C010\n" // distance P -> dP + "0:\n" + "lv.s S220, 8(%1)\n" // Load vertex S XYZ(4b) X into register + "lv.s S221, 12(%1)\n" // Load vertex S XYZ(4b) Y into register + "lv.s S222, 16(%1)\n" // Load vertex S XYZ(4b) Z into register + "lv.s S230, 0(%1)\n" // Load vertex S TEX(4b) U into register + "lv.s S231, 4(%1)\n" // Load vertex S TEX(4b) V into register + "vhdp.q S232, C220, C010\n" // distance S -> dS + "vcmp.s GT, S212, S000\n" // if (dP <= 0) + "bvf 0, 1f\n" // goto 1: "nop\n" - "move $9, %1\n" // $9 = &uv[0] set P - "4:\n" - "bne $11, $8, 0b\n" // if ( $11 != $8 ) jump to loop - "nop\n" // ( delay slot ) - ".set pop\n" // Restore assembler option - : "+r"( *cvc ) - : "r"( uv ), "r"( uvc ), "r"( cv ), "m"( *plane ) - : "$8", "$9", "$10", "$11", "$12" - ); + "sv.s S210, 0(%0)\n" // cv->uv[0] = C020 U + "sv.s S211, 4(%0)\n" // cv->uv[1] = C021 V + "sv.s S200, 8(%0)\n" // cv->xyz[0] = C030 X + "sv.s S201, 12(%0)\n" // cv->xyz[1] = C031 Y + "sv.s S202, 16(%0)\n" // cv->xyz[2] = C032 Z + "addiu %0, %0, 20\n" + "1:\n" + "vmul.s S020, S232, S212\n" // (dS * dP) + "vcmp.s LT, S020, S000\n" // if (dS * dP < 0) + "bvf 0, 2f\n" // goto 2: + "vsub.s S021, S232, S212\n" // (dS - dP) + "vrcp.s S021, S021\n" + "vmul.s S021, S021, S232\n" // R = dS / ( dS - dP ) +#if 0 + "vsub.t C200, C220, C200\n" // (S - P) XYZ + "vsub.p C210, C230, C210\n" // (S - P) UV + "vscl.t C200, C200, S021\n" // ((S - P) * R) XYZ + "vscl.p C210, C210, S021\n" // ((S - P) * R) UV + "vsub.t C200, C220, C200\n" // (S - (S - P) * R) XYZ + "vsub.p C210, C230, C210\n" // (S - (S - P) * R) UV +#else + "vsub.t C200, C200, C220\n" // (P - S) XYZ + "vsub.p C210, C210, C230\n" // (P - S) UV + "vscl.t C200, C200, S021\n" // ((P - S) * R) XYZ + "vscl.p C210, C210, S021\n" // ((P - S) * R) UV + "vadd.t C200, C220, C200\n" // (S + (P - S) * R) XYZ + "vadd.p C210, C230, C210\n" // (S + (P - S) * R) UV +#endif + "sv.s S210, 0(%0)\n" // cv->uv[0] = S210 U + "sv.s S211, 4(%0)\n" // cv->uv[1] = S211 V + "sv.s S200, 8(%0)\n" // cv->xyz[0] = S200 X + "sv.s S201, 12(%0)\n" // cv->xyz[1] = S201 Y + "sv.s S202, 16(%0)\n" // cv->xyz[2] = S202 Z + "addiu %0, %0, %4\n" // cv + sizeof(gu_vert_t) + "2:\n" + "vmov.t C200, C220\n" // P = S XYZ + "vmov.t C210, C230\n" // P = S UV and dS + "bne %1, %2, 0b\n" // if (uv != uv_end) goto 0: + "addiu %1, %1, %4\n" // uv + sizeof(gu_vert_t) ( delay slot ) + ".set pop\n" // suppress reordering + : "+r"( cv ), "+r"( uv ) + : "r"( uv_end ), "r"( plane ), + "n"( sizeof( gu_vert_t )) + : "memory" + ) ; + *cvc = ( cv - cv_start ); } /* @@ -393,9 +363,9 @@ GU_Clip Clips a polygon against the frustum ================= */ -void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ) +void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc ) { - size_t vc; + size_t vc; if ( !uvc ) // no vertices to clip? gEngfuncs.Host_Error( "GU_Clip: calling clip with zero vertices!" ); @@ -411,6 +381,6 @@ void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ) if ( !vc ) return; *cv = extGuBeginPacket( NULL ); // uncached GU_Clip2Plane( &clipping_frustum[CPLANE_TOP], work_buffer[0], vc, *cv, cvc ); - if ( !cvc ) return; + if (!( *cvc )) return; extGuEndPacket(( void * )( *cv + *cvc )); } \ No newline at end of file diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index 81e6ae24..cdba1474 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -694,8 +694,8 @@ void GU_ClipBeginFrame( void ); void GU_ClipBeginBrush( void ); void GU_ClipEndBrush( void ); void GU_ClipLoadFrustum( const mplane_t *plane ); // Experimental -qboolean GU_ClipIsRequired( const gu_vert_t* v, size_t vc ); -void GU_Clip( gu_vert_t *uv, size_t uvc, gu_vert_t **cv, size_t* cvc ); +int GU_ClipIsRequired( gu_vert_t* uv, int uvc ); +void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc ); /* ======================================================================= diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index 6b22c484..188f70b3 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -885,7 +885,7 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale ) { // clip the polygon. gu_vert_t* cv; - size_t cvc; + int cvc; GU_Clip( &p->verts[0], p->numverts, &cv, &cvc ); if( cvc ) @@ -935,7 +935,7 @@ void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset ) { // clip the polygon. gu_vert_t* cv; - size_t cvc; + int cvc; GU_Clip( &p->verts[p->numverts], p->numverts, &cv, &cvc ); if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); diff --git a/ref_gu/gu_warp.c b/ref_gu/gu_warp.c index e62fad0f..bc048a86 100644 --- a/ref_gu/gu_warp.c +++ b/ref_gu/gu_warp.c @@ -427,7 +427,7 @@ void R_DrawSkyBox( void ) if ( GU_ClipIsRequired( uv, 4 ) ) { gu_vert_t* cv; - size_t cvc; + int cvc; GU_Clip( uv, 4, &cv, &cvc ); if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); @@ -846,7 +846,7 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse ) { // Clip the polygon. gu_vert_t* cv; - size_t cvc; + int cvc; GU_Clip( out, p->numverts, &cv, &cvc ); if( cvc ) sceGuDrawArray( GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF, cvc, 0, cv ); From 57ddff5457b4f0d42aa43b4a9e1f7ba5c96e8174 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Sun, 2 Oct 2022 21:36:41 +0300 Subject: [PATCH 48/84] engine: R_BreakModel limit reduction for psp --- engine/client/cl_tent.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 1e3bdc03..4c6c03af 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -1023,8 +1023,12 @@ void GAME_EXPORT R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0]) / (3 * SHARD_VOLUME * SHARD_VOLUME); } +#if XASH_PSP + if( count > 15 ) count = 15; +#else // limit to 100 pieces if( count > 100 ) count = 100; +#endif for( i = 0; i < count; i++ ) { From f4ae5cf8e06dcf87cecd239bb10ec40bca33adf0 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 3 Oct 2022 08:19:49 +0300 Subject: [PATCH 49/84] platform: using sceKernelGetSystemTimeWide instead of sceRtcGetCurrentTick --- engine/platform/psp/sys_psp.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index 5e2cc518..f5bf29fb 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -73,24 +73,7 @@ static int Platform_SetupCallbacks( void ) #if XASH_TIMER == TIMER_PSP double Platform_DoubleTime( void ) { -/* - static u64 start_ticks; - static qboolean timer_init = false; - u64 current_ticks; - - if ( !timer_init ) - { - sceRtcGetCurrentTick( &start_ticks ); - timer_init = true; - } - sceRtcGetCurrentTick( ¤t_ticks ); - - return ( current_ticks - start_ticks ) * 0.000001; -*/ - u64 current_ticks; - sceRtcGetCurrentTick( ¤t_ticks ); - - return ( double )current_ticks * 0.000001; + return ( double )sceKernelGetSystemTimeWide() * 0.000001; // microseconds to seconds } void Platform_Sleep( int msec ) From 1abec2620a2e791c4c77671adf5f7f2d2689cc2e Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 4 Oct 2022 09:00:49 +0300 Subject: [PATCH 50/84] psp: fixed bug in asm code, returned vsqrt+vrcp in TransformPositivePlane and TransformStandartPlane --- public/matrixlib.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/public/matrixlib.c b/public/matrixlib.c index 4e4e3fe6..a6963b2d 100644 --- a/public/matrixlib.c +++ b/public/matrixlib.c @@ -538,7 +538,8 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal, "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 @@ -1182,7 +1183,8 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 @@ -1223,7 +1225,8 @@ void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, "lv.s S201, 4 + %3\n" // S201 = normal[1] "lv.s S202, 8 + %3\n" // S202 = normal[2] "vdot.t S211, C100, C100\n" // S211 = C100 * C100 - "vrsq.s S211, S211\n" // S211 = 1 / sqrt( S211 ) + "vsqrt.s S211, S211\n" // S211 = sqrt( S211 ) + "vrcp.s S212, S211\n" // S212 = 1 / S211 "vtfm3.t C000, M100, C200\n" // C000 = M100 * C200 "vscl.t C000, C000, S212\n" // C000 = C000 * S211 "vmul.s S003, S210, S211\n" // S003 = S210 * S211 From ed2ba1f2269eaa488dd51e89fbfe1ffcaa640ff3 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 4 Oct 2022 10:27:01 +0300 Subject: [PATCH 51/84] psp: additional buttons, when pressed HOME --- engine/platform/psp/in_psp.c | 106 ++++++++++++++++++++++------------ engine/platform/psp/sys_psp.c | 4 +- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c index dcd5e1a2..00351f6d 100644 --- a/engine/platform/psp/in_psp.c +++ b/engine/platform/psp/in_psp.c @@ -20,45 +20,48 @@ GNU General Public License for more details. #if XASH_INPUT == INPUT_PSP #include -#define PSP_MAX_KEYS 12 +#define PSP_MAX_KEYS sizeof(psp_keymap) / sizeof(struct psp_keymap_s) +#define PSP_EXT_KEY PSP_CTRL_HOME convar_t *psp_deadzone_min; convar_t *psp_deadzone_max; static struct psp_keymap_s { - unsigned int srckey; - int dstkey; + int srckey; + int dstkey; + qboolean stdpressed; + qboolean extpressed; }psp_keymap[] = { #if 0 - { PSP_CTRL_SELECT, '~' }, - { PSP_CTRL_START, K_ESCAPE }, - { PSP_CTRL_UP, K_UPARROW }, - { PSP_CTRL_RIGHT, K_RIGHTARROW }, - { PSP_CTRL_DOWN, K_DOWNARROW }, - { PSP_CTRL_LEFT, K_LEFTARROW }, - { PSP_CTRL_LTRIGGER, K_JOY1 }, - { PSP_CTRL_RTRIGGER, K_JOY2 }, - { PSP_CTRL_TRIANGLE, K_SHIFT }, - { PSP_CTRL_CIRCLE, K_SPACE }, - { PSP_CTRL_CROSS, K_ENTER }, - { PSP_CTRL_SQUARE, K_BACKSPACE }, + { PSP_CTRL_SELECT, '~' , false, false }, + { PSP_CTRL_START, K_ESCAPE , false, false }, + { PSP_CTRL_UP, K_UPARROW , false, false }, + { PSP_CTRL_RIGHT, K_RIGHTARROW, false, false }, + { PSP_CTRL_DOWN, K_DOWNARROW , false, false }, + { PSP_CTRL_LEFT, K_LEFTARROW , false, false }, + { PSP_CTRL_LTRIGGER, K_JOY1 , false, false }, + { PSP_CTRL_RTRIGGER, K_JOY2 , false, false }, + { PSP_CTRL_TRIANGLE, K_SHIFT , false, false }, + { PSP_CTRL_CIRCLE, K_SPACE , false, false }, + { PSP_CTRL_CROSS, K_ENTER , false, false }, + { PSP_CTRL_SQUARE, K_BACKSPACE , false, false }, #else - { PSP_CTRL_SELECT, K_MODE_BUTTON }, - { PSP_CTRL_START, K_START_BUTTON }, - { PSP_CTRL_UP, K_UPARROW }, - { PSP_CTRL_RIGHT, K_RIGHTARROW }, - { PSP_CTRL_DOWN, K_DOWNARROW }, - { PSP_CTRL_LEFT, K_LEFTARROW }, - { PSP_CTRL_LTRIGGER, K_L1_BUTTON }, - { PSP_CTRL_RTRIGGER, K_R1_BUTTON }, - { PSP_CTRL_TRIANGLE, K_Y_BUTTON }, - { PSP_CTRL_CIRCLE, K_B_BUTTON }, - { PSP_CTRL_CROSS, K_A_BUTTON }, - { PSP_CTRL_SQUARE, K_X_BUTTON }, + { PSP_CTRL_SELECT , K_MODE_BUTTON , false, false }, + { PSP_CTRL_START , K_START_BUTTON, false, false }, + { PSP_CTRL_UP , K_UPARROW , false, false }, + { PSP_CTRL_RIGHT , K_RIGHTARROW , false, false }, + { PSP_CTRL_DOWN , K_DOWNARROW , false, false }, + { PSP_CTRL_LEFT , K_LEFTARROW , false, false }, + { PSP_CTRL_LTRIGGER, K_L1_BUTTON , false, false }, + { PSP_CTRL_RTRIGGER, K_R1_BUTTON , false, false }, + { PSP_CTRL_TRIANGLE, K_Y_BUTTON , false, false }, + { PSP_CTRL_CIRCLE , K_B_BUTTON , false, false }, + { PSP_CTRL_CROSS , K_A_BUTTON , false, false }, + { PSP_CTRL_SQUARE , K_X_BUTTON , false, false }, #endif -#if 0 +#if 0 PSP_CTRL_HOME, PSP_CTRL_HOLD, PSP_CTRL_NOTE, @@ -77,10 +80,10 @@ static float Platform_JoyRescale( float axis, float deadzone_min, float deadzone { float abs_axis, scale, r_deadzone_max; int flip_axis = 0; - + // (-127) - (0) - (+127) abs_axis = axis - 128.0f; - if( abs_axis < 0.0f ) + if( abs_axis < 0.0f ) { abs_axis = -abs_axis - 1.0f; flip_axis = 1; @@ -88,16 +91,16 @@ static float Platform_JoyRescale( float axis, float deadzone_min, float deadzone if( abs_axis <= deadzone_min ) return 0.0f; r_deadzone_max = 127.0f - deadzone_max; if( abs_axis >= r_deadzone_max ) return ( flip_axis ? -127.0f : 127.0f ); - + scale = 127.0f / ( r_deadzone_max - deadzone_min ); abs_axis -= deadzone_min; abs_axis *= scale; - + return ( flip_axis ? -abs_axis : abs_axis ); } void Platform_RunEvents( void ) -{ +{ int i; SceCtrlData buf; signed short curr_X, curr_Y; @@ -108,8 +111,37 @@ void Platform_RunEvents( void ) for( i = 0; i < PSP_MAX_KEYS; i++ ) { - if( ( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) - Key_Event( psp_keymap[i].dstkey, buf.Buttons & psp_keymap[i].srckey ); + if( buf.Buttons & PSP_EXT_KEY ) + { + if(( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) + { + if( psp_keymap[i].stdpressed ) + { + psp_keymap[i].stdpressed = false; + Key_Event( psp_keymap[i].dstkey, psp_keymap[i].stdpressed ); + } + else + { + psp_keymap[i].extpressed = buf.Buttons & psp_keymap[i].srckey; + Key_Event( K_AUX16 + i, psp_keymap[i].extpressed); + } + } + } + else + { + // release + if( psp_keymap[i].extpressed ) + { + psp_keymap[i].extpressed = false; + Key_Event( K_AUX16 + i, psp_keymap[i].extpressed); + } + + if(( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey ) + { + psp_keymap[i].stdpressed = buf.Buttons & psp_keymap[i].srckey; + Key_Event( psp_keymap[i].dstkey, psp_keymap[i].stdpressed ); + } + } } last_buttons = buf.Buttons; @@ -130,7 +162,7 @@ void Platform_RunEvents( void ) if( last_X != curr_X ) Joy_AxisMotionEvent( 2, -curr_X ); - + if( last_Y != curr_Y ) Joy_AxisMotionEvent( 3, -curr_Y ); @@ -160,7 +192,7 @@ int Platform_JoyInit( int numjoy ) // set up cvars psp_deadzone_min = Cvar_Get( "psp_deadzone_min", "20", FCVAR_ARCHIVE, "Joy deadzone min (0 - 127)" ); psp_deadzone_max = Cvar_Get( "psp_deadzone_max", "0", FCVAR_ARCHIVE, "Joy deadzone max (0 - 127)" ); - + // set up the controller. sceCtrlSetSamplingCycle( 0 ); sceCtrlSetSamplingMode( PSP_CTRL_MODE_ANALOG ); diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index f5bf29fb..eba7a9e0 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -46,8 +46,8 @@ static int Platform_CallbackThread( SceSize args, void *argp ) { int cbid; - cbid = sceKernelCreateCallback( "Exit Callback", Platform_ExitCallback, NULL ); - sceKernelRegisterExitCallback( cbid ); + //cbid = sceKernelCreateCallback( "Exit Callback", Platform_ExitCallback, NULL ); + //sceKernelRegisterExitCallback( cbid ); cbid = sceKernelCreateCallback( "Power Callback", Platform_PowerCallback, NULL ); scePowerRegisterCallback( 0, cbid ); From 01affdcbbdbfa50d58dc3d3e4d2aeb5a5e7ab23a Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 4 Oct 2022 10:27:31 +0300 Subject: [PATCH 52/84] psp: lower sound thread priority --- engine/platform/psp/snd_psp.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/engine/platform/psp/snd_psp.c b/engine/platform/psp/snd_psp.c index 37f55878..91e194ba 100644 --- a/engine/platform/psp/snd_psp.c +++ b/engine/platform/psp/snd_psp.c @@ -23,21 +23,21 @@ GNU General Public License for more details. #include "sound.h" -#define PSP_NUM_AUDIO_SAMPLES 1024 // must be multiple of 64 -#define PSP_OUTPUT_CHANNELS 2 -#define PSP_OUTPUT_BUFFER_SIZE ( ( PSP_NUM_AUDIO_SAMPLES ) * ( PSP_OUTPUT_CHANNELS ) ) +#define PSP_NUM_AUDIO_SAMPLES 1024 // must be multiple of 64 +#define PSP_OUTPUT_CHANNELS 2 +#define PSP_OUTPUT_BUFFER_SIZE (( PSP_NUM_AUDIO_SAMPLES ) * ( PSP_OUTPUT_CHANNELS )) static struct { - SceUID threadUID; - SceUID semaUID; - int channel; + SceUID threadUID; + SceUID semaUID; + int channel; volatile int volL; volatile int volR; volatile int running; } snd_psp = { -1, -1, -1, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, 1 }; -static short snd_psp_buff[2][PSP_OUTPUT_BUFFER_SIZE] __attribute__( ( aligned( 64 ) ) ); +static short snd_psp_buff[2][PSP_OUTPUT_BUFFER_SIZE] __attribute__(( aligned( 64 ))); /* ================== @@ -112,12 +112,11 @@ qboolean SNDDMA_Init( void ) // clearing buffers memset( dma.buffer, 0, dma.samples * 2 ); - memset( snd_psp_buff, 0, sizeof( snd_psp_buff ) ); + memset( snd_psp_buff, 0, sizeof( snd_psp_buff )); // allocate and initialize a hardware output channel - snd_psp.channel = sceAudioChReserve( PSP_AUDIO_NEXT_CHANNEL, - PSP_NUM_AUDIO_SAMPLES, - PSP_AUDIO_FORMAT_STEREO ); + snd_psp.channel = sceAudioChReserve( PSP_AUDIO_NEXT_CHANNEL, + PSP_NUM_AUDIO_SAMPLES, PSP_AUDIO_FORMAT_STEREO ); if( snd_psp.channel < 0 ) { SNDDMA_Shutdown(); @@ -133,7 +132,7 @@ qboolean SNDDMA_Init( void ) } // create audio thread - snd_psp.threadUID = sceKernelCreateThread( "sound_thread", SNDDMA_MainThread, 0x11, 0x8000, 0, 0 ); + snd_psp.threadUID = sceKernelCreateThread( "sound_thread", SNDDMA_MainThread, 0x12, 0x8000, 0, 0 ); if( snd_psp.threadUID < 0 ) { SNDDMA_Shutdown(); @@ -202,7 +201,7 @@ int SNDDMA_GetSoundtime( void ) oldsamplepos = samplepos; - return (buffers * fullsamples + samplepos / 2); + return ( buffers * fullsamples + samplepos / 2 ); } /* From e66400ca391e48a814ed818fc1fa4b32975db5f4 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 4 Oct 2022 10:31:33 +0300 Subject: [PATCH 53/84] engine: net_encode.c, net_buffer.c inline functions optimization --- engine/common/net_buffer.c | 3 +-- engine/common/net_buffer.h | 19 ++++++++----------- engine/common/net_encode.c | 4 ---- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index 653e3a7a..6b6b8791 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -94,14 +94,13 @@ void MSG_Clear( sizebuf_t *sb ) sb->bOverflow = false; } -#if XASH_EXT_OPT != 2 static qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) { if( sb->iCurBit + nBits > sb->nDataBits ) sb->bOverflow = true; return sb->bOverflow; } -#endif + qboolean MSG_CheckOverflow( sizebuf_t *sb ) { return MSG_Overflow( sb, 0 ); diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 0ad16130..2a953ce9 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -71,21 +71,18 @@ void MSG_Clear( sizebuf_t *sb ); // Bit-write functions #if XASH_EXT_OPT == 2 -_inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits ) -{ - if( sb->iCurBit + nBits > sb->nDataBits ) - sb->bOverflow = true; - return sb->bOverflow; -} _inline void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) { - if( !MSG_Overflow( sb, 1 )) + if( sb->iCurBit + 1 > sb->nDataBits ) { - if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 ); - else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 ); - - sb->iCurBit++; + sb->bOverflow = true; + return; } + + if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 ); + else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 ); + + sb->iCurBit++; } #else void MSG_WriteOneBit( sizebuf_t *sb, int nValue ); diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index af7274a4..f18546fb 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -1134,11 +1134,7 @@ write fields by offsets assume from and to is valid ===================== */ -#if XASH_EXT_OPT == 2 -_inline qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) -#else qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase ) -#endif { qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false; float flValue, flAngle, flTime; From 8850d2ae522936ad1a6a47f065567c6da79913d7 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 5 Oct 2022 10:26:13 +0300 Subject: [PATCH 54/84] waf: updated build rules for psp --- scripts/waifulib/xcompile.py | 126 ++++++++++++++++++++++------------- scripts/waifulib/xshlib.py | 2 + wscript | 47 ++++++------- 3 files changed, 102 insertions(+), 73 deletions(-) diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 63375a41..44748b8c 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -13,7 +13,7 @@ try: from fwgslib import get_flags_by_compiler except: from waflib.extras.fwgslib import get_flags_by_compiler -from waflib import Logs, TaskGen +from waflib import Logs, TaskGen, Task from waflib.Tools import c_config from collections import OrderedDict import os @@ -330,13 +330,13 @@ class PSP: psptoolchain_path = None pspsdk_path = None binutils_path = None - module_type = None + build_prx = None fw_version = None render_type = None def __init__(self, ctx, moduletype, fwversion, rendertype): self.ctx = ctx - self.module_type = moduletype + self.build_prx = True if moduletype == 'prx' else False self.fw_version = fwversion self.render_type = rendertype @@ -361,15 +361,11 @@ class PSP: # they go before object list def linkflags(self): linkflags = [] -# if self.module_type == 'prx': -# linkflags += ['-specs=%s' % os.path.join(self.pspsdk_path, 'lib/prxspecs')] -# linkflags += ['-Wl,-q,-T%s' % os.path.join(self.pspsdk_path, 'lib/linkfile.prx')] -# linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined', '-no-canonical-prefixes'] return linkflags def ldflags(self): ldflags = [] - if self.module_type == 'prx': + if self.build_prx: ldflags += ['-specs=%s' % os.path.join(self.pspsdk_path, 'lib/prxspecs')] ldflags += ['-Wl,-q,-T%s' % os.path.join(self.pspsdk_path, 'lib/linkfile.prx')] ldflags += ['-L%s' % os.path.join(self.pspsdk_path, 'lib')] @@ -391,7 +387,7 @@ def options(opt): help='enable building for android, format: --android=,,, example: --android=armeabi-v7a-hard,4.9,9') psp = opt.add_option_group('Sony PSP options') - psp.add_option('--psp', action='store', dest='PSP_OPTS', default=None, + psp.add_option('--psp', action='store', dest='PSP_OPTS', default=None, help='enable building for Sony PSP, format: --psp=,, example: --psp=prx,660,HW') def configure(conf): @@ -453,11 +449,6 @@ def configure(conf): conf.environ['RANLIB'] = os.path.join(psp.binutils_path, 'psp-ranlib') conf.environ['OBJCOPY'] = os.path.join(psp.binutils_path, 'psp-objcopy') -# conf.environ['PRXGEN'] = os.path.join(psp.binutils_path, 'prxgen') -# conf.environ['MKSFO'] = os.path.join(psp.binutils_path, 'mksfoex') -# conf.environ['PACK_PBP'] = os.path.join(psp.binutils_path, 'pack-pbp') -# conf.environ['FIXUP'] = os.path.join(psp.binutils_path, 'psp-fixup-imports') - conf.env.PRXGEN = conf.find_program('psp-prxgen', path_list = psp.binutils_path) conf.env.MKSFO = conf.find_program('mksfoex', path_list = psp.binutils_path) conf.env.PACK_PBP = conf.find_program('pack-pbp', path_list = psp.binutils_path) @@ -469,13 +460,12 @@ def configure(conf): conf.env.LINKFLAGS += psp.linkflags() conf.env.LDFLAGS += psp.ldflags() - conf.env.PREFIX = '/lib' - conf.msg('Selected PSPSDK', '%s' % (psp.sdk_home)) # no need to print C/C++ compiler, as it would be printed by compiler_c/cxx conf.msg('... C/C++ flags', ' '.join(psp.cflags()).replace(psp.sdk_home, '$PSPSDK')) conf.msg('... link flags', ' '.join(psp.linkflags()).replace(psp.sdk_home, '$PSPSDK')) conf.msg('... ld flags', ' '.join(psp.ldflags()).replace(psp.sdk_home, '$PSPSDK')) + conf.msg('Bulid prx', '%s' % (psp.build_prx)) if conf.options.PROFILING: conf.env.LDFLAGS += ['-lpspprof'] @@ -484,12 +474,7 @@ def configure(conf): conf.env.DEST_OS2 = 'psp' conf.env.PSP_RENDER_TYPE = psp.render_type - conf.env.PSP_PATTERN_program = '%s' - conf.env.PSP_PATTERN_stlib = 'lib%s.a' - conf.env.PSP_PATTERN_shlib = '%s.elf' - - if psp.module_type == 'prx': - conf.env.PSP_BUILD_PRX = True + conf.env.PSP_BUILD_PRX = psp.build_prx MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android', '__psp__' : 'psp'}) for k in c_config.MACRO_TO_DESTOS: @@ -498,30 +483,7 @@ def configure(conf): def build(bld): if bld.env.DEST_OS == 'psp': - bld(rule='${FIXUP} -o ${TGT} ${SRC}', source='engine/xash', target='xash.elf') - if bld.env.PSP_BUILD_PRX: - bld(rule='${PRXGEN} ${SRC} ${TGT}', source='xash.elf', target='xash.prx') - bld(rule='${MKSFO} -d MEMSIZE=1 Xash3D ${TGT}', source='xash.prx', target='PARAM.SFO') - bld(rule='${PACK_PBP} ${TGT} ${SRC[1]} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0]} ${PSP_EBOOT_PSAR}', source='xash.prx PARAM.SFO', target='EBOOT.PBP') - else: - bld(rule='${STRIP} -o ${TGT} ${SRC}', source='xash.elf', target='xash_strip.elf') - bld(rule='${MKSFO} -d MEMSIZE=1 Xash3D ${TGT}', source='xash_strip.elf', target='PARAM.SFO') - bld(rule='${PACK_PBP} ${TGT} ${SRC[1]} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0]} ${PSP_EBOOT_PSAR}', source='xash_strip.elf PARAM.SFO', target='EBOOT.PBP') -# source_target = os.path.join('engine', bld.env.PSP_BUILD_TARGET) -# Logs.info(source_target) -# Logs.info(bld.env.PSP_BUILD_TARGET) -# bld(rule='${FIXUP} -o ${PSP_BUILD_TARGET}.elf ${SRC}', source=source_target, always=True) -# if bld.env.PSP_BUILD_PRX: -# bld(rule='${PRXGEN} ${PSP_BUILD_TARGET}.elf ${PSP_BUILD_TARGET}.prx', always=True) -# if bld.env.PSP_BUILD_EBOOT: -# bld(rule='${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${PSP_EBOOT_SFO}', always=True) -# bld(rule='${PACK_PBP} ${PSP_EBOOT} ${PSP_EBOOT_SFO} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${PSP_BUILD_TARGET}.prx ${PSP_EBOOT_PSAR}', always=True) -# else: -# if bld.env.PSP_BUILD_EBOOT: -# bld(rule='${STRIP} -o ${PSP_BUILD_TARGET}.elf ${PSP_BUILD_TARGET}_strip.elf', always=True) -# bld(rule='${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${PSP_EBOOT_SFO}', always=True) -# bld(rule='${PACK_PBP} ${PSP_EBOOT} ${PSP_EBOOT_SFO} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${PSP_BUILD_TARGET}_strip.elf ${PSP_EBOOT_PSAR}', always=True) -# bld(rule='rm -f ${PSP_BUILD_TARGET}_strip.elf', always=True) + apply_psptools() def post_compiler_cxx_configure(conf): conf.msg('Target OS', conf.env.DEST_OS) @@ -573,3 +535,75 @@ def apply_android_soname(self): libname = node.name v = self.env.SONAME_ST % libname self.env.append_value('LINKFLAGS', v.split()) + +################################## +# PSP Tools # +################################## +class psp_fixup(Task.Task): + run_str = '${FIXUP} -o ${TGT} ${SRC}' + color = 'BLUE' + +class psp_prxgen(Task.Task): + run_str = '${PRXGEN} ${SRC} ${TGT}' + color = 'BLUE' + +class psp_strip(Task.Task): + run_str = '${STRIP} -o ${TGT} ${SRC}' + color = 'BLUE' + +class psp_mksfo(Task.Task): + run_str = '${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${TGT}' + color = 'YELLOW' + +class psp_packpbp(Task.Task): + run_str = '${PACK_PBP} ${TGT} ${SRC[1].abspath()} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0].abspath()} ${PSP_EBOOT_PSAR}' + color = 'GREEN' + +def apply_psptools(): + "apply PSP tools" + + @TaskGen.feature('cshlib', 'cxxshlib') + @TaskGen.after_method('apply_link') + def build_module(self): + link_output = self.link_task.outputs[0] + for d in self.env.STATIC_LINKING: + if link_output.name.startswith(d): + return + fixup_output = self.path.find_or_declare(link_output.name + '_fixup') + prxgen_output = self.path.find_or_declare(link_output.change_ext('.prx').name) + + task = self.create_task('psp_fixup', src=link_output, tgt=fixup_output) + task = self.create_task('psp_prxgen', src=fixup_output, tgt=prxgen_output) + + if getattr(self, 'install_path', None): + if self.bld.is_install: + for k in self.install_task.inputs: + if k == self.path.find_or_declare(link_output.name): + self.install_task.inputs.remove(k) + self.add_install_files(install_to=self.install_path, install_from=prxgen_output) + + @TaskGen.feature('cprogram', 'cxxprogram', 'cprogram_static', 'cxxprogram_static') + @TaskGen.after_method('apply_link') + def build_eboot(self): + finalobj_ext = '.elf' + finalobj_tool = 'psp_strip' + if self.env.PSP_BUILD_PRX: + finalobj_ext = '.prx' + finalobj_tool = 'psp_prxgen' + + link_output = self.link_task.outputs[0] + fixup_output = self.path.find_or_declare(link_output.name + '_fixup') + finalobj_output = self.path.find_or_declare(link_output.change_ext(finalobj_ext).name) + + mksfo_output = self.path.find_or_declare('PARAM.SFO') + packpbp_output = self.path.find_or_declare('EBOOT.PBP') + + task = self.create_task('psp_fixup', src=link_output, tgt=fixup_output) + task = self.create_task(finalobj_tool, src=fixup_output, tgt=finalobj_output) + task = self.create_task('psp_mksfo', tgt=mksfo_output) + task = self.create_task('psp_packpbp', src=[finalobj_output, mksfo_output], tgt=packpbp_output) + + if getattr(self, 'install_path', None): + if getattr(self, 'install_task', None): + self.install_task.inputs = self.install_task.outputs = [] + self.add_install_files(install_to=self.install_path, install_from=[packpbp_output, finalobj_output]) diff --git a/scripts/waifulib/xshlib.py b/scripts/waifulib/xshlib.py index 60c10120..47c7547d 100644 --- a/scripts/waifulib/xshlib.py +++ b/scripts/waifulib/xshlib.py @@ -96,6 +96,8 @@ def apply_static(main, *reloc): for k in ('cshlib', 'cxxshlib'): if k in self.features: self.features.remove(k) + if getattr(self, 'install_path', None): + delattr(self, 'install_path') self.features.append('xshlib') in_node = self.path.get_src().make_node('exports.txt') bldnode = self.path.get_bld() diff --git a/wscript b/wscript index d495dfd2..adbb6a34 100644 --- a/wscript +++ b/wscript @@ -19,12 +19,14 @@ class Subproject: singlebin = False # if true will be ignored when singlebinary is set ignore = False # if true will be ignored, set by user request mandatory = False + psp = False - def __init__(self, name, dedicated=True, singlebin=False, mandatory = False): + def __init__(self, name, dedicated=True, singlebin=False, mandatory = False, onlypsp = False): self.name = name self.dedicated = dedicated self.singlebin = singlebin self.mandatory = mandatory + self.onlypsp = onlypsp def is_enabled(self, ctx): if not self.mandatory: @@ -40,6 +42,9 @@ class Subproject: if ctx.env.DEST_OS == 'android' and self.singlebin: return False + if ctx.env.DEST_OS != 'psp' and self.onlypsp: + return False + if ctx.env.DEDICATED and self.dedicated: return False @@ -49,7 +54,7 @@ SUBDIRS = [ Subproject('public', dedicated=False, mandatory = True), Subproject('game_launch', singlebin=True), Subproject('ref_gl',), - Subproject('ref_gu',), + Subproject('ref_gu', onlypsp=True), Subproject('ref_soft'), Subproject('mainui'), Subproject('vgui_support'), @@ -172,14 +177,6 @@ def configure(conf): conf.options.STATIC = True enforce_pic = False - # rewrite compile patterns - conf.env.cprogram_PATTERN = conf.env.PSP_PATTERN_program - conf.env.cxxprogram_PATTERN = conf.env.PSP_PATTERN_program - conf.env.cshlib_PATTERN = conf.env.PSP_PATTERN_shlib - conf.env.cxxshlib_PATTERN = conf.env.PSP_PATTERN_shlib - conf.env.cstlib_PATTERN = conf.env.PSP_PATTERN_stlib - conf.env.cxxstlib_PATTERN = conf.env.PSP_PATTERN_stlib - # set EBOOT.PBP generation parameters conf.env.PSP_EBOOT_TITLE = 'Xash3D' conf.env.PSP_EBOOT_SFO = 'PARAM.SFO' @@ -189,30 +186,27 @@ def configure(conf): conf.env.PSP_EBOOT_PIC1 = 'NULL' conf.env.PSP_EBOOT_SND0 = 'NULL' conf.env.PSP_EBOOT_PSAR = 'NULL' - conf.env.PSP_EBOOT = 'EBOOT.PBP' - - # set target parameters - conf.env.PSP_BUILD_TARGET = 'xash' - conf.env.PSP_BUILD_EBOOT = True if conf.options.SINGLE_BINARY: - conf.options.IGNORE_PROJECTS = 'ref_gl,stub/server,stub/client' - conf.options.STATIC_LINKING = 'menu' + static_list = ['menu'] + ignore_list = ['ref_gl','stub/server','stub/client'] + if conf.env.PSP_RENDER_TYPE == 'SW': - conf.options.STATIC_LINKING += ',ref_soft' + static_list.append('ref_soft') else: - conf.options.IGNORE_PROJECTS += ',ref_soft' + ignore_list.append('ref_soft') if conf.env.PSP_RENDER_TYPE == 'HW': - conf.options.STATIC_LINKING += ',ref_gu' + static_list.append('ref_gu') else: - conf.options.IGNORE_PROJECTS += ',ref_gu' + ignore_list.append('ref_gu') if conf.env.PSP_RENDER_TYPE == 'ALL': - conf.options.STATIC_LINKING += 'ref_soft,ref_gu' + static_list.append(['ref_soft','ref_gu']) - conf.env.IGNORE_PROJECTS = conf.options.IGNORE_PROJECTS.split(',') - conf.load('xshlib') # for set linking + conf.options.STATIC_LINKING = ','.join(static_list) + conf.env.IGNORE_PROJECTS = ignore_list + conf.load('xshlib') # apply static link options if conf.env.STATIC_LINKING: enforce_pic = False # PIC may break static linking @@ -466,7 +460,7 @@ def configure(conf): # conf.multicheck(*a, run_all_tests = True, mandatory = True) # indicate if we are packaging for Linux/BSD - if not conf.options.WIN_INSTALL and conf.env.DEST_OS not in ['win32', 'darwin', 'android']: + if not conf.options.WIN_INSTALL and conf.env.DEST_OS not in ['win32', 'darwin', 'android', 'psp']: conf.env.LIBDIR = conf.env.BINDIR = '${PREFIX}/lib/xash3d' else: conf.env.LIBDIR = conf.env.BINDIR = conf.env.PREFIX @@ -489,10 +483,9 @@ def configure(conf): conf.add_subproject(i.name) def build(bld): - bld.load('xshlib') + bld.load('xshlib xcompile') for i in SUBDIRS: if not i.is_enabled(bld): continue bld.add_subproject(i.name) - bld.load('xcompile') From ef117ffbb3cc70ae575bd43dbc8770b9f286ba8b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 5 Oct 2022 10:36:39 +0300 Subject: [PATCH 55/84] readme: psp profiling --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0786004..fc184986 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,12 @@ Even if Xash3D FWGS does support targetting 64-bit, you can't load games without #### PSP 0) Navigate to `xash3d-fwgs` directory. 1) Examine which build options are available: `./waf --help` -2) Configure build: `./waf configure -T fast --psp=prx,660,HW --prefix=/path/to/any/output/directory` +2) Configure build: + Normal: `./waf configure -T fast --psp=prx,660,HW --prefix=/path/to/any/output/directory` + Profiling: `./waf configure -T debug --psp=elf,660,HW --enable-profiling --prefix=/path/to/any/output/directory` 3) Compile: `./waf build` +4) Install(optional): `./waf install` + ## Running 0) Copy libraries and main executable somewhere, if you're skipped installation stage. From 5ad4f43a7edb839b64d4c51e4aaa7ab5e6225af6 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 5 Oct 2022 10:42:11 +0300 Subject: [PATCH 56/84] waf: self.onlypsp fixed --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index adbb6a34..a98b4a41 100644 --- a/wscript +++ b/wscript @@ -19,7 +19,7 @@ class Subproject: singlebin = False # if true will be ignored when singlebinary is set ignore = False # if true will be ignored, set by user request mandatory = False - psp = False + onlypsp = False def __init__(self, name, dedicated=True, singlebin=False, mandatory = False, onlypsp = False): self.name = name From 3b50fded8b2ec75342f6d8a5dd2ce7de6fb118ec Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 6 Oct 2022 15:25:07 +0300 Subject: [PATCH 57/84] ref_gu: menu freeze fix --- ref_gu/gu_rmain.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 903611d7..49edafbf 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -1066,6 +1066,9 @@ void R_CheckGamma( void ) glConfig.softwareGammaUpdate = true; GL_RebuildLightmaps(); glConfig.softwareGammaUpdate = false; + + ClearBits( vid_brightness->flags, FCVAR_CHANGED ); + ClearBits( vid_gamma->flags, FCVAR_CHANGED ); } } From f8452b8490ad1d332fef3b8166d8e1efb978d343 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 6 Oct 2022 16:45:15 +0300 Subject: [PATCH 58/84] ref_gu: R_TextureList_f total size fix --- ref_gu/gu_image.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ref_gu/gu_image.c b/ref_gu/gu_image.c index 561c389f..739a50d2 100644 --- a/ref_gu/gu_image.c +++ b/ref_gu/gu_image.c @@ -1937,53 +1937,53 @@ void R_TextureList_f( void ) { if( !image->dstTexture ) continue; - if( image->dstPalette ) ram_bytes += PALETTE_SIZE; + if( image->dstPalette && image->dstPalette != gl_palette_332 ) ram_bytes += PALETTE_SIZE; vram_bytes += ( FBitSet( image->flags, TF_IMG_INVRAM ) ) ? image->size : 0; ram_bytes += ( FBitSet( image->flags, TF_IMG_INVRAM ) ) ? 0 : image->size; texCount++; gEngfuncs.Con_Printf( "%4i: ", i ); - gEngfuncs.Con_Printf( "%4i %4i ", image->width, image->height ); + gEngfuncs.Con_Printf( "%3i %3i ", image->width, image->height ); gEngfuncs.Con_Printf( "%12s ", Q_memprint( image->size )); switch( image->format ) { case GU_PSM_T4: - gEngfuncs.Con_Printf( "T4 " ); + gEngfuncs.Con_Printf( "T4 " ); break; case GU_PSM_T8: - gEngfuncs.Con_Printf( "T8 " ); + gEngfuncs.Con_Printf( "T8 " ); break; case GU_PSM_T16: - gEngfuncs.Con_Printf( "T16 " ); + gEngfuncs.Con_Printf( "T16 " ); break; case GU_PSM_T32: - gEngfuncs.Con_Printf( "T32 " ); + gEngfuncs.Con_Printf( "T32 " ); break; case GU_PSM_DXT1: - gEngfuncs.Con_Printf( "DXT1 " ); + gEngfuncs.Con_Printf( "DXT1 " ); break; case GU_PSM_DXT3: - gEngfuncs.Con_Printf( "DXT3 " ); + gEngfuncs.Con_Printf( "DXT3 " ); break; case GU_PSM_DXT5: - gEngfuncs.Con_Printf( "DXT5 " ); + gEngfuncs.Con_Printf( "DXT5 " ); break; case GU_PSM_4444: - gEngfuncs.Con_Printf( "4444 " ); + gEngfuncs.Con_Printf( "4444 " ); break; case GU_PSM_5551: - gEngfuncs.Con_Printf( "5551 " ); + gEngfuncs.Con_Printf( "5551 " ); break; case GU_PSM_5650: - gEngfuncs.Con_Printf( "5650 " ); + gEngfuncs.Con_Printf( "5650 " ); break; case GU_PSM_8888: - gEngfuncs.Con_Printf( "8888 " ); + gEngfuncs.Con_Printf( "8888 " ); break; default: - gEngfuncs.Con_Printf( " ^1ERROR^7 " ); + gEngfuncs.Con_Printf( " ^1ERR^7 " ); break; } From 40dca1ea1f9ecce380ae475b4c9ca7a8e92f93c8 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 6 Oct 2022 16:58:33 +0300 Subject: [PATCH 59/84] ref_gu: vsync fix --- ref_gu/gu_rmain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 49edafbf..331c7b20 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -1184,15 +1184,15 @@ void R_EndFrame( void ) // finish rendering. sceGuFinish(); sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT ); - + + gEngfuncs.GL_SwapBuffers(); // vsync + // swap the buffers. sceGuSwapBuffers(); void* p_swap = guRender.disp_buffer; guRender.disp_buffer = guRender.draw_buffer; guRender.draw_buffer = p_swap; - - gEngfuncs.GL_SwapBuffers(); // vsync // start a new render. sceGuStart( GU_DIRECT, guRender.context_list ); From f70938d2b0f0ad01ced0b7d59e5897552fde0e60 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 10 Oct 2022 16:44:48 +0300 Subject: [PATCH 60/84] ref_gl: ref_soft: ref_gu: engine: TriAPI update --- engine/client/cl_game.c | 186 +++--------------------------------- engine/client/cl_gameui.c | 12 +-- engine/client/cl_netgraph.c | 20 ++-- engine/client/cl_tent.c | 2 +- engine/client/cl_tent.h | 13 --- engine/client/cl_view.c | 18 ++-- engine/client/client.h | 5 +- engine/client/console.c | 14 +-- engine/client/in_touch.c | 16 ++-- engine/client/ref_common.c | 37 ++----- engine/ref_api.h | 16 +--- ref_gl/gl_backend.c | 10 ++ ref_gl/gl_context.c | 16 +--- ref_gl/gl_local.h | 7 +- ref_gl/gl_triapi.c | 115 ++++++++++++++++------ ref_gu/gu_backend.c | 10 ++ ref_gu/gu_context.c | 16 +--- ref_gu/gu_local.h | 12 +-- ref_gu/gu_triapi.c | 101 ++++++++++++++++++-- ref_soft/r_context.c | 21 ++-- ref_soft/r_local.h | 7 ++ ref_soft/r_triapi.c | 82 ++++++++++++++++ 22 files changed, 374 insertions(+), 362 deletions(-) diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index c8397b7a..bd149096 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -94,6 +94,9 @@ static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher { NULL, NULL } }; +// shared between client and server +triangleapi_t gTriApi; + static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc ); /* @@ -542,7 +545,7 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei // scale for screen sizes SPR_AdjustSize( &x, &y, &width, &height ); texnum = ref.dllFuncs.R_GetSpriteTexture( clgame.ds.pSprite, frame ); - ref.dllFuncs.Color4ub( clgame.ds.spriteColor[0], clgame.ds.spriteColor[1], clgame.ds.spriteColor[2], clgame.ds.spriteColor[3] ); + ref.dllFuncs.GL_SetColor4ub( clgame.ds.spriteColor[0], clgame.ds.spriteColor[1], clgame.ds.spriteColor[2], clgame.ds.spriteColor[3] ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, texnum ); } @@ -649,14 +652,14 @@ void CL_DrawScreenFade( void ) iFadeAlpha = bound( 0, iFadeAlpha, sf->fadealpha ); } - ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, iFadeAlpha ); + ref.dllFuncs.GL_SetColor4ub( sf->fader, sf->fadeg, sf->fadeb, iFadeAlpha ); if( sf->fadeFlags & FFADE_MODULATE ) ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd ); else ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( 0, 0, refState.width, refState.height, 0, 0, 1, 1, R_GetBuiltinTexture( REF_WHITE_TEXTURE )); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* @@ -938,7 +941,7 @@ void CL_DrawCrosshair( void ) VectorAdd( refState.viewangles, cl.crosshairangle, angles ); AngleVectors( angles, forward, NULL, NULL ); VectorAdd( refState.vieworg, forward, point ); - ref.dllFuncs.WorldToScreen( point, screen ); + gTriApi.WorldToScreen( point, screen ); x += ( clgame.viewport[2] >> 1 ) * screen[0] + 0.5f; y += ( clgame.viewport[3] >> 1 ) * screen[1] + 0.5f; @@ -982,7 +985,7 @@ static void CL_DrawLoadingOrPaused( qboolean paused, float percent ) { float step, s2; - ref.dllFuncs.Color4ub( 128, 128, 128, 255 ); + ref.dllFuncs.GL_SetColor4ub( 128, 128, 128, 255 ); ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); @@ -991,14 +994,14 @@ static void CL_DrawLoadingOrPaused( qboolean paused, float percent ) s2 = (float)right / width; width = right; - ref.dllFuncs.Color4ub( 208, 152, 0, 255 ); + ref.dllFuncs.GL_SetColor4ub( 208, 152, 0, 255 ); ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } else { - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); } @@ -1107,7 +1110,6 @@ void CL_ClearWorld( void ) world.max_recursion = 0; - clgame.ds.cullMode = TRI_FRONT; clgame.numStatics = 0; } @@ -3094,169 +3096,6 @@ char *pfnParseFile( char *data, char *token ) return out; } -/* -================= -TriAPI implementation - -================= -*/ -/* -================= -TriRenderMode -================= -*/ -void TriRenderMode( int mode ) -{ - clgame.ds.renderMode = mode; - ref.dllFuncs.TriRenderMode( mode ); -} - -/* -================= -TriColor4f -================= -*/ -void TriColor4f( float r, float g, float b, float a ) -{ - if( clgame.ds.renderMode == kRenderTransAlpha ) - ref.dllFuncs.Color4ub( r * 255.9f, g * 255.9f, b * 255.9f, a * 255.0f ); - else ref.dllFuncs.Color4f( r * a, g * a, b * a, 1.0 ); - - clgame.ds.triRGBA[0] = r; - clgame.ds.triRGBA[1] = g; - clgame.ds.triRGBA[2] = b; - clgame.ds.triRGBA[3] = a; -} - -/* -============= -TriColor4ub -============= -*/ -void TriColor4ub( byte r, byte g, byte b, byte a ) -{ - clgame.ds.triRGBA[0] = r * (1.0f / 255.0f); - clgame.ds.triRGBA[1] = g * (1.0f / 255.0f); - clgame.ds.triRGBA[2] = b * (1.0f / 255.0f); - clgame.ds.triRGBA[3] = a * (1.0f / 255.0f); - - ref.dllFuncs.Color4f( clgame.ds.triRGBA[0], clgame.ds.triRGBA[1], clgame.ds.triRGBA[2], 1.0f ); -} - -/* -============= -TriBrightness -============= -*/ -void TriBrightness( float brightness ) -{ - float r, g, b; - - r = clgame.ds.triRGBA[0] * clgame.ds.triRGBA[3] * brightness; - g = clgame.ds.triRGBA[1] * clgame.ds.triRGBA[3] * brightness; - b = clgame.ds.triRGBA[2] * clgame.ds.triRGBA[3] * brightness; - - ref.dllFuncs.Color4f( r, g, b, 1.0f ); -} - -/* -============= -TriCullFace -============= -*/ -void TriCullFace( TRICULLSTYLE style ) -{ - clgame.ds.cullMode = style; - ref.dllFuncs.CullFace( style ); -} - -/* -============= -TriWorldToScreen -convert world coordinates (x,y,z) into screen (x, y) -============= -*/ -int TriWorldToScreen( const float *world, float *screen ) -{ - int retval; - - retval = ref.dllFuncs.WorldToScreen( world, screen ); - - screen[0] = 0.5f * screen[0] * (float)clgame.viewport[2]; - screen[1] = -0.5f * screen[1] * (float)clgame.viewport[3]; - screen[0] += 0.5f * (float)clgame.viewport[2]; - screen[1] += 0.5f * (float)clgame.viewport[3]; - - return retval; -} - -/* -============= -TriBoxInPVS - -check box in pvs (absmin, absmax) -============= -*/ -int TriBoxInPVS( float *mins, float *maxs ) -{ - return Mod_BoxVisible( mins, maxs, ref.dllFuncs.Mod_GetCurrentVis( )); -} - -/* -============= -TriLightAtPoint -NOTE: dlights are ignored -============= -*/ -void TriLightAtPoint( float *pos, float *value ) -{ - colorVec vLightColor; - - if( !pos || !value ) return; - - vLightColor = ref.dllFuncs.R_LightPoint( pos ); - - value[0] = vLightColor.r; - value[1] = vLightColor.g; - value[2] = vLightColor.b; -} - -/* -============= -TriColor4fRendermode -Heavy legacy of Quake... -============= -*/ -void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ) -{ - if( clgame.ds.renderMode == kRenderTransAlpha ) - { - clgame.ds.triRGBA[3] = a / 255.0f; - ref.dllFuncs.Color4f( r, g, b, a ); - } - else ref.dllFuncs.Color4f( r * a, g * a, b * a, 1.0f ); -} - - -/* -============= -TriSpriteTexture - -bind current texture -============= -*/ -int TriSpriteTexture( model_t *pSpriteModel, int frame ) -{ - int gl_texturenum; - - if(( gl_texturenum = ref.dllFuncs.R_GetSpriteTexture( pSpriteModel, frame )) <= 0 ) - return 0; - - ref.dllFuncs.GL_Bind( XASH_TEXTURE0, gl_texturenum ); - - return 1; -} - /* ================= DemoApi implementation @@ -3616,9 +3455,6 @@ static void GAME_EXPORT VGui_ViewportPaintBackground( int extents[4] ) // stub } -// shared between client and server -triangleapi_t gTriApi; - static efx_api_t gEfxApi = { R_AllocParticle, diff --git a/engine/client/cl_gameui.c b/engine/client/cl_gameui.c index b5b70325..4453cfce 100644 --- a/engine/client/cl_gameui.c +++ b/engine/client/cl_gameui.c @@ -514,7 +514,7 @@ static void PIC_DrawGeneric( float x, float y, float width, float height, const PicAdjustSize( &x, &y, &width, &height ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.gl_texturenum ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* @@ -592,7 +592,7 @@ void GAME_EXPORT pfnPIC_Set( HIMAGE hPic, int r, int g, int b, int a ) g = bound( 0, g, 255 ); b = bound( 0, b, 255 ); a = bound( 0, a, 255 ); - ref.dllFuncs.Color4ub( r, g, b, a ); + ref.dllFuncs.GL_SetColor4ub( r, g, b, a ); } /* @@ -691,10 +691,10 @@ static void GAME_EXPORT pfnFillRGBA( int x, int y, int width, int height, int r, g = bound( 0, g, 255 ); b = bound( 0, b, 255 ); a = bound( 0, a, 255 ); - ref.dllFuncs.Color4ub( r, g, b, a ); + ref.dllFuncs.GL_SetColor4ub( r, g, b, a ); ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, R_GetBuiltinTexture( REF_WHITE_TEXTURE ) ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* @@ -752,7 +752,7 @@ static void GAME_EXPORT pfnDrawCharacter( int ix, int iy, int iwidth, int iheigh color[0] = (ulRGBA & 0xFF0000) >> 16; color[1] = (ulRGBA & 0xFF00) >> 8; color[2] = (ulRGBA & 0xFF) >> 0; - ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] ); + ref.dllFuncs.GL_SetColor4ub( color[0], color[1], color[2], color[3] ); col = (ch & 15) * 0.0625f + (0.5f / 256.0f); row = (ch >> 4) * 0.0625f + (0.5f / 256.0f); @@ -769,7 +769,7 @@ static void GAME_EXPORT pfnDrawCharacter( int ix, int iy, int iwidth, int iheigh ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hFont ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* diff --git a/engine/client/cl_netgraph.c b/engine/client/cl_netgraph.c index 3aa51ce0..945d7301 100644 --- a/engine/client/cl_netgraph.c +++ b/engine/client/cl_netgraph.c @@ -80,12 +80,12 @@ NetGraph_FillRGBA shortcut */ static void NetGraph_DrawRect( wrect_t *rect, byte colors[4] ) { - ref.dllFuncs.Color4ub( colors[0], colors[1], colors[2], colors[3] ); // color for this quad + gTriApi.Color4ub( colors[0], colors[1], colors[2], colors[3] ); // color for this quad - ref.dllFuncs.Vertex3f( rect->left, rect->top, 0 ); - ref.dllFuncs.Vertex3f( rect->left + rect->right, rect->top, 0 ); - ref.dllFuncs.Vertex3f( rect->left + rect->right, rect->top + rect->bottom, 0 ); - ref.dllFuncs.Vertex3f( rect->left, rect->top + rect->bottom, 0 ); + gTriApi.Vertex3f( rect->left, rect->top, 0 ); + gTriApi.Vertex3f( rect->left + rect->right, rect->top, 0 ); + gTriApi.Vertex3f( rect->left + rect->right, rect->top + rect->bottom, 0 ); + gTriApi.Vertex3f( rect->left, rect->top + rect->bottom, 0 ); } /* @@ -657,17 +657,17 @@ void SCR_DrawNetGraph( void ) if( net_graph->value < 3 ) { - ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd ); + gTriApi.RenderMode( kRenderTransAdd ); - ref.dllFuncs.Begin( TRI_QUADS ); // draw all the fills as a long solid sequence of quads for speedup reasons + gTriApi.Begin( TRI_QUADS ); // draw all the fills as a long solid sequence of quads for speedup reasons // NOTE: fill colors without texture at this point NetGraph_DrawDataUsage( x, y, w ); NetGraph_DrawTimes( rect, x, w ); - ref.dllFuncs.End(); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); - ref.dllFuncs.GL_SetRenderMode( kRenderNormal ); + gTriApi.End(); + gTriApi.Color4ub( 255, 255, 255, 255 ); + gTriApi.RenderMode( kRenderNormal ); } } diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 4c6c03af..ef1daece 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -393,7 +393,7 @@ int CL_TempEntAddEntity( cl_entity_t *pEntity ) VectorAdd( pEntity->origin, pEntity->model->maxs, maxs ); // g-cont. just use PVS from previous frame - if( TriBoxInPVS( mins, maxs )) + if( Mod_BoxVisible( mins, maxs, ref.dllFuncs.Mod_GetCurrentVis( ))) { VectorCopy( pEntity->angles, pEntity->curstate.angles ); VectorCopy( pEntity->origin, pEntity->curstate.origin ); diff --git a/engine/client/cl_tent.h b/engine/client/cl_tent.h index 1cae7155..0e088ae5 100644 --- a/engine/client/cl_tent.h +++ b/engine/client/cl_tent.h @@ -102,19 +102,6 @@ struct beam_s *R_BeamRing( int startEnt, int endEnt, int modelIndex, float life, struct beam_s *R_BeamFollow( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); void R_BeamKill( int deadEntity ); - -// TriAPI -void TriRenderMode( int mode ); -void TriColor4f( float r, float g, float b, float a ); -void TriColor4ub( byte r, byte g, byte b, byte a ); -void TriBrightness( float brightness ); -void TriCullFace( TRICULLSTYLE mode ); -int TriWorldToScreen( const float *world, float *screen ); -int TriBoxInPVS( float *mins, float *maxs ); -void TriLightAtPoint( float *pos, float *value ); -void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ); -int TriSpriteTexture( model_t *pSpriteModel, int frame ); - extern model_t *cl_sprite_dot; extern model_t *cl_sprite_shell; diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 050bdaaf..00759ec8 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -360,10 +360,10 @@ void R_DrawLeafNode( float x, float y, float scale ) void R_DrawNodeConnection( float x, float y, float x2, float y2 ) { - ref.dllFuncs.Begin( TRI_LINES ); - ref.dllFuncs.Vertex3f( x, y, 0 ); - ref.dllFuncs.Vertex3f( x2, y2, 0 ); - ref.dllFuncs.End( ); + gTriApi.Begin( TRI_LINES ); + gTriApi.Vertex3f( x, y, 0 ); + gTriApi.Vertex3f( x2, y2, 0 ); + gTriApi.End( ); } void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes, mleaf_t *viewleaf ) @@ -386,10 +386,10 @@ void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes, if( shownodes == 1 ) { if( cl.worldmodel->leafs == leaf ) - ref.dllFuncs.Color4f( 1.0f, 1.0f, 1.0f, 1.0f ); + gTriApi.Color4f( 1.0f, 1.0f, 1.0f, 1.0f ); else if( viewleaf && viewleaf == leaf ) - ref.dllFuncs.Color4f( 1.0f, 0.0f, 0.0f, 1.0f ); - else ref.dllFuncs.Color4f( 0.0f, 1.0f, 0.0f, 1.0f ); + gTriApi.Color4f( 1.0f, 0.0f, 0.0f, 1.0f ); + else gTriApi.Color4f( 0.0f, 1.0f, 0.0f, 1.0f ); R_DrawLeafNode( x, y, scale ); } world.recursion_level--; @@ -398,7 +398,7 @@ void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes, if( shownodes == 1 ) { - ref.dllFuncs.Color4f( 0.0f, 0.0f, 1.0f, 1.0f ); + gTriApi.Color4f( 0.0f, 0.0f, 1.0f, 1.0f ); R_DrawLeafNode( x, y, scale ); } else if( shownodes == 2 ) @@ -430,7 +430,7 @@ void R_ShowTree( void ) //pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //pglLineWidth( 2.0f ); - ref.dllFuncs.Color4f( 1, 0.7f, 0, 1.0f ); + gTriApi.Color4f( 1, 0.7f, 0, 1.0f ); //pglDisable( GL_TEXTURE_2D ); R_ShowTree_r( cl.worldmodel->nodes, x, y, world.max_recursion * 3.5f, 2, viewleaf ); //pglEnable( GL_TEXTURE_2D ); diff --git a/engine/client/client.h b/engine/client/client.h index b8bb14a6..5e8e11d1 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -344,13 +344,9 @@ typedef struct qboolean scissor_test; qboolean adjust_size; // allow to adjust scale for fonts - int renderMode; // override kRenderMode from TriAPI - TRICULLSTYLE cullMode; // override CULL FACE from TriAPI - // holds text color rgba_t textColor; rgba_t spriteColor; - vec4_t triRGBA; // crosshair members const model_t *pCrosshair; @@ -1149,5 +1145,6 @@ int Key_ToUpper( int key ); void OSK_Draw( void ); extern rgba_t g_color_table[8]; +extern triangleapi_t gTriApi; #endif//CLIENT_H diff --git a/engine/client/console.c b/engine/client/console.c index bafbcfb6..600586ee 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -908,8 +908,8 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color ) // don't apply color to fixed fonts it's already colored if( con.curFont->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, con.curFont->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8 - ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] ); - else ref.dllFuncs.Color4ub( 255, 255, 255, color[3] ); + ref.dllFuncs.GL_SetColor4ub( color[0], color[1], color[2], color[3] ); + else ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, color[3] ); // calc rectangle s1 = (float)rc->left / width; @@ -922,7 +922,7 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color ) if( clgame.ds.adjust_size ) Con_TextAdjustSize( &x, &y, &width, &height ); ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, con.curFont->hFontTexture ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); // don't forget reset color + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); // don't forget reset color return con.curFont->charWidths[number]; } @@ -1083,7 +1083,7 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb s++; } - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); return drawLen; } @@ -2039,7 +2039,7 @@ void Con_DrawNotify( void ) Field_DrawInputLine( x + len, y, &con.chat ); } - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* @@ -2112,7 +2112,7 @@ void Con_DrawSolidConsole( int lines ) // draw the background ref.dllFuncs.GL_SetRenderMode( kRenderNormal ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade if( refState.width * 3 / 4 < refState.height && lines >= refState.height ) ref.dllFuncs.R_DrawStretchPic( 0, lines - refState.height, refState.width, refState.height - refState.width * 3 / 4, 0, 0, 1, 1, R_GetBuiltinTexture( REF_BLACK_TEXTURE) ); ref.dllFuncs.R_DrawStretchPic( 0, lines - refState.width * 3 / 4, refState.width, refState.width * 3 / 4, 0, 0, 1, 1, con.background ); @@ -2180,7 +2180,7 @@ void Con_DrawSolidConsole( int lines ) y = lines - ( con.curFont->charHeight * 1.2f ); SCR_DrawFPS( max( y, 4 )); // to avoid to hide fps counter - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } /* diff --git a/engine/client/in_touch.c b/engine/client/in_touch.c index cf754f87..31f0d779 100644 --- a/engine/client/in_touch.c +++ b/engine/client/in_touch.c @@ -1071,7 +1071,7 @@ void Touch_DrawTexture ( float x1, float y1, float x2, float y2, int texture, by if( y1 >= y2 ) return; - ref.dllFuncs.Color4ub( r, g, b, a ); + ref.dllFuncs.GL_SetColor4ub( r, g, b, a ); ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X(x1), TO_SCRN_Y(y1), TO_SCRN_X(x2 - x1), @@ -1154,7 +1154,7 @@ float Touch_DrawText( float x1, float y1, float x2, float y2, const char *s, byt ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd ); // text is additive and alpha does not work - ref.dllFuncs.Color4ub( color[0] * ( (float)color[3] /255.0f ), color[1] * ( (float)color[3] /255.0f ), + ref.dllFuncs.GL_SetColor4ub( color[0] * ( (float)color[3] /255.0f ), color[1] * ( (float)color[3] /255.0f ), color[2] * ( (float)color[3] /255.0f ), 255 ); while( *s ) @@ -1223,7 +1223,7 @@ void Touch_DrawButtons( touchbuttonlist_t *list ) } if( B(flags) & TOUCH_FL_STROKE ) { - ref.dllFuncs.Color4ub( touch.scolor[0], touch.scolor[1], touch.scolor[2], touch.scolor[3] * B( fade ) ); + ref.dllFuncs.GL_SetColor4ub( touch.scolor[0], touch.scolor[1], touch.scolor[2], touch.scolor[3] * B( fade ) ); ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X(B(x1)), TO_SCRN_Y(B(y1)), touch.swidth, @@ -1244,7 +1244,7 @@ void Touch_DrawButtons( touchbuttonlist_t *list ) TO_SCRN_X(B(x2)-B(x1)) - touch.swidth, touch.swidth, 0, 0, 1, 1, touch.whitetexture ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); } } if( touch.state >= state_edit && !( button->flags & TOUCH_FL_NOEDIT ) ) @@ -1282,7 +1282,7 @@ void Touch_Draw( void ) Touch_DrawTexture( 0, 0, 1, 1, touch.whitetexture, 32, 32, 32, 255 ); else Touch_DrawTexture( 0, 0, 1, 1, touch.whitetexture, 0, 0, 0, 112 ); - ref.dllFuncs.Color4ub( 0, 224, 224, 112 ); + ref.dllFuncs.GL_SetColor4ub( 0, 224, 224, 112 ); for ( x = 0; x < 1 ; x += GRID_X ) ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X(x), 0, @@ -1337,7 +1337,7 @@ void Touch_Draw( void ) } } - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); if( ( touch.move_finger != -1 ) && touch.move_button && touch_move_indicator->value ) { @@ -1358,11 +1358,11 @@ void Touch_Draw( void ) width = (touch.move_button->x2 - touch.move_button->x1)/2; height = (touch.move_button->y2 - touch.move_button->y1)/2; } - ref.dllFuncs.Color4ub( 255, 255, 255, 128 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 128 ); ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X( touch.move_start_x - GRID_X * touch_move_indicator->value ), TO_SCRN_Y( touch.move_start_y - GRID_Y * touch_move_indicator->value ), TO_SCRN_X( GRID_X * 2 * touch_move_indicator->value ), TO_SCRN_Y( GRID_Y * 2 * touch_move_indicator->value ), 0, 0, 1, 1, touch.joytexture ); - ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); + ref.dllFuncs.GL_SetColor4ub( 255, 255, 255, 255 ); ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X( touch.move_start_x + touch.side * width - GRID_X * touch_move_indicator->value ), TO_SCRN_Y( touch.move_start_y - touch.forward * height - GRID_Y * touch_move_indicator->value ), TO_SCRN_X( GRID_X * 2 * touch_move_indicator->value ), TO_SCRN_Y( GRID_Y * 2 * touch_move_indicator->value ), 0, 0, 1, 1, touch.joytexture ); diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index 8e4aaf81..1e86134c 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -418,33 +418,8 @@ static void R_UnloadProgs( void ) Cmd_Unlink( CMD_REFDLL ); } -static void CL_FillTriAPIFromRef( triangleapi_t *dst, const ref_interface_t *src ) -{ - dst->version = TRI_API_VERSION; - dst->Begin = src->Begin; - dst->RenderMode = TriRenderMode; - dst->End = src->End; - dst->Color4f = TriColor4f; - dst->Color4ub = TriColor4ub; - dst->TexCoord2f = src->TexCoord2f; - dst->Vertex3f = src->Vertex3f; - dst->Vertex3fv = src->Vertex3fv; - dst->Brightness = TriBrightness; - dst->CullFace = TriCullFace; - dst->SpriteTexture = TriSpriteTexture; - dst->WorldToScreen = TriWorldToScreen; - dst->Fog = src->Fog; - dst->ScreenToWorld = src->ScreenToWorld; - dst->GetMatrix = src->GetMatrix; - dst->BoxInPVS = TriBoxInPVS; - dst->LightAtPoint = TriLightAtPoint; - dst->Color4fRendermode = TriColor4fRendermode; - dst->FogParams = src->FogParams; -} - static qboolean R_LoadProgs( const char *name ) { - extern triangleapi_t gTriApi; static ref_api_t gpEngfuncs; REFAPI GetRefAPI; // single export @@ -489,12 +464,18 @@ static qboolean R_LoadProgs( const char *name ) return false; } + // initialize TriAPI callbacks + if( !ref.dllFuncs.getTriAPI( TRI_API_VERSION, &gTriApi )) + { + COM_FreeLibrary( ref.hInstance ); + Con_Reportf( "R_LoadProgs: can't init TriAPI Interface: wrong version, %i must be %i\n", gTriApi.version, TRI_API_VERSION ); + ref.hInstance = NULL; + return false; + } + Cvar_FullSet( "host_refloaded", "1", FCVAR_READ_ONLY ); ref.initialized = true; - // initialize TriAPI callbacks - CL_FillTriAPIFromRef( &gTriApi, &ref.dllFuncs ); - return true; } diff --git a/engine/ref_api.h b/engine/ref_api.h index 6abbf799..efc1843e 100644 --- a/engine/ref_api.h +++ b/engine/ref_api.h @@ -465,6 +465,7 @@ typedef struct ref_interface_s void (*R_ClearScreen)( void ); // clears color buffer on GL void (*R_AllowFog)( qboolean allow ); void (*GL_SetRenderMode)( int renderMode ); + void (*GL_SetColor4ub)( byte r, byte g, byte b, byte a ); qboolean (*R_AddEntity)( struct cl_entity_s *clent, int type ); void (*CL_AddCustomBeam)( cl_entity_t *pEnvBeam ); @@ -592,20 +593,7 @@ typedef struct ref_interface_s // TriAPI Interface // NOTE: implementation isn't required to be compatible - void (*TriRenderMode)( int mode ); - void (*Begin)( int primitiveCode ); - void (*End)( void ); - void (*Color4f)( float r, float g, float b, float a ); // real glColor4f - void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); // real glColor4ub - void (*TexCoord2f)( float u, float v ); - void (*Vertex3fv)( const float *worldPnt ); - void (*Vertex3f)( float x, float y, float z ); - int (*WorldToScreen)( const float *world, float *screen ); // Returns 1 if it's z clipped - void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. - void (*ScreenToWorld)( const float *screen, float *world ); - void (*GetMatrix)( const int pname, float *matrix ); - void (*FogParams)( float flDensity, int iFogSkybox ); - void (*CullFace)( TRICULLSTYLE mode ); + int (*getTriAPI)( int version, triangleapi_t *api ); // vgui drawing implementation void (*VGUI_DrawInit)( void ); diff --git a/ref_gl/gl_backend.c b/ref_gl/gl_backend.c index 297f7ca4..a3035590 100644 --- a/ref_gl/gl_backend.c +++ b/ref_gl/gl_backend.c @@ -420,6 +420,16 @@ void GL_SetRenderMode( int mode ) } } +/* +================= +GL_SetColor4ub +================= +*/ +void GL_SetColor4ub( byte r, byte g, byte b, byte a ) +{ + pglColor4ub( r, g, b, a ); +} + /* ============================================================================== diff --git a/ref_gl/gl_context.c b/ref_gl/gl_context.c index 19cec68e..251827ff 100644 --- a/ref_gl/gl_context.c +++ b/ref_gl/gl_context.c @@ -371,6 +371,7 @@ ref_interface_t gReffuncs = R_ClearScreen, R_AllowFog, GL_SetRenderMode, + GL_SetColor4ub, R_AddEntity, CL_AddCustomBeam, @@ -467,20 +468,7 @@ ref_interface_t gReffuncs = R_ClearScene, R_GetProcAddress, - TriRenderMode, - TriBegin, - TriEnd, - _TriColor4f, - _TriColor4ub, - TriTexCoord2f, - TriVertex3fv, - TriVertex3f, - TriWorldToScreen, - TriFog, - R_ScreenToWorld, - TriGetMatrix, - TriFogParams, - TriCullFace, + getTriAPI, VGUI_DrawInit, VGUI_DrawShutdown, diff --git a/ref_gl/gl_local.h b/ref_gl/gl_local.h index 7f80268a..17efaff7 100644 --- a/ref_gl/gl_local.h +++ b/ref_gl/gl_local.h @@ -291,6 +291,7 @@ void GL_CleanupAllTextureUnits( void ); void GL_LoadIdentityTexMatrix( void ); void GL_DisableAllTexGens( void ); void GL_SetRenderMode( int mode ); +void GL_SetColor4ub( byte r, byte g, byte b, byte a ); void GL_TextureTarget( uint target ); void GL_Cull( GLenum cull ); void R_ShowTextures( void ); @@ -574,8 +575,6 @@ void TriEnd( void ); void TriTexCoord2f( float u, float v ); void TriVertex3fv( const float *v ); void TriVertex3f( float x, float y, float z ); -void _TriColor4f( float r, float g, float b, float a ); -void _TriColor4ub( byte r, byte g, byte b, byte a ); void TriColor4f( float r, float g, float b, float a ); void TriColor4ub( byte r, byte g, byte b, byte a ); void TriBrightness( float brightness ); @@ -585,6 +584,10 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ); void TriGetMatrix( const int pname, float *matrix ); void TriFogParams( float flDensity, int iFogSkybox ); void TriCullFace( TRICULLSTYLE mode ); +int TriBoxInPVS( float *mins, float *maxs ); +void TriLightAtPoint( float *pos, float *value ); +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ); +int getTriAPI( int version, triangleapi_t *api ); /* ======================================================================= diff --git a/ref_gl/gl_triapi.c b/ref_gl/gl_triapi.c index 4d4bffce..2e19c38b 100644 --- a/ref_gl/gl_triapi.c +++ b/ref_gl/gl_triapi.c @@ -120,29 +120,6 @@ void TriEnd( void ) pglEnd( ); } -/* -============= -_TriColor4f - -============= -*/ -void _TriColor4f( float r, float g, float b, float a ) -{ - pglColor4f( r, g, b, a ); -} - -/* -============= -_TriColor4f - -============= -*/ -void _TriColor4ub( byte r, byte g, byte b, byte a ) -{ - pglColor4ub( r, g, b, a ); -} - - /* ============= TriColor4ub @@ -156,7 +133,7 @@ void TriColor4ub( byte r, byte g, byte b, byte a ) ds.triRGBA[2] = b * (1.0f / 255.0f); ds.triRGBA[3] = a * (1.0f / 255.0f); - _TriColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f ); + pglColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f ); } /* @@ -167,8 +144,8 @@ TriColor4f void TriColor4f( float r, float g, float b, float a ) { if( ds.renderMode == kRenderTransAlpha ) - TriColor4ub( r * 255.9f, g * 255.9f, b * 255.9f, a * 255.0f ); - else _TriColor4f( r * a, g * a, b * a, 1.0 ); + pglColor4ub( r * 255.9f, g * 255.9f, b * 255.9f, a * 255.0f ); + else pglColor4f( r * a, g * a, b * a, 1.0 ); ds.triRGBA[0] = r; ds.triRGBA[1] = g; @@ -338,7 +315,7 @@ void TriCullFace( TRICULLSTYLE mode ) break; } - GL_Cull( mode ); + GL_Cull( glMode ); } /* @@ -354,6 +331,88 @@ void TriBrightness( float brightness ) g = ds.triRGBA[1] * ds.triRGBA[3] * brightness; b = ds.triRGBA[2] * ds.triRGBA[3] * brightness; - _TriColor4f( r, g, b, 1.0f ); + pglColor4f( r, g, b, 1.0f ); } +/* +============= +TriBoxInPVS + +check box in pvs (absmin, absmax) +============= +*/ +int TriBoxInPVS( float *mins, float *maxs ) +{ + return gEngfuncs.Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( )); +} + +/* +============= +TriLightAtPoint +NOTE: dlights are ignored +============= +*/ +void TriLightAtPoint( float *pos, float *value ) +{ + colorVec vLightColor; + + if( !pos || !value ) return; + + vLightColor = R_LightPoint( pos ); + + value[0] = vLightColor.r; + value[1] = vLightColor.g; + value[2] = vLightColor.b; +} + +/* +============= +TriColor4fRendermode +Heavy legacy of Quake... +============= +*/ +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ) +{ + if( ds.renderMode == kRenderTransAlpha ) + { + ds.triRGBA[3] = a / 255.0f; + pglColor4f( r, g, b, a ); + } + else pglColor4f( r * a, g * a, b * a, 1.0f ); +} + +/* +============= +getTriAPI +export +============= +*/ +int getTriAPI( int version, triangleapi_t *api ) +{ + api->version = TRI_API_VERSION; + + if( version != TRI_API_VERSION ) + return 0; + + api->RenderMode = TriRenderMode; + api->Begin = TriBegin; + api->End = TriEnd; + api->Color4f = TriColor4f; + api->Color4ub = TriColor4ub; + api->TexCoord2f = TriTexCoord2f; + api->Vertex3fv = TriVertex3fv; + api->Vertex3f = TriVertex3f; + api->Brightness = TriBrightness; + api->CullFace = TriCullFace; + api->SpriteTexture = TriSpriteTexture; + api->WorldToScreen = R_WorldToScreen; + api->Fog = TriFog; + api->ScreenToWorld = R_ScreenToWorld; + api->GetMatrix = TriGetMatrix; + api->BoxInPVS = TriBoxInPVS; + api->LightAtPoint = TriLightAtPoint; + api->Color4fRendermode = TriColor4fRendermode; + api->FogParams = TriFogParams; + + return 1; +} diff --git a/ref_gu/gu_backend.c b/ref_gu/gu_backend.c index 88c0ed2f..e6ca717e 100644 --- a/ref_gu/gu_backend.c +++ b/ref_gu/gu_backend.c @@ -309,6 +309,16 @@ void GL_SetRenderMode( int mode ) } } +/* +================= +GL_SetColor4ub +================= +*/ +void GL_SetColor4ub( byte r, byte g, byte b, byte a ) +{ + sceGuColor( GU_RGBA( r, g, b, a )); +} + /* ============================================================================== diff --git a/ref_gu/gu_context.c b/ref_gu/gu_context.c index 0e0e8e2d..3118ceae 100644 --- a/ref_gu/gu_context.c +++ b/ref_gu/gu_context.c @@ -370,6 +370,7 @@ ref_interface_t gReffuncs = R_ClearScreen, R_AllowFog, GL_SetRenderMode, + GL_SetColor4ub, R_AddEntity, CL_AddCustomBeam, @@ -466,20 +467,7 @@ ref_interface_t gReffuncs = R_ClearScene, R_GetProcAddress, - TriRenderMode, - TriBegin, - TriEnd, - _TriColor4f, - _TriColor4ub, - TriTexCoord2f, - TriVertex3fv, - TriVertex3f, - TriWorldToScreen, - TriFog, - R_ScreenToWorld, - TriGetMatrix, - TriFogParams, - TriCullFace, + getTriAPI, VGUI_DrawInit, VGUI_DrawShutdown, diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index cdba1474..c637c5ef 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -643,6 +643,7 @@ void Mod_SpriteUnloadTextures( void *data ); void Mod_UnloadAliasModel( struct model_s *mod ); void Mod_AliasUnloadTextures( void *data ); void GL_SetRenderMode( int mode ); +void GL_SetColor4ub( byte r, byte g, byte b, byte a ); void R_RunViewmodelEvents( void ); void R_DrawViewModel( void ); int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame ); @@ -670,8 +671,6 @@ void TriEnd( void ); void TriTexCoord2f( float u, float v ); void TriVertex3fv( const float *v ); void TriVertex3f( float x, float y, float z ); -void _TriColor4f( float r, float g, float b, float a ); -void _TriColor4ub( byte r, byte g, byte b, byte a ); void TriColor4f( float r, float g, float b, float a ); void TriColor4ub( byte r, byte g, byte b, byte a ); void TriBrightness( float brightness ); @@ -681,10 +680,11 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ); void TriGetMatrix( const int pname, float *matrix ); void TriFogParams( float flDensity, int iFogSkybox ); void TriCullFace( TRICULLSTYLE mode ); -#if 1 -/* Needs for psp */ -unsigned int getTriBrightness( float brightness ); -#endif +uint getTriBrightness( float brightness ); +int TriBoxInPVS( float *mins, float *maxs ); +void TriLightAtPoint( float *pos, float *value ); +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ); +int getTriAPI( int version, triangleapi_t *api ); // // gu_clipping.c diff --git a/ref_gu/gu_triapi.c b/ref_gu/gu_triapi.c index 9cf25f76..64efe935 100644 --- a/ref_gu/gu_triapi.c +++ b/ref_gu/gu_triapi.c @@ -28,8 +28,8 @@ static struct { byte *start; byte *end; - int count; - int prim; + int count; + int prim; uint flags; float lastTexCord[2]; uint lastColor; @@ -150,7 +150,7 @@ _TriColor4f ============= */ -void _TriColor4f( float r, float g, float b, float a ) +static void _TriColor4f( float r, float g, float b, float a ) { if( triContext.start ) { @@ -169,7 +169,7 @@ _TriColor4ub ============= */ -void _TriColor4ub( byte r, byte g, byte b, byte a ) +static void _TriColor4ub( byte r, byte g, byte b, byte a ) { if( triContext.start ) { @@ -196,7 +196,7 @@ void TriColor4ub( byte r, byte g, byte b, byte a ) ds.triRGBA[2] = b * (1.0f / 255.0f); ds.triRGBA[3] = a * (1.0f / 255.0f); - _TriColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f ); + _TriColor4ub( r, g, b, 255 ); } /* @@ -207,7 +207,7 @@ TriColor4f void TriColor4f( float r, float g, float b, float a ) { if( ds.renderMode == kRenderTransAlpha ) - TriColor4ub( r * 255.0f, g * 255.0f, b * 255.0f, a * 255.0f ); + _TriColor4ub( r * 255.9f, g * 255.9f, b * 255.9f, a * 255.0f ); else _TriColor4f( r * a, g * a, b * a, 1.0 ); ds.triRGBA[0] = r; @@ -460,7 +460,7 @@ void TriCullFace( TRICULLSTYLE mode ) break; } - GL_Cull( mode ); + GL_Cull( glMode ); } /* @@ -483,13 +483,96 @@ unsigned int getTriBrightness( float brightness ) { vec3_t color; - if(brightness < 0.0f) return 0; + if( brightness < 0.0f ) return 0; color[0] = ds.triRGBA[0] * ds.triRGBA[3] * brightness; color[1] = ds.triRGBA[1] * ds.triRGBA[3] * brightness; color[2] = ds.triRGBA[2] * ds.triRGBA[3] * brightness; - VectorNormalizeFast( color ); + //VectorNormalizeFast( color ); return GUCOLOR3FV( color ); } + +/* +============= +TriBoxInPVS + +check box in pvs (absmin, absmax) +============= +*/ +int TriBoxInPVS( float *mins, float *maxs ) +{ + return gEngfuncs.Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( )); +} + +/* +============= +TriLightAtPoint +NOTE: dlights are ignored +============= +*/ +void TriLightAtPoint( float *pos, float *value ) +{ + colorVec vLightColor; + + if( !pos || !value ) return; + + vLightColor = R_LightPoint( pos ); + + value[0] = vLightColor.r; + value[1] = vLightColor.g; + value[2] = vLightColor.b; +} + +/* +============= +TriColor4fRendermode +Heavy legacy of Quake... +============= +*/ +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ) +{ + if( ds.renderMode == kRenderTransAlpha ) + { + ds.triRGBA[3] = a / 255.0f; + _TriColor4f( r, g, b, a ); + } + else _TriColor4f( r * a, g * a, b * a, 1.0f ); +} + +/* +============= +getTriAPI +export +============= +*/ +int getTriAPI( int version, triangleapi_t *api ) +{ + api->version = TRI_API_VERSION; + + if( version != TRI_API_VERSION ) + return 0; + + api->RenderMode = TriRenderMode; + api->Begin = TriBegin; + api->End = TriEnd; + api->Color4f = TriColor4f; + api->Color4ub = TriColor4ub; + api->TexCoord2f = TriTexCoord2f; + api->Vertex3fv = TriVertex3fv; + api->Vertex3f = TriVertex3f; + api->Brightness = TriBrightness; + api->CullFace = TriCullFace; + api->SpriteTexture = TriSpriteTexture; + api->WorldToScreen = R_WorldToScreen; + api->Fog = TriFog; + api->ScreenToWorld = R_ScreenToWorld; + api->GetMatrix = TriGetMatrix; + api->BoxInPVS = TriBoxInPVS; + api->LightAtPoint = TriLightAtPoint; + api->Color4fRendermode = TriColor4fRendermode; + api->FogParams = TriFogParams; + + return 1; +} diff --git a/ref_soft/r_context.c b/ref_soft/r_context.c index e0b1e6a9..2209dd2a 100644 --- a/ref_soft/r_context.c +++ b/ref_soft/r_context.c @@ -329,6 +329,11 @@ void GAME_EXPORT GL_SetRenderMode(int mode) /// maybe, setup block drawing function pointers here } +void GAME_EXPORT GL_SetColor4ub( byte r, byte g, byte b, byte a ) +{ + _TriColor4ub(r,g,b,a); +} + void GAME_EXPORT R_ShowTextures( void ) { // textures undone too @@ -452,6 +457,7 @@ ref_interface_t gReffuncs = R_ClearScreen, R_AllowFog, GL_SetRenderMode, + GL_SetColor4ub, R_AddEntity, CL_AddCustomBeam, @@ -548,20 +554,7 @@ ref_interface_t gReffuncs = R_ClearScene, R_GetProcAddress, - TriRenderMode, - TriBegin, - TriEnd, - _TriColor4f, - _TriColor4ub, - TriTexCoord2f, - TriVertex3fv, - TriVertex3f, - TriWorldToScreen, - TriFog, - R_ScreenToWorld, - TriGetMatrix, - TriFogParams, - TriCullFace, + getTriAPI, VGUI_DrawInit, VGUI_DrawShutdown, diff --git a/ref_soft/r_local.h b/ref_soft/r_local.h index 99cb2635..487dc49b 100644 --- a/ref_soft/r_local.h +++ b/ref_soft/r_local.h @@ -387,6 +387,7 @@ void GL_CleanupAllTextureUnits( void ); void GL_LoadIdentityTexMatrix( void ); void GL_DisableAllTexGens( void ); void GL_SetRenderMode( int mode ); +void GL_SetColor4ub( byte r, byte g, byte b, byte a ); void GL_TextureTarget( uint target ); void GL_Cull( unsigned int cull ); void R_ShowTextures( void ); @@ -640,6 +641,7 @@ void Mod_SpriteUnloadTextures( void *data ); void Mod_UnloadAliasModel( struct model_s *mod ); void Mod_AliasUnloadTextures( void *data ); void GL_SetRenderMode( int mode ); +void GL_SetColor4ub( byte r, byte g, byte b, byte a ); void R_RunViewmodelEvents( void ); void R_DrawViewModel( void ); int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame ); @@ -674,6 +676,7 @@ void TriEnd( void ); void TriTexCoord2f( float u, float v ); void TriVertex3fv( const float *v ); void TriVertex3f( float x, float y, float z ); +void TriColor4f( float r, float g, float b, float a ); void _TriColor4f( float r, float g, float b, float a ); void TriColor4ub( byte r, byte g, byte b, byte a ); void _TriColor4ub( byte r, byte g, byte b, byte a ); @@ -684,6 +687,10 @@ void TriGetMatrix( const int pname, float *matrix ); void TriFogParams( float flDensity, int iFogSkybox ); void TriCullFace( TRICULLSTYLE mode ); void TriBrightness( float brightness ); +int TriBoxInPVS( float *mins, float *maxs ); +void TriLightAtPoint( float *pos, float *value ); +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ); +int getTriAPI( int version, triangleapi_t *api ); #define ENGINE_GET_PARM_ (*gEngfuncs.EngineGetParm) #define ENGINE_GET_PARM( parm ) ENGINE_GET_PARM_( (parm), 0 ) diff --git a/ref_soft/r_triapi.c b/ref_soft/r_triapi.c index c98f717c..93b4ddf0 100644 --- a/ref_soft/r_triapi.c +++ b/ref_soft/r_triapi.c @@ -503,3 +503,85 @@ void TriBrightness( float brightness ) _TriColor4f( r, g, b, 1.0f ); } +/* +============= +TriBoxInPVS + +check box in pvs (absmin, absmax) +============= +*/ +int TriBoxInPVS( float *mins, float *maxs ) +{ + return gEngfuncs.Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( )); +} + +/* +============= +TriLightAtPoint +NOTE: dlights are ignored +============= +*/ +void TriLightAtPoint( float *pos, float *value ) +{ + colorVec vLightColor; + + if( !pos || !value ) return; + + vLightColor = R_LightPoint( pos ); + + value[0] = vLightColor.r; + value[1] = vLightColor.g; + value[2] = vLightColor.b; +} + +/* +============= +TriColor4fRendermode +Heavy legacy of Quake... +============= +*/ +void TriColor4fRendermode( float r, float g, float b, float a, int rendermode ) +{ + if( ds.renderMode == kRenderTransAlpha ) + { + ds.triRGBA[3] = a / 255.0f; + _TriColor4f( r, g, b, a ); + } + else _TriColor4f( r * a, g * a, b * a, 1.0f ); +} + +/* +============= +getTriAPI +export +============= +*/ +int getTriAPI( int version, triangleapi_t *api ) +{ + api->version = TRI_API_VERSION; + + if( version != TRI_API_VERSION ) + return 0; + + api->RenderMode = TriRenderMode; + api->Begin = TriBegin; + api->End = TriEnd; + api->Color4f = TriColor4f; + api->Color4ub = TriColor4ub; + api->TexCoord2f = TriTexCoord2f; + api->Vertex3fv = TriVertex3fv; + api->Vertex3f = TriVertex3f; + api->Brightness = TriBrightness; + api->CullFace = TriCullFace; + api->SpriteTexture = TriSpriteTexture; + api->WorldToScreen = R_WorldToScreen; + api->Fog = TriFog; + api->ScreenToWorld = R_ScreenToWorld; + api->GetMatrix = TriGetMatrix; + api->BoxInPVS = TriBoxInPVS; + api->LightAtPoint = TriLightAtPoint; + api->Color4fRendermode = TriColor4fRendermode; + api->FogParams = TriFogParams; + + return 1; +} From 122a11005b8ffc32cbcf241e65924fb6b0474778 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 10 Oct 2022 16:49:01 +0300 Subject: [PATCH 61/84] imagelib: hardware palette support for tga --- engine/common/imagelib/img_tga.c | 64 ++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/engine/common/imagelib/img_tga.c b/engine/common/imagelib/img_tga.c index 6b8a06a5..be8f77be 100644 --- a/engine/common/imagelib/img_tga.c +++ b/engine/common/imagelib/img_tga.c @@ -24,7 +24,7 @@ Image_LoadTGA */ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesize ) { - int i, columns, rows, row_inc, row, col; + int i, columns, rows, row_inc, row, col, bpp = 1; byte *buf_p, *pixbuf, *targa_rgba; rgba_t palette[256]; byte red = 0, green = 0, blue = 0, alpha = 0; @@ -32,6 +32,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi int reflectivity[3] = { 0, 0, 0 }; qboolean compressed; tga_t targa_header; + int palIndex = 0; if( filesize < sizeof( tga_t )) return false; @@ -55,8 +56,6 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi // check for tga file if( !Image_ValidSize( name )) return false; - image.type = PF_RGBA_32; // always exctracted to 32-bit buffer - if( targa_header.image_type == 1 || targa_header.image_type == 9 ) { // uncompressed colormapped image @@ -119,11 +118,35 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi return false; } } + else + { + Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Type %i not supported\n", name, targa_header.image_type ); + return false; + } columns = targa_header.width; rows = targa_header.height; - image.size = image.width * image.height * 4; + if( Image_CheckFlag( IL_KEEP_8BIT ) && ( targa_header.image_type == 1 || targa_header.image_type == 9 )) + { + pixbuf = image.palette = Mem_Malloc( host.imagepool, 1024 ); + for( i = 0; i < targa_header.colormap_length; i++ ) + { + *pixbuf++ = palette[i][0]; + *pixbuf++ = palette[i][1]; + *pixbuf++ = palette[i][2]; + *pixbuf++ = palette[i][3]; + } + image.type = PF_INDEXED_32; + } + else + { + image.palette = NULL; + image.type = PF_RGBA_32; + bpp = 4; + } + + image.size = image.width * image.height * bpp; targa_rgba = image.rgba = Mem_Malloc( host.imagepool, image.size ); // if bit 5 of attributes isn't set, the image has been stored from bottom to top @@ -134,8 +157,8 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi } else { - pixbuf = targa_rgba + ( rows - 1 ) * columns * 4; - row_inc = -columns * 4 * 2; + pixbuf = targa_rgba + ( rows - 1 ) * columns * bpp; + row_inc = -columns * bpp * 2; } compressed = ( targa_header.image_type == 9 || targa_header.image_type == 10 || targa_header.image_type == 11 ); @@ -161,13 +184,13 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi case 1: case 9: // colormapped image - blue = *buf_p++; - if( blue < targa_header.colormap_length ) + palIndex = *buf_p++; + if( palIndex < targa_header.colormap_length ) { - red = palette[blue][0]; - green = palette[blue][1]; - alpha = palette[blue][3]; - blue = palette[blue][2]; + red = palette[palIndex][0]; + green = palette[palIndex][1]; + blue = palette[palIndex][2]; + alpha = palette[palIndex][3]; if( alpha != 255 ) image.flags |= IMAGE_HAS_ALPHA; } break; @@ -208,10 +231,18 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi reflectivity[1] += green; reflectivity[2] += blue; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alpha; + if( image.type == PF_INDEXED_32 || image.type == PF_INDEXED_24 ) + { + *pixbuf++ = palIndex; + } + else + { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + } + if( ++col == columns ) { // run spans across rows @@ -223,6 +254,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi } VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams ); + if( image.palette ) Image_GetPaletteBMP( image.palette ); image.depth = 1; return true; From a375adb9eab99fe074c79062057d60570f2d5d6c Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 10 Oct 2022 16:54:11 +0300 Subject: [PATCH 62/84] ref_gu: skybox_ext reordering --- ref_gu/gu_warp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref_gu/gu_warp.c b/ref_gu/gu_warp.c index bc048a86..abbf86fa 100644 --- a/ref_gu/gu_warp.c +++ b/ref_gu/gu_warp.c @@ -67,7 +67,7 @@ float r_turbsin[] = static int CheckSkybox( const char *name ) { - const char *skybox_ext[3] = { "dds", "tga", "bmp" }; + const char *skybox_ext[3] = { "bmp", "tga", "dds" }; int i, j, num_checked_sides; const char *sidename; From bdc20096830201d0f7360de4a02a5aadedaead85 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 12 Oct 2022 11:04:35 +0300 Subject: [PATCH 63/84] server: minor fix for inline functions --- engine/server/server.h | 15 +++++++-------- engine/server/sv_phys.c | 9 ++------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/engine/server/server.h b/engine/server/server.h index 20ff633f..5d8b2632 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -61,7 +61,7 @@ extern int SV_UPDATE_BACKUP; #endif #define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - svgame.edicts)) #if XASH_EXT_OPT == 2 -#define EDICT_NUM( num ) ( ( ( ( num ) >= 0 ) && ( ( num ) < GI->max_edicts) ) ? svgame.edicts + ( num ) : NULL ) +#define EDICT_NUM( num ) (((( num ) >= 0 ) && (( num ) < GI->max_edicts )) ? svgame.edicts + ( num ) : NULL ) #else #define EDICT_NUM( num ) SV_EdictNum( num ) #endif @@ -481,7 +481,7 @@ void Master_Packet( void ); void SV_ActivateServer( int runPhysics ); qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background ); #if XASH_EXT_OPT == 2 -#define SV_ModelHandle( modelindex ) ( ( modelindex < 0 || modelindex >= MAX_MODELS ) ? NULL : sv.models[( modelindex )] ) +#define SV_ModelHandle( modelindex ) (( modelindex < 0 || modelindex >= MAX_MODELS ) ? NULL : sv.models[( modelindex )]) model_t *pfnSV_ModelHandle( int modelindex ); #else model_t *SV_ModelHandle( int modelindex ); @@ -501,12 +501,11 @@ qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker ); void SV_Impact( edict_t *e1, edict_t *e2, trace_t *trace ); #if XASH_EXT_OPT == 2 // filter movetypes to collide with -#define SV_CanPushed( ent ) ( ( ent )->v.movetype == MOVETYPE_NONE || \ - ( ent )->v.movetype == MOVETYPE_PUSH || \ - ( ent )->v.movetype == MOVETYPE_FOLLOW || \ - ( ent )->v.movetype == MOVETYPE_NOCLIP || \ - ( ent )->v.movetype == MOVETYPE_COMPOUND ) ? false : true -qboolean pfnSV_CanPushed( edict_t *ent ); +#define SV_CanPushed( ent ) (( ent )->v.movetype == MOVETYPE_NONE || \ + ( ent )->v.movetype == MOVETYPE_PUSH || \ + ( ent )->v.movetype == MOVETYPE_FOLLOW || \ + ( ent )->v.movetype == MOVETYPE_NOCLIP || \ + ( ent )->v.movetype == MOVETYPE_COMPOUND ) ? false : true #else qboolean SV_CanPushed( edict_t *ent ); #endif diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index a57ef84e..9d489a96 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -842,12 +842,7 @@ SV_CanPushed filter entities for push ============ */ -#if XASH_EXT_OPT > 1 -qboolean pfnSV_CanPushed( edict_t *ent ) -{ - return SV_CanPushed( ent ); -} -#else +#if XASH_EXT_OPT != 2 qboolean SV_CanPushed( edict_t *ent ) { // filter movetypes to collide with @@ -872,7 +867,7 @@ allow entity to block pusher? ============ */ #if XASH_PSP -static inline qboolean SV_CanBlock( edict_t *ent ) +_inline qboolean SV_CanBlock( edict_t *ent ) #else static qboolean SV_CanBlock( edict_t *ent ) #endif From 53d44f4c0ed52657a499c331353e90b0b29d44fd Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 13 Oct 2022 14:40:02 +0300 Subject: [PATCH 64/84] paltform: psp filesystem helper --- engine/common/filesystem.c | 38 ++++++- engine/platform/platform.h | 1 + engine/platform/psp/fsh_psp.c | 205 ++++++++++++++++++++++++++++++++++ engine/platform/psp/fsh_psp.h | 34 ++++++ 4 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 engine/platform/psp/fsh_psp.c create mode 100644 engine/platform/psp/fsh_psp.h diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index e93f2bb6..f9520270 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -195,6 +195,10 @@ static zip_t *fs_last_zip; #endif // XASH_NO_ZIP static pack_t *fs_last_pak; +#if XASH_PSP +static fsh_handle_t *fsh_gamedir = NULL; +#endif + static void FS_EnsureOpenFile( file_t *file ) { if( fs_last_readfile == file ) @@ -2337,6 +2341,11 @@ void FS_Init( void ) } stringlistfreecontents( &dirs ); +#if XASH_PSP + fsh_gamedir = FSH_Init( fs_gamedir, 5000 ); + if( !fsh_gamedir ) + Con_Reportf( "FS_Init: FS Helper error\n" ); +#endif Con_Reportf( "FS_Init: done\n" ); } @@ -2362,6 +2371,10 @@ void FS_Shutdown( void ) FS_ClearSearchPath(); // release all wad files too Mem_FreePool( &fs_mempool ); +#if XASH_PSP + FSH_Shutdown( fsh_gamedir ); + fsh_gamedir = NULL; +#endif } /* @@ -2492,7 +2505,7 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) #endif #if XASH_PSP file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t ) + FILE_BUFF_SIZE + 64 ); - file->buff = (byte *)( ( ( ( u32 )file + sizeof( file_t ) ) & ( ~( 64 - 1 ) ) ) + 64 ); + file->buff = (byte *)(((( u32 )file + sizeof( file_t )) & ( ~( 64 - 1 ))) + 64 ); #else file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file )); #endif @@ -2501,7 +2514,7 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) #endif file->ungetc = EOF; #if XASH_PSP - file->handle = sceIoOpen( filepath, mod|opt, 0666 ); + file->handle = sceIoOpen( filepath, mod|opt, 0666 ); #else file->handle = open( filepath, mod|opt, 0666 ); #endif @@ -2509,7 +2522,11 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) #if XASH_PSP file->backup_hold = backup_hold; if( file->handle >= 0 ) + { FS_BackupFileName( file, filepath, mod|opt ); + if( mod == PSP_O_WRONLY || mod == PSP_O_RDWR ) + FSH_AddFilePath( fsh_gamedir, filepath ); + } #elif !XASH_WIN32 if( file->handle < 0 ) { @@ -2668,8 +2685,17 @@ qboolean FS_SysFileExists( const char *path, qboolean caseinsensitive ) close( desc ); return true; #elif XASH_PSP - SceIoStat buf; - if ( sceIoGetstat( path, &buf ) < 0 ) + int result; + SceIoStat buf; + + result = FSH_Find( fsh_gamedir, path ); + if( result >= 0 ) + return true; + if( result == -1 ) + return false; + + result = sceIoGetstat( path, &buf ); + if ( result < 0 ) return false; return FIO_S_ISREG( buf.st_mode ); #else @@ -3813,6 +3839,10 @@ qboolean GAME_EXPORT FS_Delete( const char *path ) COM_FixSlashes( real_path ); iRet = remove( real_path ); +#if XASH_PSP + FSH_RemoveFilePath( fsh_gamedir, real_path ); +#endif + return (iRet == 0); } diff --git a/engine/platform/platform.h b/engine/platform/platform.h index 4939e155..86250a70 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -44,6 +44,7 @@ SceUID Platform_LoadModule( const char *filename, int mpid, SceSize argsize, voi int Platform_UnloadModule( SceUID modid, int *sce_code ); #include "psp/p5ram_psp.h" +#include "psp/fsh_psp.h" #endif #if XASH_ANDROID const char *Android_GetAndroidID( void ); diff --git a/engine/platform/psp/fsh_psp.c b/engine/platform/psp/fsh_psp.c new file mode 100644 index 00000000..93924f86 --- /dev/null +++ b/engine/platform/psp/fsh_psp.c @@ -0,0 +1,205 @@ +/* +fsh_psp.c - PSP filesystem helper +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#include +#include "common.h" +#include "fsh_psp.h" + +#define FSH_MAX_PATH 63 + +#define FSH_STATE_USED 0x01 + +typedef struct fsh_path_s +{ + byte state; + char path[FSH_MAX_PATH]; +}fsh_path_t; + +typedef struct fsh_handle_s +{ + qboolean ready; + int count; + char folderpath[FSH_MAX_PATH]; + int folderpath_size; + int pathlist_size; + fsh_path_t *pathlist; +}fsh_handle_t; + +int FSH_AddFilePath( fsh_handle_t *handle, char *path ) +{ + int index; + + if( !handle ) + return -2; + + if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) + return -2; + + if( handle->ready && handle->count > 0 ) + { + // see if already added + for( index = 0; index < handle->count; index++ ) + { + if( !Q_stricmp( handle->pathlist[index].path, path )) + return index; + } + + // find empty + for( index = 0; index < handle->count; index++ ) + { + if(!( handle->pathlist[index].state & FSH_STATE_USED )) + { + Q_strncpy( handle->pathlist[index].path, path, FSH_MAX_PATH - 1 ); + handle->pathlist[index].state |= FSH_STATE_USED; + + return index; + } + } + } + + // create new + if( handle->count + 1 >= handle->pathlist_size ) + return -1; + + Q_strncpy( handle->pathlist[handle->count].path, path, FSH_MAX_PATH - 1 ); + handle->pathlist[handle->count].state |= FSH_STATE_USED; + handle->count++; + + return handle->count; +} + +int FSH_RemoveFilePath( fsh_handle_t *handle, char *path ) +{ + int index; + + if( !handle ) + return -2; + + if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) + return -2; + + for( index = 0; index < handle->count; index++ ) + { + if( !Q_stricmp( handle->pathlist[index].path, path )) + { + memset( handle->pathlist[index].path, 0, FSH_MAX_PATH) ; + handle->pathlist[index].state &= ~FSH_STATE_USED; + + return index; + } + } + + return -1; +} + +int FSH_Find( fsh_handle_t *handle, char *path ) +{ + int index; + + if( !handle ) + return -2; + + if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) + return -2; + + for( index = 0; index < handle->count; index++ ) + { + if( !Q_stricmp(handle->pathlist[index].path, path )) + return index; + } + + return -1; +} + +static int FSH_ScanDir( fsh_handle_t *handle, char *path ) +{ + SceUID dir; + SceIoDirent entry; + char temp[FSH_MAX_PATH]; + int result; + + if(( dir = sceIoDopen( path )) < 0 ) + return -1; + + result = 0; + + // iterate through the directory + while( 1 ) + { + // zero the dirent, to avoid possible problems with sceIoDread + memset( &entry, 0, sizeof( SceIoDirent )); + if( !sceIoDread( dir, &entry )) + break; + + // ignore the virtual directories + if( !Q_stricmp( entry.d_name, "." ) || !Q_stricmp( entry.d_name, ".." )) + continue; + + sprintf( temp, "%s/%s", path, entry.d_name ); + + if(FIO_S_ISDIR( entry.d_stat.st_mode )) + result = FSH_ScanDir( handle, temp ); + else if(FIO_S_ISREG( entry.d_stat.st_mode )) + result = FSH_AddFilePath( handle, temp ); + else continue; + if( result < 0 ) break; + } + sceIoDclose( dir ); + + return result; +} + +fsh_handle_t *FSH_Init( char *path, int maxfiles ) +{ + fsh_handle_t *handle; + + handle = P5Ram_Alloc( sizeof( fsh_handle_t ), 1); + if( !handle ) + return NULL; + + handle->pathlist_size = maxfiles; + handle->pathlist = P5Ram_Alloc( handle->pathlist_size * sizeof( fsh_path_t ), 1 ); + if( !handle->pathlist ) + { + FSH_Shutdown( handle ); + return NULL; + } + + if( !Q_strnicmp( path, "./", 2 )) + path += 2; + + Q_strncpy( handle->folderpath, path, FSH_MAX_PATH - 1 ); + handle->folderpath_size = Q_strlen( handle->folderpath ); + + if( FSH_ScanDir( handle, handle->folderpath ) < 0 ) + { + FSH_Shutdown( handle ); + return NULL; + } + + handle->ready = true; + + return handle; +} + +void FSH_Shutdown( fsh_handle_t *handle ) +{ + if( !handle ) + return; + + if( handle->pathlist ) + P5Ram_Free( handle->pathlist ); + + P5Ram_Free( handle ); +} diff --git a/engine/platform/psp/fsh_psp.h b/engine/platform/psp/fsh_psp.h new file mode 100644 index 00000000..5a78dfae --- /dev/null +++ b/engine/platform/psp/fsh_psp.h @@ -0,0 +1,34 @@ +/* +fsh_psp.h - PSP filesystem helper header +Copyright (C) 2022 Sergey Galushko + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#ifndef FSH_PSP_H +#define FSH_PSP_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +typedef struct fsh_handle_s fsh_handle_t; + +int FSH_AddFilePath( fsh_handle_t *handle, char *path ); +int FSH_RemoveFilePath( fsh_handle_t *handle, char *path ); +int FSH_Find( fsh_handle_t *handle, char *path ); +fsh_handle_t *FSH_Init( char *path, int maxfiles ); +void FSH_Shutdown( fsh_handle_t *handle ); + +#ifdef __cplusplus +} +#endif + +#endif // P5RAM_PSP_H From 3889ed8c52bbf2a85d505138a25100426026da64 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 14 Oct 2022 15:37:24 +0300 Subject: [PATCH 65/84] engine: using sceIoRemove() instead of remove() for psp --- engine/common/filesystem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index e93f2bb6..7ff227ed 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -3811,7 +3811,11 @@ qboolean GAME_EXPORT FS_Delete( const char *path ) Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_writedir, path ); COM_FixSlashes( real_path ); +#if XASH_PSP + iRet = sceIoRemove( real_path ); +#else iRet = remove( real_path ); +#endif return (iRet == 0); } From a440d1ff7ab103877ccafe65f9edb992297613bb Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 18 Oct 2022 09:19:57 +0300 Subject: [PATCH 66/84] paltform: psp filesystem helper update --- engine/common/filesystem.c | 144 ++++++++++++------ engine/platform/psp/fsh_psp.c | 266 +++++++++++++++++++++++++++++----- engine/platform/psp/fsh_psp.h | 13 +- 3 files changed, 338 insertions(+), 85 deletions(-) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index f9520270..0550e29d 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -196,6 +196,7 @@ static zip_t *fs_last_zip; static pack_t *fs_last_pak; #if XASH_PSP +static fsh_handle_t *fsh_basedir = NULL; static fsh_handle_t *fsh_gamedir = NULL; #endif @@ -1246,7 +1247,7 @@ static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loade pack_t *pak = NULL; const char *ext = COM_FileExtension( pakfile ); int i, errorcode = PAK_LOAD_COULDNT_OPEN; - + for( search = fs_searchpaths; search; search = search->next ) { if( search->pack && !Q_stricmp( search->pack->filename, pakfile )) @@ -1301,7 +1302,7 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int zip_t *zip = NULL; const char *ext = COM_FileExtension( zipfile ); int errorcode = ZIP_LOAD_COULDNT_OPEN; - + for( search = fs_searchpaths; search; search = search->next ) { if( search->pack && !Q_stricmp( search->pack->filename, zipfile )) @@ -1310,12 +1311,12 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int return true; // already loaded } } - + if( already_loaded ) *already_loaded = false; - + if( !Q_stricmp( ext, "pk3" ) ) zip = FS_LoadZip( zipfile, &errorcode ); - + if( zip ) { string fullpath; @@ -1495,7 +1496,7 @@ void FS_ClearSearchPath( void ) if( search->pack ) { - if( search->pack->files ) + if( search->pack->files ) Mem_Free( search->pack->files ); #if XASH_PSP if( search->pack->handle >= 0 ) @@ -1669,7 +1670,7 @@ static void FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) FS_Printf( f, "date\t\t\"%s\"\n", GameInfo->date ); if( Q_strlen( GameInfo->dll_path )) - FS_Printf( f, "dllpath\t\t\"%s\"\n", GameInfo->dll_path ); + FS_Printf( f, "dllpath\t\t\"%s\"\n", GameInfo->dll_path ); if( Q_strlen( GameInfo->game_dll )) FS_Printf( f, "gamedll\t\t\"%s\"\n", GameInfo->game_dll ); @@ -1751,7 +1752,7 @@ void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir ) Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx )); #if XASH_PSP Q_strncpy( GameInfo->game_dll_psp, "dlls/server.prx", sizeof( GameInfo->game_dll_psp )); -#endif +#endif // .ico path Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath )); @@ -1976,7 +1977,7 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool } } } - + #if XASH_PSP if( !found_psp ) Q_snprintf( GameInfo->game_dll_psp, sizeof( GameInfo->game_dll_psp ), "dlls/server.prx" ); @@ -1994,7 +1995,7 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool if( !found_osx ) Q_snprintf( GameInfo->game_dll_osx, sizeof( GameInfo->game_dll_osx ), "%s.dylib", gamedll ); } -#endif +#endif // make sure what gamedir is really exist if( !FS_SysFolderExists( va( "%s"PATH_SPLITTER"%s", host.rootdir, GameInfo->falldir ))) GameInfo->falldir[0] = '\0'; @@ -2024,7 +2025,7 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g { char *afile; - if( !GameInfo ) return false; + if( !GameInfo ) return false; afile = (char *)FS_LoadFile( filename, NULL, false ); if( !afile ) return false; @@ -2223,7 +2224,7 @@ void FS_LoadGameInfo( const char *rootfolder ) { SI.clientlib[0] = 0; } - + FS_Rescan(); // create new filesystem Image_CheckPaletteQ1 (); @@ -2241,7 +2242,7 @@ void FS_Init( void ) qboolean hasBaseDir = false; qboolean hasGameDir = false; int i; - + FS_InitMemory(); Cmd_AddCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" ); @@ -2272,7 +2273,7 @@ void FS_Init( void ) SI.numgames = 0; Q_strncpy( fs_basedir, SI.basedirName, sizeof( fs_basedir )); // default dir - + if( !Sys_GetParmFromCmdLine( "-game", fs_gamedir )) Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir )); // gamedir == basedir @@ -2342,9 +2343,17 @@ void FS_Init( void ) stringlistfreecontents( &dirs ); #if XASH_PSP - fsh_gamedir = FSH_Init( fs_gamedir, 5000 ); - if( !fsh_gamedir ) - Con_Reportf( "FS_Init: FS Helper error\n" ); + fsh_basedir = FSH_Create( fs_basedir, 5000 ); + if( !fsh_basedir ) + Con_Reportf( "FS_Init: FS Helper error (fsh_basedir)\n" ); + + if( Q_stricmp( fs_basedir, fs_gamedir )) + { + fsh_gamedir = FSH_Create( fs_gamedir, 5000 ); + if( !fsh_gamedir ) + Con_Reportf( "FS_Init: FS Helper error (fsh_gamedir)\n" ); + } + else fsh_gamedir = NULL; #endif Con_Reportf( "FS_Init: done\n" ); } @@ -2372,7 +2381,12 @@ void FS_Shutdown( void ) FS_ClearSearchPath(); // release all wad files too Mem_FreePool( &fs_mempool ); #if XASH_PSP - FSH_Shutdown( fsh_gamedir ); + if( fsh_basedir ) + FSH_Free( fsh_basedir ); + fsh_basedir = NULL; + + if( fsh_gamedir ) + FSH_Free( fsh_gamedir ); fsh_gamedir = NULL; #endif } @@ -2399,7 +2413,7 @@ static int FS_SysFileTime( const char *filename ) return fileTime; #else struct stat buf; - + if( stat( filename, &buf ) == -1 ) return -1; @@ -2525,7 +2539,10 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode ) { FS_BackupFileName( file, filepath, mod|opt ); if( mod == PSP_O_WRONLY || mod == PSP_O_RDWR ) - FSH_AddFilePath( fsh_gamedir, filepath ); + { + if( FSH_AddFilePath( fsh_basedir, filepath ) == -2 ) + FSH_AddFilePath( fsh_gamedir, filepath ); + } } #elif !XASH_WIN32 if( file->handle < 0 ) @@ -2688,7 +2705,10 @@ qboolean FS_SysFileExists( const char *path, qboolean caseinsensitive ) int result; SceIoStat buf; - result = FSH_Find( fsh_gamedir, path ); + result = FSH_Find( fsh_basedir, path ); + if( result == -2 ) + result = FSH_Find( fsh_gamedir, path ); + if( result >= 0 ) return true; if( result == -1 ) @@ -2823,7 +2843,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir } else if( search->wad ) { - dlumpinfo_t *lump; + dlumpinfo_t *lump; signed char type = W_TypeFromExt( name ); qboolean anywadname = true; string wadname, wadfolder; @@ -2956,7 +2976,7 @@ file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedi // not found? if( search == NULL ) - return NULL; + return NULL; if( search->pack ) return FS_OpenPackedFile( search->pack, pack_ind ); @@ -2973,7 +2993,7 @@ file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedi // found in the filesystem? Q_sprintf( path, "%s%s", search->filename, filename ); return FS_SysOpen( path, mode ); - } + } return NULL; } @@ -3018,7 +3038,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly ) FS_CreatePath( real_path );// Create directories up to the file return FS_SysOpen( real_path, mode ); } - + // else, we look at the various search paths and open the file in read-only mode return FS_OpenReadFile( filepath, mode, gamedironly ); } @@ -3161,7 +3181,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) #if XASH_PSP if( count > FILE_BUFF_SIZE ) count = FILE_BUFF_SIZE; - + if( count == 0 ) return done; @@ -3346,10 +3366,10 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence ) case SEEK_END: offset += file->real_length; break; - default: + default: return -1; } - + if( offset < 0 || offset > file->real_length ) return -1; @@ -3695,7 +3715,7 @@ dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath ) // NOTE: for libraries we not fail even if search is NULL // let the OS find library himself - hInst = Mem_Calloc( host.mempool, sizeof( dll_user_t )); + hInst = Mem_Calloc( host.mempool, sizeof( dll_user_t )); // save dllname for debug purposes Q_strncpy( hInst->dllName, dllname, sizeof( hInst->dllName )); @@ -3717,7 +3737,7 @@ dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath ) hInst->custom_loader = (search) ? true : false; } fs_ext_path = false; // always reset direct paths - + return hInst; } @@ -3731,8 +3751,33 @@ return size of file in bytes fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly ) { int length = -1; // in case file was missed - file_t *fp; + file_t *fp; +#if XASH_PSP + char buffer[64]; + + Q_sprintf( buffer, "%s/%s", fs_basedir, filename ); + length = FSH_FindSize( fsh_basedir, buffer ); + if( length < 0 && length != -3 ) + { + Q_sprintf( buffer, "%s/%s", fs_gamedir, filename ); + length = FSH_FindSize( fsh_gamedir, buffer ); + } + + if( length < 0 ) + { + fp = FS_Open( filename, "rb", gamedironly ); + + if( fp ) + { + // it exists + FS_Seek( fp, 0, SEEK_END ); + length = FS_Tell( fp ); + FS_Close( fp ); + } + else length = -1; + } +#else fp = FS_Open( filename, "rb", gamedironly ); if( fp ) @@ -3742,7 +3787,7 @@ fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly ) length = FS_Tell( fp ); FS_Close( fp ); } - +#endif return length; } @@ -3770,7 +3815,7 @@ int FS_FileTime( const char *filename, qboolean gamedironly ) { searchpath_t *search; int pack_ind; - + search = FS_FindFile( filename, &pack_ind, gamedironly ); if( !search ) return -1; // doesn't exist @@ -3815,7 +3860,16 @@ qboolean FS_Rename( const char *oldname, const char *newname ) COM_FixSlashes( oldpath ); COM_FixSlashes( newpath ); +#if XASH_PSP + iRet = sceIoRename( oldpath, newpath ); + if( !iRet ) + { + if( FSH_RenameFilePath( fsh_basedir, oldpath, newpath ) == -2 ) + FSH_RenameFilePath( fsh_gamedir, oldpath, newpath ); + } +#else iRet = rename( oldpath, newpath ); +#endif return (iRet == 0); } @@ -3837,10 +3891,16 @@ qboolean GAME_EXPORT FS_Delete( const char *path ) Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_writedir, path ); COM_FixSlashes( real_path ); - iRet = remove( real_path ); #if XASH_PSP - FSH_RemoveFilePath( fsh_gamedir, real_path ); + iRet = sceIoRemove( real_path ); + if( !iRet ) + { + if( FSH_RemoveFilePath( fsh_basedir, real_path ) == -2 ) + FSH_RemoveFilePath( fsh_gamedir, real_path ); + } +#else + iRet = remove( real_path ); #endif return (iRet == 0); @@ -4099,7 +4159,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) void FS_InitMemory( void ) { - fs_mempool = Mem_AllocPool( "FileSystem Pool" ); + fs_mempool = Mem_AllocPool( "FileSystem Pool" ); fs_searchpaths = NULL; } @@ -4137,7 +4197,7 @@ static signed char W_TypeFromExt( const char *lumpname ) // we not known about filetype, so match only by filename if( !Q_strcmp( ext, "*" ) || !Q_strcmp( ext, "" )) return TYP_ANY; - + for( type = wad_types; type->ext; type++ ) { if( !Q_stricmp( ext, type->ext )) @@ -4186,7 +4246,7 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const signed cha // look for the file (binary search) left = 0; right = wad->numlumps - 1; - + while( left <= right ) { int middle = (left + right) / 2; @@ -4336,7 +4396,7 @@ wfile_t *W_Open( const char *filename, int *error ) wad->handle = FS_SysOpen( filename, "rb" ); if( wad->handle == NULL ) - { + { Con_Reportf( S_ERROR "W_Open: couldn't open %s\n", filename ); if( error ) *error = WAD_LOAD_COULDNT_OPEN; W_Close( wad ); @@ -4423,7 +4483,7 @@ wfile_t *W_Open( const char *filename, int *error ) // check for Quake 'conchars' issues (only lmp loader really allows to read this lame pic) if( srclumps[i].type == 68 && !Q_stricmp( srclumps[i].name, "conchars" )) - srclumps[i].type = TYP_GFXPIC; + srclumps[i].type = TYP_GFXPIC; W_AddFileToWad( name, wad, &srclumps[i] ); } @@ -4448,7 +4508,7 @@ void W_Close( wfile_t *wad ) Mem_FreePool( &wad->mempool ); if( wad->handle != NULL ) - FS_Close( wad->handle ); + FS_Close( wad->handle ); Mem_Free( wad ); // free himself } @@ -4473,6 +4533,6 @@ static byte *W_LoadFile( const char *path, fs_offset_t *lumpsizeptr, qboolean ga search = FS_FindFile( path, &index, gamedironly ); if( search && search->wad ) - return W_ReadLump( search->wad, &search->wad->lumps[index], lumpsizeptr ); + return W_ReadLump( search->wad, &search->wad->lumps[index], lumpsizeptr ); return NULL; } diff --git a/engine/platform/psp/fsh_psp.c b/engine/platform/psp/fsh_psp.c index 93924f86..ff7f893c 100644 --- a/engine/platform/psp/fsh_psp.c +++ b/engine/platform/psp/fsh_psp.c @@ -16,14 +16,17 @@ GNU General Public License for more details. #include "common.h" #include "fsh_psp.h" -#define FSH_MAX_PATH 63 +#define FSH_MAX_PATH 64 +#define FSH_EMPTY_STRING "*empty*" -#define FSH_STATE_USED 0x01 +#define FSH_STATE_USED 0x01 typedef struct fsh_path_s { - byte state; - char path[FSH_MAX_PATH]; + char path[FSH_MAX_PATH]; + int fsize; + uint hashvalue; + struct fsh_path_s *nexthash; }fsh_path_t; typedef struct fsh_handle_s @@ -32,13 +35,56 @@ typedef struct fsh_handle_s int count; char folderpath[FSH_MAX_PATH]; int folderpath_size; + uint empty_hash; int pathlist_size; + int hashlist_size; fsh_path_t *pathlist; + fsh_path_t **hashlist; + struct fsh_handle_s *next; }fsh_handle_t; -int FSH_AddFilePath( fsh_handle_t *handle, char *path ) +static fsh_handle_t *fsh_poolchain = NULL; + +/* +================ +FSH_AddHash +================ +*/ +_inline void FSH_AddHash( fsh_path_t **hashlist, uint hash, fsh_path_t *fptr ) { - int index; + fptr->hashvalue = hash; + fptr->nexthash = hashlist[hash]; + hashlist[hash] = fptr; +} + +/* +================ +FSH_RemoveHash +================ +*/ +_inline void FSH_RemoveHash( fsh_path_t **hashlist, uint hash, fsh_path_t *fptr ) +{ + fsh_path_t **fptr_prev; + + for( fptr_prev = &hashlist[hash]; *fptr_prev != NULL; fptr_prev = &( *fptr_prev )->nexthash ) + { + if( *fptr_prev == fptr ) + { + *fptr_prev = fptr->nexthash; + break; + } + } +} + +/* +================ +FSH_AddFilePath +================ +*/ +int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ) +{ + uint hash; + fsh_path_t *fptr; if( !handle ) return -2; @@ -46,24 +92,34 @@ int FSH_AddFilePath( fsh_handle_t *handle, char *path ) if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; + hash = COM_HashKey( path, handle->hashlist_size ); + if( handle->ready && handle->count > 0 ) { // see if already added - for( index = 0; index < handle->count; index++ ) + for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( handle->pathlist[index].path, path )) - return index; + if( !Q_stricmp( fptr->path, path )) + return fptr - handle->pathlist; // index } // find empty - for( index = 0; index < handle->count; index++ ) + for( fptr = handle->hashlist[handle->empty_hash]; fptr != NULL; fptr = fptr->nexthash ) { - if(!( handle->pathlist[index].state & FSH_STATE_USED )) + if( !Q_stricmp( fptr->path, FSH_EMPTY_STRING )) { - Q_strncpy( handle->pathlist[index].path, path, FSH_MAX_PATH - 1 ); - handle->pathlist[index].state |= FSH_STATE_USED; + Q_strncpy( fptr->path, path, FSH_MAX_PATH - 1 ); - return index; + // file size + fptr->fsize = size; + + // remove empty from hash table + FSH_RemoveHash( handle->hashlist, handle->empty_hash, fptr ); + + // add to hash table + FSH_AddHash( handle->hashlist, hash, fptr ); + + return fptr - handle->pathlist; // index } } } @@ -72,16 +128,29 @@ int FSH_AddFilePath( fsh_handle_t *handle, char *path ) if( handle->count + 1 >= handle->pathlist_size ) return -1; - Q_strncpy( handle->pathlist[handle->count].path, path, FSH_MAX_PATH - 1 ); - handle->pathlist[handle->count].state |= FSH_STATE_USED; + fptr = &handle->pathlist[handle->count]; + Q_strncpy( fptr->path, path, FSH_MAX_PATH - 1 ); + + // file size + fptr->fsize = size; + + // add to hash table + FSH_AddHash( handle->hashlist, hash, fptr ); + handle->count++; - return handle->count; + return fptr - handle->pathlist; // index } -int FSH_RemoveFilePath( fsh_handle_t *handle, char *path ) +/* +================ +FSH_RemoveFilePath +================ +*/ +int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path ) { - int index; + uint hash; + fsh_path_t *fptr, **fptr_prev; if( !handle ) return -2; @@ -89,23 +158,77 @@ int FSH_RemoveFilePath( fsh_handle_t *handle, char *path ) if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - for( index = 0; index < handle->count; index++ ) - { - if( !Q_stricmp( handle->pathlist[index].path, path )) - { - memset( handle->pathlist[index].path, 0, FSH_MAX_PATH) ; - handle->pathlist[index].state &= ~FSH_STATE_USED; + hash = COM_HashKey( path, handle->hashlist_size ); - return index; + for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) + { + if( !Q_stricmp( fptr->path, path )) + { + memset( fptr->path, 0, FSH_MAX_PATH ); + Q_strncpy( fptr->path, FSH_EMPTY_STRING, FSH_MAX_PATH - 1 ); + fptr->fsize = -3; // undefined + + // remove from hash table + FSH_RemoveHash( handle->hashlist, hash, fptr ); + + // add empty to hash table + FSH_AddHash( handle->hashlist, handle->empty_hash, fptr ); + + return fptr - handle->pathlist; // index } } return -1; } -int FSH_Find( fsh_handle_t *handle, char *path ) +/* +================ +FSH_RenameFilePath +================ +*/ +int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *newname ) { - int index; + uint hash; + fsh_path_t *fptr, **fptr_prev; + + if( !handle ) + return -2; + + if( Q_strnicmp( oldname, handle->folderpath, handle->folderpath_size )) + return -2; + + hash = COM_HashKey( oldname, handle->hashlist_size ); + + for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) + { + if( !Q_stricmp( fptr->path, oldname )) + { + memset( fptr->path, 0, FSH_MAX_PATH ); + Q_strncpy( fptr->path, newname, FSH_MAX_PATH - 1 ); + + // remove old from hash table + FSH_RemoveHash( handle->hashlist, hash, fptr ); + + // add new to hash table + hash = COM_HashKey( newname, handle->hashlist_size ); + FSH_AddHash( handle->hashlist, hash, fptr ); + + return fptr - handle->pathlist; // index; + } + } + + return -1; +} + +/* +================ +FSH_FindSize +================ +*/ +int FSH_FindSize( fsh_handle_t *handle, const char *path ) +{ + uint hash; + fsh_path_t *fptr; if( !handle ) return -2; @@ -113,21 +236,56 @@ int FSH_Find( fsh_handle_t *handle, char *path ) if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - for( index = 0; index < handle->count; index++ ) + hash = COM_HashKey( path, handle->hashlist_size ); + + for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp(handle->pathlist[index].path, path )) - return index; + if( !Q_stricmp( fptr->path, path )) + return fptr->fsize; } return -1; } -static int FSH_ScanDir( fsh_handle_t *handle, char *path ) +/* +================ +FSH_Find +================ +*/ +int FSH_Find( fsh_handle_t *handle, const char *path ) +{ + uint hash; + fsh_path_t *fptr; + + if( !handle ) + return -2; + + if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) + return -2; + + hash = COM_HashKey( path, handle->hashlist_size ); + + for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) + { + if( !Q_stricmp( fptr->path, path )) + return fptr - handle->pathlist; // index + } + + return -1; +} + +/* +================ +FSH_ScanDir +================ +*/ +static int FSH_ScanDir( fsh_handle_t *handle, const char *path ) { SceUID dir; SceIoDirent entry; char temp[FSH_MAX_PATH]; int result; + int fsize; if(( dir = sceIoDopen( path )) < 0 ) return -1; @@ -151,7 +309,13 @@ static int FSH_ScanDir( fsh_handle_t *handle, char *path ) if(FIO_S_ISDIR( entry.d_stat.st_mode )) result = FSH_ScanDir( handle, temp ); else if(FIO_S_ISREG( entry.d_stat.st_mode )) - result = FSH_AddFilePath( handle, temp ); + { + if( entry.d_stat.st_size <= __INT_MAX__ ) + fsize = ( int )entry.d_stat.st_size; + else fsize = -3; // undefined + + result = FSH_AddFilePathWs( handle, temp, fsize ); + } else continue; if( result < 0 ) break; } @@ -160,11 +324,16 @@ static int FSH_ScanDir( fsh_handle_t *handle, char *path ) return result; } -fsh_handle_t *FSH_Init( char *path, int maxfiles ) +/* +================ +FSH_Create +================ +*/ +fsh_handle_t *FSH_Create( const char *path, int maxfiles ) { fsh_handle_t *handle; - handle = P5Ram_Alloc( sizeof( fsh_handle_t ), 1); + handle = P5Ram_Alloc( sizeof( fsh_handle_t ), 1 ); if( !handle ) return NULL; @@ -172,10 +341,20 @@ fsh_handle_t *FSH_Init( char *path, int maxfiles ) handle->pathlist = P5Ram_Alloc( handle->pathlist_size * sizeof( fsh_path_t ), 1 ); if( !handle->pathlist ) { - FSH_Shutdown( handle ); + P5Ram_Free( handle ); return NULL; } + handle->hashlist_size = maxfiles >> 2; + handle->hashlist = P5Ram_Alloc( handle->hashlist_size * sizeof( fsh_path_t* ), 1 ); + if( !handle->hashlist ) + { + P5Ram_Free( handle ); + return NULL; + } + + handle->empty_hash = COM_HashKey( FSH_EMPTY_STRING, handle->hashlist_size ); + if( !Q_strnicmp( path, "./", 2 )) path += 2; @@ -184,16 +363,24 @@ fsh_handle_t *FSH_Init( char *path, int maxfiles ) if( FSH_ScanDir( handle, handle->folderpath ) < 0 ) { - FSH_Shutdown( handle ); + P5Ram_Free( handle ); return NULL; } + handle->next = fsh_poolchain; + fsh_poolchain = handle; + handle->ready = true; return handle; } -void FSH_Shutdown( fsh_handle_t *handle ) +/* +================ +FSH_Shutdown +================ +*/ +void FSH_Free( fsh_handle_t *handle ) { if( !handle ) return; @@ -201,5 +388,8 @@ void FSH_Shutdown( fsh_handle_t *handle ) if( handle->pathlist ) P5Ram_Free( handle->pathlist ); + if( handle->hashlist ) + P5Ram_Free( handle->hashlist ); + P5Ram_Free( handle ); } diff --git a/engine/platform/psp/fsh_psp.h b/engine/platform/psp/fsh_psp.h index 5a78dfae..228514dd 100644 --- a/engine/platform/psp/fsh_psp.h +++ b/engine/platform/psp/fsh_psp.h @@ -21,11 +21,14 @@ extern "C" { typedef struct fsh_handle_s fsh_handle_t; -int FSH_AddFilePath( fsh_handle_t *handle, char *path ); -int FSH_RemoveFilePath( fsh_handle_t *handle, char *path ); -int FSH_Find( fsh_handle_t *handle, char *path ); -fsh_handle_t *FSH_Init( char *path, int maxfiles ); -void FSH_Shutdown( fsh_handle_t *handle ); +int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ); +#define FSH_AddFilePath( handle, path ) FSH_AddFilePathWs(handle, path, -2 ) +int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path ); +int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *newname ); +int FSH_FindSize( fsh_handle_t *handle, const char *path ); +int FSH_Find( fsh_handle_t *handle, const char *path ); +fsh_handle_t *FSH_Create( const char *path, int maxfiles ); +void FSH_Free( fsh_handle_t *handle ); #ifdef __cplusplus } From c6520b83b291351dafb8c2216c3e5b2d5871bfa2 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 18 Oct 2022 09:31:03 +0300 Subject: [PATCH 67/84] server: sv_save.c: checking P5Ram_Alloc results; memory leak fix --- engine/server/sv_save.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index f6dc900c..588b07f4 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -293,6 +293,8 @@ static void InitEntityTable( SAVERESTOREDATA *pSaveData, int entityCount ) #if XASH_PSP pSaveData->pTable = P5Ram_Alloc( sizeof( ENTITYTABLE ) * entityCount, 1 ); + if( !pSaveData->pTable ) + Host_Error( "%s: P5Ram_Alloc (pSaveData->pTable) failed!", __FUNCTION__ ); #else pSaveData->pTable = Mem_Calloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount ); #endif @@ -613,7 +615,11 @@ static SAVERESTOREDATA *SaveInit( int size, int tokenCount ) #if XASH_PSP pSaveData = P5Ram_Alloc( sizeof( SAVERESTOREDATA ) + size, 1 ); + if( !pSaveData ) + Host_Error( "%s: P5Ram_Alloc (pSaveData) failed!", __FUNCTION__ ); pSaveData->pTokens = (char **)P5Ram_Alloc( tokenCount * sizeof( char* ), 1 ); + if( !pSaveData->pTokens ) + Host_Error( "%s: P5Ram_Alloc (pSaveData->pTokens) failed!", __FUNCTION__ ); #else pSaveData = Mem_Calloc( host.mempool, sizeof( SAVERESTOREDATA ) + size ); pSaveData->pTokens = (char **)Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); @@ -2260,7 +2266,13 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) return 0; } +#if XASH_PSP + pSaveData = (char *)P5Ram_Alloc( size, 0 ); + if( !pSaveData ) + Host_Error( "%s: P5Ram_Alloc (pSaveData) failed!", __FUNCTION__ ); +#else pSaveData = (char *)Mem_Malloc( host.mempool, size ); +#endif FS_Read( f, pSaveData, size ); pData = pSaveData; @@ -2269,6 +2281,8 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment ) { #if XASH_PSP pTokenList = P5Ram_Alloc( tokenCount * sizeof( char* ), 1 ); + if( !pTokenList ) + Host_Error( "%s: P5Ram_Alloc (pTokenList) failed!", __FUNCTION__ ); #else pTokenList = Mem_Calloc( host.mempool, tokenCount * sizeof( char* )); #endif From 5559f728b735a92278604dbe6eefcc4feb0edcf5 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 19 Oct 2022 10:57:21 +0300 Subject: [PATCH 68/84] waf: psp profiling flags for c++ --- scripts/waifulib/xcompile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 44748b8c..cda9f2ed 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -470,6 +470,7 @@ def configure(conf): if conf.options.PROFILING: conf.env.LDFLAGS += ['-lpspprof'] conf.env.CFLAGS += ['-pg'] + conf.env.CXXFLAGS += ['-pg'] conf.env.LDFLAGS += psp.stdlibs() conf.env.DEST_OS2 = 'psp' From f5ca0175a54de6a85812308dd31ac71214723bb2 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 20 Oct 2022 16:45:05 +0300 Subject: [PATCH 69/84] engine: DSP optimization --- engine/client/s_dsp.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/engine/client/s_dsp.c b/engine/client/s_dsp.c index 2aee0483..49132654 100644 --- a/engine/client/s_dsp.c +++ b/engine/client/s_dsp.c @@ -594,7 +594,11 @@ RVB_DoReverbForOneDly Do reverberation for one dly =========== */ +#if XASH_EXT_OPT +_inline int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair ) +#else int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair ) +#endif { int delay; int samplexf; @@ -668,6 +672,29 @@ RVB_DoReverb Do reverberation processing =========== */ +#if XASH_EXT_OPT +void RVB_DoReverb( int count ) +{ + portable_samplepair_t *paint = paintto; + int i, vlr, voutm; + + if( !rgsxdly[REVERBPOS].lpdelayline ) + return; + + for( ; count; count--, paint++ ) + { + vlr = ( paint->left + paint->right ) >> 1; + voutm = 0; + for( i = 0; i < 2; i++ ) + voutm += RVB_DoReverbForOneDly( &rgsxdly[REVERBPOS + i], vlr, paint ); + + voutm = (11 * voutm) >> 6; + + paint->left = CLIP( paint->left + voutm ); + paint->right = CLIP( paint->right + voutm ); + } +} +#else void RVB_DoReverb( int count ) { dly_t *const dly1 = &rgsxdly[REVERBPOS]; @@ -691,6 +718,7 @@ void RVB_DoReverb( int count ) paint->right = CLIP( paint->right + voutm ); } } +#endif /* =========== From 89ee68d5d0bc7b8efd55e500680a0aeae77eb58e Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 20 Oct 2022 16:50:48 +0300 Subject: [PATCH 70/84] ref_gu: depth bug fixed, sort code removed --- engine/common/mod_bmodel.c | 4 ++++ ref_gu/gu_rsurf.c | 47 ++++---------------------------------- 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/engine/common/mod_bmodel.c b/engine/common/mod_bmodel.c index 10c27e7c..3fc8da0e 100644 --- a/engine/common/mod_bmodel.c +++ b/engine/common/mod_bmodel.c @@ -1616,12 +1616,16 @@ static void Mod_LoadSubmodels( dbspmodel_t *bmod ) oldmaxfaces = Q_max( oldmaxfaces, out->numfaces ); } +#if XASH_PSP + refState.max_surfaces = 0; // sorting disabled +#else // these array used to sort translucent faces in bmodels if( oldmaxfaces > refState.max_surfaces ) { refState.draw_surfaces = (sortedface_t *)Z_Realloc( refState.draw_surfaces, oldmaxfaces * sizeof( sortedface_t )); refState.max_surfaces = oldmaxfaces; } +#endif } /* diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index 188f70b3..f0f1f2b9 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -1578,7 +1578,7 @@ void R_SetRenderMode( cl_entity_t *e ) sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, tr.blend ) ); - sceGuDepthMask( GU_TRUE ); + sceGuDepthMask( GU_FALSE ); // bug? sceGuEnable( GU_BLEND ); break; } @@ -1662,8 +1662,10 @@ void R_DrawBrushModel( cl_entity_t *e ) } psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; -#if 1 /* no sorting */ + GU_ClipBeginBrush(); + + // sorting is not required, +Z_Realloc in Mod_LoadSubmodels (mod_bmodel.c) for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) { if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) @@ -1689,48 +1691,7 @@ void R_DrawBrushModel( cl_entity_t *e ) if( e->curstate.rendermode == kRenderTransColor ) sceGuEnable( GU_TEXTURE_2D ); -#else - num_sorted = 0; - for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) - { - if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) - { - if( psurf->plane->type != PLANE_Z && !FBitSet( e->curstate.effects, EF_WATERSIDES )) - continue; - if( mins[2] + 1.0f >= psurf->plane->dist ) - continue; - } - cull_type = R_CullSurface( psurf, &RI.frustum, RI.frustum.clipFlags ); - - if( cull_type >= CULL_FRUSTUM ) - continue; - - if( cull_type == CULL_BACKSIDE ) - { - if( !FBitSet( psurf->flags, SURF_DRAWTURB ) && !( psurf->pdecals && e->curstate.rendermode == kRenderTransTexture )) - continue; - } - - if( num_sorted < gpGlobals->max_surfaces ) - { - gpGlobals->draw_surfaces[num_sorted].surf = psurf; - gpGlobals->draw_surfaces[num_sorted].cull = cull_type; - num_sorted++; - } - } - - // sort faces if needs - if( !FBitSet( clmodel->flags, MODEL_LIQUID ) && e->curstate.rendermode == kRenderTransTexture && !CVAR_TO_BOOL( gl_nosort )) - qsort( gpGlobals->draw_surfaces, num_sorted, sizeof( sortedface_t ), R_SurfaceCompare ); - - // draw sorted translucent surfaces - GU_ClipBeginBrush(); - for( i = 0; i < num_sorted; i++ ) - R_RenderBrushPoly( gpGlobals->draw_surfaces[i].surf, gpGlobals->draw_surfaces[i].cull ); - if( e->curstate.rendermode == kRenderTransColor ) - sceGuEnable( GU_TEXTURE_2D ); -#endif DrawDecalsBatch(); GL_ResetFogColor(); R_BlendLightmaps(); From d6d8ee3e578e2c42d5d651329b0b18656cd77d55 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 20 Oct 2022 16:54:06 +0300 Subject: [PATCH 71/84] ref_gu: updated initial GU settings --- ref_gu/gu_render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ref_gu/gu_render.c b/ref_gu/gu_render.c index def3e776..0e5bf549 100644 --- a/ref_gu/gu_render.c +++ b/ref_gu/gu_render.c @@ -140,7 +140,7 @@ static void GU_Init( void ) // Xash default sceGuClearColor( GU_COLOR( 0.5f, 0.5f, 0.5f, 1.0f ) ); - sceGuDisable( GU_DEPTH_TEST ); + sceGuEnable( GU_DEPTH_TEST ); sceGuDisable( GU_CULL_FACE ); sceGuEnable( GU_CLIP_PLANES ); sceGuDepthFunc( GU_LEQUAL ); @@ -165,7 +165,7 @@ static void GU_Init( void ) sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff ); sceGuEnable( GU_TEXTURE_2D ); sceGuShadeModel( GU_SMOOTH ); - sceGuFrontFace( GU_CW ); // reversed + sceGuFrontFace( GU_CCW ); // Set the default matrices. sceGumMatrixMode( GU_PROJECTION ); From da161103b1dfb55a9ef1ea31927deb62fe1246e2 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Thu, 20 Oct 2022 16:57:48 +0300 Subject: [PATCH 72/84] ref_gu: correct ONE/ZERO modifier for sceGuBlendFunc --- ref_gu/gu_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ref_gu/gu_helper.h b/ref_gu/gu_helper.h index acc94c32..5730bbd8 100644 --- a/ref_gu/gu_helper.h +++ b/ref_gu/gu_helper.h @@ -61,7 +61,7 @@ typedef float GLmatrix[16]; #define GUCOLOR3UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], 255 ) // blend function wrapping -#define GUBLEND1 0xffffff -#define GUBLEND0 0x000000 +#define GUBLEND1 0xffffffff +#define GUBLEND0 0x00000000 #endif // GU_HELPER_H From e3e5fe8e184d7c43285125367193f609ba8eade7 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 31 Oct 2022 09:21:37 +0300 Subject: [PATCH 73/84] platform: psp filesystem helper strip_path --- engine/platform/psp/fsh_psp.c | 47 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/engine/platform/psp/fsh_psp.c b/engine/platform/psp/fsh_psp.c index ff7f893c..4fa1d62f 100644 --- a/engine/platform/psp/fsh_psp.c +++ b/engine/platform/psp/fsh_psp.c @@ -19,8 +19,6 @@ GNU General Public License for more details. #define FSH_MAX_PATH 64 #define FSH_EMPTY_STRING "*empty*" -#define FSH_STATE_USED 0x01 - typedef struct fsh_path_s { char path[FSH_MAX_PATH]; @@ -85,6 +83,7 @@ int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ) { uint hash; fsh_path_t *fptr; + const char *strip_path; if( !handle ) return -2; @@ -92,14 +91,16 @@ int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ) if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - hash = COM_HashKey( path, handle->hashlist_size ); + strip_path = path + handle->folderpath_size + 1; // + '/' + + hash = COM_HashKey( strip_path, handle->hashlist_size ); if( handle->ready && handle->count > 0 ) { // see if already added for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( fptr->path, path )) + if( !Q_stricmp( fptr->path, strip_path )) return fptr - handle->pathlist; // index } @@ -108,7 +109,7 @@ int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ) { if( !Q_stricmp( fptr->path, FSH_EMPTY_STRING )) { - Q_strncpy( fptr->path, path, FSH_MAX_PATH - 1 ); + Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 ); // file size fptr->fsize = size; @@ -129,7 +130,7 @@ int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size ) return -1; fptr = &handle->pathlist[handle->count]; - Q_strncpy( fptr->path, path, FSH_MAX_PATH - 1 ); + Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 ); // file size fptr->fsize = size; @@ -151,6 +152,7 @@ int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path ) { uint hash; fsh_path_t *fptr, **fptr_prev; + const char *strip_path; if( !handle ) return -2; @@ -158,11 +160,13 @@ int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path ) if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - hash = COM_HashKey( path, handle->hashlist_size ); + strip_path = path + handle->folderpath_size + 1; // + '/' + + hash = COM_HashKey( strip_path, handle->hashlist_size ); for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( fptr->path, path )) + if( !Q_stricmp( fptr->path, strip_path )) { memset( fptr->path, 0, FSH_MAX_PATH ); Q_strncpy( fptr->path, FSH_EMPTY_STRING, FSH_MAX_PATH - 1 ); @@ -190,6 +194,7 @@ int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *n { uint hash; fsh_path_t *fptr, **fptr_prev; + const char *strip_path; if( !handle ) return -2; @@ -197,20 +202,24 @@ int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *n if( Q_strnicmp( oldname, handle->folderpath, handle->folderpath_size )) return -2; - hash = COM_HashKey( oldname, handle->hashlist_size ); + strip_path = oldname + handle->folderpath_size + 1; // + '/' + + hash = COM_HashKey( strip_path, handle->hashlist_size ); for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( fptr->path, oldname )) + if( !Q_stricmp( fptr->path, strip_path )) { + strip_path = newname + handle->folderpath_size + 1; // + '/' + memset( fptr->path, 0, FSH_MAX_PATH ); - Q_strncpy( fptr->path, newname, FSH_MAX_PATH - 1 ); + Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 ); // remove old from hash table FSH_RemoveHash( handle->hashlist, hash, fptr ); // add new to hash table - hash = COM_HashKey( newname, handle->hashlist_size ); + hash = COM_HashKey( strip_path, handle->hashlist_size ); FSH_AddHash( handle->hashlist, hash, fptr ); return fptr - handle->pathlist; // index; @@ -229,6 +238,7 @@ int FSH_FindSize( fsh_handle_t *handle, const char *path ) { uint hash; fsh_path_t *fptr; + const char *strip_path; if( !handle ) return -2; @@ -236,11 +246,13 @@ int FSH_FindSize( fsh_handle_t *handle, const char *path ) if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - hash = COM_HashKey( path, handle->hashlist_size ); + strip_path = path + handle->folderpath_size + 1; // + '/' + + hash = COM_HashKey( strip_path, handle->hashlist_size ); for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( fptr->path, path )) + if( !Q_stricmp( fptr->path, strip_path )) return fptr->fsize; } @@ -256,6 +268,7 @@ int FSH_Find( fsh_handle_t *handle, const char *path ) { uint hash; fsh_path_t *fptr; + const char *strip_path; if( !handle ) return -2; @@ -263,11 +276,13 @@ int FSH_Find( fsh_handle_t *handle, const char *path ) if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size )) return -2; - hash = COM_HashKey( path, handle->hashlist_size ); + strip_path = path + handle->folderpath_size + 1; // + '/' + + hash = COM_HashKey( strip_path, handle->hashlist_size ); for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash ) { - if( !Q_stricmp( fptr->path, path )) + if( !Q_stricmp( fptr->path, strip_path )) return fptr - handle->pathlist; // index } From 0b500168a744f146135842704408d2e250e49f63 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 31 Oct 2022 09:32:22 +0300 Subject: [PATCH 74/84] ref_gu: gl_nosort cvar removed --- ref_gu/gu_local.h | 1 - ref_gu/gu_render.c | 2 -- ref_gu/gu_rmain.c | 9 ++++----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index c637c5ef..b9ed4365 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -776,7 +776,6 @@ extern cvar_t *gl_round_down; extern cvar_t *gl_detailscale; extern cvar_t *gl_wireframe; extern cvar_t *gl_depthoffset; -extern cvar_t *gl_nosort; extern cvar_t *gl_clear; extern cvar_t *gl_test; // cvar to testify new effects extern cvar_t *gl_subdivide_size; diff --git a/ref_gu/gu_render.c b/ref_gu/gu_render.c index 0e5bf549..1aa28e9a 100644 --- a/ref_gu/gu_render.c +++ b/ref_gu/gu_render.c @@ -26,7 +26,6 @@ cvar_t *gl_emboss_scale; cvar_t *gl_detailscale; cvar_t *gl_depthoffset; cvar_t *gl_wireframe; -cvar_t *gl_nosort; cvar_t *gl_vsync; cvar_t *gl_clear; cvar_t *gl_test; @@ -373,7 +372,6 @@ void GL_InitCommands( void ) gl_keeptjunctions = gEngfuncs.Cvar_Get( "gl_keeptjunctions", "1", FCVAR_GLCONFIG, "removing tjuncs causes blinking pixels" ); gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_GLCONFIG|FCVAR_LATCH, "fake bumpmapping scale" ); gl_showtextures = gEngfuncs.pfnGetCvarPointer( "r_showtextures", 0 ); - gl_nosort = gEngfuncs.Cvar_Get( "gl_nosort", "1", FCVAR_GLCONFIG, "disable sorting of translucent surfaces" ); gl_clear = gEngfuncs.pfnGetCvarPointer( "gl_clear", 0 ); gl_test = gEngfuncs.Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" ); gl_wireframe = gEngfuncs.Cvar_Get( "gl_wireframe", "0", FCVAR_GLCONFIG|FCVAR_SPONLY, "show wireframe overlay" ); diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 331c7b20..4baf4f38 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -535,11 +535,10 @@ static void R_SetupFrame( void ) glState.isFogEnabled = pglIsEnabled( GL_FOG ); #endif - if( !gl_nosort->value ) - { - // sort translucents entities by rendermode and distance - qsort( tr.draw_list->trans_entities, tr.draw_list->num_trans_entities, sizeof( cl_entity_t* ), R_TransEntityCompare ); - } +#if 0 + // sort translucents entities by rendermode and distance + qsort( tr.draw_list->trans_entities, tr.draw_list->num_trans_entities, sizeof( cl_entity_t* ), R_TransEntityCompare ); +#endif // current viewleaf if( RI.drawWorld ) From 066d87f5460fff3cc2766460154bd8f163aedad1 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 31 Oct 2022 09:34:16 +0300 Subject: [PATCH 75/84] ref_gu: depth mask returned --- ref_gu/gu_rsurf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index f0f1f2b9..05266fed 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -1578,7 +1578,7 @@ void R_SetRenderMode( cl_entity_t *e ) sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA ); sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, tr.blend ) ); - sceGuDepthMask( GU_FALSE ); // bug? + sceGuDepthMask( GU_TRUE ); sceGuEnable( GU_BLEND ); break; } From 1704712650ab4c4e22411ab8a7f27d63384066d0 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 2 Nov 2022 09:52:42 +0300 Subject: [PATCH 76/84] platform: psp fixed issues with libc --- engine/platform/psp/lib_psp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/engine/platform/psp/lib_psp.c b/engine/platform/psp/lib_psp.c index 910eaa7f..ae7156af 100644 --- a/engine/platform/psp/lib_psp.c +++ b/engine/platform/psp/lib_psp.c @@ -137,10 +137,11 @@ mod_handle_t *Module_Load( const char *name ) mod_func_t *modFunc; qboolean skipPrefix; char modStaticName[32]; - void *modArg; + void *modArg[2]; SceUID modUid; uint modSegAddr, modSegSize; SceKernelModuleInfo info; + char engine_cwd[256]; if( !name ) return NULL; @@ -152,8 +153,11 @@ mod_handle_t *Module_Load( const char *name ) skipPrefix = false; modSegAddr = modSegSize = 0; - modArg = &modFunc; - modUid = Platform_LoadModule( name, 0, sizeof( modArg ), &modArg ); + Q_sprintf( engine_cwd, "%s/", host.rootdir ); + + modArg[0] = &modFunc; + modArg[1] = engine_cwd; + modUid = Platform_LoadModule( name, 0, sizeof( modArg ), modArg ); if( modUid < 0 ) { COM_FileBase( name, modStaticName ); From 0dc1c13b83d966c9bd0d677a941ae33bc9581d7b Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 2 Nov 2022 16:36:23 +0300 Subject: [PATCH 77/84] engine: psp Adrenaline bug --- engine/common/filesystem.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index 0550e29d..e09db6ef 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -3854,8 +3854,13 @@ qboolean FS_Rename( const char *oldname, const char *newname ) if( !oldname || !newname || !*oldname || !*newname ) return false; +#if XASH_PSP // BUG: Adrenaline PSVITA: sceIoRename requires full path + Q_snprintf( oldpath, sizeof( oldpath ), "%s/%s%s", host.rootdir, fs_writedir, oldname ); + Q_snprintf( newpath, sizeof( newpath ), "%s/%s%s", host.rootdir, fs_writedir, newname ); +#else Q_snprintf( oldpath, sizeof( oldpath ), "%s%s", fs_writedir, oldname ); Q_snprintf( newpath, sizeof( newpath ), "%s%s", fs_writedir, newname ); +#endif COM_FixSlashes( oldpath ); COM_FixSlashes( newpath ); From 28723b01a9842fd070bcd41d83d47de21a259034 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 2 Nov 2022 16:38:33 +0300 Subject: [PATCH 78/84] platform: psp PATH_MAX fix --- common/port.h | 14 ++++++++------ engine/platform/psp/fsh_psp.c | 2 +- engine/platform/psp/lib_psp.c | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/common/port.h b/common/port.h index 0756fe7e..0aed7cc4 100644 --- a/common/port.h +++ b/common/port.h @@ -80,15 +80,17 @@ GNU General Public License for more details. #if XASH_PSP #include #include - #define PATH_MAX 1024 + + #define PATH_MAX 256 //PSP FATMS Maximum length of a full pathname 260 characters #define PATH_SPLITTER "/" #define O_BINARY 0 #define O_TEXT 0 - #define _mkdir( x ) sceIoMkdir( x, FIO_S_IRWXU | FIO_S_IRWXG | FIO_S_IROTH | FIO_S_IXOTH ) - #define SetCurrentDirectory( x ) ( !sceIoChdir( x ) ) - #define LoadLibrary( x ) ( 0 ) - #define GetProcAddress( x, y ) ( 0 ) - #define FreeLibrary( x ) ( 0 ) + + #define _mkdir( x ) sceIoMkdir( x, FIO_S_IRWXU | FIO_S_IRWXG | FIO_S_IROTH | FIO_S_IXOTH ) + #define SetCurrentDirectory( x ) ( !sceIoChdir( x ) ) + #define LoadLibrary( x ) ( 0 ) + #define GetProcAddress( x, y ) ( 0 ) + #define FreeLibrary( x ) ( 0 ) #endif //#define MAKEWORD( a, b ) ((short int)(((unsigned char)(a))|(((short int)((unsigned char)(b)))<<8))) diff --git a/engine/platform/psp/fsh_psp.c b/engine/platform/psp/fsh_psp.c index 4fa1d62f..a0c00a67 100644 --- a/engine/platform/psp/fsh_psp.c +++ b/engine/platform/psp/fsh_psp.c @@ -31,7 +31,7 @@ typedef struct fsh_handle_s { qboolean ready; int count; - char folderpath[FSH_MAX_PATH]; + char folderpath[PATH_MAX]; int folderpath_size; uint empty_hash; int pathlist_size; diff --git a/engine/platform/psp/lib_psp.c b/engine/platform/psp/lib_psp.c index ae7156af..d9f63374 100644 --- a/engine/platform/psp/lib_psp.c +++ b/engine/platform/psp/lib_psp.c @@ -141,7 +141,7 @@ mod_handle_t *Module_Load( const char *name ) SceUID modUid; uint modSegAddr, modSegSize; SceKernelModuleInfo info; - char engine_cwd[256]; + char engine_cwd[PATH_MAX]; if( !name ) return NULL; From e6a9724d7cd1e639b2f81618d9cfd440bc55b767 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 2 Nov 2022 16:40:39 +0300 Subject: [PATCH 79/84] platform: psp joystick curve support --- engine/platform/psp/in_psp.c | 49 +++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/engine/platform/psp/in_psp.c b/engine/platform/psp/in_psp.c index 00351f6d..b174d508 100644 --- a/engine/platform/psp/in_psp.c +++ b/engine/platform/psp/in_psp.c @@ -23,8 +23,10 @@ GNU General Public License for more details. #define PSP_MAX_KEYS sizeof(psp_keymap) / sizeof(struct psp_keymap_s) #define PSP_EXT_KEY PSP_CTRL_HOME -convar_t *psp_deadzone_min; -convar_t *psp_deadzone_max; +convar_t *psp_joy_dz_min; +convar_t *psp_joy_dz_max; +convar_t *psp_joy_cv_power; +convar_t *psp_joy_cv_expo; static struct psp_keymap_s { @@ -76,10 +78,16 @@ static struct psp_keymap_s }; static signed short psp_joymap[256]; /* -32768 <> 32767 */ -static float Platform_JoyRescale( float axis, float deadzone_min, float deadzone_max ) +static float Platform_JoyAxisCompute( float axis, float deadzone_min, float deadzone_max, float power, float expo ) { - float abs_axis, scale, r_deadzone_max; - int flip_axis = 0; + float abs_axis, fabs_axis, fcurve; + float scale, r_deadzone_max; + qboolean flip_axis = 0; + + expo = bound( 0.0f, expo, 1.0f ); + power = bound( 0.0f, power, 10.0f ); + deadzone_min = bound( 0.0f, deadzone_min, 127.0f ); + deadzone_max = bound( 0.0f, deadzone_max, 127.0f ); // (-127) - (0) - (+127) abs_axis = axis - 128.0f; @@ -96,13 +104,21 @@ static float Platform_JoyRescale( float axis, float deadzone_min, float deadzone abs_axis -= deadzone_min; abs_axis *= scale; + if( expo ) + { + // x * ( x^power * expo + x * ( 1.0 - expo )) + fabs_axis = abs_axis / 127.0f; // 0.0f - 1.0f + fcurve = powf(fabs_axis, power) * expo + fabs_axis * (1.0f - expo); + abs_axis = fabs_axis * fcurve * 127.0f; + } + return ( flip_axis ? -abs_axis : abs_axis ); } void Platform_RunEvents( void ) { - int i; - SceCtrlData buf; + int i; + SceCtrlData buf; signed short curr_X, curr_Y; static unsigned int last_buttons; static signed short last_X, last_Y; @@ -145,16 +161,19 @@ void Platform_RunEvents( void ) } last_buttons = buf.Buttons; - if( FBitSet( psp_deadzone_min->flags, FCVAR_CHANGED ) || FBitSet( psp_deadzone_max->flags, FCVAR_CHANGED ) ) + if( FBitSet( psp_joy_dz_min->flags, FCVAR_CHANGED ) || FBitSet( psp_joy_dz_max->flags, FCVAR_CHANGED ) || + FBitSet( psp_joy_cv_power->flags, FCVAR_CHANGED ) || FBitSet( psp_joy_cv_expo->flags, FCVAR_CHANGED )) { for ( i = 0; i < 256; i++ ) { - psp_joymap[i] = Platform_JoyRescale( i, psp_deadzone_min->value, psp_deadzone_max->value ); + psp_joymap[i] = Platform_JoyAxisCompute( i, psp_joy_dz_min->value, psp_joy_dz_max->value, psp_joy_cv_power->value, psp_joy_cv_expo->value ); psp_joymap[i] *= 256; } - ClearBits( psp_deadzone_min->flags, FCVAR_CHANGED ); - ClearBits( psp_deadzone_max->flags, FCVAR_CHANGED ); + ClearBits( psp_joy_dz_min->flags, FCVAR_CHANGED ); + ClearBits( psp_joy_dz_max->flags, FCVAR_CHANGED ); + ClearBits( psp_joy_cv_power->flags, FCVAR_CHANGED ); + ClearBits( psp_joy_cv_expo->flags, FCVAR_CHANGED ); } curr_X = psp_joymap[buf.Lx]; @@ -190,8 +209,10 @@ int Platform_JoyInit( int numjoy ) int i; // set up cvars - psp_deadzone_min = Cvar_Get( "psp_deadzone_min", "20", FCVAR_ARCHIVE, "Joy deadzone min (0 - 127)" ); - psp_deadzone_max = Cvar_Get( "psp_deadzone_max", "0", FCVAR_ARCHIVE, "Joy deadzone max (0 - 127)" ); + psp_joy_dz_min = Cvar_Get( "psp_joy_dz_min", "15", FCVAR_ARCHIVE, "joy deadzone min (0 - 127)" ); + psp_joy_dz_max = Cvar_Get( "psp_joy_dz_max", "0", FCVAR_ARCHIVE, "joy deadzone max (0 - 127)" ); + psp_joy_cv_power = Cvar_Get( "psp_joy_cv_power", "2", FCVAR_ARCHIVE, "joy curve power (0 - 10)" ); + psp_joy_cv_expo = Cvar_Get( "psp_joy_cv_expo", "0.5", FCVAR_ARCHIVE, "joy curve expo (0 - 1.0)" ); // set up the controller. sceCtrlSetSamplingCycle( 0 ); @@ -200,7 +221,7 @@ int Platform_JoyInit( int numjoy ) // building a joystick map for ( i = 0; i < 256; i++ ) { - psp_joymap[i] = Platform_JoyRescale( i, psp_deadzone_min->value, psp_deadzone_max->value ); + psp_joymap[i] = Platform_JoyAxisCompute( i, psp_joy_dz_min->value, psp_joy_dz_max->value, psp_joy_cv_power->value, psp_joy_cv_expo->value ); psp_joymap[i] *= 256; } return 1; From 15ea61ea34932d1e79a1bb71c82f184d0678c2fd Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Fri, 11 Nov 2022 10:10:47 +0300 Subject: [PATCH 80/84] psp: mainui update --- mainui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mainui b/mainui index 5ad02202..855e4257 160000 --- a/mainui +++ b/mainui @@ -1 +1 @@ -Subproject commit 5ad0220211016dbb9535e2d637377f161aa32a25 +Subproject commit 855e4257ead921568a91a1a7e090968ad04e53b0 From 3ccb15655441561ed20afb0f39048510aed021b1 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Mon, 21 Nov 2022 11:14:22 +0300 Subject: [PATCH 81/84] platform: using hw psp mp3 decoder for streams --- engine/common/soundlib/snd_mp3.c | 492 +++++++++++++++++++++++++++- engine/common/soundlib/soundlib.h | 2 + engine/platform/psp/scemp3/pspmp3.h | 248 ++++++++++++++ engine/platform/psp/scemp3/sceMp3.S | 29 ++ engine/platform/psp/sys_psp.c | 71 +++- engine/wscript | 4 +- 6 files changed, 835 insertions(+), 11 deletions(-) create mode 100644 engine/platform/psp/scemp3/pspmp3.h create mode 100644 engine/platform/psp/scemp3/sceMp3.S diff --git a/engine/common/soundlib/snd_mp3.c b/engine/common/soundlib/snd_mp3.c index a512bee7..9e85d3b9 100644 --- a/engine/common/soundlib/snd_mp3.c +++ b/engine/common/soundlib/snd_mp3.c @@ -12,8 +12,8 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ - #include "soundlib.h" +#if !XASH_PSP #include "libmpg/libmpg.h" /* @@ -117,12 +117,8 @@ stream_t *Stream_OpenMPG( const char *filename ) file_t *file; int ret; wavinfo_t sc; -#if XASH_PSP - // h - hold mode - file = FS_Open( filename, "rbh", false ); -#else + file = FS_Open( filename, "rb", false ); -#endif if( !file ) return NULL; // at this point we have valid stream @@ -190,7 +186,7 @@ int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer ) // check remaining size if( bytesWritten + stream->pos > needBytes ) - outsize = ( needBytes - bytesWritten ); + outsize = ( needBytes - bytesWritten ); else outsize = stream->pos; // copy raw sample to output buffer @@ -265,3 +261,485 @@ void Stream_FreeMPG( stream_t *stream ) Mem_Free( stream ); } + +#else // XASH_PSP +#include "platform/psp/scemp3/pspmp3.h" + +/* +================================================================= + + PSP MPEG decoding + +================================================================= +*/ +#define MP3_ID3V1_ID "TAG" +#define MP3_ID3V1_ID_SZ 3 +#define MP3_ID3V1_SZ 128 + +#define MP3_ID3V2_ID "ID3" +#define MP3_ID3V2_ID_SZ 3 +#define MP3_ID3V2_SIZE_OFF 6 +#define MP3_ID3V2_SIZE_SZ 4 +#define MP3_ID3V2_HEADER_SZ 10 + +#define MP3_ERRORS_MAX 3 + +#define PCM_WIDTH 2 // always 16-bit PCM +#define PCM_CHANNELS 2 // always 2 + +#define MP3_BUFFER_SIZE ( 128 * 1024 ) +#define PCM_BUFFER_SIZE (( 1152 * PCM_WIDTH * PCM_CHANNELS ) * 2 ) // framesample * width * channels * 2(double buffer) + +typedef struct +{ + int handle; + int cachePos; + int frameCount; + byte *pcmTempPtr; +} mp3_decoder_t; + +/* +================= +Sound_GetID3V2SizeMPG +================= +*/ +__inline int Sound_GetID3V2SizeMPG( const byte *tagSize ) +{ + int size; + byte *sizePtr = (byte*)&size; + + // 7 bit per byte, invert endian + sizePtr[0] = (( tagSize[3] >> 0 ) & 0x7F ) | (( tagSize[2] & 0x01 ) << 7 ); + sizePtr[1] = (( tagSize[2] >> 1 ) & 0x3F ) | (( tagSize[1] & 0x03 ) << 6 ); + sizePtr[2] = (( tagSize[1] >> 2 ) & 0x1F ) | (( tagSize[0] & 0x07 ) << 5 ); + sizePtr[3] = (( tagSize[0] >> 3 ) & 0x0F ); + + return size; +} + +#if 0 +/* +================= +Sound_FindHeadMPG +================= +*/ +fs_offset_t Sound_FindHeadMPG( const byte *buffer, fs_offset_t filesize ) +{ + fs_offset_t result; + + result = 0; + if( filesize >= MP3_ID3V2_HEADER_SZ ) + { + if( !memcmp( buffer, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ )) + result = Sound_GetID3V2SizeMPG( &buffer[MP3_ID3V2_SIZE_OFF] ) + MP3_ID3V2_HEADER_SZ; + } + return result; +} + +/* +================= +Sound_FindTailMPG +================= +*/ +fs_offset_t Sound_FindTailMPG( const byte *buffer, fs_offset_t filesize ) +{ + fs_offset_t result; + + result = filesize; + if( filesize >= MP3_ID3V1_SZ ) + { + if( !memcmp( &buffer[filesize - MP3_ID3V1_SZ], MP3_ID3V1_ID, MP3_ID3V1_ID_SZ )) + result -= MP3_ID3V1_SZ; + } + return result; +} +#endif + +qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesize ) +{ +#if 0 + int status; + int handle; + size_t bytesWrite = 0; + byte out[PCM_BUFFER_SIZE] __attribute__((aligned(64))); + fs_offset_t headOffset; + fs_offset_t tailOffset; + fs_offset_t contentSize; + int frameSample; + uint bps; + int frameLen; + int frameSize; + int frameCount; + + headOffset = Sound_FindHeadMPG( buffer, filesize ); + tailOffset = Sound_FindTailMPG( buffer, filesize ); + contentSize = tailOffset - headOffset; + // TODO: read Xing header + + handle = sceMp3ReserveMp3Handle( NULL ); + if ( handle < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", handle ); + return false; + } + + status = sceMp3LowLevelInit( handle, &buffer[headOffset] ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3LowLevelInit returned 0x%08X\n", status ); + return false; + } + + frameSample = sceMp3GetMaxOutputSample( handle ); + frameSize = (( frameSample / 8 ) * sceMp3GetBitRate( handle ) * 1000 ) / sceMp3GetSamplingRate( handle ); + frameCount = contentSize / frameSize; + + sound.channels = sceMp3GetMp3ChannelNum( handle ); + sound.rate = sceMp3GetSamplingRate( handle ); + sound.width = PCM_WIDTH; // always 16-bit PCM + sound.loopstart = -1; + sound.size = (frameCount * frameSample) * sound.channels * sound.width; // invalid for VBR +/* + status = sceMp3LowLevelDecode(handle, &buffer[headOffset + mp3usedsize], &mp3usedsize, pcm, &pcmoutsize); + if(status < 0) + { + Con_DPrintf( S_ERROR "sceMp3LowLevelDecode returned 0x%08X\n", status); + } + sceMp3ReleaseMp3Handle( handle ); +*/ + return true; +#else + Con_DPrintf( S_ERROR "Sound_LoadMPG unimplemented function!\n"); + return false; +#endif +} + +/* +================= +Stream_FindHeadMPG +================= +*/ +SceOff Stream_FindHeadMPG( file_t *file ) +{ + SceOff result; + byte tagId[MP3_ID3V2_ID_SZ]; + byte tagSize[MP3_ID3V2_SIZE_SZ]; + + result = 0; + + FS_Seek( file, 0, SEEK_SET ); + + if( FS_Read( file, tagId, MP3_ID3V2_ID_SZ) < MP3_ID3V2_ID_SZ ) + { + Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 ID read error\n"); + return result; + } + + if( !memcmp( tagId, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ )) + { + FS_Seek( file, MP3_ID3V2_SIZE_OFF, SEEK_SET ); + if( FS_Read( file, tagSize, MP3_ID3V2_SIZE_SZ ) < MP3_ID3V2_SIZE_SZ ) + Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 SIZE read error\n"); + else result = Sound_GetID3V2SizeMPG( tagSize ) + MP3_ID3V2_HEADER_SZ; + } + + return result; +} + +/* +================= +Stream_FindTailMPG +================= +*/ +SceOff Stream_FindTailMPG( file_t *file ) +{ + SceOff result; + byte tagId[MP3_ID3V1_ID_SZ]; + + result = FS_FileLength( file ); + + FS_Seek( file, result - MP3_ID3V1_SZ, SEEK_SET ); + + if( FS_Read( file, tagId, MP3_ID3V1_ID_SZ ) < MP3_ID3V1_ID_SZ ) + { + Con_DPrintf( S_ERROR "Sound_Mp3FindTail: ID3V1 ID read error\n"); + return result; + } + + if( !memcmp( tagId, MP3_ID3V1_ID, MP3_ID3V1_ID_SZ )) + result -= MP3_ID3V1_SZ; + + return result; +} + +/* +================= +Stream_FillBufferMPG +================= +*/ +int Stream_FillBufferMPG( file_t *file, mp3_decoder_t *desc ) +{ + int status; + byte *dstPtr; + int dstSize; + int dstPos; + fs_offset_t readSize; + + if( sceMp3CheckStreamDataNeeded( desc->handle ) <= 0 ) + return 0; + + // get Info on the stream (where to fill to, how much to fill, where to fill from) + status = sceMp3GetInfoToAddStreamData( desc->handle, &dstPtr, &dstSize, &dstPos ); + if( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3GetInfoToAddStreamData returned 0x%08X\n", status); + return status; + } + + // seek file to position requested + if( desc->cachePos != dstPos ) + { + FS_Seek( file, dstPos, SEEK_SET ); + desc->cachePos = dstPos; + } + + // read the amount of data + readSize = FS_Read( file, dstPtr, dstSize ); + desc->cachePos += ( int )readSize; + + // notify mp3 library about how much we really wrote to the stream buffer + status = sceMp3NotifyAddStreamData( desc->handle, ( int )readSize ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceMp3NotifyAddStreamData returned 0x%08X\n", status); + + return status; +} + +/* +================= +Stream_OpenMPG +================= +*/ +stream_t *Stream_OpenMPG( const char *filename ) +{ + stream_t *stream; + mp3_decoder_t *desc; + file_t *file; + int status; + void *bufferBase; + + file = FS_Open( filename, "rbh", false ); // hold mode + if( !file ) return NULL; + + // at this point we have valid stream + stream = Mem_Calloc( host.soundpool, sizeof( stream_t )); + stream->file = file; + stream->pos = 0; + + desc = Mem_Calloc( host.soundpool, sizeof( mp3_decoder_t ) + MP3_BUFFER_SIZE + PCM_BUFFER_SIZE + 63 ); + bufferBase = (void *)(((( uintptr_t )desc + sizeof( mp3_decoder_t )) & (~( 64 - 1 ))) + 64 ); + + // reserve a mp3 handle + SceMp3InitArg mp3Init; + mp3Init.mp3StreamStart = Stream_FindHeadMPG( file ); + mp3Init.mp3StreamEnd = Stream_FindTailMPG( file ); + mp3Init.mp3Buf = bufferBase; + mp3Init.mp3BufSize = MP3_BUFFER_SIZE; + mp3Init.pcmBuf = (void *)(( uintptr_t )bufferBase + MP3_BUFFER_SIZE ); + mp3Init.pcmBufSize = PCM_BUFFER_SIZE; + + desc->cachePos = 0; + desc->pcmTempPtr = mp3Init.pcmBuf; + desc->handle = sceMp3ReserveMp3Handle( &mp3Init ); + if ( desc->handle < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", desc->handle ); + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + // Fill the stream buffer with some data so that sceMp3Init has something to work with + if( Stream_FillBufferMPG( file, desc ) != 0 ) + { + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + status = sceMp3Init( desc->handle ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3Init returned 0x%08X\n", status ); + Mem_Free( stream ); + Mem_Free( desc ); + FS_Close( file ); + return NULL; + } + + desc->frameCount = sceMp3GetFrameNum( desc->handle ); + + stream->buffsize = 0; // how many samples left from previous frame + stream->channels = PCM_CHANNELS; // always 2 PCM channels + stream->rate = sceMp3GetSamplingRate( desc->handle ); + stream->width = PCM_WIDTH; // always 16 bit PCM + stream->ptr = (void *)desc; + stream->type = WF_MPGDATA; + + return stream; +} + +/* +================= +Stream_ReadMPG + +assume stream is valid +================= +*/ +int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer ) +{ + // buffer handling + int bytesWritten = 0; + mp3_decoder_t *desc; + int errdec; + + desc = ( mp3_decoder_t* )stream->ptr; + + while(1) + { + byte *data; + int outsize; + + if( !stream->buffsize ) + { + // Check if we need to fill our stream buffer + if( Stream_FillBufferMPG( stream->file, desc ) != 0 ) + return 0; + + for( errdec = 0; errdec < MP3_ERRORS_MAX; errdec++ ) + { + stream->pos = sceMp3Decode( desc->handle, (SceShort16**)&desc->pcmTempPtr ); + if(( int )stream->pos >= 0 ) // decoding successful + { + break; + } + else if( stream->pos == 0x80671402 ) // next frame header + { + if( Stream_FillBufferMPG( stream->file, desc ) != 0 ) + return 0; + } + else break; + } + + if(( int )stream->pos < 0 ) + { + if( stream->pos != 0x80671402 ) + Con_DPrintf( S_ERROR "sceMp3Decode returned 0x%08X\n", stream->pos ); + return 0; // ??? + } + } + + // check remaining size + if( bytesWritten + stream->pos > needBytes ) + outsize = ( needBytes - bytesWritten ); + else outsize = stream->pos; + + // copy raw sample to output buffer + data = (byte *)buffer + bytesWritten; + memcpy( data, &desc->pcmTempPtr[stream->buffsize], outsize ); + bytesWritten += outsize; + stream->pos -= outsize; + stream->buffsize += outsize; + + // continue from this sample on a next call + if( bytesWritten >= needBytes ) + return bytesWritten; + + stream->buffsize = 0; // no bytes remaining + } + + return 0; +} + +/* +================= +Stream_SetPosMPG + +assume stream is valid +================= +*/ +int Stream_SetPosMPG( stream_t *stream, int newpos ) +{ + mp3_decoder_t *desc; + int frame; + int status; + + desc = ( mp3_decoder_t* )stream->ptr; + + // get frame num + frame = newpos / sceMp3GetMaxOutputSample( desc->handle ); // VBR? + + if( frame < 1 || frame >= desc->frameCount - 1 ) + return false; + + status = sceMp3ResetPlayPositionByFrame( desc->handle, frame ); + if( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3ResetPlayPositionByFrame returned 0x%08X\n", status ); + + // failed to seek for some reasons + return false; + } + + // flush any previous data + stream->buffsize = 0; + + return true; +} + +/* +================= +Stream_GetPosMPG + +assume stream is valid +================= +*/ +int Stream_GetPosMPG( stream_t *stream ) +{ + mp3_decoder_t *desc; + + desc = ( mp3_decoder_t * )stream->ptr; + + return sceMp3GetSumDecodedSample( desc->handle ); +} + +/* +================= +Stream_FreeMPG + +assume stream is valid +================= +*/ +void Stream_FreeMPG( stream_t *stream ) +{ + mp3_decoder_t *desc; + + desc = ( mp3_decoder_t * )stream->ptr; + if( desc ) + { + sceMp3ReleaseMp3Handle( desc->handle ); + Mem_Free( desc ); + stream->ptr = NULL; + } + + if( stream->file ) + { + FS_Close( stream->file ); + stream->file = NULL; + } + + Mem_Free( stream ); +} +#endif // XASH_PSP diff --git a/engine/common/soundlib/soundlib.h b/engine/common/soundlib/soundlib.h index 686d50b1..d94bec17 100644 --- a/engine/common/soundlib/soundlib.h +++ b/engine/common/soundlib/soundlib.h @@ -74,7 +74,9 @@ struct stream_s // current stream state void *ptr; // internal decoder state +#if !XASH_PSP char temp[OUTBUF_SIZE]; // mpeg decoder stuff +#endif size_t pos; // actual track position (or actual buffer remains) int buffsize; // cached buffer size }; diff --git a/engine/platform/psp/scemp3/pspmp3.h b/engine/platform/psp/scemp3/pspmp3.h new file mode 100644 index 00000000..cc40773d --- /dev/null +++ b/engine/platform/psp/scemp3/pspmp3.h @@ -0,0 +1,248 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * pspmp3.h - Prototypes for the sceMp3 library + * + * Copyright (c) 2008 David Perry + * Copyright (c) 2008 Alexander Berl + * Copyright (c) 2022 Sergey Galushko + * + */ + +#ifndef __SCELIBMP3_H__ +#define __SCELIBMP3_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SceMp3InitArg { + /** Stream start position */ + SceOff mp3StreamStart; + /** Stream end position */ + SceOff mp3StreamEnd; + /** Pointer to a buffer to contain raw mp3 stream data (+1472 bytes workspace) */ + SceUChar8* mp3Buf; + /** Size of mp3Buf buffer (must be >= 8192) */ + SceInt32 mp3BufSize; + /** Pointer to decoded pcm samples buffer */ + SceUChar8* pcmBuf; + /** Size of pcmBuf buffer (must be >= 9216) */ + SceInt32 pcmBufSize; +} SceMp3InitArg; + +/** + * sceMp3ReserveMp3Handle + * + * @param args - Pointer to SceMp3InitArg structure + * + * @return sceMp3 handle on success, < 0 on error. + */ +SceInt32 sceMp3ReserveMp3Handle(SceMp3InitArg* args); + +/** + * sceMp3ReleaseMp3Handle + * + * @param handle - sceMp3 handle + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3ReleaseMp3Handle(SceInt32 handle); + +/** + * sceMp3InitResource + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3InitResource(); + +/** + * sceMp3TermResource + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3TermResource(); + +/** + * sceMp3Init + * + * @param handle - sceMp3 handle + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3Init(SceInt32 handle); + +/** + * sceMp3Decode + * + * @param handle - sceMp3 handle + * @param dst - Pointer to destination pcm samples buffer + * + * @return number of bytes in decoded pcm buffer, < 0 on error. + */ +SceInt32 sceMp3Decode(SceInt32 handle, SceShort16** dst); + +/** + * sceMp3GetInfoToAddStreamData + * + * @param handle - sceMp3 handle + * @param dst - Pointer to stream data buffer + * @param towrite - Space remaining in stream data buffer + * @param srcpos - Position in source stream to start reading from + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3GetInfoToAddStreamData(SceInt32 handle, SceUChar8** dst, SceInt32* towrite, SceInt32* srcpos); + +/** + * sceMp3NotifyAddStreamData + * + * @param handle - sceMp3 handle + * @param size - number of bytes added to the stream data buffer + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3NotifyAddStreamData(SceInt32 handle, SceInt32 size); + +/** + * sceMp3CheckStreamDataNeeded + * + * @param handle - sceMp3 handle + * + * @return 1 if more stream data is needed, < 0 on error. + */ +SceInt32 sceMp3CheckStreamDataNeeded(SceInt32 handle); + +/** + * sceMp3SetLoopNum + * + * @param handle - sceMp3 handle + * @param loop - Number of loops + * + * @return 0 if success, < 0 on error. + */ +SceInt32 sceMp3SetLoopNum(SceInt32 handle, SceInt32 loop); + +/** + * sceMp3GetLoopNum + * + * @param handle - sceMp3 handle + * + * @return Number of loops + */ +SceInt32 sceMp3GetLoopNum(SceInt32 handle); + +/** + * sceMp3GetSumDecodedSample + * + * @param handle - sceMp3 handle + * + * @return Number of decoded samples + */ +SceInt32 sceMp3GetSumDecodedSample(SceInt32 handle); + +/** + * sceMp3GetMaxOutputSample + * + * @param handle - sceMp3 handle + * + * @return Number of max samples to output + */ +SceInt32 sceMp3GetMaxOutputSample(SceInt32 handle); + +/** + * sceMp3GetSamplingRate + * + * @param handle - sceMp3 handle + * + * @return Sampling rate of the mp3 + */ +SceInt32 sceMp3GetSamplingRate(SceInt32 handle); + +/** + * sceMp3GetBitRate + * + * @param handle - sceMp3 handle + * + * @return Bitrate of the mp3 + */ +SceInt32 sceMp3GetBitRate(SceInt32 handle); + +/** + * sceMp3GetMp3ChannelNum + * + * @param handle - sceMp3 handle + * + * @return Number of channels of the mp3 + */ +SceInt32 sceMp3GetMp3ChannelNum(SceInt32 handle); + +/** + * sceMp3ResetPlayPosition + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3ResetPlayPosition(SceInt32 handle); + +/** + * sceMp3GetFrameNum + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3GetFrameNum(SceInt32 handle); + +/** + * sceMp3ResetPlayPositionByFrame + * + * @param handle - sceMp3 handle + * @param frame - frame + * + * @return < 0 on error + */ +SceInt32 sceMp3ResetPlayPositionByFrame(SceInt32 handle, SceUInt32 frame); + +/** + * sceMp3GetMPEGVersion + * + * @param handle - sceMp3 handle + * + * @return < 0 on error + */ +SceInt32 sceMp3GetMPEGVersion(SceInt32 handle); + +/** + * sceMp3LowLevelInit + * + * @param handle - sceMp3 handle + * @param src - Pointer to a buffer to contain raw mp3 stream data + * + * @return < 0 on error + */ +SceInt32 sceMp3LowLevelInit(SceInt32 handle, SceUChar8* src); + +/** + * sceMp3LowLevelDecode + * + * @param handle - sceMp3 handle + * @param mp3src - + * @param mp3srcused - + * @param pcmdst - + * @param pcmdstoutsz - + * + * @return < 0 on error + */ +SceInt32 sceMp3LowLevelDecode(SceInt32 handle, SceUChar8* mp3src, SceUInt32* mp3srcused, SceShort16* pcmdst, SceUInt32* pcmdstoutsz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/platform/psp/scemp3/sceMp3.S b/engine/platform/psp/scemp3/sceMp3.S new file mode 100644 index 00000000..7f5d798e --- /dev/null +++ b/engine/platform/psp/scemp3/sceMp3.S @@ -0,0 +1,29 @@ + .set noreorder + +#include "pspimport.s" + + IMPORT_START "sceMp3",0x00090011 + IMPORT_FUNC "sceMp3",0x07EC321A,sceMp3ReserveMp3Handle + IMPORT_FUNC "sceMp3",0x0DB149F4,sceMp3NotifyAddStreamData + IMPORT_FUNC "sceMp3",0x2A368661,sceMp3ResetPlayPosition + IMPORT_FUNC "sceMp3",0x354D27EA,sceMp3GetSumDecodedSample + IMPORT_FUNC "sceMp3",0x35750070,sceMp3InitResource + IMPORT_FUNC "sceMp3",0x3C2FA058,sceMp3TermResource + IMPORT_FUNC "sceMp3",0x3CEF484F,sceMp3SetLoopNum + IMPORT_FUNC "sceMp3",0x44E07129,sceMp3Init + IMPORT_FUNC "sceMp3",0x732B042A,sceMp3EndEntry + IMPORT_FUNC "sceMp3",0x7F696782,sceMp3GetMp3ChannelNum + IMPORT_FUNC "sceMp3",0x87677E40,sceMp3GetBitRate + IMPORT_FUNC "sceMp3",0x87C263D1,sceMp3GetMaxOutputSample + IMPORT_FUNC "sceMp3",0x8AB81558,sceMp3StartEntry + IMPORT_FUNC "sceMp3",0x8F450998,sceMp3GetSamplingRate + IMPORT_FUNC "sceMp3",0xA703FE0F,sceMp3GetInfoToAddStreamData + IMPORT_FUNC "sceMp3",0xD021C0FB,sceMp3Decode + IMPORT_FUNC "sceMp3",0xD0A56296,sceMp3CheckStreamDataNeeded + IMPORT_FUNC "sceMp3",0xD8F54A51,sceMp3GetLoopNum + IMPORT_FUNC "sceMp3",0xF5478233,sceMp3ReleaseMp3Handle + IMPORT_FUNC "sceMp3",0xAE6D2027,sceMp3GetMPEGVersion + IMPORT_FUNC "sceMp3",0x3548AEC8,sceMp3GetFrameNum + IMPORT_FUNC "sceMp3",0x0840E808,sceMp3ResetPlayPositionByFrame + IMPORT_FUNC "sceMp3",0x1B839B83,sceMp3LowLevelInit + IMPORT_FUNC "sceMp3",0xE3EE2C81,sceMp3LowLevelDecode diff --git a/engine/platform/psp/sys_psp.c b/engine/platform/psp/sys_psp.c index eba7a9e0..3cea58df 100644 --- a/engine/platform/psp/sys_psp.c +++ b/engine/platform/psp/sys_psp.c @@ -15,12 +15,14 @@ GNU General Public License for more details. #include "platform/platform.h" #include "platform/psp/ka/ka.h" +#include "platform/psp/scemp3/pspmp3.h" #include #include #include #include #include #include +#include #include @@ -30,6 +32,8 @@ PSP_MAIN_THREAD_ATTR( PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_VFPU ); PSP_MAIN_THREAD_STACK_SIZE_KB( 512 ); PSP_HEAP_SIZE_KB( -3 * 1024 ); /* 3 MB for prx modules */ +static qboolean psp_audiolib_init = false; + static int Platform_ExitCallback( int count, int arg, void *common ) { host.crashed = true; @@ -251,10 +255,68 @@ int Platform_UnloadModule( SceUID modid, int *sce_code ) return ( ( ( *sce_code ) < 0 ) ? -2 : 0 ); } +int Platform_InitAudioLibs( void ) +{ + int status; + + if( psp_audiolib_init ) + return -1; + + status = sceUtilityLoadModule( PSP_MODULE_AV_AVCODEC ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status ); + return status; + } + + status = sceUtilityLoadModule( PSP_MODULE_AV_MP3 ); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status ); + return status; + } + + // init mp3 resources + status = sceMp3InitResource(); + if ( status < 0 ) + { + Con_DPrintf( S_ERROR "sceMp3InitResource returned 0x%08X\n", status ); + return status; + } + + psp_audiolib_init = true; + + return 0; +} + +int Platform_ShutdownAudioLibs( void ) +{ + int status; + + if( !psp_audiolib_init ) + return -1; + + status = sceMp3TermResource(); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceMp3TermResource returned 0x%08X\n", status ); + + status = sceUtilityUnloadModule( PSP_MODULE_AV_MP3 ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status ); + + status = sceUtilityUnloadModule( PSP_MODULE_AV_AVCODEC ); + if ( status < 0 ) + Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status ); + + psp_audiolib_init = false; + + return 0; +} + void Platform_Init( void ) { - SceUID kamID; - int result; + SceUID kamID; + int result; // disable fpu exceptions (division by zero and etc...) pspSdkDisableFPUExceptions(); @@ -275,13 +337,16 @@ void Platform_Init( void ) Platform_UnloadModule( kamID, &result ); } + Platform_InitAudioLibs(); + // P5 Ram init - P5Ram_Init(); + P5Ram_Init(); } void Platform_Shutdown( void ) { P5Ram_Shutdown(); + Platform_ShutdownAudioLibs(); #if XASH_PROFILING gprof_cleanup(); #endif diff --git a/engine/wscript b/engine/wscript index 18e26531..9a8df89e 100644 --- a/engine/wscript +++ b/engine/wscript @@ -95,9 +95,11 @@ def build(bld): 'common/*.c', 'common/imagelib/*.c', 'common/soundlib/*.c', - 'common/soundlib/libmpg/*.c', 'server/*.c']) + if bld.env.DEST_OS != 'psp': + source += bld.path.ant_glob(['common/soundlib/libmpg/*.c']) + # basic build: dedicated only, no dependencies if bld.env.DEST_OS == 'win32': libs += ['USER32', 'SHELL32', 'GDI32', 'ADVAPI32', 'DBGHELP', 'PSAPI', 'WS2_32' ] From d419921ca307fdff061859edc402b7fa6d555809 Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 6 Dec 2022 11:46:31 +0300 Subject: [PATCH 82/84] engine: psp filesystem fix --- engine/common/filesystem.c | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index e09db6ef..6e5eff67 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -188,6 +188,11 @@ static qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pa static qboolean fs_caseinsensitive = true; // try to search missing files #endif +#if XASH_PSP +static fsh_handle_t *fsh_basedir = NULL; +static fsh_handle_t *fsh_gamedir = NULL; +#endif + #ifdef XASH_REDUCE_FD static file_t *fs_last_readfile; #ifndef XASH_NO_ZIP @@ -195,11 +200,6 @@ static zip_t *fs_last_zip; #endif // XASH_NO_ZIP static pack_t *fs_last_pak; -#if XASH_PSP -static fsh_handle_t *fsh_basedir = NULL; -static fsh_handle_t *fsh_gamedir = NULL; -#endif - static void FS_EnsureOpenFile( file_t *file ) { if( fs_last_readfile == file ) @@ -270,7 +270,7 @@ static void FS_BackupFileName( file_t *file, const char *path, uint options ) if( file->backup_path ) Mem_Free( (void*)file->backup_path ); if( file == fs_last_readfile ) - FS_EnsureOpenFile( NULL ); + fs_last_readfile = NULL; // FS_EnsureOpenFile( NULL ); } #if XASH_PSP else if( options == PSP_O_RDONLY ) @@ -1066,7 +1066,7 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game FS_EnsureOpenZip( search->zip ); #if XASH_PSP - if( sceIoLseek( search->zip->handle, file->offset, PSP_SEEK_SET ) == -1 ) + if( sceIoLseek( search->zip->handle, file->offset, PSP_SEEK_SET ) < 0 ) return NULL; #else if( lseek( search->zip->handle, file->offset, SEEK_SET ) == -1 ) @@ -2608,8 +2608,13 @@ static file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offse #ifndef XASH_REDUCE_FD #if XASH_PSP file->handle = sceIoOpen( syspath, PSP_O_RDONLY, 0666 ); + if( file->handle < 0 ) + { + Mem_Free( file ); + return NULL; + } - if( sceIoLseek( file->handle, offset, SEEK_SET ) == -1 ) + if( sceIoLseek( file->handle, offset, SEEK_SET ) < 0 ) { Mem_Free( file ); return NULL; @@ -3058,7 +3063,7 @@ int FS_Close( file_t *file ) if( file->handle >= 0 ) #if XASH_PSP - if( sceIoClose( file->handle ) ) + if( sceIoClose( file->handle )) #else if( close( file->handle )) #endif @@ -3084,7 +3089,11 @@ fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize ) // if necessary, seek to the exact file position we're supposed to be if( file->buff_ind != file->buff_len ) #if XASH_PSP - sceIoLseek( file->handle, file->buff_ind - file->buff_len, PSP_SEEK_CUR ); + if(file->position != file->buff_ind - file->buff_len) + { + sceIoLseek( file->handle, file->buff_ind - file->buff_len, PSP_SEEK_CUR ); + file->position = file->buff_ind - file->buff_len; + } #else lseek( file->handle, file->buff_ind - file->buff_len, SEEK_CUR ); #endif @@ -3093,7 +3102,7 @@ fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize ) #if XASH_PSP // write the buffer and update the position result = sceIoWrite( file->handle, data, (fs_offset_t)datasize ); - file->position = sceIoLseek( file->handle, 0, PSP_SEEK_CUR ); + file->position += result; //sceIoLseek( file->handle, 0, PSP_SEEK_CUR ); #else // write the buffer and update the position result = write( file->handle, data, (fs_offset_t)datasize ); @@ -3162,7 +3171,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) if( count > (fs_offset_t)buffersize ) count = (fs_offset_t)buffersize; #if XASH_PSP - sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); + if( file->offset > 0 ) + sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); nb = sceIoRead (file->handle, &((byte *)buffer)[done], count ); #else lseek( file->handle, file->offset + file->position, SEEK_SET ); @@ -3185,7 +3195,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize ) if( count == 0 ) return done; - sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); + if( file->offset > 0 ) + sceIoLseek( file->handle, file->offset + file->position, PSP_SEEK_SET ); nb = sceIoRead( file->handle, file->buff, count ); #else if( count > (fs_offset_t)sizeof( file->buff )) @@ -3384,7 +3395,9 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence ) // Purge cached data FS_Purge( file ); #if XASH_PSP - if( sceIoLseek( file->handle, file->offset + offset, PSP_SEEK_SET ) == -1 ) + if( file->position == offset && file->offset <= 0 ) + return 0; + if( sceIoLseek( file->handle, file->offset + offset, PSP_SEEK_SET ) < 0 ) return -1; #else if( lseek( file->handle, file->offset + offset, SEEK_SET ) == -1 ) From 9812a9104b54903f3f22d6537cd0ce69459a7f1f Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Wed, 7 Dec 2022 17:03:11 +0300 Subject: [PATCH 83/84] ref_gu: clipping code update --- ref_gu/gu_backend.c | 6 +- ref_gu/gu_clipping.c | 251 +++++++++++++++++-------------------------- ref_gu/gu_local.h | 10 +- ref_gu/gu_rmain.c | 2 +- ref_gu/gu_rmath.c | 100 ++++++++--------- ref_gu/gu_rsurf.c | 4 +- 6 files changed, 162 insertions(+), 211 deletions(-) diff --git a/ref_gu/gu_backend.c b/ref_gu/gu_backend.c index e6ca717e..18a1a79e 100644 --- a/ref_gu/gu_backend.c +++ b/ref_gu/gu_backend.c @@ -154,10 +154,10 @@ GL_LoadMatrix */ void GL_LoadMatrix( const matrix4x4 source ) { - float dest[16]; + ScePspFMatrix4 dest; - Matrix4x4_ToArrayFloatGL( source, dest ); - sceGumLoadMatrix( ( const ScePspFMatrix4 * ) dest ); + Matrix4x4_ToFMatrix4( source, &dest ); + sceGumLoadMatrix( &dest ); } /* diff --git a/ref_gu/gu_clipping.c b/ref_gu/gu_clipping.c index eb92c09d..84c359f6 100644 --- a/ref_gu/gu_clipping.c +++ b/ref_gu/gu_clipping.c @@ -18,25 +18,20 @@ GNU General Public License for more details. Based on clipping system from PSP Quake by Peter Mackay and Chris Swindle. */ +/* + VFPU REGS: + + M700 - current frustum + M600 - world frustum + C010 - current plane ( GU_Clip2Plane ) +*/ #include "gu_local.h" #define MAX_CLIPPED_VERTICES 32 -#define CPLANE_BOTTOM 0 -#define CPLANE_LEFT 1 -#define CPLANE_RIGHT 2 -#define CPLANE_TOP 3 -#define MAX_CPLANES 4 - -// Types. -typedef ScePspFVector4 plane_type; -typedef plane_type frustum_t[MAX_CPLANES]; - -// Transformed frustum. -static ScePspFMatrix4 projection_view_matrix __attribute__(( aligned( 16 ))); -static frustum_t projection_view_frustum __attribute__(( aligned( 16 ))); -static frustum_t clipping_frustum __attribute__(( aligned( 16 ))); +// Cache +static ScePspFMatrix4 projection_view_matrix; // The temporary working buffers. static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__(( aligned( 16 ))); @@ -46,16 +41,16 @@ static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__(( aligned( 1 GU_ClipGetFrustum ================= */ -_inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) +_inline void GU_ClipGetAndStoreFrustum( const ScePspFMatrix4 *matrix ) { __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "vzero.q C210\n" // set zero vector - "lv.q C100, 0(%4)\n" // C000 = matrix->x - "lv.q C110, 16(%4)\n" // C010 = matrix->y - "lv.q C120, 32(%4)\n" // C020 = matrix->z - "lv.q C130, 48(%4)\n" // C030 = matrix->w + "lv.q C100, 0(%0)\n" // C000 = matrix->x + "lv.q C110, 16(%0)\n" // C010 = matrix->y + "lv.q C120, 32(%0)\n" // C020 = matrix->z + "lv.q C130, 48(%0)\n" // C030 = matrix->w "vadd.q C000, R103, R101\n" // C000 = R103 + R101 ( BOTTOM ) "vadd.q C010, R103, R100\n" // C010 = R103 + R100 ( LEFT ) "vsub.q C020, R103, R100\n" // C020 = R103 - R100 ( RIGHT ) @@ -64,23 +59,15 @@ _inline void GU_ClipGetFrustum(const ScePspFMatrix4 *matrix, frustum_t* frustum) "vdot.q S201, C010, C010\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( LEFT ) "vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT ) "vdot.q S203, C030, C030\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( TOP ) - "vcmp.q EZ, C200\n" // CC[0] = ( C200 == 0.0f ) + "vcmp.q EZ, C200\n" // CC[*] = ( C200 == 0.0f ) "vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 ) - "vcmovt.q C200, C210, 0\n" // if ( CC[*] ) C200 = C210 - "vscl.q C000, C000, S200\n" // C000 = C000 * S200 ( BOTTOM ) - "vscl.q C010, C010, S201\n" // C010 = C010 * S201 ( LEFT ) - "vscl.q C020, C020, S202\n" // C020 = C020 * S202 ( RIGHT ) - "vscl.q C030, C030, S203\n" // C030 = C030 * S203 ( TOP ) - "sv.q C000, %0\n" // Store plane from register - "sv.q C010, %1\n" // Store plane from register - "sv.q C020, %2\n" // Store plane from register - "sv.q C030, %3\n" // Store plane from register + "vcmovt.q C200, C210, 6\n" // if ( CC[*] ) C200 = C210 + "vscl.q C700, C000, S200\n" // C700 = C000 * S200 ( BOTTOM ) + "vscl.q C710, C010, S201\n" // C710 = C010 * S201 ( LEFT ) + "vscl.q C720, C020, S202\n" // C720 = C020 * S202 ( RIGHT ) + "vscl.q C730, C030, S203\n" // C730 = C030 * S203 ( TOP ) ".set pop\n" // Restore assembler option - : "=m"( ( *frustum )[CPLANE_BOTTOM] ), - "=m"( ( *frustum )[CPLANE_LEFT] ), - "=m"( ( *frustum )[CPLANE_RIGHT] ), - "=m"( ( *frustum )[CPLANE_TOP] ) - : "r"( matrix ) /* addr */ + :: "r"( matrix ) ); } @@ -91,117 +78,63 @@ GU_ClipBeginFrame Calculate the clipping frustum for static objects ================= */ -void GU_ClipBeginFrame( void ) +void GU_ClipSetWorldFrustum( const matrix4x4 in ) { - // Get the projection matrix. - sceGumMatrixMode( GU_PROJECTION ); - ScePspFMatrix4 proj; - sceGumStoreMatrix( &proj ); - - // Get the view matrix. - sceGumMatrixMode( GU_VIEW ); - ScePspFMatrix4 view; - sceGumStoreMatrix( &view ); - - // Restore matrix mode. - sceGumMatrixMode( GU_MODEL ); - - // Combine the two matrices (multiply projection by view). - gumMultMatrix( &projection_view_matrix, &proj, &view ); + // Get matrix. + Matrix4x4_ToFMatrix4( in, &projection_view_matrix ); // Calculate and cache the clipping frustum. - GU_ClipGetFrustum( &projection_view_matrix, &projection_view_frustum ); + GU_ClipGetAndStoreFrustum( &projection_view_matrix ); + // Save the clipping frustum. __asm__ volatile( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C700, %4\n" // Load plane into register - "lv.q C710, %5\n" // Load plane into register - "lv.q C720, %6\n" // Load plane into register - "lv.q C730, %7\n" // Load plane into register - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register + "vmmov.q M600, M700\n" // Save frustum ".set pop\n" // Restore assembler option - : "=m"( clipping_frustum[CPLANE_BOTTOM] ), - "=m"( clipping_frustum[CPLANE_LEFT] ), - "=m"( clipping_frustum[CPLANE_RIGHT] ), - "=m"( clipping_frustum[CPLANE_TOP] ) - : "m"( projection_view_frustum[CPLANE_BOTTOM] ), - "m"( projection_view_frustum[CPLANE_LEFT] ), - "m"( projection_view_frustum[CPLANE_RIGHT] ), - "m"( projection_view_frustum[CPLANE_TOP] ) ); } /* ================= -GU_ClipBeginBrush - -Calculate the clipping frustum for dynamic objects -================= -*/ -void GU_ClipBeginBrush( void ) -{ - // Get the model matrix. - ScePspFMatrix4 model_matrix; - sceGumStoreMatrix( &model_matrix ); - - // Combine the matrices (multiply projection-view by model). - ScePspFMatrix4 projection_view_model_matrix; - gumMultMatrix( &projection_view_model_matrix, &projection_view_matrix, &model_matrix ); - - // Calculate the clipping frustum. - GU_ClipGetFrustum( &projection_view_model_matrix, &clipping_frustum ); - - __asm__ volatile( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C700, %0\n" // Load plane into register - "lv.q C710, %1\n" // Load plane into register - "lv.q C720, %2\n" // Load plane into register - "lv.q C730, %3\n" // Load plane into register - ".set pop\n" // Restore assembler option - :: "m"( clipping_frustum[CPLANE_BOTTOM] ), - "m"( clipping_frustum[CPLANE_LEFT] ), - "m"( clipping_frustum[CPLANE_RIGHT] ), - "m"( clipping_frustum[CPLANE_TOP] ) - ); -} - -/* -================= -GU_ClipEndBrush +GU_ClipRestoreWorldFrustum Restore the clipping frustum ================= */ -void GU_ClipEndBrush( void ) +void GU_ClipRestoreWorldFrustum( void ) { + // Restore the clipping frustum. __asm__ volatile( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "lv.q C700, %4\n" // Load plane into register - "lv.q C710, %5\n" // Load plane into register - "lv.q C720, %6\n" // Load plane into register - "lv.q C730, %7\n" // Load plane into register - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register + "vmmov.q M700, M600\n" // Restore frustum ".set pop\n" // Restore assembler option - : "=m"( clipping_frustum[CPLANE_BOTTOM] ), - "=m"( clipping_frustum[CPLANE_LEFT] ), - "=m"( clipping_frustum[CPLANE_RIGHT] ), - "=m"( clipping_frustum[CPLANE_TOP] ) - : "m"( projection_view_frustum[CPLANE_BOTTOM] ), - "m"( projection_view_frustum[CPLANE_LEFT] ), - "m"( projection_view_frustum[CPLANE_RIGHT] ), - "m"( projection_view_frustum[CPLANE_TOP] ) ); } +/* +================= +GU_ClipSetModelFrustum + +Calculate the clipping frustum for dynamic objects +================= +*/ +void GU_ClipSetModelFrustum( const matrix4x4 in ) +{ + ScePspFMatrix4 model_matrix; + ScePspFMatrix4 projection_view_model_matrix; + + // Get matrix. + Matrix4x4_ToFMatrix4( in, &model_matrix ); + + // Combine the matrices (multiply projection-view by model). + gumMultMatrix( &projection_view_model_matrix, &projection_view_matrix, &model_matrix ); + + // Calculate and cache the clipping frustum. + GU_ClipGetAndStoreFrustum( &projection_view_model_matrix ); +} + /* ================= GU_ClipLoadFrustum @@ -215,21 +148,13 @@ void GU_ClipLoadFrustum( const mplane_t *plane ) __asm__ volatile( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "ulv.q C700, %4\n" // Load plane into register - "ulv.q C710, %5\n" // Load plane into register - "ulv.q C720, %6\n" // Load plane into register - "ulv.q C730, %7\n" // Load plane into register + "ulv.q C700, %0\n" // Load plane into register + "ulv.q C710, %1\n" // Load plane into register + "ulv.q C720, %2\n" // Load plane into register + "ulv.q C730, %3\n" // Load plane into register "vneg.q R703, R703\n" // R703 = -R703 = -dist - "sv.q C700, %0\n" // Store plane from register - "sv.q C710, %1\n" // Store plane from register - "sv.q C720, %2\n" // Store plane from register - "sv.q C730, %3\n" // Store plane from register ".set pop\n" // Restore assembler option - : "=m"( clipping_frustum[CPLANE_BOTTOM] ), - "=m"( clipping_frustum[CPLANE_LEFT] ), - "=m"( clipping_frustum[CPLANE_RIGHT] ), - "=m"( clipping_frustum[CPLANE_TOP] ) - : "m"( plane[FRUSTUM_BOTTOM] ), + :: "m"( plane[FRUSTUM_BOTTOM] ), "m"( plane[FRUSTUM_LEFT] ), "m"( plane[FRUSTUM_RIGHT] ), "m"( plane[FRUSTUM_TOP] ) @@ -253,13 +178,13 @@ int GU_ClipIsRequired( gu_vert_t* uv, int uvc ) __asm__ ( ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering - "vzero.q C600\n" // C600 = [0.0f, 0.0f, 0.0f. 0.0f] + "vzero.q C000\n" // C000 = [0.0f, 0.0f, 0.0f. 0.0f] "0:\n" // loop - "lv.s S610, 8(%1)\n" // S610 = v[i].xyz[0] - "lv.s S611, 12(%1)\n" // S611 = v[i].xyz[1] - "lv.s S612, 16(%1)\n" // S612 = v[i].xyz[2] - "vhtfm4.q C620, M700, C610\n" // C620 = frustrum * v[i].xyz - "vcmp.q LT, C620, C600\n" // S620 < 0.0f || S621 < 0.0f || S622 < 0.0f || S623 < 0.0f + "lv.s S010, 8(%1)\n" // S010 = v[i].xyz[0] + "lv.s S011, 12(%1)\n" // S011 = v[i].xyz[1] + "lv.s S012, 16(%1)\n" // S012 = v[i].xyz[2] + "vhtfm4.q C020, M700, C010\n" // C020 = frustrum * v[i].xyz + "vcmp.q LT, C020, C000\n" // S020 < 0.0f || S021 < 0.0f || S022 < 0.0f || S023 < 0.0f "bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit "nop\n" // ( delay slot ) "bne %1, %2, 0b\n" // if ( $10 != $8 ) jump to loop @@ -282,7 +207,7 @@ GU_Clip2Plane Clips a polygon against a plane. ================= */ -_inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, int uvc, gu_vert_t *cv, int *cvc ) +_inline void GU_Clip2Plane( gu_vert_t *uv, int uvc, gu_vert_t *cv, int *cvc ) { gu_vert_t *uv_end = uv + ( uvc - 1 ); gu_vert_t *cv_start = cv; @@ -291,7 +216,6 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, int uvc, gu_vert_t ".set push\n" // save assembler option ".set noreorder\n" // suppress reordering "vzero.q C000\n" // set zero vector - "lv.q C010, 0(%3)\n" // plane "lv.s S200, 8(%2)\n" // Load vertex P XYZ(4b) X into register "lv.s S201, 12(%2)\n" // Load vertex P XYZ(4b) Y into register "lv.s S202, 16(%2)\n" // Load vertex P XYZ(4b) Z into register @@ -313,7 +237,7 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, int uvc, gu_vert_t "sv.s S200, 8(%0)\n" // cv->xyz[0] = C030 X "sv.s S201, 12(%0)\n" // cv->xyz[1] = C031 Y "sv.s S202, 16(%0)\n" // cv->xyz[2] = C032 Z - "addiu %0, %0, 20\n" + "addiu %0, %0, %3\n" // cv + sizeof(gu_vert_t) "1:\n" "vmul.s S020, S232, S212\n" // (dS * dP) "vcmp.s LT, S020, S000\n" // if (dS * dP < 0) @@ -341,15 +265,15 @@ _inline void GU_Clip2Plane( plane_type *plane, gu_vert_t *uv, int uvc, gu_vert_t "sv.s S200, 8(%0)\n" // cv->xyz[0] = S200 X "sv.s S201, 12(%0)\n" // cv->xyz[1] = S201 Y "sv.s S202, 16(%0)\n" // cv->xyz[2] = S202 Z - "addiu %0, %0, %4\n" // cv + sizeof(gu_vert_t) + "addiu %0, %0, %3\n" // cv + sizeof(gu_vert_t) "2:\n" "vmov.t C200, C220\n" // P = S XYZ "vmov.t C210, C230\n" // P = S UV and dS "bne %1, %2, 0b\n" // if (uv != uv_end) goto 0: - "addiu %1, %1, %4\n" // uv + sizeof(gu_vert_t) ( delay slot ) + "addiu %1, %1, %3\n" // uv + sizeof(gu_vert_t) ( delay slot ) ".set pop\n" // suppress reordering : "+r"( cv ), "+r"( uv ) - : "r"( uv_end ), "r"( plane ), + : "r"( uv_end ), "n"( sizeof( gu_vert_t )) : "memory" ) ; @@ -373,14 +297,41 @@ void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc ) vc = uvc; *cvc = 0; - GU_Clip2Plane( &clipping_frustum[CPLANE_BOTTOM], uv, vc, work_buffer[0], &vc ); + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "vmov.q C010, C700\n" // CPLANE_BOTTOM + ".set pop\n" // suppress reordering + ); + GU_Clip2Plane( uv, vc, work_buffer[0], &vc ); if ( !vc ) return; - GU_Clip2Plane( &clipping_frustum[CPLANE_LEFT], work_buffer[0], vc, work_buffer[1], &vc ); + + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "vmov.q C010, C710\n" // CPLANE_LEFT + ".set pop\n" // suppress reordering + ); + GU_Clip2Plane( work_buffer[0], vc, work_buffer[1], &vc ); if ( !vc ) return; - GU_Clip2Plane( &clipping_frustum[CPLANE_RIGHT], work_buffer[1], vc, work_buffer[0], &vc ); + + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "vmov.q C010, C720\n" // CPLANE_RIGHT + ".set pop\n" // suppress reordering + ); + GU_Clip2Plane( work_buffer[1], vc, work_buffer[0], &vc ); if ( !vc ) return; + + __asm__ volatile( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "vmov.q C010, C730\n" // CPLANE_TOP + ".set pop\n" // suppress reordering + ); *cv = extGuBeginPacket( NULL ); // uncached - GU_Clip2Plane( &clipping_frustum[CPLANE_TOP], work_buffer[0], vc, *cv, cvc ); + GU_Clip2Plane( work_buffer[0], vc, *cv, cvc ); if (!( *cvc )) return; extGuEndPacket(( void * )( *cv + *cvc )); -} \ No newline at end of file +} diff --git a/ref_gu/gu_local.h b/ref_gu/gu_local.h index b9ed4365..c193d935 100644 --- a/ref_gu/gu_local.h +++ b/ref_gu/gu_local.h @@ -497,8 +497,8 @@ int CL_FxBlend( cl_entity_t *e ); // // gu_rmath.c // -void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] ); -void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] ); +void Matrix4x4_ToFMatrix4( const matrix4x4 in, ScePspFMatrix4 *out ); +void Matrix4x4_FromFMatrix4( matrix4x4 out, ScePspFMatrix4 *in ); void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ); void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z ); void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z ); @@ -690,9 +690,9 @@ int getTriAPI( int version, triangleapi_t *api ); // gu_clipping.c // #define CLIPPING_DEBUGGING 0 -void GU_ClipBeginFrame( void ); -void GU_ClipBeginBrush( void ); -void GU_ClipEndBrush( void ); +void GU_ClipSetWorldFrustum( const matrix4x4 in ); +void GU_ClipRestoreWorldFrustum( void ); +void GU_ClipSetModelFrustum( const matrix4x4 in ); void GU_ClipLoadFrustum( const mplane_t *plane ); // Experimental int GU_ClipIsRequired( gu_vert_t* uv, int uvc ); void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc ); diff --git a/ref_gu/gu_rmain.c b/ref_gu/gu_rmain.c index 4baf4f38..ea74802f 100644 --- a/ref_gu/gu_rmain.c +++ b/ref_gu/gu_rmain.c @@ -625,7 +625,7 @@ void R_SetupGL( qboolean set_gl_state ) sceGuDisable( GU_ALPHA_TEST ); sceGuColor( GUCOLOR4F( 1.0f, 1.0f, 1.0f, 1.0f ) ); - GU_ClipBeginFrame(); + GU_ClipSetWorldFrustum( RI.worldviewProjectionMatrix ); } diff --git a/ref_gu/gu_rmath.c b/ref_gu/gu_rmath.c index 78b91e3e..60c530a8 100644 --- a/ref_gu/gu_rmath.c +++ b/ref_gu/gu_rmath.c @@ -27,22 +27,22 @@ void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ) { #if 1 __asm__ ( - ".set push\n" // save assembler option - ".set noreorder\n" // suppress reordering - "lv.q C100, 0 + %1\n" // C100 = in1[0] - "lv.q C110, 16 + %1\n" // C110 = in1[1] - "lv.q C120, 32 + %1\n" // C120 = in1[2] - "lv.q C130, 48 + %1\n" // C130 = in1[3] - "lv.q C200, 0 + %2\n" // C200 = in2[0] - "lv.q C210, 16 + %2\n" // C210 = in2[1] - "lv.q C220, 32 + %2\n" // C220 = in2[2] - "lv.q C230, 48 + %2\n" // C230 = in2[3] - "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 - "sv.q C000, 0 + %0\n" // out[0] = C000 - "sv.q C010, 16 + %0\n" // out[1] = C010 - "sv.q C020, 32 + %0\n" // out[2] = C020 - "sv.q C030, 48 + %0\n" // out[3] = C030 - ".set pop\n" // restore assembler option + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C100, 0 + %1\n" // C100 = in1[0] + "lv.q C110, 16 + %1\n" // C110 = in1[1] + "lv.q C120, 32 + %1\n" // C120 = in1[2] + "lv.q C130, 48 + %1\n" // C130 = in1[3] + "lv.q C200, 0 + %2\n" // C200 = in2[0] + "lv.q C210, 16 + %2\n" // C210 = in2[1] + "lv.q C220, 32 + %2\n" // C220 = in2[2] + "lv.q C230, 48 + %2\n" // C230 = in2[3] + "vmmul.q E000, E100, E200\n" // E000 = E100 * E200 + "sv.q C000, 0 + %0\n" // out[0] = C000 + "sv.q C010, 16 + %0\n" // out[1] = C010 + "sv.q C020, 32 + %0\n" // out[2] = C020 + "sv.q C030, 48 + %0\n" // out[3] = C030 + ".set pop\n" // restore assembler option : "=m"( *out ) : "m"( *in1 ), "m"( *in2 ) ); @@ -122,44 +122,44 @@ void Matrix4x4_CreateModelview( matrix4x4 out ) out[1][2] = 1.0f; } -void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] ) +void Matrix4x4_ToFMatrix4( const matrix4x4 in, ScePspFMatrix4 *out ) { - out[ 0] = in[0][0]; - out[ 1] = in[1][0]; - out[ 2] = in[2][0]; - out[ 3] = in[3][0]; - out[ 4] = in[0][1]; - out[ 5] = in[1][1]; - out[ 6] = in[2][1]; - out[ 7] = in[3][1]; - out[ 8] = in[0][2]; - out[ 9] = in[1][2]; - out[10] = in[2][2]; - out[11] = in[3][2]; - out[12] = in[0][3]; - out[13] = in[1][3]; - out[14] = in[2][3]; - out[15] = in[3][3]; + // transpose matrix + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C000, 0 + %1\n" // C000 = in->x + "lv.q C010, 16 + %1\n" // C010 = in->y + "lv.q C020, 32 + %1\n" // C020 = in->z + "lv.q C030, 48 + %1\n" // C030 = in->w + "sv.q R000, 0 + %0\n" // out->x = R000 + "sv.q R001, 16 + %0\n" // out->y = R010 + "sv.q R002, 32 + %0\n" // out->z = R020 + "sv.q R003, 48 + %0\n" // out->w = R030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ) + ); } -void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] ) +void Matrix4x4_FromFMatrix4( matrix4x4 out, ScePspFMatrix4 *in ) { - out[0][0] = in[0]; - out[1][0] = in[1]; - out[2][0] = in[2]; - out[3][0] = in[3]; - out[0][1] = in[4]; - out[1][1] = in[5]; - out[2][1] = in[6]; - out[3][1] = in[7]; - out[0][2] = in[8]; - out[1][2] = in[9]; - out[2][2] = in[10]; - out[3][2] = in[11]; - out[0][3] = in[12]; - out[1][3] = in[13]; - out[2][3] = in[14]; - out[3][3] = in[15]; + // transpose matrix + __asm__ ( + ".set push\n" // save assembler option + ".set noreorder\n" // suppress reordering + "lv.q C000, 0 + %1\n" // C000 = in->x + "lv.q C010, 16 + %1\n" // C010 = in->y + "lv.q C020, 32 + %1\n" // C020 = in->z + "lv.q C030, 48 + %1\n" // C030 = in->w + "sv.q R000, 0 + %0\n" // out->x = R000 + "sv.q R001, 16 + %0\n" // out->y = R010 + "sv.q R002, 32 + %0\n" // out->z = R020 + "sv.q R003, 48 + %0\n" // out->w = R030 + ".set pop\n" // restore assembler option + : "=m"( *out ) + : "m"( *in ) + ); } void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z ) diff --git a/ref_gu/gu_rsurf.c b/ref_gu/gu_rsurf.c index 05266fed..1c53814c 100644 --- a/ref_gu/gu_rsurf.c +++ b/ref_gu/gu_rsurf.c @@ -1663,7 +1663,7 @@ void R_DrawBrushModel( cl_entity_t *e ) psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; - GU_ClipBeginBrush(); + GU_ClipSetModelFrustum( RI.objectMatrix ); // sorting is not required, +Z_Realloc in Mod_LoadSubmodels (mod_bmodel.c) for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) @@ -1697,7 +1697,6 @@ void R_DrawBrushModel( cl_entity_t *e ) R_BlendLightmaps(); R_RenderFullbrights(); R_RenderDetails(); - GU_ClipEndBrush(); // restore fog here if( e->curstate.rendermode == kRenderTransAdd ) @@ -1711,6 +1710,7 @@ void R_DrawBrushModel( cl_entity_t *e ) sceGuDepthMask( GU_FALSE ); R_DrawModelHull(); // draw before restore + GU_ClipRestoreWorldFrustum(); R_LoadIdentity(); // restore worldmatrix } From cae351f7b1b921020aed1422230d95f38be9f6cf Mon Sep 17 00:00:00 2001 From: Crow-bar Date: Tue, 20 Dec 2022 11:10:04 +0300 Subject: [PATCH 84/84] engine: psp math optimization, QuaternionSlerp, BoundsIntersect, Mod_SetStudioHullPlane --- engine/common/mod_studio.c | 3 ++ public/xash3d_mathlib.c | 5 +- public/xash3d_mathlib.h | 6 +++ public/xash3d_mathlib_asm.S | 92 +++++++++++++++++++++++++++++++++++-- ref_gu/gu_studio.c | 2 +- 5 files changed, 103 insertions(+), 5 deletions(-) diff --git a/engine/common/mod_studio.c b/engine/common/mod_studio.c index a20f4fa6..98bce2fe 100644 --- a/engine/common/mod_studio.c +++ b/engine/common/mod_studio.c @@ -204,6 +204,9 @@ mstudiocache_t *Mod_CheckStudioCache( model_t *model, float frame, int sequence, SetStudioHullPlane ==================== */ +#if XASH_PSP +static inline +#endif void Mod_SetStudioHullPlane( int planenum, int bone, int axis, float offset, const vec3_t size ) { mplane_t *pl = &studio_planes[planenum]; diff --git a/public/xash3d_mathlib.c b/public/xash3d_mathlib.c index 05de993d..8980ec0c 100644 --- a/public/xash3d_mathlib.c +++ b/public/xash3d_mathlib.c @@ -600,6 +600,7 @@ void ExpandBounds( vec3_t mins, vec3_t maxs, float offset ) BoundsIntersect ================= */ +#if !XASH_PSP qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2 ) { if( mins1[0] > maxs2[0] || mins1[1] > maxs2[1] || mins1[2] > maxs2[2] ) @@ -608,6 +609,7 @@ qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t m return false; return true; } +#endif /* ================= @@ -757,6 +759,7 @@ make sure quaternions are within 180 degrees of one another, if not, reverse q ==================== */ +#if !XASH_PSP void QuaternionAlign( const vec4_t p, const vec4_t q, vec4_t qt ) { // decide if one of the quaternions is backwards @@ -845,9 +848,9 @@ void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt ) // 0.0 returns p, 1.0 return q. // decide if one of the quaternions is backwards QuaternionAlign( p, q, q2 ); - QuaternionSlerpNoAlign( p, q2, t, qt ); } +#endif /* ==================== diff --git a/public/xash3d_mathlib.h b/public/xash3d_mathlib.h index 34a1e16b..e199c5a3 100644 --- a/public/xash3d_mathlib.h +++ b/public/xash3d_mathlib.h @@ -153,7 +153,13 @@ void PlaneIntersect( const struct mplane_s *plane, const vec3_t p0, const vec3_t void ClearBounds( vec3_t mins, vec3_t maxs ); void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ); +#if XASH_PSP +#define BoundsIntersect( mins1, maxs1, mins2, maxs2 ) \ + (( mins1[0] > maxs2[0] || mins1[1] > maxs2[1] || mins1[2] > maxs2[2] ) ? false : \ + ( maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2] ) ? false : true ) +#else qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2 ); +#endif qboolean BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t origin, float radius ); qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared, const vec3_t vLinePt, const vec3_t vLineDir ); float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ); diff --git a/public/xash3d_mathlib_asm.S b/public/xash3d_mathlib_asm.S index 901e39e6..833d03e7 100644 --- a/public/xash3d_mathlib_asm.S +++ b/public/xash3d_mathlib_asm.S @@ -20,15 +20,101 @@ GNU General Public License for more details. .text .align 4 + .global QuaternionSlerp .global BoxOnPlaneSide +// void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt ); + .ent QuaternionSlerp +QuaternionSlerp: + ############################ + # a0 - IN *p # + # a1 - IN *q # + # f12 - IN t # + # a2 - IN *qt # + ############################ + mfc1 $t0, $f12 + mtv $t0, S031 // S031 = sclq = t + li $t0, 0x358637bd // t0 = EPSILON = 0.000001f + mtv $t0, S033 // S002 = t0 = EPSILON + lv.q C010, 0($a0) // C010 = p + lv.q C020, 0($a1) // C020 = q + + // QuaternionAlign + vsub.q C100, C010, C020 // C100 = p[*] - q[*] + vadd.q C110, C010, C020 // C110 = p[*] + q[*] + vdot.q S000, C100, C100 // S000 = a += (p[*] - q[*]) * (p[*] - q[*]) + vdot.q S001, C110, C110 // S001 = b += (p[*] + q[*]) * (p[*] + q[*]) + vcmp.s GT, S000, S001 // CC[0] = a > b + vcmovt.q C020, C020[-X,-Y,-Z,-W], 0 // if CC[0] q = -q + // *** + + // QuaternionSlerpNoAlign + vdot.q S000, C010, C020 // S000 = cosom += p[*] * q[*] + vadd.s S001, S000[1], S000 // S002 = 1.0f + cosom + vcmp.s LE, S001, S033 // CC[0] = ( 1.0f + cosom ) <= 0.000001f + bvt 0, Lqs2 // if CC[0] goto Lqs2 + vocp.s S030, S031 // S030 = sclp = 1.0f - t (delay slot) + vsub.s S001, S000[1], S000 // S002 = 1.0f - cosom + vcmp.s LE, S001, S033 // CC[0] = ( 1.0f - cosom ) <= 0.000001f + bvt 0, Lqs1 + nop + + // acos + vcst.s S001, VFPU_SQRT1_2 // S001 = VFPU_SQRT1_2 = 1 / sqrt(2) + vcmp.s LT, S000[|x|], S001 // CC[0] = abs(cosom) < (1 / sqrt(2)) + vasin.s S032, S000[|x|] // S032 = asin(abs(cosom)) + bvtl 0, Lqs0 // if CC[0] goto Lqs0 + vocp.s S032, S032 // S032 = 1 - S032 = acos(abs(cosom)) = omega (bvtl delay slot) + vmul.s S001, S000, S000 // S001 = cosom * cosom + vocp.s S001[0:1], S001 // S001 = 1 - S001[0:1] + vsqrt.s S001, S001 // S001 = sqrt(S001) + vasin.s S032, S001 // S032 = asin(S001) = acos(abs(cosom)) = omega + // *** +Lqs0: + vscl.p C030, C030, S032 // S030 = S030 * S032 = sclp * omega + // S031 = S031 * S032 = sclq * omega + vsin.t C030, C030 // S030 = sin(S030) = sin(sclp * omega) = sclp + // S031 = sin(S031) = sin(sclq * omega) = sclq + // S032 = sin(S032) = sin(omega) + vrcp.s S032, S032 // S032 = 1.0f / S032 = 1 / sin(omega) = sinom + vscl.p C030, C030, S032 // S030 = S030 * S032 = sin(sclp * omega) / sinom + // S031 = S031 * S032 = sin(sclq * omega) / sinom +Lqs1: + vscl.q C010, C010, S030 // C010 = p[*4] * sclp + vscl.q C020, C020, S031 // C020 = qt[*4] * sclq + b LqsEnd // goto LqsEnd + vadd.q C000, C010, C020 // S000 = qt[0] = sclp * p[0] + sclq * qt[0] (delay slot) + // S001 = qt[1] = sclp * p[1] + sclq * qt[1] + // S002 = qt[2] = sclp * p[2] + sclq * qt[2] + // S003 = qt[3] = sclp * p[3] + sclq * qt[3] +Lqs2: + vmov.q C000, C020[-Y,X,-W,Z] // S000 = qt[0] = -q[1]; + // S001 = qt[1] = q[0]; + // S002 = qt[2] = -q[3]; + // S003 = qt[3] = q[2]; + vsin.p C030, C030 // S030 = sclp = sin(( 1.0f - t ) * ( 0.5f * M_PI_F )) + // S031 = sclq = sin( t * ( 0.5f * M_PI_F )) + vscl.t C010, C010, S030 // C000 = p[*3] * sclp + vscl.t C020, C000, S031 // C030 = qt[*3] * sclq + vadd.t C000, C010, C020 // S000 = qt[0] = sclp * p[0] + sclq * qt[0] + // S001 = qt[1] = sclp * p[1] + sclq * qt[1] + // S002 = qt[2] = sclp * p[2] + sclq * qt[2] + // S003 = qt[3] +LqsEnd: + sv.q C000, 0($a2) + jr $ra + .end QuaternionSlerp + + + + // int BoxOnPlaneSide( vec3_t emins, vec3_t emaxs, mplane_t *p ); .ent BoxOnPlaneSide BoxOnPlaneSide: ############################ - # a0 - IN emins # - # a1 - IN emaxs # - # a2 - IN p # + # a0 - IN *emins # + # a1 - IN *emaxs # + # a2 - IN *p # # v0 - OUT sides # ############################ lbu $v0, 17($a2) // p->signbits diff --git a/ref_gu/gu_studio.c b/ref_gu/gu_studio.c index 1b8f6eaf..3c79d526 100644 --- a/ref_gu/gu_studio.c +++ b/ref_gu/gu_studio.c @@ -2427,7 +2427,7 @@ static void R_StudioDrawPoints( void ) { mstudioboneweight_t *pvertweight = (mstudioboneweight_t *)((byte *)m_pStudioHeader + m_pSubModel->blendvertinfoindex); mstudioboneweight_t *pnormweight = (mstudioboneweight_t *)((byte *)m_pStudioHeader + m_pSubModel->blendnorminfoindex); - matrix3x4 skinMat __attribute__( (aligned( 16 ) ) ); + matrix3x4 skinMat; for( i = 0; i < m_pSubModel->numverts; i++ ) {