5 1 new backport x11 fs rework (#1485)
* Use XRandR 1.2 to set fullscreen resolution for single output Squash of roothorick's PR #497 (also includes Kyzentun's CMake changes from PR #716) * Cherry-pick json c++1x stuff (b9e3d7174e) * Cherry-pick c++11 support from 5bba5c0038 and 9f8b045309 * rework Linux (X11) fullscreen, improve display-related Graphics Options Implement option to select between monitors for exclusive fullscreen mode on X11 (using XRandR 1.2), or use a fullscreen borderless window. Reimplement resolution/refresh rate/display mode-related option rows using Lua, update choices dynamically so only known-good groupings of resolution/refresh rate/aspect ratio can be selected. Minimally update Windows/MacOS LowLevelWindow implementations to support changes made for Linux side. Fullscreen Borderless Window/multi monitor support from X11 not implemented for those in this commit. * allow forcibly disabling xinerama use on Linux When libXinerama is available, SM tries to use it to find the proper monitor indexes to use to set _NET_WM_FULLSCREEN_MONITORS (on borderless fullscreen). xfwm4 seems to assume that monitors are numbered in increasing order from left to right (rather than using the Xinerama-assigned numbers), so _NET_WM_FULLSCREEN_MONITORS misbehaves on Xfce. This commit bypasses use of libXinerama, and instead forces SM to induce fullscreen on the desired monitor in the backup, hacky way: remove all window hints, move window to desired monitor, then add _NET_WM_STATE_FULLSCREEN hint. This works on mutter and Xfce. * Remove multiple warnings on redundant define. This used to be hard-coded due to pthread related items, but now it's dynamically determined. * fix _fallback menu behavior for unrecognized aspect ratios * Fix error recreating existing FS texture * Bump deployment target to 10.7 to use libc++ on XCode 8 * Add explicit casts to please clang * Update changelog
This commit is contained in:
committed by
Colby Klein
parent
7ef14c340d
commit
557be7cf1b
@@ -27,7 +27,13 @@ function(sm_add_compile_definition target def)
|
||||
endfunction()
|
||||
|
||||
function(sm_add_compile_flag target flag)
|
||||
sm_append_simple_target_property(${target} COMPILE_FLAGS ${flag})
|
||||
get_target_property(current_property ${target} COMPILE_FLAGS)
|
||||
if (current_property)
|
||||
set(current_property "${current_property} ${flag}")
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${current_property}")
|
||||
else()
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS ${flag})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(sm_add_link_flag target flag)
|
||||
|
||||
@@ -68,4 +68,5 @@ elseif(LINUX)
|
||||
option(WITH_GTK2 "Build with GTK2 Support." ON)
|
||||
option(WITH_PARALLEL_PORT "Build with Parallel Lights I/O Support." OFF)
|
||||
option(WITH_CRASH_HANDLER "Build with Crash Handler Support." ON)
|
||||
option(WITH_XINERAMA "Build using libXinerama to query for monitor numbers (if available)." ON)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# This is borrowed from FreeRDP.
|
||||
# - Find XINERAMA
|
||||
# Find the XINERAMA libraries
|
||||
#
|
||||
# This module defines the following variables:
|
||||
# XINERAMA_FOUND - true if XINERAMA_INCLUDE_DIR & XINERAMA_LIBRARY are found
|
||||
# XINERAMA_LIBRARIES - Set when XINERAMA_LIBRARY is found
|
||||
# XINERAMA_INCLUDE_DIRS - Set when XINERAMA_INCLUDE_DIR is found
|
||||
#
|
||||
# XINERAMA_INCLUDE_DIR - where to find Xinerama.h, etc.
|
||||
# XINERAMA_LIBRARY - the XINERAMA library
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#=============================================================================
|
||||
|
||||
find_path(XINERAMA_INCLUDE_DIR NAMES X11/extensions/Xinerama.h
|
||||
PATHS /opt/X11/include
|
||||
PATH_SUFFIXES X11/extensions
|
||||
DOC "The Xinerama include directory"
|
||||
)
|
||||
|
||||
find_library(XINERAMA_LIBRARY NAMES Xinerama
|
||||
PATHS /opt/X11/lib
|
||||
DOC "The Xinerama library"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xinerama DEFAULT_MSG XINERAMA_LIBRARY XINERAMA_INCLUDE_DIR)
|
||||
|
||||
if(XINERAMA_FOUND)
|
||||
set( XINERAMA_LIBRARIES ${XINERAMA_LIBRARY} )
|
||||
set( XINERAMA_INCLUDE_DIRS ${XINERAMA_INCLUDE_DIR} )
|
||||
endif()
|
||||
|
||||
mark_as_advanced(XINERAMA_INCLUDE_DIR XINERAMA_LIBRARY)
|
||||
|
||||
@@ -3,6 +3,11 @@ ________________________________________________________________________________
|
||||
The StepMania 5.1 Changelog covers all post-5.0.12 changes.
|
||||
________________________________________________________________________________
|
||||
|
||||
2017/06/18
|
||||
----------
|
||||
* [RageDisplay, LLW_X11] Backport fullscreen borderless window, per-monitor
|
||||
fullscreen options to X11 backend
|
||||
|
||||
2017/06/06
|
||||
----------
|
||||
* [General] Backport custom song support. [kyzentun]
|
||||
|
||||
@@ -744,6 +744,23 @@
|
||||
<Function name='get_dirty'/>
|
||||
<Function name='destroy'/>
|
||||
</Class>
|
||||
<Class name='DisplayMode'>
|
||||
<Function name='GetWidth'/>
|
||||
<Function name='GetHeight'/>
|
||||
<Function name='GetRefreshRate'/>
|
||||
</Class>
|
||||
<Class name='DisplaySpec'>
|
||||
<Function name='GetId'/>
|
||||
<Function name='GetName'/>
|
||||
<Function name='GetCurrentMode'/>
|
||||
<Function name='GetSupportedModes'/>
|
||||
<Function name='IsVirtual'/>
|
||||
</Class>
|
||||
<Class name='DisplaySpecs'>
|
||||
<Function name='__len'/>
|
||||
<Function name='__index'/>
|
||||
<Function name='__tostring'/>
|
||||
</Class>
|
||||
<Class base='Sprite' name='DifficultyIcon'>
|
||||
<Function name='SetFromDifficulty'/>
|
||||
<Function name='SetFromSteps'/>
|
||||
@@ -1480,8 +1497,11 @@
|
||||
<Function name='GetCumFPS'/>
|
||||
<Function name='GetDisplayHeight'/>
|
||||
<Function name='GetDisplayWidth'/>
|
||||
<Function name='GetDisplaySpecs'/>
|
||||
<Function name='GetFPS'/>
|
||||
<Function name='GetVPF'/>
|
||||
<Function name='SupportsFullscreenBorderlessWindow'/>
|
||||
<Function name='SupportsRenderToTexture'/>
|
||||
</Class>
|
||||
<Class name='RageFile'>
|
||||
<Function name='AtEOF'/>
|
||||
@@ -2479,6 +2499,15 @@
|
||||
<EnumValue name=''NoteType_64th'' value='7'/>
|
||||
<EnumValue name=''NoteType_192nd'' value='8'/>
|
||||
</Enum>
|
||||
<Enum name='OptEffect'>
|
||||
<EnumValue name=''OptEffect_SavePreferences'' value='1'/>
|
||||
<EnumValue name=''OptEffect_ApplyGraphics'' value='2'/>
|
||||
<EnumValue name=''OptEffect_ApplyTheme'' value='4'/>
|
||||
<EnumValue name=''OptEffect_ChangeGame'' value='8'/>
|
||||
<EnumValue name=''OptEffect_ApplySound'' value='16'/>
|
||||
<EnumValue name=''OptEffect_ApplySong'' value='32'/>
|
||||
<EnumValue name=''OptEffect_ApplyAspectRatio'' value='64'/>
|
||||
</Enum>
|
||||
<Enum name='PaneCategory'>
|
||||
<EnumValue name=''PaneCategory_NumSteps'' value='0'/>
|
||||
<EnumValue name=''PaneCategory_Jumps'' value='1'/>
|
||||
@@ -2566,6 +2595,11 @@
|
||||
<EnumValue name=''RankingType_Category'' value='0'/>
|
||||
<EnumValue name=''RankingType_Course'' value='1'/>
|
||||
</Enum>
|
||||
<Enum name='ReloadChanged'>
|
||||
<EnumValue name=''ReloadChanged_None'' value='0'/>
|
||||
<EnumValue name=''ReloadChanged_Enabled'' value='1'/>
|
||||
<EnumValue name=''ReloadChanged_All'' value='2'/>
|
||||
</Enum>
|
||||
<Enum name='SampleMusicPreviewMode'>
|
||||
<EnumValue name=''SampleMusicPreviewMode_Normal'' value='0'/>
|
||||
<EnumValue name=''SampleMusicPreviewMode_StartToPreview'' value='1'/>
|
||||
@@ -2800,6 +2834,7 @@
|
||||
<Constants>
|
||||
<Constant name='ASPECT_SCALE_FACTOR' value='854'/>
|
||||
<Constant name='NUM_PLAYERS' value='2'/>
|
||||
<Constant name='REFRESH_DEFAULT'/>
|
||||
<Constant name='SAFE_HEIGHT' value='36'/>
|
||||
<Constant name='SAFE_WIDTH' value='64'/>
|
||||
<Constant name='SCREEN_BOTTOM' value='480'/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
save yourself some time, copy this for undocumented things:
|
||||
<Function name='' return='' arguments=''>
|
||||
|
||||
|
||||
</Function>
|
||||
-->
|
||||
|
||||
@@ -451,7 +451,7 @@ save yourself some time, copy this for undocumented things:
|
||||
Returns a formatted percent with the specified <code>num</code>erator and <code>den</code>ominator.
|
||||
</Function>
|
||||
<Function name='print' theme='_fallback' return='void' arguments='string s'>
|
||||
[00 init.lua]
|
||||
[00 init.lua]
|
||||
</Function>
|
||||
<Function name='PrintTable' theme='_fallback' return='void' arguments='table t'>
|
||||
[03 ThemePrefs.lua] Prints a table's contents to the log.
|
||||
@@ -568,7 +568,7 @@ save yourself some time, copy this for undocumented things:
|
||||
[03 UserPreferences2.lua] Themer-facing function for setting a user preference.
|
||||
</Function>
|
||||
<Function name='ShowHoldJudgments' theme='_fallback' return='bool' arguments=''>
|
||||
[03 Gameplay.lua]
|
||||
[03 Gameplay.lua]
|
||||
</Function>
|
||||
<Function name='ShowStandardDecoration' theme='_fallback' return='bool' arguments='string sMetricsName'>
|
||||
[02 ActorDef.lua] Returns <code>true</code> if a decoration should be shown on the current screen or not.
|
||||
@@ -586,13 +586,13 @@ save yourself some time, copy this for undocumented things:
|
||||
[02 Colors.lua]
|
||||
</Function>
|
||||
<Function name='StandardDecorationFromTable' theme='_fallback' return='Actor' arguments='string sMetricsName, table t'>
|
||||
[02 ActorDef.lua]
|
||||
[02 ActorDef.lua]
|
||||
</Function>
|
||||
<Function name='StandardDecorationFromFile' theme='_fallback' return='Actor' arguments='string sMetricsName, string sFileName'>
|
||||
[02 ActorDef.lua]
|
||||
[02 ActorDef.lua]
|
||||
</Function>
|
||||
<Function name='StandardDecorationFromFileOptional' theme='_fallback' return='Actor' arguments='string sMetricsName, string sFileName'>
|
||||
[02 ActorDef.lua]
|
||||
[02 ActorDef.lua]
|
||||
</Function>
|
||||
<Function name='tableshuffle' theme='_fallback' return='table' arguments='table t'>
|
||||
[02 Utilities.lua] Returns a shuffled version of <code>t</code>.
|
||||
@@ -760,7 +760,7 @@ save yourself some time, copy this for undocumented things:
|
||||
<Function name='GetZoom' return='float' arguments='PlayerState ps'>
|
||||
Returns the zoom of a note for the provided PlayerState.
|
||||
</Function>
|
||||
<Function name='GetFrameWidthScale' return='float' arguments='PlayerState ps, float fYOffset, fOverlappedTime'>
|
||||
<Function name='GetFrameWidthScale' return='float' arguments='PlayerState ps, float fYOffset, float fOverlappedTime'>
|
||||
Returns the FrameWidthScale of a hold part with a Y offset of <code>fYOffset</code> for the provided PlayerState.<br/> <code>fOverlappedTime</code> is optional and will default to 0.
|
||||
</Function>
|
||||
</Namespace>
|
||||
@@ -776,7 +776,7 @@ save yourself some time, copy this for undocumented things:
|
||||
of <code>Enum</code>. Instead of
|
||||
<code><Link function='GetName'>Enum.GetName</Link>(
|
||||
<Link class='ENUM' function='PlayerNumber' /> )</code> or
|
||||
<code><Link function='Reverse'>Enum.Reverse</Link>(
|
||||
<code><Link function='Reverse'>Enum.Reverse</Link>(
|
||||
<Link class='ENUM' function='PlayerNumber' /> )</code>, one can use
|
||||
<code><Link class='ENUM' function='PlayerNumber' />:<!--
|
||||
--><Link function='GetName'>GetName</Link>()</code> or
|
||||
@@ -2353,6 +2353,61 @@ save yourself some time, copy this for undocumented things:
|
||||
Blanks the DifficultyIcon.
|
||||
</Function>
|
||||
</Class>
|
||||
<Class name='DisplayMode'>
|
||||
<Function name='GetWidth' return='int' arguments=''>
|
||||
Return the width of the display in this mode.
|
||||
</Function>
|
||||
<Function name='GetWidth' return='int' arguments=''>
|
||||
Return the height of the display in this mode.
|
||||
</Function>
|
||||
<Function name='GetRefreshRate' return='float' arguments=''>
|
||||
Return the refresh rate of the display in this mode.
|
||||
</Function>
|
||||
</Class>
|
||||
<Class name='DisplaySpec'>
|
||||
<Description>
|
||||
An object describing a display: its supported and current video modes.
|
||||
</Description>
|
||||
<Function name='GetId' return='string' arguments=''>
|
||||
Return the unique identifier of the display.
|
||||
</Function>
|
||||
<Function name='GetName' return='string' arguments=''>
|
||||
Return the "human-readable" display name.
|
||||
</Function>
|
||||
<Function name='GetSupportedModes' return='{DisplayMode}' arguments=''>
|
||||
Return the <Link class='DisplayMode' />s supported by this device.
|
||||
</Function>
|
||||
<Function name='GetCurrentMode' return='DisplayMode' arguments=''>
|
||||
Return the currently active <Link class='DisplayMode' /> for this display,
|
||||
or <code>nil</code> if there is no such mode.
|
||||
</Function>
|
||||
<Function name='IsVirtual' return='bool' arguments=''>
|
||||
Return <code>true</code> if this <code>DisplaySpec</code> is describing the
|
||||
"logical display" like an X screen or the Win32 "Virtual screen", or
|
||||
<code>false</code> otherwise (if this describes a physical display).
|
||||
</Function>
|
||||
</Class>
|
||||
<Class name='DisplaySpecs'>
|
||||
<Description>
|
||||
An array-like <code>userdata</code> object which describes the displays
|
||||
configured on the user's machine.
|
||||
|
||||
This object supports the <code>__len</code> operator (<code>#t</code>), and
|
||||
integer indexing, but does not support
|
||||
iteration via <code>pairs</code> or <code>ipairs</code>.
|
||||
|
||||
Each element of the array is a <Link class='DisplaySpec' />.
|
||||
</Description>
|
||||
|
||||
<Function name='__len' return='int' arguments=''>
|
||||
Return the number of <Link class='DisplaySpec' /> instances in the array.
|
||||
</Function>
|
||||
<Function name='__index' return='DisplaySpec' arguments='int i'>
|
||||
Return the <Link class='DisplaySpec' /> instance at index <code>i</code>
|
||||
</Function>
|
||||
<Function name='__tostring' return='string' arguments=''>
|
||||
</Function>
|
||||
</Class>
|
||||
<Class name='FadingBanner'>
|
||||
<Function name='GetLatestIndex' return='int' arguments=''>
|
||||
Returns the index of the last banner loaded.
|
||||
@@ -2518,7 +2573,7 @@ save yourself some time, copy this for undocumented things:
|
||||
<code>musicLength</code> seconds one time. Both <code>fadeIn</code> and
|
||||
<code>fadeOut</code> can be customized as required. <code>loop</code>
|
||||
tells the sound manager to loop the music part. <code>applyRate</code>
|
||||
tells the sound manager to apply the current music rate. If <code>alignBeat</code>
|
||||
tells the sound manager to apply the current music rate. If <code>alignBeat</code>
|
||||
is true or nil, the length is automatically adjusted to cover an integer number of beats.
|
||||
</Function>
|
||||
<Function name='PlayOnce' return='void' arguments='string sPath, bool is_action'>
|
||||
@@ -2903,7 +2958,7 @@ save yourself some time, copy this for undocumented things:
|
||||
Sets if the Jukebox should use modifiers.
|
||||
</Function>
|
||||
<Function name='SetMultiplayer' return='void' arguments='bool b'>
|
||||
|
||||
|
||||
</Function>
|
||||
<Function name='SetNumMultiplayerNoteFields' return='void' arguments='int iFields'>
|
||||
Sets the number of multiplayer notefields to <code>iFields</code>
|
||||
@@ -3183,7 +3238,7 @@ save yourself some time, copy this for undocumented things:
|
||||
<Function name='SelectCourse' return='bool' arguments='Course cCourse'>
|
||||
Selects a course. Returns <code>false</code> on failure.
|
||||
</Function>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name='NoteSkinManager'>
|
||||
<Function name='GetMetric' return='string' arguments='string sElement, string sValue'>
|
||||
Returns a string from the specified element and value.
|
||||
@@ -4162,7 +4217,7 @@ save yourself some time, copy this for undocumented things:
|
||||
<Function name='ProfileWasLoadedFromMemoryCard' return='bool' arguments='PlayerNumber pn'>
|
||||
Returns <code>true</code> if <code>pn</code>'s Profile was loaded from a memory card.
|
||||
</Function>
|
||||
|
||||
|
||||
<Function name='LastLoadWasFromLastGood' return='bool' arguments='PlayerNumber pn'>
|
||||
Returns <code>true</code> if the last load of player <code>pn</code>'s profile was a LastGood copy of the profile.
|
||||
</Function>
|
||||
@@ -4229,6 +4284,18 @@ save yourself some time, copy this for undocumented things:
|
||||
<Function name='GetCumFPS' return='int' arguments=''>
|
||||
Return the cumulative FPS.
|
||||
</Function>
|
||||
<Function name='GetDisplaySpecs' return='DisplaySpecs' arguments=''>
|
||||
Return an array-like <code>userdata</code> of type <Link class='DisplaySpecs' />,
|
||||
which describes the displays configured on the user's machine.
|
||||
</Function>
|
||||
<Function name='SupportsRenderToTexture' return='bool' arguments=''>
|
||||
Return <code>true</code> if the current renderer supports render-to-texture,
|
||||
<code>false</code> otherwise.
|
||||
</Function>
|
||||
<Function name='SupportsFullscreenBorderlessWindow' return='bool' arguments=''>
|
||||
Return <code>true</code> if the current renderer/window implementation supports
|
||||
a fullscreen borderless-window mode, <code>false</code> otherwise.
|
||||
</Function>
|
||||
</Class>
|
||||
<Class name='RageFile'>
|
||||
<Description>
|
||||
@@ -5516,7 +5583,7 @@ save yourself some time, copy this for undocumented things:
|
||||
Returns <code>true</code> if the theme has the specified metric.
|
||||
</Function>
|
||||
<Function name='HasString' return='bool' arguments='string section, string value'>
|
||||
Returns <code>true</code> if the theme has the specified string.
|
||||
Returns <code>true</code> if the theme has the specified string.
|
||||
</Function>
|
||||
<Function name='IsThemeSelectable' return='bool' arguments='string theme'>
|
||||
Returns <code>true</code> if the specified theme is selectable.
|
||||
@@ -5525,7 +5592,7 @@ save yourself some time, copy this for undocumented things:
|
||||
Reloads the current theme's metrics.
|
||||
</Function>
|
||||
<Function name='RunLuaScripts' return='void' arguments='string sMask'>
|
||||
|
||||
|
||||
</Function>
|
||||
<Function name='SetTheme' return='void' arguments='string theme'>
|
||||
Changes the current theme.<br />
|
||||
|
||||
@@ -59,13 +59,23 @@ function FooMods()
|
||||
return {PLAYER_2}
|
||||
end,
|
||||
|
||||
-- Optional function. If non-nil, this function must return the string representation
|
||||
-- of a member of the ReloadChanged enum. This function is called in response to a message
|
||||
-- listed in the optional ReloadRowMessages table below. For example,
|
||||
-- to completely change the Choices presented by this OptionRow, modify
|
||||
-- self.Choices in the body of this function and return "ReloadChanged_All"
|
||||
Reload= function(self)
|
||||
Trace("FooMods:Reload() called.")
|
||||
return "ReloadChanged_None"
|
||||
end,
|
||||
|
||||
-- A table of strings that are the names of choices. Choice names are not
|
||||
-- localized.
|
||||
Choices= {"a", "b", "c", "d"},
|
||||
|
||||
-- Optional table. If non-nil, this table must contain a list of messages
|
||||
-- this row should listen for. If one of the messages is recieved, the
|
||||
-- row is reloaded (and the EnabledForPlayers function is called if it is
|
||||
-- row is reloaded (and each of the EnabledForPlayers/Reload functions is called if it is
|
||||
-- non-nil).
|
||||
ReloadRowMessages= {"ReloadFooMods"},
|
||||
|
||||
@@ -90,6 +100,12 @@ function FooMods()
|
||||
-- SaveSelections should examine the list of what the player has selected
|
||||
-- and apply the appropriate modifiers to the player.
|
||||
-- Same args as LoadSelections.
|
||||
--
|
||||
-- May optionally return an "effects" bit mask (constructed by combination of
|
||||
-- the bit masks from the OptEffect enum), which dictates actions the
|
||||
-- game should take in response to the selected option. For example,
|
||||
-- OPT_SAVE_PREFERENCES directs the game to save Preferences.ini,
|
||||
-- OPT_APPLY_ASPECT_RATIO directs the game to recompute the projection matrix, etc.
|
||||
SaveSelections= function(self, list, pn)
|
||||
Trace("FooMods:SaveSelections(" .. pn .. ")")
|
||||
for i, choice in ipairs(self.Choices) do
|
||||
|
||||
+14
-4
@@ -19,18 +19,21 @@ set(SM_EXE_NAME "StepMania")
|
||||
# Some OS specific helpers.
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(LINUX TRUE)
|
||||
set(SM_CPP_STANDARD "gnu++11")
|
||||
else()
|
||||
set(LINUX FALSE)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
set(MACOSX TRUE)
|
||||
set(SM_CPP_STANDARD "gnu++14")
|
||||
else()
|
||||
set(MACOSX FALSE)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "BSD")
|
||||
set(BSD TRUE)
|
||||
set(SM_CPP_STANDARD "gnu++11")
|
||||
else()
|
||||
set(BSD FALSE)
|
||||
endif()
|
||||
@@ -279,8 +282,8 @@ elseif(MACOSX)
|
||||
# Apple Archs needs to be 32-bit for now.
|
||||
# When SDL2 is introduced, this may change.
|
||||
set(CMAKE_OSX_ARCHITECTURES "i386")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.6")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET_FULL "10.6.8")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET_FULL "10.7.1")
|
||||
|
||||
find_library(MAC_FRAME_ACCELERATE Accelerate ${CMAKE_SYSTEM_FRAMEWORK_PATH})
|
||||
find_library(MAC_FRAME_APPKIT AppKit ${CMAKE_SYSTEM_FRAMEWORK_PATH})
|
||||
@@ -346,11 +349,18 @@ elseif(LINUX)
|
||||
|
||||
find_package(Dl)
|
||||
|
||||
find_package(Xrandr)
|
||||
find_package(Xrandr REQUIRED)
|
||||
if (${XRANDR_FOUND})
|
||||
set(HAS_XRANDR TRUE)
|
||||
else()
|
||||
set(HAX_XRANDR FALSE)
|
||||
set(HAS_XRANDR FALSE)
|
||||
endif()
|
||||
|
||||
find_package(Xinerama)
|
||||
if (${XINERAMA_FOUND})
|
||||
set(HAS_XINERAMA TRUE)
|
||||
else()
|
||||
set(HAS_XINERAMA FALSE)
|
||||
endif()
|
||||
|
||||
find_package(PulseAudio)
|
||||
|
||||
@@ -397,6 +397,7 @@ DelayedTextureDelete=Set to ON hold textures in memory instead of freeing them.
|
||||
Delete=
|
||||
Difficulty=
|
||||
DisplayAspectRatio=Change the width-to-height ratio of graphics in the game. Most modern displays are either 16:9 or 16:10.
|
||||
FullscreenType=Change whether fullscreen mode uses the display exclusively (traditional), or is a borderless window (nicer).
|
||||
DisplayColorDepth=Choose the color depth of the window. This option may not take effect in windowed mode.
|
||||
DisplayResolution=Choose the output resolution. A higher resolution will show more detail, but requires a faster video card.
|
||||
Display Options=BGFit, Appearance and UI options.
|
||||
@@ -1055,6 +1056,7 @@ DisplayAspectRatio=Aspect Ratio
|
||||
DisplayColorDepth=Display Color
|
||||
DisplayResolution=Display Resolution
|
||||
Display Options=Display Options
|
||||
FullscreenType=Fullscreen Type
|
||||
Disqualification=Disqualification
|
||||
Duration seconds=Duration seconds
|
||||
EasterEggs=Easter Eggs
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- Find a key in tab with the given value.
|
||||
function FindValue(tab, value)
|
||||
for key, name in tab do
|
||||
for key, name in pairs(tab) do
|
||||
if value == name then
|
||||
return key
|
||||
end
|
||||
@@ -11,7 +11,7 @@ end
|
||||
|
||||
-- Return the index of a true value in list.
|
||||
function FindSelection(list)
|
||||
for index, on in list do
|
||||
for index, on in ipairs(list) do
|
||||
if on then
|
||||
return index
|
||||
end
|
||||
@@ -32,7 +32,7 @@ end
|
||||
function wrap(val,n)
|
||||
local x = val
|
||||
Trace( "wrap "..x.." "..n )
|
||||
if x<0 then
|
||||
if x<0 then
|
||||
x = x + (math.ceil(-x/n)+1)*n
|
||||
end
|
||||
Trace( "adjusted "..x )
|
||||
@@ -122,18 +122,26 @@ end
|
||||
--Get the count of all items in a table
|
||||
function table.itemcount(t)
|
||||
local i = 0
|
||||
while next(t)~=nil do
|
||||
i=i+1
|
||||
for _, v in pairs(t) do
|
||||
i = i+1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
function math.round(num, pre)
|
||||
if pre and pre < 0 then pre = 0 end
|
||||
local mult = 10^(pre or 0)
|
||||
if num >= 0 then return math.floor(num*mult+.5)/mult
|
||||
local mult = 10^(pre or 0)
|
||||
if num >= 0 then return math.floor(num*mult+.5)/mult
|
||||
else return math.ceil(num*mult-.5)/mult end
|
||||
end
|
||||
|
||||
function math.gcd(a, b)
|
||||
while b ~= 0 do
|
||||
a, b = b, math.mod(a, b)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
-- deprecated?
|
||||
function round(val, decimal)
|
||||
if decimal then
|
||||
@@ -197,7 +205,7 @@ function ArgsIfPlayerJoinedOrNil(arg1,arg2)
|
||||
if arg1==nil then arg1=arg2
|
||||
elseif arg2==nil then arg2=arg1 end
|
||||
return (GAMESTATE:IsSideJoined(PLAYER_1) and arg1 or nil),(GAMESTATE:IsSideJoined(PLAYER_2) and arg2 or nil)
|
||||
end
|
||||
end
|
||||
|
||||
function Center1Player()
|
||||
local styleType = GAMESTATE:GetCurrentStyle():GetStyleType()
|
||||
@@ -345,16 +353,13 @@ local function round(num, idp)
|
||||
end
|
||||
|
||||
function IsUsingWideScreen()
|
||||
local curAspect = round(GetScreenAspectRatio(),5);
|
||||
for k,v in pairs(AspectRatios) do
|
||||
if AspectRatios[k] == curAspect then
|
||||
if k == "SixteenNine" or k == "SixteenTen" then
|
||||
return true;
|
||||
else return false;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
local curAspect = GetScreenAspectRatio()
|
||||
if math.abs(curAspect-16/9) <= .044 or math.abs(curAspect - 16/10) <= .044 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Usage: Pass in an ActorFrame and a string to put in front of every line.
|
||||
-- indent will be appended to at each level of the recursion, to indent each
|
||||
@@ -511,7 +516,7 @@ end
|
||||
|
||||
-- (c) 2005-2011 Glenn Maynard, Chris Danford, SSC
|
||||
-- All rights reserved.
|
||||
--
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a
|
||||
-- copy of this software and associated documentation files (the
|
||||
-- "Software"), to deal in the Software without restriction, including
|
||||
@@ -521,7 +526,7 @@ end
|
||||
-- copyright notice(s) and this permission notice appear in all copies of
|
||||
-- the Software and that both the above copyright notice(s) and this
|
||||
-- permission notice appear in supporting documentation.
|
||||
--
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
@@ -531,4 +536,3 @@ end
|
||||
-- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
@@ -0,0 +1,614 @@
|
||||
-- A shim to make an honest-to-goodness lua table (array) out of the
|
||||
-- userdata DisplaySpecs we get from c++
|
||||
local cachedSpecs = nil
|
||||
|
||||
local function GetDisplaySpecs()
|
||||
if cachedSpecs == nil then
|
||||
local specs = DISPLAY:GetDisplaySpecs()
|
||||
t = {
|
||||
ById= function(self, id)
|
||||
for i, d in ipairs(self) do
|
||||
if d:GetId() == id or
|
||||
((id == '' or id == nil) and d:IsVirtual()) then
|
||||
return self[i]
|
||||
end
|
||||
end
|
||||
-- default to returning first DisplaySpec
|
||||
return self[1]
|
||||
end,
|
||||
-- hold on to a reference to the userdata, so it isn't GC'd prematurely
|
||||
c_specs= specs
|
||||
}
|
||||
for i = 1, #specs do
|
||||
t[i] = specs[i]
|
||||
end
|
||||
|
||||
cachedSpecs = t
|
||||
end
|
||||
|
||||
return cachedSpecs
|
||||
end
|
||||
|
||||
-- Ease lookup of OptionRow effects masks
|
||||
local OE = OptEffect:Reverse()
|
||||
|
||||
function ConfDisplayMode()
|
||||
local effectsMask = 2^OE["OptEffect_SavePreferences"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyGraphics"]
|
||||
|
||||
local specs = GetDisplaySpecs()
|
||||
local choices = {}
|
||||
for i, d in ipairs(specs) do
|
||||
choices[i] = d:GetName()
|
||||
end
|
||||
local origDisplay = PREFSMAN:GetPreference("DisplayId")
|
||||
local origWindowed = PREFSMAN:GetPreference("Windowed")
|
||||
choices[#choices + 1] = "Windowed"
|
||||
|
||||
local t = {
|
||||
Name= "Windowed",
|
||||
GoToFirstOnStart= false,
|
||||
OneChoiceForAllPlayers= true,
|
||||
ExportOnChange= false,
|
||||
LayoutType= "ShowAllInRow",
|
||||
SelectType= "SelectOne",
|
||||
|
||||
Choices= choices,
|
||||
LoadSelections= function(self, list, pn)
|
||||
local windowed = PREFSMAN:GetPreference("Windowed")
|
||||
local displayIdx = FindValue(specs, specs:ById(PREFSMAN:GetPreference("DisplayId")))
|
||||
local i = windowed and #self.Choices or displayIdx
|
||||
list[i] = true
|
||||
end,
|
||||
SaveSelections= function(self, list, pn)
|
||||
local choice = FindSelection(list)
|
||||
local selWindowed = choice == #self.Choices
|
||||
local selDisplay = selWindowed and origDisplay or specs[choice]:GetId()
|
||||
|
||||
-- If we've changed from the established preferences in place at our
|
||||
-- instantiation, then we'll return our effects
|
||||
if selWindowed ~= origWindowed
|
||||
or selDisplay ~= origDisplay then
|
||||
return effectsMask
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
NotifyOfSelection= function(self, pn, choice)
|
||||
local curDisplay = PREFSMAN:GetPreference("DisplayId")
|
||||
local curWindowed = PREFSMAN:GetPreference("Windowed")
|
||||
local selWindowed = choice == #self.Choices
|
||||
local selDisplay = selWindowed and curDisplay or specs[choice]:GetId()
|
||||
-- If we've changed from what's currently saved in PREFSMAN,
|
||||
-- then we'll broadcast that state
|
||||
if selWindowed ~= curWindowed
|
||||
or selDisplay ~= curDisplay then
|
||||
PREFSMAN:SetPreference("Windowed", selWindowed)
|
||||
PREFSMAN:SetPreference("DisplayId", selDisplay)
|
||||
MESSAGEMAN:Broadcast("DisplayChoiceChanged")
|
||||
end
|
||||
end
|
||||
}
|
||||
return t
|
||||
end
|
||||
|
||||
-- TODO: here, I'm replicating the AspectRatios table from "02 Utilities.lua",
|
||||
-- but in a friendly format
|
||||
local winFracs = {
|
||||
{n=3, d=4},
|
||||
{n=1, d=1},
|
||||
{n=5, d=4},
|
||||
{n=4, d=3},
|
||||
{n=16, d=10},
|
||||
{n=16, d=9},
|
||||
{n=8, d=3}
|
||||
}
|
||||
-- Maximum distance between aspect ratios to be considered equivalent
|
||||
-- (approximately half the distance between 16:9 and 16:10)
|
||||
local RATIO_EPSILON = .044
|
||||
|
||||
|
||||
local function GetWindowAspectRatios()
|
||||
local ratios = {}
|
||||
for i, f in ipairs(winFracs) do
|
||||
ratios[math.round(f.n/f.d, 3)] = f
|
||||
end
|
||||
|
||||
return ratios
|
||||
end
|
||||
|
||||
-- build a map from DisplayId to supported aspect ratios
|
||||
local function GetDisplayAspectRatios(specs)
|
||||
local ratios = {}
|
||||
local recognized = GetWindowAspectRatios()
|
||||
for _, d in ipairs(specs) do
|
||||
local dRatios = {}
|
||||
for j, mode in ipairs(d:GetSupportedModes()) do
|
||||
local trueRatio = mode:GetWidth()/mode:GetHeight()
|
||||
local truncRatio = math.round(trueRatio, 3)
|
||||
if not dRatios[truncRatio] then
|
||||
local f = {}
|
||||
-- Check if this is a known aspect ratio, or practically the
|
||||
-- same (e.g. 1366x768 is typically considered 16:9)
|
||||
for knownRatio, fraction in pairs(recognized) do
|
||||
if math.abs(trueRatio - (fraction.n/fraction.d)) < RATIO_EPSILON then
|
||||
truncRatio = knownRatio
|
||||
f = fraction
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- If we didn't find a recognized ratio, then register a new ratio
|
||||
-- as the reduced fraction of width / height
|
||||
if not f.n then
|
||||
local w = mode:GetWidth()
|
||||
local h = mode:GetHeight()
|
||||
local gcd = math.gcd(w, h)
|
||||
dRatios[trueRatio] = {n=w/gcd, d=h/gcd}
|
||||
else
|
||||
dRatios[truncRatio] = f
|
||||
end
|
||||
end
|
||||
end
|
||||
ratios[d:GetId()] = dRatios
|
||||
-- Allow looking up the virtual display's aspect ratio by empty string
|
||||
if d:IsVirtual() then
|
||||
ratios[""] = dRatios
|
||||
end
|
||||
end
|
||||
|
||||
return ratios
|
||||
end
|
||||
|
||||
-- hack, use as a space to share value between ConfAspectRatio() and
|
||||
-- ConfDisplayResoltuion(). Can't use PREFSMAN:SetPreference("DisplayAspectRatio", x)
|
||||
-- because that change take effect *immediately* (it is read in the rendering loop)
|
||||
local CurAspectRatio = 0
|
||||
|
||||
function ConfAspectRatio()
|
||||
local effectsMask = 2^OE["OptEffect_SavePreferences"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyGraphics"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyAspectRatio"]
|
||||
local specs = GetDisplaySpecs()
|
||||
local origAspectRatio = PREFSMAN:GetPreference("DisplayAspectRatio")
|
||||
CurAspectRatio = origAspectRatio
|
||||
|
||||
local dRatios = GetDisplayAspectRatios(specs)
|
||||
local wRatios = GetWindowAspectRatios()
|
||||
local t = {
|
||||
Name= "DisplayAspectRatio",
|
||||
GoToFirstOnStart= false,
|
||||
OneChoiceForAllPlayers= true,
|
||||
ExportOnChange= false,
|
||||
LayoutType= "ShowAllInRow",
|
||||
SelectType= "SelectOne",
|
||||
ReloadRowMessages= {"DisplayChoiceChanged"},
|
||||
LoadSelections= function(self, list, pn)
|
||||
local r = CurAspectRatio
|
||||
for i, v in ipairs(self.ChoiceVals) do
|
||||
if math.abs(CurAspectRatio - v) < RATIO_EPSILON then
|
||||
list[i] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
SaveSelections= function(self, list, pn)
|
||||
local i = FindSelection(list)
|
||||
PREFSMAN:SetPreference("DisplayAspectRatio", self.ChoiceVals[i])
|
||||
if math.abs(self.ChoiceVals[i] - origAspectRatio) < RATIO_EPSILON then
|
||||
return 0
|
||||
else
|
||||
return effectsMask
|
||||
end
|
||||
end,
|
||||
|
||||
NotifyOfSelection= function(self, pn, choice)
|
||||
local selRatio = self.ChoiceVals[choice]
|
||||
if math.abs(selRatio-CurAspectRatio) >= RATIO_EPSILON then
|
||||
CurAspectRatio = selRatio
|
||||
MESSAGEMAN:Broadcast("AspectRatioChoiceChanged")
|
||||
end
|
||||
end,
|
||||
|
||||
Reload= function(self)
|
||||
local origVals = self.ChoiceVals
|
||||
self:GenChoices()
|
||||
|
||||
-- Pass along the message to ConfDisplayResolution()
|
||||
-- regardless, but important we do this *after* self:GenChoices()
|
||||
-- to ensure we've updated the CurAspectRatio in accordance
|
||||
-- with what this display supports
|
||||
MESSAGEMAN:Broadcast("AspectRatioChoiceChanged")
|
||||
|
||||
if #origVals ~= #self.ChoiceVals then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
|
||||
for i, v in ipairs(origVals) do
|
||||
if origVals[i] ~= self.ChoiceVals[i] then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
end
|
||||
|
||||
return "ReloadChanged_None"
|
||||
end,
|
||||
|
||||
GenChoices= function(self)
|
||||
-- Determine the available aspect ratios for the current display mode
|
||||
local isWindowed = PREFSMAN:GetPreference("Windowed")
|
||||
local curDisplayId = PREFSMAN:GetPreference("DisplayId")
|
||||
local ratios = isWindowed and wRatios or (dRatios[curDisplayId] or dRatios[specs[1]:GetId()])
|
||||
local choices = {}
|
||||
local vals = {}
|
||||
foreach_ordered(ratios, function(v, f)
|
||||
vals[#vals + 1] = f.n/f.d
|
||||
choices[#choices + 1] = tostring(f.n) .. ':' .. tostring(f.d)
|
||||
end)
|
||||
self.Choices = choices
|
||||
self.ChoiceVals = vals
|
||||
|
||||
-- Get the closest aspect ratio to the currently-configured one
|
||||
-- that this display mode supports
|
||||
local closestRatio = vals[1]
|
||||
local closestDist = math.abs(vals[1] - CurAspectRatio)
|
||||
for _, v in ipairs(vals) do
|
||||
local dist = math.abs(v - CurAspectRatio)
|
||||
if dist < closestDist then
|
||||
closestRatio = v
|
||||
closestDist = dist
|
||||
end
|
||||
end
|
||||
CurAspectRatio = closestRatio
|
||||
end
|
||||
}
|
||||
t:GenChoices()
|
||||
return t
|
||||
end
|
||||
|
||||
local function GenerateFeasibleWindowSizesForRatio(specs, r)
|
||||
-- Get the largest feasible window size *for a single monitor*,
|
||||
-- then generate a sequence of smaller window sizes, until
|
||||
-- one of height/width < 300 (arbitrary)
|
||||
-- TODO: Get fancy and consider larger rectangles that span
|
||||
-- multiple monitors
|
||||
local maxWinWidth = 0
|
||||
for _, d in ipairs(specs) do
|
||||
local modes = d:GetSupportedModes()
|
||||
local dLargestMode = modes[#modes]
|
||||
local w = dLargestMode:GetWidth()
|
||||
local h = dLargestMode:GetHeight()
|
||||
local dMaxWinWidth = w/r <= h and w or r*h
|
||||
maxWinWidth = dMaxWinWidth > maxWinWidth and dMaxWinWidth or maxWinWidth
|
||||
end
|
||||
|
||||
-- Generate successively smaller rectangles
|
||||
local sizes = {}
|
||||
|
||||
local w = maxWinWidth
|
||||
local h = maxWinWidth/r
|
||||
while w > 300 and h > 300 do
|
||||
sizes[#sizes + 1] = {w=math.round(w), h=math.round(h)}
|
||||
w = 0.75*w
|
||||
h = w/r
|
||||
end
|
||||
|
||||
-- Reverse the list (sort in increasing size)
|
||||
local rsizes = {}
|
||||
for i = #sizes, 1, -1 do
|
||||
rsizes[i] = sizes[#sizes - i + 1]
|
||||
end
|
||||
|
||||
return rsizes
|
||||
end
|
||||
|
||||
local function GetFeasibleWindowSizesForRatio(specs, r)
|
||||
-- First, try to see if we have a sufficiently large set of
|
||||
-- resolutions to pick from in the list(s) of supported modes for the display(s)
|
||||
-- (since those resolutions tend to be "natural" looking), otherwise just generate
|
||||
-- some window sizes (which might look weird).
|
||||
local widths = {}
|
||||
for _, d in ipairs(specs) do
|
||||
for _, m in ipairs(d:GetSupportedModes()) do
|
||||
local w = m:GetWidth()
|
||||
local h = m:GetHeight()
|
||||
if math.abs((w/h) - r) < RATIO_EPSILON then
|
||||
widths[w] = h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if table.itemcount(widths) < 4 then
|
||||
return GenerateFeasibleWindowSizesForRatio(specs, r)
|
||||
else
|
||||
local resolutions = {}
|
||||
for w, h in pairs(widths) do
|
||||
resolutions[#resolutions + 1] = {w=w, h=h}
|
||||
end
|
||||
table.sort(resolutions, function (a, b) return a.w < b.w end)
|
||||
return resolutions
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function GetDisplayResolutionsForRatio(d, r)
|
||||
local sizes = {}
|
||||
for _, m in ipairs(d:GetSupportedModes()) do
|
||||
local w = m:GetWidth()
|
||||
local h = m:GetHeight()
|
||||
local trueRatio = w/h
|
||||
if math.abs(trueRatio - r) < RATIO_EPSILON then
|
||||
-- This depends on the fact that GetSupportedModes returns
|
||||
-- a *sorted* list
|
||||
if #sizes == 0 or sizes[#sizes].w ~= w or sizes[#sizes].h ~= h then
|
||||
sizes[#sizes + 1] = {w=m:GetWidth(), h=m:GetHeight()}
|
||||
end
|
||||
end
|
||||
end
|
||||
return sizes
|
||||
end
|
||||
|
||||
function ConfDisplayResolution()
|
||||
local effectsMask = 2^OE["OptEffect_SavePreferences"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyGraphics"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyAspectRatio"]
|
||||
local specs = GetDisplaySpecs()
|
||||
local origWidth = PREFSMAN:GetPreference("DisplayWidth")
|
||||
local origHeight = PREFSMAN:GetPreference("DisplayHeight")
|
||||
|
||||
local t = {
|
||||
Name= "DisplayResolution",
|
||||
GoToFirstOnStart= false,
|
||||
OneChoiceForAllPlayers= true,
|
||||
ExportOnChange= false,
|
||||
LayoutType= "ShowAllInRow",
|
||||
SelectType= "SelectOne",
|
||||
ReloadRowMessages= {"AspectRatioChoiceChanged"},
|
||||
LoadSelections= function(self, list, pn)
|
||||
local w = PREFSMAN:GetPreference("DisplayWidth")
|
||||
local h = PREFSMAN:GetPreference("DisplayHeight")
|
||||
for i, v in ipairs(self.ChoiceVals) do
|
||||
if v.w == w and v.h == h then
|
||||
list[i] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
SaveSelections= function(self, list, pn)
|
||||
local i = FindSelection(list)
|
||||
local w = self.ChoiceVals[i].w
|
||||
local h = self.ChoiceVals[i].h
|
||||
PREFSMAN:SetPreference("DisplayWidth", w)
|
||||
PREFSMAN:SetPreference("DisplayHeight", h)
|
||||
if w == origWidth and h == origHeight then
|
||||
return 0
|
||||
else
|
||||
return effectsMask
|
||||
end
|
||||
end,
|
||||
|
||||
NotifyOfSelection= function(self, pn, choice)
|
||||
local selRes = self.ChoiceVals[choice]
|
||||
local curWidth = PREFSMAN:GetPreference("DisplayWidth")
|
||||
local curHeight = PREFSMAN:GetPreference("DisplayHeight")
|
||||
if selRes.w ~= curWidth or selRes.h ~= curHeight then
|
||||
PREFSMAN:SetPreference("DisplayWidth", selRes.w)
|
||||
PREFSMAN:SetPreference("DisplayHeight", selRes.h)
|
||||
MESSAGEMAN:Broadcast("DisplayResolutionChoiceChanged")
|
||||
end
|
||||
end,
|
||||
|
||||
Reload= function(self)
|
||||
local origVals = self.ChoiceVals
|
||||
self:GenChoices()
|
||||
|
||||
-- Pass along the message to ConfRefreshRate() regardless of
|
||||
-- what happens here. Do this *after* GenChoices() so that
|
||||
-- *if* currently configured resolution needed to change in response
|
||||
-- to change in configured AspectRatio, ConfRefreshRate() can change
|
||||
-- accordingly
|
||||
MESSAGEMAN:Broadcast("DisplayResolutionChoiceChanged")
|
||||
|
||||
if #origVals ~= #self.ChoiceVals then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
|
||||
for i, v in ipairs(origVals) do
|
||||
if origVals[i] ~= self.ChoiceVals[i] then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
end
|
||||
|
||||
return "ReloadChanged_None"
|
||||
end,
|
||||
|
||||
GenChoices= function(self)
|
||||
local isWindowed = PREFSMAN:GetPreference("Windowed")
|
||||
local curDisplay = specs:ById(PREFSMAN:GetPreference("DisplayId"))
|
||||
local curRatio = CurAspectRatio ~= 0 and CurAspectRatio or PREFSMAN:GetPreference("DisplayAspectRatio")
|
||||
local resolutions = isWindowed and GetFeasibleWindowSizesForRatio(specs, curRatio)
|
||||
or GetDisplayResolutionsForRatio(curDisplay, curRatio)
|
||||
|
||||
local choices = {}
|
||||
local vals = {}
|
||||
for i, r in ipairs(resolutions) do
|
||||
vals[#vals + 1] = r
|
||||
choices[#choices + 1] = tostring(r.w) .. 'x' .. tostring(r.h)
|
||||
end
|
||||
self.Choices = choices
|
||||
self.ChoiceVals = vals
|
||||
|
||||
-- If the currently configured resolution isn't available at this
|
||||
-- aspect ratio, then pick the closest resolution
|
||||
local w = PREFSMAN:GetPreference("DisplayWidth")
|
||||
local h = PREFSMAN:GetPreference("DisplayHeight")
|
||||
local closest = nil
|
||||
local mindist = -1
|
||||
for i, v in ipairs(vals) do
|
||||
local dist = math.sqrt((v.w - w)^2 + (v.h - h)^2)
|
||||
if mindist == -1 or dist < mindist then
|
||||
mindist = dist
|
||||
closest = v
|
||||
end
|
||||
end
|
||||
PREFSMAN:SetPreference("DisplayWidth", closest.w)
|
||||
PREFSMAN:SetPreference("DisplayHeight", closest.h)
|
||||
end
|
||||
}
|
||||
t:GenChoices()
|
||||
return t
|
||||
end
|
||||
|
||||
function GetDisplayRatesForResolution(d, w, h)
|
||||
local rates = {}
|
||||
for _, m in ipairs(d:GetSupportedModes()) do
|
||||
if m:GetWidth() == w and m:GetHeight() == h then
|
||||
rates[#rates + 1] = math.round(m:GetRefreshRate())
|
||||
end
|
||||
end
|
||||
return rates
|
||||
end
|
||||
|
||||
function ConfRefreshRate()
|
||||
local effectsMask = 2^OE["OptEffect_SavePreferences"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyGraphics"]
|
||||
local specs = GetDisplaySpecs()
|
||||
local origRate = PREFSMAN:GetPreference("RefreshRate")
|
||||
|
||||
local t = {
|
||||
Name= "RefreshRate",
|
||||
GoToFirstOnStart= false,
|
||||
OneChoiceForAllPlayers= true,
|
||||
ExportOnChange= false,
|
||||
LayoutType= "ShowAllInRow",
|
||||
SelectType= "SelectOne",
|
||||
ReloadRowMessages= {"DisplayResolutionChoiceChanged"},
|
||||
LoadSelections= function(self, list, pn)
|
||||
local r = PREFSMAN:GetPreference("RefreshRate")
|
||||
local i = FindValue(self.ChoiceVals, r)
|
||||
list[i] = true
|
||||
end,
|
||||
|
||||
SaveSelections= function(self, list, pn)
|
||||
local i = FindSelection(list)
|
||||
local r = self.ChoiceVals[i]
|
||||
PREFSMAN:SetPreference("RefreshRate", r)
|
||||
if r ~= origRate then
|
||||
return effectsMask
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
NotifyOfSelection= function(self, pn, choice)
|
||||
local selRate = self.ChoiceVals[choice]
|
||||
local curRate = PREFSMAN:GetPreference("RefreshRate")
|
||||
if selRate ~= curRate then
|
||||
PREFSMAN:SetPreference("RefreshRate", selRate)
|
||||
end
|
||||
end,
|
||||
|
||||
Reload= function(self)
|
||||
local origVals = self.ChoiceVals
|
||||
self:GenChoices()
|
||||
if #origVals ~= #self.ChoiceVals then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
|
||||
for i, v in ipairs(origVals) do
|
||||
if origVals[i] ~= self.ChoiceVals[i] then
|
||||
return "ReloadChanged_All"
|
||||
end
|
||||
end
|
||||
|
||||
return "ReloadChanged_None"
|
||||
end,
|
||||
|
||||
GenChoices= function(self)
|
||||
local isWindowed = PREFSMAN:GetPreference("Windowed")
|
||||
local d = specs:ById(PREFSMAN:GetPreference("DisplayId"))
|
||||
local w = PREFSMAN:GetPreference("DisplayWidth")
|
||||
local h = PREFSMAN:GetPreference("DisplayHeight")
|
||||
local rates = isWindowed and {}
|
||||
or GetDisplayRatesForResolution(d, w, h)
|
||||
|
||||
local choices = {"Default"}
|
||||
local choiceVals = {REFRESH_DEFAULT}
|
||||
for i, r in ipairs(rates) do
|
||||
choiceVals[#choiceVals + 1] = math.round(r)
|
||||
choices[#choices + 1] = tostring(math.round(r))
|
||||
end
|
||||
|
||||
self.Choices = choices
|
||||
self.ChoiceVals = choiceVals
|
||||
|
||||
-- If the currently configured refresh rate isn't available at this
|
||||
-- resolution, then pick the closest one (so long as it's within
|
||||
-- a fixed threshold)
|
||||
local curRate = PREFSMAN:GetPreference("RefreshRate")
|
||||
local threshold = 10
|
||||
local closestIdx = nil
|
||||
local mindist = -1
|
||||
for i, r in ipairs(choiceVals) do
|
||||
local dist = math.abs(r - curRate)
|
||||
if mindist == -1 or dist < mindist then
|
||||
mindist = dist
|
||||
closestIdx = i
|
||||
end
|
||||
end
|
||||
local curRateIdx = mindist < threshold and closestIdx or 1
|
||||
PREFSMAN:SetPreference("RefreshRate", choiceVals[curRateIdx])
|
||||
end
|
||||
}
|
||||
t:GenChoices()
|
||||
return t
|
||||
end
|
||||
|
||||
function ConfFullscreenType()
|
||||
local effectsMask = 2^OE["OptEffect_SavePreferences"]
|
||||
effectsMask = effectsMask + 2^OE["OptEffect_ApplyGraphics"]
|
||||
|
||||
local FULLSCREEN_EXCLUSIVE = 0
|
||||
local FULLSCREEN_BORDERLESS_WIN = 1
|
||||
|
||||
local fsbwSupported = DISPLAY:SupportsFullscreenBorderlessWindow()
|
||||
|
||||
local choiceVals = {FULLSCREEN_EXCLUSIVE}
|
||||
local choices = {"Default"}
|
||||
if fsbwSupported then
|
||||
choices = {"Exclusive", "Borderless Window"}
|
||||
choiceVals = {FULLSCREEN_EXCLUSIVE, FULLSCREEN_BORDERLESS_WIN}
|
||||
end
|
||||
local origFSType = PREFSMAN:GetPreference("FullscreenIsBorderlessWindow") and FULLSCREEN_BORDERLESS_WIN or FULLSCREEN_EXCLUSIVE
|
||||
|
||||
local t = {
|
||||
Name= "FullscreenType",
|
||||
GoToFirstOnStart= false,
|
||||
OneChoiceForAllPlayers= true,
|
||||
ExportOnChange= false,
|
||||
LayoutType= "ShowAllInRow",
|
||||
SelectType= "SelectOne",
|
||||
Choices= choices,
|
||||
ChoiceVals= choiceVals,
|
||||
|
||||
LoadSelections= function(self, list, pn)
|
||||
local fsType = PREFSMAN:GetPreference("FullscreenIsBorderlessWindow") and FULLSCREEN_BORDERLESS_WIN
|
||||
or FULLSCREEN_EXCLUSIVE
|
||||
local i = FindValue(self.ChoiceVals, fsType)
|
||||
list[i] = true
|
||||
end,
|
||||
SaveSelections= function(self, list, pn)
|
||||
local selFSType = self.ChoiceVals[FindSelection(list)]
|
||||
PREFSMAN:SetPreference("FullscreenIsBorderlessWindow", selFSType == FULLSCREEN_BORDERLESS_WIN)
|
||||
if selFSType ~= origFSType then
|
||||
return effectsMask
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
return t
|
||||
end
|
||||
@@ -3051,10 +3051,12 @@ Line22="conf,EventMode"
|
||||
Fallback="ScreenOptionsServiceChild"
|
||||
NextScreen="ScreenOptionsService"
|
||||
PrevScreen="ScreenOptionsService"
|
||||
LineNames="1,2,3,4,5,6,7,8,9,10,11,12,13,FNR,14,17,18,19,20"
|
||||
Line1="conf,Windowed"
|
||||
Line2="conf,DisplayResolution"
|
||||
Line3="conf,DisplayAspectRatio"
|
||||
LineNames="1,2,3,RefreshRate,FSType,4,5,6,7,8,9,10,11,13,FNR,14,17,18,19,20"
|
||||
Line1="lua,ConfDisplayMode()"
|
||||
Line2="lua,ConfAspectRatio()"
|
||||
Line3="lua,ConfDisplayResolution()"
|
||||
LineRefreshRate="lua,ConfRefreshRate()"
|
||||
LineFSType="lua,ConfFullscreenType()"
|
||||
Line4="conf,DisplayColorDepth"
|
||||
Line5="conf,HighResolutionTextures"
|
||||
Line6="conf,MaxTextureResolution"
|
||||
@@ -3063,6 +3065,7 @@ Line8="conf,MovieColorDepth"
|
||||
Line9="conf,SmoothLines"
|
||||
Line10="conf,CelShadeModels"
|
||||
Line11="conf,DelayedTextureDelete"
|
||||
# RefreshRate ConfOption no longer used
|
||||
Line12="conf,RefreshRate"
|
||||
Line13="conf,Vsync"
|
||||
LineFNR="conf,FastNoteRendering"
|
||||
|
||||
+26
-6
@@ -33,9 +33,7 @@ AC_DEFUN([SM_X11],
|
||||
fi
|
||||
|
||||
# Check for Xrandr
|
||||
# Can someone fix this for me? This is producing bizarre warnings from
|
||||
# configure... I have no clue what I'm doing -Ben
|
||||
AC_CHECK_LIB(Xrandr, XRRSizes,
|
||||
AC_CHECK_LIB(Xrandr, XRRQueryVersion,
|
||||
have_xrandr=yes,
|
||||
have_xrandr=no,
|
||||
[$XLIBS])
|
||||
@@ -45,14 +43,36 @@ AC_DEFUN([SM_X11],
|
||||
have_xrandr=no
|
||||
fi
|
||||
|
||||
if test "$have_xrandr" = "no"; then
|
||||
# Check for Xxf86vm
|
||||
AC_CHECK_LIB(Xxf86vm, XF86VidModeSwitchToMode,
|
||||
have_xf86vm=yes,
|
||||
have_xf86vm=no,
|
||||
[$XLIBS])
|
||||
AC_CHECK_HEADER(X11/extensions/xf86vmode.h, have_xf86vm_header=yes, have_xf86vm_header=no, [#include <X11/Xlib.h>])
|
||||
|
||||
if test "$have_xf86vm_header" = "no"; then
|
||||
have_xf86vm=no
|
||||
fi
|
||||
|
||||
no_modeset=yes
|
||||
if test "$have_xrandr" = "yes"; then
|
||||
XLIBS="$XLIBS -lXrandr"
|
||||
AC_DEFINE(HAVE_XRANDR, 1, [Xrandr is available])
|
||||
no_modeset=no
|
||||
fi
|
||||
|
||||
if test "$have_xf86vm" = "yes"; then
|
||||
XLIBS="$XLIBS -lXxf86vm"
|
||||
AC_DEFINE(HAVE_XF86VIDMODE, 1, [XF86VidMode is available])
|
||||
no_modeset=no
|
||||
fi
|
||||
|
||||
if test "$no_modeset" = "yes"; then
|
||||
if test "$unix" = "yes"; then
|
||||
AC_MSG_ERROR("Couldn't find X11 libraries.")
|
||||
else
|
||||
no_x=yes
|
||||
fi
|
||||
else
|
||||
XLIBS="$XLIBS -lXrandr"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_X11, test "$no_x" != "yes")
|
||||
|
||||
Vendored
+14
-4
@@ -20,11 +20,21 @@ add_library("jsoncpp" STATIC ${JSON_SRC} ${JSON_HPP})
|
||||
|
||||
set_property(TARGET "jsoncpp" PROPERTY FOLDER "External Libraries")
|
||||
|
||||
if(MSVC)
|
||||
sm_add_compile_definition("jsoncpp" _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
disable_project_warnings("jsoncpp")
|
||||
|
||||
target_include_directories("jsoncpp" PUBLIC "jsoncpp/include")
|
||||
|
||||
if(MSVC)
|
||||
sm_add_compile_definition("jsoncpp" _CRT_SECURE_NO_WARNINGS)
|
||||
elseif(APPLE)
|
||||
set_target_properties("jsoncpp" PROPERTIES
|
||||
XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "gnu++14"
|
||||
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++"
|
||||
)
|
||||
else() # Unix/Linux
|
||||
sm_add_compile_flag("jsoncpp" "-std=gnu++11")
|
||||
if (CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
sm_add_compile_flag("jsoncpp" "-stdlib=libc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -258,6 +258,79 @@ Actor::Actor( const Actor &cpy ):
|
||||
#undef CPY
|
||||
}
|
||||
|
||||
Actor &Actor::operator=(Actor other)
|
||||
{
|
||||
/* Don't copy an Actor in the middle of rendering. */
|
||||
ASSERT( other.m_pTempState == nullptr );
|
||||
m_pTempState = nullptr;
|
||||
|
||||
using std::swap;
|
||||
#define SWAP(x) swap(x, other.x)
|
||||
SWAP( m_sName );
|
||||
SWAP( m_pParent );
|
||||
SWAP( m_FakeParent );
|
||||
SWAP( m_pLuaInstance );
|
||||
|
||||
SWAP( m_WrapperStates );
|
||||
|
||||
SWAP( m_baseRotation );
|
||||
SWAP( m_baseScale );
|
||||
SWAP( m_fBaseAlpha );
|
||||
SWAP( m_internalDiffuse );
|
||||
SWAP( m_internalGlow );
|
||||
|
||||
|
||||
SWAP( m_size );
|
||||
SWAP( m_current );
|
||||
SWAP( m_start );
|
||||
SWAP( m_Tweens );
|
||||
|
||||
SWAP( m_bFirstUpdate );
|
||||
|
||||
SWAP( m_fHorizAlign );
|
||||
SWAP( m_fVertAlign );
|
||||
#if defined(SSC_FUTURES)
|
||||
SWAP( M_Effects );
|
||||
#else
|
||||
SWAP( m_Effect );
|
||||
#endif
|
||||
SWAP( m_fSecsIntoEffect );
|
||||
SWAP( m_fEffectDelta );
|
||||
SWAP(m_effect_ramp_to_half);
|
||||
SWAP(m_effect_hold_at_half);
|
||||
SWAP(m_effect_ramp_to_full);
|
||||
SWAP(m_effect_hold_at_full);
|
||||
SWAP(m_effect_hold_at_zero);
|
||||
SWAP(m_effect_period);
|
||||
SWAP( m_fEffectOffset );
|
||||
SWAP( m_EffectClock );
|
||||
|
||||
SWAP( m_effectColor1 );
|
||||
SWAP( m_effectColor2 );
|
||||
SWAP( m_vEffectMagnitude );
|
||||
|
||||
SWAP( m_bVisible );
|
||||
SWAP( m_fHibernateSecondsLeft );
|
||||
SWAP( m_fShadowLengthX );
|
||||
SWAP( m_fShadowLengthY );
|
||||
SWAP( m_ShadowColor );
|
||||
SWAP( m_bIsAnimating );
|
||||
SWAP( m_iDrawOrder );
|
||||
|
||||
SWAP( m_bTextureWrapping );
|
||||
SWAP( m_bTextureFiltering );
|
||||
SWAP( m_BlendMode );
|
||||
SWAP( m_bClearZBuffer );
|
||||
SWAP( m_ZTestMode );
|
||||
SWAP( m_bZWrite );
|
||||
SWAP( m_fZBias );
|
||||
SWAP( m_CullMode );
|
||||
|
||||
SWAP( m_mapNameToCommands );
|
||||
#undef SWAP
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* XXX: This calls InitCommand, which must happen after all other
|
||||
* initialization (eg. ActorFrame loading children). However, it
|
||||
* also loads input variables, which should happen first. The
|
||||
|
||||
@@ -111,6 +111,7 @@ public:
|
||||
* @brief Copy a new Actor to the old one.
|
||||
* @param cpy the new Actor to use in place of this one. */
|
||||
Actor( const Actor &cpy );
|
||||
Actor &operator=( Actor other );
|
||||
virtual ~Actor();
|
||||
virtual Actor *Copy() const;
|
||||
virtual void InitState();
|
||||
|
||||
@@ -167,6 +167,7 @@ list(APPEND SM_DATA_REST_SRC
|
||||
"CryptHelpers.cpp"
|
||||
"DateTime.cpp"
|
||||
"Difficulty.cpp"
|
||||
"DisplaySpec.cpp"
|
||||
"EnumHelper.cpp"
|
||||
"FileDownload.cpp"
|
||||
"Game.cpp"
|
||||
@@ -218,7 +219,7 @@ list(APPEND SM_DATA_REST_HPP
|
||||
"CryptHelpers.h"
|
||||
"CubicSpline.h"
|
||||
"DateTime.h"
|
||||
"DisplayResolutions.h"
|
||||
"DisplaySpec.h"
|
||||
"Difficulty.h"
|
||||
"EnumHelper.h"
|
||||
"FileDownload.h"
|
||||
|
||||
@@ -8,6 +8,12 @@ add_library("GtkModule"
|
||||
"arch/LoadingWindow/LoadingWindow_GtkModule.h"
|
||||
)
|
||||
|
||||
sm_add_compile_flag("GtkModule" "-std=${SM_CPP_STANDARD}")
|
||||
if (CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
sm_add_compile_flag("GtkModule" "-stdlib=libc++")
|
||||
set_target_properties("GtkModule" PROPERTIES LINK_FLAGS "-stdlib=libc++")
|
||||
endif()
|
||||
|
||||
# It is normally not appropriate to set the prefix to the empty string.
|
||||
# This is to maintain compatibility with the current source.
|
||||
# At some point, it may be worth being more flexible.
|
||||
|
||||
+25
-8
@@ -165,7 +165,7 @@ if(WIN32)
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" _CRT_SECURE_NO_WARNINGS)
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" _WINSOCK_DEPRECATED_NO_WARNINGS)
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" GLEW_STATIC)
|
||||
|
||||
|
||||
set_target_properties("${SM_EXE_NAME}" PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${SM_PROGRAM_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${SM_PROGRAM_DIR}"
|
||||
@@ -173,7 +173,7 @@ if(WIN32)
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${SM_PROGRAM_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${SM_PROGRAM_DIR}"
|
||||
)
|
||||
|
||||
|
||||
if(MSVC)
|
||||
# Allow for getting a virtualdub stack trace.
|
||||
add_custom_command(TARGET "${SM_EXE_NAME}"
|
||||
@@ -190,6 +190,8 @@ elseif(APPLE)
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${SM_ROOT_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${SM_ROOT_DIR}"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${SM_XCODE_DIR}/Info.StepMania.plist"
|
||||
XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "${SM_CPP_STANDARD}"
|
||||
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++"
|
||||
XCODE_ATTRIBUTE_INFOPLIST_FILE "${SM_XCODE_DIR}/Info.StepMania.plist"
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESS "YES"
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESSOR_DEFINITIONS[variant=Release] "RELEASE"
|
||||
@@ -198,6 +200,7 @@ elseif(APPLE)
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESSOR_DEFINITIONS[variant=RelWithDebInfo] "RELWITHDEBINFO"
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREFIX_HEADER "${SM_XCODE_DIR}/plistHelper.hpp"
|
||||
XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/archutils/Darwin/StepMania.pch"
|
||||
XCODE_ATTRIBUTE_GCC_ENABLE_CPP_EXCEPTIONS "NO"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "${SM_XCODE_DIR}/Libraries"
|
||||
)
|
||||
|
||||
@@ -304,6 +307,13 @@ else() # Linux
|
||||
if (${HAS_FFMPEG})
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_FFMPEG)
|
||||
endif()
|
||||
if (${HAS_XRANDR})
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_XRANDR)
|
||||
endif()
|
||||
if (${HAS_XINERAMA} AND WITH_XINERAMA)
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_XINERAMA)
|
||||
endif()
|
||||
|
||||
if (BSD)
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" BSD)
|
||||
endif()
|
||||
@@ -316,6 +326,12 @@ else() # Linux
|
||||
if("${CMAKE_SYSTEM}" MATCHES "Linux")
|
||||
sm_add_compile_definition("${SM_EXE_NAME}" LINUX)
|
||||
endif()
|
||||
|
||||
sm_add_compile_flag("${SM_EXE_NAME}" "-std=${SM_CPP_STANDARD}")
|
||||
if (CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
sm_add_compile_flag("${SM_EXE_NAME}" "-stdlib=libc++")
|
||||
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS "-stdlib=libc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_property(TARGET "${SM_EXE_NAME}" PROPERTY FOLDER "Internal Libraries")
|
||||
@@ -346,7 +362,7 @@ if (NOT SYSTEM_PCRE_FOUND)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
|
||||
|
||||
list(APPEND SMDATA_LINK_LIB
|
||||
# The misc libraries are here.
|
||||
"${LIB_SWSCALE}"
|
||||
@@ -354,7 +370,7 @@ if (WIN32)
|
||||
"${LIB_AVFORMAT}"
|
||||
"${LIB_AVUTIL}"
|
||||
)
|
||||
|
||||
|
||||
if (WITH_OGG)
|
||||
list(APPEND SMDATA_LINK_LIB
|
||||
"ogg"
|
||||
@@ -362,15 +378,15 @@ if (WIN32)
|
||||
"vorbisfile"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
list(APPEND SMDATA_LINK_LIB
|
||||
"dbghelp.lib"
|
||||
"setupapi.lib"
|
||||
"hid.lib"
|
||||
)
|
||||
|
||||
|
||||
get_filename_component(DIRECTX_LIBRARY_DIR "${DIRECTX_LIBRARIES}" DIRECTORY)
|
||||
|
||||
|
||||
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${DIRECTX_LIBRARY_DIR}\"")
|
||||
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${SM_EXTERN_DIR}/ffmpeg/lib\"")
|
||||
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${SM_SRC_DIR}/archutils/Win32/ddk\"")
|
||||
@@ -385,7 +401,7 @@ if (WIN32)
|
||||
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt.lib")
|
||||
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||
|
||||
|
||||
elseif(APPLE)
|
||||
# The following were removed from SMDATA_LINK_LIB to "match" StepMania's pbxproj.
|
||||
# ${MAC_FRAME_APPKIT}
|
||||
@@ -508,6 +524,7 @@ else() # Unix / Linux
|
||||
|
||||
list(APPEND SMDATA_LINK_LIB
|
||||
${XRANDR_LIBRARIES}
|
||||
${XINERAMA_LIBRARIES}
|
||||
)
|
||||
|
||||
list(REMOVE_ITEM SMDATA_LINK_LIB "zlib")
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "global.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "LuaBinding.h"
|
||||
#include "RageLog.h"
|
||||
|
||||
class LunaDisplayMode: public Luna<DisplayMode>
|
||||
{
|
||||
public:
|
||||
DEFINE_METHOD( GetWidth, width );
|
||||
DEFINE_METHOD( GetHeight, height );
|
||||
DEFINE_METHOD( GetRefreshRate, refreshRate );
|
||||
LunaDisplayMode()
|
||||
{
|
||||
ADD_METHOD( GetWidth );
|
||||
ADD_METHOD( GetHeight );
|
||||
ADD_METHOD( GetRefreshRate );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_CLASS( DisplayMode )
|
||||
|
||||
class LunaDisplaySpec: public Luna<DisplaySpec>
|
||||
{
|
||||
public:
|
||||
DEFINE_METHOD( GetId, id() );
|
||||
DEFINE_METHOD( GetName, name() );
|
||||
DEFINE_METHOD( IsVirtual, isVirtual() );
|
||||
static int GetSupportedModes( T* p, lua_State *L)
|
||||
{
|
||||
std::vector<DisplayMode*> v;
|
||||
for (auto const &m: p->supportedModes())
|
||||
{
|
||||
v.push_back( const_cast<DisplayMode*>(&m));
|
||||
}
|
||||
LuaHelpers::CreateTableFromArray( v, L );
|
||||
return 1;
|
||||
}
|
||||
static int GetCurrentMode( T *p, lua_State *L )
|
||||
{
|
||||
if (p->currentMode() != NULL) {
|
||||
DisplayMode *m = const_cast<DisplayMode *>( p->currentMode() );
|
||||
m->PushSelf( L );
|
||||
} else {
|
||||
lua_pushnil( L );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LunaDisplaySpec()
|
||||
{
|
||||
ADD_METHOD( GetId );
|
||||
ADD_METHOD( GetName );
|
||||
ADD_METHOD( GetSupportedModes );
|
||||
ADD_METHOD( IsVirtual );
|
||||
ADD_METHOD( GetCurrentMode );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_CLASS( DisplaySpec )
|
||||
|
||||
namespace
|
||||
{
|
||||
const char *DISPLAYSPECS = "DisplaySpecs";
|
||||
|
||||
DisplaySpecs *check_DisplaySpecs(lua_State *L)
|
||||
{
|
||||
void *ud = luaL_checkudata( L, 1, DISPLAYSPECS );
|
||||
luaL_argcheck( L, ud != NULL, 1, "`DisplaySpecs` expected" );
|
||||
return static_cast<DisplaySpecs *>(ud);
|
||||
}
|
||||
|
||||
int DisplaySpecs_gc(lua_State *L)
|
||||
{
|
||||
DisplaySpecs *specs = static_cast<DisplaySpecs *> (lua_touserdata( L, 1 ));
|
||||
if (specs)
|
||||
{
|
||||
specs->~DisplaySpecs();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DisplaySpecs_len(lua_State *L)
|
||||
{
|
||||
DisplaySpecs *specs = check_DisplaySpecs( L );
|
||||
if (specs)
|
||||
{
|
||||
lua_pushinteger( L, specs->size() );
|
||||
} else
|
||||
{
|
||||
lua_pushinteger( L, 0 );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DisplaySpecs_tostring(lua_State *L)
|
||||
{
|
||||
DisplaySpecs *specs = check_DisplaySpecs( L );
|
||||
lua_pushfstring( L, "DisplaySpecs: %p", specs );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DisplaySpecs_get(lua_State *L)
|
||||
{
|
||||
DisplaySpecs *specs = check_DisplaySpecs( L );
|
||||
if (specs)
|
||||
{
|
||||
int index = luaL_checkint( L, 2 );
|
||||
luaL_argcheck( L, 1 <= index && static_cast<unsigned int> (index) <= specs->size(), 2,
|
||||
"index out of range" );
|
||||
DisplaySpecs::iterator it = specs->begin();
|
||||
std::advance( it, index - 1 );
|
||||
DisplaySpec *s = const_cast<DisplaySpec *>(&(*it));
|
||||
s->PushSelf( L );
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushnil( L );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg DisplaySpecs_meta[] =
|
||||
{
|
||||
{"__gc", DisplaySpecs_gc},
|
||||
{"__index", DisplaySpecs_get},
|
||||
{"__len", DisplaySpecs_len},
|
||||
{"__tostring", DisplaySpecs_tostring},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
void register_DisplaySpecs(lua_State *L)
|
||||
{
|
||||
luaL_newmetatable( L, DISPLAYSPECS );
|
||||
luaL_openlib( L, 0, DisplaySpecs_meta, 0 );
|
||||
lua_pop( L, 1 );
|
||||
}
|
||||
}
|
||||
REGISTER_WITH_LUA_FUNCTION(register_DisplaySpecs);
|
||||
|
||||
DisplaySpecs *pushDisplaySpecs(lua_State *L, const DisplaySpecs &specs)
|
||||
{
|
||||
void *vpSpecs = lua_newuserdata( L, sizeof( DisplaySpecs ));
|
||||
DisplaySpecs *pspecs = new( vpSpecs ) DisplaySpecs( specs );
|
||||
luaL_getmetatable( L, DISPLAYSPECS );
|
||||
lua_setmetatable( L, -2 );
|
||||
return pspecs;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
#ifndef DisplaySpec_H
|
||||
#define DisplaySpec_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "RageTypes.h"
|
||||
|
||||
struct DisplayMode {
|
||||
// Width (in pixels) of the display in this mode
|
||||
unsigned int width;
|
||||
// Height (in pixels) of the display in this mode
|
||||
unsigned int height;
|
||||
/** Refresh rate, in hz, of the display for the given mode
|
||||
* MacOS Quartz Display Services provides rate as double,
|
||||
* winapi DEVMODE uses 32bit unsigned int (still gives rate as hz),
|
||||
* RandR gives 32 bit pixel clock, which is then divided by width*height.
|
||||
*/
|
||||
double refreshRate;
|
||||
/*
|
||||
* Bits-per-pixel is *not* a property of the DisplayMode for our purposes:
|
||||
* bit-depth is going to be a property of the OpenGL/D3D context, not a display
|
||||
* configuration
|
||||
*/
|
||||
|
||||
bool operator<( const DisplayMode &other ) const
|
||||
{
|
||||
/** @brief A quick way to compare the two DisplayResolutions. */
|
||||
#define COMPARE(x) if( x != other.x ) return x < other.x;
|
||||
COMPARE( width );
|
||||
COMPARE( height );
|
||||
COMPARE( refreshRate );
|
||||
#undef COMPARE
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
};
|
||||
|
||||
/** @brief The dimensions of the program. */
|
||||
class DisplaySpec
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct a specification for the display with the given ID, which supports the given modes,
|
||||
* and is currently using the specified mode with the specified logical screen bounds
|
||||
*/
|
||||
DisplaySpec(const std::string &id,
|
||||
const std::string &name,
|
||||
const std::set<DisplayMode> &modes,
|
||||
const DisplayMode &curMode,
|
||||
const RectI &curBounds,
|
||||
const bool isVirtual=false):
|
||||
m_sId( id ), m_sName( name ),
|
||||
m_sModes( modes ), m_bCurModeActive( true ), m_CurMode( curMode ),
|
||||
m_rectBounds( curBounds ), m_bIsVirtual( isVirtual )
|
||||
{
|
||||
if ( m_sModes.find( curMode ) == m_sModes.end() )
|
||||
{
|
||||
// This is an error, make a failing assertion with a descriptive error message
|
||||
std::stringstream msgStream;
|
||||
msgStream << "DisplaySpec current mode (" << curMode.width << "x" <<
|
||||
curMode.height << "@" << curMode.refreshRate << ") not in given list of supported modes: ";
|
||||
for ( auto &m : modes )
|
||||
{
|
||||
msgStream << m.width << "x" << m.height << "@" << m.refreshRate << ", ";
|
||||
}
|
||||
auto msg = msgStream.str();
|
||||
// Drop the trailing ", "
|
||||
msg.resize( msg.size() - 2 );
|
||||
|
||||
ASSERT_M( false, msg.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a specification for the display with the given ID, which supports the given modes,
|
||||
* and is currently disabled (has no active mode)
|
||||
*/
|
||||
DisplaySpec(const std::string id,
|
||||
const std::string name,
|
||||
const std::set<DisplayMode> modes,
|
||||
const bool isVirtual=false):
|
||||
m_sId( id ), m_sName( name ),
|
||||
m_sModes( modes ), m_bCurModeActive( false ), m_CurMode( { } ),
|
||||
m_bIsVirtual( isVirtual )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Create a specification for a display supporting a single (and currently active) mode
|
||||
DisplaySpec(std::string id, std::string name, DisplayMode mode) : m_sId( id ), m_sName( name ), m_bIsVirtual( false ),
|
||||
m_bCurModeActive( true ), m_CurMode( mode )
|
||||
{
|
||||
m_sModes.insert( mode );
|
||||
m_rectBounds = RectI( 0, 0, mode.width, mode.height );
|
||||
}
|
||||
|
||||
DisplaySpec( const DisplaySpec &other ) = default;
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
return m_sName;
|
||||
}
|
||||
|
||||
std::string id() const
|
||||
{
|
||||
return m_sId;
|
||||
}
|
||||
|
||||
const std::set<DisplayMode> &supportedModes() const
|
||||
{
|
||||
return m_sModes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to the currently active display mode, or NULL if
|
||||
* display is inactive
|
||||
*
|
||||
* Note that inactive *does not* necessarily mean unusable. E.g., in X11,
|
||||
* an output can be enabled/disabled by an application by connecting/disconnecting
|
||||
* a crtc
|
||||
*/
|
||||
const DisplayMode *currentMode() const
|
||||
{
|
||||
return m_bCurModeActive ? &m_CurMode : nullptr;
|
||||
}
|
||||
|
||||
const RectI ¤tBounds() const
|
||||
{
|
||||
return m_rectBounds;
|
||||
}
|
||||
|
||||
bool isVirtual() const
|
||||
{
|
||||
return m_bIsVirtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine if one DisplaySpec compares less than the other.
|
||||
*
|
||||
* Used to enforce a consistent ordering of displays, e.g. for consistent option
|
||||
* presentation. Also allows DisplaySpec to be placed in a std::set
|
||||
*
|
||||
* @param other the other DisplaySpec to check.
|
||||
* @return true if this DisplaySpec is less than the other, or false otherwise. */
|
||||
bool operator<( const DisplaySpec &other ) const
|
||||
{
|
||||
return m_sId < other.id();
|
||||
}
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
private:
|
||||
// Unique identifier of the display
|
||||
std::string m_sId;
|
||||
// "Human-readable" display name
|
||||
std::string m_sName;
|
||||
// Modes supported by this display
|
||||
std::set<DisplayMode> m_sModes;
|
||||
// currently configured mode, if available
|
||||
bool m_bCurModeActive;
|
||||
DisplayMode m_CurMode;
|
||||
// The current bounds of this display in global display coordinate space
|
||||
RectI m_rectBounds;
|
||||
// Flag is "true" when display represents a logical display like an X screen
|
||||
// or the Win32 "Virtual screen"
|
||||
bool m_bIsVirtual;
|
||||
};
|
||||
/** @brief The collection of DisplaySpec available within the program. */
|
||||
typedef std::set<DisplaySpec> DisplaySpecs;
|
||||
//Lua
|
||||
DisplaySpecs *pushDisplaySpecs(lua_State *L, const DisplaySpecs &specs);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2001-2005
|
||||
* @section LICENSE
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||
* whom the Software is furnished to do so, provided that the above
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
@@ -82,9 +82,11 @@ namespace LuaHelpers
|
||||
{
|
||||
template<> void Push<bool>( lua_State *L, const bool &Object ) { lua_pushboolean( L, Object ); }
|
||||
template<> void Push<float>( lua_State *L, const float &Object ) { lua_pushnumber( L, Object ); }
|
||||
template<> void Push<double>( lua_State *L, const double &Object ) { lua_pushnumber( L, Object ); }
|
||||
template<> void Push<int>( lua_State *L, const int &Object ) { lua_pushinteger( L, Object ); }
|
||||
template<> void Push<unsigned int>( lua_State *L, const unsigned int &Object ) { lua_pushnumber( L, double(Object) ); }
|
||||
template<> void Push<RString>( lua_State *L, const RString &Object ) { lua_pushlstring( L, Object.data(), Object.size() ); }
|
||||
template<> void Push<std::string>( lua_State *L, std::string const& object ) { lua_pushlstring( L, object.data(), object.size() ); }
|
||||
|
||||
template<> bool FromStack<bool>( Lua *L, bool &Object, int iOffset ) { Object = !!lua_toboolean( L, iOffset ); return true; }
|
||||
template<> bool FromStack<float>( Lua *L, float &Object, int iOffset ) { Object = (float)lua_tonumber( L, iOffset ); return true; }
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ CreateZip.cpp CreateZip.h \
|
||||
CryptHelpers.cpp CryptHelpers.h \
|
||||
DateTime.cpp DateTime.h \
|
||||
Difficulty.cpp Difficulty.h \
|
||||
DisplayResolutions.h \
|
||||
DisplaySpec.h \
|
||||
EnumHelper.cpp EnumHelper.h \
|
||||
FileDownload.cpp FileDownload.h \
|
||||
Font.cpp Font.h \
|
||||
|
||||
+3
-3
@@ -845,10 +845,10 @@ void OptionRow::Reload()
|
||||
|
||||
switch( m_pHand->Reload() )
|
||||
{
|
||||
case OptionRowHandler::RELOAD_CHANGED_NONE:
|
||||
case RELOAD_CHANGED_NONE:
|
||||
break;
|
||||
|
||||
case OptionRowHandler::RELOAD_CHANGED_ALL:
|
||||
case RELOAD_CHANGED_ALL:
|
||||
{
|
||||
ChoicesChanged( m_RowType );
|
||||
|
||||
@@ -861,7 +861,7 @@ void OptionRow::Reload()
|
||||
// fall through
|
||||
}
|
||||
|
||||
case OptionRowHandler::RELOAD_CHANGED_ENABLED:
|
||||
case RELOAD_CHANGED_ENABLED:
|
||||
UpdateEnabledDisabled();
|
||||
FOREACH_HumanPlayer( pn )
|
||||
PositionUnderlines( pn );
|
||||
|
||||
+93
-17
@@ -834,6 +834,7 @@ class OptionRowHandlerLua : public OptionRowHandler
|
||||
public:
|
||||
LuaReference *m_pLuaTable;
|
||||
LuaReference m_EnabledForPlayersFunc;
|
||||
LuaReference m_ReloadFunc;
|
||||
|
||||
bool m_TableIsSane;
|
||||
bool m_GoToFirstOnStart;
|
||||
@@ -941,6 +942,17 @@ public:
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "Reload");
|
||||
if(!lua_isnil(L, -1))
|
||||
{
|
||||
if(!lua_isfunction(L, -1))
|
||||
{
|
||||
LuaHelpers::ReportScriptErrorFmt("LUA_ERROR: \"%s\" \"Reload\" entry is not a function.", RowName.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "LoadSelections");
|
||||
if(!lua_isfunction(L, -1))
|
||||
{
|
||||
@@ -1007,6 +1019,22 @@ public:
|
||||
LUA->Release(L);
|
||||
}
|
||||
|
||||
void LoadChoices( Lua *L )
|
||||
{
|
||||
// Iterate over the "Choices" table.
|
||||
lua_getfield(L, -1, "Choices");
|
||||
lua_pushnil( L );
|
||||
while( lua_next(L, -2) != 0 )
|
||||
{
|
||||
// `key' is at index -2 and `value' at index -1
|
||||
const char *pValue = lua_tostring( L, -1 );
|
||||
//LOG->Trace( "choice: '%s'", pValue);
|
||||
m_Def.m_vsChoices.push_back( pValue );
|
||||
lua_pop( L, 1 ); // removes `value'; keeps `key' for next iteration
|
||||
}
|
||||
lua_pop( L, 1 ); // pop choices table
|
||||
}
|
||||
|
||||
virtual bool LoadInternal( const Commands &cmds )
|
||||
{
|
||||
const Command &command = cmds.v[0];
|
||||
@@ -1059,18 +1087,7 @@ public:
|
||||
m_Def.m_selectType = StringToSelectType( pStr );
|
||||
lua_pop( L, 1 );
|
||||
|
||||
// Iterate over the "Choices" table.
|
||||
lua_getfield(L, -1, "Choices");
|
||||
lua_pushnil( L );
|
||||
while( lua_next(L, -2) != 0 )
|
||||
{
|
||||
// `key' is at index -2 and `value' at index -1
|
||||
const char *pValue = lua_tostring( L, -1 );
|
||||
//LOG->Trace( "choice: '%s'", pValue);
|
||||
m_Def.m_vsChoices.push_back( pValue );
|
||||
lua_pop( L, 1 ); // removes `value'; keeps `key' for next iteration
|
||||
}
|
||||
lua_pop( L, 1 ); // pop choices table
|
||||
LoadChoices( L );
|
||||
|
||||
// Set the EnabledForPlayers function.
|
||||
lua_getfield(L, -1, "EnabledForPlayers");
|
||||
@@ -1093,6 +1110,10 @@ public:
|
||||
}
|
||||
lua_pop( L, 1 ); // pop ReloadRowMessages table
|
||||
|
||||
// Set the Reload function
|
||||
lua_getfield(L, -1, "Reload");
|
||||
m_ReloadFunc.SetFromStack( L );
|
||||
|
||||
lua_pop( L, 1 ); // pop main table
|
||||
ASSERT( lua_gettop(L) == 0 );
|
||||
|
||||
@@ -1102,8 +1123,47 @@ public:
|
||||
|
||||
virtual ReloadChanged Reload()
|
||||
{
|
||||
if (!m_TableIsSane)
|
||||
{
|
||||
return RELOAD_CHANGED_NONE;
|
||||
}
|
||||
|
||||
/* We'll always call SetEnabledForPlayers, and
|
||||
* return at least RELOAD_CHANGED_ENABLED,
|
||||
* to preserve original OptionRowHandlerLua behavior.
|
||||
*
|
||||
* Will also call the standard OptionRowHandler::Reload
|
||||
* function to determine whether we should declare a full
|
||||
* RELOAD_CHANGED_ALL
|
||||
*/
|
||||
ReloadChanged effect = RELOAD_CHANGED_ENABLED;
|
||||
|
||||
if (!m_ReloadFunc.IsNil())
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
m_ReloadFunc.PushSelf( L );
|
||||
|
||||
// Argument 1: (self)
|
||||
m_pLuaTable->PushSelf( L );
|
||||
RString error = "Reload: ";
|
||||
|
||||
LuaHelpers::RunScriptOnStack( L, error, 1, 1, true );
|
||||
effect = std::max( effect, Enum::Check<ReloadChanged>( L, -1 ));
|
||||
lua_pop( L, 1 );
|
||||
|
||||
if (effect == RELOAD_CHANGED_ALL)
|
||||
{
|
||||
m_Def.m_vsChoices.clear();
|
||||
m_pLuaTable->PushSelf( L );
|
||||
LoadChoices( L );
|
||||
lua_pop( L, 1 );
|
||||
ASSERT( lua_gettop(L) == 0 );
|
||||
}
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
SetEnabledForPlayers();
|
||||
return RELOAD_CHANGED_ENABLED;
|
||||
return effect;
|
||||
}
|
||||
|
||||
virtual void ImportOption( OptionRow *pRow, const vector<PlayerNumber> &vpns, vector<bool> vbSelectedOut[NUM_PLAYERS] ) const
|
||||
@@ -1174,6 +1234,7 @@ public:
|
||||
|
||||
ASSERT( lua_gettop(L) == 0 );
|
||||
|
||||
int effects = 0;
|
||||
FOREACH_CONST( PlayerNumber, vpns, pn )
|
||||
{
|
||||
PlayerNumber p = *pn;
|
||||
@@ -1206,9 +1267,14 @@ public:
|
||||
ASSERT( lua_gettop(L) == 6 ); // vbSelectedOut, m_iLuaTable, function, self, arg, arg
|
||||
|
||||
RString error= "SaveSelections: ";
|
||||
LuaHelpers::RunScriptOnStack( L, error, 3, 0, true );
|
||||
ASSERT( lua_gettop(L) == 2 );
|
||||
LuaHelpers::RunScriptOnStack( L, error, 3, 1, true );
|
||||
ASSERT( lua_gettop(L) == 3 ); // SaveSelections *may* return effects flags, otherwise nil
|
||||
double ret = lua_tonumber( L, -1 );
|
||||
ASSERT_M( (lua_isnumber( L, -1 ) && std::floor( ret ) == ret) || lua_isnil( L, -1 ),
|
||||
"SaveSelections must return integer flags, or nill" );
|
||||
effects |= static_cast<int>( ret );
|
||||
|
||||
lua_pop( L, 1 ); // pop effects
|
||||
lua_pop( L, 1 ); // pop option table
|
||||
lua_pop( L, 1 ); // pop vbSelected table
|
||||
|
||||
@@ -1217,8 +1283,7 @@ public:
|
||||
|
||||
LUA->Release(L);
|
||||
|
||||
// XXX: allow specifying the mask
|
||||
return 0;
|
||||
return effects;
|
||||
}
|
||||
virtual bool NotifyOfSelection(PlayerNumber pn, int choice)
|
||||
{
|
||||
@@ -1593,6 +1658,17 @@ OptionRowHandler* OptionRowHandlerUtil::MakeSimple( const MenuRowDef &mr )
|
||||
return pHand;
|
||||
}
|
||||
|
||||
// Expose ReloadChanged to Lua
|
||||
static const char *ReloadChangedNames[] =
|
||||
{
|
||||
"None",
|
||||
"Enabled",
|
||||
"All"
|
||||
};
|
||||
XToString( ReloadChanged );
|
||||
StringToX( ReloadChanged );
|
||||
LuaXType( ReloadChanged );
|
||||
|
||||
/*
|
||||
* (c) 2002-2004 Chris Danford
|
||||
* All rights reserved.
|
||||
|
||||
@@ -31,6 +31,13 @@ enum LayoutType
|
||||
const RString& LayoutTypeToString( LayoutType pm );
|
||||
LayoutType StringToLayoutType( const RString& s );
|
||||
LuaDeclareType( LayoutType );
|
||||
enum ReloadChanged
|
||||
{
|
||||
RELOAD_CHANGED_NONE, RELOAD_CHANGED_ENABLED, RELOAD_CHANGED_ALL, NUM_ReloadChanged, ReloadChanged_Invalid
|
||||
};
|
||||
const RString& ReloadChangedToString( ReloadChanged rc );
|
||||
ReloadChanged StringToReloadChanged( const std::string& rc );
|
||||
LuaDeclareType( ReloadChanged );
|
||||
|
||||
/** @brief Define the purpose of the OptionRow. */
|
||||
struct OptionRowDefinition
|
||||
@@ -169,7 +176,6 @@ public:
|
||||
* graphic elements will also be reinitialized. If only m_vEnabledForPlayers
|
||||
* has been changed, return RELOAD_CHANGED_ENABLED. If the row is static, and
|
||||
* nothing has changed, return RELOAD_CHANGED_NONE. */
|
||||
enum ReloadChanged { RELOAD_CHANGED_NONE, RELOAD_CHANGED_ENABLED, RELOAD_CHANGED_ALL };
|
||||
virtual ReloadChanged Reload() { return RELOAD_CHANGED_NONE; }
|
||||
|
||||
virtual int GetDefaultOption() const { return -1; }
|
||||
|
||||
@@ -166,6 +166,7 @@ PrefsManager::PrefsManager() :
|
||||
m_sDefaultModifiers ( "DefaultModifiers", "" ),
|
||||
|
||||
m_bWindowed ( "Windowed", true ),
|
||||
m_sDisplayId ( "DisplayId", "" ),
|
||||
m_iDisplayWidth ( "DisplayWidth", 854 ),
|
||||
m_iDisplayHeight ( "DisplayHeight", 480 ),
|
||||
m_fDisplayAspectRatio ( "DisplayAspectRatio", 16/9.f, ValidateDisplayAspectRatio ),
|
||||
@@ -178,6 +179,7 @@ PrefsManager::PrefsManager() :
|
||||
m_iMaxTextureResolution ( "MaxTextureResolution", 2048 ),
|
||||
m_iRefreshRate ( "RefreshRate", REFRESH_DEFAULT ),
|
||||
m_bAllowMultitexture ( "AllowMultitexture", true ),
|
||||
m_bFullscreenIsBorderlessWindow( "FullscreenIsBorderlessWindow", false ),
|
||||
m_bShowStats ( "ShowStats", TRUE_IF_DEBUG),
|
||||
m_bShowBanners ( "ShowBanners", true ),
|
||||
m_bShowMouseCursor ( "ShowMouseCursor", true ),
|
||||
@@ -379,7 +381,7 @@ void PrefsManager::StoreGamePrefs()
|
||||
ASSERT( !m_sCurrentGame.Get().empty() );
|
||||
|
||||
// save off old values
|
||||
GamePrefs &gp = m_mapGameNameToGamePrefs[m_sCurrentGame];
|
||||
GamePrefs &gp = m_mapGameNameToGamePrefs[m_sCurrentGame.Get()];
|
||||
gp.m_sAnnouncer = m_sAnnouncer;
|
||||
gp.m_sTheme = m_sTheme;
|
||||
gp.m_sDefaultModifiers = m_sDefaultModifiers;
|
||||
|
||||
@@ -158,6 +158,7 @@ protected:
|
||||
|
||||
public:
|
||||
Preference<bool> m_bWindowed;
|
||||
Preference<RString> m_sDisplayId;
|
||||
Preference<int> m_iDisplayWidth;
|
||||
Preference<int> m_iDisplayHeight;
|
||||
Preference<float> m_fDisplayAspectRatio;
|
||||
@@ -170,6 +171,7 @@ public:
|
||||
Preference<int> m_iMaxTextureResolution;
|
||||
Preference<int> m_iRefreshRate;
|
||||
Preference<bool> m_bAllowMultitexture;
|
||||
Preference<bool> m_bFullscreenIsBorderlessWindow;
|
||||
Preference<bool> m_bShowStats;
|
||||
Preference<bool> m_bShowBanners;
|
||||
Preference<bool> m_bShowMouseCursor;
|
||||
|
||||
@@ -230,7 +230,7 @@ bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn )
|
||||
void ProfileManager::GetMemoryCardProfileDirectoriesToTry( vector<RString> &asDirsToTry )
|
||||
{
|
||||
/* Try to load the preferred profile. */
|
||||
asDirsToTry.push_back( PREFSMAN->m_sMemoryCardProfileSubdir );
|
||||
asDirsToTry.push_back( PREFSMAN->m_sMemoryCardProfileSubdir.Get() );
|
||||
|
||||
/* If that failed, try loading from all fallback directories. */
|
||||
split( g_sMemoryCardProfileImportSubdirs, ";", asDirsToTry, true );
|
||||
|
||||
+57
-8
@@ -12,7 +12,7 @@
|
||||
#include "RageSurface.h"
|
||||
#include "Preference.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "arch/ArchHooks/ArchHooks.h"
|
||||
|
||||
// Statistics stuff
|
||||
@@ -90,17 +90,33 @@ RString RageDisplay::SetVideoMode( VideoModeParams p, bool &bNeedReloadTextures
|
||||
vs.push_back( err );
|
||||
|
||||
// Fall back on a known resolution good rather than 640 x 480.
|
||||
DisplayResolutions dr;
|
||||
this->GetDisplayResolutions( dr );
|
||||
DisplaySpecs dr;
|
||||
this->GetDisplaySpecs(dr);
|
||||
if( dr.empty() )
|
||||
{
|
||||
vs.push_back( "No display resolutions" );
|
||||
return SETVIDEOMODE_FAILED.GetValue() + " " + join(";",vs);
|
||||
}
|
||||
|
||||
const DisplayResolution &d = *dr.begin();
|
||||
p.width = d.iWidth;
|
||||
p.height = d.iHeight;
|
||||
DisplaySpec d = *dr.begin();
|
||||
// Try to find DisplaySpec corresponding to requested display
|
||||
for (const auto &candidate: dr)
|
||||
{
|
||||
if (candidate.currentMode() != nullptr)
|
||||
{
|
||||
d = candidate;
|
||||
if (candidate.id() == p.sDisplayId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.sDisplayId = d.id();
|
||||
const DisplayMode supported = d.currentMode() != nullptr ? *d.currentMode() : *d.supportedModes().begin();
|
||||
p.width = supported.width;
|
||||
p.height = supported.height;
|
||||
p.rate = static_cast<int> (round(supported.refreshRate));
|
||||
if( (err = this->TryVideoMode(p,bNeedReloadTextures)) == "" )
|
||||
return RString();
|
||||
vs.push_back( err );
|
||||
@@ -714,8 +730,8 @@ void RageDisplay::ChangeCentering( int iTranslateX, int iTranslateY, int iAddWid
|
||||
RageMatrix RageDisplay::GetCenteringMatrix( float fTranslateX, float fTranslateY, float fAddWidth, float fAddHeight ) const
|
||||
{
|
||||
// in screen space, left edge = -1, right edge = 1, bottom edge = -1. top edge = 1
|
||||
float fWidth = (float) GetActualVideoModeParams().width;
|
||||
float fHeight = (float) GetActualVideoModeParams().height;
|
||||
float fWidth = (float) GetActualVideoModeParams().windowWidth;
|
||||
float fHeight = (float) GetActualVideoModeParams().windowHeight;
|
||||
float fPercentShiftX = SCALE( fTranslateX, 0, fWidth, 0, +2.0f );
|
||||
float fPercentShiftY = SCALE( fTranslateY, 0, fHeight, 0, -2.0f );
|
||||
float fPercentScaleX = SCALE( fAddWidth, 0, fWidth, 1.0f, 2.0f );
|
||||
@@ -990,6 +1006,16 @@ void RageCompiledGeometry::Set( const vector<msMesh> &vMeshes, bool bNeedsNormal
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
// Register with Lua.
|
||||
static void register_REFRESH_DEFAULT(lua_State *L)
|
||||
{
|
||||
lua_pushstring( L, "REFRESH_DEFAULT" );
|
||||
lua_pushinteger( L, REFRESH_DEFAULT );
|
||||
lua_settable( L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
REGISTER_WITH_LUA_FUNCTION( register_REFRESH_DEFAULT );
|
||||
|
||||
|
||||
/** @brief Allow Lua to have access to the RageDisplay. */
|
||||
class LunaRageDisplay: public Luna<RageDisplay>
|
||||
{
|
||||
@@ -1026,6 +1052,26 @@ public:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetDisplaySpecs( T* p, lua_State *L )
|
||||
{
|
||||
DisplaySpecs s;
|
||||
p->GetDisplaySpecs(s);
|
||||
pushDisplaySpecs(L, s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SupportsRenderToTexture( T* p, lua_State *L )
|
||||
{
|
||||
lua_pushboolean(L, p->SupportsRenderToTexture());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SupportsFullscreenBorderlessWindow( T* p, lua_State *L )
|
||||
{
|
||||
lua_pushboolean(L, p->SupportsFullscreenBorderlessWindow());
|
||||
return 1;
|
||||
}
|
||||
|
||||
LunaRageDisplay()
|
||||
{
|
||||
ADD_METHOD( GetDisplayWidth );
|
||||
@@ -1033,6 +1079,9 @@ public:
|
||||
ADD_METHOD( GetFPS );
|
||||
ADD_METHOD( GetVPF );
|
||||
ADD_METHOD( GetCumFPS );
|
||||
ADD_METHOD( GetDisplaySpecs );
|
||||
ADD_METHOD( SupportsRenderToTexture );
|
||||
ADD_METHOD( SupportsFullscreenBorderlessWindow);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+60
-9
@@ -7,8 +7,8 @@
|
||||
#include "ModelTypes.h"
|
||||
#include <set>
|
||||
|
||||
class DisplayResolution;
|
||||
typedef set<DisplayResolution> DisplayResolutions;
|
||||
class DisplaySpec;
|
||||
typedef std::set<DisplaySpec> DisplaySpecs;
|
||||
|
||||
const int REFRESH_DEFAULT = 0;
|
||||
struct RageSurface;
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
// are filled (in case new params are added).
|
||||
VideoModeParams(
|
||||
bool windowed_,
|
||||
RString sDisplayId_,
|
||||
int width_,
|
||||
int height_,
|
||||
int bpp_,
|
||||
@@ -88,12 +89,14 @@ public:
|
||||
bool bSmoothLines_,
|
||||
bool bTrilinearFiltering_,
|
||||
bool bAnisotropicFiltering_,
|
||||
bool bWindowIsFullscreenBorderless_,
|
||||
RString sWindowTitle_,
|
||||
RString sIconFile_,
|
||||
bool PAL_,
|
||||
float fDisplayAspectRatio_
|
||||
):
|
||||
windowed(windowed_),
|
||||
sDisplayId(sDisplayId_),
|
||||
width(width_),
|
||||
height(height_),
|
||||
bpp(bpp_),
|
||||
@@ -103,18 +106,36 @@ public:
|
||||
bSmoothLines(bSmoothLines_),
|
||||
bTrilinearFiltering(bTrilinearFiltering_),
|
||||
bAnisotropicFiltering(bAnisotropicFiltering_),
|
||||
bWindowIsFullscreenBorderless(bWindowIsFullscreenBorderless_),
|
||||
sWindowTitle(sWindowTitle_),
|
||||
sIconFile(sIconFile_),
|
||||
PAL(PAL_),
|
||||
fDisplayAspectRatio(fDisplayAspectRatio_) {}
|
||||
|
||||
VideoModeParams(const VideoModeParams &other):
|
||||
windowed(other.windowed), sDisplayId(other.sDisplayId),
|
||||
width(other.width), height(other.height),
|
||||
bpp(other.bpp), rate(other.rate),
|
||||
vsync(other.vsync), interlaced(other.interlaced),
|
||||
bSmoothLines(other.bSmoothLines), bTrilinearFiltering(other.bTrilinearFiltering),
|
||||
bAnisotropicFiltering(other.bAnisotropicFiltering), bWindowIsFullscreenBorderless(other.bWindowIsFullscreenBorderless),
|
||||
sWindowTitle(other.sWindowTitle), sIconFile(other.sIconFile),
|
||||
PAL(other.PAL), fDisplayAspectRatio(other.fDisplayAspectRatio)
|
||||
{}
|
||||
|
||||
VideoModeParams(): windowed(false), width(0), height(0),
|
||||
bpp(0), rate(0), vsync(false), interlaced(false),
|
||||
bSmoothLines(false), bTrilinearFiltering(false),
|
||||
bAnisotropicFiltering(false), sWindowTitle(RString()),
|
||||
sIconFile(RString()), PAL(false), fDisplayAspectRatio(0.0f) {}
|
||||
bpp(0), rate(0), vsync(false), interlaced(false),
|
||||
bSmoothLines(false), bTrilinearFiltering(false),
|
||||
bAnisotropicFiltering(false), bWindowIsFullscreenBorderless(false),
|
||||
sWindowTitle(RString()), sIconFile(RString()),
|
||||
PAL(false), fDisplayAspectRatio(0.0f) {}
|
||||
|
||||
// Subclassing VideoModeParams in ActualVideoModeParams. Make destructor virtual just in case
|
||||
// someone tries to delete one of those through a pointer to base...
|
||||
virtual ~VideoModeParams() {}
|
||||
|
||||
bool windowed;
|
||||
RString sDisplayId;
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
@@ -124,12 +145,41 @@ public:
|
||||
bool bSmoothLines;
|
||||
bool bTrilinearFiltering;
|
||||
bool bAnisotropicFiltering;
|
||||
bool bWindowIsFullscreenBorderless;
|
||||
RString sWindowTitle;
|
||||
RString sIconFile;
|
||||
bool PAL;
|
||||
float fDisplayAspectRatio;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The _actual_ VideoModeParams determined by the LowLevelWindow implementation.
|
||||
* Contains all the attributes of VideoModeParams, plus the actual window width/height determined by
|
||||
* LLW
|
||||
*/
|
||||
class ActualVideoModeParams: public VideoModeParams
|
||||
{
|
||||
public:
|
||||
ActualVideoModeParams(): VideoModeParams(), windowWidth(0), windowHeight(0), renderOffscreen(false) {}
|
||||
ActualVideoModeParams( const VideoModeParams ¶ms ) : VideoModeParams( params ),
|
||||
windowWidth( params.width ),
|
||||
windowHeight( params.height ),
|
||||
renderOffscreen( false )
|
||||
{ }
|
||||
ActualVideoModeParams( const VideoModeParams ¶ms, int windowWidth, int windowHeight, bool renderOffscreen ) :
|
||||
VideoModeParams( params ), windowWidth( windowWidth ), windowHeight( windowHeight ),
|
||||
renderOffscreen( renderOffscreen )
|
||||
{ }
|
||||
ActualVideoModeParams (const ActualVideoModeParams &other) = default;
|
||||
|
||||
// If bWindowIsFullscreenBorderless is true,
|
||||
// then these properties will differ from width/height (which describe the
|
||||
// render size)
|
||||
int windowWidth;
|
||||
int windowHeight;
|
||||
bool renderOffscreen;
|
||||
};
|
||||
|
||||
struct RenderTargetParam
|
||||
{
|
||||
RenderTargetParam():
|
||||
@@ -181,7 +231,7 @@ public:
|
||||
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer ) = 0;
|
||||
|
||||
virtual RString GetApiDescription() const = 0;
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const = 0;
|
||||
virtual void GetDisplaySpecs(DisplaySpecs &out) const = 0;
|
||||
|
||||
// Don't override this. Override TryVideoMode() instead.
|
||||
// This will set the video mode to be as close as possible to params.
|
||||
@@ -193,7 +243,7 @@ public:
|
||||
|
||||
virtual bool BeginFrame();
|
||||
virtual void EndFrame();
|
||||
virtual VideoModeParams GetActualVideoModeParams() const = 0;
|
||||
virtual ActualVideoModeParams GetActualVideoModeParams() const = 0;
|
||||
bool IsWindowed() const { return this->GetActualVideoModeParams().windowed; }
|
||||
|
||||
virtual void SetBlendMode( BlendMode mode ) = 0;
|
||||
@@ -235,7 +285,8 @@ public:
|
||||
virtual void SetEffectMode( EffectMode ) { }
|
||||
virtual bool IsEffectModeSupported( EffectMode effect ) { return effect == EffectMode_Normal; }
|
||||
|
||||
bool SupportsRenderToTexture() const { return false; }
|
||||
virtual bool SupportsRenderToTexture() const { return false; }
|
||||
virtual bool SupportsFullscreenBorderlessWindow() const { return false; }
|
||||
|
||||
/* Create a render target, returning a texture handle. In addition to normal
|
||||
* texture functions, this can be passed to SetRenderTarget. Delete with
|
||||
|
||||
+29
-10
@@ -10,7 +10,7 @@
|
||||
#include "RageSurface.h"
|
||||
#include "RageSurfaceUtils.h"
|
||||
#include "EnumHelper.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "LocalizedString.h"
|
||||
|
||||
#include <D3dx9tex.h>
|
||||
@@ -271,19 +271,39 @@ RageDisplay_D3D::~RageDisplay_D3D()
|
||||
}
|
||||
}
|
||||
|
||||
void RageDisplay_D3D::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
void RageDisplay_D3D::GetDisplaySpecs( DisplaySpecs &out ) const
|
||||
{
|
||||
out.clear();
|
||||
int iCnt = g_pd3d->GetAdapterModeCount( D3DADAPTER_DEFAULT, g_DefaultAdapterFormat );
|
||||
|
||||
for( int i = 0; i < iCnt; ++i )
|
||||
std::set<DisplayMode> modes;
|
||||
D3DDISPLAYMODE mode;
|
||||
for ( int i = 0; i < iCnt; ++i )
|
||||
{
|
||||
D3DDISPLAYMODE mode;
|
||||
g_pd3d->EnumAdapterModes( D3DADAPTER_DEFAULT, g_DefaultAdapterFormat, i, &mode );
|
||||
|
||||
DisplayResolution res = { mode.Width, mode.Height };
|
||||
out.insert( res );
|
||||
modes.insert( { mode.Width, mode.Height, static_cast<double> (mode.RefreshRate) } );
|
||||
}
|
||||
|
||||
// Get the current display mode
|
||||
if ( g_pd3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &mode ) == D3D_OK )
|
||||
{
|
||||
D3DADAPTER_IDENTIFIER9 ID;
|
||||
g_pd3d->GetAdapterIdentifier( D3DADAPTER_DEFAULT, 0, &ID );
|
||||
DisplayMode active = { mode.Width, mode.Height, static_cast<double> (mode.RefreshRate) };
|
||||
RectI bounds( 0, 0, active.width, active.height );
|
||||
out.insert( DisplaySpec( "", "Fullscreen", modes, active, bounds ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG->Warn( "Could not find active mode for default D3D adapter" );
|
||||
if ( !modes.empty() )
|
||||
{
|
||||
const DisplayMode &m = *modes.begin();
|
||||
RectI bounds( 0, 0, m.width, m.height );
|
||||
out.insert( DisplaySpec( "", "Fullscreen", modes, m, bounds ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
D3DFORMAT FindBackBufferType(bool bWindowed, int iBPP)
|
||||
@@ -677,10 +697,9 @@ RageSurface* RageDisplay_D3D::CreateScreenshot()
|
||||
return result;
|
||||
}
|
||||
|
||||
VideoModeParams RageDisplay_D3D::GetActualVideoModeParams() const
|
||||
ActualVideoModeParams RageDisplay_D3D::GetActualVideoModeParams() const
|
||||
{
|
||||
VideoModeParams p = GraphicsWindow::GetParams();
|
||||
return p;
|
||||
return GraphicsWindow::GetParams();
|
||||
}
|
||||
|
||||
void RageDisplay_D3D::SendCurrentMatrices()
|
||||
|
||||
@@ -11,13 +11,13 @@ public:
|
||||
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
|
||||
|
||||
virtual RString GetApiDescription() const { return "D3D"; }
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
virtual void GetDisplaySpecs( DisplaySpecs &out ) const;
|
||||
void ResolutionChanged();
|
||||
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
|
||||
|
||||
bool BeginFrame();
|
||||
void EndFrame();
|
||||
VideoModeParams GetActualVideoModeParams() const;
|
||||
ActualVideoModeParams GetActualVideoModeParams() const;
|
||||
void SetBlendMode( BlendMode mode );
|
||||
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
|
||||
bool SupportsThreadedRendering();
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "RageSurface.h"
|
||||
#include "RageTextureManager.h"
|
||||
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
|
||||
#include "arch/LowLevelWindow/LowLevelWindow.h"
|
||||
|
||||
@@ -444,10 +444,10 @@ RageDisplay_GLES2::~RageDisplay_GLES2()
|
||||
}
|
||||
|
||||
void
|
||||
RageDisplay_GLES2::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
RageDisplay_GLES2::GetDisplaySpecs(DisplaySpecs &out) const
|
||||
{
|
||||
out.clear();
|
||||
g_pWind->GetDisplayResolutions( out );
|
||||
g_pWind->GetDisplaySpecs(out);
|
||||
}
|
||||
|
||||
RageSurface*
|
||||
@@ -517,7 +517,7 @@ RageDisplay_GLES2::GetApiDescription() const
|
||||
return "OpenGL ES 2.0";
|
||||
}
|
||||
|
||||
VideoModeParams
|
||||
ActualVideoModeParams
|
||||
RageDisplay_GLES2::GetActualVideoModeParams() const
|
||||
{
|
||||
return g_pWind->GetActualVideoModeParams();
|
||||
|
||||
@@ -9,21 +9,21 @@ public:
|
||||
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
|
||||
|
||||
virtual RString GetApiDescription() const;
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
|
||||
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
|
||||
|
||||
bool BeginFrame();
|
||||
void EndFrame();
|
||||
VideoModeParams GetActualVideoModeParams() const;
|
||||
ActualVideoModeParams GetActualVideoModeParams() const;
|
||||
void SetBlendMode( BlendMode mode );
|
||||
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
|
||||
bool SupportsPerVertexMatrixScale();
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat pixfmt,
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat pixfmt,
|
||||
RageSurface* img,
|
||||
bool bGenerateMipMaps );
|
||||
void UpdateTexture(
|
||||
unsigned iTexHandle,
|
||||
void UpdateTexture(
|
||||
unsigned iTexHandle,
|
||||
RageSurface* img,
|
||||
int xoffset, int yoffset, int width, int height );
|
||||
void DeleteTexture( unsigned iTexHandle );
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
void ClearZBuffer();
|
||||
void SetCullMode( CullMode mode );
|
||||
void SetAlphaTest( bool b );
|
||||
void SetMaterial(
|
||||
void SetMaterial(
|
||||
const RageColor &emissive,
|
||||
const RageColor &ambient,
|
||||
const RageColor &diffuse,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "RageTypes.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageSurface.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
|
||||
static RageDisplay::RagePixelFormatDesc PIXEL_FORMAT_DESC[NUM_RagePixelFormat] = {
|
||||
{
|
||||
@@ -81,11 +81,12 @@ RString RageDisplay_Null::Init( const VideoModeParams &p, bool /* bAllowUnaccele
|
||||
return RString();
|
||||
}
|
||||
|
||||
void RageDisplay_Null::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
void RageDisplay_Null::GetDisplaySpecs(DisplaySpecs &out) const
|
||||
{
|
||||
out.clear();
|
||||
DisplayResolution res = { 640, 480, true };
|
||||
out.insert( res );
|
||||
DisplayMode nullMode = {640U, 480U, 30.0};
|
||||
DisplaySpec nullSpec("NullDisplay", "NullDisplay", nullMode);
|
||||
out.insert( nullSpec );
|
||||
}
|
||||
|
||||
RageSurface* RageDisplay_Null::CreateScreenshot()
|
||||
|
||||
@@ -10,23 +10,23 @@ public:
|
||||
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
|
||||
|
||||
virtual RString GetApiDescription() const { return "Null"; }
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
|
||||
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
|
||||
|
||||
bool BeginFrame() { return true; }
|
||||
void EndFrame();
|
||||
VideoModeParams GetActualVideoModeParams() const { return m_Params; }
|
||||
ActualVideoModeParams GetActualVideoModeParams() const { return m_Params; }
|
||||
void SetBlendMode( BlendMode ) { }
|
||||
bool SupportsTextureFormat( RagePixelFormat, bool /* realtime */ =false ) { return true; }
|
||||
bool SupportsPerVertexMatrixScale() { return false; }
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat,
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat,
|
||||
RageSurface* /* img */,
|
||||
bool /* bGenerateMipMaps */ ) { return 1; }
|
||||
void UpdateTexture(
|
||||
unsigned /* iTexHandle */,
|
||||
void UpdateTexture(
|
||||
unsigned /* iTexHandle */,
|
||||
RageSurface* /* img */,
|
||||
int /* xoffset */, int /* yoffset */, int /* width */, int /* height */
|
||||
int /* xoffset */, int /* yoffset */, int /* width */, int /* height */
|
||||
) { }
|
||||
void DeleteTexture( unsigned /* iTexHandle */ ) { }
|
||||
void ClearAllTextures() { }
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void ClearZBuffer() { }
|
||||
void SetCullMode( CullMode ) { }
|
||||
void SetAlphaTest( bool ) { }
|
||||
void SetMaterial(
|
||||
void SetMaterial(
|
||||
const RageColor & /* unreferenced: emissive */,
|
||||
const RageColor & /* unreferenced: ambient */,
|
||||
const RageColor & /* unreferenced: diffuse */,
|
||||
|
||||
+106
-20
@@ -15,7 +15,7 @@ using namespace RageDisplay_Legacy_Helpers;
|
||||
#include "RageUtil.h"
|
||||
#include "EnumHelper.h"
|
||||
#include "Foreach.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "LocalizedString.h"
|
||||
|
||||
#include "arch/LowLevelWindow/LowLevelWindow.h"
|
||||
@@ -63,7 +63,7 @@ static const GLenum RageSpriteVertexFormat = GL_T2F_C4F_N3F_V3F;
|
||||
/* If we support texture matrix scaling, a handle to the vertex program: */
|
||||
static GLhandleARB g_bTextureMatrixShader = 0;
|
||||
|
||||
static map<unsigned, RenderTarget *> g_mapRenderTargets;
|
||||
static std::map<unsigned, RenderTarget *> g_mapRenderTargets;
|
||||
static RenderTarget *g_pCurrentRenderTarget = NULL;
|
||||
|
||||
static LowLevelWindow *g_pWind;
|
||||
@@ -264,6 +264,7 @@ RageDisplay_Legacy::RageDisplay_Legacy()
|
||||
|
||||
g_pWind = NULL;
|
||||
g_bTextureMatrixShader = 0;
|
||||
offscreenRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
RString GetInfoLog( GLhandleARB h )
|
||||
@@ -561,10 +562,10 @@ RageDisplay_Legacy::~RageDisplay_Legacy()
|
||||
delete g_pWind;
|
||||
}
|
||||
|
||||
void RageDisplay_Legacy::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
void RageDisplay_Legacy::GetDisplaySpecs(DisplaySpecs &out) const
|
||||
{
|
||||
out.clear();
|
||||
g_pWind->GetDisplayResolutions( out );
|
||||
g_pWind->GetDisplaySpecs(out);
|
||||
}
|
||||
|
||||
static void CheckPalettedTextures()
|
||||
@@ -685,7 +686,9 @@ void SetupExtensions()
|
||||
const float fGLUVersion = StringToFloat( (const char *) gluGetString(GLU_VERSION) );
|
||||
g_gluVersion = lrintf( fGLUVersion * 10 );
|
||||
|
||||
#ifndef HAVE_X11 // LLW_X11 needs to init GLEW early for GLX exts
|
||||
glewInit();
|
||||
#endif
|
||||
|
||||
g_iMaxTextureUnits = 1;
|
||||
if (GLEW_ARB_multitexture)
|
||||
@@ -712,6 +715,39 @@ void SetupExtensions()
|
||||
}
|
||||
}
|
||||
|
||||
bool RageDisplay_Legacy::UseOffscreenRenderTarget()
|
||||
{
|
||||
if ( !GetActualVideoModeParams().renderOffscreen || !TEXTUREMAN )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !offscreenRenderTarget )
|
||||
{
|
||||
RenderTargetParam param;
|
||||
param.bWithDepthBuffer = true;
|
||||
param.bWithAlpha = true;
|
||||
param.bFloat = false;
|
||||
param.iWidth = GetActualVideoModeParams().width;
|
||||
param.iHeight = GetActualVideoModeParams().height;
|
||||
RageTextureID id( ssprintf( "FullscreenTexture%dx%d", param.iWidth,
|
||||
param.iHeight ) );
|
||||
// See if we have this texture loaded already
|
||||
// (not GC'd yet). If it exists and we try to recreate
|
||||
// it, we'll get an error
|
||||
if ( TEXTUREMAN->IsTextureRegistered( id ) )
|
||||
{
|
||||
offscreenRenderTarget = static_cast<RageTextureRenderTarget*>( TEXTUREMAN->LoadTexture( id ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
offscreenRenderTarget = new RageTextureRenderTarget( id, param );
|
||||
TEXTUREMAN->RegisterTexture( id, offscreenRenderTarget );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RageDisplay_Legacy::ResolutionChanged()
|
||||
{
|
||||
//LOG->Warn( "RageDisplay_Legacy::ResolutionChanged" );
|
||||
@@ -721,6 +757,13 @@ void RageDisplay_Legacy::ResolutionChanged()
|
||||
EndFrame();
|
||||
|
||||
RageDisplay::ResolutionChanged();
|
||||
|
||||
if (offscreenRenderTarget && TEXTUREMAN)
|
||||
{
|
||||
TEXTUREMAN->UnloadTexture( offscreenRenderTarget );
|
||||
offscreenRenderTarget = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return true if mode change was successful.
|
||||
@@ -746,6 +789,7 @@ RString RageDisplay_Legacy::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
if (TEXTUREMAN)
|
||||
TEXTUREMAN->InvalidateTextures();
|
||||
|
||||
|
||||
/* Delete all render targets. They may have associated resources other than
|
||||
* the texture itself. */
|
||||
FOREACHM( unsigned, RenderTarget *, g_mapRenderTargets, rt )
|
||||
@@ -784,8 +828,8 @@ bool RageDisplay_Legacy::BeginFrame()
|
||||
{
|
||||
/* We do this in here, rather than ResolutionChanged, or we won't update the
|
||||
* viewport for the concurrent rendering context. */
|
||||
int fWidth = g_pWind->GetActualVideoModeParams().width;
|
||||
int fHeight = g_pWind->GetActualVideoModeParams().height;
|
||||
int fWidth = g_pWind->GetActualVideoModeParams().windowWidth;
|
||||
int fHeight = g_pWind->GetActualVideoModeParams().windowHeight;
|
||||
|
||||
glViewport( 0, 0, fWidth, fHeight );
|
||||
|
||||
@@ -793,11 +837,34 @@ bool RageDisplay_Legacy::BeginFrame()
|
||||
SetZWrite( true );
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
return RageDisplay::BeginFrame();
|
||||
bool beginFrame = RageDisplay::BeginFrame();
|
||||
if (beginFrame && UseOffscreenRenderTarget()) {
|
||||
offscreenRenderTarget->BeginRenderingTo( false );
|
||||
}
|
||||
|
||||
return beginFrame;
|
||||
}
|
||||
|
||||
void RageDisplay_Legacy::EndFrame()
|
||||
{
|
||||
if (UseOffscreenRenderTarget())
|
||||
{
|
||||
offscreenRenderTarget->FinishRenderingTo();
|
||||
Sprite fullscreenSprite;
|
||||
// We've got a hold of this, don't want sprite deleting it when
|
||||
// it's deleted
|
||||
offscreenRenderTarget->m_iRefCount++;
|
||||
fullscreenSprite.SetTexture(offscreenRenderTarget);
|
||||
fullscreenSprite.SetHorizAlign(align_left);
|
||||
fullscreenSprite.SetVertAlign(align_top);
|
||||
CameraPushMatrix();
|
||||
LoadMenuPerspective( 0, GetActualVideoModeParams().width, GetActualVideoModeParams().height,
|
||||
static_cast<float> (GetActualVideoModeParams().width) / 2.f,
|
||||
static_cast<float> (GetActualVideoModeParams().height) / 2.f );
|
||||
fullscreenSprite.Draw();
|
||||
CameraPopMatrix();
|
||||
}
|
||||
|
||||
FrameLimitBeforeVsync( g_pWind->GetActualVideoModeParams().rate );
|
||||
g_pWind->SwapBuffers();
|
||||
FrameLimitAfterVsync();
|
||||
@@ -823,20 +890,31 @@ RageSurface* RageDisplay_Legacy::CreateScreenshot()
|
||||
int width = g_pWind->GetActualVideoModeParams().width;
|
||||
int height = g_pWind->GetActualVideoModeParams().height;
|
||||
|
||||
const RagePixelFormatDesc &desc = PIXEL_FORMAT_DESC[RagePixelFormat_RGBA8];
|
||||
RageSurface *image = CreateSurface( width, height, desc.bpp,
|
||||
desc.masks[0], desc.masks[1], desc.masks[2], 0 );
|
||||
RageSurface *image = NULL;
|
||||
if (offscreenRenderTarget) {
|
||||
RageSurface *raw = GetTexture(offscreenRenderTarget->GetTexHandle());
|
||||
image = CreateSurface( offscreenRenderTarget->GetImageWidth(), offscreenRenderTarget->GetImageHeight(),
|
||||
raw->fmt.BitsPerPixel, raw->fmt.Rmask, raw->fmt.Gmask, raw->fmt.Bmask,
|
||||
raw->fmt.Amask );
|
||||
RageSurfaceUtils::Blit(raw, image);
|
||||
delete raw;
|
||||
} else {
|
||||
const RagePixelFormatDesc &desc = PIXEL_FORMAT_DESC[RagePixelFormat_RGBA8];
|
||||
image = CreateSurface( width, height, desc.bpp,
|
||||
desc.masks[0], desc.masks[1], desc.masks[2], 0 );
|
||||
|
||||
DebugFlushGLErrors();
|
||||
DebugFlushGLErrors();
|
||||
|
||||
glReadBuffer( GL_FRONT );
|
||||
DebugAssertNoGLError();
|
||||
//TODO: revisit for MacOS, where backbuffer size can be less than window size
|
||||
glReadBuffer( GL_FRONT );
|
||||
DebugAssertNoGLError();
|
||||
|
||||
glReadPixels( 0, 0, g_pWind->GetActualVideoModeParams().width, g_pWind->GetActualVideoModeParams().height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, image->pixels );
|
||||
DebugAssertNoGLError();
|
||||
glReadPixels( 0, 0, g_pWind->GetActualVideoModeParams().width, g_pWind->GetActualVideoModeParams().height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, image->pixels );
|
||||
DebugAssertNoGLError();
|
||||
|
||||
RageSurfaceUtils::FlipVertically( image );
|
||||
RageSurfaceUtils::FlipVertically( image );
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
@@ -865,7 +943,7 @@ RageSurface *RageDisplay_Legacy::GetTexture( unsigned iTexture )
|
||||
return pImage;
|
||||
}
|
||||
|
||||
VideoModeParams RageDisplay_Legacy::GetActualVideoModeParams() const
|
||||
ActualVideoModeParams RageDisplay_Legacy::GetActualVideoModeParams() const
|
||||
{
|
||||
return g_pWind->GetActualVideoModeParams();
|
||||
}
|
||||
@@ -2483,6 +2561,14 @@ bool RageDisplay_Legacy::SupportsRenderToTexture() const
|
||||
return GLEW_EXT_framebuffer_object || g_pWind->SupportsRenderToTexture();
|
||||
}
|
||||
|
||||
bool RageDisplay_Legacy::SupportsFullscreenBorderlessWindow() const
|
||||
{
|
||||
// In order to support FSBW, we're going to need the LowLevelWindow implementation
|
||||
// to support creating a fullscreen borderless window, and we're going to need
|
||||
// RenderToTexture support in order to render in alternative resolutions
|
||||
return g_pWind->SupportsFullscreenBorderlessWindow() && SupportsRenderToTexture();
|
||||
}
|
||||
|
||||
/*
|
||||
* Render-to-texture can be implemented in several ways: the generic GL_ARB_pixel_buffer_object,
|
||||
* or platform-specifically. PBO is not available on all hardware that supports RTT,
|
||||
@@ -2525,8 +2611,8 @@ void RageDisplay_Legacy::SetRenderTarget( unsigned iTexture, bool bPreserveTextu
|
||||
DISPLAY->CameraPopMatrix();
|
||||
|
||||
/* Reset the viewport. */
|
||||
int fWidth = g_pWind->GetActualVideoModeParams().width;
|
||||
int fHeight = g_pWind->GetActualVideoModeParams().height;
|
||||
int fWidth = g_pWind->GetActualVideoModeParams().windowWidth;
|
||||
int fHeight = g_pWind->GetActualVideoModeParams().windowHeight;
|
||||
glViewport( 0, 0, fWidth, fHeight );
|
||||
|
||||
if (g_pCurrentRenderTarget)
|
||||
|
||||
+17
-10
@@ -4,9 +4,11 @@
|
||||
#define RAGE_DISPLAY_OGL_H
|
||||
|
||||
#include "RageDisplay.h"
|
||||
#include "RageTextureRenderTarget.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
/* Making an OpenGL call doesn't also flush the error state; if we happen
|
||||
* to have an error from a previous call, then the assert below will fail.
|
||||
* to have an error from a previous call, then the assert below will fail.
|
||||
* Flush it. */
|
||||
#define FlushGLErrors() do { } while( glGetError() != GL_NO_ERROR )
|
||||
#define AssertNoGLError() \
|
||||
@@ -31,7 +33,7 @@ public:
|
||||
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
|
||||
|
||||
virtual RString GetApiDescription() const { return "OpenGL"; }
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
|
||||
void ResolutionChanged();
|
||||
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
|
||||
|
||||
@@ -41,22 +43,23 @@ public:
|
||||
void BeginConcurrentRendering();
|
||||
void EndConcurrentRendering();
|
||||
|
||||
bool BeginFrame();
|
||||
bool BeginFrame();
|
||||
void EndFrame();
|
||||
VideoModeParams GetActualVideoModeParams() const;
|
||||
ActualVideoModeParams GetActualVideoModeParams() const;
|
||||
void SetBlendMode( BlendMode mode );
|
||||
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
|
||||
bool SupportsPerVertexMatrixScale();
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat pixfmt,
|
||||
unsigned CreateTexture(
|
||||
RagePixelFormat pixfmt,
|
||||
RageSurface* img,
|
||||
bool bGenerateMipMaps );
|
||||
void UpdateTexture(
|
||||
unsigned iTexHandle,
|
||||
void UpdateTexture(
|
||||
unsigned iTexHandle,
|
||||
RageSurface* img,
|
||||
int xoffset, int yoffset, int width, int height
|
||||
int xoffset, int yoffset, int width, int height
|
||||
);
|
||||
void DeleteTexture( unsigned iTexHandle );
|
||||
bool UseOffscreenRenderTarget();
|
||||
RageSurface *GetTexture( unsigned iTexture );
|
||||
RageTextureLock *CreateTextureLock();
|
||||
|
||||
@@ -70,6 +73,7 @@ public:
|
||||
void SetEffectMode( EffectMode effect );
|
||||
bool IsEffectModeSupported( EffectMode effect );
|
||||
bool SupportsRenderToTexture() const;
|
||||
bool SupportsFullscreenBorderlessWindow() const;
|
||||
unsigned CreateRenderTarget( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut );
|
||||
unsigned GetRenderTarget();
|
||||
void SetRenderTarget( unsigned iHandle, bool bPreserveTexture );
|
||||
@@ -81,7 +85,7 @@ public:
|
||||
void ClearZBuffer();
|
||||
void SetCullMode( CullMode mode );
|
||||
void SetAlphaTest( bool b );
|
||||
void SetMaterial(
|
||||
void SetMaterial(
|
||||
const RageColor &emissive,
|
||||
const RageColor &ambient,
|
||||
const RageColor &diffuse,
|
||||
@@ -125,6 +129,9 @@ protected:
|
||||
bool SupportsSurfaceFormat( RagePixelFormat pixfmt );
|
||||
|
||||
void SendCurrentMatrices();
|
||||
|
||||
private:
|
||||
RageTextureRenderTarget *offscreenRenderTarget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -247,6 +247,7 @@ ScreenManager::ScreenManager()
|
||||
m_bZeroNextUpdate = false;
|
||||
m_PopTopScreen = SM_Invalid;
|
||||
m_OnDonePreparingScreen = SM_Invalid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "Game.h"
|
||||
#include "Foreach.h"
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "SpecialFiles.h"
|
||||
#include "RageLog.h"
|
||||
@@ -248,22 +248,25 @@ static void ThemeChoices( vector<RString> &out )
|
||||
*s = THEME->GetThemeDisplayName( *s );
|
||||
}
|
||||
|
||||
static DisplayResolutions display_resolution_list;
|
||||
static void cache_display_resolution_list()
|
||||
static DisplaySpecs display_specs;
|
||||
static void cache_display_specs()
|
||||
{
|
||||
if(display_resolution_list.empty())
|
||||
if(display_specs.empty())
|
||||
{
|
||||
DISPLAY->GetDisplayResolutions(display_resolution_list);
|
||||
DISPLAY->GetDisplaySpecs(display_specs);
|
||||
}
|
||||
}
|
||||
|
||||
static void DisplayResolutionChoices( vector<RString> &out )
|
||||
{
|
||||
cache_display_resolution_list();
|
||||
FOREACHS_CONST( DisplayResolution, display_resolution_list, iter )
|
||||
cache_display_specs();
|
||||
FOREACHS_CONST( DisplaySpec, display_specs, iter )
|
||||
{
|
||||
RString s = ssprintf("%dx%d", iter->iWidth, iter->iHeight);
|
||||
out.push_back( s );
|
||||
if (iter->currentMode() != NULL)
|
||||
{
|
||||
RString s = ssprintf("%dx%d", iter->currentMode()->width, iter->currentMode()->height);
|
||||
out.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,6 +519,8 @@ static void MaxHighScoresPerListForPlayer(int& sel, bool to_sel, ConfOption cons
|
||||
|
||||
|
||||
#include "LuaManager.h"
|
||||
#include "LuaBinding.h"
|
||||
|
||||
static int GetTimingDifficulty()
|
||||
{
|
||||
int iTimingDifficulty = 0;
|
||||
@@ -583,12 +588,14 @@ static void DisplayResolutionM( int &sel, bool ToSel, const ConfOption *pConfOpt
|
||||
{
|
||||
static vector<res_t> res_choices;
|
||||
|
||||
if(res_choices.empty())
|
||||
if( res_choices.empty() )
|
||||
{
|
||||
cache_display_resolution_list();
|
||||
FOREACHS_CONST(DisplayResolution, display_resolution_list, iter)
|
||||
FOREACHS_CONST( DisplaySpec, display_specs, iter )
|
||||
{
|
||||
res_choices.push_back(res_t(iter->iWidth, iter->iHeight));
|
||||
if ( iter->currentMode() != NULL )
|
||||
{
|
||||
res_choices.push_back( res_t( iter->currentMode()->width, iter->currentMode()->height ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,10 +740,10 @@ static void InitializeConfOptions()
|
||||
if( !g_ConfOptions.empty() )
|
||||
return;
|
||||
|
||||
// Clear the display_resolution_list so that we don't get problems from
|
||||
// Clear the display_specs so that we don't get problems from
|
||||
// caching it. If the DisplayResolution option row is on the screen, it'll
|
||||
// recache the list. -Kyz
|
||||
display_resolution_list.clear();
|
||||
display_specs.clear();
|
||||
|
||||
// There are a couple ways of getting the current preference column or turning
|
||||
// a new choice in the interface into a new preference. The easiest is when
|
||||
@@ -958,6 +965,19 @@ void ConfOption::MakeOptionsList( vector<RString> &out ) const
|
||||
out = names;
|
||||
}
|
||||
|
||||
static const char *OptEffectNames[] = {
|
||||
"SavePreferences",
|
||||
"ApplyGraphics",
|
||||
"ApplyTheme",
|
||||
"ChangeGame",
|
||||
"ApplySound",
|
||||
"ApplySong",
|
||||
"ApplyAspectRatio"
|
||||
};
|
||||
XToString( OptEffect );
|
||||
StringToX( OptEffect );
|
||||
LuaXType( OptEffect );
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2003-2004
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
#ifndef SCREEN_OPTIONS_MASTER_PREFS_H
|
||||
#define SCREEN_OPTIONS_MASTER_PREFS_H
|
||||
|
||||
#include "EnumHelper.h"
|
||||
|
||||
static const int MAX_OPTIONS=16;
|
||||
#define OPT_SAVE_PREFERENCES (1<<0)
|
||||
#define OPT_APPLY_GRAPHICS (1<<1)
|
||||
#define OPT_APPLY_THEME (1<<2)
|
||||
#define OPT_CHANGE_GAME (1<<3)
|
||||
#define OPT_APPLY_SOUND (1<<4)
|
||||
#define OPT_APPLY_SONG (1<<5)
|
||||
#define OPT_APPLY_ASPECT_RATIO (1<<6)
|
||||
enum OptEffect
|
||||
{
|
||||
OPT_SAVE_PREFERENCES = (1<<0),
|
||||
OPT_APPLY_GRAPHICS = (1<<1),
|
||||
OPT_APPLY_THEME = (1<<2),
|
||||
OPT_CHANGE_GAME = (1<<3),
|
||||
OPT_APPLY_SOUND = (1<<4),
|
||||
OPT_APPLY_SONG = (1<<5),
|
||||
OPT_APPLY_ASPECT_RATIO = (1<<6),
|
||||
NUM_OptEffect = 7,
|
||||
OptEffect_Invalid = MAX_OPTIONS+1
|
||||
};
|
||||
const RString& OptEffectToString( OptEffect e );
|
||||
OptEffect StringToOptEffect( const std::string &e );
|
||||
LuaDeclareType( OptEffect );
|
||||
|
||||
struct ConfOption
|
||||
{
|
||||
|
||||
+37
-12
@@ -84,6 +84,31 @@ Sprite::Sprite( const Sprite &cpy ):
|
||||
m_pTexture = NULL;
|
||||
}
|
||||
|
||||
Sprite &Sprite::operator=( Sprite other )
|
||||
{
|
||||
using std::swap;
|
||||
#define SWAP(a) swap(a, other.a)
|
||||
SWAP( m_States );
|
||||
SWAP(m_animation_length_seconds);
|
||||
SWAP( m_iCurState );
|
||||
SWAP( m_fSecsIntoState );
|
||||
SWAP( m_bUsingCustomTexCoords );
|
||||
SWAP( m_bUsingCustomPosCoords );
|
||||
SWAP( m_bSkipNextUpdate );
|
||||
SWAP( m_DecodeMovie );
|
||||
SWAP( m_EffectMode );
|
||||
memcpy( m_CustomTexCoords, other.m_CustomTexCoords, sizeof(m_CustomTexCoords) );
|
||||
memcpy( m_CustomPosCoords, other.m_CustomPosCoords, sizeof(m_CustomPosCoords) );
|
||||
SWAP( m_fRememberedClipWidth );
|
||||
SWAP( m_fRememberedClipHeight );
|
||||
SWAP( m_fTexCoordVelocityX );
|
||||
SWAP( m_fTexCoordVelocityY );
|
||||
SWAP(m_use_effect_clock_for_texcoords);
|
||||
SWAP(m_pTexture);
|
||||
#undef SWAP
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Sprite::InitState()
|
||||
{
|
||||
Actor::InitState();
|
||||
@@ -934,7 +959,7 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
|
||||
Sprite::ScaleToCover( RectF(0, 0, fWidth, fHeight) );
|
||||
// find which dimension is larger
|
||||
bool bXDimNeedsToBeCropped = GetZoomedWidth() > fWidth+0.01;
|
||||
|
||||
|
||||
if( bXDimNeedsToBeCropped ) // crop X
|
||||
{
|
||||
float fPercentageToCutOff = (this->GetZoomedWidth() - fWidth) / this->GetZoomedWidth();
|
||||
@@ -943,9 +968,9 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
|
||||
|
||||
// generate a rectangle with new texture coordinates
|
||||
RectF fCustomImageRect(
|
||||
fPercentageToCutOffEachSide,
|
||||
0,
|
||||
1 - fPercentageToCutOffEachSide,
|
||||
fPercentageToCutOffEachSide,
|
||||
0,
|
||||
1 - fPercentageToCutOffEachSide,
|
||||
1 );
|
||||
SetCustomImageRect( fCustomImageRect );
|
||||
}
|
||||
@@ -957,9 +982,9 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
|
||||
|
||||
// generate a rectangle with new texture coordinates
|
||||
RectF fCustomImageRect(
|
||||
0,
|
||||
0,
|
||||
fPercentageToCutOffEachSide,
|
||||
1,
|
||||
1,
|
||||
1 - fPercentageToCutOffEachSide );
|
||||
SetCustomImageRect( fCustomImageRect );
|
||||
}
|
||||
@@ -995,7 +1020,7 @@ void Sprite::CropTo( float fWidth, float fHeight )
|
||||
Sprite::ScaleToCover( RectF(0, 0, fWidth, fHeight) );
|
||||
// find which dimension is larger
|
||||
bool bXDimNeedsToBeCropped = GetZoomedWidth() > fWidth+0.01;
|
||||
|
||||
|
||||
if( bXDimNeedsToBeCropped ) // crop X
|
||||
{
|
||||
float fPercentageToCutOff = (this->GetZoomedWidth() - fWidth) / this->GetZoomedWidth();
|
||||
@@ -1003,9 +1028,9 @@ void Sprite::CropTo( float fWidth, float fHeight )
|
||||
|
||||
// generate a rectangle with new texture coordinates
|
||||
RectF fCustomImageRect(
|
||||
fPercentageToCutOffEachSide,
|
||||
0,
|
||||
1 - fPercentageToCutOffEachSide,
|
||||
fPercentageToCutOffEachSide,
|
||||
0,
|
||||
1 - fPercentageToCutOffEachSide,
|
||||
1 );
|
||||
SetCustomImageRect( fCustomImageRect );
|
||||
}
|
||||
@@ -1016,9 +1041,9 @@ void Sprite::CropTo( float fWidth, float fHeight )
|
||||
|
||||
// generate a rectangle with new texture coordinates
|
||||
RectF fCustomImageRect(
|
||||
0,
|
||||
0,
|
||||
fPercentageToCutOffEachSide,
|
||||
1,
|
||||
1,
|
||||
1 - fPercentageToCutOffEachSide );
|
||||
SetCustomImageRect( fCustomImageRect );
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
|
||||
Sprite();
|
||||
Sprite( const Sprite &cpy );
|
||||
Sprite &operator=( Sprite other );
|
||||
virtual ~Sprite();
|
||||
|
||||
// See explanation in source.
|
||||
|
||||
+10
-2
@@ -96,7 +96,8 @@ void StepMania::GetPreferredVideoModeParams( VideoModeParams ¶msOut )
|
||||
}
|
||||
|
||||
paramsOut = VideoModeParams(
|
||||
PREFSMAN->m_bWindowed,
|
||||
PREFSMAN->m_bWindowed || PREFSMAN->m_bFullscreenIsBorderlessWindow,
|
||||
PREFSMAN->m_sDisplayId,
|
||||
iWidth,
|
||||
PREFSMAN->m_iDisplayHeight,
|
||||
PREFSMAN->m_iDisplayColorDepth,
|
||||
@@ -106,6 +107,7 @@ void StepMania::GetPreferredVideoModeParams( VideoModeParams ¶msOut )
|
||||
PREFSMAN->m_bSmoothLines,
|
||||
PREFSMAN->m_bTrilinearFiltering,
|
||||
PREFSMAN->m_bAnisotropicFiltering,
|
||||
!PREFSMAN->m_bWindowed && PREFSMAN->m_bFullscreenIsBorderlessWindow,
|
||||
CommonMetrics::WINDOW_TITLE,
|
||||
THEME->GetPathG("Common","window icon"),
|
||||
PREFSMAN->m_bPAL,
|
||||
@@ -146,7 +148,13 @@ static void StoreActualGraphicOptions()
|
||||
* we don't go through the process of auto-detecting a usable video mode
|
||||
* every time. */
|
||||
const VideoModeParams ¶ms = DISPLAY->GetActualVideoModeParams();
|
||||
PREFSMAN->m_bWindowed.Set( params.windowed );
|
||||
PREFSMAN->m_bWindowed.Set( params.windowed && !params.bWindowIsFullscreenBorderless );
|
||||
if (!params.windowed && !params.bWindowIsFullscreenBorderless) {
|
||||
// In all other cases, want to preserve the value of this preference,
|
||||
// but if DISPLAY decides to go fullscreen exclusive, we'll persist that decision
|
||||
PREFSMAN->m_bFullscreenIsBorderlessWindow.Set( false );
|
||||
}
|
||||
|
||||
|
||||
/* If we're windowed, we may have tweaked the width based on the aspect ratio.
|
||||
* Don't save this new value over the preferred value. */
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
#include <set>
|
||||
|
||||
class DisplayResolution;
|
||||
typedef set<DisplayResolution> DisplayResolutions;
|
||||
class DisplaySpec;
|
||||
typedef std::set<DisplaySpec> DisplaySpecs;
|
||||
class VideoModeParams;
|
||||
class ActualVideoModeParams;
|
||||
class RenderTarget;
|
||||
struct RenderTargetParam;
|
||||
/** @brief Handle low-level operations that OGL 1.x doesn't give us. */
|
||||
@@ -22,7 +23,7 @@ public:
|
||||
// bNewDeviceOut is set true if a new device was created and textures
|
||||
// need to be reloaded.
|
||||
virtual RString TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) = 0;
|
||||
virtual void GetDisplayResolutions( DisplayResolutions &out ) const = 0;
|
||||
virtual void GetDisplaySpecs(DisplaySpecs &out) const = 0;
|
||||
|
||||
virtual void LogDebugInformation() const { }
|
||||
virtual bool IsSoftwareRenderer( RString & /* sError */ ) { return false; }
|
||||
@@ -30,11 +31,13 @@ public:
|
||||
virtual void SwapBuffers() = 0;
|
||||
virtual void Update() { }
|
||||
|
||||
virtual const VideoModeParams &GetActualVideoModeParams() const = 0;
|
||||
virtual const ActualVideoModeParams GetActualVideoModeParams() const = 0;
|
||||
|
||||
virtual bool SupportsRenderToTexture() const { return false; }
|
||||
virtual RenderTarget *CreateRenderTarget() { return NULL; }
|
||||
|
||||
virtual bool SupportsFullscreenBorderlessWindow() const { return false; };
|
||||
|
||||
virtual bool SupportsThreadedRendering() { return false; }
|
||||
virtual void BeginConcurrentRenderingMainThread() { }
|
||||
virtual void EndConcurrentRenderingMainThread() { }
|
||||
|
||||
@@ -22,12 +22,12 @@ public:
|
||||
~LowLevelWindow_MacOSX();
|
||||
void *GetProcAddress( RString s );
|
||||
RString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut );
|
||||
void GetDisplayResolutions( DisplayResolutions &dr ) const;
|
||||
void GetDisplaySpecs( DisplaySpecs &specs ) const;
|
||||
|
||||
void SwapBuffers();
|
||||
void Update();
|
||||
|
||||
const VideoModeParams &GetActualVideoModeParams() const { return m_CurrentParams; }
|
||||
const ActualVideoModeParams GetActualVideoModeParams() const { return m_CurrentParams; }
|
||||
|
||||
bool SupportsRenderToTexture() const { return true; }
|
||||
RenderTarget *CreateRenderTarget();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#import "global.h"
|
||||
#import "LowLevelWindow_MacOSX.h"
|
||||
#import "DisplayResolutions.h"
|
||||
#import "DisplaySpec.h"
|
||||
#import "RageUtil.h"
|
||||
#import "RageThreads.h"
|
||||
#import "RageDisplay_OGL_Helpers.h"
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
- (void) setParams:(NSValue *)params
|
||||
{
|
||||
const VideoModeParams &p = *(const VideoModeParams *)[params pointerValue];
|
||||
NSRect contentRect = { { 0, 0 }, { p.width, p.height } };
|
||||
NSRect contentRect = { { 0, 0 }, { static_cast<CGFloat>(p.width), static_cast<CGFloat>(p.height) } };
|
||||
|
||||
[m_Window setContentSize:contentRect.size];
|
||||
[m_Window setTitle:[NSString stringWithUTF8String:p.sWindowTitle.c_str()]];
|
||||
@@ -564,28 +564,50 @@ static bool GetBoolValue( CFTypeRef r )
|
||||
return r && CFGetTypeID( r ) == CFBooleanGetTypeID() && CFBooleanGetValue( CFBooleanRef(r) );
|
||||
}
|
||||
|
||||
void LowLevelWindow_MacOSX::GetDisplayResolutions( DisplayResolutions &dr ) const
|
||||
static double GetDoubleValue( CFTypeRef r )
|
||||
{
|
||||
double ret;
|
||||
|
||||
if( !r || CFGetTypeID(r) != CFNumberGetTypeID() || !CFNumberGetValue(CFNumberRef(r), kCFNumberDoubleType, &ret) )
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DisplayMode ConvertDisplayMode( CFDictionaryRef dict )
|
||||
{
|
||||
int width = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayWidth) );
|
||||
int height = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayHeight) );
|
||||
double rate = GetDoubleValue( CFDictionaryGetValue(dict, kCGDisplayRefreshRate) );
|
||||
|
||||
return { static_cast<unsigned int> (width), static_cast<unsigned int> (height), rate};
|
||||
}
|
||||
|
||||
void LowLevelWindow_MacOSX::GetDisplaySpecs( DisplaySpecs &specs ) const
|
||||
{
|
||||
CFArrayRef modes = CGDisplayAvailableModes( kCGDirectMainDisplay );
|
||||
ASSERT( modes );
|
||||
const CFIndex count = CFArrayGetCount( modes );
|
||||
|
||||
|
||||
std::set<DisplayMode> available;
|
||||
CFDictionaryRef currentModeDict = CGDisplayCurrentMode( kCGDirectMainDisplay );
|
||||
DisplayMode current = ConvertDisplayMode( currentModeDict );
|
||||
|
||||
for( CFIndex i = 0; i < count; ++i )
|
||||
{
|
||||
CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, i );
|
||||
int width = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayWidth) );
|
||||
int height = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayHeight) );
|
||||
CFTypeRef safe = CFDictionaryGetValue( dict, kCGDisplayModeIsSafeForHardware );
|
||||
bool stretched = GetBoolValue( CFDictionaryGetValue(dict, kCGDisplayModeIsStretched) );
|
||||
|
||||
if( !width || !height )
|
||||
DisplayMode mode = ConvertDisplayMode( dict );
|
||||
|
||||
if( !mode.width || !mode.height )
|
||||
continue;
|
||||
if( safe && !GetBoolValue( safe ) )
|
||||
continue;
|
||||
DisplayResolution res = { width, height, stretched };
|
||||
dr.insert( res );
|
||||
available.insert( mode );
|
||||
}
|
||||
// Do not release modes! We don't own them here.
|
||||
RectI bounds( 0, 0, current.width, current.height );
|
||||
DisplaySpec s( "", "Fullscreen", available, current, bounds );
|
||||
specs.insert( s );
|
||||
}
|
||||
|
||||
void LowLevelWindow_MacOSX::SwapBuffers()
|
||||
|
||||
@@ -59,9 +59,9 @@ LowLevelWindow_Win32::~LowLevelWindow_Win32()
|
||||
GraphicsWindow::Shutdown();
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
void LowLevelWindow_Win32::GetDisplaySpecs( DisplaySpecs &out ) const
|
||||
{
|
||||
GraphicsWindow::GetDisplayResolutions( out );
|
||||
GraphicsWindow::GetDisplaySpecs( out );
|
||||
}
|
||||
|
||||
int ChooseWindowPixelFormat( const VideoModeParams &p, PIXELFORMATDESCRIPTOR *pixfmt )
|
||||
@@ -292,7 +292,7 @@ void LowLevelWindow_Win32::Update()
|
||||
GraphicsWindow::Update();
|
||||
}
|
||||
|
||||
const VideoModeParams &LowLevelWindow_Win32::GetActualVideoModeParams() const
|
||||
const ActualVideoModeParams LowLevelWindow_Win32::GetActualVideoModeParams() const
|
||||
{
|
||||
return GraphicsWindow::GetParams();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
~LowLevelWindow_Win32();
|
||||
void *GetProcAddress( RString s );
|
||||
RString TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut );
|
||||
void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
void GetDisplaySpecs( DisplaySpecs &out ) const;
|
||||
bool IsSoftwareRenderer( RString &sError );
|
||||
void SwapBuffers();
|
||||
void Update();
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
virtual bool SupportsRenderToTexture() const { return true; }
|
||||
virtual RenderTarget *CreateRenderTarget();
|
||||
|
||||
const VideoModeParams &GetActualVideoModeParams() const;
|
||||
const ActualVideoModeParams GetActualVideoModeParams() const;
|
||||
};
|
||||
|
||||
#ifdef ARCH_LOW_LEVEL_WINDOW
|
||||
|
||||
@@ -5,31 +5,54 @@
|
||||
#include "archutils/Unix/X11Helper.h"
|
||||
#include "PrefsManager.h" // XXX
|
||||
#include "RageDisplay.h" // VideoModeParams
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "LocalizedString.h"
|
||||
|
||||
#include "RageDisplay_OGL_Helpers.h"
|
||||
using namespace RageDisplay_Legacy_Helpers;
|
||||
using namespace X11Helper;
|
||||
|
||||
#include <stack>
|
||||
#include <set>
|
||||
#include <math.h> // ceil()
|
||||
#include <GL/glxew.h>
|
||||
#define GLX_GLXEXT_PROTOTYPES
|
||||
#include <GL/glx.h> // All sorts of stuff...
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#if defined(HAVE_XINERAMA)
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBXTST)
|
||||
#include <X11/extensions/XTest.h>
|
||||
#endif
|
||||
|
||||
// Display ID for treating the entire X screen as the display
|
||||
const std::string ID_XSCREEN = "XSCREEN_RANDR";
|
||||
|
||||
static GLXContext g_pContext = NULL;
|
||||
static GLXContext g_pBackgroundContext = NULL;
|
||||
static Window g_AltWindow = None;
|
||||
static Rotation g_OldRotation;
|
||||
static int g_iOldSize;
|
||||
XRRScreenConfiguration *g_pScreenConfig = NULL;
|
||||
static bool g_bChangedScreenSize = false;
|
||||
static SizeID g_iOldSize = None;
|
||||
static Rotation g_OldRotation = RR_Rotate_0;
|
||||
static XRRScreenConfiguration *g_pScreenConfig = nullptr;
|
||||
static RRMode g_originalRandRMode = None;
|
||||
static RROutput g_usedCrtc = None;
|
||||
static int g_iRandRVerMinor = 0;
|
||||
static int g_iRandRVerMajor = 0;
|
||||
static bool g_bUseXRandR12 = false;
|
||||
static bool g_bUseXinerama = false;
|
||||
|
||||
inline float calcRandRRefresh( unsigned long iPixelClock, int iHTotal, int iVTotal )
|
||||
{
|
||||
// Pixel Clock divided by total pixels in mode,
|
||||
// not just those onscreen!
|
||||
return ( iPixelClock ) / ( iHTotal * iVTotal );
|
||||
}
|
||||
|
||||
bool NetWMSupported(Display *Dpy, Atom feature);
|
||||
|
||||
static LocalizedString FAILED_CONNECTION_XSERVER( "LowLevelWindow_X11", "Failed to establish a connection with the X server" );
|
||||
LowLevelWindow_X11::LowLevelWindow_X11()
|
||||
@@ -37,6 +60,18 @@ LowLevelWindow_X11::LowLevelWindow_X11()
|
||||
if( !OpenXConnection() )
|
||||
RageException::Throw( "%s", FAILED_CONNECTION_XSERVER.GetValue().c_str() );
|
||||
|
||||
if( XRRQueryVersion( Dpy, &g_iRandRVerMajor, &g_iRandRVerMinor ) && g_iRandRVerMajor >= 1 && g_iRandRVerMinor >= 2) g_bUseXRandR12 = true;
|
||||
#ifdef HAVE_XINERAMA
|
||||
int xinerama_event_base = 0;
|
||||
int xinerama_error_base = 0;
|
||||
Atom fullscreen_monitors = XInternAtom( Dpy, "_NET_WM_FULLSCREEN_MONITORS", False );
|
||||
if (XineramaQueryExtension( Dpy, &xinerama_event_base, &xinerama_error_base ) &&
|
||||
NetWMSupported( Dpy, fullscreen_monitors ))
|
||||
{
|
||||
g_bUseXinerama = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const int iScreen = DefaultScreen( Dpy );
|
||||
int iXServerVersion = XVendorRelease( Dpy ); /* eg. 40201001 */
|
||||
int iMajor = iXServerVersion / 10000000; iXServerVersion %= 10000000;
|
||||
@@ -50,7 +85,6 @@ LowLevelWindow_X11::LowLevelWindow_X11()
|
||||
LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( Dpy, GLX_VENDOR ), glXGetClientString( Dpy, GLX_VERSION ) );
|
||||
m_bWasWindowed = true;
|
||||
g_pScreenConfig = XRRGetScreenInfo( Dpy, RootWindow(Dpy, DefaultScreen(Dpy)) );
|
||||
g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation );
|
||||
}
|
||||
|
||||
LowLevelWindow_X11::~LowLevelWindow_X11()
|
||||
@@ -58,8 +92,7 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
|
||||
// Reset the display
|
||||
if( !m_bWasWindowed )
|
||||
{
|
||||
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime );
|
||||
|
||||
RestoreOutputConfig();
|
||||
XUngrabKeyboard( Dpy, CurrentTime );
|
||||
}
|
||||
if( g_pContext )
|
||||
@@ -72,9 +105,6 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
|
||||
glXDestroyContext( Dpy, g_pBackgroundContext );
|
||||
g_pBackgroundContext = NULL;
|
||||
}
|
||||
XRRFreeScreenConfigInfo( g_pScreenConfig );
|
||||
g_pScreenConfig = NULL;
|
||||
|
||||
XDestroyWindow( Dpy, Win );
|
||||
Win = None;
|
||||
XDestroyWindow( Dpy, g_AltWindow );
|
||||
@@ -82,6 +112,29 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
|
||||
CloseXConnection();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore saved X screen/CRTC configuration
|
||||
*/
|
||||
void LowLevelWindow_X11::RestoreOutputConfig() {
|
||||
if (g_bChangedScreenSize) {
|
||||
XRRSetScreenConfig(Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation,
|
||||
CurrentTime);
|
||||
}
|
||||
if (g_usedCrtc != None) {
|
||||
ASSERT(g_bUseXRandR12);
|
||||
XRRScreenResources *res = XRRGetScreenResources(Dpy, Win);
|
||||
XRRCrtcInfo *conf = XRRGetCrtcInfo(Dpy, res, g_usedCrtc);
|
||||
XRRSetCrtcConfig(Dpy, res, g_usedCrtc, conf->timestamp, conf->x, conf->y, g_originalRandRMode, conf->rotation,
|
||||
conf->outputs, conf->noutput);
|
||||
XRRFreeScreenResources(res);
|
||||
XRRFreeCrtcInfo(conf);
|
||||
}
|
||||
g_iOldSize = None;
|
||||
g_bChangedScreenSize = false;
|
||||
g_usedCrtc = None;
|
||||
g_OldRotation = RR_Rotate_0;
|
||||
}
|
||||
|
||||
void *LowLevelWindow_X11::GetProcAddress( RString s )
|
||||
{
|
||||
// XXX: We should check whether glXGetProcAddress or
|
||||
@@ -92,19 +145,20 @@ void *LowLevelWindow_X11::GetProcAddress( RString s )
|
||||
|
||||
RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut )
|
||||
{
|
||||
#if defined(UNIX)
|
||||
/* nVidia cards:
|
||||
* This only works the first time we set up a window; after that, the
|
||||
* drivers appear to cache the value, so you have to actually restart
|
||||
* the program to change it again. */
|
||||
static char buf[128];
|
||||
strcpy( buf, "__GL_SYNC_TO_VBLANK=" );
|
||||
strcat( buf, p.vsync?"1":"0" );
|
||||
putenv( buf );
|
||||
#endif
|
||||
// We're going to be interested in MapNotify/ConfigureNotify events in this routine,
|
||||
// so ensure our event mask includes these, restore it on exit
|
||||
XWindowAttributes winAttrib;
|
||||
auto restore = [&](XWindowAttributes *attr) { XSelectInput( Dpy, Win, attr->your_event_mask );};
|
||||
auto restoreAttrib = std::unique_ptr<XWindowAttributes, decltype(restore)>(&winAttrib, restore);
|
||||
|
||||
// These might change if we're rendering at different resolution than window
|
||||
int windowWidth = p.width;
|
||||
int windowHeight = p.height;
|
||||
bool renderOffscreen = false;
|
||||
|
||||
if( g_pContext == NULL || p.bpp != CurrentParams.bpp || m_bWasWindowed != p.windowed )
|
||||
{
|
||||
bool bFirstRun = g_pContext == NULL;
|
||||
// Different depth, or we didn't make a window before. New context.
|
||||
bNewDeviceOut = true;
|
||||
|
||||
@@ -156,128 +210,377 @@ RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
|
||||
|
||||
glXMakeCurrent( Dpy, Win, g_pContext );
|
||||
|
||||
// Map the window, ensuring we get the MapNotify event
|
||||
XWindowAttributes winAttrib;
|
||||
XGetWindowAttributes( Dpy, Win, &winAttrib );
|
||||
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask );
|
||||
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask | PropertyChangeMask );
|
||||
|
||||
XMapWindow( Dpy, Win );
|
||||
|
||||
// Wait until we actually have a mapped window before trying to
|
||||
// use it!
|
||||
XEvent event;
|
||||
do
|
||||
{
|
||||
XNextEvent( Dpy, &event );
|
||||
} while (event.type != MapNotify);
|
||||
XEvent ev;
|
||||
do {XWindowEvent( Dpy, Win, StructureNotifyMask, &ev );}
|
||||
while ( ev.type != MapNotify);
|
||||
|
||||
// Set the event mask back to what it was
|
||||
XSelectInput( Dpy, Win, winAttrib.your_event_mask );
|
||||
// I can't find official docs saying what happens if you re-init GLEW.
|
||||
// I'll just assume the behavior is undefined.
|
||||
if(bFirstRun)
|
||||
{
|
||||
GLenum err = glewInit();
|
||||
ASSERT( err == GLEW_OK );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're remodeling the existing window, and not touching the context.
|
||||
bNewDeviceOut = false;
|
||||
|
||||
XGetWindowAttributes( Dpy, Win, &winAttrib );
|
||||
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask | PropertyChangeMask );
|
||||
|
||||
if( !p.windowed )
|
||||
{
|
||||
// X11 is an asynchronous beast. If we're resizing an existing
|
||||
// window directly (i.e. override-redirect as opposed to asking the
|
||||
// WM to do it) and don't wait for the window to actually be
|
||||
// resized, we'll get unexpected results from glViewport() etc. I
|
||||
// don't know why, or why it *doesn't* break in the slower process
|
||||
// of waiting for the WM to resize the window.
|
||||
|
||||
// So, set the event mask so we're notified when the window is resized...
|
||||
// Send the resize command...
|
||||
XResizeWindow( Dpy, Win, static_cast<unsigned int> (p.width), static_cast<unsigned int> (p.height) );
|
||||
|
||||
// We'll wait for the notification once we've done everything else,
|
||||
// to save time.
|
||||
}
|
||||
}
|
||||
|
||||
float rate = 60; // Will be unchanged if windowed. Not sure I care.
|
||||
|
||||
if( !p.windowed )
|
||||
{
|
||||
if( m_bWasWindowed )
|
||||
{
|
||||
RestoreOutputConfig();
|
||||
|
||||
if (p.sDisplayId == ID_XSCREEN || p.sDisplayId.empty()) {
|
||||
// If the user changed the resolution while StepMania was windowed we overwrite the resolution to restore with it at exit.
|
||||
g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation );
|
||||
m_bWasWindowed = false;
|
||||
}
|
||||
|
||||
// Find a matching mode.
|
||||
int iSizesXct;
|
||||
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct );
|
||||
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
|
||||
// Find a matching mode.
|
||||
int iSizesXct;
|
||||
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct );
|
||||
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
|
||||
|
||||
int iSizeMatch = -1;
|
||||
int iSizeMatch = -1;
|
||||
|
||||
for( int i = 0; i < iSizesXct; ++i )
|
||||
{
|
||||
if( pSizesX[i].width == p.width && pSizesX[i].height == p.height )
|
||||
{
|
||||
iSizeMatch = i;
|
||||
break;
|
||||
for (int i = 0; i < iSizesXct; ++i) {
|
||||
if (pSizesX[i].width == p.width && pSizesX[i].height == p.height) {
|
||||
iSizeMatch = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iSizeMatch != g_iOldSize) {
|
||||
g_bChangedScreenSize = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set this mode.
|
||||
// XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr)
|
||||
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime );
|
||||
// Set this mode.
|
||||
// XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr)
|
||||
Status s = XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime );
|
||||
if (s)
|
||||
{
|
||||
return "Failed to set screen config";
|
||||
}
|
||||
|
||||
XMoveWindow( Dpy, Win, 0, 0 );
|
||||
|
||||
XRaiseWindow( Dpy, Win );
|
||||
|
||||
// We want to prevent the WM from catching anything that comes from the keyboard.
|
||||
// We should do this every time on fullscreen and not only we entering from windowed mode because we could lose focus at resolution change and that will leave the user input locked.
|
||||
while (XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ));
|
||||
|
||||
} else {
|
||||
ASSERT(g_bUseXRandR12);
|
||||
/* === Configuring a specific CRTC === */
|
||||
// Arcane and undocumented but PROPER XRandR 1.2 method.
|
||||
// What we do is directly reconfigure the CRTC of the primary display,
|
||||
// Which prevents the (RandR) screen itself from resizing, and therefore
|
||||
// leaving user's desktop unmolested.
|
||||
LOG->Info("LowLevelWindow_X11: Using XRandR");
|
||||
|
||||
XRRScreenResources *scrRes = XRRGetScreenResources(Dpy, Win);
|
||||
ASSERT(scrRes != NULL);
|
||||
ASSERT(scrRes->ncrtc > 0);
|
||||
ASSERT(scrRes->noutput > 0);
|
||||
ASSERT(scrRes->nmode > 0);
|
||||
|
||||
// If an output name has been specified, search for it
|
||||
RROutput targetOut = None;
|
||||
if (p.sDisplayId.length() > 0) {
|
||||
for (unsigned int i = 0; i < scrRes->noutput && targetOut == None; ++i) {
|
||||
XRROutputInfo *outInfo = XRRGetOutputInfo(Dpy, scrRes, scrRes->outputs[i]);
|
||||
std::string outName = std::string(outInfo->name, static_cast<unsigned int> (outInfo->nameLen));
|
||||
if (p.sDisplayId == outName) {
|
||||
targetOut = scrRes->outputs[i];
|
||||
}
|
||||
XRRFreeOutputInfo(outInfo);
|
||||
}
|
||||
}
|
||||
if (targetOut == None) {
|
||||
LOG->Info("Did not find display output %s, trying another", p.sDisplayId.c_str());
|
||||
// didn't find named output, pick primary/or at least one that works
|
||||
if (g_iRandRVerMajor >= 1 && g_iRandRVerMinor >= 3) {
|
||||
// RandR 1.3 can tell us what the primary display is.
|
||||
targetOut = XRRGetOutputPrimary(Dpy, Win);
|
||||
} else {
|
||||
// Only RandR 1.2. We'll look for a "Connected" output, or if we can't find that,
|
||||
// (it is possible the connection state could be unknown), we'll at least
|
||||
// look for an output with a CRTC driving it
|
||||
RROutput connected = None, hasCrtc = None;
|
||||
for (unsigned int i = 0; i < scrRes->noutput; ++i) {
|
||||
XRROutputInfo *outInfo = XRRGetOutputInfo(Dpy, scrRes, scrRes->outputs[i]);
|
||||
if (outInfo->connection == RR_Connected) { // Check for CONNECTED state: Connected == 0
|
||||
connected = scrRes->outputs[i];
|
||||
}
|
||||
if (outInfo->crtc != None) {
|
||||
hasCrtc = outInfo->crtc;
|
||||
}
|
||||
XRRFreeOutputInfo(outInfo);
|
||||
}
|
||||
targetOut = connected != None ? connected : hasCrtc;
|
||||
ASSERT(targetOut != None);
|
||||
}
|
||||
}
|
||||
|
||||
// if the target output is not currently being driven by a crtc,
|
||||
// find an unused crtc that can be connected to it
|
||||
XRROutputInfo *tgtOutInfo = XRRGetOutputInfo( Dpy, scrRes, targetOut );
|
||||
if (tgtOutInfo == NULL)
|
||||
{
|
||||
XRRFreeScreenResources(scrRes);
|
||||
return "Failed to find XRROutput";
|
||||
}
|
||||
|
||||
RRCrtc tgtOutCrtc = tgtOutInfo->crtc;
|
||||
if (tgtOutCrtc == None)
|
||||
{
|
||||
for (unsigned int i = 0; i < tgtOutInfo->ncrtc; ++i)
|
||||
{
|
||||
XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo( Dpy, scrRes, tgtOutInfo->crtcs[i] );
|
||||
if (crtcInfo->mode == None)
|
||||
{
|
||||
tgtOutCrtc = tgtOutInfo->crtcs[i];
|
||||
}
|
||||
XRRFreeCrtcInfo( crtcInfo );
|
||||
}
|
||||
}
|
||||
ASSERT(tgtOutCrtc != None);
|
||||
|
||||
|
||||
XRRCrtcInfo *oldConf = XRRGetCrtcInfo( Dpy, scrRes, tgtOutCrtc );
|
||||
|
||||
float fRefreshDiff = 99999;
|
||||
float fRefreshRate = 0;
|
||||
RRMode mode = None;
|
||||
// A quirk of XRandR is that the width and height are as the display
|
||||
// controller ("CRTC") sees it, which means height and width are
|
||||
// flipped if there's rotation going on.
|
||||
const bool bPortrait = (oldConf->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0;
|
||||
// Find a mode that matches our exact wanted resolution,
|
||||
// with as close to our desired refresh rate as possible.
|
||||
for (int i = 0; i < scrRes->nmode; i++) {
|
||||
const XRRModeInfo &thisMI = scrRes->modes[i];
|
||||
const unsigned int modeWidth = bPortrait ? thisMI.height : thisMI.width;
|
||||
const unsigned int modeHeight = bPortrait ? thisMI.width : thisMI.height;
|
||||
if (modeWidth == p.width && modeHeight == p.height) {
|
||||
float fTempRefresh = calcRandRRefresh(thisMI.dotClock, thisMI.hTotal, thisMI.vTotal);
|
||||
float fTempDiff = std::abs(p.rate - fTempRefresh);
|
||||
if ((p.rate != REFRESH_DEFAULT && fTempDiff < fRefreshDiff) ||
|
||||
(p.rate == REFRESH_DEFAULT && fTempRefresh > fRefreshRate)) {
|
||||
int j;
|
||||
// Ensure that the output supports the mode
|
||||
for (j = 0; j < tgtOutInfo->nmode; j++)
|
||||
if (tgtOutInfo->modes[j] == scrRes->modes[i].id) {
|
||||
mode = tgtOutInfo->modes[j];
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < tgtOutInfo->nmode) {
|
||||
fRefreshRate = fTempRefresh;
|
||||
fRefreshDiff = fTempDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rate = roundf(fRefreshRate);
|
||||
|
||||
g_usedCrtc = tgtOutCrtc;
|
||||
g_originalRandRMode = oldConf->mode;
|
||||
|
||||
const std::string tgtOutName = std::string(tgtOutInfo->name, static_cast<unsigned int> (tgtOutInfo->nameLen));
|
||||
LOG->Info("XRandR output config using CRTC %lu in mode %lu, driving output %s",
|
||||
g_usedCrtc, mode, tgtOutName.c_str());
|
||||
// and FIRE!
|
||||
Status s = XRRSetCrtcConfig(Dpy, scrRes, g_usedCrtc, oldConf->timestamp, oldConf->x, oldConf->y, mode,
|
||||
oldConf->rotation, oldConf->outputs, oldConf->noutput);
|
||||
if (s) {
|
||||
XRRFreeCrtcInfo(oldConf);
|
||||
XRRFreeOutputInfo(tgtOutInfo);
|
||||
XRRFreeScreenResources(scrRes);
|
||||
return "Failed to set CRTC config";
|
||||
}
|
||||
|
||||
// We don't move to absolute 0,0 because that may be in the area of a different output.
|
||||
// Instead we preserved the corner of our CRTC; go to that.
|
||||
XMoveWindow(Dpy, Win, oldConf->x, oldConf->y);
|
||||
|
||||
// Final cleanup
|
||||
XRRFreeCrtcInfo(oldConf);
|
||||
XRRFreeOutputInfo(tgtOutInfo);
|
||||
XRRFreeScreenResources(scrRes);
|
||||
}
|
||||
m_bWasWindowed = false;
|
||||
|
||||
XRaiseWindow( Dpy, Win );
|
||||
|
||||
// We want to prevent the WM from catching anything that comes from the keyboard.
|
||||
// We should do this every time on fullscreen and not only we entering from windowed mode because we could lose focus at resolution change and that will leave the user input locked.
|
||||
XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime );
|
||||
while (XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ));
|
||||
}
|
||||
else
|
||||
else // if(p.windowed)
|
||||
{
|
||||
if( !m_bWasWindowed )
|
||||
{
|
||||
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime );
|
||||
// In windowed mode, we actually want the WM to function normally.
|
||||
// Release any previous grab.
|
||||
// Return the display to the mode it was in before we fullscreened.
|
||||
RestoreOutputConfig();
|
||||
XUngrabKeyboard( Dpy, CurrentTime );
|
||||
m_bWasWindowed = true;
|
||||
}
|
||||
|
||||
Atom net_wm_state = XInternAtom( Dpy, "_NET_WM_STATE", False );
|
||||
Atom fullscreen_state = XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False );
|
||||
Atom maximized_vert = XInternAtom( Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False );
|
||||
Atom maximized_horz = XInternAtom( Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False );
|
||||
// if FSBW, find matching monitor, move window to its origin,
|
||||
// then set fullscreen hint, and set the CurrentParams.outWidth, CurrentParams.outHeight to the values of that display
|
||||
// otherwise set the size hints and disable MAXIMIZED_*
|
||||
if (p.bWindowIsFullscreenBorderless)
|
||||
{
|
||||
auto specs = DisplaySpecs{};
|
||||
GetDisplaySpecs( specs );
|
||||
auto target = std::find_if( specs.begin(), specs.end(), [&]( const DisplaySpec &spec ) {
|
||||
return p.sDisplayId == spec.id() && spec.currentMode() != nullptr;
|
||||
} );
|
||||
// If we didn't find a matching DisplaySpec for the requested ID, pick the first one with a current mode
|
||||
if (target == specs.end())
|
||||
{
|
||||
target = std::find_if( specs.begin(), specs.end(), [&]( const DisplaySpec &spec ) {
|
||||
return spec.currentMode() != nullptr;
|
||||
} );
|
||||
}
|
||||
// If we _still_ haven't found anything (unlikely), then just give up
|
||||
if (target == specs.end())
|
||||
{
|
||||
return "Unable to find destination monitor for fullscreen borderless";
|
||||
}
|
||||
|
||||
windowWidth = target->currentMode()->width;
|
||||
windowHeight = target->currentMode()->height;
|
||||
|
||||
if (windowWidth != p.width || windowHeight != p.height)
|
||||
{
|
||||
renderOffscreen = true;
|
||||
}
|
||||
|
||||
// Reset anything that might've been set previously:
|
||||
// (1) Undo Min/Max size bounds
|
||||
// (2) Remove FULLSCREEN/MAXIMIZED_{HORIZ,VERT} hints
|
||||
// Without doing this, WM may not let us move/resize window to new display
|
||||
// Give Window manager the chance to react to changes (otherwise, Mutter had problems
|
||||
// properly reacting to moving a _NET_WM_STATE_FULLSCREEN window to a different output
|
||||
// and fullscreen resetting FULLSCREEN hint.
|
||||
XSizeHints hints;
|
||||
hints.flags = 0;
|
||||
XSetWMNormalHints( Dpy, Win, &hints );
|
||||
#if defined(HAVE_XINERAMA)
|
||||
if (!g_bUseXinerama || !SetWMFullscreenMonitors( *target ))
|
||||
#endif
|
||||
{
|
||||
SetWMState( winAttrib.root, Win, 0, maximized_horz );
|
||||
SetWMState( winAttrib.root, Win, 0, maximized_vert );
|
||||
SetWMState( winAttrib.root, Win, 0, fullscreen_state );
|
||||
|
||||
XFlush( Dpy );
|
||||
XResizeWindow( Dpy, Win, static_cast<unsigned int> (windowWidth), static_cast<unsigned int> (windowHeight) );
|
||||
XMoveWindow( Dpy, Win, target->currentBounds().left, target->currentBounds().top );
|
||||
XRaiseWindow( Dpy, Win );
|
||||
|
||||
SetWMState( winAttrib.root, Win, 1, fullscreen_state );
|
||||
SetWMState( winAttrib.root, Win, 1, maximized_horz );
|
||||
SetWMState( winAttrib.root, Win, 1, maximized_vert );
|
||||
}
|
||||
} else
|
||||
{
|
||||
windowWidth = p.width;
|
||||
windowHeight = p.height;
|
||||
|
||||
SetWMState( winAttrib.root, Win, 0, fullscreen_state );
|
||||
// Make a window fixed size, don't let resize it or maximize it.
|
||||
// Do this before resizing the window so that pane-style WMs (Ion,
|
||||
// ratpoison) don't resize us back inappropriately.
|
||||
{
|
||||
XSizeHints hints;
|
||||
|
||||
hints.flags = PMinSize|PMaxSize|PWinGravity;
|
||||
hints.min_width = hints.max_width = windowWidth;
|
||||
hints.min_height = hints.max_height = windowHeight;
|
||||
hints.win_gravity = CenterGravity;
|
||||
|
||||
XSetWMNormalHints( Dpy, Win, &hints );
|
||||
}
|
||||
/* Workaround for metacity and compiz: if the window have the same
|
||||
* resolution or higher than the screen, it gets automaximized even
|
||||
* when the window is set to not let it happen. This happens when
|
||||
* changing from fullscreen to window mode and our screen resolution
|
||||
* is bigger. */
|
||||
{
|
||||
SetWMState( winAttrib.root, Win, 1, maximized_vert );
|
||||
SetWMState( winAttrib.root, Win, 1, maximized_horz );
|
||||
|
||||
// This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running.
|
||||
// Commented out per the patch at http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=398
|
||||
//XMoveWindow( Dpy, Win, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// NOTE: nVidia's implementation of this is broken by default.
|
||||
// The only ways around this are mucking with xorg.conf or querying
|
||||
// nvidia-settings with "$ nvidia-settings -t -q RefreshRate".
|
||||
int rate = XRRConfigCurrentRate( g_pScreenConfig );
|
||||
|
||||
// Make a window fixed size, don't let resize it or maximize it.
|
||||
// Do this before resizing the window so that pane-style WMs (Ion,
|
||||
// ratpoison) don't resize us back inappropriately.
|
||||
{
|
||||
XSizeHints hints;
|
||||
|
||||
hints.flags = PMinSize|PMaxSize|PWinGravity;
|
||||
hints.min_width = hints.max_width = p.width;
|
||||
hints.min_height = hints.max_height = p.height;
|
||||
hints.win_gravity = CenterGravity;
|
||||
|
||||
XSetWMNormalHints( Dpy, Win, &hints );
|
||||
}
|
||||
|
||||
/* Workaround for metacity and compiz: if the window have the same
|
||||
* resolution or higher than the screen, it gets automaximized even
|
||||
* when the window is set to not let it happen. This happens when
|
||||
* changing from fullscreen to window mode and our screen resolution
|
||||
* is bigger. */
|
||||
{
|
||||
XEvent xev;
|
||||
Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False);
|
||||
Atom maximized_vert = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||
Atom maximized_horz = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = Win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 1;
|
||||
xev.xclient.data.l[1] = maximized_vert;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev);
|
||||
xev.xclient.data.l[1] = maximized_horz;
|
||||
XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev);
|
||||
|
||||
// This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running.
|
||||
// Commented out per the patch at http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=398
|
||||
//XMoveWindow( Dpy, Win, 0, 0 );
|
||||
}
|
||||
|
||||
// Resize the window.
|
||||
XResizeWindow( Dpy, Win, p.width, p.height );
|
||||
|
||||
CurrentParams = p;
|
||||
CurrentParams.rate = rate;
|
||||
CurrentParams.windowWidth = windowWidth;
|
||||
CurrentParams.windowHeight = windowHeight;
|
||||
CurrentParams.renderOffscreen = renderOffscreen;
|
||||
ASSERT( rate > 0 );
|
||||
CurrentParams.rate = static_cast<int> (roundf(rate));
|
||||
|
||||
if (!p.windowed)
|
||||
{
|
||||
// Set our V-sync hint.
|
||||
if (GLXEW_EXT_swap_control) // I haven't seen this actually implemented yet, but why not.
|
||||
glXSwapIntervalEXT( Dpy, Win, CurrentParams.vsync ? 1 : 0 );
|
||||
// XXX: These two might be server-global. I should look into whether
|
||||
// to try to preserve the original value on exit.
|
||||
#ifdef GLXEW_MESA_swap_control // Added in 1.7. 1.6 is still common out there apparently.
|
||||
else if(GLXEW_MESA_swap_control) // Haven't seen this NOT implemented yet
|
||||
glXSwapIntervalMESA( CurrentParams.vsync ? 1 : 0 );
|
||||
#endif
|
||||
else if (GLXEW_SGI_swap_control) // But old GLEW.
|
||||
glXSwapIntervalSGI( CurrentParams.vsync ? 1 : 0 );
|
||||
else
|
||||
CurrentParams.vsync = false; // Assuming it's not on
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return ""; // Success
|
||||
}
|
||||
|
||||
@@ -332,16 +635,114 @@ void LowLevelWindow_X11::SwapBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
{
|
||||
int iSizesXct;
|
||||
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen( Dpy ), &iSizesXct );
|
||||
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
|
||||
void LowLevelWindow_X11::GetDisplaySpecs(DisplaySpecs &out) const {
|
||||
int screenNum = DefaultScreen(Dpy);
|
||||
Screen *screen = ScreenOfDisplay(Dpy, screenNum);
|
||||
|
||||
for( int i = 0; i < iSizesXct; ++i )
|
||||
{
|
||||
DisplayResolution res = { pSizesX[i].width, pSizesX[i].height, true };
|
||||
out.insert( res );
|
||||
XWindowAttributes winAttr = XWindowAttributes();
|
||||
if (XGetWindowAttributes(Dpy, Win, &winAttr)) {
|
||||
screen = winAttr.screen;
|
||||
screenNum = XScreenNumberOfScreen(screen);
|
||||
}
|
||||
|
||||
// Create a display spec for the entire X screen itself
|
||||
// First get current config
|
||||
Rotation curRotation;
|
||||
XRRScreenConfiguration *screenConf = XRRGetScreenInfo(Dpy, Win);
|
||||
const short curRate = XRRConfigCurrentRate(screenConf);
|
||||
SizeID curSizeId = XRRConfigCurrentConfiguration(screenConf, &curRotation);
|
||||
// curRotation does not factor into how we report supported XScreen sizes:
|
||||
// XRR reports the supported *screen* sizes with height/width swapped appropriately
|
||||
// for currently configured rotation. Supported sizes for *output* modes (below)
|
||||
// DO NOT account for screen rotation
|
||||
|
||||
std::set<DisplayMode> screenModes;
|
||||
int nsizes = 0;
|
||||
XRRScreenSize *screenSizes = XRRSizes( Dpy, screenNum, &nsizes);
|
||||
DisplayMode screenCurMode = {0};
|
||||
for (unsigned int szIdx = 0, mode_idx = 0; szIdx < nsizes; ++szIdx) {
|
||||
XRRScreenSize &size = screenSizes[szIdx];
|
||||
int nrates = 0;
|
||||
short *rates = XRRRates(Dpy, screenNum, szIdx, &nrates);
|
||||
for (unsigned int rIdx = 0; rIdx < nrates; ++rIdx, ++mode_idx) {
|
||||
DisplayMode m = {static_cast<unsigned int> (size.width), static_cast<unsigned int> (size.height), static_cast<double> (rates[rIdx])};
|
||||
screenModes.insert(m);
|
||||
if (rates[rIdx] == curRate && szIdx == curSizeId) {
|
||||
screenCurMode = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
const RectI screenBounds( 0, 0, screenSizes[curSizeId].width, screenSizes[curSizeId].height);
|
||||
const DisplaySpec screenSpec( ID_XSCREEN, "X Screen", screenModes, screenCurMode, screenBounds, true);
|
||||
out.insert(screenSpec);
|
||||
// XRRScreenSize array from XRRSizes does *not* have to be returned (valgrind said XFree was an invalid
|
||||
// free in a small test program, there is no XRRFreeScreenSize, etc)
|
||||
XRRFreeScreenConfigInfo(screenConf);
|
||||
|
||||
if (g_bUseXRandR12) {
|
||||
// Build per-output DisplaySpecs
|
||||
|
||||
// First, get the list of resolutions that'll be referenced (by RRMode) in each
|
||||
// OutputInfo
|
||||
XRRScreenResources *scrRes = XRRGetScreenResources(Dpy, Win);
|
||||
std::map<RRMode, DisplayMode> outputModes;
|
||||
for (unsigned int i = 0; i < scrRes->nmode; ++i) {
|
||||
const XRRModeInfo &mode = scrRes->modes[i];
|
||||
DisplayMode m = {mode.width, mode.height,
|
||||
calcRandRRefresh(mode.dotClock, mode.hTotal, mode.vTotal)};
|
||||
outputModes[mode.id] = m;
|
||||
}
|
||||
|
||||
// Now, for each output, build a corresponding DisplaySpec
|
||||
for (unsigned int outIdx = 0; outIdx < scrRes->noutput; ++outIdx)
|
||||
{
|
||||
XRROutputInfo *outInfo = XRRGetOutputInfo( Dpy, scrRes, scrRes->outputs[outIdx] );
|
||||
if (outInfo->nmode > 0)
|
||||
{
|
||||
// Get the current configuration of the Output, if it's being driven by
|
||||
// a crtc
|
||||
RRMode curRRMode = None;
|
||||
bool bPortrait = false;
|
||||
int crtcX = 0, crtcY = 0;
|
||||
if (outInfo->crtc != None)
|
||||
{
|
||||
XRRCrtcInfo *conf = XRRGetCrtcInfo( Dpy, scrRes, outInfo->crtc );
|
||||
curRRMode = conf->mode;
|
||||
bPortrait = (conf->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0;
|
||||
crtcX = conf->x;
|
||||
crtcY = conf->y;
|
||||
XRRFreeCrtcInfo( conf );
|
||||
}
|
||||
// Get all supported modes, noting which one, if any, is currently active
|
||||
std::set<DisplayMode> outputSupported;
|
||||
DisplayMode outputCurMode = {0};
|
||||
RectI outBounds;
|
||||
for (unsigned int modeIdx = 0; modeIdx < outInfo->nmode; ++modeIdx)
|
||||
{
|
||||
DisplayMode mode = outputModes[outInfo->modes[modeIdx]];
|
||||
unsigned int modeWidth = bPortrait ? mode.height : mode.width;
|
||||
unsigned int modeHeight = bPortrait ? mode.width : mode.height;
|
||||
DisplayMode m = {modeWidth, modeHeight, mode.refreshRate};
|
||||
outputSupported.insert( m );
|
||||
if (curRRMode != None && outInfo->modes[modeIdx] == curRRMode)
|
||||
{
|
||||
outputCurMode = m;
|
||||
outBounds = RectI( crtcX, crtcY, crtcX + modeWidth, crtcY + modeHeight);
|
||||
}
|
||||
}
|
||||
const std::string outId( outInfo->name, static_cast<unsigned int> (outInfo->nameLen) );
|
||||
const std::string outName( outId );
|
||||
if (curRRMode != None)
|
||||
{
|
||||
out.insert( DisplaySpec( outId, outName, outputSupported, outputCurMode, outBounds ));
|
||||
} else
|
||||
{
|
||||
out.insert( DisplaySpec( outId, outName, outputSupported ));
|
||||
}
|
||||
}
|
||||
XRRFreeOutputInfo( outInfo );
|
||||
}
|
||||
XRRFreeScreenResources( scrRes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,6 +913,34 @@ bool LowLevelWindow_X11::SupportsRenderToTexture() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetWMSupported(Display *Dpy, Atom feature)
|
||||
{
|
||||
Atom net_supported = XInternAtom( Dpy, "_NET_SUPPORTED", False );
|
||||
Atom actual_type_return = BadAtom;
|
||||
int actual_format_return = 0;
|
||||
unsigned long nitems_return = 0;
|
||||
unsigned long bytes_after_return = 0;
|
||||
Atom *prop_return;
|
||||
Status status = XGetWindowProperty( Dpy, RootWindow( Dpy, DefaultScreen( Dpy )), net_supported, 0, 8192, False,
|
||||
XA_ATOM, &actual_type_return,
|
||||
&actual_format_return, &nitems_return, &bytes_after_return,
|
||||
reinterpret_cast<unsigned char **> (&prop_return));
|
||||
if (status != Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto supported = std::find( prop_return, prop_return + nitems_return, feature ) != prop_return + nitems_return;
|
||||
XFree( prop_return );
|
||||
return supported;
|
||||
}
|
||||
|
||||
bool LowLevelWindow_X11::SupportsFullscreenBorderlessWindow() const
|
||||
{
|
||||
Atom fullscreen = XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False );
|
||||
return NetWMSupported( Dpy, fullscreen );
|
||||
}
|
||||
|
||||
RenderTarget *LowLevelWindow_X11::CreateRenderTarget()
|
||||
{
|
||||
return new RenderTarget_X11( this );
|
||||
|
||||
@@ -18,13 +18,15 @@ public:
|
||||
bool IsSoftwareRenderer( RString &sError );
|
||||
void SwapBuffers();
|
||||
|
||||
const VideoModeParams &GetActualVideoModeParams() const { return CurrentParams; }
|
||||
const ActualVideoModeParams GetActualVideoModeParams() const { return CurrentParams; }
|
||||
|
||||
void GetDisplayResolutions( DisplayResolutions &out ) const;
|
||||
void GetDisplaySpecs(DisplaySpecs &out) const;
|
||||
|
||||
bool SupportsRenderToTexture() const;
|
||||
RenderTarget *CreateRenderTarget();
|
||||
|
||||
bool SupportsFullscreenBorderlessWindow() const;
|
||||
|
||||
bool SupportsThreadedRendering();
|
||||
void BeginConcurrentRenderingMainThread();
|
||||
void EndConcurrentRenderingMainThread();
|
||||
@@ -32,8 +34,10 @@ public:
|
||||
void EndConcurrentRendering();
|
||||
|
||||
private:
|
||||
void RestoreOutputConfig();
|
||||
|
||||
bool m_bWasWindowed;
|
||||
VideoModeParams CurrentParams;
|
||||
ActualVideoModeParams CurrentParams;
|
||||
};
|
||||
|
||||
#ifdef ARCH_LOW_LEVEL_WINDOW
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
extern "C" int sm_main( int argc, char *argv[] );
|
||||
|
||||
#define HAVE_CXA_DEMANGLE
|
||||
#define HAVE_PTHREAD_COND_TIMEDWAIT
|
||||
/* This must be defined to 1 because autoconf's AC_CHECK_DECLS macro decides to define
|
||||
* this in all cases. If only they could be consistent... */
|
||||
#define HAVE_DECL_SIGUSR1 1
|
||||
|
||||
@@ -129,6 +129,23 @@ bool X11Helper::MakeWindow( Window &win, int screenNum, int depth, Visual *visua
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11Helper::SetWMState( const Window &root, const Window &win, const long action, const Atom atom )
|
||||
{
|
||||
if ( !Dpy )
|
||||
return;
|
||||
Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False);
|
||||
XEvent xev;
|
||||
memset( &xev, 0, sizeof( xev ));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = Win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = action; // 0 = Remove, 1 = Add, 2 = Toggle
|
||||
xev.xclient.data.l[1] = atom;
|
||||
xev.xclient.data.l[2] = 0; // end list of Atoms
|
||||
XSendEvent( Dpy, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
|
||||
}
|
||||
|
||||
int ErrorCallback( Display *d, XErrorEvent *err )
|
||||
{
|
||||
char errText[512];
|
||||
@@ -144,6 +161,85 @@ int FatalCallback( Display *d )
|
||||
RageException::Throw( "Fatal I/O error communicating with X server." );
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
|
||||
bool X11Helper::SetWMFullscreenMonitors( const DisplaySpec &target )
|
||||
{
|
||||
int num_screens = 0;
|
||||
XineramaScreenInfo *screens = XineramaQueryScreens( Dpy, &num_screens );
|
||||
if (screens == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
XineramaScreenInfo *end = screens + num_screens;
|
||||
RectI monitors{};
|
||||
bool found_bounds = false;
|
||||
|
||||
if (target.isVirtual())
|
||||
{
|
||||
auto topmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.y_org < b.y_org;
|
||||
} );
|
||||
monitors.top = topmost->screen_number;
|
||||
|
||||
auto bottommost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.y_org < b.y_org;
|
||||
} );
|
||||
monitors.bottom = bottommost->screen_number;
|
||||
|
||||
auto leftmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.x_org < b.x_org;
|
||||
} );
|
||||
monitors.left = leftmost->screen_number;
|
||||
|
||||
auto rightmost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
|
||||
return a.x_org < b.x_org;
|
||||
} );
|
||||
monitors.right = rightmost->screen_number;
|
||||
found_bounds = true;
|
||||
}
|
||||
else if (target.currentMode() != nullptr)
|
||||
{
|
||||
auto mon = std::find_if( screens, end, [&]( XineramaScreenInfo &screen ) {
|
||||
return screen.x_org == target.currentBounds().left && screen.y_org == target.currentBounds().top
|
||||
&& screen.width == target.currentMode()->width && screen.height == target.currentMode()->height;
|
||||
} );
|
||||
if (mon != end)
|
||||
{
|
||||
monitors.left = monitors.right = monitors.top = monitors.bottom = mon->screen_number;
|
||||
found_bounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
XFree( screens );
|
||||
XWindowAttributes attr = {0};
|
||||
if (!found_bounds || !XGetWindowAttributes( Dpy, Win, &attr ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SetWMState( attr.root, Win, 1, XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False ));
|
||||
|
||||
XClientMessageEvent xclient = {0};
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = Win;
|
||||
xclient.message_type = XInternAtom( Dpy, "_NET_WM_FULLSCREEN_MONITORS", False );
|
||||
xclient.format = 32;
|
||||
xclient.data.l[0] = monitors.top;
|
||||
xclient.data.l[1] = monitors.bottom;
|
||||
xclient.data.l[2] = monitors.left;
|
||||
xclient.data.l[3] = monitors.right;
|
||||
xclient.data.l[4] = 1;
|
||||
XSendEvent( Dpy, attr.root, False, SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
reinterpret_cast<XEvent *> (&xclient));
|
||||
XFlush( Dpy );
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (c) 2005, 2006 Ben Anderson, Steve Checkoway
|
||||
* All rights reserved.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <X11/Xlib.h> // Window
|
||||
#include <X11/Xutil.h>
|
||||
#include <DisplaySpec.h>
|
||||
|
||||
namespace X11Helper
|
||||
{
|
||||
// All functions in here that return a bool return true on success, and
|
||||
@@ -25,6 +27,12 @@ namespace X11Helper
|
||||
// (Re)create the Window win.
|
||||
bool MakeWindow( Window &win, int screenNum, int depth, Visual *visual,
|
||||
int width, int height, bool overrideRedirect );
|
||||
|
||||
void SetWMState( const Window &root, const Window &win, const long action, const Atom atom );
|
||||
|
||||
#ifdef HAVE_XINERAMA
|
||||
bool SetWMFullscreenMonitors( const DisplaySpec &target );
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
#include "arch/ArchHooks/ArchHooks.h"
|
||||
#include "archutils/Win32/AppInstance.h"
|
||||
#include "archutils/Win32/Crash.h"
|
||||
@@ -539,29 +539,53 @@ HWND GraphicsWindow::GetHwnd()
|
||||
return g_hWndMain;
|
||||
}
|
||||
|
||||
void GraphicsWindow::GetDisplayResolutions( DisplayResolutions &out )
|
||||
void GraphicsWindow::GetDisplaySpecs( DisplaySpecs &out )
|
||||
{
|
||||
DEVMODE dm;
|
||||
ZERO( dm );
|
||||
dm.dmSize = sizeof(dm);
|
||||
int i=0;
|
||||
while(EnumDisplaySettings(NULL, i++, &dm))
|
||||
{
|
||||
const size_t DM_DRIVER_EXTRA_BYTES = 4096;
|
||||
const size_t DMSIZE = sizeof( DEVMODE ) + DM_DRIVER_EXTRA_BYTES;
|
||||
auto reset = [=]( std::unique_ptr<DEVMODE> &p ) {
|
||||
::memset( p.get(), 0, DMSIZE );
|
||||
p->dmSize = sizeof( DEVMODE );
|
||||
p->dmDriverExtra = static_cast<WORD> (DM_DRIVER_EXTRA_BYTES);
|
||||
};
|
||||
auto isvalid = []( std::unique_ptr<DEVMODE> &dm ) {
|
||||
// Windows 8 and later don't support less than 32bpp, so don't even test
|
||||
// for them. GetDisplayResolutions is only for resolutions anyway. -Kyz
|
||||
if(dm.dmBitsPerPel < 32)
|
||||
// for them. GetDisplaySpecs only tracks resolution/refresh rate anyway. -Kyz, drewbarbs
|
||||
return (dm->dmFields & DM_PELSWIDTH) && (dm->dmFields & DM_PELSHEIGHT) && (dm->dmFields & DM_DISPLAYFREQUENCY)
|
||||
&& (dm->dmBitsPerPel >= 32 || !(dm->dmFields & DM_BITSPERPEL));
|
||||
};
|
||||
|
||||
std::unique_ptr<DEVMODE> dm( static_cast<DEVMODE*> (operator new(DMSIZE)) );
|
||||
reset( dm );
|
||||
|
||||
int i = 0;
|
||||
std::set<DisplayMode> modes;
|
||||
while ( EnumDisplaySettingsEx( nullptr, i++, dm.get(), 0 ) )
|
||||
{
|
||||
if ( isvalid( dm ) && ChangeDisplaySettingsEx( nullptr, dm.get(), nullptr, CDS_TEST, nullptr ) == DISP_CHANGE_SUCCESSFUL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DisplayResolution res = { dm.dmPelsWidth, dm.dmPelsHeight };
|
||||
std::set<DisplayResolution>::iterator entry= out.find(res);
|
||||
if(entry == out.end())
|
||||
{
|
||||
if(ChangeDisplaySettings(&dm, CDS_TEST)==DISP_CHANGE_SUCCESSFUL)
|
||||
{
|
||||
out.insert(res);
|
||||
}
|
||||
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
|
||||
modes.insert(m);
|
||||
}
|
||||
reset( dm );
|
||||
}
|
||||
|
||||
reset( dm );
|
||||
// Get the current display mode
|
||||
if ( EnumDisplaySettingsEx( nullptr, ENUM_CURRENT_SETTINGS, dm.get(), 0 ) && isvalid( dm ) )
|
||||
{
|
||||
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
|
||||
RectI bounds = { 0, 0, static_cast<int> (m.width), static_cast<int> (m.height) };
|
||||
out.insert( DisplaySpec( "", "Fullscreen", modes, m, bounds ) );
|
||||
}
|
||||
else if ( !modes.empty() )
|
||||
{
|
||||
LOG->Warn( "Could not retrieve valid current display mode" );
|
||||
out.insert( DisplaySpec( "", "Fullscreen", *modes.begin() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG->Warn( "Could not retrieve *any* DisplaySpec's!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define GRAPHICS_WINDOW_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "DisplayResolutions.h"
|
||||
#include "DisplaySpec.h"
|
||||
class VideoModeParams;
|
||||
class DisplayResolution;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace GraphicsWindow
|
||||
void CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow = false );
|
||||
void DestroyGraphicsWindow();
|
||||
|
||||
void GetDisplayResolutions( DisplayResolutions &out );
|
||||
void GetDisplaySpecs( DisplaySpecs &out );
|
||||
|
||||
const VideoModeParams &GetParams();
|
||||
HDC GetHDC();
|
||||
|
||||
Reference in New Issue
Block a user