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.
587 lines
15 KiB
587 lines
15 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==*/ |
|
#include "hsTypes.h" |
|
#include "plDeviceSelector.h" |
|
#include "hsStream.h" |
|
#include "hsUtils.h" |
|
|
|
#include <algorithm> |
|
|
|
DeviceSelector::DeviceSelector() : |
|
fSelDevType(hsG3DDeviceSelector::kDevTypeUnknown), |
|
fSelDev(0), |
|
fSelMode(0), |
|
fDevDesc(0), |
|
fModeDesc(0), |
|
fPerformance(0), |
|
fFilterBPP(0), |
|
fFilterWidth(0), |
|
fFilterHeight(0), |
|
fWindowed(false) |
|
{ |
|
memset(fStr, 0x00, sizeof(fStr)); |
|
} |
|
|
|
const char *DeviceSelector::GetErrorString( void ) |
|
{ |
|
return fSelector.GetErrorString(); |
|
} |
|
|
|
hsBool DeviceSelector::Enumerate(HWND hWnd, hsBool expertMode ) |
|
{ |
|
plDemoDebugFile::Enable( true ); /// ALWAYS enable (well, for now at least) |
|
|
|
if( !fSelector.Init() ) |
|
return false; |
|
|
|
fSelector.Enumerate(hWnd); |
|
|
|
// 11.25.2000 mcn - Now we are tough if we're not in expert mode |
|
fSelector.RemoveUnusableDevModes( !expertMode ); |
|
|
|
// Sort the modes |
|
hsTArray<hsG3DDeviceRecord> &recs = fSelector.GetDeviceRecords(); |
|
for (Int32 i = 0; i < recs.Count(); i++) |
|
{ |
|
hsTArray<hsG3DDeviceMode> &modes = recs[i].GetModes(); |
|
std::sort(modes.FirstIter(), modes.StopIter()); |
|
} |
|
|
|
IRefreshFilter(); |
|
|
|
return true; |
|
} |
|
|
|
void DeviceSelector::SetModeFilter( int bitDepth, int minWidth, int minHeight ) |
|
{ |
|
fFilterBPP = bitDepth; |
|
fFilterWidth = minWidth; |
|
fFilterHeight = minHeight; |
|
|
|
IRefreshFilter(); |
|
} |
|
|
|
void DeviceSelector::IRefreshFilter( void ) |
|
{ |
|
if (fSelDev >= fRecords.Count() ) |
|
return; |
|
|
|
// Make sure to preserve fSelMode if possible |
|
const hsG3DDeviceMode *oldMode = nil; |
|
if( fSelMode < fFilteredModes.GetCount() && fFilteredModes[ fSelMode ]<fSelRec.GetModes().GetCount() ) |
|
oldMode = fSelRec.GetMode( fFilteredModes[ fSelMode ] ); |
|
|
|
fFilteredModes.Reset(); |
|
|
|
int i; |
|
for( i = 0; i < fRecords[ fSelDev ].GetModes().Count(); i++ ) |
|
{ |
|
hsG3DDeviceMode* mode = fRecords[ fSelDev ].GetMode( i ); |
|
|
|
// Filter out modes we don't want listed |
|
if( fFilterBPP != 0 && fFilterBPP != mode->GetColorDepth() ) |
|
continue; |
|
|
|
if( mode->GetWidth() < fFilterWidth || mode->GetHeight() < fFilterHeight ) |
|
continue; |
|
|
|
// Remove any non 4:3 modes |
|
bool goodAspectRatio = (mode->GetWidth() / 4 == mode->GetHeight() / 3) && |
|
(mode->GetWidth() % 4 == 0) && |
|
(mode->GetHeight() % 3 == 0); |
|
|
|
if (!goodAspectRatio && !(mode->GetWidth() == 1280 && mode->GetHeight() == 1024)) |
|
{ |
|
continue; |
|
} |
|
|
|
// Add the remaining to our filter index |
|
fFilteredModes.Append( i ); |
|
} |
|
|
|
if( oldMode != nil ) |
|
{ |
|
fSelMode = IFindFiltered( GetModeNum( oldMode ) ); |
|
if( fSelMode == -1 ) |
|
{ |
|
// Try w/o bpp |
|
fSelMode = IFindFiltered( IGetModeNumNoBPP( oldMode ) ); |
|
if( fSelMode == -1 ) |
|
fSelMode = 0; |
|
} |
|
} |
|
else |
|
fSelMode = 0; |
|
|
|
} |
|
|
|
int DeviceSelector::IFindFiltered( int realIndex ) |
|
{ |
|
int idx = fFilteredModes.Find( realIndex ); |
|
if( idx == fFilteredModes.kMissingIndex ) |
|
return -1; |
|
|
|
return idx; |
|
} |
|
|
|
hsBool DeviceSelector::CheckDeviceType(UInt32 type) |
|
{ |
|
hsTArray<hsG3DDeviceRecord>& records = fSelector.GetDeviceRecords(); |
|
|
|
for (Int32 i = 0; i < records.Count(); i++) |
|
{ |
|
if (type == records[i].GetG3DDeviceType()) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::IsDirect3DAvailable() |
|
{ |
|
return CheckDeviceType(hsG3DDeviceSelector::kDevTypeDirect3D); |
|
} |
|
|
|
hsBool DeviceSelector::IsDirect3DTnLAvailable() |
|
{ |
|
return CheckDeviceType(hsG3DDeviceSelector::kDevTypeDirect3DTnL); |
|
} |
|
|
|
hsBool DeviceSelector::IsGlideAvailable() |
|
{ |
|
return CheckDeviceType(hsG3DDeviceSelector::kDevTypeGlide); |
|
} |
|
|
|
hsBool DeviceSelector::IsOpenGLAvailable() |
|
{ |
|
return CheckDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); |
|
} |
|
|
|
void DeviceSelector::SetDirect3D() |
|
{ |
|
SetDeviceType(hsG3DDeviceSelector::kDevTypeDirect3D); |
|
} |
|
|
|
void DeviceSelector::SetDirect3DTnL() |
|
{ |
|
SetDeviceType(hsG3DDeviceSelector::kDevTypeDirect3DTnL); |
|
} |
|
|
|
void DeviceSelector::SetGlide() |
|
{ |
|
SetDeviceType(hsG3DDeviceSelector::kDevTypeGlide); |
|
} |
|
|
|
void DeviceSelector::SetOpenGL() |
|
{ |
|
SetDeviceType(hsG3DDeviceSelector::kDevTypeOpenGL); |
|
} |
|
|
|
void DeviceSelector::SetDeviceType (UInt32 type) |
|
{ |
|
Int32 i; |
|
for(i = 0; i < fRecords.GetCount(); i++) |
|
fRecords[i].Clear(); |
|
fRecords.Reset(); |
|
|
|
hsTArray<hsG3DDeviceRecord>& records = fSelector.GetDeviceRecords(); |
|
for (i = 0; i < records.Count(); i++) |
|
{ |
|
if (records[i].GetG3DDeviceType() == type) |
|
fRecords.Push(records[i]); |
|
} |
|
|
|
fSelDevType = type; |
|
fSelDev = 0; |
|
fDevDesc = 0; |
|
fModeDesc = 0; |
|
|
|
IRefreshFilter(); |
|
} |
|
|
|
hsBool DeviceSelector::IsDirect3D() |
|
{ |
|
if (fSelDevType == hsG3DDeviceSelector::kDevTypeDirect3D) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::IsDirect3DTnL() |
|
{ |
|
return ( fSelDevType == hsG3DDeviceSelector::kDevTypeDirect3DTnL ) ? true : false; |
|
} |
|
|
|
hsBool DeviceSelector::IsGlide() |
|
{ |
|
if (fSelDevType == hsG3DDeviceSelector::kDevTypeGlide) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::IsOpenGL() |
|
{ |
|
if (fSelDevType == hsG3DDeviceSelector::kDevTypeOpenGL) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::SetDevice(UInt32 index) |
|
{ |
|
if (index < fRecords.Count()) |
|
{ |
|
fSelDev = index; |
|
fSelMode = 0; |
|
fSelRec = fRecords[index]; |
|
fSelRec.SetMaxAnisotropicSamples(0); |
|
|
|
IRefreshFilter(); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::SetMode(UInt32 index) |
|
{ |
|
if (fSelDev >= fRecords.Count()) |
|
return false; |
|
|
|
if (index < fFilteredModes.GetCount()) |
|
{ |
|
fSelMode = index; |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
char* DeviceSelector::GetDeviceDescription() |
|
{ |
|
if (fDevDesc == fRecords.Count()) |
|
{ |
|
fDevDesc = 0; |
|
return nil; |
|
} |
|
|
|
sprintf(fStr, "%s [%s]", fRecords[fDevDesc].GetDriverDesc(), fRecords[fDevDesc].GetDeviceDesc()); |
|
fDevDesc++; |
|
return fStr; |
|
} |
|
|
|
char* DeviceSelector::GetModeDescription( void ) |
|
{ |
|
if (fSelDev >= fRecords.Count() ) |
|
return nil; |
|
|
|
if (fModeDesc == fFilteredModes.GetCount()) |
|
{ |
|
fModeDesc = 0; |
|
return nil; |
|
} |
|
|
|
hsG3DDeviceMode* mode = fRecords[fSelDev].GetMode( fFilteredModes[ fModeDesc ] ); |
|
fModeDesc++; |
|
|
|
if( fFilterBPP != 0 ) |
|
sprintf( fStr, "%ux%u", mode->GetWidth(), mode->GetHeight() ); |
|
else |
|
sprintf(fStr, "%ux%u %u bit", mode->GetWidth(), mode->GetHeight(), mode->GetColorDepth()); |
|
|
|
return fStr; |
|
} |
|
|
|
UInt32 DeviceSelector::GetNumModes() |
|
{ |
|
return fFilteredModes.GetCount(); |
|
} |
|
|
|
void DeviceSelector::GetMode(UInt32 i, int& width, int& height, int& depth) |
|
{ |
|
if (i >= fFilteredModes.GetCount()) |
|
return; |
|
|
|
hsG3DDeviceMode* mode = fRecords[fSelDev].GetMode(fFilteredModes[i]); |
|
|
|
width = mode->GetWidth(); |
|
height = mode->GetHeight(); |
|
depth = mode->GetColorDepth(); |
|
} |
|
|
|
hsBool DeviceSelector::SetDefault() |
|
{ |
|
hsG3DDeviceModeRecord dmr; |
|
if (fSelector.GetDefault(&dmr)) |
|
{ |
|
SetDeviceType(dmr.GetDevice()->GetG3DDeviceType()); |
|
fSelDev = GetDeviceNum(dmr.GetDevice()); |
|
fSelMode = IFindFiltered( GetModeNum(dmr.GetMode()) ); |
|
fSelRec = fRecords[fSelDev]; |
|
fSelRec.SetMaxAnisotropicSamples( 0 ); // Also off unless explicitly requested |
|
|
|
// Set a default detail level based on the available memory |
|
if (hsMemorySpec() == kBlows) |
|
fPerformance = 25; |
|
else |
|
fPerformance = 100; |
|
|
|
IRefreshFilter(); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
hsBool DeviceSelector::Save() |
|
{ |
|
hsUNIXStream stream; |
|
if (!stream.Open(DEV_MODE_DAT, "wb")) |
|
return false; |
|
|
|
hsG3DDeviceRecord selRec = fSelRec; |
|
hsG3DDeviceMode selMode = *(selRec.GetMode( fFilteredModes[ fSelMode ] )); |
|
selRec.ClearModes(); |
|
|
|
selRec.Write(&stream); |
|
|
|
if (fWindowed) |
|
selMode.SetColorDepth(0); |
|
selMode.Write(&stream); |
|
|
|
stream.WriteSwap16(fPerformance); |
|
|
|
stream.Close(); |
|
|
|
return true; |
|
} |
|
|
|
hsBool DeviceSelector::Load() |
|
{ |
|
hsUNIXStream stream; |
|
if (!stream.Open(DEV_MODE_DAT, "rb")) |
|
return false; |
|
|
|
hsG3DDeviceRecord LoadRec; // Device copy for reading/writing |
|
hsG3DDeviceMode LoadMode; // Modes copy for reading/writing |
|
|
|
LoadRec.Read(&stream); |
|
if (LoadRec.IsInvalid()) |
|
{ |
|
stream.Close(); |
|
return false; |
|
} |
|
|
|
LoadMode.Read(&stream); |
|
|
|
fPerformance = stream.ReadSwap16(); |
|
|
|
stream.Close(); |
|
|
|
// If selected device is available use it, otherwise return false |
|
if ((LoadRec.GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3D) && IsDirect3DAvailable()) |
|
SetDirect3D(); |
|
else if ((LoadRec.GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeDirect3DTnL) && IsDirect3DTnLAvailable()) |
|
SetDirect3DTnL(); |
|
else if ((LoadRec.GetG3DDeviceType() == hsG3DDeviceSelector::kDevTypeGlide) && IsGlideAvailable()) |
|
SetGlide(); |
|
else |
|
return false; |
|
|
|
//////////////////////////////////////////////////////////////////////////// |
|
// Attempt to match the saved device and mode to the ones that are currently |
|
// available. |
|
//////////////////////////////////////////////////////////////////////////// |
|
int num = GetDeviceNum(&LoadRec); |
|
if (num == -1) |
|
return false; |
|
SetDevice(num); |
|
|
|
// Copy the flags |
|
fSelRec.SetCap(hsG3DDeviceSelector::kCapsCompressTextures, |
|
LoadRec.GetCap(hsG3DDeviceSelector::kCapsCompressTextures)); |
|
fSelRec.SetAASetting( LoadRec.GetAASetting() ); |
|
fSelRec.SetMaxAnisotropicSamples( LoadRec.GetMaxAnisotropicSamples() ); |
|
|
|
if (LoadMode.GetColorDepth() == 0) |
|
{ |
|
fWindowed = true; |
|
LoadMode.SetColorDepth(32); |
|
} |
|
num = GetModeNum(&LoadMode); |
|
if (num == -1) |
|
return false; |
|
|
|
SetMode(IFindFiltered(num)); |
|
|
|
return true; |
|
} |
|
|
|
int DeviceSelector::GetDeviceNum(const hsG3DDeviceRecord *pLoadRec) |
|
{ |
|
hsTArray<hsG3DDeviceRecord>& records = fRecords; |
|
|
|
for (int i = 0; i < records.Count(); i++) |
|
{ |
|
if (!strcmp(records[i].GetDriverDesc(), pLoadRec->GetDriverDesc()) && |
|
!strcmp(records[i].GetDriverName(), pLoadRec->GetDriverName()) && |
|
!strcmp(records[i].GetDriverVersion(), pLoadRec->GetDriverVersion()) && |
|
!strcmp(records[i].GetDeviceDesc(), pLoadRec->GetDeviceDesc())) |
|
return i; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
int DeviceSelector::IGetModeNumNoBPP( const hsG3DDeviceMode *pLoadMode ) |
|
{ |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[fSelDev].GetModes(); |
|
|
|
for (int i = 0; i < modes.Count(); i++) |
|
{ |
|
if ((modes[i].GetWidth() == pLoadMode->GetWidth()) && |
|
(modes[i].GetHeight() == pLoadMode->GetHeight()) |
|
) |
|
{ |
|
if( fFilteredModes.Find( i ) != fFilteredModes.kMissingIndex ) |
|
{ |
|
#ifndef M3DRELEASE |
|
if (pLoadMode->GetColorDepth() == 0) |
|
fSelRec.GetMode( i )->SetColorDepth(0); |
|
#endif |
|
return i; |
|
} |
|
} |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
int DeviceSelector::GetModeNum(const hsG3DDeviceMode *pLoadMode) |
|
{ |
|
hsTArray<hsG3DDeviceMode>& modes = fRecords[fSelDev].GetModes(); |
|
|
|
for (int i = 0; i < modes.Count(); i++) |
|
{ |
|
if ((modes[i].GetWidth() == pLoadMode->GetWidth()) && |
|
(modes[i].GetHeight() == pLoadMode->GetHeight()) && |
|
(modes[i].GetColorDepth() == pLoadMode->GetColorDepth())) |
|
{ |
|
return i; |
|
} |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
UInt8 DeviceSelector::CanAntiAlias() |
|
{ |
|
hsG3DDeviceMode *mode = fRecords[ fSelDev ].GetMode( fFilteredModes[ fSelMode ] ); |
|
|
|
return mode->GetNumFSAATypes(); |
|
} |
|
|
|
UInt8 DeviceSelector::IsAntiAliased() |
|
{ |
|
return fSelRec.GetAASetting(); |
|
} |
|
|
|
void DeviceSelector::SetAntiAlias(UInt8 numSamples) |
|
{ |
|
fSelRec.SetAASetting( numSamples ); |
|
} |
|
|
|
UInt8 DeviceSelector::CanAnisotropicFilter() |
|
{ |
|
UInt8 hi = fRecords[ fSelDev ].GetMaxAnisotropicSamples(); |
|
if( hi > 1 ) |
|
return hi; |
|
|
|
return 0; |
|
} |
|
|
|
UInt8 DeviceSelector::GetAnisotropicLevel() |
|
{ |
|
return fSelRec.GetMaxAnisotropicSamples(); |
|
} |
|
|
|
void DeviceSelector::SetAnisotropicLevel( UInt8 level ) |
|
{ |
|
fSelRec.SetMaxAnisotropicSamples( level ); |
|
} |
|
|
|
bool DeviceSelector::CanWindow () |
|
{ |
|
return !fSelRec.GetCap(hsG3DDeviceSelector::kCapsNoWindow); |
|
} |
|
|
|
bool DeviceSelector::IsWindowed() |
|
{ |
|
return fWindowed; |
|
} |
|
|
|
void DeviceSelector::SetWindowed(bool state) |
|
{ |
|
fWindowed = state; |
|
} |
|
|
|
hsBool DeviceSelector::CanCompress () |
|
{ |
|
return fRecords[fSelDev].GetCap(hsG3DDeviceSelector::kCapsCompressTextures); |
|
} |
|
|
|
hsBool DeviceSelector::IsCompressed() |
|
{ |
|
return fSelRec.GetCap(hsG3DDeviceSelector::kCapsCompressTextures); |
|
} |
|
|
|
void DeviceSelector::SetCompressed(hsBool state) |
|
{ |
|
fSelRec.SetCap(hsG3DDeviceSelector::kCapsCompressTextures, state); |
|
} |
|
|
|
bool DeviceSelector::GetCap(UInt32 cap) |
|
{ |
|
return fSelRec.GetCap(cap) != 0; |
|
}
|
|
|