Initial commit.

This commit is contained in:
Jim Gray
2013-04-04 14:32:05 -07:00
parent ba5c81da32
commit d71d53e8ec
2180 changed files with 1393544 additions and 1 deletions

490
code/client/BinkVideo.cpp Normal file
View File

@@ -0,0 +1,490 @@
/*
* This version of BinkVideo.cpp now ONLY works on Xbox.
* GCN support is hosed.
*/
#include "snd_local_console.h"
#include "../renderer/tr_local.h"
#include "BinkVideo.h"
#include "RAD.h"
#include "../win32/xbox_texture_man.h"
#include <xgraphics.h>
#include "../client/client.h"
char *binkSndMem = NULL;
// Taste the hackery!
extern void *BonePoolTempAlloc( unsigned long size );
extern void BonePoolTempFree( void *p );
extern void *TempAlloc( unsigned long size );
extern void TempFree( void );
extern void SP_DrawSPLoadScreen( void );
// Allocation wrappers, that go to our static 2.5MB buffer:
static void PTR4* RADEXPLINK AllocWrapper(U32 size)
{
// Give bink pre-initialized sound mem on xbox
if(size == XBOX_BINK_SND_MEM) {
return binkSndMem;
}
return BinkVideo::Allocate(size);
}
static void RADEXPLINK FreeWrapper(void PTR4* ptr)
{
BinkVideo::Free(ptr);
}
/*********
BinkVideo
*********/
BinkVideo::BinkVideo()
{
bink = NULL;
buffer = NULL;
x1 = 0.0f;
y1 = 0.0f;
x2 = 0.0f;
y2 = 0.0f;
status = NS_BV_STOPPED;
looping = false;
alpha = false;
initialized = false;
loadScreenOnStop = false;
Image[0].surface = NULL;
Image[0].texture = NULL;
Image[1].surface = NULL;
Image[1].texture = NULL;
stopNextFrame = false;
}
/*********
~BinkVideo
*********/
BinkVideo::~BinkVideo()
{
Free(buffer);
BinkClose(bink);
}
/*********
AllocateXboxMem
Pre-Allocates sound memory for xbox to avoid fragmenting
*********/
void BinkVideo::AllocateXboxMem(void)
{
// binkSndMem = (char*)Allocate(XBOX_BINK_SND_MEM);
// Force the sound memory to come from the Zone:
binkSndMem = (char *) Z_Malloc(XBOX_BINK_SND_MEM, TAG_BINK, qfalse, 32);
initialized = true;
}
/*********
FreeXboxMem
*********/
void BinkVideo::FreeXboxMem(void)
{
initialized = false;
Z_Free(binkSndMem);
}
/*********
Start
Opens a bink file and gets it ready to play
*********/
bool BinkVideo::Start(const char *filename, float xOrigin, float yOrigin, float width, float height)
{
assert(initialized);
// Check to see if a video is being played.
if(status == NS_BV_PLAYING)
{
// stop
this->Stop();
}
// Hack! Remember if this was the logo movies, so that we can show the load screen later:
if( strstr( filename, "logos" ) )
loadScreenOnStop = true;
else
loadScreenOnStop = false;
// Blow away all sounds that aren't playing - this helps prevent crashing:
SND_FreeOldestSound();
// Just use the zone for bink allocations:
RADSetMemory( AllocWrapper, FreeWrapper );
// Set up sound for consoles
// We are on XBox, tell Bink to play all of the 5.1 tracks
// U32 TrackIDsToPlay[ 4 ] = { 0, 1, 2, 3 };
// BinkSetSoundTrack( 4, TrackIDsToPlay );
// Now route the sound tracks to the correct speaker
// U32 bins[ 2 ];
// bins[ 0 ] = DSMIXBIN_FRONT_LEFT;
// bins[ 1 ] = DSMIXBIN_FRONT_RIGHT;
// BinkSetMixBins( bink, 0, bins, 2 );
// bins[ 0 ] = DSMIXBIN_FRONT_CENTER;
// BinkSetMixBins( bink, 1, bins, 1 );
// bins[ 0 ] = DSMIXBIN_LOW_FREQUENCY;
// BinkSetMixBins( bink, 2, bins, 1 );
// bins[ 0 ] = DSMIXBIN_BACK_LEFT;
// bins[ 1 ] = DSMIXBIN_BACK_RIGHT;
// BinkSetMixBins( bink, 3, bins, 2 );
// Try to open the Bink file.
// bink = BinkOpen( filename, BINKSNDTRACK | BINKALPHA );
bink = BinkOpen( filename, BINKALPHA );
if(!bink)
{
return false;
}
assert(bink->Width <= MAX_WIDTH && bink->Height <=MAX_HEIGHT);
// Did the source .bik file have an alpha plane?
alpha = (bool)(bink->OpenFlags & BINKALPHA);
// set the height, width, etc...
x1 = xOrigin;
y1 = yOrigin;
x2 = x1 + width;
y2 = y1 + height;
// flush any background sound reads
extern void S_DrainRawSoundData(void);
S_DrainRawSoundData();
// Full-screen movies (without alpha) need a pair of YUV2 textures:
if( !alpha )
{
// YUY2 is 16 bpp? But we need two:
gTextures.SwapTextureMemory( (bink->Width * bink->Height * 4) + 1024 );
// Make our two textures:
Image[0].texture = new IDirect3DTexture9;
Image[1].texture = new IDirect3DTexture9;
// Fill in the texture headers:
DWORD pixelSize =
XGSetTextureHeader( bink->Width,
bink->Height,
1,
0,
D3DFMT_YUY2,
0,
Image[0].texture,
0,
0 );
XGSetTextureHeader( bink->Width,
bink->Height,
1,
0,
D3DFMT_YUY2,
0,
Image[1].texture,
0,
0 );
// texNum is unused:
Image[0].texture->Register( gTextures.Allocate( pixelSize, 0 ) );
Image[1].texture->Register( gTextures.Allocate( pixelSize, 0 ) );
// Turn on overlays:
glw_state->device->EnableOverlay( TRUE );
// Get surface pointers:
Image[0].texture->GetSurfaceLevel( 0, &Image[0].surface );
Image[1].texture->GetSurfaceLevel( 0, &Image[1].surface );
// Just to be safe:
currentImage = 0;
buffer = NULL;
}
else
{
// Planet movies (with alpha) re-use tr.binkPlanetImage, so no texture setup
// is needed. But we do need a temporary buffer to decompress into. Let's steal
// from the bone pool.
buffer = BonePoolTempAlloc( bink->Width * bink->Height * 4 );
}
status = NS_BV_PLAYING;
return true;
}
/*********
Run
Decompresses a frame, renders it to the screen, and advances to
the next frame. Only used for full-screen movies (no alpha).
*********/
bool BinkVideo::Run(void)
{
// Make sure movie is running:
if( status == NS_BV_STOPPED )
return false;
// Wait for proper frame timing:
while(BinkWait(bink));
// Are we supposed to stop now?
if( stopNextFrame )
{
stopNextFrame = false;
Stop();
return false;
}
// Try to decompress the frame:
if( DecompressFrame( &Image[currentImage ^ 1] ) == 0 )
{
// The blt succeeded, update our current image index.
currentImage ^= 1;
// Draw the next frame.
Draw( &Image[currentImage] );
}
// Are we done? Set a flag, we don't want to stop until next frame, so the
// last frame stays up for the right amount of time!
if( bink->FrameNum == bink->Frames && !looping )
{
stopNextFrame = true;
}
// Keep playing:
BinkNextFrame( bink );
// Are we done?
/*
if( bink->FrameNum == (bink->Frames - 1) && !looping )
{
Stop();
return false;
}
*/
return true;
}
/*********
GetBinkData
Returns the buffer data for the next frame of the video - only used for
movies with alpha (the planets).
This doesn't follow Bink guidelines. They suggest that you call BinkWait()
very frequently, something like 4 to 5 times as fast as the framerate of
the movie. We're technically coming close to that, but this code won't work
if we have videoMap shaders with higher framerates than the planets (8).
*********/
void* BinkVideo::GetBinkData(void)
{
assert( alpha );
if (!BinkWait(bink))
{
BinkDoFrame(bink);
BinkCopyToBuffer( bink,
buffer,
bink->Width * 4, // Pitch
bink->Height,
0,
0,
BINKCOPYALL | BINKSURFACE32A );
BinkNextFrame(bink);
}
return buffer;
}
/********
Draw
Draws the current movie full-screen
********/
void BinkVideo::Draw( OVERLAYINFO * oi )
{
// Draw the image on the screen (centered)...
RECT dst_rect = { 0, 0, 640, 480 };
RECT src_rect = { 0, 0, bink->Width, bink->Height };
// Update this bugger.
glw_state->device->UpdateOverlay( oi->surface, &src_rect, &dst_rect, FALSE, 0 );
}
/*********
Stop
Stops the current movie, and clears it from memory
*********/
void BinkVideo::Stop(void)
{
if( bink ) {
BinkClose( bink );
}
if( alpha )
{
// Release all the temp space we grabbed, no texture cleanup to do:
if( buffer )
BonePoolTempFree( buffer );
}
else
{
// We wrap all this in a single check - it should be all or nothing:
if( Image[0].surface )
{
// Release surfaces:
Image[0].surface->Release();
Image[0].surface = NULL;
Image[1].surface->Release();
Image[1].surface = NULL;
// Clean up the textures we made for the overlay stuff:
Image[0].texture->BlockUntilNotBusy();
delete Image[0].texture;
Image[0].texture = NULL;
Image[1].texture->BlockUntilNotBusy();
delete Image[1].texture;
Image[1].texture = NULL;
// We're going to be stripping the overlay off, leave a black screen,
// unless it was the logo movies that we just played, in which case we
// draw the loading screen!
if( loadScreenOnStop )
{
SP_DrawSPLoadScreen();
glw_state->device->BlockUntilVerticalBlank();
// Filth. Don't call Present until this gets cleared.
extern bool connectSwapOverride;
connectSwapOverride = true;
}
else
{
glw_state->device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_COLORVALUE(0, 0, 0, 0), 0, 0 );
glw_state->device->Present( NULL, NULL, NULL, NULL );
glw_state->device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_COLORVALUE(0, 0, 0, 0), 0, 0 );
glw_state->device->Present( NULL, NULL, NULL, NULL );
glw_state->device->BlockUntilVerticalBlank();
}
// Turn overlays back off:
glw_state->device->EnableOverlay( FALSE );
// Restore the textures that we dumped to disk
gTextures.UnswapTextureMemory();
}
}
x1 = 0.0f;
y1 = 0.0f;
x2 = 0.0f;
y2 = 0.0f;
buffer = NULL;
bink = NULL;
status = NS_BV_STOPPED;
// Now free all the temp memory that Bink took with it's internal allocations:
TempFree();
if( !alpha && (cls.state == CA_CINEMATIC || cls.state == CA_ACTIVE) )
re.InitDissolve(qfalse);
}
/*********
SetExtents
Sets dimmension variables
*********/
void BinkVideo::SetExtents(float xOrigin, float yOrigin, float width, float height)
{
x1 = xOrigin;
y1 = yOrigin;
x2 = x1 + width;
y2 = y1 + height;
}
/*********
SetMasterVolume
Sets the volume of the specified track
*********/
void BinkVideo::SetMasterVolume(s32 volume)
{
int i;
for(i = 0; i < 4; i++)
{
BinkSetVolume(bink,i,volume);
}
}
/*********
DecompressFrame
Decompresses current frame and copies the data to
the buffer
*********/
S32 BinkVideo::DecompressFrame( OVERLAYINFO *oi )
{
s32 copy_skipped;
D3DLOCKED_RECT lock_rect;
// Decompress the Bink frame.
BinkDoFrame( bink );
// Lock the 3D image so that we can copy the decompressed frame into it.
oi->texture->LockRect( 0, &lock_rect, 0, 0 );
// Copy the decompressed frame into the 3D image.
copy_skipped = BinkCopyToBuffer( bink,
lock_rect.pBits,
lock_rect.Pitch,
bink->Height,
0, 0,
BINKSURFACEYUY2 | BINKCOPYALL );
// Unlock the 3D image.
oi->texture->UnlockRect( 0 );
return copy_skipped;
}
/*********
Allocate
Allocates memory for the frame buffer
*********/
void *BinkVideo::Allocate(U32 size)
{
void *retVal = TempAlloc( size );
// Fall back to Zone if we didn't get it
if( !retVal )
retVal = Z_Malloc(size, TAG_BINK, qfalse, 32);
return retVal;
}
/*********
FreeBuffer
Releases the frame buffer memory
*********/
void BinkVideo::Free(void* ptr)
{
// Did this pointer come from the Zone up above?
if( !Z_IsFromTempPool( ptr ) )
Z_Free(ptr);
// Else, do nothing - we don't free temp allocations until movie is done
}

72
code/client/BinkVideo.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef NS_BINKVIDEO
#define NS_BINKVIDEO
#include "bink.h"
#define NS_BV_DEFAULT_CIN_BPS (4)
#define MAX_WIDTH 512
#define MAX_HEIGHT 512
#define XBOX_BUFFER_SIZE NS_BV_DEFAULT_CIN_BPS * MAX_WIDTH * MAX_HEIGHT
#define XBOX_BINK_SND_MEM 16448
typedef enum {
NS_BV_PLAYING, // Movie is playing
NS_BV_STOPPED, // Movie is stopped
};
struct OVERLAYINFO
{
D3DTexture *texture;
D3DSurface *surface;
};
class BinkVideo
{
private:
HBINK bink;
void *buffer; // Only used for movies with alpha
// int texture;
int status;
bool looping;
bool alpha; // Important flag
float x1;
float y1;
float x2;
float y2;
bool loadScreenOnStop; // Set to true when we play the logos, so we know to show the loading screen
bool stopNextFrame; // Used to stop movies with *correct* timing
OVERLAYINFO Image[2];
unsigned currentImage;
bool initialized;
void Draw( OVERLAYINFO *oi );
S32 DecompressFrame( OVERLAYINFO *oi );
public:
BinkVideo();
~BinkVideo();
bool Start(const char *filename, float xOrigin, float yOrigin, float width, float height);
bool Run(void);
void Stop(void);
void SetExtents(float xOrigin, float yOrigin, float width, float height);
int GetStatus(void) { return status; }
void SetLooping(bool loop) { looping = loop; }
void* GetBinkData(void);
int GetBinkWidth(void) { return this->bink->Width; }
int GetBinkHeight(void) { return this->bink->Height; }
void SetMasterVolume(s32 volume);
void AllocateXboxMem(void);
void FreeXboxMem(void);
static void* Allocate(U32 size);
static void Free(void* ptr);
bool Ready(void) { return (bool)this->bink; }
};
#endif

564
code/client/OpenAL/al.h Normal file
View File

@@ -0,0 +1,564 @@
#ifndef _AL_H_
#define _AL_H_
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "altypes.h"
#ifdef _XBOX
#define ALAPI
#define ALAPIENTRY
#define AL_CALLBACK
#else
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef _OPENAL32LIB
#define ALAPI __declspec(dllexport)
#else
#define ALAPI __declspec(dllimport)
#endif
#define ALAPIENTRY __cdecl
#define AL_CALLBACK
#else
#ifdef TARGET_OS_MAC
#if TARGET_OS_MAC
#pragma export on
#endif
#endif
#define ALAPI
#define ALAPIENTRY __cdecl
#define AL_CALLBACK
#endif
#endif
#define OPENAL
#ifndef AL_NO_PROTOTYPES
/**
* OpenAL Maintenance Functions
* Initialization and exiting.
* State Management and Query.
* Error Handling.
* Extension Support.
*/
/** State management. */
ALAPI ALvoid ALAPIENTRY alEnable( ALenum capability );
ALAPI ALvoid ALAPIENTRY alDisable( ALenum capability );
ALAPI ALboolean ALAPIENTRY alIsEnabled( ALenum capability );
/** Application preferences for driver performance choices. */
ALAPI ALvoid ALAPIENTRY alHint( ALenum target, ALenum mode );
/** State retrieval. */
ALAPI ALboolean ALAPIENTRY alGetBoolean( ALenum param );
ALAPI ALint ALAPIENTRY alGetInteger( ALenum param );
ALAPI ALfloat ALAPIENTRY alGetFloat( ALenum param );
ALAPI ALdouble ALAPIENTRY alGetDouble( ALenum param );
ALAPI ALvoid ALAPIENTRY alGetBooleanv( ALenum param, ALboolean* data );
ALAPI ALvoid ALAPIENTRY alGetIntegerv( ALenum param, ALint* data );
ALAPI ALvoid ALAPIENTRY alGetFloatv( ALenum param, ALfloat* data );
ALAPI ALvoid ALAPIENTRY alGetDoublev( ALenum param, ALdouble* data );
ALAPI ALubyte* ALAPIENTRY alGetString( ALenum param );
/**
* Error support.
* Obtain the most recent error generated in the AL state machine.
*/
ALAPI ALenum ALAPIENTRY alGetError( ALvoid );
#ifdef _XBOX
/**
* Update cycle.
*/
ALAPI ALvoid ALAPIENTRY alUpdate( ALvoid );
/**
* Returns a global state parameter.
*/
ALAPI ALvoid ALAPIENTRY alGeti( ALenum param, ALint* value );
/**
* Adjust the size of the sound buffer pool.
*/
ALAPI ALvoid ALAPIENTRY alResizePool( ALuint size );
#endif
/**
* Extension support.
* Obtain the address of a function (usually an extension)
* with the name fname. All addresses are context-independent.
*/
ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( ALubyte* fname );
/**
* Extension support.
* Obtain the address of a function (usually an extension)
* with the name fname. All addresses are context-independent.
*/
ALAPI ALvoid* ALAPIENTRY alGetProcAddress( ALubyte* fname );
/**
* Extension support.
* Obtain the integer value of an enumeration (usually an extension) with the name ename.
*/
ALAPI ALenum ALAPIENTRY alGetEnumValue( ALubyte* ename );
/**
* LISTENER
* Listener is the sample position for a given context.
* The multi-channel (usually stereo) output stream generated
* by the mixer is parametrized by this Listener object:
* its position and velocity relative to Sources, within
* occluder and reflector geometry.
*/
#ifdef _XBOX
/**
* Listener create and delete
*/
ALAPI ALvoid ALAPIENTRY alGenListeners( ALsizei n, ALuint* listeners );
ALAPI ALvoid ALAPIENTRY alDeleteListeners( ALsizei n, ALuint* listeners );
#endif
// VV's Console version of openAL includes multiple listener support,
// as an extra first arg to the alListener functions. We wrap that up
// in a macro here, to make the following more concise.
#ifdef _XBOX
#define AL_VV_LISTENER ALuint listener,
#else
#define AL_VV_LISTENER
#endif
/**
*
* Listener Environment: default 0.
*/
ALAPI ALvoid ALAPIENTRY alListeneri( AL_VV_LISTENER ALenum param, ALint value );
/**
*
* Listener Gain: default 1.0f.
*/
ALAPI ALvoid ALAPIENTRY alListenerf( AL_VV_LISTENER ALenum param, ALfloat value );
/**
*
* Listener Position.
* Listener Velocity.
*/
ALAPI ALvoid ALAPIENTRY alListener3f( AL_VV_LISTENER ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 );
/**
*
* Listener Position: ALfloat[3]
* Listener Velocity: ALfloat[3]
* Listener Orientation: ALfloat[6] (forward and up vector).
*/
ALAPI ALvoid ALAPIENTRY alListenerfv( AL_VV_LISTENER ALenum param, ALfloat* values );
ALAPI ALvoid ALAPIENTRY alGetListeneri( AL_VV_LISTENER ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY alGetListenerf( AL_VV_LISTENER ALenum param, ALfloat* value );
ALAPI ALvoid ALAPIENTRY alGetListener3f( AL_VV_LISTENER ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 );
ALAPI ALvoid ALAPIENTRY alGetListenerfv( AL_VV_LISTENER ALenum param, ALfloat* values );
/**
* SOURCE
* Source objects are by default localized. Sources
* take the PCM data provided in the specified Buffer,
* apply Source-specific modifications, and then
* submit them to be mixed according to spatial
* arrangement etc.
*/
/** Create Source objects. */
#ifdef _XBOX
ALAPI ALvoid ALAPIENTRY alGenSources2D( ALsizei n, ALuint* sources );
ALAPI ALvoid ALAPIENTRY alGenSources3D( ALsizei n, ALuint* sources );
#else
ALAPI ALvoid ALAPIENTRY alGenSources( ALsizei n, ALuint* sources );
#endif
/** Delete Source objects. */
ALAPI ALvoid ALAPIENTRY alDeleteSources( ALsizei n, ALuint* sources );
/** Verify a handle is a valid Source. */
ALAPI ALboolean ALAPIENTRY alIsSource( ALuint id );
/** Set an integer parameter for a Source object. */
ALAPI ALvoid ALAPIENTRY alSourcei( ALuint source, ALenum param, ALint value );
ALAPI ALvoid ALAPIENTRY alSourcef( ALuint source, ALenum param, ALfloat value );
ALAPI ALvoid ALAPIENTRY alSource3f( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 );
ALAPI ALvoid ALAPIENTRY alSourcefv( ALuint source, ALenum param, ALfloat* values );
/** Get an integer parameter for a Source object. */
ALAPI ALvoid ALAPIENTRY alGetSourcei( ALuint source, ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY alGetSourcef( ALuint source, ALenum param, ALfloat* value );
ALAPI ALvoid ALAPIENTRY alGetSource3f( ALuint source, ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 );
ALAPI ALvoid ALAPIENTRY alGetSourcefv( ALuint source, ALenum param, ALfloat* values );
ALAPI ALvoid ALAPIENTRY alSourcePlayv( ALsizei n, ALuint *sources );
ALAPI ALvoid ALAPIENTRY alSourcePausev( ALsizei n, ALuint *sources );
ALAPI ALvoid ALAPIENTRY alSourceStopv( ALsizei n, ALuint *sources );
ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n,ALuint *sources);
/** Activate a source, start replay. */
ALAPI ALvoid ALAPIENTRY alSourcePlay( ALuint source );
/**
* Pause a source,
* temporarily remove it from the mixer list.
*/
ALAPI ALvoid ALAPIENTRY alSourcePause( ALuint source );
/**
* Stop a source,
* temporarily remove it from the mixer list,
* and reset its internal state to pre-Play.
* To remove a Source completely, it has to be
* deleted following Stop, or before Play.
*/
ALAPI ALvoid ALAPIENTRY alSourceStop( ALuint source );
/**
* Rewinds a source,
* temporarily remove it from the mixer list,
* and reset its internal state to pre-Play.
*/
ALAPI ALvoid ALAPIENTRY alSourceRewind( ALuint source );
/**
* BUFFER
* Buffer objects are storage space for sample data.
* Buffers are referred to by Sources. There can be more than
* one Source using the same Buffer data. If Buffers have
* to be duplicated on a per-Source basis, the driver has to
* take care of allocation, copying, and deallocation as well
* as propagating buffer data changes.
*/
/** Buffer object generation. */
ALAPI ALvoid ALAPIENTRY alGenBuffers( ALsizei n, ALuint* buffers );
ALAPI ALvoid ALAPIENTRY alDeleteBuffers( ALsizei n, ALuint* buffers );
ALAPI ALboolean ALAPIENTRY alIsBuffer( ALuint buffer );
/**
* Specify the data to be filled into a buffer.
*/
ALAPI ALvoid ALAPIENTRY alBufferData( ALuint buffer,
ALenum format,
ALvoid* data,
ALsizei size,
ALsizei freq );
ALAPI ALvoid ALAPIENTRY alGetBufferi( ALuint buffer, ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY alGetBufferf( ALuint buffer, ALenum param, ALfloat* value );
/**
* Queue stuff
*/
ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, ALuint* buffers );
ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers );
#ifdef _XBOX
/**
* STREAM
* Stream objects encapsulate traditional sound stream and
* act as both sources and buffers. They emit sound and
* manage sound data.
*/
ALAPI ALvoid ALAPIENTRY alGenStream( ALvoid );
ALAPI ALvoid ALAPIENTRY alDeleteStream( ALvoid );
ALAPI ALvoid ALAPIENTRY alStreamStop( ALvoid );
ALAPI ALvoid ALAPIENTRY alStreamPlay( ALsizei offset, ALint file, ALint loop );
ALAPI ALvoid ALAPIENTRY alStreamf( ALenum param, ALfloat value );
ALAPI ALvoid ALAPIENTRY alGetStreamf( ALenum param, ALfloat* value );
ALAPI ALvoid ALAPIENTRY alGetStreami( ALenum param, ALint* value );
#endif
/**
* Knobs and dials
*/
ALAPI ALvoid ALAPIENTRY alDistanceModel( ALenum value );
ALAPI ALvoid ALAPIENTRY alDopplerFactor( ALfloat value );
ALAPI ALvoid ALAPIENTRY alDopplerVelocity( ALfloat value );
#ifdef _XBOX
ALAPI ALvoid ALAPIENTRY alGain( ALfloat value );
#endif
#else /* AL_NO_PROTOTYPES */
/**
* OpenAL Maintenance Functions
* Initialization and exiting.
* State Management and Query.
* Error Handling.
* Extension Support.
*/
/** State management. */
ALAPI ALvoid ALAPIENTRY (*alEnable)( ALenum capability );
ALAPI ALvoid ALAPIENTRY (*alDisable)( ALenum capability );
ALAPI ALboolean ALAPIENTRY (*alIsEnabled)( ALenum capability );
/** Application preferences for driver performance choices. */
ALAPI ALvoid ALAPIENTRY (*alHint)( ALenum target, ALenum mode );
/** State retrieval. */
ALAPI ALboolean ALAPIENTRY (*alGetBoolean)( ALenum param );
ALAPI ALint ALAPIENTRY (*alGetInteger)( ALenum param );
ALAPI ALfloat ALAPIENTRY (*alGetFloat)( ALenum param );
ALAPI ALdouble ALAPIENTRY (*alGetDouble)( ALenum param );
ALAPI ALvoid ALAPIENTRY (*alGetBooleanv)( ALenum param, ALboolean* data );
ALAPI ALvoid ALAPIENTRY (*alGetIntegerv)( ALenum param, ALint* data );
ALAPI ALvoid ALAPIENTRY (*alGetFloatv)( ALenum param, ALfloat* data );
ALAPI ALvoid ALAPIENTRY (*alGetDoublev)( ALenum param, ALdouble* data );
ALAPI ALubyte* ALAPIENTRY (*alGetString)( ALenum param );
/**
* Error support.
* Obtain the most recent error generated in the AL state machine.
*/
ALAPI ALenum ALAPIENTRY (*alGetError)( ALvoid );
/**
* Extension support.
* Obtain the address of a function (usually an extension)
* with the name fname. All addresses are context-independent.
*/
ALAPI ALboolean ALAPIENTRY (*alIsExtensionPresent)( ALubyte* fname );
/**
* Extension support.
* Obtain the address of a function (usually an extension)
* with the name fname. All addresses are context-independent.
*/
ALAPI ALvoid* ALAPIENTRY (*alGetProcAddress)( ALubyte* fname );
/**
* Extension support.
* Obtain the integer value of an enumeration (usually an extension) with the name ename.
*/
ALAPI ALenum ALAPIENTRY (*alGetEnumValue)( ALubyte* ename );
/**
* LISTENER
* Listener is the sample position for a given context.
* The multi-channel (usually stereo) output stream generated
* by the mixer is parametrized by this Listener object:
* its position and velocity relative to Sources, within
* occluder and reflector geometry.
*/
/**
*
* Listener Environment: default 0.
*/
ALAPI ALvoid ALAPIENTRY (*alListeneri)( ALenum param, ALint value );
/**
*
* Listener Gain: default 1.0f.
*/
ALAPI ALvoid ALAPIENTRY (*alListenerf)( ALenum param, ALfloat value );
/**
*
* Listener Position.
* Listener Velocity.
*/
ALAPI ALvoid ALAPIENTRY (*alListener3f)( ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 );
/**
*
* Listener Position: ALfloat[3]
* Listener Velocity: ALfloat[3]
* Listener Orientation: ALfloat[6] (forward and up vector).
*/
ALAPI ALvoid ALAPIENTRY (*alListenerfv)( ALenum param, ALfloat* values );
ALAPI ALvoid ALAPIENTRY (*alGetListeneri)( ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY (*alGetListenerf)( ALenum param, ALfloat* value );
ALAPI ALvoid ALAPIENTRY (*alGetListener3f)( ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 );
ALAPI ALvoid ALAPIENTRY (*alGetListenerfv)( ALenum param, ALfloat* values );
/**
* SOURCE
* Source objects are by default localized. Sources
* take the PCM data provided in the specified Buffer,
* apply Source-specific modifications, and then
* submit them to be mixed according to spatial
* arrangement etc.
*/
/** Create Source objects. */
ALAPI ALvoid ALAPIENTRY (*alGenSources)( ALsizei n, ALuint* sources );
/** Delete Source objects. */
ALAPI ALvoid ALAPIENTRY (*alDeleteSources)( ALsizei n, ALuint* sources );
/** Verify a handle is a valid Source. */
ALAPI ALboolean ALAPIENTRY (*alIsSource)( ALuint id );
/** Set an integer parameter for a Source object. */
ALAPI ALvoid ALAPIENTRY (*alSourcei)( ALuint source, ALenum param, ALint value );
ALAPI ALvoid ALAPIENTRY (*alSourcef)( ALuint source, ALenum param, ALfloat value );
ALAPI ALvoid ALAPIENTRY (*alSource3f)( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 );
ALAPI ALvoid ALAPIENTRY (*alSourcefv)( ALuint source, ALenum param, ALfloat* values );
/** Get an integer parameter for a Source object. */
ALAPI ALvoid ALAPIENTRY (*alGetSourcei)( ALuint source, ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY (*alGetSourcef)( ALuint source, ALenum param, ALfloat* value );
ALAPI ALvoid ALAPIENTRY (*alGetSourcefv)( ALuint source, ALenum param, ALfloat* values );
ALAPI ALvoid ALAPIENTRY (*alSourcePlayv)( ALsizei n, ALuint *sources );
ALAPI ALvoid ALAPIENTRY (*alSourceStopv)( ALsizei n, ALuint *sources );
/** Activate a source, start replay. */
ALAPI ALvoid ALAPIENTRY (*alSourcePlay)( ALuint source );
/**
* Pause a source,
* temporarily remove it from the mixer list.
*/
ALAPI ALvoid ALAPIENTRY (*alSourcePause)( ALuint source );
/**
* Stop a source,
* temporarily remove it from the mixer list,
* and reset its internal state to pre-Play.
* To remove a Source completely, it has to be
* deleted following Stop, or before Play.
*/
ALAPI ALvoid ALAPIENTRY (*alSourceStop)( ALuint source );
/**
* BUFFER
* Buffer objects are storage space for sample data.
* Buffers are referred to by Sources. There can be more than
* one Source using the same Buffer data. If Buffers have
* to be duplicated on a per-Source basis, the driver has to
* take care of allocation, copying, and deallocation as well
* as propagating buffer data changes.
*/
/** Buffer object generation. */
ALAPI ALvoid ALAPIENTRY (*alGenBuffers)( ALsizei n, ALuint* buffers );
ALAPI ALvoid ALAPIENTRY (*alDeleteBuffers)( ALsizei n, ALuint* buffers );
ALAPI ALboolean ALAPIENTRY (*alIsBuffer)( ALuint buffer );
/**
* Specify the data to be filled into a buffer.
*/
ALAPI ALvoid ALAPIENTRY (*alBufferData)( ALuint buffer,
ALenum format,
ALvoid* data,
ALsizei size,
ALsizei freq );
ALAPI ALvoid ALAPIENTRY (*alGetBufferi)( ALuint buffer, ALenum param, ALint* value );
ALAPI ALvoid ALAPIENTRY (*alGetBufferf)( ALuint buffer, ALenum param, ALfloat* value );
/**
* Queue stuff
*/
ALAPI ALvoid ALAPIENTRY (*alSourceQueueBuffers)( ALuint source, ALsizei n, ALuint* buffers );
ALAPI ALvoid ALAPIENTRY (*alSourceUnqueueBuffers)( ALuint source, ALsizei n, ALuint* buffers );
/**
* Knobs and dials
*/
ALAPI ALvoid ALAPIENTRY (*alDistanceModel)( ALenum value );
ALAPI ALvoid ALAPIENTRY (*alDopplerFactor)( ALfloat value );
ALAPI ALvoid ALAPIENTRY (*alDopplerVelocity)( ALfloat value );
#endif /* AL_NO_PROTOTYPES */
#ifdef TARGET_OS_MAC
#if TARGET_OS_MAC
#pragma export off
#endif
#endif
#ifndef _XBOX
#ifdef __cplusplus
}
#endif
#endif
#endif

97
code/client/OpenAL/alc.h Normal file
View File

@@ -0,0 +1,97 @@
#ifndef _ALC_H_
#define _ALC_H_
#include "altypes.h"
#include "alctypes.h"
#ifdef _XBOX
#define ALCAPI
#define ALCAPIENTRY
#else
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef _OPENAL32LIB
#define ALCAPI __declspec(dllexport)
#else
#define ALCAPI __declspec(dllimport)
#endif
typedef struct ALCdevice_struct ALCdevice;
typedef struct ALCcontext_struct ALCcontext;
#define ALCAPIENTRY __cdecl
#else
#ifdef TARGET_OS_MAC
#if TARGET_OS_MAC
#pragma export on
#endif
#endif
#define ALCAPI
#define ALCAPIENTRY __cdecl
#endif
#endif
#ifndef ALC_NO_PROTOTYPES
ALCAPI ALCubyte* ALCAPIENTRY alcGetString(ALCdevice *device,ALCenum param);
ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data);
ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(ALCubyte *deviceName);
ALCAPI ALCvoid ALCAPIENTRY alcCloseDevice(ALCdevice *device);
ALCAPI ALCcontext*ALCAPIENTRY alcCreateContext(ALCdevice *device,ALCint *attrList);
ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *context);
ALCAPI ALCcontext*ALCAPIENTRY alcGetCurrentContext(ALCvoid);
ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context);
ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device);
ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device,ALCubyte *extName);
ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device,ALCubyte *funcName);
ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device,ALCubyte *enumName);
#else /* AL_NO_PROTOTYPES */
ALCAPI ALCubyte* ALCAPIENTRY (*alcGetString)(ALCdevice *device,ALCenum param);
ALCAPI ALCvoid ALCAPIENTRY (*alcGetIntegerv)(ALCdevice * device,ALCenum param,ALCsizei size,ALCint *data);
ALCAPI ALCdevice* ALCAPIENTRY (*alcOpenDevice)(ALubyte *deviceName);
ALCAPI ALCvoid ALCAPIENTRY (*alcCloseDevice)(ALCdevice *device);
ALCAPI ALCcontext*ALCAPIENTRY (*alcCreateContext)(ALCdevice *device,ALCint *attrList);
ALCAPI ALCboolean ALCAPIENTRY (*alcMakeContextCurrent)(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY (*alcProcessContext)(ALCcontext *context);
ALCAPI ALCcontext*ALCAPIENTRY (*alcGetCurrentContext)(ALCvoid);
ALCAPI ALCdevice* ALCAPIENTRY (*alcGetContextsDevice)(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY (*alcSuspendContext)(ALCcontext *context);
ALCAPI ALCvoid ALCAPIENTRY (*alcDestroyContext)(ALCcontext *context);
ALCAPI ALCenum ALCAPIENTRY (*alcGetError)(ALCdevice *device);
ALCAPI ALCboolean ALCAPIENTRY (*alcIsExtensionPresent)(ALCdevice *device,ALCubyte *extName);
ALCAPI ALCvoid * ALCAPIENTRY (*alcGetProcAddress)(ALCdevice *device,ALCubyte *funcName);
ALCAPI ALCenum ALCAPIENTRY (*alcGetEnumValue)(ALCdevice *device,ALCubyte *enumName);
#endif /* AL_NO_PROTOTYPES */
#ifdef TARGET_OS_MAC
#if TARGET_OS_MAC
#pragma export off
#endif
#endif
#ifndef _XBOX
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@@ -0,0 +1,133 @@
#ifndef _ALCTYPES_H_
#define _ALCTYPES_H_
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _XBOX
/** ALC device type. */
typedef int ALCdevice;
/** ALC context type. */
typedef int ALCcontext;
#endif
/** ALC boolean type. */
typedef char ALCboolean;
/** ALC 8bit signed byte. */
typedef char ALCbyte;
/** ALC 8bit unsigned byte. */
typedef unsigned char ALCubyte;
/** ALC 16bit signed short integer type. */
typedef short ALCshort;
/** ALC 16bit unsigned short integer type. */
typedef unsigned short ALCushort;
/** ALC 32bit unsigned integer type. */
typedef unsigned ALCuint;
/** ALC 32bit signed integer type. */
typedef int ALCint;
/** ALC 32bit floating point type. */
typedef float ALCfloat;
/** ALC 64bit double point type. */
typedef double ALCdouble;
/** ALC 32bit type. */
typedef unsigned int ALCsizei;
/** ALC void type */
typedef void ALCvoid;
/** ALC enumerations. */
typedef int ALCenum;
/* Bad value. */
#define ALC_INVALID (-1)
/* Boolean False. */
#define ALC_FALSE 0
/* Boolean True. */
#define ALC_TRUE 1
/** Errors: No Error. */
#define ALC_NO_ERROR ALC_FALSE
#define ALC_MAJOR_VERSION 0x1000
#define ALC_MINOR_VERSION 0x1001
#define ALC_ATTRIBUTES_SIZE 0x1002
#define ALC_ALL_ATTRIBUTES 0x1003
#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
#define ALC_DEVICE_SPECIFIER 0x1005
#define ALC_EXTENSIONS 0x1006
#define ALC_FREQUENCY 0x1007
#define ALC_REFRESH 0x1008
#define ALC_SYNC 0x1009
/**
* The device argument does not name a valid dvice.
*/
#define ALC_INVALID_DEVICE 0xA001
/**
* The context argument does not name a valid context.
*/
#define ALC_INVALID_CONTEXT 0xA002
/**
* A function was called at inappropriate time,
* or in an inappropriate way, causing an illegal state.
* This can be an incompatible ALenum, object ID,
* and/or function.
*/
#define ALC_INVALID_ENUM 0xA003
/**
* Illegal value passed as an argument to an AL call.
* Applies to parameter values, but not to enumerations.
*/
#define ALC_INVALID_VALUE 0xA004
/**
* A function could not be completed,
* because there is not enough memory available.
*/
#define ALC_OUT_OF_MEMORY 0xA005
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,351 @@
#ifndef _ALTYPES_H_
#define _ALTYPES_H_
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef __cplusplus
extern "C" {
#endif
/** OpenAL boolean type. */
typedef char ALboolean;
/** OpenAL 8bit signed byte. */
typedef char ALbyte;
/** OpenAL 8bit unsigned byte. */
typedef unsigned char ALubyte;
/** OpenAL 16bit signed short integer type. */
typedef short ALshort;
/** OpenAL 16bit unsigned short integer type. */
typedef unsigned short ALushort;
/** OpenAL 32bit unsigned integer type. */
typedef unsigned ALuint;
/** OpenAL 32bit signed integer type. */
typedef int ALint;
/** OpenAL 32bit floating point type. */
typedef float ALfloat;
/** OpenAL 64bit double point type. */
typedef double ALdouble;
/** OpenAL 32bit type. */
typedef unsigned int ALsizei;
/** OpenAL void type */
typedef void ALvoid;
/** OpenAL enumerations. */
typedef int ALenum;
/* Bad value. */
#define AL_INVALID (-1)
/* Disable value. */
#define AL_NONE 0
/* Boolean False. */
#define AL_FALSE 0
/* Boolean True. */
#define AL_TRUE 1
/**
* Indicate the type of AL_SOURCE.
* Sources can be spatialized
*/
#define AL_SOURCE_TYPE 0x200
/** Indicate source has absolute coordinates. */
#define AL_SOURCE_ABSOLUTE 0x201
/** Indicate Source has listener relative coordinates. */
#define AL_SOURCE_RELATIVE 0x202
/**
* Directional source, inner cone angle, in degrees.
* Range: [0-360]
* Default: 360
*/
#define AL_CONE_INNER_ANGLE 0x1001
/**
* Directional source, outer cone angle, in degrees.
* Range: [0-360]
* Default: 360
*/
#define AL_CONE_OUTER_ANGLE 0x1002
/**
* Specify the pitch to be applied, either at source,
* or on mixer results, at listener.
* Range: [0.5-2.0]
* Default: 1.0
*/
#define AL_PITCH 0x1003
/**
* Specify the current location in three dimensional space.
* OpenAL, like OpenGL, uses a right handed coordinate system,
* where in a frontal default view X (thumb) points right,
* Y points up (index finger), and Z points towards the
* viewer/camera (middle finger).
* To switch from a left handed coordinate system, flip the
* sign on the Z coordinate.
* Listener position is always in the world coordinate system.
*/
#define AL_POSITION 0x1004
/** Specify the current direction as forward vector. */
#define AL_DIRECTION 0x1005
/** Specify the current velocity in three dimensional space. */
#define AL_VELOCITY 0x1006
/**
* Indicate whether source has to loop infinite.
* Type: ALboolean
* Range: [AL_TRUE, AL_FALSE]
* Default: AL_FALSE
*/
#define AL_LOOPING 0x1007
/**
* Indicate the buffer to provide sound samples.
* Type: ALuint.
* Range: any valid Buffer id.
*/
#define AL_BUFFER 0x1009
/**
* Indicate the gain (volume amplification) applied.
* Type: ALfloat.
* Range: ]0.0- ]
* A value of 1.0 means un-attenuated/unchanged.
* Each division by 2 equals an attenuation of -6dB.
* Each multiplicaton with 2 equals an amplification of +6dB.
* A value of 0.0 is meaningless with respect to a logarithmic
* scale; it is interpreted as zero volume - the channel
* is effectively disabled.
*/
#define AL_GAIN 0x100A
/**
* Indicate minimum source attenuation.
* Type: ALfloat
* Range: [0.0 - 1.0]
*/
#define AL_MIN_GAIN 0x100D
/**
* Indicate maximum source attenuation.
* Type: ALfloat
* Range: [0.0 - 1.0]
*/
#define AL_MAX_GAIN 0x100E
/**
* Specify the current orientation.
* Type: ALfv6 (at/up)
* Range: N/A
*/
#define AL_ORIENTATION 0x100F
/* byte offset into source (in canon format). -1 if source
* is not playing. Don't set this, get this.
*
* Type: ALfloat
* Range: [0.0 - ]
* Default: 1.0
*/
#define AL_REFERENCE_DISTANCE 0x1020
/**
* Indicate the rolloff factor for the source.
* Type: ALfloat
* Range: [0.0 - ]
* Default: 1.0
*/
#define AL_ROLLOFF_FACTOR 0x1021
/**
* Indicate the gain (volume amplification) applied.
* Type: ALfloat.
* Range: ]0.0- ]
* A value of 1.0 means un-attenuated/unchanged.
* Each division by 2 equals an attenuation of -6dB.
* Each multiplicaton with 2 equals an amplification of +6dB.
* A value of 0.0 is meaningless with respect to a logarithmic
* scale; it is interpreted as zero volume - the channel
* is effectively disabled.
*/
#define AL_CONE_OUTER_GAIN 0x1022
/**
* Specify the maximum distance.
* Type: ALfloat
* Range: [0.0 - ]
*/
#define AL_MAX_DISTANCE 0x1023
/**
* Specify the panning to be applied (2D only.)
* Range: [-1.0 - 1.0]
* Default: 0.0
*/
#define AL_PAN 0x1024
/**
* Get the playing time of a stream.
* Range: [0.0 - infinity]
*/
#define AL_TIME 0x1025
/**
* Specify the channel mask. (Creative)
* Type: ALuint
* Range: [0 - 255]
*/
#define AL_CHANNEL_MASK 0x3000
/**
* Source state information
*/
#define AL_SOURCE_STATE 0x1010
#define AL_INITIAL 0x1011
#define AL_PLAYING 0x1012
#define AL_PAUSED 0x1013
#define AL_STOPPED 0x1014
/**
* Buffer Queue params
*/
#define AL_BUFFERS_QUEUED 0x1015
#define AL_BUFFERS_PROCESSED 0x1016
/** Sound buffers: format specifier. */
#define AL_FORMAT_MONO8 0x1100
#define AL_FORMAT_MONO16 0x1101
#define AL_FORMAT_STEREO8 0x1102
#define AL_FORMAT_STEREO16 0x1103
#define AL_FORMAT_MONO4 0x1104
#define AL_FORMAT_STEREO4 0x1105
/**
* Sound buffers: frequency, in units of Hertz [Hz].
* This is the number of samples per second. Half of the
* sample frequency marks the maximum significant
* frequency component.
*/
#define AL_FREQUENCY 0x2001
#define AL_BITS 0x2002
#define AL_CHANNELS 0x2003
#define AL_SIZE 0x2004
#define AL_DATA 0x2005
/**
* Buffer state.
*
* Not supported for public use (yet).
*/
#define AL_UNUSED 0x2010
#define AL_PENDING 0x2011
#define AL_PROCESSED 0x2012
/** Errors: No Error. */
#define AL_NO_ERROR AL_FALSE
/**
* Illegal name passed as an argument to an AL call.
*/
#define AL_INVALID_NAME 0xA001
/**
* Illegal enum passed as an argument to an AL call.
*/
#define AL_INVALID_ENUM 0xA002
/**
* Illegal value passed as an argument to an AL call.
* Applies to parameter values, but not to enumerations.
*/
#define AL_INVALID_VALUE 0xA003
/**
* A function was called at inappropriate time,
* or in an inappropriate way, causing an illegal state.
* This can be an incompatible ALenum, object ID,
* and/or function.
*/
#define AL_INVALID_OPERATION 0xA004
/**
* A function could not be completed,
* because there is not enough memory available.
*/
#define AL_OUT_OF_MEMORY 0xA005
/** Context strings: Vendor Name. */
#define AL_VENDOR 0xB001
#define AL_VERSION 0xB002
#define AL_RENDERER 0xB003
#define AL_EXTENSIONS 0xB004
#define AL_MEMORY_USED 0xB005
#define AL_MEMORY_ALLOCATOR 0xB006
#define AL_MEMORY_DEALLOCATOR 0xB007
#define AL_STEREO 0xB008
/** Global tweakage. */
/**
* Doppler scale. Default 1.0
*/
#define AL_DOPPLER_FACTOR 0xC000
/**
* Doppler velocity. Default 1.0
*/
#define AL_DOPPLER_VELOCITY 0xC001
/**
* Distance model. Default AL_INVERSE_DISTANCE_CLAMPED
*/
#define AL_DISTANCE_MODEL 0xD000
/** Distance models. */
#define AL_INVERSE_DISTANCE 0xD001
#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
/**
* enables
*/
#ifdef __cplusplus
}
#endif
#endif

34
code/client/OpenAL/alu.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef _ALU_H_
#define _ALU_H_
#define ALUAPI
#define ALUAPIENTRY __cdecl
#define BUFFERSIZE 48000
#define FRACTIONBITS 14
#define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
#define OUTPUTCHANNELS 2
#include "altypes.h"
#ifdef __cplusplus
extern "C" {
#endif
ALUAPI ALint ALUAPIENTRY aluF2L(ALfloat value);
ALUAPI ALshort ALUAPIENTRY aluF2S(ALfloat value);
ALUAPI ALvoid ALUAPIENTRY aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector);
ALUAPI ALfloat ALUAPIENTRY aluDotproduct(ALfloat *inVector1,ALfloat *inVector2);
ALUAPI ALvoid ALUAPIENTRY aluNormalize(ALfloat *inVector);
ALUAPI ALvoid ALUAPIENTRY aluMatrixVector(ALfloat matrix[3][3],ALfloat *vector);
ALUAPI ALvoid ALUAPIENTRY aluCalculateSourceParameters(ALuint source,ALuint channels,ALfloat *drysend,ALfloat *wetsend,ALfloat *pitch);
ALUAPI ALvoid ALUAPIENTRY aluMixData(ALvoid *context,ALvoid *buffer,ALsizei size,ALenum format);
ALUAPI ALvoid ALUAPIENTRY aluSetReverb(ALvoid *Reverb,ALuint Environment);
ALUAPI ALvoid ALUAPIENTRY aluReverb(ALvoid *Reverb,ALfloat Buffer[][2],ALsizei BufferSize);
#ifdef __cplusplus
}
#endif
#endif

24
code/client/OpenAL/alut.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef _ALUT_H_
#define _ALUT_H_
#define ALUTAPI
#define ALUTAPIENTRY __cdecl
#include "al.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
ALUTAPI ALvoid ALUTAPIENTRY alutInit(ALint *argc,ALbyte **argv);
ALUTAPI ALvoid ALUTAPIENTRY alutExit(ALvoid);
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop);
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop);
ALUTAPI ALvoid ALUTAPIENTRY alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,66 @@
/*
* UNPUBLISHED -- Rights reserved under the copyright laws of the
* United States. Use of a copyright notice is precautionary only and
* does not imply publication or disclosure.
*
* THIS DOCUMENTATION CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION
* OF VICARIOUS VISIONS, INC. ANY DUPLICATION, MODIFICATION,
* DISTRIBUTION, OR DISCLOSURE IS STRICTLY PROHIBITED WITHOUT THE PRIOR
* EXPRESS WRITTEN PERMISSION OF VICARIOUS VISIONS, INC.
*/
#include <xtl.h>
HANDLE s_BCThread = INVALID_HANDLE_VALUE;
static DWORD WINAPI _BinkCopier(LPVOID)
{
#ifndef FINAL_BUILD
OutputDebugString( "_BinkCopier starting.\n" );
#endif
#ifdef XBOX_DEMO
// Demo only has two planets, and needs to re-map paths.
// But we're in a thread, and va isn't thread-safe. Fuck.
char planetPath[64];
extern char demoBasePath[64];
strcpy( planetPath, demoBasePath );
strcat( planetPath, "\\base\\video\\tatooine.bik" );
CopyFile( planetPath, "Z:\\tatooine.bik", FALSE );
strcpy( planetPath, demoBasePath );
strcat( planetPath, "\\base\\video\\chandrila.bik" );
CopyFile( planetPath, "Z:\\chandrila.bik", FALSE );
#else
CopyFile( "D:\\base\\video\\cos.bik", "Z:\\cos.bik", FALSE );
CopyFile( "D:\\base\\video\\bakura.bik", "Z:\\bakura.bik", FALSE );
CopyFile( "D:\\base\\video\\blenjeel.bik", "Z:\\blenjeel.bik", FALSE );
CopyFile( "D:\\base\\video\\chandrila.bik", "Z:\\chandrila.bik", FALSE );
CopyFile( "D:\\base\\video\\core.bik", "Z:\\core.bik", FALSE );
CopyFile( "D:\\base\\video\\ast.bik", "Z:\\ast.bik", FALSE );
CopyFile( "D:\\base\\video\\dosunn.bik", "Z:\\dosunn.bik", FALSE );
CopyFile( "D:\\base\\video\\krildor.bik", "Z:\\krildor.bik", FALSE );
CopyFile( "D:\\base\\video\\narkreeta.bik", "Z:\\narkreeta.bik", FALSE );
CopyFile( "D:\\base\\video\\ordman.bik", "Z:\\ordman.bik", FALSE );
CopyFile( "D:\\base\\video\\tanaab.bik", "Z:\\tanaab.bik", FALSE );
CopyFile( "D:\\base\\video\\tatooine.bik", "Z:\\tatooine.bik", FALSE );
CopyFile( "D:\\base\\video\\yalara.bik", "Z:\\yalara.bik", FALSE );
CopyFile( "D:\\base\\video\\zonju.bik", "Z:\\zonju.bik", FALSE );
#endif
#ifndef FINAL_BUILD
OutputDebugString( "_BinkCopier exiting.\n" );
#endif
ExitThread(0);
return TRUE;
}
// Spawn our short-lived worker thread that copies all the planet movies to the Z: drive
void Sys_BinkCopyInit(void)
{
// Create a thread to service IO
s_BCThread = CreateThread(NULL, 64*1024, _BinkCopier, 0, 0, NULL);
}

1384
code/client/cl_cgame.cpp Normal file

File diff suppressed because it is too large Load Diff

1955
code/client/cl_cin.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,478 @@
/*****************************************************************************
* name: cl_cin_console.cpp
*
* desc: video and cinematic playback interface for Xbox (using Bink)
*
*****************************************************************************/
#include "client.h"
#include "../win32/win_local.h"
#include "../win32/win_input.h"
#include "../win32/glw_win_dx8.h"
#include "BinkVideo.h"
//#define XBOX_VIDEO_PATH "d:\\base\\video\\"
char XBOX_VIDEO_PATH[64] = "d:\\base\\video\\";
#define SHADER_VIDEO_PATH "z:\\"
BinkVideo bVideo; // bink video object
connstate_t previousState = CA_UNINITIALIZED; // previous cinematic state
struct CinematicData
{
char filename[MAX_OSPATH]; // No path, no extension
int x, y, w, h; // Dimensions
int bits; // Flags (loop, silent, shader)
};
// We have a fixed lookup table of all cinematics that can be played
// Video handles are just indices into the array. An entry is not
// considered initialized until its width is nonzero
CinematicData cinFiles[] = {
// Opening logos
{ "logos", 0, 0, 0, 0, 0 },
// Attract sequence
{ "attract", 0, 0, 0, 0, 0 },
// Planet shaders
{ "cos", 0, 0, 0, 0, 0 },
{ "bakura", 0, 0, 0, 0, 0 },
{ "blenjeel", 0, 0, 0, 0, 0 },
{ "chandrila", 0, 0, 0, 0, 0 },
{ "core", 0, 0, 0, 0, 0 },
{ "ast", 0, 0, 0, 0, 0 },
{ "dosunn", 0, 0, 0, 0, 0 },
{ "krildor", 0, 0, 0, 0, 0 },
{ "narkreeta", 0, 0, 0, 0, 0 },
{ "ordman", 0, 0, 0, 0, 0 },
{ "tanaab", 0, 0, 0, 0, 0 },
{ "tatooine", 0, 0, 0, 0, 0 },
{ "yalara", 0, 0, 0, 0, 0 },
{ "zonju", 0, 0, 0, 0, 0 },
// Others
// { "jk0101_sw", 0, 0, 0, 0, 0 }, // Folded into ja01!
// { "ja01", 0, 0, 0, 0, 0 }, // Contains the text crawl, so must be localized:
{ "ja01_e", 0, 0, 0, 0, 0 },
{ "ja01_f", 0, 0, 0, 0, 0 },
{ "ja01_d", 0, 0, 0, 0, 0 },
{ "ja02", 0, 0, 0, 0, 0 },
{ "ja03", 0, 0, 0, 0, 0 },
{ "ja04", 0, 0, 0, 0, 0 },
{ "ja05", 0, 0, 0, 0, 0 },
{ "ja06", 0, 0, 0, 0, 0 },
{ "ja07", 0, 0, 0, 0, 0 },
{ "ja08", 0, 0, 0, 0, 0 },
{ "ja09", 0, 0, 0, 0, 0 },
{ "ja10", 0, 0, 0, 0, 0 },
{ "ja11", 0, 0, 0, 0, 0 },
{ "ja12", 0, 0, 0, 0, 0 },
};
const int cinNumFiles = sizeof(cinFiles) / sizeof(cinFiles[0]);
static int currentHandle = -1;
// Stupid PC filth
static qboolean qbInGameCinematicOnStandBy = qfalse;
static char sInGameCinematicStandingBy[MAX_QPATH];
bool CIN_PlayAllFrames( const char *arg, int x, int y, int w, int h, int systemBits, bool keyBreakAllowed );
/********
CIN_CloseAllVideos
Stops all currently running videos
*********/
void CIN_CloseAllVideos(void)
{
// Stop the current bink video
bVideo.Stop();
currentHandle = -1;
}
/********
CIN_StopCinematic
handle - Not used
return - FMV status
Stops the current cinematic
*********/
e_status CIN_StopCinematic(int handle)
{
assert( handle == currentHandle );
currentHandle = -1;
if(previousState != CA_UNINITIALIZED)
{
cls.state = previousState;
previousState = CA_UNINITIALIZED;
}
if(bVideo.GetStatus() != NS_BV_STOPPED)
{
bVideo.Stop();
}
return FMV_EOF;
}
/********
CIN_RunCinematic
handle - Ensure that the supplied cinematic is the one running
return - FMV status
Fetch and decompress the pending frame
*********/
e_status CIN_RunCinematic (int handle)
{
if (handle < 0 || handle >= cinNumFiles || !cinFiles[handle].w)
{
assert( 0 );
return FMV_EOF;
}
// If we weren't playing a movie, or playing the wrong one - start up
if (handle != currentHandle)
{
bool shader = cinFiles[handle].bits & CIN_shader;
CIN_StopCinematic(currentHandle);
if (!bVideo.Start(
va("%s%s.bik",
shader ? SHADER_VIDEO_PATH : XBOX_VIDEO_PATH,
cinFiles[handle].filename),
cinFiles[handle].x, cinFiles[handle].y,
cinFiles[handle].w, cinFiles[handle].h))
{
return FMV_EOF;
}
if (cinFiles[handle].bits & CIN_loop)
{
bVideo.SetLooping(true);
}
else
{
bVideo.SetLooping(false);
}
if (cinFiles[handle].bits & CIN_silent)
{
bVideo.SetMasterVolume(0);
}
else
{
bVideo.SetMasterVolume(16384); //32768); // Default Bink volume
}
if (!shader)
{
previousState = cls.state;
cls.state = CA_CINEMATIC;
}
currentHandle = handle;
}
// Normal case does nothing here
if(bVideo.GetStatus() == NS_BV_STOPPED)
{
return FMV_EOF;
}
else
{
return FMV_PLAY;
}
}
/********
CIN_PlayCinematic
arg0 - filename of bink video
xpos - x origin
ypos - y origin
width - width of the movie window
height - height of the movie window
bits - CIN flags
psAudioFile - audio file for movie (not used)
Starts playing the given bink video file
*********/
int CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits, const char *psAudioFile /* = NULL */)
{
char arg[MAX_OSPATH];
char* nameonly;
int handle;
// get a local copy of the name
strcpy(arg,arg0);
// remove path, find in list
nameonly = COM_SkipPath(arg);
// ja01 contains the text crawl, so we need to add on the right language suffix
extern DWORD g_dwLanguage;
if( Q_stricmp(nameonly, "ja01") == 0)
{
switch( g_dwLanguage )
{
case XC_LANGUAGE_FRENCH:
strcat(nameonly, "_f");
break;
case XC_LANGUAGE_GERMAN:
strcat(nameonly, "_d");
break;
case XC_LANGUAGE_ENGLISH:
default:
strcat(nameonly, "_e");
break;
}
}
for (handle = 0; handle < cinNumFiles; ++handle)
{
if (!Q_stricmp(cinFiles[handle].filename, nameonly))
break;
}
// Don't have the requested movie in our table?
if (handle == cinNumFiles)
{
Com_Printf( "ERROR: Movie file %s not found!\n", nameonly );
return -1;
}
// Store off information about the movie in the right place. Don't
// actually play them movie, CIN_RunCinematic takes care of that.
cinFiles[handle].x = xpos;
cinFiles[handle].y = ypos;
cinFiles[handle].w = width;
cinFiles[handle].h = height;
cinFiles[handle].bits = bits;
currentHandle = -1;
return handle;
}
/*********
CIN_SetExtents
handle - handle to a video
x - x origin for window
y - y origin for window
w - width for window
h - height for window
*********/
void CIN_SetExtents (int handle, int x, int y, int w, int h)
{
if (handle < 0 || handle >= cinNumFiles)
return;
cinFiles[handle].x = x;
cinFiles[handle].y = y;
cinFiles[handle].w = w;
cinFiles[handle].h = h;
if (handle == currentHandle)
bVideo.SetExtents(x,y,w,h);
}
/*********
SCR_DrawCinematic
Externally-called only, and only if cls.state == CA_CINEMATIC (or CL_IsRunningInGameCinematic() == true now)
*********/
void SCR_DrawCinematic (void)
{
if (CL_InGameCinematicOnStandBy())
{
CIN_PlayAllFrames( sInGameCinematicStandingBy, 0, 0, 640, 480, 0, true );
}
else
{
// Run and draw a frame:
bVideo.Run();
}
}
/*********
SCR_RunCinematic
*********/
void SCR_RunCinematic (void)
{
// This is called every frame, even when we're not playing a movie
// VVFIXME - Check return val for EOF - then stop cinematic?
if (currentHandle > 0 && currentHandle < cinNumFiles)
CIN_RunCinematic(currentHandle);
}
/*********
SCR_StopCinematic
*********/
void SCR_StopCinematic(qboolean bAllowRefusal /* = qfalse */)
{
CIN_StopCinematic(currentHandle);
}
/*********
CIN_UploadCinematic
handle - (not used)
This function can be used to render a frame of a movie, if
it needs to be done outside of CA_CINEMATIC. For example,
a menu background or wall texture.
*********/
void CIN_UploadCinematic(int handle)
{
int w, h;
byte* data;
assert( handle == currentHandle );
if(!bVideo.Ready()) {
return;
}
w = bVideo.GetBinkWidth();
h = bVideo.GetBinkHeight();
data = (byte*)bVideo.GetBinkData();
// handle is actually being used to pick from scratchImages in
// this function - we only have two on Xbox, let's just use one.
//re.UploadCinematic( w, h, data, handle, 1);
re.UploadCinematic( w, h, data, 0, 1);
}
/*********
CIN_PlayAllFrames
arg - bink video filename
x - x origin for movie
y - y origin for movie
w - width of the movie
h - height of the movie
systemBits - bit rate for movie
keyBreakAllowed - if true, button press will end playback
Plays the target movie in full
*********/
bool CIN_PlayAllFrames( const char *arg, int x, int y, int w, int h, int systemBits, bool keyBreakAllowed )
{
bool retval;
Key_ClearStates();
// PC hack
qbInGameCinematicOnStandBy = qfalse;
#ifdef XBOX_DEMO
// When run from CDX, we can pause the timer during cutscenes:
extern void Demo_TimerPause( bool bPaused );
Demo_TimerPause( true );
#endif
int Handle = CIN_PlayCinematic(arg, x, y, w, h, systemBits, NULL);
if (Handle != -1)
{
while (CIN_RunCinematic(Handle) == FMV_PLAY && !(keyBreakAllowed && kg.anykeydown))
{
SCR_UpdateScreen ();
IN_Frame ();
Com_EventLoop ();
}
#ifdef _XBOX
// while (CIN_RunCinematic(Handle) == FMV_PLAY && !(keyBreakAllowed && !kg.anykeydown))
// {
// SCR_UpdateScreen ();
// IN_Frame ();
// Com_EventLoop ();
// }
#endif
CIN_StopCinematic(Handle);
}
#ifdef XBOX_DEMO
Demo_TimerPause( false );
#endif
retval =(keyBreakAllowed && kg.anykeydown);
Key_ClearStates();
// Soooper hack! Game ends up running for a couple frames after this cutscene. We don't want it to!
if( Q_stricmp(arg, "ja08") == 0 )
{
// Filth. Don't call Present until this gets cleared.
extern bool connectSwapOverride;
connectSwapOverride = true;
}
return retval;
}
/*********
CIN_Init
Initializes cinematic system
*********/
void CIN_Init(void)
{
// Allocate Memory for Bink System
bVideo.AllocateXboxMem();
}
/********
CIN_Shutdown
Shutdown the cinematic system
********/
void CIN_Shutdown(void)
{
// Free Memory for the Bink System
bVideo.FreeXboxMem();
}
/***** Possible FIXME *****/
/***** The following function may need to be implemented *****/
/***** BEGIN *****/
void CL_PlayCinematic_f(void)
{
char *arg;
arg = Cmd_Argv(1);
CIN_PlayAllFrames(arg, 48, 36, 544, 408, 0, true);
}
qboolean CL_IsRunningInGameCinematic(void)
{
return qfalse; //qbPlayingInGameCinematic;
}
void CL_PlayInGameCinematic_f(void)
{
if (cls.state == CA_ACTIVE)
{
// In some situations (during yavin1 intro) we move to a cutscene directly from
// a shaking camera - so rumble never gets killed.
IN_KillRumbleScripts();
char *arg = Cmd_Argv( 1 );
CIN_PlayAllFrames(arg, 48, 36, 544, 408, 0, true);
}
else
{
qbInGameCinematicOnStandBy = qtrue;
strcpy(sInGameCinematicStandingBy,Cmd_Argv(1));
}
}
qboolean CL_InGameCinematicOnStandBy(void)
{
return qbInGameCinematicOnStandBy;
}
// Used by fatal error handler
void MuteBinkSystem( void )
{
bVideo.SetMasterVolume( 0 );
}
/***** END *****/

730
code/client/cl_console.cpp Normal file
View File

@@ -0,0 +1,730 @@
// console.c
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "client.h"
#include "../qcommon/stv_version.h"
int g_console_field_width = 78;
console_t con;
cvar_t *con_conspeed;
cvar_t *con_notifytime;
cvar_t *con_conAlpha; //background alpha multiplier
#define DEFAULT_CONSOLE_WIDTH 78
/*
================
Con_ToggleConsole_f
================
*/
void Con_ToggleConsole_f (void) {
// closing a full screen console restarts the demo loop
if ( cls.state == CA_DISCONNECTED && cls.keyCatchers == KEYCATCH_CONSOLE ) {
// CL_StartDemoLoop();
return;
}
Field_Clear( &kg.g_consoleField );
kg.g_consoleField.widthInChars = g_console_field_width;
Con_ClearNotify ();
cls.keyCatchers ^= KEYCATCH_CONSOLE;
}
/*
================
Con_MessageMode_f
================
*/
void Con_MessageMode_f (void) {
Field_Clear( &chatField );
chatField.widthInChars = 30;
// cls.keyCatchers ^= KEYCATCH_MESSAGE;
}
/*
================
Con_Clear_f
================
*/
void Con_Clear_f (void) {
int i;
for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
Con_Bottom(); // go to end
}
/*
================
Con_Dump_f
Save the console contents out to a file
================
*/
void Con_Dump_f (void)
{
#ifndef _XBOX
int l, x, i;
short *line;
fileHandle_t f;
char buffer[1024];
if (Cmd_Argc() != 2)
{
Com_Printf (SE_GetString("CON_TEXT_DUMP_USAGE"));
return;
}
Com_Printf ("Dumped console text to %s.\n", Cmd_Argv(1) );
f = FS_FOpenFileWrite( Cmd_Argv( 1 ) );
if (!f)
{
Com_Printf (S_COLOR_RED"ERROR: couldn't open dump file.\n");
return;
}
// skip empty lines
for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
{
line = con.text + (l%con.totallines)*con.linewidth;
for (x=0 ; x<con.linewidth ; x++)
if ((line[x] & 0xff) != ' ')
break;
if (x != con.linewidth)
break;
}
// write the remaining lines
buffer[con.linewidth] = 0;
for ( ; l <= con.current ; l++)
{
line = con.text + (l%con.totallines)*con.linewidth;
for(i=0; i<con.linewidth; i++)
buffer[i] = line[i] & 0xff;
for (x=con.linewidth-1 ; x>=0 ; x--)
{
if (buffer[x] == ' ')
buffer[x] = 0;
else
break;
}
FS_Printf (f, "%s\n", buffer);
}
FS_FCloseFile( f );
#endif
}
/*
================
Con_ClearNotify
================
*/
void Con_ClearNotify( void ) {
int i;
for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
con.times[i] = 0;
}
}
/*
================
Con_CheckResize
If the line width has changed, reformat the buffer.
================
*/
void Con_CheckResize (void)
{
int i, j, width, oldwidth, oldtotallines, numlines, numchars;
MAC_STATIC short tbuf[CON_TEXTSIZE];
//width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
width = (cls.glconfig.vidWidth / SMALLCHAR_WIDTH) - 2;
if (width == con.linewidth)
return;
if (width < 1) // video hasn't been initialized yet
{
con.xadjust = 1;
con.yadjust = 1;
width = DEFAULT_CONSOLE_WIDTH;
con.linewidth = width;
con.totallines = CON_TEXTSIZE / con.linewidth;
for(i=0; i<CON_TEXTSIZE; i++)
{
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
}
else
{
// on wide screens, we will center the text
con.xadjust = 640.0f / cls.glconfig.vidWidth;
con.yadjust = 480.0f / cls.glconfig.vidHeight;
oldwidth = con.linewidth;
con.linewidth = width;
oldtotallines = con.totallines;
con.totallines = CON_TEXTSIZE / con.linewidth;
numlines = oldtotallines;
if (con.totallines < numlines)
numlines = con.totallines;
numchars = oldwidth;
if (con.linewidth < numchars)
numchars = con.linewidth;
memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));
for(i=0; i<CON_TEXTSIZE; i++)
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
for (i=0 ; i<numlines ; i++)
{
for (j=0 ; j<numchars ; j++)
{
con.text[(con.totallines - 1 - i) * con.linewidth + j] =
tbuf[((con.current - i + oldtotallines) %
oldtotallines) * oldwidth + j];
}
}
Con_ClearNotify ();
}
con.current = con.totallines - 1;
con.display = con.current;
}
/*
================
Con_Init
================
*/
void Con_Init (void) {
int i;
con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
con_conAlpha= Cvar_Get( "conAlpha", "1.6", CVAR_ARCHIVE );
Field_Clear( &kg.g_consoleField );
kg.g_consoleField.widthInChars = g_console_field_width;
for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
Field_Clear( &kg.historyEditLines[i] );
kg.historyEditLines[i].widthInChars = g_console_field_width;
}
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
Cmd_AddCommand ("messagemode", Con_MessageMode_f);
Cmd_AddCommand ("clear", Con_Clear_f);
Cmd_AddCommand ("condump", Con_Dump_f);
}
/*
===============
Con_Linefeed
===============
*/
void Con_Linefeed (void)
{
int i;
// mark time for transparent overlay
if (con.current >= 0)
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
con.x = 0;
if (con.display == con.current)
con.display++;
con.current++;
for(i=0; i<con.linewidth; i++)
con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
/*
================
CL_ConsolePrint
Handles cursor positioning, line wrapping, etc
All console printing must go through this in order to be logged to disk
If no console is visible, the text will appear at the top of the game window
================
*/
void CL_ConsolePrint( char *txt ) {
int y;
int c, l;
int color;
// for some demos we don't want to ever show anything on the console
if ( cl_noprint && cl_noprint->integer ) {
return;
}
if (!con.initialized) {
con.color[0] =
con.color[1] =
con.color[2] =
con.color[3] = 1.0f;
con.linewidth = -1;
Con_CheckResize ();
con.initialized = qtrue;
}
color = ColorIndex(COLOR_WHITE);
while ( (c = (unsigned char )*txt) != 0 ) {
if ( Q_IsColorString( (unsigned char*) txt ) ) {
color = ColorIndex( *(txt+1) );
txt += 2;
continue;
}
// count word length
for (l=0 ; l< con.linewidth ; l++) {
if ( txt[l] <= ' ') {
break;
}
}
// word wrap
if (l != con.linewidth && (con.x + l >= con.linewidth) ) {
Con_Linefeed();
}
txt++;
switch (c)
{
case '\n':
Con_Linefeed ();
break;
case '\r':
con.x = 0;
break;
default: // display character and advance
y = con.current % con.totallines;
con.text[y*con.linewidth+con.x] = (color << 8) | c;
con.x++;
if (con.x >= con.linewidth) {
Con_Linefeed();
con.x = 0;
}
break;
}
}
// mark time for transparent overlay
if (con.current >= 0)
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
}
/*
==============================================================================
DRAWING
==============================================================================
*/
/*
================
Con_DrawInput
Draw the editline after a ] prompt
================
*/
void Con_DrawInput (void) {
int y;
if ( cls.state != CA_DISCONNECTED && !(cls.keyCatchers & KEYCATCH_CONSOLE ) ) {
return;
}
y = con.vislines - ( SMALLCHAR_HEIGHT * (re.Language_IsAsian() ? 1.5 : 2) );
re.SetColor( con.color );
SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' );
Field_Draw( &kg.g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y,
SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue );
}
/*
================
Con_DrawNotify
Draws the last few lines of output transparently over the game top
================
*/
void Con_DrawNotify (void)
{
int x, v;
short *text;
int i;
int time;
int skip;
int currentColor;
currentColor = 7;
re.SetColor( g_color_table[currentColor] );
v = 0;
for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
{
if (i < 0)
continue;
time = con.times[i % NUM_CON_TIMES];
if (time == 0)
continue;
time = cls.realtime - time;
if (time > con_notifytime->value*1000)
continue;
text = con.text + (i % con.totallines)*con.linewidth;
// asian language needs to use the new font system to print glyphs...
//
// (ignore colours since we're going to print the whole thing as one string)
//
if (re.Language_IsAsian())
{
int iFontIndex = re.RegisterFont("ocr_a"); // this seems naughty
const float fFontScale = 0.75f*con.yadjust;
const int iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re.Font_HeightPixels(iFontIndex, fFontScale); // for asian spacing, since we don't want glyphs to touch.
// concat the text to be printed...
//
char sTemp[4096]={0}; // ott
for (x = 0 ; x < con.linewidth ; x++)
{
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
strcat(sTemp,va("^%i", (text[x]>>8)&7) );
}
strcat(sTemp,va("%c",text[x] & 0xFF));
}
//
// and print...
//
re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*aesthetics*/)), con.yadjust*(v), sTemp, g_color_table[currentColor], iFontIndex, -1, fFontScale);
v += iPixelHeightToAdvance;
}
else
{
for (x = 0 ; x < con.linewidth ; x++) {
if ( ( text[x] & 0xff ) == ' ' ) {
continue;
}
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
re.SetColor( g_color_table[currentColor] );
}
SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
}
v += SMALLCHAR_HEIGHT;
}
}
re.SetColor( NULL );
// draw the chat line
if ( cls.keyCatchers & KEYCATCH_MESSAGE )
{
SCR_DrawBigString (8, v, "say:", 1.0f );
skip = 5;
Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue );
v += BIGCHAR_HEIGHT;
}
}
/*
================
Con_DrawSolidConsole
Draws the console with the solid background
================
*/
#ifndef _XBOX
void Con_DrawSolidConsole( float frac )
{
int i, x, y;
int rows;
short *text;
int row;
int lines;
int currentColor;
lines = cls.glconfig.vidHeight * frac;
if (lines <= 0)
return;
if (lines > cls.glconfig.vidHeight )
lines = cls.glconfig.vidHeight;
// draw the background
y = frac * SCREEN_HEIGHT - 2;
if ( y < 1 ) {
y = 0;
}
else {
// draw the background only if fullscreen
if ( frac != 1.0f )
{
vec4_t con_color;
MAKERGBA( con_color, 0.0f, 0.0f, 0.0f, frac*con_conAlpha->value );
re.SetColor(con_color);
}
else
{
re.SetColor(NULL);
}
SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader);
}
const vec4_t color = { 0.509f, 0.609f, 0.847f, 1.0f};
// draw the bottom bar and version number
re.SetColor( color );
re.DrawStretchPic( 0, y, SCREEN_WIDTH, 2, 0, 0, 0, 0, cls.whiteShader );
i = strlen( Q3_VERSION );
for (x=0 ; x<i ; x++) {
SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x ) * SMALLCHAR_WIDTH,
(lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] );
}
// draw the text
con.vislines = lines;
rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw
y = lines - (SMALLCHAR_HEIGHT*3);
// draw from the bottom up
if (con.display != con.current)
{
// draw arrows to show the buffer is backscrolled
re.SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
for (x=0 ; x<con.linewidth ; x+=4)
SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
y -= SMALLCHAR_HEIGHT;
rows--;
}
row = con.display;
if ( con.x == 0 ) {
row--;
}
currentColor = 7;
re.SetColor( g_color_table[currentColor] );
int iFontIndexForAsian = 0; // kinda tacky, this just gets the first registered font, since Asian stuff ignores the contents anyway
const float fFontScaleForAsian = 0.75f*con.yadjust;
int iPixelHeightToAdvance = SMALLCHAR_HEIGHT;
if (re.Language_IsAsian())
{
if (!iFontIndexForAsian)
{
iFontIndexForAsian = re.RegisterFont("ocr_a"); // must be a font that's used elsewhere
}
iPixelHeightToAdvance = (1.3/con.yadjust) * re.Font_HeightPixels(iFontIndexForAsian, fFontScaleForAsian); // for asian spacing, since we don't want glyphs to touch.
}
for (i=0 ; i<rows ; i++, y -= iPixelHeightToAdvance, row--)
{
if (row < 0)
break;
if (con.current - row >= con.totallines) {
// past scrollback wrap point
continue;
}
text = con.text + (row % con.totallines)*con.linewidth;
// asian language needs to use the new font system to print glyphs...
//
// (ignore colours since we're going to print the whole thing as one string)
//
if (re.Language_IsAsian())
{
// concat the text to be printed...
//
char sTemp[4096]={0}; // ott
for (x = 0 ; x < con.linewidth ; x++)
{
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
strcat(sTemp,va("^%i", (text[x]>>8)&7) );
}
strcat(sTemp,va("%c",text[x] & 0xFF));
}
//
// and print...
//
re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*(aesthetics)*/)), con.yadjust*(y), sTemp, g_color_table[currentColor], iFontIndexForAsian, -1, fFontScaleForAsian);
}
else
{
for (x=0 ; x<con.linewidth ; x++) {
if ( ( text[x] & 0xff ) == ' ' ) {
continue;
}
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
re.SetColor( g_color_table[currentColor] );
}
SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
}
}
}
// draw the input prompt, user text, and cursor if desired
Con_DrawInput ();
re.SetColor( NULL );
}
#endif
/*
==================
Con_DrawConsole
==================
*/
#ifndef _XBOX
void Con_DrawConsole( void ) {
// check for console width changes from a vid mode change
Con_CheckResize ();
// if disconnected, render console full screen
if ( cls.state == CA_DISCONNECTED ) {
if ( !( cls.keyCatchers & KEYCATCH_UI ) ) {
Con_DrawSolidConsole( 1.0 );
return;
}
}
if ( con.displayFrac ) {
Con_DrawSolidConsole( con.displayFrac );
} else {
// draw notify lines
if ( cls.state == CA_ACTIVE ) {
Con_DrawNotify ();
}
}
}
#endif
//================================================================
/*
==================
Con_RunConsole
Scroll it up or down
==================
*/
void Con_RunConsole (void) {
// decide on the destination height of the console
if ( cls.keyCatchers & KEYCATCH_CONSOLE )
con.finalFrac = 0.5; // half screen
else
con.finalFrac = 0; // none visible
// scroll towards the destination height
if (con.finalFrac < con.displayFrac)
{
con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
if (con.finalFrac > con.displayFrac)
con.displayFrac = con.finalFrac;
}
else if (con.finalFrac > con.displayFrac)
{
con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
if (con.finalFrac < con.displayFrac)
con.displayFrac = con.finalFrac;
}
}
void Con_PageUp( void ) {
con.display -= 2;
if ( con.current - con.display >= con.totallines ) {
con.display = con.current - con.totallines + 1;
}
}
void Con_PageDown( void ) {
con.display += 2;
if (con.display > con.current) {
con.display = con.current;
}
}
void Con_Top( void ) {
con.display = con.totallines;
if ( con.current - con.display >= con.totallines ) {
con.display = con.current - con.totallines + 1;
}
}
void Con_Bottom( void ) {
con.display = con.current;
}
void Con_Close( void ) {
Field_Clear( &kg.g_consoleField );
Con_ClearNotify ();
cls.keyCatchers &= ~KEYCATCH_CONSOLE;
con.finalFrac = 0; // none visible
con.displayFrac = 0;
}

1039
code/client/cl_input.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/*
TODO: finalize item support
1) Make ItemSelectUp() work.
2) Change cg.itemSelect to whatever var is used to store selected item.
3) Make sure commands in itemCommands work in both multi & single player.
*/
#include "client.h"
#include "../cgame/cg_local.h"
#include "cl_input_hotswap.h"
#include "../qcommon/xb_settings.h"
#define FORCESELECTTIME forcepowerSelectTime
#define FORCESELECT forcepowerSelect
#define INVSELECTTIME inventorySelectTime
#define INVSELECT inventorySelect
#define REGISTERSOUND cgi_S_RegisterSound
#define STARTSOUND cgi_S_StartLocalSound
#define WEAPONBINDSTR "weapon"
#define BIND_TIME 2000 //number of milliseconds button is held before binding
const char *itemCommands[INV_MAX] = {
"use_electrobinoculars\n",
"use_bacta\n",
"use_seeker\n",
"use_goggles\n",
"use_sentry\n",
NULL, //goodie key
NULL, //security key
};
// Commands to issue when user presses a force-bound button
const char *forceDownCommands[MAX_SHOWPOWERS] = {
"force_absorb\n",
"force_heal\n",
"force_protect\n",
"force_distract\n",
"force_speed\n",
"force_throw\n",
"force_pull\n",
"force_sight\n",
"+force_drain\n",
"+force_lightning\n",
"force_rage\n",
"+force_grip\n",
};
// Commands to issue when user releases a force-bound button
const char *forceUpCommands[MAX_SHOWPOWERS] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"-force_drain\n",
"-force_lightning\n",
NULL,
"-force_grip\n",
};
HotSwapManager::HotSwapManager(int uniqueID) :
uniqueID(uniqueID)
{
Reset();
}
const char *HotSwapManager::GetBinding(void)
{
char buf[64];
sprintf(buf, "hotswap%d", uniqueID);
cvar_t *cvar = Cvar_Get(buf, "", CVAR_ARCHIVE);
if(!cvar || !cvar->string[0])
return NULL;
if (cvar->integer < HOTSWAP_CAT_ITEM) { // Weapon
return va("weapon %d", cvar->integer);
} else if (cvar->integer < HOTSWAP_CAT_FORCE) { // Item
return itemCommands[cvar->integer - HOTSWAP_CAT_ITEM];
} else { // Force power
return forceDownCommands[cvar->integer - HOTSWAP_CAT_FORCE];
}
}
const char *HotSwapManager::GetBindingUp(void)
{
char buf[64];
sprintf(buf, "hotswap%d", uniqueID);
cvar_t *cvar = Cvar_Get(buf, "", CVAR_ARCHIVE);
if(!cvar || !cvar->string[0])
return NULL;
// Only force powers have release-commands
if (cvar->integer < HOTSWAP_CAT_FORCE) {
return NULL;
} else {
return forceUpCommands[cvar->integer - HOTSWAP_CAT_FORCE];
}
}
void HotSwapManager::Bind(void)
{
if(WeaponSelectUp()) {
HotSwapBind(uniqueID, HOTSWAP_CAT_WEAPON, cg.weaponSelect);
} else if(ForceSelectUp()) {
HotSwapBind(uniqueID, HOTSWAP_CAT_FORCE, cg.FORCESELECT);
} else if(ItemSelectUp()) {
HotSwapBind(uniqueID, HOTSWAP_CAT_ITEM, cg.INVSELECT);
} else{
assert(0);
}
noBind = true;
STARTSOUND(REGISTERSOUND("sound/interface/update"), 0);
}
bool HotSwapManager::ForceSelectUp(void)
{
return cg.FORCESELECTTIME != 0 &&
(cg.FORCESELECTTIME + WEAPON_SELECT_TIME >= cg.time);
}
bool HotSwapManager::WeaponSelectUp(void)
{
return cg.weaponSelectTime != 0 &&
(cg.weaponSelectTime + WEAPON_SELECT_TIME >= cg.time);
}
bool HotSwapManager::ItemSelectUp(void)
{
return cg.INVSELECTTIME != 0 &&
(cg.INVSELECTTIME + WEAPON_SELECT_TIME >= cg.time);
}
bool HotSwapManager::HUDInBindState(void)
{
return ForceSelectUp() || WeaponSelectUp() || ItemSelectUp();
}
void HotSwapManager::Update(void)
{
if(down) {
//Increment bindTime only if HUD is in select mode.
if(HUDInBindState()) {
bindTime += cls.frametime;
} else {
//Clear bind time.
bindTime = 0;
}
}
//Down long enough, bind button.
if(!noBind && bindTime >= BIND_TIME) {
Bind();
}
}
void HotSwapManager::Execute(void)
{
const char *binding = GetBinding();
if(binding) {
Cbuf_ExecuteText(EXEC_NOW, binding);
}
}
void HotSwapManager::ExecuteUp(void)
{
const char *binding = GetBindingUp();
if(binding) {
Cbuf_ExecuteText(EXEC_NOW, binding);
}
}
void HotSwapManager::SetDown(void)
{
//Set the down flag.
down = true;
//Execute the bind if the HUD isn't up. Also, prevent re-binding!
if(!HUDInBindState()) {
Execute();
noBind = true;
}
}
void HotSwapManager::SetUp(void)
{
// Execute the tail of the command if the HUD isn't up.
if(!HUDInBindState()) {
ExecuteUp();
}
Reset();
}
void HotSwapManager::Reset(void)
{
down = false;
bindTime = 0;
noBind = false;
}
void HotSwapBind(int buttonID, int category, int value)
{
char uniqueID[64];
sprintf(uniqueID, "hotswap%d", buttonID);
// Add category as an offset for when we retrieve it
Cvar_SetValue( uniqueID, value+category );
Settings.hotswapSP[buttonID] = value+category;
Settings.Save();
}

View File

@@ -0,0 +1,64 @@
#ifndef __CL_INPUT_HOTSWAP_H
#define __CL_INPUT_HOTSWAP_H
#define HOTSWAP_ID_WHITE 0
#define HOTSWAP_ID_BLACK 1
#define HOTSWAP_ID_YELLOW 2
#define HOTSWAP_CAT_WEAPON 0
#define HOTSWAP_CAT_ITEM 1024
#define HOTSWAP_CAT_FORCE 2048
class HotSwapManager
{
private:
bool down; //Is the button down?
bool noBind; //Don't bind the button.
int bindTime; //How long the button has been down with the selection up.
int uniqueID; //Unique ID for this button.
//Return the binding for the button, or NULL if none.
const char *GetBinding(void);
const char *GetBindingUp(void);
//Returns true if the weapon/force/item select screen is up.
bool HUDInBindState(void);
//Returns true if the weapon/force/item select screen is up.
bool ForceSelectUp(void);
bool WeaponSelectUp(void);
bool ItemSelectUp(void);
//Binds the button based on the current HUD selection.
void Bind(void);
//Execute the current bind, if there is one.
void Execute(void);
void ExecuteUp(void);
//Reset the object to the default state.
void Reset(void);
public:
HotSwapManager(int uniqueID);
//Call every frame. Uses cg.frametime to increment timers.
void Update(void);
//Set the button down or up.
void SetDown(void);
void SetUp(void);
//Returns true if the button is currently down.
bool ButtonDown(void) { return down; }
};
//External bind function for sharing with UI.
extern void HotSwapBind(int buttonID, int category, int value);
#endif

1479
code/client/cl_keys.cpp Normal file

File diff suppressed because it is too large Load Diff

1629
code/client/cl_main.cpp Normal file

File diff suppressed because it is too large Load Diff

554
code/client/cl_mp3.cpp Normal file
View File

@@ -0,0 +1,554 @@
// Filename:- cl_mp3.cpp
//
// (The interface module between all the MP3 stuff and Trek)
//
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "client.h"
#include "cl_mp3.h" // only included directly by a few snd_xxxx.cpp files plus this one
#include "../mp3code/mp3struct.h" // keep this rather awful file secret from the rest of the program
#include "../mp3code/copyright.h"
// expects data already loaded, filename arg is for error printing only
//
// returns success/fail
//
qboolean MP3_IsValid( const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired /* = qfalse */)
{
char *psError = C_MP3_IsValid(pvData, iDataLen, bStereoDesired);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s(%s)\n",psError, psLocalFilename));
}
return !psError;
}
// expects data already loaded, filename arg is for error printing only
//
// returns unpacked length, or 0 for errors (which will be printed internally)
//
int MP3_GetUnpackedSize( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag /* = qfalse */
, qboolean bStereoDesired /* = qfalse */
)
{
int iUnpackedSize = 0;
// always do this now that we have fast-unpack code for measuring output size... (much safer than relying on tags that may have been edited, or if MP3 has been re-saved with same tag)
//
if (1)//qbIgnoreID3Tag || !MP3_ReadSpecialTagInfo((byte *)pvData, iDataLen, NULL, &iUnpackedSize))
{
char *psError = C_MP3_GetUnpackedSize( pvData, iDataLen, &iUnpackedSize, bStereoDesired);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
return 0;
}
}
return iUnpackedSize;
}
// expects data already loaded, filename arg is for error printing only
//
// returns byte count of unpacked data (effectively a success/fail bool)
//
int MP3_UnpackRawPCM( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer, qboolean bStereoDesired /* = qfalse */)
{
int iUnpackedSize;
char *psError = C_MP3_UnpackRawPCM( pvData, iDataLen, &iUnpackedSize, pbUnpackBuffer, bStereoDesired);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
return 0;
}
return iUnpackedSize;
}
// psLocalFilename is just for error reporting (if any)...
//
qboolean MP3Stream_InitPlayingTimeFields( LP_MP3STREAM lpMP3Stream, const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired /* = qfalse */)
{
qboolean bRetval = qfalse;
int iRate, iWidth, iChannels;
char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &iRate, &iWidth, &iChannels, bStereoDesired );
if (psError)
{
Com_Printf(va(S_COLOR_RED"MP3Stream_InitPlayingTimeFields(): %s\n(File: %s)\n",psError, psLocalFilename));
}
else
{
int iUnpackLength = MP3_GetUnpackedSize( psLocalFilename, pvData, iDataLen, qfalse, // qboolean qbIgnoreID3Tag
bStereoDesired);
if (iUnpackLength)
{
lpMP3Stream->iTimeQuery_UnpackedLength = iUnpackLength;
lpMP3Stream->iTimeQuery_SampleRate = iRate;
lpMP3Stream->iTimeQuery_Channels = iChannels;
lpMP3Stream->iTimeQuery_Width = iWidth;
bRetval = qtrue;
}
}
return bRetval;
}
float MP3Stream_GetPlayingTimeInSeconds( LP_MP3STREAM lpMP3Stream )
{
if (lpMP3Stream->iTimeQuery_UnpackedLength) // fields initialised?
return (float)((((double)lpMP3Stream->iTimeQuery_UnpackedLength / (double)lpMP3Stream->iTimeQuery_SampleRate) / (double)lpMP3Stream->iTimeQuery_Channels) / (double)lpMP3Stream->iTimeQuery_Width);
return 0.0f;
}
float MP3Stream_GetRemainingTimeInSeconds( LP_MP3STREAM lpMP3Stream )
{
if (lpMP3Stream->iTimeQuery_UnpackedLength) // fields initialised?
return (float)(((((double)(lpMP3Stream->iTimeQuery_UnpackedLength - (lpMP3Stream->iBytesDecodedTotal * (lpMP3Stream->iTimeQuery_SampleRate / dma.speed)))) / (double)lpMP3Stream->iTimeQuery_SampleRate) / (double)lpMP3Stream->iTimeQuery_Channels) / (double)lpMP3Stream->iTimeQuery_Width);
return 0.0f;
}
// expects data already loaded, filename arg is for error printing only
//
qboolean MP3_FakeUpWAVInfo( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength,
int &format, int &rate, int &width, int &channels, int &samples, int &dataofs,
qboolean bStereoDesired /* = qfalse */
)
{
// some things can be done instantly...
//
format = 1; // 1 for MS format
dataofs= 0; // will be 0 for me (since there's no header in the unpacked data)
// some things need to be read... (though the whole stereo flag thing is crap)
//
char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &rate, &width, &channels, bStereoDesired );
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
}
// and some stuff needs calculating...
//
samples = iUnpackedDataLength / width;
return !psError;
}
const char sKEY_MAXVOL[]="#MAXVOL"; // formerly #defines
const char sKEY_UNCOMP[]="#UNCOMP"; // " "
// returns qtrue for success...
//
qboolean MP3_ReadSpecialTagInfo(byte *pbLoadedFile, int iLoadedFileLen,
id3v1_1** ppTAG /* = NULL */,
int *piUncompressedSize /* = NULL */,
float *pfMaxVol /* = NULL */
)
{
qboolean qbError = qfalse;
id3v1_1* pTAG = (id3v1_1*) ((pbLoadedFile+iLoadedFileLen)-sizeof(id3v1_1)); // sizeof = 128
if (!strncmp(pTAG->id, "TAG", 3))
{
// TAG found...
//
// read MAXVOL key...
//
if (strncmp(pTAG->comment, sKEY_MAXVOL, strlen(sKEY_MAXVOL)))
{
qbError = qtrue;
}
else
{
if ( pfMaxVol)
{
*pfMaxVol = atof(pTAG->comment + strlen(sKEY_MAXVOL));
}
}
//
// read UNCOMP key...
//
if (strncmp(pTAG->album, sKEY_UNCOMP, strlen(sKEY_UNCOMP)))
{
qbError = qtrue;
}
else
{
if ( piUncompressedSize)
{
*piUncompressedSize = atoi(pTAG->album + strlen(sKEY_UNCOMP));
}
}
}
else
{
pTAG = NULL;
}
if (ppTAG)
{
*ppTAG = pTAG;
}
return (pTAG && !qbError);
}
#define FUZZY_AMOUNT (5*1024) // so it has to be significantly over, not just break even, because of
// the xtra CPU time versus memory saving
cvar_t* cv_MP3overhead = NULL;
void MP3_InitCvars(void)
{
cv_MP3overhead = Cvar_Get("s_mp3overhead", va("%d", sizeof(MP3STREAM) + FUZZY_AMOUNT), CVAR_ARCHIVE );
}
// a file has been loaded in memory, see if we want to keep it as MP3, else as normal WAV...
//
// return = qtrue if keeping as MP3
//
// (note: the reason I pass in the unpacked size rather than working it out here is simply because I already have it)
//
qboolean MP3Stream_InitFromFile( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename,
int iMP3UnPackedSize, qboolean bStereoDesired /* = qfalse */
)
{
// first, make a decision based on size here as to whether or not it's worth it because of MP3 buffer space
// making small files much bigger (and therefore best left as WAV)...
//
if (cv_MP3overhead &&
(
//iSrcDatalen + sizeof(MP3STREAM) + FUZZY_AMOUNT < iMP3UnPackedSize
iSrcDatalen + cv_MP3overhead->integer < iMP3UnPackedSize
)
)
{
// ok, let's keep it as MP3 then...
//
float fMaxVol = 128; // seems to be a reasonable typical default for maxvol (for lip synch). Naturally there's no #define I can use instead...
MP3_ReadSpecialTagInfo(pbSrcData, iSrcDatalen, NULL, NULL, &fMaxVol ); // try and read a read maxvol from MP3 header
// fill in some sfx_t fields...
//
// Q_strncpyz( sfx->name, psSrcDataFilename, sizeof(sfx->name) );
sfx->eSoundCompressionMethod = ct_MP3;
sfx->fVolRange = fMaxVol;
//sfx->width = 2;
sfx->iSoundLengthInSamples = ((iMP3UnPackedSize / 2/*sfx->width*/) / (44100 / dma.speed)) / (bStereoDesired?2:1);
//
// alloc mem for data and store it (raw MP3 in this case)...
//
sfx->pSoundData = (short *) SND_malloc( iSrcDatalen, sfx );
memcpy( sfx->pSoundData, pbSrcData, iSrcDatalen );
// now init the low-level MP3 stuff...
//
MP3STREAM SFX_MP3Stream = {0}; // important to init to all zeroes!
char *psError = C_MP3Stream_DecodeInit( &SFX_MP3Stream, /*sfx->data*/ /*sfx->soundData*/ pbSrcData, iSrcDatalen,
dma.speed,//(s_khz->value == 44)?44100:(s_khz->value == 22)?22050:11025,
2/*sfx->width*/ * 8,
bStereoDesired
);
SFX_MP3Stream.pbSourceData = (byte *) sfx->pSoundData;
if (psError)
{
// This should never happen, since any errors or problems with the MP3 file would have stopped us getting
// to this whole function, but just in case...
//
Com_Printf(va(S_COLOR_YELLOW"File \"%s\": %s\n",psSrcDataFilename,psError));
// This will leave iSrcDatalen bytes on the hunk stack (since you can't dealloc that), but MP3 files are
// usually small, and like I say, it should never happen.
//
// Strictly speaking, I should do a Z_Malloc above, then I could do a Z_Free if failed, else do a Hunk_Alloc
// to copy the Z_Malloc data into, then Z_Free, but for something that shouldn't happen it seemed bad to
// penalise the rest of the game with extra alloc demands.
//
return qfalse;
}
// success ( ...on a plate).
//
// make a copy of the filled-in stream struct and attach to the sfx_t struct...
//
sfx->pMP3StreamHeader = (MP3STREAM *) Z_Malloc( sizeof(MP3STREAM), TAG_SND_MP3STREAMHDR, qfalse );
memcpy( sfx->pMP3StreamHeader, &SFX_MP3Stream, sizeof(MP3STREAM) );
//
return qtrue;
}
return qfalse;
}
// decode one packet of MP3 data only (typical output size is 2304, or 2304*2 for stereo, so input size is less
//
// return is decoded byte count, else 0 for finished
//
int MP3Stream_Decode( LP_MP3STREAM lpMP3Stream, qboolean bDoingMusic )
{
lpMP3Stream->iCopyOffset = 0;
if (0)//!bDoingMusic)
{
/*
// SOF2: need to make a local buffer up so we can decode the piece we want from a contiguous bitstream rather than
// this linklist junk...
//
// since MP3 packets are generally 416 or 417 bytes in length it seems reasonable to just find which linked-chunk
// the current read offset lies within then grab the next one as well (since they're 2048 bytes) and make one
// buffer with just the two concat'd together. Shouldn't be much of a processor hit.
//
sndBuffer *pChunk = (sndBuffer *) lpMP3Stream->pbSourceData;
//
// may as well make this static to avoid cut down on stack-validation run-time...
//
static byte byRawBuffer[SND_CHUNK_SIZE_BYTE*2]; // *2 for byte->short // easily enough to decode one frame of MP3 data, most are 416 or 417 bytes
// fast-forward to the correct chunk...
//
int iBytesToSkipPast = lpMP3Stream->iSourceReadIndex;
while (iBytesToSkipPast >= SND_CHUNK_SIZE_BYTE)
{
pChunk = pChunk->next;
if (!pChunk)
{
// err.... reading off the end of the data stream guys...
//
// pChunk = (sndBuffer *) lpMP3Stream->pbSourceData; // restart
return 0; // ... 0 bytes decoded, so will just stop caller-decoder all nice and legal as EOS
}
iBytesToSkipPast -= SND_CHUNK_SIZE_BYTE;
}
{
// ok, pChunk is now the 2k or so chunk we're in the middle of...
//
int iChunk1BytesToCopy = SND_CHUNK_SIZE_BYTE - iBytesToSkipPast;
memcpy(byRawBuffer,((byte *)pChunk->sndChunk) + iBytesToSkipPast, iChunk1BytesToCopy);
//
// concat next chunk on to this as well...
//
pChunk = pChunk->next;
if (pChunk)
{
memcpy(byRawBuffer + iChunk1BytesToCopy, pChunk->sndChunk, SND_CHUNK_SIZE_BYTE);
}
else
{
memset(byRawBuffer + iChunk1BytesToCopy, 0, SND_CHUNK_SIZE_BYTE);
}
}
{
// now we need to backup some struct fields, fake 'em, do the lo-level call, then restore 'em...
//
byte *pbSourceData_Old = lpMP3Stream->pbSourceData;
int iSourceReadIndex_Old= lpMP3Stream->iSourceReadIndex;
lpMP3Stream->pbSourceData = &byRawBuffer[0];
lpMP3Stream->iSourceReadIndex= 0; // since this is zero, not the buffer offset within a chunk, we can play tricks further down when restoring
{
unsigned int uiBytesDecoded = C_MP3Stream_Decode( lpMP3Stream, qfalse );
lpMP3Stream->iSourceReadIndex += iSourceReadIndex_Old; // note '+=' rather than '=', to take account of movement.
lpMP3Stream->pbSourceData = pbSourceData_Old;
return uiBytesDecoded;
}
}
*/
}
else
{
// SOF2 music, or EF1 anything...
//
return C_MP3Stream_Decode( lpMP3Stream, qfalse ); // bFastForwarding
}
}
qboolean MP3Stream_SeekTo( channel_t *ch, float fTimeToSeekTo )
{
const float fEpsilon = 0.05f; // accurate to 1/50 of a second, but plus or minus this gives 1/10 of second
MP3Stream_Rewind( ch );
//
// sanity... :-)
//
const float fTrackLengthInSeconds = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader );
if (fTimeToSeekTo > fTrackLengthInSeconds)
{
fTimeToSeekTo = fTrackLengthInSeconds;
}
// now do the seek...
//
while (1)
{
float fPlayingTimeElapsed = MP3Stream_GetPlayingTimeInSeconds( &ch->MP3StreamHeader ) - MP3Stream_GetRemainingTimeInSeconds( &ch->MP3StreamHeader );
float fAbsTimeDiff = fabs(fTimeToSeekTo - fPlayingTimeElapsed);
if ( fAbsTimeDiff <= fEpsilon)
return qtrue;
// when decoding, use fast-forward until within 3 seconds, then slow-decode (which should init stuff properly?)...
//
int iBytesDecodedThisPacket = C_MP3Stream_Decode( &ch->MP3StreamHeader, (fAbsTimeDiff > 3.0f) ); // bFastForwarding
if (iBytesDecodedThisPacket == 0)
break; // EOS
}
return qfalse;
}
// returns qtrue for all ok
//
qboolean MP3Stream_Rewind( channel_t *ch )
{
ch->iMP3SlidingDecodeWritePos = 0;
ch->iMP3SlidingDecodeWindowPos= 0;
/*
char *psError = C_MP3Stream_Rewind( &ch->MP3StreamHeader );
if (psError)
{
Com_Printf(S_COLOR_YELLOW"%s\n",psError);
return qfalse;
}
return qtrue;
*/
// speed opt, since I know I already have the right data setup here...
//
memcpy(&ch->MP3StreamHeader, ch->thesfx->pMP3StreamHeader, sizeof(ch->MP3StreamHeader));
return qtrue;
}
// returns qtrue while still playing normally, else qfalse for either finished or request-offset-error
//
qboolean MP3Stream_GetSamples( channel_t *ch, int startingSampleNum, int count, short *buf, qboolean bStereo )
{
qboolean qbStreamStillGoing = qtrue;
const int iQuarterOfSlidingBuffer = sizeof(ch->MP3SlidingDecodeBuffer)/4;
const int iThreeQuartersOfSlidingBuffer = (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4;
// Com_Printf("startingSampleNum %d\n",startingSampleNum);
count *= 2/* <- = SOF2; ch->sfx->width*/; // count arg was for words, so double it for bytes;
// convert sample number into a byte offset... (make new variable for clarity?)
//
startingSampleNum *= 2 /* <- = SOF2; ch->sfx->width*/ * (bStereo?2:1);
if ( startingSampleNum < ch->iMP3SlidingDecodeWindowPos)
{
// what?!?!?! smegging time travel needed or something?, forget it
memset(buf,0,count);
return qfalse;
}
// OutputDebugString(va("\nRequest: startingSampleNum %d, count %d\n",startingSampleNum,count));
// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos));
// qboolean _bDecoded = qfalse;
while (!
(
(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos)
&&
(startingSampleNum + count < ch->iMP3SlidingDecodeWindowPos + ch->iMP3SlidingDecodeWritePos)
)
)
{
// if (!_bDecoded)
// {
// Com_Printf(S_COLOR_YELLOW"Decode needed!\n");
// }
// _bDecoded = qtrue;
// OutputDebugString("Scrolling...");
int _iBytesDecoded = MP3Stream_Decode( (LP_MP3STREAM) &ch->MP3StreamHeader, bStereo ); // stereo only for music, so this is safe
// OutputDebugString(va("%d bytes decoded\n",_iBytesDecoded));
if (_iBytesDecoded == 0)
{
// no more source data left so clear the remainder of the buffer...
//
memset(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos, 0, sizeof(ch->MP3SlidingDecodeBuffer)-ch->iMP3SlidingDecodeWritePos);
// OutputDebugString("Finished\n");
qbStreamStillGoing = qfalse;
break;
}
else
{
memcpy(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos,ch->MP3StreamHeader.bDecodeBuffer,_iBytesDecoded);
ch->iMP3SlidingDecodeWritePos += _iBytesDecoded;
// if reached 3/4 of buffer pos, backscroll the decode window by one quarter...
//
if (ch->iMP3SlidingDecodeWritePos > iThreeQuartersOfSlidingBuffer)
{
memmove(ch->MP3SlidingDecodeBuffer, ((byte *)ch->MP3SlidingDecodeBuffer + iQuarterOfSlidingBuffer), iThreeQuartersOfSlidingBuffer);
ch->iMP3SlidingDecodeWritePos -= iQuarterOfSlidingBuffer;
ch->iMP3SlidingDecodeWindowPos+= iQuarterOfSlidingBuffer;
}
}
// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos));
}
// if (!_bDecoded)
// {
// Com_Printf(S_COLOR_YELLOW"No decode needed\n");
// }
assert(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos);
memcpy( buf, ch->MP3SlidingDecodeBuffer + (startingSampleNum-ch->iMP3SlidingDecodeWindowPos), count);
// OutputDebugString("OK\n\n");
return qbStreamStillGoing;
}
///////////// eof /////////////

87
code/client/cl_mp3.h Normal file
View File

@@ -0,0 +1,87 @@
// Filename:- cl_mp3.h
//
// (Interface to the rest of the game for the MP3 functions)
//
#ifndef CL_MP3_H
#define CL_MP3_H
#ifndef sfx_t
#include "snd_local.h"
#endif
typedef struct id3v1_1 {
char id[3];
char title[30]; // <file basename>
char artist[30]; // "Raven Software"
char album[30]; // "#UNCOMP %d" // needed
char year[4]; // "2000"
char comment[28]; // "#MAXVOL %g" // needed
char zero;
char track;
char genre;
} id3v1_1; // 128 bytes in size
extern const char sKEY_MAXVOL[];
extern const char sKEY_UNCOMP[];
// (so far, all these functions are only called from one place in snd_mem.cpp)
//
// (filenames are used purely for error reporting, all files should already be loaded before you get here)
//
void MP3_InitCvars ( void );
qboolean MP3_IsValid ( const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired = qfalse );
int MP3_GetUnpackedSize ( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag = qfalse, qboolean bStereoDesired = qfalse );
qboolean MP3_UnpackRawPCM ( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer, qboolean bStereoDesired = qfalse );
qboolean MP3Stream_InitPlayingTimeFields( LP_MP3STREAM lpMP3Stream, const char *psLocalFilename, void *pvData, int iDataLen, qboolean bStereoDesired = qfalse);
float MP3Stream_GetPlayingTimeInSeconds( LP_MP3STREAM lpMP3Stream );
float MP3Stream_GetRemainingTimeInSeconds( LP_MP3STREAM lpMP3Stream );
qboolean MP3_FakeUpWAVInfo ( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength, int &format, int &rate, int &width, int &channels, int &samples, int &dataofs, qboolean bStereoDesired = qfalse );
qboolean MP3_ReadSpecialTagInfo ( byte *pbLoadedFile, int iLoadedFileLen,
id3v1_1** ppTAG = NULL, int *piUncompressedSize = NULL, float *pfMaxVol = NULL);
qboolean MP3Stream_InitFromFile ( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, int iMP3UnPackedSize, qboolean bStereoDesired = qfalse );
int MP3Stream_Decode ( LP_MP3STREAM lpMP3Stream, qboolean bDoingMusic );
qboolean MP3Stream_SeekTo ( channel_t *ch, float fTimeToSeekTo );
qboolean MP3Stream_Rewind ( channel_t *ch );
qboolean MP3Stream_GetSamples ( channel_t *ch, int startingSampleNum, int count, short *buf, qboolean bStereo );
///////////////////////////////////////
//
// the real worker code deep down in the MP3 C code... (now externalised here so the music streamer can access one)
//
#ifdef __cplusplus
extern "C"
{
#endif
char* C_MP3_IsValid (void *pvData, int iDataLen, int bStereoDesired);
char* C_MP3_GetUnpackedSize (void *pvData, int iDataLen, int *piUnpackedSize, int bStereoDesired);
char* C_MP3_UnpackRawPCM (void *pvData, int iDataLen, int *piUnpackedSize, void *pbUnpackBuffer, int bStereoDesired);
char* C_MP3_GetHeaderData (void *pvData, int iDataLen, int *piRate, int *piWidth, int *piChannels, int bStereoDesired);
char* C_MP3Stream_DecodeInit (LP_MP3STREAM pSFX_MP3Stream, void *pvSourceData, int iSourceBytesRemaining,
int iGameAudioSampleRate, int iGameAudioSampleBits, int bStereoDesired);
unsigned int C_MP3Stream_Decode( LP_MP3STREAM pSFX_MP3Stream, int bFastForwarding );
char* C_MP3Stream_Rewind (LP_MP3STREAM pSFX_MP3Stream);
#ifdef __cplusplus
}
#endif
//
///////////////////////////////////////
#endif // #ifndef CL_MP3_H
///////////////// eof /////////////////////

419
code/client/cl_mp3.org Normal file
View File

@@ -0,0 +1,419 @@
// Filename:- cl_mp3.cpp
//
// (The interface module between all the MP3 stuff and Trek)
//
#include "client.h"
#include "cl_mp3.h" //(only included directly from snd_mem.cpp, so not in client.h)
#include "../mp3code/mp3struct.h" // keep this rather awful file secret from the rest of the program
// call the real worker code in the messy C stuff...
//
#ifdef __cplusplus
extern "C"
{
#endif
char* C_MP3_IsValid (void *pvData, int iDataLen);
char* C_MP3_GetUnpackedSize (void *pvData, int iDataLen, int *piUnpackedSize);
char* C_MP3_UnpackRawPCM (void *pvData, int iDataLen, int *piUnpackedSize, void *pbUnpackBuffer);
char* C_MP3_GetHeaderData (void *pvData, int iDataLen, int *piRate, int *piWidth, int *piChannels);
char* C_MP3Stream_DecodeInit (LP_MP3STREAM pSFX_MP3Stream, void *pvSourceData, int iSourceBytesRemaining,
int iGameAudioSampleRate, int iGameAudioSampleBits );
unsigned int C_MP3Stream_Decode (LP_MP3STREAM pSFX_MP3Stream);
char* C_MP3Stream_Rewind (LP_MP3STREAM pSFX_MP3Stream);
// these two are temp and will eventually be deleted... honest...
//
char* C_TEST_MP3_GetUnpackedSize( const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3,
void *data1,void *data2,void *data3,
int size1,int size2,int size3,
int *iUnpackedSize1,int *iUnpackedSize2,int *iUnpackedSize3
);
char * C_TEST_MP3_UnpackRawPCM(const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3,
void *data1,void *data2,void *data3,
int iSourceBytesRemaining1,int iSourceBytesRemaining2,int iSourceBytesRemaining3,
int *piUnpackedSize1,int *piUnpackedSize2,int *piUnpackedSize3,
void *pbUnpackBuffer1,void *pbUnpackBuffer2,void *pbUnpackBuffer3
);
#ifdef __cplusplus
}
#endif
// expects data already loaded, filename arg is for error printing only
//
// returns success/fail
//
qboolean MP3_IsValid( const char *psLocalFilename, void *pvData, int iDataLen )
{
char *psError = C_MP3_IsValid(pvData, iDataLen);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
}
return !psError;
}
// expects data already loaded, filename arg is for error printing only
//
// returns unpacked length, or 0 for errors (which will be printed internally)
//
int MP3_GetUnpackedSize( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag /* = qfalse */)
{
int iUnpackedSize = 0;
if (qbIgnoreID3Tag || !MP3_ReadSpecialTagInfo((byte *)pvData, iDataLen, NULL, &iUnpackedSize))
{
char *psError = C_MP3_GetUnpackedSize( pvData, iDataLen, &iUnpackedSize);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
return 0;
}
}
return iUnpackedSize;
}
// expects data already loaded, filename arg is for error printing only
//
// returns byte count of unpacked data (effectively a success/fail bool)
//
int MP3_UnpackRawPCM( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer )
{
int iUnpackedSize;
char *psError = C_MP3_UnpackRawPCM( pvData, iDataLen, &iUnpackedSize, pbUnpackBuffer);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
return 0;
}
return iUnpackedSize;
}
// expects data already loaded, filename arg is for error printing only
//
qboolean MP3_FakeUpWAVInfo( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength, int &format, int &rate, int &width, int &channels, int &samples, int &dataofs)
{
// some things can be done instantly...
//
format = 1; // 1 for MS format
dataofs= 0; // will be 0 for me (since there's no header in the unpacked data)
// some things need to be read...
//
char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &rate, &width, &channels);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename));
}
// and some stuff needs calculating...
//
samples = iUnpackedDataLength / width;
return !psError;
}
const char sKEY_MAXVOL[]="#MAXVOL"; // formerly #defines
const char sKEY_UNCOMP[]="#UNCOMP"; // " "
// returns qtrue for success...
//
qboolean MP3_ReadSpecialTagInfo(byte *pbLoadedFile, int iLoadedFileLen, // (in)
id3v1_1** ppTAG, // (out), can be NULL
int *piUncompressedSize, float *pfMaxVol // (out), can be NULL
)
{
qboolean qbError = qfalse;
id3v1_1* pTAG = (id3v1_1*) ((pbLoadedFile+iLoadedFileLen)-sizeof(id3v1_1)); // sizeof = 128
if (!strncmp(pTAG->id, "TAG", 3))
{
// TAG found...
//
// read MAXVOL key...
//
if (strncmp(pTAG->comment, sKEY_MAXVOL, strlen(sKEY_MAXVOL)))
{
qbError = qtrue;
}
else
{
if ( pfMaxVol)
{
*pfMaxVol = atof(pTAG->comment + strlen(sKEY_MAXVOL));
}
}
//
// read UNCOMP key...
//
if (strncmp(pTAG->album, sKEY_UNCOMP, strlen(sKEY_UNCOMP)))
{
qbError = qtrue;
}
else
{
if ( piUncompressedSize)
{
*piUncompressedSize = atoi(pTAG->album + strlen(sKEY_UNCOMP));
}
}
}
else
{
pTAG = NULL;
}
if (ppTAG)
{
*ppTAG = pTAG;
}
return (pTAG && !qbError);
}
qboolean TEST_MP3_GetUnpackedSize(const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3,
void *data1,void *data2,void *data3,
int size1,int size2,int size3,
int *iUnpackedSize1,int *iUnpackedSize2,int *iUnpackedSize3
)
{
char *psError = C_TEST_MP3_GetUnpackedSize(_FILENAME1, _FILENAME2, _FILENAME3,
data1,data2,data3,
size1,size2,size3,
iUnpackedSize1,iUnpackedSize2,iUnpackedSize3
);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n",psError));
return qfalse;
}
return qtrue;
}
// expects data already loaded, filename arg is for error printing only
//
// returns byte count of unpacked data (effectively a success/fail bool)
//
qboolean TEST_MP3_UnpackRawPCM( const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3,
void *data1,void *data2,void *data3,
int iSourceBytesRemaining1,int iSourceBytesRemaining2,int iSourceBytesRemaining3,
int *piUnpackedSize1,int *piUnpackedSize2,int *piUnpackedSize3,
void *pbUnpackBuffer1,void *pbUnpackBuffer2,void *pbUnpackBuffer3
)
{
char *psError = C_TEST_MP3_UnpackRawPCM(_FILENAME1, _FILENAME2, _FILENAME3,
data1,data2,data3,
iSourceBytesRemaining1,iSourceBytesRemaining2,iSourceBytesRemaining3,
piUnpackedSize1,piUnpackedSize2,piUnpackedSize3,
pbUnpackBuffer1,pbUnpackBuffer2,pbUnpackBuffer3
);
if (psError)
{
Com_Printf(va(S_COLOR_RED"%s\n",psError));
return qfalse;
}
return qtrue;
}
// a file has been loaded in memory, see if we want to keep it as MP3, else as normal WAV...
//
// return = qtrue if keeping as MP3
//
// (note: the reason I pass in the unpacked size rather than working it out here is simply because I already have it)
//
qboolean MP3Stream_InitFromFile( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, int iMP3UnPackedSize )
{
// first, make a decision based on size here as to whether or not it's worth it because of MP3 buffer space
// making small files much bigger (and therefore best left as WAV)...
//
#define FUZZY_AMOUNT (5*1024) // so it has to be significantly over, not just break even, because of
// the xtra CPU time versus memory saving
if (iSrcDatalen + sizeof(MP3STREAM) + FUZZY_AMOUNT < iMP3UnPackedSize)
{
// ok, let's keep it as MP3 then...
//
float fMaxVol = 128; // seems to be a reasonable typical default for maxvol (for lip synch). Naturally there's no #define I can use instead...
MP3_ReadSpecialTagInfo(pbSrcData, iSrcDatalen, NULL, NULL, &fMaxVol ); // try and read a read maxvol from MP3 header
// fill in some sfx_t fields...
//
sfx->eCompressionType = ct_MP3;
sfx->data = (byte*) Hunk_Alloc( iSrcDatalen ); // will err_drop if fails
memcpy ( sfx->data, pbSrcData, iSrcDatalen ); // ... so the -> data field is MP3, not PCM
sfx->width = 2;//(s_compression->value == 1)?1:2;
sfx->length = (iMP3UnPackedSize / sfx->width) / (44100 / dma.speed);
sfx->vol_range = fMaxVol;
// now init the low-level MP3 stuff...
//
MP3STREAM SFX_MP3Stream = {0};
char *psError = C_MP3Stream_DecodeInit( &SFX_MP3Stream, sfx->data, iSrcDatalen,
dma.speed,//(s_khz->value == 44)?44100:(s_khz->value == 22)?22050:11025,
sfx->width * 8
);
if (psError)
{
// This should never happen, since any errors or problems with the MP3 file would have stopped us getting
// to this whole function, but just in case...
//
Com_Printf(va(S_COLOR_YELLOW"File \"%s\": %s\n",psSrcDataFilename,psError));
// This will leave iSrcDatalen bytes on the hunk stack (since you can't dealloc that), but MP3 files are
// usually small, and like I say, it should never happen.
//
// Strictly speaking, I should do a Z_Malloc above, then I could do a Z_Free if failed, else do a Hunk_Alloc
// to copy the Z_Malloc data into, then Z_Free, but for something that shouldn't happen it seemed bad to
// penalise the rest of the game with extra malloc demands.
//
return qfalse;
}
// success ( ...on a plate).
//
// make a copy of the filled-in stream struct and attach to the sfx_t struct...
//
sfx->pMP3StreamHeader = (MP3STREAM *) Hunk_Alloc( sizeof(MP3STREAM) );
memcpy( sfx->pMP3StreamHeader, &SFX_MP3Stream, sizeof(MP3STREAM) );
//
return qtrue;
}
return qfalse;
}
// return is decoded byte count, else 0 for finished
//
int MP3Stream_Decode( LP_MP3STREAM lpMP3Stream )
{
lpMP3Stream->iCopyOffset = 0;
return C_MP3Stream_Decode( lpMP3Stream );
}
// returns qtrue for all ok
//
// (this can be optimised by copying the whole header from the sfx struct sometime)
//
qboolean MP3Stream_Rewind( channel_t *ch )
{
/* char *psError = C_MP3Stream_Rewind( lpMP3Stream );
if (psError)
{
Com_Printf(S_COLOR_YELLOW"%s\n",psError);
return qfalse;
}
return qtrue;
*/
memcpy(&ch->MP3StreamHeader, ch->sfx->pMP3StreamHeader, sizeof(ch->MP3StreamHeader));
return qtrue;
}
void MP3Stream_GetSamples( channel_t *ch, int startingSampleNum, int count, short *buf )
{
static const int iQuarterOfSlidingBuffer = sizeof(ch->MP3SlidingDecodeBuffer)/4;
static const int iThreeQuartersOfSlidingBuffer = (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4;
// Com_Printf("startingSampleNum %d\n",startingSampleNum);
count *= ch->sfx->width; // count arg was for words, so double it for bytes;
startingSampleNum *= ch->sfx->width;
if ( startingSampleNum < ch->iMP3SlidingDecodeWindowPos)
{
// what?!?!?! Fucking time travel needed or something?, forget it
memset(buf,0,count);
return;
}
// OutputDebugString(va("\nRequest: startingSampleNum %d, count %d\n",startingSampleNum,count));
// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos));
while (!
(
(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos)
&&
(startingSampleNum + count < ch->iMP3SlidingDecodeWindowPos + ch->iMP3SlidingDecodeWritePos)
)
)
{
// OutputDebugString("Scrolling...");
int _iBytesDecoded = MP3Stream_Decode( (LP_MP3STREAM) &ch->MP3StreamHeader );
// OutputDebugString(va("%d bytes decoded\n",_iBytesDecoded));
if (_iBytesDecoded == 0)
{
// no more source data left so clear the remainder of the buffer...
//
memset(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos, 0, sizeof(ch->MP3SlidingDecodeBuffer)-ch->iMP3SlidingDecodeWritePos);
//MP3Stream_Rewind(ch); // should I do this???
// OutputDebugString("Finished\n");
break;
}
else
{
memcpy(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos,ch->MP3StreamHeader.bDecodeBuffer,_iBytesDecoded);
ch->iMP3SlidingDecodeWritePos += _iBytesDecoded;
// if reached 3/4 of buffer pos, backscroll the decode window by one quarter...
//
if (ch->iMP3SlidingDecodeWritePos > (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4)
{
memmove(ch->MP3SlidingDecodeBuffer, ((byte *)ch->MP3SlidingDecodeBuffer + (sizeof(ch->MP3SlidingDecodeBuffer)/4)), (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4);
ch->iMP3SlidingDecodeWritePos -= sizeof(ch->MP3SlidingDecodeBuffer)/4;
ch->iMP3SlidingDecodeWindowPos+= sizeof(ch->MP3SlidingDecodeBuffer)/4;
}
}
// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos));
}
assert(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos);
memcpy( buf, ch->MP3SlidingDecodeBuffer + (startingSampleNum-ch->iMP3SlidingDecodeWindowPos), count);
// OutputDebugString("OK\n");
}
///////////// eof /////////////

510
code/client/cl_parse.cpp Normal file
View File

@@ -0,0 +1,510 @@
// cl_parse.c -- parse a message received from the server
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "client.h"
#include "client_ui.h"
char *svc_strings[256] = {
"svc_bad",
"svc_nop",
"svc_gamestate",
"svc_configstring",
"svc_baseline",
"svc_serverCommand",
"svc_download",
"svc_snapshot"
};
void SHOWNET( msg_t *msg, char *s) {
if ( cl_shownet->integer >= 2) {
Com_Printf ("%3i:%s\n", msg->readcount-1, s);
}
}
/*
=========================================================================
MESSAGE PARSING
=========================================================================
*/
/*
==================
CL_DeltaEntity
Parses deltas from the given base and adds the resulting entity
to the current frame
==================
*/
void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame)
{
entityState_t *state;
// save the parsed entity state into the big circular buffer so
// it can be used as the source for a later delta
state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
MSG_ReadEntity( msg, state);
if ( state->number == (MAX_GENTITIES-1) ) {
return; // entity was delta removed
}
cl.parseEntitiesNum++;
frame->numEntities++;
}
/*
==================
CL_ParsePacketEntities
==================
*/
void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
int newnum;
entityState_t *oldstate;
int oldindex, oldnum;
newframe->parseEntitiesNum = cl.parseEntitiesNum;
newframe->numEntities = 0;
// delta from the entities present in oldframe
oldindex = 0;
oldstate = NULL;
if (!oldframe) {
oldnum = 99999;
} else {
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
while ( 1 ) {
// read the entity index number
newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
if ( newnum == (MAX_GENTITIES-1) ) {
break;
}
if ( msg->readcount > msg->cursize ) {
Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
}
while ( oldnum < newnum ) {
// one or more entities from the old packet are unchanged
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
}
CL_DeltaEntity( msg, newframe );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
if (oldnum == newnum) {
// delta from previous state
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
}
CL_DeltaEntity( msg, newframe );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
continue;
}
if ( oldnum > newnum ) {
// delta from baseline
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
}
CL_DeltaEntity( msg, newframe );
continue;
}
}
// any remaining entities in the old frame are copied over
while ( oldnum != 99999 ) {
// one or more entities from the old packet are unchanged
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
}
CL_DeltaEntity( msg, newframe );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
}
/*
================
CL_ParseSnapshot
If the snapshot is parsed properly, it will be copied to
cl.frame and saved in cl.frames[]. If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
int len;
clSnapshot_t *old;
clSnapshot_t newSnap;
int deltaNum;
int oldMessageNum;
int i, packetNum;
// get the reliable sequence acknowledge number
clc.reliableAcknowledge = MSG_ReadLong( msg );
// read in the new snapshot to a temporary buffer
// we will only copy to cl.frame if it is valid
memset (&newSnap, 0, sizeof(newSnap));
newSnap.serverCommandNum = clc.serverCommandSequence;
newSnap.serverTime = MSG_ReadLong( msg );
newSnap.messageNum = MSG_ReadLong( msg );
deltaNum = MSG_ReadByte( msg );
if ( !deltaNum ) {
newSnap.deltaNum = -1;
} else {
newSnap.deltaNum = newSnap.messageNum - deltaNum;
}
newSnap.cmdNum = MSG_ReadLong( msg );
newSnap.snapFlags = MSG_ReadByte( msg );
// If the frame is delta compressed from data that we
// no longer have available, we must suck up the rest of
// the frame, but not use it, then ask for a non-compressed
// message
if ( newSnap.deltaNum <= 0 ) {
newSnap.valid = qtrue; // uncompressed frame
old = NULL;
} else {
old = &cl.frames[newSnap.deltaNum & PACKET_MASK];
if ( !old->valid ) {
// should never happen
Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
} else if ( old->messageNum != newSnap.deltaNum ) {
// The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
Com_Printf ("Delta frame too old.\n");
} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES ) {
Com_Printf ("Delta parseEntitiesNum too old.\n");
} else {
newSnap.valid = qtrue; // valid delta parse
}
}
// read areamask
len = MSG_ReadByte( msg );
MSG_ReadData( msg, &newSnap.areamask, len);
// read playerinfo
SHOWNET( msg, "playerstate" );
if ( old ) {
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
} else {
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
}
// read packet entities
SHOWNET( msg, "packet entities" );
CL_ParsePacketEntities( msg, old, &newSnap );
// if not valid, dump the entire thing now that it has
// been properly read
if ( !newSnap.valid ) {
return;
}
// clear the valid flags of any snapshots between the last
// received and this one
oldMessageNum = cl.frame.messageNum + 1;
if ( cl.frame.messageNum - oldMessageNum >= PACKET_BACKUP ) {
oldMessageNum = cl.frame.messageNum - ( PACKET_BACKUP - 1 );
}
for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
cl.frames[oldMessageNum & PACKET_MASK].valid = qfalse;
}
// copy to the current good spot
cl.frame = newSnap;
// calculate ping time
for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
if ( cl.frame.cmdNum == cl.packetCmdNumber[ packetNum ] ) {
cl.frame.ping = cls.realtime - cl.packetTime[ packetNum ];
break;
}
}
// save the frame off in the backup array for later delta comparisons
cl.frames[cl.frame.messageNum & PACKET_MASK] = cl.frame;
if (cl_shownet->integer == 3) {
Com_Printf (" frame:%i delta:%i\n", cl.frame.messageNum,
cl.frame.deltaNum);
}
// actions for valid frames
cl.newSnapshots = qtrue;
}
//=====================================================================
/*
==================
CL_SystemInfoChanged
The systeminfo configstring has been changed, so parse
new information out of it. This will happen at every
gamestate, and possibly during gameplay.
==================
*/
void CL_SystemInfoChanged( void ) {
char *systemInfo;
const char *s;
char key[MAX_INFO_KEY];
char value[MAX_INFO_VALUE];
systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
s = Info_ValueForKey( systemInfo, "helpUsObi" );
if ( atoi(s) == 0 ) {
Cvar_SetCheatState();
}
// scan through all the variables in the systeminfo and locally set cvars to match
s = systemInfo;
while ( s ) {
Info_NextPair( &s, key, value );
if ( !key[0] ) {
break;
}
Cvar_Set( key, value );
}
//if ( Cvar_VariableIntegerValue("ui_iscensored") == 1 )
//{
// Cvar_Set( "g_dismemberment", "0");
//}
}
void UI_UpdateConnectionString( char *string );
/*
==================
CL_ParseGamestate
==================
*/
void CL_ParseGamestate( msg_t *msg ) {
int i;
int cmd;
char *s;
Con_Close();
UI_UpdateConnectionString( "" );
// wipe local client state
CL_ClearState();
// a gamestate always marks a server command sequence
clc.serverCommandSequence = MSG_ReadLong( msg );
// parse all the configstrings and baselines
cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
while ( 1 ) {
cmd = MSG_ReadByte( msg );
if ( cmd <= 0 ) {
break;
}
if ( cmd == svc_configstring ) {
int len;
i = MSG_ReadShort( msg );
if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
}
s = MSG_ReadString( msg );
len = strlen( s );
if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
}
// append it to the gameState string buffer
cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
cl.gameState.dataCount += len + 1;
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: CS# %d %s (%d)\n",msg->readcount, i,s,len);
}
} else if ( cmd == svc_baseline ) {
assert(0);
} else {
Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
}
}
// parse serverId and other cvars
CL_SystemInfoChanged();
// reinitialize the filesystem if the game directory has changed
#if 0
if ( fs_game->modified ) {
}
#endif
// let the client game init and load data
cls.state = CA_LOADING;
CL_StartHunkUsers();
// make sure the game starts
Cvar_Set( "cl_paused", "0" );
}
//=====================================================================
void CL_FreeServerCommands(void)
{
int i;
for(i=0; i<MAX_RELIABLE_COMMANDS; i++) {
if ( clc.serverCommands[ i ] ) {
Z_Free( clc.serverCommands[ i ] );
clc.serverCommands[ i ] = NULL;
}
}
}
/*
=====================
CL_ParseCommandString
Command strings are just saved off until cgame asks for them
when it transitions a snapshot
=====================
*/
void CL_ParseCommandString( msg_t *msg ) {
char *s;
int seq;
int index;
seq = MSG_ReadLong( msg );
s = MSG_ReadString( msg );
// see if we have already executed stored it off
if ( clc.serverCommandSequence >= seq ) {
return;
}
clc.serverCommandSequence = seq;
index = seq & (MAX_RELIABLE_COMMANDS-1);
if ( clc.serverCommands[ index ] ) {
Z_Free( clc.serverCommands[ index ] );
}
clc.serverCommands[ index ] = CopyString( s );
}
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage( msg_t *msg ) {
int cmd;
if ( cl_shownet->integer == 1 ) {
Com_Printf ("%i ",msg->cursize);
} else if ( cl_shownet->integer >= 2 ) {
Com_Printf ("------------------\n");
}
//
// parse the message
//
while ( 1 ) {
if ( msg->readcount > msg->cursize ) {
Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
break;
}
cmd = MSG_ReadByte( msg );
if ( cmd == -1 ) {
SHOWNET( msg, "END OF MESSAGE" );
break;
}
if ( cl_shownet->integer >= 2 ) {
if ( !svc_strings[cmd] ) {
Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
} else {
SHOWNET( msg, svc_strings[cmd] );
}
}
// other commands
switch ( cmd ) {
default:
Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
break;
case svc_nop:
break;
case svc_serverCommand:
CL_ParseCommandString( msg );
break;
case svc_gamestate:
CL_ParseGamestate( msg );
break;
case svc_snapshot:
CL_ParseSnapshot( msg );
break;
}
}
}

575
code/client/cl_scrn.cpp Normal file
View File

@@ -0,0 +1,575 @@
// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "client.h"
#include "client_ui.h"
extern console_t con;
qboolean scr_initialized; // ready to draw
cvar_t *cl_timegraph;
cvar_t *cl_debuggraph;
cvar_t *cl_graphheight;
cvar_t *cl_graphscale;
cvar_t *cl_graphshift;
/*
================
SCR_DrawNamedPic
Coordinates are 640*480 virtual values
=================
*/
void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
qhandle_t hShader;
assert( width != 0 );
hShader = re.RegisterShader( picname );
re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
/*
================
SCR_FillRect
Coordinates are 640*480 virtual values
=================
*/
void SCR_FillRect( float x, float y, float width, float height, const float *color ) {
re.SetColor( color );
re.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );
re.SetColor( NULL );
}
/*
================
SCR_DrawPic
Coordinates are 640*480 virtual values
A width of 0 will draw with the original image width
=================
*/
void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
/*
** SCR_DrawBigChar
** big chars are drawn at 640*480 virtual screen size
*/
void SCR_DrawBigChar( int x, int y, int ch ) {
int row, col;
float frow, fcol;
float size;
float ax, ay, aw, ah;
ch &= 255;
if ( ch == ' ' ) {
return;
}
if ( y < -BIGCHAR_HEIGHT ) {
return;
}
ax = x;
ay = y;
aw = BIGCHAR_WIDTH;
ah = BIGCHAR_HEIGHT;
row = ch>>4;
col = ch&15;
frow = row*0.0625;
fcol = col*0.0625;
size = 0.0625;
/*
re.DrawStretchPic( ax, ay, aw, ah,
fcol, frow,
fcol + size, frow + size,
cls.charSetShader );
*/
float size2;
frow = row*0.0625;
fcol = col*0.0625;
size = 0.03125;
size2 = 0.0625;
re.DrawStretchPic( ax, ay, aw, ah,
fcol, frow,
fcol + size, frow + size2,
cls.charSetShader );
}
/*
** SCR_DrawSmallChar
** small chars are drawn at native screen resolution
*/
void SCR_DrawSmallChar( int x, int y, int ch ) {
int row, col;
float frow, fcol;
float size;
ch &= 255;
if ( ch == ' ' ) {
return;
}
if ( y < -SMALLCHAR_HEIGHT ) {
return;
}
row = ch>>4;
col = ch&15;
/*
frow = row*0.0625;
fcol = col*0.0625;
size = 0.0625;
re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
fcol, frow,
fcol + size, frow + size,
cls.charSetShader );
*/
float size2;
frow = row*0.0625;
fcol = col*0.0625;
size = 0.03125;
size2 = 0.0625;
re.DrawStretchPic( x * con.xadjust, y * con.yadjust,
SMALLCHAR_WIDTH * con.xadjust, SMALLCHAR_HEIGHT * con.yadjust,
fcol, frow,
fcol + size, frow + size2,
cls.charSetShader );
}
/*
==================
SCR_DrawBigString[Color]
Draws a multi-colored string with a drop shadow, optionally forcing
to a fixed color.
Coordinates are at 640 by 480 virtual resolution
==================
*/
void SCR_DrawBigStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor ) {
vec4_t color;
const char *s;
int xx;
// draw the drop shadow
color[0] = color[1] = color[2] = 0;
color[3] = setColor[3];
re.SetColor( color );
s = string;
xx = x;
while ( *s ) {
if ( Q_IsColorString( s ) ) {
s += 2;
continue;
}
SCR_DrawBigChar( xx+2, y+2, *s );
xx+=16;
s++;
}
// draw the colored text
s = string;
xx = x;
re.SetColor( setColor );
while ( *s ) {
if ( Q_IsColorString( s ) ) {
if ( !forceColor ) {
memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
color[3] = setColor[3];
re.SetColor( color );
}
s += 2;
continue;
}
SCR_DrawBigChar( xx, y, *s );
xx+=16;
s++;
}
re.SetColor( NULL );
}
void SCR_DrawBigString( int x, int y, const char *s, float alpha ) {
float color[4];
color[0] = color[1] = color[2] = 1.0;
color[3] = alpha;
SCR_DrawBigStringExt( x, y, s, color, qfalse );
}
void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
SCR_DrawBigStringExt( x, y, s, color, qtrue );
}
/*
** SCR_Strlen -- skips color escape codes
*/
static int SCR_Strlen( const char *str ) {
const char *s = str;
int count = 0;
while ( *s ) {
if ( Q_IsColorString( s ) ) {
s += 2;
} else {
count++;
s++;
}
}
return count;
}
/*
** SCR_GetBigStringWidth
*/
int SCR_GetBigStringWidth( const char *str ) {
return SCR_Strlen( str ) * 16;
}
//===============================================================================
/*
===============================================================================
DEBUG GRAPH
===============================================================================
*/
#ifndef _XBOX
typedef struct
{
float value;
int color;
} graphsamp_t;
static int current;
static graphsamp_t values[1024];
/*
==============
SCR_DebugGraph
==============
*/
void SCR_DebugGraph (float value, int color)
{
values[current&1023].value = value;
values[current&1023].color = color;
current++;
}
/*
==============
SCR_DrawDebugGraph
==============
*/
void SCR_DrawDebugGraph (void)
{
int a, x, y, w, i, h;
float v;
int color;
//
// draw the graph
//
w = cls.glconfig.vidWidth;
x = 0;
y = cls.glconfig.vidHeight;
re.SetColor( g_color_table[0] );
re.DrawStretchPic(x, y - cl_graphheight->integer,
w, cl_graphheight->integer, 0, 0, 0, 0, 0 );
re.SetColor( NULL );
for (a=0 ; a<w ; a++)
{
i = (current-1-a+1024) & 1023;
v = values[i].value;
color = values[i].color;
v = v * cl_graphscale->integer + cl_graphshift->integer;
if (v < 0)
v += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));
h = (int)v % cl_graphheight->integer;
re.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, 0 );
}
}
#endif // _XBOX
//=============================================================================
/*
==================
SCR_Init
==================
*/
void SCR_Init( void ) {
cl_timegraph = Cvar_Get ("timegraph", "0", CVAR_CHEAT);
cl_debuggraph = Cvar_Get ("debuggraph", "0", CVAR_CHEAT);
cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
scr_initialized = qtrue;
}
//=======================================================
void UI_SetActiveMenu( const char* menuname,const char *menuID );
void _UI_Refresh( int realtime );
void UI_DrawConnect( const char *servername, const char * updateInfoString );
/*
==================
SCR_DrawScreenField
This will be called twice if rendering in stereo mode
==================
*/
void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
re.BeginFrame( stereoFrame );
// wide aspect ratio screens need to have the sides cleared
// unless they are displaying game renderings
#ifndef _XBOX
// Xbox no want this
if ( cls.state != CA_ACTIVE ) {
if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
re.SetColor( g_color_table[0] );
re.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, 0 );
re.SetColor( NULL );
}
}
#endif
// if the menu is going to cover the entire screen, we
// don't need to render anything under it
if ( !_UI_IsFullscreen() ) {
switch( cls.state ) {
default:
Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" );
break;
case CA_CINEMATIC:
SCR_DrawCinematic();
break;
case CA_DISCONNECTED:
// force menu up
UI_SetActiveMenu( "mainMenu",NULL ); // VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
break;
case CA_CONNECTING:
case CA_CHALLENGING:
case CA_CONNECTED:
// connecting clients will only show the connection dialog
UI_DrawConnect( clc.servername, cls.updateInfoString );
break;
case CA_LOADING:
case CA_PRIMED:
// We got past the time when the UI needs to prevent swapping
extern bool connectSwapOverride;
connectSwapOverride = false;
// draw the game information screen and loading progress
CL_CGameRendering( stereoFrame );
break;
case CA_ACTIVE:
if (CL_IsRunningInGameCinematic() || CL_InGameCinematicOnStandBy())
{
SCR_DrawCinematic();
}
else
{
CL_CGameRendering( stereoFrame );
}
break;
}
}
#ifndef _XBOX // on xbox this is rendered right before a flip
re.ProcessDissolve();
#endif // _XBOX
// draw downloading progress bar
// the menu draws next
_UI_Refresh( cls.realtime );
// console draws next
// Con_DrawConsole ();
// debug graph can be drawn on top of anything
#ifndef _XBOX
if ( cl_debuggraph->integer || cl_timegraph->integer ) {
SCR_DrawDebugGraph ();
}
#endif
}
/*
==================
SCR_UpdateScreen
This is called every frame, and can also be called explicitly to flush
text to the screen.
==================
*/
void SCR_UpdateScreen( void ) {
static int recursive;
if ( !scr_initialized ) {
return; // not initialized yet
}
// load the ref / ui / cgame if needed
CL_StartHunkUsers();
if ( ++recursive > 2 ) {
Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
}
recursive = qtrue;
// if running in stereo, we need to draw the frame twice
if ( cls.glconfig.stereoEnabled ) {
SCR_DrawScreenField( STEREO_LEFT );
SCR_DrawScreenField( STEREO_RIGHT );
} else {
SCR_DrawScreenField( STEREO_CENTER );
}
if ( com_speeds->integer ) {
re.EndFrame( &time_frontend, &time_backend );
} else {
re.EndFrame( NULL, NULL );
}
recursive = 0;
}
// this stuff is only used by the savegame (SG) code for screenshots...
//
#ifdef _XBOX
/*
static byte bScreenData[SG_SCR_WIDTH * SG_SCR_HEIGHT * 4];
static qboolean screenDataValid = qfalse;
void SCR_UnprecacheScreenshot()
{
screenDataValid = qfalse;
}
*/
void SCR_PrecacheScreenshot()
{
// No screenshots unless connected to single player local server...
//
// char *psInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
// int iMaxClients = atoi(Info_ValueForKey( psInfo, "sv_maxclients" ));
// (no need to check single-player status in voyager, this code base is all singleplayer)
if ( cls.state != CA_ACTIVE )
{
return;
}
#ifndef _XBOX
if (cls.keyCatchers == 0)
{
// in-game...
//
// SCR_UnprecacheScreenshot();
// pbScreenData = (byte *)Z_Malloc(SG_SCR_WIDTH * SG_SCR_HEIGHT * 4);
S_ClearSoundBuffer(); // clear DMA etc because the following glReadPixels() call can take ages
re.GetScreenShot( (byte *) &bScreenData, SG_SCR_WIDTH, SG_SCR_HEIGHT);
screenDataValid = qtrue;
}
else
{
// we're in the console, or menu, or message input...
//
}
#endif
// save the current screenshot to the user space to be used
// with a savegame
#ifdef _XBOX
extern void SaveCompressedScreenshot( void );
SaveCompressedScreenshot();
#endif
}
/*
byte *SCR_GetScreenshot(qboolean *qValid)
{
if (!screenDataValid) {
SCR_PrecacheScreenshot();
}
if (qValid) {
*qValid = screenDataValid;
}
return (byte *)&bScreenData;
}
// called from save-game code to set the lo-res loading screen to be the one from the save file...
//
void SCR_SetScreenshot(const byte *pbData, int w, int h)
{
if (w == SG_SCR_WIDTH && h == SG_SCR_HEIGHT)
{
screenDataValid = qtrue;
memcpy(&bScreenData, pbData, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
}
else
{
screenDataValid = qfalse;
memset(&bScreenData, 0, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
}
}
*/
// This is just a client-side wrapper for the function RE_TempRawImage_ReadFromFile() in the renderer code...
//
/*
byte* SCR_TempRawImage_ReadFromFile(const char *psLocalFilename, int *piWidth, int *piHeight, byte *pbReSampleBuffer, qboolean qbVertFlip)
{
return re.TempRawImage_ReadFromFile(psLocalFilename, piWidth, piHeight, pbReSampleBuffer, qbVertFlip);
}
//
// ditto (sort of)...
//
void SCR_TempRawImage_CleanUp()
{
re.TempRawImage_CleanUp();
}
*/
#endif

503
code/client/cl_ui.cpp Normal file
View File

@@ -0,0 +1,503 @@
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "client.h"
#include "client_ui.h"
#include "vmachine.h"
int PC_ReadTokenHandle(int handle, struct pc_token_s *pc_token);
int CL_UISystemCalls( int *args );
//prototypes
//extern qboolean SG_GetSaveImage( const char *psPathlessBaseName, void *pvAddress );
extern int SG_GetSaveGameComment(const char *psPathlessBaseName, char *sComment, char *sMapName);
extern qboolean SG_GameAllowedToSaveHere(qboolean inCamera);
extern void SG_StoreSaveGameComment(const char *sComment);
//extern byte *SCR_GetScreenshot(qboolean *qValid);
/*
====================
Helper functions for User Interface
====================
*/
/*
====================
GetClientState
====================
*/
static connstate_t GetClientState( void ) {
return cls.state;
}
/*
====================
CL_GetGlConfig
====================
*/
static void UI_GetGlconfig( glconfig_t *config ) {
*config = cls.glconfig;
}
/*
====================
GetClipboardData
====================
*/
static void GetClipboardData( char *buf, int buflen ) {
char *cbd;
cbd = Sys_GetClipboardData();
if ( !cbd ) {
*buf = 0;
return;
}
Q_strncpyz( buf, cbd, buflen );
Z_Free( cbd );
}
/*
====================
Key_KeynumToStringBuf
====================
*/
// only ever called by binding-display code, therefore returns non-technical "friendly" names
// in any language that don't necessarily match those in the config file...
//
void Key_KeynumToStringBuf( int keynum, char *buf, int buflen )
{
const char *psKeyName = Key_KeynumToString( keynum/*, qtrue */);
// see if there's a more friendly (or localised) name...
//
const char *psKeyNameFriendly = SE_GetString( va("KEYNAMES_KEYNAME_%s",psKeyName) );
Q_strncpyz( buf, (psKeyNameFriendly && psKeyNameFriendly[0]) ? psKeyNameFriendly : psKeyName, buflen );
}
/*
====================
Key_GetBindingBuf
====================
*/
void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
char *value;
value = Key_GetBinding( keynum );
if ( value ) {
Q_strncpyz( buf, value, buflen );
}
else {
*buf = 0;
}
}
/*
====================
Key_GetCatcher
====================
*/
int Key_GetCatcher( void )
{
return cls.keyCatchers;
}
/*
====================
Key_GetCatcher
====================
*/
void Key_SetCatcher( int catcher )
{
cls.keyCatchers = catcher;
}
/*
====================
FloatAsInt
====================
*/
int FloatAsInt( float f )
{
int temp;
*(float *)&temp = f;
return temp;
}
static void UI_Cvar_Create( const char *var_name, const char *var_value, int flags ) {
Cvar_Get( var_name, var_value, flags );
}
static int GetConfigString(int index, char *buf, int size)
{
int offset;
if (index < 0 || index >= MAX_CONFIGSTRINGS)
return qfalse;
offset = cl.gameState.stringOffsets[index];
if (!offset)
return qfalse;
Q_strncpyz( buf, cl.gameState.stringData+offset, size);
return qtrue;
}
/*
====================
CL_ShutdownUI
====================
*/
void CL_ShutdownUI( void ) {
cls.keyCatchers &= ~KEYCATCH_UI;
cls.uiStarted = qfalse;
}
void CL_DrawDatapad(int HUDType)
{
switch(HUDType)
{
case DP_OBJECTIVES:
VM_Call( CG_DRAW_DATAPAD_OBJECTIVES );
break;
case DP_WEAPONS:
VM_Call( CG_DRAW_DATAPAD_WEAPONS );
break;
case DP_INVENTORY:
VM_Call( CG_DRAW_DATAPAD_INVENTORY );
break;
case DP_FORCEPOWERS:
VM_Call( CG_DRAW_DATAPAD_FORCEPOWERS );
break;
default:
break;
}
}
void UI_Init( int apiVersion, uiimport_t *uiimport, qboolean inGameLoad );
/*
====================
CL_InitUI
====================
*/
void CL_InitUI( void ) {
uiimport_t uii;
memset( &uii, 0, sizeof( uii ) );
uii.Printf = Com_Printf;
uii.Error = Com_Error;
uii.Cvar_Set = Cvar_Set;
uii.Cvar_VariableValue = Cvar_VariableValue;
uii.Cvar_VariableStringBuffer = Cvar_VariableStringBuffer;
uii.Cvar_SetValue = Cvar_SetValue;
uii.Cvar_Reset = Cvar_Reset;
uii.Cvar_Create = UI_Cvar_Create;
uii.Cvar_InfoStringBuffer = Cvar_InfoStringBuffer;
uii.Draw_DataPad = CL_DrawDatapad;
uii.Argc = Cmd_Argc;
uii.Argv = Cmd_ArgvBuffer;
uii.Cmd_TokenizeString = Cmd_TokenizeString;
uii.Cmd_ExecuteText = Cbuf_ExecuteText;
uii.FS_FOpenFile = FS_FOpenFileByMode;
uii.FS_Read = FS_Read;
uii.FS_Write = FS_Write;
uii.FS_FCloseFile = FS_FCloseFile;
uii.FS_GetFileList = FS_GetFileList;
uii.FS_ReadFile = FS_ReadFile;
uii.FS_FreeFile = FS_FreeFile;
uii.R_RegisterModel = re.RegisterModel;
uii.R_RegisterSkin = re.RegisterSkin;
uii.R_RegisterShader = re.RegisterShader;
uii.R_RegisterShaderNoMip = re.RegisterShaderNoMip;
uii.R_RegisterFont = re.RegisterFont;
#ifndef _XBOX
uii.R_Font_StrLenPixels = re.Font_StrLenPixels;
uii.R_Font_HeightPixels = re.Font_HeightPixels;
uii.R_Font_DrawString = re.Font_DrawString;
#endif
uii.R_Font_StrLenChars = re.Font_StrLenChars;
uii.Language_IsAsian = re.Language_IsAsian;
uii.Language_UsesSpaces = re.Language_UsesSpaces;
uii.AnyLanguage_ReadCharFromString = re.AnyLanguage_ReadCharFromString;
//uii.SG_GetSaveImage = SG_GetSaveImage;
uii.SG_GetSaveGameComment = SG_GetSaveGameComment;
uii.SG_StoreSaveGameComment = SG_StoreSaveGameComment;
uii.SG_GameAllowedToSaveHere= SG_GameAllowedToSaveHere;
//uii.SCR_GetScreenshot = SCR_GetScreenshot;
//uii.DrawStretchRaw = re.DrawStretchRaw;
uii.R_ClearScene = re.ClearScene;
uii.R_AddRefEntityToScene = re.AddRefEntityToScene;
uii.R_AddPolyToScene = re.AddPolyToScene;
uii.R_AddLightToScene = re.AddLightToScene;
uii.R_RenderScene = re.RenderScene;
uii.R_ModelBounds = re.ModelBounds;
uii.R_SetColor = re.SetColor;
uii.R_DrawStretchPic = re.DrawStretchPic;
uii.UpdateScreen = SCR_UpdateScreen;
#ifdef _XBOX
uii.PrecacheScreenshot = SCR_PrecacheScreenshot;
#endif
uii.R_LerpTag = re.LerpTag;
uii.S_StartLocalLoopingSound= S_StartLocalLoopingSound;
uii.S_StartLocalSound = S_StartLocalSound;
uii.S_RegisterSound = S_RegisterSound;
uii.Key_KeynumToStringBuf = Key_KeynumToStringBuf;
uii.Key_GetBindingBuf = Key_GetBindingBuf;
uii.Key_SetBinding = Key_SetBinding;
uii.Key_IsDown = Key_IsDown;
uii.Key_GetOverstrikeMode = Key_GetOverstrikeMode;
uii.Key_SetOverstrikeMode = Key_SetOverstrikeMode;
uii.Key_ClearStates = Key_ClearStates;
uii.Key_GetCatcher = Key_GetCatcher;
uii.Key_SetCatcher = Key_SetCatcher;
uii.GetClipboardData = GetClipboardData;
uii.GetClientState = GetClientState;
uii.GetGlconfig = UI_GetGlconfig;
uii.GetConfigString = (void (*)(int, char *, int))GetConfigString;
uii.Milliseconds = Sys_Milliseconds;
UI_Init(UI_API_VERSION, &uii, (cls.state > CA_DISCONNECTED && cls.state <= CA_ACTIVE));
//JLF MPSKIPPED
#ifdef _XBOX
extern void UpdateDemoTimer();
UpdateDemoTimer();
#endif
// uie->UI_Init( UI_API_VERSION, &uii );
}
qboolean UI_GameCommand( void ) {
if (!cls.uiStarted)
{
return qfalse;
}
return UI_ConsoleCommand();
}
void CL_GenericMenu_f(void)
{
char *arg = Cmd_Argv( 1 );
if (cls.uiStarted) {
UI_SetActiveMenu("ingame",arg);
}
}
void CL_EndScreenDissolve_f(void)
{
re.InitDissolve(qtrue); // dissolve from cinematic to underlying ingame
}
void CL_DataPad_f(void)
{
if (cls.uiStarted && cls.cgameStarted && (cls.state == CA_ACTIVE) ) {
UI_SetActiveMenu("datapad",NULL);
}
}
/*
====================
CL_GetGlConfig
====================
*/
static void CL_GetGlconfig( glconfig_t *config )
{
*config = cls.glconfig;
}
/*
int PC_ReadTokenHandle(int handle, pc_token_t *pc_token);
int PC_SourceFileAndLine(int handle, char *filename, int *line);
*/
/*
====================
CL_UISystemCalls
The ui module is making a system call
====================
*/
vm_t uivm;
#define VMA(x) ((void*)args[x])
#define VMF(x) ((float *)args)[x]
int CL_UISystemCalls( int *args )
{
switch( args[0] )
{
case UI_ERROR:
Com_Error( ERR_DROP, "%s", VMA(1) );
return 0;
case UI_CVAR_REGISTER:
Cvar_Register( (vmCvar_t *)VMA(1),(const char *) VMA(2),(const char *) VMA(3), args[4] );
return 0;
case UI_CVAR_SET:
Cvar_Set( (const char *) VMA(1), (const char *) VMA(2) );
return 0;
case UI_CVAR_SETVALUE:
Cvar_SetValue( (const char *) VMA(1), VMF(2) );
return 0;
case UI_CVAR_UPDATE:
Cvar_Update( (vmCvar_t *) VMA(1) );
return 0;
case UI_R_REGISTERMODEL:
return re.RegisterModel((const char *) VMA(1) );
case UI_R_REGISTERSHADERNOMIP:
return re.RegisterShaderNoMip((const char *) VMA(1) );
case UI_GETGLCONFIG:
CL_GetGlconfig( ( glconfig_t *) VMA(1) );
return 0;
case UI_CMD_EXECUTETEXT:
Cbuf_ExecuteText( args[1], (const char *) VMA(2) );
return 0;
case UI_CVAR_VARIABLEVALUE:
return FloatAsInt( Cvar_VariableValue( (const char *) VMA(1) ) );
case UI_FS_GETFILELIST:
return FS_GetFileList( (const char *) VMA(1), (const char *) VMA(2), (char *) VMA(3), args[4] );
case UI_KEY_SETCATCHER:
Key_SetCatcher( args[1] );
return 0;
case UI_KEY_CLEARSTATES:
Key_ClearStates();
return 0;
case UI_R_SETCOLOR:
re.SetColor( (const float *) VMA(1) );
return 0;
case UI_R_DRAWSTRETCHPIC:
re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
return 0;
case UI_CVAR_VARIABLESTRINGBUFFER:
Cvar_VariableStringBuffer( (const char *) VMA(1), (char *) VMA(2), args[3] );
return 0;
case UI_R_MODELBOUNDS:
re.ModelBounds( args[1], (float *) VMA(2),(float *) VMA(3) );
return 0;
case UI_R_CLEARSCENE:
re.ClearScene();
return 0;
// case UI_KEY_GETOVERSTRIKEMODE:
// return Key_GetOverstrikeMode();
// return 0;
// case UI_PC_READ_TOKEN:
// return PC_ReadTokenHandle( args[1], VMA(2) );
// case UI_PC_SOURCE_FILE_AND_LINE:
// return PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
case UI_KEY_GETCATCHER:
return Key_GetCatcher();
case UI_MILLISECONDS:
return Sys_Milliseconds();
case UI_S_REGISTERSOUND:
return S_RegisterSound((const char *) VMA(1));
case UI_S_STARTLOCALSOUND:
S_StartLocalSound( args[1], args[2] );
return 0;
// case UI_R_REGISTERFONT:
// re.RegisterFont( VMA(1), args[2], VMA(3));
// return 0;
case UI_CIN_PLAYCINEMATIC:
Com_DPrintf("UI_CIN_PlayCinematic\n");
return CIN_PlayCinematic((const char *)VMA(1), args[2], args[3], args[4], args[5], args[6], (const char *)VMA(7));
case UI_CIN_STOPCINEMATIC:
return CIN_StopCinematic(args[1]);
case UI_CIN_RUNCINEMATIC:
return CIN_RunCinematic(args[1]);
#ifndef _XBOX
case UI_CIN_DRAWCINEMATIC:
CIN_DrawCinematic(args[1]);
return 0;
#endif
case UI_KEY_SETBINDING:
Key_SetBinding( args[1], (const char *) VMA(2) );
return 0;
case UI_KEY_KEYNUMTOSTRINGBUF:
Key_KeynumToStringBuf( args[1],(char *) VMA(2), args[3] );
return 0;
case UI_CIN_SETEXTENTS:
CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
return 0;
case UI_KEY_GETBINDINGBUF:
Key_GetBindingBuf( args[1], (char *) VMA(2), args[3] );
return 0;
default:
Com_Error( ERR_DROP, "Bad UI system trap: %i", args[0] );
}
return 0;
}

474
code/client/client.h Normal file
View File

@@ -0,0 +1,474 @@
// client.h -- primary header for client
#pragma once
#ifndef __CLIENT_H__
#define __CLIENT_H__
#include "../game/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../renderer/tr_public.h"
#include "keys.h"
#include "snd_public.h"
#include "../cgame/cg_public.h"
// snapshots are a view of the server at a given time
typedef struct {
qboolean valid; // cleared if delta parsing was invalid
int snapFlags; // rate delayed and dropped commands
int serverTime; // server time the message is valid for (in msec)
int messageNum; // copied from netchan->incoming_sequence
int deltaNum; // messageNum the delta is from
int ping; // time from when cmdNum-1 was sent to time packet was reeceived
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
int cmdNum; // the next cmdNum the server is expecting
playerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
int parseEntitiesNum; // at the time of this snapshot
int serverCommandNum; // execute all commands up to this before
// making the snapshot current
} clSnapshot_t;
/*
=============================================================================
the clientActive_t structure is wiped completely at every
new gamestate_t, potentially several times during an established connection
=============================================================================
*/
// the parseEntities array must be large enough to hold PACKET_BACKUP frames of
// entities, so that when a delta compressed message arives from the server
// it can be un-deltad from the original
#define MAX_PARSE_ENTITIES 512
extern int g_console_field_width;
typedef struct {
int timeoutcount;
clSnapshot_t frame; // latest received from server
int serverTime;
int oldServerTime; // to prevent time from flowing bakcwards
int oldFrameServerTime; // to check tournament restarts
int serverTimeDelta; // cl.serverTime = cls.realtime + cl.serverTimeDelta
// this value changes as net lag varies
qboolean extrapolatedSnapshot; // set if any cgame frame has been forced to extrapolate
// cleared when CL_AdjustTimeDelta looks at it
qboolean newSnapshots; // set on parse, cleared when CL_AdjustTimeDelta looks at it
gameState_t gameState; // configstrings
char mapname[MAX_QPATH]; // extracted from CS_SERVERINFO
int parseEntitiesNum; // index (not anded off) into cl_parse_entities[]
int mouseDx[2], mouseDy[2]; // added to by mouse events
int mouseIndex;
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
int cgameUserCmdValue; // current weapon to add to usercmd_t
float cgameSensitivity;
// cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last
// properly generated command
usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
int cmdNumber; // incremented each frame, because multiple
// frames may need to be packed into a single packet
int packetTime[PACKET_BACKUP]; // cls.realtime sent, for calculating pings
int packetCmdNumber[PACKET_BACKUP]; // cmdNumber when packet was sent
// the client maintains its own idea of view angles, which are
// sent to the server each frame. It is cleared to 0 upon entering each level.
// the server sends a delta each frame which is added to the locally
// tracked view angles to account for standing on rotating objects,
// and teleport direction changes
vec3_t viewangles;
// these are just parsed out of the configstrings for convenience
int serverId;
// non-gameserver infornamtion
int cinematictime; // cls.realtime for first cinematic frame (FIXME: NO LONGER USED!, but I wasn't sure if I could remove it because of struct sizes assumed elsewhere? -Ste)
// big stuff at end of structure so most offsets are 15 bits or less
clSnapshot_t frames[PACKET_BACKUP];
entityState_t parseEntities[MAX_PARSE_ENTITIES];
//DJC added - making force powers in single player work like those in
//multiplayer. This makes hot swapping code more portable.
qboolean gcmdSendValue;
byte gcmdValue;
} clientActive_t;
extern clientActive_t cl;
/*
=============================================================================
the clientConnection_t structure is wiped when disconnecting from a server,
either to go to a full screen console, or connect to a different server
A connection can be to either a server through the network layer,
or just a streaming cinematic.
=============================================================================
*/
typedef struct {
int lastPacketSentTime; // for retransmits
int lastPacketTime;
char servername[MAX_OSPATH]; // name of server from original connect
netadr_t serverAddress;
int connectTime; // for connection retransmits
int connectPacketCount; // for display on connection dialog
int challenge; // from the server to use for connecting
int reliableSequence;
int reliableAcknowledge;
char *reliableCommands[MAX_RELIABLE_COMMANDS];
// reliable messages received from server
int serverCommandSequence;
char *serverCommands[MAX_RELIABLE_COMMANDS];
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;
} clientConnection_t;
extern clientConnection_t clc;
/*
==================================================================
the clientStatic_t structure is never wiped, and is used even when
no client connection is active at all
==================================================================
*/
typedef enum {
EXIT_CONSOLE,
EXIT_ARENAS,
EXIT_SERVERS,
EXIT_LAUNCH // quit all the way out of the game on disconnect
} exitTo_t;
#ifdef _XBOX
#define MAX_LOCAL_SERVERS 1
#define MAX_GLOBAL_SERVERS 1
#define MAX_PINGREQUESTS 1
#else
#define MAX_LOCAL_SERVERS 16
#define MAX_GLOBAL_SERVERS 256
#define MAX_PINGREQUESTS 16
#endif
typedef struct {
netadr_t adr;
int start;
int time;
} ping_t;
typedef struct {
netadr_t netadr;
char info[MAX_INFO_STRING];
} serverInfoResponse_t;
typedef struct {
netadr_t netadr;
char info[MAX_INFO_STRING];
} getserversResponse_t;
typedef struct {
connstate_t state; // connection status
int keyCatchers; // bit flags
char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect)
// when the server clears the hunk, all of these must be restarted
qboolean rendererStarted;
qboolean soundStarted;
qboolean soundRegistered;
qboolean uiStarted;
qboolean cgameStarted;
#ifdef _IMMERSION
qboolean forceStarted;
#endif // _IMMERSION
int framecount;
int frametime; // msec since last frame
float frametimeFraction; // fraction of a msec since last frame
int realtime; // ignores pause
float realtimeFraction; // fraction of a msec accumulated
int realFrametime; // ignoring pause, so console always works
// update server info
char updateInfoString[MAX_INFO_STRING];
// rendering info
glconfig_t glconfig;
qhandle_t charSetShader;
qhandle_t whiteShader;
// qhandle_t consoleShader;
#ifdef _XBOX
short mainGamepad;
#endif
} clientStatic_t;
#ifdef _XBOX
#define CON_TEXTSIZE 256
#else
#define CON_TEXTSIZE 32768
#endif
#define NUM_CON_TIMES 4
typedef struct {
qboolean initialized;
short text[CON_TEXTSIZE];
int current; // line where next message will be printed
int x; // offset in current line for next print
int display; // bottom of console displays this line
int linewidth; // characters across screen
int totallines; // total lines in console scrollback
float xadjust; // for wide aspect screens
float yadjust;
float displayFrac; // aproaches finalFrac at scr_conspeed
float finalFrac; // 0.0 to 1.0 lines of console to display
int vislines; // in scanlines
int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
// for transparent notify lines
vec4_t color;
} console_t;
extern clientStatic_t cls;
//=============================================================================
extern refexport_t re; // interface to refresh .dll
//
// cvars
//
extern cvar_t *cl_nodelta;
extern cvar_t *cl_debugMove;
extern cvar_t *cl_noprint;
extern cvar_t *cl_timegraph;
extern cvar_t *cl_maxpackets;
extern cvar_t *cl_packetdup;
extern cvar_t *cl_shownet;
extern cvar_t *cl_timeNudge;
extern cvar_t *cl_showTimeDelta;
extern cvar_t *cl_yawspeed;
extern cvar_t *cl_pitchspeed;
extern cvar_t *cl_run;
extern cvar_t *cl_anglespeedkey;
extern cvar_t *cl_sensitivity;
#ifdef _XBOX
extern cvar_t *cl_sensitivityY;
#endif
extern cvar_t *cl_freelook;
//extern cvar_t *cl_mouseAccel;
//extern cvar_t *cl_showMouseRate;
extern cvar_t *cl_ingameVideo;
extern cvar_t *cl_VideoQuality;
extern cvar_t *cl_VidFadeUp;
extern cvar_t *cl_VidFadeDown;
extern cvar_t *m_pitch;
extern cvar_t *m_yaw;
extern cvar_t *m_forward;
extern cvar_t *m_side;
//extern cvar_t *m_filter;
extern cvar_t *cl_activeAction;
extern cvar_t *cl_thumbStickMode;
//=================================================
//
// cl_main
//
void CL_Init (void);
void CL_AddReliableCommand( const char *cmd );
void CL_Disconnect_f (void);
void CL_GetChallengePacket (void);
void CL_Vid_Restart_f( void );
void CL_Snd_Restart_f (void);
void CL_NextDemo( void );
void CL_GetPing( int n, char *adrstr, int *pingtime );
void CL_ClearPing( int n );
int CL_GetPingQueueCount( void );
extern qboolean SG_GameAllowedToSaveHere(qboolean inCamera);
extern void CG_CenterPrint(const char *str, int y);
extern bool autosaveTrigger;
static void checkAutoSave();
//
// cl_input
//
typedef struct {
int down[2]; // key nums holding it down
unsigned downtime; // msec timestamp
unsigned msec; // msec down this frame if both a down and up happened
qboolean active; // current state
qboolean wasPressed; // set when down, not cleared when up
} kbutton_t;
extern kbutton_t in_mlook, in_klook;
extern kbutton_t in_strafe;
extern kbutton_t in_speed;
void CL_InitInput (void);
void CL_SendCmd (void);
void CL_ClearState (void);
void CL_ReadPackets (void);
void CL_UpdateHotSwap(void);
bool CL_ExtendSelectTime(void);
void CL_WritePacket( void );
void IN_CenterView (void);
float CL_KeyState (kbutton_t *key);
const char *Key_KeynumToString( int keynum/*, qboolean bTranslate*/ ); //note: translate is only called for menu display not configs
//
// cl_parse.c
//
void CL_SystemInfoChanged( void );
void CL_ParseServerMessage( msg_t *msg );
//====================================================================
void VID_MenuInit( void );
void VID_MenuDraw( void );
const char *VID_MenuKey( int );
void VID_Printf (int print_level, const char *fmt, ...);
//
// console
//
void Con_DrawCharacter (int cx, int line, int num);
void Con_CheckResize (void);
void Con_Init (void);
void Con_Clear_f (void);
void Con_ToggleConsole_f (void);
void Con_DrawNotify (void);
void Con_ClearNotify (void);
void Con_RunConsole (void);
void Con_DrawConsole (void);
void Con_PageUp( void );
void Con_PageDown( void );
void Con_Top( void );
void Con_Bottom( void );
void Con_Close( void );
//
// cl_scrn.c
//
void SCR_Init (void);
void SCR_UpdateScreen (void);
void SCR_DebugGraph (float value, int color);
int SCR_GetBigStringWidth( const char *str ); // returns in virtual 640x480 coordinates
void SCR_FillRect( float x, float y, float width, float height,
const float *color );
void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname );
void SCR_DrawBigString( int x, int y, const char *s, float alpha ); // draws a string with embedded color control characters with fade
void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color ); // ignores embedded color control characters
void SCR_DrawSmallString( int x, int y, const char *s, float alpha ); // draws a string with embedded color control characters with fade
void SCR_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ); // ignores embedded color control characters
void SCR_DrawBigChar( int x, int y, int ch );
void SCR_DrawSmallChar( int x, int y, int ch );
#ifdef _XBOX
void SCR_PrecacheScreenshot();
#endif
//
// cl_cin.c
//
void CL_PlayCinematic_f( void );
void CL_PlayInGameCinematic_f(void);
qboolean CL_CheckPendingCinematic(void);
qboolean CL_IsRunningInGameCinematic(void);
qboolean CL_InGameCinematicOnStandBy(void);
void SCR_DrawCinematic (void);
void SCR_RunCinematic (void);
void SCR_StopCinematic( qboolean bAllowRefusal = qfalse );
int CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits, const char *psAudioFile /* = NULL */);
e_status CIN_StopCinematic(int handle);
e_status CIN_RunCinematic (int handle);
void CIN_DrawCinematic (int handle);
void CIN_SetExtents (int handle, int x, int y, int w, int h);
void CIN_SetLooping (int handle, qboolean loop);
void CIN_UploadCinematic(int handle);
void CIN_CloseAllVideos(void);
#ifdef _XBOX
void CIN_Init(void);
bool CIN_PlayAllFrames( const char *arg, int x, int y, int w, int h, int systemBits, bool keyBreakAllowed );
#endif
//
// cl_cgame.c
//
void CL_InitCGame( void );
void CL_ShutdownCGame( void );
qboolean CL_GameCommand( void );
void CL_CGameRendering( stereoFrame_t stereo );
void CL_SetCGameTime( void );
void CL_FirstSnapshot( void );
//
// cl_ui.c
//
void CL_InitUI( void );
void CL_ShutdownUI( void );
void CL_GenericMenu_f(void);
void CL_DataPad_f(void);
void CL_EndScreenDissolve_f(void);
#endif //__CLIENT_H__

13
code/client/client_ui.h Normal file
View File

@@ -0,0 +1,13 @@
// client_ui.h -- header for client access to ui funcs
#ifndef __CLIENTUI_H__
#define __CLIENTUI_H__
#include "../ui/ui_public.h"
void _UI_KeyEvent( int key, qboolean down );
void UI_SetActiveMenu( const char* menuname,const char *menuID );
void UI_UpdateConnectionMessageString( char *string );
qboolean UI_ConsoleCommand( void ) ;
qboolean _UI_IsFullscreen( void );
#endif //__CLIENTUI_H__

171
code/client/eax/EaxMan.h Normal file
View File

@@ -0,0 +1,171 @@
/*
*/
#ifndef __EAXMANH
#define __EAXMANH
#define COM_NO_WINDOWS_H
#include <objbase.h>
#include "eax.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//#define CLSID_EAXMANAGER CLSID_EAX20_Manager
//#define IID_IEaxManager IID_EAX20_Manager
#define EM_MAX_NAME 32
#define EMFLAG_IDDEFAULT (-1)
#define EMFLAG_IDNONE (-2)
#define EMFLAG_LOCKPOSITION 1
#define EMFLAG_LOADFROMMEMORY 2
#define EMFLAG_NODIFFRACTION 4
typedef struct _EMPOINT {
float fX;
float fY;
float fZ;
} EMPOINT;
typedef EMPOINT FAR *LPEMPOINT;
typedef struct _LISTENERATTRIBUTES {
float fDistanceFactor;
float fRolloffFactor;
float fDopplerFactor;
} LISTENERATTRIBUTES;
typedef LISTENERATTRIBUTES FAR *LPLISTENERATTRIBUTES;
typedef struct _SOURCEATTRIBUTES {
EAXSOURCEPROPERTIES eaxAttributes;
unsigned long ulInsideConeAngle;
unsigned long ulOutsideConeAngle;
long lConeOutsideVolume;
float fConeXdir;
float fConeYdir;
float fConeZdir;
float fMinDistance;
float fMaxDistance;
long lDupCount;
long lPriority;
} SOURCEATTRIBUTES;
typedef SOURCEATTRIBUTES FAR *LPSOURCEATTRIBUTES;
typedef struct _MATERIALATTRIBUTES {
long lLevel;
float fLFRatio;
float fRoomRatio;
DWORD dwFlags;
} MATERIALATTRIBUTES;
typedef MATERIALATTRIBUTES FAR *LPMATERIALATTRIBUTES;
#define EMMATERIAL_OBSTRUCTS 1
#define EMMATERIAL_OCCLUDES 3
typedef struct _DIFFRACTIONBOX {
long lSubspaceID;
EMPOINT empMin;
EMPOINT empMax;
} DIFFRACTIONBOX;
typedef DIFFRACTIONBOX FAR *LPDIFFRACTIONBOX;
// {7CE4D6E6-562F-11d3-8812-005004062F83}
DEFINE_GUID(CLSID_EAXMANAGER, 0x60b721a1, 0xf7c8, 0x11d2, 0xa0, 0x2e, 0x0, 0x50, 0x4, 0x6, 0x18, 0xb8);
#ifdef __cplusplus
struct IEaxManager;
#endif // __cplusplus
typedef struct IEaxManager *LPEAXMANAGER;
// {7CE4D6E8-562F-11d3-8812-005004062F83}
DEFINE_GUID(IID_IEaxManager, 0x60b721a2, 0xf7c8, 0x11d2, 0xa0, 0x2e, 0x0, 0x50, 0x4, 0x6, 0x18, 0xb8);
#undef INTERFACE
#define INTERFACE IEaxManager
extern HRESULT __stdcall EaxManagerCreate(LPEAXMANAGER*);
typedef HRESULT (__stdcall *LPEAXMANAGERCREATE)(LPEAXMANAGER*);
DECLARE_INTERFACE_(IEaxManager, IUnknown)
{
// IUnknown methods
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
STDMETHOD(GetDataSetSize) (THIS_ unsigned long*, DWORD) PURE;
STDMETHOD(LoadDataSet) (THIS_ char*, DWORD) PURE;
STDMETHOD(FreeDataSet) (THIS_ DWORD) PURE;
STDMETHOD(GetListenerAttributes) (THIS_ LPLISTENERATTRIBUTES) PURE;
STDMETHOD(GetSourceID) (THIS_ char*, long*) PURE;
STDMETHOD(GetSourceAttributes) (THIS_ long, LPSOURCEATTRIBUTES) PURE;
STDMETHOD(GetSourceNumInstances) (THIS_ long, long*) PURE;
STDMETHOD(GetSourceInstancePos) (THIS_ long, long, LPEMPOINT) PURE;
STDMETHOD(GetEnvironmentID) (THIS_ char*, long*) PURE;
STDMETHOD(GetEnvironmentAttributes) (THIS_ long, LPEAXREVERBPROPERTIES) PURE;
STDMETHOD(GetMaterialID) (THIS_ char*, long*) PURE;
STDMETHOD(GetMaterialAttributes) (THIS_ long, LPMATERIALATTRIBUTES) PURE;
STDMETHOD(GetGeometrySetID) (THIS_ char*, long*) PURE;
STDMETHOD(GetListenerDynamicAttributes) (THIS_ long, LPEMPOINT, long*, DWORD) PURE;
STDMETHOD(GetSourceDynamicAttributes) (THIS_ long, LPEMPOINT, long*, float*, long*, float*, float*, LPEMPOINT, DWORD) PURE;
// STDMETHOD(GetSubSpaceID) (THIS_ long, LPEMPOINT, long *) PURE;
STDMETHOD(GetEnvironmentName) (THIS_ long, char *szString, long lStrlen) PURE;
};
#if !defined(__cplusplus) || defined(CINTERFACE)
#define IEaxManager_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
#define IEaxManager_AddRef(p) (p)->lpVtbl->AddRef(p)
#define IEaxManager_Release(p) (p)->lpVtbl->Release(p)
#define IEaxManager_GetDataSetSize(p,a,b) (p)->lpVtbl->GetDataSetSize(p,a,b)
#define IEaxManager_LoadDataSet(p,a,b) (p)->lpVtbl->LoadDataSet(p,a,b)
#define IEaxManager_FreeDataSet(p,a) (p)->lpVtbl->FreeDataSet(p,a)
#define IEaxManager_GetListenerAttributes(p,a) (p)->lpVtbl->GetListenerAttributes(p,a)
#define IEaxManager_GetSourceID(p,a,b) (p)->lpVtbl->GetSourceID(p,a,b)
#define IEaxManager_GetSourceAttributes(p,a,b) (p)->lpVtbl->GetSourceAttributes(p,a,b)
#define IEaxManager_GetSourceNumInstances(p,a,b) (p)->lpVtbl->GetSourceNumInstances(p,a,b)
#define IEaxManager_GetSourceInstancePos(p,a,b,c) (p)->lpVtbl->GetSourceInstancePos(p,a,b,c)
#define IEaxManager_GetEnvironmentID(p,a,b) (p)->lpVtbl->GetEnvironmentID(p,a,b)
#define IEaxManager_GetEnvironmentAttributes(p,a,b) (p)->lpVtbl->GetEnvironmentAttributes(p,a,b)
#define IEaxManager_GetMaterialID(p,a,b) (p)->lpVtbl->GetMaterialID(p,a,b)
#define IEaxManager_GetMaterialAttributes(p,a,b) (p)->lpVtbl->GetMaterialAttributes(p,a,b)
#define IEaxManager_GetGeometrySetID(p,a,b) (p)->lpVtbl->GetGeometrySetID(p,a,b)
#define IEaxManager_GetListenerDynamicAttributes(p,a,b,c,d) (p)->lpVtbl->GetListenerDynamicAttributes(p,a,b,c,d)
#define IEaxManager_GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i)
//#define IEaxManager_GetSubSpaceID(p,a,b,c) (p)->lpVtbl->GetSubSpaceID(p,a,b,c)
#define IEaxManager_GetEnvironmentName(p,a,b,c) (p)->lpVtbl->GetEnvironmentName(p,a,b,c)
#else
#define IEaxManager_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
#define IEaxManager_AddRef(p) (p)->AddRef()
#define IEaxManager_Release(p) (p)->Release()
#define IEaxManager_GetDataSetSize(p,a,b) (p)->GetDataSetSize(a,b)
#define IEaxManager_LoadDataSet(p,a,b) (p)->LoadDataSet(a,b)
#define IEaxManager_FreeDataSet(p,a) (p)->FreeDataSet(a)
#define IEaxManager_GetListenerAttributes(p,a) (p)->GetListenerAttributes(a)
#define IEaxManager_GetSourceID(p,a,b) (p)->GetSourceID(a,b)
#define IEaxManager_GetSourceAttributes(p,a,b) (p)->GetSourceAttributes(a,b)
#define IEaxManager_GetSourceNumInstances(p,a,b) (p)->GetSourceNumInstances(a,b)
#define IEaxManager_GetSourceInstancePos(p,a,b,c) (p)->GetSourceInstancePos(a,b,c)
#define IEaxManager_GetEnvironmentID(p,a,b) (p)->GetEnvironmentID(a,b)
#define IEaxManager_GetEnvironmentAttributes(p,a,b) (p)->GetEnvironmentAttributes(a,b)
#define IEaxManager_GetMaterialID(p,a,b) (p)->GetMaterialID(a,b)
#define IEaxManager_GetMaterialAttributes(p,a,b) (p)->GetMaterialAttributes(a,b)
#define IEaxManager_GetGeometrySetID(p,a,b) (p)->GetGeometrySetID(a,b)
#define IEaxManager_GetListenerDynamicAttributes(p,a,b,c,d) (p)->GetListenerDynamicAttributes(a,b,c,d)
#define IEaxManager_GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i) (p)->GetSourceDynamicAttributes(a,b,c,d,e,f,g,h,i)
//#define IEaxManager_GetSubSpaceID(p,a,b,c) (p)->GetSubSpaceID(a,b,c)
#define IEaxManager_GetEnvironmentName(p,a,b,c) (p)->GetEnvironmentName(a,b,c)
#endif
#define EM_OK 0
#define EM_INVALIDID MAKE_HRESULT(1, FACILITY_ITF, 1)
#define EM_IDNOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 2)
#define EM_FILENOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 3)
#define EM_FILEINVALID MAKE_HRESULT(1, FACILITY_ITF, 4)
#define EM_VERSIONINVALID MAKE_HRESULT(1, FACILITY_ITF, 5)
#define EM_INSTANCENOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 6)
#ifdef __cplusplus
};
#endif // __cplusplus
#endif

1562
code/client/eax/eax.h Normal file

File diff suppressed because it is too large Load Diff

129
code/client/fffx.h Normal file
View File

@@ -0,0 +1,129 @@
// Filename:- fffx.h (Force Feedback FX)
#ifndef FFFX_H
#define FFFX_H
// this part can be seen by the CGAME as well...
// These enums match the generic ones built into the effects ROM in the MS SideWinder FF Joystick,
// so blame MS for anything you don't like (like that aircraft carrier one - jeez!)...
//
// (Judging from the names of most of these, the MS FF guys appear to be rather fond of ID-type games...)
//
typedef enum
{
fffx_RandomNoise=0,
fffx_AircraftCarrierTakeOff, // this one is pointless / dumb
fffx_BasketballDribble,
fffx_CarEngineIdle,
fffx_ChainsawIdle,
fffx_ChainsawInAction,
fffx_DieselEngineIdle,
fffx_Jump,
fffx_Land,
fffx_MachineGun,
fffx_Punched,
fffx_RocketLaunch,
fffx_SecretDoor,
fffx_SwitchClick,
fffx_WindGust,
fffx_WindShear, // also pretty crap
fffx_Pistol,
fffx_Shotgun,
fffx_Laser1,
fffx_Laser2,
fffx_Laser3,
fffx_Laser4,
fffx_Laser5,
fffx_Laser6,
fffx_OutOfAmmo,
fffx_LightningGun,
fffx_Missile,
fffx_GatlingGun,
fffx_ShortPlasma,
fffx_PlasmaCannon1,
fffx_PlasmaCannon2,
fffx_Cannon,
#ifdef _XBOX
fffx_FallingShort,
fffx_FallingMedium,
fffx_FallingFar,
fffx_StartConst,
fffx_StopConst,
#endif
//
fffx_NUMBEROF,
fffx_NULL // special use, ignore during array mallocs etc, use fffx_NUMBEROF instead
} ffFX_e;
#ifndef CGAME_ONLY
/////////////////////////// START of functions to call /////////////////////////////////
//
//
//
// Once the game is running you should *only* access FF functions through these 4 macros. Savvy?
//
// Usage note: In practice, you can have about 4 FF FX running concurrently, though I defy anyone to make sense
// of that amount of white-noise vibration. MS guidelines say you shouldn't leave vibration on for long periods
// of time (eg engine rumble) because of various nerve-damage/lawsuit issues, so for this reason there is no API
// support for setting durations etc. All FF FX stuff here is designed for things like firing, hit damage, driving
// over bumps, etc that can be played as one-off events, though you *can* do things like FFFX_ENSURE(fffx_ChainsawIdle)
// if you really want to.
//
// Combining small numbers of effects such as having a laser firing (MS photons have higher mass apparently <g>),
// and then firing a machine gun in bursts as well are no problem, and easily felt, hence the ability to stop playing
// individual FF FX.
//
#define FFFX_START(f) FF_Play(f)
#define FFFX_ENSURE(f) FF_EnsurePlaying(f)
#define FFFX_STOP(f) FF_Stop(f) // some effects (eg. gatling, chainsaw), need this, or they play too long after trigger-off.
#define FFFX_STOPALL FF_StopAll()
//
// These 2 are called at app start/stop, but you can call FF_Init to change FF devices anytime (takes a couple of seconds)
//
void FF_Init(qboolean bTryMouseFirst=true);
void FF_Shutdown(void);
//
// other stuff you may want to call but don't have to...
//
qboolean FF_IsAvailable(void);
qboolean FF_IsMouse(void);
qboolean FF_SetTension(int iTension); // tension setting 0..3 (0=none)
qboolean FF_SetSpring(long lSpring); // precision version of above, 0..n..10000
// (only provided for command line fiddling with
// weird hardware. FF_SetTension(1) = default
// = FF_SetSpring(2000) (internal lookup table))
//
//
//
/////////////////////////// END of functions to call /////////////////////////////////
// do *not* call this functions directly (or else!), use the macros above
//
void FF_Play (ffFX_e fffx);
void FF_EnsurePlaying (ffFX_e fffx);
void FF_Stop (ffFX_e fffx);
void FF_StopAll (void);
#ifdef _XBOX
void FF_XboxShake (float intensity, int duration);
void FF_XboxDamage (int damage, float xpos);
#endif
#define MAX_CONCURRENT_FFFXs 4 // only for my code to use/read, do NOT alter!
#endif // #ifndef CGAME_ONLY
#endif // #ifndef FFFX_H
//////////////////////// eof //////////////////////

347
code/client/keycodes.h Normal file
View File

@@ -0,0 +1,347 @@
#ifndef __KEYCODES_H__
#define __KEYCODES_H__
// these are the key numbers that should be passed to KeyEvent
typedef enum
{
A_NULL = 0,
A_SHIFT,
A_CTRL,
A_ALT,
A_CAPSLOCK,
A_NUMLOCK,
A_SCROLLLOCK,
A_PAUSE,
A_BACKSPACE,
A_TAB,
A_ENTER,
A_KP_PLUS,
A_KP_MINUS,
A_KP_ENTER,
A_KP_PERIOD,
A_PRINTSCREEN,
A_KP_0,
A_KP_1,
A_KP_2,
A_KP_3,
A_KP_4,
A_KP_5,
A_KP_6,
A_KP_7,
A_KP_8,
A_KP_9,
A_CONSOLE,
A_ESCAPE,
A_F1,
A_F2,
A_F3,
A_F4,
A_SPACE,
A_PLING,
A_DOUBLE_QUOTE,
A_HASH,
A_STRING,
A_PERCENT,
A_AND,
A_SINGLE_QUOTE,
A_OPEN_BRACKET,
A_CLOSE_BRACKET,
A_STAR,
A_PLUS,
A_COMMA,
A_MINUS,
A_PERIOD,
A_FORWARD_SLASH,
A_0,
A_1,
A_2,
A_3,
A_4,
A_5,
A_6,
A_7,
A_8,
A_9,
A_COLON,
A_SEMICOLON,
A_LESSTHAN,
A_EQUALS,
A_GREATERTHAN,
A_QUESTION,
A_AT,
A_CAP_A,
A_CAP_B,
A_CAP_C,
A_CAP_D,
A_CAP_E,
A_CAP_F,
A_CAP_G,
A_CAP_H,
A_CAP_I,
A_CAP_J,
A_CAP_K,
A_CAP_L,
A_CAP_M,
A_CAP_N,
A_CAP_O,
A_CAP_P,
A_CAP_Q,
A_CAP_R,
A_CAP_S,
A_CAP_T,
A_CAP_U,
A_CAP_V,
A_CAP_W,
A_CAP_X,
A_CAP_Y,
A_CAP_Z,
A_OPEN_SQUARE,
A_BACKSLASH,
A_CLOSE_SQUARE,
A_CARET,
A_UNDERSCORE,
A_LEFT_SINGLE_QUOTE,
A_LOW_A,
A_LOW_B,
A_LOW_C,
A_LOW_D,
A_LOW_E,
A_LOW_F,
A_LOW_G,
A_LOW_H,
A_LOW_I,
A_LOW_J,
A_LOW_K,
A_LOW_L,
A_LOW_M,
A_LOW_N,
A_LOW_O,
A_LOW_P,
A_LOW_Q,
A_LOW_R,
A_LOW_S,
A_LOW_T,
A_LOW_U,
A_LOW_V,
A_LOW_W,
A_LOW_X,
A_LOW_Y,
A_LOW_Z,
A_OPEN_BRACE,
A_BAR,
A_CLOSE_BRACE,
A_TILDE,
A_DELETE,
A_EURO,
A_SHIFT2,
A_CTRL2,
A_ALT2,
A_F5,
A_F6,
A_F7,
A_F8,
A_CIRCUMFLEX,
A_MWHEELUP,
A_CAP_SCARON,
A_MWHEELDOWN,
A_CAP_OE,
A_MOUSE1,
A_MOUSE2,
A_INSERT,
A_HOME,
A_PAGE_UP,
A_RIGHT_SINGLE_QUOTE,
A_LEFT_DOUBLE_QUOTE,
A_RIGHT_DOUBLE_QUOTE,
A_F9,
A_F10,
A_F11,
A_F12,
A_TRADEMARK,
A_LOW_SCARON,
A_SHIFT_ENTER,
A_LOW_OE,
A_END,
A_PAGE_DOWN,
A_CAP_YDIERESIS,
A_SHIFT_SPACE,
A_EXCLAMDOWN,
A_CENT,
A_POUND,
A_SHIFT_KP_ENTER,
A_YEN,
A_MOUSE3,
A_MOUSE4,
A_MOUSE5,
A_COPYRIGHT,
A_CURSOR_UP,
A_CURSOR_DOWN,
A_CURSOR_LEFT,
A_CURSOR_RIGHT,
A_REGISTERED,
A_UNDEFINED_7,
A_UNDEFINED_8,
A_UNDEFINED_9,
A_UNDEFINED_10,
A_UNDEFINED_11,
A_UNDEFINED_12,
A_UNDEFINED_13,
A_UNDEFINED_14,
A_UNDEFINED_15,
A_UNDEFINED_16,
A_UNDEFINED_17,
A_UNDEFINED_18,
A_UNDEFINED_19,
A_UNDEFINED_20,
A_UNDEFINED_21,
A_UNDEFINED_22,
A_QUESTION_DOWN,
A_CAP_AGRAVE,
A_CAP_AACUTE,
A_CAP_ACIRCUMFLEX,
A_CAP_ATILDE,
A_CAP_ADIERESIS,
A_CAP_ARING,
A_CAP_AE,
A_CAP_CCEDILLA,
A_CAP_EGRAVE,
A_CAP_EACUTE,
A_CAP_ECIRCUMFLEX,
A_CAP_EDIERESIS,
A_CAP_IGRAVE,
A_CAP_IACUTE,
A_CAP_ICIRCUMFLEX,
A_CAP_IDIERESIS,
A_CAP_ETH,
A_CAP_NTILDE,
A_CAP_OGRAVE,
A_CAP_OACUTE,
A_CAP_OCIRCUMFLEX,
A_CAP_OTILDE,
A_CAP_ODIERESIS,
A_MULTIPLY,
A_CAP_OSLASH,
A_CAP_UGRAVE,
A_CAP_UACUTE,
A_CAP_UCIRCUMFLEX,
A_CAP_UDIERESIS,
A_CAP_YACUTE,
A_CAP_THORN,
A_GERMANDBLS,
A_LOW_AGRAVE,
A_LOW_AACUTE,
A_LOW_ACIRCUMFLEX,
A_LOW_ATILDE,
A_LOW_ADIERESIS,
A_LOW_ARING,
A_LOW_AE,
A_LOW_CCEDILLA,
A_LOW_EGRAVE,
A_LOW_EACUTE,
A_LOW_ECIRCUMFLEX,
A_LOW_EDIERESIS,
A_LOW_IGRAVE,
A_LOW_IACUTE,
A_LOW_ICIRCUMFLEX,
A_LOW_IDIERESIS,
A_LOW_ETH,
A_LOW_NTILDE,
A_LOW_OGRAVE,
A_LOW_OACUTE,
A_LOW_OCIRCUMFLEX,
A_LOW_OTILDE,
A_LOW_ODIERESIS,
A_DIVIDE,
A_LOW_OSLASH,
A_LOW_UGRAVE,
A_LOW_UACUTE,
A_LOW_UCIRCUMFLEX,
A_LOW_UDIERESIS,
A_LOW_YACUTE,
A_LOW_THORN,
A_LOW_YDIERESIS,
A_JOY0,
A_JOY1,
A_JOY2,
A_JOY3,
A_JOY4,
A_JOY5,
A_JOY6,
A_JOY7,
A_JOY8,
A_JOY9,
A_JOY10,
A_JOY11,
A_JOY12,
A_JOY13,
A_JOY14,
A_JOY15,
A_JOY16,
A_JOY17,
A_JOY18,
A_JOY19,
A_JOY20,
A_JOY21,
A_JOY22,
A_JOY23,
A_JOY24,
A_JOY25,
A_JOY26,
A_JOY27,
A_JOY28,
A_JOY29,
A_JOY30,
A_JOY31,
A_AUX0,
A_AUX1,
A_AUX2,
A_AUX3,
A_AUX4,
A_AUX5,
A_AUX6,
A_AUX7,
A_AUX8,
A_AUX9,
A_AUX10,
A_AUX11,
A_AUX12,
A_AUX13,
A_AUX14,
A_AUX15,
A_AUX16,
A_AUX17,
A_AUX18,
A_AUX19,
A_AUX20,
A_AUX21,
A_AUX22,
A_AUX23,
A_AUX24,
A_AUX25,
A_AUX26,
A_AUX27,
A_AUX28,
A_AUX29,
A_AUX30,
A_AUX31,
MAX_KEYS
} fakeAscii_t;
// The menu code needs to get both key and char events, but
// to avoid duplicating the paths, the char events are just
// distinguished by or'ing in K_CHAR_FLAG (ugly)
#define K_CHAR_FLAG 1024
#endif

61
code/client/keys.h Normal file
View File

@@ -0,0 +1,61 @@
#include "keycodes.h"
typedef struct {
qboolean down;
int repeats; // if > 1, it is autorepeating
char *binding;
} qkey_t;
#define MAX_EDIT_LINE 256
#define COMMAND_HISTORY 32
typedef struct {
int cursor;
int scroll;
int widthInChars;
char buffer[MAX_EDIT_LINE];
} field_t;
typedef struct keyGlobals_s
{
field_t historyEditLines[COMMAND_HISTORY];
int nextHistoryLine; // the last line in the history buffer, not masked
int historyLine; // the line being displayed from history buffer
// will be <= nextHistoryLine
field_t g_consoleField;
qboolean anykeydown;
qboolean key_overstrikeMode;
int keyDownCount;
qkey_t keys[MAX_KEYS];
} keyGlobals_t;
typedef struct
{
word upper;
word lower;
char *name;
int keynum;
bool menukey;
} keyname_t;
extern keyGlobals_t kg;
extern keyname_t keynames[MAX_KEYS];
void Field_Clear( field_t *edit );
void Field_KeyDownEvent( field_t *edit, int key );
void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor );
void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor );
extern field_t chatField;
void Key_WriteBindings( fileHandle_t f );
void Key_SetBinding( int keynum, const char *binding );
char *Key_GetBinding( int keynum );
qboolean Key_IsDown( int keynum );
qboolean Key_GetOverstrikeMode( void );
void Key_SetOverstrikeMode( qboolean state );
void Key_ClearStates( void );

1165
code/client/snd_ambient.cpp Normal file

File diff suppressed because it is too large Load Diff

118
code/client/snd_ambient.h Normal file
View File

@@ -0,0 +1,118 @@
#ifndef __SND_AMBIENT__
#define __SND_AMBIENT__
// Includes
#pragma warning ( disable : 4786 )
#pragma warning ( disable : 4511 ) //copy constructor could not be gen
#pragma warning ( disable : 4512 ) //assign constructor could not be gen
//these don't work because stl re-sets them
//#pragma warning ( disable : 4663 ) //spcialize class
//#pragma warning ( disable : 4018 ) //signed/unsigned
#pragma warning (disable:4503) // decorated name length xceeded, name was truncated
#pragma warning (push, 3) //go back down to 3 for the stl include
#include "../qcommon/sstring.h" // #include <string>
#include <vector>
#include <map>
#pragma warning (pop)
#pragma warning (disable:4503) // decorated name length xceeded, name was truncated
using namespace std;
// Defines
#define AMBIENT_SET_FILENAME "sound/sound.txt"
const int MAX_WAVES_PER_GROUP = 8;
const int MAX_SET_NAME_LENGTH = 64;
// Enums
enum set_e
{
AS_SET_GENERAL, //General sets
AS_SET_LOCAL, //Local sets (regional)
AS_SET_BMODEL, //Brush model sets (doors, plats, etc.)
NUM_AS_SETS
};
enum setKeyword_e
{
SET_KEYWORD_TIMEBETWEENWAVES,
SET_KEYWORD_SUBWAVES,
SET_KEYWORD_LOOPEDWAVE,
SET_KEYWORD_VOLRANGE,
SET_KEYWORD_RADIUS,
SET_KEYWORD_TYPE,
SET_KEYWORD_AMSDIR,
SET_KEYWORD_OUTDIR,
SET_KEYWORD_BASEDIR,
NUM_AS_KEYWORDS,
};
// Structures
//NOTENOTE: Was going to make this a class, but don't want to muck around
typedef struct ambientSet_s
{
char name[MAX_SET_NAME_LENGTH];
unsigned char loopedVolume;
unsigned int time_start, time_end;
unsigned int volRange_start, volRange_end;
unsigned char numSubWaves;
int subWaves[MAX_WAVES_PER_GROUP];
int loopedWave;
int radius; //NOTENOTE: -1 is global
int masterVolume; //Used for fading ambient sets (not a byte to prevent wrapping)
int id; //Used for easier referencing of sets
int fadeTime; //When the fade was started on this set
} ambientSet_t;
typedef void (*parseFunc_t)( ambientSet_t & );
// Classes
//NOTENOTE: But this one should be a class because of all the mapping and internal data handling
class CSetGroup
{
public:
CSetGroup();
~CSetGroup();
void Init( void )
{
Free();
}
void Free( void );
ambientSet_t *AddSet( const char *name );
ambientSet_t *GetSet ( const char *name );
ambientSet_t *GetSet ( int ID );
protected:
int m_numSets;
vector < ambientSet_t * > *m_ambientSets;
map < sstring_t, ambientSet_t * > *m_setMap;
};
// Prototypes
extern void AS_Init( void );
extern void AS_Free( void );
extern void AS_ParseSets( void );
extern void AS_AddPrecacheEntry( const char *name );
extern void S_UpdateAmbientSet ( const char *name, vec3_t origin );
extern int S_AddLocalSet( const char *name, vec3_t origin, int time );
extern sfxHandle_t AS_GetBModelSound( const char *name, int stage );
#endif //__SND_AMBIENT__

6276
code/client/snd_dma.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

228
code/client/snd_local.h Normal file
View File

@@ -0,0 +1,228 @@
// snd_local.h -- private sound definations
#ifndef SND_LOCAL_H
#define SND_LOCAL_H
#include "../game/q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"
#include "../mp3code/mp3struct.h"
// Open AL Specific
#include "openal\al.h"
#include "openal\alc.h"
#include "eax\eax.h"
#include "eax\eaxman.h"
// Added for Open AL to know when to mute all sounds (e.g when app. loses focus)
void S_AL_MuteAllSounds(qboolean bMute);
//from SND_AMBIENT
extern void AS_Init( void );
extern void AS_Free( void );
#define PAINTBUFFER_SIZE 1024
// !!! if this is changed, the asm code must change !!!
typedef struct {
int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
int right;
} portable_samplepair_t;
// keep this enum in sync with the table "sSoundCompressionMethodStrings" -ste
//
typedef enum
{
ct_16 = 0, // formerly ct_NONE in EF1, now indicates 16-bit samples (the default)
ct_MP3,
//
ct_NUMBEROF // used only for array sizing
} SoundCompressionMethod_t;
typedef struct sfx_s {
short *pSoundData;
bool bDefaultSound; // couldn't be loaded, so use buzz
bool bInMemory; // not in Memory, set qtrue when loaded, and qfalse when its buffers are freed up because of being old, so can be reloaded
short iLastLevelUsedOn; // used for cacheing purposes
SoundCompressionMethod_t eSoundCompressionMethod;
MP3STREAM *pMP3StreamHeader; // NULL ptr unless this sfx_t is an MP3. Use Z_Malloc and Z_Free
int iSoundLengthInSamples; // length in samples, always kept as 16bit now so this is #shorts (watch for stereo later for music?)
char sSoundName[MAX_QPATH];
int iLastTimeUsed;
float fVolRange; // used to set the highest volume this sample has at load time - used for lipsynching
// Open AL
ALuint Buffer;
char *lipSyncData;
struct sfx_s *next; // only used because of hash table when registering
} sfx_t;
typedef struct {
int channels;
int samples; // mono samples in buffer
int submission_chunk; // don't mix less than this #
int samplebits;
int speed;
byte *buffer;
} dma_t;
#define START_SAMPLE_IMMEDIATE 0x7fffffff
// Open AL specific
typedef struct
{
ALuint BufferID;
ALuint Status;
char *Data;
} STREAMINGBUFFER;
#define NUM_STREAMING_BUFFERS 4
#define STREAMING_BUFFER_SIZE 4608 // 4 decoded MP3 frames
#define QUEUED 1
#define UNQUEUED 2
typedef struct
{
// back-indented fields new in TA codebase, will re-format when MP3 code finished -ste
// note: field missing in TA: qboolean loopSound; // from an S_AddLoopSound call, cleared each frame
//
int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
int entnum; // to allow overriding a specific sound
soundChannel_t entchannel; // to allow overriding a specific sound
int leftvol; // 0-255 volume after spatialization
int rightvol; // 0-255 volume after spatialization
int master_vol; // 0-255 volume before spatialization
vec3_t origin; // only use if fixed_origin is set
qboolean fixed_origin; // use origin instead of fetching entnum's origin
sfx_t *thesfx; // sfx structure
qboolean loopSound; // from an S_AddLoopSound call, cleared each frame
//
MP3STREAM MP3StreamHeader;
byte MP3SlidingDecodeBuffer[50000/*12000*/]; // typical back-request = -3072, so roughly double is 6000 (safety), then doubled again so the 6K pos is in the middle of the buffer)
int iMP3SlidingDecodeWritePos;
int iMP3SlidingDecodeWindowPos;
// Open AL specific
bool bLooping; // Signifies if this channel / source is playing a looping sound
// bool bAmbient; // Signifies if this channel / source is playing a looping ambient sound
bool bProcessed; // Signifies if this channel / source has been processed
bool bStreaming; // Set to true if the data needs to be streamed (MP3 or dialogue)
STREAMINGBUFFER buffers[NUM_STREAMING_BUFFERS]; // AL Buffers for streaming
ALuint alSource; // Open AL Source
bool bPlaying; // Set to true when a sound is playing on this channel / source
int iStartTime; // Time playback of Source begins
int lSlotID; // ID of Slot rendering Source's environment (enables a send to this FXSlot)
} channel_t;
#define WAV_FORMAT_PCM 1
#define WAV_FORMAT_ADPCM 2 // not actually implemented, but is the value that you get in a header
#define WAV_FORMAT_MP3 3 // not actually used this way, but just ensures we don't match one of the legit formats
typedef struct {
int format;
int rate;
int width;
int channels;
int samples;
int dataofs; // chunk starts this many bytes from file start
} wavinfo_t;
/*
====================================================================
SYSTEM SPECIFIC FUNCTIONS
====================================================================
*/
// initializes cycling through a DMA buffer and returns information on it
qboolean SNDDMA_Init(void);
// gets the current DMA position
int SNDDMA_GetDMAPos(void);
// shutdown the DMA xfer.
void SNDDMA_Shutdown(void);
void SNDDMA_BeginPainting (void);
void SNDDMA_Submit(void);
//====================================================================
#define MAX_CHANNELS 32
extern channel_t s_channels[MAX_CHANNELS];
extern int s_paintedtime;
extern int s_rawend;
extern vec3_t listener_origin;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern dma_t dma;
#define MAX_RAW_SAMPLES 16384
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
portable_samplepair_t *S_GetRawSamplePointer(); // TA added this, but it just returns the s_rawsamples[] array above. Oh well...
extern cvar_t *s_volume;
extern cvar_t *s_volumeVoice;
extern cvar_t *s_nosound;
extern cvar_t *s_khz;
extern cvar_t *s_allowDynamicMusic;
extern cvar_t *s_show;
extern cvar_t *s_mixahead;
extern cvar_t *s_testsound;
extern cvar_t *s_separation;
wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength);
qboolean S_LoadSound( sfx_t *sfx );
void S_PaintChannels(int endtime);
// picks a channel based on priorities, empty slots, number of channels
channel_t *S_PickChannel(int entnum, int entchannel);
// spatializes a channel
void S_Spatialize(channel_t *ch);
//////////////////////////////////
//
// new stuff from TA codebase
byte *SND_malloc(int iSize, sfx_t *sfx);
void SND_setup();
int SND_FreeOldestSound(sfx_t *pButNotThisOne = NULL);
void SND_TouchSFX(sfx_t *sfx);
void S_DisplayFreeMemory(void);
void S_memoryLoad(sfx_t *sfx);
//
//////////////////////////////////
#include "cl_mp3.h"
#endif // #ifndef SND_LOCAL_H

View File

@@ -0,0 +1,141 @@
// snd_local.h -- private sound definations
#ifndef SND_LOCAL_H
#define SND_LOCAL_H
// Following #define is ONLY for MP JKA code.
// They want to keep qboolean pure enum in that code, so all
// sound code uses sboolean.
#define sboolean int
#include "../game/q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"
#include "../mp3code/mp3struct.h"
#include "openal/al.h"
#include "openal/alc.h"
typedef int streamHandle_t;
//from SND_AMBIENT
extern void AS_Init( void );
extern void AS_Free( void );
//Changing this? It needs to be synced with the create_soundbank util.
enum SoundFilenameFlags
{
SFF_WEAPONS_ATST,
SFF_SAND_CREATURE,
SFF_HOWLER,
SFF_ALTCHARGE,
SFF_FALLING,
SFF_TIEEXPLODE,
//Can't have more than 8.
};
//Changing this? It needs to be synced with the create_soundbank util.
typedef struct {
int format;
int size;
int width;
int rate;
int samples;
} wavinfo_t;
extern wavinfo_t GetWavInfo(byte *data);
#define SFX_FLAG_UNLOADED (1 << 0)
#define SFX_FLAG_LOADING (1 << 1)
#define SFX_FLAG_RESIDENT (1 << 2)
#define SFX_FLAG_DEFAULT (1 << 3)
#define SFX_FLAG_DEMAND (1 << 4)
#define SFX_FLAG_VOICE (1 << 5)
typedef struct sfx_s {
int iFlags;
int iSoundLength; // length in bytes
int iLastTimeUsed; // last time sound was played in ms
unsigned int iFileCode; // CRC of the file name
streamHandle_t iStreamHandle; // handle to the sound file when reading
void* pSoundData; // buffer to hold sound as we are loading it
char* pLipSyncData; // buffer to hold lip sync information on characters
// store the total number of samples in the first 4 bytes
// followed by the actual lipsync data in the remaining bytes
ALuint Buffer;
//char* sSoundName; // added for debugging
} sfx_t;
typedef struct
{
int entnum; // to allow overriding a specific sound
int entchannel; // to allow overriding a specific sound
int master_vol; // 0-255 volume before spatialization
float fLastVolume; // 0-1 last volume sent to AL
vec3_t origin; // sound location
bool bOriginDirty; // does the AL position need to be updated
sfx_t *thesfx; // sfx structure
int loopChannel; // index into loopSounds (if appropriate)
bool bPlaying; // Set to true when a sound is playing on this channel / source
bool b2D; // Signifies a 2d sound
bool bLooping; // Signifies if this channel / source is playing a looping sound
ALuint alSource; // Open AL Source
unsigned int iLastPlayTime; // Last time a sound was played on this channel
} channel_t;
extern cvar_t *s_nosound;
extern cvar_t *s_allowDynamicMusic;
extern cvar_t *s_show;
extern cvar_t *s_testsound;
extern cvar_t *s_separation;
extern int* s_entityWavVol;
int Sys_GetFileCode( const char* sSoundName );
int S_GetFileCode( const char* sSoundName );
qboolean S_StartLoadSound( sfx_t *sfx );
qboolean S_EndLoadSound( sfx_t *sfx );
void S_InitLoad(void);
void S_CloseLoad(void);
void S_UpdateLoading(void);
// New stuff from VV
void S_LoadSound( sfxHandle_t sfxHandle );
// picks a channel based on priorities, empty slots, number of channels
channel_t *S_PickChannel(int entnum, int entchannel);
//////////////////////////////////
//
// new stuff from TA codebase
void SND_update(sfx_t *sfx);
void SND_setup();
int SND_FreeOldestSound(sfx_t *pButNotThisOne = NULL);
void SND_TouchSFX(sfx_t *sfx);
void S_DisplayFreeMemory(void);
void S_memoryLoad(sfx_t *sfx);
void S_PreProcessLipSync(sfx_t *sfx);
bool Sys_StreamIsReading(streamHandle_t handle);
int Sys_StreamOpen(int code, streamHandle_t *handle);
bool Sys_StreamRead(void* buffer, int size, int pos, streamHandle_t handle);
void Sys_StreamClose(streamHandle_t handle);
bool Sys_StreamIsError(streamHandle_t handle);
//
//////////////////////////////////
#endif // #ifndef SND_LOCAL_H

1015
code/client/snd_mem.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,368 @@
// snd_mem.c: sound caching
// leave this as first line for PCH reasons...
//
// #include "../server/exe_headers.h"
#include "snd_local_console.h"
#ifdef _XBOX
#include <xtl.h>
#endif
#define SND_MAX_LOADS 48
static sfx_t** s_LoadList = NULL;
static int s_LoadListSize = 0;
qboolean gbInsideLoadSound = qfalse; // Needed to link VVFIXME
extern int Sys_GetFileCode(const char *name);
//Drain sound main memory into ARAM.
void S_DrainRawSoundData(void)
{
extern int s_soundStarted;
if (!s_soundStarted) return;
do
{
S_UpdateLoading();
#ifdef _GAMECUBE
extern void ERR_DiscFail(bool);
ERR_DiscFail(true);
#endif
}
while (s_LoadListSize);
}
/*
============
GetWavInfo
============
*/
wavinfo_t GetWavInfo(byte *data)
{
wavinfo_t info;
memset(&info, 0, sizeof(wavinfo_t));
if (!data) return info;
#ifdef _GAMECUBE
if (*(short*)&data[14] != 0)
{
// invalid type, abort
return info;
}
info.format = AL_FORMAT_MONO4;
info.width = 4;
info.size = ((*(int*)&data[20]) >> 1) + 96;
info.rate = *(int*)&data[8];
#else
int dataofs = 0;
if (strncmp((char *)&data[dataofs + 0], "RIFF", 4) ||
strncmp((char *)&data[dataofs + 8], "WAVE", 4))
{
// invalid type, abort
return info;
}
dataofs += 12; // done with riff chunk
WAVEFORMATEX* wav = (WAVEFORMATEX*)&data[dataofs + 8];
info.format = wav->nChannels == 1 ? AL_FORMAT_MONO4 : AL_FORMAT_STEREO4;
info.rate = wav->nSamplesPerSec;
info.width = wav->wBitsPerSample;
dataofs += sizeof(WAVEFORMATEX) + wav->cbSize + 8; // done with fmt chunk
info.size = *(int*)&data[dataofs + 4];
info.samples = (info.size * 2);
dataofs += 8; // done with data chunk
#endif
return info;
}
// adjust filename for foreign languages and WAV/MP3 issues.
//
unsigned int Sys_GetSoundFileCode(const char* name);
int Sys_GetSoundFileCodeSize(unsigned int filecode);
static qboolean S_LoadSound_FileNameAdjuster(char *psFilename)
{
const char* ext = "wxb";
int len = strlen(psFilename);
char *psVoice = strstr(psFilename,"chars");
if (psVoice)
{
// account for foreign voices...
//
extern DWORD g_dwLanguage;
if (g_dwLanguage == XC_LANGUAGE_GERMAN)
strncpy(psVoice, "chr_d", 5); // Same number of letters as "chars"
else if (g_dwLanguage == XC_LANGUAGE_FRENCH)
strncpy(psVoice, "chr_f", 5); // Same number of letters as "chars"
else
psVoice = NULL; // Flag that we didn't substitute
}
psFilename[len-3] = ext[0];
psFilename[len-2] = ext[1];
psFilename[len-1] = ext[2];
for(int i = 0; i < len; i++)
{
if(psFilename[i] == '/')
{
psFilename[i] = '\\';
}
}
unsigned int code = Sys_GetSoundFileCode( psFilename );
if(Sys_GetSoundFileCodeSize(code) == -1)
{
code = -1;
}
if ( code == -1 )
{
//hmmm, not found, ok, maybe we were trying a foreign noise ("arghhhhh.mp3" that doesn't matter?) but it
// was missing? Can't tell really, since both types are now in sound/chars. Oh well, fall back to English for now...
if (psVoice) // were we trying to load foreign?
{
// yep, so fallback to re-try the english...
//
strncpy(psVoice,"chars",5);
psFilename[len-3] = ext[0];
psFilename[len-2] = ext[1];
psFilename[len-1] = ext[2];
code = Sys_GetSoundFileCode( psFilename );
}
}
if(Sys_GetSoundFileCodeSize(code) == -1)
{
code = -1;
}
return code;
}
/*
==============
S_GetFileCode
==============
*/
int S_GetFileCode( const char* sSoundName )
{
char sLoadName[MAX_QPATH];
// make up a local filename to try wav/mp3 substitutes...
//
Q_strncpyz(sLoadName, sSoundName, sizeof(sLoadName));
Q_strlwr( sLoadName );
// make sure we have an extension...
//
if (sLoadName[strlen(sLoadName) - 4] != '.')
{
strcat(sLoadName, ".xxx");
}
return S_LoadSound_FileNameAdjuster(sLoadName);
}
/*
============
S_UpdateLoading
============
*/
void S_UpdateLoading(void) {
for ( int i = 0; i < SND_MAX_LOADS; ++i )
{
if ( s_LoadList[i] &&
(s_LoadList[i]->iFlags & SFX_FLAG_LOADING) &&
!Sys_StreamIsReading(s_LoadList[i]->iStreamHandle) )
{
S_EndLoadSound(s_LoadList[i]);
s_LoadList[i] = NULL;
--s_LoadListSize;
}
}
}
/*
==============
S_BeginLoadSound
==============
*/
qboolean S_StartLoadSound( sfx_t *sfx )
{
assert(sfx->iFlags & SFX_FLAG_UNLOADED);
sfx->iFlags &= ~SFX_FLAG_UNLOADED;
// Valid file?
if (sfx->iFileCode == -1)
{
sfx->iFlags |= SFX_FLAG_RESIDENT | SFX_FLAG_DEFAULT;
return qfalse;
}
#if PROFILE_SOUND
extern char* Sys_GetSoundName( unsigned int crc );
char* name = Sys_GetSoundName(sfx->iFileCode);
int time = Sys_Milliseconds();
Com_Printf("SOUND: %s at %d\n", name, time);
#endif
// Finish up any pending loads
do
{
S_UpdateLoading();
}
while (s_LoadListSize >= SND_MAX_LOADS);
// Open the file
sfx->iSoundLength = Sys_StreamOpen(sfx->iFileCode, &sfx->iStreamHandle);
if ( sfx->iSoundLength <= 0 )
{
sfx->iFlags |= SFX_FLAG_RESIDENT | SFX_FLAG_DEFAULT;
return qfalse;
}
#ifdef _GAMECUBE
// Allocate a buffer to read into...
sfx->pSoundData = Z_Malloc(sfx->iSoundLength + 64, TAG_SND_RAWDATA,
qtrue, 32);
#else
// Allocate a buffer to read into...
sfx->pSoundData = Z_Malloc(sfx->iSoundLength, TAG_SND_RAWDATA, qtrue, 32);
#endif
// Setup the background read
if ( !sfx->pSoundData ||
!Sys_StreamRead(sfx->pSoundData, sfx->iSoundLength, 0,
sfx->iStreamHandle) )
{
if(sfx->pSoundData) {
Z_Free(sfx->pSoundData);
}
Sys_StreamClose(sfx->iStreamHandle);
sfx->iFlags |= SFX_FLAG_RESIDENT | SFX_FLAG_DEFAULT;
return qfalse;
}
sfx->iFlags |= SFX_FLAG_LOADING;
// add sound to load list
for (int i = 0; i < SND_MAX_LOADS; ++i)
{
if (!s_LoadList[i])
{
s_LoadList[i] = sfx;
++s_LoadListSize;
break;
}
}
return qtrue;
}
/*
==============
S_EndLoadSound
==============
*/
qboolean S_EndLoadSound( sfx_t *sfx )
{
wavinfo_t info;
byte* data;
ALuint Buffer;
assert(sfx->iFlags & SFX_FLAG_LOADING);
sfx->iFlags &= ~SFX_FLAG_LOADING;
// was the read successful?
if (Sys_StreamIsError(sfx->iStreamHandle))
{
#if defined(FINAL_BUILD)
extern void ERR_DiscFail(bool);
ERR_DiscFail(false);
#endif
Sys_StreamClose(sfx->iStreamHandle);
Z_Free(sfx->pSoundData);
sfx->iFlags |= SFX_FLAG_RESIDENT | SFX_FLAG_DEFAULT;
return qfalse;
}
Sys_StreamClose(sfx->iStreamHandle);
SND_TouchSFX(sfx);
sfx->iLastTimeUsed = Com_Milliseconds()+1; // why +1? Hmmm, leave it for now I guess
// loading a WAV, presumably...
data = (byte*)sfx->pSoundData;
info = GetWavInfo( data );
if (info.size == 0)
{
Z_Free(sfx->pSoundData);
sfx->iFlags |= SFX_FLAG_RESIDENT | SFX_FLAG_DEFAULT;
return qfalse;
}
sfx->iSoundLength = info.size;
// make sure we have enough space for the sound
SND_update(sfx);
// Clear Open AL Error State
alGetError();
// Generate AL Buffer
alGenBuffers(1, &Buffer);
// Copy audio data to AL Buffer
alBufferData(Buffer, info.format, data,
sfx->iSoundLength, info.rate);
if (alGetError() != AL_NO_ERROR)
{
Z_Free(sfx->pSoundData);
sfx->iFlags |= SFX_FLAG_UNLOADED;
return qfalse;
}
sfx->Buffer = Buffer;
#ifdef _GAMECUBE
Z_Free(sfx->pSoundData);
#endif
sfx->iFlags |= SFX_FLAG_RESIDENT;
return qtrue;
}
/*
============
S_InitLoad
============
*/
void S_InitLoad(void) {
s_LoadList = new sfx_t*[SND_MAX_LOADS];
memset(s_LoadList, 0, SND_MAX_LOADS * sizeof(sfx_t*));
s_LoadListSize = 0;
}
/*
============
S_CloseLoad
============
*/
void S_CloseLoad(void) {
delete [] s_LoadList;
}

471
code/client/snd_mix.cpp Normal file
View File

@@ -0,0 +1,471 @@
// snd_mix.c -- portable code to mix sounds for snd_dma.c
// leave this as first line for PCH reasons...
//
#include "../server/exe_headers.h"
#include "snd_local.h"
portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
int *snd_p, snd_linear_count, snd_vol;
short *snd_out;
#if !(defined __linux__ && defined __i386__)
#if !id386
void S_WriteLinearBlastStereo16 (void)
{
int i;
int val;
for (i=0 ; i<snd_linear_count ; i+=2)
{
val = snd_p[i]>>8;
if (val > 0x7fff)
snd_out[i] = 0x7fff;
else if (val < (short)0x8000)
snd_out[i] = (short)0x8000;
else
snd_out[i] = val;
val = snd_p[i+1]>>8;
if (val > 0x7fff)
snd_out[i+1] = 0x7fff;
else if (val < (short)0x8000)
snd_out[i+1] = (short)0x8000;
else
snd_out[i+1] = val;
}
}
#else
unsigned int uiMMXAvailable = 0; // leave as 32 bit
__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
{
__asm {
push edi
push ebx
mov ecx,ds:dword ptr[snd_linear_count] // snd_linear_count is always even at this point, but not nec. mult of 4
mov ebx,ds:dword ptr[snd_p]
mov edi,ds:dword ptr[snd_out]
cmp [uiMMXAvailable], dword ptr 0
je NoMMX
// writes 8 items (128 bits) per loop pass...
//
cmp ecx,8
jb NoMMX
LWLBLoopTop_MMX:
movq mm1,[-8+ebx+ecx*4]
movq mm0,[-16+ebx+ecx*4]
movq mm3,[-24+ebx+ecx*4]
movq mm2,[-32+ebx+ecx*4]
psrad mm0,8
psrad mm1,8
psrad mm2,8
psrad mm3,8
packssdw mm0,mm1
packssdw mm2,mm3
movq [-8+edi+ecx*2],mm0
movq [-16+edi+ecx*2],mm2
sub ecx,8
cmp ecx,8
jae LWLBLoopTop_MMX
emms
// now deal with any remaining count...
//
jecxz LExit
NoMMX:
// writes 2 items (32 bits) per loop pass...
//
LWLBLoopTop:
mov eax,ds:dword ptr[-8+ebx+ecx*4]
sar eax,8
cmp eax,07FFFh
jg LClampHigh
cmp eax,0FFFF8000h
jnl LClampDone
mov eax,0FFFF8000h
jmp LClampDone
LClampHigh:
mov eax,07FFFh
LClampDone:
mov edx,ds:dword ptr[-4+ebx+ecx*4]
sar edx,8
cmp edx,07FFFh
jg LClampHigh2
cmp edx,0FFFF8000h
jnl LClampDone2
mov edx,0FFFF8000h
jmp LClampDone2
LClampHigh2:
mov edx,07FFFh
LClampDone2:
shl edx,16
and eax,0FFFFh
or edx,eax
mov ds:dword ptr[-4+edi+ecx*2],edx
sub ecx,2
jnz LWLBLoopTop
LExit:
pop ebx
pop edi
ret
}
}
#endif
#endif
void S_TransferStereo16 (unsigned long *pbuf, int endtime)
{
int lpos;
int ls_paintedtime;
snd_p = (int *) paintbuffer;
ls_paintedtime = s_paintedtime;
while (ls_paintedtime < endtime)
{
// handle recirculating buffer issues
lpos = ls_paintedtime & ((dma.samples>>1)-1);
snd_out = (short *) pbuf + (lpos<<1);
snd_linear_count = (dma.samples>>1) - lpos;
if (ls_paintedtime + snd_linear_count > endtime)
snd_linear_count = endtime - ls_paintedtime;
snd_linear_count <<= 1;
// write a linear blast of samples
S_WriteLinearBlastStereo16 ();
snd_p += snd_linear_count;
ls_paintedtime += (snd_linear_count>>1);
}
}
/*
===================
S_TransferPaintBuffer
===================
*/
void S_TransferPaintBuffer(int endtime)
{
int out_idx;
int count;
int out_mask;
int *p;
int step;
int val;
unsigned long *pbuf;
pbuf = (unsigned long *)dma.buffer;
if ( s_testsound->integer ) {
int i;
int count;
// write a fixed sine wave
count = (endtime - s_paintedtime);
for (i=0 ; i<count ; i++)
paintbuffer[i].left = paintbuffer[i].right = (int)(sin((s_paintedtime+i)*0.1)*20000*256);
}
if (dma.samplebits == 16 && dma.channels == 2)
{ // optimized case
S_TransferStereo16 (pbuf, endtime);
}
else
{ // general case
p = (int *) paintbuffer;
count = (endtime - s_paintedtime) * dma.channels;
out_mask = dma.samples - 1;
out_idx = s_paintedtime * dma.channels & out_mask;
step = 3 - dma.channels;
if (dma.samplebits == 16)
{
short *out = (short *) pbuf;
while (count--)
{
val = *p >> 8;
p+= step;
if (val > 0x7fff)
val = 0x7fff;
else if (val < (short)0x8000)
val = (short)0x8000;
out[out_idx] = (short)val;
out_idx = (out_idx + 1) & out_mask;
}
}
else if (dma.samplebits == 8)
{
unsigned char *out = (unsigned char *) pbuf;
while (count--)
{
val = *p >> 8;
p+= step;
if (val > 0x7fff)
val = 0x7fff;
else if (val < (short)0x8000)
val = (short)0x8000;
out[out_idx] = (short)((val>>8) + 128);
out_idx = (out_idx + 1) & out_mask;
}
}
}
}
/*
===============================================================================
CHANNEL MIXING
===============================================================================
*/
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sfx, int count, int sampleOffset, int bufferOffset )
{
portable_samplepair_t *pSamplesDest;
int iData;
int iLeftVol = ch->leftvol * snd_vol;
int iRightVol = ch->rightvol * snd_vol;
pSamplesDest = &paintbuffer[ bufferOffset ];
for ( int i=0 ; i<count ; i++ )
{
iData = sfx->pSoundData[ sampleOffset++ ];
pSamplesDest[i].left += (iData * iLeftVol )>>8;
pSamplesDest[i].right += (iData * iRightVol)>>8;
}
}
void S_PaintChannelFromMP3( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset )
{
int data;
int leftvol, rightvol;
signed short *sfx;
int i;
portable_samplepair_t *samp;
static short tempMP3Buffer[PAINTBUFFER_SIZE];
MP3Stream_GetSamples( ch, sampleOffset, count, tempMP3Buffer, qfalse ); // qfalse = not stereo
leftvol = ch->leftvol*snd_vol;
rightvol = ch->rightvol*snd_vol;
sfx = tempMP3Buffer;
samp = &paintbuffer[ bufferOffset ];
while ( count & 3 ) {
data = *sfx;
samp->left += (data * leftvol)>>8;
samp->right += (data * rightvol)>>8;
sfx++;
samp++;
count--;
}
for ( i=0 ; i<count ; i += 4 ) {
data = sfx[i];
samp[i].left += (data * leftvol)>>8;
samp[i].right += (data * rightvol)>>8;
data = sfx[i+1];
samp[i+1].left += (data * leftvol)>>8;
samp[i+1].right += (data * rightvol)>>8;
data = sfx[i+2];
samp[i+2].left += (data * leftvol)>>8;
samp[i+2].right += (data * rightvol)>>8;
data = sfx[i+3];
samp[i+3].left += (data * leftvol)>>8;
samp[i+3].right += (data * rightvol)>>8;
}
}
// subroutinised to save code dup (called twice) -ste
//
void ChannelPaint(channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset)
{
switch (sc->eSoundCompressionMethod)
{
case ct_16:
S_PaintChannelFrom16 (ch, sc, count, sampleOffset, bufferOffset);
break;
case ct_MP3:
S_PaintChannelFromMP3 (ch, sc, count, sampleOffset, bufferOffset);
break;
default:
assert(0); // debug aid, ignored in release. FIXME: Should we ERR_DROP here for badness-catch?
break;
}
}
void S_PaintChannels( int endtime ) {
int i;
int end;
channel_t *ch;
sfx_t *sc;
int ltime, count;
int sampleOffset;
int normal_vol,voice_vol;
snd_vol = normal_vol = s_volume->value*256.0f;
voice_vol = (s_volumeVoice->value*256.0f);
//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
while ( s_paintedtime < endtime ) {
// if paintbuffer is smaller than DMA buffer
// we may need to fill it multiple times
end = endtime;
if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
end = s_paintedtime + PAINTBUFFER_SIZE;
}
// clear the paint buffer to either music or zeros
if ( s_rawend < s_paintedtime ) {
if ( s_rawend ) {
//Com_DPrintf ("background sound underrun\n");
}
memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
} else {
// copy from the streaming sound source
int s;
int stop;
stop = (end < s_rawend) ? end : s_rawend;
for ( i = s_paintedtime ; i < stop ; i++ ) {
s = i&(MAX_RAW_SAMPLES-1);
paintbuffer[i-s_paintedtime] = s_rawsamples[s];
}
// if (i != end)
// Com_Printf ("partial stream\n");
// else
// Com_Printf ("full stream\n");
for ( ; i < end ; i++ ) {
paintbuffer[i-s_paintedtime].left =
paintbuffer[i-s_paintedtime].right = 0;
}
}
// paint in the channels.
ch = s_channels;
for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
continue;
}
if ( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_VOICE_ATTEN || ch->entchannel == CHAN_VOICE_GLOBAL )
snd_vol = voice_vol;
else
snd_vol = normal_vol;
ltime = s_paintedtime;
sc = ch->thesfx;
// we might have to make 2 passes if it is
// a looping sound effect and the end of
// the sameple is hit...
//
do
{
if (ch->loopSound) {
sampleOffset = ltime % sc->iSoundLengthInSamples;
} else {
sampleOffset = ltime - ch->startSample;
}
count = end - ltime;
if ( sampleOffset + count > sc->iSoundLengthInSamples ) {
count = sc->iSoundLengthInSamples - sampleOffset;
}
if ( count > 0 ) {
ChannelPaint(ch, sc, count, sampleOffset, ltime - s_paintedtime);
ltime += count;
}
} while ( ltime < end && ch->loopSound );
}
/* temprem
// paint in the looped channels.
ch = loop_channels;
for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
continue;
}
{
ltime = s_paintedtime;
sc = ch->thesfx;
if (sc->soundData==NULL || sc->soundLength==0) {
continue;
}
// we might have to make two passes if it
// is a looping sound effect and the end of
// the sample is hit
do {
sampleOffset = (ltime % sc->soundLength);
count = end - ltime;
if ( sampleOffset + count > sc->soundLength ) {
count = sc->soundLength - sampleOffset;
}
if ( count > 0 )
{
ChannelPaint(ch, sc, count, sampleOffset, ltime - s_paintedtime);
ltime += count;
}
} while ( ltime < end);
}
}
*/
// transfer out according to DMA format
S_TransferPaintBuffer( end );
s_paintedtime = end;
}
}

1155
code/client/snd_music.cpp Normal file

File diff suppressed because it is too large Load Diff

67
code/client/snd_music.h Normal file
View File

@@ -0,0 +1,67 @@
// Filename:- snd_music.h
//
//
#ifndef SND_MUSIC_H
#define SND_MUSIC_H
// if you change this enum, you MUST update the #defines below
typedef enum
{
//( eBGRNDTRACK_DATABEGIN ) // begin-label for FOR loops
//
eBGRNDTRACK_EXPLORE = 0, // for normal walking around
eBGRNDTRACK_ACTION, // for excitement
eBGRNDTRACK_BOSS, // (optional) for final encounter
eBGRNDTRACK_DEATH, // (optional) death "flourish"
eBGRNDTRACK_ACTIONTRANS0, // transition from action to explore
eBGRNDTRACK_ACTIONTRANS1, // "
eBGRNDTRACK_ACTIONTRANS2, // "
eBGRNDTRACK_ACTIONTRANS3, // "
eBGRNDTRACK_EXPLORETRANS0, // transition from explore to silence
eBGRNDTRACK_EXPLORETRANS1, // "
eBGRNDTRACK_EXPLORETRANS2, // "
eBGRNDTRACK_EXPLORETRANS3, // "
//
//( eBGRNDTRACK_DATAEND ), // tracks from this point on are for logic or copies, do NOT free them.
//
eBGRNDTRACK_NONDYNAMIC, // used for when music is just streaming, not part of dynamic stuff (used to be defined as same as explore entry, but this allows playing music in between 2 invokations of the same dynamic music without midleve reload, and also faster level transitioning if two consecutive dynamic sections use same DMS.DAT entries. Are you still reading this far?
eBGRNDTRACK_SILENCE, // silence (more of a logic thing than an actual track at the moment)
eBGRNDTRACK_FADE, // the xfade channel
//
eBGRNDTRACK_NUMBEROF
} MusicState_e;
#define iMAX_ACTION_TRANSITIONS 4 // these can be increased easily enough, I just need to know about them
#define iMAX_EXPLORE_TRANSITIONS 4 //
#define eBGRNDTRACK_DATABEGIN eBGRNDTRACK_EXPLORE // label for FOR() loops (not in enum, else debugger shows in instead of the explore one unless I declare them backwards, which is gay)
#define eBGRNDTRACK_DATAEND eBGRNDTRACK_NONDYNAMIC // tracks from this point on are for logic or copies, do NOT free them.
#define eBGRNDTRACK_FIRSTTRANSITION eBGRNDTRACK_ACTIONTRANS0 // used for "are we in transition mode" check
#define eBGRNDTRACK_LASTTRANSITION eBGRNDTRACK_EXPLORETRANS3 //
void Music_SetLevelName ( const char *psLevelName );
qboolean Music_DynamicDataAvailable ( const char *psDynamicMusicLabel );
const char *Music_GetFileNameForState ( MusicState_e eMusicState );
qboolean Music_StateIsTransition ( MusicState_e eMusicState );
qboolean Music_StateCanBeInterrupted ( MusicState_e eMusicState, MusicState_e eProposedMusicState );
float Music_GetRandomEntryTime ( MusicState_e eMusicState );
#ifdef MP3STUFF_KNOWN
qboolean Music_AllowedToTransition ( float fPlayingTimeElapsed, MusicState_e eMusicState, MusicState_e *peTransition = NULL, float *pfNewTrackEntryTime = NULL);
#endif
const char *Music_BaseStateToString ( MusicState_e eMusicState, qboolean bDebugPrintQuery = qfalse);
#endif // #ifndef SND_MUSIC_H
//////////////// eof /////////////////

59
code/client/snd_public.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef _SND_PUBLIC_H
#define _SND_PUBLIC_H
#ifndef FINAL_BUILD
#define PROFILE_SOUND 0
#endif
void S_Init( void );
void S_Shutdown( void );
// if origin is NULL, the sound will be dynamically sourced from the entity
void S_AddAmbientLoopingSound( const vec3_t origin, unsigned char volume, sfxHandle_t sfxHandle );
void S_StartAmbientSound( const vec3_t origin, int entityNum, unsigned char volume, sfxHandle_t sfxHandle );
void S_StartSound( const vec3_t origin, int entnum, soundChannel_t entchannel, sfxHandle_t sfx );
void S_StartLocalSound( sfxHandle_t sfx, int channelNum );
void S_StartLocalLoopingSound( sfxHandle_t sfx);
void S_UnCacheDynamicMusic( void );
void S_RestartMusic( void );
void S_StartBackgroundTrack( const char *intro, const char *loop, qboolean bCalledByCGameStart );
void S_StopBackgroundTrack( void );
float S_GetSampleLengthInMilliSeconds( sfxHandle_t sfxHandle);
// cinematics and voice-over-network will send raw samples
// 1.0 volume will be direct output of source samples
void S_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume, qboolean bFirstOrOnlyUpdateThisFrame );
// stop all sounds
void S_StopSounds(void); // from snd_dma.cpp
// stop all sounds and the background track
void S_StopAllSounds( void );
// scan all MP3s in the sound dir and add maxvol info if necessary.
void S_MP3_CalcVols_f( void );
// all continuous looping sounds must be added before calling S_Update
void S_ClearLoopingSounds( void );
void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, soundChannel_t chan = CHAN_AUTO );
// recompute the reletive volumes for all running sounds
// relative to the given entityNum / orientation
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], qboolean inwater );
// let the sound system know where an entity currently is
void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
void S_Update( void );
void S_DisableSounds( void );
void S_BeginRegistration( void );
// RegisterSound will allways return a valid sample, even if it
// has to create a placeholder. This prevents continuous filesystem
// checks for missing files
sfxHandle_t S_RegisterSound( const char *sample );
void S_FreeAllSFXMem(void);
#endif

39
code/client/vmachine.cpp Normal file
View File

@@ -0,0 +1,39 @@
// vmachine.cpp -- wrapper to fake virtual machine for client
#include "vmachine.h"
#pragma warning (disable : 4514)
/*
==============================================================
VIRTUAL MACHINE
==============================================================
*/
int VM_Call( int callnum, ... )
{
// assert (cgvm.entryPoint);
if (cgvm.entryPoint)
{
return cgvm.entryPoint( (&callnum)[0], (&callnum)[1], (&callnum)[2], (&callnum)[3],
(&callnum)[4], (&callnum)[5], (&callnum)[6], (&callnum)[7],
(&callnum)[8], (&callnum)[9] );
}
return -1;
}
/*
============
VM_DllSyscall
we pass this to the cgame dll to call back into the client
============
*/
extern int CL_CgameSystemCalls( int *args );
extern int CL_UISystemCalls( int *args );
int VM_DllSyscall( int arg, ... ) {
// return cgvm->systemCall( &arg );
return CL_CgameSystemCalls( &arg );
}

93
code/client/vmachine.h Normal file
View File

@@ -0,0 +1,93 @@
// vmachine.h -- virtual machine header for client
#ifndef __VMACHINE_H__
#define __VMACHINE_H__
/*
==================================================================
functions exported to the main executable
==================================================================
*/
typedef enum {
CG_INIT,
CG_SHUTDOWN,
CG_CONSOLE_COMMAND,
CG_DRAW_ACTIVE_FRAME,
CG_CROSSHAIR_PLAYER,
CG_CAMERA_POS,
CG_CAMERA_ANG,
/*
Ghoul2 Insert Start
*/
CG_RESIZE_G2_BOLT,
CG_RESIZE_G2,
CG_RESIZE_G2_BONE,
CG_RESIZE_G2_SURFACE,
CG_RESIZE_G2_TEMPBONE,
/*
Ghoul2 Insert End
*/
CG_DRAW_DATAPAD_HUD,
CG_DRAW_DATAPAD_OBJECTIVES,
CG_DRAW_DATAPAD_WEAPONS,
CG_DRAW_DATAPAD_INVENTORY,
CG_DRAW_DATAPAD_FORCEPOWERS
} cgameExport_t;
/*
==============================================================
VIRTUAL MACHINE
==============================================================
*/
struct vm_s {
int (*entryPoint)( int callNum, ... );
};
typedef struct vm_s vm_t;
extern vm_t cgvm; // interface to cgame dll or vm
extern vm_t uivm; // interface to ui dll or vm
extern int VM_Call( int callnum, ... );
extern int VM_DllSyscall( int arg, ... );
extern void CL_ShutdownCGame(void);
#include "../game/q_shared.h"
/*
================
VM_Create
it will attempt to load as a system dll
================
*/
extern void *Sys_LoadCgame( int (**entryPoint)(int, ...), int (*systemcalls)(int, ...) );
inline void *VM_Create( const char *module)
{
void *res;
// try to load as a system dll
if (!Q_stricmp("cl", module))
{
res = Sys_LoadCgame( &cgvm.entryPoint, VM_DllSyscall );
if ( !res)
{
//Com_Printf( "Failed.\n" );
return 0;
}
}
else
{
res = 0;
}
return res;
}
#endif //__VMACHINE_H__