PSP Port initial

This commit is contained in:
Sergey Galushko
2022-03-30 00:39:04 +03:00
parent e6b9b67825
commit 64020b2902
91 changed files with 26988 additions and 177 deletions

2
.gitmodules vendored
View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -26,7 +26,9 @@ GNU General Public License for more details.
#include <sys/syslimits.h>
#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 <unistd.h>
#include <pspiofilemgr.h>
#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))

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 ||

View File

@@ -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)" );
}

View File

@@ -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,

View File

@@ -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 );

View File

@@ -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

View File

@@ -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";

View File

@@ -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 );

View File

@@ -23,6 +23,10 @@ GNU General Public License for more details.
#elif XASH_DOS4GW
#include <direct.h>
#include <errno.h>
#elif XASH_PSP
#include <pspiofilemgr.h>
#include <dirent.h>
#include <errno.h>
#else
#include <dirent.h>
#include <errno.h>
@@ -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;

View File

@@ -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" );

View File

@@ -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
/*
=============================================================================

View File

@@ -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

View File

@@ -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

View File

@@ -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 );

View File

@@ -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 );

View File

@@ -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;

View File

@@ -93,6 +93,7 @@ static int ioctl_stub( int d, unsigned long r, ... )
#define SOCKET int
typedef int WSAsize_t;
#else
#include <errno.h> //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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -32,6 +32,10 @@ GNU General Public License for more details.
#endif
#endif
#if XASH_PSP
#include <pspkernel.h>
#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
}
/*

View File

@@ -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

View File

@@ -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 );

View File

@@ -0,0 +1,259 @@
/*
From the vitaXash3D by fgsfdsfgs.
*/
#include "common.h"
#include "dll_psp.h"
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspuser.h>
#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;
}

View File

@@ -0,0 +1,38 @@
#ifndef DLL_PSP_H
#define DLL_PSP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#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

View File

@@ -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 <pspctrl.h>
#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 */

View File

@@ -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

View File

252
engine/platform/psp/s_psp.c Normal file
View File

@@ -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 <pspaudiolib.h>
#include <pspkernel.h>
#include <psputility.h>
#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

View File

@@ -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 <pspsdk.h>
#include <pspkernel.h>
#include <psppower.h>
#include <psprtc.h>
#include <pspprof.h>
#include <pspctrl.h>
#include <ctype.h>
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( &current_ticks );
return ( current_ticks - start_ticks ) * 0.000001;
*/
u64 current_ticks;
sceRtcGetCurrentTick( &current_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
}

View File

@@ -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 <pspkernel.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspgum.h>
#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

View File

@@ -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' <raphael@fx-world.org>
* http://wordpress.fx-world.org
*/
#include "vram.h"
#include <stdio.h>
// 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)
{
#ifdef _DEBUG
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
#endif
return(0);
}
#ifdef _DEBUG
printf("allocating %i bytes, in %i blocks\n", size, bsize);
#endif
// Find smallest block that still fits the requested size
int bestblock = -1;
int bestblock_prev = 0;
int bestblock_size = __MEM_BLOCKS+1;
while (i<__MEM_BLOCKS)
{
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>=bsize)
{
if (csize<bestblock_size)
{
bestblock = i;
bestblock_prev = j;
bestblock_size = csize;
}
if (csize==bsize)
break;
}
j = i;
i += csize;
}
if (bestblock<0)
{
#ifdef _DEBUG
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
#endif
return(0);
}
i = bestblock;
j = bestblock_prev;
int csize = bestblock_size;
__mem_blocks[i] = __BLOCK_MAKE(bsize,j,0,1);
int next = i+bsize;
if (csize>bsize && 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<block)
{
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[prev])==3)
{
__BLOCK_ADD_SIZE(__mem_blocks[prev], csize);
__BLOCK_SET_BLOCK(__mem_blocks[block],0); // mark current block as inter block
if (next<__MEM_BLOCKS)
__BLOCK_SET_PREV(__mem_blocks[next], prev);
block = prev;
}
}
// Merge with next block if possible
if (next<__MEM_BLOCKS)
{
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[next])==3)
{
__BLOCK_ADD_SIZE(__mem_blocks[block], __BLOCK_GET_SIZE(__mem_blocks[next]));
__BLOCK_SET_BLOCK(__mem_blocks[next],0); // mark next block as inter block
int nextnext = next + __BLOCK_GET_SIZE(__mem_blocks[next]);
if (nextnext<__MEM_BLOCKS)
__BLOCK_SET_PREV(__mem_blocks[nextnext], block);
}
}
// Update if a new largest block emerged
if (__largest_block<__BLOCK_GET_SIZE(__mem_blocks[block]))
{
__largest_block = __BLOCK_GET_SIZE(__mem_blocks[block]);
__largest_update = 0; // No update necessary any more, because update only necessary when largest has shrinked at most
}
}
size_t vmemavail( void )
{
return __mem_free * __BLOCK_SIZE;
}
size_t vlargestblock( void )
{
if (__largest_update) __find_largest_block();
return __largest_block * __BLOCK_SIZE;
}

View File

@@ -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' <raphael@fx-world.org>
* http://wordpress.fx-world.org
*/
#ifndef vram_h__
#define vram_h__
#include <stddef.h>
#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__

View File

@@ -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

View File

@@ -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
{

View File

@@ -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 )
{

View File

@@ -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,

View File

@@ -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, "<missing GameHeader>", 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 );

View File

@@ -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

View File

@@ -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([

2
mainui

Submodule mainui updated: 6e9135516a...d3c61e2e14

View File

@@ -70,6 +70,8 @@ For more information, please refer to <http://unlicense.org/>
#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 <http://unlicense.org/>
#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

View File

@@ -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] ))
{

View File

@@ -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
}

2
ref_gu/exports.txt Normal file
View File

@@ -0,0 +1,2 @@
GetRefAPI
GetRefHumanReadableName

1545
ref_gu/gu_alias.c Normal file

File diff suppressed because it is too large Load Diff

663
ref_gu/gu_backend.c Normal file
View File

@@ -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 );
}

1544
ref_gu/gu_beams.c Normal file

File diff suppressed because it is too large Load Diff

416
ref_gu/gu_clipping.c Normal file
View File

@@ -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 ) );
}

515
ref_gu/gu_context.c Normal file
View File

@@ -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 );
}

149
ref_gu/gu_cull.c Normal file
View File

@@ -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;
}

124
ref_gu/gu_dbghulls.c Normal file
View File

@@ -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
}

1268
ref_gu/gu_decals.c Normal file

File diff suppressed because it is too large Load Diff

308
ref_gu/gu_draw.c Normal file
View File

@@ -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 );
}
}

79
ref_gu/gu_extension.c Normal file
View File

@@ -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 <pspkernel.h>
#include <pspge.h>
#include <pspgu.h>
#include <stdio.h>
#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 );
}
}

23
ref_gu/gu_extension.h Normal file
View File

@@ -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

355
ref_gu/gu_frustum.c Normal file
View File

@@ -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;
}

52
ref_gu/gu_frustum.h Normal file
View File

@@ -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

74
ref_gu/gu_helper.h Normal file
View File

@@ -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

2499
ref_gu/gu_image.c Normal file

File diff suppressed because it is too large Load Diff

349
ref_gu/gu_init.c Normal file
View File

@@ -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 )
{
}

809
ref_gu/gu_local.h Normal file
View File

@@ -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 <pspkernel.h>
#include <pspgu.h>
#include <pspgum.h>
#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 <stdio.h>
#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

496
ref_gu/gu_rlight.c Normal file
View File

@@ -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<<i, RI.currentmodel->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 );
}

1361
ref_gu/gu_rmain.c Normal file

File diff suppressed because it is too large Load Diff

267
ref_gu/gu_rmath.c Normal file
View File

@@ -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 );
}

190
ref_gu/gu_rmisc.c Normal file
View File

@@ -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();
}

405
ref_gu/gu_rpart.c Normal file
View File

@@ -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 ));
}

2352
ref_gu/gu_rsurf.c Normal file

File diff suppressed because it is too large Load Diff

1026
ref_gu/gu_sprite.c Normal file

File diff suppressed because it is too large Load Diff

4142
ref_gu/gu_studio.c Normal file

File diff suppressed because it is too large Load Diff

577
ref_gu/gu_triapi.c Normal file
View File

@@ -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 );
}

309
ref_gu/gu_vgui.c Normal file
View File

@@ -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
}

871
ref_gu/gu_warp.c Normal file
View File

@@ -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();
}

39
ref_gu/vram_psp.h Normal file
View File

@@ -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' <raphael@fx-world.org>
* http://wordpress.fx-world.org
*/
#ifndef vram_h__
#define vram_h__
#include <stddef.h>
#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__

58
ref_gu/wscript Normal file
View File

@@ -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
)

2
ref_soft/exports.txt Normal file
View File

@@ -0,0 +1,2 @@
GetRefAPI
GetRefHumanReadableName

View File

@@ -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=<arch>,<toolchain>,<api>, 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=<module type>,<fw version>,<render type> 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)

93
wscript
View File

@@ -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')