mirror of
https://github.com/DrBeef/QuestZDoom.git
synced 2025-04-24 18:22:02 +00:00
merged with lzdoom mobile
fixed and restored some files from previous update not integrated
This commit is contained in:
parent
2c531e54f9
commit
7b665f5f55
53 changed files with 10272 additions and 596 deletions
|
@ -158,6 +158,35 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
endif()
|
||||
|
||||
# Fast math flags, required by some subprojects
|
||||
set( ZD_FASTMATH_FLAG "" )
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
|
||||
elseif( MSVC )
|
||||
set( ZD_FASTMATH_FLAG "/fp:fast" )
|
||||
endif()
|
||||
|
||||
macro( use_fast_math )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||
endmacro()
|
||||
|
||||
include( CheckFunctionExists )
|
||||
|
||||
macro( require_stricmp )
|
||||
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
|
||||
if( NOT STRICMP_EXISTS )
|
||||
add_definitions( -Dstricmp=strcasecmp )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro( require_strnicmp )
|
||||
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
|
||||
if( NOT STRNICMP_EXISTS )
|
||||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
option( NO_OPENAL "Disable OpenAL sound support" OFF )
|
||||
|
||||
find_package( BZip2 )
|
||||
|
@ -219,9 +248,9 @@ if( MSVC )
|
|||
# Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations.
|
||||
option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF )
|
||||
if( ZDOOM_GENERATE_ASM )
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi /FAcs" )
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi /FAcs /GS-" )
|
||||
else()
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi" )
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi /GS-" )
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -305,21 +334,13 @@ mark_as_advanced( FORCE_INTERNAL_GME )
|
|||
option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON)
|
||||
mark_as_advanced( FORCE_INTERNAL_ASMJIT )
|
||||
|
||||
# Fast math flags, required by some subprojects
|
||||
set( ZD_FASTMATH_FLAG "" )
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
|
||||
elseif( MSVC )
|
||||
set( ZD_FASTMATH_FLAG "/fp:fast" )
|
||||
endif()
|
||||
|
||||
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal zlib" )
|
||||
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom
|
||||
add_subdirectory( zlib )
|
||||
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
|
||||
add_subdirectory( libraries/zlib )
|
||||
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib )
|
||||
set( ZLIB_LIBRARIES z )
|
||||
set( ZLIB_LIBRARY z )
|
||||
endif()
|
||||
|
@ -343,8 +364,8 @@ if( ${HAVE_VM_JIT} )
|
|||
else()
|
||||
message( STATUS "Using internal asmjit" )
|
||||
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing asmjit alongside zdoom
|
||||
add_subdirectory( asmjit )
|
||||
set( ASMJIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/asmjit )
|
||||
add_subdirectory( libraries/asmjit )
|
||||
set( ASMJIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/asmjit )
|
||||
set( ASMJIT_LIBRARIES asmjit )
|
||||
set( ASMJIT_LIBRARY asmjit )
|
||||
endif()
|
||||
|
@ -354,8 +375,8 @@ if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
|
|||
message( STATUS "Using system jpeg library, includes found at ${JPEG_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal jpeg library" )
|
||||
add_subdirectory( jpeg )
|
||||
set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jpeg )
|
||||
add_subdirectory( libraries/jpeg )
|
||||
set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/jpeg )
|
||||
set( JPEG_LIBRARIES jpeg )
|
||||
set( JPEG_LIBRARY jpeg )
|
||||
endif()
|
||||
|
@ -364,8 +385,8 @@ if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
|
|||
message( STATUS "Using system bzip2 library, includes found at ${BZIP2_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal bzip2 library" )
|
||||
add_subdirectory( bzip2 )
|
||||
set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bzip2" )
|
||||
add_subdirectory( libraries/bzip2 )
|
||||
set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/bzip2" )
|
||||
set( BZIP2_LIBRARIES bz2 )
|
||||
set( BZIP2_LIBRARY bz2 )
|
||||
endif()
|
||||
|
@ -377,12 +398,19 @@ else()
|
|||
# Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU
|
||||
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
|
||||
set( GME_YM2612_EMU "MAME" )
|
||||
add_subdirectory( game-music-emu )
|
||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
|
||||
add_subdirectory( libraries/game-music-emu )
|
||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/game-music-emu" )
|
||||
set( GME_LIBRARIES gme )
|
||||
endif()
|
||||
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" )
|
||||
set( ADL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/adlmidi" )
|
||||
set( OPN_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/opnmidi" )
|
||||
set( TIMIDITYPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidityplus" )
|
||||
set( TIMIDITY_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidity" )
|
||||
set( WILDMIDI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/wildmidi" )
|
||||
set( OPLSYNTH_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/oplsynth" )
|
||||
set( ZMUSIC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zmusic" )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
if( NOT CROSS_EXPORTS )
|
||||
|
@ -400,10 +428,22 @@ install(DIRECTORY docs/
|
|||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
COMPONENT "Documentation")
|
||||
|
||||
add_subdirectory( lzma )
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
option( DYN_OPENAL "Dynamically load OpenAL" ON )
|
||||
option( DYN_SNDFILE "Dynamically load libsndfile" ON )
|
||||
option( DYN_MPG123 "Dynamically load libmpg123" ON )
|
||||
|
||||
add_subdirectory( libraries/lzma )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( dumb )
|
||||
add_subdirectory( gdtoa )
|
||||
add_subdirectory( libraries/dumb )
|
||||
add_subdirectory( libraries/gdtoa )
|
||||
add_subdirectory( libraries/adlmidi )
|
||||
add_subdirectory( libraries/opnmidi )
|
||||
add_subdirectory( libraries/timidity )
|
||||
add_subdirectory( libraries/timidityplus )
|
||||
add_subdirectory( libraries/wildmidi )
|
||||
add_subdirectory( libraries/oplsynth )
|
||||
add_subdirectory( libraries/zmusic )
|
||||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
|
|
|
@ -23,11 +23,6 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
endif()
|
||||
endif()
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
option( DYN_OPENAL "Dynamically load OpenAL" ON )
|
||||
option( DYN_SNDFILE "Dynamically load libsndfile" ON )
|
||||
option( DYN_MPG123 "Dynamically load libmpg123" ON )
|
||||
|
||||
if( APPLE )
|
||||
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
|
||||
endif()
|
||||
|
@ -221,27 +216,8 @@ endif()
|
|||
|
||||
if( NO_OPENAL )
|
||||
add_definitions( -DNO_OPENAL=1 )
|
||||
|
||||
set(MPG123_FOUND NO)
|
||||
set(SNDFILE_FOUND NO)
|
||||
else()
|
||||
# Search for libSndFile
|
||||
|
||||
if ( NOT DYN_SNDFILE )
|
||||
find_package( SndFile )
|
||||
endif()
|
||||
|
||||
# Search for libmpg123
|
||||
|
||||
if ( NOT DYN_MPG123 )
|
||||
find_package( MPG123 )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Search for FluidSynth
|
||||
|
||||
find_package( FluidSynth )
|
||||
|
||||
# Decide on SSE setup
|
||||
|
||||
set( SSE_MATTERS NO )
|
||||
|
@ -448,15 +424,8 @@ if( NOT STRUPR_EXISTS )
|
|||
add_definitions( -DNEED_STRUPR=1 )
|
||||
endif()
|
||||
|
||||
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
|
||||
if( NOT STRICMP_EXISTS )
|
||||
add_definitions( -Dstricmp=strcasecmp )
|
||||
endif()
|
||||
|
||||
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
|
||||
if( NOT STRNICMP_EXISTS )
|
||||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif()
|
||||
require_stricmp()
|
||||
require_strnicmp()
|
||||
|
||||
if( NOT MSVC )
|
||||
add_definitions( -D__forceinline=inline )
|
||||
|
@ -480,15 +449,14 @@ endif()
|
|||
# Update gitinfo.h
|
||||
|
||||
add_custom_target( revision_check ALL
|
||||
COMMAND updaterevision src/gitinfo.h
|
||||
COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/tools/updaterevision/UpdateRevision.cmake" src/gitinfo.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
DEPENDS updaterevision )
|
||||
)
|
||||
|
||||
# Libraries ZDoom needs
|
||||
|
||||
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" "${CMAKE_DL_LIBS}" )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" )
|
||||
|
||||
if( ${HAVE_VM_JIT} )
|
||||
add_definitions( -DHAVE_VM_JIT )
|
||||
|
@ -496,30 +464,12 @@ if( ${HAVE_VM_JIT} )
|
|||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ASMJIT_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
if( SNDFILE_FOUND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" )
|
||||
include_directories( "${SNDFILE_INCLUDE_DIRS}" )
|
||||
endif()
|
||||
if( MPG123_FOUND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${MPG123_LIBRARIES}" )
|
||||
include_directories( "${MPG123_INCLUDE_DIR}" )
|
||||
endif()
|
||||
if( NOT DYN_FLUIDSYNTH )
|
||||
if( FLUIDSYNTH_FOUND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
||||
include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Start defining source files for ZDoom
|
||||
set( PLAT_WIN32_SOURCES
|
||||
sound/mididevices/music_win_mididevice.cpp
|
||||
win32/fb_d3d9.cpp
|
||||
win32/fb_d3d9_wipe.cpp
|
||||
win32/fb_ddraw.cpp
|
||||
win32/hardware.cpp
|
||||
win32/helperthread.cpp
|
||||
win32/i_cd.cpp
|
||||
win32/i_crash.cpp
|
||||
win32/i_input.cpp
|
||||
win32/i_keyboard.cpp
|
||||
|
@ -531,11 +481,12 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/i_system.cpp
|
||||
win32/i_specialpaths.cpp
|
||||
win32/st_start.cpp
|
||||
win32/st_start_util.cpp
|
||||
win32/win32gliface.cpp
|
||||
win32/win32video.cpp )
|
||||
set( PLAT_POSIX_SOURCES
|
||||
posix/i_cd.cpp
|
||||
posix/i_steam.cpp )
|
||||
posix/i_steam.cpp
|
||||
posix/i_system_posix.cpp )
|
||||
set( PLAT_SDL_SOURCES
|
||||
posix/sdl/crashcatcher.c
|
||||
posix/sdl/hardware.cpp
|
||||
|
@ -558,7 +509,6 @@ set( PLAT_COCOA_SOURCES
|
|||
posix/cocoa/i_input.mm
|
||||
posix/cocoa/i_joystick.cpp
|
||||
posix/cocoa/i_main.mm
|
||||
posix/cocoa/i_main_except.cpp
|
||||
posix/cocoa/i_system.mm
|
||||
posix/cocoa/i_video.mm
|
||||
posix/cocoa/st_console.mm
|
||||
|
@ -642,37 +592,12 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
|
|||
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
if( DYN_SNDFILE)
|
||||
add_definitions( -DHAVE_SNDFILE -DDYN_SNDFILE )
|
||||
elseif( SNDFILE_FOUND )
|
||||
add_definitions( -DHAVE_SNDFILE )
|
||||
endif()
|
||||
|
||||
if( DYN_MPG123)
|
||||
add_definitions( -DHAVE_MPG123 -DDYN_MPG123 )
|
||||
elseif( MPG123_FOUND )
|
||||
add_definitions( -DHAVE_MPG123 )
|
||||
endif()
|
||||
|
||||
if( DYN_FLUIDSYNTH )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
||||
elseif( FLUIDSYNTH_FOUND )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH )
|
||||
endif()
|
||||
|
||||
option( SEND_ANON_STATS "Enable sending of anonymous hardware statistics" ON )
|
||||
|
||||
if( NOT SEND_ANON_STATS )
|
||||
add_definitions( -DNO_SEND_STATS )
|
||||
endif()
|
||||
|
||||
# Disable ADLMIDI's and OPNMIDI's MIDI Sequencer
|
||||
add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
add_definitions(-DOPNMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
|
||||
# Disable OPNMIDI's experimental yet emulator (using of it has some issues and missing notes in playback)
|
||||
add_definitions(-DOPNMIDI_DISABLE_GX_EMULATOR)
|
||||
|
||||
# Project files should be aware of the header files. We can GLOB these since
|
||||
# there's generally a new cpp for every header so this file will get changed
|
||||
file( GLOB HEADER_FILES
|
||||
|
@ -682,10 +607,9 @@ file( GLOB HEADER_FILES
|
|||
g_inventory/*.h
|
||||
intermission/*.h
|
||||
menu/*.h
|
||||
sound/adlmidi/*.h*
|
||||
sound/opnmidi/*.h*
|
||||
sound/oplsynth/*.h
|
||||
sound/oplsynth/dosbox/*.h
|
||||
sound/*.h
|
||||
sound/backend/*.h*
|
||||
sound/music/*.h*
|
||||
posix/*.h
|
||||
posix/cocoa/*.h
|
||||
posix/sdl/*.h
|
||||
|
@ -695,7 +619,6 @@ file( GLOB HEADER_FILES
|
|||
rapidjson/*.h
|
||||
resourcefiles/*.h
|
||||
sfmt/*.h
|
||||
sound/*.h
|
||||
textures/*.h
|
||||
scripting/*.h
|
||||
scripting/backend/*.h
|
||||
|
@ -703,12 +626,7 @@ file( GLOB HEADER_FILES
|
|||
scripting/zscript/*.h
|
||||
scripting/vm/*.h
|
||||
sound/midisources/*.h
|
||||
sound/oplsynth/*.h
|
||||
sound/oplsynth/dosbox/*.h
|
||||
sound/thirdparty/*.h
|
||||
sound/timidity/*.h
|
||||
sound/timiditypp/*.h
|
||||
sound/wildmidi/*.h
|
||||
xlat/*.h
|
||||
swrenderer/*.h
|
||||
swrenderer/drawers/*.h
|
||||
|
@ -848,13 +766,8 @@ set( VM_JIT_SOURCES
|
|||
set( FASTMATH_SOURCES
|
||||
swrenderer/r_all.cpp
|
||||
polyrenderer/poly_all.cpp
|
||||
sound/oplsynth/opl_mus_player.cpp
|
||||
sound/mpg123_decoder.cpp
|
||||
sound/music_midi_base.cpp
|
||||
sound/oalsound.cpp
|
||||
sound/sndfile_decoder.cpp
|
||||
sound/timiditypp/fft4g.cpp
|
||||
sound/timiditypp/reverb.cpp
|
||||
sound/music/music_midi_base.cpp
|
||||
sound/backend/oalsound.cpp
|
||||
gl/utility/gl_clock.cpp
|
||||
gl/renderer/gl_2ddrawer.cpp
|
||||
gl/hqnx/init.cpp
|
||||
|
@ -885,32 +798,6 @@ set( FASTMATH_SOURCES
|
|||
gl/models/gl_models.cpp
|
||||
r_data/models/models.cpp
|
||||
r_data/matrix.cpp
|
||||
sound/adlmidi/adldata.cpp
|
||||
sound/adlmidi/adlmidi.cpp
|
||||
sound/adlmidi/adlmidi_load.cpp
|
||||
sound/adlmidi/adlmidi_midiplay.cpp
|
||||
sound/adlmidi/adlmidi_opl3.cpp
|
||||
sound/adlmidi/adlmidi_private.cpp
|
||||
sound/adlmidi/chips/dosbox/dbopl.cpp
|
||||
sound/adlmidi/chips/dosbox_opl3.cpp
|
||||
sound/adlmidi/chips/nuked/nukedopl3_174.c
|
||||
sound/adlmidi/chips/nuked/nukedopl3.c
|
||||
sound/adlmidi/chips/nuked_opl3.cpp
|
||||
sound/adlmidi/chips/nuked_opl3_v174.cpp
|
||||
sound/adlmidi/wopl/wopl_file.c
|
||||
sound/opnmidi/chips/gens_opn2.cpp
|
||||
sound/opnmidi/chips/gens/Ym2612_Emu.cpp
|
||||
sound/opnmidi/chips/mame/mame_ym2612fm.c
|
||||
sound/opnmidi/chips/mame_opn2.cpp
|
||||
sound/opnmidi/chips/nuked_opn2.cpp
|
||||
sound/opnmidi/chips/nuked/ym3438.c
|
||||
sound/opnmidi/opnmidi.cpp
|
||||
sound/opnmidi/opnmidi_load.cpp
|
||||
sound/opnmidi/opnmidi_midiplay.cpp
|
||||
sound/opnmidi/opnmidi_opn2.cpp
|
||||
sound/opnmidi/opnmidi_private.cpp
|
||||
sound/opnmidi/wopn/wopn_file.c
|
||||
|
||||
)
|
||||
|
||||
set (PCH_SOURCES
|
||||
|
@ -964,7 +851,6 @@ set (PCH_SOURCES
|
|||
gi.cpp
|
||||
gitinfo.cpp
|
||||
hu_scores.cpp
|
||||
i_module.cpp
|
||||
i_net.cpp
|
||||
i_time.cpp
|
||||
info.cpp
|
||||
|
@ -1037,12 +923,14 @@ set (PCH_SOURCES
|
|||
r_utility.cpp
|
||||
r_sky.cpp
|
||||
r_videoscale.cpp
|
||||
s_advsound.cpp
|
||||
s_environment.cpp
|
||||
s_playlist.cpp
|
||||
s_sndseq.cpp
|
||||
s_sound.cpp
|
||||
sound/s_advsound.cpp
|
||||
sound/s_environment.cpp
|
||||
sound/s_reverbedit.cpp
|
||||
sound/s_sndseq.cpp
|
||||
sound/s_doomsound.cpp
|
||||
sound/s_sound.cpp
|
||||
sound/s_music.cpp
|
||||
s_playlist.cpp
|
||||
serializer.cpp
|
||||
sc_man.cpp
|
||||
scriptutil.cpp
|
||||
|
@ -1223,73 +1111,11 @@ set (PCH_SOURCES
|
|||
scripting/zscript/zcc_compile.cpp
|
||||
scripting/zscript/zcc_parser.cpp
|
||||
sfmt/SFMT.cpp
|
||||
sound/i_music.cpp
|
||||
sound/i_sound.cpp
|
||||
sound/i_soundfont.cpp
|
||||
sound/mididevices/music_adlmidi_mididevice.cpp
|
||||
sound/mididevices/music_opldumper_mididevice.cpp
|
||||
sound/mididevices/music_opl_mididevice.cpp
|
||||
sound/mididevices/music_opnmidi_mididevice.cpp
|
||||
sound/mididevices/music_timiditypp_mididevice.cpp
|
||||
sound/mididevices/music_fluidsynth_mididevice.cpp
|
||||
sound/mididevices/music_softsynth_mididevice.cpp
|
||||
sound/mididevices/music_timidity_mididevice.cpp
|
||||
sound/mididevices/music_wildmidi_mididevice.cpp
|
||||
sound/mididevices/music_wavewriter_mididevice.cpp
|
||||
sound/midisources/midisource.cpp
|
||||
sound/midisources/midisource_mus.cpp
|
||||
sound/midisources/midisource_smf.cpp
|
||||
sound/midisources/midisource_hmi.cpp
|
||||
sound/midisources/midisource_xmi.cpp
|
||||
sound/musicformats/music_cd.cpp
|
||||
sound/musicformats/music_dumb.cpp
|
||||
sound/musicformats/music_gme.cpp
|
||||
sound/musicformats/music_libsndfile.cpp
|
||||
sound/musicformats/music_midistream.cpp
|
||||
sound/musicformats/music_opl.cpp
|
||||
sound/musicformats/music_stream.cpp
|
||||
sound/musicformats/music_xa.cpp
|
||||
sound/oplsynth/fmopl.cpp
|
||||
sound/oplsynth/musicblock.cpp
|
||||
sound/oplsynth/oplio.cpp
|
||||
sound/oplsynth/dosbox/opl.cpp
|
||||
sound/oplsynth/OPL3.cpp
|
||||
sound/oplsynth/nukedopl3.cpp
|
||||
sound/timidity/common.cpp
|
||||
sound/timidity/instrum.cpp
|
||||
sound/timidity/instrum_dls.cpp
|
||||
sound/timidity/instrum_font.cpp
|
||||
sound/timidity/instrum_sf2.cpp
|
||||
sound/timidity/mix.cpp
|
||||
sound/timidity/playmidi.cpp
|
||||
sound/timidity/resample.cpp
|
||||
sound/timidity/timidity.cpp
|
||||
sound/timiditypp/common.cpp
|
||||
sound/timiditypp/configfile.cpp
|
||||
sound/timiditypp/effect.cpp
|
||||
sound/timiditypp/filter.cpp
|
||||
sound/timiditypp/freq.cpp
|
||||
sound/timiditypp/instrum.cpp
|
||||
sound/timiditypp/mblock.cpp
|
||||
sound/timiditypp/mix.cpp
|
||||
sound/timiditypp/playmidi.cpp
|
||||
sound/timiditypp/quantity.cpp
|
||||
sound/timiditypp/readmidic.cpp
|
||||
sound/timiditypp/recache.cpp
|
||||
sound/timiditypp/resample.cpp
|
||||
sound/timiditypp/sbkconv.cpp
|
||||
sound/timiditypp/sffile.cpp
|
||||
sound/timiditypp/sfitem.cpp
|
||||
sound/timiditypp/smplfile.cpp
|
||||
sound/timiditypp/sndfont.cpp
|
||||
sound/timiditypp/tables.cpp
|
||||
sound/wildmidi/file_io.cpp
|
||||
sound/wildmidi/gus_pat.cpp
|
||||
sound/wildmidi/reverb.cpp
|
||||
sound/wildmidi/wildmidi_lib.cpp
|
||||
sound/wildmidi/wm_error.cpp
|
||||
sound/music/i_music.cpp
|
||||
sound/music/i_soundfont.cpp
|
||||
sound/backend/i_sound.cpp
|
||||
sound/music/music_config.cpp
|
||||
events.cpp
|
||||
atterm.cpp
|
||||
GuillotineBinPack.cpp
|
||||
SkylineBinPack.cpp
|
||||
)
|
||||
|
@ -1312,6 +1138,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
|
|||
x86.cpp
|
||||
strnatcmp.c
|
||||
zstring.cpp
|
||||
dictionary.cpp
|
||||
math/asin.c
|
||||
math/atan.c
|
||||
math/const.c
|
||||
|
@ -1354,23 +1181,21 @@ if( UNIX )
|
|||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
|
||||
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma adl opn timidity timidityplus wildmidi oplsynth zmusic )
|
||||
|
||||
include_directories( .
|
||||
g_statusbar
|
||||
g_shared
|
||||
g_inventory
|
||||
sound
|
||||
sound/music
|
||||
sound/backend
|
||||
textures
|
||||
sound/oplsynth
|
||||
sound/timidity
|
||||
sound/wildmidi
|
||||
xlat
|
||||
scripting
|
||||
scripting/vm
|
||||
../gdtoa
|
||||
../dumb/include
|
||||
${CMAKE_BINARY_DIR}/gdtoa
|
||||
../libraries/gdtoa
|
||||
${CMAKE_BINARY_DIR}/libraries/gdtoa
|
||||
${SYSTEM_SOURCES_DIR} )
|
||||
|
||||
add_dependencies( zdoom revision_check )
|
||||
|
@ -1448,7 +1273,8 @@ endif()
|
|||
if( APPLE )
|
||||
set_target_properties(zdoom PROPERTIES
|
||||
LINK_FLAGS "-framework Cocoa -framework IOKit -framework OpenGL"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" )
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "" )
|
||||
|
||||
endif()
|
||||
|
||||
|
@ -1462,15 +1288,7 @@ install(TARGETS zdoom
|
|||
COMPONENT "Game executable")
|
||||
|
||||
source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+")
|
||||
source_group("Audio Files\\ADL MIDI" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/adlmidi/.+")
|
||||
source_group("Audio Files\\OPN MIDI" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/opnmidi/.+")
|
||||
source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/oplsynth/.+")
|
||||
source_group("Audio Files\\OPL Synth\\DOSBox" FILES sound/oplsynth/dosbox/opl.cpp sound/oplsynth/dosbox/opl.h)
|
||||
source_group("Audio Files\\Timidity" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/timidity/.+")
|
||||
source_group("Audio Files\\Timiditypp" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/timiditypp/.+")
|
||||
source_group("Audio Files\\WildMidi" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/wildmidi/.+")
|
||||
source_group("Audio Files\\MIDI Devices" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/mididevices/.+")
|
||||
source_group("Audio Files\\MIDI Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/midisources/.+")
|
||||
source_group("Audio Files\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/backend/.+")
|
||||
source_group("Audio Files\\Music formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/musicformats/.+")
|
||||
source_group("Audio Files\\Third-party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/thirdparty/.+")
|
||||
source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/math/.+")
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
** i_common.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2015 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef COCOA_I_COMMON_INCLUDED
|
||||
#define COCOA_I_COMMON_INCLUDED
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
|
||||
struct RenderBufferOptions
|
||||
{
|
||||
float pixelScale;
|
||||
|
||||
float shiftX;
|
||||
float shiftY;
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
extern RenderBufferOptions rbOpts;
|
||||
|
||||
|
||||
// Version of AppKit framework we are interested in
|
||||
// The following values are needed to build with earlier SDKs
|
||||
|
||||
#define AppKit10_7 1138
|
||||
#define AppKit10_8 1187
|
||||
#define AppKit10_9 1265
|
||||
|
||||
|
||||
@interface NSWindow(ExitAppOnClose)
|
||||
- (void)exitAppOnClose;
|
||||
@end
|
||||
|
||||
|
||||
void I_ProcessEvent(NSEvent* event);
|
||||
|
||||
void I_ProcessJoysticks();
|
||||
|
||||
NSSize I_GetContentViewSize(const NSWindow* window);
|
||||
void I_SetMainWindowVisible(bool visible);
|
||||
void I_SetNativeMouse(bool wantNative);
|
||||
|
||||
#endif // COCOA_I_COMMON_INCLUDED
|
|
@ -0,0 +1,789 @@
|
|||
/*
|
||||
** i_input.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2015 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "i_common.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "dikeys.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "v_video.h"
|
||||
#include "events.h"
|
||||
|
||||
|
||||
EXTERN_CVAR(Int, m_use_mouse)
|
||||
|
||||
CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||
{
|
||||
if (self < 0)
|
||||
{
|
||||
self = 0;
|
||||
}
|
||||
else if (self > 2)
|
||||
{
|
||||
self = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern int paused, chatmodeon;
|
||||
extern constate_e ConsoleState;
|
||||
|
||||
bool GUICapture;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// TODO: remove this magic!
|
||||
size_t s_skipMouseMoves;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void CheckGUICapture()
|
||||
{
|
||||
bool wantCapture = (MENU_Off == menuactive)
|
||||
? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon)
|
||||
: (MENU_On == menuactive || MENU_OnNoPause == menuactive);
|
||||
|
||||
// [ZZ] check active event handlers that want the UI processing
|
||||
if (!wantCapture && E_CheckUiProcessors())
|
||||
{
|
||||
wantCapture = true;
|
||||
}
|
||||
|
||||
if (wantCapture != GUICapture)
|
||||
{
|
||||
GUICapture = wantCapture;
|
||||
|
||||
ResetButtonStates();
|
||||
}
|
||||
}
|
||||
|
||||
void SetCursorPosition(const NSPoint position)
|
||||
{
|
||||
NSWindow* window = [NSApp keyWindow];
|
||||
if (nil == window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const NSRect displayRect = [[window screen] frame];
|
||||
const CGPoint eventPoint = CGPointMake(position.x, displayRect.size.height - position.y);
|
||||
|
||||
CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
|
||||
|
||||
if (NULL != eventSource)
|
||||
{
|
||||
CGEventRef mouseMoveEvent = CGEventCreateMouseEvent(eventSource,
|
||||
kCGEventMouseMoved, eventPoint, kCGMouseButtonLeft);
|
||||
|
||||
if (NULL != mouseMoveEvent)
|
||||
{
|
||||
CGEventPost(kCGHIDEventTap, mouseMoveEvent);
|
||||
CFRelease(mouseMoveEvent);
|
||||
}
|
||||
|
||||
CFRelease(eventSource);
|
||||
}
|
||||
|
||||
// TODO: remove this magic!
|
||||
s_skipMouseMoves = 2;
|
||||
}
|
||||
|
||||
void CenterCursor()
|
||||
{
|
||||
NSWindow* window = [NSApp keyWindow];
|
||||
if (nil == window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const NSRect displayRect = [[window screen] frame];
|
||||
const NSRect windowRect = [window frame];
|
||||
const NSPoint centerPoint = { NSMidX(windowRect), NSMidY(windowRect) };
|
||||
|
||||
SetCursorPosition(centerPoint);
|
||||
}
|
||||
|
||||
bool IsInGame()
|
||||
{
|
||||
switch (mouse_capturemode)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return gamestate == GS_LEVEL;
|
||||
|
||||
case 1:
|
||||
return gamestate == GS_LEVEL
|
||||
|| gamestate == GS_INTERMISSION
|
||||
|| gamestate == GS_FINALE;
|
||||
|
||||
case 2:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckNativeMouse()
|
||||
{
|
||||
const bool windowed = (NULL == screen) || !screen->IsFullscreen();
|
||||
bool wantNative;
|
||||
|
||||
if (windowed)
|
||||
{
|
||||
if (![NSApp isActive] || !use_mouse)
|
||||
{
|
||||
wantNative = true;
|
||||
}
|
||||
else if (MENU_WaitKey == menuactive)
|
||||
{
|
||||
wantNative = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantNative = (!m_use_mouse || MENU_WaitKey != menuactive)
|
||||
&& (!IsInGame() || GUICapture || paused || demoplayback);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ungrab mouse when in the menu with mouse control on.
|
||||
wantNative = m_use_mouse
|
||||
&& (MENU_On == menuactive || MENU_OnNoPause == menuactive);
|
||||
}
|
||||
|
||||
if (!wantNative && E_CheckRequireMouse())
|
||||
wantNative = true;
|
||||
|
||||
I_SetNativeMouse(wantNative);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
void I_GetEvent()
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
void I_StartTic()
|
||||
{
|
||||
CheckGUICapture();
|
||||
CheckNativeMouse();
|
||||
|
||||
I_ProcessJoysticks();
|
||||
I_GetEvent();
|
||||
}
|
||||
|
||||
void I_StartFrame()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void I_SetMouseCapture()
|
||||
{
|
||||
}
|
||||
|
||||
void I_ReleaseMouseCapture()
|
||||
{
|
||||
}
|
||||
|
||||
void I_SetNativeMouse(bool wantNative)
|
||||
{
|
||||
static bool nativeMouse = true;
|
||||
static NSPoint mouseLocation;
|
||||
|
||||
if (wantNative != nativeMouse)
|
||||
{
|
||||
nativeMouse = wantNative;
|
||||
|
||||
if (!wantNative)
|
||||
{
|
||||
mouseLocation = [NSEvent mouseLocation];
|
||||
CenterCursor();
|
||||
}
|
||||
|
||||
CGAssociateMouseAndMouseCursorPosition(wantNative);
|
||||
|
||||
if (wantNative)
|
||||
{
|
||||
SetCursorPosition(mouseLocation);
|
||||
|
||||
[NSCursor unhide];
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSCursor hide];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const size_t KEY_COUNT = 128;
|
||||
|
||||
|
||||
// See Carbon -> HIToolbox -> Events.h for kVK_ constants
|
||||
|
||||
const uint8_t KEYCODE_TO_DIK[KEY_COUNT] =
|
||||
{
|
||||
DIK_A, DIK_S, DIK_D, DIK_F, DIK_H, DIK_G, DIK_Z, DIK_X, // 0x00 - 0x07
|
||||
DIK_C, DIK_V, 0, DIK_B, DIK_Q, DIK_W, DIK_E, DIK_R, // 0x08 - 0x0F
|
||||
DIK_Y, DIK_T, DIK_1, DIK_2, DIK_3, DIK_4, DIK_6, DIK_5, // 0x10 - 0x17
|
||||
DIK_EQUALS, DIK_9, DIK_7, DIK_MINUS, DIK_8, DIK_0, DIK_RBRACKET, DIK_O, // 0x18 - 0x1F
|
||||
DIK_U, DIK_LBRACKET, DIK_I, DIK_P, DIK_RETURN, DIK_L, DIK_J, DIK_APOSTROPHE, // 0x20 - 0x27
|
||||
DIK_K, DIK_SEMICOLON, DIK_BACKSLASH, DIK_COMMA, DIK_SLASH, DIK_N, DIK_M, DIK_PERIOD, // 0x28 - 0x2F
|
||||
DIK_TAB, DIK_SPACE, DIK_GRAVE, DIK_BACK, 0, DIK_ESCAPE, 0, DIK_LWIN, // 0x30 - 0x37
|
||||
DIK_LSHIFT, DIK_CAPITAL, DIK_LMENU, DIK_LCONTROL, DIK_RSHIFT, DIK_RMENU, DIK_RCONTROL, 0, // 0x38 - 0x3F
|
||||
0, DIK_DECIMAL, 0, DIK_MULTIPLY, 0, DIK_ADD, 0, 0, // 0x40 - 0x47
|
||||
DIK_VOLUMEUP, DIK_VOLUMEDOWN, DIK_MUTE, DIK_SLASH, DIK_NUMPADENTER, 0, DIK_SUBTRACT, 0, // 0x48 - 0x4F
|
||||
0, DIK_NUMPAD_EQUALS, DIK_NUMPAD0, DIK_NUMPAD1, DIK_NUMPAD2, DIK_NUMPAD3, DIK_NUMPAD4, DIK_NUMPAD5, // 0x50 - 0x57
|
||||
DIK_NUMPAD6, DIK_NUMPAD7, 0, DIK_NUMPAD8, DIK_NUMPAD9, 0, 0, 0, // 0x58 - 0x5F
|
||||
DIK_F5, DIK_F6, DIK_F7, DIK_F3, DIK_F8, DIK_F9, 0, DIK_F11, // 0x60 - 0x67
|
||||
0, DIK_F13, 0, DIK_F14, 0, DIK_F10, 0, DIK_F12, // 0x68 - 0x6F
|
||||
0, DIK_F15, 0, DIK_HOME, 0, DIK_DELETE, DIK_F4, DIK_END, // 0x70 - 0x77
|
||||
DIK_F2, 0, DIK_F1, DIK_LEFT, DIK_RIGHT, DIK_DOWN, DIK_UP, 0, // 0x78 - 0x7F
|
||||
};
|
||||
|
||||
const uint8_t KEYCODE_TO_ASCII[KEY_COUNT] =
|
||||
{
|
||||
'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', // 0x00 - 0x07
|
||||
'c', 'v', 0, 'b', 'q', 'w', 'e', 'r', // 0x08 - 0x0F
|
||||
'y', 't', '1', '2', '3', '4', '6', '5', // 0x10 - 0x17
|
||||
'=', '9', '7', '-', '8', '0', ']', 'o', // 0x18 - 0x1F
|
||||
'u', '[', 'i', 'p', 13, 'l', 'j', '\'', // 0x20 - 0x27
|
||||
'k', ';', '\\', ',', '/', 'n', 'm', '.', // 0x28 - 0x2F
|
||||
9, ' ', '`', 12, 0, 27, 0, 0, // 0x30 - 0x37
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x38 - 0x3F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0x47
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x48 - 0x4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0x57
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x58 - 0x5F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x60 - 0x67
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x68 - 0x6F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0x77
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // 0x78 - 0x7F
|
||||
};
|
||||
|
||||
|
||||
uint8_t ModifierToDIK(const uint32_t modifier)
|
||||
{
|
||||
switch (modifier)
|
||||
{
|
||||
case NSAlphaShiftKeyMask: return DIK_CAPITAL;
|
||||
case NSShiftKeyMask: return DIK_LSHIFT;
|
||||
case NSControlKeyMask: return DIK_LCONTROL;
|
||||
case NSAlternateKeyMask: return DIK_LMENU;
|
||||
case NSCommandKeyMask: return DIK_LWIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t ModifierFlagsToGUIKeyModifiers(NSEvent* theEvent)
|
||||
{
|
||||
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
|
||||
return ((modifiers & NSShiftKeyMask ) ? GKM_SHIFT : 0)
|
||||
| ((modifiers & NSControlKeyMask ) ? GKM_CTRL : 0)
|
||||
| ((modifiers & NSAlternateKeyMask) ? GKM_ALT : 0)
|
||||
| ((modifiers & NSCommandKeyMask ) ? GKM_META : 0);
|
||||
}
|
||||
|
||||
bool ShouldGenerateGUICharEvent(NSEvent* theEvent)
|
||||
{
|
||||
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
|
||||
return !(modifiers & NSControlKeyMask)
|
||||
&& !(modifiers & NSAlternateKeyMask)
|
||||
&& !(modifiers & NSCommandKeyMask)
|
||||
&& !(modifiers & NSFunctionKeyMask);
|
||||
}
|
||||
|
||||
|
||||
NSStringEncoding GetEncodingForUnicodeCharacter(const unichar character)
|
||||
{
|
||||
if (character >= L'\u0100' && character <= L'\u024F')
|
||||
{
|
||||
return NSWindowsCP1250StringEncoding; // Central and Eastern Europe
|
||||
}
|
||||
else if (character >= L'\u0370' && character <= L'\u03FF')
|
||||
{
|
||||
return NSWindowsCP1253StringEncoding; // Greek
|
||||
}
|
||||
else if (character >= L'\u0400' && character <= L'\u04FF')
|
||||
{
|
||||
return NSWindowsCP1251StringEncoding; // Cyrillic
|
||||
}
|
||||
|
||||
// TODO: add handling for other characters
|
||||
// TODO: Turkish should use NSWindowsCP1254StringEncoding
|
||||
|
||||
return NSWindowsCP1252StringEncoding;
|
||||
}
|
||||
|
||||
unsigned char GetCharacterFromNSEvent(NSEvent* theEvent, unichar *realchar)
|
||||
{
|
||||
const NSString* unicodeCharacters = [theEvent characters];
|
||||
|
||||
if (0 == [unicodeCharacters length])
|
||||
{
|
||||
return '\0';
|
||||
}
|
||||
|
||||
const unichar unicodeCharacter = [unicodeCharacters characterAtIndex:0];
|
||||
const NSStringEncoding encoding = GetEncodingForUnicodeCharacter(unicodeCharacter);
|
||||
|
||||
unsigned char character = '\0';
|
||||
|
||||
if (NSWindowsCP1252StringEncoding == encoding)
|
||||
{
|
||||
// TODO: make sure that the following is always correct
|
||||
character = unicodeCharacter & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
const NSData* const characters =
|
||||
[[theEvent characters] dataUsingEncoding:encoding];
|
||||
|
||||
character = [characters length] > 0
|
||||
? *static_cast<const unsigned char*>([characters bytes])
|
||||
: '\0';
|
||||
}
|
||||
|
||||
*realchar = unicodeCharacter;
|
||||
return character;
|
||||
}
|
||||
|
||||
void ProcessKeyboardEventInMenu(NSEvent* theEvent)
|
||||
{
|
||||
event_t event = {};
|
||||
|
||||
unichar realchar;
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = NSKeyDown == [theEvent type] ? EV_GUI_KeyDown : EV_GUI_KeyUp;
|
||||
event.data2 = GetCharacterFromNSEvent(theEvent, &realchar);
|
||||
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||
|
||||
if (EV_GUI_KeyDown == event.subtype && [theEvent isARepeat])
|
||||
{
|
||||
event.subtype = EV_GUI_KeyRepeat;
|
||||
}
|
||||
|
||||
const unsigned short keyCode = [theEvent keyCode];
|
||||
|
||||
switch (keyCode)
|
||||
{
|
||||
case kVK_Return: event.data1 = GK_RETURN; break;
|
||||
case kVK_PageUp: event.data1 = GK_PGUP; break;
|
||||
case kVK_PageDown: event.data1 = GK_PGDN; break;
|
||||
case kVK_End: event.data1 = GK_END; break;
|
||||
case kVK_Home: event.data1 = GK_HOME; break;
|
||||
case kVK_LeftArrow: event.data1 = GK_LEFT; break;
|
||||
case kVK_RightArrow: event.data1 = GK_RIGHT; break;
|
||||
case kVK_UpArrow: event.data1 = GK_UP; break;
|
||||
case kVK_DownArrow: event.data1 = GK_DOWN; break;
|
||||
case kVK_Delete: event.data1 = GK_BACKSPACE; break;
|
||||
case kVK_ForwardDelete: event.data1 = GK_DEL; break;
|
||||
case kVK_Escape: event.data1 = GK_ESCAPE; break;
|
||||
case kVK_F1: event.data1 = GK_F1; break;
|
||||
case kVK_F2: event.data1 = GK_F2; break;
|
||||
case kVK_F3: event.data1 = GK_F3; break;
|
||||
case kVK_F4: event.data1 = GK_F4; break;
|
||||
case kVK_F5: event.data1 = GK_F5; break;
|
||||
case kVK_F6: event.data1 = GK_F6; break;
|
||||
case kVK_F7: event.data1 = GK_F7; break;
|
||||
case kVK_F8: event.data1 = GK_F8; break;
|
||||
case kVK_F9: event.data1 = GK_F9; break;
|
||||
case kVK_F10: event.data1 = GK_F10; break;
|
||||
case kVK_F11: event.data1 = GK_F11; break;
|
||||
case kVK_F12: event.data1 = GK_F12; break;
|
||||
case kVK_F13: event.data1 = GK_SYSRQ; break;
|
||||
default:
|
||||
event.data1 = KEYCODE_TO_ASCII[keyCode];
|
||||
break;
|
||||
}
|
||||
|
||||
if (event.data1 < 128)
|
||||
{
|
||||
event.data1 = toupper(event.data1);
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
if (!iscntrl(event.data2)
|
||||
&& EV_GUI_KeyUp != event.subtype
|
||||
&& ShouldGenerateGUICharEvent(theEvent))
|
||||
{
|
||||
event.subtype = EV_GUI_Char;
|
||||
event.data1 = realchar;
|
||||
event.data2 = event.data3 & GKM_ALT;
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NSEventToGameMousePosition(NSEvent* inEvent, event_t* outEvent)
|
||||
{
|
||||
const NSWindow* window = [inEvent window];
|
||||
const NSView* view = [window contentView];
|
||||
|
||||
const NSPoint screenPos = [NSEvent mouseLocation];
|
||||
const NSRect screenRect = NSMakeRect(screenPos.x, screenPos.y, 0, 0);
|
||||
const NSRect windowRect = [window convertRectFromScreen:screenRect];
|
||||
const NSPoint viewPos = [view convertPointToBacking:windowRect.origin];
|
||||
const CGFloat frameHeight = I_GetContentViewSize(window).height;
|
||||
|
||||
outEvent->data1 = static_cast<int16_t>( viewPos.x);
|
||||
outEvent->data2 = static_cast<int16_t>(frameHeight - viewPos.y);
|
||||
|
||||
// Compensate letterbox adjustment done by cross-platform code
|
||||
// More elegant solution is a bit problematic due to HiDPI/Retina support
|
||||
outEvent->data2 += (int(frameHeight) - screen->VideoHeight) / 2;
|
||||
|
||||
screen->ScaleCoordsFromWindow(outEvent->data1, outEvent->data2);
|
||||
}
|
||||
|
||||
void ProcessMouseMoveInMenu(NSEvent* theEvent)
|
||||
{
|
||||
event_t event = {};
|
||||
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = EV_GUI_MouseMove;
|
||||
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||
|
||||
NSEventToGameMousePosition(theEvent, &event);
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
void ProcessMouseMoveInGame(NSEvent* theEvent)
|
||||
{
|
||||
int x([theEvent deltaX]);
|
||||
int y(-[theEvent deltaY]);
|
||||
|
||||
if (0 == x && 0 == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_noprescale)
|
||||
{
|
||||
x *= 3;
|
||||
y *= 2;
|
||||
}
|
||||
|
||||
event_t event = {};
|
||||
|
||||
static int lastX = 0, lastY = 0;
|
||||
|
||||
if (m_filter)
|
||||
{
|
||||
event.x = (x + lastX) / 2;
|
||||
event.y = (y + lastY) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
event.x = x;
|
||||
event.y = y;
|
||||
}
|
||||
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
|
||||
if (0 != event.x || 0 != event.y)
|
||||
{
|
||||
event.type = EV_Mouse;
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProcessKeyboardEvent(NSEvent* theEvent)
|
||||
{
|
||||
const unsigned short keyCode = [theEvent keyCode];
|
||||
if (keyCode >= KEY_COUNT)
|
||||
{
|
||||
assert(!"Unknown keycode");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isARepeat = [theEvent isARepeat];
|
||||
|
||||
if (k_allowfullscreentoggle
|
||||
&& (kVK_ANSI_F == keyCode)
|
||||
&& (NSCommandKeyMask & [theEvent modifierFlags])
|
||||
&& (NSKeyDown == [theEvent type])
|
||||
&& !isARepeat)
|
||||
{
|
||||
ToggleFullscreen = !ToggleFullscreen;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUICapture)
|
||||
{
|
||||
ProcessKeyboardEventInMenu(theEvent);
|
||||
}
|
||||
else if (!isARepeat)
|
||||
{
|
||||
event_t event = {};
|
||||
|
||||
event.type = NSKeyDown == [theEvent type] ? EV_KeyDown : EV_KeyUp;
|
||||
event.data1 = KEYCODE_TO_DIK[ keyCode ];
|
||||
|
||||
if (0 != event.data1)
|
||||
{
|
||||
event.data2 = KEYCODE_TO_ASCII[ keyCode ];
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessKeyboardFlagsEvent(NSEvent* theEvent)
|
||||
{
|
||||
if (GUICapture)
|
||||
{
|
||||
// Ignore events from modifier keys in menu/console/chat
|
||||
return;
|
||||
}
|
||||
|
||||
static const uint32_t FLAGS_MASK =
|
||||
NSDeviceIndependentModifierFlagsMask & ~NSNumericPadKeyMask;
|
||||
|
||||
const uint32_t modifiers = [theEvent modifierFlags] & FLAGS_MASK;
|
||||
static uint32_t oldModifiers = 0;
|
||||
const uint32_t deltaModifiers = modifiers ^ oldModifiers;
|
||||
|
||||
if (0 == deltaModifiers)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event_t event = {};
|
||||
event.type = modifiers > oldModifiers ? EV_KeyDown : EV_KeyUp;
|
||||
event.data1 = ModifierToDIK(deltaModifiers);
|
||||
|
||||
oldModifiers = modifiers;
|
||||
|
||||
if (DIK_CAPITAL == event.data1)
|
||||
{
|
||||
// Caps Lock is a modifier key which generates one event per state change
|
||||
// but not per actual key press or release. So treat any event as key down
|
||||
event.type = EV_KeyDown;
|
||||
}
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
|
||||
void ProcessMouseMoveEvent(NSEvent* theEvent)
|
||||
{
|
||||
if (!use_mouse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_skipMouseMoves > 0)
|
||||
{
|
||||
--s_skipMouseMoves;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUICapture)
|
||||
{
|
||||
ProcessMouseMoveInMenu(theEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMouseMoveInGame(theEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMouseButtonEvent(NSEvent* theEvent)
|
||||
{
|
||||
if (!use_mouse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event_t event = {};
|
||||
|
||||
const NSEventType cocoaEventType = [theEvent type];
|
||||
|
||||
if (GUICapture)
|
||||
{
|
||||
event.type = EV_GUI_Event;
|
||||
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||
|
||||
switch (cocoaEventType)
|
||||
{
|
||||
case NSLeftMouseDown: event.subtype = EV_GUI_LButtonDown; break;
|
||||
case NSRightMouseDown: event.subtype = EV_GUI_RButtonDown; break;
|
||||
case NSOtherMouseDown: event.subtype = EV_GUI_MButtonDown; break;
|
||||
case NSLeftMouseUp: event.subtype = EV_GUI_LButtonUp; break;
|
||||
case NSRightMouseUp: event.subtype = EV_GUI_RButtonUp; break;
|
||||
case NSOtherMouseUp: event.subtype = EV_GUI_MButtonUp; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
NSEventToGameMousePosition(theEvent, &event);
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cocoaEventType)
|
||||
{
|
||||
case NSLeftMouseDown:
|
||||
case NSRightMouseDown:
|
||||
case NSOtherMouseDown:
|
||||
event.type = EV_KeyDown;
|
||||
break;
|
||||
|
||||
case NSLeftMouseUp:
|
||||
case NSRightMouseUp:
|
||||
case NSOtherMouseUp:
|
||||
event.type = EV_KeyUp;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
event.data1 = MIN(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8));
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMouseWheelEvent(NSEvent* theEvent)
|
||||
{
|
||||
if (!use_mouse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int16_t modifiers = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||
const CGFloat delta = (modifiers & GKM_SHIFT)
|
||||
? [theEvent deltaX]
|
||||
: [theEvent deltaY];
|
||||
const bool isZeroDelta = fabs(delta) < 1.0E-5;
|
||||
|
||||
if (isZeroDelta && GUICapture)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event_t event = {};
|
||||
|
||||
if (GUICapture)
|
||||
{
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = delta > 0.0f ? EV_GUI_WheelUp : EV_GUI_WheelDown;
|
||||
event.data3 = modifiers;
|
||||
}
|
||||
else
|
||||
{
|
||||
event.type = isZeroDelta ? EV_KeyUp : EV_KeyDown;
|
||||
event.data1 = delta > 0.0f ? KEY_MWHEELUP : KEY_MWHEELDOWN;
|
||||
}
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
void I_ProcessEvent(NSEvent* event)
|
||||
{
|
||||
const NSEventType eventType = [event type];
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case NSMouseMoved:
|
||||
ProcessMouseMoveEvent(event);
|
||||
break;
|
||||
|
||||
case NSLeftMouseDown:
|
||||
case NSLeftMouseUp:
|
||||
case NSRightMouseDown:
|
||||
case NSRightMouseUp:
|
||||
case NSOtherMouseDown:
|
||||
case NSOtherMouseUp:
|
||||
ProcessMouseButtonEvent(event);
|
||||
break;
|
||||
|
||||
case NSLeftMouseDragged:
|
||||
case NSRightMouseDragged:
|
||||
case NSOtherMouseDragged:
|
||||
ProcessMouseButtonEvent(event);
|
||||
ProcessMouseMoveEvent(event);
|
||||
break;
|
||||
|
||||
case NSScrollWheel:
|
||||
ProcessMouseWheelEvent(event);
|
||||
break;
|
||||
|
||||
case NSKeyDown:
|
||||
case NSKeyUp:
|
||||
ProcessKeyboardEvent(event);
|
||||
break;
|
||||
|
||||
case NSFlagsChanged:
|
||||
ProcessKeyboardFlagsEvent(event);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,507 @@
|
|||
/*
|
||||
** i_main.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2018 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "i_common.h"
|
||||
#include "s_sound.h"
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
#include "cmdlib.h"
|
||||
#include "d_main.h"
|
||||
#include "doomerrors.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "s_sound.h"
|
||||
#include "st_console.h"
|
||||
#include "version.h"
|
||||
#include "doomerrors.h"
|
||||
#include "s_music.h"
|
||||
|
||||
|
||||
#define ZD_UNUSED(VARIABLE) ((void)(VARIABLE))
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
EXTERN_CVAR(Int, vid_defwidth )
|
||||
EXTERN_CVAR(Int, vid_defheight)
|
||||
EXTERN_CVAR(Bool, vid_vsync )
|
||||
EXTERN_CVAR(Bool, fullscreen )
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void Mac_I_FatalError(const char* const message)
|
||||
{
|
||||
I_SetMainWindowVisible(false);
|
||||
S_StopMusic(true);
|
||||
|
||||
FConsoleWindow::GetInstance().ShowFatalError(message);
|
||||
}
|
||||
|
||||
|
||||
void I_DetectOS()
|
||||
{
|
||||
SInt32 majorVersion = 0;
|
||||
Gestalt(gestaltSystemVersionMajor, &majorVersion);
|
||||
|
||||
SInt32 minorVersion = 0;
|
||||
Gestalt(gestaltSystemVersionMinor, &minorVersion);
|
||||
|
||||
SInt32 bugFixVersion = 0;
|
||||
Gestalt(gestaltSystemVersionBugFix, &bugFixVersion);
|
||||
|
||||
const char* name = "Unknown version";
|
||||
|
||||
if (10 == majorVersion) switch (minorVersion)
|
||||
{
|
||||
case 4: name = "Mac OS X Tiger"; break;
|
||||
case 5: name = "Mac OS X Leopard"; break;
|
||||
case 6: name = "Mac OS X Snow Leopard"; break;
|
||||
case 7: name = "Mac OS X Lion"; break;
|
||||
case 8: name = "OS X Mountain Lion"; break;
|
||||
case 9: name = "OS X Mavericks"; break;
|
||||
case 10: name = "OS X Yosemite"; break;
|
||||
case 11: name = "OS X El Capitan"; break;
|
||||
case 12: name = "macOS Sierra"; break;
|
||||
case 13: name = "macOS High Sierra"; break;
|
||||
case 14: name = "macOS Mojave"; break;
|
||||
case 15: name = "macOS Catalina"; break;
|
||||
}
|
||||
|
||||
char release[16] = "unknown";
|
||||
size_t size = sizeof release - 1;
|
||||
sysctlbyname("kern.osversion", release, &size, nullptr, 0);
|
||||
|
||||
const char* const architecture =
|
||||
#ifdef __i386__
|
||||
"32-bit Intel";
|
||||
#elif defined __x86_64__
|
||||
"64-bit Intel";
|
||||
#else
|
||||
"Unknown";
|
||||
#endif
|
||||
|
||||
Printf("OS: %s %d.%d.%d (%s) %s\n", name,
|
||||
int(majorVersion), int(minorVersion), int(bugFixVersion),
|
||||
release, architecture);
|
||||
}
|
||||
|
||||
|
||||
FArgs* Args; // command line arguments
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
TArray<FString> s_argv;
|
||||
|
||||
int DoMain(int argc, char** argv)
|
||||
{
|
||||
printf(GAMENAME" %s - %s - Cocoa version\nCompiled on %s\n\n",
|
||||
GetVersionString(), GetGitTime(), __DATE__);
|
||||
|
||||
seteuid(getuid());
|
||||
|
||||
// Set LC_NUMERIC environment variable in case some library decides to
|
||||
// clear the setlocale call at least this will be correct.
|
||||
// Note that the LANG environment variable is overridden by LC_*
|
||||
setenv("LC_NUMERIC", "C", 1);
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
// Set reasonable default values for video settings
|
||||
|
||||
const NSSize screenSize = [[NSScreen mainScreen] frame].size;
|
||||
vid_defwidth = static_cast<int>(screenSize.width);
|
||||
vid_defheight = static_cast<int>(screenSize.height);
|
||||
vid_vsync = true;
|
||||
fullscreen = true;
|
||||
|
||||
Args = new FArgs(argc, argv);
|
||||
|
||||
NSString* exePath = [[NSBundle mainBundle] executablePath];
|
||||
progdir = [[exePath stringByDeletingLastPathComponent] UTF8String];
|
||||
progdir += "/";
|
||||
|
||||
auto ret = D_DoomMain();
|
||||
FConsoleWindow::DeleteInstance();
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@interface ApplicationController : NSResponder<NSApplicationDelegate>
|
||||
{
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent*)theEvent;
|
||||
- (void)keyUp:(NSEvent*)theEvent;
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification*)aNotification;
|
||||
- (void)applicationWillResignActive:(NSNotification*)aNotification;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
|
||||
|
||||
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename;
|
||||
|
||||
- (void)processEvents:(NSTimer*)timer;
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
|
||||
|
||||
- (void)sendExitEvent:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
ApplicationController* appCtrl;
|
||||
|
||||
|
||||
@implementation ApplicationController
|
||||
|
||||
- (void)keyDown:(NSEvent*)theEvent
|
||||
{
|
||||
// Empty but present to avoid playing of 'beep' alert sound
|
||||
|
||||
ZD_UNUSED(theEvent);
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent*)theEvent
|
||||
{
|
||||
// Empty but present to avoid playing of 'beep' alert sound
|
||||
|
||||
ZD_UNUSED(theEvent);
|
||||
}
|
||||
|
||||
|
||||
extern bool AppActive;
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification*)aNotification
|
||||
{
|
||||
ZD_UNUSED(aNotification);
|
||||
|
||||
S_SetSoundPaused(1);
|
||||
|
||||
AppActive = true;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(NSNotification*)aNotification
|
||||
{
|
||||
ZD_UNUSED(aNotification);
|
||||
|
||||
S_SetSoundPaused(i_soundinbackground);
|
||||
|
||||
AppActive = false;
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
|
||||
{
|
||||
// When starting from command line with real executable path, e.g. ZDoom.app/Contents/MacOS/ZDoom
|
||||
// application remains deactivated for an unknown reason.
|
||||
// The following call resolves this issue
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
// Setup timer for custom event loop
|
||||
|
||||
NSTimer* timer = [NSTimer timerWithTimeInterval:0
|
||||
target:self
|
||||
selector:@selector(processEvents:)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
[[NSRunLoop currentRunLoop] addTimer:timer
|
||||
forMode:NSDefaultRunLoopMode];
|
||||
|
||||
FConsoleWindow::CreateInstance();
|
||||
|
||||
const size_t argc = s_argv.Size();
|
||||
TArray<char*> argv(argc + 1, true);
|
||||
|
||||
for (size_t i = 0; i < argc; ++i)
|
||||
{
|
||||
argv[i] = s_argv[i].LockBuffer();
|
||||
}
|
||||
|
||||
argv[argc] = nullptr;
|
||||
|
||||
exit(DoMain(argc, &argv[0]));
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename
|
||||
{
|
||||
ZD_UNUSED(theApplication);
|
||||
|
||||
// Some parameters from command line are passed to this function
|
||||
// These parameters need to be skipped to avoid duplication
|
||||
// Note: SDL has different approach to fix this issue, see the same method in SDLMain.m
|
||||
|
||||
const char* const charFileName = [filename UTF8String];
|
||||
|
||||
for (size_t i = 0, count = s_argv.Size(); i < count; ++i)
|
||||
{
|
||||
if (0 == strcmp(s_argv[i], charFileName))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
bool iwad = false;
|
||||
|
||||
if (const char* const extPos = strrchr(charFileName, '.'))
|
||||
{
|
||||
iwad = 0 == stricmp(extPos, ".iwad")
|
||||
|| 0 == stricmp(extPos, ".ipk3")
|
||||
|| 0 == stricmp(extPos, ".ipk7");
|
||||
}
|
||||
|
||||
s_argv.Push(iwad ? "-iwad" : "-file");
|
||||
s_argv.Push(charFileName);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
- (void)processEvents:(NSTimer*)timer
|
||||
{
|
||||
ZD_UNUSED(timer);
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
while (true)
|
||||
{
|
||||
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:[NSDate dateWithTimeIntervalSinceNow:0]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
if (nil == event)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
I_ProcessEvent(event);
|
||||
|
||||
[NSApp sendEvent:event];
|
||||
}
|
||||
|
||||
[NSApp updateWindows];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
[self sendExitEvent:sender];
|
||||
return NSTerminateLater;
|
||||
}
|
||||
|
||||
- (void)sendExitEvent:(id)sender
|
||||
{
|
||||
throw CExitEvent(0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
NSMenuItem* CreateApplicationMenu()
|
||||
{
|
||||
NSMenu* menu = [NSMenu new];
|
||||
|
||||
[menu addItemWithTitle:[@"About " stringByAppendingString:@GAMENAME]
|
||||
action:@selector(orderFrontStandardAboutPanel:)
|
||||
keyEquivalent:@""];
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
[menu addItemWithTitle:[@"Hide " stringByAppendingString:@GAMENAME]
|
||||
action:@selector(hide:)
|
||||
keyEquivalent:@"h"];
|
||||
[[menu addItemWithTitle:@"Hide Others"
|
||||
action:@selector(hideOtherApplications:)
|
||||
keyEquivalent:@"h"]
|
||||
setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask];
|
||||
[menu addItemWithTitle:@"Show All"
|
||||
action:@selector(unhideAllApplications:)
|
||||
keyEquivalent:@""];
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
[menu addItemWithTitle:[@"Quit " stringByAppendingString:@GAMENAME]
|
||||
action:@selector(sendExitEvent:)
|
||||
keyEquivalent:@"q"];
|
||||
|
||||
NSMenuItem* menuItem = [NSMenuItem new];
|
||||
[menuItem setSubmenu:menu];
|
||||
|
||||
if ([NSApp respondsToSelector:@selector(setAppleMenu:)])
|
||||
{
|
||||
[NSApp performSelector:@selector(setAppleMenu:) withObject:menu];
|
||||
}
|
||||
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
NSMenuItem* CreateEditMenu()
|
||||
{
|
||||
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
||||
|
||||
[menu addItemWithTitle:@"Undo"
|
||||
action:@selector(undo:)
|
||||
keyEquivalent:@"z"];
|
||||
[menu addItemWithTitle:@"Redo"
|
||||
action:@selector(redo:)
|
||||
keyEquivalent:@"Z"];
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
[menu addItemWithTitle:@"Cut"
|
||||
action:@selector(cut:)
|
||||
keyEquivalent:@"x"];
|
||||
[menu addItemWithTitle:@"Copy"
|
||||
action:@selector(copy:)
|
||||
keyEquivalent:@"c"];
|
||||
[menu addItemWithTitle:@"Paste"
|
||||
action:@selector(paste:)
|
||||
keyEquivalent:@"v"];
|
||||
[menu addItemWithTitle:@"Delete"
|
||||
action:@selector(delete:)
|
||||
keyEquivalent:@""];
|
||||
[menu addItemWithTitle:@"Select All"
|
||||
action:@selector(selectAll:)
|
||||
keyEquivalent:@"a"];
|
||||
|
||||
NSMenuItem* menuItem = [NSMenuItem new];
|
||||
[menuItem setSubmenu:menu];
|
||||
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
NSMenuItem* CreateWindowMenu()
|
||||
{
|
||||
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
[NSApp setWindowsMenu:menu];
|
||||
|
||||
[menu addItemWithTitle:@"Minimize"
|
||||
action:@selector(performMiniaturize:)
|
||||
keyEquivalent:@"m"];
|
||||
[menu addItemWithTitle:@"Zoom"
|
||||
action:@selector(performZoom:)
|
||||
keyEquivalent:@""];
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
[menu addItemWithTitle:@"Bring All to Front"
|
||||
action:@selector(arrangeInFront:)
|
||||
keyEquivalent:@""];
|
||||
|
||||
NSMenuItem* menuItem = [NSMenuItem new];
|
||||
[menuItem setSubmenu:menu];
|
||||
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
void CreateMenu()
|
||||
{
|
||||
NSMenu* menuBar = [NSMenu new];
|
||||
[menuBar addItem:CreateApplicationMenu()];
|
||||
[menuBar addItem:CreateEditMenu()];
|
||||
[menuBar addItem:CreateWindowMenu()];
|
||||
|
||||
[NSApp setMainMenu:menuBar];
|
||||
}
|
||||
|
||||
void ReleaseApplicationController()
|
||||
{
|
||||
if (NULL != appCtrl)
|
||||
{
|
||||
[NSApp setDelegate:nil];
|
||||
[NSApp deactivate];
|
||||
|
||||
[appCtrl release];
|
||||
appCtrl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
const char* const argument = argv[i];
|
||||
|
||||
#if _DEBUG
|
||||
if (0 == strcmp(argument, "-wait_for_debugger"))
|
||||
{
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:@GAMENAME];
|
||||
[alert setInformativeText:@"Waiting for debugger..."];
|
||||
[alert addButtonWithTitle:@"Continue"];
|
||||
[alert runModal];
|
||||
}
|
||||
#endif // _DEBUG
|
||||
|
||||
s_argv.Push(argument);
|
||||
}
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
// The following code isn't mandatory,
|
||||
// but it enables to run the application without a bundle
|
||||
if ([NSApp respondsToSelector:@selector(setActivationPolicy:)])
|
||||
{
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
}
|
||||
|
||||
CreateMenu();
|
||||
|
||||
atexit(ReleaseApplicationController);
|
||||
|
||||
appCtrl = [ApplicationController new];
|
||||
[NSApp setDelegate:appCtrl];
|
||||
[NSApp run];
|
||||
|
||||
[pool release];
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
** i_system.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2018 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "i_common.h"
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include "i_system.h"
|
||||
#include "st_console.h"
|
||||
#include "v_text.h"
|
||||
|
||||
|
||||
double PerfToSec, PerfToMillisec;
|
||||
|
||||
void CalculateCPUSpeed()
|
||||
{
|
||||
long long frequency;
|
||||
size_t size = sizeof frequency;
|
||||
|
||||
if (0 == sysctlbyname("machdep.tsc.frequency", &frequency, &size, nullptr, 0) && 0 != frequency)
|
||||
{
|
||||
PerfToSec = 1.0 / frequency;
|
||||
PerfToMillisec = 1000.0 / frequency;
|
||||
|
||||
if (!batchrun)
|
||||
{
|
||||
Printf("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I_SetIWADInfo()
|
||||
{
|
||||
FConsoleWindow::GetInstance().SetTitleText();
|
||||
}
|
||||
|
||||
|
||||
void I_DebugPrint(const char *cp)
|
||||
{
|
||||
NSLog(@"%s", cp);
|
||||
}
|
||||
|
||||
|
||||
void I_PrintStr(const char* const message)
|
||||
{
|
||||
FConsoleWindow::GetInstance().AddText(message);
|
||||
|
||||
// Strip out any color escape sequences before writing to output
|
||||
char* const copy = new char[strlen(message) + 1];
|
||||
const char* srcp = message;
|
||||
char* dstp = copy;
|
||||
|
||||
while ('\0' != *srcp)
|
||||
{
|
||||
if (TEXTCOLOR_ESCAPE == *srcp)
|
||||
{
|
||||
if ('\0' != srcp[1])
|
||||
{
|
||||
srcp += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character
|
||||
{
|
||||
*dstp++ = '-';
|
||||
++srcp;
|
||||
}
|
||||
else if (0x1e == *srcp) // Middle bar character
|
||||
{
|
||||
*dstp++ = '=';
|
||||
++srcp;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dstp++ = *srcp++;
|
||||
}
|
||||
}
|
||||
|
||||
*dstp = '\0';
|
||||
|
||||
fputs(copy, stdout);
|
||||
delete[] copy;
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
void Mac_I_FatalError(const char* const message);
|
||||
|
||||
void I_ShowFatalError(const char *message)
|
||||
{
|
||||
Mac_I_FatalError(message);
|
||||
}
|
||||
|
||||
|
||||
int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad)
|
||||
{
|
||||
if (!showwin)
|
||||
{
|
||||
return defaultiwad;
|
||||
}
|
||||
|
||||
I_SetMainWindowVisible(false);
|
||||
|
||||
extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int);
|
||||
const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad);
|
||||
|
||||
I_SetMainWindowVisible(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void I_PutInClipboard(const char* const string)
|
||||
{
|
||||
NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
|
||||
NSString* const stringType = NSStringPboardType;
|
||||
NSArray* const types = [NSArray arrayWithObjects:stringType, nil];
|
||||
NSString* const content = [NSString stringWithUTF8String:string];
|
||||
|
||||
[pasteBoard declareTypes:types
|
||||
owner:nil];
|
||||
[pasteBoard setString:content
|
||||
forType:stringType];
|
||||
}
|
||||
|
||||
FString I_GetFromClipboard(bool returnNothing)
|
||||
{
|
||||
if (returnNothing)
|
||||
{
|
||||
return FString();
|
||||
}
|
||||
|
||||
NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
|
||||
NSString* const value = [pasteBoard stringForType:NSStringPboardType];
|
||||
|
||||
return FString([value UTF8String]);
|
||||
}
|
||||
|
||||
|
||||
unsigned int I_MakeRNGSeed()
|
||||
{
|
||||
return static_cast<unsigned int>(arc4random());
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
** sdlglvideo.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2014 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
// IMPORTANT NOTE!
|
||||
// This file was intentially named sdlglvideo.h but it has nothing with SDL
|
||||
// The name was selected to avoid spreding of changes over the project
|
||||
// The same applies to SDLGLFB class
|
||||
// See gl/system/gl_framebuffer.h for details about its usage
|
||||
|
||||
|
||||
#ifndef COCOA_SDLGLVIDEO_H_INCLUDED
|
||||
#define COCOA_SDLGLVIDEO_H_INCLUDED
|
||||
|
||||
#include "v_video.h"
|
||||
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_hwtexture.h"
|
||||
|
||||
|
||||
class SDLGLFB : public DFrameBuffer
|
||||
{
|
||||
public:
|
||||
// This must have the same parameters as the Windows version, even if they are not used!
|
||||
SDLGLFB(void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
|
||||
~SDLGLFB();
|
||||
|
||||
virtual bool Lock(bool buffered = true);
|
||||
virtual void Unlock();
|
||||
virtual bool IsLocked();
|
||||
|
||||
virtual bool IsFullscreen();
|
||||
virtual void SetVSync(bool vsync);
|
||||
|
||||
int GetClientWidth();
|
||||
int GetClientHeight();
|
||||
|
||||
virtual int GetTrueHeight() { return GetClientHeight(); }
|
||||
protected:
|
||||
int m_Lock;
|
||||
bool UpdatePending;
|
||||
|
||||
static const uint32_t GAMMA_CHANNEL_SIZE = 256;
|
||||
static const uint32_t GAMMA_CHANNEL_COUNT = 3;
|
||||
static const uint32_t GAMMA_TABLE_SIZE = GAMMA_CHANNEL_SIZE * GAMMA_CHANNEL_COUNT;
|
||||
|
||||
bool m_supportsGamma;
|
||||
uint16_t m_originalGamma[GAMMA_TABLE_SIZE];
|
||||
|
||||
SDLGLFB();
|
||||
|
||||
void InitializeState();
|
||||
|
||||
void SwapBuffers();
|
||||
|
||||
void SetGammaTable(uint16_t* table);
|
||||
void ResetGammaTable();
|
||||
};
|
||||
|
||||
#endif // COCOA_SDLGLVIDEO_H_INCLUDED
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
** st_console.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef COCOA_ST_CONSOLE_INCLUDED
|
||||
#define COCOA_ST_CONSOLE_INCLUDED
|
||||
|
||||
@class NSButton;
|
||||
@class NSProgressIndicator;
|
||||
@class NSScrollView;
|
||||
@class NSTextField;
|
||||
@class NSTextView;
|
||||
@class NSView;
|
||||
@class NSWindow;
|
||||
|
||||
struct PalEntry;
|
||||
|
||||
|
||||
class FConsoleWindow
|
||||
{
|
||||
public:
|
||||
static FConsoleWindow& GetInstance();
|
||||
|
||||
static void CreateInstance();
|
||||
static void DeleteInstance();
|
||||
|
||||
void Show(bool visible);
|
||||
void ShowFatalError(const char* message);
|
||||
|
||||
void AddText(const char* message);
|
||||
|
||||
void SetTitleText();
|
||||
void SetProgressBar(bool visible);
|
||||
|
||||
// FStartupScreen functionality
|
||||
void Progress(int current, int maximum);
|
||||
void NetInit(const char* message, int playerCount);
|
||||
void NetProgress(int count);
|
||||
void NetDone();
|
||||
|
||||
private:
|
||||
NSWindow* m_window;
|
||||
NSTextView* m_textView;
|
||||
NSScrollView* m_scrollView;
|
||||
NSProgressIndicator* m_progressBar;
|
||||
|
||||
NSView* m_netView;
|
||||
NSTextField* m_netMessageText;
|
||||
NSTextField* m_netCountText;
|
||||
NSProgressIndicator* m_netProgressBar;
|
||||
NSButton* m_netAbortButton;
|
||||
|
||||
unsigned int m_characterCount;
|
||||
|
||||
int m_netCurPos;
|
||||
int m_netMaxPos;
|
||||
|
||||
FConsoleWindow();
|
||||
|
||||
void ExpandTextView(float height);
|
||||
|
||||
void AddText(const PalEntry& color, const char* message);
|
||||
|
||||
void ScrollTextToBottom();
|
||||
};
|
||||
|
||||
#endif // COCOA_ST_CONSOLE_INCLUDED
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
** st_console.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "i_common.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "i_system.h"
|
||||
#include "st_console.h"
|
||||
#include "v_text.h"
|
||||
#include "version.h"
|
||||
#include "i_time.h"
|
||||
|
||||
|
||||
static NSColor* RGB(const uint8_t red, const uint8_t green, const uint8_t blue)
|
||||
{
|
||||
return [NSColor colorWithCalibratedRed:red / 255.0f
|
||||
green:green / 255.0f
|
||||
blue:blue / 255.0f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
static NSColor* RGB(const PalEntry& color)
|
||||
{
|
||||
return RGB(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
static NSColor* RGB(const uint32_t color)
|
||||
{
|
||||
return RGB(PalEntry(color));
|
||||
}
|
||||
|
||||
|
||||
static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f;
|
||||
static const CGFloat NET_VIEW_HEIGHT = 88.0f;
|
||||
|
||||
|
||||
FConsoleWindow::FConsoleWindow()
|
||||
: m_window([NSWindow alloc])
|
||||
, m_textView([NSTextView alloc])
|
||||
, m_scrollView([NSScrollView alloc])
|
||||
, m_progressBar(nil)
|
||||
, m_netView(nil)
|
||||
, m_netMessageText(nil)
|
||||
, m_netCountText(nil)
|
||||
, m_netProgressBar(nil)
|
||||
, m_netAbortButton(nil)
|
||||
, m_characterCount(0)
|
||||
, m_netCurPos(0)
|
||||
, m_netMaxPos(0)
|
||||
{
|
||||
const CGFloat initialWidth = 512.0f;
|
||||
const CGFloat initialHeight = 384.0f;
|
||||
const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight);
|
||||
|
||||
[m_textView initWithFrame:initialRect];
|
||||
[m_textView setEditable:NO];
|
||||
[m_textView setBackgroundColor:RGB(70, 70, 70)];
|
||||
[m_textView setMinSize:NSMakeSize(0.0f, initialHeight)];
|
||||
[m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
|
||||
[m_textView setVerticallyResizable:YES];
|
||||
[m_textView setHorizontallyResizable:NO];
|
||||
[m_textView setAutoresizingMask:NSViewWidthSizable];
|
||||
|
||||
NSTextContainer* const textContainer = [m_textView textContainer];
|
||||
[textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)];
|
||||
[textContainer setWidthTracksTextView:YES];
|
||||
|
||||
[m_scrollView initWithFrame:initialRect];
|
||||
[m_scrollView setBorderType:NSNoBorder];
|
||||
[m_scrollView setHasVerticalScroller:YES];
|
||||
[m_scrollView setHasHorizontalScroller:NO];
|
||||
[m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[m_scrollView setDocumentView:m_textView];
|
||||
|
||||
NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()];
|
||||
|
||||
[m_window initWithContentRect:initialRect
|
||||
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[m_window setMinSize:[m_window frame].size];
|
||||
[m_window setShowsResizeIndicator:NO];
|
||||
[m_window setTitle:title];
|
||||
[m_window center];
|
||||
[m_window exitAppOnClose];
|
||||
|
||||
// Do not allow fullscreen mode for this window
|
||||
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
|
||||
|
||||
[[m_window contentView] addSubview:m_scrollView];
|
||||
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
|
||||
static FConsoleWindow* s_instance;
|
||||
|
||||
|
||||
void FConsoleWindow::CreateInstance()
|
||||
{
|
||||
assert(NULL == s_instance);
|
||||
s_instance = new FConsoleWindow;
|
||||
}
|
||||
|
||||
void FConsoleWindow::DeleteInstance()
|
||||
{
|
||||
assert(NULL != s_instance);
|
||||
delete s_instance;
|
||||
s_instance = NULL;
|
||||
}
|
||||
|
||||
FConsoleWindow& FConsoleWindow::GetInstance()
|
||||
{
|
||||
assert(NULL != s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::Show(const bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
[m_window orderFront:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m_window orderOut:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void FConsoleWindow::ShowFatalError(const char* const message)
|
||||
{
|
||||
SetProgressBar(false);
|
||||
NetDone();
|
||||
|
||||
const CGFloat textViewWidth = [m_scrollView frame].size.width;
|
||||
|
||||
ExpandTextView(-32.0f);
|
||||
|
||||
NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)];
|
||||
[quitButton setAutoresizingMask:NSViewMinXMargin];
|
||||
[quitButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[quitButton setTitle:@"Quit"];
|
||||
[quitButton setKeyEquivalent:@"\r"];
|
||||
[quitButton setTarget:NSApp];
|
||||
[quitButton setAction:@selector(stopModal)];
|
||||
|
||||
NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)];
|
||||
[quitPanel setAutoresizingMask:NSViewWidthSizable];
|
||||
[quitPanel addSubview:quitButton];
|
||||
|
||||
[[m_window contentView] addSubview:quitPanel];
|
||||
[m_window orderFront:nil];
|
||||
|
||||
AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n");
|
||||
AddText(PalEntry(255, 255, 170), message);
|
||||
AddText("\n");
|
||||
|
||||
ScrollTextToBottom();
|
||||
|
||||
[NSApp runModalForWindow:m_window];
|
||||
}
|
||||
|
||||
|
||||
static const unsigned int THIRTY_FPS = 33; // milliseconds per update
|
||||
|
||||
|
||||
template <typename Function, unsigned int interval = THIRTY_FPS>
|
||||
struct TimedUpdater
|
||||
{
|
||||
explicit TimedUpdater(const Function& function)
|
||||
{
|
||||
const unsigned int currentTime = I_msTime();
|
||||
|
||||
if (currentTime - m_previousTime > interval)
|
||||
{
|
||||
m_previousTime = currentTime;
|
||||
|
||||
function();
|
||||
|
||||
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int m_previousTime;
|
||||
};
|
||||
|
||||
template <typename Function, unsigned int interval>
|
||||
unsigned int TimedUpdater<Function, interval>::m_previousTime;
|
||||
|
||||
template <typename Function, unsigned int interval = THIRTY_FPS>
|
||||
static void UpdateTimed(const Function& function)
|
||||
{
|
||||
TimedUpdater<Function, interval> dummy(function);
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::AddText(const char* message)
|
||||
{
|
||||
PalEntry color(223, 223, 223);
|
||||
|
||||
char buffer[1024] = {};
|
||||
size_t pos = 0;
|
||||
bool reset = false;
|
||||
|
||||
while (*message != '\0')
|
||||
{
|
||||
if ((TEXTCOLOR_ESCAPE == *message && 0 != pos)
|
||||
|| (pos == sizeof buffer - 1)
|
||||
|| reset)
|
||||
{
|
||||
buffer[pos] = '\0';
|
||||
pos = 0;
|
||||
reset = false;
|
||||
|
||||
AddText(color, buffer);
|
||||
}
|
||||
|
||||
if (TEXTCOLOR_ESCAPE == *message)
|
||||
{
|
||||
const uint8_t* colorID = reinterpret_cast<const uint8_t*>(message) + 1;
|
||||
if ('\0' == *colorID)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW);
|
||||
|
||||
if (range != CR_UNDEFINED)
|
||||
{
|
||||
color = V_LogColorFromColorRange(range);
|
||||
}
|
||||
|
||||
message += 2;
|
||||
}
|
||||
else if (0x1d == *message || 0x1f == *message) // Opening and closing bar characters
|
||||
{
|
||||
buffer[pos++] = '-';
|
||||
++message;
|
||||
}
|
||||
else if (0x1e == *message) // Middle bar character
|
||||
{
|
||||
buffer[pos++] = '=';
|
||||
++message;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[pos++] = *message++;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != pos)
|
||||
{
|
||||
buffer[pos] = '\0';
|
||||
|
||||
AddText(color, buffer);
|
||||
}
|
||||
|
||||
if ([m_window isVisible])
|
||||
{
|
||||
UpdateTimed([&]()
|
||||
{
|
||||
[m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void FConsoleWindow::AddText(const PalEntry& color, const char* const message)
|
||||
{
|
||||
NSString* const text = [NSString stringWithCString:message
|
||||
encoding:NSISOLatin1StringEncoding];
|
||||
|
||||
NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSFont systemFontOfSize:14.0f], NSFontAttributeName,
|
||||
RGB(color), NSForegroundColorAttributeName,
|
||||
nil];
|
||||
|
||||
NSAttributedString* const formattedText =
|
||||
[[NSAttributedString alloc] initWithString:text
|
||||
attributes:attributes];
|
||||
[[m_textView textStorage] appendAttributedString:formattedText];
|
||||
|
||||
m_characterCount += [text length];
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::ScrollTextToBottom()
|
||||
{
|
||||
[m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
|
||||
|
||||
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::SetTitleText()
|
||||
{
|
||||
static const CGFloat TITLE_TEXT_HEIGHT = 32.0f;
|
||||
|
||||
NSRect textViewFrame = [m_scrollView frame];
|
||||
textViewFrame.size.height -= TITLE_TEXT_HEIGHT;
|
||||
[m_scrollView setFrame:textViewFrame];
|
||||
|
||||
const NSRect titleTextRect = NSMakeRect(
|
||||
0.0f,
|
||||
textViewFrame.origin.y + textViewFrame.size.height,
|
||||
textViewFrame.size.width,
|
||||
TITLE_TEXT_HEIGHT);
|
||||
|
||||
// Temporary solution for the same foreground and background colors
|
||||
// It's used in graphical startup screen, with Hexen style in particular
|
||||
// Native OS X backend doesn't implement this yet
|
||||
|
||||
if (DoomStartupInfo.FgColor == DoomStartupInfo.BkColor)
|
||||
{
|
||||
DoomStartupInfo.FgColor = ~DoomStartupInfo.FgColor;
|
||||
}
|
||||
|
||||
NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
|
||||
[titleText setStringValue:[NSString stringWithCString:DoomStartupInfo.Name
|
||||
encoding:NSISOLatin1StringEncoding]];
|
||||
[titleText setAlignment:NSCenterTextAlignment];
|
||||
[titleText setTextColor:RGB(DoomStartupInfo.FgColor)];
|
||||
[titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)];
|
||||
[titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
|
||||
[titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
|
||||
[titleText setSelectable:NO];
|
||||
[titleText setBordered:NO];
|
||||
|
||||
[[m_window contentView] addSubview:titleText];
|
||||
}
|
||||
|
||||
void FConsoleWindow::SetProgressBar(const bool visible)
|
||||
{
|
||||
if ( (!visible && nil == m_progressBar)
|
||||
|| (visible && nil != m_progressBar))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
ExpandTextView(-PROGRESS_BAR_HEIGHT);
|
||||
|
||||
static const CGFloat PROGRESS_BAR_X = 2.0f;
|
||||
const NSRect PROGRESS_BAR_RECT = NSMakeRect(
|
||||
PROGRESS_BAR_X, 0.0f,
|
||||
[m_window frame].size.width - PROGRESS_BAR_X * 2, 16.0f);
|
||||
|
||||
m_progressBar = [[NSProgressIndicator alloc] initWithFrame:PROGRESS_BAR_RECT];
|
||||
[m_progressBar setIndeterminate:NO];
|
||||
[m_progressBar setAutoresizingMask:NSViewWidthSizable];
|
||||
|
||||
[[m_window contentView] addSubview:m_progressBar];
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpandTextView(PROGRESS_BAR_HEIGHT);
|
||||
|
||||
[m_progressBar removeFromSuperview];
|
||||
[m_progressBar release];
|
||||
m_progressBar = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::ExpandTextView(const float height)
|
||||
{
|
||||
NSRect textFrame = [m_scrollView frame];
|
||||
textFrame.origin.y -= height;
|
||||
textFrame.size.height += height;
|
||||
[m_scrollView setFrame:textFrame];
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::Progress(const int current, const int maximum)
|
||||
{
|
||||
if (nil == m_progressBar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateTimed([&]()
|
||||
{
|
||||
[m_progressBar setMaxValue:maximum];
|
||||
[m_progressBar setDoubleValue:current];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void FConsoleWindow::NetInit(const char* const message, const int playerCount)
|
||||
{
|
||||
if (nil == m_netView)
|
||||
{
|
||||
SetProgressBar(false);
|
||||
ExpandTextView(-NET_VIEW_HEIGHT);
|
||||
|
||||
// Message like 'Waiting for players' or 'Contacting host'
|
||||
m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)];
|
||||
[m_netMessageText setAutoresizingMask:NSViewWidthSizable];
|
||||
[m_netMessageText setDrawsBackground:NO];
|
||||
[m_netMessageText setSelectable:NO];
|
||||
[m_netMessageText setBordered:NO];
|
||||
|
||||
// Text with connected/total players count
|
||||
m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)];
|
||||
[m_netCountText setAutoresizingMask:NSViewMinXMargin];
|
||||
[m_netCountText setAlignment:NSRightTextAlignment];
|
||||
[m_netCountText setDrawsBackground:NO];
|
||||
[m_netCountText setSelectable:NO];
|
||||
[m_netCountText setBordered:NO];
|
||||
|
||||
// Connection progress
|
||||
m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)];
|
||||
[m_netProgressBar setAutoresizingMask:NSViewWidthSizable];
|
||||
[m_netProgressBar setMaxValue:playerCount];
|
||||
|
||||
if (0 == playerCount)
|
||||
{
|
||||
// Joining game
|
||||
[m_netProgressBar setIndeterminate:YES];
|
||||
[m_netProgressBar startAnimation:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hosting game
|
||||
[m_netProgressBar setIndeterminate:NO];
|
||||
}
|
||||
|
||||
// Cancel network game button
|
||||
m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)];
|
||||
[m_netAbortButton setAutoresizingMask:NSViewMinXMargin];
|
||||
[m_netAbortButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[m_netAbortButton setTitle:@"Cancel"];
|
||||
[m_netAbortButton setKeyEquivalent:@"\r"];
|
||||
[m_netAbortButton setTarget:[NSApp delegate]];
|
||||
[m_netAbortButton setAction:@selector(sendExitEvent:)];
|
||||
|
||||
// Panel for controls above
|
||||
m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)];
|
||||
[m_netView setAutoresizingMask:NSViewWidthSizable];
|
||||
[m_netView addSubview:m_netMessageText];
|
||||
[m_netView addSubview:m_netCountText];
|
||||
[m_netView addSubview:m_netProgressBar];
|
||||
[m_netView addSubview:m_netAbortButton];
|
||||
|
||||
NSRect windowRect = [m_window frame];
|
||||
windowRect.origin.y -= NET_VIEW_HEIGHT;
|
||||
windowRect.size.height += NET_VIEW_HEIGHT;
|
||||
|
||||
[m_window setFrame:windowRect display:YES];
|
||||
[[m_window contentView] addSubview:m_netView];
|
||||
|
||||
ScrollTextToBottom();
|
||||
}
|
||||
|
||||
[m_netMessageText setStringValue:[NSString stringWithUTF8String:message]];
|
||||
|
||||
m_netCurPos = 0;
|
||||
m_netMaxPos = playerCount;
|
||||
|
||||
NetProgress(1); // You always know about yourself
|
||||
}
|
||||
|
||||
void FConsoleWindow::NetProgress(const int count)
|
||||
{
|
||||
if (0 == count)
|
||||
{
|
||||
++m_netCurPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_netCurPos = count;
|
||||
}
|
||||
|
||||
if (nil == m_netView)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_netMaxPos > 1)
|
||||
{
|
||||
[m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]];
|
||||
[m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)];
|
||||
}
|
||||
}
|
||||
|
||||
void FConsoleWindow::NetDone()
|
||||
{
|
||||
if (nil != m_netView)
|
||||
{
|
||||
ExpandTextView(NET_VIEW_HEIGHT);
|
||||
|
||||
[m_netView removeFromSuperview];
|
||||
[m_netView release];
|
||||
m_netView = nil;
|
||||
|
||||
// Released by m_netView
|
||||
m_netMessageText = nil;
|
||||
m_netCountText = nil;
|
||||
m_netProgressBar = nil;
|
||||
m_netAbortButton = nil;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
** st_start.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#import <Foundation/NSRunLoop.h>
|
||||
|
||||
#include "c_cvars.h"
|
||||
#include "doomtype.h"
|
||||
#include "st_console.h"
|
||||
#include "st_start.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
|
||||
FStartupScreen *StartScreen;
|
||||
|
||||
|
||||
CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
{
|
||||
self = 0;
|
||||
}
|
||||
else if (self > 2)
|
||||
{
|
||||
self = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar)
|
||||
: FStartupScreen(maxProgress)
|
||||
{
|
||||
FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance();
|
||||
consoleWindow.SetProgressBar(true);
|
||||
|
||||
#if 0
|
||||
// Testing code, please do not remove
|
||||
consoleWindow.AddText("----------------------------------------------------------------\n");
|
||||
consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ "
|
||||
"This is very very very long message needed to trigger word wrapping...\n\n");
|
||||
consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n");
|
||||
|
||||
consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_ICE "TEXTCOLOR_ICE\n" TEXTCOLOR_FIRE "TEXTCOLOR_FIRE\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_SAPPHIRE "TEXTCOLOR_SAPPHIRE\n" TEXTCOLOR_TEAL "TEXTCOLOR_TEAL\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n");
|
||||
consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n");
|
||||
consoleWindow.AddText("----------------------------------------------------------------\n");
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
FBasicStartupScreen::~FBasicStartupScreen()
|
||||
{
|
||||
FConsoleWindow::GetInstance().SetProgressBar(false);
|
||||
}
|
||||
|
||||
|
||||
void FBasicStartupScreen::Progress()
|
||||
{
|
||||
if (CurPos < MaxPos)
|
||||
{
|
||||
++CurPos;
|
||||
}
|
||||
|
||||
FConsoleWindow::GetInstance().Progress(CurPos, MaxPos);
|
||||
}
|
||||
|
||||
|
||||
void FBasicStartupScreen::NetInit(const char* const message, const int playerCount)
|
||||
{
|
||||
FConsoleWindow::GetInstance().NetInit(message, playerCount);
|
||||
}
|
||||
|
||||
void FBasicStartupScreen::NetProgress(const int count)
|
||||
{
|
||||
FConsoleWindow::GetInstance().NetProgress(count);
|
||||
}
|
||||
|
||||
void FBasicStartupScreen::NetMessage(const char* const format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
FString message;
|
||||
message.VFormat(format, args);
|
||||
va_end(args);
|
||||
|
||||
Printf("%s\n", message.GetChars());
|
||||
}
|
||||
|
||||
void FBasicStartupScreen::NetDone()
|
||||
{
|
||||
FConsoleWindow::GetInstance().NetDone();
|
||||
}
|
||||
|
||||
bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (timerCallback(userData))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
|
||||
|
||||
// Do not poll to often
|
||||
usleep(50000);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress)
|
||||
{
|
||||
return new FBasicStartupScreen(maxProgress, true);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void ST_Endoom()
|
||||
{
|
||||
throw CExitEvent(0);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 1993-1996 id Software
|
||||
// Copyright 1999-2016 Randy Heit
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif // __APPLE__
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "d_protocol.h"
|
||||
#include "i_system.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "x86.h"
|
||||
|
||||
|
||||
void I_Tactile(int /*on*/, int /*off*/, int /*total*/)
|
||||
{
|
||||
}
|
||||
|
||||
static ticcmd_t emptycmd;
|
||||
|
||||
ticcmd_t *I_BaseTiccmd()
|
||||
{
|
||||
return &emptycmd;
|
||||
}
|
||||
|
||||
//
|
||||
// I_Init
|
||||
//
|
||||
void I_Init()
|
||||
{
|
||||
extern void CalculateCPUSpeed();
|
||||
|
||||
CheckCPUID(&CPU);
|
||||
CalculateCPUSpeed();
|
||||
DumpCPUInfo(&CPU);
|
||||
}
|
||||
|
||||
|
||||
bool I_WriteIniFailed()
|
||||
{
|
||||
printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno));
|
||||
return false; // return true to retry
|
||||
}
|
||||
|
||||
|
||||
static const char *pattern;
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED < 1080
|
||||
static int matchfile(struct dirent *ent)
|
||||
#else
|
||||
static int matchfile(const struct dirent *ent)
|
||||
#endif
|
||||
{
|
||||
return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0;
|
||||
}
|
||||
|
||||
void *I_FindFirst(const char *const filespec, findstate_t *const fileinfo)
|
||||
{
|
||||
FString dir;
|
||||
|
||||
const char *const slash = strrchr(filespec, '/');
|
||||
|
||||
if (slash)
|
||||
{
|
||||
pattern = slash + 1;
|
||||
dir = FString(filespec, slash - filespec + 1);
|
||||
fileinfo->path = dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = filespec;
|
||||
dir = ".";
|
||||
}
|
||||
|
||||
fileinfo->current = 0;
|
||||
fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort);
|
||||
|
||||
if (fileinfo->count > 0)
|
||||
{
|
||||
return fileinfo;
|
||||
}
|
||||
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
int I_FindNext(void *const handle, findstate_t *const fileinfo)
|
||||
{
|
||||
findstate_t *const state = static_cast<findstate_t *>(handle);
|
||||
|
||||
if (state->current < fileinfo->count)
|
||||
{
|
||||
return ++state->current < fileinfo->count ? 0 : -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int I_FindClose(void *const handle)
|
||||
{
|
||||
findstate_t *const state = static_cast<findstate_t *>(handle);
|
||||
|
||||
if (handle != (void *)-1 && state->count > 0)
|
||||
{
|
||||
for (int i = 0; i < state->count; ++i)
|
||||
{
|
||||
free(state->namelist[i]);
|
||||
}
|
||||
|
||||
free(state->namelist);
|
||||
state->namelist = nullptr;
|
||||
state->count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I_FindAttr(findstate_t *const fileinfo)
|
||||
{
|
||||
dirent *const ent = fileinfo->namelist[fileinfo->current];
|
||||
const FString path = fileinfo->path + ent->d_name;
|
||||
bool isdir;
|
||||
|
||||
if (DirEntryExists(path, &isdir))
|
||||
{
|
||||
return isdir ? FA_DIREC : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TArray<FString> I_GetGogPaths()
|
||||
{
|
||||
// GOG's Doom games are Windows only at the moment
|
||||
return TArray<FString>();
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
** i_specialpaths.mm
|
||||
** Gets special system folders where data should be stored. (macOS version)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2013-2016 Randy Heit
|
||||
** Copyright 2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "m_misc.h"
|
||||
#include "version.h" // for GAMENAME
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath macOS
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
FString path;
|
||||
|
||||
char pathstr[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
|
||||
{
|
||||
path = pathstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
path += "/" GAMENAMELOWERCASE;
|
||||
if (create) CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetCachePath macOS
|
||||
//
|
||||
// Returns the path for cache GL nodes.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetCachePath(bool create)
|
||||
{
|
||||
FString path;
|
||||
|
||||
char pathstr[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
|
||||
{
|
||||
path = pathstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
path += "/zdoom/cache";
|
||||
if (create) CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAutoexecPath macOS
|
||||
//
|
||||
// Returns the expected location of autoexec.cfg.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAutoexecPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
char cpath[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
|
||||
{
|
||||
path << cpath << "/" GAME_DIR "/autoexec.cfg";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetCajunPath macOS
|
||||
//
|
||||
// Returns the location of the Cajun Bot definitions.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetCajunPath(const char *botfilename)
|
||||
{
|
||||
FString path;
|
||||
|
||||
// Just copies the Windows code. Should this be more Mac-specific?
|
||||
path << progdir << "zcajun/" << botfilename;
|
||||
if (!FileExists(path))
|
||||
{
|
||||
path = "";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetConfigPath macOS
|
||||
//
|
||||
// Returns the path to the config file. On Windows, this can vary for reading
|
||||
// vs writing. i.e. If $PROGDIR/zdoom-<user>.ini does not exist, it will try
|
||||
// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetConfigPath(bool for_reading)
|
||||
{
|
||||
char cpath[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
|
||||
{
|
||||
FString path;
|
||||
path << cpath << "/" GAMENAMELOWERCASE ".ini";
|
||||
return path;
|
||||
}
|
||||
// Ungh.
|
||||
return GAMENAMELOWERCASE ".ini";
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetScreenshotsPath macOS
|
||||
//
|
||||
// Returns the path to the default screenshots directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetScreenshotsPath()
|
||||
{
|
||||
FString path;
|
||||
char cpath[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
|
||||
{
|
||||
path << cpath << "/" GAME_DIR "/Screenshots/";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = "~/";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetSavegamesPath macOS
|
||||
//
|
||||
// Returns the path to the default save games directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetSavegamesPath()
|
||||
{
|
||||
FString path;
|
||||
char cpath[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
|
||||
{
|
||||
path << cpath << "/" GAME_DIR "/Savegames/";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetDocumentsPath Unix
|
||||
//
|
||||
// Returns the path to the default documents directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetDocumentsPath()
|
||||
{
|
||||
FString path;
|
||||
char cpath[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
|
||||
{
|
||||
path << cpath << "/" GAME_DIR "/";
|
||||
}
|
||||
return path;
|
||||
}
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
** iwadpicker_cocoa.mm
|
||||
**
|
||||
** Implements Mac OS X native IWAD Picker.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Braden Obrzut
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "d_main.h"
|
||||
#include "version.h"
|
||||
#include "c_cvars.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_misc.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <wordexp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
CVAR(String, osx_additional_parameters, "", CVAR_ARCHIVE | CVAR_NOSET | CVAR_GLOBALCONFIG);
|
||||
|
||||
enum
|
||||
{
|
||||
COLUMN_IWAD,
|
||||
COLUMN_GAME,
|
||||
|
||||
NUM_COLUMNS
|
||||
};
|
||||
|
||||
static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" };
|
||||
|
||||
// Class to convert the IWAD data into a form that Cocoa can use.
|
||||
@interface IWADTableData : NSObject<NSTableViewDataSource>
|
||||
{
|
||||
NSMutableArray *data;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
- (IWADTableData *)init:(WadStuff *) wads num:(int) numwads;
|
||||
|
||||
- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
|
||||
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex;
|
||||
@end
|
||||
|
||||
@implementation IWADTableData
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[data release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (IWADTableData *)init:(WadStuff *) wads num:(int) numwads
|
||||
{
|
||||
data = [[NSMutableArray alloc] initWithCapacity:numwads];
|
||||
|
||||
for(int i = 0;i < numwads;i++)
|
||||
{
|
||||
NSMutableDictionary *record = [[NSMutableDictionary alloc] initWithCapacity:NUM_COLUMNS];
|
||||
const char* filename = strrchr(wads[i].Path, '/');
|
||||
if(filename == NULL)
|
||||
filename = wads[i].Path;
|
||||
else
|
||||
filename++;
|
||||
[record setObject:[NSString stringWithUTF8String:filename] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_IWAD]]];
|
||||
[record setObject:[NSString stringWithUTF8String:wads[i].Name] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_GAME]]];
|
||||
[data addObject:record];
|
||||
[record release];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
|
||||
{
|
||||
return [data count];
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
|
||||
{
|
||||
NSParameterAssert(rowIndex >= 0 && (unsigned int) rowIndex < [data count]);
|
||||
NSMutableDictionary *record = [data objectAtIndex:rowIndex];
|
||||
return [record objectForKey:[aTableColumn identifier]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSDictionary* GetKnownFileTypes()
|
||||
{
|
||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"-file" , @"wad",
|
||||
@"-file" , @"pk3",
|
||||
@"-file" , @"zip",
|
||||
@"-file" , @"pk7",
|
||||
@"-file" , @"7z",
|
||||
@"-deh" , @"deh",
|
||||
@"-bex" , @"bex",
|
||||
@"-exec" , @"cfg",
|
||||
@"-playdemo", @"lmp",
|
||||
nil];
|
||||
}
|
||||
|
||||
static NSArray* GetKnownExtensions()
|
||||
{
|
||||
return [GetKnownFileTypes() allKeys];
|
||||
}
|
||||
|
||||
@interface NSMutableString(AppendKnownFileType)
|
||||
- (void)appendKnownFileType:(NSString *)filePath;
|
||||
@end
|
||||
|
||||
@implementation NSMutableString(AppendKnownFileType)
|
||||
- (void)appendKnownFileType:(NSString *)filePath
|
||||
{
|
||||
NSString* extension = [[filePath pathExtension] lowercaseString];
|
||||
NSString* parameter = [GetKnownFileTypes() objectForKey:extension];
|
||||
|
||||
if (nil == parameter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
[self appendFormat:@"%@ \"%@\" ", parameter, filePath];
|
||||
}
|
||||
@end
|
||||
|
||||
// So we can listen for button actions and such we need to have an Obj-C class.
|
||||
@interface IWADPicker : NSObject
|
||||
{
|
||||
NSApplication *app;
|
||||
NSWindow *window;
|
||||
NSButton *okButton;
|
||||
NSButton *cancelButton;
|
||||
NSButton *browseButton;
|
||||
NSTextField *parametersTextField;
|
||||
bool cancelled;
|
||||
}
|
||||
|
||||
- (void)buttonPressed:(id) sender;
|
||||
- (void)browseButtonPressed:(id) sender;
|
||||
- (void)doubleClicked:(id) sender;
|
||||
- (void)makeLabel:(NSTextField *)label withString:(const char*) str;
|
||||
- (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin defaultWad:(int) defaultiwad;
|
||||
- (NSString*)commandLineParameters;
|
||||
- (void)menuActionSent:(NSNotification*)notification;
|
||||
@end
|
||||
|
||||
@implementation IWADPicker
|
||||
|
||||
- (void)buttonPressed:(id) sender
|
||||
{
|
||||
if(sender == cancelButton)
|
||||
cancelled = true;
|
||||
|
||||
[window orderOut:self];
|
||||
[app stopModal];
|
||||
}
|
||||
|
||||
- (void)browseButtonPressed:(id) sender
|
||||
{
|
||||
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
|
||||
[openPanel setAllowsMultipleSelection:YES];
|
||||
[openPanel setCanChooseFiles:YES];
|
||||
[openPanel setCanChooseDirectories:YES];
|
||||
[openPanel setResolvesAliases:YES];
|
||||
[openPanel setAllowedFileTypes:GetKnownExtensions()];
|
||||
|
||||
if (NSOKButton == [openPanel runModal])
|
||||
{
|
||||
NSArray* files = [openPanel URLs];
|
||||
NSMutableString* parameters = [NSMutableString string];
|
||||
|
||||
for (NSUInteger i = 0, ei = [files count]; i < ei; ++i)
|
||||
{
|
||||
NSString* filePath = [[files objectAtIndex:i] path];
|
||||
BOOL isDirectory = false;
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory)
|
||||
{
|
||||
[parameters appendFormat:@"-file \"%@\" ", filePath];
|
||||
}
|
||||
else
|
||||
{
|
||||
[parameters appendKnownFileType:filePath];
|
||||
}
|
||||
}
|
||||
|
||||
if ([parameters length] > 0)
|
||||
{
|
||||
NSString* newParameters = [parametersTextField stringValue];
|
||||
|
||||
if ([newParameters length] > 0
|
||||
&& NO == [newParameters hasSuffix:@" "])
|
||||
{
|
||||
newParameters = [newParameters stringByAppendingString:@" "];
|
||||
}
|
||||
|
||||
newParameters = [newParameters stringByAppendingString:parameters];
|
||||
|
||||
[parametersTextField setStringValue: newParameters];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doubleClicked:(id) sender
|
||||
{
|
||||
if ([sender clickedRow] >= 0)
|
||||
{
|
||||
[window orderOut:self];
|
||||
[app stopModal];
|
||||
}
|
||||
}
|
||||
|
||||
// Apparently labels in Cocoa are uneditable text fields, so lets make this a
|
||||
// little more automated.
|
||||
- (void)makeLabel:(NSTextField *)label withString:(const char*) str
|
||||
{
|
||||
[label setStringValue:[NSString stringWithUTF8String:str]];
|
||||
[label setBezeled:NO];
|
||||
[label setDrawsBackground:NO];
|
||||
[label setEditable:NO];
|
||||
[label setSelectable:NO];
|
||||
}
|
||||
|
||||
- (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin defaultWad:(int) defaultiwad
|
||||
{
|
||||
cancelled = false;
|
||||
|
||||
app = [NSApplication sharedApplication];
|
||||
id windowTitle = [NSString stringWithFormat:@"%s %s", GAMENAME, GetVersionString()];
|
||||
|
||||
NSRect frame = NSMakeRect(0, 0, 440, 450);
|
||||
window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];
|
||||
[window setTitle:windowTitle];
|
||||
|
||||
NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 384, 402, 50)];
|
||||
[self makeLabel:description withString:GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"];
|
||||
[[window contentView] addSubview:description];
|
||||
[description release];
|
||||
|
||||
NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 135, 402, 256)];
|
||||
NSTableView *iwadTable = [[NSTableView alloc] initWithFrame:[iwadScroller bounds]];
|
||||
IWADTableData *tableData = [[IWADTableData alloc] init:wads num:numwads];
|
||||
for(int i = 0;i < NUM_COLUMNS;i++)
|
||||
{
|
||||
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[NSString stringWithUTF8String:tableHeaders[i]]];
|
||||
[[column headerCell] setStringValue:[column identifier]];
|
||||
if(i == 0)
|
||||
[column setMaxWidth:110];
|
||||
[column setEditable:NO];
|
||||
[column setResizingMask:NSTableColumnAutoresizingMask];
|
||||
[iwadTable addTableColumn:column];
|
||||
[column release];
|
||||
}
|
||||
[iwadScroller setDocumentView:iwadTable];
|
||||
[iwadScroller setHasVerticalScroller:YES];
|
||||
[iwadTable setDataSource:tableData];
|
||||
[iwadTable sizeToFit];
|
||||
[iwadTable setDoubleAction:@selector(doubleClicked:)];
|
||||
[iwadTable setTarget:self];
|
||||
NSIndexSet *selection = [[NSIndexSet alloc] initWithIndex:defaultiwad];
|
||||
[iwadTable selectRowIndexes:selection byExtendingSelection:NO];
|
||||
[selection release];
|
||||
[iwadTable scrollRowToVisible:defaultiwad];
|
||||
[[window contentView] addSubview:iwadScroller];
|
||||
[iwadTable release];
|
||||
[iwadScroller release];
|
||||
|
||||
NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 108, 144, 17)];
|
||||
[self makeLabel:additionalParametersLabel withString:"Additional Parameters:"];
|
||||
[[window contentView] addSubview:additionalParametersLabel];
|
||||
parametersTextField = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 48, 402, 54)];
|
||||
[parametersTextField setStringValue:[NSString stringWithUTF8String:osx_additional_parameters]];
|
||||
[[window contentView] addSubview:parametersTextField];
|
||||
|
||||
// Doesn't look like the SDL version implements this so lets not show it.
|
||||
/*NSButton *dontAsk = [[NSButton alloc] initWithFrame:NSMakeRect(18, 18, 178, 18)];
|
||||
[dontAsk setTitle:[NSString stringWithCString:"Don't ask me this again"]];
|
||||
[dontAsk setButtonType:NSSwitchButton];
|
||||
[dontAsk setState:(showwin ? NSOffState : NSOnState)];
|
||||
[[window contentView] addSubview:dontAsk];*/
|
||||
|
||||
okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 8, 96, 32)];
|
||||
[okButton setTitle:@"OK"];
|
||||
[okButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[okButton setAction:@selector(buttonPressed:)];
|
||||
[okButton setTarget:self];
|
||||
[okButton setKeyEquivalent:@"\r"];
|
||||
[[window contentView] addSubview:okButton];
|
||||
|
||||
cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 8, 96, 32)];
|
||||
[cancelButton setTitle:@"Cancel"];
|
||||
[cancelButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[cancelButton setAction:@selector(buttonPressed:)];
|
||||
[cancelButton setTarget:self];
|
||||
[cancelButton setKeyEquivalent:@"\033"];
|
||||
[[window contentView] addSubview:cancelButton];
|
||||
|
||||
browseButton = [[NSButton alloc] initWithFrame:NSMakeRect(14, 8, 96, 32)];
|
||||
[browseButton setTitle:@"Browse..."];
|
||||
[browseButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[browseButton setAction:@selector(browseButtonPressed:)];
|
||||
[browseButton setTarget:self];
|
||||
[[window contentView] addSubview:browseButton];
|
||||
|
||||
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(menuActionSent:) name:NSMenuDidSendActionNotification object:nil];
|
||||
|
||||
[window center];
|
||||
[app runModalForWindow:window];
|
||||
|
||||
[center removeObserver:self name:NSMenuDidSendActionNotification object:nil];
|
||||
|
||||
[window release];
|
||||
[okButton release];
|
||||
[cancelButton release];
|
||||
[browseButton release];
|
||||
|
||||
return cancelled ? -1 : [iwadTable selectedRow];
|
||||
}
|
||||
|
||||
- (NSString*)commandLineParameters
|
||||
{
|
||||
return [parametersTextField stringValue];
|
||||
}
|
||||
|
||||
- (void)menuActionSent:(NSNotification*)notification
|
||||
{
|
||||
NSDictionary* userInfo = [notification userInfo];
|
||||
NSMenuItem* menuItem = [userInfo valueForKey:@"MenuItem"];
|
||||
|
||||
if ( @selector(terminate:) == [menuItem action] )
|
||||
{
|
||||
throw CExitEvent(0);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
EXTERN_CVAR(String, defaultiwad)
|
||||
|
||||
static NSString* GetArchitectureString()
|
||||
{
|
||||
#ifdef __i386__
|
||||
return @"i386";
|
||||
#elif defined __x86_64__
|
||||
return @"x86_64";
|
||||
#endif
|
||||
}
|
||||
|
||||
static void RestartWithParameters(const WadStuff& wad, NSString* parameters)
|
||||
{
|
||||
assert(nil != parameters);
|
||||
|
||||
defaultiwad = wad.Name;
|
||||
|
||||
GameConfig->DoGameSetup("Doom");
|
||||
M_SaveDefaults(NULL);
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
@try
|
||||
{
|
||||
NSString* executablePath = [NSString stringWithUTF8String:Args->GetArg(0)];
|
||||
|
||||
NSMutableArray* const arguments = [[NSMutableArray alloc] init];
|
||||
|
||||
// The following value shoud be equal to NSAppKitVersionNumber10_5
|
||||
// It's hard-coded in order to build with earlier SDKs
|
||||
const bool canSelectArchitecture = NSAppKitVersionNumber >= 949;
|
||||
|
||||
if (canSelectArchitecture)
|
||||
{
|
||||
[arguments addObject:@"-arch"];
|
||||
[arguments addObject:GetArchitectureString()];
|
||||
[arguments addObject:executablePath];
|
||||
|
||||
executablePath = @"/usr/bin/arch";
|
||||
}
|
||||
|
||||
[arguments addObject:@"-iwad"];
|
||||
[arguments addObject:[NSString stringWithUTF8String:wad.Path]];
|
||||
|
||||
for (int i = 1, count = Args->NumArgs(); i < count; ++i)
|
||||
{
|
||||
NSString* currentParameter = [NSString stringWithUTF8String:Args->GetArg(i)];
|
||||
[arguments addObject:currentParameter];
|
||||
}
|
||||
|
||||
wordexp_t expansion = {};
|
||||
|
||||
if (0 == wordexp([parameters UTF8String], &expansion, 0))
|
||||
{
|
||||
for (size_t i = 0; i < expansion.we_wordc; ++i)
|
||||
{
|
||||
NSString* argumentString = [NSString stringWithCString:expansion.we_wordv[i]
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[arguments addObject:argumentString];
|
||||
}
|
||||
|
||||
wordfree(&expansion);
|
||||
}
|
||||
|
||||
[NSTask launchedTaskWithLaunchPath:executablePath
|
||||
arguments:arguments];
|
||||
|
||||
_exit(0); // to avoid atexit()'s functions
|
||||
}
|
||||
@catch (NSException* e)
|
||||
{
|
||||
NSLog(@"Cannot restart: %@", [e reason]);
|
||||
}
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
// Simple wrapper so we can call this from outside.
|
||||
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
IWADPicker *picker = [IWADPicker alloc];
|
||||
int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad];
|
||||
|
||||
NSString* parametersToAppend = [picker commandLineParameters];
|
||||
osx_additional_parameters = [parametersToAppend UTF8String];
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
if (0 != [parametersToAppend length])
|
||||
{
|
||||
RestartWithParameters(wads[ret], parametersToAppend);
|
||||
}
|
||||
}
|
||||
|
||||
[pool release];
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>zdoom.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.drdteam.gzdoom</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>GZDoom</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>Development Version</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.action-games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Doom Resource File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wad</string>
|
||||
<string>pk3</string>
|
||||
<string>zip</string>
|
||||
<string>pk7</string>
|
||||
<string>7z</string>
|
||||
<string>iwad</string>
|
||||
<string>ipk3</string>
|
||||
<string>ipk7</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -0,0 +1,428 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#ifndef PR_SET_PTRACER
|
||||
#define PR_SET_PTRACER 0x59616d61
|
||||
#endif
|
||||
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
static const char crash_switch[] = "--cc-handle-crash";
|
||||
|
||||
static const char fatal_err[] = "\n\n*** Fatal Error ***\n";
|
||||
static const char pipe_err[] = "!!! Failed to create pipe\n";
|
||||
static const char fork_err[] = "!!! Failed to fork debug process\n";
|
||||
static const char exec_err[] = "!!! Failed to exec debug process\n";
|
||||
|
||||
static char argv0[PATH_MAX];
|
||||
|
||||
static char altstack[SIGSTKSZ];
|
||||
|
||||
|
||||
static struct {
|
||||
int signum;
|
||||
pid_t pid;
|
||||
int has_siginfo;
|
||||
siginfo_t siginfo;
|
||||
char buf[4096];
|
||||
} crash_info;
|
||||
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
int signum;
|
||||
} signals[] = {
|
||||
{ "Segmentation fault", SIGSEGV },
|
||||
{ "Illegal instruction", SIGILL },
|
||||
{ "FPU exception", SIGFPE },
|
||||
{ "System BUS error", SIGBUS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
} sigill_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ ILL_ILLOPC, "Illegal opcode" },
|
||||
{ ILL_ILLOPN, "Illegal operand" },
|
||||
{ ILL_ILLADR, "Illegal addressing mode" },
|
||||
{ ILL_ILLTRP, "Illegal trap" },
|
||||
{ ILL_PRVOPC, "Privileged opcode" },
|
||||
{ ILL_PRVREG, "Privileged register" },
|
||||
{ ILL_COPROC, "Coprocessor error" },
|
||||
{ ILL_BADSTK, "Internal stack error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
} sigfpe_codes[] = {
|
||||
{ FPE_INTDIV, "Integer divide by zero" },
|
||||
{ FPE_INTOVF, "Integer overflow" },
|
||||
{ FPE_FLTDIV, "Floating point divide by zero" },
|
||||
{ FPE_FLTOVF, "Floating point overflow" },
|
||||
{ FPE_FLTUND, "Floating point underflow" },
|
||||
{ FPE_FLTRES, "Floating point inexact result" },
|
||||
{ FPE_FLTINV, "Floating point invalid operation" },
|
||||
{ FPE_FLTSUB, "Subscript out of range" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
} sigsegv_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ SEGV_MAPERR, "Address not mapped to object" },
|
||||
{ SEGV_ACCERR, "Invalid permissions for mapped object" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
} sigbus_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ BUS_ADRALN, "Invalid address alignment" },
|
||||
{ BUS_ADRERR, "Non-existent physical address" },
|
||||
{ BUS_OBJERR, "Object specific hardware error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static int (*cc_user_info)(char*, char*);
|
||||
|
||||
|
||||
static void gdb_info(pid_t pid)
|
||||
{
|
||||
char respfile[64];
|
||||
char cmd_buf[128];
|
||||
FILE *f;
|
||||
int fd;
|
||||
|
||||
/* Create a temp file to put gdb commands into */
|
||||
strcpy(respfile, "gdb-respfile-XXXXXX");
|
||||
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
|
||||
{
|
||||
fprintf(f, "attach %d\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Loaded Libraries\"\n"
|
||||
"info sharedlibrary\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Threads\"\n"
|
||||
"info threads\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* FPU Status\"\n"
|
||||
"info float\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Registers\"\n"
|
||||
"info registers\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Backtrace\"\n"
|
||||
"thread apply all backtrace full\n"
|
||||
"detach\n"
|
||||
"quit\n", pid);
|
||||
fclose(f);
|
||||
|
||||
/* Run gdb and print process info. */
|
||||
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
|
||||
printf("Executing: %s\n", cmd_buf);
|
||||
fflush(stdout);
|
||||
|
||||
system(cmd_buf);
|
||||
/* Clean up */
|
||||
remove(respfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error creating temp file */
|
||||
if(fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
remove(respfile);
|
||||
}
|
||||
printf("!!! Could not create gdb command file\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void sys_info(void)
|
||||
{
|
||||
#ifdef __unix__
|
||||
system("echo \"System: `uname -a`\"");
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static size_t safe_write(int fd, const void *buf, size_t len)
|
||||
{
|
||||
size_t ret = 0;
|
||||
while(ret < len)
|
||||
{
|
||||
ssize_t rem;
|
||||
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ret += rem;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
|
||||
{
|
||||
//ucontext_t *ucontext = (ucontext_t*)context;
|
||||
pid_t dbg_pid;
|
||||
int fd[2];
|
||||
|
||||
/* Make sure the effective uid is the real uid */
|
||||
if(getuid() != geteuid())
|
||||
{
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
|
||||
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
|
||||
if(pipe(fd) == -1)
|
||||
{
|
||||
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
|
||||
crash_info.signum = signum;
|
||||
crash_info.pid = getpid();
|
||||
crash_info.has_siginfo = !!siginfo;
|
||||
if(siginfo)
|
||||
crash_info.siginfo = *siginfo;
|
||||
if(cc_user_info)
|
||||
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
|
||||
|
||||
/* Fork off to start a crash handler */
|
||||
switch((dbg_pid=fork()))
|
||||
{
|
||||
/* Error */
|
||||
case -1:
|
||||
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
dup2(fd[0], STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
execl(argv0, argv0, crash_switch, NULL);
|
||||
|
||||
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
|
||||
_exit(1);
|
||||
|
||||
default:
|
||||
#ifdef __linux__
|
||||
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
|
||||
#endif
|
||||
safe_write(fd[1], &crash_info, sizeof(crash_info));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
/* Wait; we'll be killed when gdb is done */
|
||||
do {
|
||||
int status;
|
||||
if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
|
||||
(WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
{
|
||||
/* The debug process died before it could kill us */
|
||||
raise(signum);
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void crash_handler(const char *logfile)
|
||||
{
|
||||
const char *sigdesc = "";
|
||||
int i;
|
||||
|
||||
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
|
||||
{
|
||||
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the signal description */
|
||||
for(i = 0;signals[i].name;++i)
|
||||
{
|
||||
if(signals[i].signum == crash_info.signum)
|
||||
{
|
||||
sigdesc = signals[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(crash_info.has_siginfo)
|
||||
{
|
||||
switch(crash_info.signum)
|
||||
{
|
||||
case SIGSEGV:
|
||||
for(i = 0;sigsegv_codes[i].name;++i)
|
||||
{
|
||||
if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigsegv_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGFPE:
|
||||
for(i = 0;sigfpe_codes[i].name;++i)
|
||||
{
|
||||
if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigfpe_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGILL:
|
||||
for(i = 0;sigill_codes[i].name;++i)
|
||||
{
|
||||
if(sigill_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigill_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGBUS:
|
||||
for(i = 0;sigbus_codes[i].name;++i)
|
||||
{
|
||||
if(sigbus_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigbus_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stderr);
|
||||
|
||||
if(logfile)
|
||||
{
|
||||
/* Create crash log file and redirect shell output to it */
|
||||
if(freopen(logfile, "wa", stdout) != stdout)
|
||||
{
|
||||
fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
|
||||
|
||||
printf("*** Fatal Error ***\n"
|
||||
"%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
printf("Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
sys_info();
|
||||
|
||||
crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
|
||||
printf("%s\n", crash_info.buf);
|
||||
fflush(stdout);
|
||||
|
||||
if(crash_info.pid > 0)
|
||||
{
|
||||
gdb_info(crash_info.pid);
|
||||
kill(crash_info.pid, SIGKILL);
|
||||
}
|
||||
|
||||
if(logfile)
|
||||
{
|
||||
const char *str;
|
||||
char buf[512];
|
||||
|
||||
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
||||
snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile);
|
||||
else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0')
|
||||
snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile);
|
||||
|
||||
system(buf);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
|
||||
{
|
||||
struct sigaction sa;
|
||||
stack_t altss;
|
||||
int retval;
|
||||
|
||||
if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
|
||||
crash_handler(logfile);
|
||||
|
||||
cc_user_info = user_info;
|
||||
|
||||
if(argv[0][0] == '/')
|
||||
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
||||
else
|
||||
{
|
||||
getcwd(argv0, sizeof(argv0));
|
||||
retval = strlen(argv0);
|
||||
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
||||
}
|
||||
|
||||
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows
|
||||
* still run */
|
||||
altss.ss_sp = altstack;
|
||||
altss.ss_flags = 0;
|
||||
altss.ss_size = sizeof(altstack);
|
||||
sigaltstack(&altss, NULL);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_catcher;
|
||||
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
retval = 0;
|
||||
while(num_signals--)
|
||||
{
|
||||
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE &&
|
||||
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
|
||||
{
|
||||
*signals = 0;
|
||||
retval = -1;
|
||||
}
|
||||
++signals;
|
||||
}
|
||||
return retval;
|
||||
}
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
** hardware.cpp
|
||||
** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <SDL.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "hardware.h"
|
||||
#include "i_video.h"
|
||||
#include "i_system.h"
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "sdlvideo.h"
|
||||
#include "v_text.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_argv.h"
|
||||
#include "sdlglvideo.h"
|
||||
#include "r_renderer.h"
|
||||
#include "swrenderer/r_swrenderer.h"
|
||||
|
||||
EXTERN_CVAR (Bool, ticker)
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
EXTERN_CVAR (Bool, swtruecolor)
|
||||
EXTERN_CVAR (Float, vid_winscale)
|
||||
|
||||
IVideo *Video;
|
||||
|
||||
extern int NewWidth, NewHeight, NewBits, DisplayBits;
|
||||
bool V_DoModeSetup (int width, int height, int bits);
|
||||
void I_RestartRenderer();
|
||||
|
||||
int currentrenderer;
|
||||
|
||||
// [ZDoomGL]
|
||||
CUSTOM_CVAR (Int, vid_renderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
// 0: Software renderer
|
||||
// 1: OpenGL renderer
|
||||
|
||||
if (self != currentrenderer)
|
||||
{
|
||||
switch (self)
|
||||
{
|
||||
case 0:
|
||||
Printf("Switching to software renderer...\n");
|
||||
break;
|
||||
case 1:
|
||||
Printf("Switching to OpenGL renderer...\n");
|
||||
break;
|
||||
default:
|
||||
Printf("Unknown renderer (%d). Falling back to software renderer...\n", (int) vid_renderer);
|
||||
self = 0; // make sure to actually switch to the software renderer
|
||||
break;
|
||||
}
|
||||
Printf("You must restart " GAMENAME " to switch the renderer\n");
|
||||
}
|
||||
}
|
||||
|
||||
void I_ShutdownGraphics ()
|
||||
{
|
||||
if (screen)
|
||||
{
|
||||
DFrameBuffer *s = screen;
|
||||
screen = NULL;
|
||||
delete s;
|
||||
}
|
||||
if (Video)
|
||||
delete Video, Video = NULL;
|
||||
|
||||
SDL_QuitSubSystem (SDL_INIT_VIDEO);
|
||||
}
|
||||
|
||||
void I_InitGraphics ()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0");
|
||||
#endif // __APPLE__
|
||||
|
||||
if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0)
|
||||
{
|
||||
I_FatalError ("Could not initialize SDL video:\n%s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
Printf("Using video driver %s\n", SDL_GetCurrentVideoDriver());
|
||||
|
||||
UCVarValue val;
|
||||
|
||||
val.Bool = !!Args->CheckParm ("-devparm");
|
||||
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
||||
|
||||
//currentrenderer = vid_renderer;
|
||||
Video = new SDLGLVideo(0);
|
||||
|
||||
if (Video == NULL)
|
||||
I_FatalError ("Failed to initialize display");
|
||||
|
||||
Video->SetWindowedScale (vid_winscale);
|
||||
}
|
||||
|
||||
void I_DeleteRenderer()
|
||||
{
|
||||
if (Renderer != NULL) delete Renderer;
|
||||
}
|
||||
|
||||
void I_CreateRenderer()
|
||||
{
|
||||
currentrenderer = vid_renderer;
|
||||
if (Renderer == NULL)
|
||||
{
|
||||
if (currentrenderer==1) Renderer = gl_CreateInterface();
|
||||
else Renderer = new FSoftwareRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Remaining code is common to Win32 and Linux **/
|
||||
|
||||
// VIDEO WRAPPERS ---------------------------------------------------------
|
||||
|
||||
DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
|
||||
{
|
||||
bool fs = false;
|
||||
switch (Video->GetDisplayType ())
|
||||
{
|
||||
case DISPLAY_WindowOnly:
|
||||
fs = false;
|
||||
break;
|
||||
case DISPLAY_FullscreenOnly:
|
||||
fs = true;
|
||||
break;
|
||||
case DISPLAY_Both:
|
||||
fs = fullscreen;
|
||||
break;
|
||||
}
|
||||
DFrameBuffer *res = Video->CreateFrameBuffer (width, height, swtruecolor, fs, old);
|
||||
|
||||
/* Right now, CreateFrameBuffer cannot return NULL
|
||||
if (res == NULL)
|
||||
{
|
||||
I_FatalError ("Mode %dx%d is unavailable\n", width, height);
|
||||
}
|
||||
*/
|
||||
return res;
|
||||
}
|
||||
|
||||
bool I_CheckResolution (int width, int height, int bits)
|
||||
{
|
||||
int twidth, theight;
|
||||
|
||||
Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen);
|
||||
while (Video->NextMode (&twidth, &theight, NULL))
|
||||
{
|
||||
if (width == twidth && height == theight)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void I_ClosestResolution (int *width, int *height, int bits)
|
||||
{
|
||||
#ifdef __MOBILE__ // We want to always use the resolution of the device!
|
||||
return;
|
||||
#endif
|
||||
|
||||
int twidth, theight;
|
||||
int cwidth = 0, cheight = 0;
|
||||
int iteration;
|
||||
uint32_t closest = 4294967295u;
|
||||
|
||||
for (iteration = 0; iteration < 2; iteration++)
|
||||
{
|
||||
Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen);
|
||||
while (Video->NextMode (&twidth, &theight, NULL))
|
||||
{
|
||||
if (twidth == *width && theight == *height)
|
||||
return;
|
||||
|
||||
if (iteration == 0 && (twidth < *width || theight < *height))
|
||||
continue;
|
||||
|
||||
uint32_t dist = (twidth - *width) * (twidth - *width)
|
||||
+ (theight - *height) * (theight - *height);
|
||||
|
||||
if (dist < closest)
|
||||
{
|
||||
closest = dist;
|
||||
cwidth = twidth;
|
||||
cheight = theight;
|
||||
}
|
||||
}
|
||||
if (closest != 4294967295u)
|
||||
{
|
||||
*width = cwidth;
|
||||
*height = cheight;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SetFPSLimit
|
||||
//
|
||||
// Initializes an event timer to fire at a rate of <limit>/sec. The video
|
||||
// update will wait for this timer to trigger before updating.
|
||||
//
|
||||
// Pass 0 as the limit for unlimited.
|
||||
// Pass a negative value for the limit to use the value of vid_maxfps.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
EXTERN_CVAR(Int, vid_maxfps);
|
||||
EXTERN_CVAR(Bool, cl_capfps);
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
||||
Semaphore FPSLimitSemaphore;
|
||||
|
||||
static void FPSLimitNotify(sigval val)
|
||||
{
|
||||
SEMAPHORE_SIGNAL(FPSLimitSemaphore)
|
||||
}
|
||||
|
||||
void I_SetFPSLimit(int limit)
|
||||
{
|
||||
static sigevent FPSLimitEvent;
|
||||
static timer_t FPSLimitTimer;
|
||||
static bool FPSLimitTimerEnabled = false;
|
||||
static bool EventSetup = false;
|
||||
if(!EventSetup)
|
||||
{
|
||||
EventSetup = true;
|
||||
FPSLimitEvent.sigev_notify = SIGEV_THREAD;
|
||||
FPSLimitEvent.sigev_signo = 0;
|
||||
FPSLimitEvent.sigev_value.sival_int = 0;
|
||||
FPSLimitEvent.sigev_notify_function = FPSLimitNotify;
|
||||
FPSLimitEvent.sigev_notify_attributes = NULL;
|
||||
|
||||
SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0)
|
||||
}
|
||||
|
||||
if (limit < 0)
|
||||
{
|
||||
limit = vid_maxfps;
|
||||
}
|
||||
// Kill any leftover timer.
|
||||
if (FPSLimitTimerEnabled)
|
||||
{
|
||||
timer_delete(FPSLimitTimer);
|
||||
FPSLimitTimerEnabled = false;
|
||||
}
|
||||
if (limit == 0)
|
||||
{ // no limit
|
||||
DPrintf(DMSG_NOTIFY, "FPS timer disabled\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
FPSLimitTimerEnabled = true;
|
||||
if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1)
|
||||
Printf(DMSG_WARNING, "Failed to create FPS limitter event\n");
|
||||
itimerspec period = { {0, 0}, {0, 0} };
|
||||
period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit;
|
||||
if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1)
|
||||
Printf(DMSG_WARNING, "Failed to set FPS limitter timer\n");
|
||||
DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// So Apple doesn't support POSIX timers and I can't find a good substitute short of
|
||||
// having Objective-C Cocoa events or something like that.
|
||||
void I_SetFPSLimit(int limit)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (vid_maxfps < TICRATE && vid_maxfps != 0)
|
||||
{
|
||||
vid_maxfps = TICRATE;
|
||||
}
|
||||
else if (vid_maxfps > 1000)
|
||||
{
|
||||
vid_maxfps = 1000;
|
||||
}
|
||||
else if (cl_capfps == 0)
|
||||
{
|
||||
I_SetFPSLimit(vid_maxfps);
|
||||
}
|
||||
}
|
||||
|
||||
extern int NewWidth, NewHeight, NewBits, DisplayBits;
|
||||
|
||||
CUSTOM_CVAR(Bool, swtruecolor, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||
{
|
||||
// Strictly speaking this doesn't require a mode switch, but it is the easiest
|
||||
// way to force a CreateFramebuffer call without a lot of refactoring.
|
||||
if (currentrenderer == 0)
|
||||
{
|
||||
NewWidth = screen->VideoWidth;
|
||||
NewHeight = screen->VideoHeight;
|
||||
NewBits = DisplayBits;
|
||||
setmodeneeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||
{
|
||||
NewWidth = screen->VideoWidth;
|
||||
NewHeight = screen->VideoHeight;
|
||||
NewBits = DisplayBits;
|
||||
setmodeneeded = true;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Float, vid_winscale, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 1.f)
|
||||
{
|
||||
self = 1.f;
|
||||
}
|
||||
else if (Video)
|
||||
{
|
||||
Video->SetWindowedScale (self);
|
||||
NewWidth = screen->VideoWidth;
|
||||
NewHeight = screen->VideoHeight;
|
||||
NewBits = DisplayBits;
|
||||
setmodeneeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (vid_listmodes)
|
||||
{
|
||||
static const char *ratios[7] = { "", " - 16:9", " - 16:10", "", " - 5:4", "", " - 21:9" };
|
||||
int width, height, bits;
|
||||
bool letterbox;
|
||||
|
||||
if (Video == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (bits = 1; bits <= 32; bits++)
|
||||
{
|
||||
Video->StartModeIterator (bits, screen->IsFullscreen());
|
||||
while (Video->NextMode (&width, &height, &letterbox))
|
||||
{
|
||||
bool thisMode = (width == DisplayWidth && height == DisplayHeight && bits == DisplayBits);
|
||||
int ratio = CheckRatio (width, height);
|
||||
Printf (thisMode ? PRINT_BOLD : PRINT_HIGH,
|
||||
"%s%4d x%5d x%3d%s%s\n",
|
||||
thisMode || !IsRatioWidescreen(ratio) ? "" : TEXTCOLOR_GOLD,
|
||||
width, height, bits,
|
||||
ratios[ratio],
|
||||
thisMode || !letterbox ? "" : TEXTCOLOR_BROWN " LB"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (vid_currentmode)
|
||||
{
|
||||
Printf ("%dx%dx%d\n", DisplayWidth, DisplayHeight, DisplayBits);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
** i_gui.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "v_palette.h"
|
||||
#include "textures.h"
|
||||
|
||||
bool I_SetCursor(FTexture *cursorpic)
|
||||
{
|
||||
static SDL_Cursor *cursor;
|
||||
static SDL_Surface *cursorSurface;
|
||||
|
||||
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
|
||||
{
|
||||
// Must be no larger than 32x32.
|
||||
if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cursorSurface == NULL)
|
||||
cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0));
|
||||
|
||||
SDL_LockSurface(cursorSurface);
|
||||
uint8_t buffer[32*32*4];
|
||||
memset(buffer, 0, 32*32*4);
|
||||
FBitmap bmp(buffer, 32*4, 32, 32);
|
||||
cursorpic->CopyTrueColorPixels(&bmp, 0, 0);
|
||||
memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4);
|
||||
SDL_UnlockSurface(cursorSurface);
|
||||
|
||||
if (cursor)
|
||||
SDL_FreeCursor (cursor);
|
||||
cursor = SDL_CreateColorCursor (cursorSurface, 0, 0);
|
||||
SDL_SetCursor (cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cursor)
|
||||
{
|
||||
SDL_SetCursor (NULL);
|
||||
SDL_FreeCursor (cursor);
|
||||
cursor = NULL;
|
||||
}
|
||||
if (cursorSurface != NULL)
|
||||
{
|
||||
SDL_FreeSurface(cursorSurface);
|
||||
cursorSurface = NULL;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,591 @@
|
|||
/*
|
||||
** i_input.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include <SDL.h>
|
||||
#include <ctype.h>
|
||||
#include "doomtype.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_argv.h"
|
||||
#include "i_input.h"
|
||||
#include "v_video.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
#include "i_system.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "dikeys.h"
|
||||
#include "templates.h"
|
||||
#include "s_sound.h"
|
||||
#include "events.h"
|
||||
#include "utf8.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
static void I_CheckGUICapture ();
|
||||
static void I_CheckNativeMouse ();
|
||||
|
||||
bool GUICapture;
|
||||
static bool NativeMouse = true;
|
||||
|
||||
extern int paused;
|
||||
|
||||
CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
|
||||
extern int WaitingForKey, chatmodeon;
|
||||
extern constate_e ConsoleState;
|
||||
|
||||
static const SDL_Keycode DIKToKeySym[256] =
|
||||
{
|
||||
0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6,
|
||||
SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB,
|
||||
SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i,
|
||||
SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s,
|
||||
SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON,
|
||||
SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v,
|
||||
SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY,
|
||||
SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5,
|
||||
SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7,
|
||||
SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1,
|
||||
SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11,
|
||||
SDLK_F12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0,
|
||||
0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ,
|
||||
SDLK_RALT, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME,
|
||||
SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END,
|
||||
SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0,
|
||||
0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP,
|
||||
0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH,
|
||||
SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const SDL_Scancode DIKToKeyScan[256] =
|
||||
{
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
|
||||
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB,
|
||||
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I,
|
||||
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S,
|
||||
SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON,
|
||||
SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V,
|
||||
SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY,
|
||||
SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5,
|
||||
SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7,
|
||||
SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1,
|
||||
SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11,
|
||||
SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ,
|
||||
SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME,
|
||||
SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END,
|
||||
SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH,
|
||||
SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN
|
||||
};
|
||||
|
||||
static TMap<SDL_Keycode, uint8_t> InitKeySymMap ()
|
||||
{
|
||||
TMap<SDL_Keycode, uint8_t> KeySymToDIK;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
KeySymToDIK[DIKToKeySym[i]] = i;
|
||||
}
|
||||
KeySymToDIK[0] = 0;
|
||||
KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT;
|
||||
KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL;
|
||||
KeySymToDIK[SDLK_RALT] = DIK_LMENU;
|
||||
// Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ
|
||||
KeySymToDIK[SDLK_PRINTSCREEN] = DIK_SYSRQ;
|
||||
|
||||
return KeySymToDIK;
|
||||
}
|
||||
static const TMap<SDL_Keycode, uint8_t> KeySymToDIK(InitKeySymMap());
|
||||
|
||||
static TMap<SDL_Scancode, uint8_t> InitKeyScanMap ()
|
||||
{
|
||||
TMap<SDL_Scancode, uint8_t> KeyScanToDIK;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
KeyScanToDIK[DIKToKeyScan[i]] = i;
|
||||
}
|
||||
|
||||
return KeyScanToDIK;
|
||||
}
|
||||
static const TMap<SDL_Scancode, uint8_t> KeyScanToDIK(InitKeyScanMap());
|
||||
|
||||
static void I_CheckGUICapture ()
|
||||
{
|
||||
bool wantCapt;
|
||||
|
||||
if (menuactive == MENU_Off)
|
||||
{
|
||||
wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
|
||||
}
|
||||
|
||||
// [ZZ] check active event handlers that want the UI processing
|
||||
if (!wantCapt && E_CheckUiProcessors())
|
||||
wantCapt = true;
|
||||
|
||||
if (wantCapt != GUICapture)
|
||||
{
|
||||
GUICapture = wantCapt;
|
||||
ResetButtonStates();
|
||||
}
|
||||
}
|
||||
|
||||
void I_SetMouseCapture()
|
||||
{
|
||||
// Clear out any mouse movement.
|
||||
SDL_GetRelativeMouseState (NULL, NULL);
|
||||
SDL_SetRelativeMouseMode (SDL_TRUE);
|
||||
#ifdef __MOBILE__
|
||||
// Need to clear this again because setting mode above adds relative values
|
||||
SDL_GetRelativeMouseState (NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void I_ReleaseMouseCapture()
|
||||
{
|
||||
SDL_SetRelativeMouseMode (SDL_FALSE);
|
||||
}
|
||||
|
||||
static void PostMouseMove (int x, int y)
|
||||
{
|
||||
static int lastx = 0, lasty = 0;
|
||||
event_t ev = { 0,0,0,0,0,0,0 };
|
||||
|
||||
if (m_filter)
|
||||
{
|
||||
ev.x = (x + lastx) / 2;
|
||||
ev.y = (y + lasty) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ev.x = x;
|
||||
ev.y = y;
|
||||
}
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
if (ev.x | ev.y)
|
||||
{
|
||||
ev.type = EV_Mouse;
|
||||
D_PostEvent (&ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void MouseRead ()
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if (NativeMouse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_GetRelativeMouseState (&x, &y);
|
||||
if (!m_noprescale)
|
||||
{
|
||||
x *= 3;
|
||||
y *= 2;
|
||||
}
|
||||
if (x | y)
|
||||
{
|
||||
PostMouseMove (x, -y);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
|
||||
{
|
||||
if (self < 0) self = 0;
|
||||
else if (self > 2) self = 2;
|
||||
}
|
||||
|
||||
static bool inGame()
|
||||
{
|
||||
switch (mouse_capturemode)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return gamestate == GS_LEVEL;
|
||||
case 1:
|
||||
return gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE;
|
||||
case 2:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void I_CheckNativeMouse ()
|
||||
{
|
||||
bool focus = SDL_GetKeyboardFocus() != NULL;
|
||||
bool fs = screen->IsFullscreen();
|
||||
|
||||
bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame());
|
||||
|
||||
if (wantNative != NativeMouse)
|
||||
{
|
||||
NativeMouse = wantNative;
|
||||
SDL_ShowCursor (wantNative);
|
||||
if (wantNative)
|
||||
I_ReleaseMouseCapture ();
|
||||
else
|
||||
I_SetMouseCapture ();
|
||||
}
|
||||
}
|
||||
|
||||
void MessagePump (const SDL_Event &sev)
|
||||
{
|
||||
static int lastx = 0, lasty = 0;
|
||||
int x, y;
|
||||
event_t event = { 0,0,0,0,0,0,0 };
|
||||
|
||||
switch (sev.type)
|
||||
{
|
||||
case SDL_QUIT:
|
||||
throw CExitEvent(0);
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (sev.window.event)
|
||||
{
|
||||
extern bool AppActive;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
S_SetSoundPaused(1);
|
||||
AppActive = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
S_SetSoundPaused(i_soundinbackground);
|
||||
AppActive = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (!GUICapture)
|
||||
{
|
||||
event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
||||
|
||||
switch (sev.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT: event.data1 = KEY_MOUSE1; break;
|
||||
case SDL_BUTTON_MIDDLE: event.data1 = KEY_MOUSE3; break;
|
||||
case SDL_BUTTON_RIGHT: event.data1 = KEY_MOUSE2; break;
|
||||
case SDL_BUTTON_X1: event.data1 = KEY_MOUSE4; break;
|
||||
case SDL_BUTTON_X2: event.data1 = KEY_MOUSE5; break;
|
||||
case 6: event.data1 = KEY_MOUSE6; break;
|
||||
case 7: event.data1 = KEY_MOUSE7; break;
|
||||
case 8: event.data1 = KEY_MOUSE8; break;
|
||||
default: printf("SDL mouse button %s %d\n",
|
||||
sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break;
|
||||
}
|
||||
|
||||
if (event.data1 != 0)
|
||||
{
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
}
|
||||
else if ((sev.button.button >= SDL_BUTTON_LEFT && sev.button.button <= SDL_BUTTON_X2))
|
||||
{
|
||||
int x, y;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
|
||||
event.type = EV_GUI_Event;
|
||||
event.data1 = x;
|
||||
event.data2 = y;
|
||||
|
||||
screen->ScaleCoordsFromWindow(event.data1, event.data2);
|
||||
|
||||
if (sev.type == SDL_MOUSEBUTTONDOWN)
|
||||
{
|
||||
switch(sev.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonDown; break;
|
||||
case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonDown; break;
|
||||
case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonDown; break;
|
||||
case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonDown; break;
|
||||
case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonDown; break;
|
||||
default: assert(false); event.subtype = EV_GUI_None; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(sev.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonUp; break;
|
||||
case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonUp; break;
|
||||
case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonUp; break;
|
||||
case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonUp; break;
|
||||
case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonUp; break;
|
||||
default: assert(false); event.subtype = EV_GUI_None; break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Keymod kmod = SDL_GetModState();
|
||||
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((kmod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
if (GUICapture)
|
||||
{
|
||||
event.data1 = sev.motion.x;
|
||||
event.data2 = sev.motion.y;
|
||||
|
||||
screen->ScaleCoordsFromWindow(event.data1, event.data2);
|
||||
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = EV_GUI_MouseMove;
|
||||
|
||||
SDL_Keymod kmod = SDL_GetModState();
|
||||
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((kmod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (GUICapture)
|
||||
{
|
||||
event.type = EV_GUI_Event;
|
||||
|
||||
if (sev.wheel.y == 0)
|
||||
event.subtype = sev.wheel.x > 0 ? EV_GUI_WheelRight : EV_GUI_WheelLeft;
|
||||
else
|
||||
event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown;
|
||||
|
||||
SDL_Keymod kmod = SDL_GetModState();
|
||||
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((kmod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
else
|
||||
{
|
||||
event.type = EV_KeyDown;
|
||||
|
||||
if (sev.wheel.y != 0)
|
||||
event.data1 = sev.wheel.y > 0 ? KEY_MWHEELUP : KEY_MWHEELDOWN;
|
||||
else
|
||||
event.data1 = sev.wheel.x > 0 ? KEY_MWHEELRIGHT : KEY_MWHEELLEFT;
|
||||
|
||||
D_PostEvent (&event);
|
||||
event.type = EV_KeyUp;
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (!GUICapture)
|
||||
{
|
||||
if (sev.key.repeat)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp;
|
||||
|
||||
// Try to look up our key mapped key for conversion to DirectInput.
|
||||
// If that fails, then we'll do a lookup against the scan code,
|
||||
// which may not return the right key, but at least the key should
|
||||
// work in the game.
|
||||
if (const uint8_t *dik = KeySymToDIK.CheckKey (sev.key.keysym.sym))
|
||||
event.data1 = *dik;
|
||||
else if (const uint8_t *dik = KeyScanToDIK.CheckKey (sev.key.keysym.scancode))
|
||||
event.data1 = *dik;
|
||||
|
||||
if (event.data1)
|
||||
{
|
||||
if (sev.key.keysym.sym < 256)
|
||||
{
|
||||
event.data2 = sev.key.keysym.sym;
|
||||
}
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp;
|
||||
SDL_Keymod kmod = SDL_GetModState();
|
||||
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((kmod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
|
||||
if (event.subtype == EV_GUI_KeyDown && sev.key.repeat)
|
||||
{
|
||||
event.subtype = EV_GUI_KeyRepeat;
|
||||
}
|
||||
|
||||
switch (sev.key.keysym.sym)
|
||||
{
|
||||
case SDLK_KP_ENTER: event.data1 = GK_RETURN; break;
|
||||
case SDLK_PAGEUP: event.data1 = GK_PGUP; break;
|
||||
case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break;
|
||||
case SDLK_END: event.data1 = GK_END; break;
|
||||
case SDLK_HOME: event.data1 = GK_HOME; break;
|
||||
case SDLK_LEFT: event.data1 = GK_LEFT; break;
|
||||
case SDLK_RIGHT: event.data1 = GK_RIGHT; break;
|
||||
case SDLK_UP: event.data1 = GK_UP; break;
|
||||
case SDLK_DOWN: event.data1 = GK_DOWN; break;
|
||||
case SDLK_DELETE: event.data1 = GK_DEL; break;
|
||||
case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break;
|
||||
case SDLK_F1: event.data1 = GK_F1; break;
|
||||
case SDLK_F2: event.data1 = GK_F2; break;
|
||||
case SDLK_F3: event.data1 = GK_F3; break;
|
||||
case SDLK_F4: event.data1 = GK_F4; break;
|
||||
case SDLK_F5: event.data1 = GK_F5; break;
|
||||
case SDLK_F6: event.data1 = GK_F6; break;
|
||||
case SDLK_F7: event.data1 = GK_F7; break;
|
||||
case SDLK_F8: event.data1 = GK_F8; break;
|
||||
case SDLK_F9: event.data1 = GK_F9; break;
|
||||
case SDLK_F10: event.data1 = GK_F10; break;
|
||||
case SDLK_F11: event.data1 = GK_F11; break;
|
||||
case SDLK_F12: event.data1 = GK_F12; break;
|
||||
case SDLK_SYSREQ: event.data1 = GK_SYSRQ; break;
|
||||
default:
|
||||
if (sev.key.keysym.sym < 256)
|
||||
{
|
||||
event.data1 = sev.key.keysym.sym;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (event.data1 < 128)
|
||||
{
|
||||
event.data1 = toupper(event.data1);
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_TEXTINPUT:
|
||||
if (GUICapture)
|
||||
{
|
||||
int size;
|
||||
|
||||
int unichar = utf8_decode((const uint8_t*)sev.text.text, &size);
|
||||
if (size != 4)
|
||||
{
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = EV_GUI_Char;
|
||||
event.data1 = (int16_t)unichar;
|
||||
event.data2 = !!(SDL_GetModState() & KMOD_ALT);
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
if (!GUICapture)
|
||||
{
|
||||
event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
||||
event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button;
|
||||
if(event.data1 != 0)
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void I_GetEvent ()
|
||||
{
|
||||
SDL_Event sev;
|
||||
|
||||
while (SDL_PollEvent (&sev))
|
||||
{
|
||||
MessagePump (sev);
|
||||
}
|
||||
if (use_mouse)
|
||||
{
|
||||
MouseRead ();
|
||||
}
|
||||
}
|
||||
|
||||
void I_StartTic ()
|
||||
{
|
||||
I_CheckGUICapture ();
|
||||
I_CheckNativeMouse ();
|
||||
I_GetEvent ();
|
||||
}
|
||||
|
||||
void I_ProcessJoysticks ();
|
||||
void I_StartFrame ()
|
||||
{
|
||||
I_ProcessJoysticks();
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
** i_joystick.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include <SDL.h>
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "version.h"
|
||||
#include "templates.h"
|
||||
#include "m_joy.h"
|
||||
|
||||
// Very small deadzone so that floating point magic doesn't happen
|
||||
#define MIN_DEADZONE 0.000001f
|
||||
|
||||
CUSTOM_CVAR(Bool, joy_background, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
|
||||
class SDLInputJoystick: public IJoystickConfig
|
||||
{
|
||||
public:
|
||||
SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f)
|
||||
{
|
||||
Device = SDL_JoystickOpen(DeviceIndex);
|
||||
if(Device != NULL)
|
||||
{
|
||||
NumAxes = SDL_JoystickNumAxes(Device);
|
||||
NumHats = SDL_JoystickNumHats(Device);
|
||||
|
||||
SetDefaultConfig();
|
||||
}
|
||||
}
|
||||
~SDLInputJoystick()
|
||||
{
|
||||
if(Device != NULL)
|
||||
M_SaveJoystickConfig(this);
|
||||
SDL_JoystickClose(Device);
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return Device != NULL;
|
||||
}
|
||||
|
||||
FString GetName()
|
||||
{
|
||||
return SDL_JoystickName(Device);
|
||||
}
|
||||
float GetSensitivity()
|
||||
{
|
||||
return Multiplier;
|
||||
}
|
||||
void SetSensitivity(float scale)
|
||||
{
|
||||
Multiplier = scale;
|
||||
}
|
||||
|
||||
int GetNumAxes()
|
||||
{
|
||||
return NumAxes + NumHats*2;
|
||||
}
|
||||
float GetAxisDeadZone(int axis)
|
||||
{
|
||||
return Axes[axis].DeadZone;
|
||||
}
|
||||
EJoyAxis GetAxisMap(int axis)
|
||||
{
|
||||
return Axes[axis].GameAxis;
|
||||
}
|
||||
const char *GetAxisName(int axis)
|
||||
{
|
||||
return Axes[axis].Name.GetChars();
|
||||
}
|
||||
float GetAxisScale(int axis)
|
||||
{
|
||||
return Axes[axis].Multiplier;
|
||||
}
|
||||
|
||||
void SetAxisDeadZone(int axis, float zone)
|
||||
{
|
||||
Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f);
|
||||
}
|
||||
void SetAxisMap(int axis, EJoyAxis gameaxis)
|
||||
{
|
||||
Axes[axis].GameAxis = gameaxis;
|
||||
}
|
||||
void SetAxisScale(int axis, float scale)
|
||||
{
|
||||
Axes[axis].Multiplier = scale;
|
||||
}
|
||||
|
||||
// Used by the saver to not save properties that are at their defaults.
|
||||
bool IsSensitivityDefault()
|
||||
{
|
||||
return Multiplier == 1.0f;
|
||||
}
|
||||
bool IsAxisDeadZoneDefault(int axis)
|
||||
{
|
||||
return Axes[axis].DeadZone <= MIN_DEADZONE;
|
||||
}
|
||||
bool IsAxisMapDefault(int axis)
|
||||
{
|
||||
if(axis >= 5)
|
||||
return Axes[axis].GameAxis == JOYAXIS_None;
|
||||
return Axes[axis].GameAxis == DefaultAxes[axis];
|
||||
}
|
||||
bool IsAxisScaleDefault(int axis)
|
||||
{
|
||||
return Axes[axis].Multiplier == 1.0f;
|
||||
}
|
||||
|
||||
void SetDefaultConfig()
|
||||
{
|
||||
for(int i = 0;i < GetNumAxes();i++)
|
||||
{
|
||||
AxisInfo info;
|
||||
if(i < NumAxes)
|
||||
info.Name.Format("Axis %d", i+1);
|
||||
else
|
||||
info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
|
||||
info.DeadZone = MIN_DEADZONE;
|
||||
info.Multiplier = 1.0f;
|
||||
info.Value = 0.0;
|
||||
info.ButtonValue = 0;
|
||||
if(i >= 5)
|
||||
info.GameAxis = JOYAXIS_None;
|
||||
else
|
||||
info.GameAxis = DefaultAxes[i];
|
||||
Axes.Push(info);
|
||||
}
|
||||
}
|
||||
FString GetIdentifier()
|
||||
{
|
||||
char id[16];
|
||||
mysnprintf(id, countof(id), "JS:%d", DeviceIndex);
|
||||
return id;
|
||||
}
|
||||
|
||||
void AddAxes(float axes[NUM_JOYAXIS])
|
||||
{
|
||||
// Add to game axes.
|
||||
for (int i = 0; i < GetNumAxes(); ++i)
|
||||
{
|
||||
if(Axes[i].GameAxis != JOYAXIS_None)
|
||||
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessInput()
|
||||
{
|
||||
uint8_t buttonstate;
|
||||
|
||||
for (int i = 0; i < NumAxes; ++i)
|
||||
{
|
||||
buttonstate = 0;
|
||||
|
||||
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0;
|
||||
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
|
||||
|
||||
// Map button to axis
|
||||
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
|
||||
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
|
||||
{
|
||||
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
|
||||
Axes[i].ButtonValue = buttonstate;
|
||||
}
|
||||
}
|
||||
|
||||
if(NumAxes > 1)
|
||||
{
|
||||
buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value);
|
||||
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
|
||||
Axes[0].ButtonValue = buttonstate;
|
||||
}
|
||||
|
||||
// Map POV hats to buttons and axes. Why axes? Well apparently I have
|
||||
// a gamepad where the left control stick is a POV hat (instead of the
|
||||
// d-pad like you would expect, no that's pressure sensitive). Also
|
||||
// KDE's joystick dialog maps them to axes as well.
|
||||
for (int i = 0; i < NumHats; ++i)
|
||||
{
|
||||
AxisInfo &x = Axes[NumAxes + i*2];
|
||||
AxisInfo &y = Axes[NumAxes + i*2 + 1];
|
||||
|
||||
buttonstate = SDL_JoystickGetHat(Device, i);
|
||||
|
||||
// If we're going to assume that we can pass SDL's value into
|
||||
// Joy_GenerateButtonEvents then we might as well assume the format here.
|
||||
if(buttonstate & 0x1) // Up
|
||||
y.Value = -1.0;
|
||||
else if(buttonstate & 0x4) // Down
|
||||
y.Value = 1.0;
|
||||
else
|
||||
y.Value = 0.0;
|
||||
if(buttonstate & 0x2) // Left
|
||||
x.Value = 1.0;
|
||||
else if(buttonstate & 0x8) // Right
|
||||
x.Value = -1.0;
|
||||
else
|
||||
x.Value = 0.0;
|
||||
|
||||
if(i < 4)
|
||||
{
|
||||
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
|
||||
x.ButtonValue = buttonstate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
struct AxisInfo
|
||||
{
|
||||
FString Name;
|
||||
float DeadZone;
|
||||
float Multiplier;
|
||||
EJoyAxis GameAxis;
|
||||
double Value;
|
||||
uint8_t ButtonValue;
|
||||
};
|
||||
static const EJoyAxis DefaultAxes[5];
|
||||
|
||||
int DeviceIndex;
|
||||
SDL_Joystick *Device;
|
||||
|
||||
float Multiplier;
|
||||
TArray<AxisInfo> Axes;
|
||||
int NumAxes;
|
||||
int NumHats;
|
||||
};
|
||||
const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up};
|
||||
|
||||
class SDLInputJoystickManager
|
||||
{
|
||||
public:
|
||||
SDLInputJoystickManager()
|
||||
{
|
||||
for(int i = 0;i < SDL_NumJoysticks();i++)
|
||||
{
|
||||
SDLInputJoystick *device = new SDLInputJoystick(i);
|
||||
if(device->IsValid())
|
||||
Joysticks.Push(device);
|
||||
else
|
||||
delete device;
|
||||
}
|
||||
}
|
||||
~SDLInputJoystickManager()
|
||||
{
|
||||
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
||||
delete Joysticks[i];
|
||||
}
|
||||
|
||||
void AddAxes(float axes[NUM_JOYAXIS])
|
||||
{
|
||||
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
||||
Joysticks[i]->AddAxes(axes);
|
||||
}
|
||||
void GetDevices(TArray<IJoystickConfig *> &sticks)
|
||||
{
|
||||
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
||||
{
|
||||
M_LoadJoystickConfig(Joysticks[i]);
|
||||
sticks.Push(Joysticks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessInput() const
|
||||
{
|
||||
for(unsigned int i = 0;i < Joysticks.Size();++i)
|
||||
Joysticks[i]->ProcessInput();
|
||||
}
|
||||
protected:
|
||||
TArray<SDLInputJoystick *> Joysticks;
|
||||
};
|
||||
static SDLInputJoystickManager *JoystickManager;
|
||||
|
||||
void I_StartupJoysticks()
|
||||
{
|
||||
if (joy_background)
|
||||
SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1");
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0)
|
||||
JoystickManager = new SDLInputJoystickManager();
|
||||
}
|
||||
void I_ShutdownInput()
|
||||
{
|
||||
if(JoystickManager)
|
||||
{
|
||||
delete JoystickManager;
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
}
|
||||
|
||||
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
|
||||
{
|
||||
sticks.Clear();
|
||||
|
||||
JoystickManager->GetDevices(sticks);
|
||||
}
|
||||
|
||||
void I_GetAxes(float axes[NUM_JOYAXIS])
|
||||
{
|
||||
for (int i = 0; i < NUM_JOYAXIS; ++i)
|
||||
{
|
||||
axes[i] = 0;
|
||||
}
|
||||
if (use_joystick)
|
||||
{
|
||||
JoystickManager->AddAxes(axes);
|
||||
}
|
||||
}
|
||||
|
||||
void I_ProcessJoysticks()
|
||||
{
|
||||
if (use_joystick)
|
||||
JoystickManager->ProcessInput();
|
||||
}
|
||||
|
||||
IJoystickConfig *I_UpdateDeviceList()
|
||||
{
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
** i_main.cpp
|
||||
** System-specific startup code. Eventually calls D_DoomMain.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include <SDL.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <new>
|
||||
#include <sys/param.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "doomerrors.h"
|
||||
#include "m_argv.h"
|
||||
#include "d_main.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
#include "c_console.h"
|
||||
#include "errors.h"
|
||||
#include "version.h"
|
||||
#include "w_wad.h"
|
||||
#include "g_level.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "r_state.h"
|
||||
#include "cmdlib.h"
|
||||
#include "r_utility.h"
|
||||
#include "doomstat.h"
|
||||
#include "vm.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*));
|
||||
|
||||
#ifdef __APPLE__
|
||||
void Mac_I_FatalError(const char* errortext);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
void Linux_I_FatalError(const char* errortext);
|
||||
#endif
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
// The command line arguments.
|
||||
FArgs *Args;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
static int DoomSpecificInfo (char *buffer, char *end)
|
||||
{
|
||||
const char *arg;
|
||||
int size = end-buffer-2;
|
||||
int i, p;
|
||||
|
||||
p = 0;
|
||||
p += snprintf (buffer+p, size-p, GAMENAME" version %s (%s)\n", GetVersionString(), GetGitHash());
|
||||
#ifdef __VERSION__
|
||||
p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__);
|
||||
#endif
|
||||
|
||||
// If Args is nullptr, then execution is at either
|
||||
// * early stage of initialization, additional info contains only default values
|
||||
// * late stage of shutdown, most likely main() was done, and accessing global variables is no longer safe
|
||||
if (Args)
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, "\nCommand line:");
|
||||
for (i = 0; i < Args->NumArgs(); ++i)
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, " %s", Args->GetArg(i));
|
||||
}
|
||||
p += snprintf(buffer + p, size - p, "\n");
|
||||
|
||||
for (i = 0; (arg = Wads.GetWadName(i)) != NULL; ++i)
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, "\nWad %d: %s", i, arg);
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL)
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, "\n\nNot in a level.");
|
||||
}
|
||||
else
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, "\n\nCurrent map: %s", level.MapName.GetChars());
|
||||
|
||||
if (!viewactive)
|
||||
{
|
||||
p += snprintf(buffer + p, size - p, "\n\nView not active.");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& vp = r_viewpoint;
|
||||
p += snprintf(buffer + p, size - p, "\n\nviewx = %f", vp.Pos.X);
|
||||
p += snprintf(buffer + p, size - p, "\nviewy = %f", vp.Pos.Y);
|
||||
p += snprintf(buffer + p, size - p, "\nviewz = %f", vp.Pos.Z);
|
||||
p += snprintf(buffer + p, size - p, "\nviewangle = %f", vp.Angles.Yaw.Degrees);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer[p++] = '\n';
|
||||
buffer[p++] = '\0';
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void I_DetectOS()
|
||||
{
|
||||
// The POSIX version never implemented this.
|
||||
}
|
||||
|
||||
void I_StartupJoysticks();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include <android/log.h>
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"JNITouchControlsUtils", __VA_ARGS__))
|
||||
#include "LogWritter.h"
|
||||
|
||||
int main_android (int argc, char **argv)
|
||||
{
|
||||
#else
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
#endif
|
||||
#if !defined (__APPLE__) && !defined (__ANDROID__)
|
||||
{
|
||||
int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS };
|
||||
cc_install_handlers(argc, argv, 4, s, GAMENAMELOWERCASE "-crash.log", DoomSpecificInfo);
|
||||
}
|
||||
#endif // !__APPLE__
|
||||
|
||||
printf(GAMENAME" %s - %s - SDL version\nCompiled on %s\n",
|
||||
GetVersionString(), GetGitTime(), __DATE__);
|
||||
|
||||
seteuid (getuid ());
|
||||
// Set LC_NUMERIC environment variable in case some library decides to
|
||||
// clear the setlocale call at least this will be correct.
|
||||
// Note that the LANG environment variable is overridden by LC_*
|
||||
setenv ("LC_NUMERIC", "C", 1);
|
||||
|
||||
setlocale (LC_ALL, "C");
|
||||
|
||||
if (SDL_Init (0) < 0)
|
||||
{
|
||||
fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
||||
Args = new FArgs(argc, argv);
|
||||
|
||||
// Should we even be doing anything with progdir on Unix systems?
|
||||
char program[PATH_MAX];
|
||||
if (realpath (argv[0], program) == NULL)
|
||||
strcpy (program, argv[0]);
|
||||
char *slash = strrchr (program, '/');
|
||||
if (slash != NULL)
|
||||
{
|
||||
*(slash + 1) = '\0';
|
||||
progdir = program;
|
||||
}
|
||||
else
|
||||
{
|
||||
progdir = "./";
|
||||
}
|
||||
|
||||
I_StartupJoysticks();
|
||||
|
||||
const int result = D_DoomMain();
|
||||
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
#ifdef __ANDROID__ // So it it properly reset next time it starts up
|
||||
usleep(1000 * 500);
|
||||
exit(0);
|
||||
#endif
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 1993-1996 id Software
|
||||
// Copyright 1999-2016 Randy Heit
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "d_main.h"
|
||||
#include "i_system.h"
|
||||
#include "version.h"
|
||||
#include "x86.h"
|
||||
|
||||
|
||||
#ifndef NO_GTK
|
||||
bool I_GtkAvailable ();
|
||||
int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
|
||||
void I_ShowFatalError_Gtk(const char* errortext);
|
||||
#elif defined(__APPLE__)
|
||||
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
|
||||
#endif
|
||||
|
||||
double PerfToSec, PerfToMillisec;
|
||||
|
||||
void I_SetIWADInfo()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// I_Error
|
||||
//
|
||||
|
||||
#ifdef __APPLE__
|
||||
void Mac_I_FatalError(const char* errortext);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"Gzdoom", __VA_ARGS__))
|
||||
#include "LogWritter.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
void Linux_I_FatalError(const char* errortext)
|
||||
{
|
||||
// Close window or exit fullscreen and release mouse capture
|
||||
SDL_Quit();
|
||||
|
||||
const char *str;
|
||||
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
||||
{
|
||||
FString cmd;
|
||||
cmd << "kdialog --title \"" GAMESIG " " << GetVersionString()
|
||||
<< "\" --msgbox \"" << errortext << "\"";
|
||||
popen(cmd, "r");
|
||||
}
|
||||
#ifndef NO_GTK
|
||||
else if (I_GtkAvailable())
|
||||
{
|
||||
I_ShowFatalError_Gtk(errortext);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
FString title;
|
||||
title << GAMESIG " " << GetVersionString();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
LOGI("FATAL ERROR: %s", errortext);
|
||||
LogWritter_Write(errortext);
|
||||
#endif
|
||||
|
||||
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, errortext, NULL) < 0)
|
||||
{
|
||||
printf("\n%s\n", errortext);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void I_ShowFatalError(const char *message)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
LOGI("ERROR: %s", message);
|
||||
LogWritter_Write(message);
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
Mac_I_FatalError(message);
|
||||
#elif defined __linux__
|
||||
Linux_I_FatalError(message);
|
||||
#else
|
||||
// ???
|
||||
#endif
|
||||
}
|
||||
|
||||
void CalculateCPUSpeed()
|
||||
{
|
||||
}
|
||||
|
||||
void I_DebugPrint(const char *cp)
|
||||
{
|
||||
}
|
||||
|
||||
void I_PrintStr(const char *cp)
|
||||
{
|
||||
// Strip out any color escape sequences before writing to debug output
|
||||
TArray<char> copy(strlen(cp) + 1, true);
|
||||
const char * srcp = cp;
|
||||
char * dstp = copy.Data();
|
||||
|
||||
while (*srcp != 0)
|
||||
{
|
||||
if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f)
|
||||
{
|
||||
*dstp++ = *srcp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (srcp[1] != 0) srcp += 2;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
*dstp = 0;
|
||||
|
||||
fputs(copy.Data(), stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!showwin)
|
||||
{
|
||||
return defaultiwad;
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
const char *str;
|
||||
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
||||
{
|
||||
FString cmd("kdialog --title \"" GAMESIG " ");
|
||||
cmd << GetVersionString() << ": Select an IWAD to use\""
|
||||
" --menu \"" GAMENAME " found more than one IWAD\n"
|
||||
"Select from the list below to determine which one to use:\"";
|
||||
|
||||
for(i = 0; i < numwads; ++i)
|
||||
{
|
||||
const char *filepart = strrchr(wads[i].Path, '/');
|
||||
if(filepart == NULL)
|
||||
filepart = wads[i].Path;
|
||||
else
|
||||
filepart++;
|
||||
// Menu entries are specified in "tag" "item" pairs, where when a
|
||||
// particular item is selected (and the Okay button clicked), its
|
||||
// corresponding tag is printed to stdout for identification.
|
||||
cmd.AppendFormat(" \"%d\" \"%s (%s)\"", i, wads[i].Name.GetChars(), filepart);
|
||||
}
|
||||
|
||||
if(defaultiwad >= 0 && defaultiwad < numwads)
|
||||
{
|
||||
const char *filepart = strrchr(wads[defaultiwad].Path, '/');
|
||||
if(filepart == NULL)
|
||||
filepart = wads[defaultiwad].Path;
|
||||
else
|
||||
filepart++;
|
||||
cmd.AppendFormat(" --default \"%s (%s)\"", wads[defaultiwad].Name.GetChars(), filepart);
|
||||
}
|
||||
|
||||
FILE *f = popen(cmd, "r");
|
||||
if(f != NULL)
|
||||
{
|
||||
char gotstr[16];
|
||||
|
||||
if(fgets(gotstr, sizeof(gotstr), f) == NULL ||
|
||||
sscanf(gotstr, "%d", &i) != 1)
|
||||
i = -1;
|
||||
|
||||
// Exit status = 1 means the selection was canceled (either by
|
||||
// Cancel/Esc or the X button), not that there was an error running
|
||||
// the program. In that case, nothing was printed so fgets will
|
||||
// have failed. Other values can indicate an error running the app,
|
||||
// so fall back to whatever else can be used.
|
||||
int status = pclose(f);
|
||||
if(WIFEXITED(status) && (WEXITSTATUS(status) == 0 || WEXITSTATUS(status) == 1))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_GTK
|
||||
if (I_GtkAvailable())
|
||||
{
|
||||
return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad);
|
||||
#endif
|
||||
|
||||
if (!isatty(fileno(stdin)))
|
||||
{
|
||||
return defaultiwad;
|
||||
}
|
||||
|
||||
printf ("Please select a game wad (or 0 to exit):\n");
|
||||
for (i = 0; i < numwads; ++i)
|
||||
{
|
||||
const char *filepart = strrchr (wads[i].Path, '/');
|
||||
if (filepart == NULL)
|
||||
filepart = wads[i].Path;
|
||||
else
|
||||
filepart++;
|
||||
printf ("%d. %s (%s)\n", i+1, wads[i].Name.GetChars(), filepart);
|
||||
}
|
||||
printf ("Which one? ");
|
||||
if (scanf ("%d", &i) != 1 || i > numwads)
|
||||
return -1;
|
||||
return i-1;
|
||||
}
|
||||
|
||||
void I_PutInClipboard (const char *str)
|
||||
{
|
||||
SDL_SetClipboardText(str);
|
||||
}
|
||||
|
||||
FString I_GetFromClipboard (bool use_primary_selection)
|
||||
{
|
||||
if(char *ret = SDL_GetClipboardText())
|
||||
{
|
||||
FString text(ret);
|
||||
SDL_free(ret);
|
||||
return text;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Return a random seed, preferably one with lots of entropy.
|
||||
unsigned int I_MakeRNGSeed()
|
||||
{
|
||||
unsigned int seed;
|
||||
int file;
|
||||
|
||||
// Try reading from /dev/urandom first, then /dev/random, then
|
||||
// if all else fails, use a crappy seed from time().
|
||||
seed = time(NULL);
|
||||
file = open("/dev/urandom", O_RDONLY);
|
||||
if (file < 0)
|
||||
{
|
||||
file = open("/dev/random", O_RDONLY);
|
||||
}
|
||||
if (file >= 0)
|
||||
{
|
||||
read(file, &seed, sizeof(seed));
|
||||
close(file);
|
||||
}
|
||||
return seed;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "SDL.h"
|
||||
|
||||
void Mac_I_FatalError(const char* errortext)
|
||||
{
|
||||
// Close window or exit fullscreen and release mouse capture
|
||||
SDL_Quit();
|
||||
|
||||
const CFStringRef errorString = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault,
|
||||
errortext, kCFStringEncodingASCII, kCFAllocatorNull );
|
||||
if ( NULL != errorString )
|
||||
{
|
||||
CFOptionFlags dummy;
|
||||
|
||||
CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL,
|
||||
CFSTR( "Fatal Error" ), errorString, CFSTR( "Exit" ), NULL, NULL, &dummy );
|
||||
CFRelease( errorString );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,591 @@
|
|||
/*
|
||||
** sdlglvideo.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2016 Christoph Oelckers et.al.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
#include "templates.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
#include "m_argv.h"
|
||||
#include "v_video.h"
|
||||
#include "v_pfx.h"
|
||||
#include "stats.h"
|
||||
#include "version.h"
|
||||
#include "c_console.h"
|
||||
|
||||
#include "videomodes.h"
|
||||
#include "sdlglvideo.h"
|
||||
#include "sdlvideo.h"
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "r_defs.h"
|
||||
#include "gl/gl_functions.h"
|
||||
//#include "gl/gl_intern.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
extern IVideo *Video;
|
||||
// extern int vid_renderer;
|
||||
|
||||
EXTERN_CVAR (Float, Gamma)
|
||||
EXTERN_CVAR (Int, vid_adapter)
|
||||
EXTERN_CVAR (Int, vid_displaybits)
|
||||
EXTERN_CVAR (Int, vid_renderer)
|
||||
EXTERN_CVAR (Int, vid_maxfps)
|
||||
EXTERN_CVAR (Bool, cl_capfps)
|
||||
|
||||
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool bgra, bool fullscreen);
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
#ifdef __arm__
|
||||
CUSTOM_CVAR(Bool, vid_glswfb, false, CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
CUSTOM_CVAR(Bool, gl_es, false, CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
#else
|
||||
CUSTOM_CVAR(Bool, vid_glswfb, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
SDLGLVideo::SDLGLVideo (int parm)
|
||||
{
|
||||
IteratorBits = 0;
|
||||
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
|
||||
fprintf( stderr, "Video initialization failed: %s\n",
|
||||
SDL_GetError( ) );
|
||||
}
|
||||
}
|
||||
|
||||
SDLGLVideo::~SDLGLVideo ()
|
||||
{
|
||||
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
||||
}
|
||||
|
||||
void SDLGLVideo::StartModeIterator (int bits, bool fs)
|
||||
{
|
||||
IteratorMode = 0;
|
||||
IteratorBits = bits;
|
||||
}
|
||||
|
||||
bool SDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
|
||||
{
|
||||
if (IteratorBits != 8)
|
||||
return false;
|
||||
|
||||
if ((unsigned)IteratorMode < sizeof(VideoModes)/sizeof(VideoModes[0]))
|
||||
{
|
||||
*width = VideoModes[IteratorMode].width;
|
||||
*height = VideoModes[IteratorMode].height;
|
||||
++IteratorMode;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
|
||||
{
|
||||
static int retry = 0;
|
||||
static int owidth, oheight;
|
||||
|
||||
PalEntry flashColor;
|
||||
// int flashAmount;
|
||||
|
||||
if (old != NULL)
|
||||
{ // Reuse the old framebuffer if its attributes are the same
|
||||
SDLBaseFB *fb = static_cast<SDLBaseFB *> (old);
|
||||
if (fb->Width == width &&
|
||||
fb->Height == height)
|
||||
{
|
||||
bool fsnow = (SDL_GetWindowFlags (fb->GetSDLWindow()) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
||||
|
||||
if (fsnow != fullscreen)
|
||||
{
|
||||
SDL_SetWindowFullscreen (fb->GetSDLWindow(), fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
}
|
||||
return old;
|
||||
}
|
||||
// old->GetFlash (flashColor, flashAmount);
|
||||
delete old;
|
||||
}
|
||||
else
|
||||
{
|
||||
flashColor = 0;
|
||||
// flashAmount = 0;
|
||||
}
|
||||
|
||||
SDLBaseFB *fb;
|
||||
if (vid_renderer == 1)
|
||||
{
|
||||
#ifdef USE_GL_HW_BUFFERS
|
||||
const char *hwBuffers = Args->CheckValue("-hwbuffers");
|
||||
int buffers = 1;
|
||||
if (hwBuffers)
|
||||
{
|
||||
buffers = atoi(hwBuffers);
|
||||
}
|
||||
Printf("HW buffers = %d\n", buffers);
|
||||
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen, buffers);
|
||||
#else
|
||||
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen);
|
||||
#endif
|
||||
}
|
||||
else if (vid_glswfb == 0)
|
||||
{
|
||||
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
fb = (SDLBaseFB*)CreateGLSWFrameBuffer(width, height, bgra, fullscreen);
|
||||
if (!fb->IsValid())
|
||||
{
|
||||
delete fb;
|
||||
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
retry = 0;
|
||||
|
||||
// If we could not create the framebuffer, try again with slightly
|
||||
// different parameters in this order:
|
||||
// 1. Try with the closest size
|
||||
// 2. Try in the opposite screen mode with the original size
|
||||
// 3. Try in the opposite screen mode with the closest size
|
||||
// This is a somewhat confusing mass of recursion here.
|
||||
|
||||
while (fb == NULL || !fb->IsValid ())
|
||||
{
|
||||
if (fb != NULL)
|
||||
{
|
||||
delete fb;
|
||||
}
|
||||
|
||||
switch (retry)
|
||||
{
|
||||
case 0:
|
||||
owidth = width;
|
||||
oheight = height;
|
||||
case 2:
|
||||
// Try a different resolution. Hopefully that will work.
|
||||
I_ClosestResolution (&width, &height, 8);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Try changing fullscreen mode. Maybe that will work.
|
||||
width = owidth;
|
||||
height = oheight;
|
||||
fullscreen = !fullscreen;
|
||||
break;
|
||||
|
||||
default:
|
||||
// I give up!
|
||||
I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight);
|
||||
|
||||
fprintf( stderr, "!!! [SDLGLVideo::CreateFrameBuffer] Got beyond I_FatalError !!!" );
|
||||
return NULL; //[C] actually this shouldn't be reached; probably should be replaced with an ASSERT
|
||||
}
|
||||
|
||||
++retry;
|
||||
fb = static_cast<SDLBaseFB *>(CreateFrameBuffer (width, height, false, fullscreen, NULL));
|
||||
}
|
||||
|
||||
// fb->SetFlash (flashColor, flashAmount);
|
||||
return fb;
|
||||
}
|
||||
|
||||
void SDLGLVideo::SetWindowedScale (float scale)
|
||||
{
|
||||
}
|
||||
|
||||
bool SDLGLVideo::SetResolution (int width, int height, int bits)
|
||||
{
|
||||
// FIXME: Is it possible to do this without completely destroying the old
|
||||
// interface?
|
||||
#ifndef NO_GL
|
||||
|
||||
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
||||
I_ShutdownGraphics();
|
||||
|
||||
Video = new SDLGLVideo(0);
|
||||
if (Video == NULL) I_FatalError ("Failed to initialize display");
|
||||
|
||||
#if (defined(WINDOWS)) || defined(WIN32)
|
||||
bits=32;
|
||||
#else
|
||||
bits=24;
|
||||
#endif
|
||||
|
||||
V_DoModeSetup(width, height, bits);
|
||||
#endif
|
||||
return true; // We must return true because the old video context no longer exists.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
#ifdef __MOBILE__
|
||||
extern "C" extern int glesLoad;
|
||||
#endif
|
||||
|
||||
void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
|
||||
{
|
||||
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
|
||||
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
|
||||
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
|
||||
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
|
||||
#ifdef __MOBILE__
|
||||
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
|
||||
#else
|
||||
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
|
||||
#endif
|
||||
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
|
||||
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
||||
if (multisample > 0) {
|
||||
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
|
||||
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, multisample );
|
||||
}
|
||||
if (gl_debug)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
|
||||
#ifdef __MOBILE__
|
||||
|
||||
const char *version = Args->CheckValue("-glversion");
|
||||
int major,min;
|
||||
if( !strcmp(version, "gles1") )
|
||||
{
|
||||
glesLoad = 1;
|
||||
major = 1;
|
||||
min = 0;
|
||||
}
|
||||
else if ( !strcmp(version, "gles2") )
|
||||
{
|
||||
glesLoad = 2;
|
||||
major = 2;
|
||||
min = 0;
|
||||
}
|
||||
else if ( !strcmp(version, "gles3") )
|
||||
{
|
||||
glesLoad = 3;
|
||||
major = 3;
|
||||
min = 1;
|
||||
}
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, min);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (gl_es)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
else if (glver[0] > 2)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FrameBuffer implementation -----------------------------------------------
|
||||
|
||||
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
|
||||
: SDLBaseFB (width, height, bgra)
|
||||
{
|
||||
// NOTE: Core profiles were added with GL 3.2, so there's no sense trying
|
||||
// to set core 3.1 or 3.0. We could try a forward-compatible context
|
||||
// instead, but that would be too restrictive (w.r.t. shaders).
|
||||
static const int glvers[][2] = {
|
||||
{ 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
|
||||
{ 3, 3 }, { 3, 2 }, { 2, 0 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
int glveridx = 0;
|
||||
int i;
|
||||
|
||||
m_Lock=0;
|
||||
UpdatePending = false;
|
||||
|
||||
const char *version = Args->CheckValue("-glversion");
|
||||
if (version != NULL)
|
||||
{
|
||||
double gl_version = strtod(version, NULL) + 0.01;
|
||||
int vermaj = (int)gl_version;
|
||||
int vermin = (int)(gl_version*10.0) % 10;
|
||||
|
||||
while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj &&
|
||||
glvers[glveridx][1] > vermin))
|
||||
{
|
||||
glveridx++;
|
||||
if (glvers[glveridx][0] == 0)
|
||||
{
|
||||
glveridx = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FString caption;
|
||||
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
|
||||
|
||||
for ( ; glvers[glveridx][0] > 0; ++glveridx)
|
||||
{
|
||||
static_cast<SDLGLVideo*>(Video)->SetupPixelFormat(false, 0, glvers[glveridx]);
|
||||
|
||||
Screen = SDL_CreateWindow (caption,
|
||||
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
|
||||
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
|
||||
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_OPENGL
|
||||
);
|
||||
if (Screen != NULL)
|
||||
{
|
||||
GLContext = SDL_GL_CreateContext(Screen);
|
||||
if (GLContext != NULL)
|
||||
{
|
||||
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen,
|
||||
m_origGamma[0], m_origGamma[1], m_origGamma[2]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_DestroyWindow(Screen);
|
||||
Screen = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDLGLFB::~SDLGLFB ()
|
||||
{
|
||||
if (Screen)
|
||||
{
|
||||
ResetGammaTable();
|
||||
|
||||
if (GLContext)
|
||||
{
|
||||
SDL_GL_DeleteContext(GLContext);
|
||||
}
|
||||
|
||||
SDL_DestroyWindow(Screen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SDLGLFB::InitializeState()
|
||||
{
|
||||
}
|
||||
|
||||
void SDLGLFB::SetGammaTable(uint16_t *tbl)
|
||||
{
|
||||
if (m_supportsGamma)
|
||||
{
|
||||
SDL_SetWindowGammaRamp(Screen, &tbl[0], &tbl[256], &tbl[512]);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLGLFB::ResetGammaTable()
|
||||
{
|
||||
if (m_supportsGamma)
|
||||
{
|
||||
SDL_SetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDLGLFB::Lock(bool buffered)
|
||||
{
|
||||
m_Lock++;
|
||||
Buffer = MemBuffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLGLFB::Lock ()
|
||||
{
|
||||
return Lock(false);
|
||||
}
|
||||
|
||||
void SDLGLFB::Unlock ()
|
||||
{
|
||||
if (UpdatePending && m_Lock == 1)
|
||||
{
|
||||
Update ();
|
||||
}
|
||||
else if (--m_Lock <= 0)
|
||||
{
|
||||
m_Lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SDLGLFB::IsLocked ()
|
||||
{
|
||||
return m_Lock>0;// true;
|
||||
}
|
||||
|
||||
bool SDLGLFB::IsFullscreen ()
|
||||
{
|
||||
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
||||
}
|
||||
|
||||
|
||||
bool SDLGLFB::IsValid ()
|
||||
{
|
||||
return DFrameBuffer::IsValid() && Screen != NULL;
|
||||
}
|
||||
|
||||
void SDLGLFB::SetVSync( bool vsync )
|
||||
{
|
||||
#if defined (__APPLE__)
|
||||
const GLint value = vsync ? 1 : 0;
|
||||
CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value );
|
||||
#else
|
||||
if (vsync)
|
||||
{
|
||||
if (SDL_GL_SetSwapInterval(-1) == -1)
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SDLGLFB::NewRefreshRate ()
|
||||
{
|
||||
}
|
||||
|
||||
void SDLGLFB::SwapBuffers()
|
||||
{
|
||||
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
||||
if (vid_maxfps && !cl_capfps)
|
||||
{
|
||||
SEMAPHORE_WAIT(FPSLimitSemaphore)
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_GL_SwapWindow (Screen);
|
||||
}
|
||||
|
||||
int SDLGLFB::GetClientWidth()
|
||||
{
|
||||
int width = 0;
|
||||
SDL_GL_GetDrawableSize(Screen, &width, nullptr);
|
||||
return width;
|
||||
}
|
||||
|
||||
int SDLGLFB::GetClientHeight()
|
||||
{
|
||||
int height = 0;
|
||||
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
|
||||
return height;
|
||||
}
|
||||
|
||||
void SDLGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
|
||||
{
|
||||
int w, h;
|
||||
SDL_GetWindowSize (Screen, &w, &h);
|
||||
|
||||
// Detect if we're doing scaling in the Window and adjust the mouse
|
||||
// coordinates accordingly. This could be more efficent, but I
|
||||
// don't think performance is an issue in the menus.
|
||||
if(IsFullscreen())
|
||||
{
|
||||
int realw = w, realh = h;
|
||||
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
|
||||
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
|
||||
{
|
||||
double xratio = (double)SCREENWIDTH/realw;
|
||||
double yratio = (double)SCREENHEIGHT/realh;
|
||||
if (realw < w)
|
||||
{
|
||||
x = (x - (w - realw)/2)*xratio;
|
||||
y *= yratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = (y - (h - realh)/2)*yratio;
|
||||
x *= xratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = (int16_t)(x*Width/w);
|
||||
y = (int16_t)(y*Height/h);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,580 @@
|
|||
/*
|
||||
** sdlvideo.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
#include "templates.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
#include "v_video.h"
|
||||
#include "v_pfx.h"
|
||||
#include "stats.h"
|
||||
#include "v_palette.h"
|
||||
#include "sdlvideo.h"
|
||||
#include "swrenderer/r_swrenderer.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#endif // __APPLE__
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
struct MiniModeInfo
|
||||
{
|
||||
uint16_t Width, Height;
|
||||
};
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
extern IVideo *Video;
|
||||
extern bool GUICapture;
|
||||
|
||||
EXTERN_CVAR (Float, Gamma)
|
||||
EXTERN_CVAR (Int, vid_maxfps)
|
||||
EXTERN_CVAR (Bool, cl_capfps)
|
||||
EXTERN_CVAR (Bool, vid_vsync)
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR (Int, vid_displaybits, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR (Bool, vid_forcesurface, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (screen != NULL)
|
||||
{
|
||||
screen->SetGamma (Gamma);
|
||||
}
|
||||
}
|
||||
CUSTOM_CVAR (Float, ggamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (screen != NULL)
|
||||
{
|
||||
screen->SetGamma (Gamma);
|
||||
}
|
||||
}
|
||||
CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (screen != NULL)
|
||||
{
|
||||
screen->SetGamma (Gamma);
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static cycle_t BlitCycles;
|
||||
static cycle_t SDLFlipCycles;
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
// FrameBuffer implementation -----------------------------------------------
|
||||
|
||||
SDLFB::SDLFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
|
||||
: SDLBaseFB (width, height, bgra)
|
||||
{
|
||||
int i;
|
||||
|
||||
NeedPalUpdate = false;
|
||||
NeedGammaUpdate = false;
|
||||
UpdatePending = false;
|
||||
NotPaletted = false;
|
||||
FlashAmount = 0;
|
||||
|
||||
if (oldwin)
|
||||
{
|
||||
// In some cases (Mac OS X fullscreen) SDL2 doesn't like having multiple windows which
|
||||
// appears to inevitably happen while compositor animations are running. So lets try
|
||||
// to reuse the existing window.
|
||||
Screen = oldwin;
|
||||
SDL_SetWindowSize (Screen, width, height);
|
||||
SetFullscreen (fullscreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
FString caption;
|
||||
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
|
||||
|
||||
#ifdef __ANDROID__
|
||||
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // Defaults to 24 which is not needed and fails on old Tegras
|
||||
#endif
|
||||
|
||||
Screen = SDL_CreateWindow (caption,
|
||||
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
|
||||
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_RESIZABLE);
|
||||
|
||||
if (Screen == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
Renderer = NULL;
|
||||
Texture = NULL;
|
||||
ResetSDLRenderer ();
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
GammaTable[0][i] = GammaTable[1][i] = GammaTable[2][i] = i;
|
||||
}
|
||||
|
||||
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
|
||||
UpdateColors ();
|
||||
|
||||
#ifdef __APPLE__
|
||||
SetVSync (vid_vsync);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SDLFB::~SDLFB ()
|
||||
{
|
||||
if (Renderer)
|
||||
{
|
||||
if (Texture)
|
||||
SDL_DestroyTexture (Texture);
|
||||
SDL_DestroyRenderer (Renderer);
|
||||
}
|
||||
|
||||
if(Screen)
|
||||
{
|
||||
SDL_DestroyWindow (Screen);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDLFB::IsValid ()
|
||||
{
|
||||
return DFrameBuffer::IsValid() && Screen != NULL;
|
||||
}
|
||||
|
||||
int SDLFB::GetPageCount ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SDLFB::Lock (bool buffered)
|
||||
{
|
||||
return DSimpleCanvas::Lock ();
|
||||
}
|
||||
|
||||
bool SDLFB::Relock ()
|
||||
{
|
||||
return DSimpleCanvas::Lock ();
|
||||
}
|
||||
|
||||
void SDLFB::Unlock ()
|
||||
{
|
||||
if (UpdatePending && LockCount == 1)
|
||||
{
|
||||
Update ();
|
||||
}
|
||||
else if (--LockCount <= 0)
|
||||
{
|
||||
Buffer = NULL;
|
||||
LockCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SDLFB::Update ()
|
||||
{
|
||||
if (LockCount != 1)
|
||||
{
|
||||
if (LockCount > 0)
|
||||
{
|
||||
UpdatePending = true;
|
||||
--LockCount;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DrawRateStuff ();
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
||||
if(vid_maxfps && !cl_capfps)
|
||||
{
|
||||
SEMAPHORE_WAIT(FPSLimitSemaphore)
|
||||
}
|
||||
#endif
|
||||
|
||||
Buffer = NULL;
|
||||
LockCount = 0;
|
||||
UpdatePending = false;
|
||||
|
||||
BlitCycles.Reset();
|
||||
SDLFlipCycles.Reset();
|
||||
BlitCycles.Clock();
|
||||
|
||||
void *pixels;
|
||||
int pitch;
|
||||
if (UsingRenderer)
|
||||
{
|
||||
if (SDL_LockTexture (Texture, NULL, &pixels, &pitch))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_LockSurface (Surface))
|
||||
return;
|
||||
|
||||
pixels = Surface->pixels;
|
||||
pitch = Surface->pitch;
|
||||
}
|
||||
|
||||
if (Bgra)
|
||||
{
|
||||
CopyWithGammaBgra(pixels, pitch, GammaTable[0], GammaTable[1], GammaTable[2], Flash, FlashAmount);
|
||||
}
|
||||
else if (NotPaletted)
|
||||
{
|
||||
GPfx.Convert (MemBuffer, Pitch,
|
||||
pixels, pitch, Width, Height,
|
||||
FRACUNIT, FRACUNIT, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch == Pitch)
|
||||
{
|
||||
memcpy (pixels, MemBuffer, Width*Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < Height; ++y)
|
||||
{
|
||||
memcpy ((uint8_t *)pixels+y*pitch, MemBuffer+y*Pitch, Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UsingRenderer)
|
||||
{
|
||||
SDL_UnlockTexture (Texture);
|
||||
|
||||
SDLFlipCycles.Clock();
|
||||
SDL_RenderClear(Renderer);
|
||||
SDL_RenderCopy(Renderer, Texture, NULL, NULL);
|
||||
SDL_RenderPresent(Renderer);
|
||||
SDLFlipCycles.Unclock();
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_UnlockSurface (Surface);
|
||||
|
||||
SDLFlipCycles.Clock();
|
||||
SDL_UpdateWindowSurface (Screen);
|
||||
SDLFlipCycles.Unclock();
|
||||
}
|
||||
|
||||
BlitCycles.Unclock();
|
||||
|
||||
if (NeedGammaUpdate)
|
||||
{
|
||||
bool Windowed = false;
|
||||
NeedGammaUpdate = false;
|
||||
CalcGamma ((Windowed || rgamma == 0.f) ? Gamma : (Gamma * rgamma), GammaTable[0]);
|
||||
CalcGamma ((Windowed || ggamma == 0.f) ? Gamma : (Gamma * ggamma), GammaTable[1]);
|
||||
CalcGamma ((Windowed || bgamma == 0.f) ? Gamma : (Gamma * bgamma), GammaTable[2]);
|
||||
NeedPalUpdate = true;
|
||||
}
|
||||
|
||||
if (NeedPalUpdate)
|
||||
{
|
||||
NeedPalUpdate = false;
|
||||
UpdateColors ();
|
||||
}
|
||||
}
|
||||
|
||||
void SDLFB::UpdateColors ()
|
||||
{
|
||||
if (NotPaletted)
|
||||
{
|
||||
PalEntry palette[256];
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
palette[i].r = GammaTable[0][SourcePalette[i].r];
|
||||
palette[i].g = GammaTable[1][SourcePalette[i].g];
|
||||
palette[i].b = GammaTable[2][SourcePalette[i].b];
|
||||
}
|
||||
if (FlashAmount)
|
||||
{
|
||||
DoBlending (palette, palette,
|
||||
256, GammaTable[0][Flash.r], GammaTable[1][Flash.g], GammaTable[2][Flash.b],
|
||||
FlashAmount);
|
||||
}
|
||||
GPfx.SetPalette (palette);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_Color colors[256];
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
colors[i].r = GammaTable[0][SourcePalette[i].r];
|
||||
colors[i].g = GammaTable[1][SourcePalette[i].g];
|
||||
colors[i].b = GammaTable[2][SourcePalette[i].b];
|
||||
}
|
||||
if (FlashAmount)
|
||||
{
|
||||
DoBlending ((PalEntry *)colors, (PalEntry *)colors,
|
||||
256, GammaTable[2][Flash.b], GammaTable[1][Flash.g], GammaTable[0][Flash.r],
|
||||
FlashAmount);
|
||||
}
|
||||
SDL_SetPaletteColors (Surface->format->palette, colors, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
PalEntry *SDLFB::GetPalette ()
|
||||
{
|
||||
return SourcePalette;
|
||||
}
|
||||
|
||||
void SDLFB::UpdatePalette ()
|
||||
{
|
||||
NeedPalUpdate = true;
|
||||
}
|
||||
|
||||
bool SDLFB::SetGamma (float gamma)
|
||||
{
|
||||
Gamma = gamma;
|
||||
NeedGammaUpdate = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLFB::SetFlash (PalEntry rgb, int amount)
|
||||
{
|
||||
Flash = rgb;
|
||||
FlashAmount = amount;
|
||||
NeedPalUpdate = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLFB::GetFlash (PalEntry &rgb, int &amount)
|
||||
{
|
||||
rgb = Flash;
|
||||
amount = FlashAmount;
|
||||
}
|
||||
|
||||
// Q: Should I gamma adjust the returned palette?
|
||||
void SDLFB::GetFlashedPalette (PalEntry pal[256])
|
||||
{
|
||||
memcpy (pal, SourcePalette, 256*sizeof(PalEntry));
|
||||
if (FlashAmount)
|
||||
{
|
||||
DoBlending (pal, pal, 256, Flash.r, Flash.g, Flash.b, FlashAmount);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLFB::SetFullscreen (bool fullscreen)
|
||||
{
|
||||
if (IsFullscreen() == fullscreen)
|
||||
return;
|
||||
|
||||
SDL_SetWindowFullscreen (Screen, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
if (!fullscreen)
|
||||
{
|
||||
// Restore proper window size
|
||||
SDL_SetWindowSize (Screen, Width, Height);
|
||||
}
|
||||
|
||||
ResetSDLRenderer ();
|
||||
}
|
||||
|
||||
bool SDLFB::IsFullscreen ()
|
||||
{
|
||||
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
||||
}
|
||||
|
||||
void SDLFB::ResetSDLRenderer ()
|
||||
{
|
||||
if (Renderer)
|
||||
{
|
||||
if (Texture)
|
||||
SDL_DestroyTexture (Texture);
|
||||
SDL_DestroyRenderer (Renderer);
|
||||
}
|
||||
|
||||
UsingRenderer = !vid_forcesurface;
|
||||
if (UsingRenderer)
|
||||
{
|
||||
#ifdef __MOBILE__
|
||||
Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED);
|
||||
#else
|
||||
Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE|
|
||||
(vid_vsync ? SDL_RENDERER_PRESENTVSYNC : 0));
|
||||
#endif
|
||||
|
||||
|
||||
if (!Renderer)
|
||||
return;
|
||||
|
||||
SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255);
|
||||
|
||||
Uint32 fmt;
|
||||
if (Bgra)
|
||||
{
|
||||
fmt = SDL_PIXELFORMAT_ARGB8888;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (vid_displaybits)
|
||||
{
|
||||
default: fmt = SDL_PIXELFORMAT_ARGB8888; break;
|
||||
case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break;
|
||||
case 24: fmt = SDL_PIXELFORMAT_RGB888; break;
|
||||
case 16: fmt = SDL_PIXELFORMAT_RGB565; break;
|
||||
case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break;
|
||||
}
|
||||
}
|
||||
Texture = SDL_CreateTexture (Renderer, fmt, SDL_TEXTUREACCESS_STREAMING, Width, Height);
|
||||
|
||||
{
|
||||
NotPaletted = true;
|
||||
|
||||
Uint32 format;
|
||||
SDL_QueryTexture(Texture, &format, NULL, NULL, NULL);
|
||||
|
||||
Uint32 Rmask, Gmask, Bmask, Amask;
|
||||
int bpp;
|
||||
SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
|
||||
GPfx.SetFormat (bpp, Rmask, Gmask, Bmask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface = SDL_GetWindowSurface (Screen);
|
||||
|
||||
if (Surface->format->palette == NULL)
|
||||
{
|
||||
NotPaletted = true;
|
||||
GPfx.SetFormat (Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask);
|
||||
}
|
||||
else
|
||||
NotPaletted = false;
|
||||
}
|
||||
|
||||
// In fullscreen, set logical size according to animorphic ratio.
|
||||
// Windowed modes are rendered to fill the window (usually 1:1)
|
||||
if (IsFullscreen ())
|
||||
{
|
||||
int w, h;
|
||||
SDL_GetWindowSize (Screen, &w, &h);
|
||||
ScaleWithAspect (w, h, Width, Height);
|
||||
#ifndef __MOBILE__
|
||||
SDL_RenderSetLogicalSize (Renderer, w, h);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void SDLFB::SetVSync (bool vsync)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (CGLContextObj context = CGLGetCurrentContext())
|
||||
{
|
||||
// Apply vsync for native backend only (where OpenGL context is set)
|
||||
const GLint value = vsync ? 1 : 0;
|
||||
CGLSetParameter(context, kCGLCPSwapInterval, &value);
|
||||
}
|
||||
#else
|
||||
ResetSDLRenderer ();
|
||||
#endif // __APPLE__
|
||||
}
|
||||
|
||||
void SDLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
|
||||
{
|
||||
int w, h;
|
||||
SDL_GetWindowSize (Screen, &w, &h);
|
||||
|
||||
// Detect if we're doing scaling in the Window and adjust the mouse
|
||||
// coordinates accordingly. This could be more efficent, but I
|
||||
// don't think performance is an issue in the menus.
|
||||
if(IsFullscreen())
|
||||
{
|
||||
int realw = w, realh = h;
|
||||
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
|
||||
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
|
||||
{
|
||||
double xratio = (double)SCREENWIDTH/realw;
|
||||
double yratio = (double)SCREENHEIGHT/realh;
|
||||
if (realw < w)
|
||||
{
|
||||
x = (x - (w - realw)/2)*xratio;
|
||||
y *= yratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = (y - (h - realh)/2)*yratio;
|
||||
x *= xratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = (int16_t)(x*Width/w);
|
||||
y = (int16_t)(y*Height/h);
|
||||
}
|
||||
}
|
||||
|
||||
ADD_STAT (blit)
|
||||
{
|
||||
FString out;
|
||||
out.Format ("blit=%04.1f ms flip=%04.1f ms",
|
||||
BlitCycles.TimeMS(), SDLFlipCycles.TimeMS());
|
||||
return out;
|
||||
}
|
||||
|
||||
// each platform has its own specific version of this function.
|
||||
void I_SetWindowTitle(const char* caption)
|
||||
{
|
||||
auto Screen = static_cast<SDLFB *>(screen)->GetSDLWindow();
|
||||
if (caption)
|
||||
SDL_SetWindowTitle(static_cast<SDLFB *>(screen)->GetSDLWindow(), caption);
|
||||
else
|
||||
{
|
||||
FString default_caption;
|
||||
default_caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
|
||||
SDL_SetWindowTitle(static_cast<SDLFB *>(screen)->GetSDLWindow(), default_caption);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
** st_start.cpp
|
||||
** Handles the startup screen.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "st_start.h"
|
||||
#include "doomdef.h"
|
||||
#include "i_system.h"
|
||||
#include "c_cvars.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "JNITouchControlsUtils.h"
|
||||
#include <android/log.h>
|
||||
#define LOG_TAG "JWZGLES"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"NETOWRK",__VA_ARGS__)
|
||||
#define fprintf my_fprintf
|
||||
|
||||
|
||||
|
||||
void my_fprintf(FILE * x, const char *format, ...)
|
||||
{
|
||||
FString str;
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr, format);
|
||||
str.VFormat (format, argptr);
|
||||
va_end (argptr);
|
||||
//fprintf (stderr, "\r%-40s\n", str.GetChars());
|
||||
addTextConsoleBox(str.GetChars());
|
||||
}
|
||||
|
||||
#endif
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
class FTTYStartupScreen : public FStartupScreen
|
||||
{
|
||||
public:
|
||||
FTTYStartupScreen(int max_progress);
|
||||
~FTTYStartupScreen();
|
||||
|
||||
void Progress();
|
||||
void NetInit(const char *message, int num_players);
|
||||
void NetProgress(int count);
|
||||
void NetMessage(const char *format, ...); // cover for printf
|
||||
void NetDone();
|
||||
bool NetLoop(bool (*timer_callback)(void *), void *userdata);
|
||||
protected:
|
||||
bool DidNetInit;
|
||||
int NetMaxPos, NetCurPos;
|
||||
const char *TheNetMessage;
|
||||
termios OldTermIOS;
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
FStartupScreen *StartScreen;
|
||||
|
||||
CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0) self = 0;
|
||||
else if (self > 2) self=2;
|
||||
}
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' };
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FStartupScreen :: CreateInstance
|
||||
//
|
||||
// Initializes the startup screen for the detected game.
|
||||
// Sets the size of the progress bar and displays the startup screen.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FStartupScreen *FStartupScreen::CreateInstance(int max_progress)
|
||||
{
|
||||
return new FTTYStartupScreen(max_progress);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen Constructor
|
||||
//
|
||||
// Sets the size of the progress bar and displays the startup screen.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FTTYStartupScreen::FTTYStartupScreen(int max_progress)
|
||||
: FStartupScreen(max_progress)
|
||||
{
|
||||
DidNetInit = false;
|
||||
NetMaxPos = 0;
|
||||
NetCurPos = 0;
|
||||
TheNetMessage = NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen Destructor
|
||||
//
|
||||
// Called just before entering graphics mode to deconstruct the startup
|
||||
// screen.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FTTYStartupScreen::~FTTYStartupScreen()
|
||||
{
|
||||
NetDone(); // Just in case it wasn't called yet and needs to be.
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: Progress
|
||||
//
|
||||
// If there was a progress bar, this would move it. But the basic TTY
|
||||
// startup screen doesn't have one, so this function does nothing.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTTYStartupScreen::Progress()
|
||||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: NetInit
|
||||
//
|
||||
// Sets stdin for unbuffered I/O, displays the given message, and shows
|
||||
// a progress meter.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTTYStartupScreen::NetInit(const char *message, int numplayers)
|
||||
{
|
||||
if (!DidNetInit)
|
||||
{
|
||||
termios rawtermios;
|
||||
|
||||
fprintf (stderr, "Press 'Q' to abort network game synchronization.");
|
||||
// Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort()
|
||||
// immediately without waiting for an EOL.
|
||||
tcgetattr (STDIN_FILENO, &OldTermIOS);
|
||||
rawtermios = OldTermIOS;
|
||||
rawtermios.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios);
|
||||
DidNetInit = true;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
openConsoleBox( "Network synchronization" );
|
||||
#endif
|
||||
}
|
||||
if (numplayers == 1)
|
||||
{
|
||||
// Status message without any real progress info.
|
||||
fprintf (stderr, "\n%s.", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "\n%s: ", message);
|
||||
}
|
||||
fflush (stderr);
|
||||
TheNetMessage = message;
|
||||
NetMaxPos = numplayers;
|
||||
NetCurPos = 0;
|
||||
NetProgress(1); // You always know about yourself
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: NetDone
|
||||
//
|
||||
// Restores the old stdin tty settings.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTTYStartupScreen::NetDone()
|
||||
{
|
||||
// Restore stdin settings
|
||||
if (DidNetInit)
|
||||
{
|
||||
tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS);
|
||||
printf ("\n");
|
||||
DidNetInit = false;
|
||||
#ifdef __ANDROID__
|
||||
closeConsoleBox();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: NetMessage
|
||||
//
|
||||
// Call this between NetInit() and NetDone() instead of Printf() to
|
||||
// display messages, because the progress meter is mixed in the same output
|
||||
// stream as normal messages.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTTYStartupScreen::NetMessage(const char *format, ...)
|
||||
{
|
||||
FString str;
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr, format);
|
||||
str.VFormat (format, argptr);
|
||||
va_end (argptr);
|
||||
fprintf (stderr, "\r%-40s\n", str.GetChars());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: NetProgress
|
||||
//
|
||||
// Sets the network progress meter. If count is 0, it gets bumped by 1.
|
||||
// Otherwise, it is set to count.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FTTYStartupScreen::NetProgress(int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
NetCurPos++;
|
||||
}
|
||||
else if (count > 0)
|
||||
{
|
||||
NetCurPos = count;
|
||||
}
|
||||
if (NetMaxPos == 0)
|
||||
{
|
||||
// Spinny-type progress meter, because we're a guest waiting for the host.
|
||||
fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]);
|
||||
fflush (stderr);
|
||||
}
|
||||
else if (NetMaxPos > 1)
|
||||
{
|
||||
// Dotty-type progress meter.
|
||||
fprintf (stderr, "\r%s: ", TheNetMessage);
|
||||
for (i = 0; i < NetCurPos; ++i)
|
||||
{
|
||||
fputc ('.', stderr);
|
||||
}
|
||||
fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTTYStartupScreen :: NetLoop
|
||||
//
|
||||
// The timer_callback function is called at least two times per second
|
||||
// and passed the userdata value. It should return true to stop the loop and
|
||||
// return control to the caller or false to continue the loop.
|
||||
//
|
||||
// ST_NetLoop will return true if the loop was halted by the callback and
|
||||
// false if the loop was halted because the user wants to abort the
|
||||
// network synchronization.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata)
|
||||
{
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
int retval;
|
||||
char k;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Don't flood the network with packets on startup.
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 500000;
|
||||
|
||||
FD_ZERO (&rfds);
|
||||
FD_SET (STDIN_FILENO, &rfds);
|
||||
|
||||
retval = select (1, &rfds, NULL, NULL, &tv);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
usleep(1000*200);
|
||||
//The select command is to wait for the console input to be ready, obv don't need this on droid
|
||||
retval = 0;
|
||||
|
||||
if( getConsoleBoxCanceled() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (retval == -1)
|
||||
{
|
||||
// Error
|
||||
}
|
||||
else if (retval == 0)
|
||||
{
|
||||
if (timer_callback (userdata))
|
||||
{
|
||||
fputc ('\n', stderr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (read (STDIN_FILENO, &k, 1) == 1)
|
||||
{
|
||||
// Check input on stdin
|
||||
if (k == 'q' || k == 'Q')
|
||||
{
|
||||
fprintf (stderr, "\nNetwork game synchronization aborted.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ST_Endoom()
|
||||
{
|
||||
throw CExitEvent(0);
|
||||
}
|
|
@ -79,7 +79,7 @@ const char *GetVersionString();
|
|||
#define SAVEGAME_EXT "zds"
|
||||
|
||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||
#define MINSAVEVER 4555
|
||||
#define MINSAVEVER 4555
|
||||
|
||||
// Use 4500 as the base git save version, since it's higher than the
|
||||
// SVN revision ever got.
|
||||
|
@ -98,7 +98,10 @@ const char *GetVersionString();
|
|||
|
||||
// More stuff that needs to be different for derivatives.
|
||||
#define GAMENAME "QZDoom"
|
||||
#define WGAMENAME L"QZDoom"
|
||||
#define GAMENAMELOWERCASE "qzdoom"
|
||||
#define FORUM_URL "http://forum.zdoom.org/"
|
||||
#define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=2"
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
#define GAME_DIR GAMENAME
|
||||
|
|
|
@ -2829,6 +2829,10 @@ void D3DFB::DrawTextureParms (FTexture *img, DrawParms &parms)
|
|||
{
|
||||
swapvalues(u0, u1);
|
||||
}
|
||||
if (parms.flipY)
|
||||
{
|
||||
swapvalues(v0, v1);
|
||||
}
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
double wi = MIN(parms.windowright, parms.texwidth);
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
#include "cmdlib.h"
|
||||
#include "v_text.h"
|
||||
#include "m_argv.h"
|
||||
#include "rawinput.h"
|
||||
|
||||
#define SAFE_RELEASE(x) { if (x != NULL) { x->Release(); x = NULL; } }
|
||||
|
||||
|
@ -263,8 +262,6 @@ protected:
|
|||
static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
|
||||
static int NameSort(const void *a, const void *b);
|
||||
static bool IsXInputDevice(const GUID *guid);
|
||||
static bool IsXInputDeviceFast(const GUID *guid);
|
||||
static bool IsXInputDeviceSlow(const GUID *guid);
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -1208,140 +1205,6 @@ BOOL CALLBACK FDInputJoystickManager::EnumCallback(LPCDIDEVICEINSTANCE lpddi, LP
|
|||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystickManager :: IsXInputDevice STATIC
|
||||
//
|
||||
// Does the DirectInput product GUID correspond to an XInput controller?
|
||||
|
||||
// If the product's device ID contains contains "IG_"
|
||||
// (ex. "VID_045E&PID_028E&IG_00"), then it is an XInput device.
|
||||
// Unfortunately this information can not be found by just using DirectInput.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDInputJoystickManager::IsXInputDevice(const GUID *guid)
|
||||
{
|
||||
if (MyGetRawInputDeviceList == NULL || MyGetRawInputDeviceInfoA == NULL)
|
||||
{
|
||||
return IsXInputDeviceSlow(guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsXInputDeviceFast(guid);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystickManager :: IsXInputDeviceSlow STATIC
|
||||
//
|
||||
// Pretty much copied straight from the article "XInput and DirectInput".
|
||||
//
|
||||
// Enum each PNP device using WMI and check each device ID. This is
|
||||
// Microsoft's reference implementation, but it is damn slow. After
|
||||
// a hardware change, connecting to the WMI server can take nearly three
|
||||
// seconds, and creating the instance enumerator consistantly takes longer
|
||||
// than 0.25 seconds.
|
||||
//
|
||||
// The XInput DLL can apparently be hacked fairly simply to work with
|
||||
// Windows 2000, and since Raw Input wasn't introduced until XP, I think
|
||||
// that's reason enough to keep this version around, despite it being
|
||||
// so horrendously slow.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDInputJoystickManager::IsXInputDeviceSlow(const GUID *guid)
|
||||
{
|
||||
IWbemLocator *wbemlocator = NULL;
|
||||
IEnumWbemClassObject *enumdevices = NULL;
|
||||
IWbemClassObject *devices[20] = { 0 };
|
||||
IWbemServices *wbemservices = NULL;
|
||||
BSTR namespce = NULL;
|
||||
BSTR deviceid = NULL;
|
||||
BSTR classname = NULL;
|
||||
DWORD returned = 0;
|
||||
bool isxinput = false;
|
||||
UINT device = 0;
|
||||
VARIANT var;
|
||||
HRESULT hr;
|
||||
|
||||
// Create WMI
|
||||
hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemlocator);
|
||||
if (FAILED(hr) || wbemlocator == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (NULL == (namespce = SysAllocString(OLESTR("\\\\.\\root\\cimv2")))) goto cleanup;
|
||||
if (NULL == (classname = SysAllocString(OLESTR("Win32_PNPEntity")))) goto cleanup;
|
||||
if (NULL == (deviceid = SysAllocString(OLESTR("DeviceID")))) goto cleanup;
|
||||
|
||||
// Connect to WMI
|
||||
hr = wbemlocator->ConnectServer(namespce, NULL, NULL, 0, 0, NULL, NULL, &wbemservices);
|
||||
if (FAILED(hr) || wbemservices == NULL)
|
||||
goto cleanup;
|
||||
|
||||
// Switch security level to IMPERSONATE.
|
||||
CoSetProxyBlanket(wbemservices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
|
||||
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
|
||||
hr = wbemservices->CreateInstanceEnum(classname, 0, NULL, &enumdevices);
|
||||
if (FAILED(hr) || enumdevices == NULL)
|
||||
goto cleanup;
|
||||
|
||||
// Loop over all devices
|
||||
for (;;)
|
||||
{
|
||||
// Get 20 at a time.
|
||||
hr = enumdevices->Next(10000, countof(devices), devices, &returned);
|
||||
if (FAILED(hr))
|
||||
goto cleanup;
|
||||
if (returned == 0)
|
||||
break;
|
||||
|
||||
for (device = 0; device < returned; device++)
|
||||
{
|
||||
// For each device, get its device ID.
|
||||
hr = devices[device]->Get(deviceid, 0L, &var, NULL, NULL);
|
||||
if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL)
|
||||
{
|
||||
// Check if the device ID contains "IG_". If it does, then it's an XInput device.
|
||||
// This information cannot be found from DirectInput.
|
||||
if (wcsstr(var.bstrVal, L"IG_"))
|
||||
{
|
||||
// If it does, then get the VID/PID from var.bstrVal.
|
||||
DWORD pid = 0, vid = 0;
|
||||
WCHAR *strvid = wcsstr(var.bstrVal, L"VID_");
|
||||
if (strvid && swscanf(strvid, L"VID_%4X", &vid) != 1)
|
||||
vid = 0;
|
||||
WCHAR *strpid = wcsstr(var.bstrVal, L"PID_");
|
||||
if (strpid && swscanf(strpid, L"PID_%4X", &pid) != 1)
|
||||
pid = 0;
|
||||
|
||||
// Compare the VID/PID to the DInput device.
|
||||
DWORD vidpid = MAKELONG(vid, pid);
|
||||
if (vidpid == guid->Data1)
|
||||
{
|
||||
isxinput = true;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
SAFE_RELEASE(devices[device]);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (namespce) SysFreeString(namespce);
|
||||
if (deviceid) SysFreeString(deviceid);
|
||||
if (classname) SysFreeString(classname);
|
||||
for (device = 0; device < countof(devices); ++device)
|
||||
SAFE_RELEASE(devices[device]);
|
||||
SAFE_RELEASE(enumdevices);
|
||||
SAFE_RELEASE(wbemlocator);
|
||||
SAFE_RELEASE(wbemservices);
|
||||
return isxinput;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystickManager :: IsXInputDeviceFast STATIC
|
||||
|
@ -1354,14 +1217,14 @@ cleanup:
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDInputJoystickManager::IsXInputDeviceFast(const GUID *guid)
|
||||
bool FDInputJoystickManager::IsXInputDevice(const GUID *guid)
|
||||
{
|
||||
UINT nDevices, numDevices;
|
||||
RAWINPUTDEVICELIST *devices;
|
||||
UINT i;
|
||||
bool isxinput = false;
|
||||
|
||||
if (MyGetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1369,7 +1232,7 @@ bool FDInputJoystickManager::IsXInputDeviceFast(const GUID *guid)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if ((numDevices = MyGetRawInputDeviceList(devices, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT)-1)
|
||||
if ((numDevices = GetRawInputDeviceList(devices, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT)-1)
|
||||
{
|
||||
free(devices);
|
||||
return false;
|
||||
|
@ -1385,7 +1248,7 @@ bool FDInputJoystickManager::IsXInputDeviceFast(const GUID *guid)
|
|||
UINT cbSize;
|
||||
|
||||
cbSize = rdi.cbSize = sizeof(rdi);
|
||||
if ((INT)MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) >= 0)
|
||||
if ((INT)GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) >= 0)
|
||||
{
|
||||
if(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)guid->Data1)
|
||||
{
|
||||
|
@ -1393,7 +1256,7 @@ bool FDInputJoystickManager::IsXInputDeviceFast(const GUID *guid)
|
|||
UINT namelen = countof(name);
|
||||
UINT reslen;
|
||||
|
||||
reslen = MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, name, &namelen);
|
||||
reslen = GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, name, &namelen);
|
||||
if (reslen != (UINT)-1)
|
||||
{
|
||||
isxinput = (strstr(name, "IG_") != NULL);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#ifndef __GNUC__
|
||||
#define INITGUID
|
||||
#endif
|
||||
#define DIRECTINPUT_VERSION 0x800
|
||||
#include <windows.h>
|
||||
#include <dbt.h>
|
||||
#include <dinput.h>
|
||||
|
@ -91,13 +92,6 @@
|
|||
#include "events.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
// Prototypes and declarations.
|
||||
#include "rawinput.h"
|
||||
// Definitions
|
||||
#define RIF(name, ret, args) \
|
||||
name##Proto My##name;
|
||||
#include "rawinput.h"
|
||||
|
||||
|
||||
// Compensate for w32api's lack
|
||||
#ifndef GET_XBUTTON_WPARAM
|
||||
|
@ -112,7 +106,6 @@
|
|||
#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS
|
||||
#endif
|
||||
|
||||
static void FindRawInputFunctions();
|
||||
FJoystickCollection *JoyDevices[NUM_JOYDEVICES];
|
||||
|
||||
|
||||
|
@ -152,11 +145,6 @@ int BlockMouseMove;
|
|||
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR(Bool, norawinput, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
|
||||
extern int chatmodeon;
|
||||
|
||||
static void I_CheckGUICapture ()
|
||||
|
@ -378,25 +366,22 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
if (message == WM_INPUT)
|
||||
{
|
||||
if (MyGetRawInputData != NULL)
|
||||
{
|
||||
UINT size;
|
||||
UINT size;
|
||||
|
||||
if (!MyGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) &&
|
||||
size != 0)
|
||||
if (!GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) &&
|
||||
size != 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)alloca(size);
|
||||
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)) == size)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)alloca(size);
|
||||
if (MyGetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)) == size)
|
||||
int code = GET_RAWINPUT_CODE_WPARAM(wParam);
|
||||
if (Keyboard == NULL || !Keyboard->ProcessRawInput((RAWINPUT *)buffer, code))
|
||||
{
|
||||
int code = GET_RAWINPUT_CODE_WPARAM(wParam);
|
||||
if (Keyboard == NULL || !Keyboard->ProcessRawInput((RAWINPUT *)buffer, code))
|
||||
if (Mouse == NULL || !Mouse->ProcessRawInput((RAWINPUT *)buffer, code))
|
||||
{
|
||||
if (Mouse == NULL || !Mouse->ProcessRawInput((RAWINPUT *)buffer, code))
|
||||
if (JoyDevices[INPUT_RawPS2] != NULL)
|
||||
{
|
||||
if (JoyDevices[INPUT_RawPS2] != NULL)
|
||||
{
|
||||
JoyDevices[INPUT_RawPS2]->ProcessRawInput((RAWINPUT *)buffer, code);
|
||||
}
|
||||
JoyDevices[INPUT_RawPS2]->ProcessRawInput((RAWINPUT *)buffer, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -651,8 +636,6 @@ bool I_InitInput (void *hwnd)
|
|||
g_pdi = NULL;
|
||||
g_pdi3 = NULL;
|
||||
|
||||
FindRawInputFunctions();
|
||||
|
||||
// Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit.
|
||||
DInputDLL = LoadLibraryA("dinput8.dll");
|
||||
if (DInputDLL != NULL)
|
||||
|
@ -966,26 +949,3 @@ bool FInputDevice::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
|
|||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FindRawInputFunctions
|
||||
//
|
||||
// Finds functions for raw input, if available.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void FindRawInputFunctions()
|
||||
{
|
||||
if (!norawinput)
|
||||
{
|
||||
HMODULE user32 = GetModuleHandleA("user32.dll");
|
||||
|
||||
if (user32 == NULL)
|
||||
{
|
||||
return; // WTF kind of broken system are we running on?
|
||||
}
|
||||
#define RIF(name,ret,args) \
|
||||
My##name = (name##Proto)GetProcAddress(user32, #name);
|
||||
#include "rawinput.h"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,12 +42,8 @@
|
|||
#include "i_input.h"
|
||||
#include "i_system.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "c_cvars.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "win32iface.h"
|
||||
#include "rawinput.h"
|
||||
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -430,15 +426,12 @@ FRawKeyboard::FRawKeyboard()
|
|||
|
||||
FRawKeyboard::~FRawKeyboard()
|
||||
{
|
||||
if (MyRegisterRawInputDevices != NULL)
|
||||
{
|
||||
RAWINPUTDEVICE rid;
|
||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||
rid.usUsage = HID_GDP_KEYBOARD;
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL;
|
||||
MyRegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
}
|
||||
RAWINPUTDEVICE rid;
|
||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||
rid.usUsage = HID_GDP_KEYBOARD;
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL;
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -453,15 +446,11 @@ bool FRawKeyboard::GetDevice()
|
|||
{
|
||||
RAWINPUTDEVICE rid;
|
||||
|
||||
if (MyRegisterRawInputDevices == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||
rid.usUsage = HID_GDP_KEYBOARD;
|
||||
rid.dwFlags = RIDEV_INPUTSINK;
|
||||
rid.hwndTarget = Window;
|
||||
if (!MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,11 +43,8 @@
|
|||
#include "i_system.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "c_cvars.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "win32iface.h"
|
||||
#include "rawinput.h"
|
||||
#include "menu/menu.h"
|
||||
#include "events.h"
|
||||
|
||||
|
@ -550,21 +547,17 @@ bool FRawMouse::GetDevice()
|
|||
{
|
||||
RAWINPUTDEVICE rid;
|
||||
|
||||
if (MyRegisterRawInputDevices == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||
rid.usUsage = HID_GDP_MOUSE;
|
||||
rid.dwFlags = 0;
|
||||
rid.hwndTarget = Window;
|
||||
if (!MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL; // Must be NULL for RIDEV_REMOVE.
|
||||
MyRegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -584,7 +577,7 @@ void FRawMouse::Grab()
|
|||
rid.usUsage = HID_GDP_MOUSE;
|
||||
rid.dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY;
|
||||
rid.hwndTarget = Window;
|
||||
if (MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
GetCursorPos(&UngrabbedPointerPos);
|
||||
Grabbed = true;
|
||||
|
@ -613,7 +606,7 @@ void FRawMouse::Ungrab()
|
|||
rid.usUsage = HID_GDP_MOUSE;
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL;
|
||||
if (MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
Grabbed = false;
|
||||
ClearButtonState();
|
||||
|
@ -1189,18 +1182,6 @@ void I_StartupMouse ()
|
|||
|
||||
switch(in_mouse)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
if (MyRegisterRawInputDevices != NULL)
|
||||
{
|
||||
new_mousemode = MM_RawInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_mousemode = MM_DInput;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new_mousemode = MM_Win32;
|
||||
break;
|
||||
|
@ -1209,6 +1190,7 @@ void I_StartupMouse ()
|
|||
new_mousemode = MM_DInput;
|
||||
break;
|
||||
|
||||
default:
|
||||
case 3:
|
||||
new_mousemode = MM_RawInput;
|
||||
break;
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#include "cmdlib.h"
|
||||
#include "v_text.h"
|
||||
#include "m_argv.h"
|
||||
#include "rawinput.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -913,23 +912,17 @@ bool FRawPS2Manager::GetDevice()
|
|||
{
|
||||
RAWINPUTDEVICE rid;
|
||||
|
||||
if (MyRegisterRawInputDevices == NULL ||
|
||||
MyGetRawInputDeviceList == NULL ||
|
||||
MyGetRawInputDeviceInfoA == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE;
|
||||
rid.usUsage = HID_GDP_JOYSTICK;
|
||||
rid.dwFlags = RIDEV_INPUTSINK;
|
||||
rid.hwndTarget = Window;
|
||||
if (!MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL; // Must be NULL for RIDEV_REMOVE.
|
||||
MyRegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
EnumDevices();
|
||||
return true;
|
||||
}
|
||||
|
@ -1025,7 +1018,7 @@ FRawPS2Controller *FRawPS2Manager::EnumDevices()
|
|||
RAWINPUTDEVICELIST *devices;
|
||||
UINT i, j;
|
||||
|
||||
if (MyGetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1033,7 +1026,7 @@ FRawPS2Controller *FRawPS2Manager::EnumDevices()
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
if ((numDevices = MyGetRawInputDeviceList(devices, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT)-1)
|
||||
if ((numDevices = GetRawInputDeviceList(devices, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT)-1)
|
||||
{
|
||||
free(devices);
|
||||
return NULL;
|
||||
|
@ -1049,7 +1042,7 @@ FRawPS2Controller *FRawPS2Manager::EnumDevices()
|
|||
UINT cbSize;
|
||||
|
||||
cbSize = rdi.cbSize = sizeof(rdi);
|
||||
if ((INT)MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) >= 0)
|
||||
if ((INT)GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) >= 0)
|
||||
{
|
||||
// All the PS2 adapters report themselves as joysticks.
|
||||
// (By comparison, the 360 controller reports itself as a gamepad.)
|
||||
|
@ -1092,41 +1085,41 @@ FRawPS2Controller *FRawPS2Manager::EnumDevices()
|
|||
// <Enumerator>#<Device ID>#<Device Interface Class GUID>
|
||||
// The Device ID has multiple #-seperated parts and uniquely identifies
|
||||
// this device and which USB port it is connected to.
|
||||
char name[256];
|
||||
wchar_t name[256];
|
||||
UINT namelen = countof(name);
|
||||
char *devid, *devidend;
|
||||
wchar_t *devid, *devidend;
|
||||
|
||||
if (MyGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, name, &namelen) == (UINT)-1)
|
||||
if (GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, name, &namelen) == (UINT)-1)
|
||||
{ // Can't get name. Skip it, since there's stuff in there we need for config.
|
||||
continue;
|
||||
}
|
||||
|
||||
devid = strchr(name, '#');
|
||||
devid = wcschr(name, '#');
|
||||
if (devid == NULL)
|
||||
{ // Should not happen
|
||||
continue;
|
||||
}
|
||||
devidend = strrchr(++devid, '#');
|
||||
devidend = wcsrchr(++devid, '#');
|
||||
if (devidend != NULL)
|
||||
{
|
||||
*devidend = '\0';
|
||||
}
|
||||
|
||||
FAdapterHandle handle = { devices[i].hDevice, type, 0, devid };
|
||||
FAdapterHandle handle = { devices[i].hDevice, type, 0, FString(devid) };
|
||||
|
||||
// Adapters that support more than one controller have a seperate device
|
||||
// entry for each controller. We can examine the name to determine which
|
||||
// controller this device is for.
|
||||
if (Descriptors[type].ControllerNumber >= 0)
|
||||
{
|
||||
char *col = strstr(devid, "&Col");
|
||||
wchar_t *col = wcsstr(devid, L"&Col");
|
||||
if (col != NULL)
|
||||
{
|
||||
// I have no idea if this number is base 16 or base 10. Every
|
||||
// other number in the name is base 16, so I assume this one is
|
||||
// too, but since I don't have anything that goes higher than 02,
|
||||
// I can't be sure.
|
||||
handle.ControllerNumber = strtoul(col + 4, NULL, 16);
|
||||
handle.ControllerNumber = wcstoul(col + 4, NULL, 16);
|
||||
}
|
||||
}
|
||||
adapters.Push(handle);
|
||||
|
@ -1279,7 +1272,7 @@ void FRawPS2Manager::DoRegister()
|
|||
{
|
||||
rid.dwFlags = RIDEV_REMOVE;
|
||||
rid.hwndTarget = NULL;
|
||||
if (MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
Registered = false;
|
||||
}
|
||||
|
@ -1291,7 +1284,7 @@ void FRawPS2Manager::DoRegister()
|
|||
{
|
||||
rid.dwFlags = RIDEV_INPUTSINK;
|
||||
rid.hwndTarget = Window;
|
||||
if (MyRegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)))
|
||||
{
|
||||
Registered = true;
|
||||
}
|
||||
|
|
|
@ -869,7 +869,8 @@ bool Win32GLVideo::SetupPixelFormat(int multisample)
|
|||
if (pfd.dwFlags & PFD_GENERIC_FORMAT)
|
||||
{
|
||||
vid_renderer = 0;
|
||||
I_Error("R_OPENGL: OpenGL driver not accelerated! Falling back to software renderer.\n");
|
||||
I_Error("R_OPENGL: OpenGL driver not accelerated! Falling back to software renderer. Get a driver from your manufacturer.\n"
|
||||
"For some Intel cards run " GAMENAME " in Windows 8 compatibility mode or use the wtfi tool.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
add_subdirectory( lemon )
|
||||
add_subdirectory( re2c )
|
||||
if( WIN32 AND NOT CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
||||
add_subdirectory( fixrtext )
|
||||
endif()
|
||||
add_subdirectory( updaterevision )
|
||||
add_subdirectory( lemon )
|
||||
add_subdirectory( zipdir )
|
||||
|
||||
set( CROSS_EXPORTS ${CROSS_EXPORTS} PARENT_SCOPE )
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
if( WIN32 )
|
||||
if( MSVC_VERSION GREATER 1399 )
|
||||
# VC 8+ adds a manifest automatically to the executable. We need to
|
||||
# merge ours with it.
|
||||
set( MT_MERGE ON )
|
||||
else()
|
||||
set( TRUSTINFO trustinfo.rc )
|
||||
endif()
|
||||
else( WIN32 )
|
||||
set( TRUSTINFO "" )
|
||||
endif()
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
add_executable( updaterevision updaterevision.c ${TRUSTINFO} )
|
||||
set( CROSS_EXPORTS ${CROSS_EXPORTS} updaterevision PARENT_SCOPE )
|
||||
endif()
|
||||
|
||||
if( MT_MERGE )
|
||||
add_custom_command(TARGET updaterevision POST_BUILD
|
||||
COMMAND mt -inputresource:$<TARGET_FILE:updaterevision> -manifest ${CMAKE_CURRENT_SOURCE_DIR}/trustinfo.txt -outputresource:$<TARGET_FILE:updaterevision> -nologo
|
||||
COMMENT "Embedding trustinfo into updaterevision" )
|
||||
endif()
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/cmake -P
|
||||
|
||||
# UpdateRevision.cmake
|
||||
#
|
||||
# Public domain. This program uses git commands command to get
|
||||
# various bits of repository status for a particular directory
|
||||
# and writes it into a header file so that it can be used for a
|
||||
# project's versioning.
|
||||
|
||||
# Boilerplate to return a variable from a function.
|
||||
macro(ret_var VAR)
|
||||
set(${VAR} "${${VAR}}" PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
# Populate variables "Hash", "Tag", and "Timestamp" with relevant information
|
||||
# from source repository. If anything goes wrong return something in "Error."
|
||||
function(query_repo_info)
|
||||
execute_process(
|
||||
COMMAND git describe --tags --dirty=-m
|
||||
RESULT_VARIABLE Error
|
||||
OUTPUT_VARIABLE Tag
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT "${Error}" STREQUAL "0")
|
||||
ret_var(Error)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND git log -1 "--format=%ai;%H"
|
||||
RESULT_VARIABLE Error
|
||||
OUTPUT_VARIABLE CommitInfo
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT "${Error}" STREQUAL "0")
|
||||
ret_var(Error)
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(GET CommitInfo 0 Timestamp)
|
||||
list(GET CommitInfo 1 Hash)
|
||||
|
||||
ret_var(Tag)
|
||||
ret_var(Timestamp)
|
||||
ret_var(Hash)
|
||||
endfunction()
|
||||
|
||||
# Although configure_file doesn't overwrite the file if the contents are the
|
||||
# same we can't easily observe that to change the status message. This
|
||||
# function parses the existing file (if it exists) and puts the hash in
|
||||
# variable "OldHash"
|
||||
function(get_existing_hash File)
|
||||
if(EXISTS "${File}")
|
||||
file(STRINGS "${File}" OldHash LIMIT_COUNT 1)
|
||||
if(OldHash)
|
||||
string(SUBSTRING "${OldHash}" 3 -1 OldHash)
|
||||
ret_var(OldHash)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(main)
|
||||
if(NOT CMAKE_ARGC EQUAL 4) # cmake -P UpdateRevision.cmake <OutputFile>
|
||||
message("Usage: ${CMAKE_ARGV2} <path to gitinfo.h>")
|
||||
return()
|
||||
endif()
|
||||
set(OutputFile "${CMAKE_ARGV3}")
|
||||
|
||||
get_filename_component(ScriptDir "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY)
|
||||
|
||||
query_repo_info()
|
||||
if(NOT Hash)
|
||||
message("Failed to get commit info: ${Error}")
|
||||
set(Hash "0")
|
||||
set(Tag "<unknown version>")
|
||||
set(Timestamp "")
|
||||
endif()
|
||||
|
||||
get_existing_hash("${OutputFile}")
|
||||
if(Hash STREQUAL OldHash)
|
||||
message("${OutputFile} is up to date at commit ${Tag}.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
configure_file("${ScriptDir}/gitinfo.h.in" "${OutputFile}")
|
||||
message("${OutputFile} updated to commit ${Tag}.")
|
||||
endfunction()
|
||||
|
||||
main()
|
|
@ -0,0 +1,8 @@
|
|||
// @Hash@
|
||||
//
|
||||
// This file was automatically generated by the
|
||||
// updaterevision tool. Do not edit by hand.
|
||||
|
||||
#define GIT_DESCRIPTION "@Tag@"
|
||||
#define GIT_HASH "@Hash@"
|
||||
#define GIT_TIME "@Timestamp@"
|
|
@ -1,6 +0,0 @@
|
|||
// This resource script is for compiling with MinGW only. Visual C++
|
||||
// compilations use the manifest tool to insert the manifest instead.
|
||||
|
||||
#include <WinUser.h>
|
||||
|
||||
1 RT_MANIFEST "trustinfo.txt"
|
|
@ -1,16 +0,0 @@
|
|||
<!-- Ignore any warnings about Unrecognized Element "trustInfo" -->
|
||||
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0"
|
||||
processorArchitecture="X86"
|
||||
name="UpdateRevision"
|
||||
type="win32" />
|
||||
<description>Update svnrevision.h for the ZDoom source build process.</description>
|
||||
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<ms_asmv3:security>
|
||||
<ms_asmv3:requestedPrivileges>
|
||||
<ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</ms_asmv3:requestedPrivileges>
|
||||
</ms_asmv3:security>
|
||||
</ms_asmv3:trustInfo>
|
||||
</assembly>
|
|
@ -0,0 +1,3 @@
|
|||
/* Default keybindings for Hexen */
|
||||
|
||||
/ +jump
|
|
@ -1,6 +1,5 @@
|
|||
/* Default keybindings for Hexen */
|
||||
|
||||
/ +jump
|
||||
backspace invuseall
|
||||
\ "use ArtiHealth"
|
||||
0 useflechette
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Default keybindings for Strife */
|
||||
|
||||
w "showpop 1"
|
||||
u "showpop 2"
|
||||
s "showpop 2"
|
||||
|
||||
|
|
Binary file not shown.
|
@ -74,8 +74,8 @@ extend class StateProvider
|
|||
if (psp)
|
||||
{
|
||||
State cur = psp.CurState;
|
||||
int theflash = atk == cur? 0:1;
|
||||
player.SetSafeFlash(weap, flash, theflash);
|
||||
int theflash = atk == cur? 0:1;
|
||||
player.SetSafeFlash(weap, flash, theflash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,11 +366,11 @@ class Weapon : StateProvider
|
|||
let pspr = player.GetPSprite(PSP_WEAPON);
|
||||
if (pspr)
|
||||
{
|
||||
pspr.x = 0;
|
||||
pspr.y = WEAPONTOP;
|
||||
pspr.x = 0;
|
||||
pspr.y = WEAPONTOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int GetButtonStateFlags(int flags)
|
||||
{
|
||||
|
@ -877,9 +877,9 @@ class Weapon : StateProvider
|
|||
let pspr = p.GetPSprite(PSP_WEAPON);
|
||||
if (pspr)
|
||||
{
|
||||
pspr.y = WEAPONBOTTOM;
|
||||
pspr.ResetInterpolation();
|
||||
pspr.SetState(GetUpState());
|
||||
pspr.y = WEAPONBOTTOM;
|
||||
pspr.ResetInterpolation();
|
||||
pspr.SetState(GetUpState());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,22 +123,22 @@ class StrifePlayer : PlayerPawn
|
|||
|
||||
if (psp)
|
||||
{
|
||||
if (psp.CurState != null && firehandslower != null && firehands != null)
|
||||
{
|
||||
// Calculate state to go to.
|
||||
int dist = firehands.DistanceTo(psp.curState);
|
||||
if (dist > 0)
|
||||
if (psp.CurState != null && firehandslower != null && firehands != null)
|
||||
{
|
||||
player.playerstate = PST_DEAD;
|
||||
psp.SetState(firehandslower + dist);
|
||||
return;
|
||||
// Calculate state to go to.
|
||||
int dist = firehands.DistanceTo(psp.curState);
|
||||
if (dist > 0)
|
||||
{
|
||||
player.playerstate = PST_DEAD;
|
||||
psp.SetState(firehandslower + dist);
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.playerstate = PST_DEAD;
|
||||
psp.SetState(null);
|
||||
}
|
||||
player.playerstate = PST_DEAD;
|
||||
psp.SetState(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void A_HandLower()
|
||||
{
|
||||
|
@ -147,17 +147,17 @@ class StrifePlayer : PlayerPawn
|
|||
PSprite psp = player.GetPSprite(PSP_STRIFEHANDS);
|
||||
if (psp)
|
||||
{
|
||||
if (psp.CurState == null)
|
||||
{
|
||||
psp.SetState(null);
|
||||
return;
|
||||
}
|
||||
|
||||
psp.y += 9;
|
||||
if (psp.y > WEAPONBOTTOM*2)
|
||||
{
|
||||
psp.SetState(null);
|
||||
}
|
||||
if (psp.CurState == null)
|
||||
{
|
||||
psp.SetState(null);
|
||||
return;
|
||||
}
|
||||
|
||||
psp.y += 9;
|
||||
if (psp.y > WEAPONBOTTOM*2)
|
||||
{
|
||||
psp.SetState(null);
|
||||
}
|
||||
}
|
||||
if (player.extralight > 0) player.extralight--;
|
||||
}
|
||||
|
|
|
@ -139,8 +139,8 @@ class Mauler2 : Mauler
|
|||
PSprite psp = player.GetPSprite(PSP_WEAPON);
|
||||
if (psp)
|
||||
{
|
||||
psp.x += Random2[Mauler2]() / 64.;
|
||||
psp.y += Random2[Mauler2]() / 64.;
|
||||
psp.x += Random2[Mauler2]() / 64.;
|
||||
psp.y += Random2[Mauler2]() / 64.;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,9 +202,9 @@ struct InputEvent native play version("2.4")
|
|||
Key_Mouse8 = 0x107,
|
||||
|
||||
Key_FirstJoyButton = 0x108,
|
||||
Key_FirstJoy2Button = 0x128,
|
||||
Key_FirstJoy3Button = 0x148,
|
||||
Key_FirstJoy4Button = 0x168,
|
||||
Key_FirstJoy2Button = 0x128,
|
||||
Key_FirstJoy3Button = 0x148,
|
||||
Key_FirstJoy4Button = 0x168,
|
||||
Key_Joy1 = (Key_FirstJoyButton+0),
|
||||
Key_Joy2 = (Key_FirstJoyButton+1),
|
||||
Key_Joy3 = (Key_FirstJoyButton+2),
|
||||
|
|
|
@ -148,7 +148,7 @@ class AltHud ui
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DrawHudNumber(Font fnt, int color, int num, int x, int y, double trans = 0.75)
|
||||
void DrawHudNumber(Font fnt, int color, int num, int x, int y, double trans = 0.75)
|
||||
{
|
||||
DrawHudText(fnt, color, String.Format("%d", num), x, y, trans);
|
||||
}
|
||||
|
@ -748,14 +748,14 @@ class AltHud ui
|
|||
|
||||
if (withmapname)
|
||||
{
|
||||
screen.DrawText(SmallFont, hudcolor_titl, hudwidth - 6 - SmallFont.StringWidth(level.MapName), ypos, level.MapName,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight);
|
||||
|
||||
screen.DrawText(SmallFont, hudcolor_titl, hudwidth - 6 - SmallFont.StringWidth(level.LevelName), ypos + h, level.LevelName,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight);
|
||||
screen.DrawText(SmallFont, hudcolor_titl, hudwidth - 6 - SmallFont.StringWidth(level.MapName), ypos, level.MapName,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight);
|
||||
|
||||
screen.DrawText(SmallFont, hudcolor_titl, hudwidth - 6 - SmallFont.StringWidth(level.LevelName), ypos + h, level.LevelName,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight);
|
||||
|
||||
ypos += 3 * h;
|
||||
}
|
||||
|
||||
|
|
|
@ -1130,7 +1130,7 @@ class BaseStatusBar native ui
|
|||
if (offtex.IsValid() && TexMan.GetScaledSize(offtex) == texsize) DrawTexture(offtex, position, flags | DI_ITEM_LEFT_TOP, alpha);
|
||||
else Fill(color(int(255*alpha),0,0,0), position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3]);
|
||||
|
||||
if (border == 0)
|
||||
if (border == 0)
|
||||
{
|
||||
SetClipRect(position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3], flags);
|
||||
DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP, alpha);
|
||||
|
|
Loading…
Reference in a new issue