Add initial files
This commit is contained in:
commit
90a2471d07
46 changed files with 51707 additions and 0 deletions
75
.gitignore
vendored
Normal file
75
.gitignore
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
build/
|
||||||
|
*build/
|
||||||
|
|
||||||
|
imgui.ini
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xccheckout
|
||||||
|
|
||||||
|
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
||||||
|
build/
|
||||||
|
DerivedData/
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
!default.pbxuser
|
||||||
|
*.mode1v3
|
||||||
|
!default.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
!default.mode2v3
|
||||||
|
*.perspectivev3
|
||||||
|
!default.perspectivev3
|
||||||
|
|
||||||
|
## Gcc Patch
|
||||||
|
/*.gcno
|
||||||
|
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
27
CMakeLists.txt
Normal file
27
CMakeLists.txt
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(chip8)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||||
|
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
add_subdirectory(extern)
|
||||||
|
|
||||||
|
add_library(chip8-shared
|
||||||
|
src/emu.hpp
|
||||||
|
src/emu.cpp)
|
||||||
|
target_include_directories(chip8-shared PUBLIC src)
|
||||||
|
set_target_properties(chip8-shared PROPERTIES CXX_STANDARD 17)
|
||||||
|
|
||||||
|
add_executable(chip8
|
||||||
|
src/main.cpp
|
||||||
|
src/compiler.hpp
|
||||||
|
src/compiler.cpp)
|
||||||
|
target_link_libraries(chip8 PRIVATE SDL2::Core chip8-shared imgui glad)
|
||||||
|
target_include_directories(chip8 PRIVATE src)
|
||||||
|
set_target_properties(chip8 PROPERTIES CXX_STANDARD 17)
|
||||||
|
|
||||||
|
add_executable(chip8-tests
|
||||||
|
tests/test.cpp)
|
||||||
|
target_link_libraries(chip8-tests PRIVATE chip8-shared doctest)
|
||||||
|
set_target_properties(chip8-tests PROPERTIES CXX_STANDARD 17)
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Joshua Goins
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
388
cmake/FindSDL2.cmake
Normal file
388
cmake/FindSDL2.cmake
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2
|
||||||
|
--------
|
||||||
|
|
||||||
|
Locate SDL2 library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' targets:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::Core
|
||||||
|
The SDL2 library, if found.
|
||||||
|
Libraries should link to SDL2::Core
|
||||||
|
|
||||||
|
SDL2::Main
|
||||||
|
The SDL2main library, if found.
|
||||||
|
Applications should link to SDL2::Main instead of SDL2::Core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_INCLUDE_DIRS, where to find SDL.h
|
||||||
|
SDL2_FOUND, if false, do not try to link to SDL2
|
||||||
|
SDL2MAIN_FOUND, if false, do not try to link to SDL2main
|
||||||
|
SDL2_VERSION_STRING, human-readable string containing the version of SDL2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_PATH
|
||||||
|
Set a custom SDL2 Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2 Library in default path.
|
||||||
|
If SDL2_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_INCLUDE_DIR
|
||||||
|
SDL2 headers path.
|
||||||
|
|
||||||
|
SDL2_LIBRARY
|
||||||
|
SDL2 Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
SDL2MAIN_LIBRAY
|
||||||
|
SDL2main Library (.a) path.
|
||||||
|
|
||||||
|
SDL2_BUILDING_LIBRARY
|
||||||
|
This flag is useful only when linking to SDL2_LIBRARIES insead of
|
||||||
|
SDL2::Main. It is required only when building a library that links to
|
||||||
|
SDL2_LIBRARIES, because only applications need main() (No need to also
|
||||||
|
link to SDL2main).
|
||||||
|
If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES
|
||||||
|
and no SDL2::Main target will be created.
|
||||||
|
|
||||||
|
|
||||||
|
Don't forget to include SDLmain.h and SDLmain.m in your project for the
|
||||||
|
OS X framework based version. (Other versions link to -lSDL2main which
|
||||||
|
this module will try to find on your behalf.) Also for OS X, this
|
||||||
|
module will automatically add the -framework Cocoa on your behalf.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2 library
|
||||||
|
(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point
|
||||||
|
to your SDL2 library, and configure again. Similarly, if you see an
|
||||||
|
empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These
|
||||||
|
values are used to generate the final SDL2_LIBRARIES variable and the
|
||||||
|
SDL2::Core and SDL2::Main targets, but when these values are unset,
|
||||||
|
SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Mark 'Threads' as a required dependency for non-OSX systems.
|
||||||
|
Modernize the FindSDL2.cmake module by creating specific targets:
|
||||||
|
SDL2::Core and SDL2::Main (for details, see doc above).
|
||||||
|
|
||||||
|
|
||||||
|
Original FindSDL.cmake module:
|
||||||
|
Modified by Eric Wing. Added code to assist with automated building
|
||||||
|
by using environmental variables and providing a more
|
||||||
|
controlled/consistent search behavior. Added new modifications to
|
||||||
|
recognize OS X frameworks and additional Unix paths (FreeBSD, etc).
|
||||||
|
Also corrected the header search path to follow "proper" SDL
|
||||||
|
guidelines. Added a search for SDLmain which is needed by some
|
||||||
|
platforms. Added a search for threads which is needed by some
|
||||||
|
platforms. Added needed compile switches for MinGW.
|
||||||
|
|
||||||
|
On OSX, this will prefer the Framework version (if found) over others.
|
||||||
|
People will have to manually change the cache value of SDL2_LIBRARY to
|
||||||
|
override this selection or set the SDL2_PATH variable or the CMake
|
||||||
|
environment CMAKE_INCLUDE_PATH to modify the search paths.
|
||||||
|
|
||||||
|
Note that the header path has changed from SDL/SDL.h to just SDL.h
|
||||||
|
This needed to change because "proper" SDL convention is #include
|
||||||
|
"SDL.h", not <SDL/SDL.h>. This is done for portability reasons
|
||||||
|
because not all systems place things in SDL/ (see FreeBSD).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# Define options for searching SDL2 Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path")
|
||||||
|
|
||||||
|
set(_SDL2_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_PATH)
|
||||||
|
set(_SDL2_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2 Library in default path")
|
||||||
|
unset(_SDL2_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2 include directory
|
||||||
|
find_path(SDL2_INCLUDE_DIR SDL.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_PATH}
|
||||||
|
DOC "Where the SDL2 headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# SDL-2.0 is the name used by FreeBSD ports...
|
||||||
|
# don't confuse it for the version number.
|
||||||
|
find_library(SDL2_LIBRARY
|
||||||
|
NAMES SDL2 SDL-2.0
|
||||||
|
HINTS
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_PATH}
|
||||||
|
DOC "Where the SDL2 Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SDL2_LIBRARIES "${SDL2_LIBRARY}")
|
||||||
|
|
||||||
|
if(NOT SDL2_BUILDING_LIBRARY)
|
||||||
|
if(NOT SDL2_INCLUDE_DIR MATCHES ".framework")
|
||||||
|
# Non-OS X framework versions expect you to also dynamically link to
|
||||||
|
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||||
|
# seem to provide SDL2main for compatibility even though they don't
|
||||||
|
# necessarily need it.
|
||||||
|
|
||||||
|
if(SDL2_PATH)
|
||||||
|
set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT SDL2_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2MAIN_LIBRARY_PATHS
|
||||||
|
/sw
|
||||||
|
/opt/local
|
||||||
|
/opt/csw
|
||||||
|
/opt
|
||||||
|
"${SDL2MAIN_LIBRARY_PATHS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_library(SDL2MAIN_LIBRARY
|
||||||
|
NAMES SDL2main
|
||||||
|
HINTS
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2MAIN_LIBRARY_PATHS}
|
||||||
|
DOC "Where the SDL2main library can be found"
|
||||||
|
)
|
||||||
|
unset(SDL2MAIN_LIBRARY_PATHS)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# SDL2 may require threads on your system.
|
||||||
|
# The Apple build may not need an explicit flag because one of the
|
||||||
|
# frameworks may already provide it.
|
||||||
|
# But for non-OSX systems, I will use the CMake Threads package.
|
||||||
|
if(NOT APPLE)
|
||||||
|
find_package(Threads QUIET)
|
||||||
|
if(NOT Threads_FOUND)
|
||||||
|
set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).")
|
||||||
|
if(SDL2_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_THREADS_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_THREADS_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# MinGW needs an additional link flag, -mwindows
|
||||||
|
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows
|
||||||
|
if(MINGW)
|
||||||
|
set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SDL2_LIBRARY)
|
||||||
|
# For SDL2main
|
||||||
|
if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY)
|
||||||
|
list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX)
|
||||||
|
if(_SDL2_MAIN_INDEX EQUAL -1)
|
||||||
|
set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
unset(_SDL2_MAIN_INDEX)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||||
|
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||||
|
# though it actually is there if I modify a pre-used variable.
|
||||||
|
# I think it has something to do with the CACHE STRING.
|
||||||
|
# So I use a temporary variable until the end so I can set the
|
||||||
|
# "real" variable in one-shot.
|
||||||
|
if(APPLE)
|
||||||
|
set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# For threads, as mentioned Apple doesn't need this.
|
||||||
|
# In fact, there seems to be a problem if I used the Threads package
|
||||||
|
# and try using this line, so I'm just skipping it entirely for OS X.
|
||||||
|
if(NOT APPLE)
|
||||||
|
set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# For MinGW library
|
||||||
|
if(MINGW)
|
||||||
|
set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Read SDL2 version
|
||||||
|
if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h")
|
||||||
|
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH})
|
||||||
|
unset(SDL2_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_VERSION_MAJOR)
|
||||||
|
unset(SDL2_VERSION_MINOR)
|
||||||
|
unset(SDL2_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
|
||||||
|
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR
|
||||||
|
VERSION_VAR SDL2_VERSION_STRING)
|
||||||
|
|
||||||
|
if(SDL2MAIN_LIBRARY)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main
|
||||||
|
REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR
|
||||||
|
VERSION_VAR SDL2_VERSION_STRING)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_PATH
|
||||||
|
SDL2_NO_DEFAULT_PATH
|
||||||
|
SDL2_LIBRARY
|
||||||
|
SDL2MAIN_LIBRARY
|
||||||
|
SDL2_INCLUDE_DIR
|
||||||
|
SDL2_BUILDING_LIBRARY)
|
||||||
|
|
||||||
|
|
||||||
|
# SDL2:: targets (SDL2::Core and SDL2::Main)
|
||||||
|
if(SDL2_FOUND)
|
||||||
|
|
||||||
|
# SDL2::Core target
|
||||||
|
if(SDL2_LIBRARY AND NOT TARGET SDL2::Core)
|
||||||
|
add_library(SDL2::Core UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::Core PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||||
|
# For more details, please see above.
|
||||||
|
set_property(TARGET SDL2::Core APPEND PROPERTY
|
||||||
|
INTERFACE_LINK_OPTIONS -framework Cocoa)
|
||||||
|
else()
|
||||||
|
# For threads, as mentioned Apple doesn't need this.
|
||||||
|
# For more details, please see above.
|
||||||
|
set_property(TARGET SDL2::Core APPEND PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES Threads::Threads)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# SDL2::Main target
|
||||||
|
# Applications should link to SDL2::Main instead of SDL2::Core
|
||||||
|
# For more details, please see above.
|
||||||
|
if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main)
|
||||||
|
|
||||||
|
if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY)
|
||||||
|
add_library(SDL2::Main INTERFACE IMPORTED)
|
||||||
|
set_property(TARGET SDL2::Main PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
elseif(SDL2MAIN_LIBRARY)
|
||||||
|
# MinGW requires that the mingw32 library is specified before the
|
||||||
|
# libSDL2main.a static library when linking.
|
||||||
|
# The SDL2::MainInternal target is used internally to make sure that
|
||||||
|
# CMake respects this condition.
|
||||||
|
add_library(SDL2::MainInternal UNKNOWN IMPORTED)
|
||||||
|
set_property(TARGET SDL2::MainInternal PROPERTY
|
||||||
|
IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}")
|
||||||
|
set_property(TARGET SDL2::MainInternal PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
|
||||||
|
add_library(SDL2::Main INTERFACE IMPORTED)
|
||||||
|
|
||||||
|
if(MINGW)
|
||||||
|
# MinGW needs an additional link flag '-mwindows' and link to mingw32
|
||||||
|
set_property(TARGET SDL2::Main PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_property(TARGET SDL2::Main APPEND PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::MainInternal)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
|
endif()
|
222
cmake/FindSDL2_gfx.cmake
Normal file
222
cmake/FindSDL2_gfx.cmake
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2_gfx
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Locate SDL2_gfx library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' target:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::GFX
|
||||||
|
The SDL2_gfx library, if found.
|
||||||
|
Have SDL2::Core as a link dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_GFX_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_GFX_INCLUDE_DIRS, where to find the headers
|
||||||
|
SDL2_GFX_FOUND, if false, do not try to link against
|
||||||
|
SDL2_GFX_VERSION_STRING - human-readable string containing the
|
||||||
|
version of SDL2_gfx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_GFX_PATH
|
||||||
|
Set a custom SDL2_gfx Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_GFX_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2_gfx Library in default path.
|
||||||
|
If SDL2_GFX_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_GFX_INCLUDE_DIR
|
||||||
|
SDL2_gfx headers path.
|
||||||
|
|
||||||
|
SDL2_GFX_LIBRARY
|
||||||
|
SDL2_gfx Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_GFX_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2_gfx library
|
||||||
|
(SDL2_gfx.dll, libsdl2_gfx.so, etc). Set SDL2_GFX_LIBRARY to point
|
||||||
|
to your SDL2_gfx library, and configure again. This value is used to
|
||||||
|
generate the final SDL2_GFX_LIBRARIES variable and the SDL2::GFX target,
|
||||||
|
but when this value is unset, SDL2_GFX_LIBRARIES and SDL2::GFX does not
|
||||||
|
get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2GFXDIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2GFXDIR used in building SDL2_gfx.
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL_image.cmake to SDL2_gfx (FindSDL2_gfx.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_GFX_PATH, SDL2_GFX_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Add SDL2 as a required dependency.
|
||||||
|
Modernize the FindSDL2_gfx.cmake module by creating a specific target:
|
||||||
|
SDL2::GFX (for details, see doc above).
|
||||||
|
|
||||||
|
Original FindSDL_image.cmake module:
|
||||||
|
Created by Eric Wing. This was influenced by the FindSDL.cmake
|
||||||
|
module, but with modifications to recognize OS X frameworks and
|
||||||
|
additional Unix paths (FreeBSD, etc).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# SDL2 Library required
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
|
if(NOT SDL2_FOUND)
|
||||||
|
set(SDL2_GFX_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_gfx).")
|
||||||
|
if(SDL2_gfx_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_GFX_SDL2_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_gfx_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_GFX_SDL2_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_GFX_SDL2_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Define options for searching SDL2_gfx Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_GFX_PATH "" CACHE STRING "Custom SDL2_gfx Library path")
|
||||||
|
|
||||||
|
set(_SDL2_GFX_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_GFX_PATH)
|
||||||
|
set(_SDL2_GFX_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_GFX_NO_DEFAULT_PATH ${_SDL2_GFX_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2_gfx Library in default path")
|
||||||
|
unset(_SDL2_GFX_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_GFX_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_GFX_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_GFX_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_gfx include directory
|
||||||
|
find_path(SDL2_GFX_INCLUDE_DIR SDL2_gfxPrimitives.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2GFXDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_GFX_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
# and ENV{SDL2GFXDIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_GFX_PATH}
|
||||||
|
DOC "Where the SDL2_gfx headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_gfx library
|
||||||
|
find_library(SDL2_GFX_LIBRARY
|
||||||
|
NAMES SDL2_gfx
|
||||||
|
HINTS
|
||||||
|
ENV SDL2GFXDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_GFX_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_GFX_PATH}
|
||||||
|
DOC "Where the SDL2_gfx Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read SDL2_gfx version
|
||||||
|
if(SDL2_GFX_INCLUDE_DIR AND EXISTS "${SDL2_GFX_INCLUDE_DIR}/SDL2_gfxPrimitives.h")
|
||||||
|
file(STRINGS "${SDL2_GFX_INCLUDE_DIR}/SDL2_gfxPrimitives.h" SDL2_GFX_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_GFXPRIMITIVES_MAJOR[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_GFX_INCLUDE_DIR}/SDL2_gfxPrimitives.h" SDL2_GFX_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_GFXPRIMITIVES_MINOR[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_GFX_INCLUDE_DIR}/SDL2_gfxPrimitives.h" SDL2_GFX_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_GFXPRIMITIVES_MICRO[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL2_GFXPRIMITIVES_MAJOR[ \t]+([0-9]+)$" "\\1" SDL2_GFX_VERSION_MAJOR "${SDL2_GFX_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL2_GFXPRIMITIVES_MINOR[ \t]+([0-9]+)$" "\\1" SDL2_GFX_VERSION_MINOR "${SDL2_GFX_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL2_GFXPRIMITIVES_MICRO[ \t]+([0-9]+)$" "\\1" SDL2_GFX_VERSION_PATCH "${SDL2_GFX_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_GFX_VERSION_STRING ${SDL2_GFX_VERSION_MAJOR}.${SDL2_GFX_VERSION_MINOR}.${SDL2_GFX_VERSION_PATCH})
|
||||||
|
unset(SDL2_GFX_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_GFX_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_GFX_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_GFX_VERSION_MAJOR)
|
||||||
|
unset(SDL2_GFX_VERSION_MINOR)
|
||||||
|
unset(SDL2_GFX_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_GFX_LIBRARIES ${SDL2_GFX_LIBRARY})
|
||||||
|
set(SDL2_GFX_INCLUDE_DIRS ${SDL2_GFX_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_gfx
|
||||||
|
REQUIRED_VARS SDL2_GFX_LIBRARIES SDL2_GFX_INCLUDE_DIRS
|
||||||
|
VERSION_VAR SDL2_GFX_VERSION_STRING)
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_GFX_PATH
|
||||||
|
SDL2_GFX_NO_DEFAULT_PATH
|
||||||
|
SDL2_GFX_LIBRARY
|
||||||
|
SDL2_GFX_INCLUDE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL2_GFX_FOUND)
|
||||||
|
|
||||||
|
# SDL2::GFX target
|
||||||
|
if(SDL2_GFX_LIBRARY AND NOT TARGET SDL2::GFX)
|
||||||
|
add_library(SDL2::GFX UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::GFX PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_GFX_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_GFX_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
endif()
|
||||||
|
endif()
|
222
cmake/FindSDL2_image.cmake
Normal file
222
cmake/FindSDL2_image.cmake
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2_image
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Locate SDL2_image library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' target:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::Image
|
||||||
|
The SDL2_image library, if found.
|
||||||
|
Have SDL2::Core as a link dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_IMAGE_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_IMAGE_INCLUDE_DIRS, where to find the headers
|
||||||
|
SDL2_IMAGE_FOUND, if false, do not try to link against
|
||||||
|
SDL2_IMAGE_VERSION_STRING - human-readable string containing the
|
||||||
|
version of SDL2_image
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_IMAGE_PATH
|
||||||
|
Set a custom SDL2_image Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_IMAGE_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2_image Library in default path.
|
||||||
|
If SDL2_IMAGE_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_IMAGE_INCLUDE_DIR
|
||||||
|
SDL2_image headers path.
|
||||||
|
|
||||||
|
SDL2_IMAGE_LIBRARY
|
||||||
|
SDL2_image Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_IMAGE_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2_image library
|
||||||
|
(SDL2_image.dll, libsdl2_image.so, etc). Set SDL2_IMAGE_LIBRARY to point
|
||||||
|
to your SDL2_image library, and configure again. This value is used to
|
||||||
|
generate the final SDL2_IMAGE_LIBRARIES variable and the SDL2::Image target,
|
||||||
|
but when this value is unset, SDL2_IMAGE_LIBRARIES and SDL2::Image does not
|
||||||
|
get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2IMAGEDIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2IMAGEDIR used in building SDL2_image.
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL_image.cmake to SDL2_image (FindSDL2_image.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_IMAGE_PATH, SDL2_IMAGE_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Add SDL2 as a required dependency.
|
||||||
|
Modernize the FindSDL2_image.cmake module by creating a specific target:
|
||||||
|
SDL2::Image (for details, see doc above).
|
||||||
|
|
||||||
|
Original FindSDL_image.cmake module:
|
||||||
|
Created by Eric Wing. This was influenced by the FindSDL.cmake
|
||||||
|
module, but with modifications to recognize OS X frameworks and
|
||||||
|
additional Unix paths (FreeBSD, etc).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# SDL2 Library required
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
|
if(NOT SDL2_FOUND)
|
||||||
|
set(SDL2_IMAGE_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_image).")
|
||||||
|
if(SDL2_image_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_IMAGE_SDL2_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_image_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_IMAGE_SDL2_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_IMAGE_SDL2_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Define options for searching SDL2_image Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_IMAGE_PATH "" CACHE STRING "Custom SDL2_image Library path")
|
||||||
|
|
||||||
|
set(_SDL2_IMAGE_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_IMAGE_PATH)
|
||||||
|
set(_SDL2_IMAGE_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_IMAGE_NO_DEFAULT_PATH ${_SDL2_IMAGE_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2_image Library in default path")
|
||||||
|
unset(_SDL2_IMAGE_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_IMAGE_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_IMAGE_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_IMAGE_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_image include directory
|
||||||
|
find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2IMAGEDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_IMAGE_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
# and ENV{SDL2IMAGEDIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_IMAGE_PATH}
|
||||||
|
DOC "Where the SDL2_image headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_image library
|
||||||
|
find_library(SDL2_IMAGE_LIBRARY
|
||||||
|
NAMES SDL2_image
|
||||||
|
HINTS
|
||||||
|
ENV SDL2IMAGEDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_IMAGE_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_IMAGE_PATH}
|
||||||
|
DOC "Where the SDL2_image Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read SDL2_image version
|
||||||
|
if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h")
|
||||||
|
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH})
|
||||||
|
unset(SDL2_IMAGE_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_IMAGE_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_IMAGE_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_IMAGE_VERSION_MAJOR)
|
||||||
|
unset(SDL2_IMAGE_VERSION_MINOR)
|
||||||
|
unset(SDL2_IMAGE_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY})
|
||||||
|
set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image
|
||||||
|
REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS
|
||||||
|
VERSION_VAR SDL2_IMAGE_VERSION_STRING)
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_IMAGE_PATH
|
||||||
|
SDL2_IMAGE_NO_DEFAULT_PATH
|
||||||
|
SDL2_IMAGE_LIBRARY
|
||||||
|
SDL2_IMAGE_INCLUDE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL2_IMAGE_FOUND)
|
||||||
|
|
||||||
|
# SDL2::Image target
|
||||||
|
if(SDL2_IMAGE_LIBRARY AND NOT TARGET SDL2::Image)
|
||||||
|
add_library(SDL2::Image UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::Image PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_IMAGE_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_IMAGE_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
endif()
|
||||||
|
endif()
|
220
cmake/FindSDL2_mixer.cmake
Normal file
220
cmake/FindSDL2_mixer.cmake
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2_mixer
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Locate SDL2_mixer library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' target:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::Mixer
|
||||||
|
The SDL2_mixer library, if found.
|
||||||
|
Have SDL2::Core as a link dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_MIXER_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_MIXER_INCLUDE_DIRS, where to find the headers
|
||||||
|
SDL2_MIXER_FOUND, if false, do not try to link against
|
||||||
|
SDL2_MIXER_VERSION_STRING - human-readable string containing the
|
||||||
|
version of SDL2_mixer
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_MIXER_PATH
|
||||||
|
Set a custom SDL2_mixer Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_MIXER_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2_mixer Library in default path.
|
||||||
|
If SDL2_MIXER_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_MIXER_INCLUDE_DIR
|
||||||
|
SDL2_mixer headers path.
|
||||||
|
|
||||||
|
SDL2_MIXER_LIBRARY
|
||||||
|
SDL2_mixer Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_MIXER_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2_mixer library
|
||||||
|
(SDL2_mixer.dll, libsdl2_mixer.so, etc). Set SDL2_MIXER_LIBRARY to point
|
||||||
|
to your SDL2_mixer library, and configure again. This value is used to
|
||||||
|
generate the final SDL2_MIXER_LIBRARIES variable and the SDL2::Mixer target,
|
||||||
|
but when this value is unset, SDL2_MIXER_LIBRARIES and SDL2::Mixer does not
|
||||||
|
get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2MIXERDIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2MIXERDIR used in building SDL2_mixer.
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL_mixer.cmake to SDL2_mixer (FindSDL2_mixer.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_MIXER_PATH, SDL2_MIXER_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Add SDL2 as a required dependency.
|
||||||
|
Modernize the FindSDL2_mixer.cmake module by creating a specific target:
|
||||||
|
SDL2::Mixer (for details, see doc above).
|
||||||
|
|
||||||
|
Original FindSDL_mixer.cmake module:
|
||||||
|
Created by Eric Wing. This was influenced by the FindSDL.cmake
|
||||||
|
module, but with modifications to recognize OS X frameworks and
|
||||||
|
additional Unix paths (FreeBSD, etc).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# SDL2 Library required
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
|
if(NOT SDL2_FOUND)
|
||||||
|
set(SDL2_MIXER_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_mixer).")
|
||||||
|
if(SDL2_mixer_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_MIXER_SDL2_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_mixer_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_MIXER_SDL2_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_MIXER_SDL2_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Define options for searching SDL2_mixer Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_MIXER_PATH "" CACHE STRING "Custom SDL2_mixer Library path")
|
||||||
|
|
||||||
|
set(_SDL2_MIXER_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_MIXER_PATH)
|
||||||
|
set(_SDL2_MIXER_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_MIXER_NO_DEFAULT_PATH ${_SDL2_MIXER_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2_mixer Library in default path")
|
||||||
|
unset(_SDL2_MIXER_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_MIXER_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_MIXER_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_MIXER_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_mixer include directory
|
||||||
|
find_path(SDL2_MIXER_INCLUDE_DIR SDL_mixer.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2MIXERDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_MIXER_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
# and ENV{SDL2MIXERDIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_MIXER_PATH}
|
||||||
|
DOC "Where the SDL2_mixer headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_mixer library
|
||||||
|
find_library(SDL2_MIXER_LIBRARY
|
||||||
|
NAMES SDL2_mixer
|
||||||
|
HINTS
|
||||||
|
ENV SDL2MIXERDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_MIXER_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_MIXER_PATH}
|
||||||
|
DOC "Where the SDL2_mixer Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read SDL2_mixer version
|
||||||
|
if(SDL2_MIXER_INCLUDE_DIR AND EXISTS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h")
|
||||||
|
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MAJOR "${SDL2_MIXER_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MINOR "${SDL2_MIXER_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_PATCH "${SDL2_MIXER_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_MIXER_VERSION_STRING ${SDL2_MIXER_VERSION_MAJOR}.${SDL2_MIXER_VERSION_MINOR}.${SDL2_MIXER_VERSION_PATCH})
|
||||||
|
unset(SDL2_MIXER_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_MIXER_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_MIXER_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_MIXER_VERSION_MAJOR)
|
||||||
|
unset(SDL2_MIXER_VERSION_MINOR)
|
||||||
|
unset(SDL2_MIXER_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_MIXER_LIBRARIES ${SDL2_MIXER_LIBRARY})
|
||||||
|
set(SDL2_MIXER_INCLUDE_DIRS ${SDL2_MIXER_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_mixer
|
||||||
|
REQUIRED_VARS SDL2_MIXER_LIBRARIES SDL2_MIXER_INCLUDE_DIRS
|
||||||
|
VERSION_VAR SDL2_MIXER_VERSION_STRING)
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_MIXER_PATH
|
||||||
|
SDL2_MIXER_NO_DEFAULT_PATH
|
||||||
|
SDL2_MIXER_LIBRARY
|
||||||
|
SDL2_MIXER_INCLUDE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL2_MIXER_FOUND)
|
||||||
|
|
||||||
|
# SDL2::Mixer target
|
||||||
|
if(SDL2_MIXER_LIBRARY AND NOT TARGET SDL2::Mixer)
|
||||||
|
add_library(SDL2::Mixer UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::Mixer PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_MIXER_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_MIXER_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
endif()
|
||||||
|
endif()
|
222
cmake/FindSDL2_net.cmake
Normal file
222
cmake/FindSDL2_net.cmake
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2_net
|
||||||
|
------------
|
||||||
|
|
||||||
|
Locate SDL2_net library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' target:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::Net
|
||||||
|
The SDL2_net library, if found.
|
||||||
|
Have SDL2::Core as a link dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_NET_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_NET_INCLUDE_DIRS, where to find the headers
|
||||||
|
SDL2_NET_FOUND, if false, do not try to link against
|
||||||
|
SDL2_NET_VERSION_STRING - human-readable string containing the
|
||||||
|
version of SDL2_net
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_NET_PATH
|
||||||
|
Set a custom SDL2_net Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_NET_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2_net Library in default path.
|
||||||
|
If SDL2_NET_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_NET_INCLUDE_DIR
|
||||||
|
SDL2_net headers path.
|
||||||
|
|
||||||
|
SDL2_NET_LIBRARY
|
||||||
|
SDL2_net Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_NET_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2_net library
|
||||||
|
(SDL2_net.dll, libsdl2_net.so, etc). Set SDL2_NET_LIBRARY to point
|
||||||
|
to your SDL2_net library, and configure again. This value is used to
|
||||||
|
generate the final SDL2_NET_LIBRARIES variable and the SDL2::Net target,
|
||||||
|
but when this value is unset, SDL2_NET_LIBRARIES and SDL2::Net does not
|
||||||
|
get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2NETDIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2NETDIR used in building SDL2_net.
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL_net.cmake to SDL2_net (FindSDL2_net.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_NET_PATH, SDL2_NET_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Add SDL2 as a required dependency.
|
||||||
|
Modernize the FindSDL2_net.cmake module by creating a specific target:
|
||||||
|
SDL2::Net (for details, see doc above).
|
||||||
|
|
||||||
|
Original FindSDL_net.cmake module:
|
||||||
|
Created by Eric Wing. This was influenced by the FindSDL.cmake
|
||||||
|
module, but with modifications to recognize OS X frameworks and
|
||||||
|
additional Unix paths (FreeBSD, etc).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# SDL2 Library required
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
|
if(NOT SDL2_FOUND)
|
||||||
|
set(SDL2_NET_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_net).")
|
||||||
|
if(SDL2_net_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_NET_SDL2_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_net_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_NET_SDL2_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_NET_SDL2_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Define options for searching SDL2_net Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_NET_PATH "" CACHE STRING "Custom SDL2_net Library path")
|
||||||
|
|
||||||
|
set(_SDL2_NET_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_NET_PATH)
|
||||||
|
set(_SDL2_NET_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_NET_NO_DEFAULT_PATH ${_SDL2_NET_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2_net Library in default path")
|
||||||
|
unset(_SDL2_NET_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_NET_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_NET_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_NET_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_net include directory
|
||||||
|
find_path(SDL2_NET_INCLUDE_DIR SDL_net.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2NETDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_NET_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
# and ENV{SDL2NETDIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_NET_PATH}
|
||||||
|
DOC "Where the SDL2_net headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_net library
|
||||||
|
find_library(SDL2_NET_LIBRARY
|
||||||
|
NAMES SDL2_net
|
||||||
|
HINTS
|
||||||
|
ENV SDL2NETDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_NET_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_NET_PATH}
|
||||||
|
DOC "Where the SDL2_net Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read SDL2_net version
|
||||||
|
if(SDL2_NET_INCLUDE_DIR AND EXISTS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h")
|
||||||
|
file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MAJOR "${SDL2_NET_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MINOR "${SDL2_NET_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_PATCH "${SDL2_NET_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_NET_VERSION_STRING ${SDL2_NET_VERSION_MAJOR}.${SDL2_NET_VERSION_MINOR}.${SDL2_NET_VERSION_PATCH})
|
||||||
|
unset(SDL2_NET_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_NET_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_NET_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_NET_VERSION_MAJOR)
|
||||||
|
unset(SDL2_NET_VERSION_MINOR)
|
||||||
|
unset(SDL2_NET_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_NET_LIBRARIES ${SDL2_NET_LIBRARY})
|
||||||
|
set(SDL2_NET_INCLUDE_DIRS ${SDL2_NET_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_net
|
||||||
|
REQUIRED_VARS SDL2_NET_LIBRARIES SDL2_NET_INCLUDE_DIRS
|
||||||
|
VERSION_VAR SDL2_NET_VERSION_STRING)
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_NET_PATH
|
||||||
|
SDL2_NET_NO_DEFAULT_PATH
|
||||||
|
SDL2_NET_LIBRARY
|
||||||
|
SDL2_NET_INCLUDE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL2_NET_FOUND)
|
||||||
|
|
||||||
|
# SDL2::Net target
|
||||||
|
if(SDL2_NET_LIBRARY AND NOT TARGET SDL2::Net)
|
||||||
|
add_library(SDL2::Net UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::Net PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_NET_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_NET_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
endif()
|
||||||
|
endif()
|
222
cmake/FindSDL2_ttf.cmake
Normal file
222
cmake/FindSDL2_ttf.cmake
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||||
|
# Copyright 2000-2019 Kitware, Inc. and Contributors
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
# * 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.
|
||||||
|
|
||||||
|
# * Neither the name of Kitware, Inc. nor the names of Contributors
|
||||||
|
# may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "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 COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS 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.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindSDL2_ttf
|
||||||
|
------------
|
||||||
|
|
||||||
|
Locate SDL2_ttf library
|
||||||
|
|
||||||
|
This module defines the following 'IMPORTED' target:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2::TTF
|
||||||
|
The SDL2_ttf library, if found.
|
||||||
|
Have SDL2::Core as a link dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_TTF_LIBRARIES, the name of the library to link against
|
||||||
|
SDL2_TTF_INCLUDE_DIRS, where to find the headers
|
||||||
|
SDL2_TTF_FOUND, if false, do not try to link against
|
||||||
|
SDL2_TTF_VERSION_STRING - human-readable string containing the
|
||||||
|
version of SDL2_ttf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This module responds to the following cache variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SDL2_TTF_PATH
|
||||||
|
Set a custom SDL2_ttf Library path (default: empty)
|
||||||
|
|
||||||
|
SDL2_TTF_NO_DEFAULT_PATH
|
||||||
|
Disable search SDL2_ttf Library in default path.
|
||||||
|
If SDL2_TTF_PATH (default: ON)
|
||||||
|
Else (default: OFF)
|
||||||
|
|
||||||
|
SDL2_TTF_INCLUDE_DIR
|
||||||
|
SDL2_ttf headers path.
|
||||||
|
|
||||||
|
SDL2_TTF_LIBRARY
|
||||||
|
SDL2_ttf Library (.dll, .so, .a, etc) path.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Note: If you see an empty SDL2_TTF_LIBRARY in your project
|
||||||
|
configuration, it means CMake did not find your SDL2_ttf library
|
||||||
|
(SDL2_ttf.dll, libsdl2_ttf.so, etc). Set SDL2_TTF_LIBRARY to point
|
||||||
|
to your SDL2_ttf library, and configure again. This value is used to
|
||||||
|
generate the final SDL2_TTF_LIBRARIES variable and the SDL2::TTF target,
|
||||||
|
but when this value is unset, SDL2_TTF_LIBRARIES and SDL2::TTF does not
|
||||||
|
get created.
|
||||||
|
|
||||||
|
|
||||||
|
$SDL2TTFDIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2TTFDIR used in building SDL2_ttf.
|
||||||
|
|
||||||
|
$SDL2DIR is an environment variable that would correspond to the
|
||||||
|
./configure --prefix=$SDL2DIR used in building SDL2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Created by Amine Ben Hassouna:
|
||||||
|
Adapt FindSDL_ttf.cmake to SDL2_ttf (FindSDL2_ttf.cmake).
|
||||||
|
Add cache variables for more flexibility:
|
||||||
|
SDL2_TTF_PATH, SDL2_TTF_NO_DEFAULT_PATH (for details, see doc above).
|
||||||
|
Add SDL2 as a required dependency.
|
||||||
|
Modernize the FindSDL2_ttf.cmake module by creating a specific target:
|
||||||
|
SDL2::TTF (for details, see doc above).
|
||||||
|
|
||||||
|
Original FindSDL_ttf.cmake module:
|
||||||
|
Created by Eric Wing. This was influenced by the FindSDL.cmake
|
||||||
|
module, but with modifications to recognize OS X frameworks and
|
||||||
|
additional Unix paths (FreeBSD, etc).
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
# SDL2 Library required
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
|
if(NOT SDL2_FOUND)
|
||||||
|
set(SDL2_TTF_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_ttf).")
|
||||||
|
if(SDL2_ttf_FIND_REQUIRED)
|
||||||
|
message(FATAL_ERROR ${SDL2_TTF_SDL2_NOT_FOUND})
|
||||||
|
else()
|
||||||
|
if(NOT SDL2_ttf_FIND_QUIETLY)
|
||||||
|
message(STATUS ${SDL2_TTF_SDL2_NOT_FOUND})
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
unset(SDL2_TTF_SDL2_NOT_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Define options for searching SDL2_ttf Library in a custom path
|
||||||
|
|
||||||
|
set(SDL2_TTF_PATH "" CACHE STRING "Custom SDL2_ttf Library path")
|
||||||
|
|
||||||
|
set(_SDL2_TTF_NO_DEFAULT_PATH OFF)
|
||||||
|
if(SDL2_TTF_PATH)
|
||||||
|
set(_SDL2_TTF_NO_DEFAULT_PATH ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_TTF_NO_DEFAULT_PATH ${_SDL2_TTF_NO_DEFAULT_PATH}
|
||||||
|
CACHE BOOL "Disable search SDL2_ttf Library in default path")
|
||||||
|
unset(_SDL2_TTF_NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
set(SDL2_TTF_NO_DEFAULT_PATH_CMD)
|
||||||
|
if(SDL2_TTF_NO_DEFAULT_PATH)
|
||||||
|
set(SDL2_TTF_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_ttf include directory
|
||||||
|
find_path(SDL2_TTF_INCLUDE_DIR SDL_ttf.h
|
||||||
|
HINTS
|
||||||
|
ENV SDL2TTFDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_TTF_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES SDL2
|
||||||
|
# path suffixes to search inside ENV{SDL2DIR}
|
||||||
|
# and ENV{SDL2TTFDIR}
|
||||||
|
include/SDL2 include
|
||||||
|
PATHS ${SDL2_TTF_PATH}
|
||||||
|
DOC "Where the SDL2_ttf headers can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x64)
|
||||||
|
else()
|
||||||
|
set(VC_LIB_PATH_SUFFIX lib/x86)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Search for the SDL2_ttf library
|
||||||
|
find_library(SDL2_TTF_LIBRARY
|
||||||
|
NAMES SDL2_ttf
|
||||||
|
HINTS
|
||||||
|
ENV SDL2TTFDIR
|
||||||
|
ENV SDL2DIR
|
||||||
|
${SDL2_TTF_NO_DEFAULT_PATH_CMD}
|
||||||
|
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
|
||||||
|
PATHS ${SDL2_TTF_PATH}
|
||||||
|
DOC "Where the SDL2_ttf Library can be found"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read SDL2_ttf version
|
||||||
|
if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h")
|
||||||
|
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}")
|
||||||
|
set(SDL2_TTF_VERSION_STRING ${SDL2_TTF_VERSION_MAJOR}.${SDL2_TTF_VERSION_MINOR}.${SDL2_TTF_VERSION_PATCH})
|
||||||
|
unset(SDL2_TTF_VERSION_MAJOR_LINE)
|
||||||
|
unset(SDL2_TTF_VERSION_MINOR_LINE)
|
||||||
|
unset(SDL2_TTF_VERSION_PATCH_LINE)
|
||||||
|
unset(SDL2_TTF_VERSION_MAJOR)
|
||||||
|
unset(SDL2_TTF_VERSION_MINOR)
|
||||||
|
unset(SDL2_TTF_VERSION_PATCH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SDL2_TTF_LIBRARIES ${SDL2_TTF_LIBRARY})
|
||||||
|
set(SDL2_TTF_INCLUDE_DIRS ${SDL2_TTF_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_ttf
|
||||||
|
REQUIRED_VARS SDL2_TTF_LIBRARIES SDL2_TTF_INCLUDE_DIRS
|
||||||
|
VERSION_VAR SDL2_TTF_VERSION_STRING)
|
||||||
|
|
||||||
|
|
||||||
|
mark_as_advanced(SDL2_TTF_PATH
|
||||||
|
SDL2_TTF_NO_DEFAULT_PATH
|
||||||
|
SDL2_TTF_LIBRARY
|
||||||
|
SDL2_TTF_INCLUDE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL2_TTF_FOUND)
|
||||||
|
|
||||||
|
# SDL2::TTF target
|
||||||
|
if(SDL2_TTF_LIBRARY AND NOT TARGET SDL2::TTF)
|
||||||
|
add_library(SDL2::TTF UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(SDL2::TTF PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${SDL2_TTF_LIBRARY}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_TTF_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES SDL2::Core)
|
||||||
|
endif()
|
||||||
|
endif()
|
3
extern/CMakeLists.txt
vendored
Normal file
3
extern/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
add_subdirectory(doctest)
|
||||||
|
add_subdirectory(glad)
|
||||||
|
add_subdirectory(imgui)
|
2
extern/doctest/CMakeLists.txt
vendored
Normal file
2
extern/doctest/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
add_library(doctest INTERFACE)
|
||||||
|
target_include_directories(doctest INTERFACE include)
|
5971
extern/doctest/include/doctest.h
vendored
Normal file
5971
extern/doctest/include/doctest.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
3
extern/glad/CMakeLists.txt
vendored
Normal file
3
extern/glad/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
add_library(glad
|
||||||
|
src/glad.c)
|
||||||
|
target_include_directories(glad PUBLIC include)
|
290
extern/glad/include/KHR/khrplatform.h
vendored
Normal file
290
extern/glad/include/KHR/khrplatform.h
vendored
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
#ifndef __khrplatform_h_
|
||||||
|
#define __khrplatform_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
** the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included
|
||||||
|
** in all copies or substantial portions of the Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Khronos platform-specific types and definitions.
|
||||||
|
*
|
||||||
|
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||||
|
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||||
|
* The last semantic modification to khrplatform.h was at commit ID:
|
||||||
|
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||||
|
*
|
||||||
|
* Adopters may modify this file to suit their platform. Adopters are
|
||||||
|
* encouraged to submit platform specific modifications to the Khronos
|
||||||
|
* group so that they can be included in future versions of this file.
|
||||||
|
* Please submit changes by filing pull requests or issues on
|
||||||
|
* the EGL Registry repository linked above.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Implementer's Guidelines for information about where this file
|
||||||
|
* should be located on your system and for more details of its use:
|
||||||
|
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||||
|
*
|
||||||
|
* This file should be included as
|
||||||
|
* #include <KHR/khrplatform.h>
|
||||||
|
* by Khronos client API header files that use its types and defines.
|
||||||
|
*
|
||||||
|
* The types in khrplatform.h should only be used to define API-specific types.
|
||||||
|
*
|
||||||
|
* Types defined in khrplatform.h:
|
||||||
|
* khronos_int8_t signed 8 bit
|
||||||
|
* khronos_uint8_t unsigned 8 bit
|
||||||
|
* khronos_int16_t signed 16 bit
|
||||||
|
* khronos_uint16_t unsigned 16 bit
|
||||||
|
* khronos_int32_t signed 32 bit
|
||||||
|
* khronos_uint32_t unsigned 32 bit
|
||||||
|
* khronos_int64_t signed 64 bit
|
||||||
|
* khronos_uint64_t unsigned 64 bit
|
||||||
|
* khronos_intptr_t signed same number of bits as a pointer
|
||||||
|
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||||
|
* khronos_ssize_t signed size
|
||||||
|
* khronos_usize_t unsigned size
|
||||||
|
* khronos_float_t signed 32 bit floating point
|
||||||
|
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||||
|
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||||
|
* nanoseconds
|
||||||
|
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||||
|
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||||
|
* only be used as a base type when a client API's boolean type is
|
||||||
|
* an enum. Client APIs which use an integer or other type for
|
||||||
|
* booleans cannot use this as the base type for their boolean.
|
||||||
|
*
|
||||||
|
* Tokens defined in khrplatform.h:
|
||||||
|
*
|
||||||
|
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||||
|
*
|
||||||
|
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||||
|
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||||
|
*
|
||||||
|
* Calling convention macros defined in this file:
|
||||||
|
* KHRONOS_APICALL
|
||||||
|
* KHRONOS_APIENTRY
|
||||||
|
* KHRONOS_APIATTRIBUTES
|
||||||
|
*
|
||||||
|
* These may be used in function prototypes as:
|
||||||
|
*
|
||||||
|
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||||
|
* int arg1,
|
||||||
|
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||||
|
# define KHRONOS_STATIC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APICALL
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This precedes the return type of the function in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(KHRONOS_STATIC)
|
||||||
|
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||||
|
* header compatible with static linking. */
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define KHRONOS_APICALL __declspec(dllimport)
|
||||||
|
#elif defined (__SYMBIAN32__)
|
||||||
|
# define KHRONOS_APICALL IMPORT_C
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIENTRY
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the return type of the function and precedes the function
|
||||||
|
* name in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
|
||||||
|
/* Win32 but not WinCE */
|
||||||
|
# define KHRONOS_APIENTRY __stdcall
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APIENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIATTRIBUTES
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the closing parenthesis of the function prototype arguments.
|
||||||
|
*/
|
||||||
|
#if defined (__ARMCC_2__)
|
||||||
|
#define KHRONOS_APIATTRIBUTES __softfp
|
||||||
|
#else
|
||||||
|
#define KHRONOS_APIATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* basic type definitions
|
||||||
|
*-----------------------------------------------------------------------*/
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <stdint.h>
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__VMS ) || defined(__sgi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <inttypes.h>
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Win32
|
||||||
|
*/
|
||||||
|
typedef __int32 khronos_int32_t;
|
||||||
|
typedef unsigned __int32 khronos_uint32_t;
|
||||||
|
typedef __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__sun__) || defined(__digital__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun or Digital
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#if defined(__arch64__) || defined(_LP64)
|
||||||
|
typedef long int khronos_int64_t;
|
||||||
|
typedef unsigned long int khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef long long int khronos_int64_t;
|
||||||
|
typedef unsigned long long int khronos_uint64_t;
|
||||||
|
#endif /* __arch64__ */
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypothetical platform with no float or int64 support
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 0
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic fallback
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that are (so far) the same on all platforms
|
||||||
|
*/
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||||
|
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||||
|
* to be the only LLP64 architecture in current use.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef unsigned long long int khronos_uintptr_t;
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
typedef unsigned long long int khronos_usize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef unsigned long int khronos_uintptr_t;
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
typedef unsigned long int khronos_usize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_FLOAT
|
||||||
|
/*
|
||||||
|
* Float type
|
||||||
|
*/
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_INT64
|
||||||
|
/* Time types
|
||||||
|
*
|
||||||
|
* These types can be used to represent a time interval in nanoseconds or
|
||||||
|
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||||
|
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||||
|
* time the system booted). The Unadjusted System Time is an unsigned
|
||||||
|
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||||
|
* may be either signed or unsigned.
|
||||||
|
*/
|
||||||
|
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||||
|
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy value used to pad enum types to 32 bits.
|
||||||
|
*/
|
||||||
|
#ifndef KHRONOS_MAX_ENUM
|
||||||
|
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerated boolean type
|
||||||
|
*
|
||||||
|
* Values other than zero should be considered to be true. Therefore
|
||||||
|
* comparisons should not be made against KHRONOS_TRUE.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
KHRONOS_FALSE = 0,
|
||||||
|
KHRONOS_TRUE = 1,
|
||||||
|
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||||
|
} khronos_boolean_enum_t;
|
||||||
|
|
||||||
|
#endif /* __khrplatform_h_ */
|
2129
extern/glad/include/glad/glad.h
vendored
Normal file
2129
extern/glad/include/glad/glad.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1140
extern/glad/src/glad.c
vendored
Normal file
1140
extern/glad/src/glad.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
19
extern/imgui/CMakeLists.txt
vendored
Normal file
19
extern/imgui/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
add_library(imgui
|
||||||
|
include/imconfig.h
|
||||||
|
include/imgui_impl_opengl3.h
|
||||||
|
include/imgui_impl_sdl.h
|
||||||
|
include/imgui.h
|
||||||
|
src/imgui_demo.cpp
|
||||||
|
src/imgui_draw.cpp
|
||||||
|
src/imgui_impl_opengl3.cpp
|
||||||
|
src/imgui_impl_sdl.cpp
|
||||||
|
src/imgui_internal.h
|
||||||
|
src/imgui_widgets.cpp
|
||||||
|
src/imgui.cpp
|
||||||
|
src/imstb_rectpack.h
|
||||||
|
src/imstb_textedit.h
|
||||||
|
src/imstb_truetype.h)
|
||||||
|
target_include_directories(imgui PUBLIC include PRIVATE src)
|
||||||
|
target_link_libraries(imgui PUBLIC SDL2::Core glad)
|
110
extern/imgui/include/imconfig.h
vendored
Normal file
110
extern/imgui/include/imconfig.h
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||||
|
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||||
|
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h)
|
||||||
|
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
|
||||||
|
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include
|
||||||
|
// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||||
|
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||||
|
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
|
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||||
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
|
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||||
|
|
||||||
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||||
|
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||||
|
//#define IMGUI_API __declspec( dllexport )
|
||||||
|
//#define IMGUI_API __declspec( dllimport )
|
||||||
|
|
||||||
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
|
||||||
|
//---- Disable all of Dear ImGui or don't implement standard windows.
|
||||||
|
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
|
||||||
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
|
||||||
|
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty.
|
||||||
|
|
||||||
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||||
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
|
||||||
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
|
||||||
|
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||||
|
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
|
||||||
|
//---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points.
|
||||||
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
|
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||||
|
// By default the embedded implementations are declared static and not available outside of imgui cpp files.
|
||||||
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
|
||||||
|
//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library.
|
||||||
|
// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
|
||||||
|
// #define IMGUI_USE_STB_SPRINTF
|
||||||
|
|
||||||
|
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||||
|
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||||
|
/*
|
||||||
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
|
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||||
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
|
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||||
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||||
|
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices).
|
||||||
|
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||||
|
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||||
|
//#define ImDrawIdx unsigned int
|
||||||
|
|
||||||
|
//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
|
||||||
|
//struct ImDrawList;
|
||||||
|
//struct ImDrawCmd;
|
||||||
|
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||||
|
//#define ImDrawCallback MyImDrawCallback
|
||||||
|
|
||||||
|
//---- Debug Tools: Macro to break in Debugger
|
||||||
|
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||||
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
|
|
||||||
|
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||||
|
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||||
|
// This adds a small runtime cost which is why it is not enabled by default.
|
||||||
|
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable slower asserts
|
||||||
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
|
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||||
|
/*
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
void MyFunction(const char* name, const MyMatrix44& v);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD1
|
2337
extern/imgui/include/imgui.h
vendored
Normal file
2337
extern/imgui/include/imgui.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
71
extern/imgui/include/imgui_impl_opengl3.h
vendored
Normal file
71
extern/imgui/include/imgui_impl_opengl3.h
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// About Desktop OpenGL function loaders:
|
||||||
|
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||||
|
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||||
|
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||||
|
|
||||||
|
// About GLSL version:
|
||||||
|
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
||||||
|
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||||
|
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
// Backend API
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// (Optional) Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
// Specific OpenGL versions
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||||
|
|
||||||
|
// Desktop OpenGL: attempt to detect default GL loader based on available header files.
|
||||||
|
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||||
|
// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
|
||||||
|
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
#if defined(__has_include)
|
||||||
|
#if __has_include(<GL/glew.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||||
|
#elif __has_include(<glad/glad.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||||
|
#elif __has_include(<GL/gl3w.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||||
|
#elif __has_include(<glbinding/glbinding.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||||
|
#elif __has_include(<glbinding/Binding.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||||
|
#else
|
||||||
|
#error "Cannot detect OpenGL loader!"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
29
extern/imgui/include/imgui_impl_sdl.h
vendored
Normal file
29
extern/imgui/include/imgui_impl_sdl.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// dear imgui: Platform Binding for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct SDL_Window;
|
||||||
|
typedef union SDL_Event SDL_Event;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
10419
extern/imgui/src/imgui.cpp
vendored
Normal file
10419
extern/imgui/src/imgui.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
4917
extern/imgui/src/imgui_demo.cpp
vendored
Normal file
4917
extern/imgui/src/imgui_demo.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
3594
extern/imgui/src/imgui_draw.cpp
vendored
Normal file
3594
extern/imgui/src/imgui_draw.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
665
extern/imgui/src/imgui_impl_opengl3.cpp
vendored
Normal file
665
extern/imgui/src/imgui_impl_opengl3.cpp
vendored
Normal file
|
@ -0,0 +1,665 @@
|
||||||
|
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||||
|
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||||
|
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||||
|
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||||
|
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||||
|
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||||
|
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||||
|
// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||||
|
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||||
|
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||||
|
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||||
|
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||||
|
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||||
|
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||||
|
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||||
|
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||||
|
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||||
|
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||||
|
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||||
|
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||||
|
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||||
|
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||||
|
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// OpenGL GLSL GLSL
|
||||||
|
// version version string
|
||||||
|
//----------------------------------------
|
||||||
|
// 2.0 110 "#version 110"
|
||||||
|
// 2.1 120 "#version 120"
|
||||||
|
// 3.0 130 "#version 130"
|
||||||
|
// 3.1 140 "#version 140"
|
||||||
|
// 3.2 150 "#version 150"
|
||||||
|
// 3.3 330 "#version 330 core"
|
||||||
|
// 4.0 400 "#version 400 core"
|
||||||
|
// 4.1 410 "#version 410 core"
|
||||||
|
// 4.2 420 "#version 410 core"
|
||||||
|
// 4.3 430 "#version 430 core"
|
||||||
|
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||||
|
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||||
|
//----------------------------------------
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_opengl3.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||||
|
#include <stddef.h> // intptr_t
|
||||||
|
#else
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
#endif
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include "TargetConditionals.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Auto-enable GLES on matching platforms
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||||
|
#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GL includes
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
|
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||||
|
#else
|
||||||
|
#include <GLES3/gl3.h> // Use GL ES 3
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// About Desktop OpenGL function loaders:
|
||||||
|
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||||
|
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||||
|
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#else
|
||||||
|
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0
|
||||||
|
#else
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// OpenGL Data
|
||||||
|
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||||
|
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
|
||||||
|
static GLuint g_FontTexture = 0;
|
||||||
|
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||||
|
static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
|
||||||
|
static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
|
||||||
|
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
|
{
|
||||||
|
// Query for GL version (e.g. 320 for GL 3.2)
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
GLint major, minor;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
g_GlVersion = major * 100 + minor * 10;
|
||||||
|
#else
|
||||||
|
g_GlVersion = 200; // GLES 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl3";
|
||||||
|
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (g_GlVersion >= 320)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||||
|
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 100";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 300 es";
|
||||||
|
#else
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 130";
|
||||||
|
#endif
|
||||||
|
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
||||||
|
strcpy(g_GlslVersionString, glsl_version);
|
||||||
|
strcat(g_GlslVersionString, "\n");
|
||||||
|
|
||||||
|
// Make a dummy GL call (we don't actually need the result)
|
||||||
|
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
|
||||||
|
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
|
||||||
|
GLint current_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_ShaderHandle)
|
||||||
|
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||||
|
{
|
||||||
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
const float ortho_projection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||||
|
};
|
||||||
|
glUseProgram(g_ShaderHandle);
|
||||||
|
glUniform1i(g_AttribLocationTex, 0);
|
||||||
|
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||||
|
#ifdef GL_SAMPLER_BINDING
|
||||||
|
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)vertex_array_object;
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(vertex_array_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxPos);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxUV);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxColor);
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL3 Render function.
|
||||||
|
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||||
|
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
|
||||||
|
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||||
|
if (fb_width <= 0 || fb_height <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||||
|
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
#ifdef GL_SAMPLER_BINDING
|
||||||
|
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
|
||||||
|
#endif
|
||||||
|
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||||
|
#endif
|
||||||
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||||
|
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||||
|
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||||
|
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||||
|
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||||
|
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||||
|
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||||
|
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||||
|
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||||
|
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||||
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
bool clip_origin_lower_left = true;
|
||||||
|
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
|
||||||
|
GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
|
||||||
|
if (last_clip_origin == GL_UPPER_LEFT)
|
||||||
|
clip_origin_lower_left = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup desired GL state
|
||||||
|
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||||
|
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||||
|
GLuint vertex_array_object = 0;
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glGenVertexArrays(1, &vertex_array_object);
|
||||||
|
#endif
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
|
// Upload vertex/index buffers
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec4 clip_rect;
|
||||||
|
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||||
|
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||||
|
|
||||||
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
if (clip_origin_lower_left)
|
||||||
|
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||||
|
else
|
||||||
|
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||||
|
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (g_GlVersion >= 320)
|
||||||
|
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the temporary VAO
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glDeleteVertexArrays(1, &vertex_array_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glUseProgram(last_program);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
#ifdef GL_SAMPLER_BINDING
|
||||||
|
glBindSampler(0, last_sampler);
|
||||||
|
#endif
|
||||||
|
glActiveTexture(last_active_texture);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||||
|
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||||
|
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||||
|
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||||
|
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||||
|
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||||
|
#endif
|
||||||
|
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||||
|
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &g_FontTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
#ifdef GL_UNPACK_ROW_LENGTH
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
#endif
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
if (g_FontTexture)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
glDeleteTextures(1, &g_FontTexture);
|
||||||
|
io.Fonts->TexID = 0;
|
||||||
|
g_FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||||
|
static bool CheckShader(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
|
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||||
|
static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||||
|
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_texture, last_array_buffer;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
GLint last_vertex_array;
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Parse GLSL version string
|
||||||
|
int glsl_version = 130;
|
||||||
|
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_120 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"attribute vec2 Position;\n"
|
||||||
|
"attribute vec2 UV;\n"
|
||||||
|
"attribute vec4 Color;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_130 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"in vec2 Position;\n"
|
||||||
|
"in vec2 UV;\n"
|
||||||
|
"in vec4 Color;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_300_es =
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_410_core =
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_120 =
|
||||||
|
"#ifdef GL_ES\n"
|
||||||
|
" precision mediump float;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_130 =
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_300_es =
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_410_core =
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// Select shaders matching our GLSL versions
|
||||||
|
const GLchar* vertex_shader = NULL;
|
||||||
|
const GLchar* fragment_shader = NULL;
|
||||||
|
if (glsl_version < 130)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_120;
|
||||||
|
fragment_shader = fragment_shader_glsl_120;
|
||||||
|
}
|
||||||
|
else if (glsl_version >= 410)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_410_core;
|
||||||
|
fragment_shader = fragment_shader_glsl_410_core;
|
||||||
|
}
|
||||||
|
else if (glsl_version == 300)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_300_es;
|
||||||
|
fragment_shader = fragment_shader_glsl_300_es;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_130;
|
||||||
|
fragment_shader = fragment_shader_glsl_130;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create shaders
|
||||||
|
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
|
||||||
|
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
||||||
|
glCompileShader(g_VertHandle);
|
||||||
|
CheckShader(g_VertHandle, "vertex shader");
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
|
||||||
|
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
||||||
|
glCompileShader(g_FragHandle);
|
||||||
|
CheckShader(g_FragHandle, "fragment shader");
|
||||||
|
|
||||||
|
g_ShaderHandle = glCreateProgram();
|
||||||
|
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||||
|
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||||
|
glLinkProgram(g_ShaderHandle);
|
||||||
|
CheckProgram(g_ShaderHandle, "shader program");
|
||||||
|
|
||||||
|
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||||
|
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||||
|
g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position");
|
||||||
|
g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV");
|
||||||
|
g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color");
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
glGenBuffers(1, &g_VboHandle);
|
||||||
|
glGenBuffers(1, &g_ElementsHandle);
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
|
||||||
|
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
|
||||||
|
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
|
||||||
|
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
|
||||||
|
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
|
||||||
|
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
|
||||||
|
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
}
|
367
extern/imgui/src/imgui_impl_sdl.cpp
vendored
Normal file
367
extern/imgui/src/imgui_impl_sdl.cpp
vendored
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
// dear imgui: Platform Binding for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||||
|
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||||
|
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||||
|
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||||
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||||
|
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||||
|
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||||
|
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||||
|
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||||
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdl.h"
|
||||||
|
|
||||||
|
// SDL
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include "TargetConditionals.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
|
||||||
|
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static SDL_Window* g_Window = NULL;
|
||||||
|
static Uint64 g_Time = 0;
|
||||||
|
static bool g_MousePressed[3] = { false, false, false };
|
||||||
|
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||||
|
static char* g_ClipboardTextData = NULL;
|
||||||
|
static bool g_MouseCanUseGlobalState = true;
|
||||||
|
|
||||||
|
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||||
|
{
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
SDL_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = SDL_GetClipboardText();
|
||||||
|
return g_ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||||
|
{
|
||||||
|
SDL_SetClipboardText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||||
|
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||||
|
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||||
|
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
{
|
||||||
|
if (event->wheel.x > 0) io.MouseWheelH += 1;
|
||||||
|
if (event->wheel.x < 0) io.MouseWheelH -= 1;
|
||||||
|
if (event->wheel.y > 0) io.MouseWheel += 1;
|
||||||
|
if (event->wheel.y < 0) io.MouseWheel -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
{
|
||||||
|
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
|
||||||
|
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
|
||||||
|
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
{
|
||||||
|
io.AddInputCharactersUTF8(event->text.text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
{
|
||||||
|
int key = event->key.keysym.scancode;
|
||||||
|
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
|
||||||
|
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
|
||||||
|
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||||
|
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||||
|
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||||
|
#ifdef _WIN32
|
||||||
|
io.KeySuper = false;
|
||||||
|
#else
|
||||||
|
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplSDL2_Init(SDL_Window* window)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_sdl";
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||||
|
io.ClipboardUserData = NULL;
|
||||||
|
|
||||||
|
// Load mouse cursors
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||||
|
|
||||||
|
// Check and store if we are on Wayland
|
||||||
|
g_MouseCanUseGlobalState = strncmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
SDL_SysWMinfo wmInfo;
|
||||||
|
SDL_VERSION(&wmInfo.version);
|
||||||
|
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||||
|
io.ImeWindowHandle = wmInfo.info.win.window;
|
||||||
|
#else
|
||||||
|
(void)window;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||||
|
{
|
||||||
|
(void)sdl_gl_context; // Viewport branch will need this.
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !SDL_HAS_VULKAN
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_Shutdown()
|
||||||
|
{
|
||||||
|
g_Window = NULL;
|
||||||
|
|
||||||
|
// Destroy last known clipboard data
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
SDL_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = NULL;
|
||||||
|
|
||||||
|
// Destroy SDL mouse cursors
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
SDL_FreeCursor(g_MouseCursors[cursor_n]);
|
||||||
|
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||||
|
else
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
|
||||||
|
int mx, my;
|
||||||
|
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
|
||||||
|
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||||
|
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
|
||||||
|
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
|
||||||
|
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
|
||||||
|
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||||
|
if (g_Window == focused_window)
|
||||||
|
{
|
||||||
|
if (g_MouseCanUseGlobalState)
|
||||||
|
{
|
||||||
|
// SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
|
||||||
|
// The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
|
||||||
|
// Won't use this workaround when on Wayland, as there is no global mouse position.
|
||||||
|
int wx, wy;
|
||||||
|
SDL_GetWindowPosition(focused_window, &wx, &wy);
|
||||||
|
SDL_GetGlobalMouseState(&mx, &my);
|
||||||
|
mx -= wx;
|
||||||
|
my -= wy;
|
||||||
|
}
|
||||||
|
io.MousePos = ImVec2((float)mx, (float)my);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
|
||||||
|
// The function is only supported from SDL 2.0.4 (released Jan 2016)
|
||||||
|
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
|
||||||
|
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
|
||||||
|
#else
|
||||||
|
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
|
||||||
|
io.MousePos = ImVec2((float)mx, (float)my);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
SDL_ShowCursor(SDL_FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
SDL_ShowCursor(SDL_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get gamepad
|
||||||
|
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||||
|
if (!game_controller)
|
||||||
|
{
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||||
|
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
|
||||||
|
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||||
|
|
||||||
|
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||||
|
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||||
|
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||||
|
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_UpdateMousePosAndButtons();
|
||||||
|
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplSDL2_UpdateGamepads();
|
||||||
|
}
|
1955
extern/imgui/src/imgui_internal.h
vendored
Normal file
1955
extern/imgui/src/imgui_internal.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
7736
extern/imgui/src/imgui_widgets.cpp
vendored
Normal file
7736
extern/imgui/src/imgui_widgets.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
639
extern/imgui/src/imstb_rectpack.h
vendored
Normal file
639
extern/imgui/src/imstb_rectpack.h
vendored
Normal file
|
@ -0,0 +1,639 @@
|
||||||
|
// [DEAR IMGUI]
|
||||||
|
// This is a slightly modified version of stb_rect_pack.h 1.00.
|
||||||
|
// Those changes would need to be pushed into nothings/stb:
|
||||||
|
// - Added STBRP__CDECL
|
||||||
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
|
||||||
|
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
|
||||||
|
// Sean Barrett 2014
|
||||||
|
//
|
||||||
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
|
// Does not do rotation.
|
||||||
|
//
|
||||||
|
// Not necessarily the awesomest packing method, but better than
|
||||||
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
|
// this is meant to replace).
|
||||||
|
//
|
||||||
|
// Has only had a few tests run, may have issues.
|
||||||
|
//
|
||||||
|
// More docs to come.
|
||||||
|
//
|
||||||
|
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||||
|
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||||
|
//
|
||||||
|
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||||
|
//
|
||||||
|
// Please note: better rectangle packers are welcome! Please
|
||||||
|
// implement them to the same API, but with a different init
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// Credits
|
||||||
|
//
|
||||||
|
// Library
|
||||||
|
// Sean Barrett
|
||||||
|
// Minor features
|
||||||
|
// Martins Mozeiko
|
||||||
|
// github:IntellectualKitty
|
||||||
|
//
|
||||||
|
// Bugfixes / warning fixes
|
||||||
|
// Jeremy Jaussaud
|
||||||
|
// Fabian Giesen
|
||||||
|
//
|
||||||
|
// Version history:
|
||||||
|
//
|
||||||
|
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||||
|
// 0.99 (2019-02-07) warning fixes
|
||||||
|
// 0.11 (2017-03-03) return packing success/fail result
|
||||||
|
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||||
|
// 0.09 (2016-08-27) fix compiler warnings
|
||||||
|
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||||
|
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||||
|
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||||
|
// 0.01: initial release
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INCLUDE SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_VERSION 1
|
||||||
|
|
||||||
|
#ifdef STBRP_STATIC
|
||||||
|
#define STBRP_DEF static
|
||||||
|
#else
|
||||||
|
#define STBRP_DEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stbrp_context stbrp_context;
|
||||||
|
typedef struct stbrp_node stbrp_node;
|
||||||
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
typedef int stbrp_coord;
|
||||||
|
#else
|
||||||
|
typedef unsigned short stbrp_coord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||||
|
// are 'num_rects' many of them.
|
||||||
|
//
|
||||||
|
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||||
|
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||||
|
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||||
|
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||||
|
// have the 'was_packed' flag set to 0.
|
||||||
|
//
|
||||||
|
// You should not try to access the 'rects' array from another thread
|
||||||
|
// while this function is running, as the function temporarily reorders
|
||||||
|
// the array while it executes.
|
||||||
|
//
|
||||||
|
// To pack into another rectangle, you need to call stbrp_init_target
|
||||||
|
// again. To continue packing into the same rectangle, you can call
|
||||||
|
// this function again. Calling this multiple times with multiple rect
|
||||||
|
// arrays will probably produce worse packing results than calling it
|
||||||
|
// a single time with the full rectangle array, but the option is
|
||||||
|
// available.
|
||||||
|
//
|
||||||
|
// The function returns 1 if all of the rectangles were successfully
|
||||||
|
// packed and 0 otherwise.
|
||||||
|
|
||||||
|
struct stbrp_rect
|
||||||
|
{
|
||||||
|
// reserved for your use:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// input:
|
||||||
|
stbrp_coord w, h;
|
||||||
|
|
||||||
|
// output:
|
||||||
|
stbrp_coord x, y;
|
||||||
|
int was_packed; // non-zero if valid packing
|
||||||
|
|
||||||
|
}; // 16 bytes, nominally
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||||
|
// Initialize a rectangle packer to:
|
||||||
|
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||||
|
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||||
|
//
|
||||||
|
// You must call this function every time you start packing into a new target.
|
||||||
|
//
|
||||||
|
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||||
|
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||||
|
// the call (or calls) finish.
|
||||||
|
//
|
||||||
|
// Note: to guarantee best results, either:
|
||||||
|
// 1. make sure 'num_nodes' >= 'width'
|
||||||
|
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||||
|
//
|
||||||
|
// If you don't do either of the above things, widths will be quantized to multiples
|
||||||
|
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||||
|
//
|
||||||
|
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||||
|
// may run out of temporary storage and be unable to pack some rectangles.
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||||
|
// Optionally call this function after init but before doing any packing to
|
||||||
|
// change the handling of the out-of-temp-memory scenario, described above.
|
||||||
|
// If you call init again, this will be reset to the default (false).
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||||
|
// Optionally select which packing heuristic the library should use. Different
|
||||||
|
// heuristics will produce better/worse results for different data sets.
|
||||||
|
// If you call init again, this will be reset to the default.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP_HEURISTIC_Skyline_default=0,
|
||||||
|
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||||
|
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
|
struct stbrp_node
|
||||||
|
{
|
||||||
|
stbrp_coord x,y;
|
||||||
|
stbrp_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stbrp_context
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int align;
|
||||||
|
int init_mode;
|
||||||
|
int heuristic;
|
||||||
|
int num_nodes;
|
||||||
|
stbrp_node *active_head;
|
||||||
|
stbrp_node *free_head;
|
||||||
|
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPLEMENTATION SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#ifndef STBRP_SORT
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STBRP_SORT qsort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBRP_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBRP_ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// [DEAR IMGUI] Added STBRP__CDECL
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define STBRP__NOTUSED(v) (void)(v)
|
||||||
|
#define STBRP__CDECL __cdecl
|
||||||
|
#else
|
||||||
|
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||||
|
#define STBRP__CDECL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP__INIT_skyline = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||||
|
{
|
||||||
|
switch (context->init_mode) {
|
||||||
|
case STBRP__INIT_skyline:
|
||||||
|
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||||
|
context->heuristic = heuristic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
STBRP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||||
|
{
|
||||||
|
if (allow_out_of_mem)
|
||||||
|
// if it's ok to run out of memory, then don't bother aligning them;
|
||||||
|
// this gives better packing, but may fail due to OOM (even though
|
||||||
|
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||||
|
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||||
|
context->align = 1;
|
||||||
|
else {
|
||||||
|
// if it's not ok to run out of memory, then quantize the widths
|
||||||
|
// so that num_nodes is always enough nodes.
|
||||||
|
//
|
||||||
|
// I.e. num_nodes * align >= width
|
||||||
|
// align >= width / num_nodes
|
||||||
|
// align = ceil(width/num_nodes)
|
||||||
|
|
||||||
|
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#ifndef STBRP_LARGE_RECTS
|
||||||
|
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
|
nodes[i].next = &nodes[i+1];
|
||||||
|
nodes[i].next = NULL;
|
||||||
|
context->init_mode = STBRP__INIT_skyline;
|
||||||
|
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||||
|
context->free_head = &nodes[0];
|
||||||
|
context->active_head = &context->extra[0];
|
||||||
|
context->width = width;
|
||||||
|
context->height = height;
|
||||||
|
context->num_nodes = num_nodes;
|
||||||
|
stbrp_setup_allow_out_of_mem(context, 0);
|
||||||
|
|
||||||
|
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||||
|
context->extra[0].x = 0;
|
||||||
|
context->extra[0].y = 0;
|
||||||
|
context->extra[0].next = &context->extra[1];
|
||||||
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
context->extra[1].y = (1<<30);
|
||||||
|
#else
|
||||||
|
context->extra[1].y = 65535;
|
||||||
|
#endif
|
||||||
|
context->extra[1].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find minimum y position if it starts at x1
|
||||||
|
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||||
|
{
|
||||||
|
stbrp_node *node = first;
|
||||||
|
int x1 = x0 + width;
|
||||||
|
int min_y, visited_width, waste_area;
|
||||||
|
|
||||||
|
STBRP__NOTUSED(c);
|
||||||
|
|
||||||
|
STBRP_ASSERT(first->x <= x0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// skip in case we're past the node
|
||||||
|
while (node->next->x <= x0)
|
||||||
|
++node;
|
||||||
|
#else
|
||||||
|
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_ASSERT(node->x <= x0);
|
||||||
|
|
||||||
|
min_y = 0;
|
||||||
|
waste_area = 0;
|
||||||
|
visited_width = 0;
|
||||||
|
while (node->x < x1) {
|
||||||
|
if (node->y > min_y) {
|
||||||
|
// raise min_y higher.
|
||||||
|
// we've accounted for all waste up to min_y,
|
||||||
|
// but we'll now add more waste for everything we've visted
|
||||||
|
waste_area += visited_width * (node->y - min_y);
|
||||||
|
min_y = node->y;
|
||||||
|
// the first time through, visited_width might be reduced
|
||||||
|
if (node->x < x0)
|
||||||
|
visited_width += node->next->x - x0;
|
||||||
|
else
|
||||||
|
visited_width += node->next->x - node->x;
|
||||||
|
} else {
|
||||||
|
// add waste area
|
||||||
|
int under_width = node->next->x - node->x;
|
||||||
|
if (under_width + visited_width > width)
|
||||||
|
under_width = width - visited_width;
|
||||||
|
waste_area += under_width * (min_y - node->y);
|
||||||
|
visited_width += under_width;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pwaste = waste_area;
|
||||||
|
return min_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
stbrp_node **prev_link;
|
||||||
|
} stbrp__findresult;
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||||
|
{
|
||||||
|
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||||
|
stbrp__findresult fr;
|
||||||
|
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||||
|
|
||||||
|
// align to multiple of c->align
|
||||||
|
width = (width + c->align - 1);
|
||||||
|
width -= width % c->align;
|
||||||
|
STBRP_ASSERT(width % c->align == 0);
|
||||||
|
|
||||||
|
// if it can't possibly fit, bail immediately
|
||||||
|
if (width > c->width || height > c->height) {
|
||||||
|
fr.prev_link = NULL;
|
||||||
|
fr.x = fr.y = 0;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
while (node->x + width <= c->width) {
|
||||||
|
int y,waste;
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||||
|
// bottom left
|
||||||
|
if (y < best_y) {
|
||||||
|
best_y = y;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// best-fit
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
// can only use it if it first vertically
|
||||||
|
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||||
|
|
||||||
|
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||||
|
//
|
||||||
|
// e.g, if fitting
|
||||||
|
//
|
||||||
|
// ____________________
|
||||||
|
// |____________________|
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | ____________|
|
||||||
|
// |____________|
|
||||||
|
//
|
||||||
|
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||||
|
//
|
||||||
|
// This makes BF take about 2x the time
|
||||||
|
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||||
|
tail = c->active_head;
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
// find first node that's admissible
|
||||||
|
while (tail->x < width)
|
||||||
|
tail = tail->next;
|
||||||
|
while (tail) {
|
||||||
|
int xpos = tail->x - width;
|
||||||
|
int y,waste;
|
||||||
|
STBRP_ASSERT(xpos >= 0);
|
||||||
|
// find the left position that matches this
|
||||||
|
while (node->next->x <= xpos) {
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
if (y <= best_y) {
|
||||||
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
|
best_x = xpos;
|
||||||
|
STBRP_ASSERT(y <= best_y);
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.prev_link = best;
|
||||||
|
fr.x = best_x;
|
||||||
|
fr.y = best_y;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||||
|
{
|
||||||
|
// find best position according to heuristic
|
||||||
|
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||||
|
stbrp_node *node, *cur;
|
||||||
|
|
||||||
|
// bail if:
|
||||||
|
// 1. it failed
|
||||||
|
// 2. the best node doesn't fit (we don't always check this)
|
||||||
|
// 3. we're out of memory
|
||||||
|
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||||
|
res.prev_link = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on success, create new node
|
||||||
|
node = context->free_head;
|
||||||
|
node->x = (stbrp_coord) res.x;
|
||||||
|
node->y = (stbrp_coord) (res.y + height);
|
||||||
|
|
||||||
|
context->free_head = node->next;
|
||||||
|
|
||||||
|
// insert the new node into the right starting point, and
|
||||||
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
|
// stiched back in
|
||||||
|
|
||||||
|
cur = *res.prev_link;
|
||||||
|
if (cur->x < res.x) {
|
||||||
|
// preserve the existing one, so start testing with the next one
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
cur->next = node;
|
||||||
|
cur = next;
|
||||||
|
} else {
|
||||||
|
*res.prev_link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from here, traverse cur and free the nodes, until we get to one
|
||||||
|
// that shouldn't be freed
|
||||||
|
while (cur->next && cur->next->x <= res.x + width) {
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
// move the current node to the free list
|
||||||
|
cur->next = context->free_head;
|
||||||
|
context->free_head = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stitch the list back in
|
||||||
|
node->next = cur;
|
||||||
|
|
||||||
|
if (cur->x < res.x + width)
|
||||||
|
cur->x = (stbrp_coord) (res.x + width);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur->x < context->width) {
|
||||||
|
STBRP_ASSERT(cur->x < cur->next->x);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(cur->next == NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
cur = context->free_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(count == context->num_nodes+2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [DEAR IMGUI] Added STBRP__CDECL
|
||||||
|
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
if (p->h > q->h)
|
||||||
|
return -1;
|
||||||
|
if (p->h < q->h)
|
||||||
|
return 1;
|
||||||
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [DEAR IMGUI] Added STBRP__CDECL
|
||||||
|
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
#define STBRP__MAXVAL 0xffffffff
|
||||||
|
#else
|
||||||
|
#define STBRP__MAXVAL 0xffff
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
|
{
|
||||||
|
int i, all_rects_packed = 1;
|
||||||
|
|
||||||
|
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort according to heuristic
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||||
|
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||||
|
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||||
|
} else {
|
||||||
|
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||||
|
if (fr.prev_link) {
|
||||||
|
rects[i].x = (stbrp_coord) fr.x;
|
||||||
|
rects[i].y = (stbrp_coord) fr.y;
|
||||||
|
} else {
|
||||||
|
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsort
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||||
|
|
||||||
|
// set was_packed flags and all_rects_packed status
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||||
|
if (!rects[i].was_packed)
|
||||||
|
all_rects_packed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the all_rects_packed status
|
||||||
|
return all_rects_packed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
1417
extern/imgui/src/imstb_textedit.h
vendored
Normal file
1417
extern/imgui/src/imstb_textedit.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
4903
extern/imgui/src/imstb_truetype.h
vendored
Normal file
4903
extern/imgui/src/imstb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
roms/breakout.ch8
Normal file
BIN
roms/breakout.ch8
Normal file
Binary file not shown.
BIN
roms/fishie.ch8
Normal file
BIN
roms/fishie.ch8
Normal file
Binary file not shown.
BIN
roms/frame.ch8
Normal file
BIN
roms/frame.ch8
Normal file
Binary file not shown.
BIN
roms/ibm.ch8
Normal file
BIN
roms/ibm.ch8
Normal file
Binary file not shown.
BIN
roms/invaders.ch8
Normal file
BIN
roms/invaders.ch8
Normal file
Binary file not shown.
BIN
roms/jumping.ch8
Normal file
BIN
roms/jumping.ch8
Normal file
Binary file not shown.
BIN
roms/pic.ch8
Normal file
BIN
roms/pic.ch8
Normal file
Binary file not shown.
BIN
roms/pong.ch8
Normal file
BIN
roms/pong.ch8
Normal file
Binary file not shown.
BIN
roms/tetris.ch8
Normal file
BIN
roms/tetris.ch8
Normal file
Binary file not shown.
314
src/compiler.cpp
Normal file
314
src/compiler.cpp
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
#include "compiler.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "emu.hpp"
|
||||||
|
|
||||||
|
// hard-coded :-(
|
||||||
|
const std::string test_program =
|
||||||
|
"var count = 3;"
|
||||||
|
"label(main);"
|
||||||
|
"count += 3;"
|
||||||
|
"draw_char(0, 5, count);"
|
||||||
|
"jump(main);";
|
||||||
|
|
||||||
|
void set_bit(uint16_t& opcode, int digit, int value) {
|
||||||
|
uint16_t mask = 0x0000;
|
||||||
|
switch(digit) {
|
||||||
|
case 0:
|
||||||
|
mask = 0xF000;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mask = 0x0F00;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mask = 0x00F0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mask = 0x000F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode = (opcode & ~mask) | (digit == 3 ? value : (value << (8 / digit)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nn(uint16_t& opcode, int value) {
|
||||||
|
opcode = (opcode & ~0x00FF) | value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nnn(uint16_t& opcode, int value) {
|
||||||
|
opcode = (opcode & ~0x0FFF) | value;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class RegisterOp {
|
||||||
|
Assign,
|
||||||
|
Add
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string& s, const char delimiter) {
|
||||||
|
std::vector<std::string> splits;
|
||||||
|
|
||||||
|
std::istringstream ss(s);
|
||||||
|
std::string split;
|
||||||
|
while (std::getline(ss, split, delimiter))
|
||||||
|
splits.push_back(split);
|
||||||
|
|
||||||
|
return splits;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint16_t> opcodes;
|
||||||
|
int v_offset = 0;
|
||||||
|
|
||||||
|
bool is_number(const std::string& str) {
|
||||||
|
return std::find_if(str.begin(), str.end(), [](unsigned char c) { return !std::isdigit(c); }) == str.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VariableData {
|
||||||
|
int offset = program_begin;
|
||||||
|
int default_value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, VariableData> variable_data;
|
||||||
|
|
||||||
|
enum class VariableType {
|
||||||
|
VRegister,
|
||||||
|
Constant,
|
||||||
|
Variable
|
||||||
|
};
|
||||||
|
|
||||||
|
VariableType determine_Type(std::string str) {
|
||||||
|
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
||||||
|
|
||||||
|
if(str.find('v') != std::string::npos) {
|
||||||
|
return VariableType::VRegister;
|
||||||
|
} else if(!is_number(str)) {
|
||||||
|
return VariableType::Variable;
|
||||||
|
} else {
|
||||||
|
return VariableType::Constant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_v_index(std::string str) {
|
||||||
|
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
||||||
|
|
||||||
|
if(str.find('v') != std::string::npos) {
|
||||||
|
auto left_side_index = str.substr(str.find('[') + 1, str.length() - 2);
|
||||||
|
return std::stoi(left_side_index);
|
||||||
|
} else if(!is_number(str)) {
|
||||||
|
uint16_t opcode = 0xA000;
|
||||||
|
set_nnn(opcode, variable_data[str].offset);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
opcode = 0xF065;
|
||||||
|
set_bit(opcode, 1, v_offset);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
return v_offset++;
|
||||||
|
} else {
|
||||||
|
uint16_t opcode = 0x6000;
|
||||||
|
set_bit(opcode, 1, v_offset);
|
||||||
|
set_nn(opcode, std::stoi(str));
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
return v_offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, int> get_arguments(std::vector<std::string> args, std::vector<std::string> arg_format) {
|
||||||
|
struct OrderData {
|
||||||
|
std::string arg, name;
|
||||||
|
int v_offset;
|
||||||
|
VariableType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<OrderData> datas;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(auto arg : args) {
|
||||||
|
arg.erase(std::remove(arg.begin(), arg.end(), ' '), arg.end());
|
||||||
|
|
||||||
|
OrderData data = {};
|
||||||
|
data.name = arg_format[i];
|
||||||
|
data.arg = arg;
|
||||||
|
data.v_offset = parse_v_index(arg);
|
||||||
|
data.type = determine_Type(arg);
|
||||||
|
|
||||||
|
datas.push_back(data);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(datas.begin(), datas.end(), [](const OrderData& a, const OrderData& b) {
|
||||||
|
return a.type == VariableType::Variable && (a.v_offset > b.v_offset);
|
||||||
|
});
|
||||||
|
|
||||||
|
std::map<std::string, int> real_args;
|
||||||
|
for(auto data : datas) {
|
||||||
|
real_args[data.name] = parse_v_index(data.arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return real_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile() {
|
||||||
|
int current_offset = 0;
|
||||||
|
int next_instruction = 0;
|
||||||
|
|
||||||
|
std::map<std::string, int> function_map;
|
||||||
|
bool needs_to_store_next_function = false;
|
||||||
|
std::string next_function_to_store;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
next_instruction = test_program.find_first_of(';', current_offset + 1);
|
||||||
|
if(next_instruction == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
auto instruction = test_program.substr(current_offset == 0 ? current_offset : current_offset + 1, current_offset == 0 ? (next_instruction - current_offset) : (next_instruction - current_offset) - 1);
|
||||||
|
|
||||||
|
if(needs_to_store_next_function) {
|
||||||
|
int offset = (int)opcodes.size() + variable_data.size() + program_begin;
|
||||||
|
needs_to_store_next_function = false;
|
||||||
|
function_map[next_function_to_store] = offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignment
|
||||||
|
if(instruction.find("var") != std::string::npos) {
|
||||||
|
auto var_string = split(instruction, ' ');
|
||||||
|
|
||||||
|
auto var_name = var_string[1];
|
||||||
|
auto var_default = var_string[3];
|
||||||
|
|
||||||
|
VariableData data = {};
|
||||||
|
data.default_value = std::stoi(var_default);
|
||||||
|
data.offset = program_begin + variable_data.size();
|
||||||
|
|
||||||
|
variable_data[var_name] = data;
|
||||||
|
|
||||||
|
uint16_t opcode = 0xA000;
|
||||||
|
set_nnn(opcode, data.offset);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
opcode = 0x7000;
|
||||||
|
set_bit(opcode, 1, 0);
|
||||||
|
set_nn(opcode, data.default_value);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
opcode = 0xA000;
|
||||||
|
set_nnn(opcode, data.offset);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
opcode = 0xF055;
|
||||||
|
set_bit(opcode, 1, 0);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
} else if(instruction.find("+=") != std::string::npos) {
|
||||||
|
auto left_side = instruction.substr(0, instruction.find_first_of(' '));
|
||||||
|
auto right_side = instruction.substr(instruction.find("+=") + 2, instruction.length());
|
||||||
|
|
||||||
|
int right_side_integer = std::stoi(right_side);
|
||||||
|
|
||||||
|
auto left_side_type = determine_Type(left_side);
|
||||||
|
auto left_side_integer = parse_v_index(left_side);
|
||||||
|
|
||||||
|
// 6XNN
|
||||||
|
uint16_t opcode = 0x7000;
|
||||||
|
set_bit(opcode, 1, left_side_integer);
|
||||||
|
set_nn(opcode, right_side_integer);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
// if it is a variable, update it in memory
|
||||||
|
if(left_side_type == VariableType::Variable) {
|
||||||
|
opcode = 0xA000;
|
||||||
|
set_nnn(opcode, variable_data[left_side].offset);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
opcode = 0xF055;
|
||||||
|
set_bit(opcode, 1, left_side_integer);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
}
|
||||||
|
} else if(instruction.find('=') != std::string::npos) {
|
||||||
|
auto left_side = instruction.substr(0, instruction.find_first_of(' '));
|
||||||
|
auto right_side = instruction.substr(instruction.find('=') + 2, instruction.length());
|
||||||
|
|
||||||
|
int right_side_integer = std::stoi(right_side);
|
||||||
|
|
||||||
|
// this is a v register
|
||||||
|
if(left_side.find('[') != std::string::npos) {
|
||||||
|
auto left_side_integer = parse_v_index(left_side);
|
||||||
|
|
||||||
|
// 6XNN
|
||||||
|
uint16_t opcode = 0x6000;
|
||||||
|
set_bit(opcode, 1, left_side_integer);
|
||||||
|
set_nn(opcode, right_side_integer);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
}
|
||||||
|
} else if(instruction.find('(') != std::string::npos) {
|
||||||
|
// function
|
||||||
|
auto function_name = instruction.substr(0, instruction.find_first_of('('));
|
||||||
|
|
||||||
|
auto arguments_string = instruction.substr(instruction.find_first_of('(') + 1, instruction.length() - instruction.find_first_of('(') - 2);
|
||||||
|
auto arguments = split(arguments_string, ',');
|
||||||
|
|
||||||
|
if(function_name == "draw_char") {
|
||||||
|
auto args = get_arguments(arguments, {"x", "y", "n"});
|
||||||
|
|
||||||
|
auto x_index = args["x"];
|
||||||
|
auto y_index = args["y"];
|
||||||
|
auto c_index = args["n"];
|
||||||
|
|
||||||
|
// FX29
|
||||||
|
uint16_t opcode = 0xF029;
|
||||||
|
set_bit(opcode, 1, c_index);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
|
||||||
|
// DXYN
|
||||||
|
opcode = 0xD000;
|
||||||
|
set_bit(opcode, 1, x_index);
|
||||||
|
set_bit(opcode, 2, y_index);
|
||||||
|
set_bit(opcode, 3, 5);
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
} else if(function_name == "label") {
|
||||||
|
needs_to_store_next_function = true;
|
||||||
|
next_function_to_store = arguments[0];
|
||||||
|
} else if(function_name == "jump") {
|
||||||
|
// 1NNN
|
||||||
|
uint16_t opcode = 0x1000;
|
||||||
|
set_nnn(opcode, function_map[arguments[0]]);
|
||||||
|
|
||||||
|
opcodes.push_back(opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v_offset = 0;
|
||||||
|
current_offset = next_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Finished compilation!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_compiled_rom() {
|
||||||
|
std::vector<uint8_t> compiled_opcodes;
|
||||||
|
for(auto& opcode : opcodes) {
|
||||||
|
compiled_opcodes.push_back(opcode >> 8); // hi
|
||||||
|
compiled_opcodes.push_back(opcode); // low
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(state.memory + program_begin, compiled_opcodes.data(), compiled_opcodes.size());
|
||||||
|
}
|
4
src/compiler.hpp
Normal file
4
src/compiler.hpp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void compile();
|
||||||
|
void load_compiled_rom();
|
446
src/emu.cpp
Normal file
446
src/emu.cpp
Normal file
|
@ -0,0 +1,446 @@
|
||||||
|
#include "emu.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
typedef void (*cpu_func)(const uint16_t opcode);
|
||||||
|
|
||||||
|
void null_func(const uint16_t opcode) {
|
||||||
|
printf("unimplemented: %.4X\n", opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Size>
|
||||||
|
void safe_call(const std::array<T, Size>& array, const int index, const uint16_t opcode) {
|
||||||
|
if(index < Size) {
|
||||||
|
array[index](opcode);
|
||||||
|
} else {
|
||||||
|
null_func(opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x00E0
|
||||||
|
void op_e0(const uint16_t opcode) {
|
||||||
|
for(int y = 0; y < screen_height; y++) {
|
||||||
|
for(int x = 0; x < screen_width; x++) {
|
||||||
|
state.pixels[to_coord(x, y)] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.draw_dirty = true;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x00EE
|
||||||
|
void op_ee(const uint16_t opcode) {
|
||||||
|
state.stack_pointer--;
|
||||||
|
state.PC = state.stack[state.stack_pointer];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::array op0_func = {
|
||||||
|
op_e0, // e0
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
op_ee // ee
|
||||||
|
};
|
||||||
|
|
||||||
|
void operation0(const uint16_t opcode) {
|
||||||
|
safe_call(op0_func, opcode & 0x000f, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1NNN
|
||||||
|
void operation1(const uint16_t opcode) {
|
||||||
|
const uint16_t nnn = opcode & 0x0fff;
|
||||||
|
|
||||||
|
state.PC = nnn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2NNN
|
||||||
|
void operation2(const uint16_t opcode) {
|
||||||
|
const uint16_t nnn = opcode & 0x0fff;
|
||||||
|
|
||||||
|
state.stack[state.stack_pointer] = state.PC;
|
||||||
|
state.stack_pointer++;
|
||||||
|
state.PC = nnn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3XNN
|
||||||
|
void operation3(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
if(state.v[x] == nn)
|
||||||
|
state.PC += 4;
|
||||||
|
else
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4XNN
|
||||||
|
void operation4(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
if(state.v[x] != nn)
|
||||||
|
state.PC += 4;
|
||||||
|
else
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6XNN
|
||||||
|
void operation6(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
state.v[x] = nn;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// &XNN
|
||||||
|
void operation7(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
state.v[x] += nn;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY0
|
||||||
|
void op8_func0(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
state.v[x] = state.v[y];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY1
|
||||||
|
void op8_func2(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
state.v[x] = state.v[x] & state.v[y];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY3
|
||||||
|
void op8_func3(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
state.v[x] = state.v[x] ^ state.v[y];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY4
|
||||||
|
void op8_func4(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
// TODO: implement tests
|
||||||
|
if(state.v[y] < (0xFF - state.v[x]))
|
||||||
|
state.v[0xF] = 1;
|
||||||
|
else
|
||||||
|
state.v[0xF] = 0;
|
||||||
|
|
||||||
|
state.v[x] += state.v[y];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY5
|
||||||
|
void op8_func5(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
// TODO: implement tests
|
||||||
|
if(state.v[y] > state.v[x])
|
||||||
|
state.v[0xF] = 0;
|
||||||
|
else
|
||||||
|
state.v[0xF] = 1;
|
||||||
|
|
||||||
|
state.v[x] -= state.v[y];
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8XY6
|
||||||
|
void op8_func6(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
state.v[0xF] = (state.v[x] & 1);
|
||||||
|
state.v[x] >>= 1;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array op8_func = {
|
||||||
|
op8_func0,
|
||||||
|
null_func,
|
||||||
|
op8_func2,
|
||||||
|
op8_func3,
|
||||||
|
op8_func4,
|
||||||
|
op8_func5,
|
||||||
|
op8_func6
|
||||||
|
};
|
||||||
|
|
||||||
|
void operation8(const uint16_t opcode) {
|
||||||
|
safe_call(op8_func, opcode & 0x000f, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9XY0
|
||||||
|
void operation9(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
|
||||||
|
if(state.v[x] != state.v[y])
|
||||||
|
state.PC += 4;
|
||||||
|
else
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANNN
|
||||||
|
void operationA(const uint16_t opcode) {
|
||||||
|
const uint16_t nnn = opcode & 0x0fff;
|
||||||
|
|
||||||
|
state.I = nnn;
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CXNN
|
||||||
|
void operationC(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
srand(time(nullptr));
|
||||||
|
state.v[x] = (rand() % 0xFF) & nn;
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DXYN
|
||||||
|
void operationD(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
const uint8_t y = (opcode & 0x00f0) >> 4;
|
||||||
|
const uint8_t n = opcode & 0x000f;
|
||||||
|
|
||||||
|
const uint8_t x_pos = state.v[x];
|
||||||
|
const uint8_t y_pos = state.v[y];
|
||||||
|
const uint8_t height = n;
|
||||||
|
|
||||||
|
state.v[0xF] = 0;
|
||||||
|
state.draw_dirty = true;
|
||||||
|
|
||||||
|
for(int y = 0; y < height; y++) {
|
||||||
|
const uint8_t pixel = state.memory[state.I + y];
|
||||||
|
|
||||||
|
for(int x = 0; x < 8; x++) {
|
||||||
|
const int final_x = (x_pos + x) % screen_width;
|
||||||
|
const int final_y = (y_pos + y) % screen_height;
|
||||||
|
|
||||||
|
if((pixel & (0x80 >> x)) != 0) {
|
||||||
|
if(state.pixels[to_coord(final_x, final_y)] == 1) {
|
||||||
|
state.v[0xF] = 1;
|
||||||
|
|
||||||
|
if(options.enable_anti_flicker)
|
||||||
|
state.draw_dirty = false; // anti-flicker mechanism
|
||||||
|
}
|
||||||
|
|
||||||
|
state.pixels[to_coord(final_x, final_y)] ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EX9E & EXA1
|
||||||
|
void operationE(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
switch(opcode & 0x00ff) {
|
||||||
|
case 0x9E:
|
||||||
|
{
|
||||||
|
if(state.keys[state.v[x]] == 1)
|
||||||
|
state.PC += 4;
|
||||||
|
else
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xA1:
|
||||||
|
{
|
||||||
|
if(state.keys[state.v[x]] == 0)
|
||||||
|
state.PC += 4;
|
||||||
|
else
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX07
|
||||||
|
void opF_func7(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
state.v[x] = state.delay_timer;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX0A
|
||||||
|
void opF_funcA(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
if(state.keys[i] != 0) {
|
||||||
|
state.v[x] = i;
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX55/FX65 & FX15
|
||||||
|
void opF_func5(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
switch((opcode & 0x00F0) >> 4) {
|
||||||
|
case 0x6:
|
||||||
|
{
|
||||||
|
for(int i = 0; i <= x; i++)
|
||||||
|
state.v[i] = state.memory[state.I + i];
|
||||||
|
|
||||||
|
if(options.emulate_original)
|
||||||
|
state.I += x + 1;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
{
|
||||||
|
for(int i = 0; i <= x; i++)
|
||||||
|
state.memory[state.I + i] = state.v[i];
|
||||||
|
|
||||||
|
if(options.emulate_original)
|
||||||
|
state.I += x + 1;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
{
|
||||||
|
state.delay_timer = state.v[x];
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX18
|
||||||
|
void opF_func8(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
state.sound_timer = state.v[x];
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX29
|
||||||
|
void opF_func9(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
state.I = state.v[x] * 0x5;
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX1E
|
||||||
|
void opF_funcE(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
if((state.I + state.v[x]) > 0xFFF)
|
||||||
|
state.v[15] = 1;
|
||||||
|
else
|
||||||
|
state.v[15] = 0;
|
||||||
|
|
||||||
|
state.I += state.v[x];
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FX33
|
||||||
|
void opF_func3(const uint16_t opcode) {
|
||||||
|
const uint8_t x = (opcode & 0x0f00) >> 8;
|
||||||
|
|
||||||
|
int decimal_rep = state.v[x];
|
||||||
|
|
||||||
|
state.memory[state.I] = (decimal_rep % 1000) / 100;
|
||||||
|
state.memory[state.I + 1] = (decimal_rep % 100) / 10;
|
||||||
|
state.memory[state.I + 2] = (decimal_rep % 10);
|
||||||
|
|
||||||
|
state.PC += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array opF_func = {
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
opF_func3,
|
||||||
|
null_func,
|
||||||
|
opF_func5,
|
||||||
|
null_func,
|
||||||
|
opF_func7,
|
||||||
|
opF_func8,
|
||||||
|
opF_func9,
|
||||||
|
opF_funcA,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
null_func,
|
||||||
|
opF_funcE
|
||||||
|
};
|
||||||
|
|
||||||
|
void operationF(const uint16_t opcode) {
|
||||||
|
safe_call(opF_func, opcode & 0x000F, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::array cpu_opcode = {
|
||||||
|
operation0, // 0x0,
|
||||||
|
operation1, // 0x1
|
||||||
|
operation2, // 0x2
|
||||||
|
operation3, // 0x3
|
||||||
|
operation4, // 0x4
|
||||||
|
null_func, // 0x5
|
||||||
|
operation6, // 0x6
|
||||||
|
operation7, // 0x7
|
||||||
|
operation8, // 0x8
|
||||||
|
operation9, // 0x9
|
||||||
|
operationA, // 0xA
|
||||||
|
null_func, // 0xB
|
||||||
|
operationC, // 0xC
|
||||||
|
operationD, // 0xD
|
||||||
|
operationE, // 0xE
|
||||||
|
operationF, // 0xF
|
||||||
|
};
|
||||||
|
|
||||||
|
void process_opcode(const uint16_t opcode) {
|
||||||
|
safe_call(cpu_opcode, opcode >> 12, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_state() {
|
||||||
|
stored_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_state() {
|
||||||
|
state = stored_state;
|
||||||
|
}
|
77
src/emu.hpp
Normal file
77
src/emu.hpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// chip-8 constants
|
||||||
|
constexpr int screen_width = 64;
|
||||||
|
constexpr int screen_height = 32;
|
||||||
|
constexpr int program_begin = 0x200;
|
||||||
|
constexpr int stack_size = 16;
|
||||||
|
|
||||||
|
inline int to_coord(int x, int y) {
|
||||||
|
return (y * screen_width) + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EmulatorState {
|
||||||
|
void reset() {
|
||||||
|
for(int i = 0; i < 4096; i++)
|
||||||
|
memory[i] = 0;
|
||||||
|
|
||||||
|
PC = program_begin;
|
||||||
|
|
||||||
|
for(int i = 0; i < 12; i++)
|
||||||
|
stack[i] = 0;
|
||||||
|
|
||||||
|
stack_pointer = 0;
|
||||||
|
|
||||||
|
I = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
v[i] = 0;
|
||||||
|
|
||||||
|
delay_timer = 0;
|
||||||
|
sound_timer = 0;
|
||||||
|
|
||||||
|
for(int y = 0; y < screen_height; y++) {
|
||||||
|
for(int x = 0; x < screen_width; x++) {
|
||||||
|
pixels[to_coord(x, y)] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t memory[4096] = {};
|
||||||
|
uint16_t PC = program_begin;
|
||||||
|
|
||||||
|
uint16_t stack[stack_size] = {};
|
||||||
|
int stack_pointer = 0;
|
||||||
|
|
||||||
|
uint16_t I = 0;
|
||||||
|
|
||||||
|
uint8_t v[16] = {};
|
||||||
|
|
||||||
|
uint8_t delay_timer = 0, sound_timer = 0;
|
||||||
|
|
||||||
|
uint8_t pixels[screen_width * screen_height] = {};
|
||||||
|
bool draw_dirty = false;
|
||||||
|
|
||||||
|
bool keys[16] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EmuOptions {
|
||||||
|
bool enable_anti_flicker = true;
|
||||||
|
bool emulate_original = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline EmuOptions options;
|
||||||
|
|
||||||
|
inline bool pause_execution = false;
|
||||||
|
|
||||||
|
inline EmulatorState state;
|
||||||
|
inline EmulatorState stored_state;
|
||||||
|
|
||||||
|
void process_opcode(const uint16_t opcode);
|
||||||
|
|
||||||
|
void save_state();
|
||||||
|
void load_state();
|
353
src/main.cpp
Normal file
353
src/main.cpp
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <climits>
|
||||||
|
#include <cmath>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <map>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "emu.hpp"
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdl.h"
|
||||||
|
#include "imgui_impl_opengl3.h"
|
||||||
|
#include "compiler.hpp"
|
||||||
|
|
||||||
|
constexpr std::array<uint8_t, 80> chip8_fontset = {
|
||||||
|
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||||
|
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||||
|
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||||
|
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||||
|
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||||
|
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||||
|
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||||
|
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||||
|
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||||
|
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||||
|
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||||
|
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::map<SDL_Scancode, int> scancodes = {
|
||||||
|
{SDL_SCANCODE_0, 0},
|
||||||
|
{SDL_SCANCODE_1, 1},
|
||||||
|
{SDL_SCANCODE_2, 2},
|
||||||
|
{SDL_SCANCODE_3, 3},
|
||||||
|
{SDL_SCANCODE_4, 4},
|
||||||
|
{SDL_SCANCODE_5, 5},
|
||||||
|
{SDL_SCANCODE_6, 6},
|
||||||
|
|
||||||
|
{SDL_SCANCODE_KP_0, 0},
|
||||||
|
{SDL_SCANCODE_KP_1, 1},
|
||||||
|
{SDL_SCANCODE_KP_2, 2},
|
||||||
|
{SDL_SCANCODE_KP_3, 3},
|
||||||
|
{SDL_SCANCODE_KP_4, 4},
|
||||||
|
{SDL_SCANCODE_KP_5, 5},
|
||||||
|
{SDL_SCANCODE_KP_6, 6}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_rom_open = false;
|
||||||
|
|
||||||
|
void load_rom(const char* path) {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
memcpy(state.memory, chip8_fontset.data(), chip8_fontset.size());
|
||||||
|
|
||||||
|
FILE* file = fopen(path, "rb");
|
||||||
|
|
||||||
|
fseek(file, 0L, SEEK_END);
|
||||||
|
auto sz = ftell(file);
|
||||||
|
fseek(file, 0L, SEEK_SET);
|
||||||
|
|
||||||
|
fread(state.memory + program_begin, sz, 1, file);
|
||||||
|
|
||||||
|
is_rom_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_short_debug_string(uint16_t opcode) {
|
||||||
|
if(opcode == 0)
|
||||||
|
return "invalid opcode";
|
||||||
|
|
||||||
|
const uint16_t id = opcode >> 12;
|
||||||
|
const uint8_t nn = opcode & 0x00ff;
|
||||||
|
|
||||||
|
switch(id) {
|
||||||
|
case 0x0:
|
||||||
|
{
|
||||||
|
if(nn == 0xE0) {
|
||||||
|
return "clear screen";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
{
|
||||||
|
return "call subroutine";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
{
|
||||||
|
return "v[x] = nn";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
return "display sprite";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint quad_vao = 0;
|
||||||
|
GLuint pixel_program = 0;
|
||||||
|
GLuint pixels_texture = 0;
|
||||||
|
|
||||||
|
void setup_gfx() {
|
||||||
|
// create quad for pixel rendering
|
||||||
|
constexpr std::array vertices = {
|
||||||
|
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array elements = {
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &quad_vao);
|
||||||
|
glBindVertexArray(quad_vao);
|
||||||
|
|
||||||
|
GLuint vbo = 0;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float)));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
GLuint ebo = 0;
|
||||||
|
glGenBuffers(1, &ebo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(uint32_t), elements.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
constexpr std::string_view vertex_glsl =
|
||||||
|
"#version 330 core\n"
|
||||||
|
"layout (location = 0) in vec3 in_position;\n"
|
||||||
|
"layout (location = 1) in vec2 in_uv;\n"
|
||||||
|
"out vec2 uv;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_Position = vec4(in_position.xyz, 1.0);\n"
|
||||||
|
" uv = in_uv;\n"
|
||||||
|
"}\n";
|
||||||
|
const char* vertex_src = vertex_glsl.data();
|
||||||
|
|
||||||
|
constexpr std::string_view fragment_glsl =
|
||||||
|
"#version 330 core\n"
|
||||||
|
"in vec2 uv;\n"
|
||||||
|
"out vec4 out_color;\n"
|
||||||
|
"uniform sampler2D pixel_texture;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" out_color.rgb = vec3(1) * (texture(pixel_texture, uv).r * 255);\n"
|
||||||
|
"}\n";
|
||||||
|
const char* fragment_src = fragment_glsl.data();
|
||||||
|
|
||||||
|
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(vertex_shader, 1, &vertex_src, nullptr);
|
||||||
|
glCompileShader(vertex_shader);
|
||||||
|
|
||||||
|
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(fragment_shader, 1, &fragment_src, nullptr);
|
||||||
|
glCompileShader(fragment_shader);
|
||||||
|
|
||||||
|
pixel_program = glCreateProgram();
|
||||||
|
|
||||||
|
glAttachShader(pixel_program, vertex_shader);
|
||||||
|
glAttachShader(pixel_program, fragment_shader);
|
||||||
|
glLinkProgram(pixel_program);
|
||||||
|
|
||||||
|
glDeleteShader(vertex_shader);
|
||||||
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
|
glGenTextures(1, &pixels_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pixels_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, screen_width, screen_height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
|
SDL_Window* window = SDL_CreateWindow("chip8", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
|
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||||
|
SDL_GL_MakeCurrent(window, gl_context);
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
|
||||||
|
gladLoadGL();
|
||||||
|
setup_gfx();
|
||||||
|
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 330 core");
|
||||||
|
|
||||||
|
std::vector<std::string> rom_paths;
|
||||||
|
for(auto& p: std::filesystem::directory_iterator("roms/"))
|
||||||
|
rom_paths.push_back(p.path());
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
while(running) {
|
||||||
|
SDL_Event event = {};
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
|
|
||||||
|
if(event.type == SDL_QUIT)
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
if(event.type == SDL_KEYDOWN) {
|
||||||
|
if(scancodes.count(event.key.keysym.scancode))
|
||||||
|
state.keys[scancodes.at(event.key.keysym.scancode)] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.type == SDL_KEYUP) {
|
||||||
|
if(scancodes.count(event.key.keysym.scancode))
|
||||||
|
state.keys[scancodes.at(event.key.keysym.scancode)] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame(window);
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
if(ImGui::BeginMainMenuBar()) {
|
||||||
|
if(ImGui::BeginMenu("File")) {
|
||||||
|
if(ImGui::BeginMenu("Open ROM...")) {
|
||||||
|
for(auto& rom : rom_paths) {
|
||||||
|
if(ImGui::Button(rom.c_str()))
|
||||||
|
load_rom(rom.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem("Compile & Run Program")) {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
memcpy(state.memory, chip8_fontset.data(), chip8_fontset.size());
|
||||||
|
|
||||||
|
compile();
|
||||||
|
load_compiled_rom();
|
||||||
|
|
||||||
|
is_rom_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu("Options")) {
|
||||||
|
ImGui::MenuItem("Enable Anti-flicker", nullptr, &options.enable_anti_flicker);
|
||||||
|
ImGui::MenuItem("Emulate Original CHIP-8", nullptr, &options.emulate_original);
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state.delay_timer > 0)
|
||||||
|
state.delay_timer--;
|
||||||
|
|
||||||
|
const uint16_t opcode = (state.memory[state.PC] << 8) | state.memory[state.PC + 1];
|
||||||
|
if(is_rom_open && !pause_execution)
|
||||||
|
process_opcode(opcode);
|
||||||
|
|
||||||
|
if(ImGui::Begin("Memory")) {
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
ImGui::Text("V[%i] = %i", i, state.v[i]);
|
||||||
|
|
||||||
|
for(int i = program_begin; i < 4096; i++)
|
||||||
|
ImGui::Text("mem[%i] = %i", i, state.memory[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if(ImGui::Begin("Debugger")) {
|
||||||
|
if(ImGui::Button(pause_execution ? "Play" : "Pause"))
|
||||||
|
pause_execution = !pause_execution;
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if(ImGui::Button("Step"))
|
||||||
|
process_opcode(opcode);
|
||||||
|
|
||||||
|
static bool enable_auto_scroll = true;
|
||||||
|
ImGui::Checkbox("Enable auto scroll", &enable_auto_scroll);
|
||||||
|
|
||||||
|
ImGui::BeginChild("progam_edit", ImVec2(-1, -1), true);
|
||||||
|
|
||||||
|
for(int i = program_begin; i < 4096; i += 2) {
|
||||||
|
std::string s;
|
||||||
|
s.reserve(50);
|
||||||
|
|
||||||
|
uint16_t opcode = (state.memory[i] << 8) | state.memory[i + 1];
|
||||||
|
auto debug_string = get_short_debug_string(opcode);
|
||||||
|
|
||||||
|
sprintf(s.data(), "[0x%02X] 0x%04X ; %s", i, opcode, debug_string.c_str());
|
||||||
|
|
||||||
|
ImGui::Selectable(s.c_str(), state.PC == i);
|
||||||
|
|
||||||
|
if(state.PC == i && enable_auto_scroll && !pause_execution && is_rom_open) {
|
||||||
|
ImGui::SetScrollHereY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if(state.draw_dirty) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pixels_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, screen_width, screen_height, 0, GL_RED, GL_UNSIGNED_BYTE, state.pixels);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
state.draw_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
glUseProgram(pixel_program);
|
||||||
|
glBindVertexArray(quad_vao);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, pixels_texture);
|
||||||
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
|
SDL_GL_SwapWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
178
tests/test.cpp
Normal file
178
tests/test.cpp
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#define DOCTEST_CONFIG_COLORS_NONE
|
||||||
|
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||||
|
#include "doctest.h"
|
||||||
|
|
||||||
|
#include "emu.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x1") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
process_opcode(0x1100);
|
||||||
|
|
||||||
|
CHECK(state.PC == 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x3") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
// set v[1] to 1
|
||||||
|
process_opcode(0x6101);
|
||||||
|
|
||||||
|
// should skip if v[1] == 1
|
||||||
|
process_opcode(0x3101);
|
||||||
|
CHECK(state.PC == 0x206);
|
||||||
|
|
||||||
|
// should not skip since v[1] != 2
|
||||||
|
process_opcode(0x3102);
|
||||||
|
CHECK(state.PC == 0x208);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x4") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
// set v[1] to 1
|
||||||
|
process_opcode(0x6101);
|
||||||
|
|
||||||
|
// should not skip since v[1] == 1
|
||||||
|
process_opcode(0x4101);
|
||||||
|
CHECK(state.PC == 0x204);
|
||||||
|
|
||||||
|
// should skip since v[1] != 2
|
||||||
|
process_opcode(0x4102);
|
||||||
|
CHECK(state.PC == 0x208);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x6") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
process_opcode(0x6199);
|
||||||
|
|
||||||
|
CHECK(state.v[1] == 0x99);
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x7") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
// add 1 + 1
|
||||||
|
process_opcode(0x7101);
|
||||||
|
process_opcode(0x7101);
|
||||||
|
|
||||||
|
CHECK(state.v[1] == 0x02);
|
||||||
|
CHECK(state.PC == 0x204);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x8XY0") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
// set v[1] to 3
|
||||||
|
process_opcode(0x6103);
|
||||||
|
|
||||||
|
// set v[2] = 4
|
||||||
|
process_opcode(0x6204);
|
||||||
|
|
||||||
|
// set v[1] to v[2]
|
||||||
|
process_opcode(0x8120);
|
||||||
|
|
||||||
|
CHECK(state.v[1] == 0x04);
|
||||||
|
CHECK(state.PC == 0x206);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0xA") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
process_opcode(0xABCD);
|
||||||
|
|
||||||
|
CHECK(state.I == 0xBCD);
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: find a way to test this!!
|
||||||
|
TEST_CASE("Test 0xC") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
process_opcode(0xC122);
|
||||||
|
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0xFX07") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
state.delay_timer = 5;
|
||||||
|
|
||||||
|
process_opcode(0xF107);
|
||||||
|
|
||||||
|
CHECK(state.v[1] == 0x5);
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0xFX1E") {
|
||||||
|
SUBCASE("") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
state.I = 5;
|
||||||
|
|
||||||
|
// set v[1] to 5
|
||||||
|
process_opcode(0x6105);
|
||||||
|
|
||||||
|
process_opcode(0xF11E);
|
||||||
|
|
||||||
|
CHECK(state.I == 10);
|
||||||
|
CHECK(state.PC == 0x204);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Overflow") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
state.I = 4095;
|
||||||
|
|
||||||
|
// set v[1] to 5
|
||||||
|
process_opcode(0x6125);
|
||||||
|
|
||||||
|
process_opcode(0xF11E);
|
||||||
|
|
||||||
|
CHECK(state.v[0xF] == 1);
|
||||||
|
CHECK(state.PC == 0x204);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x33") {
|
||||||
|
SUBCASE("Zero") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
process_opcode(0xF133);
|
||||||
|
|
||||||
|
CHECK(state.memory[state.I] == 0);
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Larger than Zero") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
// store 0x65 == 101
|
||||||
|
process_opcode(0x6165);
|
||||||
|
|
||||||
|
process_opcode(0xF133);
|
||||||
|
|
||||||
|
CHECK(state.memory[state.I] == 1);
|
||||||
|
CHECK(state.memory[state.I + 1] == 0);
|
||||||
|
CHECK(state.memory[state.I + 2] == 1);
|
||||||
|
CHECK(state.PC == 0x204);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test 0x65") {
|
||||||
|
state.reset();
|
||||||
|
|
||||||
|
state.memory[state.I] = 0x1;
|
||||||
|
state.memory[state.I + 1] = 0x2;
|
||||||
|
state.memory[state.I + 2] = 0x3;
|
||||||
|
|
||||||
|
process_opcode(0xF265);
|
||||||
|
|
||||||
|
CHECK(state.v[0] == 0x1);
|
||||||
|
CHECK(state.v[1] == 0x2);
|
||||||
|
CHECK(state.v[2] == 0x3);
|
||||||
|
CHECK(state.PC == 0x202);
|
||||||
|
}
|
Reference in a new issue