/*==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 . 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 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 &recs = fSelector.GetDeviceRecords(); for (Int32 i = 0; i < recs.Count(); i++) { hsTArray &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 ]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& 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& 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& 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& 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& 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; }