summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/cl_avi.c619
-rw-r--r--src/client/cl_main.c143
-rw-r--r--src/client/client.h12
-rw-r--r--src/client/snd_dma.c6
-rw-r--r--src/client/snd_main.c4
-rw-r--r--src/client/snd_mix.c4
-rw-r--r--src/qcommon/common.c310
-rw-r--r--src/qcommon/files.c92
-rw-r--r--src/qcommon/md4.c5
-rw-r--r--src/qcommon/q_shared.h5
-rw-r--r--src/qcommon/qcommon.h4
-rw-r--r--src/renderer/tr_backend.c3
-rw-r--r--src/renderer/tr_cmds.c27
-rw-r--r--src/renderer/tr_image.c58
-rw-r--r--src/renderer/tr_init.c47
-rw-r--r--src/renderer/tr_local.h18
-rw-r--r--src/renderer/tr_public.h3
-rw-r--r--src/unix/Makefile360
-rw-r--r--src/unix/ftola.s2
-rw-r--r--src/unix/linux_common.c347
20 files changed, 1033 insertions, 1036 deletions
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c
new file mode 100644
index 00000000..4a372d8b
--- /dev/null
+++ b/src/client/cl_avi.c
@@ -0,0 +1,619 @@
+/*
+===========================================================================
+Copyright (C) 2005-2006 Tim Angus
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_local.h"
+
+#define MAX_RIFF_CHUNKS 16
+
+typedef struct audioFormat_s
+{
+ int rate;
+ int format;
+ int channels;
+ int bits;
+
+ int sampleSize;
+ int totalBytes;
+} audioFormat_t;
+
+typedef struct aviFileData_s
+{
+ qboolean fileOpen;
+ fileHandle_t f;
+ char fileName[ MAX_QPATH ];
+ int fileSize;
+ int moviOffset;
+ int moviSize;
+
+ fileHandle_t idxF;
+ int numIndices;
+
+ int frameRate;
+ int framePeriod;
+ int width, height;
+ int numVideoFrames;
+ int maxRecordSize;
+ qboolean motionJpeg;
+
+ qboolean audio;
+ audioFormat_t a;
+ int numAudioFrames;
+
+ int chunkStack[ MAX_RIFF_CHUNKS ];
+ int chunkStackTop;
+
+ byte *cBuffer, *eBuffer;
+} aviFileData_t;
+
+static aviFileData_t afd;
+
+#define MAX_AVI_BUFFER 2048
+
+static byte buffer[ MAX_AVI_BUFFER ];
+static int bufIndex;
+
+/*
+===============
+SafeFS_Write
+===============
+*/
+static ID_INLINE void SafeFS_Write( const void *buffer, int len, fileHandle_t f )
+{
+ if( FS_Write( buffer, len, f ) < len )
+ Com_Error( ERR_DROP, "Failed to write avi file\n" );
+}
+
+/*
+===============
+WRITE_STRING
+===============
+*/
+static ID_INLINE void WRITE_STRING( const char *s )
+{
+ Com_Memcpy( &buffer[ bufIndex ], s, strlen( s ) );
+ bufIndex += strlen( s );
+}
+
+/*
+===============
+WRITE_4BYTES
+===============
+*/
+static ID_INLINE void WRITE_4BYTES( int x )
+{
+ buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
+ buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
+ buffer[ bufIndex + 2 ] = (byte)( ( x >> 16 ) & 0xFF );
+ buffer[ bufIndex + 3 ] = (byte)( ( x >> 24 ) & 0xFF );
+ bufIndex += 4;
+}
+
+/*
+===============
+WRITE_2BYTES
+===============
+*/
+static ID_INLINE void WRITE_2BYTES( int x )
+{
+ buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
+ buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
+ bufIndex += 2;
+}
+
+/*
+===============
+WRITE_1BYTES
+===============
+*/
+static ID_INLINE void WRITE_1BYTES( int x )
+{
+ buffer[ bufIndex ] = x;
+ bufIndex += 1;
+}
+
+/*
+===============
+START_CHUNK
+===============
+*/
+static ID_INLINE void START_CHUNK( const char *s )
+{
+ if( afd.chunkStackTop == MAX_RIFF_CHUNKS )
+ {
+ Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached\n" );
+ }
+
+ afd.chunkStack[ afd.chunkStackTop ] = bufIndex;
+ afd.chunkStackTop++;
+ WRITE_STRING( s );
+ WRITE_4BYTES( 0 );
+}
+
+/*
+===============
+END_CHUNK
+===============
+*/
+static ID_INLINE void END_CHUNK( void )
+{
+ int endIndex = bufIndex;
+
+ if( afd.chunkStackTop <= 0 )
+ {
+ Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached\n" );
+ }
+
+ afd.chunkStackTop--;
+ bufIndex = afd.chunkStack[ afd.chunkStackTop ];
+ bufIndex += 4;
+ WRITE_4BYTES( endIndex - bufIndex - 1 );
+ bufIndex = endIndex;
+ bufIndex = PAD( bufIndex, 2 );
+}
+
+/*
+===============
+CL_WriteAVIHeader
+===============
+*/
+void CL_WriteAVIHeader( void )
+{
+ bufIndex = 0;
+ afd.chunkStackTop = 0;
+
+ START_CHUNK( "RIFF" );
+ {
+ WRITE_STRING( "AVI " );
+ {
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "hdrl" );
+ WRITE_STRING( "avih" );
+ WRITE_4BYTES( 56 ); //"avih" "chunk" size
+ WRITE_4BYTES( afd.framePeriod ); //dwMicroSecPerFrame
+ WRITE_4BYTES( afd.maxRecordSize *
+ afd.frameRate ); //dwMaxBytesPerSec
+ WRITE_4BYTES( 0 ); //dwReserved1
+ WRITE_4BYTES( 0x110 ); //dwFlags bits HAS_INDEX and IS_INTERLEAVED
+ WRITE_4BYTES( afd.numVideoFrames ); //dwTotalFrames
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ if( afd.audio ) //dwStreams
+ WRITE_4BYTES( 2 );
+ else
+ WRITE_4BYTES( 1 );
+
+ WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
+ WRITE_4BYTES( afd.width ); //dwWidth
+ WRITE_4BYTES( afd.height ); //dwHeight
+ WRITE_4BYTES( 0 ); //dwReserved[ 0 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 1 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 2 ]
+ WRITE_4BYTES( 0 ); //dwReserved[ 3 ]
+
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "strl" );
+ WRITE_STRING( "strh" );
+ WRITE_4BYTES( 56 ); //"strh" "chunk" size
+ WRITE_STRING( "vids" );
+
+ if( afd.motionJpeg )
+ WRITE_STRING( "MJPG" );
+ else
+ WRITE_STRING( " BGR" );
+
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( 0 ); //dwPriority
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ WRITE_4BYTES( 1 ); //dwTimescale
+ WRITE_4BYTES( afd.frameRate ); //dwDataRate
+ WRITE_4BYTES( 0 ); //dwStartTime
+ WRITE_4BYTES( afd.numVideoFrames ); //dwDataLength
+
+ WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
+ WRITE_4BYTES( -1 ); //dwQuality
+ WRITE_4BYTES( 0 ); //dwSampleSize
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( afd.width ); //rcFrame
+ WRITE_2BYTES( afd.height ); //rcFrame
+
+ WRITE_STRING( "strf" );
+ WRITE_4BYTES( 40 ); //"strf" "chunk" size
+ WRITE_4BYTES( 40 ); //biSize
+ WRITE_4BYTES( afd.width ); //biWidth
+ WRITE_4BYTES( afd.height ); //biHeight
+ WRITE_2BYTES( 1 ); //biPlanes
+ WRITE_2BYTES( 24 ); //biBitCount
+
+ if( afd.motionJpeg ) //biCompression
+ WRITE_STRING( "MJPG" );
+ else
+ WRITE_STRING( " BGR" );
+
+ WRITE_4BYTES( afd.width *
+ afd.height ); //biSizeImage
+ WRITE_4BYTES( 0 ); //biXPelsPetMeter
+ WRITE_4BYTES( 0 ); //biYPelsPetMeter
+ WRITE_4BYTES( 0 ); //biClrUsed
+ WRITE_4BYTES( 0 ); //biClrImportant
+ }
+ END_CHUNK( );
+
+ if( afd.audio )
+ {
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "strl" );
+ WRITE_STRING( "strh" );
+ WRITE_4BYTES( 56 ); //"strh" "chunk" size
+ WRITE_STRING( "auds" );
+ WRITE_4BYTES( 0 ); //FCC
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( 0 ); //dwPriority
+ WRITE_4BYTES( 0 ); //dwInitialFrame
+
+ WRITE_4BYTES( afd.a.sampleSize ); //dwTimescale
+ WRITE_4BYTES( afd.a.sampleSize *
+ afd.a.rate ); //dwDataRate
+ WRITE_4BYTES( 0 ); //dwStartTime
+ WRITE_4BYTES( afd.a.totalBytes /
+ afd.a.sampleSize ); //dwDataLength
+
+ WRITE_4BYTES( 0 ); //dwSuggestedBufferSize
+ WRITE_4BYTES( -1 ); //dwQuality
+ WRITE_4BYTES( afd.a.sampleSize ); //dwSampleSize
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+ WRITE_2BYTES( 0 ); //rcFrame
+
+ WRITE_STRING( "strf" );
+ WRITE_4BYTES( 18 ); //"strf" "chunk" size
+ WRITE_2BYTES( afd.a.format ); //wFormatTag
+ WRITE_2BYTES( afd.a.channels ); //nChannels
+ WRITE_4BYTES( afd.a.rate ); //nSamplesPerSec
+ WRITE_4BYTES( afd.a.sampleSize *
+ afd.a.rate ); //nAvgBytesPerSec
+ WRITE_2BYTES( afd.a.sampleSize ); //nBlockAlign
+ WRITE_2BYTES( afd.a.bits ); //wBitsPerSample
+ WRITE_2BYTES( 0 ); //cbSize
+ }
+ END_CHUNK( );
+ }
+ }
+ END_CHUNK( );
+
+ afd.moviOffset = bufIndex;
+
+ START_CHUNK( "LIST" );
+ {
+ WRITE_STRING( "movi" );
+ }
+ }
+ }
+}
+
+/*
+===============
+CL_OpenAVIForWriting
+
+Creates an AVI file and gets it into a state where
+writing the actual data can begin
+===============
+*/
+qboolean CL_OpenAVIForWriting( const char *fileName )
+{
+ if( afd.fileOpen )
+ return qfalse;
+
+ Com_Memset( &afd, 0, sizeof( aviFileData_t ) );
+
+ // Don't start if a framerate has not been chosen
+ if( cl_avidemo->integer <= 0 )
+ {
+ Com_Printf( S_COLOR_RED "cl_avidemo must be >= 1\n" );
+ return qfalse;
+ }
+
+ if( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 )
+ return qfalse;
+
+ if( ( afd.idxF = FS_FOpenFileWrite( va( "%s.idx", fileName ) ) ) <= 0 )
+ {
+ FS_FCloseFile( afd.f );
+ return qfalse;
+ }
+
+ Q_strncpyz( afd.fileName, fileName, MAX_QPATH );
+
+ afd.frameRate = cl_avidemo->integer;
+ afd.framePeriod = (int)( 1000000.0f / afd.frameRate );
+ afd.width = cls.glconfig.vidWidth;
+ afd.height = cls.glconfig.vidHeight;
+
+ if( cl_aviMotionJpeg->integer )
+ afd.motionJpeg = qtrue;
+ else
+ afd.motionJpeg = qfalse;
+
+ afd.cBuffer = Z_Malloc( afd.width * afd.height * 4 );
+ afd.eBuffer = Z_Malloc( afd.width * afd.height * 4 );
+
+ afd.a.rate = dma.speed;
+ afd.a.format = WAV_FORMAT_PCM;
+ afd.a.channels = dma.channels;
+ afd.a.bits = dma.samplebits;
+ afd.a.sampleSize = ( afd.a.bits / 8 ) * afd.a.channels;
+
+ if( afd.a.rate % afd.frameRate )
+ {
+ int suggestRate = afd.frameRate;
+
+ while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 )
+ suggestRate--;
+
+ Com_Printf( S_COLOR_YELLOW "WARNING: cl_avidemo is not a divisor "
+ "of the audio rate, suggest %d\n", suggestRate );
+ }
+
+ if( !Cvar_VariableIntegerValue( "s_initsound" ) )
+ {
+ afd.audio = qfalse;
+ }
+ else if( Q_stricmp( Cvar_VariableString( "s_backend" ), "OpenAL" ) )
+ {
+ if( afd.a.bits == 16 && afd.a.channels == 2 )
+ afd.audio = qtrue;
+ else
+ afd.audio = qfalse; //FIXME: audio not implemented for this case
+ }
+ else
+ {
+ afd.audio = qfalse;
+ Com_Printf( S_COLOR_YELLOW "WARNING: Audio capture is not supported "
+ "with OpenAL. Set s_useOpenAL to 0 for audio capture\n" );
+ }
+
+ // This doesn't write a real header, but allocates the
+ // correct amount of space at the beginning of the file
+ CL_WriteAVIHeader( );
+
+ SafeFS_Write( buffer, bufIndex, afd.f );
+ afd.fileSize = bufIndex;
+
+ bufIndex = 0;
+ START_CHUNK( "idx1" );
+ SafeFS_Write( buffer, bufIndex, afd.idxF );
+
+ afd.moviSize = 4; // For the "movi"
+ afd.fileOpen = qtrue;
+
+ return qtrue;
+}
+
+/*
+===============
+CL_WriteAVIVideoFrame
+===============
+*/
+void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size )
+{
+ int chunkOffset = afd.fileSize - afd.moviOffset - 8;
+ int chunkSize = 8 + size;
+ int paddingSize = PAD( size, 2 ) - size;
+ byte padding[ 4 ] = { 0 };
+
+ if( !afd.fileOpen )
+ return;
+
+ bufIndex = 0;
+ WRITE_STRING( "00dc" );
+ WRITE_4BYTES( size );
+
+ SafeFS_Write( buffer, 8, afd.f );
+ SafeFS_Write( imageBuffer, size, afd.f );
+ SafeFS_Write( padding, paddingSize, afd.f );
+ afd.fileSize += ( chunkSize + paddingSize );
+
+ afd.numVideoFrames++;
+ afd.moviSize += ( chunkSize + paddingSize );
+
+ if( size > afd.maxRecordSize )
+ afd.maxRecordSize = size;
+
+ // Index
+ bufIndex = 0;
+ WRITE_STRING( "00dc" ); //dwIdentifier
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( chunkOffset ); //dwOffset
+ WRITE_4BYTES( size ); //dwLength
+ SafeFS_Write( buffer, 16, afd.idxF );
+
+ afd.numIndices++;
+}
+
+#define PCM_BUFFER_SIZE 44100
+
+/*
+===============
+CL_WriteAVIAudioFrame
+===============
+*/
+void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size )
+{
+ static byte pcmCaptureBuffer[ PCM_BUFFER_SIZE ] = { 0 };
+ static int bytesInBuffer = 0;
+
+ if( !afd.audio )
+ return;
+
+ if( !afd.fileOpen )
+ return;
+
+ if( bytesInBuffer + size > PCM_BUFFER_SIZE )
+ {
+ Com_Printf( S_COLOR_YELLOW
+ "WARNING: Audio capture buffer overflow -- truncating\n" );
+ size = PCM_BUFFER_SIZE - bytesInBuffer;
+ }
+
+ Com_Memcpy( &pcmCaptureBuffer[ bytesInBuffer ], pcmBuffer, size );
+ bytesInBuffer += size;
+
+ // Only write if we have a frame's worth of audio
+ if( bytesInBuffer >= (int)ceil( afd.a.rate / cl_avidemo->value ) *
+ afd.a.sampleSize )
+ {
+ int chunkOffset = afd.fileSize - afd.moviOffset - 8;
+ int chunkSize = 8 + bytesInBuffer;
+ int paddingSize = PAD( bytesInBuffer, 2 ) - bytesInBuffer;
+ byte padding[ 4 ] = { 0 };
+
+ bufIndex = 0;
+ WRITE_STRING( "01wb" );
+ WRITE_4BYTES( bytesInBuffer );
+
+ SafeFS_Write( buffer, 8, afd.f );
+ SafeFS_Write( pcmBuffer, bytesInBuffer, afd.f );
+ SafeFS_Write( padding, paddingSize, afd.f );
+ afd.fileSize += ( chunkSize + paddingSize );
+
+ afd.numAudioFrames++;
+ afd.moviSize += ( chunkSize + paddingSize );
+ afd.a.totalBytes =+ bytesInBuffer;
+
+ // Index
+ bufIndex = 0;
+ WRITE_STRING( "01wb" ); //dwIdentifier
+ WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( chunkOffset ); //dwOffset
+ WRITE_4BYTES( bytesInBuffer ); //dwLength
+ SafeFS_Write( buffer, 16, afd.idxF );
+
+ afd.numIndices++;
+
+ bytesInBuffer = 0;
+ }
+}
+
+/*
+===============
+CL_TakeVideoFrame
+===============
+*/
+void CL_TakeVideoFrame( void )
+{
+ // AVI file isn't open
+ if( !afd.fileOpen )
+ return;
+
+ re.TakeVideoFrame( afd.width, afd.height,
+ afd.cBuffer, afd.eBuffer, afd.motionJpeg );
+}
+
+/*
+===============
+CL_CloseAVI
+
+Closes the AVI file and writes an index chunk
+===============
+*/
+qboolean CL_CloseAVI( void )
+{
+ int indexRemainder;
+ int indexSize = afd.numIndices * 16;
+ const char *idxFileName = va( "%s.idx", afd.fileName );
+
+ // AVI file isn't open
+ if( !afd.fileOpen )
+ return qfalse;
+
+ afd.fileOpen = qfalse;
+
+ FS_Seek( afd.idxF, 4, FS_SEEK_SET );
+ bufIndex = 0;
+ WRITE_4BYTES( indexSize );
+ SafeFS_Write( buffer, bufIndex, afd.idxF );
+ FS_FCloseFile( afd.idxF );
+
+ // Write index
+
+ // Open the temp index file
+ if( ( indexSize = FS_FOpenFileRead( idxFileName,
+ &afd.idxF, qtrue ) ) <= 0 )
+ {
+ FS_FCloseFile( afd.f );
+ return qfalse;
+ }
+
+ indexRemainder = indexSize;
+
+ // Append index to end of avi file
+ while( indexRemainder > MAX_AVI_BUFFER )
+ {
+ FS_Read( buffer, MAX_AVI_BUFFER, afd.idxF );
+ SafeFS_Write( buffer, MAX_AVI_BUFFER, afd.f );
+ afd.fileSize += MAX_AVI_BUFFER;
+ indexRemainder -= MAX_AVI_BUFFER;
+ }
+ FS_Read( buffer, indexRemainder, afd.idxF );
+ SafeFS_Write( buffer, indexRemainder, afd.f );
+ afd.fileSize += indexRemainder;
+ FS_FCloseFile( afd.idxF );
+
+ // Remove temp index file
+ FS_HomeRemove( idxFileName );
+
+ // Write the real header
+ FS_Seek( afd.f, 0, FS_SEEK_SET );
+ CL_WriteAVIHeader( );
+
+ bufIndex = 4;
+ WRITE_4BYTES( afd.fileSize - 8 ); // "RIFF" size
+
+ bufIndex = afd.moviOffset + 4; // Skip "LIST"
+ WRITE_4BYTES( afd.moviSize );
+
+ SafeFS_Write( buffer, bufIndex, afd.f );
+
+ Z_Free( afd.cBuffer );
+ Z_Free( afd.eBuffer );
+ FS_FCloseFile( afd.f );
+
+ Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
+
+ return qtrue;
+}
+
+/*
+===============
+CL_VideoRecording
+===============
+*/
+qboolean CL_VideoRecording( void )
+{
+ return afd.fileOpen;
+}
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 0789ac9b..04d87cc1 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -44,7 +44,9 @@ cvar_t *cl_freezeDemo;
cvar_t *cl_shownet;
cvar_t *cl_showSend;
cvar_t *cl_timedemo;
+cvar_t *cl_autoRecordDemo;
cvar_t *cl_avidemo;
+cvar_t *cl_aviMotionJpeg;
cvar_t *cl_forceavidemo;
cvar_t *cl_freelook;
@@ -283,7 +285,7 @@ void CL_Record_f( void ) {
}
// sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
- if ( !Cvar_VariableValue( "g_synchronousClients" ) ) {
+ if ( NET_IsLocalAddress( clc.serverAddress ) && !Cvar_VariableValue( "g_synchronousClients" ) ) {
Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
}
@@ -774,6 +776,11 @@ void CL_Disconnect( qboolean showMainMenu ) {
// not connected to a pure server anymore
cl_connectedToPureServer = qfalse;
+
+ // Stop recording any video
+ if( CL_VideoRecording( ) ) {
+ CL_CloseAVI( );
+ }
}
@@ -1105,6 +1112,11 @@ doesn't know what graphics to reload
*/
void CL_Vid_Restart_f( void ) {
+ // Settings may have changed so stop recording now
+ if( CL_VideoRecording( ) ) {
+ CL_CloseAVI( );
+ }
+
// don't let them loop during the restart
S_StopAllSounds();
// shutdown the UI
@@ -1916,18 +1928,57 @@ void CL_Frame ( int msec ) {
}
// if recording an avi, lock to a fixed fps
- if ( cl_avidemo->integer && msec) {
+ if ( CL_VideoRecording( ) && cl_avidemo->integer && msec) {
// save the current screen
if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) {
- Cbuf_ExecuteText( EXEC_NOW, "screenshot silent\n" );
- }
- // fixed time for next frame'
- msec = (1000 / cl_avidemo->integer) * com_timescale->value;
- if (msec == 0) {
- msec = 1;
+ CL_TakeVideoFrame( );
+
+ // fixed time for next frame'
+ msec = (int)ceil( (1000.0f / cl_avidemo->value) * com_timescale->value );
+ if (msec == 0) {
+ msec = 1;
+ }
}
}
+ if( cl_autoRecordDemo->integer ) {
+ if( cls.state == CA_ACTIVE && !clc.demorecording ) {
+ // If not recording a demo, and we should be, start one
+ qtime_t now;
+ char *nowString;
+ char *p;
+ char mapName[ MAX_QPATH ];
+ char serverName[ MAX_OSPATH ];
+
+ Com_RealTime( &now );
+ nowString = va( "%04d%02d%02d%02d%02d%02d",
+ 1900 + now.tm_year,
+ 1 + now.tm_mon,
+ now.tm_mday,
+ now.tm_hour,
+ now.tm_min,
+ now.tm_sec );
+
+ Q_strncpyz( serverName, cls.servername, MAX_OSPATH );
+ // Replace the ":" in the address as it is not a valid
+ // file name character
+ p = strstr( serverName, ":" );
+ if( p ) {
+ *p = '.';
+ }
+
+ Q_strncpyz( mapName, COM_SkipPath( cl.mapname ), sizeof( cl.mapname ) );
+ COM_StripExtension( mapName, mapName );
+
+ Cbuf_ExecuteText( EXEC_NOW,
+ va( "record %s-%s-%s", nowString, serverName, mapName ) );
+ }
+ else if( cls.state != CA_ACTIVE && clc.demorecording ) {
+ // Recording, but not CA_ACTIVE, so stop recording
+ CL_StopRecord_f( );
+ }
+ }
+
// save the msec before checking pause
cls.realFrametime = msec;
@@ -2124,6 +2175,8 @@ void CL_InitRef( void ) {
ri.CIN_UploadCinematic = CIN_UploadCinematic;
ri.CIN_PlayCinematic = CIN_PlayCinematic;
ri.CIN_RunCinematic = CIN_RunCinematic;
+
+ ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
ret = GetRefAPI( REF_API_VERSION, &ri );
@@ -2161,6 +2214,72 @@ void CL_SetModel_f( void ) {
}
}
+
+//===========================================================================================
+
+
+/*
+===============
+CL_Video_f
+
+video
+video [filename]
+===============
+*/
+void CL_Video_f( void )
+{
+ char filename[ MAX_OSPATH ];
+ int i, last;
+
+ if( Cmd_Argc( ) == 2 )
+ {
+ // explicit filename
+ Com_sprintf( filename, MAX_OSPATH, "videos/%s.avi", Cmd_Argv( 1 ) );
+ }
+ else
+ {
+ // scan for a free filename
+ for( i = 0; i <= 9999; i++ )
+ {
+ int a, b, c, d;
+
+ last = i;
+
+ a = last / 1000;
+ last -= a * 1000;
+ b = last / 100;
+ last -= b * 100;
+ c = last / 10;
+ last -= c * 10;
+ d = last;
+
+ Com_sprintf( filename, MAX_OSPATH, "videos/video%d%d%d%d.avi",
+ a, b, c, d );
+
+ if( !FS_FileExists( filename ) )
+ break; // file doesn't exist
+ }
+
+ if( i > 9999 )
+ {
+ Com_Printf( S_COLOR_RED "ERROR: no free file names to create video\n" );
+ return;
+ }
+ }
+
+ CL_OpenAVIForWriting( filename );
+}
+
+/*
+===============
+CL_StopVideo_f
+===============
+*/
+void CL_StopVideo_f( void )
+{
+ CL_CloseAVI( );
+}
+
/*
====================
CL_Init
@@ -2196,7 +2315,9 @@ void CL_Init( void ) {
cl_activeAction = Cvar_Get( "activeAction", "", CVAR_TEMP );
cl_timedemo = Cvar_Get ("timedemo", "0", 0);
- cl_avidemo = Cvar_Get ("cl_avidemo", "0", 0);
+ cl_autoRecordDemo = Cvar_Get ("cl_autoRecordDemo", "0", CVAR_ARCHIVE);
+ cl_avidemo = Cvar_Get ("cl_avidemo", "25", CVAR_ARCHIVE);
+ cl_aviMotionJpeg = Cvar_Get ("cl_aviMotionJpeg", "1", CVAR_ARCHIVE);
cl_forceavidemo = Cvar_Get ("cl_forceavidemo", "0", 0);
rconAddress = Cvar_Get ("rconAddress", "", 0);
@@ -2297,6 +2418,8 @@ void CL_Init( void ) {
Cmd_AddCommand ("fs_openedList", CL_OpenedPK3List_f );
Cmd_AddCommand ("fs_referencedList", CL_ReferencedPK3List_f );
Cmd_AddCommand ("model", CL_SetModel_f );
+ Cmd_AddCommand ("video", CL_Video_f );
+ Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
CL_InitRef();
SCR_Init ();
@@ -2352,6 +2475,8 @@ void CL_Shutdown( void ) {
Cmd_RemoveCommand ("serverstatus");
Cmd_RemoveCommand ("showip");
Cmd_RemoveCommand ("model");
+ Cmd_RemoveCommand ("video");
+ Cmd_RemoveCommand ("stopvideo");
Cvar_Set( "cl_running", "0" );
diff --git a/src/client/client.h b/src/client/client.h
index e597047f..5f609dde 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -343,6 +343,8 @@ extern cvar_t *m_side;
extern cvar_t *m_filter;
extern cvar_t *cl_timedemo;
+extern cvar_t *cl_avidemo;
+extern cvar_t *cl_aviMotionJpeg;
extern cvar_t *cl_activeAction;
@@ -518,3 +520,13 @@ void LAN_SaveServersToCache( void );
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg); //int length, const byte *data );
void CL_Netchan_TransmitNextFragment( netchan_t *chan );
qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg );
+
+//
+// cl_avi.c
+//
+qboolean CL_OpenAVIForWriting( const char *filename );
+void CL_TakeVideoFrame( void );
+void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size );
+void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size );
+qboolean CL_CloseAVI( void );
+qboolean CL_VideoRecording( void );
diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c
index 6860179f..d51a4b85 100644
--- a/src/client/snd_dma.c
+++ b/src/client/snd_dma.c
@@ -1140,6 +1140,12 @@ void S_GetSoundtime(void)
fullsamples = dma.samples / dma.channels;
+ if( CL_VideoRecording( ) )
+ {
+ s_soundtime += (int)ceil( dma.speed / cl_avidemo->value );
+ return;
+ }
+
// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update. Oh well.
samplepos = SNDDMA_GetDMAPos();
diff --git a/src/client/snd_main.c b/src/client/snd_main.c
index d83996a8..1ecdc237 100644
--- a/src/client/snd_main.c
+++ b/src/client/snd_main.c
@@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
cvar_t *s_volume;
cvar_t *s_musicVolume;
cvar_t *s_doppler;
+cvar_t *s_backend;
static soundInterface_t si;
@@ -371,6 +372,7 @@ void S_Init( void )
s_volume = Cvar_Get( "s_volume", "0.8", CVAR_ARCHIVE );
s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE );
s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE );
+ s_backend = Cvar_Get( "s_backend", "", CVAR_ROM );
cv = Cvar_Get( "s_initsound", "1", 0 );
if( !cv->integer ) {
@@ -389,10 +391,12 @@ void S_Init( void )
if( cv->integer ) {
//OpenAL
started = S_AL_Init( &si );
+ Cvar_Set( "s_backend", "OpenAL" );
}
if( !started ) {
started = S_Base_Init( &si );
+ Cvar_Set( "s_backend", "base" );
}
if( started ) {
diff --git a/src/client/snd_mix.c b/src/client/snd_mix.c
index 85b10cba..4d9e716a 100644
--- a/src/client/snd_mix.c
+++ b/src/client/snd_mix.c
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// snd_mix.c -- portable code to mix sounds for snd_dma.c
+#include "client.h"
#include "snd_local.h"
#if idppc_altivec && !defined(MACOS_X)
#include <altivec.h>
@@ -138,6 +139,9 @@ void S_TransferStereo16 (unsigned long *pbuf, int endtime)
snd_p += snd_linear_count;
ls_paintedtime += (snd_linear_count>>1);
+
+ if( CL_VideoRecording( ) )
+ CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 );
}
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index 231f4aa8..b0cee0d3 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -2714,316 +2714,6 @@ void Com_Shutdown (void) {
}
-#if I_WANT_A_CUSTOM_MEMCPY && !defined(_WIN32)
-void Com_Memcpy (void* dest, const void* src, const size_t count)
-{
- memcpy(dest, src, count);
-}
-
-void Com_Memset (void* dest, const int val, const size_t count)
-{
- memset(dest, val, count);
-}
-
-#elif I_WANT_A_CUSTOM_MEMCPY && defined(_WIN32)
-
-typedef enum
-{
- PRE_READ, // prefetch assuming that buffer is used for reading only
- PRE_WRITE, // prefetch assuming that buffer is used for writing only
- PRE_READ_WRITE // prefetch assuming that buffer is used for both reading and writing
-} e_prefetch;
-
-void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type);
-
-#define EMMS_INSTRUCTION __asm emms
-
-void _copyDWord (unsigned int* dest, const unsigned int constant, const unsigned int count) {
- __asm
- {
- mov edx,dest
- mov eax,constant
- mov ecx,count
- and ecx,~7
- jz padding
- sub ecx,8
- jmp loopu
- align 16
-loopu:
- test [edx+ecx*4 + 28],ebx // fetch next block destination to L1 cache
- mov [edx+ecx*4 + 0],eax
- mov [edx+ecx*4 + 4],eax
- mov [edx+ecx*4 + 8],eax
- mov [edx+ecx*4 + 12],eax
- mov [edx+ecx*4 + 16],eax
- mov [edx+ecx*4 + 20],eax
- mov [edx+ecx*4 + 24],eax
- mov [edx+ecx*4 + 28],eax
- sub ecx,8
- jge loopu
-padding: mov ecx,count
- mov ebx,ecx
- and ecx,7
- jz outta
- and ebx,~7
- lea edx,[edx+ebx*4] // advance dest pointer
- test [edx+0],eax // fetch destination to L1 cache
- cmp ecx,4
- jl skip4
- mov [edx+0],eax
- mov [edx+4],eax
- mov [edx+8],eax
- mov [edx+12],eax
- add edx,16
- sub ecx,4
-skip4: cmp ecx,2
- jl skip2
- mov [edx+0],eax
- mov [edx+4],eax
- add edx,8
- sub ecx,2
-skip2: cmp ecx,1
- jl outta
- mov [edx+0],eax
-outta:
- }
-}
-
-// optimized memory copy routine that handles all alignment
-// cases and block sizes efficiently
-void Com_Memcpy (void* dest, const void* src, const size_t count) {
- Com_Prefetch (src, count, PRE_READ);
- __asm
- {
- push edi
- push esi
- mov ecx,count
- cmp ecx,0 // count = 0 check (just to be on the safe side)
- je outta
- mov edx,dest
- mov ebx,src
- cmp ecx,32 // padding only?
- jl padding
-
- mov edi,ecx
- and edi,~31 // edi = count&~31
- sub edi,32
-
- align 16
-loopMisAligned:
- mov eax,[ebx + edi + 0 + 0*8]
- mov esi,[ebx + edi + 4 + 0*8]
- mov [edx+edi+0 + 0*8],eax
- mov [edx+edi+4 + 0*8],esi
- mov eax,[ebx + edi + 0 + 1*8]
- mov esi,[ebx + edi + 4 + 1*8]
- mov [edx+edi+0 + 1*8],eax
- mov [edx+edi+4 + 1*8],esi
- mov eax,[ebx + edi + 0 + 2*8]
- mov esi,[ebx + edi + 4 + 2*8]
- mov [edx+edi+0 + 2*8],eax
- mov [edx+edi+4 + 2*8],esi
- mov eax,[ebx + edi + 0 + 3*8]
- mov esi,[ebx + edi + 4 + 3*8]
- mov [edx+edi+0 + 3*8],eax
- mov [edx+edi+4 + 3*8],esi
- sub edi,32
- jge loopMisAligned
-
- mov edi,ecx
- and edi,~31
- add ebx,edi // increase src pointer
- add edx,edi // increase dst pointer
- and ecx,31 // new count
- jz outta // if count = 0, get outta here
-
-padding:
- cmp ecx,16
- jl skip16
- mov eax,dword ptr [ebx]
- mov dword ptr [edx],eax
- mov eax,dword ptr [ebx+4]
- mov dword ptr [edx+4],eax
- mov eax,dword ptr [ebx+8]
- mov dword ptr [edx+8],eax
- mov eax,dword ptr [ebx+12]
- mov dword ptr [edx+12],eax
- sub ecx,16
- add ebx,16
- add edx,16
-skip16:
- cmp ecx,8
- jl skip8
- mov eax,dword ptr [ebx]
- mov dword ptr [edx],eax
- mov eax,dword ptr [ebx+4]
- sub ecx,8
- mov dword ptr [edx+4],eax
- add ebx,8
- add edx,8
-skip8:
- cmp ecx,4
- jl skip4
- mov eax,dword ptr [ebx] // here 4-7 bytes
- add ebx,4
- sub ecx,4
- mov dword ptr [edx],eax
- add edx,4
-skip4: // 0-3 remaining bytes
- cmp ecx,2
- jl skip2
- mov ax,word ptr [ebx] // two bytes
- cmp ecx,3 // less than 3?
- mov word ptr [edx],ax
- jl outta
- mov al,byte ptr [ebx+2] // last byte
- mov byte ptr [edx+2],al
- jmp outta
-skip2:
- cmp ecx,1
- jl outta
- mov al,byte ptr [ebx]
- mov byte ptr [edx],al
-outta:
- pop esi
- pop edi
- }
-}
-
-void Com_Memset (void* dest, const int val, const size_t count)
-{
- unsigned int fillval;
-
- if (count < 8)
- {
- __asm
- {
- mov edx,dest
- mov eax, val
- mov ah,al
- mov ebx,eax
- and ebx, 0xffff
- shl eax,16
- add eax,ebx // eax now contains pattern
- mov ecx,count
- cmp ecx,4
- jl skip4
- mov [edx],eax // copy first dword
- add edx,4
- sub ecx,4
- skip4: cmp ecx,2
- jl skip2
- mov word ptr [edx],ax // copy 2 bytes
- add edx,2
- sub ecx,2
- skip2: cmp ecx,0
- je skip1
- mov byte ptr [edx],al // copy single byte
- skip1:
- }
- return;
- }
-
- fillval = val;
-
- fillval = fillval|(fillval<<8);
- fillval = fillval|(fillval<<16); // fill dword with 8-bit pattern
-
- _copyDWord ((unsigned int*)(dest),fillval, count/4);
-
- __asm // padding of 0-3 bytes
- {
- mov ecx,count
- mov eax,ecx
- and ecx,3
- jz skipA
- and eax,~3
- mov ebx,dest
- add ebx,eax
- mov eax,fillval
- cmp ecx,2
- jl skipB
- mov word ptr [ebx],ax
- cmp ecx,2
- je skipA
- mov byte ptr [ebx+2],al
- jmp skipA
-skipB:
- cmp ecx,0
- je skipA
- mov byte ptr [ebx],al
-skipA:
- }
-}
-
-qboolean Com_Memcmp (const void *src0, const void *src1, const unsigned int count)
-{
- unsigned int i;
- // MMX version anyone?
-
- if (count >= 16)
- {
- unsigned int *dw = (unsigned int*)(src0);
- unsigned int *sw = (unsigned int*)(src1);
-
- unsigned int nm2 = count/16;
- for (i = 0; i < nm2; i+=4)
- {
- unsigned int tmp = (dw[i+0]-sw[i+0])|(dw[i+1]-sw[i+1])|
- (dw[i+2]-sw[i+2])|(dw[i+3]-sw[i+3]);
- if (tmp)
- return qfalse;
- }
- }
- if (count & 15)
- {
- byte *d = (byte*)src0;
- byte *s = (byte*)src1;
- for (i = count & 0xfffffff0; i < count; i++)
- if (d[i]!=s[i])
- return qfalse;
- }
-
- return qtrue;
-}
-
-void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type)
-{
- // write buffer prefetching is performed only if
- // the processor benefits from it. Read and read/write
- // prefetching is always performed.
-
- switch (type)
- {
- case PRE_WRITE : break;
- case PRE_READ:
- case PRE_READ_WRITE:
-
- __asm
- {
- mov ebx,s
- mov ecx,bytes
- cmp ecx,4096 // clamp to 4kB
- jle skipClamp
- mov ecx,4096
-skipClamp:
- add ecx,0x1f
- shr ecx,5 // number of cache lines
- jz skip
- jmp loopie
-
- align 16
- loopie: test byte ptr [ebx],al
- add ebx,32
- dec ecx
- jnz loopie
- skip:
- }
-
- break;
- }
-}
-#endif
//------------------------------------------------------------------------
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 1ea34cc6..4ebca39a 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -56,7 +56,7 @@ The "cd path" is the path to an alternate hierarchy that will be searched if a f
is not located in the base path. A user can do a partial install that copies some
data to a base path created on their hard drive and leave the rest on the cd. Files
are never writen to the cd path. It defaults to a value set by the installer, like
-"e:\quake3", but it can be overridden with "+set ds_cdpath g:\quake3".
+"e:\quake3", but it can be overridden with "+set fs_cdpath g:\quake3".
If a user runs the game directly from a CD, the base path would be on the CD. This
should still function correctly, but all file writes will fail (harmlessly).
@@ -201,7 +201,8 @@ or configs will never get loaded from disk!
// every time a new demo pk3 file is built, this checksum must be updated.
// the easiest way to get it is to just run the game and see what it spits out
-#define DEMO_PAK_CHECKSUM 437558517u
+#define DEMO_PAK0_CHECKSUM 2985612116u
+#define PAK0_CHECKSUM 1566731103u
// if this is defined, the executable positively won't work with any paks other
// than the demo pak, even if productid is present. This is only used for our
@@ -307,11 +308,6 @@ static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; // pk3 names
char lastValidBase[MAX_OSPATH];
char lastValidGame[MAX_OSPATH];
-// productId: This file is copyright 1999 Id Software, and may not be duplicated except during a licensed installation of the full commercial version of Quake 3:Arena
-static byte fs_scrambledProductId[152] = {
-220, 129, 255, 108, 244, 163, 171, 55, 133, 65, 199, 36, 140, 222, 53, 99, 65, 171, 175, 232, 236, 193, 210, 250, 169, 104, 231, 231, 21, 201, 170, 208, 135, 175, 130, 136, 85, 215, 71, 23, 96, 32, 96, 83, 44, 240, 219, 138, 184, 215, 73, 27, 196, 247, 55, 139, 148, 68, 78, 203, 213, 238, 139, 23, 45, 205, 118, 186, 236, 230, 231, 107, 212, 1, 10, 98, 30, 20, 116, 180, 216, 248, 166, 35, 45, 22, 215, 229, 35, 116, 250, 167, 117, 3, 57, 55, 201, 229, 218, 222, 128, 12, 141, 149, 32, 110, 168, 215, 184, 53, 31, 147, 62, 12, 138, 67, 132, 54, 125, 6, 221, 148, 140, 4, 21, 44, 198, 3, 126, 12, 100, 236, 61, 42, 44, 251, 15, 135, 14, 134, 89, 92, 177, 246, 152, 106, 124, 78, 118, 80, 28, 42
-};
-
#ifdef FS_MISSING
FILE* missingFiles = NULL;
#endif
@@ -566,11 +562,22 @@ FS_Remove
===========
*/
-static void FS_Remove( const char *osPath ) {
+void FS_Remove( const char *osPath ) {
remove( osPath );
}
/*
+===========
+FS_HomeRemove
+
+===========
+*/
+void FS_HomeRemove( const char *homePath ) {
+ remove( FS_BuildOSPath( fs_homepath->string,
+ fs_gamedir, homePath ) );
+}
+
+/*
================
FS_FileExists
@@ -2829,69 +2836,6 @@ static void FS_Startup( const char *gameName ) {
Com_Printf( "%d files in pk3 files\n", fs_packFiles );
}
-
-/*
-===================
-FS_SetRestrictions
-
-Looks for product keys and restricts media add on ability
-if the full version is not found
-===================
-*/
-static void FS_SetRestrictions( void ) {
- searchpath_t *path;
- char *productId;
-
- return;
-
-#ifndef PRE_RELEASE_DEMO
-
- // if fs_restrict is set, don't even look for the id file,
- // which allows the demo release to be tested even if
- // the full game is present
- if ( !fs_restrict->integer ) {
- // look for the full game id
- FS_ReadFile( "productid.txt", (void **)&productId );
- if ( productId ) {
- // check against the hardcoded string
- int seed, i;
-
- seed = 5000;
- for ( i = 0 ; i < sizeof( fs_scrambledProductId ) ; i++ ) {
- if ( ( fs_scrambledProductId[i] ^ (seed&255) ) != productId[i] ) {
- break;
- }
- seed = (69069 * seed + 1);
- }
-
- FS_FreeFile( productId );
-
- if ( i == sizeof( fs_scrambledProductId ) ) {
- return; // no restrictions
- }
- Com_Error( ERR_FATAL, "Invalid product identification" );
- }
- }
-#endif
- Cvar_Set( "fs_restrict", "1" );
-
- Com_Printf( "\nRunning in restricted demo mode.\n\n" );
-
- // restart the filesystem with just the demo directory
- FS_Shutdown(qfalse);
- FS_Startup( DEMOGAME );
-
- // make sure that the pak file has the header checksum we expect
- for ( path = fs_searchpaths ; path ; path = path->next ) {
- if ( path->pack ) {
- // a tiny attempt to keep the checksum from being scannable from the exe
- if ( (path->pack->checksum ^ 0x02261994u) != (DEMO_PAK_CHECKSUM ^ 0x02261994u) ) {
- Com_Error( ERR_FATAL, "Corrupted pak0.pk3: %u", path->pack->checksum );
- }
- }
- }
-}
-
/*
=====================
FS_GamePureChecksum
@@ -3259,9 +3203,6 @@ void FS_InitFilesystem( void ) {
// try to start up normally
FS_Startup( BASEGAME );
- // see if we are going to allow add-ons
- FS_SetRestrictions();
-
// if we can't find default.cfg, assume that the paths are
// busted and error out now, rather than getting an unreadable
// graphics screen when the font fails to load
@@ -3296,9 +3237,6 @@ void FS_Restart( int checksumFeed ) {
// try to start up normally
FS_Startup( BASEGAME );
- // see if we are going to allow add-ons
- FS_SetRestrictions();
-
// if we can't find default.cfg, assume that the paths are
// busted and error out now, rather than getting an unreadable
// graphics screen when the font fails to load
diff --git a/src/qcommon/md4.c b/src/qcommon/md4.c
index 24b79610..82c4b0d8 100644
--- a/src/qcommon/md4.c
+++ b/src/qcommon/md4.c
@@ -38,13 +38,8 @@ void MD4Init (MD4_CTX *);
void MD4Update (MD4_CTX *, const unsigned char *, unsigned int);
void MD4Final (unsigned char [16], MD4_CTX *);
-#if I_WANT_A_CUSTOM_MEMCPY
-void Com_Memset (void* dest, const int val, const size_t count);
-void Com_Memcpy (void* dest, const void* src, const size_t count);
-#else
#define Com_Memset memset
#define Com_Memcpy memcpy
-#endif
/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 53848aa4..537dee36 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -243,13 +243,8 @@ void Snd_Memset (void* dest, const int val, const size_t count);
#define Snd_Memset Com_Memset
#endif
-#if I_WANT_A_CUSTOM_MEMCPY
-void Com_Memset (void* dest, const int val, const size_t count);
-void Com_Memcpy (void* dest, const void* src, const size_t count);
-#else
#define Com_Memset memset
#define Com_Memcpy memcpy
-#endif
#define CIN_system 1
#define CIN_loop 2
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 843f04ef..9e9ca513 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -651,6 +651,9 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
void FS_Rename( const char *from, const char *to );
+void FS_Remove( const char *osPath );
+void FS_HomeRemove( const char *homePath );
+
/*
==============================================================
@@ -892,7 +895,6 @@ void S_ClearSoundBuffer( void );
void SCR_DebugGraph (float value, int color); // FIXME: move logging to common?
-
//
// server interface
//
diff --git a/src/renderer/tr_backend.c b/src/renderer/tr_backend.c
index 73449586..9c9b841a 100644
--- a/src/renderer/tr_backend.c
+++ b/src/renderer/tr_backend.c
@@ -1082,6 +1082,9 @@ void RB_ExecuteRenderCommands( const void *data ) {
case RC_SCREENSHOT:
data = RB_TakeScreenshotCmd( data );
break;
+ case RC_VIDEOFRAME:
+ data = RB_TakeVideoFrameCmd( data );
+ break;
case RC_END_OF_LIST:
default:
diff --git a/src/renderer/tr_cmds.c b/src/renderer/tr_cmds.c
index bbcf6385..d637aec0 100644
--- a/src/renderer/tr_cmds.c
+++ b/src/renderer/tr_cmds.c
@@ -446,3 +446,30 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
backEnd.pc.msec = 0;
}
+/*
+=============
+RE_TakeVideoFrame
+=============
+*/
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
+{
+ videoFrameCommand_t *cmd;
+
+ if( !tr.registered ) {
+ return;
+ }
+
+ cmd = R_GetCommandBuffer( sizeof( *cmd ) );
+ if( !cmd ) {
+ return;
+ }
+
+ cmd->commandId = RC_VIDEOFRAME;
+
+ cmd->width = width;
+ cmd->height = height;
+ cmd->captureBuffer = captureBuffer;
+ cmd->encodeBuffer = encodeBuffer;
+ cmd->motionJpeg = motionJpeg;
+}
diff --git a/src/renderer/tr_image.c b/src/renderer/tr_image.c
index a3efa2f1..692f00c6 100644
--- a/src/renderer/tr_image.c
+++ b/src/renderer/tr_image.c
@@ -1853,6 +1853,64 @@ void SaveJPG(char * filename, int quality, int image_width, int image_height, un
/* And we're done! */
}
+/*
+=================
+SaveJPGToBuffer
+=================
+*/
+int SaveJPGToBuffer( byte *buffer, int quality,
+ int image_width, int image_height,
+ byte *image_buffer )
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+
+ /* Step 1: allocate and initialize JPEG compression object */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+ jpegDest(&cinfo, buffer, image_width*image_height*4);
+
+ /* Step 3: set parameters for compression */
+ cinfo.image_width = image_width; /* image width and height, in pixels */
+ cinfo.image_height = image_height;
+ cinfo.input_components = 4; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+ row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+ jpeg_finish_compress(&cinfo);
+
+ /* Step 7: release JPEG compression object */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+ return hackSize;
+}
+
//===================================================================
/*
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c
index a3fd2ca6..79c910d1 100644
--- a/src/renderer/tr_init.c
+++ b/src/renderer/tr_init.c
@@ -701,6 +701,51 @@ void R_ScreenShotJPEG_f (void) {
//============================================================================
/*
+==================
+RB_TakeVideoFrameCmd
+==================
+*/
+const void *RB_TakeVideoFrameCmd( const void *data )
+{
+ const videoFrameCommand_t *cmd;
+ int frameSize;
+ int i;
+
+ cmd = (const videoFrameCommand_t *)data;
+
+ qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
+ GL_UNSIGNED_BYTE, cmd->captureBuffer );
+
+ // gamma correct
+ if( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma )
+ R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
+
+ if( cmd->motionJpeg )
+ {
+ frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95,
+ cmd->width, cmd->height, cmd->captureBuffer );
+ }
+ else
+ {
+ frameSize = cmd->width * cmd->height * 4;
+
+ // Vertically flip the image
+ for( i = 0; i < cmd->height; i++ )
+ {
+ Com_Memcpy( &cmd->encodeBuffer[ i * ( cmd->width * 4 ) ],
+ &cmd->captureBuffer[ ( cmd->height - i - 1 ) * ( cmd->width * 4 ) ],
+ cmd->width * 4 );
+ }
+ }
+
+ ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
+
+ return (const void *)(cmd + 1);
+}
+
+//============================================================================
+
+/*
** GL_SetDefaultState
*/
void GL_SetDefaultState( void )
@@ -1202,5 +1247,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
re.GetEntityToken = R_GetEntityToken;
re.inPVS = R_inPVS;
+ re.TakeVideoFrame = RE_TakeVideoFrame;
+
return &re;
}
diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h
index 4119efac..7efed35d 100644
--- a/src/renderer/tr_local.h
+++ b/src/renderer/tr_local.h
@@ -1216,6 +1216,7 @@ skin_t *R_GetSkinByHandle( qhandle_t hSkin );
int R_ComputeLOD( trRefEntity_t *ent );
+const void *RB_TakeVideoFrameCmd( const void *data );
//
// tr_shader.c
@@ -1580,6 +1581,15 @@ typedef struct {
qboolean jpeg;
} screenshotCommand_t;
+typedef struct {
+ int commandId;
+ int width;
+ int height;
+ byte *captureBuffer;
+ byte *encodeBuffer;
+ qboolean motionJpeg;
+} videoFrameCommand_t;
+
typedef enum {
RC_END_OF_LIST,
RC_SET_COLOR,
@@ -1587,7 +1597,8 @@ typedef enum {
RC_DRAW_SURFS,
RC_DRAW_BUFFER,
RC_SWAP_BUFFERS,
- RC_SCREENSHOT
+ RC_SCREENSHOT,
+ RC_VIDEOFRAME
} renderCommand_t;
@@ -1636,6 +1647,11 @@ void RE_StretchPic ( float x, float y, float w, float h,
void RE_BeginFrame( stereoFrame_t stereoFrame );
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer);
+int SaveJPGToBuffer( byte *buffer, int quality,
+ int image_width, int image_height,
+ byte *image_buffer );
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
// font stuff
void R_InitFreeType( void );
diff --git a/src/renderer/tr_public.h b/src/renderer/tr_public.h
index 92801ac4..e4e4d047 100644
--- a/src/renderer/tr_public.h
+++ b/src/renderer/tr_public.h
@@ -98,6 +98,8 @@ typedef struct {
void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
qboolean (*GetEntityToken)( char *buffer, int size );
qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
+
+ void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
} refexport_t;
//
@@ -157,6 +159,7 @@ typedef struct {
int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
e_status (*CIN_RunCinematic) (int handle);
+ void (*CL_WriteAVIVideoFrame)( const byte *buffer, int size );
} refimport_t;
diff --git a/src/unix/Makefile b/src/unix/Makefile
index 793f3c7e..db7802dd 100644
--- a/src/unix/Makefile
+++ b/src/unix/Makefile
@@ -21,6 +21,12 @@ else
COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/i386/)
endif
+BUILD_CLIENT =
+BUILD_CLIENT_SMP =
+BUILD_SERVER =
+BUILD_GAME_SO =
+BUILD_GAME_QVM =
+
#############################################################################
#
# If you require a different configuration from the defaults below, create a
@@ -90,14 +96,6 @@ ifndef USE_LOCAL_HEADERS
USE_LOCAL_HEADERS=1
endif
-ifndef BUILD_CLIENT
-BUILD_CLIENT=1
-endif
-
-ifndef BUILD_SERVER
-BUILD_SERVER=1
-endif
-
#############################################################################
BD=debug-$(PLATFORM)-$(ARCH)
@@ -135,7 +133,6 @@ MKDIR=mkdir
ifeq ($(PLATFORM),linux)
- GLIBC=-glibc
CC=gcc
ifeq ($(ARCH),alpha)
@@ -227,23 +224,6 @@ ifeq ($(PLATFORM),linux)
LDFLAGS+=-m32
endif
- ifeq ($(ARCH),axp)
- TARGETS=\
- $(B)/$(PLATFORM)tremded
- else
- TARGETS=\
- $(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm
-# $(B)/$(PLATFORM)tremulous-smp \
-
- endif
-
else # ifeq Linux
#############################################################################
@@ -251,7 +231,6 @@ else # ifeq Linux
#############################################################################
ifeq ($(PLATFORM),darwin)
- GLIBC=
CC=gcc
# !!! FIXME: calling conventions are still broken! See Bugzilla #2519
@@ -326,17 +305,6 @@ ifeq ($(PLATFORM),darwin)
endif
endif
- TARGETS=\
- $(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm
- $(B)/$(PLATFORM)tremulous-smp \
-
else # ifeq darwin
@@ -382,14 +350,8 @@ ifeq ($(PLATFORM),mingw32)
LDFLAGS+=-m32
endif
- TARGETS=\
- $(B)/$(PLATFORM)tremulous$(BINEXT) \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm
+ BUILD_SERVER = 0
+ BUILD_CLIENT_SMP = 0
else # ifeq mingw32
@@ -399,8 +361,6 @@ else # ifeq mingw32
ifeq ($(PLATFORM),freebsd)
- GLIBC= #libc is irrelevant
-
ifneq (,$(findstring alpha,$(shell uname -m)))
ARCH=axp
else #default to i386
@@ -441,21 +401,6 @@ ifeq ($(PLATFORM),freebsd)
CLIENT_LDFLAGS=-L/usr/X11R6/$(LIB) -lGL -lX11 -lXext -lXxf86dga -lXxf86vm
- ifeq ($(ARCH),axp)
- TARGETS=\
- $(B)/$(PLATFORM)tremded
- else
- TARGETS=\
- $(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm
- endif
-
else # ifeq freebsd
#############################################################################
@@ -482,17 +427,8 @@ ifeq ($(PLATFORM),netbsd)
BASE_CFLAGS += -DNO_VM_COMPILED
endif
- ifeq ($(ARCH),i386)
- TARGETS=\
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/$(PLATFORM)tremded
- else
- TARGETS=\
- $(B)/$(PLATFORM)tremded
-
- endif
+ BUILD_CLIENT = 0
+ BUILD_GAME_QVM = 0
else # ifeq netbsd
@@ -503,7 +439,6 @@ else # ifeq netbsd
ifeq ($(PLATFORM),irix)
ARCH=mips #default to MIPS
- GLIBC= #libc is irrelevant
CC=cc
BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 -mips3 \
@@ -518,9 +453,6 @@ ifeq ($(PLATFORM),irix)
LDFLAGS=-ldl -lm
CLIENT_LDFLAGS=-L/usr/X11/$(LIB) -lGL -lX11 -lXext -lm
- TARGETS=$(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded
-
else # ifeq IRIX
#############################################################################
@@ -529,7 +461,6 @@ else # ifeq IRIX
ifeq ($(PLATFORM),SunOS)
- GLIBC= #libc is irrelevant
CC=gcc
INSTALL=ginstall
MKDIR=gmkdir
@@ -560,9 +491,9 @@ ifeq ($(PLATFORM),SunOS)
OPTIMIZE = -O3 -ffast-math -funroll-loops
ifeq ($(ARCH),sparc)
- OPTIMIZE = -O0 -ffast-math -falign-loops=2 \
+ OPTIMIZE = -O3 -ffast-math -falign-loops=2 \
-falign-jumps=2 -falign-functions=2 -fstrength-reduce \
- -mtune=ultrasparc -mv8plus -munaligned-doubles \
+ -mtune=ultrasparc -mv8plus -mno-faster-structs \
-funroll-loops
BASE_CFLAGS += -DNO_VM_COMPILED
else
@@ -584,6 +515,8 @@ ifeq ($(PLATFORM),SunOS)
THREAD_LDFLAGS=-lpthread
LDFLAGS=-lsocket -lnsl -ldl -lm
+ BOTCFLAGS=-O0
+
ifeq ($(USE_SDL),1)
CLIENT_LDFLAGS=$(shell sdl-config --libs) -L/usr/X11/lib -lGLU -lX11 -lXext
else
@@ -596,31 +529,6 @@ ifeq ($(PLATFORM),SunOS)
LDFLAGS+=-m32
endif
- ifeq ($(ARCH),sparc)
- TARGETS=\
- $(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm \
- $(B)/$(PLATFORM)tremulous-smp
- else
- TARGETS=\
- $(B)/$(PLATFORM)tremulous \
- $(B)/$(PLATFORM)tremded \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/base/vm/cgame.qvm \
- $(B)/base/vm/qagame.qvm \
- $(B)/base/vm/ui.qvm \
- $(B)/$(PLATFORM)tremulous-smp
-
- endif
-
else # ifeq SunOS
#############################################################################
@@ -635,12 +543,6 @@ else # ifeq SunOS
SHLIBCFLAGS=-fPIC
SHLIBLDFLAGS=-shared
- TARGETS=\
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT) \
- $(B)/$(PLATFORM)tremded
-
endif #Linux
endif #darwin
endif #mingw32
@@ -649,30 +551,38 @@ endif #NetBSD
endif #IRIX
endif #SunOS
-ifeq ($(USE_CCACHE),1)
- CC := ccache $(CC)
+TARGETS =
+
+ifneq ($(BUILD_SERVER),0)
+ TARGETS += $(B)/tremded.$(ARCH)$(BINEXT)
endif
-ifneq ($(BUILD_SERVER),1)
- TARGETS := $(subst $(B)/$(PLATFORM)tremded,,$(TARGETS))
+ifneq ($(BUILD_CLIENT),0)
+ TARGETS += $(B)/tremulous.$(ARCH)$(BINEXT)
+ ifneq ($(BUILD_CLIENT_SMP),0)
+ TARGETS += $(B)/tremulous.$(ARCH)$(BINEXT)
+ endif
endif
-ifneq ($(BUILD_CLIENT),1)
- TARGETS := \
- $(subst $(B)/base/cgame$(ARCH).$(SHLIBEXT),,\
- $(subst $(B)/base/ui$(ARCH).$(SHLIBEXT),,\
- $(subst $(B)/base/vm/cgame.qvm,,\
- $(subst $(B)/base/vm/ui.qvm,,\
- $(subst $(B)/$(PLATFORM)tremulous-smp$(BINEXT),,\
- $(subst $(B)/$(PLATFORM)tremulous$(BINEXT),,$(TARGETS) ))))))
+ifneq ($(BUILD_GAME_SO),0)
+ TARGETS += \
+ $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
+ $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
+ $(B)/base/ui$(ARCH).$(SHLIBEXT)
endif
-# Never build qvms when cross-compiling
-ifeq ($(CROSS_COMPILING),1)
- TARGETS := \
- $(subst $(B)/base/vm/qagame.qvm,,\
- $(subst $(B)/base/vm/cgame.qvm,,\
- $(subst $(B)/base/vm/ui.qvm,,$(TARGETS) )))
+ifneq ($(BUILD_GAME_QVM),0)
+ ifneq ($(CROSS_COMPILING),1)
+ TARGETS += \
+ $(B)/base/vm/cgame.qvm \
+ $(B)/base/vm/qagame.qvm \
+ $(B)/base/vm/ui.qvm \
+ qvmdeps
+ endif
+endif
+
+ifeq ($(USE_CCACHE),1)
+ CC := ccache $(CC)
endif
ifdef DEFAULT_BASEDIR
@@ -691,7 +601,7 @@ endif
DO_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $<
DO_SMP_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $<
-DO_BOT_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212
+DO_BOT_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212
DO_DEBUG_CC=$(CC) $(NOTSHLIBCFLAGS) $(DEBUG_CFLAGS) -o $@ -c $<
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
DO_SHLIB_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
@@ -767,6 +677,7 @@ Q3OBJ = \
$(B)/client/cl_parse.o \
$(B)/client/cl_scrn.o \
$(B)/client/cl_ui.o \
+ $(B)/client/cl_avi.o \
\
$(B)/client/cm_load.o \
$(B)/client/cm_patch.o \
@@ -901,12 +812,21 @@ Q3OBJ = \
$(B)/client/tr_surface.o \
$(B)/client/tr_world.o \
-
ifeq ($(ARCH),i386)
Q3OBJ += $(B)/client/vm_x86.o
+ Q3OBJ += \
+ $(B)/client/snd_mixa.o \
+ $(B)/client/matha.o \
+ $(B)/client/ftola.o \
+ $(B)/client/snapvectora.o
endif
ifeq ($(ARCH),x86)
Q3OBJ += $(B)/client/vm_x86.o
+ Q3OBJ += \
+ $(B)/client/snd_mixa.o \
+ $(B)/client/matha.o \
+ $(B)/client/ftola.o \
+ $(B)/client/snapvectora.o
endif
ifeq ($(ARCH),x86_64)
Q3OBJ += $(B)/client/vm_x86_64.o
@@ -918,48 +838,9 @@ ifeq ($(ARCH),ppc)
endif
endif
-#platform specific objects
-ifeq ($(PLATFORM),freebsd)
-ifeq ($(ARCH),axp)
- Q3POBJ=
-else
- Q3POBJ=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
- $(B)/client/sdl_glimp.o \
- $(B)/client/linux_glimp.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o
- ifeq ($(ARCH),i386)
- Q3POBJ += $(B)/client/ftola.o $(B)/client/snapvectora.o
- Q3POBJ_SMP += $(B)/client/ftola.o $(B)/client/snapvectora.o
- endif
-
-endif # FreeBSD-axp
-else
-ifeq ($(PLATFORM),irix)
- Q3POBJ=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/irix_qgl.o \
- $(B)/client/irix_glimp.o \
- $(B)/client/irix_snd.o
-else
ifeq ($(PLATFORM),mingw32)
- Q3POBJ=\
- $(B)/client/linux_common.o \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o \
+ Q3OBJ += \
$(B)/client/win_gamma.o \
$(B)/client/win_glimp.o \
$(B)/client/win_input.o \
@@ -972,123 +853,38 @@ ifeq ($(PLATFORM),mingw32)
$(B)/client/win_wndproc.o \
$(B)/client/win_resource.o
else
-ifeq ($(PLATFORM),linux)
-ifeq ($(ARCH),axp)
- Q3POBJ=
-else
- Q3POBJ=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
- $(B)/client/linux_glimp.o \
- $(B)/client/sdl_glimp.o \
- $(B)/client/linux_joystick.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
-
- Q3POBJ_SMP=\
+ Q3OBJ += \
$(B)/client/unix_main.o \
$(B)/client/unix_net.o \
$(B)/client/unix_shared.o \
$(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
$(B)/client/linux_qgl.o \
- $(B)/client/linux_glimp_smp.o \
- $(B)/client/linux_joystick.o \
$(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o
+ $(B)/client/sdl_snd.o
- ifeq ($(ARCH),i386)
- Q3POBJ += $(B)/client/ftola.o $(B)/client/snapvectora.o
- Q3POBJ_SMP += $(B)/client/ftola.o $(B)/client/snapvectora.o
+ ifeq ($(PLATFORM),linux)
+ Q3OBJ += $(B)/client/linux_joystick.o
endif
-endif #Linux-axp
-
-else
-ifeq ($(PLATFORM),darwin)
- Q3POBJ=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
- $(B)/client/linux_glimp.o \
- $(B)/client/sdl_glimp.o \
- $(B)/client/linux_joystick.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o \
-
- Q3POBJ_SMP=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
- $(B)/client/sdl_glimp_smp.o \
- $(B)/client/linux_joystick.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o \
- ifeq ($(ARCH),i386)
- I386OBJS := \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
-
- Q3POBJ += $(I386OBJS)
- Q3POBJ_SMP += $(I386OBJS)
+ ifeq ($(USE_SDL),1)
+ ifneq ($(PLATFORM),darwin)
+ BUILD_CLIENT_SMP = 0
+ endif
endif
-else
-ifeq ($(PLATFORM),SunOS)
- Q3POBJ=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
+ Q3POBJ = \
$(B)/client/linux_glimp.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o
+ $(B)/client/sdl_glimp.o
- Q3POBJ_SMP=\
- $(B)/client/unix_main.o \
- $(B)/client/unix_net.o \
- $(B)/client/unix_shared.o \
- $(B)/client/linux_signals.o \
- $(B)/client/linux_common.o \
- $(B)/client/linux_qgl.o \
+ Q3POBJ_SMP = \
$(B)/client/linux_glimp_smp.o \
- $(B)/client/linux_snd.o \
- $(B)/client/sdl_snd.o
-
- ifeq ($(ARCH),i386)
- Q3POBJ += $(B)/client/ftola.o $(B)/client/snapvectora.o $(B)/client/snd_mixa.o $(B)/client/matha.o
- Q3POBJ_SMP += $(B)/client/ftola.o $(B)/client/snapvectora.o
- endif
-
-endif #SunOS
-endif #Linux
-endif #darwin
-endif #mingw32
-endif #IRIX
-endif #FreeBSD
+ $(B)/client/sdl_glimp_smp.o
+endif
-$(B)/$(PLATFORM)tremulous$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
+$(B)/tremulous.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
$(CC) -o $@ $(Q3OBJ) $(Q3POBJ) $(CLIENT_LDFLAGS) $(LDFLAGS) $(LIBSDLMAIN)
-$(B)/$(PLATFORM)tremulous-smp$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
+$(B)/tremulous-smp.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
$(CC) -o $@ $(Q3OBJ) $(Q3POBJ_SMP) $(CLIENT_LDFLAGS) \
$(THREAD_LDFLAGS) $(LDFLAGS) $(LIBSDLMAIN)
@@ -1110,6 +906,7 @@ $(B)/client/cl_net_chan.o : $(CDIR)/cl_net_chan.c; $(DO_CC)
$(B)/client/cl_parse.o : $(CDIR)/cl_parse.c; $(DO_CC)
$(B)/client/cl_scrn.o : $(CDIR)/cl_scrn.c; $(DO_CC)
$(B)/client/cl_ui.o : $(CDIR)/cl_ui.c; $(DO_CC)
+$(B)/client/cl_avi.o : $(CDIR)/cl_avi.c; $(DO_CC)
$(B)/client/snd_adpcm.o : $(CDIR)/snd_adpcm.c; $(DO_CC)
$(B)/client/snd_dma.o : $(CDIR)/snd_dma.c; $(DO_CC)
$(B)/client/snd_mem.o : $(CDIR)/snd_mem.c; $(DO_CC)
@@ -1249,7 +1046,6 @@ $(B)/client/irix_glimp_smp.o : $(UDIR)/irix_glimp.c; $(DO_SMP_CC)
$(B)/client/irix_snd.o : $(UDIR)/irix_snd.c; $(DO_CC)
$(B)/client/irix_input.o : $(UDIR)/irix_input.c; $(DO_CC)
$(B)/client/linux_signals.o : $(UDIR)/linux_signals.c; $(DO_CC) $(GL_CFLAGS)
-$(B)/client/linux_common.o : $(UDIR)/linux_common.c; $(DO_CC)
$(B)/client/linux_glimp.o : $(UDIR)/linux_glimp.c; $(DO_CC) $(GL_CFLAGS)
$(B)/client/sdl_glimp.o : $(UDIR)/sdl_glimp.c; $(DO_CC) $(GL_CFLAGS)
$(B)/client/linux_glimp_smp.o : $(UDIR)/linux_glimp.c; $(DO_SMP_CC) $(GL_CFLAGS)
@@ -1352,7 +1148,6 @@ Q3DOBJ = \
$(B)/ded/l_struct.o \
\
$(B)/ded/linux_signals.o \
- $(B)/ded/linux_common.o \
$(B)/ded/unix_main.o \
$(B)/ded/unix_net.o \
$(B)/ded/unix_shared.o \
@@ -1376,7 +1171,7 @@ ifeq ($(ARCH),ppc)
endif
endif
-$(B)/$(PLATFORM)tremded$(BINEXT): $(Q3DOBJ)
+$(B)/tremded.$(ARCH)$(BINEXT): $(Q3DOBJ)
$(CC) -o $@ $(Q3DOBJ) $(LDFLAGS)
$(B)/ded/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_DED_CC)
@@ -1434,7 +1229,6 @@ $(B)/ded/l_script.o : $(BLIBDIR)/l_script.c; $(DO_BOT_CC)
$(B)/ded/l_struct.o : $(BLIBDIR)/l_struct.c; $(DO_BOT_CC)
$(B)/ded/linux_signals.o : $(UDIR)/linux_signals.c; $(DO_DED_CC)
-$(B)/ded/linux_common.o : $(UDIR)/linux_common.c; $(DO_DED_CC)
$(B)/ded/unix_main.o : $(UDIR)/unix_main.c; $(DO_DED_CC)
$(B)/ded/unix_net.o : $(UDIR)/unix_net.c; $(DO_DED_CC)
$(B)/ded/unix_shared.o : $(UDIR)/unix_shared.c; $(DO_DED_CC)
@@ -1611,11 +1405,11 @@ $(B)/base/qcommon/%.asm: $(CMDIR)/%.c
#############################################################################
copyfiles: build_release
- @if [ ! -d $(COPYDIR)/base ]; then echo "You need to set COPYDIR to where you installed Quake III!"; false; fi
- $(INSTALL) -s -m 0755 $(BR)/$(PLATFORM)tremulous$(BINEXT) $(COPYDIR)/tremulous
+ @if [ ! -d $(COPYDIR)/baseq3 ]; then echo "You need to set COPYDIR to where you installed Trem!"; false; fi
+ $(INSTALL) -s -m 0755 $(BR)/tremulous.$(ARCH)$(BINEXT) $(COPYDIR)/tremulous.$(ARCH)$(BINEXT)
- @if [ -f $(BR)/$(PLATFORM)tremded$(BINEXT) ]; then \
- $(INSTALL) -s -m 0755 $(BR)/$(PLATFORM)tremded$(BINEXT) $(COPYDIR)/tremded
+ @if [ -f $(BR)/tremded.$(ARCH)$(BINEXT) ]; then \
+ $(INSTALL) -s -m 0755 $(BR)/tremded.$(ARCH)$(BINEXT) $(COPYDIR)/tremded.$(ARCH)$(BINEXT); \
fi
-$(MKDIR) -p -m 0755 $(COPYDIR)/base
$(INSTALL) -s -m 0755 $(BR)/base/cgame$(ARCH).$(SHLIBEXT) \
@@ -1655,6 +1449,12 @@ installer: build_release
D_FILES=$(shell find . -name '*.d')
+$(B)/base/vm/vm.d: $(GOBJ) $(CGOBJ) $(UIOBJ)
+ -rm -f $@
+ find $(B)/base -iname '*.d' | xargs sed -e 's/\.o/\.asm/g' > $@
+
+qvmdeps: $(B)/base/vm/vm.d
+
ifneq ($(strip $(D_FILES)),)
include $(D_FILES)
endif
diff --git a/src/unix/ftola.s b/src/unix/ftola.s
index a84f6aae..2459021b 100644
--- a/src/unix/ftola.s
+++ b/src/unix/ftola.s
@@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "qasm.h"
-#ifdef id386
+#if id386
.data
diff --git a/src/unix/linux_common.c b/src/unix/linux_common.c
deleted file mode 100644
index d7f31189..00000000
--- a/src/unix/linux_common.c
+++ /dev/null
@@ -1,347 +0,0 @@
-#if 0 // not used anymore
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/**
- * GAS syntax equivalents of the MSVC asm memory calls in common.c
- *
- * The following changes have been made to the asm:
- * 1. Registers are loaded by the inline asm arguments when possible
- * 2. Labels have been changed to local label format (0,1,etc.) to allow inlining
- *
- * HISTORY:
- * AH - Created on 08 Dec 2000
- */
-
-#include <unistd.h> // AH - for size_t
-#include <string.h>
-
-// bk001207 - we need something under Linux, too. Mac?
-#if 1 // defined(C_ONLY) // bk010102 - dedicated?
-void Com_Memcpy (void* dest, const void* src, const size_t count) {
- memcpy(dest, src, count);
-}
-
-void Com_Memset (void* dest, const int val, const size_t count) {
- memset(dest, val, count);
-}
-
-#else
-
-typedef enum {
- PRE_READ, // prefetch assuming that buffer is used for reading only
- PRE_WRITE, // prefetch assuming that buffer is used for writing only
- PRE_READ_WRITE // prefetch assuming that buffer is used for both reading and writing
-} e_prefetch;
-
-void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type);
-
-void _copyDWord (unsigned int* dest, const unsigned int constant, const unsigned int count) {
- // MMX version not used on standard Pentium MMX
- // because the dword version is faster (with
- // proper destination prefetching)
- __asm__ __volatile__ (" \
- //mov eax,constant // eax = val \
- //mov edx,dest // dest \
- //mov ecx,count \
- movd %%eax, %%mm0 \
- punpckldq %%mm0, %%mm0 \
-\
- // ensure that destination is qword aligned \
-\
- testl $7, %%edx // qword padding?\
- jz 0f \
- movl %%eax, (%%edx) \
- decl %%ecx \
- addl $4, %%edx \
-\
-0: movl %%ecx, %%ebx \
- andl $0xfffffff0, %%ecx \
- jz 2f \
- jmp 1f \
- .align 16 \
-\
- // funny ordering here to avoid commands \
- // that cross 32-byte boundaries (the \
- // [edx+0] version has a special 3-byte opcode... \
-1: movq %%mm0, 8(%%edx) \
- movq %%mm0, 16(%%edx) \
- movq %%mm0, 24(%%edx) \
- movq %%mm0, 32(%%edx) \
- movq %%mm0, 40(%%edx) \
- movq %%mm0, 48(%%edx) \
- movq %%mm0, 56(%%edx) \
- movq %%mm0, (%%edx)\
- addl $64, %%edx \
- subl $16, %%ecx \
- jnz 1b \
-2: \
- movl %%ebx, %%ecx // ebx = cnt \
- andl $0xfffffff0, %%ecx // ecx = cnt&~15 \
- subl %%ecx, %%ebx \
- jz 6f \
- cmpl $8, %%ebx \
- jl 3f \
-\
- movq %%mm0, (%%edx) \
- movq %%mm0, 8(%%edx) \
- movq %%mm0, 16(%%edx) \
- movq %%mm0, 24(%%edx) \
- addl $32, %%edx \
- subl $8, %%ebx \
- jz 6f \
-\
-3: cmpl $4, %%ebx \
- jl 4f \
- \
- movq %%mm0, (%%edx) \
- movq %%mm0, 8(%%edx) \
- addl $16, %%edx \
- subl $4, %%ebx \
-\
-4: cmpl $2, %%ebx \
- jl 5f \
- movq %%mm0, (%%edx) \
- addl $8, %%edx \
- subl $2, %%ebx \
-\
-5: cmpl $1, %%ebx \
- jl 6f \
- movl %%eax, (%%edx) \
-6: \
- emms \
- "
- : : "a" (constant), "c" (count), "d" (dest)
- : "%ebx", "%edi", "%esi", "cc", "memory");
-}
-
-// optimized memory copy routine that handles all alignment
-// cases and block sizes efficiently
-void Com_Memcpy (void* dest, const void* src, const size_t count) {
- Com_Prefetch (src, count, PRE_READ);
- __asm__ __volatile__ (" \
- pushl %%edi \
- pushl %%esi \
- //mov ecx,count \
- cmpl $0, %%ecx // count = 0 check (just to be on the safe side) \
- je 6f \
- //mov edx,dest \
- movl %0, %%ebx \
- cmpl $32, %%ecx // padding only? \
- jl 1f \
-\
- movl %%ecx, %%edi \
- andl $0xfffffe00, %%edi // edi = count&~31 \
- subl $32, %%edi \
-\
- .align 16 \
-0: \
- movl (%%ebx, %%edi, 1), %%eax \
- movl 4(%%ebx, %%edi, 1), %%esi \
- movl %%eax, (%%edx, %%edi, 1) \
- movl %%esi, 4(%%edx, %%edi, 1) \
- movl 8(%%ebx, %%edi, 1), %%eax \
- movl 12(%%ebx, %%edi, 1), %%esi \
- movl %%eax, 8(%%edx, %%edi, 1) \
- movl %%esi, 12(%%edx, %%edi, 1) \
- movl 16(%%ebx, %%edi, 1), %%eax \
- movl 20(%%ebx, %%edi, 1), %%esi \
- movl %%eax, 16(%%edx, %%edi, 1) \
- movl %%esi, 20(%%edx, %%edi, 1) \
- movl 24(%%ebx, %%edi, 1), %%eax \
- movl 28(%%ebx, %%edi, 1), %%esi \
- movl %%eax, 24(%%edx, %%edi, 1) \
- movl %%esi, 28(%%edx, %%edi, 1) \
- subl $32, %%edi \
- jge 0b \
- \
- movl %%ecx, %%edi \
- andl $0xfffffe00, %%edi \
- addl %%edi, %%ebx // increase src pointer \
- addl %%edi, %%edx // increase dst pointer \
- andl $31, %%ecx // new count \
- jz 6f // if count = 0, get outta here \
-\
-1: \
- cmpl $16, %%ecx \
- jl 2f \
- movl (%%ebx), %%eax \
- movl %%eax, (%%edx) \
- movl 4(%%ebx), %%eax \
- movl %%eax, 4(%%edx) \
- movl 8(%%ebx), %%eax \
- movl %%eax, 8(%%edx) \
- movl 12(%%ebx), %%eax \
- movl %%eax, 12(%%edx) \
- subl $16, %%ecx \
- addl $16, %%ebx \
- addl $16, %%edx \
-2: \
- cmpl $8, %%ecx \
- jl 3f \
- movl (%%ebx), %%eax \
- movl %%eax, (%%edx) \
- movl 4(%%ebx), %%eax \
- subl $8, %%ecx \
- movl %%eax, 4(%%edx) \
- addl $8, %%ebx \
- addl $8, %%edx \
-3: \
- cmpl $4, %%ecx \
- jl 4f \
- movl (%%ebx), %%eax // here 4-7 bytes \
- addl $4, %%ebx \
- subl $4, %%ecx \
- movl %%eax, (%%edx) \
- addl $4, %%edx \
-4: // 0-3 remaining bytes \
- cmpl $2, %%ecx \
- jl 5f \
- movw (%%ebx), %%ax // two bytes \
- cmpl $3, %%ecx // less than 3? \
- movw %%ax, (%%edx) \
- jl 6f \
- movb 2(%%ebx), %%al // last byte \
- movb %%al, 2(%%edx) \
- jmp 6f \
-5: \
- cmpl $1, %%ecx \
- jl 6f \
- movb (%%ebx), %%al \
- movb %%al, (%%edx) \
-6: \
- popl %%esi \
- popl %%edi \
- "
- : : "m" (src), "d" (dest), "c" (count)
- : "%eax", "%ebx", "%edi", "%esi", "cc", "memory");
-}
-
-void Com_Memset (void* dest, const int val, const size_t count)
-{
- unsigned int fillval;
-
- if (count < 8)
- {
- __asm__ __volatile__ (" \
- //mov edx,dest \
- //mov eax, val \
- movb %%al, %%ah \
- movl %%eax, %%ebx \
- andl $0xffff, %%ebx \
- shll $16, %%eax \
- addl %%ebx, %%eax // eax now contains pattern \
- //mov ecx,count \
- cmpl $4, %%ecx \
- jl 0f \
- movl %%eax, (%%edx) // copy first dword \
- addl $4, %%edx \
- subl $4, %%ecx \
- 0: cmpl $2, %%ecx \
- jl 1f \
- movw %%ax, (%%edx) // copy 2 bytes \
- addl $2, %%edx \
- subl $2, %%ecx \
- 1: cmpl $0, %%ecx \
- je 2f \
- movb %%al, (%%edx) // copy single byte \
- 2: \
- "
- : : "d" (dest), "a" (val), "c" (count)
- : "%ebx", "%edi", "%esi", "cc", "memory");
-
- return;
- }
-
- fillval = val;
-
- fillval = fillval|(fillval<<8);
- fillval = fillval|(fillval<<16); // fill dword with 8-bit pattern
-
- _copyDWord ((unsigned int*)(dest),fillval, count/4);
-
- __asm__ __volatile__ (" // padding of 0-3 bytes \
- //mov ecx,count \
- movl %%ecx, %%eax \
- andl $3, %%ecx \
- jz 1f \
- andl $0xffffff00, %%eax \
- //mov ebx,dest \
- addl %%eax, %%edx \
- movl %0, %%eax \
- cmpl $2, %%ecx \
- jl 0f \
- movw %%ax, (%%edx) \
- cmpl $2, %%ecx \
- je 1f \
- movb %%al, 2(%%edx) \
- jmp 1f \
-0: \
- cmpl $0, %%ecx\
- je 1f\
- movb %%al, (%%edx)\
-1: \
- "
- : : "m" (fillval), "c" (count), "d" (dest)
- : "%eax", "%ebx", "%edi", "%esi", "cc", "memory");
-}
-
-void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type)
-{
- // write buffer prefetching is performed only if
- // the processor benefits from it. Read and read/write
- // prefetching is always performed.
-
- switch (type)
- {
- case PRE_WRITE : break;
- case PRE_READ:
- case PRE_READ_WRITE:
-
- __asm__ __volatile__ ("\
- //mov ebx,s\
- //mov ecx,bytes\
- cmpl $4096, %%ecx // clamp to 4kB\
- jle 0f\
- movl $4096, %%ecx\
- 0:\
- addl $0x1f, %%ecx\
- shrl $5, %%ecx // number of cache lines\
- jz 2f\
- jmp 1f\
-\
- .align 16\
- 1: testb %%al, (%%edx)\
- addl $32, %%edx\
- decl %%ecx\
- jnz 1b\
- 2:\
- "
- : : "d" (s), "c" (bytes)
- : "%eax", "%ebx", "%edi", "%esi", "memory", "cc");
-
- break;
- }
-}
-
-#endif
-#endif