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.
 
 
 
 
 

571 lines
14 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/>.
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;
}