You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1984 lines
72 KiB
1984 lines
72 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
|
|
//#define DYNAHEADER_CREATE_STORAGE |
|
|
|
#include "hsTypes.h" |
|
|
|
#include <time.h> |
|
|
|
#include "hsWindows.h" |
|
|
|
#include "hsG3DDeviceSelector.h" |
|
#include "hsStream.h" |
|
#include "hsUtils.h" |
|
#include "plPipeline.h" |
|
|
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
#include <gls.h> |
|
#include <glswgl.h> |
|
#include <glext.h> |
|
#endif |
|
#endif |
|
|
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
hsG3DDeviceMode::hsG3DDeviceMode() |
|
: fWidth(0), fHeight(0), |
|
fDepth(0), |
|
fFlags(kNone) |
|
{ |
|
} |
|
|
|
hsG3DDeviceMode::~hsG3DDeviceMode() |
|
{ |
|
Clear(); |
|
} |
|
|
|
hsBool hsG3DDeviceMode::operator< (const hsG3DDeviceMode &mode) const |
|
{ |
|
// Color depth overrides everything else |
|
if (fDepth < mode.GetColorDepth()) |
|
return true; |
|
// Only compare width and height if the color depth is the same |
|
else if (fDepth == mode.GetColorDepth() ) |
|
{ |
|
if( fWidth < mode.GetWidth() ) |
|
return true; |
|
else if( fWidth == mode.GetWidth() && fHeight < mode.GetHeight() ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void hsG3DDeviceMode::Clear() |
|
{ |
|
fFlags = kNone; |
|
fWidth = 0; |
|
fHeight = 0; |
|
fDepth = 0; |
|
fZStencilDepths.Reset(); |
|
fFSAATypes.Reset(); |
|
} |
|
|
|
void hsG3DDeviceMode::Read( hsStream* s ) |
|
{ |
|
Clear(); |
|
|
|
fFlags = s->ReadSwap32(); |
|
fWidth = s->ReadSwap32(); |
|
fHeight = s->ReadSwap32(); |
|
fDepth = s->ReadSwap32(); |
|
|
|
fZStencilDepths.Reset(); |
|
UInt8 count= s->ReadByte(); |
|
while( count-- ) |
|
fZStencilDepths.Append( s->ReadSwap16() ); |
|
|
|
/// Version 9 |
|
fFSAATypes.Reset(); |
|
count = s->ReadByte(); |
|
while( count-- ) |
|
fFSAATypes.Append( s->ReadByte() ); |
|
|
|
fCanRenderToCubics = s->ReadBool(); |
|
} |
|
|
|
void hsG3DDeviceMode::Write( hsStream* s ) const |
|
{ |
|
s->WriteSwap32(fFlags); |
|
s->WriteSwap32(fWidth); |
|
s->WriteSwap32(fHeight); |
|
s->WriteSwap32(fDepth); |
|
|
|
UInt8 i, count = (UInt8)fZStencilDepths.GetCount(); |
|
s->WriteByte( count ); |
|
for( i = 0; i < count; i++ ) |
|
s->WriteSwap16( fZStencilDepths[ i ] ); |
|
|
|
/// Version 9 |
|
count = (UInt8)fFSAATypes.GetCount(); |
|
s->WriteByte( count ); |
|
for( i = 0; i < count; i++ ) |
|
s->WriteByte( fFSAATypes[ i ] ); |
|
|
|
s->WriteBool( fCanRenderToCubics ); |
|
} |
|
|
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
|
|
hsG3DDeviceRecord::hsG3DDeviceRecord() |
|
: fFlags(kNone), |
|
fG3DDeviceType(hsG3DDeviceSelector::kDevTypeUnknown), |
|
fG3DDriverDesc(nil), fG3DDriverName(nil), fG3DDriverVersion(nil), fG3DDeviceDesc(nil), |
|
fLayersAtOnce(0), fMemoryBytes(0), |
|
fG3DHALorHEL(hsG3DDeviceSelector::kHHTypeUnknown), |
|
fZBiasRating( 0 ), fRecordVersion( kCurrRecordVersion ), fLODBiasRating( 0 ), |
|
fFogExpApproxStart( 0.0 ), fFogExp2ApproxStart( 0.0 ), fFogEndBias( 0.0 ), fMaxAnisotropicSamples( 1 ) |
|
{ |
|
SetFogKneeParams( kFogExp, 0, 0 ); |
|
SetFogKneeParams( kFogExp2, 0, 0 ); |
|
} |
|
|
|
hsG3DDeviceRecord::~hsG3DDeviceRecord() |
|
{ |
|
Clear(); |
|
} |
|
|
|
hsG3DDeviceRecord::hsG3DDeviceRecord(const hsG3DDeviceRecord& src) |
|
: fFlags(kNone), |
|
fG3DDeviceType(hsG3DDeviceSelector::kDevTypeUnknown), |
|
fG3DDriverDesc(nil), fG3DDriverName(nil), fG3DDriverVersion(nil), fG3DDeviceDesc(nil), |
|
fG3DHALorHEL(hsG3DDeviceSelector::kHHTypeUnknown), |
|
fZBiasRating( src.fZBiasRating ), fRecordVersion( kCurrRecordVersion ), fLODBiasRating( 0 ), |
|
fFogExpApproxStart( src.fFogExpApproxStart ), fFogExp2ApproxStart( src.fFogExp2ApproxStart ), |
|
fFogEndBias( src.fFogEndBias ), fMaxAnisotropicSamples( src.fMaxAnisotropicSamples ) |
|
{ |
|
*this = src; |
|
} |
|
|
|
hsG3DDeviceRecord& hsG3DDeviceRecord::operator=(const hsG3DDeviceRecord& src) |
|
{ |
|
fFlags = src.fFlags; |
|
|
|
SetG3DDeviceType(src.GetG3DDeviceType()); |
|
SetG3DHALorHEL(src.GetG3DHALorHEL()); |
|
|
|
SetDriverDesc(src.GetDriverDesc()); |
|
SetDriverName(src.GetDriverName()); |
|
SetDriverVersion(src.GetDriverVersion()); |
|
SetDeviceDesc(src.GetDeviceDesc()); |
|
|
|
fCaps = src.fCaps; |
|
fLayersAtOnce = src.fLayersAtOnce; |
|
fMemoryBytes = src.fMemoryBytes; |
|
fZBiasRating = src.fZBiasRating; |
|
fLODBiasRating = src.fLODBiasRating; |
|
fFogExpApproxStart = src.fFogExpApproxStart; |
|
fFogExp2ApproxStart = src.fFogExp2ApproxStart; |
|
fFogEndBias = src.fFogEndBias; |
|
|
|
fModes.SetCount(src.fModes.GetCount()); |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i] = src.fModes[i]; |
|
|
|
fFogKnees[ 0 ] = src.fFogKnees[ 0 ]; |
|
fFogKnees[ 1 ] = src.fFogKnees[ 1 ]; |
|
fFogKneeVals[ 0 ] = src.fFogKneeVals[ 0 ]; |
|
fFogKneeVals[ 1 ] = src.fFogKneeVals[ 1 ]; |
|
|
|
fAASetting = src.fAASetting; |
|
|
|
fMaxAnisotropicSamples = src.fMaxAnisotropicSamples; |
|
|
|
return *this; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverDesc( const char *s ) |
|
{ |
|
delete [] fG3DDriverDesc; |
|
fG3DDriverDesc = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverName( const char *s ) |
|
{ |
|
delete [] fG3DDriverName; |
|
fG3DDriverName = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDriverVersion( const char *s ) |
|
{ |
|
delete [] fG3DDriverVersion; |
|
fG3DDriverVersion = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
void hsG3DDeviceRecord::SetDeviceDesc( const char *s ) |
|
{ |
|
delete [] fG3DDeviceDesc; |
|
fG3DDeviceDesc = s ? hsStrcpy(s) : nil; |
|
} |
|
|
|
const char* hsG3DDeviceRecord::GetG3DDeviceTypeName() const |
|
{ |
|
static const char* deviceNames[hsG3DDeviceSelector::kNumDevTypes] = { |
|
"Unknown", |
|
"Glide", |
|
"Direct3D", |
|
"OpenGL" |
|
}; |
|
|
|
UInt32 devType = GetG3DDeviceType(); |
|
if( devType > hsG3DDeviceSelector::kNumDevTypes ) |
|
devType = hsG3DDeviceSelector::kDevTypeUnknown; |
|
|
|
return deviceNames[devType]; |
|
} |
|
|
|
void hsG3DDeviceRecord::RemoveDiscarded() |
|
{ |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); ) |
|
{ |
|
if( fModes[i].GetDiscarded() ) |
|
{ |
|
fModes[i].Clear(); |
|
fModes.Remove(i); |
|
} |
|
else |
|
i++; |
|
} |
|
if( !fModes.GetCount() ) |
|
SetDiscarded(true); |
|
} |
|
|
|
void hsG3DDeviceRecord::ClearModes() |
|
{ |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i].Clear(); |
|
fModes.Reset(); |
|
} |
|
|
|
void hsG3DDeviceRecord::Clear() |
|
{ |
|
fFlags = kNone; |
|
|
|
delete [] fG3DDriverDesc; |
|
fG3DDriverDesc = nil; |
|
|
|
delete [] fG3DDriverName; |
|
fG3DDriverName = nil; |
|
|
|
delete [] fG3DDriverVersion; |
|
fG3DDriverVersion = nil; |
|
|
|
delete [] fG3DDeviceDesc; |
|
fG3DDeviceDesc = nil; |
|
|
|
fCaps.Clear(); |
|
fLayersAtOnce = 0; |
|
|
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i].Clear(); |
|
fModes.Reset(); |
|
|
|
fZBiasRating = 0; |
|
fLODBiasRating = 0; |
|
fFogExpApproxStart = 0; |
|
fFogExp2ApproxStart = 0; |
|
fFogEndBias = 0; |
|
|
|
SetFogKneeParams( kFogExp, 0, 0 ); |
|
SetFogKneeParams( kFogExp2, 0, 0 ); |
|
|
|
fAASetting = 0; |
|
fMaxAnisotropicSamples = 1; |
|
} |
|
|
|
//// Read ///////////////////////////////////////////////////////////////////// |
|
// 9.6.2000 mcn - Updated to reflect version 2 format |
|
// 9.8.2000 mcn - (temporary?) set to invalid on old (<2) versions |
|
|
|
void hsG3DDeviceRecord::Read(hsStream* s) |
|
{ |
|
Clear(); |
|
|
|
/// Read version |
|
fRecordVersion = s->ReadSwap32(); |
|
hsAssert( fRecordVersion <= kCurrRecordVersion, "Invalid version number in hsG3DDeviceRecord::Read()" ); |
|
if( fRecordVersion == kCurrRecordVersion ) |
|
{ |
|
fFlags = s->ReadSwap32(); |
|
} |
|
else |
|
{ |
|
SetInvalid(); |
|
return; |
|
// fFlags = fRecordVersion; |
|
// fRecordVersion = 1; |
|
// hsStatusMessage( "WARNING: Old version of hsG3DDeviceRecord found. Attempting to read." ); |
|
} |
|
|
|
/// Now read everything else in as normal |
|
fG3DDeviceType = s->ReadSwap32(); |
|
|
|
int len; |
|
|
|
len = s->ReadSwap32(); |
|
fG3DDriverDesc = TRACKED_NEW char[len + 1]; |
|
s->Read(len, fG3DDriverDesc); |
|
fG3DDriverDesc[len] = 0; |
|
|
|
len = s->ReadSwap32(); |
|
fG3DDriverName = TRACKED_NEW char[len + 1]; |
|
s->Read(len, fG3DDriverName); |
|
fG3DDriverName[len] = 0; |
|
|
|
len = s->ReadSwap32(); |
|
fG3DDriverVersion = TRACKED_NEW char[len + 1]; |
|
s->Read(len, fG3DDriverVersion); |
|
fG3DDriverVersion[len] = 0; |
|
|
|
len = s->ReadSwap32(); |
|
fG3DDeviceDesc = TRACKED_NEW char[len + 1]; |
|
s->Read(len, fG3DDeviceDesc); |
|
fG3DDeviceDesc[len] = 0; |
|
|
|
|
|
fCaps.Read(s); |
|
fLayersAtOnce = s->ReadSwap32(); |
|
fMemoryBytes = s->ReadSwap32(); |
|
|
|
len = s->ReadSwap32(); |
|
fModes.SetCount(len); |
|
int i; |
|
for( i = 0; i < len; i++ ) |
|
fModes[i].Read( s ); |
|
|
|
/// Version 3 stuff |
|
fZBiasRating = s->ReadSwapFloat(); |
|
fLODBiasRating = s->ReadSwapFloat(); |
|
fFogExpApproxStart = s->ReadSwapFloat(); |
|
fFogExp2ApproxStart = s->ReadSwapFloat(); |
|
fFogEndBias = s->ReadSwapFloat(); |
|
|
|
/// Version 7 stuff |
|
float knee, kneeVal; |
|
knee = s->ReadSwapFloat(); kneeVal = s->ReadSwapFloat(); |
|
SetFogKneeParams( kFogExp, knee, kneeVal ); |
|
knee = s->ReadSwapFloat(); kneeVal = s->ReadSwapFloat(); |
|
SetFogKneeParams( kFogExp2, knee, kneeVal ); |
|
|
|
/// Version 9 stuff |
|
fAASetting = s->ReadByte(); |
|
|
|
/// Version A stuff |
|
fMaxAnisotropicSamples = s->ReadByte(); |
|
|
|
/// Reset record version now |
|
fRecordVersion = kCurrRecordVersion; |
|
} |
|
|
|
void hsG3DDeviceRecord::Write(hsStream* s) const |
|
{ |
|
s->WriteSwap32( fRecordVersion ); |
|
|
|
s->WriteSwap32(fFlags); |
|
|
|
s->WriteSwap32(fG3DDeviceType); |
|
|
|
int len; |
|
|
|
len = hsStrlen(fG3DDriverDesc); |
|
s->WriteSwap32(len); |
|
s->Write(len, fG3DDriverDesc); |
|
|
|
len = hsStrlen(fG3DDriverName); |
|
s->WriteSwap32(len); |
|
s->Write(len, fG3DDriverName); |
|
|
|
len = hsStrlen(fG3DDriverVersion); |
|
s->WriteSwap32(len); |
|
s->Write(len, fG3DDriverVersion); |
|
|
|
len = hsStrlen(fG3DDeviceDesc); |
|
s->WriteSwap32(len); |
|
s->Write(len, fG3DDeviceDesc); |
|
|
|
fCaps.Write(s); |
|
s->WriteSwap32(fLayersAtOnce); |
|
s->WriteSwap32(fMemoryBytes); |
|
|
|
s->WriteSwap32(fModes.GetCount()); |
|
int i; |
|
for( i = 0; i < fModes.GetCount(); i++ ) |
|
fModes[i].Write( s ); |
|
|
|
/// Version 3 data |
|
s->WriteSwapFloat( fZBiasRating ); |
|
s->WriteSwapFloat( fLODBiasRating ); |
|
s->WriteSwapFloat( fFogExpApproxStart ); |
|
s->WriteSwapFloat( fFogExp2ApproxStart ); |
|
s->WriteSwapFloat( fFogEndBias ); |
|
|
|
/// Version 7 data |
|
s->WriteSwapFloat( fFogKnees[ kFogExp ] ); |
|
s->WriteSwapFloat( fFogKneeVals[ kFogExp ] ); |
|
s->WriteSwapFloat( fFogKnees[ kFogExp2 ] ); |
|
s->WriteSwapFloat( fFogKneeVals[ kFogExp2 ] ); |
|
|
|
/// Version 9 data |
|
s->WriteByte( fAASetting ); |
|
|
|
/// Version A stuff |
|
s->WriteByte( fMaxAnisotropicSamples ); |
|
} |
|
|
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord(const hsG3DDeviceRecord& devRec, const hsG3DDeviceMode& devMode) |
|
: fDevice(devRec), fMode(devMode) |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord() |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::~hsG3DDeviceModeRecord() |
|
{ |
|
} |
|
|
|
hsG3DDeviceModeRecord::hsG3DDeviceModeRecord(const hsG3DDeviceModeRecord& src) |
|
{ |
|
*this = src; |
|
} |
|
|
|
hsG3DDeviceModeRecord& hsG3DDeviceModeRecord::operator=(const hsG3DDeviceModeRecord& src) |
|
{ |
|
fDevice = src.fDevice; |
|
fMode = src.fMode; |
|
return *this; |
|
} |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////// |
|
|
|
hsG3DDeviceSelector::hsG3DDeviceSelector() |
|
{ |
|
} |
|
|
|
hsG3DDeviceSelector::~hsG3DDeviceSelector() |
|
{ |
|
Clear(); |
|
} |
|
|
|
void hsG3DDeviceSelector::RemoveDiscarded() |
|
{ |
|
int i; |
|
for( i = 0; i < fRecords.GetCount(); ) |
|
{ |
|
fRecords[i].RemoveDiscarded(); |
|
|
|
if( fRecords[i].GetDiscarded() ) |
|
{ |
|
fRecords[i].Clear(); |
|
fRecords.Remove(i); |
|
} |
|
else |
|
i++; |
|
} |
|
} |
|
|
|
void hsG3DDeviceSelector::Clear() |
|
{ |
|
int i; |
|
for( i = 0; i < fRecords.GetCount(); i++ ) |
|
fRecords[i].Clear(); |
|
fRecords.Reset(); |
|
} |
|
|
|
void hsG3DDeviceSelector::RemoveUnusableDevModes(hsBool bTough) |
|
{ |
|
plDemoDebugFile::Write( "Removing unusable devices and modes..." ); |
|
for (int i = 0; i < fRecords.GetCount(); i++) |
|
{ |
|
// |
|
// Remove modes |
|
// |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[i].GetModes(); |
|
for (int j = 0; j < modes.GetCount(); j++) |
|
{ |
|
// Remove windowed modes |
|
if ((modes[j].GetWidth() == 0) && |
|
(modes[j].GetHeight() == 0) && |
|
(modes[j].GetColorDepth() == 0)) |
|
{ |
|
plDemoDebugFile::Write( " Removing windowed mode on ", (char *)fRecords[ i ].GetDriverDesc() ); |
|
modes[j].SetDiscarded(true); |
|
} |
|
// If tough, remove modes less than 640x480 |
|
else if (bTough && ((modes[j].GetWidth() < 640) || (modes[j].GetHeight() < 480))) |
|
{ |
|
plDemoDebugFile::Write( " Removing mode < 640x480 on ", (char *)fRecords[ i ].GetDriverDesc() ); |
|
modes[j].SetDiscarded(true); |
|
} |
|
else |
|
{ |
|
char str[ 256 ]; |
|
sprintf( str, " Keeping mode (%dx%d) on device %s", modes[j].GetWidth(), modes[j].GetHeight(), fRecords[ i ].GetDriverDesc() ); |
|
plDemoDebugFile::Write( str ); |
|
} |
|
} |
|
|
|
// |
|
// Remove devices |
|
// |
|
if (fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeUnknown) |
|
{ |
|
plDemoDebugFile::Write( " Removing unknown device. Description", (char *)fRecords[ i ].GetDriverDesc() ); |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
else if( fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3D || |
|
fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3DTnL ) |
|
{ |
|
UInt32 totalMem; |
|
char devDesc[ 256 ]; |
|
|
|
|
|
// For our 3dfx test later |
|
strncpy( devDesc, fRecords[i].GetDriverDesc(), sizeof( devDesc ) - 1 ); |
|
hsStrLower( devDesc ); |
|
|
|
// Remove software Direct3D devices |
|
if ((fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3DHALDev) && |
|
(fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3DTnLHalDev) && |
|
(fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3D3dfxDev) && |
|
(fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3D3dfxVoodoo5Dev) |
|
#ifdef HS_ALLOW_D3D_REF_DRIVER |
|
&& (fRecords[i].GetG3DHALorHEL() != hsG3DDeviceSelector::kHHD3DRefDev) |
|
#endif |
|
) |
|
{ |
|
plDemoDebugFile::Write( " Removing software Direct3D device. Description", (char *)fRecords[ i ].GetDriverDesc() ); |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
// Remove 3Dfx Direct3D devices, take 2 |
|
// 10.13.2000 mcn - Now we do it even when we're wimpy |
|
// 10.25.2000 mcn - Think again. |
|
// 11.3.2000 mcn - Shesh, is this EVER going to be stable?? |
|
else if( bTough && fRecords[i].GetG3DHALorHEL() == hsG3DDeviceSelector::kHHD3D3dfxDev ) |
|
// else if( bTough && ( strstr( devDesc, "3dfx" ) || strstr( devDesc, "voodoo" ) ) ) |
|
{ |
|
plDemoDebugFile::Write( " Removing 3Dfx non-Voodoo5 Direct3D device (We only support Glide on 3Dfx). Description", (char *)fRecords[ i ].GetDriverDesc() ); |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
// Remove Direct3D devices with less than 11 megs of RAM |
|
else if (bTough && ( totalMem = IAdjustDirectXMemory( fRecords[i].GetMemoryBytes() ) ) < 11*1024*1024 ) |
|
{ |
|
char str[ 256 ]; |
|
sprintf( str, " Removing Direct3D device with < 11MB RAM. Device RAM (in kB): %d (Description: %s)", |
|
totalMem / 1024, fRecords[ i ].GetDriverDesc() ); |
|
plDemoDebugFile::Write( str ); |
|
fRecords[i].SetDiscarded(true); |
|
} |
|
else |
|
{ |
|
if( fRecords[i].GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3DTnL ) |
|
plDemoDebugFile::Write( " Keeping DX8 Direct3D device", (char *)fRecords[ i ].GetDriverDesc() ); |
|
else |
|
plDemoDebugFile::Write( " Keeping Direct3D device", (char *)fRecords[ i ].GetDriverDesc() ); |
|
} |
|
} |
|
else |
|
plDemoDebugFile::Write( " Keeping device", (char *)fRecords[ i ].GetDriverDesc() ); |
|
} |
|
|
|
RemoveDiscarded(); |
|
} |
|
|
|
//// IAdjustDirectXMemory ///////////////////////////////////////////////////// |
|
// Adjusts the number coming off of the DirectX caps for "total video memory" |
|
// to be more reflective of what is really on the board. According to |
|
// Microsoft, the best way to do this is to add in the memory necessary for |
|
// the entire desktop. Okay, whatever... |
|
|
|
UInt32 hsG3DDeviceSelector::IAdjustDirectXMemory( UInt32 cardMem ) |
|
{ |
|
#if HS_BUILD_FOR_WIN32 |
|
HDC deskDC; |
|
int width, height, bpp, total; |
|
|
|
deskDC = GetDC( nil ); |
|
width = GetDeviceCaps( deskDC, HORZRES ); |
|
height = GetDeviceCaps( deskDC, VERTRES ); |
|
bpp = GetDeviceCaps( deskDC, BITSPIXEL ); |
|
|
|
total = width * height; |
|
if( bpp > 8 ) |
|
total *= ( bpp >> 3 ); |
|
|
|
return cardMem + total; |
|
#else |
|
return cardMem; |
|
#endif |
|
} |
|
|
|
hsBool hsG3DDeviceSelector::Init( void ) |
|
{ |
|
// See if we're all capable of initing |
|
if( !IInitDirect3D() ) |
|
{ |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void hsG3DDeviceSelector::Enumerate(hsWinRef winRef) |
|
{ |
|
Clear(); |
|
|
|
#ifdef HS_BUILD_FOR_WIN32 |
|
/// 9.6.2000 - Create the class to use as our temporary window class |
|
WNDCLASS tempClass; |
|
|
|
strcpy( fTempWinClass, "DSTestClass" ); |
|
memset( &tempClass, 0, sizeof( tempClass ) ); |
|
tempClass.lpfnWndProc = DefWindowProc; |
|
tempClass.hInstance = GetModuleHandle( nil ); |
|
tempClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); |
|
tempClass.lpszClassName = fTempWinClass; |
|
UInt16 ret = RegisterClass(&tempClass); |
|
hsAssert(ret, "Cannot create temporary window class to test for device modes" ); |
|
#endif |
|
|
|
/// Now try our devices |
|
#ifdef HS_SELECT_DX7 |
|
ITryDirect3D(winRef); |
|
#endif // HS_SELECT_DX7 |
|
|
|
ITryDirect3DTnL(winRef); |
|
|
|
// ITryOpenGL(winRef); |
|
|
|
#ifdef HS_BUILD_FOR_WIN32 |
|
/// Get rid of the class |
|
UnregisterClass( fTempWinClass, GetModuleHandle( nil ) ); |
|
#endif |
|
} |
|
|
|
hsBool hsG3DDeviceSelector::GetDefault (hsG3DDeviceModeRecord *dmr) |
|
{ |
|
Int32 iTnL, iD3D, iOpenGL, device, mode, i; |
|
device = iTnL = iD3D = iOpenGL = mode = -1; |
|
|
|
if (device == -1) |
|
{ |
|
// Get an index for any 3D devices |
|
for (i = 0; i < fRecords.GetCount(); i++) |
|
{ |
|
switch (fRecords[i].GetG3DDeviceType()) |
|
{ |
|
case kDevTypeDirect3D: |
|
case kDevTypeDirect3DTnL: |
|
if (fRecords[i].GetG3DHALorHEL() == kHHD3DTnLHalDev) |
|
{ |
|
if (iTnL == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iTnL = i; |
|
} |
|
} |
|
else if (fRecords[i].GetG3DHALorHEL() == kHHD3DHALDev || fRecords[i].GetG3DHALorHEL() == kHHD3D3dfxVoodoo5Dev ) |
|
{ |
|
if (iD3D == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iD3D = i; |
|
} |
|
} |
|
break; |
|
|
|
case kDevTypeOpenGL: |
|
if (iOpenGL == -1 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
|| plPipeline::fInitialPipeParams.ForceSecondMonitor |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
) |
|
{ |
|
iOpenGL = i; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
// Pick a default device (Priority D3D T&L, D3D HAL, OpenGL) |
|
if (iTnL != -1) |
|
device = iTnL; |
|
else if (iD3D != -1) |
|
device = iD3D; |
|
else if (iOpenGL != -1) |
|
device = iOpenGL; |
|
else |
|
return false; |
|
} |
|
|
|
// |
|
// Try and find the default mode |
|
// |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[device].GetModes(); |
|
|
|
// If there are no modes (for some insane reason), fail |
|
if (modes.GetCount() == 0) |
|
return false; |
|
|
|
for (i = 0; i < modes.GetCount(); i++) |
|
{ |
|
if ((modes[i].GetWidth() == kDefaultWidth) && |
|
(modes[i].GetHeight() == kDefaultHeight) && |
|
(modes[i].GetNumZStencilDepths() > 0)) |
|
{ |
|
// Don't be too picky about the depth, use what's available if the |
|
// default isn't found. |
|
if (mode == -1 || modes[mode].GetColorDepth() != kDefaultDepth) |
|
mode = i; |
|
} |
|
} |
|
// Default mode not found, what kind of card is this?! |
|
// Regardless, just use the first mode since this isn't a fatal error. |
|
if (mode == -1) |
|
mode = 0; |
|
|
|
*dmr = hsG3DDeviceModeRecord(fRecords[device], modes[mode]); |
|
|
|
return true; |
|
} |
|
|
|
//// ITryOpenGL /////////////////////////////////////////////////////////////// |
|
// Updated 8.24.2000 mcn to (hopefully) detect OpenGL drivers. |
|
|
|
void hsG3DDeviceSelector::ITryOpenGL(hsWinRef winRef) |
|
{ |
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
int i, numDrivers; |
|
int modeRes[ 6 ][ 3 ] = { { 640, 480, 16 }, { 800, 600, 16 }, { 1024, 768, 16 }, |
|
{ 1152, 864, 16 }, { 1280, 1024, 16 }, { 1600, 1200, 16 } }; |
|
gls_driver_info driverInfo; |
|
hsG3DDeviceRecord devRec; |
|
hsG3DDeviceMode devMode; |
|
char str[ 128 ]; |
|
HDC hDC; |
|
HGLRC tempContext; |
|
HWND testWindow = nil, testWindow2 = nil; |
|
|
|
WINDOWPLACEMENT oldWindowPlace; |
|
|
|
|
|
/// Save old window position |
|
oldWindowPlace.length = sizeof( oldWindowPlace ); |
|
GetWindowPlacement( (HWND)winRef, &oldWindowPlace ); |
|
|
|
/// Use the GLS API to get us a list of all OpenGL drivers available on |
|
/// this system and their capabilities |
|
numDrivers = glsGetNumberOfDrivers(); |
|
for( i = 0; i < numDrivers; i++ ) |
|
{ |
|
/// Get main driver info |
|
glsGetDriverInfo( i, &driverInfo ); |
|
|
|
devRec.SetG3DDeviceType( kDevTypeOpenGL ); |
|
|
|
devRec.SetDriverDesc( driverInfo.aDriverDescription ); |
|
devRec.SetDriverName( driverInfo.GLDriver.aDriverFilePath ); |
|
|
|
sprintf( str, "%d.%d", driverInfo.GLDriver.DriverFileVersionHigh, |
|
driverInfo.GLDriver.DriverFileVersionLow ); |
|
devRec.SetDriverVersion( str ); |
|
|
|
devRec.SetCap( kCapsMipmap ); |
|
devRec.SetCap( kCapsMipmap ); |
|
devRec.SetCap( kCapsPerspective ); |
|
|
|
if( driverInfo.DriverFlags & GLS_FLAGS_FULLSCREEN_ONLY ) |
|
devRec.SetCap( kCapsNoWindow ); |
|
if( !( driverInfo.DriverFlags & GLS_FLAGS_SOFTWARE_ONLY ) ) |
|
devRec.SetCap( kCapsHardware ); |
|
devRec.SetCap( kCapsDoesSmallTextures ); |
|
|
|
/// We have a problem here--OpenGL has no way of detecting the rest of |
|
/// the information we want, so we'll have to guess/kludge on most of it. |
|
|
|
glsLoadDriver( i ); |
|
sprintf( str, "ITryOpenGL(): FOUND OpenGL Driver: %s (%s)\n", driverInfo.aDriverDescription, |
|
driverInfo.GLDriver.aDriverFilePath ); |
|
hsStatusMessage( str ); |
|
|
|
/// (and of COURSE we have to open a bloody rendering context for |
|
/// glGetString to work...whose bright idea was THAT?) |
|
testWindow = CreateWindowEx( WS_EX_APPWINDOW, fTempWinClass, "OpenGL Screen Test Window", |
|
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE, |
|
0, 0, 640, 480, nil, nil, GetModuleHandle( nil ), 0 ); |
|
hDC = GetDC( testWindow ); |
|
tempContext = (HGLRC)ICreateTempOpenGLContext( hDC, |
|
driverInfo.DriverFlags & GLS_FLAGS_FULLSCREEN_ONLY ); |
|
if( tempContext != nil ) |
|
{ |
|
wglMakeCurrent( hDC, tempContext ); |
|
|
|
IGetExtOpenGLInfo( devRec ); |
|
|
|
/// Reset everything back now |
|
wglMakeCurrent( nil, nil ); |
|
wglDeleteContext( tempContext ); |
|
ReleaseDC( testWindow, hDC ); |
|
} |
|
|
|
/// Resize window to hide what we're about to do |
|
SetWindowPos( testWindow, nil, 0, 0, 1600, 1200, SWP_NOZORDER | SWP_NOMOVE ); |
|
|
|
/// Check for windowed screen mode (which SOMEBODY decided to test for |
|
/// bitdepth of 0 instead of the caps flag we're setting....hmmmm wasn't me....) |
|
if( !( driverInfo.DriverFlags & GLS_FLAGS_FULLSCREEN_ONLY ) ) |
|
{ |
|
devMode.Clear(); |
|
devMode.SetWidth( 0 ); |
|
devMode.SetHeight( 0 ); |
|
devMode.SetColorDepth( 0 ); |
|
devRec.GetModes().Append( devMode ); |
|
} |
|
|
|
/// Go get the screen modes |
|
IGetOpenGLModes( devRec, driverInfo.aDriverDescription ); |
|
|
|
/// Get rid of the window now |
|
DestroyWindow( testWindow ); |
|
|
|
/// Unload this driver now |
|
glsUnloadDriver(); |
|
} |
|
|
|
/// Restore old window position |
|
SetWindowPlacement( (HWND)winRef, &oldWindowPlace ); |
|
#endif |
|
#endif |
|
} |
|
|
|
//// IGetOpenGLModes ////////////////////////////////////////////////////////// |
|
// Scans through all the possible imaginable combinations of screen modes, |
|
// pixel formats whatnot and adds the final, culled-down list of graphics |
|
// modes to the given device record. |
|
|
|
void hsG3DDeviceSelector::IGetOpenGLModes( hsG3DDeviceRecord &devRec, char *driverName ) |
|
{ |
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
int j; |
|
int maxMode, mode; |
|
int modeRes[ 6 ][ 3 ] = { { 640, 480, 16 }, { 800, 600, 16 }, { 1024, 768, 16 }, |
|
{ 1152, 864, 16 }, { 1280, 1024, 16 }, { 1600, 1200, 16 } }; |
|
int bitDepths[ 3 ] = { 32, 24, 16 }, bitDepth; |
|
hsG3DDeviceMode devMode; |
|
DEVMODE modeInfo; |
|
HWND testWindow = nil, testWindow2 = nil; |
|
char str[ 128 ]; |
|
|
|
|
|
/// Find the maximum resolution that we can support on this monitor--then |
|
/// we'll start there and work down until we find a mode supported by OpenGL |
|
modeInfo.dmSize = sizeof( modeInfo ); |
|
maxMode = -1; |
|
for( j = 0; EnumDisplaySettings( nil, j, &modeInfo ) != 0; j++ ) |
|
{ |
|
for( mode = 0; mode < sizeof( modeRes ) / sizeof( modeRes[ 0 ] ); mode++ ) |
|
{ |
|
if( modeRes[ mode ][ 0 ] == modeInfo.dmPelsWidth && |
|
modeRes[ mode ][ 1 ] == modeInfo.dmPelsHeight ) |
|
{ |
|
if( modeInfo.dmBitsPerPel > modeRes[ mode ][ 2 ] ) |
|
modeRes[ mode ][ 2 ] = modeInfo.dmBitsPerPel; |
|
|
|
if( mode > maxMode ) |
|
{ |
|
maxMode = mode; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
if( maxMode != -1 ) |
|
{ |
|
/// Outer loop: loop through color depths |
|
for( bitDepth = 0; bitDepth < 3; bitDepth++ ) |
|
{ |
|
/// Loop through each of the display settings, starting at |
|
/// the maxMode and going down, happily get pixel formats for each |
|
modeInfo.dmSize = sizeof( modeInfo ); |
|
modeInfo.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; |
|
for( mode = maxMode; mode >= 0; mode-- ) |
|
{ |
|
/// Does this resolution work at this bit depth? |
|
if( modeRes[ mode ][ 2 ] < bitDepths[ bitDepth ] ) |
|
continue; |
|
|
|
/// Attempt to set this screen mode |
|
modeInfo.dmPelsWidth = modeRes[ mode ][ 0 ]; |
|
modeInfo.dmPelsHeight = modeRes[ mode ][ 1 ]; |
|
modeInfo.dmBitsPerPel = bitDepths[ bitDepth ]; |
|
if( ChangeDisplaySettings( &modeInfo, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) |
|
{ |
|
if( ITestOpenGLRes( modeRes[ mode ][ 0 ], modeRes[ mode ][ 1 ], |
|
bitDepths[ bitDepth ], |
|
devRec, driverName ) ) |
|
{ |
|
/// Go and add the rest of 'em (we just assume that we can get |
|
/// lower resolutions if we got this one) |
|
for( mode--; mode >= 0; mode-- ) |
|
{ |
|
devMode.SetWidth( modeRes[ mode ][ 0 ] ); |
|
devMode.SetHeight( modeRes[ mode ][ 1 ] ); |
|
devMode.SetColorDepth( bitDepths[ bitDepth ] ); |
|
devRec.GetModes().Append( devMode ); |
|
|
|
sprintf( str, "ITryOpenGL(): Assuming mode: %dx%dx%dbpp, %s\n", |
|
modeRes[ mode ][ 0 ], modeRes[ mode ][ 1 ], bitDepths[ bitDepth ], driverName ); |
|
hsStatusMessage( str ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// Note: this will also reset the screen after any mode changes from |
|
/// creating our context |
|
ChangeDisplaySettings( nil, 0 ); |
|
|
|
if( devRec.GetModes().GetCount() ) |
|
fRecords.Append( devRec ); |
|
} |
|
#endif |
|
#endif |
|
} |
|
|
|
//// ITestOpenGLRes /////////////////////////////////////////////////////////// |
|
// Tests all the possible OpenGL settings once the screen has been set |
|
// to a given test resolution. |
|
|
|
hsBool hsG3DDeviceSelector::ITestOpenGLRes( int width, int height, int bitDepth, |
|
hsG3DDeviceRecord &devRec, char *driverName ) |
|
{ |
|
hsBool retValue = false; |
|
|
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
int j, bitDepthFlags, myBitDepth; |
|
hsG3DDeviceMode devMode; |
|
char str[ 128 ]; |
|
HDC hDC, hDC2; |
|
HGLRC tempContext; |
|
HWND testWindow = nil, testWindow2 = nil; |
|
|
|
PIXELFORMATDESCRIPTOR pfd; |
|
|
|
|
|
/// Create test window #1 |
|
testWindow = CreateWindowEx( WS_EX_APPWINDOW, fTempWinClass, "OpenGL Screen Test Window", |
|
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE, |
|
0, 0, width, height, |
|
nil, nil, GetModuleHandle( nil ), 0 ); |
|
hDC = GetDC( testWindow ); |
|
|
|
/// Loop through using DescribePixelFormat in an attempt to find all the |
|
/// pixel formats we actually do support using this OpenGL driver |
|
devMode.Clear(); |
|
pfd.nSize = sizeof( pfd ); |
|
bitDepthFlags = 0; |
|
for( j = 1; retValue == false && DescribePixelFormat( hDC, j, sizeof( pfd ), &pfd ) != 0; j++ ) |
|
{ |
|
/// Can we use this one? |
|
if( pfd.cColorBits != bitDepth ) |
|
continue; |
|
|
|
myBitDepth = ( pfd.cColorBits == 32 ) ? 0x04 : ( pfd.cColorBits == 24 ) ? 0x02 : 0x01; |
|
|
|
if( ( pfd.dwFlags & PFD_SUPPORT_OPENGL ) && |
|
( pfd.dwFlags & PFD_DRAW_TO_WINDOW ) && |
|
( pfd.dwFlags & PFD_DOUBLEBUFFER ) && |
|
( pfd.iPixelType == PFD_TYPE_RGBA ) && |
|
( pfd.iLayerType == PFD_MAIN_PLANE ) && |
|
( ( bitDepthFlags & myBitDepth ) == 0 ) ) |
|
{ |
|
/// Looks like it! But is it REALLY? |
|
testWindow2 = CreateWindowEx( WS_EX_APPWINDOW, fTempWinClass, "OpenGL Screen Test Window #2", |
|
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE, |
|
0, 0, width, height, |
|
nil, nil, GetModuleHandle( nil ), 0 ); |
|
hDC2 = GetDC( testWindow2 ); |
|
|
|
if( SetPixelFormat( hDC2, j, &pfd ) ) |
|
{ |
|
tempContext = wglCreateContext( hDC2 ); |
|
if( tempContext != nil ) |
|
{ |
|
if( wglMakeCurrent( hDC2, tempContext ) ) |
|
{ |
|
/// Guess it really does work... |
|
devMode.SetWidth( width ); |
|
devMode.SetHeight( height ); |
|
devMode.SetColorDepth( pfd.cColorBits ); |
|
devRec.GetModes().Append( devMode ); |
|
bitDepthFlags |= myBitDepth; |
|
|
|
sprintf( str, "ITryOpenGL(): Adding mode: %dx%dx%dbpp, %s\n", |
|
width, height, pfd.cColorBits, driverName ); |
|
hsStatusMessage( str ); |
|
|
|
wglMakeCurrent( nil, nil ); |
|
retValue = true; /// Break us out |
|
} |
|
wglDeleteContext( tempContext ); |
|
} |
|
} |
|
ReleaseDC( testWindow2, hDC2 ); |
|
DestroyWindow( testWindow2 ); |
|
} |
|
} |
|
ReleaseDC( testWindow, hDC ); |
|
DestroyWindow( testWindow ); |
|
|
|
#endif |
|
#endif |
|
return retValue; |
|
} |
|
|
|
|
|
//// IGetExtOpenGLInfo //////////////////////////////////////////////////////// |
|
// Gets extended info--i.e. info requiring an OpenGL context. Assumes the |
|
// said context is already created and active. |
|
|
|
void hsG3DDeviceSelector::IGetExtOpenGLInfo( hsG3DDeviceRecord &devRec ) |
|
{ |
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
GLint numTMUs; |
|
char *extString, *c, *c2; |
|
char str[ 128 ]; |
|
int j; |
|
|
|
|
|
if( ( extString = (char *)glGetString( GL_RENDERER ) ) != nil ) |
|
{ |
|
devRec.SetDeviceDesc( extString ); |
|
|
|
/// Can we guess at the amount of texture memory? |
|
c = strstr( extString, "MB" ); |
|
if( c != nil && c != extString && ( isdigit( *( c - 1 ) ) || isspace( *( c - 1 ) ) ) ) |
|
{ |
|
/// Looks like we found a "xxMB" texture memory specification--use it |
|
/// as our guess |
|
c2 = c; |
|
do { |
|
c2--; |
|
} while( c2 >= extString && ( isdigit( *c2 ) || isspace( *c2 ) ) ); |
|
c2++; |
|
|
|
strncpy( str, c2, (UInt32)c - (UInt32)c2 ); |
|
j = atoi( str ); |
|
sprintf( str, "ITryOpenGL(): Device has %d MB texture memory\n", j ); |
|
hsStatusMessage( str ); |
|
|
|
j *= 1024 * 1024; /// Translate to bytes |
|
devRec.SetMemoryBytes( j ); |
|
} |
|
else |
|
{ |
|
devRec.SetMemoryBytes( 4 * 1024 * 1024 ); |
|
hsStatusMessage( "ITryOpenGL(): WARNING: Cannot determine texture memory for this card, assuming 4MB\n" ); |
|
} |
|
} |
|
else |
|
{ |
|
devRec.SetDeviceDesc( "" ); |
|
devRec.SetMemoryBytes( 4 * 1024 * 1024 ); |
|
hsStatusMessage( "ITryOpenGL(): WARNING: Cannot determine texture memory for this card, assuming 4MB\n" ); |
|
} |
|
|
|
|
|
if( ( extString = (char *)glGetString( GL_EXTENSIONS ) ) != nil ) |
|
{ |
|
/// For the number of TMUs, we'll detect for the availability of the |
|
/// multitexture extension--if it's there, we'll assume we have two TMUs |
|
/// (if we don't, OpenGL will probably handle it for us--or rather, it BETTER). |
|
if( strstr( extString, "ARB_multitexture" ) ) |
|
devRec.SetLayersAtOnce( 2 ); |
|
else |
|
devRec.SetLayersAtOnce( 1 ); |
|
|
|
/// Can we use compressed textures? |
|
if( strstr( extString, "ARB_texture_compression" ) ) |
|
devRec.SetCap( kCapsCompressTextures ); |
|
} |
|
|
|
/// Get TMU count |
|
glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &numTMUs ); |
|
if( numTMUs <= 0 ) |
|
numTMUs = 0; |
|
devRec.SetLayersAtOnce( numTMUs ); |
|
#endif |
|
#endif |
|
} |
|
|
|
//// ICreateTempOpenGLContext ///////////////////////////////////////////////// |
|
// Creates a temporary context for testing OpenGL stuff with. |
|
|
|
#ifdef HS_OPEN_GL |
|
#if HS_BUILD_FOR_WIN32 |
|
|
|
UInt32 hsG3DDeviceSelector::ICreateTempOpenGLContext( HDC hDC, hsBool32 makeItFull ) |
|
{ |
|
DEVMODE modeInfo; |
|
int pixFmt; |
|
|
|
|
|
if( makeItFull ) |
|
{ |
|
/// Attempt resolution change to 640x480x32bpp |
|
memset( &modeInfo, 0, sizeof( modeInfo ) ); |
|
modeInfo.dmSize = sizeof( modeInfo ); |
|
modeInfo.dmBitsPerPel = 16; |
|
modeInfo.dmPelsWidth = 640; |
|
modeInfo.dmPelsHeight = 480; |
|
if( ChangeDisplaySettings( &modeInfo, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL ) |
|
{ |
|
return nil; /// We want fullscreen, can't get it, oops. |
|
} |
|
} |
|
|
|
/// Now try to set a pixel format |
|
PIXELFORMATDESCRIPTOR pfd = { |
|
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd |
|
1, // version number |
|
PFD_DRAW_TO_WINDOW | // support window |
|
PFD_SUPPORT_OPENGL | // support OpenGL |
|
PFD_DOUBLEBUFFER, // double buffered |
|
PFD_TYPE_RGBA, // RGBA type |
|
16, // 24-bit color depth |
|
0, 0, 0, 0, 0, 0, // color bits ignored |
|
0, // no alpha buffer |
|
0, // shift bit ignored |
|
0, // no accumulation buffer |
|
0, 0, 0, 0, // accum bits ignored |
|
0, // 32-bit z-buffer |
|
0, // no stencil buffer |
|
0, // no auxiliary buffer |
|
PFD_MAIN_PLANE, // main layer |
|
0, // reserved |
|
0, 0, 0 // layer masks ignored |
|
}; |
|
|
|
pixFmt = ChoosePixelFormat( hDC, &pfd ); |
|
if( pixFmt > 0 && SetPixelFormat( hDC, pixFmt, &pfd ) ) |
|
return (UInt32)wglCreateContext( hDC ); |
|
|
|
return 0; |
|
} |
|
#endif |
|
#endif |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Fudging Routines ///////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
namespace |
|
{ |
|
/// Here's our CFT--Chipset Fudgefactor Table |
|
/// The table consists of entries for each of our supported chipsets in the table, |
|
/// plus, flags to be forced set and flags to be forced cleared. Also included |
|
/// is a Z-buffer suckiness rating, which represents how badly we need to bias |
|
/// the z and w values to avoid z-buffer artifacts, stored as an hsScalar (i.e |
|
/// a float). A rating of 0 means very good/default (read: Nvidia), while, say, |
|
/// a 9.0 (i.e. shift the scale 9 times above normal) means s****y, like, say, |
|
/// a Savage4. Also also included is a forced value for max # of layers (0 means |
|
/// to use default). Also also also included is an LOD rating indicating how much |
|
/// (and in which direction) to alter the base LOD bias value for this device. General |
|
/// interpretation of this value is to add (-lodRating) to the LOD bias value. |
|
/// This is because the LOD bias starts out negative and typically goes in 0.25 |
|
/// increments. |
|
/// Also also ALSO included are three new values for fog tweaking. The first two-- |
|
/// fFogExp/Exp2ApproxStart, are the start of the linear approximation of exponential |
|
/// fog. Tweak these to adjust the linear approximation on any cards that don't support |
|
/// exponential and exponential-squared fog natively. The third value is the fFogEndBias-- |
|
/// this is a value (stored as a percentage of the max possible fog value) to add on to |
|
/// to the linear fog-end parameter AFTER ALL CALCULATIONS. This is so we can, for |
|
/// example, tweak the end of the fog on the ATI Rage cards to not fog out as quickly. |
|
/// 9.14.2000 - fog end bias now has a new meaning. What it *really* represents is the |
|
/// quantization of fog on a particular card, where the end bias = ( 2^bitdepth - 2 ) / ( 2^bitdepth - 1 ) |
|
/// So, for 8 bit fog, we end up with 254 / 255, etc. So far, everything is set to 8 |
|
/// bit fog, but we have it here just in case we need to change it in the future. |
|
|
|
enum { |
|
kDefaultChipset = 0x00, |
|
kSavage4Chipset, |
|
kATIRageFuryChipset, |
|
kATIRageProChipset, |
|
kNVidiaTNTChipset, |
|
kNVidiaGeForceChipset, |
|
kMatroxG400Chipset, |
|
kIntelI810Chipset, |
|
kSavage2000Chipset, |
|
kS3GenericChipset, |
|
kATIGenericChipset, |
|
kMatroxGenericChipset, |
|
kKYROChipset, |
|
k3dfxV5Chipset, |
|
kSavage3DChipset, |
|
kATIRadeonChipset, |
|
kATIR7X00Chipset, |
|
kATIR7500Chipset, |
|
kATIR8X00Chipset, |
|
kMatroxParhelia, |
|
kNVidiaGeForce2Chipset, |
|
kNVidiaGeForce3Chipset, |
|
kNVidiaGeForce4MXChipset, |
|
kNVidiaGeForce4Chipset, |
|
kNVidiaGeForceFXChipset |
|
}; |
|
|
|
typedef struct |
|
{ |
|
hsScalar fFogExpApproxStart; |
|
hsScalar fFogExp2ApproxStart; |
|
hsScalar fFogEndBias; |
|
hsScalar fFogExpKnee; // Fog knees |
|
hsScalar fFogExpKneeVal; |
|
hsScalar fFogExp2Knee; |
|
hsScalar fFogExp2KneeVal; |
|
} FogTweakTable; |
|
|
|
FogTweakTable dsDefaultFogVals = { 0, 0, 254.0 / 255.0, 0.5f, 0.15f, 0.5f, 0.15f }; |
|
FogTweakTable dsATIFogVals = { 0.1f, 0.1f, 254.0 / 255.0, 0.85f, 0.15f, 0.5f, 0.15f }; |
|
FogTweakTable dsS3DFogVals = { 0, 0, 254.0 / 255.0, 1.0f, 1.0f, 1.0f, 1.0f }; |
|
FogTweakTable dsi810FogVals = { 0, 0, 254.0 / 255.0, 0.6f, 0.15f, 0.4f, 0.15f }; |
|
FogTweakTable dsRadeonFogVals = { 0, 0, 254.0 / 255.0, 0.7f, 0.15f, 0.5f, 0.2f }; |
|
|
|
|
|
typedef struct { |
|
UInt8 fType; // Our chipset ID |
|
UInt32 *fFlagsToSet; |
|
UInt32 *fFlagsToClear; |
|
hsScalar fZSuckiness; // See above |
|
UInt32 fForceMaxLayers; // The max # of layers we REALLY want (0 to not force) |
|
hsScalar fLODRating; |
|
FogTweakTable *fFogTweaks; |
|
} CFTable; |
|
|
|
UInt32 dsSavageCapsClr[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsCompressTextures, |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsSavageCapsSet[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsBadYonStuff }; |
|
|
|
UInt32 dsSavage2kCapsClr[] = { |
|
5, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsCompressTextures, |
|
hsG3DDeviceSelector::kCapsPixelFog, |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsS3GenerCapsClr[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsCompressTextures, |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsATIFuryCapsClr[] = { |
|
3, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsPixelFog }; |
|
|
|
UInt32 dsATIRageCapsClr[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures, |
|
hsG3DDeviceSelector::kCapsPixelFog }; |
|
|
|
UInt32 dsATIGenerCapsClr[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsPixelFog, |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsATIRadeonCapsSet[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsBadManaged, |
|
hsG3DDeviceSelector::kCapsShareDepth |
|
}; |
|
|
|
UInt32 dsATIRadeonCapsClr[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsWBuffer, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsATIR7X00CapsSet[] = { |
|
4, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsCantShadow, |
|
hsG3DDeviceSelector::kCapsBadManaged, |
|
hsG3DDeviceSelector::kCapsShareDepth, |
|
hsG3DDeviceSelector::kCapsNoAniso |
|
}; |
|
|
|
UInt32 dsATIR7500CapsSet[] = { |
|
5, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsMaxUVWSrc2, |
|
hsG3DDeviceSelector::kCapsCantShadow, |
|
hsG3DDeviceSelector::kCapsBadManaged, |
|
hsG3DDeviceSelector::kCapsShareDepth, |
|
hsG3DDeviceSelector::kCapsNoAniso |
|
}; |
|
|
|
UInt32 dsATIR7X00CapsClr[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsWBuffer, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsATIR8X00CapsSet[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsBadManaged, |
|
hsG3DDeviceSelector::kCapsShareDepth |
|
}; |
|
|
|
UInt32 dsATIR8X00CapsClr[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsWBuffer, |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsTNTCapsClr[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsDefaultCapsClr[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsMG400CapsClr[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures }; |
|
|
|
UInt32 dsKYROCapsClr[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsDoesSmallTextures, |
|
hsG3DDeviceSelector::kCapsPixelFog }; |
|
|
|
UInt32 dsKYROCapsSet[] = { |
|
1, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsNoKindaSmallTexs }; |
|
|
|
UInt32 ds3dfxV5CapsClr[] = { |
|
2, // First integer is always the length |
|
hsG3DDeviceSelector::kCapsFogExp, |
|
hsG3DDeviceSelector::kCapsFogExp2 }; |
|
|
|
UInt32 dsMatroxParheliaSet[] = { |
|
1, |
|
hsG3DDeviceSelector::kCapsNoAA }; |
|
|
|
UInt32 dsGeForceSet[] = { |
|
2, |
|
hsG3DDeviceSelector::kCapsCantProj, |
|
hsG3DDeviceSelector::kCapsDoubleFlush }; |
|
|
|
UInt32 dsGeForce2Set[] = { |
|
1, |
|
hsG3DDeviceSelector::kCapsDoubleFlush }; |
|
|
|
UInt32 dsGeForce3Set[] = { |
|
1, |
|
hsG3DDeviceSelector::kCapsSingleFlush }; |
|
|
|
UInt32 dsGeForce4MXSet[] = { |
|
1, |
|
hsG3DDeviceSelector::kCapsSingleFlush }; |
|
|
|
UInt32 dsGeForce4Set[] = { |
|
1, |
|
hsG3DDeviceSelector::kCapsSingleFlush |
|
}; |
|
|
|
CFTable dsCFTable[] = |
|
{ |
|
// Chipset ID // F2Set // F2Clear // ZSuck // MaxLayers // LODBias // Fog Value Tables |
|
{ kDefaultChipset, nil, dsDefaultCapsClr, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kATIRageFuryChipset, nil, dsATIFuryCapsClr, 4.25f, 1, 0, &dsATIFogVals }, |
|
{ kATIRageProChipset, nil, dsATIRageCapsClr, 4.25f, 1, 0, &dsATIFogVals }, |
|
{ kATIGenericChipset, nil, dsATIGenerCapsClr, 4.25f, 1, 0, &dsATIFogVals }, |
|
{ kNVidiaTNTChipset, nil, dsTNTCapsClr, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForce2Chipset,dsGeForce2Set, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForce3Chipset,dsGeForce3Set, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForce4MXChipset,dsGeForce4MXSet, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForce4Chipset,dsGeForce4Set, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForceChipset,dsGeForceSet, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kNVidiaGeForceFXChipset,nil, nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kMatroxG400Chipset, nil, dsMG400CapsClr, 3.25f, 0, 0, &dsDefaultFogVals }, |
|
{ kMatroxParhelia, dsMatroxParheliaSet,nil, 0, 0, 0, &dsDefaultFogVals }, |
|
{ kMatroxGenericChipset,nil, dsMG400CapsClr, 3.25f, 0, 0, &dsDefaultFogVals }, |
|
{ kIntelI810Chipset, nil, dsDefaultCapsClr, 4.5f, 1, -0.5f, &dsi810FogVals }, |
|
{ kSavage4Chipset, dsSavageCapsSet, dsSavageCapsClr, 4.0f, 1, 0, &dsDefaultFogVals }, // LOD bias should be -0.5 here |
|
{ kSavage2000Chipset, dsSavageCapsSet, dsSavage2kCapsClr, 4.0f, 1, 0, &dsDefaultFogVals }, |
|
{ kS3GenericChipset, dsSavageCapsSet, dsS3GenerCapsClr, 4.0f, 1, 0, &dsDefaultFogVals }, |
|
{ kKYROChipset, dsKYROCapsSet, dsKYROCapsClr, -151.0f, 1, 0, &dsDefaultFogVals }, |
|
{ k3dfxV5Chipset, nil, ds3dfxV5CapsClr, 3.5f, 0, 0, &dsDefaultFogVals }, |
|
{ kSavage3DChipset, nil, dsDefaultCapsClr, 0, 0, 0, &dsS3DFogVals }, |
|
{ kATIRadeonChipset, dsATIRadeonCapsSet, dsATIRadeonCapsClr, 0, 0, 0, &dsRadeonFogVals }, |
|
{ kATIR7X00Chipset, dsATIR7X00CapsSet, dsATIR7X00CapsClr, 3.f, 2, 0, &dsRadeonFogVals }, |
|
{ kATIR7500Chipset, dsATIR7500CapsSet, dsATIR7X00CapsClr, 3.f, 2, 0, &dsRadeonFogVals }, |
|
{ kATIR8X00Chipset, dsATIR8X00CapsSet, dsATIR8X00CapsClr, 0, 0, 0, &dsRadeonFogVals }, |
|
}; |
|
|
|
}; |
|
|
|
//// IFudgeDirectXDevice ////////////////////////////////////////////////////// |
|
// Checks this DirectX device against all our known types and fudges our caps |
|
// flags and bias values, etc, accordingly |
|
|
|
#ifdef HS_SELECT_DIRECT3D |
|
void hsG3DDeviceSelector::IFudgeDirectXDevice( hsG3DDeviceRecord &record, |
|
D3DEnum_DriverInfo *driverInfo, |
|
D3DEnum_DeviceInfo *deviceInfo ) |
|
{ |
|
char desc[ 512 ]; // Can't rely on D3D constant, since that's in another file now |
|
DWORD vendorID, deviceID; |
|
char *szDriver, *szDesc; |
|
|
|
|
|
/// Send it off to each D3D device, respectively |
|
if( record.GetG3DDeviceType() == kDevTypeDirect3DTnL ) |
|
{ |
|
if( !IGetD3DCardInfo( record, driverInfo, deviceInfo, &vendorID, &deviceID, &szDriver, &szDesc ) ) |
|
{ |
|
// {} to make VC6 happy in release build |
|
hsAssert( false, "Trying to fudge D3D device but D3D support isn't in this EXE!" ); |
|
} |
|
} |
|
#ifdef HS_SELECT_DX7 |
|
else if( record.GetG3DDeviceType() == kDevTypeDirect3D ) |
|
{ |
|
if( !IGetD3D7CardInfo( record, driverInfo, deviceInfo, &vendorID, &deviceID, &szDriver, &szDesc ) ) |
|
{ |
|
// {} to make VC6 happy in release build |
|
hsAssert( false, "Trying to fudge D3D7 device but D3D7 support isn't in this EXE!" ); |
|
} |
|
} |
|
#endif // HS_SELECT_DX7 |
|
else |
|
{ |
|
hsAssert( false, "IFudgeDirectXDevice got a device type that support wasn't compiled for!" ); |
|
} |
|
|
|
/// So capitalization won't matter in our tests |
|
hsAssert( strlen( szDesc ) < sizeof( desc ), "D3D device description longer than expected!" ); |
|
hsStrcpy( desc, szDesc ); |
|
hsStrLower( desc ); |
|
|
|
//// S3-based Cards /////////////////////////////////////////////////////// |
|
/// Detect Savage 4 chipset |
|
if( deviceID == 0x00008a22 || stricmp( szDriver, "s3savg4.dll" ) == 0 || |
|
( strstr( desc, "diamond" ) != nil && strstr( desc, "stealth iii" ) != nil ) || |
|
strstr( desc, "savage4 " ) != nil ) |
|
{ |
|
/// Yup, Savage 4. |
|
hsStatusMessage( "== Using fudge factors for a Savage 4 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a Savage 4 chipset" ); |
|
ISetFudgeFactors( kSavage4Chipset, record ); |
|
} |
|
/// Detect Savage 2000 chipset |
|
else if( deviceID == 0x00009102 || |
|
stricmp( szDriver, "s3sav2k.dll" ) == 0 || |
|
( strstr( desc, "diamond" ) != nil && |
|
strstr( desc, "viperii" ) != nil ) || |
|
strstr( desc, "savage2000 " ) != nil ) |
|
{ |
|
/// Yup, Savage 2000. |
|
hsStatusMessage( "== Using fudge factors for a Savage 2000 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a Savage 2000 chipset" ); |
|
ISetFudgeFactors( kSavage2000Chipset, record ); |
|
} |
|
/// Detect Savage3D chipset |
|
else if( deviceID == 0x00008a20 || |
|
stricmp( szDriver, "s3_6.dll" ) == 0 || |
|
strstr( desc, "savage3d" ) != nil ) |
|
{ |
|
/// Yup, Savage3D. |
|
hsStatusMessage( "== Using fudge factors for a Savage3D chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a Savage3D chipset" ); |
|
ISetFudgeFactors( kSavage3DChipset, record ); |
|
} |
|
/// Detect Generic S3 chipset |
|
else if( ( strncmp( szDriver, "s3", 2 ) == 0 ) || ( strstr( desc, "savage" ) != nil ) ) |
|
{ |
|
/// Yup, Generic S3. |
|
hsStatusMessage( "== Using fudge factors for a generic S3 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a generic S3 chipset" ); |
|
ISetFudgeFactors( kS3GenericChipset, record ); |
|
} |
|
|
|
//// ATI-based Cards ////////////////////////////////////////////////////// |
|
/// Detect ATI Rage 128 Pro chipset |
|
else if( ( deviceID == 0x00005046 && // Normal ATI Rage 128 Pro detection |
|
( stricmp( szDriver, "ati2dvaa.dll" ) == 0 |
|
|| strstr( desc, "rage 128 pro" ) != nil ) ) || |
|
( deviceID == 0x00005246 && // ATI All-in-wonder--same chipset, diff values |
|
( stricmp( szDriver, "ati3draa.dll" ) == 0 |
|
|| strstr( desc, "all-in-wonder 128" ) != nil ) ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an ATI Rage 128 Pro chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an ATI Rage 128 Pro chipset" ); |
|
ISetFudgeFactors( kATIRageProChipset, record ); |
|
} |
|
/// Detect(detest?) ATI Rage FURY MAXX chipset |
|
else if( deviceID == 0x00005046 && |
|
( stricmp( szDriver, "ati3drau.dll" ) == 0 |
|
|| strstr( desc, "rage fury" ) != nil ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an ATI Rage Fury MAXX chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an ATI Rage Fury MAXX chipset" ); |
|
ISetFudgeFactors( kATIRageFuryChipset, record ); |
|
} |
|
/// Detect ATI Radeon chipset |
|
// We will probably need to differentiate between different Radeons at some point in |
|
// the future, but not now. |
|
else if( // deviceID == 0x00005144 && |
|
( stricmp( szDriver, "ati2dvag.dll" ) == 0 |
|
|| strstr( desc, "radeon" ) != nil ) ) |
|
{ |
|
int series = 0; |
|
const char* str = strstr(desc, "radeon"); |
|
if( str ) |
|
str += strlen("radeon"); |
|
else |
|
{ |
|
str = strstr(desc, "all-in-wonder"); |
|
if( str ) |
|
str += strlen("all-in-wonder"); |
|
} |
|
if( str ) |
|
{ |
|
if( 1 == sscanf(str, "%d", &series) ) |
|
{ |
|
if( (series == 7500) || (series == 7200) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon 7200/7500 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for ATI Radeon 7200/7500 chipset" ); |
|
ISetFudgeFactors( kATIR7500Chipset, record ); |
|
} |
|
else |
|
if( (series >= 7000) && (series < 8000) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon 7X00 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for ATI Radeon 7X00 chipset" ); |
|
ISetFudgeFactors( kATIR7X00Chipset, record ); |
|
} |
|
else |
|
if( (series >= 8000) && (series < 9000) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon 8X00 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for ATI Radeon 8X00 chipset" ); |
|
ISetFudgeFactors( kATIR8X00Chipset, record ); |
|
} |
|
else |
|
{ |
|
series = 0; |
|
} |
|
} |
|
else |
|
{ |
|
series = 0; |
|
|
|
// Skip white space |
|
while( *str && (*str <= 0x32) ) |
|
str++; |
|
|
|
// I've still never seen either of these, so I'm just going by ATI's site. |
|
// Don't have the option of using device-id's. |
|
if( (str[0] == 'v') && (str[1] == 'e') ) |
|
{ |
|
// Got an alias here. If it's an All-in-Wonder VE, it's really a 7500. |
|
// If it's a Radeon VE, it's really a 7000. |
|
if( strstr(desc, "radeon") ) |
|
series = 7000; |
|
else if( strstr(desc, "all-in-wonder") ) |
|
series = 7500; |
|
} |
|
} |
|
} |
|
if( !series ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for ATI Radeon chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for ATI Radeon chipset" ); |
|
ISetFudgeFactors( kATIRadeonChipset, record ); |
|
} |
|
} |
|
/// Detect generic ATI chipset |
|
else if( ( strncmp( szDriver, "ati", 3 ) == 0 ) || ( strstr( desc, "ati " ) != nil ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a generic ATI chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a generic ATI chipset" ); |
|
ISetFudgeFactors( kATIGenericChipset, record ); |
|
} |
|
|
|
//// Matrox-based Cards /////////////////////////////////////////////////// |
|
else if( (deviceID == 0x527) |
|
|| strstr(desc, "parhelia") ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a Matrox Parhelia chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a Matrox Millenium G400 chipset" ); |
|
ISetFudgeFactors( kMatroxParhelia, record ); |
|
} |
|
/// Detect Matrox G400 chipset |
|
else if( deviceID == 0x00000525 && |
|
( stricmp( szDriver, "g400d.dll" ) == 0 |
|
|| ( strstr( desc, "matrox" ) != nil && strstr( desc, "g400" ) != nil ) ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a Matrox Millenium G400 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a Matrox Millenium G400 chipset" ); |
|
ISetFudgeFactors( kMatroxG400Chipset, record ); |
|
} |
|
/// Detect generic Matrox chipset |
|
else if( strstr( desc, "matrox" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a generic Matrox chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a generic Matrox chipset" ); |
|
ISetFudgeFactors( kMatroxGenericChipset, record ); |
|
} |
|
|
|
//// Other Cards ////////////////////////////////////////////////////////// |
|
/// Detect NVidia RIVA TNT chipset |
|
else if( deviceID == 0x00000020 && |
|
( stricmp( szDriver, "nvdd32.dll" ) == 0 |
|
|| strstr( desc, "nvidia riva tnt" ) != nil ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia RIVA TNT chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia RIVA TNT chipset" ); |
|
ISetFudgeFactors( kNVidiaTNTChipset, record ); |
|
if( record.GetMemoryBytes() < 16 * 1024 * 1024 ) |
|
{ |
|
hsStatusMessage( "== (also fudging memory up to 16MB) ==\n" ); |
|
plDemoDebugFile::Write( " (also fudging memory up to 16MB)" ); |
|
record.SetMemoryBytes( 16 * 1024 * 1024 ); |
|
} |
|
} |
|
/// Detect Intel i810 chipset |
|
else if( deviceID == 0x00007125 && |
|
( stricmp( szDriver, "i81xdd.dll" ) == 0 |
|
|| ( strstr( desc, "intel" ) != nil && strstr( desc, "810" ) != nil ) ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an Intel i810 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an Intel i810 chipset" ); |
|
ISetFudgeFactors( kIntelI810Chipset, record ); |
|
} |
|
/// Detect STMicroelectronics KYRO chipset |
|
else if( deviceID == 0x00000010 && ( strstr( desc, "kyro" ) != nil ) ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a KYRO chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a KYRO chipset" ); |
|
ISetFudgeFactors( kKYROChipset, record ); |
|
} |
|
/// Detect for a 3dfx Voodoo5 |
|
else if( vendorID == 0x121a && deviceID == 0x00000009 && |
|
stricmp( szDriver, "3dfxvs.dll" ) == 0 ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for a 3dfx Voodoo5 chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for a 3dfx Voodoo5 chipset" ); |
|
ISetFudgeFactors( k3dfxV5Chipset, record ); |
|
} |
|
/// Detect for a GeForce-class card. We can be loose here because we want |
|
/// to get ALL GeForce/2/256 cards |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce2" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForce2-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForce2-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForce2Chipset, record ); |
|
} |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce3" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForce3-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForce3-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForce3Chipset, record ); |
|
} |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce4 mx" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForce4MX-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForce4MX-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForce4MXChipset, record ); |
|
} |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce4" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForce4-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForce4-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForce4Chipset, record ); |
|
} |
|
else if( |
|
strstr( desc, "nvidia" ) && strstr( desc, "geforce" ) |
|
&& ( |
|
(deviceID == 0x101) |
|
||(deviceID == 0x100) |
|
||strstr(desc, "256") |
|
) |
|
) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForce-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForce-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForceChipset, record ); |
|
} |
|
else if( strstr( desc, "nvidia" ) != nil && strstr( desc, "geforce" ) != nil ) |
|
{ |
|
hsStatusMessage( "== Using fudge factors for an NVidia GeForceFX-based chipset ==\n" ); |
|
plDemoDebugFile::Write( " Using fudge factors for an NVidia GeForceFX-based chipset" ); |
|
ISetFudgeFactors( kNVidiaGeForceFXChipset, record ); |
|
} |
|
/// Detect for a TNT-based card and force it to >= 16MB memory, so we always use it |
|
else if( strstr( desc, "tnt" ) != nil && record.GetMemoryBytes() < 16 * 1024 * 1024 ) |
|
{ |
|
hsStatusMessage( "== NVidia TNT-based card detected. Fudging memory reading to 16MB ==\n" ); |
|
plDemoDebugFile::Write( " NVidia TNT-based card detected. Fudging memory reading to 16MB" ); |
|
record.SetMemoryBytes( 16 * 1024 * 1024 ); |
|
} |
|
|
|
/// Default fudge values |
|
else |
|
{ |
|
hsStatusMessage( "== Using default fudge factors ==\n" ); |
|
plDemoDebugFile::Write( " Using default fudge factors" ); |
|
ISetFudgeFactors( kDefaultChipset, record ); |
|
} |
|
} |
|
#endif |
|
|
|
//// ISetFudgeFactors ///////////////////////////////////////////////////////// |
|
// Given a chipset ID, looks the values up in the CFT and sets the appropriate |
|
// values. |
|
|
|
void hsG3DDeviceSelector::ISetFudgeFactors( UInt8 chipsetID, hsG3DDeviceRecord &record ) |
|
{ |
|
int i, maxIDs, j; |
|
|
|
|
|
maxIDs = sizeof( dsCFTable ) / sizeof( dsCFTable[ 0 ] ); |
|
|
|
/// Search for our chipset |
|
for( i = 0; i < maxIDs; i++ ) |
|
{ |
|
if( dsCFTable[ i ].fType == chipsetID ) |
|
{ |
|
/// Found it! |
|
|
|
// Flags to force set |
|
if( dsCFTable[ i ].fFlagsToSet != nil ) |
|
{ |
|
for( j = 0; j < dsCFTable[ i ].fFlagsToSet[ 0 ]; j++ ) |
|
record.SetCap( dsCFTable[ i ].fFlagsToSet[ j + 1 ] ); |
|
} |
|
|
|
// Flags to force clear |
|
if( dsCFTable[ i ].fFlagsToClear != nil ) |
|
{ |
|
for( j = 0; j < dsCFTable[ i ].fFlagsToClear[ 0 ]; j++ ) |
|
record.SetCap( dsCFTable[ i ].fFlagsToClear[ j + 1 ], false ); |
|
} |
|
|
|
// Suckiness |
|
record.SetZBiasRating( dsCFTable[ i ].fZSuckiness ); |
|
|
|
// Max # of layers |
|
if( dsCFTable[ i ].fForceMaxLayers > 0 ) |
|
record.SetLayersAtOnce( dsCFTable[ i ].fForceMaxLayers ); |
|
|
|
// LOD bias rating |
|
record.SetLODBiasRating( dsCFTable[ i ].fLODRating ); |
|
|
|
// Fog tweaks |
|
FogTweakTable *fogTweaks = dsCFTable[ i ].fFogTweaks; |
|
|
|
record.SetFogApproxStarts( fogTweaks->fFogExpApproxStart, fogTweaks->fFogExp2ApproxStart ); |
|
record.SetFogEndBias( fogTweaks->fFogEndBias ); |
|
record.SetFogKneeParams( hsG3DDeviceRecord::kFogExp, fogTweaks->fFogExpKnee, fogTweaks->fFogExpKneeVal ); |
|
record.SetFogKneeParams( hsG3DDeviceRecord::kFogExp2, fogTweaks->fFogExp2Knee, fogTweaks->fFogExp2KneeVal ); |
|
|
|
if( record.GetCap(kCapsNoAA) ) |
|
{ |
|
int j; |
|
for( j = 0; j < record.GetModes().GetCount(); j++ ) |
|
record.GetModes()[j].ClearFSAATypes(); |
|
} |
|
|
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Demo Debug File functions |
|
// Created 10.10.2000 by Mathew Burrack @ Cyan, Inc. |
|
// Modified 10.11 mcn to conform (more) to coding standards. |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// Local Globals //////////////////////////////////////////////////////////// |
|
|
|
#if M3DDEMOINFO // Demo Debug Build |
|
static plDemoDebugFile sMyDDFWriter; |
|
|
|
hsBool plDemoDebugFile::fIsOpen = false; |
|
FILE *plDemoDebugFile::fDemoDebugFP = nil; |
|
hsBool plDemoDebugFile::fEnabled = false; |
|
#endif |
|
|
|
|
|
//// IDDFOpen ///////////////////////////////////////////////////////////////// |
|
// Internal function--opens the demo debug file for writing. Returns true |
|
// if successful, false otherwise. |
|
|
|
hsBool plDemoDebugFile::IDDFOpen( void ) |
|
{ |
|
#if M3DDEMOINFO // Demo Debug Build |
|
char fileName[] = "log/debug_info.dat"; |
|
time_t currTime; |
|
struct tm *localTime; |
|
char timeString[ 27 ]; // see definition of asctime() |
|
char *c; |
|
|
|
|
|
/// Don't open if we're not enabled |
|
if( !fEnabled ) |
|
return false; |
|
|
|
/// Open the file |
|
if( fDemoDebugFP == nil ) |
|
fDemoDebugFP = fopen( fileName, "wt" ); |
|
|
|
if( fDemoDebugFP == nil ) |
|
return( fIsOpen = false ); |
|
|
|
/// Write out a header line |
|
time( &currTime ); |
|
localTime = localtime( &currTime ); |
|
|
|
// Note: asctime includes a carriage return. Gotta strip... |
|
strcpy( timeString, asctime( localTime ) ); |
|
c = strchr( timeString, '\n' ); |
|
if( c != nil ) |
|
*c = 0; |
|
|
|
fprintf( fDemoDebugFP, "\n--- Demo Debug Info File (Created %s) ---\n", timeString ); |
|
|
|
/// All done! |
|
return( fIsOpen = true ); |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
//// IDDFClose //////////////////////////////////////////////////////////////// |
|
// "Whatcha gonna do when the lightning strikes and hits you...." |
|
// -- "Lightning Strikes", Yes, 1999 |
|
|
|
|
|
void plDemoDebugFile::IDDFClose( void ) |
|
{ |
|
#if M3DDEMOINFO // Demo Debug Build |
|
if( fDemoDebugFP != nil ) |
|
{ |
|
// Write an exit line (fun fun) |
|
fputs( "--- End of Demo Debug Info File ---\n\n", fDemoDebugFP ); |
|
|
|
// Close |
|
fclose( fDemoDebugFP ); |
|
} |
|
|
|
fIsOpen = false; |
|
#endif |
|
} |
|
|
|
//// Write //////////////////////////////////////////////////////////////////// |
|
// Writes a string to the DDF. If the DDF isn't open, opens it. |
|
|
|
void plDemoDebugFile::Write( char *string ) |
|
{ |
|
#if M3DDEMOINFO // Demo Debug Build |
|
if( !fIsOpen ) |
|
IDDFOpen(); |
|
|
|
if( fIsOpen ) |
|
fprintf( fDemoDebugFP, "%s\n", string ); |
|
#endif |
|
} |
|
|
|
void plDemoDebugFile::Write( char *string1, char *string2 ) |
|
{ |
|
#if M3DDEMOINFO // Demo Debug Build |
|
if( !fIsOpen ) |
|
IDDFOpen(); |
|
|
|
if( fIsOpen ) |
|
fprintf( fDemoDebugFP, "%s: %s\n", string1, string2 ); |
|
#endif |
|
} |
|
|
|
void plDemoDebugFile::Write( char *string1, Int32 value ) |
|
{ |
|
#if M3DDEMOINFO // Demo Debug Build |
|
if( !fIsOpen ) |
|
IDDFOpen(); |
|
|
|
if( fIsOpen ) |
|
fprintf( fDemoDebugFP, "%s: %d (0x%x)\n", string1, value, value ); |
|
#endif |
|
} |
|
|
|
|