First merge attempt (many PSP tunings are missing, as they are outdated now)

This commit is contained in:
Alibek Omarov
2024-01-18 06:51:13 +03:00
112 changed files with 32227 additions and 240 deletions

View File

@@ -73,6 +73,10 @@ This repository contains our fork of HLSDK and restored source code for some of
* Clone this repostory:
`$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`
#### PSP
* Build pspsdk(GCC 9.3) from https://github.com/pspdev
* Clone this repository: `git clone --recursive https://github.com/Crow-bar/xash3d-fwgs`.
### Building
#### Windows (Visual Studio)
0) Open command line
@@ -90,3 +94,20 @@ If compiling 32-bit on amd64, you may need to supply `export PKG_CONFIG_PATH=/us
(You need to pass `-8` to compile 64-bit engine on 64-bit x86 processor)
2) Compile: `./waf build`
3) Install(optional): `./waf install --destdir=/path/to/any/output/directory`
#### PSP
0) Navigate to `xash3d-fwgs` directory.
1) Examine which build options are available: `./waf --help`
2) Configure build:
Normal: `./waf configure -T fast --psp=prx,660,HW --prefix=/path/to/any/output/directory`
Profiling: `./waf configure -T debug --psp=elf,660,HW --enable-profiling --prefix=/path/to/any/output/directory`
3) Compile: `./waf build`
4) Install(optional): `./waf install`
## Running
0) Copy libraries and main executable somewhere, if you're skipped installation stage.
1) Copy game files to same directory
2) Run `xash3d.exe`/`xash3d.sh`/`xash3d` depending on which platform you're using.
For additional info, run Xash3D with `-help` command line key.

View File

@@ -20,16 +20,19 @@ GNU General Public License for more details.
#define VIDEO_SDL 1
#define VIDEO_FBDEV 3
#define VIDEO_DOS 4
#define VIDEO_PSP 5
// audio backends (XASH_SOUND)
#define SOUND_NULL 0
#define SOUND_SDL 1
#define SOUND_ALSA 3
#define SOUND_PSP 4
// input (XASH_INPUT)
#define INPUT_NULL 0
#define INPUT_SDL 1
#define INPUT_EVDEV 3
#define INPUT_PSP 4
// timer (XASH_TIMER)
#define TIMER_NULL 0 // not used
@@ -37,17 +40,20 @@ GNU General Public License for more details.
#define TIMER_POSIX 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_WIN32 3
#define MSGBOX_NSWITCH 4
#define MSGBOX_PSP 5
// library loading (XASH_LIB)
#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

@@ -23,6 +23,7 @@ NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 ==
|| type == PF_BC7_UNORM \
|| type == PF_BC7_SRGB \
|| type == PF_KTX2_RAW )
#define ImageIND( type ) (type == PF_INDEXED_32 || type == PF_INDEXED_24)
typedef enum
{
@@ -33,6 +34,10 @@ typedef enum
PF_BGRA_32, // big endian RGBA (MacOS)
PF_RGB_24, // uncompressed dds or another 24-bit image
PF_BGR_24, // big-endian RGB (MacOS)
PF_RGB_332, // 8-bit R3 G3 B2
PF_RGB_5650, // 16-bit R5 G6 B5
PF_RGBA_5551, // 16-bit R5 G5 B5 A1
PF_RGBA_4444, // 16-bit R4 G4 B4 A4
PF_LUMINANCE,
PF_DXT1, // s3tc DXT1/BC1 format
PF_DXT3, // s3tc DXT3/BC2 format

View File

@@ -127,6 +127,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;
@@ -135,7 +150,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

@@ -77,6 +77,30 @@ 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
#define XASH_NO_ZIP
#endif
#endif // XASH_DEDICATED
@@ -105,7 +129,7 @@ SETUP BACKENDS DEFINITIONS
#endif // !XASH_WIN32
#endif
#ifdef XASH_STATIC_LIBS
#if defined(XASH_STATIC_LIBS) && !XASH_PSP
#define XASH_LIB LIB_STATIC
#define XASH_INTERNAL_GAMELIBS
#define XASH_ALLOW_SAVERESTORE_OFFSETS
@@ -113,6 +137,8 @@ SETUP BACKENDS DEFINITIONS
#define XASH_LIB LIB_WIN32
#elif XASH_POSIX
#define XASH_LIB LIB_POSIX
#elif XASH_PSP
#define XASH_LIB LIB_PSP
#endif
//
@@ -193,4 +219,20 @@ Default build-depended cvar and constant values
#define DEFAULT_MAX_EDICTS 1200 // was 900 before HL25
#endif // DEFAULT_MAX_EDICTS
#ifndef DEFAULT_ACCELERATED_RENDERER
#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
#define DEFAULT_SOFTWARE_RENDERER "soft" // mittorn's ref_soft
#endif // DEFAULT_SOFTWARE_RENDERER
#endif // DEFAULTS_H

View File

@@ -24,6 +24,8 @@ GNU General Public License for more details.
#include <sys/syslimits.h>
#define OS_LIB_EXT "dylib"
#define OPEN_COMMAND "open"
#elif XASH_PSP
#define OS_LIB_EXT "prx"
#else
#define OS_LIB_EXT "so"
#define OPEN_COMMAND "xdg-open"
@@ -55,6 +57,16 @@ GNU General Public License for more details.
#define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )
#endif
#if XASH_PSP
#include <unistd.h>
#include <pspiofilemgr.h>
#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 )
#endif
typedef void* HANDLE;
typedef void* HINSTANCE;

View File

@@ -101,8 +101,13 @@ typedef enum
TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D
TF_ATLAS_PAGE = (1<<21), // bit who indicate lightmap page or deluxemap page
TF_ALPHACONTRAST = (1<<22), // special texture mode for A2C
#if XASH_PSP
TF_IMG_SWIZZLED = (1<<23),
TF_IMG_INVRAM = (1<<24),
#else
// reserved
// reserved
#endif
TF_IMG_UPLOADED = (1<<25), // this is set for first time when called glTexImage, otherwise it will be call glTexSubImage
TF_ARB_FLOAT = (1<<26), // float textures
TF_NOCOMPARE = (1<<27), // disable comparing for depth textures

View File

@@ -21,12 +21,22 @@ typedef int sound_t;
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
#if XASH_PSP
typedef vec_t vec4_t[4] __attribute__( ( aligned( 16 ) ) );
typedef vec_t quat_t[4] __attribute__( ( aligned( 16 ) ) );
#else
typedef vec_t vec4_t[4];
typedef vec_t quat_t[4];
#endif
typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack
#if XASH_PSP
typedef vec_t matrix3x4[3][4] __attribute__( ( aligned( 16 ) ) );
typedef vec_t matrix4x4[4][4] __attribute__( ( aligned( 16 ) ) );
#else
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
#endif
#if XASH_64BIT
typedef uint32_t poolhandle_t;
@@ -194,6 +204,9 @@ typedef void *(*pfnCreateInterface_t)( const char *, int * );
// 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
@@ -201,6 +214,7 @@ typedef void *(*pfnCreateInterface_t)( const char *, int * );
#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

@@ -26,18 +26,6 @@ GNU General Public License for more details.
// #define STUDIO_INTERPOLATION_FIX
/*
==================
CL_IsPlayerIndex
detect player entity
==================
*/
qboolean CL_IsPlayerIndex( int idx )
{
return ( idx >= 1 && idx <= cl.maxclients );
}
/*
=========================================================================

View File

@@ -96,41 +96,6 @@ static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
/*
====================
CL_GetEntityByIndex
Render callback for studio models
====================
*/
cl_entity_t *CL_GetEntityByIndex( int index )
{
if( !clgame.entities ) // not in game yet
return NULL;
if( index < 0 || index >= clgame.maxEntities )
return NULL;
if( index == 0 )
return clgame.entities;
return CL_EDICT_NUM( index );
}
/*
================
CL_ModelHandle
get model handle by index
================
*/
model_t *CL_ModelHandle( int modelindex )
{
if( modelindex < 0 || modelindex >= MAX_MODELS )
return NULL;
return cl.models[modelindex];
}
/*
====================
CL_IsThirdPerson
@@ -939,7 +904,7 @@ void CL_DrawCrosshair( void )
VectorAdd( refState.viewangles, cl.crosshairangle, angles );
AngleVectors( angles, forward, NULL, NULL );
VectorAdd( refState.vieworg, forward, point );
ref.dllFuncs.WorldToScreen( point, screen );
gTriApi.WorldToScreen( point, screen );
x += ( clgame.viewport[2] >> 1 ) * screen[0] + 0.5f;
y += ( clgame.viewport[3] >> 1 ) * screen[1] + 0.5f;
@@ -1084,7 +1049,6 @@ void CL_ClearWorld( void )
world.max_recursion = 0;
clgame.ds.cullMode = TRI_FRONT;
clgame.numStatics = 0;
}

View File

@@ -81,12 +81,12 @@ NetGraph_FillRGBA shortcut
*/
static void NetGraph_DrawRect( wrect_t *rect, byte colors[4] )
{
ref.dllFuncs.Color4ub( colors[0], colors[1], colors[2], colors[3] ); // color for this quad
gTriApi.Color4ub( colors[0], colors[1], colors[2], colors[3] ); // color for this quad
ref.dllFuncs.Vertex3f( rect->left, rect->top, 0 );
ref.dllFuncs.Vertex3f( rect->left + rect->right, rect->top, 0 );
ref.dllFuncs.Vertex3f( rect->left + rect->right, rect->top + rect->bottom, 0 );
ref.dllFuncs.Vertex3f( rect->left, rect->top + rect->bottom, 0 );
gTriApi.Vertex3f( rect->left, rect->top, 0 );
gTriApi.Vertex3f( rect->left + rect->right, rect->top, 0 );
gTriApi.Vertex3f( rect->left + rect->right, rect->top + rect->bottom, 0 );
gTriApi.Vertex3f( rect->left, rect->top + rect->bottom, 0 );
}
/*
@@ -691,7 +691,7 @@ void SCR_DrawNetGraph( void )
ref.dllFuncs.End();
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
ref.dllFuncs.RenderMode( kRenderNormal );
}
}

View File

@@ -393,7 +393,7 @@ int CL_TempEntAddEntity( cl_entity_t *pEntity )
VectorAdd( pEntity->origin, pEntity->model->maxs, maxs );
// g-cont. just use PVS from previous frame
if( TriBoxInPVS( mins, maxs ))
if( Mod_BoxVisible( mins, maxs, ref.dllFuncs.Mod_GetCurrentVis( )))
{
VectorCopy( pEntity->angles, pEntity->curstate.angles );
VectorCopy( pEntity->origin, pEntity->curstate.origin );
@@ -1023,8 +1023,12 @@ void GAME_EXPORT R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t
count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0]) / (3 * SHARD_VOLUME * SHARD_VOLUME);
}
#if XASH_PSP
if( count > 15 ) count = 15;
#else
// limit to 100 pieces
if( count > 100 ) count = 100;
#endif
for( i = 0; i < count; i++ )
{

View File

@@ -101,19 +101,6 @@ struct beam_s *R_BeamRing( int startEnt, int endEnt, int modelIndex, float life,
struct beam_s *R_BeamFollow( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness );
void R_BeamKill( int deadEntity );
// TriAPI
void TriRenderMode( int mode );
void TriColor4f( float r, float g, float b, float a );
void TriColor4ub( byte r, byte g, byte b, byte a );
void TriBrightness( float brightness );
void TriCullFace( TRICULLSTYLE mode );
int TriWorldToScreen( const float *world, float *screen );
int TriBoxInPVS( float *mins, float *maxs );
void TriLightAtPoint( float *pos, float *value );
void TriColor4fRendermode( float r, float g, float b, float a, int rendermode );
int TriSpriteTexture( model_t *pSpriteModel, int frame );
extern model_t *cl_sprite_dot;
extern model_t *cl_sprite_shell;

View File

@@ -417,10 +417,10 @@ void R_DrawLeafNode( float x, float y, float scale )
void R_DrawNodeConnection( float x, float y, float x2, float y2 )
{
ref.dllFuncs.Begin( TRI_LINES );
ref.dllFuncs.Vertex3f( x, y, 0 );
ref.dllFuncs.Vertex3f( x2, y2, 0 );
ref.dllFuncs.End( );
gTriApi.Begin( TRI_LINES );
gTriApi.Vertex3f( x, y, 0 );
gTriApi.Vertex3f( x2, y2, 0 );
gTriApi.End( );
}
void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes, mleaf_t *viewleaf )
@@ -443,10 +443,10 @@ void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes,
if( shownodes == 1 )
{
if( cl.worldmodel->leafs == leaf )
ref.dllFuncs.Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
gTriApi.Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
else if( viewleaf && viewleaf == leaf )
ref.dllFuncs.Color4f( 1.0f, 0.0f, 0.0f, 1.0f );
else ref.dllFuncs.Color4f( 0.0f, 1.0f, 0.0f, 1.0f );
gTriApi.Color4f( 1.0f, 0.0f, 0.0f, 1.0f );
else gTriApi.Color4f( 0.0f, 1.0f, 0.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
world.recursion_level--;
@@ -455,7 +455,7 @@ void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes,
if( shownodes == 1 )
{
ref.dllFuncs.Color4f( 0.0f, 0.0f, 1.0f, 1.0f );
gTriApi.Color4f( 0.0f, 0.0f, 1.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
else if( shownodes == 2 )
@@ -487,7 +487,7 @@ void R_ShowTree( void )
//pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
//pglLineWidth( 2.0f );
ref.dllFuncs.Color4f( 1, 0.7f, 0, 1.0f );
gTriApi.Color4f( 1, 0.7f, 0, 1.0f );
//pglDisable( GL_TEXTURE_2D );
R_ShowTree_r( cl.worldmodel->nodes, x, y, world.max_recursion * 3.5f, 2, viewleaf );
//pglEnable( GL_TEXTURE_2D );

View File

@@ -370,7 +370,6 @@ typedef struct
// holds text color
rgba_t textColor;
rgba_t spriteColor;
vec4_t triRGBA;
// crosshair members
const model_t *pCrosshair;
@@ -839,7 +838,6 @@ void CL_ClearSpriteTextures( void );
void CL_CenterPrint( const char *text, float y );
void CL_TextMessageParse( byte *pMemFile, int fileSize );
client_textmessage_t *CL_TextMessageGet( const char *pName );
model_t *CL_ModelHandle( int modelindex );
void NetAPI_CancelAllRequests( void );
cl_entity_t *CL_GetLocalPlayer( void );
model_t *CL_LoadClientSprite( const char *filename );
@@ -861,19 +859,45 @@ void CL_EnableScissor( scissor_state_t *scissor, int x, int y, int width, int he
void CL_DisableScissor( scissor_state_t *scissor );
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 );
_inline cl_entity_t *CL_EDICT_NUM( int n )
static inline cl_entity_t *CL_EDICT_NUM( int n )
{
if( !clgame.entities )
if( unlikely( !clgame.entities )) // not in game yet
{
Host_Error( "CL_EDICT_NUM: clgame.entities is NULL\n");
return NULL;
}
if(( n >= 0 ) && ( n < clgame.maxEntities ))
return clgame.entities + n;
if( unlikely( n < 0 || n >= clgame.maxEntities ))
{
Host_Error( "CL_EDICT_NUM: bad number %i\n", n );
return NULL;
}
return &clgame.entities[n];
}
static inline cl_entity_t *CL_GetEntityByIndex( int n )
{
if( unlikely( !clgame.entities )) // not in game yet
return NULL;
if( unlikely( n < 0 || n >= clgame.maxEntities ))
return NULL;
return &clgame.entities[n];
}
static inline model_t *CL_ModelHandle( int modelindex )
{
if( unlikely( modelindex < 0 || modelindex >= MAX_MODELS ))
return NULL;
return cl.models[modelindex];
}
static inline qboolean CL_IsPlayerIndex( int idx )
{
return ( idx >= 1 && idx <= cl.maxclients );
}
//
@@ -995,7 +1019,6 @@ void CL_ProcessPlayerState( int playerindex, entity_state_t *state );
void CL_ComputePlayerOrigin( cl_entity_t *clent );
void CL_ProcessPacket( frame_t *frame );
void CL_MoveThirdpersonCamera( void );
qboolean CL_IsPlayerIndex( int idx );
void CL_SetIdealPitch( void );
void CL_EmitEntities( void );
@@ -1189,5 +1212,6 @@ int Key_ToUpper( int key );
void OSK_Draw( void );
extern rgba_t g_color_table[8];
extern triangleapi_t gTriApi;
#endif//CLIENT_H

View File

@@ -2195,7 +2195,7 @@ void Con_VidInit( void )
Con_LoadConchars();
Con_CheckResize();
#if XASH_LOW_MEMORY
#if XASH_LOW_MEMORY && !XASH_PSP
con.background = R_GetBuiltinTexture( REF_BLACK_TEXTURE );
#else
// loading console image

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
@@ -1529,7 +1547,6 @@ void Touch_Draw( void )
ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X( touch.move_start_x + touch.side * width - GRID_X * touch_move_indicator.value ),
TO_SCRN_Y( touch.move_start_y - touch.forward * height - GRID_Y * touch_move_indicator.value ),
TO_SCRN_X( GRID_X * 2 * touch_move_indicator.value ), TO_SCRN_Y( GRID_Y * 2 * touch_move_indicator.value ), 0, 0, 1, 1, touch.joytexture );
}
}
@@ -2191,3 +2208,5 @@ void Touch_Shutdown( void )
touch.initialized = false;
Mem_FreePool( &touch.mempool );
}
#endif /* XASH_NO_TOUCH */

View File

@@ -60,8 +60,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( touch_enable.value )
ret |= INPUT_DEVICE_TOUCH;
#endif
if( Joy_IsActive() ) // connected or enabled
ret |= INPUT_DEVICE_JOYSTICK;
@@ -91,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
}
}
@@ -351,11 +357,14 @@ void IN_MouseEvent( int key, int down )
else ClearBits( in_mstate, BIT( key ));
// touch emulation overrides all input
#if XASH_NO_TOUCH
if( touch_emulate.value )
{
Touch_KeyEvent( K_MOUSE1 + key, down );
}
else if( cls.key_dest == key_game )
else
#endif
if( cls.key_dest == key_game )
{
// perform button actions
VGui_MouseEvent( K_MOUSE1 + key, down );
@@ -364,8 +373,7 @@ void IN_MouseEvent( int key, int down )
// client may override IN_MouseEvent
// but by default it calls back to Key_Event anyway
if( in_mouseactive )
clgame.dllFuncs.IN_MouseEvent( in_mstate );
}
clgame.dllFuncs.IN_MouseEvent( in_mstate ); }
else
{
// perform button actions

View File

@@ -515,7 +515,6 @@ void Key_Init( void )
Cvar_RegisterVariable( &osk_enable );
Cvar_RegisterVariable( &key_rotate );
}
/*
@@ -703,7 +702,11 @@ void GAME_EXPORT Key_Event( int key, int down )
VGui_KeyEvent( key, down );
// console key is hardcoded, so the user can never unbind it
#if XASH_PSP
if( key == '`' || key == '~' || key == K_MODE_BUTTON )
#else
if( key == '`' || key == '~' )
#endif
{
// we are in typing mode, so don't switch to console
if( cls.key_dest == key_message || !down )
@@ -714,7 +717,11 @@ void GAME_EXPORT Key_Event( int key, int down )
}
// escape is always handled special
#if XASH_PSP
if( ( key == K_ESCAPE || key == K_START_BUTTON ) && down )
#else
if( key == K_ESCAPE && down )
#endif
{
switch( cls.key_dest )
{
@@ -881,7 +888,11 @@ Normal keyboard characters, already shifted / capslocked / etc
void CL_CharEvent( int key )
{
// the console key should never be used as a char
#if XASH_PSP
if( key == '`' || key == '~' || key == K_MODE_BUTTON ) return;
#else
if( key == '`' || key == '~' ) return;
#endif
if( cls.key_dest == key_console && !Con_Visible( ))
{
@@ -1006,7 +1017,11 @@ static qboolean OSK_KeyEvent( int key, int down )
if( osk.curbutton.val == 0 )
{
#if XASH_PSP
if( key == K_ENTER || key == K_A_BUTTON )
#else
if( key == K_ENTER )
#endif
{
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
return true;
@@ -1017,6 +1032,9 @@ static qboolean OSK_KeyEvent( int key, int down )
switch ( key )
{
#if XASH_PSP
case K_A_BUTTON:
#endif
case K_ENTER:
switch( osk.curbutton.val )
{

View File

@@ -323,6 +323,10 @@ static ref_api_t gEngfuncs =
&clgame.drawFuncs,
&g_fsapi,
#if XASH_PSP
P5Ram_Alloc,
P5Ram_Free,
#endif
};
static void R_UnloadProgs( void )
@@ -344,33 +348,8 @@ static void R_UnloadProgs( void )
memset( &ref.dllFuncs, 0, sizeof( ref.dllFuncs ));
}
static void CL_FillTriAPIFromRef( triangleapi_t *dst, const ref_interface_t *src )
{
dst->version = TRI_API_VERSION;
dst->Begin = src->Begin;
dst->RenderMode = TriRenderMode;
dst->End = src->End;
dst->Color4f = TriColor4f;
dst->Color4ub = TriColor4ub;
dst->TexCoord2f = src->TexCoord2f;
dst->Vertex3f = src->Vertex3f;
dst->Vertex3fv = src->Vertex3fv;
dst->Brightness = TriBrightness;
dst->CullFace = TriCullFace;
dst->SpriteTexture = TriSpriteTexture;
dst->WorldToScreen = TriWorldToScreen;
dst->Fog = src->Fog;
dst->ScreenToWorld = src->ScreenToWorld;
dst->GetMatrix = src->GetMatrix;
dst->BoxInPVS = TriBoxInPVS;
dst->LightAtPoint = TriLightAtPoint;
dst->Color4fRendermode = TriColor4fRendermode;
dst->FogParams = src->FogParams;
}
static qboolean R_LoadProgs( const char *name )
{
extern triangleapi_t gTriApi;
static ref_api_t gpEngfuncs;
REFAPI GetRefAPI; // single export
@@ -415,12 +394,18 @@ static qboolean R_LoadProgs( const char *name )
return false;
}
// initialize TriAPI callbacks
if( !ref.dllFuncs.getTriAPI( TRI_API_VERSION, &gTriApi ))
{
COM_FreeLibrary( ref.hInstance );
Con_Reportf( "R_LoadProgs: can't init TriAPI Interface: wrong version, %i must be %i\n", gTriApi.version, TRI_API_VERSION );
ref.hInstance = NULL;
return false;
}
Cvar_FullSet( "host_refloaded", "1", FCVAR_READ_ONLY );
ref.initialized = true;
// initialize TriAPI callbacks
CL_FillTriAPIFromRef( &gTriApi, &ref.dllFuncs );
return true;
}

View File

@@ -21,7 +21,11 @@ GNU General Public License for more details.
// than could actually be referenced during gameplay,
// because we don't want to free anything until we are
// sure we won't need it.
#if XASH_PSP
#define MAX_SFX 2048
#else
#define MAX_SFX 8192
#endif
#define MAX_SFX_HASH (MAX_SFX/4)
static int s_numSfx = 0;

View File

@@ -201,9 +201,15 @@ typedef struct
//====================================================================
#if XASH_PSP
#define MAX_DYNAMIC_CHANNELS (20 + NUM_AMBIENTS)
#define MAX_CHANNELS (128 + MAX_DYNAMIC_CHANNELS)
#define MAX_RAW_CHANNELS 16
#else
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48
#endif
#define MAX_RAW_SAMPLES 8192
extern sound_t ambient_sfx[NUM_AMBIENTS];

175
engine/common/build.c Normal file
View File

@@ -0,0 +1,175 @@
/*
build.c - returns a engine build number
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 "common.h"
static char *date = __DATE__ ;
static char *mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char mond[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// returns days since Apr 1 2015
int Q_buildnum( void )
{
int m = 0, d = 0, y = 0;
static int b = 0;
if( b != 0 ) return b;
for( m = 0; m < 11; m++ )
{
if( !Q_strnicmp( &date[0], mon[m], 3 ))
break;
d += mond[m];
}
d += Q_atoi( &date[4] ) - 1;
y = Q_atoi( &date[7] ) - 1900;
b = d + (int)((y - 1) * 365.25f );
if((( y % 4 ) == 0 ) && m > 1 )
{
b += 1;
}
b -= 41728; // Apr 1 2015
return b;
}
/*
=============
Q_buildnum_compat
Returns a Xash3D build number. This is left for compability with original Xash3D.
IMPORTANT: this value must be changed ONLY after updating to newer Xash3D
IMPORTANT: this value must be acquired through "build" cvar.
=============
*/
int Q_buildnum_compat( void )
{
// do not touch this! Only author of Xash3D can increase buildnumbers!
return 4529;
}
/*
============
Q_buildos
Returns current name of operating system. Without any spaces.
============
*/
const char *Q_buildos( void )
{
const char *osname;
#if XASH_MINGW
osname = "win32-mingw";
#elif XASH_WIN32
osname = "win32";
#elif XASH_ANDROID
osname = "android";
#elif XASH_LINUX
osname = "linux";
#elif XASH_APPLE
osname = "apple";
#elif XASH_FREEBSD
osname = "freebsd";
#elif XASH_NETBSD
osname = "netbsd";
#elif XASH_OPENBSD
osname = "openbsd";
#elif XASH_EMSCRIPTEN
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
return osname;
}
/*
============
Q_buildos
Returns current name of operating system. Without any spaces.
============
*/
const char *Q_buildarch( void )
{
const char *archname;
#if XASH_AMD64
archname = "amd64";
#elif XASH_X86
archname = "i386";
#elif XASH_ARM && XASH_64BIT
archname = "arm64";
#elif XASH_ARM
archname = "armv"
#if XASH_ARM == 8
"8_32" // for those who (mis)using 32-bit OS on 64-bit CPU
#elif XASH_ARM == 7
"7"
#elif XASH_ARM == 6
"6"
#elif XASH_ARM == 5
"5"
#elif XASH_ARM == 4
"4"
#endif
#if XASH_ARM_HARDFP
"hf";
#else
"l";
#endif
#elif XASH_MIPS && defined XASH_BIG_ENDIAN
archname = "mips";
#elif XASH_MIPS && defined XASH_LITTLE_ENDIAN
archname = "mipsel";
#elif XASH_JS
archname = "javascript";
#elif XASH_E2K
archname = "e2k";
#else
#error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug"
#endif
return archname;
}
/*
=============
Q_buildcommit
Returns a short hash of current commit in VCS as string.
XASH_BUILD_COMMIT must be passed in quotes
if XASH_BUILD_COMMIT is not defined,
Q_buildcommit will identify this build as "notset"
=============
*/
const char *Q_buildcommit( void )
{
#ifdef XASH_BUILD_COMMIT
return XASH_BUILD_COMMIT;
#else
return "notset";
#endif
}

View File

@@ -141,6 +141,7 @@ typedef enum
#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
#endif
#endif
#define GameState (&host.game)
@@ -723,7 +724,6 @@ int R_CreateDecalList( struct decallist_s *pList );
void R_ClearAllDecals( void );
void CL_ClearStaticEntities( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
struct cl_entity_s *CL_GetEntityByIndex( int index );
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
void CL_HudMessage( const char *pMessage );
const char *CL_MsgInfo( int cmd );

4556
engine/common/filesystem.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1064,10 +1064,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();
@@ -1110,6 +1110,8 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
Sys_Error( "couldn't find xash3d data directory" );
host.rootdir[0] = 0;
}
#elif XASH_PSP
COM_ExtractFilePath( argv[0], host.rootdir );
#elif (XASH_SDL == 2) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
char *szBasePath = SDL_GetBasePath();
if( szBasePath )

View File

@@ -24,7 +24,7 @@ Image_LoadTGA
*/
qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesize )
{
int i, columns, rows, row_inc, row, col;
int i, columns, rows, row_inc, row, col, bpp = 1;
byte *buf_p, *pixbuf, *targa_rgba;
rgba_t palette[256];
byte red = 0, green = 0, blue = 0, alpha = 0;
@@ -32,6 +32,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
int reflectivity[3] = { 0, 0, 0 };
qboolean compressed;
tga_t targa_header;
int palIndex = 0;
if( filesize < sizeof( tga_t ))
return false;
@@ -55,8 +56,6 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
// check for tga file
if( !Image_ValidSize( name )) return false;
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
if( targa_header.image_type == 1 || targa_header.image_type == 9 )
{
// uncompressed colormapped image
@@ -119,11 +118,35 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
return false;
}
}
else
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Type %i not supported\n", name, targa_header.image_type );
return false;
}
columns = targa_header.width;
rows = targa_header.height;
image.size = image.width * image.height * 4;
if( Image_CheckFlag( IL_KEEP_8BIT ) && ( targa_header.image_type == 1 || targa_header.image_type == 9 ))
{
pixbuf = image.palette = Mem_Malloc( host.imagepool, 1024 );
for( i = 0; i < targa_header.colormap_length; i++ )
{
*pixbuf++ = palette[i][0];
*pixbuf++ = palette[i][1];
*pixbuf++ = palette[i][2];
*pixbuf++ = palette[i][3];
}
image.type = PF_INDEXED_32;
}
else
{
image.palette = NULL;
image.type = PF_RGBA_32;
bpp = 4;
}
image.size = image.width * image.height * bpp;
targa_rgba = image.rgba = Mem_Malloc( host.imagepool, image.size );
// if bit 5 of attributes isn't set, the image has been stored from bottom to top
@@ -134,8 +157,8 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
}
else
{
pixbuf = targa_rgba + ( rows - 1 ) * columns * 4;
row_inc = -columns * 4 * 2;
pixbuf = targa_rgba + ( rows - 1 ) * columns * bpp;
row_inc = -columns * bpp * 2;
}
compressed = ( targa_header.image_type == 9 || targa_header.image_type == 10 || targa_header.image_type == 11 );
@@ -161,13 +184,13 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
case 1:
case 9:
// colormapped image
blue = *buf_p++;
if( blue < targa_header.colormap_length )
palIndex = *buf_p++;
if( palIndex < targa_header.colormap_length )
{
red = palette[blue][0];
green = palette[blue][1];
alpha = palette[blue][3];
blue = palette[blue][2];
red = palette[palIndex][0];
green = palette[palIndex][1];
blue = palette[palIndex][2];
alpha = palette[palIndex][3];
if( alpha != 255 ) image.flags |= IMAGE_HAS_ALPHA;
}
break;
@@ -208,10 +231,18 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
reflectivity[1] += green;
reflectivity[2] += blue;
if( image.type == PF_INDEXED_32 || image.type == PF_INDEXED_24 )
{
*pixbuf++ = palIndex;
}
else
{
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alpha;
}
if( ++col == columns )
{
// run spans across rows
@@ -223,6 +254,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
}
VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
if( image.palette ) Image_GetPaletteBMP( image.palette );
image.depth = 1;
return true;

View File

@@ -93,6 +93,23 @@ static const loadpixformat_t load_null[] =
{ NULL, NULL, NULL, IL_HINT_NO }
};
// a1ba: that's weird, better debug
#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", "mdl", Image_LoadMDL, IL_HINT_HL }, // hl studio model skins
{ "%s%s.%s", "spr", Image_LoadSPR, IL_HINT_HL }, // hl sprite frames
{ "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc)
{ "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc)
{ "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette
{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models
{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images
{ "%s%s.%s", "png", Image_LoadPNG, IL_HINT_NO }, // NightFire 007 menus
{ NULL, NULL, NULL, IL_HINT_NO }
};
#else
static const loadpixformat_t load_game[] =
{
{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models
@@ -108,7 +125,7 @@ static const loadpixformat_t load_game[] =
{ "%s%s.%s", "ktx2", Image_LoadKTX2, IL_HINT_NO }, // ktx2 for world and studio models
{ NULL, NULL, NULL, IL_HINT_NO }
};
#endif
/*
=============================================================================

View File

@@ -34,7 +34,13 @@ GNU General Public License for more details.
static char szGameDir[128]; // safe place to keep gamedir
static int szArgc;
#if XASH_PSP
#define MAX_NARGVS 50
static char *szArgv[MAX_NARGVS];
#else
static char **szArgv;
#endif
static void Sys_ChangeGame( const char *progname )
{
@@ -71,20 +77,23 @@ static int Sys_Start( void )
#endif
#elif XASH_IOS
IOS_LaunchDialog();
#endif
#elif XASH_PSP
return Host_Main( szArgc, szArgv, game, 0, Sys_ChangeGame );
}
int main( int argc, char **argv )
{
#if XASH_PSVITA
#if XASH_PSP
Platform_ReadCmd( "start.cmd", &szArgc, szArgv );
#elif XASH_PSVITA
// inject -dev -console into args if required
szArgc = PSVita_GetArgv( argc, argv, &szArgv );
#else
szArgc = argc;
szArgv = argv;
#endif // XASH_PSVITA
return Sys_Start();
}
#endif // XASH_ENABLE_MAIN

View File

@@ -38,6 +38,7 @@ void COM_PushLibraryError( const char *error )
Q_strncat( s_szLastError, error, sizeof( s_szLastError ) );
}
#if !XASH_PSP
void *COM_FunctionFromName_SR( void *hInstance, const char *pName )
{
char **funcs = NULL;
@@ -85,6 +86,7 @@ const char *COM_OffsetNameForFunction( void *function )
Con_Reportf( "COM_OffsetNameForFunction %s\n", sname );
return sname;
}
#endif
dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath )
{
@@ -128,7 +130,7 @@ dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath )
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 );
@@ -191,6 +193,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
@@ -203,6 +207,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

@@ -1735,12 +1735,16 @@ static void Mod_LoadSubmodels( model_t *mod, dbspmodel_t *bmod )
oldmaxfaces = Q_max( oldmaxfaces, out->numfaces );
}
#if XASH_PSP
refState.max_surfaces = 0; // sorting disabled
#else
// these array used to sort translucent faces in bmodels
if( oldmaxfaces > refState.max_surfaces )
{
refState.draw_surfaces = (sortedface_t *)Z_Realloc( refState.draw_surfaces, oldmaxfaces * sizeof( sortedface_t ));
refState.max_surfaces = oldmaxfaces;
}
#endif
}
/*

View File

@@ -151,17 +151,6 @@ void MSG_Clear( sizebuf_t *sb )
sb->bOverflow = false;
}
static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
qboolean MSG_CheckOverflow( sizebuf_t *sb )
{
return MSG_Overflow( sb, 0 );
}
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
@@ -193,17 +182,6 @@ void MSG_SeekToByte( sizebuf_t *sb, int bytePos )
sb->iCurBit = bytePos << 3;
}
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++;
}
}
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
{
Assert( numbits >= 0 && numbits <= 32 );

View File

@@ -64,6 +64,19 @@ _inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
qboolean MSG_CheckOverflow( sizebuf_t *sb );
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
static inline MSG_CheckOverflow( sizebuf_t *sb )
{
return MSG_Overflow( sb, 0 );
}
#if XASH_BIG_ENDIAN
#define MSG_BigShort( x ) ( x )
#else
@@ -78,7 +91,16 @@ void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, in
void MSG_Clear( sizebuf_t *sb );
// Bit-write functions
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
static inline void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
{
if( likely( !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++;
}
}
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, uint data, int numbits, qboolean bSigned );

View File

@@ -1095,7 +1095,6 @@ int Delta_TestBaseline( entity_state_t *from, entity_state_t *to, qboolean playe
if( from == NULL ) return 0;
return countBits;
}
if( FBitSet( to->entityType, ENTITY_BEAM ))
dt = Delta_FindStructByIndex( DT_CUSTOM_ENTITY_STATE_T );
else if( player )
@@ -1793,7 +1792,6 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
numChanges++;
}
else MSG_WriteOneBit( msg, 0 );
if( FBitSet( to->entityType, ENTITY_BEAM ))
{
dt = Delta_FindStructByIndex( DT_CUSTOM_ENTITY_STATE_T );
@@ -1806,7 +1804,6 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
{
dt = Delta_FindStructByIndex( DT_ENTITY_STATE_T );
}
Assert( dt && dt->bInitialized );
pField = dt->pFields;
@@ -1924,7 +1921,6 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
{
dt = Delta_FindStructByIndex( DT_ENTITY_STATE_T );
}
Assert( dt && dt->bInitialized );
pField = dt->pFields;

View File

@@ -356,7 +356,7 @@ qboolean NET_GetHostByName( const char *hostname, int family, struct sockaddr_st
#endif
}
#if !XASH_EMSCRIPTEN && !XASH_DOS4GW && !defined XASH_NO_ASYNC_NS_RESOLVE
#if !XASH_EMSCRIPTEN && !XASH_DOS4GW && !XASH_PSP && !defined XASH_NO_ASYNC_NS_RESOLVE
#define CAN_ASYNC_NS_RESOLVE
#endif // !XASH_EMSCRIPTEN && !XASH_DOS4GW && !defined XASH_NO_ASYNC_NS_RESOLVE

View File

@@ -86,7 +86,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
@@ -108,7 +119,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

@@ -177,6 +177,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
@@ -215,7 +238,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

@@ -12,8 +12,8 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "soundlib.h"
#if !XASH_PSP
#include "libmpg/libmpg.h"
#pragma pack( push, 1 )
@@ -455,3 +455,485 @@ void Stream_FreeMPG( stream_t *stream )
Mem_Free( stream );
}
#else // XASH_PSP
#include "platform/psp/scemp3/pspmp3.h"
/*
=================================================================
PSP MPEG decoding
=================================================================
*/
#define MP3_ID3V1_ID "TAG"
#define MP3_ID3V1_ID_SZ 3
#define MP3_ID3V1_SZ 128
#define MP3_ID3V2_ID "ID3"
#define MP3_ID3V2_ID_SZ 3
#define MP3_ID3V2_SIZE_OFF 6
#define MP3_ID3V2_SIZE_SZ 4
#define MP3_ID3V2_HEADER_SZ 10
#define MP3_ERRORS_MAX 3
#define PCM_WIDTH 2 // always 16-bit PCM
#define PCM_CHANNELS 2 // always 2
#define MP3_BUFFER_SIZE ( 128 * 1024 )
#define PCM_BUFFER_SIZE (( 1152 * PCM_WIDTH * PCM_CHANNELS ) * 2 ) // framesample * width * channels * 2(double buffer)
typedef struct
{
int handle;
int cachePos;
int frameCount;
byte *pcmTempPtr;
} mp3_decoder_t;
/*
=================
Sound_GetID3V2SizeMPG
=================
*/
__inline int Sound_GetID3V2SizeMPG( const byte *tagSize )
{
int size;
byte *sizePtr = (byte*)&size;
// 7 bit per byte, invert endian
sizePtr[0] = (( tagSize[3] >> 0 ) & 0x7F ) | (( tagSize[2] & 0x01 ) << 7 );
sizePtr[1] = (( tagSize[2] >> 1 ) & 0x3F ) | (( tagSize[1] & 0x03 ) << 6 );
sizePtr[2] = (( tagSize[1] >> 2 ) & 0x1F ) | (( tagSize[0] & 0x07 ) << 5 );
sizePtr[3] = (( tagSize[0] >> 3 ) & 0x0F );
return size;
}
#if 0
/*
=================
Sound_FindHeadMPG
=================
*/
fs_offset_t Sound_FindHeadMPG( const byte *buffer, fs_offset_t filesize )
{
fs_offset_t result;
result = 0;
if( filesize >= MP3_ID3V2_HEADER_SZ )
{
if( !memcmp( buffer, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ ))
result = Sound_GetID3V2SizeMPG( &buffer[MP3_ID3V2_SIZE_OFF] ) + MP3_ID3V2_HEADER_SZ;
}
return result;
}
/*
=================
Sound_FindTailMPG
=================
*/
fs_offset_t Sound_FindTailMPG( const byte *buffer, fs_offset_t filesize )
{
fs_offset_t result;
result = filesize;
if( filesize >= MP3_ID3V1_SZ )
{
if( !memcmp( &buffer[filesize - MP3_ID3V1_SZ], MP3_ID3V1_ID, MP3_ID3V1_ID_SZ ))
result -= MP3_ID3V1_SZ;
}
return result;
}
#endif
qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesize )
{
#if 0
int status;
int handle;
size_t bytesWrite = 0;
byte out[PCM_BUFFER_SIZE] __attribute__((aligned(64)));
fs_offset_t headOffset;
fs_offset_t tailOffset;
fs_offset_t contentSize;
int frameSample;
uint bps;
int frameLen;
int frameSize;
int frameCount;
headOffset = Sound_FindHeadMPG( buffer, filesize );
tailOffset = Sound_FindTailMPG( buffer, filesize );
contentSize = tailOffset - headOffset;
// TODO: read Xing header
handle = sceMp3ReserveMp3Handle( NULL );
if ( handle < 0 )
{
Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", handle );
return false;
}
status = sceMp3LowLevelInit( handle, &buffer[headOffset] );
if ( status < 0 )
{
Con_DPrintf( S_ERROR "sceMp3LowLevelInit returned 0x%08X\n", status );
return false;
}
frameSample = sceMp3GetMaxOutputSample( handle );
frameSize = (( frameSample / 8 ) * sceMp3GetBitRate( handle ) * 1000 ) / sceMp3GetSamplingRate( handle );
frameCount = contentSize / frameSize;
sound.channels = sceMp3GetMp3ChannelNum( handle );
sound.rate = sceMp3GetSamplingRate( handle );
sound.width = PCM_WIDTH; // always 16-bit PCM
sound.loopstart = -1;
sound.size = (frameCount * frameSample) * sound.channels * sound.width; // invalid for VBR
/*
status = sceMp3LowLevelDecode(handle, &buffer[headOffset + mp3usedsize], &mp3usedsize, pcm, &pcmoutsize);
if(status < 0)
{
Con_DPrintf( S_ERROR "sceMp3LowLevelDecode returned 0x%08X\n", status);
}
sceMp3ReleaseMp3Handle( handle );
*/
return true;
#else
Con_DPrintf( S_ERROR "Sound_LoadMPG unimplemented function!\n");
return false;
#endif
}
/*
=================
Stream_FindHeadMPG
=================
*/
SceOff Stream_FindHeadMPG( file_t *file )
{
SceOff result;
byte tagId[MP3_ID3V2_ID_SZ];
byte tagSize[MP3_ID3V2_SIZE_SZ];
result = 0;
FS_Seek( file, 0, SEEK_SET );
if( FS_Read( file, tagId, MP3_ID3V2_ID_SZ) < MP3_ID3V2_ID_SZ )
{
Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 ID read error\n");
return result;
}
if( !memcmp( tagId, MP3_ID3V2_ID, MP3_ID3V2_ID_SZ ))
{
FS_Seek( file, MP3_ID3V2_SIZE_OFF, SEEK_SET );
if( FS_Read( file, tagSize, MP3_ID3V2_SIZE_SZ ) < MP3_ID3V2_SIZE_SZ )
Con_DPrintf( S_ERROR "Sound_Mp3FindHead: ID3V2 SIZE read error\n");
else result = Sound_GetID3V2SizeMPG( tagSize ) + MP3_ID3V2_HEADER_SZ;
}
return result;
}
/*
=================
Stream_FindTailMPG
=================
*/
SceOff Stream_FindTailMPG( file_t *file )
{
SceOff result;
byte tagId[MP3_ID3V1_ID_SZ];
result = FS_FileLength( file );
FS_Seek( file, result - MP3_ID3V1_SZ, SEEK_SET );
if( FS_Read( file, tagId, MP3_ID3V1_ID_SZ ) < MP3_ID3V1_ID_SZ )
{
Con_DPrintf( S_ERROR "Sound_Mp3FindTail: ID3V1 ID read error\n");
return result;
}
if( !memcmp( tagId, MP3_ID3V1_ID, MP3_ID3V1_ID_SZ ))
result -= MP3_ID3V1_SZ;
return result;
}
/*
=================
Stream_FillBufferMPG
=================
*/
int Stream_FillBufferMPG( file_t *file, mp3_decoder_t *desc )
{
int status;
byte *dstPtr;
int dstSize;
int dstPos;
fs_offset_t readSize;
if( sceMp3CheckStreamDataNeeded( desc->handle ) <= 0 )
return 0;
// get Info on the stream (where to fill to, how much to fill, where to fill from)
status = sceMp3GetInfoToAddStreamData( desc->handle, &dstPtr, &dstSize, &dstPos );
if( status < 0 )
{
Con_DPrintf( S_ERROR "sceMp3GetInfoToAddStreamData returned 0x%08X\n", status);
return status;
}
// seek file to position requested
if( desc->cachePos != dstPos )
{
FS_Seek( file, dstPos, SEEK_SET );
desc->cachePos = dstPos;
}
// read the amount of data
readSize = FS_Read( file, dstPtr, dstSize );
desc->cachePos += ( int )readSize;
// notify mp3 library about how much we really wrote to the stream buffer
status = sceMp3NotifyAddStreamData( desc->handle, ( int )readSize );
if ( status < 0 )
Con_DPrintf( S_ERROR "sceMp3NotifyAddStreamData returned 0x%08X\n", status);
return status;
}
/*
=================
Stream_OpenMPG
=================
*/
stream_t *Stream_OpenMPG( const char *filename )
{
stream_t *stream;
mp3_decoder_t *desc;
file_t *file;
int status;
void *bufferBase;
file = FS_Open( filename, "rbh", false ); // hold mode
if( !file ) return NULL;
// at this point we have valid stream
stream = Mem_Calloc( host.soundpool, sizeof( stream_t ));
stream->file = file;
stream->pos = 0;
desc = Mem_Calloc( host.soundpool, sizeof( mp3_decoder_t ) + MP3_BUFFER_SIZE + PCM_BUFFER_SIZE + 63 );
bufferBase = (void *)(((( uintptr_t )desc + sizeof( mp3_decoder_t )) & (~( 64 - 1 ))) + 64 );
// reserve a mp3 handle
SceMp3InitArg mp3Init;
mp3Init.mp3StreamStart = Stream_FindHeadMPG( file );
mp3Init.mp3StreamEnd = Stream_FindTailMPG( file );
mp3Init.mp3Buf = bufferBase;
mp3Init.mp3BufSize = MP3_BUFFER_SIZE;
mp3Init.pcmBuf = (void *)(( uintptr_t )bufferBase + MP3_BUFFER_SIZE );
mp3Init.pcmBufSize = PCM_BUFFER_SIZE;
desc->cachePos = 0;
desc->pcmTempPtr = mp3Init.pcmBuf;
desc->handle = sceMp3ReserveMp3Handle( &mp3Init );
if ( desc->handle < 0 )
{
Con_DPrintf( S_ERROR "sceMp3ReserveMp3Handle returned 0x%08X\n", desc->handle );
Mem_Free( stream );
Mem_Free( desc );
FS_Close( file );
return NULL;
}
// Fill the stream buffer with some data so that sceMp3Init has something to work with
if( Stream_FillBufferMPG( file, desc ) != 0 )
{
Mem_Free( stream );
Mem_Free( desc );
FS_Close( file );
return NULL;
}
status = sceMp3Init( desc->handle );
if ( status < 0 )
{
Con_DPrintf( S_ERROR "sceMp3Init returned 0x%08X\n", status );
Mem_Free( stream );
Mem_Free( desc );
FS_Close( file );
return NULL;
}
desc->frameCount = sceMp3GetFrameNum( desc->handle );
stream->buffsize = 0; // how many samples left from previous frame
stream->channels = PCM_CHANNELS; // always 2 PCM channels
stream->rate = sceMp3GetSamplingRate( desc->handle );
stream->width = PCM_WIDTH; // always 16 bit PCM
stream->ptr = (void *)desc;
stream->type = WF_MPGDATA;
return stream;
}
/*
=================
Stream_ReadMPG
assume stream is valid
=================
*/
int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer )
{
// buffer handling
int bytesWritten = 0;
mp3_decoder_t *desc;
int errdec;
desc = ( mp3_decoder_t* )stream->ptr;
while(1)
{
byte *data;
int outsize;
if( !stream->buffsize )
{
// Check if we need to fill our stream buffer
if( Stream_FillBufferMPG( stream->file, desc ) != 0 )
return 0;
for( errdec = 0; errdec < MP3_ERRORS_MAX; errdec++ )
{
stream->pos = sceMp3Decode( desc->handle, (SceShort16**)&desc->pcmTempPtr );
if(( int )stream->pos >= 0 ) // decoding successful
{
break;
}
else if( stream->pos == 0x80671402 ) // next frame header
{
if( Stream_FillBufferMPG( stream->file, desc ) != 0 )
return 0;
}
else break;
}
if(( int )stream->pos < 0 )
{
if( stream->pos != 0x80671402 )
Con_DPrintf( S_ERROR "sceMp3Decode returned 0x%08X\n", stream->pos );
return 0; // ???
}
}
// check remaining size
if( bytesWritten + stream->pos > needBytes )
outsize = ( needBytes - bytesWritten );
else outsize = stream->pos;
// copy raw sample to output buffer
data = (byte *)buffer + bytesWritten;
memcpy( data, &desc->pcmTempPtr[stream->buffsize], outsize );
bytesWritten += outsize;
stream->pos -= outsize;
stream->buffsize += outsize;
// continue from this sample on a next call
if( bytesWritten >= needBytes )
return bytesWritten;
stream->buffsize = 0; // no bytes remaining
}
return 0;
}
/*
=================
Stream_SetPosMPG
assume stream is valid
=================
*/
int Stream_SetPosMPG( stream_t *stream, int newpos )
{
mp3_decoder_t *desc;
int frame;
int status;
desc = ( mp3_decoder_t* )stream->ptr;
// get frame num
frame = newpos / sceMp3GetMaxOutputSample( desc->handle ); // VBR?
if( frame < 1 || frame >= desc->frameCount - 1 )
return false;
status = sceMp3ResetPlayPositionByFrame( desc->handle, frame );
if( status < 0 )
{
Con_DPrintf( S_ERROR "sceMp3ResetPlayPositionByFrame returned 0x%08X\n", status );
// failed to seek for some reasons
return false;
}
// flush any previous data
stream->buffsize = 0;
return true;
}
/*
=================
Stream_GetPosMPG
assume stream is valid
=================
*/
int Stream_GetPosMPG( stream_t *stream )
{
mp3_decoder_t *desc;
desc = ( mp3_decoder_t * )stream->ptr;
return sceMp3GetSumDecodedSample( desc->handle );
}
/*
=================
Stream_FreeMPG
assume stream is valid
=================
*/
void Stream_FreeMPG( stream_t *stream )
{
mp3_decoder_t *desc;
desc = ( mp3_decoder_t * )stream->ptr;
if( desc )
{
sceMp3ReleaseMp3Handle( desc->handle );
Mem_Free( desc );
stream->ptr = NULL;
}
if( stream->file )
{
FS_Close( stream->file );
stream->file = NULL;
}
Mem_Free( stream );
}
#endif // XASH_PSP

View File

@@ -331,7 +331,8 @@ stream_t *Stream_OpenWAV( const char *filename )
return NULL;
// open
file = FS_Open( filename, "rb", false );
// h - hold mode
file = FS_Open( filename, "rbh", false );
if( !file ) return NULL;
// find "RIFF" chunk

View File

@@ -74,7 +74,9 @@ struct stream_s
// current stream state
void *ptr; // internal decoder state
#if !XASH_PSP
char temp[OUTBUF_SIZE]; // mpeg decoder stuff
#endif
size_t pos; // actual track position (or actual buffer remains)
int buffsize; // cached buffer size
};

View File

@@ -44,6 +44,11 @@ GNU General Public License for more details.
#include <vitasdk.h>
#endif
#if XASH_PSP
#include <pspkernel.h>
#include <psputility_sysparam.h>
#endif
#include "menu_int.h" // _UPDATE_PAGE macro
#include "library.h"
@@ -144,6 +149,10 @@ const char *Sys_GetCurrentUser( void )
if( pw )
return pw->pw_name;
#elif XASH_PSP
static string s_userName;
if( sceUtilityGetSystemParamString( PSP_SYSTEMPARAM_ID_STRING_NICKNAME, s_userName, sizeof( s_userName )) == 0 )
return s_userName;
#endif
return "Player";
}
@@ -485,7 +494,12 @@ Sys_Quit
void Sys_Quit( void )
{
Host_Shutdown();
#if XASH_PSP
sceKernelDelayThread( 50 * 1000 );
sceKernelExitGame();
#else
exit( error_on_exit );
#endif
}
/*

View File

@@ -58,6 +58,15 @@ void SDLash_Init( void );
void SDLash_Shutdown( void );
#endif
#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 );
#include "psp/p5ram_psp.h"
#include "psp/fsh_psp.h"
#endif
#if XASH_ANDROID
const char *Android_GetAndroidID( void );
const char *Android_LoadID( void );

View File

@@ -0,0 +1,410 @@
/*
fsh_psp.c - PSP filesystem helper
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <pspiofilemgr.h>
#include "common.h"
#include "fsh_psp.h"
#define FSH_MAX_PATH 64
#define FSH_EMPTY_STRING "*empty*"
typedef struct fsh_path_s
{
char path[FSH_MAX_PATH];
int fsize;
uint hashvalue;
struct fsh_path_s *nexthash;
}fsh_path_t;
typedef struct fsh_handle_s
{
qboolean ready;
int count;
char folderpath[PATH_MAX];
int folderpath_size;
uint empty_hash;
int pathlist_size;
int hashlist_size;
fsh_path_t *pathlist;
fsh_path_t **hashlist;
struct fsh_handle_s *next;
}fsh_handle_t;
static fsh_handle_t *fsh_poolchain = NULL;
/*
================
FSH_AddHash
================
*/
_inline void FSH_AddHash( fsh_path_t **hashlist, uint hash, fsh_path_t *fptr )
{
fptr->hashvalue = hash;
fptr->nexthash = hashlist[hash];
hashlist[hash] = fptr;
}
/*
================
FSH_RemoveHash
================
*/
_inline void FSH_RemoveHash( fsh_path_t **hashlist, uint hash, fsh_path_t *fptr )
{
fsh_path_t **fptr_prev;
for( fptr_prev = &hashlist[hash]; *fptr_prev != NULL; fptr_prev = &( *fptr_prev )->nexthash )
{
if( *fptr_prev == fptr )
{
*fptr_prev = fptr->nexthash;
break;
}
}
}
/*
================
FSH_AddFilePath
================
*/
int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size )
{
uint hash;
fsh_path_t *fptr;
const char *strip_path;
if( !handle )
return -2;
if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size ))
return -2;
strip_path = path + handle->folderpath_size + 1; // + '/'
hash = COM_HashKey( strip_path, handle->hashlist_size );
if( handle->ready && handle->count > 0 )
{
// see if already added
for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, strip_path ))
return fptr - handle->pathlist; // index
}
// find empty
for( fptr = handle->hashlist[handle->empty_hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, FSH_EMPTY_STRING ))
{
Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 );
// file size
fptr->fsize = size;
// remove empty from hash table
FSH_RemoveHash( handle->hashlist, handle->empty_hash, fptr );
// add to hash table
FSH_AddHash( handle->hashlist, hash, fptr );
return fptr - handle->pathlist; // index
}
}
}
// create new
if( handle->count + 1 >= handle->pathlist_size )
return -1;
fptr = &handle->pathlist[handle->count];
Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 );
// file size
fptr->fsize = size;
// add to hash table
FSH_AddHash( handle->hashlist, hash, fptr );
handle->count++;
return fptr - handle->pathlist; // index
}
/*
================
FSH_RemoveFilePath
================
*/
int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path )
{
uint hash;
fsh_path_t *fptr, **fptr_prev;
const char *strip_path;
if( !handle )
return -2;
if( Q_strnicmp( path, handle->folderpath, handle->folderpath_size ))
return -2;
strip_path = path + handle->folderpath_size + 1; // + '/'
hash = COM_HashKey( strip_path, handle->hashlist_size );
for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, strip_path ))
{
memset( fptr->path, 0, FSH_MAX_PATH );
Q_strncpy( fptr->path, FSH_EMPTY_STRING, FSH_MAX_PATH - 1 );
fptr->fsize = -3; // undefined
// remove from hash table
FSH_RemoveHash( handle->hashlist, hash, fptr );
// add empty to hash table
FSH_AddHash( handle->hashlist, handle->empty_hash, fptr );
return fptr - handle->pathlist; // index
}
}
return -1;
}
/*
================
FSH_RenameFilePath
================
*/
int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *newname )
{
uint hash;
fsh_path_t *fptr, **fptr_prev;
const char *strip_path;
if( !handle )
return -2;
if( Q_strnicmp( oldname, handle->folderpath, handle->folderpath_size ))
return -2;
strip_path = oldname + handle->folderpath_size + 1; // + '/'
hash = COM_HashKey( strip_path, handle->hashlist_size );
for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, strip_path ))
{
strip_path = newname + handle->folderpath_size + 1; // + '/'
memset( fptr->path, 0, FSH_MAX_PATH );
Q_strncpy( fptr->path, strip_path, FSH_MAX_PATH - 1 );
// remove old from hash table
FSH_RemoveHash( handle->hashlist, hash, fptr );
// add new to hash table
hash = COM_HashKey( strip_path, handle->hashlist_size );
FSH_AddHash( handle->hashlist, hash, fptr );
return fptr - handle->pathlist; // index;
}
}
return -1;
}
/*
================
FSH_FindSize
================
*/
int FSH_FindSize( fsh_handle_t *handle, const char *path )
{
uint hash;
fsh_path_t *fptr;
const char *strip_path;
if( !handle )
return -2;
if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size ))
return -2;
strip_path = path + handle->folderpath_size + 1; // + '/'
hash = COM_HashKey( strip_path, handle->hashlist_size );
for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, strip_path ))
return fptr->fsize;
}
return -1;
}
/*
================
FSH_Find
================
*/
int FSH_Find( fsh_handle_t *handle, const char *path )
{
uint hash;
fsh_path_t *fptr;
const char *strip_path;
if( !handle )
return -2;
if( !handle->ready || !handle->count || Q_strnicmp( path, handle->folderpath, handle->folderpath_size ))
return -2;
strip_path = path + handle->folderpath_size + 1; // + '/'
hash = COM_HashKey( strip_path, handle->hashlist_size );
for( fptr = handle->hashlist[hash]; fptr != NULL; fptr = fptr->nexthash )
{
if( !Q_stricmp( fptr->path, strip_path ))
return fptr - handle->pathlist; // index
}
return -1;
}
/*
================
FSH_ScanDir
================
*/
static int FSH_ScanDir( fsh_handle_t *handle, const char *path )
{
SceUID dir;
SceIoDirent entry;
char temp[FSH_MAX_PATH];
int result;
int fsize;
if(( dir = sceIoDopen( path )) < 0 )
return -1;
result = 0;
// iterate through the directory
while( 1 )
{
// zero the dirent, to avoid possible problems with sceIoDread
memset( &entry, 0, sizeof( SceIoDirent ));
if( !sceIoDread( dir, &entry ))
break;
// ignore the virtual directories
if( !Q_stricmp( entry.d_name, "." ) || !Q_stricmp( entry.d_name, ".." ))
continue;
sprintf( temp, "%s/%s", path, entry.d_name );
if(FIO_S_ISDIR( entry.d_stat.st_mode ))
result = FSH_ScanDir( handle, temp );
else if(FIO_S_ISREG( entry.d_stat.st_mode ))
{
if( entry.d_stat.st_size <= __INT_MAX__ )
fsize = ( int )entry.d_stat.st_size;
else fsize = -3; // undefined
result = FSH_AddFilePathWs( handle, temp, fsize );
}
else continue;
if( result < 0 ) break;
}
sceIoDclose( dir );
return result;
}
/*
================
FSH_Create
================
*/
fsh_handle_t *FSH_Create( const char *path, int maxfiles )
{
fsh_handle_t *handle;
handle = P5Ram_Alloc( sizeof( fsh_handle_t ), 1 );
if( !handle )
return NULL;
handle->pathlist_size = maxfiles;
handle->pathlist = P5Ram_Alloc( handle->pathlist_size * sizeof( fsh_path_t ), 1 );
if( !handle->pathlist )
{
P5Ram_Free( handle );
return NULL;
}
handle->hashlist_size = maxfiles >> 2;
handle->hashlist = P5Ram_Alloc( handle->hashlist_size * sizeof( fsh_path_t* ), 1 );
if( !handle->hashlist )
{
P5Ram_Free( handle );
return NULL;
}
handle->empty_hash = COM_HashKey( FSH_EMPTY_STRING, handle->hashlist_size );
if( !Q_strnicmp( path, "./", 2 ))
path += 2;
Q_strncpy( handle->folderpath, path, FSH_MAX_PATH - 1 );
handle->folderpath_size = Q_strlen( handle->folderpath );
if( FSH_ScanDir( handle, handle->folderpath ) < 0 )
{
P5Ram_Free( handle );
return NULL;
}
handle->next = fsh_poolchain;
fsh_poolchain = handle;
handle->ready = true;
return handle;
}
/*
================
FSH_Shutdown
================
*/
void FSH_Free( fsh_handle_t *handle )
{
if( !handle )
return;
if( handle->pathlist )
P5Ram_Free( handle->pathlist );
if( handle->hashlist )
P5Ram_Free( handle->hashlist );
P5Ram_Free( handle );
}

View File

@@ -0,0 +1,37 @@
/*
fsh_psp.h - PSP filesystem helper header
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef FSH_PSP_H
#define FSH_PSP_H
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct fsh_handle_s fsh_handle_t;
int FSH_AddFilePathWs( fsh_handle_t *handle, const char *path, int size );
#define FSH_AddFilePath( handle, path ) FSH_AddFilePathWs(handle, path, -2 )
int FSH_RemoveFilePath( fsh_handle_t *handle, const char *path );
int FSH_RenameFilePath( fsh_handle_t *handle, const char *oldname, const char *newname );
int FSH_FindSize( fsh_handle_t *handle, const char *path );
int FSH_Find( fsh_handle_t *handle, const char *path );
fsh_handle_t *FSH_Create( const char *path, int maxfiles );
void FSH_Free( fsh_handle_t *handle );
#ifdef __cplusplus
}
#endif
#endif // P5RAM_PSP_H

View File

@@ -0,0 +1,239 @@
/*
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 sizeof(psp_keymap) / sizeof(struct psp_keymap_s)
#define PSP_EXT_KEY PSP_CTRL_HOME
convar_t *psp_joy_dz_min;
convar_t *psp_joy_dz_max;
convar_t *psp_joy_cv_power;
convar_t *psp_joy_cv_expo;
static struct psp_keymap_s
{
int srckey;
int dstkey;
qboolean stdpressed;
qboolean extpressed;
}psp_keymap[] =
{
#if 0
{ PSP_CTRL_SELECT, '~' , false, false },
{ PSP_CTRL_START, K_ESCAPE , false, false },
{ PSP_CTRL_UP, K_UPARROW , false, false },
{ PSP_CTRL_RIGHT, K_RIGHTARROW, false, false },
{ PSP_CTRL_DOWN, K_DOWNARROW , false, false },
{ PSP_CTRL_LEFT, K_LEFTARROW , false, false },
{ PSP_CTRL_LTRIGGER, K_JOY1 , false, false },
{ PSP_CTRL_RTRIGGER, K_JOY2 , false, false },
{ PSP_CTRL_TRIANGLE, K_SHIFT , false, false },
{ PSP_CTRL_CIRCLE, K_SPACE , false, false },
{ PSP_CTRL_CROSS, K_ENTER , false, false },
{ PSP_CTRL_SQUARE, K_BACKSPACE , false, false },
#else
{ PSP_CTRL_SELECT , K_MODE_BUTTON , false, false },
{ PSP_CTRL_START , K_START_BUTTON, false, false },
{ PSP_CTRL_UP , K_UPARROW , false, false },
{ PSP_CTRL_RIGHT , K_RIGHTARROW , false, false },
{ PSP_CTRL_DOWN , K_DOWNARROW , false, false },
{ PSP_CTRL_LEFT , K_LEFTARROW , false, false },
{ PSP_CTRL_LTRIGGER, K_L1_BUTTON , false, false },
{ PSP_CTRL_RTRIGGER, K_R1_BUTTON , false, false },
{ PSP_CTRL_TRIANGLE, K_Y_BUTTON , false, false },
{ PSP_CTRL_CIRCLE , K_B_BUTTON , false, false },
{ PSP_CTRL_CROSS , K_A_BUTTON , false, false },
{ PSP_CTRL_SQUARE , K_X_BUTTON , false, false },
#endif
#if 0
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_JoyAxisCompute( float axis, float deadzone_min, float deadzone_max, float power, float expo )
{
float abs_axis, fabs_axis, fcurve;
float scale, r_deadzone_max;
qboolean flip_axis = 0;
expo = bound( 0.0f, expo, 1.0f );
power = bound( 0.0f, power, 10.0f );
deadzone_min = bound( 0.0f, deadzone_min, 127.0f );
deadzone_max = bound( 0.0f, deadzone_max, 127.0f );
// (-127) - (0) - (+127)
abs_axis = axis - 128.0f;
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;
if( expo )
{
// x * ( x^power * expo + x * ( 1.0 - expo ))
fabs_axis = abs_axis / 127.0f; // 0.0f - 1.0f
fcurve = powf(fabs_axis, power) * expo + fabs_axis * (1.0f - expo);
abs_axis = fabs_axis * fcurve * 127.0f;
}
return ( flip_axis ? -abs_axis : abs_axis );
}
void Platform_RunEvents( void )
{
int i;
SceCtrlData buf;
signed short curr_X, curr_Y;
static unsigned int last_buttons;
static signed short last_X, last_Y;
sceCtrlPeekBufferPositive( &buf, 1 );
for( i = 0; i < PSP_MAX_KEYS; i++ )
{
if( buf.Buttons & PSP_EXT_KEY )
{
if(( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey )
{
if( psp_keymap[i].stdpressed )
{
psp_keymap[i].stdpressed = false;
Key_Event( psp_keymap[i].dstkey, psp_keymap[i].stdpressed );
}
else
{
psp_keymap[i].extpressed = buf.Buttons & psp_keymap[i].srckey;
Key_Event( K_AUX16 + i, psp_keymap[i].extpressed);
}
}
}
else
{
// release
if( psp_keymap[i].extpressed )
{
psp_keymap[i].extpressed = false;
Key_Event( K_AUX16 + i, psp_keymap[i].extpressed);
}
if(( last_buttons ^ buf.Buttons ) & psp_keymap[i].srckey )
{
psp_keymap[i].stdpressed = buf.Buttons & psp_keymap[i].srckey;
Key_Event( psp_keymap[i].dstkey, psp_keymap[i].stdpressed );
}
}
}
last_buttons = buf.Buttons;
if( FBitSet( psp_joy_dz_min->flags, FCVAR_CHANGED ) || FBitSet( psp_joy_dz_max->flags, FCVAR_CHANGED ) ||
FBitSet( psp_joy_cv_power->flags, FCVAR_CHANGED ) || FBitSet( psp_joy_cv_expo->flags, FCVAR_CHANGED ))
{
for ( i = 0; i < 256; i++ )
{
psp_joymap[i] = Platform_JoyAxisCompute( i, psp_joy_dz_min->value, psp_joy_dz_max->value, psp_joy_cv_power->value, psp_joy_cv_expo->value );
psp_joymap[i] *= 256;
}
ClearBits( psp_joy_dz_min->flags, FCVAR_CHANGED );
ClearBits( psp_joy_dz_max->flags, FCVAR_CHANGED );
ClearBits( psp_joy_cv_power->flags, FCVAR_CHANGED );
ClearBits( psp_joy_cv_expo->flags, FCVAR_CHANGED );
}
curr_X = psp_joymap[buf.Lx];
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 cvars
psp_joy_dz_min = Cvar_Get( "psp_joy_dz_min", "15", FCVAR_ARCHIVE, "joy deadzone min (0 - 127)" );
psp_joy_dz_max = Cvar_Get( "psp_joy_dz_max", "0", FCVAR_ARCHIVE, "joy deadzone max (0 - 127)" );
psp_joy_cv_power = Cvar_Get( "psp_joy_cv_power", "2", FCVAR_ARCHIVE, "joy curve power (0 - 10)" );
psp_joy_cv_expo = Cvar_Get( "psp_joy_cv_expo", "0.5", FCVAR_ARCHIVE, "joy curve expo (0 - 1.0)" );
// set up the controller.
sceCtrlSetSamplingCycle( 0 );
sceCtrlSetSamplingMode( PSP_CTRL_MODE_ANALOG );
// building a joystick map
for ( i = 0; i < 256; i++ )
{
psp_joymap[i] = Platform_JoyAxisCompute( i, psp_joy_dz_min->value, psp_joy_dz_max->value, psp_joy_cv_power->value, psp_joy_cv_expo->value );
psp_joymap[i] *= 256;
}
return 1;
}
void Platform_MouseMove( float *x, float *y )
{
}
void Platform_PreCreateMove( void )
{
}
#endif /* XASH_INPUT */

View File

@@ -0,0 +1,8 @@
.set noreorder
#include "pspstub.s"
STUB_START "KernelAccess",0x40090000,0x00020005
STUB_FUNC 0x8A5C745F,kaGeEdramSetSize
STUB_FUNC 0x71570ECF,kaGeEdramGetHwSize
STUB_END

View File

@@ -0,0 +1,30 @@
/*
kamod.h - kernel access module header
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef KAMOD_H
#define KAMOD_H
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int kaGeEdramSetSize(int size);
int kaGeEdramGetHwSize(void);
#ifdef __cplusplus
}
#endif
#endif // KAMOD_H

View File

@@ -0,0 +1,486 @@
/*
lib_psp.c - dynamic library code for Sony PSP system
Copyright (C) 2018 Flying With Gauss
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/sor modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#if XASH_LIB == LIB_PSP
#include <pspmodulemgr.h>
#include "common.h"
#include "library.h"
#include "filesystem.h"
#include "server.h"
#define MOD_MAXNAMELEN 256
typedef struct table_s
{
const char *name;
void *pointer;
} table_t;
#include "generated_library_tables.h"
typedef struct mod_func_s
{
const char *name;
void *addr;
} mod_func_t;
typedef struct mod_handle_s
{
SceUID uid;
char name[MOD_MAXNAMELEN];
uint segAddr;
uint segSize;
mod_func_t *func;
struct mod_handle_s *next;
} mod_handle_t;
static mod_handle_t *modList = NULL;
static char *modErrorPtr = NULL;
static char modErrorBuf[1024];
#define Module_Error( fmt, ... ) Module_SetError( "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ )
int Module_SetError( const char *fmt, ... )
{
va_list args;
int result;
va_start( args, fmt );
result = Q_vsnprintf( modErrorBuf, sizeof( modErrorBuf ), fmt, args );
va_end( args );
modErrorPtr = modErrorBuf;
return result;
}
char *Module_GetError( void )
{
char *errPtr = modErrorPtr;
modErrorPtr = NULL;
return errPtr;
}
static mod_handle_t *Module_Find( const char *name )
{
mod_handle_t *modHandle;
if( !name )
{
Module_Error( "input mismatch" );
return NULL;
}
for( modHandle = modList; modHandle; modHandle = modHandle->next )
{
if( !Q_strcmp( modHandle->name, name ))
return modHandle;
}
return NULL;
}
static const char *Module_Name( void *handle )
{
mod_handle_t *modHandle;
if( !handle )
{
Module_Error( "input mismatch" );
return NULL;
}
for( modHandle = modList; modHandle; modHandle = modHandle->next )
{
if( modHandle == handle )
return modHandle->name;
}
return NULL;
}
static mod_func_t *Module_LoadStatic( const char *name )
{
table_t *staticLib;
if( !name )
{
Module_Error( "input mismatch" );
return NULL;
}
for( staticLib = ( table_t* )libs; staticLib->pointer && staticLib->name; staticLib++ )
{
if( !Q_strcmp( staticLib->name, name ))
return staticLib->pointer;
}
return NULL;
}
mod_handle_t *Module_Load( const char *name )
{
mod_handle_t *modHandle;
mod_func_t *modFunc;
qboolean skipPrefix;
char modStaticName[32];
void *modArg[2];
SceUID modUid;
uint modSegAddr, modSegSize;
SceKernelModuleInfo info;
char engine_cwd[PATH_MAX];
if( !name )
return NULL;
modHandle = Module_Find( name );
if( modHandle )
return modHandle;
skipPrefix = false;
modSegAddr = modSegSize = 0;
Q_sprintf( engine_cwd, "%s/", host.rootdir );
modArg[0] = &modFunc;
modArg[1] = engine_cwd;
modUid = Platform_LoadModule( name, 0, sizeof( modArg ), modArg );
if( modUid < 0 )
{
COM_FileBase( name, modStaticName );
if( !Q_strncmp( modStaticName, "lib", 3 ) )
skipPrefix = true;
modFunc = Module_LoadStatic( skipPrefix ? &modStaticName[3] : modStaticName );
if( !modFunc )
{
Module_Error( "module %s error ( %#010x )", name, modUid );
return NULL;
}
modUid = -1;
Con_Reportf( "Module_Load( %s ): ( static ) success!\n", name );
}
else
{
info.size = sizeof( info );
if ( sceKernelQueryModuleInfo( modUid, &info ) >= 0 )
{
if( info.nsegment > 0 )
{
modSegAddr = info.segmentaddr[0];
modSegSize = info.segmentsize[0];
}
}
Con_Reportf( "Module_Load( %s ): ( dynamic ) success!\n", name );
}
modHandle = calloc( 1, sizeof( mod_handle_t ));
if( !modHandle )
{
Module_Error( "out of memory" );
return NULL;
}
Q_strncpy( modHandle->name, name, MOD_MAXNAMELEN );
modHandle->uid = modUid;
modHandle->func = modFunc;
modHandle->segAddr = modSegAddr;
modHandle->segSize = modSegSize;
modHandle->next = modList;
modList = modHandle;
return modHandle;
}
void *Module_GetAddrByName( mod_handle_t *handle, const char *name )
{
mod_func_t *modFunc;
if( !handle || !name )
{
Module_Error( "input mismatch" );
return NULL;
}
if( !Module_Name( handle ))
{
Module_SetError( "unknown handle" );
return NULL;
}
if( !handle->func )
{
Module_SetError( "call Module_Load() first" );
return NULL;
}
for( modFunc = handle->func; modFunc->addr && modFunc->name; modFunc++ )
{
if( !Q_strcmp( modFunc->name, name ))
return modFunc->addr;
}
Module_Error( "func %s not found in %s", name, handle->name );
return NULL;
}
const char *Module_GetNameByAddr( mod_handle_t *handle, const void *addr )
{
mod_func_t *modFunc;
if( !handle || !addr )
{
Module_Error( "input mismatch" );
return NULL;
}
if( !Module_Name( handle ))
{
Module_SetError( "unknown handle" );
return NULL;
}
if( !handle->func )
{
Module_SetError( "call Module_Load() first" );
return NULL;
}
for( modFunc = handle->func; modFunc->addr && modFunc->name; modFunc++ )
{
if( modFunc->addr == addr )
return modFunc->name;
}
Module_Error( "addr %#010x not found in %s", addr, handle->name );
return NULL;
}
uint Module_GetOffsetByAddr( mod_handle_t *handle, const void *addr )
{
uint addrUInt;
if( !handle || !addr )
{
Module_Error( "input mismatch" );
return 0;
}
if( !Module_Name( handle ))
{
Module_SetError( "unknown handle" );
return 0;
}
if( !handle->segAddr )
{
Module_SetError( "unknown segment" );
return 0;
}
addrUInt = ( uint )addr;
if( addrUInt < handle->segAddr || addrUInt >= ( handle->segAddr + handle->segSize ))
{
Module_SetError( "addr %#010x is out of range", addrUInt );
return 0;
}
return addrUInt - handle->segAddr;
}
void *Module_GetAddrByOffset( mod_handle_t *handle, uint offset )
{
if( !handle || !offset )
{
Module_Error( "input mismatch" );
return NULL;
}
if( !Module_Name( handle ))
{
Module_SetError( "unknown handle" );
return NULL;
}
if( !handle->segAddr )
{
Module_SetError( "unknown segment" );
return NULL;
}
if( offset >= handle->segSize )
{
Module_SetError( "offset %#010x is out of range", offset );
return NULL;
}
return ( void* )( offset + handle->segAddr );
}
int Module_Unload( mod_handle_t *handle )
{
mod_handle_t *modHandle;
int result, sceCode;
if( !handle )
{
Module_Error( "input mismatch" );
return -1;
}
if( !Module_Name( handle ))
{
Module_Error( "unknown handle" );
return -2;
}
if( handle->uid != -1 )
{
result = Platform_UnloadModule( handle->uid, &sceCode );
if( result < 0 )
{
if( result == -1 )
Module_Error( "module %s doesn't want to stop", handle->name );
else
Module_Error( "module %s error ( %#010x )", handle->name, sceCode );
return -3;
}
}
if( handle != modList )
{
for( modHandle = modList; modHandle; modHandle = modHandle->next )
{
if( modHandle->next == handle )
{
modHandle->next = handle->next;
break;
}
}
}
else modList = handle->next;
free( handle );
return 0;
}
qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname, qboolean directpath )
{
// TODO: implement
return true;
}
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath )
{
dll_user_t *hInst = NULL;
void *pHandle = NULL;
COM_ResetLibraryError();
// platforms where gameinfo mechanism is working goes here
// and use FS_FindLibrary
hInst = FS_FindLibrary( dllname, directpath );
if( !hInst )
{
// try to find by linker(LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, LD_32_LIBRARY_PATH and so on...)
if( !pHandle )
{
pHandle = Module_Load( dllname );
if( pHandle )
return pHandle;
COM_PushLibraryError( va( "Failed to find library %s", dllname ));
COM_PushLibraryError( Module_GetError() );
return NULL;
}
}
if( hInst->custom_loader )
{
COM_PushLibraryError( va( "Custom library loader is not available. Extract library %s and fix gameinfo.txt!", hInst->fullPath ));
Mem_Free( hInst );
return NULL;
}
if( !( hInst->hInstance = Module_Load( hInst->fullPath )))
{
COM_PushLibraryError( Module_GetError() );
Mem_Free( hInst );
return NULL;
}
pHandle = hInst->hInstance;
Mem_Free( hInst );
return pHandle;
}
void COM_FreeLibrary( void *hInstance )
{
Module_Unload( hInstance );
}
void *COM_GetProcAddress( void *hInstance, const char *name )
{
return Module_GetAddrByName( hInstance, name );
}
void *COM_FunctionFromName_SR( void *hInstance, const char *pName )
{
void *funcAddr;
if( !memcmp( pName, "ofs:", 4 ))
funcAddr = Module_GetAddrByOffset( hInstance, Q_atoi( &pName[4] ));
else
funcAddr = Module_GetAddrByName( hInstance, pName );
if( !funcAddr )
Con_Reportf( S_ERROR "FunctionFromName: Can't get symbol %s: %s\n", pName, Module_GetError() );
return funcAddr;
}
const char *COM_NameForFunction( void *hInstance, void *function )
{
static char offsetName[16];
const char *funcName;
uint addrOffset;
funcName = Module_GetNameByAddr( hInstance, function );
if( funcName )
return funcName;
addrOffset = Module_GetOffsetByAddr( hInstance, function );
if( !addrOffset )
return NULL;
Q_snprintf( offsetName, sizeof( offsetName ), "ofs:%u", addrOffset );
Con_Reportf( "COM_NameForFunction: %s\n", offsetName );
return offsetName;
}
#endif // XASH_LIB == LIB_PSP

View File

@@ -0,0 +1,165 @@
/*
p5ram_psp.c - PSP P5 memory allocator
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <pspkernel.h>
#include <psppower.h>
#include <pspsuspend.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "p5ram_psp.h"
#define P5RAM_ALIGN( x, a ) ((( x ) + (( typeof( x ))( a ) - 1 )) & ~( typeof( x )( a ) - 1 ))
#define P5RAM_CHECK( addr ) ((( unsigned int )addr >= ( unsigned int )p5ram_addr) && (( unsigned int )addr < ( unsigned int )p5ram_addr + p5ram_size))
#define P5RAM_FLAG_INIT 0x01
#define P5RAM_FLAG_SUSPENDED 0x02
typedef struct __attribute__(( aligned( 64 ))) p5ram_info_s
{
SceUID uid;
size_t size;
struct p5ram_info_s *next;
}p5ram_info_t;
static unsigned char p5ram_flags = 0x00;
static p5ram_info_t *p5ram_poolchain = NULL;
static void *p5ram_addr;
static unsigned int p5ram_size;
int P5Ram_Init( void )
{
int result;
if( p5ram_flags & P5RAM_FLAG_INIT )
return -1;
result = sceKernelVolatileMemLock( 0, &p5ram_addr, &p5ram_size );
if( result == 0 )
p5ram_flags |= P5RAM_FLAG_INIT;
return result;
}
void *P5Ram_Alloc( size_t size, int clear )
{
SceUID uid;
void *ptr;
if(!( p5ram_flags & P5RAM_FLAG_INIT ))
return NULL;
uid = sceKernelAllocPartitionMemory( 5, "USER P5", PSP_SMEM_Low, size + sizeof( p5ram_info_t ), NULL );
if( uid < 0 ) return NULL;
ptr = sceKernelGetBlockHeadAddr( uid );
(( p5ram_info_t* )ptr )->uid = uid;
(( p5ram_info_t* )ptr )->size = size;
(( p5ram_info_t* )ptr )->next = p5ram_poolchain;
if( clear ) memset(( unsigned char* )ptr + sizeof( p5ram_info_t ), 0, size );
p5ram_poolchain = ptr;
return ( void* )(( unsigned char* )ptr + sizeof( p5ram_info_t ));
}
void P5Ram_Free( void *ptr )
{
p5ram_info_t *info, *next_ptr;
if( !( p5ram_flags & P5RAM_FLAG_INIT ) || ptr == NULL ) return;
info = ( p5ram_info_t* )((unsigned char*)ptr - sizeof( p5ram_info_t ));
if( info == p5ram_poolchain )
{
p5ram_poolchain = p5ram_poolchain->next;
}
else
{
next_ptr = p5ram_poolchain;
while( next_ptr )
{
if( next_ptr->next == info )
{
next_ptr->next = info->next;
break;
}
next_ptr = next_ptr->next;
}
}
sceKernelFreePartitionMemory( info->uid );
}
void P5Ram_FreeAll( void )
{
p5ram_info_t *next_ptr;
while( p5ram_poolchain )
{
next_ptr = p5ram_poolchain->next;
sceKernelFreePartitionMemory( p5ram_poolchain->uid );
p5ram_poolchain = next_ptr;
}
}
void P5Ram_Shutdown( void )
{
if( !( p5ram_flags & P5RAM_FLAG_INIT ))
return;
P5Ram_FreeAll();
sceKernelVolatileMemUnlock( 0 );
p5ram_flags &= ~P5RAM_FLAG_INIT;
}
void P5Ram_PowerCallback( int count, int arg, void *common )
{
if( !( p5ram_flags & ( P5RAM_FLAG_INIT | P5RAM_FLAG_SUSPENDED )))
return;
if ( arg & PSP_POWER_CB_POWER_SWITCH || arg & PSP_POWER_CB_SUSPENDING )
{
P5Ram_Shutdown();
p5ram_flags |= P5RAM_FLAG_SUSPENDED;
}
else if ( arg & PSP_POWER_CB_RESUMING )
{
}
else if ( arg & PSP_POWER_CB_RESUME_COMPLETE )
{
P5Ram_Init();
p5ram_flags &= ~P5RAM_FLAG_SUSPENDED;
}
}
#ifdef P5RAM_DEBUG
void P5Ram_Print( void )
{
p5ram_info_t *next_ptr;
printf("+++++++++++++++++++++++++++++\n");
next_ptr = p5ram_poolchain;
while( next_ptr )
{
printf("P5 ALLOC [ 0x%08X 0x%08X 0x%08X 0x%08X ]\n", next_ptr, next_ptr->uid, next_ptr->size, next_ptr->next );
next_ptr = next_ptr->next;
}
printf("+++++++++++++++++++++++++++++\n");
}
#endif

View File

@@ -0,0 +1,38 @@
/*
p5ram_psp.h - PSP P5 memory allocator header
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef P5RAM_PSP_H
#define P5RAM_PSP_H
//#define P5RAM_DEBUG
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int P5Ram_Init( void );
void *P5Ram_Alloc( size_t size, int clear );
void P5Ram_Free( void *ptr );
void P5Ram_FreeAll( void );
void P5Ram_Shutdown( void );
void P5Ram_PowerCallback( int count, int arg, void *common );
#ifdef P5RAM_DEBUG
void P5Ram_Print( void );
#endif
#ifdef __cplusplus
}
#endif
#endif // P5RAM_PSP_H

View File

@@ -0,0 +1,248 @@
/*
* PSP Software Development Kit - https://github.com/pspdev
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* pspmp3.h - Prototypes for the sceMp3 library
*
* Copyright (c) 2008 David Perry <tias_dp@hotmail.com>
* Copyright (c) 2008 Alexander Berl <raphael@fx-world.org>
* Copyright (c) 2022 Sergey Galushko
*
*/
#ifndef __SCELIBMP3_H__
#define __SCELIBMP3_H__
#include <psptypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SceMp3InitArg {
/** Stream start position */
SceOff mp3StreamStart;
/** Stream end position */
SceOff mp3StreamEnd;
/** Pointer to a buffer to contain raw mp3 stream data (+1472 bytes workspace) */
SceUChar8* mp3Buf;
/** Size of mp3Buf buffer (must be >= 8192) */
SceInt32 mp3BufSize;
/** Pointer to decoded pcm samples buffer */
SceUChar8* pcmBuf;
/** Size of pcmBuf buffer (must be >= 9216) */
SceInt32 pcmBufSize;
} SceMp3InitArg;
/**
* sceMp3ReserveMp3Handle
*
* @param args - Pointer to SceMp3InitArg structure
*
* @return sceMp3 handle on success, < 0 on error.
*/
SceInt32 sceMp3ReserveMp3Handle(SceMp3InitArg* args);
/**
* sceMp3ReleaseMp3Handle
*
* @param handle - sceMp3 handle
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3ReleaseMp3Handle(SceInt32 handle);
/**
* sceMp3InitResource
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3InitResource();
/**
* sceMp3TermResource
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3TermResource();
/**
* sceMp3Init
*
* @param handle - sceMp3 handle
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3Init(SceInt32 handle);
/**
* sceMp3Decode
*
* @param handle - sceMp3 handle
* @param dst - Pointer to destination pcm samples buffer
*
* @return number of bytes in decoded pcm buffer, < 0 on error.
*/
SceInt32 sceMp3Decode(SceInt32 handle, SceShort16** dst);
/**
* sceMp3GetInfoToAddStreamData
*
* @param handle - sceMp3 handle
* @param dst - Pointer to stream data buffer
* @param towrite - Space remaining in stream data buffer
* @param srcpos - Position in source stream to start reading from
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3GetInfoToAddStreamData(SceInt32 handle, SceUChar8** dst, SceInt32* towrite, SceInt32* srcpos);
/**
* sceMp3NotifyAddStreamData
*
* @param handle - sceMp3 handle
* @param size - number of bytes added to the stream data buffer
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3NotifyAddStreamData(SceInt32 handle, SceInt32 size);
/**
* sceMp3CheckStreamDataNeeded
*
* @param handle - sceMp3 handle
*
* @return 1 if more stream data is needed, < 0 on error.
*/
SceInt32 sceMp3CheckStreamDataNeeded(SceInt32 handle);
/**
* sceMp3SetLoopNum
*
* @param handle - sceMp3 handle
* @param loop - Number of loops
*
* @return 0 if success, < 0 on error.
*/
SceInt32 sceMp3SetLoopNum(SceInt32 handle, SceInt32 loop);
/**
* sceMp3GetLoopNum
*
* @param handle - sceMp3 handle
*
* @return Number of loops
*/
SceInt32 sceMp3GetLoopNum(SceInt32 handle);
/**
* sceMp3GetSumDecodedSample
*
* @param handle - sceMp3 handle
*
* @return Number of decoded samples
*/
SceInt32 sceMp3GetSumDecodedSample(SceInt32 handle);
/**
* sceMp3GetMaxOutputSample
*
* @param handle - sceMp3 handle
*
* @return Number of max samples to output
*/
SceInt32 sceMp3GetMaxOutputSample(SceInt32 handle);
/**
* sceMp3GetSamplingRate
*
* @param handle - sceMp3 handle
*
* @return Sampling rate of the mp3
*/
SceInt32 sceMp3GetSamplingRate(SceInt32 handle);
/**
* sceMp3GetBitRate
*
* @param handle - sceMp3 handle
*
* @return Bitrate of the mp3
*/
SceInt32 sceMp3GetBitRate(SceInt32 handle);
/**
* sceMp3GetMp3ChannelNum
*
* @param handle - sceMp3 handle
*
* @return Number of channels of the mp3
*/
SceInt32 sceMp3GetMp3ChannelNum(SceInt32 handle);
/**
* sceMp3ResetPlayPosition
*
* @param handle - sceMp3 handle
*
* @return < 0 on error
*/
SceInt32 sceMp3ResetPlayPosition(SceInt32 handle);
/**
* sceMp3GetFrameNum
*
* @param handle - sceMp3 handle
*
* @return < 0 on error
*/
SceInt32 sceMp3GetFrameNum(SceInt32 handle);
/**
* sceMp3ResetPlayPositionByFrame
*
* @param handle - sceMp3 handle
* @param frame - frame
*
* @return < 0 on error
*/
SceInt32 sceMp3ResetPlayPositionByFrame(SceInt32 handle, SceUInt32 frame);
/**
* sceMp3GetMPEGVersion
*
* @param handle - sceMp3 handle
*
* @return < 0 on error
*/
SceInt32 sceMp3GetMPEGVersion(SceInt32 handle);
/**
* sceMp3LowLevelInit
*
* @param handle - sceMp3 handle
* @param src - Pointer to a buffer to contain raw mp3 stream data
*
* @return < 0 on error
*/
SceInt32 sceMp3LowLevelInit(SceInt32 handle, SceUChar8* src);
/**
* sceMp3LowLevelDecode
*
* @param handle - sceMp3 handle
* @param mp3src -
* @param mp3srcused -
* @param pcmdst -
* @param pcmdstoutsz -
*
* @return < 0 on error
*/
SceInt32 sceMp3LowLevelDecode(SceInt32 handle, SceUChar8* mp3src, SceUInt32* mp3srcused, SceShort16* pcmdst, SceUInt32* pcmdstoutsz);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,29 @@
.set noreorder
#include "pspimport.s"
IMPORT_START "sceMp3",0x00090011
IMPORT_FUNC "sceMp3",0x07EC321A,sceMp3ReserveMp3Handle
IMPORT_FUNC "sceMp3",0x0DB149F4,sceMp3NotifyAddStreamData
IMPORT_FUNC "sceMp3",0x2A368661,sceMp3ResetPlayPosition
IMPORT_FUNC "sceMp3",0x354D27EA,sceMp3GetSumDecodedSample
IMPORT_FUNC "sceMp3",0x35750070,sceMp3InitResource
IMPORT_FUNC "sceMp3",0x3C2FA058,sceMp3TermResource
IMPORT_FUNC "sceMp3",0x3CEF484F,sceMp3SetLoopNum
IMPORT_FUNC "sceMp3",0x44E07129,sceMp3Init
IMPORT_FUNC "sceMp3",0x732B042A,sceMp3EndEntry
IMPORT_FUNC "sceMp3",0x7F696782,sceMp3GetMp3ChannelNum
IMPORT_FUNC "sceMp3",0x87677E40,sceMp3GetBitRate
IMPORT_FUNC "sceMp3",0x87C263D1,sceMp3GetMaxOutputSample
IMPORT_FUNC "sceMp3",0x8AB81558,sceMp3StartEntry
IMPORT_FUNC "sceMp3",0x8F450998,sceMp3GetSamplingRate
IMPORT_FUNC "sceMp3",0xA703FE0F,sceMp3GetInfoToAddStreamData
IMPORT_FUNC "sceMp3",0xD021C0FB,sceMp3Decode
IMPORT_FUNC "sceMp3",0xD0A56296,sceMp3CheckStreamDataNeeded
IMPORT_FUNC "sceMp3",0xD8F54A51,sceMp3GetLoopNum
IMPORT_FUNC "sceMp3",0xF5478233,sceMp3ReleaseMp3Handle
IMPORT_FUNC "sceMp3",0xAE6D2027,sceMp3GetMPEGVersion
IMPORT_FUNC "sceMp3",0x3548AEC8,sceMp3GetFrameNum
IMPORT_FUNC "sceMp3",0x0840E808,sceMp3ResetPlayPositionByFrame
IMPORT_FUNC "sceMp3",0x1B839B83,sceMp3LowLevelInit
IMPORT_FUNC "sceMp3",0xE3EE2C81,sceMp3LowLevelDecode

View File

@@ -0,0 +1,275 @@
/*
snd_psp.c - psp sound hardware output
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#if XASH_SOUND == SOUND_PSP
#include <malloc.h>
#include <pspaudio.h>
#include <pspkernel.h>
#include <pspdmac.h>
#include "sound.h"
#define PSP_NUM_AUDIO_SAMPLES 1024 // must be multiple of 64
#define PSP_OUTPUT_CHANNELS 2
#define PSP_OUTPUT_BUFFER_SIZE (( PSP_NUM_AUDIO_SAMPLES ) * ( PSP_OUTPUT_CHANNELS ))
static struct
{
SceUID threadUID;
SceUID semaUID;
int channel;
volatile int volL;
volatile int volR;
volatile int running;
} snd_psp = { -1, -1, -1, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, 1 };
static short snd_psp_buff[2][PSP_OUTPUT_BUFFER_SIZE] __attribute__(( aligned( 64 )));
/*
==================
SNDDMA_MainThread
Copy samples
==================
*/
static int SNDDMA_MainThread( SceSize args, void *argp )
{
int index = 0;
while( snd_psp.running )
{
sceKernelWaitSema( snd_psp.semaUID, 1, NULL );
int len = PSP_OUTPUT_BUFFER_SIZE;
int size = dma.samples;
int pos = dma.samplepos;
int wrapped = pos + len - size;
if( wrapped < 0 )
{
sceDmacMemcpy( snd_psp_buff[index], dma.buffer + ( pos * 2 ), len * 2 );
dma.samplepos += len;
}
else
{
int remaining = size - pos;
sceDmacMemcpy( snd_psp_buff[index], dma.buffer + ( pos * 2 ), remaining * 2 );
if( wrapped > 0 )
sceDmacMemcpy( snd_psp_buff[index] + ( remaining * 2 ), dma.buffer, wrapped * 2 );
dma.samplepos = wrapped;
}
sceKernelSignalSema( snd_psp.semaUID, 1 );
sceAudioOutputPannedBlocking( snd_psp.channel, snd_psp.volL, snd_psp.volR, snd_psp_buff[index] );
index = !index;
}
sceKernelExitThread( 0 );
return 0;
}
/*
==================
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
==================
*/
qboolean SNDDMA_Init( void )
{
int samplecount;
dma.format.speed = SOUND_DMA_SPEED;
dma.format.channels = PSP_OUTPUT_CHANNELS;
dma.format.width = 2;
// must be multiple of 64
samplecount = s_samplecount->value;
if( !samplecount )
samplecount = 0x4000;
dma.samples = samplecount * PSP_OUTPUT_CHANNELS;
dma.samplepos = 0;
dma.buffer = memalign( 64, dma.samples * 2 ); // 16 bit
if( !dma.buffer )
return false;
// clearing buffers
memset( dma.buffer, 0, dma.samples * 2 );
memset( snd_psp_buff, 0, sizeof( snd_psp_buff ));
// allocate and initialize a hardware output channel
snd_psp.channel = sceAudioChReserve( PSP_AUDIO_NEXT_CHANNEL,
PSP_NUM_AUDIO_SAMPLES, PSP_AUDIO_FORMAT_STEREO );
if( snd_psp.channel < 0 )
{
SNDDMA_Shutdown();
return false;
}
// create semaphore
snd_psp.semaUID = sceKernelCreateSema( "sound_sema", 0, 1, 255, NULL );
if( snd_psp.semaUID <= 0 )
{
SNDDMA_Shutdown();
return false;
}
// create audio thread
snd_psp.threadUID = sceKernelCreateThread( "sound_thread", SNDDMA_MainThread, 0x12, 0x8000, 0, 0 );
if( snd_psp.threadUID < 0 )
{
SNDDMA_Shutdown();
return false;
}
// start audio thread
if( sceKernelStartThread( snd_psp.threadUID, 0, 0 ) < 0 )
{
SNDDMA_Shutdown();
return false;
}
Con_Printf( "Using PSP audio driver: %d Hz\n", dma.format.speed );
dma.initialized = true;
return true;
}
/*
==============
SNDDMA_GetDMAPos
return the current sample position (in mono samples read)
inside the recirculating dma buffer, so the mixing code will know
how many sample are required to fill it up.
===============
*/
int SNDDMA_GetDMAPos( void )
{
return dma.samplepos;
}
/*
==============
SNDDMA_GetSoundtime
update global soundtime
===============
*/
int SNDDMA_GetSoundtime( void )
{
static int buffers, oldsamplepos;
int samplepos, fullsamples;
fullsamples = dma.samples / 2;
// it is possible to miscount buffers
// if it has wrapped twice between
// calls to S_Update. Oh well.
samplepos = SNDDMA_GetDMAPos();
if( samplepos < oldsamplepos )
{
buffers++; // buffer wrapped
if( paintedtime > 0x40000000 )
{
// time to chop things off to avoid 32 bit limits
buffers = 0;
paintedtime = fullsamples;
S_StopAllSounds( true );
}
}
oldsamplepos = samplepos;
return ( buffers * fullsamples + samplepos / 2 );
}
/*
==============
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
===============
*/
void SNDDMA_BeginPainting( void )
{
if( snd_psp.semaUID > 0 )
sceKernelWaitSema( snd_psp.semaUID, 1, NULL );
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
===============
*/
void SNDDMA_Submit( void )
{
if( snd_psp.semaUID > 0 )
sceKernelSignalSema( snd_psp.semaUID, 1 );
}
/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown( void )
{
Con_Printf("Shutting down audio.\n");
snd_psp.running = 0;
if( snd_psp.threadUID >= 0 )
{
sceKernelWaitThreadEnd( snd_psp.threadUID, NULL );
sceKernelDeleteThread( snd_psp.threadUID );
snd_psp.threadUID = -1;
}
if( snd_psp.semaUID > 0 )
{
sceKernelDeleteSema( snd_psp.semaUID );
snd_psp.semaUID = -1;
}
if( snd_psp.channel >= 0 )
{
sceAudioChRelease( snd_psp.channel );
snd_psp.channel = -1;
}
if( dma.buffer )
{
free( dma.buffer );
dma.buffer = NULL;
}
dma.initialized = false;
}
#endif // XASH_SOUND == SOUND_PSP

View File

@@ -0,0 +1,353 @@
/*
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 "platform/psp/ka/ka.h"
#include "platform/psp/scemp3/pspmp3.h"
#include <pspsdk.h>
#include <pspkernel.h>
#include <psppower.h>
#include <psprtc.h>
#include <pspprof.h>
#include <pspctrl.h>
#include <psputility.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 */
static qboolean psp_audiolib_init = false;
static int Platform_ExitCallback( int count, int arg, void *common )
{
host.crashed = true;
return 0;
}
static int Platform_PowerCallback( int count, int arg, void *common )
{
P5Ram_PowerCallback( count, arg, common );
return 0;
}
static int Platform_CallbackThread( SceSize args, void *argp )
{
int cbid;
//cbid = sceKernelCreateCallback( "Exit Callback", Platform_ExitCallback, NULL );
//sceKernelRegisterExitCallback( cbid );
cbid = sceKernelCreateCallback( "Power Callback", Platform_PowerCallback, NULL );
scePowerRegisterCallback( 0, cbid );
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
static int Platform_SetupCallbacks( void )
{
int thid = 0;
thid = sceKernelCreateThread("update_thread", Platform_CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
#if XASH_TIMER == TIMER_PSP
double Platform_DoubleTime( void )
{
return ( double )sceKernelGetSystemTimeWide() * 0.000001; // microseconds to seconds
}
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 );
}
int Platform_InitAudioLibs( void )
{
int status;
if( psp_audiolib_init )
return -1;
status = sceUtilityLoadModule( PSP_MODULE_AV_AVCODEC );
if ( status < 0 )
{
Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status );
return status;
}
status = sceUtilityLoadModule( PSP_MODULE_AV_MP3 );
if ( status < 0 )
{
Con_DPrintf( S_ERROR "sceUtilityLoadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status );
return status;
}
// init mp3 resources
status = sceMp3InitResource();
if ( status < 0 )
{
Con_DPrintf( S_ERROR "sceMp3InitResource returned 0x%08X\n", status );
return status;
}
psp_audiolib_init = true;
return 0;
}
int Platform_ShutdownAudioLibs( void )
{
int status;
if( !psp_audiolib_init )
return -1;
status = sceMp3TermResource();
if ( status < 0 )
Con_DPrintf( S_ERROR "sceMp3TermResource returned 0x%08X\n", status );
status = sceUtilityUnloadModule( PSP_MODULE_AV_MP3 );
if ( status < 0 )
Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_MP3) returned 0x%08X\n", status );
status = sceUtilityUnloadModule( PSP_MODULE_AV_AVCODEC );
if ( status < 0 )
Con_DPrintf( S_ERROR "sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) returned 0x%08X\n", status );
psp_audiolib_init = false;
return 0;
}
void Platform_Init( void )
{
SceUID kamID;
int result;
// disable fpu exceptions (division by zero and etc...)
pspSdkDisableFPUExceptions();
// exit callback thread
Platform_SetupCallbacks();
// set max cpu/gpu frequency
scePowerSetClockFrequency( 333, 333, 166 );
// set max VRAM
kamID = Platform_LoadModule( "ka.prx", 1, 0, NULL );
if( kamID >= 0 )
{
result = kaGeEdramGetHwSize();
if( result > 0 )
result = kaGeEdramSetSize( result );
Platform_UnloadModule( kamID, &result );
}
Platform_InitAudioLibs();
// P5 Ram init
P5Ram_Init();
}
void Platform_Shutdown( void )
{
P5Ram_Shutdown();
Platform_ShutdownAudioLibs();
#if XASH_PROFILING
gprof_cleanup();
#endif
}

View File

@@ -0,0 +1,384 @@
/*
vid_psp.c - PSP video component
Copyright (C) 2021 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#if XASH_VIDEO == VIDEO_PSP
#if !XASH_DEDICATED
#include <pspkernel.h>
#include <pspdisplay.h>
#include "common.h"
#include "client.h"
#include "mod_local.h"
#include "input.h"
#include "vid_common.h"
// Set frame buffer
#define PSP_FB_WIDTH 480
#define PSP_FB_HEIGHT 272
#define PSP_FB_BWIDTH 512
#define PSP_FB_FORMAT PSP_DISPLAY_PIXEL_FORMAT_565 //4444,5551,565,8888
#if PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_4444
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_5551
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_565
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == PSP_DISPLAY_PIXEL_FORMAT_8888
#define PSP_FB_BPP 4
#endif
#if 0
// Set up screen scaling
#define PSP_WIDTH_AR 30
#define PSP_HEIGHT_AR 17
#define PSP_MIN_MAR 12
#define PSP_MAX_MAR 16
#define PSP_MIN_MAR_W (PSP_WIDTH_AR * PSP_MIN_MAR)
#define PSP_MIN_MAR_H (PSP_HEIGHT_AR * PSP_MIN_MAR)
#define PSP_MAX_MAR_W (PSP_WIDTH_AR * PSP_MAX_MAR)
#define PSP_MAX_MAR_H (PSP_HEIGHT_AR * PSP_MAX_MAR)
#endif
static qboolean vsync;
#if 1
static vidmode_t vidmodes[] = { "480x272", PSP_FB_WIDTH, PSP_FB_HEIGHT};
static int num_vidmodes = 1;
#else
static vidmode_t *vidmodes = NULL;
static int num_vidmodes = 0;
#endif
static struct
{
#if 0
int in_width, in_height;
int out_width, out_height;
#endif
void *draw_buffer;
void *disp_buffer;
}vid_psp;
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
{
*stride = PSP_FB_BWIDTH;
*r = 31;
*g = 63 << 5;
*b = 31 << 11;
*bpp = 2;
vid_psp.draw_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP );
if( !vid_psp.draw_buffer )
Host_Error( "Memory allocation failled! (vid_psp.draw_buffer)\n");
vid_psp.disp_buffer = (void*)malloc( PSP_FB_HEIGHT * PSP_FB_BWIDTH * PSP_FB_BPP );
if( !vid_psp.disp_buffer )
Host_Error( "Memory allocation failled! (vid_psp.disp_buffer)\n");
sceDisplaySetMode(0, PSP_FB_WIDTH, PSP_FB_HEIGHT);
sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, 1);
return true;
}
void *SW_LockBuffer( void )
{
return vid_psp.draw_buffer;
}
void SW_UnlockBuffer( void )
{
void* p_swap = vid_psp.disp_buffer;
vid_psp.disp_buffer = vid_psp.draw_buffer;
vid_psp.draw_buffer = p_swap;
sceKernelDcacheWritebackInvalidateAll();
sceDisplaySetFrameBuf(vid_psp.disp_buffer, PSP_FB_BWIDTH, PSP_FB_FORMAT, PSP_DISPLAY_SETBUF_NEXTFRAME);
if ( vsync )
{
sceDisplayWaitVblankStart();
}
}
int R_MaxVideoModes( void )
{
return num_vidmodes;
}
vidmode_t *R_GetVideoMode( int num )
{
if( !vidmodes || num < 0 || num >= R_MaxVideoModes() )
{
return NULL;
}
return vidmodes + num;
}
#if 0
static void R_InitVideoModes( void )
{
int i;
vidmodes = Mem_Malloc( host.mempool, (PSP_MAX_MAR - PSP_MIN_MAR) * sizeof( vidmode_t ) );
// from smallest to largest
for(i = PSP_MIN_MAR ; i <= PSP_MAX_MAR; i++ )
{
vidmodes[num_vidmodes].width = PSP_WIDTH_AR * i;
vidmodes[num_vidmodes].height = PSP_HEIGHT_AR * i;
vidmodes[num_vidmodes].desc =
copystring( va( "%ix%i", vidmodes[num_vidmodes].width, vidmodes[num_vidmodes].height ));
num_vidmodes++;
}
}
static void R_FreeVideoModes( void )
{
int i;
if(!vidmodes)
return;
for( i = 0; i < num_vidmodes; i++ )
Mem_Free( (char*)vidmodes[i].desc );
Mem_Free( vidmodes );
vidmodes = NULL;
}
#endif
/*
=================
GL_GetProcAddress
=================
*/
void *GL_GetProcAddress( const char *name )
{
return NULL;
}
/*
===============
GL_UpdateSwapInterval
===============
*/
void GL_UpdateSwapInterval( void )
{
// disable VSync while level is loading
if( cls.state < ca_active )
{
// setup vsync here
vsync = false;
SetBits( gl_vsync->flags, FCVAR_CHANGED );
}
else if( FBitSet( gl_vsync->flags, FCVAR_CHANGED ))
{
ClearBits( gl_vsync->flags, FCVAR_CHANGED );
vsync = (gl_vsync->value > 0) ? true : false;
}
}
static qboolean VID_SetScreenResolution( int width, int height )
{
int render_w = width, render_h = height;
uint rotate = vid_rotate->value;
if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) )
{
if( rotate & 1 )
{
int swap = render_w;
render_w = render_h;
render_h = swap;
}
render_h /= vid_scale->value;
render_w /= vid_scale->value;
}
else
{
Con_Printf( S_WARN "failed to setup screen transform\n" );
}
R_SaveVideoMode( width, height, render_w, render_h );
return true;
}
void GL_SwapBuffers( void )
{
if ( vsync ) sceDisplayWaitVblankStart();
}
int GL_SetAttribute( int attr, int val )
{
return 0;
}
int GL_GetAttribute( int attr, int *val )
{
return 0;
}
/*
==================
R_Init_Video
==================
*/
qboolean R_Init_Video( const int type )
{
string safe;
qboolean retval;
refState.desktopBitsPixel = ( PSP_FB_BPP * 8 );
VID_StartupGamma();
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) )
glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE );
break;
default:
Host_Error( "Can't initialize unknown context type %d!\n", type );
break;
}
if( !(retval = VID_SetMode()) )
{
return retval;
}
switch( type )
{
case REF_GL:
// refdll also can check extensions
ref.dllFuncs.GL_InitExtensions();
break;
case REF_SOFTWARE:
default:
break;
}
#if 0
R_InitVideoModes();
#endif
host.renderinfo_changed = false;
return true;
}
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
{
Con_Reportf( "R_ChangeDisplaySettings: Setting video mode to %dx%d %s\n", width, height, fullscreen ? "fullscreen" : "windowed" );
refState.fullScreen = fullscreen;
if( !VID_SetScreenResolution( width, height ) )
return rserr_invalid_fullscreen;
return rserr_ok;
}
/*
==================
VID_SetMode
Set the described video mode
==================
*/
qboolean VID_SetMode( void )
{
qboolean fullscreen = false;
int iScreenWidth, iScreenHeight;
rserr_t err;
#if 1
iScreenWidth = PSP_FB_WIDTH;
iScreenHeight = PSP_FB_HEIGHT;
#else
vid_psp.out_width = PSP_FB_WIDTH;
vid_psp.out_height = PSP_FB_HEIGHT;
iScreenWidth = Cvar_VariableInteger( "width" );
iScreenHeight = Cvar_VariableInteger( "height" );
if( iScreenWidth < PSP_MIN_MAR_W ||
iScreenHeight < PSP_MIN_MAR_H ) // trying to get resolution automatically by default
{
iScreenWidth = PSP_MIN_MAR_W;
iScreenHeight = PSP_MIN_MAR_H;
}
if( iScreenWidth > PSP_MAX_MAR_W ||
iScreenHeight > PSP_MAX_MAR_H ) // trying to get resolution automatically by default
{
iScreenWidth = PSP_MAX_MAR_W;
iScreenHeight = PSP_MAX_MAR_H;
}
#endif
if( !FBitSet( vid_fullscreen->flags, FCVAR_CHANGED ) )
Cvar_SetValue( "fullscreen", DEFAULT_FULLSCREEN );
else
ClearBits( vid_fullscreen->flags, FCVAR_CHANGED );
SetBits( gl_vsync->flags, FCVAR_CHANGED );
fullscreen = true;//Cvar_VariableInteger("fullscreen") != 0;
if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, fullscreen )) == rserr_ok )
{
#if 0
vid_psp.in_width = iScreenWidth;
vid_psp.in_height = iScreenHeight;
#endif
}
else
return false;
return true;
}
/*
==================
R_Free_Video
==================
*/
void R_Free_Video( void )
{
#if 0
R_FreeVideoModes();
#endif
ref.dllFuncs.GL_ClearExtensions();
if( glw_state.software )
{
if( vid_psp.draw_buffer )
free( vid_psp.draw_buffer );
if( vid_psp.disp_buffer )
free( vid_psp.disp_buffer );
vid_psp.draw_buffer = NULL;
vid_psp.disp_buffer = NULL;
}
}
#endif // XASH_DEDICATED
#endif // XASH_VIDEO

View File

@@ -446,6 +446,11 @@ typedef struct ref_api_s
// filesystem exports
fs_api_t *fsapi;
#if XASH_PSP
void *(*P5Ram_Alloc)( size_t size, int clear );
void (*P5Ram_Free)( void *ptr );
#endif
} ref_api_t;
struct mip_s;

View File

@@ -54,7 +54,7 @@ extern int SV_UPDATE_BACKUP;
#define GROUP_OP_AND 0
#define GROUP_OP_NAND 1
#ifdef NDEBUG
#if defined( NDEBUG )
#define SV_IsValidEdict( e ) ( e && !e->free )
#else
#define SV_IsValidEdict( e ) SV_CheckEdict( e, __FILE__, __LINE__ )
@@ -509,7 +509,13 @@ qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multipla
qboolean SV_InitGame( void );
void SV_ActivateServer( int runPhysics );
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
model_t *SV_ModelHandle( int modelindex );
static inline model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
{
if( unlikely( modelindex < 0 || modelindex >= MAX_MODELS ))
return NULL;
return sv.models[modelindex];
}
void SV_DeactivateServer( void );
//
@@ -648,10 +654,17 @@ void SV_RestartAmbientSounds( void );
void SV_RestartDecals( void );
void SV_RestartStaticEnts( void );
int pfnDropToFloor( edict_t* e );
edict_t *SV_EdictNum( int n );
void SV_SetModel( edict_t *ent, const char *name );
int pfnDecalIndex( const char *m );
static inline edict_t *SV_EdictNum( int n )
{
if( unlikely( n < 0 || n >= GI->max_edicts ))
return NULL;
return &svgame.edicts[n];
}
//
// sv_log.c
//

View File

@@ -39,13 +39,6 @@ static vec3_t viewPoint[MAX_CLIENTS];
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
edict_t *SV_EdictNum( int n )
{
if(( n >= 0 ) && ( n < GI->max_edicts ))
return svgame.edicts + n;
return NULL;
}
#ifndef NDEBUG
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
{

View File

@@ -262,20 +262,6 @@ int GAME_EXPORT SV_GenericIndex( const char *filename )
return i;
}
/*
================
SV_ModelHandle
get model by handle
================
*/
model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
{
if( modelindex < 0 || modelindex >= MAX_MODELS )
return NULL;
return sv.models[modelindex];
}
static resourcetype_t SV_DetermineResourceType( const char *filename )
{
if( !Q_strncmp( filename, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ) && Sound_SupportedFileFormat( COM_FileExtension( filename )))

View File

@@ -945,12 +945,12 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
// filter movetypes to collide with
if( !SV_CanPushed( check ))
continue;
#if !XASH_PSP
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 ))
{
@@ -966,7 +966,12 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
if( !SV_TestEntityPosition( check, NULL ))
continue;
}
#if XASH_PSP
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;
@@ -1058,18 +1063,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_PSP
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 ))
{
@@ -1085,7 +1091,12 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
if( !SV_TestEntityPosition( check, NULL ))
continue;
}
#if XASH_PSP
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 );
@@ -1140,7 +1151,6 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
return check;
}
}
return NULL;
}

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
#if 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
// savedata headers
@@ -384,7 +387,13 @@ static void InitEntityTable( SAVERESTOREDATA *pSaveData, int entityCount )
ENTITYTABLE *pTable;
int i;
#if XASH_PSP
pSaveData->pTable = P5Ram_Alloc( sizeof( ENTITYTABLE ) * entityCount, 1 );
if( !pSaveData->pTable )
Host_Error( "%s: P5Ram_Alloc (pSaveData->pTable) failed!", __FUNCTION__ );
#else
pSaveData->pTable = Mem_Calloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount );
#endif
pSaveData->tableCount = entityCount;
// setup entitytable
@@ -700,8 +709,17 @@ static SAVERESTOREDATA *SaveInit( int size, int tokenCount )
{
SAVERESTOREDATA *pSaveData;
#if XASH_PSP
pSaveData = P5Ram_Alloc( sizeof( SAVERESTOREDATA ) + size, 1 );
if( !pSaveData )
Host_Error( "%s: P5Ram_Alloc (pSaveData) failed!", __FUNCTION__ );
pSaveData->pTokens = (char **)P5Ram_Alloc( tokenCount * sizeof( char* ), 1 );
if( !pSaveData->pTokens )
Host_Error( "%s: P5Ram_Alloc (pSaveData->pTokens) failed!", __FUNCTION__ );
#else
pSaveData = Mem_Calloc( host.mempool, sizeof( SAVERESTOREDATA ) + size );
pSaveData->pTokens = (char **)Mem_Calloc( host.mempool, tokenCount * sizeof( char* ));
#endif
pSaveData->tokenCount = tokenCount;
pSaveData->pBaseData = (char *)(pSaveData + 1); // skip the save structure);
@@ -750,20 +768,32 @@ static void SaveFinish( SAVERESTOREDATA *pSaveData )
if( pSaveData->pTokens )
{
#if XASH_PSP
P5Ram_Free( pSaveData->pTokens );
#else
Mem_Free( pSaveData->pTokens );
#endif
pSaveData->pTokens = NULL;
pSaveData->tokenCount = 0;
}
if( pSaveData->pTable )
{
#if XASH_PSP
P5Ram_Free( pSaveData->pTable );
#else
Mem_Free( pSaveData->pTable );
#endif
pSaveData->pTable = NULL;
pSaveData->tableCount = 0;
}
svgame.globals->pSaveData = NULL;
#if XASH_PSP
P5Ram_Free( pSaveData );
#else
Mem_Free( pSaveData );
#endif
}
/*
@@ -2333,14 +2363,26 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
return 0;
}
#if XASH_PSP
pSaveData = (char *)P5Ram_Alloc( size, 0 );
if( !pSaveData )
Host_Error( "%s: P5Ram_Alloc (pSaveData) failed!", __FUNCTION__ );
#else
pSaveData = (char *)Mem_Malloc( host.mempool, size );
#endif
FS_Read( f, pSaveData, size );
pData = pSaveData;
// allocate a table for the strings, and parse the table
if( tokenSize > 0 )
{
#if XASH_PSP
pTokenList = P5Ram_Alloc( tokenCount * sizeof( char* ), 1 );
if( !pTokenList )
Host_Error( "%s: P5Ram_Alloc (pTokenList) failed!", __FUNCTION__ );
#else
pTokenList = Mem_Calloc( host.mempool, tokenCount * sizeof( char* ));
#endif
// make sure the token strings pointed to by the pToken hashtable.
for( i = 0; i < tokenCount; i++ )
@@ -2352,22 +2394,40 @@ 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 );
#if XASH_PSP
if( pTokenList ) P5Ram_Free( pTokenList );
if( pSaveData ) P5Ram_Free( pSaveData );
#else
if( pTokenList ) Mem_Free( pTokenList );
if( pSaveData ) Mem_Free( pSaveData );
#endif
FS_Close( f );
return 0;
}
// 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)
@@ -2378,11 +2438,23 @@ 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
size = Q_min( nFieldSize, MAX_STRING );
@@ -2400,8 +2472,13 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
}
// delete the string table we allocated
#if XASH_PSP
if( pTokenList ) P5Ram_Free( pTokenList );
if( pSaveData ) P5Ram_Free( pSaveData );
#else
if( pTokenList ) Mem_Free( pTokenList );
if( pSaveData ) Mem_Free( pSaveData );
#endif
FS_Close( f );
// at least mapname should be filled

View File

@@ -65,6 +65,8 @@ typedef enum
SPR_CULL_NONE, // oriented sprite will be draw back face too
} facetype_t;
#pragma pack(push, 1)
// generic helper
typedef struct
{
@@ -133,4 +135,6 @@ typedef struct
STATIC_ASSERT( sizeof( dframetype_t ) == 4, "invalid dframetype_t size" );
#pragma pack(pop)
#endif//SPRITE_H

View File

@@ -67,6 +67,8 @@ def configure(conf):
# then remove them to avoid them getting linked to shared objects
for lib in extra_libs:
conf.env.LDFLAGS.remove(lib)
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)
@@ -87,6 +89,7 @@ def configure(conf):
if conf.options.STATIC:
conf.env.STATIC = True
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:
@@ -132,16 +135,19 @@ def build(bld):
'common/*.c',
'common/imagelib/*.c',
'common/soundlib/*.c',
'common/soundlib/libmpg/*.c',
'server/*.c'])
# PSP uses hw MP3 decoder
if bld.env.DEST_OS != 'psp':
source += bld.path.ant_glob(['common/soundlib/libmpg/*.c'])
if bld.env.ENGINE_TESTS:
source += bld.path.ant_glob(['tests/*.c'])
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 not in ['dos', 'nswitch', 'psvita']: #posix
elif bld.env.DEST_OS not in ['dos', 'nswitch', 'psvita', 'psp']: #posix
libs += [ 'M', 'RT', 'PTHREAD', 'ASOUND']
if not bld.env.STATIC:
libs += ['DL']
@@ -211,6 +217,10 @@ def build(bld):
'-lSceKernelDmacMgr_stub'
]
if bld.env.DEST_OS == 'psp':
source += bld.path.ant_glob(['platform/psp/*.c'])
source += bld.path.ant_glob(['platform/psp/*/*.S'])
# add client files
if not bld.env.DEDICATED:
source += bld.path.ant_glob([

View File

@@ -121,6 +121,8 @@ const char *Q_PlatformStringByID( const int platform )
return "nswitch";
case PLATFORM_PSVITA:
return "psvita";
case PLATFORM_PSP:
return "psp";
}
assert( 0 );

View File

@@ -86,6 +86,7 @@ Then you can use another oneliner to query all variables:
#undef XASH_X86
#undef XASH_NSWITCH
#undef XASH_PSVITA
#undef XASH_PSP
//================================================================
//
@@ -98,6 +99,8 @@ Then you can use another oneliner to query all variables:
#define XASH_EMSCRIPTEN 1
#elif defined __WATCOMC__ && defined __DOS__
#define XASH_DOS4GW 1
#elif defined __psp__
#define XASH_PSP 1
#else // POSIX compatible
#define XASH_POSIX 1
#if defined __linux__
@@ -144,7 +147,7 @@ Then you can use another oneliner to query all variables:
// but we still need XASH_MOBILE_PLATFORM for the engine.
// So this macro is defined entirely in build-system: see main wscript
// HLSDK/PrimeXT/other SDKs users note: you may ignore this macro
#if XASH_ANDROID || XASH_IOS || XASH_NSWITCH || XASH_PSVITA || XASH_SAILFISH
#if XASH_ANDROID || XASH_IOS || XASH_NSWITCH || XASH_PSVITA || XASH_SAILFISH || XASH_PSP
#define XASH_MOBILE_PLATFORM 1
#endif

View File

@@ -42,6 +42,7 @@ GNU General Public License for more details.
#define PLATFORM_NSWITCH 13
#define PLATFORM_PSVITA 14
#define PLATFORM_LINUX_UNKNOWN 15
#define PLATFORM_PSP 16
#if XASH_WIN32
#define XASH_PLATFORM PLATFORM_WIN32
@@ -73,6 +74,8 @@ GNU General Public License for more details.
#define XASH_PLATFORM PLATFORM_NSWITCH
#elif XASH_PSVITA
#define XASH_PLATFORM PLATFORM_PSVITA
#elif XASH_PSP
#define XASH_PLATFORM PLATFORM_PSP
#else
#error
#endif

View File

@@ -35,13 +35,61 @@ const matrix3x4 m_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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
"vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3]
"vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3]
"vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3]
"sv.s S000, 0 + %0\n" // out[0] = S000
"sv.s S001, 4 + %0\n" // out[1] = S001
"sv.s S002, 8 + %0\n" // out[2] = S002
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in ), "m"( *v )
);
#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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
"vsub.t C130, C130, R103\n" // C130 = v - in[][3]
#if 1
"vtfm3.t C000, E100, C130\n" // C000 = E100 * C130
#else
"vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0]
"vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1]
"vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2]
#endif
"sv.s S000, 0 + %0\n" // out[0] = S000
"sv.s S001, 4 + %0\n" // out[1] = S001
"sv.s S002, 8 + %0\n" // out[2] = S002
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in ), "m"( *v )
);
#else
vec3_t dir;
dir[0] = v[0] - in[0][3];
@@ -51,24 +99,99 @@ 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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
#if 1
"vtfm3.t C000, M100, C130\n" // C000 = M100 * C130
#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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
#if 1
"vtfm3.t C000, E100, C130\n" // C000 = E100 * C130
#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 )
{
#if XASH_PSP
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C100, 0 + %1\n" // C100 = in1[0]
"lv.q C110, 16 + %1\n" // C110 = in1[1]
"lv.q C120, 32 + %1\n" // C120 = in1[2]
"vzero.q C130\n" // C130 = [0, 0, 0, 0]
"lv.q C200, 0 + %2\n" // C100 = in2[0]
"lv.q C210, 16 + %2\n" // C110 = in2[1]
"lv.q C220, 32 + %2\n" // C120 = in2[2]
"vidt.q C230\n" // C230 = [0, 0, 0, 1]
"vmmul.q E000, E100, E200\n" // E000 = E100 * E200
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in1 ), "m"( *in2 )
);
#else
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
@@ -81,6 +204,7 @@ void Matrix3x4_ConcatTransforms( matrix3x4 out, const matrix3x4 in1, const matri
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];
#endif
}
void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out )
@@ -105,6 +229,31 @@ void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out )
void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin )
{
#if XASH_PSP
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C130, %1\n" // C130 = quaternion
"lv.s S300, 0 + %2\n" // S300 = origin[0]
"lv.s S301, 4 + %2\n" // S301 = origin[1]
"lv.s S302, 8 + %2\n" // S302 = origin[2]
"vmov.q C100, C130[ W, Z, -Y, -X]\n" // C100 = ( w, z, -y, -x)
"vmov.q C110, C130[-Z, W, X, -Y]\n" // C110 = (-z, w, x, -y)
"vmov.q C120, C130[ Y, -X, W, -Z]\n" // C120 = ( y, -x, w, -z)
"vmov.q C200, C130[ W, Z, -Y, X]\n" // C200 = ( w, z, -y, x)
"vmov.q C210, C130[-Z, W, X, Y]\n" // C210 = (-z, w, x, y)
"vmov.q C220, C130[ Y, -X, W, Z]\n" // C220 = ( y, -x, w, z)
"vmov.q C230, C130[-X, -Y, -Z, W]\n" // C230 = (-x, -y, -z, w)
"vmmul.q M000, E100, E200\n" // M000 = E100 * E200
"vmov.t R003, C300\n" // out[x][3] = origin[x]
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *quaternion ), "m"( *origin )
);
#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];
@@ -120,10 +269,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 0/*XASH_PSP*/ /* performance not tested */ /* BUG */
if( angles[ROLL] )
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.s S100, 0 + %1\n" // S100 = angles[PITCH]
"lv.s S101, 4 + %1\n" // S101 = angles[YAW]
"lv.s S102, 8 + %1\n" // S102 = angles[ROLL]
"lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0]
"lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1]
"lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2]
"lv.s S130, %3\n" // S130 = scale
/**/
"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
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
else if( angles[PITCH] )
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.s S100, 0 + %1\n" // S100 = angles[PITCH]
"lv.s S101, 4 + %1\n" // S101 = angles[YAW]
"lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0]
"lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1]
"lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2]
"lv.s S130, %3\n" // S130 = scale
/**/
"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
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
else if( angles[YAW] )
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.s S101, 4 + %1\n" // S101 = angles[YAW]
"lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0]
"lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1]
"lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2]
"lv.s S130, %3\n" // S130 = scale
/**/
"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
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
else
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.s S003, 0 + %1\n" // S003 = out[0][3] = origin[0]
"lv.s S013, 4 + %1\n" // S013 = out[1][3] = origin[1]
"lv.s S023, 8 + %1\n" // S023 = out[2][3] = origin[2]
"lv.s S130, %2\n" // S130 = scale
/**/
"vzero.t C000\n" // C000 = [0.0f, 0.0f, 0.0f]
"vzero.t C010\n" // C010 = [0.0f, 0.0f, 0.0f]
"vzero.t C020\n" // C020 = [0.0f, 0.0f, 0.0f]
"vmov.s S000, S130\n" // S000 = S130 = out[0][0] = scale
"vmov.s S011, S130\n" // S011 = S130 = out[1][1] = scale
"vmov.s S022, S130\n" // S022 = S130 = out[2][2] = scale
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *origin ), "m"( scale )
);
}
#else
float angle, sr, sp, sy, cr, cp, cy;
if( angles[ROLL] )
@@ -201,6 +506,7 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_
out[2][2] = scale;
out[2][3] = origin[2];
}
#endif
}
/*
@@ -242,13 +548,61 @@ const matrix4x4 m_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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
"vhdp.q S000, C130, C100\n" // S000 = v[0] * in[0][0] + v[1] * in[0][1] + v[2] * in[0][2] + in[0][3]
"vhdp.q S001, C130, C110\n" // S001 = v[0] * in[1][0] + v[1] * in[1][1] + v[2] * in[1][2] + in[1][3]
"vhdp.q S002, C130, C120\n" // S002 = v[0] * in[2][0] + v[1] * in[2][1] + v[2] * in[2][2] + in[2][3]
"sv.s S000, 0 + %0\n" // out[0] = S000
"sv.s S001, 4 + %0\n" // out[1] = S001
"sv.s S002, 8 + %0\n" // out[2] = S002
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in ), "m"( *v )
);
#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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
"vsub.t C130, C130, R103\n" // C130 = v - in[][3]
#if 1
"vtfm3.t C000, E100, C130\n" // C000 = E100 * C130
#else
"vdot.t S000, C130, R100\n" // S000 = dir[0] * in[0][0] + dir[1] * in[1][0] + dir[2] * in[2][0]
"vdot.t S001, C130, R101\n" // S001 = dir[0] * in[0][1] + dir[1] * in[1][1] + dir[2] * in[2][1]
"vdot.t S002, C130, R102\n" // S002 = dir[0] * in[0][2] + dir[1] * in[1][2] + dir[2] * in[2][2]
#endif
"sv.s S000, 0 + %0\n" // out[0] = S000
"sv.s S001, 4 + %0\n" // out[1] = S001
"sv.s S002, 8 + %0\n" // out[2] = S002
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in ), "m"( *v )
);
#else
vec3_t dir;
dir[0] = v[0] - in[0][3];
@@ -258,24 +612,99 @@ 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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
#if 1
"vtfm3.t C000, M100, C130\n" // C000 = M100 * C130
#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
"lv.q C100, 0 + %1\n" // C100 = in[0]
"lv.q C110, 16 + %1\n" // C110 = in[1]
"lv.q C120, 32 + %1\n" // C120 = in[2]
"lv.s S130, 0 + %2\n" // S130 = v[0]
"lv.s S131, 4 + %2\n" // S131 = v[1]
"lv.s S132, 8 + %2\n" // S132 = v[2]
#if 1
"vtfm3.t C000, E100, C130\n" // C000 = E100 * C130
#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 )
{
#if XASH_PSP
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C100, 0 + %1\n" // C100 = in1[0]
"lv.q C110, 16 + %1\n" // C110 = in1[1]
"lv.q C120, 32 + %1\n" // C120 = in1[2]
"vzero.q C130\n" // C130 = [0, 0, 0, 0]
"lv.q C200, 0 + %2\n" // C100 = in2[0]
"lv.q C210, 16 + %2\n" // C110 = in2[1]
"lv.q C220, 32 + %2\n" // C120 = in2[2]
"vidt.q C230\n" // C230 = [0, 0, 0, 1]
"vmmul.q E000, E100, E200\n" // E000 = E100 * E200
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in1 ), "m"( *in2 )
);
#else
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
@@ -288,10 +717,174 @@ void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matri
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];
#endif
}
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale )
{
#if 0/*XASH_PSP*/ /* performance not tested */ /* BUG */
if( angles[ROLL] )
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.s S100, 0 + %1\n" // S100 = angles[PITCH]
"lv.s S101, 4 + %1\n" // S101 = angles[YAW]
"lv.s S102, 8 + %1\n" // S102 = angles[ROLL]
"lv.s S003, 0 + %2\n" // S003 = out[0][3] = origin[0]
"lv.s S013, 4 + %2\n" // S013 = out[1][3] = origin[1]
"lv.s S023, 8 + %2\n" // S023 = out[2][3] = origin[2]
"lv.s S130, %3\n" // S130 = scale
/**/
"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]
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
"sv.q C030, 48 + %0\n" // out[3] = C030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
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]
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
"sv.q C030, 48 + %0\n" // out[3] = C030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
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]
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
"sv.q C030, 48 + %0\n" // out[3] = C030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *angles ), "m"( *origin ), "m"( scale )
);
}
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
/**/
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
"sv.q C030, 48 + %0\n" // out[3] = C030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *origin ), "m"( scale )
);
}
#else
float angle, sr, sp, sy, cr, cp, cy;
if( angles[ROLL] )
@@ -385,6 +978,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 )
@@ -412,6 +1006,36 @@ 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
"mfc1 $8, %4\n" // FPU->CPU
"mtv $8, S210\n" // CPU->VFPU S210 = d
"lv.q C100, 0 + %2\n" // C100 = in[0]
"lv.q C110, 16 + %2\n" // C110 = in[1]
"lv.q C120, 32 + %2\n" // C120 = in[2]
"lv.s S200, 0 + %3\n" // S200 = normal[0]
"lv.s S201, 4 + %3\n" // S201 = normal[1]
"lv.s S202, 8 + %3\n" // S202 = normal[2]
"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 ), "f"( d )
: "$8"
);
#else
float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] );
float iscale = 1.0f / scale;
@@ -419,6 +1043,7 @@ 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_Invert_Simple( matrix4x4 out, const matrix4x4 in1 )

0
public/rbtree.h Normal file
View File

View File

@@ -16,7 +16,7 @@ def configure(conf):
def build(bld):
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
bld.stlib(source = bld.path.ant_glob('*.c'),
bld.stlib(source = bld.path.ant_glob('*.c') + bld.path.ant_glob('*.S'),
target = 'public',
features = 'c',
use = 'sdk_includes',

View File

@@ -209,6 +209,30 @@ rsqrt
*/
float rsqrt( float number )
{
#if XASH_PSP
#if 0 /* experimental */
if( number == 0.0f ) return 0.0f;
return ( 1.0 / __builtin_allegrex_sqrt_s( number ));
#else
float result;
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"mfc1 $8, %1\n" // FPU->CPU
"mtv $8, S000\n" // CPU->VFPU S000 = number
"vzero.s S001\n" // S100 = 0
"vcmp.s EZ, S000\n" // CC[0] = ( S000 == 0.0f )
"vrsq.s S000, S000\n" // S000 = 1.0 / sqrt( S000 )
"vcmovt.s S000, S001, 0\n" // if ( CC[0] ) S000 = S001
"sv.s S000, %0\n" // result = S000
".set pop\n" // restore assembler option
: "=m"( result )
: "f"( number )
: "$8"
);
return result;
#endif
#else
int i;
float x, y;
@@ -222,6 +246,7 @@ float rsqrt( float number )
y = y * (1.5f - (x * y * y)); // first iteration
return y;
#endif
}
/*
@@ -384,6 +409,7 @@ void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, v
//
// bounds operations
//
/*
=================
AddPointToBounds
@@ -485,6 +511,46 @@ AngleQuaternion
*/
void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio )
{
#if XASH_PSP
vec4_t dst_angles;
if( studio )
{
dst_angles[0] = angles[PITCH];
dst_angles[1] = angles[YAW];
dst_angles[2] = angles[ROLL];
}
else
{
dst_angles[0] = DEG2RAD( angles[ROLL] );
dst_angles[1] = DEG2RAD( angles[PITCH] );
dst_angles[2] = DEG2RAD( angles[YAW] );
}
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C000, %1\n" // C000 = [PITCH, YAW, ROLL]
"vcst.s S010, VFPU_1_PI\n" // S010 = VFPU_1_PI = 1 / PI
"vscl.t C000, C000, S010\n" // C000 = C000 * S010 = C000 * 0.5f * ( 2 / PI )
"vcos.t C010, C000\n" // C010 = cos( C000 * 0.5f )
"vsin.t C000, C000\n" // C000 = sin( C000 * 0.5f )
"vcrs.t C020, C010, C010\n" // C020 = ( cp*cy, cy*cr, cr*cp )
"vcrs.t C030, C000, C000\n" // C030 = ( sp*sy, sy*sr, sr*sp )
"vmul.s S003, S020, S010\n" // S003 = S020 * S010 = cp*cy*cr
"vmul.s S013, S030, S000\n" // S013 = S030 * S000 = sp*sy*sr
"vmul.t C020, C020, C000\n" // C020 = C020 * C000 = ( cp*cy*sr, cy*cr*sp, cr*cp*sy )
"vmul.t C030, C030, C010\n" // C030 = C030 * C010 = ( sp*sy*cr, sy*sr*cp, sr*sp*cy )
"vadd.s S003, S003, S013\n" // S003 = S003 + S013 = cp*cy*cr + cp*cy*cr
"vadd.t C000, C020, C030[-X, Y, -Z]\n"
// S000 = S020 - C030 = cp*cy*sr - sp*sy*cr
// S001 = S021 + C031 = cy*cr*sp + sy*sr*cp
// S002 = S022 - C032 = cr*cp*sy - sr*sp*cy
"sv.q C000, %0\n" // *q = C000
".set pop\n" // restore assembler option
: "=m"( *q )
: "m"( dst_angles )
);
#else
float sr, sp, sy, cr, cp, cy;
if( studio )
@@ -504,6 +570,7 @@ 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
#endif
}
/*
@@ -527,6 +594,7 @@ make sure quaternions are within 180 degrees of one another,
if not, reverse q
====================
*/
#if !XASH_PSP
void QuaternionAlign( const vec4_t p, const vec4_t q, vec4_t qt )
{
// decide if one of the quaternions is backwards
@@ -615,9 +683,9 @@ void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt )
// 0.0 returns p, 1.0 return q.
// decide if one of the quaternions is backwards
QuaternionAlign( p, q, q2 );
QuaternionSlerpNoAlign( p, q2, t, qt );
}
#endif // XASH_PSP
/*
==================
@@ -626,10 +694,11 @@ BoxOnPlaneSide
Returns 1, 2, or 1 + 2
==================
*/
#if !XASH_PSP
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
{
float dist1, dist2;
int sides = 0;
float dist1, dist2;
// general case
switch( p->signbits )
@@ -679,6 +748,7 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
return sides;
}
#endif // !XASH_PSP
/*
====================

View File

@@ -175,8 +175,26 @@ static inline float UintAsFloat( uint32_t u )
static inline void SinCos( float radians, float *sine, float *cosine )
{
#if XASH_PSP
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"mfc1 $8, %2\n" // FPU->CPU
"mtv $8, S000\n" // CPU->VFPU S000 = radians
"vcst.s S001, VFPU_2_PI\n" // S001 = VFPU_2_PI = 2 / PI
"vmul.s S000, S000, S001\n" // S000 = S000 * S001
"vrot.p C002, S000, [s, c]\n" // S002 = sin( radians ), S003 = cos( radians )
"sv.s S002, %0\n" // sine = S002
"sv.s S003, %1\n" // cosine = S003
".set pop\n" // restore assembler option
: "=m"( *sine), "=m"( *cosine )
: "f"( radians )
: "$8"
);
#else
*sine = sin(radians);
*cosine = cos(radians);
#endif
}
float rsqrt( float number );

218
public/xash3d_mathlib_asm.S Normal file
View File

@@ -0,0 +1,218 @@
/*
xash3d_mathlib_asm.S - internal mathlib ASM ver.
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "build.h"
#if XASH_PSP
#include "as_reg_compat.h"
.set noreorder
.set noat
.text
.align 4
.global QuaternionSlerp
.global BoxOnPlaneSide
// void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt );
.ent QuaternionSlerp
QuaternionSlerp:
############################
# a0 - IN *p #
# a1 - IN *q #
# f12 - IN t #
# a2 - IN *qt #
############################
mfc1 $t0, $f12
mtv $t0, S031 // S031 = sclq = t
li $t0, 0x358637bd // t0 = EPSILON = 0.000001f
mtv $t0, S033 // S002 = t0 = EPSILON
lv.q C010, 0($a0) // C010 = p
lv.q C020, 0($a1) // C020 = q
// QuaternionAlign
vsub.q C100, C010, C020 // C100 = p[*] - q[*]
vadd.q C110, C010, C020 // C110 = p[*] + q[*]
vdot.q S000, C100, C100 // S000 = a += (p[*] - q[*]) * (p[*] - q[*])
vdot.q S001, C110, C110 // S001 = b += (p[*] + q[*]) * (p[*] + q[*])
vcmp.s GT, S000, S001 // CC[0] = a > b
vcmovt.q C020, C020[-X,-Y,-Z,-W], 0 // if CC[0] q = -q
// ***
// QuaternionSlerpNoAlign
vdot.q S000, C010, C020 // S000 = cosom += p[*] * q[*]
vadd.s S001, S000[1], S000 // S002 = 1.0f + cosom
vcmp.s LE, S001, S033 // CC[0] = ( 1.0f + cosom ) <= 0.000001f
bvt 0, Lqs2 // if CC[0] goto Lqs2
vocp.s S030, S031 // S030 = sclp = 1.0f - t (delay slot)
vsub.s S001, S000[1], S000 // S002 = 1.0f - cosom
vcmp.s LE, S001, S033 // CC[0] = ( 1.0f - cosom ) <= 0.000001f
bvt 0, Lqs1
nop
// acos
vcst.s S001, VFPU_SQRT1_2 // S001 = VFPU_SQRT1_2 = 1 / sqrt(2)
vcmp.s LT, S000[|x|], S001 // CC[0] = abs(cosom) < (1 / sqrt(2))
vasin.s S032, S000[|x|] // S032 = asin(abs(cosom))
bvtl 0, Lqs0 // if CC[0] goto Lqs0
vocp.s S032, S032 // S032 = 1 - S032 = acos(abs(cosom)) = omega (bvtl delay slot)
vmul.s S001, S000, S000 // S001 = cosom * cosom
vocp.s S001[0:1], S001 // S001 = 1 - S001[0:1]
vsqrt.s S001, S001 // S001 = sqrt(S001)
vasin.s S032, S001 // S032 = asin(S001) = acos(abs(cosom)) = omega
// ***
Lqs0:
vscl.p C030, C030, S032 // S030 = S030 * S032 = sclp * omega
// S031 = S031 * S032 = sclq * omega
vsin.t C030, C030 // S030 = sin(S030) = sin(sclp * omega) = sclp
// S031 = sin(S031) = sin(sclq * omega) = sclq
// S032 = sin(S032) = sin(omega)
vrcp.s S032, S032 // S032 = 1.0f / S032 = 1 / sin(omega) = sinom
vscl.p C030, C030, S032 // S030 = S030 * S032 = sin(sclp * omega) / sinom
// S031 = S031 * S032 = sin(sclq * omega) / sinom
Lqs1:
vscl.q C010, C010, S030 // C010 = p[*4] * sclp
vscl.q C020, C020, S031 // C020 = qt[*4] * sclq
b LqsEnd // goto LqsEnd
vadd.q C000, C010, C020 // S000 = qt[0] = sclp * p[0] + sclq * qt[0] (delay slot)
// S001 = qt[1] = sclp * p[1] + sclq * qt[1]
// S002 = qt[2] = sclp * p[2] + sclq * qt[2]
// S003 = qt[3] = sclp * p[3] + sclq * qt[3]
Lqs2:
vmov.q C000, C020[-Y,X,-W,Z] // S000 = qt[0] = -q[1];
// S001 = qt[1] = q[0];
// S002 = qt[2] = -q[3];
// S003 = qt[3] = q[2];
vsin.p C030, C030 // S030 = sclp = sin(( 1.0f - t ) * ( 0.5f * M_PI_F ))
// S031 = sclq = sin( t * ( 0.5f * M_PI_F ))
vscl.t C010, C010, S030 // C000 = p[*3] * sclp
vscl.t C020, C000, S031 // C030 = qt[*3] * sclq
vadd.t C000, C010, C020 // S000 = qt[0] = sclp * p[0] + sclq * qt[0]
// S001 = qt[1] = sclp * p[1] + sclq * qt[1]
// S002 = qt[2] = sclp * p[2] + sclq * qt[2]
// S003 = qt[3]
LqsEnd:
sv.q C000, 0($a2)
jr $ra
.end QuaternionSlerp
// int BoxOnPlaneSide( vec3_t emins, vec3_t emaxs, mplane_t *p );
.ent BoxOnPlaneSide
BoxOnPlaneSide:
############################
# a0 - IN *emins #
# a1 - IN *emaxs #
# a2 - IN *p #
# v0 - OUT sides #
############################
lbu $v0, 17($a2) // p->signbits
sltiu $v1, $v0, 8 // if(signbits > 8)
beq $v1, $zero, LSetSides // jump to LSetSides
vzero.p C030 // set zero vector
sll $v1, $v0, 2
la $v0, Ljmptab
addu $v0, $v0, $v1
lw $v0, 0($v0)
lv.s S000, 0($a2) // p->normal[0]
lv.s S001, 4($a2) // p->normal[1]
jr $v0
lv.s S002, 8($a2) // p->normal[2]
Lcase0:
lv.s S010, 0($a1) // emaxs[0]
lv.s S011, 4($a1) // emaxs[1]
lv.s S012, 8($a1) // emaxs[2]
lv.s S020, 0($a0) // emins[0]
lv.s S021, 4($a0) // emins[1]
b LDotProduct
lv.s S022, 8($a0) // emins[2]
Lcase1:
lv.s S010, 0($a0) // emins[0]
lv.s S011, 4($a1) // emaxs[1]
lv.s S012, 8($a1) // emaxs[2]
lv.s S020, 0($a1) // emaxs[0]
lv.s S021, 4($a0) // emins[1]
b LDotProduct
lv.s S022, 8($a0) // emins[2]
Lcase2:
lv.s S010, 0($a1) // emaxs[0]
lv.s S011, 4($a0) // emins[1]
lv.s S012, 8($a1) // emaxs[2]
lv.s S020, 0($a0) // emins[0]
lv.s S021, 4($a1) // emaxs[1]
b LDotProduct
lv.s S022, 8($a0) // emins[2]
Lcase3:
lv.s S010, 0($a0) // emins[0]
lv.s S011, 4($a0) // emins[1]
lv.s S012, 8($a1) // emaxs[2]
lv.s S020, 0($a1) // emaxs[0]
lv.s S021, 4($a1) // emaxs[1]
b LDotProduct
lv.s S022, 8($a0) // emins[2]
Lcase4:
lv.s S010, 0($a1) // emaxs[0]
lv.s S011, 4($a1) // emaxs[1]
lv.s S012, 8($a0) // emins[2]
lv.s S020, 0($a0) // emins[0]
lv.s S021, 4($a0) // emins[1]
b LDotProduct
lv.s S022, 8($a1) // emaxs[2]
Lcase5:
lv.s S010, 0($a0) // emins[0]
lv.s S011, 4($a1) // emaxs[1]
lv.s S012, 8($a0) // emins[2]
lv.s S020, 0($a1) // emaxs[0]
lv.s S021, 4($a0) // emins[1]
b LDotProduct
lv.s S022, 8($a1) // emaxs[2]
Lcase6:
lv.s S010, 0($a1) // emaxs[0]
lv.s S011, 4($a0) // emins[1]
lv.s S012, 8($a0) // emins[2]
lv.s S020, 0($a0) // emins[0]
lv.s S021, 4($a1) // emaxs[1]
b LDotProduct
lv.s S022, 8($a1) // emaxs[2]
Lcase7:
lv.s S010, 0($a0) // emins[0]
lv.s S011, 4($a0) // emins[1]
lv.s S012, 8($a0) // emins[2]
lv.s S020, 0($a1) // emaxs[0]
lv.s S021, 4($a1) // emaxs[1]
lv.s S022, 8($a1) // emaxs[2]
LDotProduct:
vdot.t S030, C000, C010 // S030 = C000 * C010
vdot.t S031, C000, C020 // S031 = C000 * C020
LSetSides:
lv.s S013, 12($a2) // p->dist
vcmp.s LT, S030, S013 // S030 < S013
bvt 0, LDist2 // if ( CC[0] == 1 ) jump to LDist2
li $v0, 0 // sides = 0
li $v0, 1 // sides = 1
LDist2:
vcmp.s GE, S031, S013 // S031 >= S013
bvt 0, LEnd // if ( CC[0] == 1 ) jump to LEnd
nop
ori $v0, $v0, 2
LEnd:
jr $ra
nop
.end BoxOnPlaneSide
.section .rodata
.align 4
Ljmptab:
.word Lcase0, Lcase1, Lcase2, Lcase3, Lcase4, Lcase5, Lcase6, Lcase7
#endif // XASH_PSP

View File

@@ -142,7 +142,6 @@ void _TriColor4ub( byte r, byte g, byte b, byte a )
pglColor4ub( r, g, b, a );
}
/*
=============
TriColor4ub
@@ -365,4 +364,3 @@ void TriBrightness( float brightness )
_TriColor4f( r, g, b, 1.0f );
}

1
ref/soft/exports.txt Normal file
View File

@@ -0,0 +1 @@
GetRefAPI

View File

@@ -201,6 +201,19 @@ void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int textu
// Build the initial list of vertices from the surface verts into the global array, 'verts'.
void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t textureSpaceBasis[3], float *verts )
{
#if XASH_PSP
int i;
if( !surf->polys )
return;
for( i = 0; i < surf->polys->numverts; i++, verts += VERTEXSIZE )
{
VectorCopy( surf->polys->verts[i].xyz, verts ); // copy model space coordinates
verts[3] = DotProduct( verts, textureSpaceBasis[0] ) - pDecal->dx + 0.5f;
verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - pDecal->dy + 0.5f;
verts[5] = verts[6] = 0.0f;
}
#else
float *v;
int i;
@@ -213,6 +226,7 @@ void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t tex
verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - pDecal->dy + 0.5f;
verts[5] = verts[6] = 0.0f;
}
#endif
}
// Figure out where the decal maps onto the surface.
@@ -524,7 +538,26 @@ glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t
v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &lnumverts );
if( !lnumverts ) return NULL; // probably this never happens
#if XASH_PSP
// allocate glpoly
// REFTODO: com_studiocache pool!
poly = Mem_Calloc( r_temppool, sizeof( glpoly_t ) + ( lnumverts * 2 - 1 ) * sizeof( gu_vert_t ));
poly->next = pdecal->polys;
poly->flags = surf->flags;
pdecal->polys = poly;
poly->numverts = lnumverts;
for( i = 0; i < lnumverts; i++, v += VERTEXSIZE )
{
poly->verts[i].uv[0] = v[3];
poly->verts[i].uv[1] = v[4];
VectorCopy( v, poly->verts[i].xyz );
poly->verts[i + lnumverts].uv[0] = v[5];
poly->verts[i + lnumverts].uv[1] = v[6];
VectorCopy( v, poly->verts[i + lnumverts].xyz );
}
#else
// allocate glpoly
// REFTODO: com_studiocache pool!
poly = Mem_Calloc( r_temppool, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
@@ -541,7 +574,7 @@ glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t
poly->verts[i][5] = v[5];
poly->verts[i][6] = v[6];
}
#endif
return poly;
}
@@ -861,8 +894,18 @@ float * GAME_EXPORT R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int te
{
v = g_DecalClipVerts[0];
count = p->numverts;
#if XASH_PSP
// if we have mesh so skip clipping and just copy vertexes out (perf)
for( i = 0; i < count; i++, v += VERTEXSIZE )
{
VectorCopy( p->verts[i].xyz, v );
v[3] = p->verts[i].uv[0];
v[4] = p->verts[i].uv[1];
v[5] = p->verts[i + count].uv[0];
v[6] = p->verts[i + count].uv[1];
}
#else
v2 = p->verts[0];
// if we have mesh so skip clipping and just copy vertexes out (perf)
for( i = 0; i < count; i++, v += VERTEXSIZE, v2 += VERTEXSIZE )
{
@@ -872,7 +915,7 @@ float * GAME_EXPORT R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int te
v[5] = v2[5];
v[6] = v2[6];
}
#endif
// restore pointer
v = g_DecalClipVerts[0];
}

View File

@@ -492,4 +492,3 @@ void TriBrightness( float brightness )
_TriColor4f( r, g, b, 1.0f );
}

2
ref_gu/exports.txt Normal file
View File

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

1551
ref_gu/gu_alias.c Normal file

File diff suppressed because it is too large Load Diff

683
ref_gu/gu_backend.c Normal file
View File

@@ -0,0 +1,683 @@
/*
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 )
{
ScePspFMatrix4 dest;
Matrix4x4_ToFMatrix4( source, &dest );
sceGumLoadMatrix( &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;
}
}
/*
=================
GL_SetColor4ub
=================
*/
void GL_SetColor4ub( byte r, byte g, byte b, byte a )
{
sceGuColor( GU_RGBA( r, g, b, a ));
}
/*
==============================================================================
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 )
{
rgbdata_t *r_shot;
uint flags = 0;
int width = 0, height = 0;
qboolean result;
int bpp;
r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t ));
r_shot->width = (gpGlobals->width + 3) & ~3;
r_shot->height = (gpGlobals->height + 3) & ~3;
r_shot->flags = IMAGE_HAS_COLOR;
r_shot->type = PF_RGB_24;
bpp = gEngfuncs.Image_GetPFDesc( r_shot->type )->bpp;
r_shot->size = r_shot->width * r_shot->height * bpp;
r_shot->palette = NULL;
r_shot->buffer = Mem_Malloc( r_temppool, r_shot->size );
// get screen frame
byte *src = ( byte* )guRender.disp_buffer;
byte *dst = r_shot->buffer;
int cheight = r_shot->height;
// stride copy
while( cheight-- )
{
GL_PixelConverter( dst, src, r_shot->width, PC_HWF( guRender.buffer_format ), PC_SWF( r_shot->type ) );
dst += r_shot->width * bpp;
src += guRender.buffer_width * guRender.buffer_bpp;
}
switch( shot_type )
{
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;
}
/*
=================
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 );
}

1410
ref_gu/gu_beams.c Normal file

File diff suppressed because it is too large Load Diff

337
ref_gu/gu_clipping.c Normal file
View File

@@ -0,0 +1,337 @@
/*
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.
*/
/*
VFPU REGS:
M700 - current frustum
M600 - world frustum
C010 - current plane ( GU_Clip2Plane )
*/
#include "gu_local.h"
#define MAX_CLIPPED_VERTICES 32
// Cache
static ScePspFMatrix4 projection_view_matrix;
// The temporary working buffers.
static gu_vert_t work_buffer[2][MAX_CLIPPED_VERTICES] __attribute__(( aligned( 16 )));
/*
=================
GU_ClipGetFrustum
=================
*/
_inline void GU_ClipGetAndStoreFrustum( const ScePspFMatrix4 *matrix )
{
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vzero.q C210\n" // set zero vector
"lv.q C100, 0(%0)\n" // C000 = matrix->x
"lv.q C110, 16(%0)\n" // C010 = matrix->y
"lv.q C120, 32(%0)\n" // C020 = matrix->z
"lv.q C130, 48(%0)\n" // C030 = matrix->w
"vadd.q C000, R103, R101\n" // C000 = R103 + R101 ( BOTTOM )
"vadd.q C010, R103, R100\n" // C010 = R103 + R100 ( LEFT )
"vsub.q C020, R103, R100\n" // C020 = R103 - R100 ( RIGHT )
"vsub.q C030, R103, R101\n" // C030 = R103 - R101 ( TOP )
"vdot.q S200, C000, C000\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( BOTTOM )
"vdot.q S201, C010, C010\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( LEFT )
"vdot.q S202, C020, C020\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( RIGHT )
"vdot.q S203, C030, C030\n" // S110 = S100*S100 + S101*S101 + S102*S102 + S103*S103 ( TOP )
"vcmp.q EZ, C200\n" // CC[*] = ( C200 == 0.0f )
"vrsq.q C200, C200\n" // C200 = 1.0 / sqrt( C200 )
"vcmovt.q C200, C210, 6\n" // if ( CC[*] ) C200 = C210
"vscl.q C700, C000, S200\n" // C700 = C000 * S200 ( BOTTOM )
"vscl.q C710, C010, S201\n" // C710 = C010 * S201 ( LEFT )
"vscl.q C720, C020, S202\n" // C720 = C020 * S202 ( RIGHT )
"vscl.q C730, C030, S203\n" // C730 = C030 * S203 ( TOP )
".set pop\n" // Restore assembler option
:: "r"( matrix )
);
}
/*
=================
GU_ClipBeginFrame
Calculate the clipping frustum for static objects
=================
*/
void GU_ClipSetWorldFrustum( const matrix4x4 in )
{
// Get matrix.
Matrix4x4_ToFMatrix4( in, &projection_view_matrix );
// Calculate and cache the clipping frustum.
GU_ClipGetAndStoreFrustum( &projection_view_matrix );
// Save the clipping frustum.
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmmov.q M600, M700\n" // Save frustum
".set pop\n" // Restore assembler option
);
}
/*
=================
GU_ClipRestoreWorldFrustum
Restore the clipping frustum
=================
*/
void GU_ClipRestoreWorldFrustum( void )
{
// Restore the clipping frustum.
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmmov.q M700, M600\n" // Restore frustum
".set pop\n" // Restore assembler option
);
}
/*
=================
GU_ClipSetModelFrustum
Calculate the clipping frustum for dynamic objects
=================
*/
void GU_ClipSetModelFrustum( const matrix4x4 in )
{
ScePspFMatrix4 model_matrix;
ScePspFMatrix4 projection_view_model_matrix;
// Get matrix.
Matrix4x4_ToFMatrix4( in, &model_matrix );
// Combine the matrices (multiply projection-view by model).
gumMultMatrix( &projection_view_model_matrix, &projection_view_matrix, &model_matrix );
// Calculate and cache the clipping frustum.
GU_ClipGetAndStoreFrustum( &projection_view_model_matrix );
}
/*
=================
GU_ClipLoadFrustum
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, %0\n" // Load plane into register
"ulv.q C710, %1\n" // Load plane into register
"ulv.q C720, %2\n" // Load plane into register
"ulv.q C730, %3\n" // Load plane into register
"vneg.q R703, R703\n" // R703 = -R703 = -dist
".set pop\n" // Restore assembler option
:: "m"( plane[FRUSTUM_BOTTOM] ),
"m"( plane[FRUSTUM_LEFT] ),
"m"( plane[FRUSTUM_RIGHT] ),
"m"( plane[FRUSTUM_TOP] )
);
}
#endif
/*
=================
GU_ClipIsRequired
Is clipping required?
=================
*/
int GU_ClipIsRequired( gu_vert_t* uv, int uvc )
{
int result = 1;
gu_vert_t *uv_end = uv + ( uvc - 1 );
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vzero.q C000\n" // C000 = [0.0f, 0.0f, 0.0f. 0.0f]
"0:\n" // loop
"lv.s S010, 8(%1)\n" // S010 = v[i].xyz[0]
"lv.s S011, 12(%1)\n" // S011 = v[i].xyz[1]
"lv.s S012, 16(%1)\n" // S012 = v[i].xyz[2]
"vhtfm4.q C020, M700, C010\n" // C020 = frustrum * v[i].xyz
"vcmp.q LT, C020, C000\n" // S020 < 0.0f || S021 < 0.0f || S022 < 0.0f || S023 < 0.0f
"bvt 4, 1f\n" // if ( CC[4] == 1 ) jump to exit
"nop\n" // ( delay slot )
"bne %1, %2, 0b\n" // if ( $10 != $8 ) jump to loop
"addiu %1, %1, %3\n" // $8 = $8 + sizeof( gu_vert_t ) ( delay slot )
"move %0, $0\n" // res = 0
"1:\n" // exit
".set pop\n" // Restore assembler option
: "=r"( result ), "+r"( uv )
: "r"( uv_end ),
"n"(sizeof( gu_vert_t ))
: "$8"
);
return result;
}
/*
=================
GU_Clip2Plane
Clips a polygon against a plane.
=================
*/
_inline void GU_Clip2Plane( gu_vert_t *uv, int uvc, gu_vert_t *cv, int *cvc )
{
gu_vert_t *uv_end = uv + ( uvc - 1 );
gu_vert_t *cv_start = cv;
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vzero.q C000\n" // set zero vector
"lv.s S200, 8(%2)\n" // Load vertex P XYZ(4b) X into register
"lv.s S201, 12(%2)\n" // Load vertex P XYZ(4b) Y into register
"lv.s S202, 16(%2)\n" // Load vertex P XYZ(4b) Z into register
"lv.s S210, 0(%2)\n" // Load vertex P TEX(4b) U into register
"lv.s S211, 4(%2)\n" // Load vertex P TEX(4b) V into register
"vhdp.q S212, C200, C010\n" // distance P -> dP
"0:\n"
"lv.s S220, 8(%1)\n" // Load vertex S XYZ(4b) X into register
"lv.s S221, 12(%1)\n" // Load vertex S XYZ(4b) Y into register
"lv.s S222, 16(%1)\n" // Load vertex S XYZ(4b) Z into register
"lv.s S230, 0(%1)\n" // Load vertex S TEX(4b) U into register
"lv.s S231, 4(%1)\n" // Load vertex S TEX(4b) V into register
"vhdp.q S232, C220, C010\n" // distance S -> dS
"vcmp.s GT, S212, S000\n" // if (dP <= 0)
"bvf 0, 1f\n" // goto 1:
"nop\n"
"sv.s S210, 0(%0)\n" // cv->uv[0] = C020 U
"sv.s S211, 4(%0)\n" // cv->uv[1] = C021 V
"sv.s S200, 8(%0)\n" // cv->xyz[0] = C030 X
"sv.s S201, 12(%0)\n" // cv->xyz[1] = C031 Y
"sv.s S202, 16(%0)\n" // cv->xyz[2] = C032 Z
"addiu %0, %0, %3\n" // cv + sizeof(gu_vert_t)
"1:\n"
"vmul.s S020, S232, S212\n" // (dS * dP)
"vcmp.s LT, S020, S000\n" // if (dS * dP < 0)
"bvf 0, 2f\n" // goto 2:
"vsub.s S021, S232, S212\n" // (dS - dP)
"vrcp.s S021, S021\n"
"vmul.s S021, S021, S232\n" // R = dS / ( dS - dP )
#if 0
"vsub.t C200, C220, C200\n" // (S - P) XYZ
"vsub.p C210, C230, C210\n" // (S - P) UV
"vscl.t C200, C200, S021\n" // ((S - P) * R) XYZ
"vscl.p C210, C210, S021\n" // ((S - P) * R) UV
"vsub.t C200, C220, C200\n" // (S - (S - P) * R) XYZ
"vsub.p C210, C230, C210\n" // (S - (S - P) * R) UV
#else
"vsub.t C200, C200, C220\n" // (P - S) XYZ
"vsub.p C210, C210, C230\n" // (P - S) UV
"vscl.t C200, C200, S021\n" // ((P - S) * R) XYZ
"vscl.p C210, C210, S021\n" // ((P - S) * R) UV
"vadd.t C200, C220, C200\n" // (S + (P - S) * R) XYZ
"vadd.p C210, C230, C210\n" // (S + (P - S) * R) UV
#endif
"sv.s S210, 0(%0)\n" // cv->uv[0] = S210 U
"sv.s S211, 4(%0)\n" // cv->uv[1] = S211 V
"sv.s S200, 8(%0)\n" // cv->xyz[0] = S200 X
"sv.s S201, 12(%0)\n" // cv->xyz[1] = S201 Y
"sv.s S202, 16(%0)\n" // cv->xyz[2] = S202 Z
"addiu %0, %0, %3\n" // cv + sizeof(gu_vert_t)
"2:\n"
"vmov.t C200, C220\n" // P = S XYZ
"vmov.t C210, C230\n" // P = S UV and dS
"bne %1, %2, 0b\n" // if (uv != uv_end) goto 0:
"addiu %1, %1, %3\n" // uv + sizeof(gu_vert_t) ( delay slot )
".set pop\n" // suppress reordering
: "+r"( cv ), "+r"( uv )
: "r"( uv_end ),
"n"( sizeof( gu_vert_t ))
: "memory"
) ;
*cvc = ( cv - cv_start );
}
/*
=================
GU_Clip
Clips a polygon against the frustum
=================
*/
void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc )
{
size_t vc;
if ( !uvc ) // no vertices to clip?
gEngfuncs.Host_Error( "GU_Clip: calling clip with zero vertices!" );
vc = uvc;
*cvc = 0;
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmov.q C010, C700\n" // CPLANE_BOTTOM
".set pop\n" // suppress reordering
);
GU_Clip2Plane( uv, vc, work_buffer[0], &vc );
if ( !vc ) return;
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmov.q C010, C710\n" // CPLANE_LEFT
".set pop\n" // suppress reordering
);
GU_Clip2Plane( work_buffer[0], vc, work_buffer[1], &vc );
if ( !vc ) return;
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmov.q C010, C720\n" // CPLANE_RIGHT
".set pop\n" // suppress reordering
);
GU_Clip2Plane( work_buffer[1], vc, work_buffer[0], &vc );
if ( !vc ) return;
__asm__ volatile(
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"vmov.q C010, C730\n" // CPLANE_TOP
".set pop\n" // suppress reordering
);
*cv = extGuBeginPacket( NULL ); // uncached
GU_Clip2Plane( work_buffer[0], vc, *cv, cvc );
if (!( *cvc )) return;
extGuEndPacket(( void * )( *cv + *cvc ));
}

503
ref_gu/gu_context.c Normal file
View File

@@ -0,0 +1,503 @@
/*
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*/0;
case PARM_TEX_MIPCOUNT:
glt = R_GetTexture( arg );
return glt->numMips;
case PARM_TEX_DEPTH:
/*glt = R_GetTexture( arg );*/
return /*glt->depth*/1;
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,
GL_SetColor4ub,
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,
getTriAPI,
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->height );
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

356
ref_gu/gu_frustum.c Normal file
View File

@@ -0,0 +1,356 @@
/*
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

67
ref_gu/gu_helper.h Normal file
View File

@@ -0,0 +1,67 @@
/*
gl_helper.h - gu helper
Copyright (C) 2021 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GU_HELPER_H
#define GU_HELPER_H
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRY_LINKAGE
#define APIENTRY_LINKAGE extern
#endif
// GL types wrapping
typedef uint GLenum;
typedef byte GLboolean;
typedef uint GLbitfield;
typedef void GLvoid;
typedef signed char GLbyte;
typedef short GLshort;
typedef int GLint;
typedef byte GLubyte;
typedef word GLushort;
typedef uint GLuint;
typedef int GLsizei;
typedef float GLfloat;
typedef float GLclampf;
typedef double GLdouble;
typedef double GLclampd;
typedef int GLintptrARB;
typedef int GLsizeiptrARB;
typedef char GLcharARB;
typedef uint GLhandleARB;
typedef float GLmatrix[16];
// GL_Cull wrapping
#define GL_NONE 0
#define GL_FRONT GU_CW + 1
#define GL_BACK GU_CCW + 1
// color functions wrapping
#define GUCOLOR4F( r, g, b, a ) GU_COLOR( ( r ), ( g ), ( b ), ( a ) )
#define GUCOLOR4FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], ( v )[3] )
#define GUCOLOR4UB( r, g, b, a ) GU_RGBA( ( r ), ( g ), ( b ), ( a ) )
#define GUCOLOR4UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], ( v )[3] )
#define GUCOLOR3F( r, g, b ) GU_COLOR( ( r ), ( g ), ( b ), 1.0f )
#define GUCOLOR3FV( v ) GU_COLOR( ( v )[0], ( v )[1], ( v )[2], 1.0f )
#define GUCOLOR3UB( r, g, b ) GU_RGBA( ( r ), ( g ), ( b ), 255 )
#define GUCOLOR3UBV( v ) GU_RGBA( ( v )[0], ( v )[1], ( v )[2], 255 )
// blend function wrapping
#define GUBLEND1 0xffffffff
#define GUBLEND0 0x00000000
#endif // GU_HELPER_H

2063
ref_gu/gu_image.c Normal file

File diff suppressed because it is too large Load Diff

829
ref_gu/gu_local.h Normal file
View File

@@ -0,0 +1,829 @@
/*
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
#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspgum.h>
#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 "gu_vram.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;
#define LIGHTMAP_BPP 1 //1 2 3 4
#if LIGHTMAP_BPP == 1
#define LIGHTMAP_FORMAT PF_RGB_332
#elif LIGHTMAP_BPP == 2
#define LIGHTMAP_FORMAT PF_RGB_5650
#elif LIGHTMAP_BPP == 3
#define LIGHTMAP_FORMAT PF_RGB_24
#elif LIGHTMAP_BPP == 4
#define LIGHTMAP_FORMAT PF_RGBA_32
#else
#error (1 > LIGHTMAP_BPP > 4)
#endif
#if 1
#define BLOCK_SIZE tr.block_size // lightmap blocksize
#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 bpp;
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
//
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 );
#define PC_SWF( X ) ( ( X ) | ( 1 << 15 ) )
#define PC_HWF( X ) ( X )
void GL_PixelConverter( byte *dst, const byte *src, int size, int inFormat, int outFormat );
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
qboolean GL_UpdateTexture( int texnum, int xoff, int yoff, int width, int height, const void *buffer );
void GL_UpdateTexSize( int texnum, int width, int height, int depth );
int GL_FindTexture( const char *name );
void GL_FreeTexture( GLenum texnum );
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_ToFMatrix4( const matrix4x4 in, ScePspFMatrix4 *out );
void Matrix4x4_FromFMatrix4( matrix4x4 out, ScePspFMatrix4 *in );
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z );
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z );
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 GL_SetColor4ub( byte r, byte g, byte b, byte a );
void R_RunViewmodelEvents( void );
void R_DrawViewModel( void );
int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame );
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 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 );
uint getTriBrightness( float brightness );
int TriBoxInPVS( float *mins, float *maxs );
void TriLightAtPoint( float *pos, float *value );
void TriColor4fRendermode( float r, float g, float b, float a, int rendermode );
int getTriAPI( int version, triangleapi_t *api );
//
// gu_clipping.c
//
#define CLIPPING_DEBUGGING 0
void GU_ClipSetWorldFrustum( const matrix4x4 in );
void GU_ClipRestoreWorldFrustum( void );
void GU_ClipSetModelFrustum( const matrix4x4 in );
void GU_ClipLoadFrustum( const mplane_t *plane ); // Experimental
int GU_ClipIsRequired( gu_vert_t* uv, int uvc );
void GU_Clip( gu_vert_t *uv, int uvc, gu_vert_t **cv, int* cvc );
/*
=======================================================================
GL STATE MACHINE
=======================================================================
*/
typedef struct
{
int max_texture_size;
qboolean softwareGammaUpdate;
} 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;
typedef struct
{
int screen_width;
int screen_height;
int buffer_width;
int buffer_format;
int buffer_bpp;
void *draw_buffer;
void *disp_buffer;
void *depth_buffer;
void *context_list;
size_t context_list_size;
}gurender_t;
extern glconfig_t glConfig;
extern glstate_t glState;
extern gurender_t guRender;
// move to engine
extern glwstate_t glw_state;
extern ref_api_t gEngfuncs;
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_clear;
extern cvar_t *gl_test; // cvar to testify new effects
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;
extern cvar_t *r_fast_particles;
//
// 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

477
ref_gu/gu_render.c Normal file
View File

@@ -0,0 +1,477 @@
/*
gu_render.c - render initialization
Copyright (C) 2010 Uncle Mike
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "gu_local.h"
cvar_t *gl_texture_lodfunc;
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_vsync;
cvar_t *gl_clear;
cvar_t *gl_test;
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 *r_fast_particles;
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;
gurender_t guRender;
// Set frame buffer
#define PSP_FB_WIDTH 480
#define PSP_FB_HEIGHT 272
#define PSP_FB_BWIDTH 512
#define PSP_FB_FORMAT GU_PSM_5650 //4444,5551,5650,8888
#if PSP_FB_FORMAT == GU_PSM_4444
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == GU_PSM_5551
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == GU_PSM_5650
#define PSP_FB_BPP 2
#elif PSP_FB_FORMAT == GU_PSM_8888
#define PSP_FB_BPP 4
#endif
#define PSP_GU_LIST_SIZE 0x100000 // 1Mb
static byte context_list[PSP_GU_LIST_SIZE] __attribute__( ( aligned( 64 ) ) );
/*
===============
GU_Init
===============
*/
static void GU_Init( void )
{
memset( &guRender, 0, sizeof( guRender ));
guRender.screen_width = PSP_FB_WIDTH;
guRender.screen_height = PSP_FB_HEIGHT;
guRender.buffer_width = PSP_FB_BWIDTH;
guRender.buffer_format = PSP_FB_FORMAT;
guRender.buffer_bpp = PSP_FB_BPP;
guRender.draw_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp );
if( !guRender.draw_buffer )
gEngfuncs.Host_Error( "Memory allocation failled! (guRender.draw_buffer)\n" );
guRender.disp_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp );
if( !guRender.disp_buffer )
gEngfuncs.Host_Error( "Memory allocation failled! (guRender.disp_buffer)\n" );
guRender.depth_buffer = ( void* )valloc( guRender.buffer_width * guRender.screen_height * guRender.buffer_bpp );
if( !guRender.depth_buffer )
gEngfuncs.Host_Error( "Memory allocation failled! (guRender.depth_buffer)\n" );
guRender.context_list = context_list;
guRender.context_list_size = sizeof( context_list );
// Initialise the GU.
sceGuInit();
// Set up the GU.
sceGuStart( GU_DIRECT, guRender.context_list );
sceGuDrawBuffer( guRender.buffer_format, vrelptr( guRender.draw_buffer ), guRender.buffer_width );
sceGuDispBuffer( guRender.screen_width, guRender.screen_height, vrelptr( guRender.disp_buffer ), guRender.buffer_width );
sceGuDepthBuffer( vrelptr( guRender.depth_buffer ), guRender.buffer_width );
// Set the rendering offset and viewport.
sceGuOffset( 2048 - ( guRender.screen_width / 2 ), 2048 - ( guRender.screen_height / 2 ) );
sceGuViewport( 2048, 2048, guRender.screen_width, guRender.screen_height );
// Set up scissoring.
sceGuEnable( GU_SCISSOR_TEST );
sceGuScissor( 0, 0, guRender.screen_width, guRender.screen_height );
// Xash default
sceGuClearColor( GU_COLOR( 0.5f, 0.5f, 0.5f, 1.0f ) );
sceGuEnable( GU_DEPTH_TEST );
sceGuDisable( GU_CULL_FACE );
sceGuEnable( GU_CLIP_PLANES );
sceGuDepthFunc( GU_LEQUAL );
sceGuColor( 0xffffffff );
// Set up stencil
if( glState.stencilEnabled )
{
sceGuDisable( GU_STENCIL_TEST );
/*pglStencilMask( ( GLuint ) ~0 );*/ // alpha color sceGuPixelMask
sceGuStencilFunc( GU_EQUAL, 0, ~0 );
sceGuStencilOp( GU_KEEP, GU_INCR, GU_INCR );
}
sceGuDepthRange( 0, 65535 );
sceGuDepthOffset( 0 );
sceGuDisable( GU_BLEND );
sceGuDisable( GU_ALPHA_TEST );
sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
sceGuAlphaFunc( GU_GREATER, DEFAULT_ALPHATEST, 0xff );
sceGuEnable( GU_TEXTURE_2D );
sceGuShadeModel( GU_SMOOTH );
sceGuFrontFace( GU_CCW );
// Set the default matrices.
sceGumMatrixMode( GU_PROJECTION );
sceGumLoadIdentity();
sceGumMatrixMode( GU_VIEW );
sceGumLoadIdentity();
sceGumMatrixMode( GU_MODEL );
sceGumLoadIdentity();
sceGumMatrixMode( GU_TEXTURE );
sceGumLoadIdentity();
sceGumUpdateMatrix();
sceGuFinish();
sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT );
// Turn on the display.
sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);
// Start a new render.
sceGuStart( GU_DIRECT, guRender.context_list );
}
/*
===============
GU_Shutdown
===============
*/
static void GU_Shutdown( void )
{
// Finish rendering.
sceGuFinish();
sceGuSync( GU_SYNC_FINISH, GU_SYNC_WAIT );
// Shut down the display.
sceGuTerm();
// Free the buffers.
if( guRender.draw_buffer )
vfree( guRender.draw_buffer );
if( guRender.disp_buffer )
vfree( guRender.disp_buffer );
if( guRender.depth_buffer )
vfree( guRender.depth_buffer );
guRender.draw_buffer = NULL;
guRender.disp_buffer = NULL;
guRender.depth_buffer = NULL;
}
/*
==============
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;
}
#if 0
/*
===============
GL_SetDefaults
===============
*/
static void GU_SetDefaults( void )
{
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 );
GL_Cull( GL_NONE );
}
#endif
/*
=================
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( "VRAM AVAILABLE: %i\n", vmemavail() );
}
void GL_InitExtensions( void )
{
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 );
r_fast_particles = gEngfuncs.Cvar_Get( "r_fast_particles", "1", FCVAR_ARCHIVE, "use GU_POINTS for particles" );
gl_texture_nearest = gEngfuncs.Cvar_Get( "gl_texture_nearest", "0", FCVAR_GLCONFIG, "disable texture filter" );
gl_lightmap_nearest = gEngfuncs.Cvar_Get( "gl_lightmap_nearest", "0", FCVAR_GLCONFIG, "disable lightmap filter" );
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", "-6.0", FCVAR_GLCONFIG, "LOD bias for mipmapped textures (perfomance|quality)" );
gl_texture_lodslope = gEngfuncs.Cvar_Get( "gl_texture_lodslope", "0.3", FCVAR_GLCONFIG, "LOD slope for mipmapped textures" );
gl_keeptjunctions = gEngfuncs.Cvar_Get( "gl_keeptjunctions", "1", FCVAR_GLCONFIG, "removing tjuncs causes blinking pixels" );
gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_GLCONFIG|FCVAR_LATCH, "fake bumpmapping scale" );
gl_showtextures = gEngfuncs.pfnGetCvarPointer( "r_showtextures", 0 );
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_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", "1", FCVAR_GLCONFIG, "round texture sizes to nearest POT value" );
// these cvar not used by engine but some mods requires this
gl_depthoffset = gEngfuncs.Cvar_Get( "gl_depthoffset", "256.0", FCVAR_GLCONFIG, "depth offset for decals" );
// 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;
if( vinit() < 0 )
{
gEngfuncs.Host_Error( "Can't initialize video subsystem\nVRam unavailable" );
return false;
}
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" );
GU_Init();
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();
GU_Shutdown();
Mem_FreePool( &r_temppool );
// shut down OS specific OpenGL stuff like contexts, etc.
gEngfuncs.R_Free_Video();
}
void GL_SetupAttributes( int safegl )
{
}

491
ref_gu/gu_rlight.c Normal file
View File

@@ -0,0 +1,491 @@
/*
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, ls = gEngfuncs.GetLightStyle( 0 ); i < MAX_LIGHTSTYLES; i++, ls++ )
{
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, l = gEngfuncs.GetDynamicLight( 0 ); i < MAX_DLIGHTS; i++, l++ )
{
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, l = gEngfuncs.GetDynamicLight( 0 ); i < MAX_DLIGHTS; i++, l++ )
{
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 );
}

1345
ref_gu/gu_rmain.c Normal file

File diff suppressed because it is too large Load Diff

290
ref_gu/gu_rmath.c Normal file
View File

@@ -0,0 +1,290 @@
/*
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 )
{
#if 1
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C100, 0 + %1\n" // C100 = in1[0]
"lv.q C110, 16 + %1\n" // C110 = in1[1]
"lv.q C120, 32 + %1\n" // C120 = in1[2]
"lv.q C130, 48 + %1\n" // C130 = in1[3]
"lv.q C200, 0 + %2\n" // C200 = in2[0]
"lv.q C210, 16 + %2\n" // C210 = in2[1]
"lv.q C220, 32 + %2\n" // C220 = in2[2]
"lv.q C230, 48 + %2\n" // C230 = in2[3]
"vmmul.q E000, E100, E200\n" // E000 = E100 * E200
"sv.q C000, 0 + %0\n" // out[0] = C000
"sv.q C010, 16 + %0\n" // out[1] = C010
"sv.q C020, 32 + %0\n" // out[2] = C020
"sv.q C030, 48 + %0\n" // out[3] = C030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in1 ), "m"( *in2 )
);
#else
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2];
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];
#endif
}
/*
================
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_ToFMatrix4( const matrix4x4 in, ScePspFMatrix4 *out )
{
// transpose matrix
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C000, 0 + %1\n" // C000 = in->x
"lv.q C010, 16 + %1\n" // C010 = in->y
"lv.q C020, 32 + %1\n" // C020 = in->z
"lv.q C030, 48 + %1\n" // C030 = in->w
"sv.q R000, 0 + %0\n" // out->x = R000
"sv.q R001, 16 + %0\n" // out->y = R010
"sv.q R002, 32 + %0\n" // out->z = R020
"sv.q R003, 48 + %0\n" // out->w = R030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in )
);
}
void Matrix4x4_FromFMatrix4( matrix4x4 out, ScePspFMatrix4 *in )
{
// transpose matrix
__asm__ (
".set push\n" // save assembler option
".set noreorder\n" // suppress reordering
"lv.q C000, 0 + %1\n" // C000 = in->x
"lv.q C010, 16 + %1\n" // C010 = in->y
"lv.q C020, 32 + %1\n" // C020 = in->z
"lv.q C030, 48 + %1\n" // C030 = in->w
"sv.q R000, 0 + %0\n" // out->x = R000
"sv.q R001, 16 + %0\n" // out->y = R010
"sv.q R002, 32 + %0\n" // out->z = R020
"sv.q R003, 48 + %0\n" // out->w = R030
".set pop\n" // restore assembler option
: "=m"( *out )
: "m"( *in )
);
}
void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
{
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();
}

359
ref_gu/gu_rpart.c Normal file
View File

@@ -0,0 +1,359 @@
/*
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;
uint vert_count;
uint vert_color;
if( !cl_active_particles )
return; // nothing to draw?
vert_count = 0;
vert_color = 0;
sceGuEnable( GU_BLEND );
sceGuDisable( GU_ALPHA_TEST );
sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
sceGuDepthMask( GU_TRUE );
if( r_fast_particles->value )
{
gu_vert_fcv_t* const out = ( gu_vert_fcv_t* )extGuBeginPacket( NULL );
sceGuDisable( GU_TEXTURE_2D );
for( p = cl_active_particles; p; p = p->next )
{
if(( p->type != pt_blob ) || ( p->packedColor == 255 ))
{
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;
out[vert_count].c = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ),
gEngfuncs.LightToTexGamma( pColor->g ),
gEngfuncs.LightToTexGamma( pColor->b ), alpha );
out[vert_count].x = p->org[0];
out[vert_count].y = p->org[1];
out[vert_count].z = p->org[2];
vert_count++;
r_stats.c_particle_count++;
}
gEngfuncs.CL_ThinkParticle( frametime, p );
}
if( vert_count )
{
extGuEndPacket( ( void * )( out + vert_count ) );
sceGuDrawArray( GU_POINTS, GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out );
}
sceGuEnable( GU_TEXTURE_2D );
}
else
{
GL_Bind( XASH_TEXTURE0, tr.particleTexture );
sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGBA );
gu_vert_ftcv_t* const out = ( gu_vert_ftcv_t* )extGuBeginPacket( NULL );
for( p = cl_active_particles; p; p = p->next )
{
if(( p->type != pt_blob ) || ( p->packedColor == 255 ))
{
size = partsize; // get initial size of particle
// scale up to keep particles from disappearing
size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0];
size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1];
size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2];
if( size < 20.0f ) size = partsize;
else size = partsize + size * 0.002f;
// scale the axes by radius
VectorScale( RI.cull_vright, size, right );
VectorScale( RI.cull_vup, size, up );
p->color = bound( 0, p->color, 255 );
pColor = gEngfuncs.CL_GetPaletteColor( p->color );
alpha = 255 * (p->die - gpGlobals->time) * 16.0f;
if( alpha > 255 || p->type == pt_static )
alpha = 255;
vert_color = GUCOLOR4UB( gEngfuncs.LightToTexGamma( pColor->r ),
gEngfuncs.LightToTexGamma( pColor->g ),
gEngfuncs.LightToTexGamma( pColor->b ), alpha );
out[vert_count].u = 0.0f;
out[vert_count].v = 0.0f;
out[vert_count].c = vert_color;
out[vert_count].x = p->org[0] + right[0] + up[0];
out[vert_count].y = p->org[1] + right[1] + up[1];
out[vert_count].z = p->org[2] + right[2] + up[2];
vert_count++;
out[vert_count].u = 1.0f;
out[vert_count].v = 1.0f;
out[vert_count].c = vert_color;
out[vert_count].x = p->org[0] - right[0] - up[0];
out[vert_count].y = p->org[1] - right[1] - up[1];
out[vert_count].z = p->org[2] - right[2] - up[2];
vert_count++;
r_stats.c_particle_count++;
}
gEngfuncs.CL_ThinkParticle( frametime, p );
}
if( vert_count )
{
extGuEndPacket(( void * )( out + vert_count ));
sceGuDrawArray( GU_SPRITES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF, vert_count, 0, out );
}
}
sceGuDepthMask( GU_FALSE );
}
/*
================
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?
sceGuEnable( GU_BLEND );
sceGuBlendFunc( GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, GUBLEND1 );
sceGuDisable( GU_ALPHA_TEST );
sceGuDepthMask( GU_TRUE );
sceGuDisable( GU_TEXTURE_2D );
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];
sceGuColor( GUCOLOR4UB( pColor->r, pColor->g, pColor->b, p->packedColor ));
gu_vert_fv_t* const out = ( gu_vert_fv_t* )sceGuGetMemory( sizeof( gu_vert_fv_t ) * 4 );
out[0].x = verts[2][0];
out[0].y = verts[2][1];
out[0].z = verts[2][2];
out[1].x = verts[3][0];
out[1].y = verts[3][1];
out[1].z = verts[3][2];
out[2].x = verts[1][0];
out[2].y = verts[1][1];
out[2].z = verts[1][2];
out[3].x = verts[0][0];
out[3].y = verts[0][1];
out[3].z = verts[0][2];
sceGuDrawArray( GU_TRIANGLE_FAN, GU_VERTEX_32BITF, 4, 0, out );
}
// 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;
}
}
sceGuEnable( GU_TEXTURE_2D );
sceGuDepthMask( GU_FALSE );
}
/*
===============
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 ));
}

2347
ref_gu/gu_rsurf.c Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More