Compare commits

...
39 Commits
Author SHA1 Message Date
OM 76f107230c Exchanged SURF_NOLIGHTMAP and SURF_HINT 2023-05-19 13:57:35 +02:00
OM 4a49b15649 Removed CONTENTS_FOG
Added more surface params
2023-05-19 13:56:07 +02:00
OM 6c448694b6 Fixed static models color rendering 2023-05-19 13:40:29 +02:00
OM 34a1cee89b Made sure to unpack static models correctly 2023-05-19 13:40:18 +02:00
OM 29239dadfa Don't call ri.Hunk_Alloc when there are no texmods 2023-05-19 13:40:03 +02:00
OM e5a4574f92 Added *R_DistanceCullPointAndRadius* 2023-05-19 13:39:31 +02:00
OM 2d70547f9d Cleanup 2023-05-19 03:21:04 +02:00
OM f6279e8c17 *R_RecursiveWorldNode* now take the fog frustum into account, it also calls *R_AddPermanentMarkFragmentSurfaces* and set the vis static models 2023-05-19 03:20:50 +02:00
OM 18ade839c6 Added more shader commands
More fox support
2023-05-19 03:19:56 +02:00
OM b72eb8c6cc Using PLANE_NON_AXIAL instead of 3 2023-05-19 03:13:37 +02:00
OM e0446db81d Added one more mark function 2023-05-19 03:13:23 +02:00
OM a8bb9aaa77 Using qglFogi instead 2023-05-19 03:12:55 +02:00
OM 6595c3c673 Added sprites and ter marks to the render scene 2023-05-19 02:12:03 +02:00
OM 4ecf3195a5 Added *R_CullLocalBoxOffset* 2023-05-19 02:11:45 +02:00
OM 02f0e309e3 Implemented *R_ClearRealDlights*, *R_UploadDlights* and *R_AllocLMBlock* 2023-05-19 02:11:28 +02:00
OM 0fdfcf48f9 Added *RB_ComputeShadowVolume* (not implemented) 2023-05-19 02:10:56 +02:00
OM e9b5c7efd5 Initialize extension and level marks
Initialize the font debug string
2023-05-19 02:10:38 +02:00
OM 2a32b75815 Added GL flags 2023-05-19 02:10:19 +02:00
OM d966afe4ef Added *g_bInfoworldtris* 2023-05-19 02:10:03 +02:00
OM 92e2d42e19 Pre-added marks functions 2023-05-19 02:09:28 +02:00
OM 58e5e3fd63 Added multi-texture GL values
Don't iterate the stage if it has a skyAlpha gen near invisibility
2023-05-19 02:09:13 +02:00
OM b61c7b3988 Fog fixes 2023-05-19 02:08:32 +02:00
OM ee030f27e2 Early implementation of fog and sky portal 2023-05-19 00:29:13 +02:00
OM 02df95fc21 Updated the README file 2023-05-18 20:54:12 +02:00
OM 03100b47c1 Set the project name to openmohaa 2023-05-18 20:24:09 +02:00
OM 67444b0f15 Fixed sound being muted on startup 2023-05-18 20:21:38 +02:00
OM f6ae9a2b43 Incremented the version number 2023-05-18 20:16:19 +02:00
OM 98cd85bc9a Fixed compilation under Linux 2023-05-18 20:07:54 +02:00
OM 83a83b08f6 Export PDB of app & modules 2023-05-18 19:56:46 +02:00
OM 448e9010dc Fixed alias random indexes being wrong 2023-05-18 19:47:50 +02:00
OM ce69ed75f7 Reverted to Quake 3 sound system 2023-05-18 19:47:37 +02:00
OM 6ac70d6b7c Fixed terrain patch not drawing properly 2023-05-18 18:51:45 +02:00
OM 4f588d939d Prevent spawning a tempmodel that has the world as a tempmodel 2023-05-18 18:45:25 +02:00
OM f6ebdd1998 Better multitexture / bundle support 2023-05-18 18:17:32 +02:00
OM 7438dd709c Fixed terrain unpacking 2023-05-18 18:17:18 +02:00
OM 1207b46937 Fixed terrains vertices being wrongly rendered 2023-05-18 17:15:52 +02:00
OM 497f853171 Fixed terrain varnodes being badly loaded 2023-05-18 17:14:00 +02:00
OM 4984f8b925 nextBundle fix 2023-05-18 16:40:17 +02:00
OM a1d581df39 Introducing full LOD terrain support 2023-05-18 14:41:37 +02:00
48 changed files with 4326 additions and 6562 deletions

No files matched your search

+6 -2
View File
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(omohaaded)
project(openmohaa)
include(TargetArch.cmake)
@@ -205,7 +205,8 @@ if(WIN32)
endif()
target_link_libraries(omohaaded PRIVATE wsock32 ws2_32)
target_link_libraries(omohaaded PRIVATE winmm)
INSTALL(FILES $<TARGET_PDB_FILE:fgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
INSTALL(FILES $<TARGET_PDB_FILE:omohaaded> DESTINATION "./" OPTIONAL)
elseif(UNIX)
find_package(Threads)
@@ -280,6 +281,9 @@ if (WITH_CLIENT)
target_link_libraries(openmohaa PRIVATE wsock32 ws2_32)
target_link_libraries(openmohaa PRIVATE winmm)
INSTALL(FILES $<TARGET_PDB_FILE:cgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
INSTALL(FILES $<TARGET_PDB_FILE:openmohaa> DESTINATION "./" OPTIONAL)
elseif(UNIX)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
+23 -11
View File
@@ -14,28 +14,36 @@
## Current State
OpenMoHAA is still in its early days.
### Server
The server version can successfully be built. There are few unimplemented stuff from the game library :
The server version can successfully be built.
Some stuff are not working as intended, such as Actor or Vehicle. These systems are both almost fully implemented, but not really in stable state.
- Actor
- Vehicle
Overall the server part and the game module are almost fully implemented, but the stability may vary, there may be some minor bugs and crashes.
### Client
There is currently no client build because the UI code is currently unimplemented. Here is what's missing or unimplemented :
The client version of OpenMoHAA is partially implemented and not stable currently. The cgame module is partially implemented as well, but is compatible with the original MOH:AA game. Credits to **Heavy Metal: F.A.K.K. 2**'s SDK for the cgame module.
- rendering (mostly advanced)
- sound (must be reworked)
- UI
Here is the current working state for each part of the engine:
Using CMake, the client build and successfully be built by adding `-DWITH_CLIENT=1`
The client game module (cgame) is partially implemented, and is compatible with the original MOH:AA module.
| Part name | Full | Almost | Half | Early | Bad | Not working | Comment |
|-------------------------|------|--------|------|-------|-----|-------------|-------------------------------------------------------------------|
| Audio | | | | | x | | Very basic implementation from Quake III |
| CG Module | | x | | | | | Missing FX, Marks and decals |
| Client | | | x | | | | Missing GameSpy, server list, binds, map picker, ... |
| Collision | x | | | | | | |
| Model/TIKI/Skeletor | x | | | | | | |
| Renderer | | | | x | | | Missing ghost, marks, sphere lights, sky portal, sun flare, swipe |
| Server | | x | | | | | Probably a few bugs remaining |
| Server module (fgame) | | x | | | | | Actor, vehicle, and few gameplay bugs |
| UI | | | | x | | | Has core features only (menu, widgets, console, hud, urc loading) |
## Running
Backup the existing **gamex86.dll** (rename it to **gamex86.bak**).
Backup existing mohaa files, **cgamex86.dll** and **gamex86.dll** (set their extension to **.bak**)
a) extract archive to your MOHAA installation directory.
@@ -53,6 +61,8 @@ You can now start a local OpenMOHAA server or play on a server.
## Compiling
OpenMoHAA supports both x86 and x64 architectures, and although the target platform is Windows, it still can be compiled for other platforms, and even other architectures.
These are the tools required for all platforms :
- CMake >= 3.5
- Flex and Bison (currently not used)
@@ -60,6 +70,8 @@ These are the tools required for all platforms :
The installation directory can be set to MOHAA directory.
The client build and successfully be built by adding `-DWITH_CLIENT=1` to the CMake command line.
### Linux
These are the tools required on Unix :
+9
View File
@@ -4732,6 +4732,15 @@ void ClientGameCommandManager::SpawnTempModel(int mcount, int timeAlive)
}
}
}
// Make sure to not spawn the world model as a tempmodel
// Of course it would become extremely confusing...
if (!(p->cgd.flags & T_DLIGHT) && p->ent.reType == ET_MODELANIM_SKEL && !p->ent.hModel)
{
Com_Printf("^~^~^ not spawning tempmodel because it is using the world as a brush model\n");
FreeTempModel(p);
break;
}
}
}
+4 -4
View File
@@ -1142,17 +1142,17 @@ redump:
case ZA_SOUND_MONO:
if (!cinTable[currentHandle].silent) {
ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
S_RawSamples(0, 22050, 2, 1, (byte *)sbuf, 1.0f);
}
break;
case ZA_SOUND_STEREO:
if (!cinTable[currentHandle].silent) {
if (cinTable[currentHandle].numQuads == -1) {
S_Update();
s_rawend[0] = s_soundtime;
s_rawend = s_soundtime;
}
ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
S_RawSamples(0, 22050, 2, 2, (byte *)sbuf, 1.0f);
}
break;
case ROQ_QUAD_INFO:
@@ -1469,7 +1469,7 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi
}
if (!cinTable[currentHandle].silent) {
s_rawend[0] = s_soundtime;
s_rawend = s_soundtime;
}
return currentHandle;
+4 -4
View File
@@ -25,7 +25,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/*
** Intel/DVI ADPCM coder/decoder.
**
** The algorithm for this coder was taken from the IMA Compatibility Project
** The algorithm for this coder was taken from the IMA Compatability Project
** proceedings, Vol 2, Number 2; May 1992.
**
** Version 1.2, 18-Dec-92.
@@ -278,7 +278,7 @@ void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
out = (byte *)chunk->sndChunk;
// get samples
S_AdpcmDecode((char *) out, to, SND_CHUNK_SIZE_BYTE*2, &state );
S_AdpcmDecode( out, to, SND_CHUNK_SIZE_BYTE*2, &state );
}
@@ -310,7 +310,7 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else if (chunk != NULL) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
@@ -322,7 +322,7 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
out = (byte *)chunk->sndChunk;
// encode the samples
S_AdpcmEncode( samples + inOffset, (char *) out, n, &state );
S_AdpcmEncode( samples + inOffset, out, n, &state );
inOffset += n;
count -= n;
-229
View File
@@ -1,229 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
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
===========================================================================
*/
/* This file is only compiled for PowerPC builds with Altivec support.
Altivec intrinsics need to be in a separate file, so GCC's -maltivec
command line can enable them, but give us the option to _not_ use that
on other files, where the compiler might then generate Altivec
instructions for normal floating point, crashing on G3 (etc) processors. */
#include "client.h"
#include "snd_local.h"
#if idppc_altivec
#if !defined(__APPLE__)
#include <altivec.h>
#endif
void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data, aoff, boff;
int leftvol, rightvol;
int i, j;
portable_samplepair_t *samp;
sndBuffer *chunk;
short *samples;
float ooff, fdata[2], fdiv, fleftvol, frightvol;
if (sc->soundChannels <= 0) {
return;
}
samp = &paintbuffer[ bufferOffset ];
if (ch->doppler) {
sampleOffset = sampleOffset*ch->oldDopplerScale;
}
if ( sc->soundChannels == 2 ) {
sampleOffset *= sc->soundChannels;
if ( sampleOffset & 1 ) {
sampleOffset &= ~1;
}
}
chunk = sc->soundData;
while (sampleOffset>=SND_CHUNK_SIZE) {
chunk = chunk->next;
sampleOffset -= SND_CHUNK_SIZE;
if (!chunk) {
chunk = sc->soundData;
}
}
if (!ch->doppler || ch->dopplerScale==1.0f) {
vector signed short volume_vec;
vector unsigned int volume_shift;
int vectorCount, samplesLeft, chunkSamplesLeft;
leftvol = ch->leftvol*snd_vol;
rightvol = ch->rightvol*snd_vol;
samples = chunk->sndChunk;
((short *)&volume_vec)[0] = leftvol;
((short *)&volume_vec)[1] = leftvol;
((short *)&volume_vec)[4] = leftvol;
((short *)&volume_vec)[5] = leftvol;
((short *)&volume_vec)[2] = rightvol;
((short *)&volume_vec)[3] = rightvol;
((short *)&volume_vec)[6] = rightvol;
((short *)&volume_vec)[7] = rightvol;
volume_shift = vec_splat_u32(8);
i = 0;
while(i < count) {
/* Try to align destination to 16-byte boundary */
while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
if ( sc->soundChannels == 2 ) {
data = samples[sampleOffset++];
}
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
i++;
}
/* Destination is now aligned. Process as many 8-sample
chunks as we can before we run out of room from the current
sound chunk. We do 8 per loop to avoid extra source data reads. */
samplesLeft = count - i;
chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
if(samplesLeft > chunkSamplesLeft)
samplesLeft = chunkSamplesLeft;
vectorCount = samplesLeft / 8;
if(vectorCount)
{
vector unsigned char tmp;
vector short s0, s1, sampleData0, sampleData1;
vector signed int merge0, merge1;
vector signed int d0, d1, d2, d3;
vector unsigned char samplePermute0 =
VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
vector unsigned char samplePermute1 =
VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
vector unsigned char loadPermute0, loadPermute1;
// Rather than permute the vectors after we load them to do the sample
// replication and rearrangement, we permute the alignment vector so
// we do everything in one step below and avoid data shuffling.
tmp = vec_lvsl(0,&samples[sampleOffset]);
loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
s0 = *(vector short *)&samples[sampleOffset];
while(vectorCount)
{
/* Load up source (16-bit) sample data */
s1 = *(vector short *)&samples[sampleOffset+7];
/* Load up destination sample data */
d0 = *(vector signed int *)&samp[i];
d1 = *(vector signed int *)&samp[i+2];
d2 = *(vector signed int *)&samp[i+4];
d3 = *(vector signed int *)&samp[i+6];
sampleData0 = vec_perm(s0,s1,loadPermute0);
sampleData1 = vec_perm(s0,s1,loadPermute1);
merge0 = vec_mule(sampleData0,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData0,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d0 = vec_add(merge0,d0);
d1 = vec_add(merge1,d1);
merge0 = vec_mule(sampleData1,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData1,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d2 = vec_add(merge0,d2);
d3 = vec_add(merge1,d3);
/* Store destination sample data */
*(vector signed int *)&samp[i] = d0;
*(vector signed int *)&samp[i+2] = d1;
*(vector signed int *)&samp[i+4] = d2;
*(vector signed int *)&samp[i+6] = d3;
i += 8;
vectorCount--;
s0 = s1;
sampleOffset += 8;
}
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
}
}
} else {
fleftvol = ch->leftvol*snd_vol;
frightvol = ch->rightvol*snd_vol;
ooff = sampleOffset;
samples = chunk->sndChunk;
for ( i=0 ; i<count ; i++ ) {
aoff = ooff;
ooff = ooff + ch->dopplerScale * sc->soundChannels;
boff = ooff;
fdata[0] = fdata[1] = 0;
for (j=aoff; j<boff; j += sc->soundChannels) {
if (j == SND_CHUNK_SIZE) {
chunk = chunk->next;
if (!chunk) {
chunk = sc->soundData;
}
samples = chunk->sndChunk;
ooff -= SND_CHUNK_SIZE;
}
if ( sc->soundChannels == 2 ) {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
} else {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
}
}
fdiv = 256 * (boff-aoff) / sc->soundChannels;
samp[i].left += (fdata[0] * fleftvol)/fdiv;
samp[i].right += (fdata[1] * frightvol)/fdiv;
}
}
}
#endif
-237
View File
@@ -1,237 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
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_codec.h"
static snd_codec_t *codecs;
/*
=================
S_CodecGetSound
Opens/loads a sound, tries codec based on the sound's file extension
then tries all supported codecs.
=================
*/
static void *S_CodecGetSound(const char *filename, snd_info_t *info)
{
snd_codec_t *codec;
snd_codec_t *orgCodec = NULL;
qboolean orgNameFailed = qfalse;
char localName[ MAX_QPATH ];
const char *ext;
char altName[ MAX_QPATH ];
void *rtn = NULL;
Q_strncpyz(localName, filename, MAX_QPATH);
ext = COM_GetExtension(localName);
if( *ext )
{
// Look for the correct loader and use it
for( codec = codecs; codec; codec = codec->next )
{
if( !Q_stricmp( ext, codec->ext ) )
{
// Load
if( info )
rtn = codec->load(localName, info);
else
rtn = codec->open(localName);
break;
}
}
// A loader was found
if( codec )
{
if( !rtn )
{
// Loader failed, most likely because the file isn't there;
// try again without the extension
orgNameFailed = qtrue;
orgCodec = codec;
COM_StripExtension( filename, localName, MAX_QPATH );
}
else
{
// Something loaded
return rtn;
}
}
}
// Try and find a suitable match using all
// the sound codecs supported
for( codec = codecs; codec; codec = codec->next )
{
if( codec == orgCodec )
continue;
Com_sprintf( altName, sizeof (altName), "%s.%s", localName, codec->ext );
// Load
if( info )
rtn = codec->load(altName, info);
else
rtn = codec->open(altName);
if( rtn )
{
if( orgNameFailed )
{
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s not present, using %s instead\n",
filename, altName );
}
return rtn;
}
}
Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename);
return NULL;
}
/*
=================
S_CodecInit
=================
*/
void S_CodecInit()
{
codecs = NULL;
#ifdef USE_CODEC_OPUS
S_CodecRegister(&opus_codec);
#endif
#ifdef USE_CODEC_VORBIS
S_CodecRegister(&ogg_codec);
#endif
// Register wav codec last so that it is always tried first when a file extension was not found
S_CodecRegister(&wav_codec);
}
/*
=================
S_CodecShutdown
=================
*/
void S_CodecShutdown()
{
codecs = NULL;
}
/*
=================
S_CodecRegister
=================
*/
void S_CodecRegister(snd_codec_t *codec)
{
codec->next = codecs;
codecs = codec;
}
/*
=================
S_CodecLoad
=================
*/
void *S_CodecLoad(const char *filename, snd_info_t *info)
{
return S_CodecGetSound(filename, info);
}
/*
=================
S_CodecOpenStream
=================
*/
snd_stream_t *S_CodecOpenStream(const char *filename)
{
return S_CodecGetSound(filename, NULL);
}
void S_CodecCloseStream(snd_stream_t *stream)
{
stream->codec->close(stream);
}
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
return stream->codec->read(stream, bytes, buffer);
}
//=======================================================================
// Util functions (used by codecs)
/*
=================
S_CodecUtilOpen
=================
*/
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
{
snd_stream_t *stream;
fileHandle_t hnd;
int length;
// Try to open the file
length = FS_FOpenFileRead(filename, &hnd, qtrue, qtrue);
if(!hnd)
{
Com_DPrintf("Can't read sound file %s\n", filename);
return NULL;
}
// Allocate a stream
stream = Z_Malloc(sizeof(snd_stream_t));
if(!stream)
{
FS_FCloseFile(hnd);
return NULL;
}
// Copy over, return
stream->codec = codec;
stream->file = hnd;
stream->length = length;
return stream;
}
/*
=================
S_CodecUtilClose
=================
*/
void S_CodecUtilClose(snd_stream_t **stream)
{
FS_FCloseFile((*stream)->file);
Z_Free(*stream);
*stream = NULL;
}
-107
View File
@@ -1,107 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
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
===========================================================================
*/
#ifndef _SND_CODEC_H_
#define _SND_CODEC_H_
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
typedef struct snd_info_s
{
int rate;
int width;
int channels;
int samples;
int size;
int dataofs;
} snd_info_t;
typedef struct snd_codec_s snd_codec_t;
typedef struct snd_stream_s
{
snd_codec_t *codec;
fileHandle_t file;
snd_info_t info;
int length;
int pos;
void *ptr;
} snd_stream_t;
// Codec functions
typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
// Codec data structure
struct snd_codec_s
{
char *ext;
CODEC_LOAD load;
CODEC_OPEN open;
CODEC_READ read;
CODEC_CLOSE close;
snd_codec_t *next;
};
// Codec management
void S_CodecInit( void );
void S_CodecShutdown( void );
void S_CodecRegister(snd_codec_t *codec);
void *S_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_CodecOpenStream(const char *filename);
void S_CodecCloseStream(snd_stream_t *stream);
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Util functions (used by codecs)
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
void S_CodecUtilClose(snd_stream_t **stream);
// WAV Codec
extern snd_codec_t wav_codec;
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
void S_WAV_CodecCloseStream(snd_stream_t *stream);
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Ogg Vorbis codec
#ifdef USE_CODEC_VORBIS
extern snd_codec_t ogg_codec;
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
void S_OGG_CodecCloseStream(snd_stream_t *stream);
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_VORBIS
// Ogg Opus codec
#ifdef USE_CODEC_OPUS
extern snd_codec_t opus_codec;
void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename);
void S_OggOpus_CodecCloseStream(snd_stream_t *stream);
int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_OPUS
#endif // !_SND_CODEC_H_
-717
View File
@@ -1,717 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de>
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
===========================================================================
*/
#if USE_CODEC_MP3
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the MP3 codec
#include <mad.h>
#define MP3_SAMPLE_WIDTH 2
#define MP3_PCMSAMPLES_PERSLICE 32
// buffer size used when reading through the mp3
#define MP3_DATA_BUFSIZ 128*1024
// undefine this if you don't want any dithering.
#define MP3_DITHERING
// Q3 MP3 codec
snd_codec_t mp3_codec =
{
".mp3",
S_MP3_CodecLoad,
S_MP3_CodecOpenStream,
S_MP3_CodecReadStream,
S_MP3_CodecCloseStream,
NULL
};
// structure used for info purposes
struct snd_codec_mp3_info
{
byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed
// by the decoder.
struct mad_stream madstream; // uses encbuf as buffer.
struct mad_frame madframe; // control structures for libmad.
struct mad_synth madsynth;
byte *pcmbuf; // buffer for not-used samples.
int buflen; // length of buffer data.
int pcmbufsize; // amount of allocated memory for
// pcmbuf. This should have at least
// the size of a decoded mp3 frame.
byte *dest; // copy decoded data here.
int destlen; // amount of already copied data.
int destsize; // amount of bytes we must decode.
};
/*************** MP3 utility functions ***************/
/*
=================
S_MP3_ReadData
=================
*/
// feed libmad with data
int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize)
{
int retval;
int leftover;
if(!stream)
return -1;
leftover = madstream->bufend - madstream->next_frame;
if(leftover > 0)
memmove(encbuf, madstream->this_frame, leftover);
// Fill the buffer right to the end
retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file);
if(retval <= 0)
{
// EOF reached, that's ok.
return 0;
}
mad_stream_buffer(madstream, encbuf, retval + leftover);
return retval;
}
/*
=================
S_MP3_Scanfile
to determine the samplecount, we apparently must get *all* headers :(
I basically used the xmms-mad plugin source to see how this stuff works.
returns a value < 0 on error.
=================
*/
int S_MP3_Scanfile(snd_stream_t *stream)
{
struct mad_stream madstream;
struct mad_header madheader;
int retval;
int samplecount;
byte encbuf[MP3_DATA_BUFSIZ];
// error out on invalid input.
if(!stream)
return -1;
mad_stream_init(&madstream);
mad_header_init(&madheader);
while(1)
{
retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf));
if(retval < 0)
return -1;
else if(retval == 0)
break;
// Start decoding the headers.
while(1)
{
if((retval = mad_header_decode(&madheader, &madstream)) < 0)
{
if(madstream.error == MAD_ERROR_BUFLEN)
{
// We need to read more data
break;
}
if(!MAD_RECOVERABLE (madstream.error))
{
// unrecoverable error... we must bail out.
return retval;
}
mad_stream_skip(&madstream, madstream.skiplen);
continue;
}
// we got a valid header.
if(madheader.layer != MAD_LAYER_III)
{
// we don't support non-mp3s
return -1;
}
if(!stream->info.samples)
{
// This here is the very first frame. Set initial values now,
// that we expect to stay constant throughout the whole mp3.
stream->info.rate = madheader.samplerate;
stream->info.width = MP3_SAMPLE_WIDTH;
stream->info.channels = MAD_NCHANNELS(&madheader);
stream->info.samples = 0;
stream->info.size = 0; // same here.
stream->info.dataofs = 0;
}
else
{
// Check whether something changed that shouldn't.
if(stream->info.rate != madheader.samplerate ||
stream->info.channels != MAD_NCHANNELS(&madheader))
return -1;
}
// Update the counters
samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE;
stream->info.samples += samplecount;
stream->info.size += samplecount * stream->info.channels * stream->info.width;
}
}
// Reset the file pointer so we can do the real decoding.
FS_Seek(stream->file, 0, FS_SEEK_SET);
return 0;
}
/************************ dithering functions ***************************/
#ifdef MP3_DITHERING
// All dithering done here is taken from the GPL'ed xmms-mad plugin.
/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome. For any question, comments, */
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */
/* matumoto@math.keio.ac.jp */
/* Period parameters */
#define MP3_DITH_N 624
#define MP3_DITH_M 397
#define MATRIX_A 0x9908b0df /* constant vector a */
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
#define LOWER_MASK 0x7fffffff /* least significant r bits */
/* Tempering parameters */
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_U(y) (y >> 11)
#define TEMPERING_SHIFT_S(y) (y << 7)
#define TEMPERING_SHIFT_T(y) (y << 15)
#define TEMPERING_SHIFT_L(y) (y >> 18)
static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */
static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */
/* initializing the array with a NONZERO seed */
void sgenrand(unsigned long seed)
{
/* setting initial seeds to mt[MP3_DITH_N] using */
/* the generator Line 25 of Table 1 in */
/* [KNUTH 1981, The Art of Computer Programming */
/* Vol. 2 (2nd Ed.), pp102] */
mt[0]= seed & 0xffffffff;
for (mti=1; mti<MP3_DITH_N; mti++)
mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
}
unsigned long genrand(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */
int kk;
if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */
sgenrand(4357); /* a default initial seed is used */
for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (;kk<MP3_DITH_N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);
return y;
}
long triangular_dither_noise(int nbits) {
// parameter nbits : the peak-to-peak amplitude desired (in bits)
// use with nbits set to 2 + nber of bits to be trimmed.
// (because triangular is made from two uniformly distributed processes,
// it starts at 2 bits peak-to-peak amplitude)
// see The Theory of Dithered Quantization by Robert Alexander Wannamaker
// for complete proof of why that's optimal
long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[
//int signe = (v>0) ? 1 : -1;
long P = 1 << (32 - nbits); // the power of 2
v /= P;
// now v in ]-2^(nbits-1), 2^(nbits-1) [
return v;
}
#endif // MP3_DITHERING
/************************ decoder functions ***************************/
/*
=================
S_MP3_Scale
Converts the signal to 16 bit LE-PCM data and does dithering.
- borrowed from xmms-mad plugin source.
=================
*/
/*
* xmms-mad - mp3 plugin for xmms
* Copyright (C) 2001-2002 Sam Clegg
*/
signed int S_MP3_Scale(mad_fixed_t sample)
{
int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
#ifdef MP3_DITHERING
int dither;
#endif
// round
sample += (1L << (n_bits_to_loose - 1));
#ifdef MP3_DITHERING
dither = triangular_dither_noise(n_bits_to_loose + 1);
sample += dither;
#endif
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> n_bits_to_loose;
}
/*
=================
S_MP3_PCMCopy
Copy and convert pcm data until bytecount bytes have been written.
return the position in pcm->samples.
indicate the amount of actually written bytes in wrotecnt.
=================
*/
int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs,
int sampleofs, int bytecount, int *wrotecnt)
{
int written = 0;
signed int sample;
int framesize = pcm->channels * MP3_SAMPLE_WIDTH;
// add new pcm data.
while(written < bytecount && sampleofs < pcm->length)
{
sample = S_MP3_Scale(pcm->samples[0][sampleofs]);
#ifdef Q3_BIG_ENDIAN
// output to 16 bit big endian PCM
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
// output to 16 bit little endian PCM
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
if(pcm->channels == 2)
{
sample = S_MP3_Scale(pcm->samples[1][sampleofs]);
#ifdef Q3_BIG_ENDIAN
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
}
sampleofs++;
written += framesize;
}
if(wrotecnt)
*wrotecnt = written;
return sampleofs;
}
/*
=================
S_MP3_Decode
=================
*/
// gets executed for every decoded frame.
int S_MP3_Decode(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
struct mad_stream *madstream;
struct mad_frame *madframe;
struct mad_synth *madsynth;
struct mad_pcm *pcm;
int cursize;
int samplecount;
int needcount;
int wrote;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
madstream = &mp3info->madstream;
madframe = &mp3info->madframe;
if(mad_frame_decode(madframe, madstream))
{
if(madstream->error == MAD_ERROR_BUFLEN)
{
// we need more data. Read another chunk.
retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf));
// call myself again now that buffer is full.
if(retval > 0)
retval = S_MP3_Decode(stream);
}
else if(MAD_RECOVERABLE(madstream->error))
{
mad_stream_skip(madstream, madstream->skiplen);
return S_MP3_Decode(stream);
}
else
retval = -1;
return retval;
}
// check whether this really is an mp3
if(madframe->header.layer != MAD_LAYER_III)
return -1;
// generate pcm data
madsynth = &mp3info->madsynth;
mad_synth_frame(madsynth, madframe);
pcm = &madsynth->pcm;
// perform a few checks to see whether something changed that shouldn't.
if(stream->info.rate != pcm->samplerate ||
stream->info.channels != pcm->channels)
{
return -1;
}
// see whether we have got enough data now.
cursize = pcm->length * pcm->channels * stream->info.width;
needcount = mp3info->destsize - mp3info->destlen;
// Copy exactly as many samples as required.
samplecount = S_MP3_PCMCopy(mp3info->dest, pcm,
mp3info->destlen, 0, needcount, &wrote);
mp3info->destlen += wrote;
if(samplecount < pcm->length)
{
// Not all samples got copied. Copy the rest into the pcm buffer.
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
if(samplecount < pcm->length)
{
// The pcm buffer was not large enough. Make it bigger.
byte *newbuf = Z_Malloc(cursize);
if(mp3info->pcmbuf)
{
memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen);
Z_Free(mp3info->pcmbuf);
}
mp3info->pcmbuf = newbuf;
mp3info->pcmbufsize = cursize;
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
}
// we're definitely done.
retval = 0;
}
else if(mp3info->destlen >= mp3info->destsize)
retval = 0;
else
retval = 1;
return retval;
}
/*************** Callback functions for quake3 ***************/
/*
=================
S_MP3_CodecOpenStream
=================
*/
snd_stream_t *S_MP3_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
struct snd_codec_mp3_info *mp3info;
// Open the stream
stream = S_CodecUtilOpen(filename, &mp3_codec);
if(!stream || stream->length <= 0)
return NULL;
// We have to scan through the MP3 to determine the important mp3 info.
if(S_MP3_Scanfile(stream) < 0)
{
// scanning didn't work out...
S_CodecUtilClose(&stream);
return NULL;
}
// Initialize the mp3 info structure we need for streaming
mp3info = Z_Malloc(sizeof(*mp3info));
if(!mp3info)
{
S_CodecUtilClose(&stream);
return NULL;
}
stream->ptr = mp3info;
// initialize the libmad control structures.
mad_stream_init(&mp3info->madstream);
mad_frame_init(&mp3info->madframe);
mad_synth_init(&mp3info->madsynth);
if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0)
{
// we didnt read anything, that's bad.
S_MP3_CodecCloseStream(stream);
return NULL;
}
return stream;
}
/*
=================
S_MP3_CodecCloseStream
=================
*/
// free all memory we allocated.
void S_MP3_CodecCloseStream(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
if(!stream)
return;
// free all data in our mp3info tree
if(stream->ptr)
{
mp3info = stream->ptr;
if(mp3info->pcmbuf)
Z_Free(mp3info->pcmbuf);
mad_synth_finish(&mp3info->madsynth);
mad_frame_finish(&mp3info->madframe);
mad_stream_finish(&mp3info->madstream);
Z_Free(stream->ptr);
}
S_CodecUtilClose(&stream);
}
/*
=================
S_MP3_CodecReadStream
=================
*/
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
struct snd_codec_mp3_info *mp3info;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
// Make sure we get complete frames all the way through.
bytes -= bytes % (stream->info.channels * stream->info.width);
if(mp3info->buflen)
{
if(bytes < mp3info->buflen)
{
// we still have enough bytes in our decoded pcm buffer
memcpy(buffer, mp3info->pcmbuf, bytes);
// remove the portion from our buffer.
mp3info->buflen -= bytes;
memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen);
return bytes;
}
else
{
// copy over the samples we already have.
memcpy(buffer, mp3info->pcmbuf, mp3info->buflen);
mp3info->destlen = mp3info->buflen;
mp3info->buflen = 0;
}
}
else
mp3info->destlen = 0;
mp3info->dest = buffer;
mp3info->destsize = bytes;
do
{
retval = S_MP3_Decode(stream);
} while(retval > 0);
// if there was an error return nothing.
if(retval < 0)
return 0;
return mp3info->destlen;
}
/*
=====================================================================
S_MP3_CodecLoad
We handle S_MP3_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *pcmbuffer;
// check if input is valid
if(!filename)
return NULL;
stream = S_MP3_CodecOpenStream(filename);
if(!stream)
return NULL;
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->dataofs = stream->info.dataofs;
// allocate enough buffer for all pcm data
// pcmbuffer = Z_Malloc(stream->info.size);
pcmbuffer = Hunk_AllocateTempMemory(stream->info.size);
if(!pcmbuffer)
{
S_MP3_CodecCloseStream(stream);
return NULL;
}
info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer);
if(info->size <= 0)
{
// we didn't read anything at all. darn.
// Z_Free(pcmbuffer);
Hunk_FreeTempMemory(pcmbuffer);
pcmbuffer = NULL;
}
S_MP3_CodecCloseStream(stream);
return pcmbuffer;
}
#endif
-475
View File
@@ -1,475 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
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
===========================================================================
*/
// OGG support is enabled by this define
#ifdef USE_CODEC_VORBIS
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the OGG codec
#include <errno.h>
#define OV_EXCLUDE_STATIC_CALLBACKS
#include <vorbis/vorbisfile.h>
// The OGG codec can return the samples in a number of different formats,
// we use the standard signed short format.
#define OGG_SAMPLEWIDTH 2
// Q3 OGG codec
snd_codec_t ogg_codec =
{
"ogg",
S_OGG_CodecLoad,
S_OGG_CodecOpenStream,
S_OGG_CodecReadStream,
S_OGG_CodecCloseStream,
NULL
};
// callbacks for vobisfile
// fread() replacement
size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
snd_stream_t *stream;
int byteSize = 0;
int bytesRead = 0;
size_t nMembRead = 0;
// check if input is valid
if(!ptr)
{
errno = EFAULT;
return 0;
}
if(!(size && nmemb))
{
// It's not an error, caller just wants zero bytes!
errno = 0;
return 0;
}
if(!datasource)
{
errno = EBADF;
return 0;
}
// we use a snd_stream_t in the generic pointer to pass around
stream = (snd_stream_t *) datasource;
// FS_Read does not support multi-byte elements
byteSize = nmemb * size;
// read it with the Q3 function FS_Read()
bytesRead = FS_Read(ptr, byteSize, stream->file);
// update the file position
stream->pos += bytesRead;
// this function returns the number of elements read not the number of bytes
nMembRead = bytesRead / size;
// even if the last member is only read partially
// it is counted as a whole in the return value
if(bytesRead % size)
{
nMembRead++;
}
return nMembRead;
}
// fseek() replacement
int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
{
snd_stream_t *stream;
int retVal = 0;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
// we must map the whence to its Q3 counterpart
switch(whence)
{
case SEEK_SET :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = (int) offset;
break;
}
case SEEK_CUR :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos += (int) offset;
break;
}
case SEEK_END :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = stream->length + (int) offset;
break;
}
default :
{
// unknown whence, so we return an error
errno = EINVAL;
return -1;
}
}
// stream->pos shouldn't be smaller than zero or bigger than the filesize
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
return 0;
}
// fclose() replacement
int S_OGG_Callback_close(void *datasource)
{
// we do nothing here and close all things manually in S_OGG_CodecCloseStream()
return 0;
}
// ftell() replacement
long S_OGG_Callback_tell(void *datasource)
{
snd_stream_t *stream;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
return (long) FS_FTell(stream->file);
}
// the callback structure
const ov_callbacks S_OGG_Callbacks =
{
&S_OGG_Callback_read,
&S_OGG_Callback_seek,
&S_OGG_Callback_close,
&S_OGG_Callback_tell
};
/*
=================
S_OGG_CodecOpenStream
=================
*/
snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
// OGG codec control structure
OggVorbis_File *vf;
// some variables used to get informations about the OGG
vorbis_info *OGGInfo;
ogg_int64_t numSamples;
// check if input is valid
if(!filename)
{
return NULL;
}
// Open the stream
stream = S_CodecUtilOpen(filename, &ogg_codec);
if(!stream)
{
return NULL;
}
// alloctate the OggVorbis_File
vf = Z_Malloc(sizeof(OggVorbis_File));
if(!vf)
{
S_CodecUtilClose(&stream);
return NULL;
}
// open the codec with our callbacks and stream as the generic pointer
if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
{
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// the stream must be seekable
if(!ov_seekable(vf))
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// we only support OGGs with one substream
if(ov_streams(vf) != 1)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the info about channels and rate
OGGInfo = ov_info(vf, 0);
if(!OGGInfo)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the number of sample-frames in the OGG
numSamples = ov_pcm_total(vf, 0);
// fill in the info-structure in the stream
stream->info.rate = OGGInfo->rate;
stream->info.width = OGG_SAMPLEWIDTH;
stream->info.channels = OGGInfo->channels;
stream->info.samples = numSamples;
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
stream->info.dataofs = 0;
// We use stream->pos for the file pointer in the compressed ogg file
stream->pos = 0;
// We use the generic pointer in stream for the OGG codec control structure
stream->ptr = vf;
return stream;
}
/*
=================
S_OGG_CodecCloseStream
=================
*/
void S_OGG_CodecCloseStream(snd_stream_t *stream)
{
// check if input is valid
if(!stream)
{
return;
}
// let the OGG codec cleanup its stuff
ov_clear((OggVorbis_File *) stream->ptr);
// free the OGG codec control struct
Z_Free(stream->ptr);
// close the stream
S_CodecUtilClose(&stream);
}
/*
=================
S_OGG_CodecReadStream
=================
*/
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
// buffer handling
int bytesRead, bytesLeft, c;
char *bufPtr;
// Bitstream for the decoder
int BS = 0;
// big endian machines want their samples in big endian order
int IsBigEndian = 0;
# ifdef Q3_BIG_ENDIAN
IsBigEndian = 1;
# endif // Q3_BIG_ENDIAN
// check if input is valid
if(!(stream && buffer))
{
return 0;
}
if(bytes <= 0)
{
return 0;
}
bytesRead = 0;
bytesLeft = bytes;
bufPtr = buffer;
// cycle until we have the requested or all available bytes read
while(-1)
{
// read some bytes from the OGG codec
c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
// no more bytes are left
if(c <= 0)
{
break;
}
bytesRead += c;
bytesLeft -= c;
bufPtr += c;
// we have enough bytes
if(bytesLeft <= 0)
{
break;
}
}
return bytesRead;
}
/*
=====================================================================
S_OGG_CodecLoad
We handle S_OGG_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *buffer;
int bytesRead;
// check if input is valid
if(!(filename && info))
{
return NULL;
}
// open the file as a stream
stream = S_OGG_CodecOpenStream(filename);
if(!stream)
{
return NULL;
}
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->size = stream->info.size;
info->dataofs = stream->info.dataofs;
// allocate a buffer
// this buffer must be free-ed by the caller of this function
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
S_OGG_CodecCloseStream(stream);
return NULL;
}
// fill the buffer
bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
// we don't even have read a single byte
if(bytesRead <= 0)
{
Hunk_FreeTempMemory(buffer);
S_OGG_CodecCloseStream(stream);
return NULL;
}
S_OGG_CodecCloseStream(stream);
return buffer;
}
#endif // USE_CODEC_VORBIS
-449
View File
@@ -1,449 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
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
===========================================================================
*/
// Ogg Opus support is enabled by this define
#ifdef USE_CODEC_OPUS
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the Ogg Opus codec
#include <errno.h>
#include <opusfile.h>
// samples are 16 bit
#define OPUS_SAMPLEWIDTH 2
// Q3 Ogg Opus codec
snd_codec_t opus_codec =
{
"opus",
S_OggOpus_CodecLoad,
S_OggOpus_CodecOpenStream,
S_OggOpus_CodecReadStream,
S_OggOpus_CodecCloseStream,
NULL
};
// callbacks for opusfile
// fread() replacement
int S_OggOpus_Callback_read(void *datasource, unsigned char *ptr, int size )
{
snd_stream_t *stream;
int bytesRead = 0;
// check if input is valid
if(!ptr)
{
errno = EFAULT;
return -1;
}
if(!size)
{
// It's not an error, caller just wants zero bytes!
errno = 0;
return 0;
}
if (size < 0)
{
errno = EINVAL;
return -1;
}
if(!datasource)
{
errno = EBADF;
return -1;
}
// we use a snd_stream_t in the generic pointer to pass around
stream = (snd_stream_t *) datasource;
// read it with the Q3 function FS_Read()
bytesRead = FS_Read(ptr, size, stream->file);
// update the file position
stream->pos += bytesRead;
return bytesRead;
}
// fseek() replacement
int S_OggOpus_Callback_seek(void *datasource, opus_int64 offset, int whence)
{
snd_stream_t *stream;
int retVal = 0;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
// we must map the whence to its Q3 counterpart
switch(whence)
{
case SEEK_SET :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = (int) offset;
break;
}
case SEEK_CUR :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos += (int) offset;
break;
}
case SEEK_END :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_END);
// something has gone wrong, so we return here
if(retVal < 0)
{
return retVal;
}
// keep track of file position
stream->pos = stream->length + (int) offset;
break;
}
default :
{
// unknown whence, so we return an error
errno = EINVAL;
return -1;
}
}
// stream->pos shouldn't be smaller than zero or bigger than the filesize
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
return 0;
}
// fclose() replacement
int S_OggOpus_Callback_close(void *datasource)
{
// we do nothing here and close all things manually in S_OggOpus_CodecCloseStream()
return 0;
}
// ftell() replacement
opus_int64 S_OggOpus_Callback_tell(void *datasource)
{
snd_stream_t *stream;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
return (opus_int64) FS_FTell(stream->file);
}
// the callback structure
const OpusFileCallbacks S_OggOpus_Callbacks =
{
&S_OggOpus_Callback_read,
&S_OggOpus_Callback_seek,
&S_OggOpus_Callback_tell,
&S_OggOpus_Callback_close
};
/*
=================
S_OggOpus_CodecOpenStream
=================
*/
snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
// Opus codec control structure
OggOpusFile *of;
// some variables used to get informations about the file
const OpusHead *opusInfo;
ogg_int64_t numSamples;
// check if input is valid
if(!filename)
{
return NULL;
}
// Open the stream
stream = S_CodecUtilOpen(filename, &opus_codec);
if(!stream)
{
return NULL;
}
// open the codec with our callbacks and stream as the generic pointer
of = op_open_callbacks(stream, &S_OggOpus_Callbacks, NULL, 0, NULL );
if (!of)
{
S_CodecUtilClose(&stream);
return NULL;
}
// the stream must be seekable
if(!op_seekable(of))
{
op_free(of);
S_CodecUtilClose(&stream);
return NULL;
}
// get the info about channels and rate
opusInfo = op_head(of, -1);
if(!opusInfo)
{
op_free(of);
S_CodecUtilClose(&stream);
return NULL;
}
if(opusInfo->stream_count != 1)
{
op_free(of);
S_CodecUtilClose(&stream);
Com_Printf("Only Ogg Opus files with one stream are support\n");
return NULL;
}
if(opusInfo->channel_count != 1 && opusInfo->channel_count != 2)
{
op_free(of);
S_CodecUtilClose(&stream);
Com_Printf("Only mono and stereo Ogg Opus files are supported\n");
return NULL;
}
// get the number of sample-frames in the file
numSamples = op_pcm_total(of, -1);
// fill in the info-structure in the stream
stream->info.rate = 48000;
stream->info.width = OPUS_SAMPLEWIDTH;
stream->info.channels = opusInfo->channel_count;
stream->info.samples = numSamples;
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
stream->info.dataofs = 0;
// We use stream->pos for the file pointer in the compressed ogg file
stream->pos = 0;
// We use the generic pointer in stream for the opus codec control structure
stream->ptr = of;
return stream;
}
/*
=================
S_OggOpus_CodecCloseStream
=================
*/
void S_OggOpus_CodecCloseStream(snd_stream_t *stream)
{
// check if input is valid
if(!stream)
{
return;
}
// let the opus codec cleanup its stuff
op_free((OggOpusFile *) stream->ptr);
// close the stream
S_CodecUtilClose(&stream);
}
/*
=================
S_OggOpus_CodecReadStream
=================
*/
int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
// buffer handling
int samplesRead, samplesLeft, c;
opus_int16 *bufPtr;
// check if input is valid
if(!(stream && buffer))
{
return 0;
}
if(bytes <= 0)
{
return 0;
}
samplesRead = 0;
samplesLeft = bytes / stream->info.channels / stream->info.width;
bufPtr = buffer;
if(samplesLeft <= 0)
{
return 0;
}
// cycle until we have the requested or all available bytes read
while(-1)
{
// read some samples from the opus codec
c = op_read((OggOpusFile *) stream->ptr, bufPtr + samplesRead * stream->info.channels, samplesLeft * stream->info.channels, NULL);
// no more samples are left
if(c <= 0)
{
break;
}
samplesRead += c;
samplesLeft -= c;
// we have enough samples
if(samplesLeft <= 0)
{
break;
}
}
return samplesRead * stream->info.channels * stream->info.width;
}
/*
=====================================================================
S_OggOpus_CodecLoad
We handle S_OggOpus_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *buffer;
int bytesRead;
// check if input is valid
if(!(filename && info))
{
return NULL;
}
// open the file as a stream
stream = S_OggOpus_CodecOpenStream(filename);
if(!stream)
{
return NULL;
}
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->size = stream->info.size;
info->dataofs = stream->info.dataofs;
// allocate a buffer
// this buffer must be free-ed by the caller of this function
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
S_OggOpus_CodecCloseStream(stream);
return NULL;
}
// fill the buffer
bytesRead = S_OggOpus_CodecReadStream(stream, info->size, buffer);
// we don't even have read a single byte
if(bytesRead <= 0)
{
Hunk_FreeTempMemory(buffer);
S_OggOpus_CodecCloseStream(stream);
return NULL;
}
S_OggOpus_CodecCloseStream(stream);
return buffer;
}
#endif // USE_CODEC_OPUS
-291
View File
@@ -1,291 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
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_codec.h"
/*
=================
FGetLittleLong
=================
*/
static int FGetLittleLong( fileHandle_t f ) {
int v;
FS_Read( &v, sizeof(v), f );
return LittleLong( v);
}
/*
=================
FGetLittleShort
=================
*/
static short FGetLittleShort( fileHandle_t f ) {
short v;
FS_Read( &v, sizeof(v), f );
return LittleShort( v);
}
/*
=================
S_ReadChunkInfo
=================
*/
static int S_ReadChunkInfo(fileHandle_t f, char *name)
{
int len, r;
name[4] = 0;
r = FS_Read(name, 4, f);
if(r != 4)
return -1;
len = FGetLittleLong(f);
if( len < 0 ) {
Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
return -1;
}
return len;
}
/*
=================
S_FindRIFFChunk
Returns the length of the data in the chunk, or -1 if not found
=================
*/
static int S_FindRIFFChunk( fileHandle_t f, char *chunk ) {
char name[5];
int len;
while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
{
// If this is the right chunk, return
if( !Q_strncmp( name, chunk, 4 ) )
return len;
len = PAD( len, 2 );
// Not the right chunk - skip it
FS_Seek( f, len, FS_SEEK_CUR );
}
return -1;
}
/*
=================
S_ByteSwapRawSamples
=================
*/
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
int i;
if ( width != 2 ) {
return;
}
if ( LittleShort( 256 ) == 256 ) {
return;
}
if ( s_channels == 2 ) {
samples <<= 1;
}
for ( i = 0 ; i < samples ; i++ ) {
((short *)data)[i] = LittleShort( ((short *)data)[i] );
}
}
/*
=================
S_ReadRIFFHeader
=================
*/
static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
{
char dump[16];
int bits;
int fmtlen = 0;
// skip the riff wav header
FS_Read(dump, 12, file);
// Scan for the format chunk
if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
return qfalse;
}
// Save the parameters
FGetLittleShort(file); // wav_format
info->channels = FGetLittleShort(file);
info->rate = FGetLittleLong(file);
FGetLittleLong(file);
FGetLittleShort(file);
bits = FGetLittleShort(file);
if( bits < 8 )
{
Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
return qfalse;
}
info->width = bits / 8;
info->dataofs = 0;
// Skip the rest of the format chunk if required
if(fmtlen > 16)
{
fmtlen -= 16;
FS_Seek( file, fmtlen, FS_SEEK_CUR );
}
// Scan for the data chunk
if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
return qfalse;
}
info->samples = (info->size / info->width) / info->channels;
return qtrue;
}
// WAV codec
snd_codec_t wav_codec =
{
"wav",
S_WAV_CodecLoad,
S_WAV_CodecOpenStream,
S_WAV_CodecReadStream,
S_WAV_CodecCloseStream,
NULL
};
/*
=================
S_WAV_CodecLoad
=================
*/
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
{
fileHandle_t file;
void *buffer;
// Try to open the file
FS_FOpenFileRead(filename, &file, qtrue, qtrue);
if(!file)
{
return NULL;
}
// Read the RIFF header
if(!S_ReadRIFFHeader(file, info))
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
filename);
return NULL;
}
// Allocate some memory
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
filename);
return NULL;
}
// Read, byteswap
FS_Read(buffer, info->size, file);
S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
// Close and return
FS_FCloseFile(file);
return buffer;
}
/*
=================
S_WAV_CodecOpenStream
=================
*/
snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
{
snd_stream_t *rv;
// Open
rv = S_CodecUtilOpen(filename, &wav_codec);
if(!rv)
return NULL;
// Read the RIFF header
if(!S_ReadRIFFHeader(rv->file, &rv->info))
{
S_CodecUtilClose(&rv);
return NULL;
}
return rv;
}
/*
=================
S_WAV_CodecCloseStream
=================
*/
void S_WAV_CodecCloseStream(snd_stream_t *stream)
{
S_CodecUtilClose(&stream);
}
/*
=================
S_WAV_CodecReadStream
=================
*/
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
int remaining = stream->info.size - stream->pos;
int samples;
if(remaining <= 0)
return 0;
if(bytes > remaining)
bytes = remaining;
stream->pos += bytes;
samples = (bytes / stream->info.width) / stream->info.channels;
FS_Read(buffer, bytes, stream->file);
S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
return bytes;
}
+789 -438
View File
File diff suppressed because it is too large. Load diff
+24 -87
View File
@@ -15,14 +15,14 @@ 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// snd_local.h -- private sound definations
#include "../qcommon/q_shared.h"
#include "q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"
@@ -30,9 +30,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
extern "C" {
#endif
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define PAINTBUFFER_SIZE 4096 // this is in samples
#define SND_CHUNK_SIZE 1024 // samples
@@ -63,7 +60,6 @@ typedef struct sfx_s {
qboolean soundCompressed; // not in Memory
int soundCompressionMethod;
int soundLength;
int soundChannels;
char soundName[MAX_QPATH];
int lastTimeUsed;
struct sfx_s *next;
@@ -72,20 +68,14 @@ typedef struct sfx_s {
typedef struct {
int channels;
int samples; // mono samples in buffer
int fullsamples; // samples with all channels in buffer (samples divided by channels)
int submission_chunk; // don't mix less than this #
int samplebits;
int isfloat;
int speed;
byte *buffer;
} dma_t;
#define START_SAMPLE_IMMEDIATE 0x7fffffff
#define MAX_DOPPLER_SCALE 50.0f //arbitrary
#define THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
typedef struct loopSound_s {
vec3_t origin;
vec3_t velocity;
@@ -114,7 +104,6 @@ typedef struct
qboolean fixed_origin; // use origin instead of fetching entnum's origin
sfx_t *thesfx; // sfx structure
qboolean doppler;
qboolean fullVolume;
} channel_t;
@@ -130,38 +119,6 @@ typedef struct {
int dataofs; // chunk starts this many bytes from file start
} wavinfo_t;
// Interface between Q3 sound "api" and the sound backend
typedef struct
{
void (*Shutdown)(void);
void (*StartSound)(const vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
void (*StartBackgroundTrack)( const char *intro, const char *loop );
void (*StopBackgroundTrack)( void );
void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
void (*StopAllSounds)( void );
void (*ClearLoopingSounds)( qboolean killall );
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*StopLoopingSound)(int entityNum );
void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
void (*UpdateEntityPosition)( int entityNum, const vec3_t origin );
void (*Update)( void );
void (*DisableSounds)( void );
void (*BeginRegistration)( void );
sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
void (*ClearSoundBuffer)( void );
void (*SoundInfo)( void );
void (*SoundList)( void );
#ifdef USE_VOIP
void (*StartCapture)( void );
int (*AvailableCaptureSamples)( void );
void (*Capture)( int samples, byte *data );
void (*StopCapture)( void );
void (*MasterGain)( float gain );
#endif
} soundInterface_t;
/*
====================================================================
@@ -184,51 +141,43 @@ void SNDDMA_BeginPainting (void);
void SNDDMA_Submit(void);
#ifdef USE_VOIP
void SNDDMA_StartCapture(void);
int SNDDMA_AvailableCaptureSamples(void);
void SNDDMA_Capture(int samples, byte *data);
void SNDDMA_StopCapture(void);
void SNDDMA_MasterGain(float val);
#endif
//====================================================================
#define MAX_SOUNDCHANNELS 96
#define MAX_CHANNELS 96
extern channel_t s_channels[MAX_SOUNDCHANNELS];
extern channel_t loop_channels[MAX_SOUNDCHANNELS];
extern channel_t s_channels[MAX_CHANNELS];
extern channel_t loop_channels[MAX_CHANNELS];
extern int numLoopChannels;
extern int s_paintedtime;
extern int s_rawend;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern dma_t dma;
#define MAX_RAW_SAMPLES 16384
#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
extern int s_rawend[MAX_RAW_STREAMS];
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
extern cvar_t *s_volume;
extern cvar_t *s_musicVolume;
extern cvar_t *s_muted;
extern cvar_t *s_doppler;
extern cvar_t *s_volume;
extern cvar_t *s_nosound;
extern cvar_t *s_khz;
extern cvar_t *s_show;
extern cvar_t *s_mixahead;
extern cvar_t *s_testsound;
extern cvar_t *s_testsound;
extern cvar_t *s_separation;
qboolean S_LoadSound( sfx_t *sfx );
void SND_free(sndBuffer *v);
sndBuffer* SND_malloc( void );
void SND_setup( void );
void SND_shutdown(void);
sndBuffer* SND_malloc();
void SND_setup();
void S_PaintChannels(int endtime);
void S_memoryLoad(sfx_t *sfx);
portable_samplepair_t *S_GetRawSamplePointer();
// spatializes a channel
void S_Spatialize(channel_t *ch);
@@ -243,7 +192,7 @@ void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
#define SENTINEL_MULAW_ZERO_RUN 127
#define SENTINEL_MULAW_FOUR_BIT_RUN 126
void S_FreeOldestSound( void );
void S_FreeOldestSound();
#define NXStream byte
@@ -257,24 +206,12 @@ extern short *sfxScratchBuffer;
extern sfx_t *sfxScratchPointer;
extern int sfxScratchIndex;
qboolean S_Base_Init( soundInterface_t *si );
// OpenAL stuff
typedef enum
{
SRCPRI_AMBIENT = 0, // Ambient sound effects
SRCPRI_ENTITY, // Entity sound effects
SRCPRI_ONESHOT, // One-shot sounds
SRCPRI_LOCAL, // Local sounds
SRCPRI_STREAM // Streams (music, cutscenes)
} alSrcPriority_t;
typedef int srcHandle_t;
qboolean S_AL_Init( soundInterface_t *si );
#ifdef idppc_altivec
void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset );
#ifdef __linux__
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
// custom Snd_Memset implementation for glibc memset bug workaround
void Snd_Memset(void* dest, const int val, const size_t count);
#else
#define Snd_Memset Com_Memset
#endif
#ifdef __cplusplus
+6 -6
View File
@@ -22,18 +22,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "client.h"
#include "snd_codec.h"
#include "snd_local.h"
#include "snd_public.h"
cvar_t *s_volume;
cvar_t *s_muted;
cvar_t *s_musicVolume;
cvar_t *s_doppler;
cvar_t *s_backend;
cvar_t *s_muteWhenMinimized;
cvar_t *s_muteWhenUnfocused;
#if 0
cvar_t* s_volume;
cvar_t* s_musicVolume;
cvar_t* s_doppler;
static soundInterface_t si;
/*
@@ -332,13 +333,11 @@ S_RegisterSound
*/
sfxHandle_t S_RegisterSound(const char *sample, qboolean compressed, qboolean streamed)
{
/*
if( si.RegisterSound ) {
return si.RegisterSound( sample, compressed );
} else {
return 0;
}
*/
// FIXME: infinite loop
}
@@ -889,3 +888,4 @@ void S_FadeSound(float fTime)
{
// FIXME: stub
}
#endif
+196 -66
View File
@@ -15,7 +15,7 @@ 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
@@ -30,7 +30,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "snd_local.h"
#include "snd_codec.h"
#define DEF_COMSOUNDMEGS "8"
@@ -57,7 +56,7 @@ void SND_free(sndBuffer *v) {
inUse += sizeof(sndBuffer);
}
sndBuffer* SND_malloc(void) {
sndBuffer* SND_malloc() {
sndBuffer *v;
redo:
if (freelist == NULL) {
@@ -74,7 +73,7 @@ redo:
return v;
}
void SND_setup(void) {
void SND_setup() {
sndBuffer *p, *q;
cvar_t *cv;
int scs;
@@ -100,12 +99,137 @@ void SND_setup(void) {
Com_Printf("Sound memory manager started\n");
}
void SND_shutdown(void)
/*
===============================================================================
WAV loading
===============================================================================
*/
static byte *data_p;
static byte *iff_end;
static byte *last_chunk;
static byte *iff_data;
static int iff_chunk_len;
static short GetLittleShort(void)
{
free(sfxScratchBuffer);
free(buffer);
short val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
data_p += 2;
return val;
}
static int GetLittleLong(void)
{
int val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
val = val + (*(data_p+2)<<16);
val = val + (*(data_p+3)<<24);
data_p += 4;
return val;
}
static void FindNextChunk(char *name)
{
while (1)
{
data_p=last_chunk;
if (data_p >= iff_end)
{ // didn't find the chunk
data_p = NULL;
return;
}
data_p += 4;
iff_chunk_len = GetLittleLong();
if (iff_chunk_len < 0)
{
data_p = NULL;
return;
}
data_p -= 8;
last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
if (!strncmp((char *)data_p, name, 4))
return;
}
}
static void FindChunk(char *name)
{
last_chunk = iff_data;
FindNextChunk (name);
}
/*
============
GetWavinfo
============
*/
static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
{
wavinfo_t info;
Com_Memset (&info, 0, sizeof(info));
if (!wav)
return info;
iff_data = wav;
iff_end = wav + wavlength;
// find "RIFF" chunk
FindChunk("RIFF");
if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
{
Com_Printf("Missing RIFF/WAVE chunks\n");
return info;
}
// get "fmt " chunk
iff_data = data_p + 12;
// DumpChunks ();
FindChunk("fmt ");
if (!data_p)
{
Com_Printf("Missing fmt chunk\n");
return info;
}
data_p += 8;
info.format = GetLittleShort();
info.channels = GetLittleShort();
info.rate = GetLittleLong();
data_p += 4+2;
info.width = GetLittleShort() / 8;
if (info.format != 1)
{
Com_Printf("Microsoft PCM format only\n");
return info;
}
// find data chunk
FindChunk("data");
if (!data_p)
{
Com_Printf("Missing data chunk\n");
return info;
}
data_p += 4;
info.samples = GetLittleLong () / info.width;
info.dataofs = data_p - wav;
return info;
}
/*
================
ResampleSfx
@@ -113,53 +237,47 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
int i;
int sample, samplefrac, fracstep;
int part;
sndBuffer *chunk;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
outcount = sfx->soundLength / stepscale;
sfx->soundLength = outcount;
srcsample = 0;
samplefrac = 0;
fracstep = stepscale * 256 * channels;
fracstep = stepscale * 256;
chunk = sfx->soundData;
for (i=0 ; i<outcount ; i++)
{
srcsample += samplefrac >> 8;
samplefrac &= 255;
srcsample = samplefrac >> 8;
samplefrac += fracstep;
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = ( ((short *)data)[srcsample+j] );
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
}
part = (i&(SND_CHUNK_SIZE-1));
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
} else {
sample = (unsigned int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
chunk->next = newchunk;
}
part = (i*channels+j)&(SND_CHUNK_SIZE-1);
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
} else {
chunk->next = newchunk;
}
chunk = newchunk;
}
chunk->sndChunk[part] = sample;
chunk = newchunk;
}
}
return outcount;
chunk->sndChunk[part] = sample;
}
}
/*
@@ -169,39 +287,35 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
int i;
int sample, samplefrac, fracstep;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
srcsample = 0;
samplefrac = 0;
fracstep = stepscale * 256 * channels;
fracstep = stepscale * 256;
for (i=0 ; i<outcount ; i++)
{
srcsample += samplefrac >> 8;
samplefrac &= 255;
srcsample = samplefrac >> 8;
samplefrac += fracstep;
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample+j] );
} else {
sample = (int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
}
sfx[i*channels+j] = sample;
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
}
sfx[i] = sample;
}
return outcount;
}
//=============================================================================
/*
@@ -216,23 +330,40 @@ qboolean S_LoadSound( sfx_t *sfx )
{
byte *data;
short *samples;
snd_info_t info;
// int size;
wavinfo_t info;
int size;
// player specific sounds are never directly loaded
if ( sfx->soundName[0] == '*') {
return qfalse;
}
// load it in
data = S_CodecLoad(sfx->soundName, &info);
if(!data)
size = FS_ReadFile( sfx->soundName, (void **)&data );
if ( !data ) {
return qfalse;
}
info = GetWavinfo( sfx->soundName, data, size );
if ( info.channels != 1 ) {
Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
FS_FreeFile (data);
return qfalse;
}
if ( info.width == 1 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName);
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
}
if ( info.rate != 22050 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName);
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
}
samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
if (!info.samples) {
return qfalse;
}
samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
sfx->lastTimeUsed = Com_Milliseconds()+1;
@@ -242,37 +373,36 @@ qboolean S_LoadSound( sfx_t *sfx )
// manager to do the right thing for us and page
// sound in as needed
if( info.channels == 1 && sfx->soundCompressed == qtrue) {
if( sfx->soundCompressed == qtrue) {
sfx->soundCompressionMethod = 1;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
S_AdpcmEncodeSound(sfx, samples);
#if 0
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
sfx->soundCompressionMethod = 3;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeMuLaw( sfx, samples);
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
} else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
sfx->soundCompressionMethod = 2;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeWavelet( sfx, samples);
#endif
} else {
sfx->soundCompressionMethod = 0;
sfx->soundLength = info.samples;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
}
sfx->soundChannels = info.channels;
Hunk_FreeTempMemory(samples);
Hunk_FreeTempMemory(data);
FS_FreeFile( data );
return qtrue;
}
void S_DisplayFreeMemory(void) {
void S_DisplayFreeMemory() {
Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
}
+182 -128
View File
@@ -15,23 +15,24 @@ 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
along with Foobar; if not, write to the Free Software
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"
static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
static int snd_vol;
// bk001119 - these not static, required by unix/snd_mixa.s
int* snd_p;
int snd_linear_count;
short* snd_out;
#if !id386 // if configured not to use asm
#if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123
#if !id386
void S_WriteLinearBlastStereo16 (void)
{
@@ -57,9 +58,6 @@ void S_WriteLinearBlastStereo16 (void)
snd_out[i+1] = val;
}
}
#elif defined(__GNUC__)
// uses snd_mixa.s
void S_WriteLinearBlastStereo16 (void);
#else
__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
@@ -106,6 +104,10 @@ LClampDone2:
}
}
#endif
#else
// forward declare, implementation somewhere else
void S_WriteLinearBlastStereo16 (void);
#endif
void S_TransferStereo16 (unsigned long *pbuf, int endtime)
@@ -119,24 +121,21 @@ void S_TransferStereo16 (unsigned long *pbuf, int endtime)
while (ls_paintedtime < endtime)
{
// handle recirculating buffer issues
lpos = ls_paintedtime % dma.fullsamples;
lpos = ls_paintedtime & ((dma.samples>>1)-1);
snd_out = (short *) pbuf + (lpos<<1); // lpos * dma.channels
snd_out = (short *) pbuf + (lpos<<1);
snd_linear_count = dma.fullsamples - lpos;
snd_linear_count = (dma.samples>>1) - lpos;
if (ls_paintedtime + snd_linear_count > endtime)
snd_linear_count = endtime - ls_paintedtime;
snd_linear_count <<= 1; // snd_linear_count *= dma.channels
snd_linear_count <<= 1;
// write a linear blast of samples
S_WriteLinearBlastStereo16 ();
snd_p += snd_linear_count;
ls_paintedtime += (snd_linear_count>>1); // snd_linear_count / dma.channels
if( CL_VideoRecording( ) )
CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 ); // snd_linear_count * (dma.samplebits/8)
ls_paintedtime += (snd_linear_count>>1);
}
}
@@ -150,16 +149,19 @@ void S_TransferPaintBuffer(int endtime)
{
int out_idx;
int count;
int out_mask;
int *p;
int step;
int val;
int i;
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++)
@@ -175,73 +177,38 @@ void S_TransferPaintBuffer(int endtime)
{ // general case
p = (int *) paintbuffer;
count = (endtime - s_paintedtime) * dma.channels;
out_idx = ((unsigned int)s_paintedtime * dma.channels) % dma.samples;
step = 3 - MIN(dma.channels, 2);
out_mask = dma.samples - 1;
out_idx = s_paintedtime * dma.channels & out_mask;
step = 3 - dma.channels;
if ((dma.isfloat) && (dma.samplebits == 32))
{
float *out = (float *) pbuf;
for (i=0 ; i<count ; i++)
{
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32767) /* clamp to one less than max to make division max out at -1.0f. */
val = -32767;
out[out_idx] = ((float) val) / 32767.0f;
out_idx = (out_idx + 1) % dma.samples;
}
}
else if (dma.samplebits == 16)
if (dma.samplebits == 16)
{
short *out = (short *) pbuf;
for (i=0 ; i<count ; i++)
while (count--)
{
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
val = *p >> 8;
p+= step;
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32768)
val = -32768;
out[out_idx] = val;
out_idx = (out_idx + 1) % dma.samples;
out_idx = (out_idx + 1) & out_mask;
}
}
else if (dma.samplebits == 8)
{
unsigned char *out = (unsigned char *) pbuf;
for (i=0 ; i<count ; i++)
while (count--)
{
if ((i % dma.channels) >= 2)
{
val = 0;
}
else
{
val = *p >> 8;
p+= step;
}
val = *p >> 8;
p+= step;
if (val > 0x7fff)
val = 0x7fff;
else if (val < -32768)
val = -32768;
out[out_idx] = (val>>8) + 128;
out_idx = (out_idx + 1) % dma.samples;
out_idx = (out_idx + 1) & out_mask;
}
}
}
@@ -256,18 +223,14 @@ CHANNEL MIXING
===============================================================================
*/
static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data, aoff, boff;
int leftvol, rightvol;
int i, j;
portable_samplepair_t *samp;
sndBuffer *chunk;
short *samples;
float ooff, fdata[2], fdiv, fleftvol, frightvol;
if (sc->soundChannels <= 0) {
return;
}
float ooff, fdata, fdiv, fleftvol, frightvol;
samp = &paintbuffer[ bufferOffset ];
@@ -275,14 +238,6 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou
sampleOffset = sampleOffset*ch->oldDopplerScale;
}
if ( sc->soundChannels == 2 ) {
sampleOffset *= sc->soundChannels;
if ( sampleOffset & 1 ) {
sampleOffset &= ~1;
}
}
chunk = sc->soundData;
while (sampleOffset>=SND_CHUNK_SIZE) {
chunk = chunk->next;
@@ -293,16 +248,126 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou
}
if (!ch->doppler || ch->dopplerScale==1.0f) {
#if idppc_altivec
vector signed short volume_vec;
vector unsigned int volume_shift;
int vectorCount, samplesLeft, chunkSamplesLeft;
#endif
leftvol = ch->leftvol*snd_vol;
rightvol = ch->rightvol*snd_vol;
samples = chunk->sndChunk;
#if idppc_altivec
((short *)&volume_vec)[0] = leftvol;
((short *)&volume_vec)[1] = leftvol;
((short *)&volume_vec)[4] = leftvol;
((short *)&volume_vec)[5] = leftvol;
((short *)&volume_vec)[2] = rightvol;
((short *)&volume_vec)[3] = rightvol;
((short *)&volume_vec)[6] = rightvol;
((short *)&volume_vec)[7] = rightvol;
volume_shift = vec_splat_u32(8);
i = 0;
while(i < count) {
/* Try to align destination to 16-byte boundary */
while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
i++;
}
/* Destination is now aligned. Process as many 8-sample
chunks as we can before we run out of room from the current
sound chunk. We do 8 per loop to avoid extra source data reads. */
samplesLeft = count - i;
chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
if(samplesLeft > chunkSamplesLeft)
samplesLeft = chunkSamplesLeft;
vectorCount = samplesLeft / 8;
if(vectorCount)
{
vector unsigned char tmp;
vector short s0, s1, sampleData0, sampleData1;
vector short samples0, samples1;
vector signed int left0, right0;
vector signed int merge0, merge1;
vector signed int d0, d1, d2, d3;
vector unsigned char samplePermute0 =
(vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
vector unsigned char samplePermute1 =
(vector unsigned char)(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
vector unsigned char loadPermute0, loadPermute1;
// Rather than permute the vectors after we load them to do the sample
// replication and rearrangement, we permute the alignment vector so
// we do everything in one step below and avoid data shuffling.
tmp = vec_lvsl(0,&samples[sampleOffset]);
loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
s0 = *(vector short *)&samples[sampleOffset];
while(vectorCount)
{
/* Load up source (16-bit) sample data */
s1 = *(vector short *)&samples[sampleOffset+7];
/* Load up destination sample data */
d0 = *(vector signed int *)&samp[i];
d1 = *(vector signed int *)&samp[i+2];
d2 = *(vector signed int *)&samp[i+4];
d3 = *(vector signed int *)&samp[i+6];
sampleData0 = vec_perm(s0,s1,loadPermute0);
sampleData1 = vec_perm(s0,s1,loadPermute1);
merge0 = vec_mule(sampleData0,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData0,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d0 = vec_add(merge0,d0);
d1 = vec_add(merge1,d1);
merge0 = vec_mule(sampleData1,volume_vec);
merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
merge1 = vec_mulo(sampleData1,volume_vec);
merge1 = vec_sra(merge1,volume_shift);
d2 = vec_add(merge0,d2);
d3 = vec_add(merge1,d3);
/* Store destination sample data */
*(vector signed int *)&samp[i] = d0;
*(vector signed int *)&samp[i+2] = d1;
*(vector signed int *)&samp[i+4] = d2;
*(vector signed int *)&samp[i+6] = d3;
i += 8;
vectorCount--;
s0 = s1;
sampleOffset += 8;
}
if (sampleOffset == SND_CHUNK_SIZE) {
chunk = chunk->next;
samples = chunk->sndChunk;
sampleOffset = 0;
}
}
}
#else
for ( i=0 ; i<count ; i++ ) {
data = samples[sampleOffset++];
samp[i].left += (data * leftvol)>>8;
if ( sc->soundChannels == 2 ) {
data = samples[sampleOffset++];
}
samp[i].right += (data * rightvol)>>8;
if (sampleOffset == SND_CHUNK_SIZE) {
@@ -311,6 +376,7 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou
sampleOffset = 0;
}
}
#endif
} else {
fleftvol = ch->leftvol*snd_vol;
frightvol = ch->rightvol*snd_vol;
@@ -324,10 +390,10 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou
for ( i=0 ; i<count ; i++ ) {
aoff = ooff;
ooff = ooff + ch->dopplerScale * sc->soundChannels;
ooff = ooff + ch->dopplerScale;
boff = ooff;
fdata[0] = fdata[1] = 0;
for (j=aoff; j<boff; j += sc->soundChannels) {
fdata = 0;
for (j=aoff; j<boff; j++) {
if (j == SND_CHUNK_SIZE) {
chunk = chunk->next;
if (!chunk) {
@@ -336,32 +402,15 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou
samples = chunk->sndChunk;
ooff -= SND_CHUNK_SIZE;
}
if ( sc->soundChannels == 2 ) {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
} else {
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
}
fdata += samples[j&(SND_CHUNK_SIZE-1)];
}
fdiv = 256 * (boff-aoff) / sc->soundChannels;
samp[i].left += (fdata[0] * fleftvol)/fdiv;
samp[i].right += (fdata[1] * frightvol)/fdiv;
fdiv = 256 * (boff-aoff);
samp[i].left += (fdata * fleftvol)/fdiv;
samp[i].right += (fdata * frightvol)/fdiv;
}
}
}
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
#if idppc_altivec
if (com_altivec->integer) {
// must be in a separate translation unit or G3 systems will crash.
S_PaintChannelFrom16_altivec( paintbuffer, snd_vol, ch, sc, count, sampleOffset, bufferOffset );
return;
}
#endif
S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
}
void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
int data;
int leftvol, rightvol;
@@ -383,7 +432,7 @@ void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleO
}
if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
decodeWavelet(chunk, sfxScratchBuffer);
S_AdpcmGetSamples( chunk, sfxScratchBuffer );
sfxScratchIndex = i;
sfxScratchPointer = sc;
}
@@ -480,7 +529,7 @@ void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOff
samp[i].left += (data * leftvol)>>8;
samp[i].right += (data * rightvol)>>8;
samples++;
if (chunk != NULL && samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
chunk = chunk->next;
samples = (byte *)chunk->sndChunk;
}
@@ -513,16 +562,13 @@ S_PaintChannels
void S_PaintChannels( int endtime ) {
int i;
int end;
int stream;
channel_t *ch;
sfx_t *sc;
int ltime, count;
int sampleOffset;
if(s_muted->integer)
snd_vol = 0;
else
snd_vol = s_volume->value*255;
snd_vol = s_volume->value*255;
//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
while ( s_paintedtime < endtime ) {
@@ -533,24 +579,36 @@ void S_PaintChannels( int endtime ) {
end = s_paintedtime + PAINTBUFFER_SIZE;
}
// clear the paint buffer and mix any raw samples...
Com_Memset(paintbuffer, 0, sizeof (paintbuffer));
for (stream = 0; stream < MAX_RAW_STREAMS; stream++) {
if ( s_rawend[stream] >= s_paintedtime ) {
// copy from the streaming sound source
const portable_samplepair_t *rawsamples = s_rawsamples[stream];
const int stop = (end < s_rawend[stream]) ? end : s_rawend[stream];
for ( i = s_paintedtime ; i < stop ; i++ ) {
const int s = i&(MAX_RAW_SAMPLES-1);
paintbuffer[i-s_paintedtime].left += rawsamples[s].left;
paintbuffer[i-s_paintedtime].right += rawsamples[s].right;
}
// clear the paint buffer to either music or zeros
if ( s_rawend < s_paintedtime ) {
if ( s_rawend ) {
//Com_DPrintf ("background sound underrun\n");
}
Com_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_SOUNDCHANNELS ; i++, ch++ ) {
for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
continue;
}
@@ -558,10 +616,6 @@ void S_PaintChannels( int endtime ) {
ltime = s_paintedtime;
sc = ch->thesfx;
if (sc->soundData==NULL || sc->soundLength==0) {
continue;
}
sampleOffset = ltime - ch->startSample;
count = end - ltime;
if ( sampleOffset + count > sc->soundLength ) {
File diff suppressed because it is too large. Load diff
+8 -18
View File
@@ -15,7 +15,7 @@ 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
@@ -38,8 +38,8 @@ void S_StopBackgroundTrack( void );
// cinematics and voice-over-network will send raw samples
// 1.0 volume will be direct output of source samples
void S_RawSamples(int stream, int samples, int rate, int width, int channels,
const byte *data, float volume, int entityNum);
void S_RawSamples (int samples, int rate, int width, int channels,
const byte *data, float volume);
// stop all sounds and the background track
void S_StopAllSounds(qboolean stop_music);
@@ -51,21 +51,20 @@ void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t s
void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void S_StopLoopingSound(int entityNum );
// recompute the relative volumes for all running sounds
// relative to the given entityNum / orientation
void S_Respatialize(int entityNum, const vec3_t origin, vec3_t axis[3], int inwater);
// recompute the reletive volumes for all running sounds
// reletive to the given entityNum / orientation
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
// let the sound system know where an entity currently is
void S_UpdateEntityPosition(int entityNum, const vec3_t origin);
void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
void S_Update( void );
void S_DisableSounds( void );
void S_BeginRegistration(void);
void S_BeginRegistration( void );
void S_EndRegistration(void);
qboolean S_IsSoundRegistered(const char* name);
// RegisterSound will allways return a valid sample, even if it
// has to create a placeholder. This prevents continuous filesystem
// checks for missing files
@@ -110,15 +109,6 @@ void S_RespatializeOld(int entityNum, const vec3_t origin, vec3_t axis[3]);
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener);
void S_FadeSound(float fTime);
#ifdef USE_VOIP
void S_StartCapture( void );
int S_AvailableCaptureSamples( void );
void S_Capture( int samples, byte *data );
void S_StopCapture( void );
void S_MasterGain( float gain );
#endif
#ifdef __cplusplus
}
#endif
+18 -17
View File
@@ -15,13 +15,15 @@ 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
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "snd_local.h"
long myftol( float f );
#define C0 0.4829629131445341
#define C1 0.8365163037378079
#define C2 0.2241438680420134
@@ -29,8 +31,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void daub4(float b[], unsigned long n, int isign)
{
float wksp[4097] = { 0.0f };
#define a(x) b[(x)-1] // numerical recipies so a[1] = b[0]
float wksp[4097];
float *a=b-1; // numerical recipies so a[1] = b[0]
unsigned long nh,nh1,i,j;
@@ -39,23 +41,22 @@ void daub4(float b[], unsigned long n, int isign)
nh1=(nh=n >> 1)+1;
if (isign >= 0) {
for (i=1,j=1;j<=n-3;j+=2,i++) {
wksp[i] = C0*a(j)+C1*a(j+1)+C2*a(j+2)+C3*a(j+3);
wksp[i+nh] = C3*a(j)-C2*a(j+1)+C1*a(j+2)-C0*a(j+3);
wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];
wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];
}
wksp[i ] = C0*a(n-1)+C1*a(n)+C2*a(1)+C3*a(2);
wksp[i+nh] = C3*a(n-1)-C2*a(n)+C1*a(1)-C0*a(2);
wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];
wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];
} else {
wksp[1] = C2*a(nh)+C1*a(n)+C0*a(1)+C3*a(nh1);
wksp[2] = C3*a(nh)-C0*a(n)+C1*a(1)-C2*a(nh1);
wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];
wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];
for (i=1,j=3;i<nh;i++) {
wksp[j++] = C2*a(i)+C1*a(i+nh)+C0*a(i+1)+C3*a(i+nh1);
wksp[j++] = C3*a(i)-C0*a(i+nh)+C1*a(i+1)-C2*a(i+nh1);
wksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];
wksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];
}
}
for (i=1;i<=n;i++) {
a(i)=wksp[i];
a[i]=wksp[i];
}
#undef a
}
void wt1(float a[], unsigned long n, int isign)
@@ -120,7 +121,7 @@ void NXPutc(NXStream *stream, char out) {
void encodeWavelet( sfx_t *sfx, short *packets) {
float wksp[4097] = {0}, temp;
float wksp[4097], temp;
int i, samples, size;
sndBuffer *newchunk, *chunk;
byte *out;
@@ -147,7 +148,7 @@ void encodeWavelet( sfx_t *sfx, short *packets) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else if (chunk != NULL) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
@@ -170,7 +171,7 @@ void encodeWavelet( sfx_t *sfx, short *packets) {
}
void decodeWavelet(sndBuffer *chunk, short *to) {
float wksp[4097] = {0};
float wksp[4097];
int i;
byte *out;
@@ -216,7 +217,7 @@ void encodeMuLaw( sfx_t *sfx, short *packets) {
newchunk = SND_malloc();
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
} else if (chunk != NULL) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
-2
View File
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(gcd)
set(CURRENT_DIR "code/gamespy")
include_directories("${CURRENT_DIR}/common")
+3 -3
View File
@@ -728,7 +728,7 @@ void Alias_ListFindRandomRange(AliasList_t* list, const char* alias, int* min_in
}
} while (r >= l);
if (l >= r)
if (r >= l)
{
numfound = 0;
*min_index = index;
@@ -736,7 +736,7 @@ void Alias_ListFindRandomRange(AliasList_t* list, const char* alias, int* min_in
totalfoundweight = 0.f;
ptr = &list->sorted_list[index];
for (i = 0; i < index; i++, ptr--)
for (i = index + 1; i > 0; i--, ptr--)
{
if (strncmp(convalias, (*ptr)->alias_name, length)) {
break;
@@ -746,7 +746,7 @@ void Alias_ListFindRandomRange(AliasList_t* list, const char* alias, int* min_in
{
foundlist[numfound++] = *ptr;
totalfoundweight += (*ptr)->weight;
*min_index = i;
*min_index = i - 1;
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ extern "C" {
#endif
#define PRODUCT_NAME "OpenMoHAA"
#define PRODUCT_VERSION "0.49-alpha"
#define PRODUCT_VERSION "0.50-alpha"
#define PRODUCT_DATE __DATE__
#if TARGET_GAME_TYPE == 1
+7
View File
@@ -1237,6 +1237,13 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
void Sys_FreeFileList( char **list );
void Sys_Sleep(int msec);
void Sys_InitStreamThread(void);
void Sys_ShutdownStreamThread(void);
void Sys_BeginStreamedFile(fileHandle_t f, int readAhead);
void Sys_EndStreamedFile(fileHandle_t f);
int Sys_StreamedRead(void* buffer, int size, int count, fileHandle_t f);
void Sys_StreamSeek(fileHandle_t f, int offset, int origin);
qboolean Sys_LowPhysicalMemory( void );
void SetNormalThreadPriority( void );
+4 -4
View File
@@ -535,7 +535,7 @@ typedef struct cTerraPatch_s {
byte s;
byte t;
float texCoord[ 2 ][ 2 ][ 2 ];
vec2_t texCoord[ 2 ][ 2 ];
char x;
char y;
@@ -555,9 +555,9 @@ typedef struct cTerraPatch_s {
} cTerraPatch_t;
typedef struct cStaticModel_s {
char model[ 128 ];
float origin[ 3 ];
float angles[ 3 ];
char model[128];
vec3_t origin;
vec3_t angles;
float scale;
int firstVertexData;
int numVertexData;
+2 -2
View File
@@ -87,7 +87,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define SURF_NOMARKS 0x20 // don't leave missile marks
#define SURF_CASTSHADOW 0x40
#define SURF_NODRAW 0x80 // don't generate a drawsurface at all
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_NOLIGHTMAP 0x100 // surface doesn't need a lightmap
#define SURF_ALPHASHADOW 0x200 // do per-pixel light shadow casting in q3map
#define SURF_NOSTEPS 0x400 // no footstep sounds
#define SURF_NONSOLID 0x800 // don't collide against curves with this set
@@ -109,7 +109,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define SURF_CARPET 0x8000000 // carpet effects
#define SURF_BACKSIDE 0x10000000 // su44: backside
#define SURF_NODLIGHT 0x20000000 // don't dlight even if solid (solid lava, skies)
#define SURF_NOLIGHTMAP 0x40000000 // surface doesn't need a lightmap
#define SURF_HINT 0x40000000 // make a primary bsp splitter
#define SURF_UNKNOWN3 0x80000000 // IneQuation: WTF?
#define SURF_FLESH 0x40 // make flesh sounds and effects
+22
View File
@@ -90,6 +90,28 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define GL_TEXTURE2_ARB 0x84C2
#define GL_TEXTURE3_ARB 0x84C3
#define GL_COMBINE 0x8570
#define GL_COMBINE4_NV 0x8503
#define GL_COMBINE_RGB 0x8571
#define GL_COMBINE_ALPHA 0x8572
#define GL_SOURCE0_RGB 0x8580
#define GL_SOURCE1_RGB 0x8581
#define GL_SOURCE2_RGB 0x8582
#define GL_SOURCE3_RGB 0x8583
#define GL_SOURCE0_ALPHA 0x8588
#define GL_SOURCE1_ALPHA 0x8589
#define GL_SOURCE2_ALPHA 0x858A
#define GL_SOURCE3_ALPHA 0x858B
#define GL_OPERAND0_RGB 0x8590
#define GL_OPERAND1_RGB 0x8591
#define GL_OPERAND2_RGB 0x8592
#define GL_OPERAND3_RGB 0x8593
#define GL_OPERAND0_ALPHA 0x8598
#define GL_OPERAND1_ALPHA 0x8599
#define GL_OPERAND2_ALPHA 0x859A
#define GL_OPERAND3_ALPHA 0x859B
// NOTE: some Linux platforms would need those prototypes
#if defined(MACOS_X)
typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+169 -10
View File
@@ -34,6 +34,16 @@ static float s_flipMatrix[16] = {
0, 0, 0, 1
};
void GL_SetFogColor(const vec4_t fColor) {
glState.fFogColor[0] = fColor[0];
glState.fFogColor[1] = fColor[1];
glState.fFogColor[2] = fColor[2];
glState.fFogColor[3] = fColor[3];
if (!(glState.glStateBits & GLS_FOG_COLOR)) {
qglFogfv(GL_FOG_COLOR, glState.fFogColor);
}
}
/*
** GL_Bind
@@ -188,6 +198,10 @@ void GL_TexEnv( int env )
case GL_ADD:
qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
break;
case GL_COMBINE4_NV:
case GL_COMBINE:
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
break;
default:
ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env );
break;
@@ -202,7 +216,7 @@ void GL_TexEnv( int env )
*/
void GL_State( unsigned long stateBits )
{
unsigned long diff = stateBits ^ glState.glStateBits;
unsigned long diff = glState.glStateBits ^ (glState.externalSetState | stateBits);
if ( !diff )
{
@@ -354,6 +368,35 @@ void GL_State( unsigned long stateBits )
}
}
if ((diff & GLS_MULTITEXTURE_ENV) || (diff & GLS_MULTITEXTURE))
{
if (stateBits & GLS_MULTITEXTURE_ENV)
{
GL_TexEnv(GL_COMBINE4_NV);
}
else if (stateBits & GLS_MULTITEXTURE)
{
if (glState.cntTexEnvExt != GLS_MULTITEXTURE)
{
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, 34165.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, 8448.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, 5890.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 770.0);
glState.cntTexEnvExt = GLS_MULTITEXTURE;
}
GL_TexEnv(GL_COMBINE);
}
else
{
GL_TexEnv(GL_MODULATE);
}
}
//
// alpha test
//
@@ -382,7 +425,109 @@ void GL_State( unsigned long stateBits )
}
}
glState.glStateBits = stateBits;
if (diff & GLS_CLAMP_EDGE)
{
float clampValue;
if (r_forceClampToEdge->value)
{
if (stateBits & GLS_CLAMP_EDGE) {
clampValue = 33071.0;
}
else {
clampValue = 10497.0;
}
}
else
{
if (stateBits & GLS_CLAMP_EDGE) {
clampValue = 10496.0;
}
else {
clampValue = 10497.0;
}
}
if (qglActiveTextureARB)
{
int currenttmu = glState.currenttmu;
GL_SelectTexture(0);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clampValue);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clampValue);
GL_SelectTexture(1);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clampValue);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clampValue);
GL_SelectTexture(currenttmu);
}
else
{
GL_SelectTexture(0);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clampValue);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clampValue);
}
}
if (diff & GLS_FOG)
{
if (glState.externalSetState & GLS_FOG)
{
qglEnable(GL_FOG);
if (stateBits & GLS_FOG_BLACK)
{
vec4_t fBlackFogColor = { 0, 0, 0, 1 };
qglFogfv(GL_FOG_COLOR, fBlackFogColor);
}
else if (stateBits & GLS_FOG_WHITE)
{
vec4_t fWhiteFogColor = { 1, 1, 1, 1 };
qglFogfv(GL_FOG_COLOR, fWhiteFogColor);
}
else
{
//
// Use the global fog
qglFogfv(GL_FOG_COLOR, glState.fFogColor);
}
}
else
{
qglDisable(GL_FOG);
}
}
else if (glState.externalSetState & GLS_FOG)
{
if (diff & GLS_FOG_ENABLED)
{
if (stateBits & GLS_FOG_ENABLED) {
qglEnable(GL_FOG);
}
else {
qglDisable(GL_FOG);
}
}
if (diff & GLS_FOG_COLOR)
{
if (stateBits & GLS_FOG_BLACK)
{
vec4_t fBlackFogColor = { 0, 0, 0, 1 };
qglFogfv(GL_FOG_COLOR, fBlackFogColor);
}
else if (stateBits & GLS_FOG_WHITE)
{
vec4_t fWhiteFogColor = { 1, 1, 1, 1 };
qglFogfv(GL_FOG_COLOR, fWhiteFogColor);
}
}
}
glState.glStateBits = stateBits | glState.externalSetState;
}
@@ -450,23 +595,33 @@ void RB_BeginDrawingView (void) {
//
SetViewportAndScissor();
R_UploadDlights();
// ensures that depth writes are enabled for the depth clear
GL_State( GLS_DEFAULT );
// clear relevant buffers
clearBits = GL_DEPTH_BUFFER_BIT;
if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
if ( r_measureOverdraw->integer || r_shadows->integer == 3 )
{
clearBits |= GL_STENCIL_BUFFER_BIT;
}
if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
if (!( backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
{
clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
#ifdef _DEBUG
qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky
#else
qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
#endif
if (backEnd.viewParms.farplane_distance && tr.skyRendered && tr.portalRendered)
{
clearBits |= GL_COLOR_BUFFER_BIT;
qglClearColor(glState.fFogColor[0], glState.fFogColor[1], glState.fFogColor[2], glState.fFogColor[3]);
}
else
{
if (r_fastsky->integer)
{
clearBits |= GL_COLOR_BUFFER_BIT;
qglClearColor(0.5, 0.5, 1.0, 1.0);
}
}
}
qglClear( clearBits );
@@ -969,6 +1124,10 @@ const void *RB_StretchPic ( const void *data ) {
return (const void *)(cmd + 1);
}
void RB_SetupFog() {
// FIXME: unimplemented
}
/*
=============
+60 -40
View File
@@ -457,7 +457,11 @@ R_UnpackTerraPatch
================
*/
void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked) {
int i;
int i, j;
union {
int16_t v;
uint8_t b[2];
} flags;
pUnpacked->byDirty = qfalse;
pUnpacked->visCountCheck = 0;
@@ -468,41 +472,54 @@ void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked
Com_Error(ERR_DROP, "invalid map: terrain has lmapScale <= 0");
}
pUnpacked->drawinfo.lmapStep = (pPacked->lmapScale / 64);
pUnpacked->drawinfo.lmapSize = (pPacked->lmapScale * 8) | 1;
pUnpacked->drawinfo.lmapStep = (float)(pPacked->lmapScale / 64);
pUnpacked->drawinfo.lmapSize = (float)((pPacked->lmapScale * 8) + 1);
pUnpacked->s = ((float)pPacked->s + 0.5) * 0.0078125;
pUnpacked->t = ((float)pPacked->t + 0.5) * 0.0078125;
//if( s_worldData.lighting ) {
// pUnpacked->drawinfo.lmData = &s_worldData.lighting[ 3 * ( ( pPacked->t << 7 ) + pPacked->s + ( pPacked->iLightMap << 14 ) ) ];
//} else {
// pUnpacked->drawinfo.lmData = NULL;
//}
// fixme: is it important to have a lightmap data?
pUnpacked->drawinfo.lmData = NULL;
memcpy(pUnpacked->texCoord, pPacked->texCoord, sizeof(pUnpacked->texCoord));
pUnpacked->x0 = ((int)pPacked->x << 6);
pUnpacked->y0 = ((int)pPacked->y << 6);
pUnpacked->z0 = pPacked->iBaseHeight;
pUnpacked->shader = ShaderForShaderNum(pPacked->iShader, pPacked->iLightMap);
pUnpacked->iNorth = pPacked->iNorth;
pUnpacked->iEast = pPacked->iEast;
pUnpacked->iSouth = pPacked->iSouth;
pUnpacked->iWest = pPacked->iWest;
for (i = 0; i < 63; i++)
{
pUnpacked->varTree[0][i / 4].fVariance = pPacked->varTree[0][i].flags >> 12;
pUnpacked->varTree[1][i / 4].fVariance = pPacked->varTree[1][i].flags >> 12;
if( s_worldData.lighting ) {
pUnpacked->drawinfo.lmData = &s_worldData.lighting[ 3 * ( ( pPacked->t << 7 ) + pPacked->s + ( pPacked->iLightMap << 14 ) ) ];
} else {
pUnpacked->drawinfo.lmData = NULL;
}
memcpy(pUnpacked->heightmap, pPacked->heightmap, sizeof(pUnpacked->heightmap));
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
pUnpacked->texCoord[i][j][0] = LittleFloat(pPacked->texCoord[i][j][0]);
pUnpacked->texCoord[i][j][1] = LittleFloat(pPacked->texCoord[i][j][1]);
}
}
pUnpacked->x0 = ((int)pPacked->x << 6);
pUnpacked->y0 = ((int)pPacked->y << 6);
pUnpacked->z0 = LittleShort(pPacked->iBaseHeight);
pUnpacked->shader = ShaderForShaderNum(LittleShort(pPacked->iShader), LittleShort(pPacked->iLightMap));
pUnpacked->iNorth = LittleShort(pPacked->iNorth);
pUnpacked->iEast = LittleShort(pPacked->iEast);
pUnpacked->iSouth = LittleShort(pPacked->iSouth);
pUnpacked->iWest = LittleShort(pPacked->iWest);
for (i = 0; i < 63; i++)
{
flags.v = pPacked->varTree[0][i].flags;
flags.b[1] &= 7;
pUnpacked->varTree[0][i].fVariance = LittleShort(flags.v);
pUnpacked->varTree[0][i].s.flags = LittleShort(pPacked->varTree[0][i].flags) >> 12;
flags.v = pPacked->varTree[1][i].flags;
flags.b[1] &= 7;
pUnpacked->varTree[1][i].fVariance = LittleShort(flags.v);
pUnpacked->varTree[1][i].s.flags = LittleShort(pPacked->varTree[1][i].flags) >> 12;
}
for (i = 0; i < sizeof(pUnpacked->heightmap) / sizeof(pUnpacked->heightmap[0]); i++) {
pUnpacked->heightmap[i] = pPacked->heightmap[i];
}
pUnpacked->zmax = 0;
pUnpacked->flags = pPacked->flags;
for (i = 0; i < sizeof(pUnpacked->heightmap); i++)
for (i = 0; i < sizeof(pUnpacked->heightmap) / sizeof(pUnpacked->heightmap[0]); i++)
{
if (pUnpacked->zmax < pUnpacked->heightmap[i]) {
pUnpacked->zmax = pUnpacked->heightmap[i];
@@ -2070,17 +2087,16 @@ void R_LoadStaticModelData(gamelump_t* lump) {
}
s_worldData.numStaticModelData = lump->length / (sizeof(byte) * 3);
s_worldData.staticModelData = ri.Hunk_Alloc(s_worldData.numStaticModelData * (sizeof(byte) * 4));
s_worldData.staticModelData = (byte*)ri.Hunk_Alloc(s_worldData.numStaticModelData * sizeof(color4ub_t));
pSrcColors = lump->buffer;
pDstColors = s_worldData.staticModelData;
for (i = 0; i < lump->length; i += 3)
{
pDstColors[0] = pSrcColors[0];
pDstColors[1] = pSrcColors[1];
pDstColors[2] = pSrcColors[2];
pDstColors[3] = -1;
for (i = 0; i < lump->length; i += sizeof(byte) * 3)
{
// Colors are stored as integers
*(unsigned int*)pDstColors = LittleLong(*(unsigned int*)pSrcColors);
pDstColors[3] = 0xFF;
pSrcColors += sizeof(byte) * 3;
pDstColors += sizeof(byte) * 4;
@@ -2094,11 +2110,15 @@ R_CopyStaticModel
*/
void R_CopyStaticModel(cStaticModel_t* pSM, cStaticModelUnpacked_t* pUnpackedSM) {
pUnpackedSM->visCount = 0;
VectorCopy(pSM->angles, pUnpackedSM->angles);
VectorCopy(pSM->origin, pUnpackedSM->origin);
pUnpackedSM->scale = pSM->scale;
pUnpackedSM->firstVertexData = pSM->firstVertexData * 4 / 3;
pUnpackedSM->numVertexData = pSM->numVertexData;
pUnpackedSM->angles[0] = LittleFloat(pSM->angles[0]);
pUnpackedSM->angles[1] = LittleFloat(pSM->angles[1]);
pUnpackedSM->angles[2] = LittleFloat(pSM->angles[2]);
pUnpackedSM->origin[0] = LittleFloat(pSM->origin[0]);
pUnpackedSM->origin[1] = LittleFloat(pSM->origin[1]);
pUnpackedSM->origin[2] = LittleFloat(pSM->origin[2]);
pUnpackedSM->scale = LittleFloat(pSM->scale);
pUnpackedSM->firstVertexData = LittleLong(pSM->firstVertexData) * sizeof(color4ub_t) / (sizeof(byte) * 3);
pUnpackedSM->numVertexData = LittleLong(pSM->numVertexData);
memcpy(pUnpackedSM->model, pSM->model, sizeof(pUnpackedSM->model));
}
-55
View File
@@ -2057,61 +2057,6 @@ static void R_CreateDlightImage( void ) {
tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, 0, 1, qfalse, qfalse, qfalse, qfalse, GL_CLAMP, GL_CLAMP);
}
/*
=================
R_InitFogTable
=================
*/
void R_InitFogTable( void ) {
int i;
float d;
float exp;
exp = 0.5;
for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
tr.fogTable[i] = d;
}
}
/*
================
R_FogFactor
Returns a 0.0 to 1.0 fog density value
This is called for each texel of the fog texture on startup
and for each vertex of transparent shaders in fog dynamically
================
*/
float R_FogFactor( float s, float t ) {
float d;
s -= 1.0/512;
if ( s < 0 ) {
return 0;
}
if ( t < 1.0/32 ) {
return 0;
}
if ( t < 31.0/32 ) {
s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
}
// we need to leave a lot of clamp range
s *= 8;
if ( s > 1.0 ) {
s = 1.0;
}
d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
return d;
}
/*
==================
R_CreateDefaultImage
+41 -1
View File
@@ -841,6 +841,13 @@ void GL_SetDefaultState( void )
qglEnable( GL_SCISSOR_TEST );
qglDisable( GL_CULL_FACE );
qglDisable( GL_BLEND );
qglFogi(GL_FOG_MODE, GL_LINEAR);
glState.fFogColor[0] = 0.0;
glState.fFogColor[1] = 0.0;
glState.fFogColor[2] = 0.0;
glState.fFogColor[3] = 1.0;
}
const char* RE_GetGraphicsInfo() {
@@ -1200,6 +1207,21 @@ void R_Register( void )
ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
}
void R_InitExtensions() {
// FIXME: qglTextureEnvCombineExists
glState.cntTexEnvExt = 0;
glState.cntnvblendmode = 0;
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, 34165.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, 8448.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, 5890.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 770.0);
}
/*
===============
R_Init
@@ -1224,6 +1246,11 @@ void R_Init( void ) {
}
Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
tr.worldEntity.e.shaderRGBA[0] = -1;
tr.worldEntity.e.shaderRGBA[1] = 0;
tr.worldEntity.e.shaderRGBA[2] = -1;
tr.worldEntity.e.shaderRGBA[3] = -1;
//
// init function tables
//
@@ -1251,10 +1278,16 @@ void R_Init( void ) {
}
}
R_InitFogTable();
tr.rendererhandle = ri.Milliseconds();
if (!tr.rendererhandle) {
tr.rendererhandle = -1;
}
R_NoiseInit();
R_Sky_Init();
R_Register();
max_polys = r_maxpolys->integer;
@@ -1292,12 +1325,19 @@ void R_Init( void ) {
InitOpenGL();
R_InitExtensions();
R_InitImages();
R_StartupShaders();
R_ModelInit();
R_LevelMarksInit();
tr.pFontDebugStrings = R_LoadFont("verdana-14");
g_bInfoworldtris = qfalse;
err = qglGetError();
if ( err != GL_NO_ERROR )
ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
+92
View File
@@ -29,6 +29,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define DLIGHT_MINIMUM_RADIUS 16
// never calculate a range less than this to prevent huge light numbers
typedef struct {
dlight_t *dl;
float power;
vec3_t origin;
} incidentLight_t;
typedef struct {
int dlightMap;
int allocated[128];
byte lightmap_buffer[65536];
byte* srcBase;
byte* dstBase;
incidentLight_t lights[32];
int numLights;
} dlightInfo_t;
dlightInfo_t dli;
/*
===============
@@ -413,3 +430,78 @@ int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, ve
return qtrue;
}
void R_ClearRealDlights() {
memset(dli.allocated, 0, sizeof(dli.allocated));
dli.dlightMap = 0;
}
void R_UploadDlights() {
int i, h;
if (!tr.pc.c_dlightSurfaces) {
return;
}
h = 0;
for (i = 0; i < 128; ++i)
{
if (h < dli.allocated[i]) {
h = dli.allocated[i];
}
}
if (h)
{
if (h > 128) {
ri.Error(ERR_DROP, "R_UploadDlights: bad allocated height");
}
GL_Bind(tr.dlightImages[dli.dlightMap]);
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, h, GL_RGBA, GL_UNSIGNED_BYTE, dli.lightmap_buffer);
tr.pc.c_dlightMaps++;
memset(dli.allocated, 0, sizeof(dli.allocated));
}
}
qboolean R_AllocLMBlock(int w, int h, int* x, int* y) {
int i, j;
int best, best2;
for (;;)
{
best = 128;
for (i = 0; i < 128 - w; i++)
{
best2 = 0;
for (j = 0; j < w && dli.allocated[i] < best; j++)
{
if (best2 < dli.allocated[i]) {
best2 = dli.allocated[i];
}
}
if (j == w)
{
*x = i;
*y = best2;
best = best2;
}
}
if (h + best <= 128) {
break;
}
if (dli.dlightMap == 14) {
return qfalse;
}
R_UploadDlights();
dli.dlightMap++;
}
return qtrue;
}
+66 -27
View File
@@ -441,7 +441,7 @@ typedef struct {
qboolean active;
textureBundle_t bundle[NUM_TEXTURE_BUNDLES];
int multitextureEnv;
int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage)
waveForm_t rgbWave;
colorGen_t rgbGen;
@@ -540,8 +540,6 @@ typedef struct shader_s {
float portalRange; // distance to fog out at
int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage)
cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
qboolean polygonOffset; // set for decals and other items that must be offset
qboolean noMipMaps; // for console fonts, 2D elements, etc.
@@ -615,21 +613,29 @@ typedef struct {
int num_entities;
trRefEntity_t *entities;
int num_sprites;
refSprite_t *sprites;
int num_dlights;
struct dlight_s *dlights;
int numTerMarks;
struct srfMarkFragment_s *terMarks;
int numPolys;
struct srfPoly_s *polys;
int numDrawSurfs;
struct drawSurf_s *drawSurfs;
int numSpriteSurfs;
struct drawSurf_s* spriteSurfs;
int numStaticModels;
struct cStaticModelUnpacked_s* staticModels;
int numStaticModelData;
unsigned char* staticModelData;
int numSpriteSurfs;
struct drawSurf_s *spriteSurfs;
int numStaticModels;
struct cStaticModelUnpacked_s *staticModels;
int numStaticModelData;
unsigned char *staticModelData;
qboolean sky_portal;
float sky_alpha;
vec3_t sky_origin;
@@ -685,7 +691,7 @@ typedef struct {
int viewportX, viewportY, viewportWidth, viewportHeight;
float fovX, fovY;
float projectionMatrix[16];
cplane_t frustum[4];
cplane_t frustum[5];
vec3_t visBounds[2];
float zFar;
depthfog_t fog;
@@ -829,7 +835,10 @@ typedef struct {
typedef union varnodeUnpacked_u {
float fVariance;
byte flags;
struct {
byte flags;
unsigned char unused[3];
} s;
} varnodeUnpacked_t;
typedef unsigned short terraInt;
@@ -893,7 +902,7 @@ typedef struct cTerraPatchUnpacked_s {
unsigned int uiDistRecalc;
float s;
float t;
float texCoord[2][2][2];
vec2_t texCoord[2][2];
float x0;
float y0;
float z0;
@@ -1023,6 +1032,7 @@ typedef struct {
int numShaders;
dshader_t *shaders;
int numBmodels;
bmodel_t *bmodels;
int numplanes;
@@ -1069,9 +1079,7 @@ typedef struct {
const byte *vis; // may be passed in by CM_LoadMap to save space
byte *novis; // clusterBytes of 0xff
char *entityString;
char *entityParsePoint;
byte *lighting;
} world_t;
//======================================================================
@@ -1157,6 +1165,8 @@ typedef struct {
int c_leafs;
int c_dlightSurfaces;
int c_dlightSurfacesCulled;
int c_dlightMaps;
int c_dlightTexels;
} frontEndCounters_t;
#define FOG_TABLE_SIZE 256
@@ -1172,12 +1182,16 @@ typedef struct {
qboolean finishCalled;
int texEnv[2];
int faceCulling;
unsigned long glStateBits;
int cntTexEnvExt;
int cntnvblendmode;
long unsigned int glStateBits;
long unsigned int externalSetState;
vec4_t fFogColor;
} glstate_t;
typedef struct {
int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;
int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes, c_characterlights;
float c_overDraw;
int c_dlightVertexes;
@@ -1249,6 +1263,7 @@ typedef struct {
image_t *flareImage;
image_t *whiteImage; // full of 0xff
image_t *identityLightImage; // full of tr.identityLightByte
image_t *dlightImages[15];
shader_t *defaultShader;
shader_t *shadowShader;
@@ -1278,6 +1293,9 @@ typedef struct {
orientationr_t ori; // for current entity
portalsky_t portalsky;
qboolean skyRendered;
qboolean portalRendered;
trRefdef_t refdef;
int viewCluster;
@@ -1313,7 +1331,6 @@ typedef struct {
float triangleTable[FUNCTABLE_SIZE];
float sawToothTable[FUNCTABLE_SIZE];
float inverseSawToothTable[FUNCTABLE_SIZE];
float fogTable[FOG_TABLE_SIZE];
spherel_t sSunLight;
spherel_t sLights[1532];
@@ -1557,6 +1574,8 @@ void R_DebugCircle(const vec3_t org, float radius, float r, float g, float b, fl
void R_DebugLine(const vec3_t start, const vec3_t end, float r, float g, float b, float alpha);
void R_RenderView( viewParms_t *parms );
qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int entityNum);
void R_AddMD3Surfaces( trRefEntity_t *e );
void R_AddNullModelSurfaces( trRefEntity_t *e );
void R_AddBeamSurfaces( trRefEntity_t *e );
@@ -1573,18 +1592,24 @@ void R_AddDrawSurf(surfaceType_t* surface, shader_t* shader, int dlightMap);
#define CULL_IN 0 // completely unclipped
#define CULL_CLIP 1 // clipped by one or more planes
#define CULL_OUT 2 // completely outside the clipping planes
void R_LocalNormalToWorld (vec3_t local, vec3_t world);
void R_LocalPointToWorld (vec3_t local, vec3_t world);
void R_LocalNormalToWorld (const vec3_t local, vec3_t world);
void R_LocalPointToWorld (const vec3_t local, vec3_t world);
int R_CullLocalBoxOffset(const vec3_t offset, vec3_t bounds[2]);
int R_CullLocalBox (vec3_t bounds[2]);
int R_CullPointAndRadius( vec3_t origin, float radius );
int R_CullLocalPointAndRadius( vec3_t origin, float radius );
int R_DistanceCullLocalPointAndRadius(float fDist, const vec3_t pt, float radius);
int R_DistanceCullPointAndRadius(float fDist, const vec3_t pt, float radius);
void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *ori );
void R_RotateForStaticModel(cStaticModelUnpacked_t* SM, const viewParms_t* viewParms, orientationr_t* ori );
void R_RotateForViewer(void);
void R_SetupFrustum(void);
/*
** GL wrapper/helper functions
*/
void GL_SetFogColor(const vec4_t fColor);
void GL_Bind( image_t *image );
void GL_SetDefaultState (void);
void GL_SelectTexture( int unit );
@@ -1616,11 +1641,19 @@ void GL_Cull( int cullType );
#define GLS_DSTBLEND_BITS 0x000000f0
#define GLS_DEPTHMASK_TRUE 0x00000100
#define GLS_POLYMODE_LINE 0x00000200
#define GLS_DEPTHTEST_DISABLE 0x00000400
#define GLS_DEPTHFUNC_EQUAL 0x00000800
#define GLS_POLYMODE_LINE 0x00001000
#define GLS_CLAMP_EDGE 0x00001000
#define GLS_MULTITEXTURE 0x00002000
#define GLS_MULTITEXTURE_ENV 0x00004000
#define GLS_FOG 0x00008000
#define GLS_DEPTHFUNC_EQUAL 0x00020000
#define GLS_FOG_ENABLED 0x00010000
#define GLS_FOG_BLACK 0x00020000
#define GLS_FOG_WHITE 0x00040000
#define GLS_FOG_COLOR (GLS_FOG_BLACK | GLS_FOG_WHITE)
#define GLS_ATEST_GT_0 0x10000000
#define GLS_ATEST_LT_80 0x20000000
@@ -1684,8 +1717,6 @@ void R_SkinList_f( void );
const void *RB_TakeScreenshotCmd( const void *data );
void R_ScreenShot_f( void );
void R_InitFogTable( void );
float R_FogFactor( float s, float t );
void R_InitImages( void );
void R_DeleteTextures( void );
int R_SumOfUsedImages( void );
@@ -1806,8 +1837,14 @@ WORLD MAP
============================================================
*/
extern terraTri_t* g_pTris;
extern terrainVert_t* g_pVert;
void R_AddBrushModelSurfaces( trRefEntity_t *e );
void R_GetInlineModelBounds(int iIndex, vec3_t vMins, vec3_t vMaxs);
mnode_t* R_PointInLeaf(const vec3_t p);
int R_DlightTerrain(cTerraPatchUnpacked_t* surf, int dlightBits);
int R_CheckDlightTerrain(cTerraPatchUnpacked_t* surf, int dlightBits);
void R_AddWorldSurfaces( void );
qboolean R_inPVS( const vec3_t p1, const vec3_t p2 );
@@ -1848,6 +1885,7 @@ void RB_Grid_SetupStaticModel();
void RB_Light_Fullbright(const color4ub_t colors);
void R_Sphere_InitLights();
int R_GatherLightSources(const vec3_t vPos, vec3_t* pvLightPos, vec3_t* pvLightIntensity, int iMaxLights);
void R_UploadDlights();
/*
@@ -1859,6 +1897,7 @@ SHADOWS
*/
void RB_ShadowTessEnd( void );
void RB_ComputeShadowVolume();
void RB_ShadowFinish( void );
void RB_ProjectionShadowDeform( void );
@@ -1963,6 +2002,7 @@ void R_LevelMarksLoad(const char* szBSPName);
void R_LevelMarksInit();
void R_LevelMarksFree();
void R_UpdateLevelMarksSystem();
void R_AddPermanentMarkFragmentSurfaces(void** pFirstMarkFragment, int iNumMarkFragment);
/*
=============================================================
@@ -2013,6 +2053,7 @@ TERRAIN
=============================================================
*/
void R_MarkTerrainPatch(cTerraPatchUnpacked_t* pPatch);
void R_AddTerrainSurfaces();
void R_InitTerrain();
void R_TerrainPrepareFrame();
@@ -2050,6 +2091,7 @@ float R_CalcLod(const vec3_t origin, float radius);
extern int g_nStaticSurfaces;
extern qboolean g_bInfostaticmodels;
extern qboolean g_bInfoworldtris;
/*
=============================================================
@@ -2096,9 +2138,6 @@ void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords );
void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords );
void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords );
void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords );
void RB_CalcModulateColorsByFog( unsigned char *dstColors );
void RB_CalcModulateAlphasByFog( unsigned char *dstColors );
void RB_CalcModulateRGBAsByFog( unsigned char *dstColors );
void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors );
void RB_CalcWaveColor(const waveForm_t* wf, unsigned char* dstColors, unsigned char* constantColor);
void RB_CalcAlphaFromEntity( unsigned char *dstColors );
+130 -26
View File
@@ -49,7 +49,7 @@ R_CullLocalBox
Returns CULL_IN, CULL_CLIP, or CULL_OUT
=================
*/
int R_CullLocalBox (vec3_t bounds[2]) {
int R_CullLocalBoxOffset(const vec3_t offset, vec3_t bounds[2]) {
int i, j;
vec3_t transformed[8];
float dists[8];
@@ -69,6 +69,7 @@ int R_CullLocalBox (vec3_t bounds[2]) {
v[2] = bounds[(i>>2)&1][2];
VectorCopy( tr.ori.origin, transformed[i] );
VectorAdd(transformed[i], offset, transformed[i]);
VectorMA( transformed[i], v[0], tr.ori.axis[0], transformed[i] );
VectorMA( transformed[i], v[1], tr.ori.axis[1], transformed[i] );
VectorMA( transformed[i], v[2], tr.ori.axis[2], transformed[i] );
@@ -76,7 +77,7 @@ int R_CullLocalBox (vec3_t bounds[2]) {
// check against frustum planes
anyBack = 0;
for (i = 0 ; i < 4 ; i++) {
for (i = 0 ; i < tr.viewParms.fog.extrafrustums + 4 ; i++) {
frust = &tr.viewParms.frustum[i];
front = back = 0;
@@ -105,6 +106,10 @@ int R_CullLocalBox (vec3_t bounds[2]) {
return CULL_CLIP; // partially clipped
}
int R_CullLocalBox(vec3_t bounds[2]) {
return R_CullLocalBoxOffset(vec3_origin, bounds);
}
/*
** R_CullLocalPointAndRadius
*/
@@ -155,6 +160,35 @@ int R_CullPointAndRadius( vec3_t pt, float radius )
return CULL_IN; // completely inside frustum
}
int R_DistanceCullLocalPointAndRadius(float fDist, const vec3_t pt, float radius) {
vec3_t transformed;
R_LocalPointToWorld(pt, transformed);
return R_DistanceCullPointAndRadius(fDist, transformed, radius);
}
int R_DistanceCullPointAndRadius(float fDist, const vec3_t pt, float radius) {
if (!r_nocull->integer)
{
vec3_t vDelta;
float fLengthSquared;
float fTotalDistSquared;
VectorSubtract(pt, tr.viewParms.ori.origin, vDelta);
fLengthSquared = VectorLengthSquared(vDelta);
fTotalDistSquared = (fDist + radius) * (fDist + radius);
if ((fDist + radius) * (fDist + radius) < vDelta[2] + fLengthSquared) {
return CULL_OUT;
} else if ((fDist - radius) * (fDist - radius) > vDelta[2] + fLengthSquared) {
return CULL_IN;
}
}
return CULL_CLIP;
// FIXME: unimplemented
}
/*
=================
@@ -162,7 +196,7 @@ R_LocalNormalToWorld
=================
*/
void R_LocalNormalToWorld (vec3_t local, vec3_t world) {
void R_LocalNormalToWorld (const vec3_t local, vec3_t world) {
world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0];
world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1];
world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2];
@@ -174,7 +208,7 @@ R_LocalPointToWorld
=================
*/
void R_LocalPointToWorld (vec3_t local, vec3_t world) {
void R_LocalPointToWorld (const vec3_t local, vec3_t world) {
world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0] + tr.ori.origin[0];
world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1] + tr.ori.origin[1];
world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2] + tr.ori.origin[2];
@@ -581,6 +615,70 @@ void R_SetupFrustum (void) {
tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.ori.origin, tr.viewParms.frustum[i].normal);
SetPlaneSignbits( &tr.viewParms.frustum[i] );
}
if (tr.portalsky.inUse) {
tr.viewParms.farplane_distance = 0.0;
}
else if (r_farplane->integer)
{
tr.viewParms.farplane_distance = r_farplane->value;
sscanf(
r_farplane_color->string,
"%f %f %f",
&tr.viewParms.farplane_color[0],
&tr.viewParms.farplane_color[1],
&tr.viewParms.farplane_color[2]);
tr.viewParms.farplane_cull = !r_farplane_nocull->integer;
}
if (tr.viewParms.farplane_distance)
{
vec3_t farPoint;
float realPlaneLen;
float tmp;
vec4_t fogColor;
tr.viewParms.fog.len = tr.viewParms.farplane_distance;
tr.viewParms.fog.oolen = 1.0 / tr.viewParms.farplane_distance;
farPoint[0] = tr.viewParms.ori.origin[0] + tr.viewParms.ori.axis[0][0] * tr.viewParms.farplane_distance;
farPoint[1] = tr.viewParms.ori.origin[1] + tr.viewParms.ori.axis[0][1] * tr.viewParms.farplane_distance;
farPoint[2] = tr.viewParms.ori.origin[2] + tr.viewParms.ori.axis[0][2] * tr.viewParms.farplane_distance;
VectorNegate(tr.viewParms.ori.axis[0], tr.viewParms.frustum[4].normal);
tr.viewParms.frustum[4].type = PLANE_NON_AXIAL;
tr.viewParms.frustum[4].dist = DotProduct(farPoint, tr.viewParms.frustum[4].normal);
SetPlaneSignbits(&tr.viewParms.frustum[4]);
tr.viewParms.fog.enabled = r_farplane_nofog->integer == 0;
tr.viewParms.fog.extrafrustums = tr.viewParms.farplane_cull;
if (!r_farplane_nofog->integer)
{
qglFogf(GL_FOG_END, tr.viewParms.farplane_distance);
fogColor[0] = tr.viewParms.farplane_color[0] * tr.identityLight;
fogColor[1] = tr.viewParms.farplane_color[1] * tr.identityLight;
fogColor[2] = tr.viewParms.farplane_color[2] * tr.identityLight;
fogColor[3] = 1.0;
GL_SetFogColor(fogColor);
glState.externalSetState |= GLS_FOG;
}
else
{
glState.externalSetState &= ~GLS_FOG;
}
}
else
{
tr.viewParms.fog.enabled = 0;
tr.viewParms.fog.extrafrustums = 0;
glState.externalSetState &= ~GLS_FOG;
}
}
@@ -837,27 +935,26 @@ static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )
**
** Determines if a surface is completely offscreen.
*/
static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int entityNum) {
float shortest = 100000000;
int entityNum;
int numTriangles;
shader_t *shader;
int dlighted;
qboolean bStaticModel;
qboolean doRange;
orientationr_t surfOr;
unsigned int* indices;
vec4_t clip, eye;
int i;
unsigned int pointOr = 0;
unsigned int pointAnd = (unsigned int)~0;
if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp!
return qfalse;
}
R_RotateForViewer();
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &dlighted, &bStaticModel );
RB_BeginSurface( shader );
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
if (entityNum == ENTITYNUM_WORLD) {
surfOr = tr.viewParms.world;
} else {
R_RotateForEntity(&tr.refdef.entities[entityNum], &tr.viewParms, &surfOr);
}
assert( tess.numVertexes < 128 );
@@ -920,21 +1017,27 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128
return qtrue;
}
// mirrors can early out at this point, since we don't do a fade over distance
// with them (although we could)
if ( IsMirror( drawSurf, entityNum ) )
if (shader->fDistRange > 0.0)
{
return qfalse;
}
if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
{
return qtrue;
if (shortest > (tess.shader->portalRange * tess.shader->portalRange))
{
return qtrue;
}
}
return qfalse;
}
static qboolean DrawSurfIsOffscreen(drawSurf_t* drawSurf) {
int entityNum;
shader_t* shader;
int dlighted;
qboolean bStaticModel;
R_DecomposeSort(drawSurf->sort, &entityNum, &shader, &dlighted, &bStaticModel);
return SurfIsOffscreen((srfSurfaceFace_t*)drawSurf->surface, shader, entityNum);
}
/*
========================
R_MirrorViewBySurface
@@ -943,7 +1046,6 @@ Returns qtrue if another view has been rendered
========================
*/
qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
vec4_t clipDest[128];
viewParms_t newParms;
viewParms_t oldParms;
orientation_t surface, camera;
@@ -959,7 +1061,7 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
}
// trivially reject portal/mirror
if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
if (DrawSurfIsOffscreen( drawSurf ) ) {
return qfalse;
}
@@ -1602,6 +1704,8 @@ void R_RenderView (viewParms_t *parms) {
R_SetupFrustum ();
R_Sky_Reset();
R_GenerateDrawSurfs();
R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
+38 -2
View File
@@ -158,8 +158,7 @@ void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **li
//
surf = *mark;
// check if the surface has NOIMPACT or NOMARKS set
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) ) {
surf->viewCount = tr.viewCount;
}
// extra check for surfaces to avoid list overflows
@@ -244,6 +243,38 @@ void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POL
(*returnedFragments)++;
}
void R_AddMarkFragmentsToTerrain(
cTerraPatchUnpacked_t* pTerPatch,
int numPlanes,
vec3_t* normals,
float* dists,
int maxPoints,
const vec3_t pointBuffer,
markFragment_t* fragmentBuffer,
int* returnedPoints,
int* returnedFragments
)
{
// FIXME: unimplemented
}
void R_TessellateMarkFragments(
int* pReturnedPoints,
int* pReturnedFragments,
int numsurfaces, surfaceType_t** surfaces,
const vec3_t projectionDir, int numPlanes,
vec3_t* normals,
float* dists,
int maxPoints,
const vec3_t pointBuffer,
int maxFragments,
markFragment_t* fragmentBuffer,
float fRadiusSquared
)
{
// FIXME: unimplemented
}
/*
=================
R_MarkFragments
@@ -441,6 +472,11 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
return returnedFragments;
}
void R_BoxSurfacesForBModel_r(bmodel_t* pBmodel, const vec3_t mins, const vec3_t maxs, surfaceType_t** list, int listsize, int* listlength, const vec3_t dir)
{
// FIXME: unimplemented
}
int R_MarkFragmentsForInlineModel(clipHandle_t bmodel, const vec3_t angles, const vec3_t origin, int numPoints,
const vec3_t* points, const vec3_t projection, int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t* fragmentBuffer, float radiusSquared)
+305 -2
View File
@@ -24,22 +24,325 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h"
typedef struct lmEditPoly_s {
srfMarkFragment_t surf;
shader_t* shader;
int viewCount;
polyVert_t verts[8];
mnode_t* pLeafs[8];
int iNumLeafs;
} lmEditPoly_t;
typedef struct lmEditMarkDef_s {
struct lmEditMarkDef_s* pNextMark;
struct lmEditMarkDef_s* pPrevMark;
shader_t* markShader;
vec3_t vPos;
vec3_t vProjection;
float fRadius;
float fHeightScale;
float fWidthScale;
float fRotation;
float color[4];
qboolean bDoLighting;
lmEditPoly_t* pMarkEditPolys;
int iNumEditPolys;
vec3_t vPathCorners[4];
} lmEditMarkDef_t;
typedef struct lmPoly_s {
srfMarkFragment_t surf;
shader_t* shader;
int viewCount;
} lmPoly_t;
typedef struct {
qboolean bLevelMarksLoaded;
char szDCLFilename[MAX_QPATH];
lmPoly_t* pMarkFragments;
qboolean bAutoApplySettings;
lmEditPoly_t* pFreeEditPolys;
lmEditMarkDef_t activeMarkDefs;
lmEditMarkDef_t* pFreeMarkDefs;
lmEditMarkDef_t* pCurrentMark;
qboolean bPathLayingMode;
treadMark_t treadMark;
lmEditMarkDef_t* pTreadMarkStartDecal;
lmEditMarkDef_t* pTreadMarkEndDecal;
} lmGlobals_t;
typedef struct {
int ident;
int version;
int checksum;
int iNumDecals;
int iNumFragments;
} dclHeader_t;
typedef struct {
char shader[MAX_RES_NAME];
vec3_t vPos;
vec3_t vProjection;
float fRadius;
float fHeightScale;
float fWidthScale;
float fRotation;
float color[4];
qboolean bDoLighting;
} dclSavedMarkDef_t;
typedef struct {
char shader[MAX_RES_NAME];
int fogIndex;
int iIndex;
int iNumVerts;
} dclSavedMarkPoly_t;
cvar_t* dcl_editmode;
cvar_t* dcl_showcurrent;
cvar_t* dcl_autogetinfo;
cvar_t* dcl_shiftstep;
cvar_t* dcl_shader;
cvar_t* dcl_radius;
cvar_t* dcl_heightscale;
cvar_t* dcl_widthscale;
cvar_t* dcl_rotation;
cvar_t* dcl_r;
cvar_t* dcl_g;
cvar_t* dcl_b;
cvar_t* dcl_alpha;
cvar_t* dcl_dolighting;
cvar_t* dcl_doworld;
cvar_t* dcl_doterrain;
cvar_t* dcl_dobmodels;
cvar_t* dcl_dostring;
cvar_t* dcl_pathmode;
cvar_t* dcl_maxsegment;
cvar_t* dcl_minsegment;
cvar_t* dcl_maxoffset;
cvar_t* dcl_texturescale;
lmGlobals_t lm;
vec3_t vec_upwards;
void DCLC_Save(void)
{
// FIXME: unimplemented
}
void R_LevelMarksLoad(const char* szBSPName)
{
// FIXME: unimplemented
}
void R_RemoveEditPolyFromPointerList(lmEditPoly_t* pPoly, void** pFragmentList, int* piNumFragments)
{
// FIXME: unimplemented
}
void R_FreeMarkFragments(lmEditMarkDef_t* pMark)
{
// FIXME: unimplemented
}
void R_InitMarkDef(lmEditMarkDef_t* pMark)
{
// FIXME: unimplemented
}
lmEditMarkDef_t* R_AllocateMarkDef(void)
{
// FIXME: unimplemented
return NULL;
}
lmEditPoly_t* R_AllocateEditPoly(void)
{
// FIXME: unimplemented
return NULL;
}
qboolean R_AddEditPolyToPointerList(lmEditPoly_t* pPoly, void*** pFragmentList, int* piNumFragments)
{
// FIXME: unimplemented
return qfalse;
}
lmEditMarkDef_t* R_ApplyLevelDecal(const vec3_t vPos, const vec3_t vDir, qboolean bUseCurrent, qboolean bUseCurrentSettings, int iPathIndex)
{
// FIXME: unimplemented
return NULL;
}
void DCLC_Make(void)
{
// FIXME: unimplemented
}
void DCLC_Reapply(void)
{
// FIXME: unimplemented
}
void DCLC_Delete(void)
{
// FIXME: unimplemented
}
void DCLC_SelectNext(void)
{
// FIXME: unimplemented
}
void DCLC_SelectPrev(void)
{
// FIXME: unimplemented
}
void DCLC_SelectCh(void)
{
// FIXME: unimplemented
}
void DCLC_SelectChNxt(void)
{
// FIXME: unimplemented
}
void DCLC_GetInfo(void)
{
// FIXME: unimplemented
}
void DCLC_ShiftUp(void)
{
// FIXME: unimplemented
}
void DCLC_ShiftDown(void)
{
// FIXME: unimplemented
}
void DCLC_ShiftLeft(void)
{
// FIXME: unimplemented
}
void DCLC_ShiftRight(void)
{
// FIXME: unimplemented
}
void DCLC_RandomRoll(void)
{
// FIXME: unimplemented
}
void R_LevelMarksInit()
{
// FIXME: unimplemented
memset(&lm, 0, sizeof(lm));
dcl_editmode = ri.Cvar_Get("dcl_editmode", "0", CVAR_LATCH);
dcl_showcurrent = ri.Cvar_Get("dcl_showcurrent", "1", 0);
dcl_autogetinfo = ri.Cvar_Get("dcl_autogetinfo", "1", 0);
dcl_shiftstep = ri.Cvar_Get("dcl_shiftstep", "4", 0);
dcl_shader = ri.Cvar_Get("dcl_shader", "blastmark", 0);
dcl_radius = ri.Cvar_Get("dcl_radius", "16", 0);
dcl_heightscale = ri.Cvar_Get("dcl_heightscale", "1", 0);
dcl_widthscale = ri.Cvar_Get("dcl_widthscale", "1", 0);
dcl_rotation = ri.Cvar_Get("dcl_rotation", "0", 0);
dcl_r = ri.Cvar_Get("dcl_r", "1", 0);
dcl_g = ri.Cvar_Get("dcl_g", "1", 0);
dcl_b = ri.Cvar_Get("dcl_b", "1", 0);
dcl_alpha = ri.Cvar_Get("dcl_alpha", "1", 0);
dcl_dolighting = ri.Cvar_Get("dcl_dolighting", "1", 0);
dcl_doworld = ri.Cvar_Get("dcl_doworld", "1", 0);
dcl_doterrain = ri.Cvar_Get("dcl_doterrain", "1", 0);
dcl_dobmodels = ri.Cvar_Get("dcl_dobmodels", "1", 0);
dcl_dostring = ri.Cvar_Get("dcl_dostring", "apply to all", 0);
dcl_pathmode = ri.Cvar_Get("dcl_pathmode", "0", 0);
dcl_maxsegment = ri.Cvar_Get("dcl_maxsegment", "512", 0);
dcl_minsegment = ri.Cvar_Get("dcl_minsegment", "24", 0);
dcl_maxoffset = ri.Cvar_Get("dcl_maxoffset", "10", 0);
dcl_texturescale = ri.Cvar_Get("dcl_texturescale", "32", 0);
if (dcl_editmode->integer)
{
ri.Cmd_AddCommand("dclc_make", DCLC_Make);
ri.Cmd_AddCommand("dclc_reapply", DCLC_Reapply);
ri.Cmd_AddCommand("dclc_delete", DCLC_Delete);
ri.Cmd_AddCommand("dclc_selectnext", DCLC_SelectNext);
ri.Cmd_AddCommand("dclc_selectprev", DCLC_SelectPrev);
ri.Cmd_AddCommand("dclc_selectch", DCLC_SelectCh);
ri.Cmd_AddCommand("dclc_selectchnxt", DCLC_SelectChNxt);
ri.Cmd_AddCommand("dclc_getinfo", DCLC_GetInfo);
ri.Cmd_AddCommand("dclc_shiftup", DCLC_ShiftUp);
ri.Cmd_AddCommand("dclc_shiftdown", DCLC_ShiftDown);
ri.Cmd_AddCommand("dclc_shiftleft", DCLC_ShiftLeft);
ri.Cmd_AddCommand("dclc_shiftright", DCLC_ShiftRight);
ri.Cmd_AddCommand("dclc_randomroll", DCLC_RandomRoll);
ri.Cmd_AddCommand("dclc_save", DCLC_Save);
lm.activeMarkDefs.pNextMark = &lm.activeMarkDefs;
lm.activeMarkDefs.pPrevMark = &lm.activeMarkDefs;
}
}
void R_LevelMarksFree()
{
// FIXME: unimplemented
int i;
if (!dcl_editmode->integer) {
return;
}
ri.Cmd_RemoveCommand("dclc_make");
ri.Cmd_RemoveCommand("dclc_reapply");
ri.Cmd_RemoveCommand("dclc_delete");
ri.Cmd_RemoveCommand("dclc_selectnext");
ri.Cmd_RemoveCommand("dclc_selectprev");
ri.Cmd_RemoveCommand("dclc_selectch");
ri.Cmd_RemoveCommand("dclc_selectchnxt");
ri.Cmd_RemoveCommand("dclc_getinfo");
ri.Cmd_RemoveCommand("dclc_shiftup");
ri.Cmd_RemoveCommand("dclc_shiftdown");
ri.Cmd_RemoveCommand("dclc_shiftleft");
ri.Cmd_RemoveCommand("dclc_shiftright");
ri.Cmd_RemoveCommand("dclc_randomroll");
ri.Cmd_RemoveCommand("dclc_save");
for (i = 0; i < tr.world->numBmodels; i++)
{
bmodel_t* pBmodel = &tr.world->bmodels[i];
if (pBmodel->iNumMarkFragment && pBmodel->pFirstMarkFragment)
{
ri.Free(pBmodel->pFirstMarkFragment);
pBmodel->pFirstMarkFragment = NULL;
pBmodel->iNumMarkFragment = 0;
}
}
for (i = tr.world->numDecisionNodes; i < tr.world->numnodes; i++)
{
mnode_t* pLeaf = &tr.world->nodes[i];
if (pLeaf->iNumMarkFragment)
{
if (pLeaf->pFirstMarkFragment)
{
ri.Free(pLeaf->pFirstMarkFragment);
pLeaf->pFirstMarkFragment = NULL;
pLeaf->iNumMarkFragment = 0;
}
}
}
}
void R_UpdateLevelMarksSystem()
{
// FIXME: unimplemented
}
void R_AddPermanentMarkFragmentSurfaces(void** pFirstMarkFragment, int iNumMarkFragment) {
// FIXME: unimplemented
}
+2
View File
@@ -28,6 +28,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define LL(x) x=LittleLong(x)
qboolean g_bInfoworldtris;
/*
** R_GetModelByHandle
*/
+42
View File
@@ -32,6 +32,12 @@ int r_firstSceneDlight;
int r_numentities;
int r_firstSceneEntity;
int r_numsprites;
int r_firstSceneSprite;
int r_numtermarks;
int r_firstSceneTerMark;
int r_numpolys;
int r_firstScenePoly;
@@ -63,6 +69,12 @@ void R_ToggleSmpFrame( void ) {
r_numentities = 0;
r_firstSceneEntity = 0;
r_numsprites = 0;
r_firstSceneSprite = 0;
r_numtermarks = 0;
r_firstSceneTerMark = 0;
r_numpolys = 0;
r_firstScenePoly = 0;
@@ -79,6 +91,8 @@ RE_ClearScene
void RE_ClearScene( void ) {
r_firstSceneDlight = r_numdlights;
r_firstSceneEntity = r_numentities;
r_firstSceneSprite = r_numsprites;
r_firstSceneTerMark = r_numtermarks;
r_firstScenePoly = r_numpolys;
}
@@ -387,6 +401,14 @@ void RE_RenderScene( const refdef_t *fd ) {
}
}
// copy the sky data
tr.refdef.sky_alpha = fd->sky_alpha;
tr.refdef.sky_portal = fd->sky_portal;
VectorCopy(fd->sky_origin, tr.refdef.sky_origin);
VectorCopy(fd->sky_axis[0], tr.refdef.sky_axis[0]);
VectorCopy(fd->sky_axis[1], tr.refdef.sky_axis[1]);
VectorCopy(fd->sky_axis[2], tr.refdef.sky_axis[2]);
// derived info
@@ -398,12 +420,20 @@ void RE_RenderScene( const refdef_t *fd ) {
tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
tr.refdef.num_sprites = r_numsprites - r_firstSceneSprite;
tr.refdef.sprites = &backEndData[tr.smpFrame]->sprites[r_firstSceneSprite];
tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];
tr.refdef.numTerMarks = r_numtermarks - r_firstSceneTerMark;
tr.refdef.terMarks = &backEndData[tr.smpFrame]->terMarks[r_firstSceneTerMark];
tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
backEndData[tr.smpFrame]->staticModelData = tr.refdef.staticModelData;
// turn off dynamic lighting globally by clearing all the
// dlights if it needs to be disabled or if vertex lighting is enabled
if (r_vertexLight->integer == 1 ) {
@@ -424,6 +454,8 @@ void RE_RenderScene( const refdef_t *fd ) {
// The refdef takes 0-at-the-top y coordinates, so
// convert to GL's 0-at-the-bottom space
//
tr.skyRendered = qfalse;
tr.portalRendered = qfalse;
Com_Memset( &parms, 0, sizeof( parms ) );
parms.viewportX = tr.refdef.x;
parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
@@ -441,12 +473,22 @@ void RE_RenderScene( const refdef_t *fd ) {
VectorCopy( fd->vieworg, parms.pvsOrigin );
// copy the farplane data
parms.farplane_distance = fd->farplane_distance;
parms.farplane_color[0] = fd->farplane_color[0];
parms.farplane_color[1] = fd->farplane_color[1];
parms.farplane_color[2] = fd->farplane_color[2];
parms.farplane_cull = fd->farplane_cull;
R_ClearRealDlights();
R_RenderView( &parms );
// the next scene rendered in this frame will tack on after this one
r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
r_firstSceneEntity = r_numentities;
r_firstSceneSprite = r_numsprites;
r_firstSceneDlight = r_numdlights;
r_firstSceneTerMark = r_numtermarks;
r_firstScenePoly = r_numpolys;
tr.frontEndMsec += ri.Milliseconds() - startTime;
+104 -41
View File
@@ -354,6 +354,37 @@ static void DrawMultitextured( shaderCommands_t *input, int stage ) {
qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
R_BindAnimatedImage( &pStage->bundle[0] );
if (pStage->stateBits & GLS_MULTITEXTURE_ENV)
{
glState.cntnvblendmode = pStage->multitextureEnv;
glState.cntTexEnvExt = GLS_MULTITEXTURE_ENV;
if (pStage->multitextureEnv == GL_ADD)
{
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, 260.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, 33984.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, 0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 33985.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE3_RGB, 0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND3_RGB, 0x44404000);
}
else if (pStage->multitextureEnv == GL_MODULATE)
{
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, 33984.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, 33985.0);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 0x44400000);
}
else
{
ri.Printf(3, "Unknown MT mode for: %s\n", input->shader);
}
}
//
// lightmap/secondary pass
//
@@ -361,23 +392,38 @@ static void DrawMultitextured( shaderCommands_t *input, int stage ) {
qglEnable( GL_TEXTURE_2D );
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
if ( r_lightmap->integer ) {
if ( r_lightmap->integer && pStage->bundle[1].isLightmap ) {
GL_TexEnv( GL_REPLACE );
} else if (pStage->stateBits & GLS_MULTITEXTURE_ENV) {
glState.cntTexEnvExt = GLS_MULTITEXTURE_ENV;
GL_TexEnv(GL_COMBINE);
qglTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, 34165);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, 34168);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 0x44400000);
qglTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, 0x47057700);
qglTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 0x44407700000);
} else {
GL_TexEnv( tess.shader->multitextureEnv );
GL_TexEnv( pStage->multitextureEnv );
}
qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
R_BindAnimatedImage( &pStage->bundle[1] );
if (!input->dlightMap || !pStage->bundle[1].isLightmap) {
R_BindAnimatedImage(&pStage->bundle[1]);
} else {
GL_Bind(&tr.identityLightImage[input->dlightMap]);
}
R_DrawElements( input->numIndexes, input->indexes );
qglDisable(GL_TEXTURE_2D);
//
// disable texturing on TEXTURE1, then select TEXTURE0
//
//qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
qglDisable( GL_TEXTURE_2D );
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
GL_SelectTexture( 0 );
}
@@ -1048,54 +1094,64 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
int stage;
for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
for (stage = 0; stage < MAX_SHADER_STAGES; stage++)
{
shaderStage_t *pStage = tess.xstages[stage];
shaderStage_t* pStage = tess.xstages[stage];
if ( !pStage )
if (!pStage)
{
break;
}
ComputeColors( pStage );
ComputeTexCoords( pStage );
if (pStage->alphaGen == AGEN_SKYALPHA && tr.refdef.sky_alpha < 0.01) {
continue;
}
else if (pStage->alphaGen == AGEN_ONE_MINUS_SKYALPHA && tr.refdef.sky_alpha > 0.99) {
continue;
}
if ( !setArraysOnce )
ComputeTexCoords(pStage);
ComputeColors(pStage);
if (!setArraysOnce)
{
qglEnableClientState( GL_COLOR_ARRAY );
qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
qglEnableClientState(GL_COLOR_ARRAY);
qglColorPointer(4, GL_UNSIGNED_BYTE, 0, input->svars.colors);
}
//
// do multitexture
//
if ( pStage->bundle[1].image[0] != 0 )
if (pStage->bundle[1].image[0] != 0)
{
DrawMultitextured( input, stage );
DrawMultitextured(input, stage);
}
else
{
if (backEnd.in2D) {
GL_State(pStage->stateBits | GLS_DEPTHTEST_DISABLE);
} else {
}
else {
GL_State(pStage->stateBits);
}
if ( !setArraysOnce )
if (!setArraysOnce)
{
qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
qglTexCoordPointer(2, GL_FLOAT, 0, input->svars.texcoords[0]);
}
//
// set state
//
if ( pStage->bundle[0].vertexLightmap && r_vertexLight->integer && r_lightmap->integer )
if (pStage->bundle[0].vertexLightmap && r_vertexLight->integer && r_lightmap->integer)
{
GL_Bind( tr.whiteImage );
} else {
GL_Bind(tr.whiteImage);
}
else {
if (input->dlightMap && tess.xstages[stage]->bundle[0].isLightmap) {
GL_Bind(&tr.identityLightImage[input->dlightMap]);
} else {
}
else {
R_BindAnimatedImage(&pStage->bundle[0]);
}
}
@@ -1103,10 +1159,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
//
// draw
//
R_DrawElements( input->numIndexes, input->indexes );
R_DrawElements(input->numIndexes, input->indexes);
}
// allow skipping out to show just lightmaps during development
if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
if (r_lightmap->integer && (pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap))
{
break;
}
@@ -1158,21 +1214,21 @@ void RB_StageIteratorGeneric( void )
// to avoid compiling those arrays since they will change
// during multipass rendering
//
if ( tess.numPasses > 1 || input->shader->multitextureEnv )
if (tess.numPasses > 1 || (tess.xstages[0] && tess.xstages[0]->multitextureEnv))
{
setArraysOnce = qfalse;
qglDisableClientState (GL_COLOR_ARRAY);
qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
qglDisableClientState(GL_COLOR_ARRAY);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
else
{
setArraysOnce = qtrue;
qglEnableClientState( GL_COLOR_ARRAY);
qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
qglEnableClientState(GL_COLOR_ARRAY);
qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.svars.colors);
qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglTexCoordPointer(2, GL_FLOAT, 0, tess.svars.texcoords[0]);
}
//
@@ -1419,7 +1475,6 @@ void RB_EndSurface( void ) {
if (input->numIndexes == 0) {
return;
}
if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
}
@@ -1427,8 +1482,12 @@ void RB_EndSurface( void ) {
ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
}
if (tess.xyz[SHADER_MAX_VERTEXES - 1][0] && r_shadows->integer != 3) {
tess.xyz[SHADER_MAX_VERTEXES - 1][0] = 0;
}
if ( tess.shader == tr.shadowShader ) {
RB_ShadowTessEnd();
RB_ComputeShadowVolume();
return;
}
@@ -1450,15 +1509,19 @@ void RB_EndSurface( void ) {
//
tess.currentStageIteratorFunc();
//
// draw debugging stuff
//
if ( r_showtris->integer ) {
DrawTris (input);
}
if ( r_shownormals->integer ) {
DrawNormals (input);
if (!(tr.refdef.rdflags & RDF_NOWORLDMODEL) && !backEnd.in2D)
{
//
// draw debugging stuff
//
if (r_showtris->integer && developer->integer) {
DrawTris(input);
}
if (r_shownormals->integer && developer->integer) {
DrawNormals(input);
}
}
// clear shader so we can tell we don't have any unclosed surfaces
tess.numIndexes = 0;
-59
View File
@@ -792,65 +792,6 @@ void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )
}
}
/*
** RB_CalcModulateColorsByFog
*/
void RB_CalcModulateColorsByFog( unsigned char *colors ) {
int i;
float texCoords[SHADER_MAX_VERTEXES][2];
// calculate texcoords so we can derive density
// this is not wasted, because it would only have
// been previously called if the surface was opaque
RB_CalcFogTexCoords( texCoords[0] );
for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
colors[0] *= f;
colors[1] *= f;
colors[2] *= f;
}
}
/*
** RB_CalcModulateAlphasByFog
*/
void RB_CalcModulateAlphasByFog( unsigned char *colors ) {
int i;
float texCoords[SHADER_MAX_VERTEXES][2];
// calculate texcoords so we can derive density
// this is not wasted, because it would only have
// been previously called if the surface was opaque
RB_CalcFogTexCoords( texCoords[0] );
for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
colors[3] *= f;
}
}
/*
** RB_CalcModulateRGBAsByFog
*/
void RB_CalcModulateRGBAsByFog( unsigned char *colors ) {
int i;
float texCoords[SHADER_MAX_VERTEXES][2];
// calculate texcoords so we can derive density
// this is not wasted, because it would only have
// been previously called if the surface was opaque
RB_CalcFogTexCoords( texCoords[0] );
for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
colors[0] *= f;
colors[1] *= f;
colors[2] *= f;
colors[3] *= f;
}
}
/*
====================================================================
+302 -192
View File
@@ -405,19 +405,19 @@ static void ParseWaveForm( char **text, waveForm_t *wave )
ParseTexMod
===================
*/
static void ParseTexMod( char *_text, shaderStage_t *stage )
static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle )
{
const char *token;
char **text = &_text;
texModInfo_t *tmi;
if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
if ( stage->bundle[cntBundle].numTexMods == TR_MAX_TEXMODS ) {
ri.Error( ERR_DROP, "ERROR: too many tcMod unfoggedStages in shader '%s'\n", shader.name );
return;
}
tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
stage->bundle[0].numTexMods++;
tmi = &stage->bundle[cntBundle].texMods[stage->bundle[cntBundle].numTexMods];
stage->bundle[cntBundle].numTexMods++;
token = COM_ParseExt( text, qfalse );
@@ -640,6 +640,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
char *token;
int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
qboolean depthMaskExplicit = qfalse;
int cntBundle = 0;
int depthTestBits = 0;
int fogBits = 0;
stage->active = qtrue;
stage->noMipMaps = shader_noMipMaps;
@@ -659,6 +662,24 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{
break;
}
// no picmip adjustment
else if ( !Q_stricmp( token, "nomipmaps" ) )
{
stage->noMipMaps = qtrue;
continue;
}
// no picmip adjustment
else if ( !Q_stricmp( token, "nopicmip" ) )
{
stage->noPicMip = qtrue;
continue;
}
// no picmip adjustment
else if ( !Q_stricmp( token, "nofog" ) )
{
fogBits = GLS_FOG;
continue;
}
//
// map <name>
//
@@ -673,23 +694,23 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "$whiteimage" ) )
{
stage->bundle[0].image[0] = tr.whiteImage;
stage->bundle[cntBundle].image[0] = tr.whiteImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[0].isLightmap = qtrue;
stage->bundle[cntBundle].isLightmap = qtrue;
if ( shader.lightmapIndex < 0 ) {
stage->bundle[0].image[0] = tr.whiteImage;
stage->bundle[cntBundle].image[0] = tr.whiteImage;
} else {
stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
stage->bundle[cntBundle].image[0] = tr.lightmaps[shader.lightmapIndex];
}
continue;
}
else
{
stage->bundle[0].image[0] = R_FindImageFile( token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT );
if ( !stage->bundle[0].image[0] )
stage->bundle[cntBundle].image[0] = R_FindImageFile( token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT );
if ( !stage->bundle[cntBundle].image[0] )
{
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse;
@@ -708,8 +729,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
return qfalse;
}
stage->bundle[0].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, r_forceClampToEdge->value ? GL_CLAMP_TO_EDGE : GL_CLAMP, r_forceClampToEdge->value ? GL_CLAMP_TO_EDGE : GL_CLAMP);
if ( !stage->bundle[0].image[0] )
stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, r_forceClampToEdge->value ? GL_CLAMP_TO_EDGE : GL_CLAMP, r_forceClampToEdge->value ? GL_CLAMP_TO_EDGE : GL_CLAMP);
if ( !stage->bundle[cntBundle].image[0] )
{
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse;
@@ -726,7 +747,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name );
return qfalse;
}
stage->bundle[0].imageAnimationSpeed = atof( token );
stage->bundle[cntBundle].imageAnimationSpeed = atof( token );
// parse up to MAX_IMAGE_ANIMATIONS animations
while ( 1 ) {
@@ -736,15 +757,15 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !token[0] ) {
break;
}
num = stage->bundle[0].numImageAnimations;
num = stage->bundle[cntBundle].numImageAnimations;
if ( num < MAX_IMAGE_ANIMATIONS ) {
stage->bundle[0].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT );
if ( !stage->bundle[0].image[num] )
stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT );
if ( !stage->bundle[cntBundle].image[num] )
{
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse;
}
stage->bundle[0].numImageAnimations++;
stage->bundle[cntBundle].numImageAnimations++;
}
}
}
@@ -777,11 +798,11 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "lequal" ) )
{
depthFuncBits = 0;
depthTestBits = 0;
}
else if ( !Q_stricmp( token, "equal" ) )
{
depthFuncBits = GLS_DEPTHFUNC_EQUAL;
depthTestBits = GLS_DEPTHFUNC_EQUAL;
}
else
{
@@ -1146,32 +1167,32 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "environment" ) )
{
shader.needsNormal = qtrue;
stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
stage->bundle[cntBundle].tcGen = TCGEN_ENVIRONMENT_MAPPED;
}
else if (!Q_stricmp(token, "environmentmodel"))
{
shader.needsNormal = qtrue;
stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED2;
stage->bundle[cntBundle].tcGen = TCGEN_ENVIRONMENT_MAPPED2;
}
else if (!Q_stricmp(token, "sunreflection"))
{
shader.needsNormal = qtrue;
stage->bundle[0].tcGen = TCGEN_SUN_REFLECTION;
stage->bundle[cntBundle].tcGen = TCGEN_SUN_REFLECTION;
}
else if ( !Q_stricmp( token, "lightmap" ) )
{
stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
stage->bundle[cntBundle].tcGen = TCGEN_LIGHTMAP;
}
else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
{
stage->bundle[0].tcGen = TCGEN_TEXTURE;
stage->bundle[cntBundle].tcGen = TCGEN_TEXTURE;
}
else if ( !Q_stricmp( token, "vector" ) )
{
ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
ParseVector( text, 3, stage->bundle[cntBundle].tcGenVectors[0] );
ParseVector( text, 3, stage->bundle[cntBundle].tcGenVectors[1] );
stage->bundle[0].tcGen = TCGEN_VECTOR;
stage->bundle[cntBundle].tcGen = TCGEN_VECTOR;
}
else
{
@@ -1194,7 +1215,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
strcat( buffer, " " );
}
ParseTexMod( buffer, stage );
ParseTexMod( buffer, stage, cntBundle );
continue;
}
@@ -1216,14 +1237,22 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
else if (!Q_stricmp(token, "nextBundle"))
{
if (!qglActiveTextureARB) {
continue;
ri.Printf(PRINT_ALL, "WARNING: " PRODUCT_NAME " requires a video card with multitexturing capability\n");
return qfalse;
}
token = COM_ParseExt(text, qfalse);
if (token[0] == 0) {
if (token[0] && !Q_stricmp(token, "add")) {
stage->multitextureEnv = GL_ADD;
} else {
stage->multitextureEnv = GL_MODULATE;
}
// FIXME: unimplemented
cntBundle++;
if (cntBundle > NUM_TEXTURE_BUNDLES) {
ri.Printf(PRINT_WARNING, "WARNING: too many nextBundle commands in shader '%s'\n", shader.name);
return qfalse;
}
continue;
}
else
@@ -1237,7 +1266,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
// if cgen isn't explicitly specified, use either identity or identitylighting
//
if ( stage->rgbGen == CGEN_BAD ) {
if ( blendSrcBits == 0 ||
if ( (!cntBundle && !stage->bundle[0].isLightmap) ||
blendSrcBits == 0 ||
blendSrcBits == GLS_SRCBLEND_ONE ||
blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
stage->rgbGen = CGEN_IDENTITY_LIGHTING;
@@ -1276,7 +1306,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->stateBits = depthMaskBits |
blendSrcBits | blendDstBits |
atestBits |
depthFuncBits;
depthFuncBits |
depthTestBits |
fogBits;
return qtrue;
}
@@ -1601,8 +1633,11 @@ infoParm_t infoParms[] = {
{"lava", 1, 0, CONTENTS_LAVA }, // very damaging
{"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
{"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
{"fence", 1, 0, CONTENTS_FENCE },
{"weaponclip", 1, 0, CONTENTS_WEAPONCLIP },
{"vehicleclip", 1, 0, CONTENTS_VEHICLECLIP },
{"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
{"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
{"nonsolid", 1, SURF_NONSOLID, 0 }, // clears the solid flag
// utility relevant attributes
{"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
@@ -1610,14 +1645,9 @@ infoParm_t infoParms[] = {
{"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
{"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
{"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
{"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
{"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
{"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
{"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
{"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
{"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
{"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
{"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
{"alphashadow", 1, SURF_ALPHASHADOW, 0 }, // carves surfaces entering
// server attributes
{"slick", 0, SURF_SLICK, 0 },
@@ -1625,16 +1655,29 @@ infoParm_t infoParms[] = {
{"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
{"ladder", 0, SURF_LADDER, 0 },
{"nodamage", 0, SURF_NODAMAGE, 0 },
{"metalsteps", 0, SURF_METALSTEPS,0 },
{"flesh", 0, SURF_FLESH, 0 },
{"nosteps", 0, SURF_NOSTEPS, 0 },
{"paper", 0, SURF_PAPER, 0 },
{"wood", 0, SURF_WOOD, 0 },
{"metal", 0, SURF_METAL, 0 },
{"rock", 0, SURF_ROCK, 0 },
{"dirt", 0, SURF_DIRT, 0 },
{"grill", 0, SURF_GRILL, 0 },
{"grass", 0, SURF_GRASS, 0 },
{"mud", 0, SURF_MUD, 0 },
{"puddle", 0, SURF_PUDDLE, 0 },
{"glass", 0, SURF_GLASS, 0 },
{"gravel", 0, SURF_GRAVEL, 0 },
{"sand", 0, SURF_SAND, 0 },
{"foliage", 0, SURF_FOLIAGE, 0 },
{"snow", 0, SURF_SNOW, 0 },
{"carpet", 0, SURF_CARPET, 0 },
// drawsurf attributes
{"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
{"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
{"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
{"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
{"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
{"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
{"castshadow", 0, SURF_CASTSHADOW, 0 }, // sample lighting at vertexes
{"nolightmap", 0, SURF_NOLIGHTMAP, 0 }, // don't generate a lightmap
{"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
{"hint", 0, SURF_HINT, 0} // leave a dust trail when walking on this surface
};
@@ -1962,7 +2005,7 @@ static void ComputeStageIteratorFunc( void )
{
if ( !shader.polygonOffset )
{
if ( !shader.multitextureEnv )
if ( !unfoggedStages[0].multitextureEnv )
{
if ( !shader.numDeforms )
{
@@ -1990,7 +2033,7 @@ static void ComputeStageIteratorFunc( void )
{
if ( !shader.numDeforms )
{
if ( shader.multitextureEnv )
if (unfoggedStages[0].multitextureEnv )
{
shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
goto done;
@@ -2052,113 +2095,121 @@ Attempt to combine two unfoggedStages into a single multitexture stage
FIXME: I think modulated add + modulated add collapses incorrectly
=================
*/
static qboolean CollapseMultitexture( void ) {
static void CollapseMultitexture(int *stagecounter) {
int iUseCollapse;
int stagenum;
int abits, bbits;
int i;
shaderStage_t* stage;
textureBundle_t tmpBundle;
if ( !qglActiveTextureARB ) {
return qfalse;
}
for (stagenum = 0; stagenum < *stagecounter - 1; stagenum++) {
stage = &unfoggedStages[stagenum];
// make sure both unfoggedStages are active
if ( !unfoggedStages[0].active || !unfoggedStages[1].active ) {
return qfalse;
}
// on voodoo2, don't combine different tmus
if ( glConfig.driverType == GLDRV_VOODOO ) {
if ( unfoggedStages[0].bundle[0].image[0]->TMU ==
unfoggedStages[1].bundle[0].image[0]->TMU ) {
return qfalse;
// make sure both unfoggedStages are active
if (!stage->active || !unfoggedStages[stagenum + 1].active) {
continue;
}
}
abits = unfoggedStages[0].stateBits;
bbits = unfoggedStages[1].stateBits;
// make sure that both unfoggedStages have identical state other than blend modes
if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
return qfalse;
}
abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
// search for a valid multitexture blend function
for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
if ( abits == collapse[i].blendA
&& bbits == collapse[i].blendB ) {
break;
if (stage->multitextureEnv) {
continue;
}
}
// nothing found
if ( collapse[i].blendA == -1 ) {
return qfalse;
}
// on voodoo2, don't combine different tmus
if (glConfig.driverType == GLDRV_VOODOO) {
if (stage->bundle[0].image[0]->TMU ==
unfoggedStages[stagenum + 1].bundle[0].image[0]->TMU) {
continue;
}
}
// GL_ADD is a separate extension
if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
return qfalse;
}
abits = stage->stateBits;
bbits = unfoggedStages[stagenum + 1].stateBits;
// make sure waveforms have identical parameters
if ( ( unfoggedStages[0].rgbGen != unfoggedStages[1].rgbGen ) ||
( unfoggedStages[0].alphaGen != unfoggedStages[1].alphaGen ) ) {
return qfalse;
}
// make sure that both unfoggedStages have identical state other than blend modes
if ((abits & ~(GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE)) !=
(bbits & ~(GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE))) {
continue;
}
// an add collapse can only have identity colors
if ( collapse[i].multitextureEnv == GL_ADD && unfoggedStages[0].rgbGen != CGEN_IDENTITY ) {
return qfalse;
}
abits &= (GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS);
bbits &= (GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS);
if ( unfoggedStages[0].rgbGen == CGEN_WAVEFORM )
{
if ( memcmp( &unfoggedStages[0].rgbWave,
&unfoggedStages[1].rgbWave,
sizeof( unfoggedStages[0].rgbWave ) ) )
// search for a valid multitexture blend function
for (iUseCollapse = 0; collapse[iUseCollapse].blendA != -1; iUseCollapse++) {
if (abits == collapse[iUseCollapse].blendA
&& bbits == collapse[iUseCollapse].blendB) {
break;
}
}
// nothing found
if (collapse[iUseCollapse].blendA == -1) {
continue;
}
// GL_ADD is a separate extension
if (collapse[iUseCollapse].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable) {
continue;
}
// make sure waveforms have identical parameters
if ((stage->rgbGen != unfoggedStages[stagenum + 1].rgbGen) ||
(stage->alphaGen != unfoggedStages[stagenum + 1].alphaGen)) {
continue;
}
// an add collapse can only have identity colors
if (collapse[iUseCollapse].multitextureEnv == GL_ADD && stage->rgbGen != CGEN_IDENTITY) {
continue;
}
if (stage->rgbGen == CGEN_WAVEFORM)
{
return qfalse;
if (memcmp(&stage->rgbWave,
&unfoggedStages[stagenum + 1].rgbWave,
sizeof(stage->rgbWave)))
{
continue;
}
}
}
if ( unfoggedStages[0].alphaGen == CGEN_WAVEFORM )
{
if ( memcmp( &unfoggedStages[0].alphaWave,
&unfoggedStages[1].alphaWave,
sizeof( unfoggedStages[0].alphaWave ) ) )
if (stage->alphaGen == CGEN_WAVEFORM)
{
return qfalse;
if (memcmp(&stage->alphaWave,
&unfoggedStages[stagenum + 1].alphaWave,
sizeof(stage->alphaWave)))
{
continue;
}
}
// make sure that lightmaps are in bundle 1 for 3dfx
if (stage->bundle[0].isLightmap)
{
tmpBundle = stage->bundle[0];
stage->bundle[0] = unfoggedStages[stagenum + 1].bundle[0];
stage->bundle[1] = tmpBundle;
}
else
{
stage->bundle[1] = unfoggedStages[stagenum + 1].bundle[0];
}
// set the new blend state bits
stage->multitextureEnv = collapse[iUseCollapse].multitextureEnv;
stage->stateBits &= ~(GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS);
stage->stateBits |= collapse[iUseCollapse].multitextureBlend;
//
// move down subsequent shaders
//
if (stagenum + 2 < MAX_SHADER_STAGES) {
memmove(&unfoggedStages[stagenum + 1], &unfoggedStages[stagenum + 2], sizeof(unfoggedStages[0]) * (MAX_SHADER_STAGES - 2 - stagenum));
}
Com_Memset(&unfoggedStages[MAX_SHADER_STAGES - 1], 0, sizeof(unfoggedStages[0]));
(*stagecounter)--;
}
// make sure that lightmaps are in bundle 1 for 3dfx
if ( unfoggedStages[0].bundle[0].isLightmap )
{
tmpBundle = unfoggedStages[0].bundle[0];
unfoggedStages[0].bundle[0] = unfoggedStages[1].bundle[0];
unfoggedStages[0].bundle[1] = tmpBundle;
}
else
{
unfoggedStages[0].bundle[1] = unfoggedStages[1].bundle[0];
}
// set the new blend state bits
shader.multitextureEnv = collapse[i].multitextureEnv;
unfoggedStages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
unfoggedStages[0].stateBits |= collapse[i].multitextureBlend;
//
// move down subsequent shaders
//
memmove( &unfoggedStages[1], &unfoggedStages[2], sizeof( unfoggedStages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
Com_Memset( &unfoggedStages[MAX_SHADER_STAGES-1], 0, sizeof( unfoggedStages[0] ) );
return qtrue;
}
/*
@@ -2291,12 +2342,6 @@ static shader_t *GeneratePermanentShader( void ) {
newShader->next = currentShader->shader;
currentShader->shader = newShader;
if ( shader.sort <= SS_OPAQUE ) {
newShader->fogPass = FP_EQUAL;
} else if ( shader.contentFlags & CONTENTS_FOG ) {
newShader->fogPass = FP_LE;
}
tr.shaders[ tr.numShaders ] = newShader;
newShader->index = tr.numShaders;
@@ -2314,8 +2359,10 @@ static shader_t *GeneratePermanentShader( void ) {
for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
size = newShader->unfoggedStages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
newShader->unfoggedStages[i]->bundle[b].texMods = ri.Hunk_Alloc( size );
Com_Memcpy( newShader->unfoggedStages[i]->bundle[b].texMods, unfoggedStages[i].bundle[b].texMods, size );
if (size) {
newShader->unfoggedStages[i]->bundle[b].texMods = ri.Hunk_Alloc(size);
Com_Memcpy(newShader->unfoggedStages[i]->bundle[b].texMods, unfoggedStages[i].bundle[b].texMods, size);
}
}
}
@@ -2425,8 +2472,9 @@ from the current global working shader
*/
static shader_t *FinishShader( void ) {
int stage;
qboolean hasLightmapStage;
qboolean vertexLightmap;
int i;
int bundle;
qboolean hasLightmapStage;
if (!currentShader) {
currentShader = FindShaderText(shader.name);
@@ -2440,11 +2488,13 @@ static shader_t *FinishShader( void ) {
}
hasLightmapStage = qfalse;
vertexLightmap = qfalse;
//
// set sky stuff appropriate
//
if ( shader.isPortalSky ) {
shader.sort = SS_PORTALSKY;
}
if ( shader.isSky ) {
shader.sort = SS_ENVIRONMENT;
}
@@ -2456,13 +2506,15 @@ static shader_t *FinishShader( void ) {
shader.sort = SS_DECAL;
}
shader.needsLGrid = qfalse;
shader.needsLSpherical = qfalse;
//
// set appropriate stage information
//
for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
shaderStage_t *pStage = &unfoggedStages[stage];
// check for a missing texture
stage = 0;
for (shaderStage_t* pStage = &unfoggedStages[0]; pStage->active; pStage++, stage++) {
// check for a missing texture
if ( !pStage->bundle[0].image[0] ) {
ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
pStage->active = qfalse;
@@ -2478,25 +2530,28 @@ static shader_t *FinishShader( void ) {
//
// default texture coordinate generation
//
if ( pStage->bundle[0].isLightmap ) {
if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
for (bundle = 2; bundle > 0; bundle--) {
if (pStage->bundle[bundle - 1].isLightmap) {
if (pStage->bundle[bundle - 1].tcGen == TCGEN_BAD) {
pStage->bundle[bundle - 1].tcGen = TCGEN_LIGHTMAP;
}
hasLightmapStage = qtrue;
}
hasLightmapStage = qtrue;
} else {
if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
pStage->bundle[0].tcGen = TCGEN_TEXTURE;
else {
if (pStage->bundle[bundle - 1].tcGen == TCGEN_BAD) {
pStage->bundle[bundle - 1].tcGen = TCGEN_TEXTURE;
}
}
}
// not a true lightmap but we want to leave existing
// behaviour in place and not print out a warning
//if (pStage->rgbGen == CGEN_VERTEX) {
// vertexLightmap = qtrue;
//}
if (pStage->multitextureEnv && pStage->bundle[0].isLightmap) {
//
// exchange bundle
//
textureBundle_t tmpBundle = pStage->bundle[0];
pStage->bundle[0] = pStage->bundle[1];
pStage->bundle[1] = tmpBundle;
}
//
// determine sort order and fog color adjustment
@@ -2527,23 +2582,70 @@ static shader_t *FinishShader( void ) {
//
// if we are in r_vertexLight mode, never use a lightmap texture
//
if ( stage > 1 && r_vertexLight->integer ) {
VertexLightingCollapse();
stage = 1;
hasLightmapStage = qfalse;
if (stage > 1)
{
if (r_vertexLight->integer) {
VertexLightingCollapse();
stage = 1;
hasLightmapStage = qfalse;
}
//
// look for multitexture potential
//
if (qglActiveTextureARB) {
CollapseMultitexture(&stage);
};
}
//
// look for multitexture potential
//
if (stage > 1 && qglActiveTextureARB) {
CollapseMultitexture();
};
for (i = 0; i < stage; i++) {
int blendSrcBits, blendDstBits;
// FIXME: fog shader
shaderStage_t* pStage = &unfoggedStages[i];
if (pStage->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS))
{
blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
if (blendSrcBits == GLS_SRCBLEND_ONE && blendDstBits == GLS_DSTBLEND_ONE
|| blendSrcBits == GLS_SRCBLEND_ZERO && blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR
|| blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && blendDstBits == GLS_DSTBLEND_ONE
|| blendSrcBits == GLS_SRCBLEND_DST_COLOR && blendDstBits == GLS_DSTBLEND_ONE
|| blendSrcBits == GLS_SRCBLEND_ONE_MINUS_DST_COLOR && blendDstBits == GLS_DSTBLEND_ONE)
{
pStage->stateBits |= GLS_FOG_ENABLED | GLS_FOG_BLACK;
}
else if (blendSrcBits == GLS_SRCBLEND_DST_COLOR && blendDstBits == GLS_DSTBLEND_ZERO
|| blendSrcBits == GLS_SRCBLEND_ZERO && blendDstBits == GLS_DSTBLEND_SRC_COLOR)
{
pStage->stateBits |= GLS_FOG_ENABLED | GLS_FOG_WHITE;
}
else if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA
|| blendSrcBits == GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA && blendDstBits == GLS_DSTBLEND_SRC_ALPHA
|| blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && blendDstBits == GLS_DSTBLEND_ONE)
{
pStage->stateBits |= GLS_FOG_ENABLED;
}
else {
ri.Printf(PRINT_WARNING, "Shader '%s' stage# %i is unfoggable\n", shader.name, i + 1);
}
if (shader.sort == SS_BAD)
{
if (pStage->stateBits & GLS_DEPTHMASK_TRUE) {
shader.sort = SS_SEE_THROUGH;
}
else {
shader.sort = SS_BLEND0;
}
}
}
else {
pStage->stateBits |= GLS_FOG_ENABLED;
}
}
// fogonly shaders don't have any normal passes
if (stage == 0) {
if (shader.sort == SS_BAD) {
shader.sort = SS_OPAQUE;
}
@@ -2558,9 +2660,11 @@ static shader_t *FinishShader( void ) {
shader.numUnfoggedPasses = 0;
for (stage = 0; stage < MAX_SHADER_STAGES; stage++) {
shaderStage_t* pStage = &unfoggedStages[stage];
if (pStage->active) {
shader.numUnfoggedPasses++;
if (!pStage->active) {
break;
}
shader.numUnfoggedPasses++;
}
// determine which stage iterator function is appropriate
@@ -2874,6 +2978,8 @@ void R_ShaderList_f (void) {
count = 0;
for ( i = 0 ; i < tr.numShaders ; i++ ) {
int stage;
if ( ri.Cmd_Argc() > 1 ) {
shader = tr.sortedShaders[i];
} else {
@@ -2887,15 +2993,19 @@ void R_ShaderList_f (void) {
} else {
ri.Printf (PRINT_ALL, " ");
}
if ( shader->multitextureEnv == GL_ADD ) {
ri.Printf( PRINT_ALL, "MT(a) " );
} else if ( shader->multitextureEnv == GL_MODULATE ) {
ri.Printf( PRINT_ALL, "MT(m) " );
} else if ( shader->multitextureEnv == GL_DECAL ) {
ri.Printf( PRINT_ALL, "MT(d) " );
} else {
ri.Printf( PRINT_ALL, " " );
for (stage = 0; shader->unfoggedStages[stage] && shader->unfoggedStages[stage]->active; stage++) {
if (shader->unfoggedStages[stage]->multitextureEnv == GL_ADD ) {
ri.Printf( PRINT_ALL, "MT(a) " );
} else if (shader->unfoggedStages[stage]->multitextureEnv == GL_MODULATE ) {
ri.Printf( PRINT_ALL, "MT(m) " );
} else if (shader->unfoggedStages[stage]->multitextureEnv == GL_DECAL ) {
ri.Printf( PRINT_ALL, "MT(d) " );
} else {
ri.Printf( PRINT_ALL, " " );
}
}
if ( shader->explicitlyDefined ) {
ri.Printf( PRINT_ALL, "E " );
} else {
+16 -13
View File
@@ -45,19 +45,6 @@ static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
static int numEdgeDefs[SHADER_MAX_VERTEXES];
static int facing[SHADER_MAX_INDEXES/3];
void R_AddEdgeDef( int i1, int i2, int facing ) {
int c;
c = numEdgeDefs[ i1 ];
if ( c == MAX_EDGE_DEFS ) {
return; // overflow
}
edgeDefs[ i1 ][ c ].i2 = i2;
edgeDefs[ i1 ][ c ].facing = facing;
numEdgeDefs[ i1 ]++;
}
void R_RenderShadowEdges( void ) {
int i;
@@ -139,6 +126,19 @@ void R_RenderShadowEdges( void ) {
#endif
}
void R_AddEdgeDef(int i1, int i2, int facing) {
int c;
c = numEdgeDefs[i1];
if (c == MAX_EDGE_DEFS) {
return; // overflow
}
edgeDefs[i1][c].i2 = i2;
edgeDefs[i1][c].facing = facing;
numEdgeDefs[i1]++;
}
/*
=================
RB_ShadowTessEnd
@@ -248,6 +248,9 @@ void RB_ShadowTessEnd( void ) {
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
}
void RB_ComputeShadowVolume() {
// FIXME: unimplemented
}
/*
=================
+117 -3
View File
@@ -26,15 +26,129 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void R_Sky_Init()
{
// FIXME: unimplemented
tr.portalsky.inUse = qfalse;
tr.portalsky.numSurfs = 0;
}
void R_Sky_Reset()
{
// FIXME: unimplemented
if (tr.portalsky.inUse) {
return;
}
tr.portalsky.mins[0] = 8192.0;
tr.portalsky.mins[1] = 8192.0;
tr.portalsky.mins[2] = 8192.0;
tr.portalsky.maxs[0] = -8192.0;
tr.portalsky.maxs[1] = -8192.0;
tr.portalsky.maxs[2] = -8192.0;
tr.portalsky.cntNode = 0;
tr.portalsky.numSurfs = 0;
}
void R_Sky_AddSurf(msurface_t* surf)
{
// FIXME: unimplemented
if (tr.portalsky.inUse)
{
static int last_sky_warning = 0;
if (tr.refdef.time - 1000 > last_sky_warning)
{
ri.Printf(3, "WARNING: sky being drawn in a sky portal! Bad! Bad!\n");
last_sky_warning = tr.refdef.time;
}
return;
}
if (tr.portalsky.numSurfs < 32) {
tr.portalsky.skySurfs[tr.portalsky.numSurfs++] = surf;
}
if (tr.portalsky.cntNode)
{
int i;
for (i = 0; i < 3; i++) {
if (tr.portalsky.mins[i] >= tr.portalsky.cntNode->mins[i]) {
tr.portalsky.mins[i] = tr.portalsky.cntNode->mins[i];
}
if (tr.portalsky.maxs[i] >= tr.portalsky.cntNode->maxs[i]) {
tr.portalsky.maxs[i] = tr.portalsky.cntNode->maxs[i];
}
}
}
}
void R_Sky_Render() {
int i;
viewParms_t newParms, oldParms;
mnode_t* leaf;
if (!tr.portalsky.numSurfs) {
return;
}
if (!tr.refdef.sky_portal) {
return;
}
if (tr.skyRendered) {
// already rendered
return;
}
if (tr.portalsky.inUse)
{
ri.Printf(PRINT_WARNING, "WARNING: Recursive skies found! Make that not happen!\n");
return;
}
for (i = 0; i < tr.portalsky.numSurfs; i++) {
if (!SurfIsOffscreen((const srfSurfaceFace_t*)tr.portalsky.skySurfs[i]->data, tr.portalsky.skySurfs[i]->shader, ENTITYNUM_WORLD)) {
break;
}
}
if (i == tr.portalsky.numSurfs) {
return;
}
tr.skyRendered = qtrue;
oldParms = tr.viewParms;
newParms = tr.viewParms;
if (r_skyportal->integer)
{
if (sscanf(r_skyportal_origin->string, "%f %f %f", &newParms.ori.origin[0], &newParms.ori.origin[1], &newParms.ori.origin[2]) != 3)
{
ri.Printf(PRINT_WARNING, "WARNING: Invalid sky portal origin: %s\n", r_skyportal_origin->string);
return;
}
}
else
{
VectorCopy(tr.refdef.sky_origin, newParms.ori.origin);
MatrixMultiply(newParms.ori.axis, tr.refdef.sky_axis, newParms.ori.axis);
}
tr.portalsky.inUse = qtrue;
VectorCopy(newParms.ori.origin, newParms.pvsOrigin);
leaf = R_PointInLeaf(newParms.pvsOrigin);
if (leaf) {
R_RenderView(&newParms);
}
tr.viewParms = oldParms;
tr.portalsky.inUse = qfalse;
tr.portalsky.numSurfs = 0;
R_RotateForViewer();
R_SetupFrustum();
}
void R_Sky_ChangeFrustum() {
// FIXME: unimplemented
}
+48 -21
View File
@@ -56,14 +56,11 @@ void R_InitStaticModels(void) {
g = (int)((float)tr.world->staticModelData[i * 4 + 1] * tr.overbrightMult);
b = (int)((float)tr.world->staticModelData[i * 4 + 2] * tr.overbrightMult);
if ((r | g | b) & 0xFFFFFF00)
if (r > 0xFF || g > 0xFF || b > 0xFF)
{
float t;
unsigned long long rgb;
rgb = (g + (~((unsigned long long)(r - g) >> 32) & (r - g)) - b);
t = 255.0 / (float)(b + (~(rgb & 0x00000000FFFFFFFF) & rgb));
t = 255.0 / (float)max(r, max(g, b));
r = (int)((float)r * t);
g = (int)((float)g * t);
@@ -326,6 +323,7 @@ void R_AddStaticModelSurfaces(void) {
{
skelHeaderGame_t* skelmodel = TIKI_GetSkel(tiki->mesh[mesh]);
skelSurfaceGame_t* surface;
staticSurface_t* s_surface;
shader_t* shader;
if (!skelmodel) {
@@ -336,7 +334,7 @@ void R_AddStaticModelSurfaces(void) {
// draw all surfaces
//
surface = skelmodel->pSurfaces;
for (j = 0; j < skelmodel->numSurfaces; j++, surface = surface->pNext, dsurf++)
for (j = 0; j < skelmodel->numSurfaces; j++, ofsStaticData += surface->numVerts, surface = surface->pNext, dsurf++)
{
if (g_nStaticSurfaces >= MAX_STATIC_MODELS_SURFS)
{
@@ -344,18 +342,44 @@ void R_AddStaticModelSurfaces(void) {
continue;
}
g_staticSurfaces[g_nStaticSurfaces].ident = SF_TIKI_STATIC;
g_staticSurfaces[g_nStaticSurfaces].ofsStaticData = ofsStaticData;
g_staticSurfaces[g_nStaticSurfaces].surface = surface;
g_staticSurfaces[g_nStaticSurfaces].meshNum = mesh;
s_surface = &g_staticSurfaces[g_nStaticSurfaces++];
s_surface->ident = SF_TIKI_STATIC;
s_surface->ofsStaticData = ofsStaticData;
s_surface->surface = surface;
s_surface->meshNum = mesh;
shader = tr.shaders[dsurf->hShader[0]];
SM->bRendered = qtrue;
R_AddDrawSurf((surfaceType_t*)&g_staticSurfaces[g_nStaticSurfaces], shader, 0);
if (shader->numUnfoggedPasses == 1)
{
if (shader->unfoggedStages[0]->alphaGen == AGEN_DIST_FADE)
{
if (R_DistanceCullPointAndRadius(shader->fDistNear + shader->fDistRange, tiki_worldorigin, SM->cull_radius) == CULL_OUT) {
continue;
}
}
else if (shader->unfoggedStages[0]->alphaGen == AGEN_ONE_MINUS_DIST_FADE)
{
if (R_DistanceCullPointAndRadius(shader->fDistNear, tiki_worldorigin, SM->cull_radius) == CULL_IN) {
continue;
}
}
}
g_nStaticSurfaces++;
ofsStaticData += surface->numVerts;
SM->bRendered = qtrue;
R_AddDrawSurf((surfaceType_t*)s_surface, shader, 0);
if (r_showstaticlod->integer) {
//
// FIXME: draw debug lods
//
}
if (r_showstaticbboxes->integer) {
//
// FIXME: draw debug bbox
//
}
}
}
}
@@ -456,15 +480,18 @@ void RB_StaticMesh(staticSurface_t* staticSurf) {
}
if (backEndData[backEnd.smpFrame]->staticModelData) {
color4ub_t* in = (color4ub_t*)&backEndData[backEnd.smpFrame]->staticModelData[backEnd.currentStaticModel->firstVertexData + staticSurf->ofsStaticData];
color4ub_t* out = &tess.vertexColors[baseVertex];
const size_t offset = backEnd.currentStaticModel->firstVertexData + staticSurf->ofsStaticData * sizeof(color4ub_t);
assert(offset < tr.world->numStaticModelData * sizeof(color4ub_t));
assert(offset + render_count * sizeof(color4ub_t) <= tr.world->numStaticModelData * sizeof(color4ub_t));
for (i = 0; i < render_count; i++, in++, out++)
const color4ub_t* in = (const color4ub_t*)&backEndData[backEnd.smpFrame]->staticModelData[offset];
for (i = 0; i < render_count; i++)
{
(*out)[0] = (*in)[0];
(*out)[1] = (*in)[1];
(*out)[2] = (*in)[2];
(*out)[3] = (*in)[3];
tess.vertexColors[baseVertex + i][0] = in[i][0];
tess.vertexColors[baseVertex + i][1] = in[i][1];
tess.vertexColors[baseVertex + i][2] = in[i][2];
tess.vertexColors[baseVertex + i][3] = in[i][3];
}
}
else {
+73 -1
View File
@@ -718,7 +718,79 @@ void RB_SurfaceSkip( void *surf ) {
}
void RB_DrawTerrainTris(srfTerrain_t* p) {
// FIXME: unimplemented
int i;
terraInt numv;
int dlightBits;
if (tess.numVertexes + p->nVerts >= SHADER_MAX_VERTEXES || tess.numIndexes + p->nTris * 3 >= SHADER_MAX_INDEXES) {
RB_CheckOverflow(p->nVerts, 3 * p->nTris);
}
dlightBits = p->dlightBits[backEnd.smpFrame];
tess.dlightBits |= dlightBits;
if (p->dlightMap[backEnd.smpFrame])
{
float lmScale = (1 / 128.0) / p->lmapStep;
for (i = p->iVertHead; i; i = g_pVert[i].iNext) {
assert(tess.numVertexes < SHADER_MAX_VERTEXES);
VectorCopy(g_pVert[i].xyz, tess.xyz[tess.numVertexes]);
tess.texCoords[tess.numVertexes][0][0] = g_pVert[i].texCoords[0][0];
tess.texCoords[tess.numVertexes][0][1] = g_pVert[i].texCoords[0][1];
tess.texCoords[tess.numVertexes][1][0] = g_pVert[i].texCoords[1][0] * lmScale + p->lmapX;
tess.texCoords[tess.numVertexes][1][1] = g_pVert[i].texCoords[1][1] * lmScale + p->lmapY;
tess.normal[tess.numVertexes][0] = 0;
tess.normal[tess.numVertexes][1] = 0;
tess.normal[tess.numVertexes][2] = 1.0;
tess.vertexColors[tess.numVertexes][0] = -1;
tess.vertexColors[tess.numVertexes][1] = -1;
tess.vertexColors[tess.numVertexes][2] = -1;
tess.vertexColors[tess.numVertexes][3] = -1;
g_pVert[i].iVertArray = tess.numVertexes;
tess.numVertexes++;
}
}
else
{
for (i = p->iVertHead; i; i = g_pVert[i].iNext) {
assert(tess.numVertexes < SHADER_MAX_VERTEXES);
VectorCopy(g_pVert[i].xyz, tess.xyz[tess.numVertexes]);
tess.texCoords[tess.numVertexes][0][0] = g_pVert[i].texCoords[0][0];
tess.texCoords[tess.numVertexes][0][1] = g_pVert[i].texCoords[0][1];
tess.texCoords[tess.numVertexes][1][0] = g_pVert[i].texCoords[1][0];
tess.texCoords[tess.numVertexes][1][1] = g_pVert[i].texCoords[1][1];
tess.vertexDlightBits[tess.numVertexes] = dlightBits;
tess.normal[tess.numVertexes][0] = 0;
tess.normal[tess.numVertexes][1] = 0;
tess.normal[tess.numVertexes][2] = 1.0;
tess.vertexColors[tess.numVertexes][0] = -1;
tess.vertexColors[tess.numVertexes][1] = -1;
tess.vertexColors[tess.numVertexes][2] = -1;
tess.vertexColors[tess.numVertexes][3] = -1;
g_pVert[i].iVertArray = tess.numVertexes;
tess.numVertexes++;
}
}
for (i = p->iTriHead; i; i = g_pTris[i].iNext)
{
assert(tess.numVertexes < SHADER_MAX_INDEXES);
//
// Make sure these can be drawn
//
if (g_pTris[i].byConstChecks & 4)
{
tess.indexes[tess.numIndexes] = g_pVert[g_pTris[i].iPt[0]].iVertArray;
tess.indexes[tess.numIndexes + 1] = g_pVert[g_pTris[i].iPt[1]].iVertArray;
tess.indexes[tess.numIndexes + 2] = g_pVert[g_pTris[i].iPt[2]].iVertArray;
tess.numIndexes += 3;
}
}
}
void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
+1366 -21
View File
File diff suppressed because it is too large. Load diff
+44 -13
View File
@@ -407,46 +407,56 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits )
if ( !r_nocull->integer ) {
int r;
if ( planeBits & 1 ) {
if (planeBits & 1) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
if (r == 1) {
planeBits &= ~1; // all descendants will also be in front
}
}
if ( planeBits & 2 ) {
if (planeBits & 2) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
if (r == 1) {
planeBits &= ~2; // all descendants will also be in front
}
}
if ( planeBits & 4 ) {
if (planeBits & 4) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
if (r == 1) {
planeBits &= ~4; // all descendants will also be in front
}
}
if ( planeBits & 8 ) {
if (planeBits & 8) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
if (r == 1) {
planeBits &= ~8; // all descendants will also be in front
}
}
if (planeBits & 16) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
if (r == 2) {
return; // culled
}
if (r == 1) {
planeBits &= ~16; // all descendants will also be in front
}
}
}
if ( node->contents != -1 ) {
@@ -488,6 +498,8 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits )
tr.viewParms.visBounds[1][2] = node->maxs[2];
}
tr.portalsky.cntNode = node;
if (r_drawbrushes->integer) {
// add the individual surfaces
mark = node->firstmarksurface;
@@ -501,9 +513,28 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits )
}
}
// FIXME: terrain
// FIXME: static decals
// FIXME: static models
if (r_drawterrain->integer)
{
int i;
for (i = 0; i < node->numTerraPatches; i++) {
R_MarkTerrainPatch(tr.world->visTerraPatches[node->firstTerraPatch + i]);
}
}
if (r_drawstaticdecals->integer) {
if (node->pFirstMarkFragment) {
R_AddPermanentMarkFragmentSurfaces(node->pFirstMarkFragment, node->iNumMarkFragment);
}
}
if (r_drawstaticmodels->integer) {
int i;
for (i = 0; i < node->numStaticModels; i++) {
tr.world->visStaticModels[node->firstStaticModel + i]->visCount = tr.visCount;
}
}
}
}
@@ -514,7 +545,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits )
R_PointInLeaf
===============
*/
static mnode_t *R_PointInLeaf( const vec3_t p ) {
mnode_t *R_PointInLeaf( const vec3_t p ) {
mnode_t *node;
float d;
cplane_t *plane;
@@ -685,7 +716,7 @@ void R_AddWorldSurfaces (void) {
tr.refdef.num_dlights = 32;
}
R_TransformDlights(tr.refdef.num_dlights, tr.refdef.dlights, &tr.viewParms.world);
R_RecursiveWorldNode(tr.world->nodes, 15, (1 << tr.refdef.num_dlights) - 1);
R_RecursiveWorldNode(tr.world->nodes, tr.viewParms.fog.extrafrustums ? 31 : 15, (1 << tr.refdef.num_dlights) - 1);
if (r_drawterrain->integer) {
R_AddTerrainSurfaces();
+3 -3
View File
@@ -237,16 +237,16 @@ static char *XLateKey(XKeyEvent *ev, int *key)
case XK_Pause: *key = K_PAUSE; break;
case XK_Shift_L:
case XK_Shift_R: *key = K_SHIFT; break;
case XK_Shift_R: *key = K_LSHIFT; break;
case XK_Execute:
case XK_Control_L:
case XK_Control_R: *key = K_CTRL; break;
case XK_Control_R: *key = K_LCTRL; break;
case XK_Alt_L:
case XK_Meta_L:
case XK_Alt_R:
case XK_Meta_R: *key = K_ALT; break;
case XK_Meta_R: *key = K_LALT; break;
case XK_KP_Begin: *key = K_KP_5; break;