├── .appveyor.yml ├── .clang-format ├── .codecov.yml ├── .dockerignore ├── .github └── workflows │ └── build-and-test.yml ├── .gitignore ├── .gitmodules ├── CMakeCPack.cmake ├── CMakeLists.txt ├── CONTRIBUTING.md ├── COPYING ├── CTestConfig.cmake ├── Doxyfile ├── README.md ├── assets └── logo_box.svg ├── benchmarks └── staunton.txt ├── cmake ├── ctest │ ├── build.ctest │ ├── configure_darwin.ctest │ ├── configure_linux.ctest │ ├── configure_windows.ctest │ ├── script_ci.ctest │ ├── script_experimental.ctest │ └── utils.ctest └── modules │ ├── CodeCoverage.cmake │ ├── FindClangTidy.cmake │ ├── FindFFmpeg.cmake │ ├── FindGLM.cmake │ ├── FindIncludeWhatYouUse.cmake │ ├── FindSDL2.cmake │ ├── GetGitRevisionDescription.cmake │ ├── GetGitRevisionDescription.cmake.in │ ├── WrapTargets.cmake │ └── llvm-cov-wrapper.in ├── cmake_configure.cmake ├── cmake_options.cmake ├── conanfile.py ├── external ├── CMakeLists.txt ├── imgui │ ├── CMakeLists.txt │ └── rw_imconfig.h └── microprofile │ └── CMakeLists.txt ├── openrw_iwyu.imp ├── rwcore ├── CMakeLists.txt ├── data │ ├── Clump.cpp │ └── Clump.hpp ├── fonts │ ├── FontMap.cpp │ ├── FontMap.hpp │ ├── FontMapGta3.cpp │ ├── FontMapGta3.hpp │ ├── GameTexts.cpp │ ├── GameTexts.hpp │ ├── Unicode.cpp │ └── Unicode.hpp ├── gl │ ├── DrawBuffer.cpp │ ├── DrawBuffer.hpp │ ├── GeometryBuffer.cpp │ ├── GeometryBuffer.hpp │ ├── TextureData.cpp │ ├── TextureData.hpp │ ├── gl_core_3_3.c │ └── gl_core_3_3.h ├── loaders │ ├── LoaderDFF.cpp │ ├── LoaderDFF.hpp │ ├── LoaderIMG.cpp │ ├── LoaderIMG.hpp │ ├── LoaderSDT.cpp │ ├── LoaderSDT.hpp │ ├── LoaderTXD.cpp │ ├── LoaderTXD.hpp │ └── RWBinaryStream.hpp ├── platform │ ├── FileHandle.hpp │ ├── FileIndex.cpp │ ├── FileIndex.hpp │ ├── RWWindows.cpp │ └── RWWindows.hpp └── rw │ ├── abort.cpp │ ├── casts.hpp │ ├── debug.hpp │ ├── forward.hpp │ └── types.hpp ├── rwengine ├── CMakeLists.txt ├── README.md └── src │ ├── ai │ ├── AIGraph.cpp │ ├── AIGraph.hpp │ ├── AIGraphNode.cpp │ ├── AIGraphNode.hpp │ ├── CharacterController.cpp │ ├── CharacterController.hpp │ ├── DefaultAIController.cpp │ ├── DefaultAIController.hpp │ ├── PlayerController.cpp │ ├── PlayerController.hpp │ ├── TrafficDirector.cpp │ └── TrafficDirector.hpp │ ├── audio │ ├── SfxParameters.cpp │ ├── SfxParameters.hpp │ ├── Sound.cpp │ ├── Sound.hpp │ ├── SoundBuffer.cpp │ ├── SoundBuffer.hpp │ ├── SoundBufferStreamed.cpp │ ├── SoundBufferStreamed.hpp │ ├── SoundManager.cpp │ ├── SoundManager.hpp │ ├── SoundSource.cpp │ ├── SoundSource.hpp │ ├── alCheck.cpp │ └── alCheck.hpp │ ├── core │ ├── Logger.cpp │ ├── Logger.hpp │ ├── Profiler.cpp │ └── Profiler.hpp │ ├── data │ ├── AnimGroup.cpp │ ├── AnimGroup.hpp │ ├── Chase.cpp │ ├── Chase.hpp │ ├── CollisionModel.hpp │ ├── CutsceneData.cpp │ ├── CutsceneData.hpp │ ├── InstanceData.hpp │ ├── ModelData.cpp │ ├── ModelData.hpp │ ├── PathData.hpp │ ├── PedData.cpp │ ├── PedData.hpp │ ├── VehicleGenerator.hpp │ ├── WeaponData.hpp │ ├── Weather.cpp │ ├── Weather.hpp │ ├── ZoneData.cpp │ └── ZoneData.hpp │ ├── dynamics │ ├── CollisionInstance.cpp │ ├── CollisionInstance.hpp │ ├── HitTest.cpp │ ├── HitTest.hpp │ └── RaycastCallbacks.hpp │ ├── engine │ ├── Animator.cpp │ ├── Animator.hpp │ ├── GameData.cpp │ ├── GameData.hpp │ ├── GameInputState.hpp │ ├── GameState.cpp │ ├── GameState.hpp │ ├── GameWorld.cpp │ ├── GameWorld.hpp │ ├── Garage.cpp │ ├── Garage.hpp │ ├── Payphone.cpp │ ├── Payphone.hpp │ ├── SaveGame.cpp │ ├── SaveGame.hpp │ ├── ScreenText.cpp │ └── ScreenText.hpp │ ├── items │ ├── Weapon.cpp │ └── Weapon.hpp │ ├── loaders │ ├── GenericDATLoader.cpp │ ├── GenericDATLoader.hpp │ ├── LoaderCOL.cpp │ ├── LoaderCOL.hpp │ ├── LoaderCutsceneDAT.cpp │ ├── LoaderCutsceneDAT.hpp │ ├── LoaderGXT.cpp │ ├── LoaderGXT.hpp │ ├── LoaderIDE.cpp │ ├── LoaderIDE.hpp │ ├── LoaderIFP.cpp │ ├── LoaderIFP.hpp │ ├── LoaderIPL.cpp │ ├── LoaderIPL.hpp │ ├── WeatherLoader.cpp │ └── WeatherLoader.hpp │ ├── objects │ ├── CharacterObject.cpp │ ├── CharacterObject.hpp │ ├── CutsceneObject.cpp │ ├── CutsceneObject.hpp │ ├── GameObject.cpp │ ├── GameObject.hpp │ ├── InstanceObject.cpp │ ├── InstanceObject.hpp │ ├── ObjectTypes.hpp │ ├── PickupObject.cpp │ ├── PickupObject.hpp │ ├── ProjectileObject.cpp │ ├── ProjectileObject.hpp │ ├── VehicleInfo.hpp │ ├── VehicleObject.cpp │ └── VehicleObject.hpp │ ├── render │ ├── DebugDraw.cpp │ ├── DebugDraw.hpp │ ├── GameRenderer.cpp │ ├── GameRenderer.hpp │ ├── GameShaders.hpp │ ├── MapRenderer.cpp │ ├── MapRenderer.hpp │ ├── ObjectRenderer.cpp │ ├── ObjectRenderer.hpp │ ├── OpenGLRenderer.cpp │ ├── OpenGLRenderer.hpp │ ├── TextRenderer.cpp │ ├── TextRenderer.hpp │ ├── ViewCamera.hpp │ ├── ViewFrustum.cpp │ ├── ViewFrustum.hpp │ ├── VisualFX.cpp │ ├── VisualFX.hpp │ ├── WaterRenderer.cpp │ └── WaterRenderer.hpp │ ├── rw_mingw.hpp │ └── script │ ├── SCMFile.cpp │ ├── SCMFile.hpp │ ├── ScriptFunctions.cpp │ ├── ScriptFunctions.hpp │ ├── ScriptMachine.cpp │ ├── ScriptMachine.hpp │ ├── ScriptModule.cpp │ ├── ScriptModule.hpp │ ├── ScriptTypes.cpp │ ├── ScriptTypes.hpp │ └── modules │ ├── GTA3Module.cpp │ ├── GTA3Module.hpp │ └── GTA3ModuleImpl.inl ├── rwgame ├── CMakeLists.txt ├── GameBase.cpp ├── GameBase.hpp ├── GameInput.cpp ├── GameInput.hpp ├── GameWindow.cpp ├── GameWindow.hpp ├── GitSHA1.cpp.in ├── GitSHA1.h ├── HUDDrawer.cpp ├── HUDDrawer.hpp ├── MenuSystem.cpp ├── MenuSystem.hpp ├── README.md ├── RWConfig.cpp ├── RWConfig.hpp ├── RWConfig.inc ├── RWGame.cpp ├── RWGame.hpp ├── RWImGui.cpp ├── RWImGui.hpp ├── State.cpp ├── State.hpp ├── StateManager.cpp ├── StateManager.hpp ├── WindowIcon.hpp ├── game.hpp ├── main.cpp └── states │ ├── BenchmarkState.cpp │ ├── BenchmarkState.hpp │ ├── DebugState.cpp │ ├── DebugState.hpp │ ├── IngameState.cpp │ ├── IngameState.hpp │ ├── LoadingState.cpp │ ├── LoadingState.hpp │ ├── MenuState.cpp │ ├── MenuState.hpp │ ├── PauseState.cpp │ └── PauseState.hpp ├── rwtools ├── CMakeLists.txt └── rwfont │ ├── CMakeLists.txt │ └── rwfontmap.cpp ├── rwviewer ├── CMakeLists.txt ├── QOpenGLContextWrapper.cpp ├── QOpenGLContextWrapper.hpp ├── README.md ├── ViewerWidget.cpp ├── ViewerWidget.hpp ├── ViewerWindow.cpp ├── ViewerWindow.hpp ├── main.cpp ├── models │ ├── AnimationListModel.cpp │ ├── AnimationListModel.hpp │ ├── DFFFramesTreeModel.cpp │ ├── DFFFramesTreeModel.hpp │ ├── IMGArchiveModel.cpp │ ├── IMGArchiveModel.hpp │ ├── ItemListModel.cpp │ ├── ItemListModel.hpp │ ├── ObjectListModel.cpp │ ├── ObjectListModel.hpp │ ├── TextModel.cpp │ └── TextModel.hpp ├── qt.conf.in ├── views │ ├── ModelViewer.cpp │ ├── ModelViewer.hpp │ ├── ObjectViewer.cpp │ ├── ObjectViewer.hpp │ ├── TextViewer.cpp │ ├── TextViewer.hpp │ ├── ViewerInterface.cpp │ ├── ViewerInterface.hpp │ ├── WorldViewer.cpp │ └── WorldViewer.hpp └── widgets │ ├── AnimationListWidget.cpp │ ├── AnimationListWidget.hpp │ ├── ItemListWidget.cpp │ ├── ItemListWidget.hpp │ ├── ModelFramesWidget.cpp │ └── ModelFramesWidget.hpp ├── scripts ├── conan │ └── create_vs_solution.py ├── docker │ ├── conan_base.docker │ ├── docker_build.sh │ └── docker_tool.py ├── generate_scripts_functions.py └── verify-commit └── tests ├── CMakeLists.txt ├── main.cpp ├── test_Animation.cpp ├── test_Archive.cpp ├── test_AudioLoading.cpp ├── test_Buoyancy.cpp ├── test_Character.cpp ├── test_Chase.cpp ├── test_Config.cpp ├── test_Cutscene.cpp ├── test_Data.cpp ├── test_FileIndex.cpp ├── test_GameData.cpp ├── test_GameWorld.cpp ├── test_Garage.cpp ├── test_Globals.cpp ├── test_Globals.hpp ├── test_HitTest.cpp ├── test_Input.cpp ├── test_Items.cpp ├── test_Lifetime.cpp ├── test_LoaderDFF.cpp ├── test_LoaderIDE.cpp ├── test_LoaderIPL.cpp ├── test_Logger.cpp ├── test_Menu.cpp ├── test_Object.cpp ├── test_Payphone.cpp ├── test_Pickup.cpp ├── test_RWBStream.cpp ├── test_Renderer.cpp ├── test_SaveGame.cpp ├── test_ScriptMachine.cpp ├── test_Sound.cpp ├── test_State.cpp ├── test_StringEncoding.cpp ├── test_Text.cpp ├── test_TrafficDirector.cpp ├── test_Vehicle.cpp ├── test_ViewCamera.cpp ├── test_VisualFX.cpp ├── test_Weapon.cpp ├── test_World.cpp └── test_ZoneData.cpp /.appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2017 3 | 4 | clone_depth: 1 5 | shallow_clone: false 6 | 7 | cache: 8 | - C:\Users\appveyor\.conan -> conanfile.py 9 | - C:\.conan -> conanfile.py 10 | 11 | environment: 12 | APPVEYOR_SAVE_CACHE_ON_ERROR: true 13 | ALSOFT_DRIVERS: null 14 | PYTHON: "C:\\Python36-x64" 15 | CMAKE_GENERATOR_BASE: "Visual Studio 15 2017" 16 | NAME_SUFFIX: "windows" 17 | USE_CONAN: 1 18 | 19 | platform: 20 | - x64 21 | 22 | configuration: 23 | - RelWithDebInfo 24 | 25 | matrix: 26 | fast_finish: false 27 | 28 | clone_folder: C:\projects\openrw 29 | 30 | init: 31 | - set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH% 32 | - python --version 33 | - cmake --version 34 | - msbuild /version 35 | - pip3 install conan 36 | - conan user 37 | - conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan 38 | 39 | install: 40 | - cd "%APPVEYOR_BUILD_FOLDER%" 41 | - for /f %%i in ('git rev-parse HEAD') do set COMMIT_HASH=%%i 42 | - echo APPVEYOR_REPO_COMMIT=%APPVEYOR_REPO_COMMIT%, COMMIT_HASH=%COMMIT_HASH% 43 | - if NOT "%APPVEYOR_REPO_COMMIT%" == "%COMMIT_HASH%" echo "Appveyor git hash does not match git checkout hash" 44 | - git submodule update --init --recursive 45 | 46 | build_script: 47 | - ctest -VV -S "%APPVEYOR_BUILD_FOLDER%/cmake/ctest/script_ci.ctest" 48 | 49 | after_build: 50 | - cd "%APPVEYOR_BUILD_FOLDER%\build" 51 | - cpack -C %CONFIGURATION% -G TXZ 52 | - appveyor PushArtifact OpenRW-%COMMIT_HASH:~0,8%.tar.xz 53 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | UseTab: Never 3 | TabWidth: 4 4 | IndentWidth: 4 5 | AccessModifierOffset: -4 6 | ColumnLimit: 80 7 | # Makes maintaining initalizer lists a little easier 8 | BreakConstructorInitializersBeforeComma: true 9 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 10 | # Single line methods can be harder to read 11 | AllowShortFunctionsOnASingleLine: false 12 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: no 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | build 2 | .git 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | documentation/ 3 | *.kdev4 4 | *~ 5 | *swp 6 | *.user* 7 | .DS_Store 8 | .vscode/ 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/microprofile/microprofile"] 2 | path = external/microprofile/microprofile 3 | url = https://github.com/jonasmr/microprofile.git 4 | [submodule "imgui"] 5 | path = external/imgui/imgui 6 | url = https://github.com/ocornut/imgui.git 7 | -------------------------------------------------------------------------------- /CMakeCPack.cmake: -------------------------------------------------------------------------------- 1 | set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") 2 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenRW 'Open ReWrite' is an un-official open source recreation of the classic Grand Theft Auto III game executable") 3 | set(CPACK_PACKAGE_VENDOR "openrw") 4 | 5 | # FIXME: better description of the project 6 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") 7 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") 8 | string(SUBSTRING "${GIT_SHA1}" 0 8 GIT_SHA1_SHORT) 9 | set(CPACK_PACKAGE_VERSION "${GIT_SHA1_SHORT}") 10 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") 11 | set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${GIT_SHA1_SHORT}") 12 | 13 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${GIT_SHA1_SHORT}") 14 | 15 | # set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakeCPackOptions.cmake") 16 | 17 | include(CPack) 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | To find out how to report bugs or contribute code, please read the [contributing](https://github.com/rwengine/openrw/wiki/Contributing) 4 | page. This page covers what types of contributions we are looking to encourage. 5 | 6 | -------------------------------------------------------------------------------- /CTestConfig.cmake: -------------------------------------------------------------------------------- 1 | set(CTEST_PROJECT_NAME "OpenRW") 2 | set(CTEST_NIGHTLY_START_TIME "00:00:00 UTC") 3 | 4 | set(CTEST_DROP_METHOD "http") 5 | set(CTEST_DROP_SITE "my.cdash.org") 6 | set(CTEST_DROP_LOCATION "/submit.php?project=OpenRW") 7 | set(CTEST_DROP_SITE_CDASH TRUE) 8 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME=OpenRW 2 | OUTPUT_DIRECTORY=documentation/ 3 | INPUT=. 4 | RECURSIVE=YES 5 | EXCLUDE=tests 6 | GENERATE_LATEX=NO 7 | GENERATE_HTML=YES 8 | HTML_OUTPUT= 9 | -------------------------------------------------------------------------------- /benchmarks/staunton.txt: -------------------------------------------------------------------------------- 1 | 08:24 2 | 0.0 223.713 -932.996 39.7714 -0.0349867 -0.000671823 0.999203 -0.019187 3 | 4.0 -58.2506 -932.051 39.0313 -0.00500017 2.90018e-05 0.999971 0.00579998 4 | 5.0 -73.2921 -912.005 42.1964 0.0385652 -0.023159 0.85643 0.514299 5 | 10.0 -68.8951 -657.732 51.1204 0.024994 -0.000394904 0.999563 0.0157931 6 | 11.0 -68.6302 -606.736 51.1204 0.029995 0.00012602 0.999541 -0.00419943 7 | 12.0 -63.6714 -551.434 50.5424 0.00761077 0.0443366 -0.169013 0.984587 8 | 14.0 -7.03103 -536.598 52.4339 -0.00597171 -0.00802059 -0.597167 0.802054 9 | 16 75.3989 -552.881 51.6476 0.0135587 0.0147009 -0.677838 0.73494 10 | 18 122.486 -619.493 51.8563 -0.00149907 0.049957 0.0299563 0.998301 11 | 20 218.728 -621.121 49.6744 -0.000149926 0.0299954 0.00499597 0.999538 12 | 22 247.987 -612.902 49.7808 -0.0107077 0.0105041 0.713782 0.700207 13 | 23 252.07 -428.022 45.268 -0.0142063 0.0140762 0.71021 0.703706 14 | 24 248.357 -407.665 45.6739 -0.00471838 0.0142383 0.314529 0.949129 15 | 28 248.874 -200.207 31.009 -0.0252925 -0.0652093 -0.360732 0.930043 16 | 30 250.075 -131.669 35.7747 0.00965595 0.0230571 0.386159 -0.922094 17 | -------------------------------------------------------------------------------- /cmake/ctest/configure_darwin.ctest: -------------------------------------------------------------------------------- 1 | set(CMAKE_GENERATOR "Xcode") 2 | if($ENV{DEBUG}) 3 | set(BUILD_TYPE "Debug") 4 | else() 5 | set(BUILD_TYPE "Release") 6 | endif() 7 | set(CONFIGURE_EXTRA_OPTIONS ";") 8 | set(BUILD_EXTRA_FLAGS "") 9 | set(BUILD_TOOLS FALSE) 10 | set(BUILD_VIEWER FALSE) 11 | set(CHECK_IWYU FALSE) 12 | set(ENABLE_SANITIZERS "") 13 | 14 | if(MODEL_NAME STREQUAL "EXPERIMENTAL") 15 | set(CHECK_IWYU FALSE) 16 | else() 17 | set(CHECK_IWYU FALSE) 18 | endif() 19 | 20 | set(CONAN_ARCH "x86_64") 21 | -------------------------------------------------------------------------------- /cmake/ctest/configure_linux.ctest: -------------------------------------------------------------------------------- 1 | set(CMAKE_GENERATOR "Ninja") 2 | if($ENV{DEBUG}) 3 | set(BUILD_TYPE "Debug") 4 | else() 5 | set(BUILD_TYPE "Release") 6 | endif() 7 | set(CONFIGURE_EXTRA_OPTIONS ";") 8 | set(BUILD_EXTRA_FLAGS "") 9 | 10 | set(BUILD_TOOLS TRUE) 11 | set(BUILD_VIEWER TRUE) 12 | set(CHECK_IWYU FALSE) 13 | set(ENABLE_SANITIZERS "address") 14 | 15 | if(MODEL_NAME STREQUAL "EXPERIMENTAL") 16 | set(CHECK_IWYU FALSE) 17 | else() 18 | set(CHECK_IWYU FALSE) 19 | endif() 20 | 21 | set(CONAN_ARCH "x86_64") 22 | -------------------------------------------------------------------------------- /cmake/ctest/configure_windows.ctest: -------------------------------------------------------------------------------- 1 | set(_WIN_NEEDED_VARS 2 | CMAKE_GENERATOR_BASE 3 | PLATFORM 4 | CONFIGURATION 5 | ) 6 | foreach(_WIN_NEEDED_VAR ${_WIN_NEEDED_VARS}) 7 | set("${_WIN_NEEDED_VAR}" "$ENV{${_WIN_NEEDED_VAR}}") 8 | message(STATUS "configure_windows: script argument: ${_WIN_NEEDED_VAR} = '${${_WIN_NEEDED_VAR}}'") 9 | if("${${_WIN_NEEDED_VAR}}" STREQUAL "") 10 | message(FATAL_ERROR "${_WIN_NEEDED_VAR} is empty") 11 | endif() 12 | endforeach() 13 | 14 | string(TOLOWER "${ARCH}" ARCH) 15 | if(PLATFORM STREQUAL "win32") 16 | set(CMAKE_GENERATOR "${CMAKE_GENERATOR_BASE}") 17 | set(CONAN_ARCH "x86") 18 | elseif(PLATFORM STREQUAL "x64") 19 | set(CMAKE_GENERATOR "${CMAKE_GENERATOR_BASE} Win64") 20 | set(CONAN_ARCH "x86_64") 21 | else() 22 | message(FATAL_ERROR "Unknown platform (${PLATFORM})") 23 | endif() 24 | 25 | set(CONFIGURE_EXTRA_OPTIONS ";") 26 | set(BUILD_EXTRA_FLAGS "") 27 | 28 | set(BUILD_TYPE "${CONFIGURATION}") 29 | 30 | set(CONAN_ARCH "x86_64") 31 | 32 | set(BUILD_TOOLS TRUE) 33 | set(BUILD_VIEWER TRUE) 34 | set(CHECK_IWYU FALSE) #FIXME: ENABLE 35 | set(ENABLE_SANITIZERS "") 36 | -------------------------------------------------------------------------------- /cmake/ctest/script_ci.ctest: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.28) 2 | 3 | set(MODEL_NAME "continuous") 4 | 5 | include("${CTEST_SCRIPT_DIRECTORY}/utils.ctest") 6 | 7 | openrw_src_dir(CTEST_SOURCE_DIRECTORY) 8 | if($ENV{DOCKER}) 9 | set(CTEST_BINARY_DIRECTORY "/build") 10 | else() 11 | openrw_bin_dir_default(CTEST_BINARY_DIRECTORY) 12 | endif() 13 | set(CTEST_COMMAND "${CMAKE_CTEST_COMMAND}") 14 | 15 | message(STATUS "CTEST_SOURCE_DIRECTORY=${CTEST_SOURCE_DIRECTORY}") 16 | message(STATUS "CTEST_BINARY_DIRECTORY=${CTEST_BINARY_DIRECTORY}") 17 | 18 | openrw_build_name(BUILDER_NAME_BASE BUILD_NAME) 19 | set(BUILDER_NAME_BASE "${BUILDER_NAME_BASE}-$ENV{NAME_SUFFIX}") 20 | 21 | message(STATUS "Removing binary directory '${CTEST_BINARY_DIRECTORY}'...") 22 | if(EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") 23 | message(STATUS "CMakeCache.txt file exists ==> removing") 24 | ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}") 25 | endif() 26 | file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}") 27 | 28 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 29 | message(STATUS "Linux detected") 30 | 31 | include("${CTEST_SCRIPT_DIRECTORY}/configure_linux.ctest") 32 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") 33 | message(STATUS "Windows detected") 34 | 35 | include("${CTEST_SCRIPT_DIRECTORY}/configure_windows.ctest") 36 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 37 | message(STATUS "MacOS X detected") 38 | 39 | include("${CTEST_SCRIPT_DIRECTORY}/configure_darwin.ctest") 40 | else() 41 | message(FATAL_ERROR "Unknown CMAKE_SYSTEM_NAME detected '${CMAKE_SYSTEM_NAME}'") 42 | endif() 43 | 44 | if($ENV{USE_CONAN}) 45 | set(USE_CONAN TRUE) 46 | else() 47 | set(USE_CONAN FALSE) 48 | endif() 49 | 50 | set(SEPARATE_TEST_SUITES FALSE) 51 | set(RUN_MEMCHECK FALSE) 52 | openrw_should_submit_ci(SUBMIT) 53 | 54 | # Build with no data and test 55 | set(BUILDER_NAME "${BUILDER_NAME_BASE}") 56 | set(APPEND_RESULTS FALSE) 57 | set(RUN_TESTS TRUE) 58 | if($ENV{TEST_COVERAGE}) 59 | set(TEST_COVERAGE TRUE) 60 | else() 61 | set(TEST_COVERAGE FALSE) 62 | endif() 63 | 64 | set(CODECOV_FLAGS "nodata") 65 | 66 | include("${CTEST_SCRIPT_DIRECTORY}/build.ctest") 67 | 68 | handle_warnings_errors() 69 | -------------------------------------------------------------------------------- /cmake/ctest/script_experimental.ctest: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.28) 2 | 3 | set(MODEL_NAME "experimental") 4 | 5 | include("${CTEST_SCRIPT_DIRECTORY}/utils.ctest") 6 | 7 | openrw_src_dir(CTEST_SOURCE_DIRECTORY) 8 | if($ENV{DOCKER}) 9 | set(CTEST_BINARY_DIRECTORY "/build") 10 | else() 11 | openrw_bin_dir(CTEST_BINARY_DIRECTORY "experimental") 12 | endif() 13 | set(CTEST_COMMAND "${CMAKE_CTEST_COMMAND}") 14 | 15 | message(STATUS "CTEST_SOURCE_DIRECTORY=${CTEST_SOURCE_DIRECTORY}") 16 | message(STATUS "CTEST_BINARY_DIRECTORY=${CTEST_BINARY_DIRECTORY}") 17 | 18 | openrw_build_name(BUILDER_NAME BUILD_NAME) 19 | 20 | message(STATUS "Removing binary directory '${CTEST_BINARY_DIRECTORY}'...") 21 | if(EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") 22 | message(STATUS "CMakeCache.txt file exists ==> removing") 23 | ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}") 24 | endif() 25 | file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}") 26 | 27 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 28 | message(STATUS "Linux detected") 29 | 30 | include("${CTEST_SCRIPT_DIRECTORY}/configure_linux.ctest") 31 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") 32 | message(STATUS "Windows detected") 33 | 34 | include("${CTEST_SCRIPT_DIRECTORY}/configure_windows.ctest") 35 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 36 | message(STATUS "MacOS X detected") 37 | 38 | include("${CTEST_SCRIPT_DIRECTORY}/configure_darwin.ctest") 39 | else() 40 | message(FATAL_ERROR "Unknown CMAKE_SYSTEM_NAME detected '${CMAKE_SYSTEM_NAME}'") 41 | endif() 42 | 43 | if($ENV{USE_CONAN}) 44 | set(USE_CONAN TRUE) 45 | else() 46 | set(USE_CONAN FALSE) 47 | endif() 48 | 49 | set(SEPARATE_TEST_SUITES TRUE) 50 | 51 | if($ENV{TEST_COVERAGE}) 52 | set(TEST_COVERAGE TRUE) 53 | else() 54 | set(TEST_COVERAGE FALSE) 55 | endif() 56 | set(RUN_MEMCHECK FALSE) #TODO 57 | 58 | set(APPEND_RESULTS FALSE) 59 | if($ENV{USE_CONAN}) 60 | set(RES TRUE) 61 | else() 62 | set(RES FALSE) 63 | endif() 64 | 65 | set(RUN_TESTS TRUE) 66 | 67 | set(SUBMIT $ENV{SUBMIT}) 68 | 69 | set(CODECOV_FLAGS "data") 70 | 71 | include("${CTEST_SCRIPT_DIRECTORY}/build.ctest") 72 | 73 | handle_warnings_errors() 74 | -------------------------------------------------------------------------------- /cmake/modules/FindIncludeWhatYouUse.cmake: -------------------------------------------------------------------------------- 1 | find_program( 2 | INCLUDE_WHAT_YOU_USE_PROGRAM 3 | NAMES include_what_you_use iwyu 4 | ) 5 | 6 | include(FindPackageHandleStandardArgs) 7 | find_package_handle_standard_args(IncludeWhatYouUse 8 | REQUIRED_VARS 9 | INCLUDE_WHAT_YOU_USE_PROGRAM 10 | ) 11 | 12 | if(INCLUDEWHATYOUUSE_FOUND) 13 | include(CMakeParseArguments) 14 | 15 | function(iwyu_check) 16 | cmake_parse_arguments("IWYU" "" "TARGET" "EXTRA_OPTS" ${ARGN}) 17 | set(IWYU_CMD "${INCLUDE_WHAT_YOU_USE_PROGRAM}") 18 | foreach(OPT ${IWYU_EXTRA_OPTS}) 19 | list(APPEND IWYU_CMD "-Xiwyu" ${OPT}) 20 | endforeach() 21 | set_target_properties("${IWYU_TARGET}" 22 | PROPERTIES 23 | C_INCLUDE_WHAT_YOU_USE 24 | "${IWYU_CMD}" 25 | CXX_INCLUDE_WHAT_YOU_USE 26 | "${IWYU_CMD}" 27 | ) 28 | get_target_property(TARGET_SOURCES "${IWYU_TARGET}" SOURCES) 29 | set_source_files_properties(${TARGET_SOURCES} 30 | PROPERTIES 31 | OBJECT_DEPENDS "${IWYU_MAPPING}" 32 | ) 33 | endfunction() 34 | endif() 35 | -------------------------------------------------------------------------------- /cmake/modules/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | else() 27 | configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) 28 | file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) 29 | if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") 30 | set(HEAD_HASH "${CMAKE_MATCH_1}") 31 | endif() 32 | endif() 33 | else() 34 | # detached HEAD 35 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 36 | endif() 37 | 38 | if(NOT HEAD_HASH) 39 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 40 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/modules/WrapTargets.cmake: -------------------------------------------------------------------------------- 1 | function(rwdep_wrap_find_packages) 2 | if(BULLET_FOUND AND NOT TARGET bullet::bullet) 3 | add_library(bullet::bullet INTERFACE IMPORTED) 4 | set_property(TARGET bullet::bullet 5 | PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${BULLET_INCLUDE_DIR}) 6 | set_property(TARGET bullet::bullet 7 | PROPERTY INTERFACE_LINK_LIBRARIES ${BULLET_LIBRARIES}) 8 | endif() 9 | 10 | if(OPENAL_FOUND AND NOT TARGET OpenAL::OpenAL) 11 | add_library(OpenAL::OpenAL INTERFACE IMPORTED) 12 | set_property(TARGET OpenAL::OpenAL 13 | PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OPENAL_INCLUDE_DIR}) 14 | set_property(TARGET OpenAL::OpenAL 15 | PROPERTY INTERFACE_LINK_LIBRARIES ${OPENAL_LIBRARY}) 16 | endif() 17 | endfunction() 18 | 19 | function(rwdep_wrap_conan_target TARGET CONAN_NAME) 20 | add_library("${TARGET}" INTERFACE IMPORTED) 21 | set_property(TARGET "${TARGET}" 22 | PROPERTY INTERFACE_LINK_LIBRARIES "CONAN_PKG::${CONAN_NAME}") 23 | endfunction() 24 | 25 | function(rwdep_wrap_conan_targets) 26 | rwdep_wrap_conan_target(OpenAL::OpenAL openal) 27 | rwdep_wrap_conan_target(bullet::bullet bullet3) 28 | rwdep_wrap_conan_target(glm::glm glm) 29 | rwdep_wrap_conan_target(ffmpeg::ffmpeg ffmpeg) 30 | rwdep_wrap_conan_target(SDL2::SDL2 sdl2) 31 | if(BUILD_TOOLS) 32 | rwdep_wrap_conan_target(Freetype::Freetype freetype) 33 | endif() 34 | 35 | rwdep_wrap_conan_target(Boost::boost boost) 36 | rwdep_wrap_conan_target(Boost::program_options boost) 37 | rwdep_wrap_conan_target(Boost::system boost) 38 | rwdep_wrap_conan_target(Boost::unit_test_framework boost) 39 | endfunction() 40 | -------------------------------------------------------------------------------- /cmake/modules/llvm-cov-wrapper.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import subprocess 5 | import sys 6 | 7 | llvm_cov_bin = "@LLVM_COV_BIN@" 8 | 9 | # The wrapper must return the version for the "-v" and "--version" flags. 10 | # llvm-cov only accepts --version 11 | if any(h in sys.argv for h in ("-v", "--version",)): 12 | p = subprocess.Popen([llvm_cov_bin, "--version"], stdout=subprocess.PIPE) 13 | output = p.stdout.read().decode("utf8") 14 | p.wait() 15 | assert p.returncode == 0 16 | versionmatch = re.search("([0-9]+\\.[0-9]+(?:\\.[0-9]+))", output) 17 | if not versionmatch: 18 | raise RuntimeError("Cannot detect version") 19 | print(versionmatch) 20 | print("{} version {}".format(sys.argv[0], versionmatch.group(1))) 21 | sys.exit(0) 22 | 23 | p = subprocess.Popen([llvm_cov_bin, "gcov"] + sys.argv[1:]) 24 | p.wait() 25 | assert p.returncode == 0 26 | -------------------------------------------------------------------------------- /cmake_options.cmake: -------------------------------------------------------------------------------- 1 | option(RW_VERBOSE_DEBUG_MESSAGES "Print verbose debugging messages" ON) 2 | 3 | option(BUILD_TOOLS "Build tools") 4 | option(BUILD_TESTS "Build test suite") 5 | option(BUILD_VIEWER "Build GUI data viewer") 6 | 7 | option(ENABLE_SCRIPT_DEBUG "Enable verbose script execution") 8 | option(ENABLE_PROFILING "Enable detailed profiling metrics") 9 | 10 | option(TEST_DATA "Enable tests that require game data") 11 | 12 | set(FAILED_CHECK_ACTION "IGNORE" CACHE STRING "What action to perform on a failed RW_CHECK (in debug mode)") 13 | set_property(CACHE FAILED_CHECK_ACTION PROPERTY STRINGS "IGNORE" "ABORT" "BREAKPOINT") 14 | 15 | set(CMAKE_CONFIGURATION_TYPES "Release;Debug;RelWithDebInfo;MinSizeRel" CACHE INTERNAL "Build types supported by this project.") 16 | if(NOT CMAKE_BUILD_TYPE) 17 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}") 18 | endif() 19 | if(MSVC) 20 | option(MSVC_NO_DEBUG_RUNTIME "Don't use the debug runtime") 21 | endif() 22 | 23 | option(CHECK_IWYU "Enable IncludeWhatYouUse (Analyze #includes in C and C++ source files)") 24 | option(CHECK_CLANGTIDY "Enable clang-tidy (A clang-based C++ linter tool)") 25 | option(CHECK_CLANGTIDY_FIX "Apply fixes from clang-tidy (!!!RUN ON CLEAN GIT TREE!!!)") 26 | 27 | set(ENABLE_SANITIZERS "" CACHE STRING "Enable selected sanitizer.") 28 | 29 | set(CODECOV_NAME "" CACHE STRING "Name of report in codecov.io ui.") 30 | option(TEST_COVERAGE "Enable coverage analysis (implies CMAKE_BUILD_TYPE=Debug)") 31 | option(SEPARATE_TEST_SUITES "Add each test suite as separate test to CTest") 32 | 33 | option(BOOST_STATIC "Link against static Boost libraries") 34 | 35 | option(USE_CONAN "Use Conan as package manager") 36 | -------------------------------------------------------------------------------- /external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(ENABLE_PROFILING) 2 | add_subdirectory(microprofile) 3 | endif() 4 | 5 | add_subdirectory(imgui) 6 | -------------------------------------------------------------------------------- /external/imgui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(imgui EXCLUDE_FROM_ALL 2 | rw_imconfig.h 3 | imgui/imgui.h 4 | imgui/imgui.cpp 5 | imgui/imgui_demo.cpp 6 | imgui/imgui_draw.cpp 7 | imgui/imgui_internal.h 8 | imgui/imgui_widgets.cpp 9 | imgui/imstb_rectpack.h 10 | imgui/imstb_textedit.h 11 | imgui/imstb_truetype.h 12 | ) 13 | 14 | target_include_directories(imgui SYSTEM 15 | PUBLIC 16 | "${CMAKE_CURRENT_LIST_DIR}/imgui" 17 | ) 18 | 19 | target_compile_definitions(imgui 20 | PUBLIC 21 | IMGUI_USER_CONFIG="${CMAKE_CURRENT_SOURCE_DIR}/rw_imconfig.h" 22 | ) 23 | 24 | target_link_libraries(imgui 25 | PUBLIC 26 | openrw::checks 27 | ) 28 | 29 | add_library(imgui::core ALIAS imgui) 30 | 31 | openrw_target_apply_options( 32 | TARGET imgui 33 | ) 34 | 35 | add_library(imgui_sdl_gl3 EXCLUDE_FROM_ALL 36 | imgui/examples/imgui_impl_opengl3.h 37 | imgui/examples/imgui_impl_opengl3.cpp 38 | imgui/examples/imgui_impl_sdl.h 39 | imgui/examples/imgui_impl_sdl.cpp 40 | ) 41 | 42 | target_include_directories(imgui_sdl_gl3 SYSTEM 43 | PUBLIC 44 | "${CMAKE_CURRENT_LIST_DIR}/imgui/examples" 45 | ) 46 | 47 | target_link_libraries(imgui_sdl_gl3 48 | PUBLIC 49 | imgui::core 50 | SDL2::SDL2 51 | ) 52 | 53 | # FIXME: extract gl loader to target + add property to get header 54 | target_compile_definitions(imgui_sdl_gl3 55 | PRIVATE 56 | "IMGUI_IMPL_OPENGL_LOADER_CUSTOM=\"${OpenRW_SOURCE_DIR}/rwcore/gl/gl_core_3_3.h\"" 57 | ) 58 | 59 | add_library(imgui::sdl_gl3 ALIAS imgui_sdl_gl3) 60 | 61 | openrw_target_apply_options( 62 | TARGET imgui_sdl_gl3 63 | ) 64 | -------------------------------------------------------------------------------- /external/imgui/rw_imconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef RW_IMCONFIG_H 2 | #define RW_IMCONFIG_H 3 | 4 | // Disable imgui assertions when not in debug mode 5 | #ifndef RW_DEBUG 6 | #define IM_ASSERT(MSG) //FIXME(madebr): remove comment 7 | #endif 8 | 9 | #endif // RW_IMCONFIG_H 10 | -------------------------------------------------------------------------------- /external/microprofile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(microprofile STATIC 2 | microprofile/microprofile.h 3 | microprofile/microprofile_html.h 4 | microprofile/microprofile.cpp 5 | ) 6 | 7 | target_include_directories(microprofile 8 | PUBLIC 9 | "${CMAKE_CURRENT_SOURCE_DIR}/microprofile" 10 | ) 11 | 12 | target_compile_definitions(microprofile 13 | PUBLIC 14 | MICROPROFILE_GPU_TIMERS=0 15 | ) 16 | 17 | find_package(Threads REQUIRED) 18 | target_link_libraries(microprofile 19 | PUBLIC 20 | Threads::Threads 21 | openrw::checks 22 | ) 23 | 24 | openrw_target_apply_options( 25 | TARGET microprofile 26 | ) 27 | 28 | set_target_properties(microprofile 29 | PROPERTIES 30 | CXX_EXTENSIONS OFF 31 | CXX_STANDARD 11 32 | ) 33 | 34 | add_library(microprofile::microprofile ALIAS microprofile) 35 | -------------------------------------------------------------------------------- /rwcore/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(rwcore 2 | # GL stuff is only here temporarily, hoping to move it back to rwengine 3 | gl/gl_core_3_3.c 4 | gl/gl_core_3_3.h 5 | gl/DrawBuffer.hpp 6 | gl/DrawBuffer.cpp 7 | gl/GeometryBuffer.hpp 8 | gl/GeometryBuffer.cpp 9 | gl/TextureData.hpp 10 | gl/TextureData.cpp 11 | 12 | rw/abort.cpp 13 | rw/casts.hpp 14 | rw/forward.hpp 15 | rw/types.hpp 16 | rw/debug.hpp 17 | 18 | platform/FileHandle.hpp 19 | platform/FileIndex.hpp 20 | platform/FileIndex.cpp 21 | 22 | data/Clump.hpp 23 | data/Clump.cpp 24 | 25 | fonts/FontMap.cpp 26 | fonts/FontMap.hpp 27 | fonts/FontMapGta3.cpp 28 | fonts/FontMapGta3.hpp 29 | fonts/GameTexts.cpp 30 | fonts/GameTexts.hpp 31 | fonts/Unicode.cpp 32 | fonts/Unicode.hpp 33 | 34 | loaders/LoaderIMG.hpp 35 | loaders/LoaderIMG.cpp 36 | loaders/RWBinaryStream.hpp 37 | loaders/LoaderDFF.hpp 38 | loaders/LoaderDFF.cpp 39 | loaders/LoaderSDT.hpp 40 | loaders/LoaderSDT.cpp 41 | loaders/LoaderTXD.hpp 42 | loaders/LoaderTXD.cpp 43 | ) 44 | 45 | if(WIN32) 46 | target_sources(rwcore 47 | PRIVATE 48 | platform/RWWindows.hpp 49 | platform/RWWindows.cpp 50 | ) 51 | endif() 52 | 53 | target_include_directories(rwcore 54 | PUBLIC 55 | "${CMAKE_CURRENT_SOURCE_DIR}" 56 | ) 57 | 58 | target_link_libraries(rwcore 59 | PUBLIC 60 | Boost::boost 61 | glm::glm 62 | openrw::interface 63 | PRIVATE 64 | OpenGL::GL 65 | ) 66 | 67 | openrw_target_apply_options(TARGET rwcore 68 | CORE 69 | COVERAGE 70 | COVERAGE_EXCEPT gl/gl_core_3_3.c gl/gl_core_3_3.h 71 | ) 72 | 73 | if(BUILD_SHARED_LIBS) 74 | install(TARGETS rwcore 75 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 76 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 77 | ) 78 | endif() 79 | -------------------------------------------------------------------------------- /rwcore/fonts/FontMapGta3.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWLIB_FONTS_FONTMAPGTA3_HPP_ 2 | #define _RWLIB_FONTS_FONTMAPGTA3_HPP_ 3 | 4 | #include "FontMap.hpp" 5 | 6 | #include 7 | 8 | /** 9 | * Commong font mapping of all fonts. 10 | */ 11 | extern const FontMap fontmap_gta3_font_common; 12 | 13 | /** 14 | * Array of all font mappings. 15 | */ 16 | extern const std::array fontmaps_gta3_font; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /rwcore/fonts/GameTexts.cpp: -------------------------------------------------------------------------------- 1 | #include "GameTexts.hpp" 2 | 3 | // FIXME: Update for GTA VC 4 | #include "FontMapGta3.hpp" 5 | 6 | #include "rw/debug.hpp" 7 | 8 | GameString GameStringUtil::fromString(const std::string& str, font_t font) { 9 | RW_ASSERT(font < FONTS_COUNT); 10 | return fontmaps_gta3_font[font].to_GameString(str); 11 | } 12 | 13 | GameString GameStringUtil::fromStringCommon(const std::string& str) { 14 | return fontmap_gta3_font_common.to_GameString(str); 15 | } 16 | 17 | std::string GameStringUtil::toString(const GameString& str, font_t font) { 18 | return fontmaps_gta3_font[font].to_string(str); 19 | } 20 | -------------------------------------------------------------------------------- /rwcore/gl/DrawBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "gl/DrawBuffer.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | DrawBuffer::DrawBuffer() : vao(0) { 9 | } 10 | 11 | DrawBuffer::~DrawBuffer() { 12 | if (vao) { 13 | glDeleteVertexArrays(1, &vao); 14 | } 15 | } 16 | 17 | void DrawBuffer::addGeometry(GeometryBuffer* gbuff) { 18 | if (vao == 0) { 19 | glGenVertexArrays(1, &vao); 20 | } 21 | 22 | glBindVertexArray(vao); 23 | glBindBuffer(GL_ARRAY_BUFFER, gbuff->getVBOName()); 24 | // Iterate the attributes present in the gbuff 25 | for (const AttributeIndex& at : gbuff->getDataAttributes()) { 26 | auto vaoindex = static_cast(at.sem); 27 | glEnableVertexAttribArray(vaoindex); 28 | glVertexAttribPointer(vaoindex, static_cast(at.size), at.type, GL_TRUE, at.stride, 29 | reinterpret_cast(at.offset)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rwcore/gl/DrawBuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_DRAWBUFFER_HPP_ 2 | #define _LIBRW_DRAWBUFFER_HPP_ 3 | 4 | #include 5 | 6 | class GeometryBuffer; 7 | 8 | /** 9 | * DrawBuffer stores VAO state 10 | */ 11 | class DrawBuffer { 12 | GLuint vao; 13 | GLenum facetype; 14 | 15 | public: 16 | DrawBuffer(); 17 | ~DrawBuffer(); 18 | 19 | GLuint getVAOName() const { 20 | return vao; 21 | } 22 | 23 | void setFaceType(GLenum ft) { 24 | facetype = ft; 25 | } 26 | 27 | GLenum getFaceType() const { 28 | return facetype; 29 | } 30 | 31 | /** 32 | * Adds a Geometry Buffer to the Draw Buffer. 33 | */ 34 | void addGeometry(GeometryBuffer* gbuff); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /rwcore/gl/GeometryBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "gl/GeometryBuffer.hpp" 2 | 3 | GeometryBuffer::~GeometryBuffer() { 4 | if (vbo != 0) { 5 | glDeleteBuffers(1, &vbo); 6 | } 7 | } 8 | 9 | void GeometryBuffer::uploadVertices(GLsizei num, GLsizeiptr size, 10 | const GLvoid* mem) { 11 | if (vbo == 0) { 12 | glGenBuffers(1, &vbo); 13 | } 14 | this->num = num; 15 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 16 | glBufferData(GL_ARRAY_BUFFER, size, mem, GL_STATIC_DRAW); 17 | } 18 | -------------------------------------------------------------------------------- /rwcore/gl/GeometryBuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_GEOMETRYBUFFER_HPP_ 2 | #define _LIBRW_GEOMETRYBUFFER_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | /** 9 | * Enum used to determine which shader input an attribute maps to 10 | */ 11 | enum AttributeSemantic { 12 | ATRS_Position = 0, 13 | ATRS_Normal = 1, 14 | ATRS_Colour = 2, 15 | ATRS_TexCoord = 3 16 | }; 17 | 18 | /** 19 | * Stores Vertex Attribute data 20 | */ 21 | struct AttributeIndex { 22 | AttributeSemantic sem; 23 | GLsizei size; 24 | GLsizei stride; 25 | size_t offset; 26 | GLenum type; 27 | 28 | AttributeIndex(AttributeSemantic s, GLsizei sz, GLsizei strd, size_t offs, 29 | GLenum type = GL_FLOAT) 30 | : sem(s), size(sz), stride(strd), offset(offs), type(type) { 31 | } 32 | }; 33 | 34 | typedef std::vector AttributeList; 35 | 36 | /** 37 | * GeometryBuffer stores a set of vertex attribute data 38 | */ 39 | class GeometryBuffer { 40 | GLuint vbo = 0; 41 | GLsizei num = 0; 42 | 43 | AttributeList attributes{}; 44 | 45 | public: 46 | GeometryBuffer() = default; 47 | template 48 | GeometryBuffer(const std::vector& data) { 49 | uploadVertices(data); 50 | } 51 | 52 | ~GeometryBuffer(); 53 | 54 | GLuint getVBOName() const { 55 | return vbo; 56 | } 57 | 58 | GLsizei getCount() const { 59 | return num; 60 | } 61 | 62 | /** 63 | * Uploads Vertex Buffer data from an STL vector 64 | * 65 | * vertex_attributes() is assumed to exist so that vertex types 66 | * can implicitly declare the strides and offsets for their data. 67 | */ 68 | template 69 | void uploadVertices(const std::vector& data) { 70 | uploadVertices(static_cast(data.size()), data.size() * sizeof(T), data.data()); 71 | // Assume T has a static method for attributes; 72 | attributes = T::vertex_attributes(); 73 | } 74 | 75 | /** 76 | * Uploads raw memory into the buffer. 77 | */ 78 | void uploadVertices(GLsizei num, GLsizeiptr size, const GLvoid* mem); 79 | 80 | const AttributeList& getDataAttributes() const { 81 | return attributes; 82 | } 83 | AttributeList& getDataAttributes() { 84 | return attributes; 85 | } 86 | }; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /rwcore/gl/TextureData.cpp: -------------------------------------------------------------------------------- 1 | #include "gl/TextureData.hpp" 2 | -------------------------------------------------------------------------------- /rwcore/gl/TextureData.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_TEXTUREDATA_HPP_ 2 | #define _LIBRW_TEXTUREDATA_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /** 12 | * Stores a handle and metadata about a loaded texture. 13 | */ 14 | class TextureData { 15 | public: 16 | TextureData(GLuint name, const glm::ivec2& dims, bool alpha) 17 | : texName(name), size(dims), hasAlpha(alpha) { 18 | } 19 | 20 | ~TextureData() { 21 | glDeleteTextures(1, &texName); 22 | } 23 | 24 | GLuint getName() const { 25 | return texName; 26 | } 27 | 28 | const glm::ivec2& getSize() const { 29 | return size; 30 | } 31 | 32 | bool isTransparent() const { 33 | return hasAlpha; 34 | } 35 | 36 | static auto create(GLuint name, const glm::ivec2& size, 37 | bool transparent) { 38 | return std::make_unique(name, size, transparent); 39 | } 40 | 41 | private: 42 | GLuint texName; 43 | glm::ivec2 size; 44 | bool hasAlpha; 45 | }; 46 | using TextureArchive = std::unordered_map>; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /rwcore/loaders/LoaderDFF.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_LOADERDFF_HPP_ 2 | #define _LIBRW_LOADERDFF_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class RWBStream; 12 | 13 | class DFFLoaderException { 14 | std::string _message; 15 | 16 | public: 17 | template 18 | DFFLoaderException(String&& message) : _message(message) { 19 | } 20 | 21 | const std::string& which() { 22 | return _message; 23 | } 24 | }; 25 | 26 | class LoaderDFF { 27 | public: 28 | using TextureLookupCallback = 29 | std::function; 30 | using GeometryList = std::vector; 31 | using FrameList = std::vector; 32 | 33 | ClumpPtr loadFromMemory(const FileContentsInfo& file); 34 | 35 | void setTextureLookupCallback(const TextureLookupCallback& tlc) { 36 | textureLookup = tlc; 37 | } 38 | 39 | private: 40 | TextureLookupCallback textureLookup; 41 | 42 | FrameList readFrameList(const RWBStream& stream); 43 | 44 | GeometryList readGeometryList(const RWBStream& stream); 45 | 46 | GeometryPtr readGeometry(const RWBStream& stream); 47 | 48 | void readMaterialList(const GeometryPtr& geom, const RWBStream& stream); 49 | 50 | void readMaterial(const GeometryPtr& geom, const RWBStream& stream); 51 | 52 | void readTexture(Geometry::Material& material, const RWBStream& stream); 53 | 54 | void readGeometryExtension(const GeometryPtr& geom, const RWBStream& stream); 55 | 56 | void readBinMeshPLG(const GeometryPtr& geom, const RWBStream& stream); 57 | 58 | AtomicPtr readAtomic(FrameList& framelist, GeometryList& geometrylist, 59 | const RWBStream& stream); 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /rwcore/loaders/LoaderTXD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_TEXTURELOADER_HPP_ 2 | #define _LIBRW_TEXTURELOADER_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class TextureLoader { 8 | public: 9 | bool loadFromMemory(const FileContentsInfo& file, TextureArchive& inTextures); 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /rwcore/platform/FileHandle.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_FILEHANDLE_HPP_ 2 | #define _LIBRW_FILEHANDLE_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | /** 8 | * @brief Contains a pointer to a file's contents. 9 | */ 10 | struct FileContentsInfo { 11 | std::unique_ptr data; 12 | size_t length; 13 | 14 | FileContentsInfo(std::unique_ptr mem, size_t len) 15 | : data(std::move(mem)), length(len) { 16 | } 17 | 18 | FileContentsInfo(FileContentsInfo&& info) 19 | : data(std::move(info.data)), length(info.length) { 20 | info.data = nullptr; 21 | } 22 | 23 | FileContentsInfo(FileContentsInfo& info) = delete; 24 | FileContentsInfo& operator=(FileContentsInfo& info) = delete; 25 | 26 | ~FileContentsInfo() = default; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /rwcore/platform/RWWindows.cpp: -------------------------------------------------------------------------------- 1 | #include "RWWindows.hpp" 2 | 3 | #include "rw/Debug.hpp" 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | std::string wideStringToACP(const wchar_t* wString) { 9 | std::string returnValue; 10 | bool result = true; 11 | 12 | int nbChars = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wString, -1, 13 | nullptr, 0, nullptr, nullptr); 14 | if (nbChars == 0) { 15 | if (GetLastError() != ERROR_SUCCESS) { 16 | RW_ERROR("Unable to calculate length of wide string"); 17 | return returnValue; 18 | } 19 | } 20 | returnValue.resize(nbChars); 21 | nbChars = 22 | WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wString, -1, 23 | &returnValue.front(), nbChars, nullptr, nullptr); 24 | if (nbChars == 0) { 25 | returnValue.resize(0); 26 | return returnValue; 27 | } 28 | returnValue.resize(nbChars - 1); 29 | return returnValue; 30 | } 31 | -------------------------------------------------------------------------------- /rwcore/platform/RWWindows.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWCORE_PLATFORM_RWWINDOWS_HPP_ 2 | #define _RWCORE_PLATFORM_RWWINDOWS_HPP_ 3 | 4 | #include 5 | 6 | /** 7 | * @brief Convert a wide string to a ACP string (=active code page) 8 | * This function converts to the active code page instead of utf8 9 | * because Windows functions need to understand the encoding. 10 | * @param str The wide string to convert 11 | */ 12 | std::string wideStringToACP(const wchar_t* str); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /rwcore/rw/abort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef RW_DEBUG 4 | std::function _rw_abort_cb[2] = {nullptr, nullptr}; 5 | 6 | #if defined(RW_WINDOWS) 7 | #define WINDOWS_LEAN_AND_MEAN 8 | #include 9 | 10 | void WinBreak() { 11 | DebugBreak(); 12 | } 13 | 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /rwcore/rw/casts.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_CASTS_HPP_ 2 | #define _LIBRW_CASTS_HPP_ 3 | 4 | #include // memcpy 5 | #include 6 | 7 | #include "rw/debug.hpp" 8 | 9 | //Based on https://gist.github.com/socantre/3472964 10 | template 11 | inline Dest bit_cast(Source const &source) { 12 | Dest dest; 13 | std::memcpy(&dest, &source, sizeof(Dest)); 14 | return dest; 15 | } 16 | 17 | template 18 | inline T lexical_cast(const S& s); 19 | 20 | template 21 | inline T lexical_cast(const S& s, int base); 22 | 23 | template <> 24 | inline int lexical_cast(const std::string& source, int base) { 25 | char* end = nullptr; //for errors handling 26 | int result = std::strtol(source.c_str(), &end, base); 27 | RW_CHECK(end != source.c_str(), "Problem with conversion " << *end << " to int"); 28 | return result; 29 | } 30 | 31 | template <> 32 | inline int lexical_cast(const std::string& source) { 33 | return lexical_cast(source, 10); 34 | } 35 | 36 | template <> 37 | inline float lexical_cast(const std::string& source) { 38 | char* end = nullptr; //for errors handling 39 | float result = std::strtof(source.c_str(), &end); 40 | RW_CHECK(end != source.c_str(), "Problem with conversion " << *end << " to float"); 41 | return result; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /rwcore/rw/debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_DEBUG_HPP_ 2 | #define _LIBRW_DEBUG_HPP_ 3 | 4 | #ifdef RW_DEBUG 5 | #include 6 | #include 7 | 8 | extern std::function _rw_abort_cb[2]; 9 | #define SET_RW_ABORT_CB(cb0, cb1) do { _rw_abort_cb[0] = cb0; _rw_abort_cb[1] = cb1;} while (0) 10 | 11 | #define RW_ABORT() do { if(_rw_abort_cb[0]) _rw_abort_cb[0](); ::abort(); } while (0) 12 | #define RW_ASSERT(cond) do { if (!(cond)) RW_ABORT();} while (0) 13 | 14 | #if defined(RW_WINDOWS) 15 | void WinBreak(); 16 | #define RW_BREAKPOINT() WinBreak() 17 | #else 18 | #include 19 | #define RW_BREAKPOINT() do { if(_rw_abort_cb[0]) _rw_abort_cb[0](); ::raise(SIGTRAP); if(_rw_abort_cb[1]) _rw_abort_cb[1](); } while (0) 20 | #endif 21 | 22 | #define RW_FAILED_NO_ACTION 0 23 | #define RW_FAILED_ABORT_OPTION 1 24 | #define RW_FAILED_BREAKPOINT_OPTION 2 25 | 26 | #if RW_FAILED_CHECK_ACTION == RW_FAILED_NO_ACTION 27 | #define _RW_FAILED_CHECK_ACTION() 28 | #elif RW_FAILED_CHECK_ACTION == RW_FAILED_ABORT_OPTION 29 | #define _RW_FAILED_CHECK_ACTION() RW_ABORT() 30 | #elif RW_FAILED_CHECK_ACTION == RW_FAILED_BREAKPOINT_OPTION 31 | #define _RW_FAILED_CHECK_ACTION() RW_BREAKPOINT() 32 | #endif 33 | 34 | #else 35 | #define SET_RW_ABORT_CB(cb0, cb1) 36 | #define RW_ABORT() 37 | #define RW_ASSERT(cond) 38 | #define RW_BREAKPOINT() 39 | #define _RW_FAILED_CHECK_ACTION() 40 | #endif 41 | 42 | #if defined(RW_DEBUG) && defined(RW_VERBOSE_DEBUG_MESSAGES) 43 | #include 44 | #define RW_MESSAGE(msg) \ 45 | std::cout << __FILE__ << ":" << __LINE__ << ": " << msg << '\n' 46 | #define RW_ERROR(msg) \ 47 | std::cerr << __FILE__ << ":" << __LINE__ << ": " << msg << '\n' 48 | #else 49 | #define RW_MESSAGE(msg) 50 | #define RW_ERROR(msg) 51 | #endif 52 | 53 | #if RW_DEBUG 54 | #define RW_CHECK(cond, msg) \ 55 | do { if (!(cond)) { RW_ERROR(msg); _RW_FAILED_CHECK_ACTION();}} while (0) 56 | #else 57 | #define RW_CHECK(cond, msg) 58 | #endif 59 | 60 | #define RW_UNUSED(var) (void)var 61 | 62 | #define RW_UNIMPLEMENTED(msg) RW_MESSAGE("Unimplemented: " << msg) 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /rwcore/rw/forward.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_RW_FORWARD_HPP_ 2 | #define _LIBRW_RW_FORWARD_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Forward Declarations 9 | struct Animation; 10 | class Clump; 11 | struct FileContentsInfo; 12 | class ModelFrame; 13 | struct Geometry; 14 | class Atomic; 15 | class Clump; 16 | 17 | // Pointer types 18 | using AnimationPtr = std::shared_ptr; 19 | using ModelFramePtr = std::shared_ptr; 20 | using GeometryPtr = std::shared_ptr; 21 | using AtomicPtr = std::shared_ptr; 22 | using ClumpPtr = std::shared_ptr; 23 | 24 | // Collections 25 | using AtomicList = std::vector; 26 | typedef std::unordered_map AnimationSet; 27 | 28 | #endif /* FORWARD_HPP */ 29 | -------------------------------------------------------------------------------- /rwcore/rw/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LIBRW_TYPES_HPP_ 2 | #define _LIBRW_TYPES_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RW_USING(feature) 1 == feature 11 | 12 | #define NO_WATER_INDEX 48 13 | #define WATER_LQ_DATA_SIZE 64 14 | #define WATER_HQ_DATA_SIZE 128 15 | #define WATER_WORLD_SIZE 4096.f 16 | #define WATER_HQ_DISTANCE 128.f 17 | #define WATER_SCALE 0.05f 18 | #define WATER_HEIGHT 0.5f 19 | #define WATER_BUOYANCY_K 1500.f 20 | #define WATER_BUOYANCY_C 1000.f 21 | 22 | /** 23 | * These control the size of grid that is applied to 24 | * AI Graph and culling. 25 | */ 26 | #define WORLD_GRID_SIZE (4000l) 27 | #define WORLD_CELL_SIZE (100l) 28 | #define WORLD_GRID_WIDTH (WORLD_GRID_SIZE / WORLD_CELL_SIZE) 29 | #define WORLD_GRID_CELLS (WORLD_GRID_WIDTH * WORLD_GRID_WIDTH) 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /rwengine/README.md: -------------------------------------------------------------------------------- 1 | # rwengine 2 | 3 | Rwengine contains the game data structures, the data loading routines, script virtual machine 4 | and generic object logic, as well as a renderer implementation for OpenGL. 5 | 6 | ## Core 7 | 8 | Implementations of platform abstraction and file system handling classes are in the core/ directory 9 | 10 | ## Data 11 | 12 | Structures that store information about object types, cutscene data, localisation information etc 13 | 14 | ## Objects 15 | 16 | The logic for Object types are implemented by the classes in the objects/ directory 17 | 18 | ## Loaders 19 | 20 | Classes for loading various file formats 21 | 22 | ## Render 23 | 24 | Implementation of a portable OpenGL renderer system lives in the render/ directory 25 | 26 | ## Script 27 | 28 | The game script virtual machine, and the function definitions are in the script/ directory -------------------------------------------------------------------------------- /rwengine/src/ai/AIGraph.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_AIGRAPH_HPP_ 2 | #define _RWENGINE_AIGRAPH_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | struct PathData; 12 | 13 | namespace ai { 14 | 15 | enum class NodeType; 16 | struct AIGraphNode; 17 | 18 | class AIGraph { 19 | public: 20 | ~AIGraph() = default; 21 | 22 | std::vector> nodes; 23 | 24 | /** 25 | * List of external nodes, which are links between each 26 | * Instance's paths and where new pedestrians and vehicles 27 | * are spawned 28 | */ 29 | std::vector externalNodes; 30 | 31 | /** 32 | * Stores the external AI Grid Nodes organised by world grid cell 33 | */ 34 | std::array, WORLD_GRID_CELLS> gridNodes; 35 | 36 | void createPathNodes(const glm::vec3& position, const glm::quat& rotation, 37 | PathData& path); 38 | 39 | void gatherExternalNodesNear(const glm::vec3& center, const float radius, 40 | std::vector& nodes, NodeType type); 41 | }; 42 | 43 | } // ai 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /rwengine/src/ai/AIGraphNode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /rwengine/src/ai/AIGraphNode.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_AIGRAPHNODE_HPP_ 2 | #define _RWENGINE_AIGRAPHNODE_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace ai { 10 | 11 | enum class NodeType { Vehicle, Pedestrian }; 12 | 13 | struct AIGraphNode { 14 | enum { 15 | None = 0, 16 | CrossesRoad = 17 | 1 /// No documentation for other flags yet, but this is mentioned. 18 | }; 19 | 20 | NodeType type; 21 | glm::vec3 position{}; 22 | float size; 23 | int leftLanes; 24 | int rightLanes; 25 | bool external; 26 | uint8_t flags; 27 | 28 | int32_t nextIndex; 29 | 30 | bool disabled; 31 | 32 | std::vector connections; 33 | }; 34 | 35 | } // namespace ai 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /rwengine/src/ai/DefaultAIController.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_DEFAULTAICONTROLLER_HPP_ 2 | #define _RWENGINE_DEFAULTAICONTROLLER_HPP_ 3 | 4 | #include 5 | 6 | #include "ai/CharacterController.hpp" 7 | 8 | namespace ai { 9 | 10 | class DefaultAIController final : public CharacterController { 11 | glm::vec3 gotoPos{}; 12 | 13 | public: 14 | DefaultAIController() : CharacterController() { 15 | } 16 | 17 | glm::vec3 getTargetPosition() override; 18 | 19 | void update(float dt) override; 20 | }; 21 | 22 | } // namespace ai 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /rwengine/src/ai/TrafficDirector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_TRAFFICDIRECTOR_HPP_ 2 | #define _RWENGINE_TRAFFICDIRECTOR_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class GameWorld; 8 | class GameObject; 9 | class ViewCamera; 10 | 11 | namespace ai { 12 | 13 | enum class NodeType; 14 | class AIGraph; 15 | struct AIGraphNode; 16 | 17 | class TrafficDirector { 18 | public: 19 | TrafficDirector(AIGraph* graph, GameWorld* world); 20 | 21 | std::vector findAvailableNodes(NodeType type, 22 | const ViewCamera& camera, 23 | float radius); 24 | 25 | void setDensity(NodeType type, float density); 26 | 27 | /** 28 | * Creates new traffic at available locations. 29 | * @param camera The camera to spawn around 30 | * @param radius the maximum distance to spawn in 31 | * @param max The maximum number of traffic to create. 32 | */ 33 | std::vector populateNearby(const ViewCamera& camera, 34 | float radius, int maxSpawn = -1); 35 | 36 | /** 37 | * Sets the maximum number of pedestrians and cars in the traffic system 38 | */ 39 | void setPopulationLimits(int maxPeds, int maxCars); 40 | 41 | private: 42 | AIGraph* graph = nullptr; 43 | GameWorld* world = nullptr; 44 | float pedDensity = 1.f; 45 | float carDensity = 1.f; 46 | size_t maximumPedestrians = 20; 47 | size_t maximumCars = 10; 48 | }; 49 | 50 | } // namespace ai 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /rwengine/src/audio/SfxParameters.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_SFX_PARAMETERS_HPP_ 2 | #define _RWENGINE_SFX_PARAMETERS_HPP_ 3 | 4 | #include 5 | 6 | /// Script is using different numeration of sounds 7 | /// than postion index in sfx file. 8 | /// Also it is needed to store range of sound. 9 | /// Struct is used by opcodes 018c, 018d. 10 | struct SoundInstanceData { 11 | int id; 12 | int sfx; 13 | int range; 14 | }; 15 | 16 | /// Get metadata for selected script index 17 | const SoundInstanceData* getSoundInstanceData(int scriptId); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /rwengine/src/audio/Sound.cpp: -------------------------------------------------------------------------------- 1 | #include "audio/Sound.hpp" 2 | 3 | #include "audio/SoundBuffer.hpp" 4 | 5 | Sound::~Sound() { 6 | if (buffer && buffer->state == SoundBuffer::State::Playing) { 7 | stop(); 8 | } 9 | } 10 | 11 | bool Sound::isPlaying() const { 12 | return buffer->isPlaying(); 13 | } 14 | 15 | bool Sound::isPaused() const { 16 | return buffer->isPaused(); 17 | } 18 | 19 | bool Sound::isStopped() const { 20 | return buffer->isStopped(); 21 | } 22 | 23 | void Sound::play() { 24 | buffer->play(); 25 | } 26 | 27 | void Sound::pause() { 28 | buffer->pause(); 29 | } 30 | 31 | void Sound::stop() { 32 | buffer->stop(); 33 | } 34 | 35 | void Sound::setPosition(const glm::vec3 &position) { 36 | buffer->setPosition(position); 37 | } 38 | 39 | void Sound::setLooping(bool looping) { 40 | buffer->setLooping(looping); 41 | } 42 | 43 | void Sound::setPitch(float pitch) { 44 | buffer->setPitch(pitch); 45 | } 46 | 47 | void Sound::setGain(float gain) { 48 | buffer->setGain(gain); 49 | } 50 | 51 | void Sound::setMaxDistance(float maxDist) { 52 | buffer->setMaxDistance(maxDist); 53 | } 54 | 55 | size_t Sound::getScriptObjectID() const { 56 | return id; 57 | } 58 | -------------------------------------------------------------------------------- /rwengine/src/audio/Sound.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_SOUND_HPP_ 2 | #define _RWENGINE_SOUND_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | class SoundSource; 9 | struct SoundBuffer; 10 | 11 | /// Wrapper for SoundBuffer and SoundSource. 12 | /// Each command connected 13 | /// with playment is passed to SoundBuffer 14 | struct Sound { 15 | size_t id = 0; 16 | bool isLoaded = false; 17 | 18 | std::shared_ptr source; 19 | std::unique_ptr buffer; 20 | 21 | Sound() = default; 22 | ~Sound(); 23 | 24 | bool isPlaying() const; 25 | 26 | bool isPaused() const; 27 | bool isStopped() const; 28 | 29 | void play(); 30 | 31 | void pause(); 32 | 33 | void stop(); 34 | 35 | void setPosition(const glm::vec3& position); 36 | 37 | void setLooping(bool looping); 38 | 39 | void setPitch(float pitch); 40 | 41 | void setGain(float gain); 42 | 43 | void setMaxDistance(float maxDist); 44 | 45 | size_t getScriptObjectID() const; 46 | }; 47 | #endif 48 | -------------------------------------------------------------------------------- /rwengine/src/audio/SoundBuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_SOUND_BUFFER_HPP_ 2 | #define _RWENGINE_SOUND_BUFFER_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | class SoundSource; 8 | 9 | /// OpenAL tool for playing 10 | /// sound instance. 11 | struct SoundBuffer { 12 | SoundBuffer(); 13 | virtual ~SoundBuffer(); 14 | virtual bool bufferData(SoundSource& soundSource); 15 | 16 | bool isPlaying() const; 17 | bool isPaused() const; 18 | bool isStopped() const; 19 | 20 | virtual void play(); 21 | virtual void pause(); 22 | virtual void stop(); 23 | 24 | void setPosition(const glm::vec3& position); 25 | void setLooping(bool looping); 26 | void setPitch(float pitch); 27 | void setGain(float gain); 28 | void setMaxDistance(float maxDist); 29 | 30 | enum class State { 31 | Created = 0, 32 | Stopped, 33 | Playing 34 | }; 35 | 36 | ALuint source; 37 | State state = State::Created; 38 | private: 39 | ALuint buffer; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /rwengine/src/audio/SoundBufferStreamed.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_SOUND_BUFFER_STREAMED_HPP_ 2 | #define _RWENGINE_SOUND_BUFFER_STREAMED_HPP_ 3 | 4 | #include "audio/SoundBuffer.hpp" 5 | 6 | #include 7 | #include 8 | 9 | struct SoundBufferStreamed : public SoundBuffer { 10 | static constexpr unsigned int kNrBuffersStreaming = 4; 11 | static constexpr unsigned int kSizeOfChunk = 4096; 12 | static constexpr std::chrono::milliseconds kTickFreqMs = 13 | std::chrono::milliseconds(100); 14 | 15 | SoundBufferStreamed(); 16 | ~SoundBufferStreamed() override; 17 | bool bufferData(SoundSource& soundSource) final; 18 | 19 | void play() final; 20 | void pause() final; 21 | void stop() final; 22 | 23 | private: 24 | SoundSource* soundSource = nullptr; 25 | void updateBuffers(); 26 | unsigned int streamedData = 0; 27 | unsigned int buffersUsed = 0; 28 | std::array buffers; 29 | std::future bufferingThread; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /rwengine/src/audio/alCheck.cpp: -------------------------------------------------------------------------------- 1 | #include "audio/alCheck.hpp" 2 | 3 | #include "al.h" 4 | #include "alc.h" 5 | 6 | #include 7 | 8 | void checkALerror(const std::string& file, unsigned int line) { 9 | ALenum err = alGetError(); 10 | if (err != AL_NO_ERROR) { 11 | std::cerr << "OpenAL error at " << file << ":" << line << ": "; 12 | 13 | switch (err) { 14 | case AL_INVALID_NAME: 15 | std::cerr << "Invalid name!"; 16 | break; 17 | case AL_INVALID_VALUE: 18 | std::cerr << "Invalid value!"; 19 | break; 20 | case AL_INVALID_OPERATION: 21 | std::cerr << "Invalid operation!"; 22 | break; 23 | default: 24 | std::cerr << err; 25 | } 26 | 27 | std::cerr << '\n'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rwengine/src/audio/alCheck.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_ALCHECK_HPP_ 2 | #define _RWENGINE_ALCHECK_HPP_ 3 | 4 | #include 5 | 6 | void checkALerror(const std::string& file, unsigned int line); 7 | 8 | #if RW_DEBUG 9 | #define alCheck(stmt) \ 10 | do { \ 11 | stmt; \ 12 | checkALerror(__FILE__, __LINE__); \ 13 | } while (0) 14 | #else 15 | #define alCheck(stmt) stmt 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /rwengine/src/core/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void Logger::log(const std::string& component, Logger::MessageSeverity severity, 8 | const std::string& message) { 9 | LogMessage m{component, severity, message}; 10 | 11 | for (MessageReceiver* r : receivers) { 12 | r->messageReceived(m); 13 | } 14 | } 15 | 16 | void Logger::addReceiver(Logger::MessageReceiver* out) { 17 | receivers.push_back(out); 18 | } 19 | 20 | void Logger::removeReceiver(Logger::MessageReceiver* out) { 21 | receivers.erase(std::remove(receivers.begin(), receivers.end(), out), 22 | receivers.end()); 23 | } 24 | 25 | void Logger::error(const std::string& component, const std::string& message) { 26 | log(component, Logger::Error, message); 27 | } 28 | 29 | void Logger::info(const std::string& component, const std::string& message) { 30 | log(component, Logger::Info, message); 31 | } 32 | 33 | void Logger::warning(const std::string& component, const std::string& message) { 34 | log(component, Logger::Warning, message); 35 | } 36 | 37 | void Logger::verbose(const std::string& component, const std::string& message) { 38 | log(component, Logger::Verbose, message); 39 | } 40 | 41 | void StdOutReceiver::messageReceived(const Logger::LogMessage& message) { 42 | std::cout << Logger::messageSeverityName[message.severity] << " [" 43 | << message.component << "] " << message.message << '\n'; 44 | } 45 | -------------------------------------------------------------------------------- /rwengine/src/core/Logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOGGER_HPP_ 2 | #define _RWENGINE_LOGGER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /** 11 | * Handles and stores messages from different components 12 | * 13 | * Dispatches received messages to logger outputs. 14 | */ 15 | class Logger { 16 | public: 17 | enum MessageSeverity { Verbose = 0, Info, Warning, Error}; 18 | static constexpr std::array messageSeverityName{{'V', 'I', 'W', 'E'}}; 19 | 20 | struct LogMessage { 21 | /// The component that produced the message 22 | std::string component; 23 | /// Severity of the message. 24 | MessageSeverity severity; 25 | /// Logged message 26 | std::string message; 27 | 28 | template 29 | LogMessage(String1&& cc, MessageSeverity ss, 30 | String2&& mm) 31 | : component(std::forward(cc)) 32 | , severity(ss) 33 | , message(std::forward(mm)) { 34 | } 35 | }; 36 | 37 | /** 38 | * Interface for handling logged messages. 39 | * 40 | * The Logger class will not clean up allocated MessageReceivers. 41 | */ 42 | struct MessageReceiver { 43 | virtual void messageReceived(const LogMessage&) = 0; 44 | }; 45 | 46 | Logger(std::initializer_list initial = {}) 47 | : receivers(initial) { 48 | } 49 | 50 | void addReceiver(MessageReceiver* out); 51 | void removeReceiver(MessageReceiver* out); 52 | 53 | void log(const std::string& component, Logger::MessageSeverity severity, 54 | const std::string& message); 55 | 56 | void verbose(const std::string& component, const std::string& message); 57 | void info(const std::string& component, const std::string& message); 58 | void warning(const std::string& component, const std::string& message); 59 | void error(const std::string& component, const std::string& message); 60 | 61 | private: 62 | std::vector receivers; 63 | }; 64 | 65 | class StdOutReceiver final : public Logger::MessageReceiver { 66 | void messageReceived(const Logger::LogMessage&) override; 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /rwengine/src/core/Profiler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /rwengine/src/core/Profiler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_PROFILER_HPP_ 2 | #define _RWENGINE_PROFILER_HPP_ 3 | 4 | #ifdef RW_PROFILER 5 | #include 6 | #define RW_PROFILE_THREAD(name) MicroProfileOnThreadCreate(name) 7 | #define RW_PROFILE_FRAME_BOUNDARY() MicroProfileFlip(nullptr) 8 | #define RW_PROFILE_SCOPE(label) MICROPROFILE_SCOPEI("Default", label, MP_YELLOW) 9 | #define RW_PROFILE_SCOPEC(label, colour) MICROPROFILE_SCOPEI("Default", label, colour) 10 | #define RW_PROFILE_COUNTER_ADD(name, qty) MICROPROFILE_COUNTER_ADD(name, qty) 11 | #define RW_PROFILE_COUNTER_SET(name, qty) MICROPROFILE_COUNTER_SET(name, qty) 12 | #define RW_TIMELINE_ENTER(name, color) MICROPROFILE_TIMELINE_ENTER_STATIC(color, name) 13 | #define RW_TIMELINE_LEAVE(name) MICROPROFILE_TIMELINE_LEAVE_STATIC(name) 14 | #else 15 | #define RW_PROFILE_THREAD(name) do {} while (0) 16 | #define RW_PROFILE_FRAME_BOUNDARY() do {} while (0) 17 | #define RW_PROFILE_SCOPE(label) do {} while (0) 18 | #define RW_PROFILE_SCOPEC(label, colour) do {} while (0) 19 | #define RW_PROFILE_COUNTER_ADD(name, qty) do {} while (0) 20 | #define RW_PROFILE_COUNTER_SET(name, qty) do {} while (0) 21 | #define RW_TIMELINE_ENTER(name, color) do {} while (0) 22 | #define RW_TIMELINE_LEAVE(name) do {} while (0) 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /rwengine/src/data/Chase.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_CHASE_HPP_ 2 | #define _RWENGINE_CHASE_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class GameObject; 12 | 13 | struct ChaseKeyframe { 14 | glm::vec3 velocity; 15 | int steeringAngle; 16 | int acceleratorPower; 17 | int brakePower; 18 | bool handbrake; 19 | glm::vec3 position; 20 | glm::quat rotation; 21 | 22 | ChaseKeyframe(glm::vec3 _velocity, int _steeringAngle, int _acceleratorPower, int _brakePower, bool _handbrake, glm::vec3 _position, glm::quat _rotation) 23 | : velocity(_velocity) 24 | , steeringAngle(_steeringAngle) 25 | , acceleratorPower(_acceleratorPower) 26 | , brakePower(_brakePower) 27 | , handbrake(_handbrake) 28 | , position(_position) 29 | , rotation(_rotation) { 30 | } 31 | 32 | static bool load(const std::string& filePath, 33 | std::vector& frames); 34 | }; 35 | 36 | /** 37 | * @brief The ChaseCoordinator class handles loading and playing a chase 38 | * 39 | * It reads in ChaseKeyframes for a set of objects, and replays them 40 | * over time. 41 | */ 42 | class ChaseCoordinator { 43 | public: 44 | ChaseCoordinator() = default; 45 | 46 | bool addChaseVehicle(GameObject* vehicle, int index, 47 | const std::string& pathFile); 48 | GameObject* getChaseVehicle(int index); 49 | void removeChaseVehicle(int index); 50 | 51 | void start(); 52 | void update(float dt); 53 | 54 | void reserve(size_t nr); 55 | 56 | void cleanup(); 57 | 58 | private: 59 | float chaseTime{-1.f}; 60 | struct ChaseObject { 61 | std::vector keyframes; 62 | GameObject* object; 63 | }; 64 | 65 | std::unordered_map chaseVehicles; 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /rwengine/src/data/CollisionModel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_COLLISIONMODEL_HPP_ 2 | #define _RWENGINE_COLLISIONMODEL_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /** 11 | * @class CollisionModel 12 | * Collision shapes data container. 13 | */ 14 | struct CollisionModel { 15 | struct Surface { 16 | uint8_t material; 17 | uint8_t flag; 18 | uint8_t brightness; 19 | uint8_t light; 20 | }; 21 | 22 | /// @todo give shapes surface data 23 | struct Sphere { 24 | glm::vec3 center{}; 25 | float radius; 26 | Surface surface; 27 | }; 28 | 29 | struct Box { 30 | glm::vec3 min{}; 31 | glm::vec3 max{}; 32 | Surface surface; 33 | }; 34 | 35 | struct Triangle { 36 | uint32_t tri[3]; 37 | Surface surface; 38 | }; 39 | 40 | /// Model name 41 | std::string name; 42 | uint16_t modelid; 43 | 44 | Sphere boundingSphere; 45 | Box boundingBox; 46 | 47 | std::vector spheres; 48 | std::vector boxes; 49 | std::vector vertices; 50 | std::vector faces; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /rwengine/src/data/CutsceneData.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_CUTSCENEDATA_HPP_ 2 | #define _RWENGINE_CUTSCENEDATA_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /** 11 | * @brief Stores data from .CUT files 12 | */ 13 | struct CutsceneMetadata { 14 | struct ModelEntry { 15 | std::string model; 16 | std::string animation; 17 | }; 18 | struct TextEntry { 19 | float length; 20 | std::string gxt; 21 | }; 22 | 23 | std::string name; 24 | 25 | /// The origin for coordinates in the cutscene 26 | glm::vec3 sceneOffset{}; 27 | 28 | std::vector models; 29 | std::map texts; 30 | }; 31 | 32 | /** 33 | * @brief Stores the Camera animation data from .DAT files 34 | */ 35 | struct CutsceneTracks { 36 | std::map zoom; 37 | std::map rotation; 38 | std::map position; 39 | std::map target; 40 | /* Rotation is angle around the target vector */ 41 | 42 | float duration{0.f}; 43 | 44 | glm::vec3 getPositionAt(float time) const; 45 | 46 | glm::vec3 getTargetAt(float time) const; 47 | 48 | float getZoomAt(float time) const; 49 | 50 | float getRotationAt(float time) const; 51 | }; 52 | 53 | struct CutsceneData { 54 | CutsceneMetadata meta; 55 | CutsceneTracks tracks; 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /rwengine/src/data/InstanceData.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_INSTANCEDATA_HPP_ 2 | #define _RWENGINE_INSTANCEDATA_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct InstanceData { 10 | /** 11 | * ID of the object this instance 12 | */ 13 | int id; 14 | /** 15 | * Model name 16 | */ 17 | std::string model; 18 | /** 19 | * Instance position 20 | */ 21 | glm::vec3 pos; 22 | /** 23 | * Instance scaleX 24 | */ 25 | glm::vec3 scale; 26 | /** 27 | * Instance rotation 28 | */ 29 | glm::quat rot; 30 | /** 31 | * Constructor 32 | */ 33 | template 34 | InstanceData(int _id, String&& _model, glm::vec3 _pos, glm::vec3 _scale, glm::quat _rot) 35 | : id(_id) 36 | , model(std::forward(_model)) 37 | , pos(_pos) 38 | , scale(_scale) 39 | , rot(_rot){ 40 | } 41 | 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /rwengine/src/data/ModelData.cpp: -------------------------------------------------------------------------------- 1 | #include "data/ModelData.hpp" 2 | 3 | #include "data/CollisionModel.hpp" 4 | #include "data/PathData.hpp" 5 | 6 | SimpleModelInfo::SimpleModelInfo() : BaseModelInfo(kType) { 7 | } 8 | 9 | SimpleModelInfo::SimpleModelInfo(ModelDataType type) : BaseModelInfo(type) { 10 | } 11 | 12 | SimpleModelInfo::~SimpleModelInfo() = default; 13 | 14 | void SimpleModelInfo::setupBigBuilding(const ModelInfoTable& models) { 15 | if (loddistances_[0] > 300.f && atomics_[2] == nullptr) { 16 | isbigbuilding_ = true; 17 | findRelatedModel(models); 18 | if (related_) { 19 | loddistances_[2] = related_->getLargestLodDistance(); 20 | } else { 21 | loddistances_[2] = 100.f; 22 | } 23 | } 24 | } 25 | 26 | void SimpleModelInfo::findRelatedModel(const ModelInfoTable& models) { 27 | for (const auto& model : models) { 28 | if (model.second.get() == this) continue; 29 | const auto& othername = model.second->name; 30 | if (othername.size() <= 3 || name.size() <= 3) continue; 31 | if (othername.substr(3) == name.substr(3)) { 32 | related_ = static_cast(model.second.get()); 33 | break; 34 | } 35 | } 36 | } 37 | 38 | BaseModelInfo::BaseModelInfo(ModelDataType type) : type_(type) { 39 | } 40 | 41 | void BaseModelInfo::setCollisionModel(std::unique_ptr &col) { 42 | collision = std::move(col); 43 | } 44 | 45 | BaseModelInfo::~BaseModelInfo() = default; 46 | -------------------------------------------------------------------------------- /rwengine/src/data/PathData.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_PATHDATA_HPP_ 2 | #define _RWENGINE_PATHDATA_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | struct PathNode { 11 | enum NodeType { 12 | EMPTY = 0, /// These are ignored 13 | EXTERNAL = 1, /// May join with other paths 14 | INTERNAL = 2 /// Internal to this path 15 | }; 16 | 17 | NodeType type; 18 | int32_t next; 19 | glm::vec3 position{}; 20 | float size; 21 | int leftLanes; 22 | int rightLanes; 23 | }; 24 | 25 | struct PathData { 26 | enum PathType { PATH_PED, PATH_CAR }; 27 | 28 | PathType type; 29 | uint16_t ID; 30 | std::string modelName; 31 | std::vector nodes; 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /rwengine/src/data/PedData.cpp: -------------------------------------------------------------------------------- 1 | #include "PedData.hpp" 2 | #include 3 | 4 | uint32_t PedRelationship::threatFromName(const std::string &name) { 5 | static const std::unordered_map kThreatMap{ 6 | {"PLAYER1", THREAT_PLAYER1}, // Player 7 | {"PLAYER2", THREAT_PLAYER2}, // Unused 8 | {"PLAYER3", THREAT_PLAYER3}, // Unused 9 | {"PLAYER4", THREAT_PLAYER4}, // Unused 10 | {"CIVMALE", THREAT_CIVMALE}, // Civilan 11 | {"CIVFEMALE", THREAT_CIVFEMALE}, // Civilan 12 | {"COP", THREAT_COP}, // Police 13 | {"GANG1", THREAT_GANG1}, // Mafia 14 | {"GANG2", THREAT_GANG2}, // Triad 15 | {"GANG3", THREAT_GANG3}, // Diablo 16 | {"GANG4", THREAT_GANG4}, // Yakuza 17 | {"GANG5", THREAT_GANG5}, // Yardie 18 | {"GANG6", THREAT_GANG6}, // Columbian 19 | {"GANG7", THREAT_GANG7}, // Hood 20 | {"GANG8", THREAT_GANG8}, // Unused 21 | {"GANG9", THREAT_GANG9}, // Unused 22 | {"EMERGENCY", THREAT_EMERGENCY}, // Emergency services 23 | {"PROSTITUTE", THREAT_PROSTITUTE}, // ... 24 | {"CRIMINAL", THREAT_CRIMINAL}, // Criminals 25 | {"SPECIAL", THREAT_SPECIAL}, // SPECIAL 26 | {"GUN", THREAT_GUN}, // Not sure 27 | {"COP_CAR", THREAT_COP_CAR}, 28 | {"FAST_CAR", THREAT_FAST_CAR}, 29 | {"EXPLOSION", THREAT_EXPLOSION}, // Explosions 30 | {"FIREMAN", THREAT_FIREMAN}, // Firemen? 31 | {"DEADPEDS", THREAT_DEADPEDS}, // Dead bodies 32 | }; 33 | 34 | return kThreatMap.at(name); 35 | } 36 | -------------------------------------------------------------------------------- /rwengine/src/data/VehicleGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RWENGINE_VEHICLEGENERATOR_HPP 2 | #define RWENGINE_VEHICLEGENERATOR_HPP 3 | 4 | #include 5 | 6 | /** 7 | * Stores information about where the game can generate vehicles. 8 | */ 9 | struct VehicleGenerator { 10 | /// Script reference ID 11 | size_t generatorID; 12 | glm::vec3 position; 13 | float heading; 14 | /// ID of the vehicle to spawn, or -1 for random. 15 | int vehicleID; 16 | /// @todo not yet used 17 | int colourFG; 18 | /// @todo not yet used 19 | int colourBG; 20 | bool alwaysSpawn; 21 | /// @todo not yet used 22 | short alarmThreshold; 23 | /// @todo not yet used 24 | short lockedThreshold; 25 | 26 | int minDelay; 27 | /// @todo not yet used 28 | int maxDelay; 29 | int lastSpawnTime; 30 | 31 | /** 32 | * Number of vehicles left to spawn 0-100, 101 = never decrement. 33 | * Intentionally disabled to match behaviour 34 | */ 35 | int remainingSpawns; 36 | 37 | VehicleGenerator(size_t id, const glm::vec3& position_, float heading_, 38 | int modelID_, int colourFG_, int colourBG_, 39 | bool alwaysSpawn_, short alarmThreshold_, 40 | short lockedThreshold_, int minDelay_, int maxDelay_, 41 | int lastSpawnTime_, int remainingSpawns_) 42 | : generatorID(id) 43 | , position(position_) 44 | , heading(heading_) 45 | , vehicleID(modelID_) 46 | , colourFG(colourFG_) 47 | , colourBG(colourBG_) 48 | , alwaysSpawn(alwaysSpawn_) 49 | , alarmThreshold(alarmThreshold_) 50 | , lockedThreshold(lockedThreshold_) 51 | , minDelay(minDelay_) 52 | , maxDelay(maxDelay_) 53 | , lastSpawnTime(lastSpawnTime_) 54 | , remainingSpawns(remainingSpawns_) { 55 | } 56 | 57 | size_t getScriptObjectID() const { 58 | return generatorID; 59 | } 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /rwengine/src/data/WeaponData.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_WEAPONDATA_HPP_ 2 | #define _RWENGINE_WEAPONDATA_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct WeaponData { 10 | enum FireType { MELEE, INSTANT_HIT, PROJECTILE }; 11 | 12 | std::string name; 13 | FireType fireType; 14 | float hitRange; 15 | int fireRate; 16 | int reloadMS; 17 | int clipSize; 18 | int damage; 19 | float speed; 20 | float meleeRadius; 21 | float lifeSpan; 22 | float spread; 23 | glm::vec3 fireOffset{}; 24 | std::string animation1; 25 | std::string animation2; 26 | float animLoopStart; 27 | float animLoopEnd; 28 | float animFirePoint; /* Must be between 2 ^ */ 29 | float animCrouchLoopStart; 30 | float animCrouchLoopEnd; 31 | float animCrouchFirePoint; 32 | float breakoutAnim; 33 | int modelID; 34 | std::uint32_t flags; 35 | 36 | std::uint32_t inventorySlot; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /rwengine/src/data/Weather.cpp: -------------------------------------------------------------------------------- 1 | #include "Weather.hpp" 2 | 3 | #include 4 | 5 | namespace { 6 | Weather::Entry interpolateWeather(const Weather::Entry& a, 7 | const Weather::Entry& b, 8 | float t) { 9 | #define MIXPROP(prop) static_cast((1.0f - t) * a.prop + (t * b.prop)) 10 | return { 11 | MIXPROP(ambientColor), 12 | MIXPROP(directLightColor), 13 | MIXPROP(skyTopColor), 14 | MIXPROP(skyBottomColor), 15 | MIXPROP(sunCoreColor), 16 | MIXPROP(sunCoronaColor), 17 | MIXPROP(sunCoreSize), 18 | MIXPROP(sunCoronaSize), 19 | MIXPROP(sunBrightness), 20 | MIXPROP(shadowIntensity), 21 | MIXPROP(lightShading), 22 | MIXPROP(poleShading), 23 | MIXPROP(farClipping), 24 | MIXPROP(fogStart), 25 | MIXPROP(amountGroundLight), 26 | MIXPROP(lowCloudColor), 27 | MIXPROP(topCloudColor), 28 | MIXPROP(bottomCloudColor), 29 | {} 30 | }; 31 | #undef MIXPROP 32 | } 33 | } 34 | 35 | Weather::Entry Weather::interpolate(WeatherCondition prev, 36 | WeatherCondition next, 37 | float a, float tod) { 38 | const float t = tod - std::floor(tod); 39 | const auto nI = size_t(next) * 24; 40 | const auto pI = size_t(prev) * 24; 41 | const auto hour = size_t(tod); 42 | 43 | RW_ASSERT(nI < entries.size()); 44 | const auto& x = entries[nI + hour]; 45 | const auto& y = entries[nI + (hour + 1) % 24]; 46 | 47 | const auto& nextWeather = interpolateWeather(x, y, t); 48 | 49 | if (a >= 1.0f) { 50 | return nextWeather; 51 | } 52 | 53 | RW_ASSERT(pI < entries.size()); 54 | const auto& z = entries[pI + hour]; 55 | const auto& w = entries[pI + (hour + 1) % 24]; 56 | 57 | const auto& prevWeather = interpolateWeather(z, w, t); 58 | 59 | return interpolateWeather(prevWeather, nextWeather, a); 60 | } 61 | -------------------------------------------------------------------------------- /rwengine/src/data/Weather.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_WEATHER_HPP_ 2 | #define _RWENGINE_WEATHER_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | enum class WeatherCondition { Sunny = 0, Cloudy = 1, Rainy = 2, Foggy = 3 }; 13 | 14 | class Weather { 15 | public: 16 | struct Entry { 17 | glm::vec3 ambientColor{}; 18 | glm::vec3 directLightColor{}; 19 | glm::vec3 skyTopColor{}; 20 | glm::vec3 skyBottomColor{}; 21 | glm::vec3 sunCoreColor{}; 22 | glm::vec3 sunCoronaColor{}; 23 | float sunCoreSize; 24 | float sunCoronaSize; 25 | float sunBrightness; 26 | int32_t shadowIntensity; 27 | int32_t lightShading; 28 | int32_t poleShading; 29 | float farClipping; 30 | float fogStart; 31 | float amountGroundLight; 32 | glm::vec3 lowCloudColor{}; 33 | glm::vec3 topCloudColor{}; 34 | glm::vec3 bottomCloudColor{}; 35 | uint8_t unknown[4]; 36 | }; 37 | 38 | Entry interpolate(WeatherCondition lastWeather, 39 | WeatherCondition nextWeather, 40 | float a, float tod); 41 | 42 | std::vector entries; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /rwengine/src/data/ZoneData.cpp: -------------------------------------------------------------------------------- 1 | #include "data/ZoneData.hpp" 2 | 3 | #include "glm/glm.hpp" 4 | 5 | #include 6 | 7 | bool ZoneData::isZoneContained(const ZoneData &inner, const ZoneData &outer) { 8 | return glm::all(glm::greaterThanEqual(inner.min, outer.min)) && 9 | glm::all(glm::lessThanEqual(inner.max, outer.max)); 10 | } 11 | 12 | bool ZoneData::containsPoint(const glm::vec3 &point) const { 13 | return glm::all(glm::greaterThanEqual(point, min)) && 14 | glm::all(glm::lessThanEqual(point, max)); 15 | } 16 | 17 | ZoneData *ZoneData::findLeafAtPoint(const glm::vec3 &point) { 18 | for (ZoneData* child : children_) { 19 | auto descendent = child->findLeafAtPoint(point); 20 | if (descendent) { 21 | return descendent; 22 | } 23 | } 24 | return containsPoint(point) ? this : nullptr; 25 | } 26 | 27 | bool ZoneData::insertZone(ZoneData &inner) { 28 | if (!isZoneContained(inner, *this)) { 29 | return false; 30 | } 31 | 32 | for (ZoneData* child : children_) { 33 | if (child->insertZone(inner)) { 34 | return true; 35 | } 36 | } 37 | 38 | // inner is a child of outer 39 | 40 | // Move any zones that are really within inner to inner 41 | auto it = std::stable_partition( 42 | children_.begin(), children_.end(), 43 | [&](ZoneData* a) { return !inner.insertZone(*a); }); 44 | children_.erase(it, children_.end()); 45 | 46 | children_.push_back(&inner); 47 | inner.parent_ = this; 48 | 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /rwengine/src/dynamics/CollisionInstance.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_COLLISIONINSTANCE_HPP_ 2 | #define _RWENGINE_COLLISIONINSTANCE_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class btCollisionShape; 10 | class btCompoundShape; 11 | class btTriangleIndexVertexArray; 12 | struct CollisionModel; 13 | 14 | class GameObject; 15 | struct DynamicObjectData; 16 | struct VehicleHandlingInfo; 17 | 18 | class GameObjectMotionState : public btMotionState { 19 | public: 20 | explicit GameObjectMotionState(GameObject* object) : m_object(object) { 21 | } 22 | 23 | void getWorldTransform(btTransform& tform) const override; 24 | 25 | void setWorldTransform(const btTransform& tform) override; 26 | 27 | private: 28 | GameObject* m_object; 29 | }; 30 | 31 | /** 32 | * @brief CollisionInstance stores bullet body information 33 | */ 34 | class CollisionInstance { 35 | public: 36 | CollisionInstance() = default; 37 | 38 | ~CollisionInstance(); 39 | 40 | bool createPhysicsBody(GameObject* object, CollisionModel* collision, 41 | DynamicObjectData* dynamics = nullptr, 42 | VehicleHandlingInfo* handling = nullptr); 43 | 44 | btRigidBody* getBulletBody() const { 45 | return m_body.get(); 46 | } 47 | 48 | float getBoundingHeight() const { 49 | return m_collisionHeight; 50 | } 51 | 52 | void changeMass(float newMass); 53 | 54 | private: 55 | std::unique_ptr m_body; 56 | 57 | std::unique_ptr cmpShape; 58 | std::vector> m_shapes; 59 | std::unique_ptr m_vertArray; 60 | 61 | std::unique_ptr m_motionState; 62 | 63 | float m_collisionHeight{0.f}; 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /rwengine/src/dynamics/HitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "HitTest.hpp" 2 | #include 3 | 4 | #ifdef _MSC_VER 5 | #pragma warning(disable : 4305 5033) 6 | #endif 7 | #include 8 | #include 9 | 10 | #ifdef _MSC_VER 11 | #pragma warning(default : 4305 5033) 12 | #endif 13 | 14 | namespace { 15 | 16 | HitTest::TestResult HitTestWorld(btDiscreteDynamicsWorld& world, btPairCachingGhostObject& tester) 17 | { 18 | world.addCollisionObject(&tester); 19 | 20 | HitTest::TestResult result; 21 | result.reserve(static_cast(tester.getNumOverlappingObjects())); 22 | 23 | for (auto i = 0; i < tester.getNumOverlappingObjects(); ++i) 24 | { 25 | auto overlapping = tester.getOverlappingObject(i); 26 | 27 | HitTest::Hit hit{}; 28 | hit.body = overlapping; 29 | 30 | if (auto object = static_cast(overlapping->getUserPointer())) 31 | { 32 | hit.object = object; 33 | } 34 | 35 | result.push_back(hit); 36 | } 37 | 38 | world.removeCollisionObject(&tester); 39 | 40 | return result; 41 | } 42 | 43 | HitTest::TestResult HitTestWithShape(btDiscreteDynamicsWorld& world, btCollisionShape& shape, 44 | const glm::vec3& center, const glm::quat& rotation) { 45 | btPairCachingGhostObject ghost{}; 46 | btTransform xform{}; 47 | xform.setOrigin({center.x, center.y, center.z}); 48 | xform.setRotation({rotation.x, rotation.y, rotation.z, rotation.w}); 49 | ghost.setWorldTransform(xform); 50 | ghost.setCollisionShape(&shape); 51 | return HitTestWorld(world, ghost); 52 | } 53 | 54 | } // namespace 55 | 56 | HitTest::TestResult HitTest::sphereTest(const glm::vec3& center, float radius) { 57 | btSphereShape sphere {radius}; 58 | return HitTestWithShape(_world, sphere, center, {}); 59 | } 60 | 61 | HitTest::TestResult HitTest::boxTest(const glm::vec3 ¢er, const glm::vec3 &size, const glm::quat& rotation) { 62 | btBoxShape box {{size.x, size.y, size.z}}; 63 | return HitTestWithShape(_world, box, center, rotation); 64 | } 65 | -------------------------------------------------------------------------------- /rwengine/src/dynamics/HitTest.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_HITTEST_HPP_ 2 | #define _RWENGINE_HITTEST_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | class btDiscreteDynamicsWorld; 11 | class btCollisionObject; 12 | class GameObject; 13 | 14 | /** 15 | * Utility for performing collision tests against the world. 16 | */ 17 | class HitTest { 18 | public: 19 | struct Hit { 20 | btCollisionObject* body; 21 | GameObject* object; 22 | }; 23 | using TestResult = std::vector; 24 | 25 | explicit HitTest(btDiscreteDynamicsWorld& world) 26 | : _world(world) 27 | {} 28 | 29 | ~HitTest() = default; 30 | 31 | TestResult sphereTest(const glm::vec3& center, float radius); 32 | TestResult boxTest(const glm::vec3& center, const glm::vec3& size, const glm::quat& rotation = {1.f, 0.f, 0.f, 0.f}); 33 | 34 | private: 35 | btDiscreteDynamicsWorld& _world; 36 | }; 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /rwengine/src/dynamics/RaycastCallbacks.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_RAYCASTCALLBACKS_HPP_ 2 | #define _RWENGINE_RAYCASTCALLBACKS_HPP_ 3 | 4 | #ifdef _MSC_VER 5 | #pragma warning(disable : 4305) 6 | #endif 7 | #include 8 | #ifdef _MSC_VER 9 | #pragma warning(default : 4305) 10 | #endif 11 | 12 | /** 13 | * Implements raycast callback that ignores a specified btCollisionObject 14 | */ 15 | class ClosestNotMeRayResultCallback final 16 | : public btCollisionWorld::ClosestRayResultCallback { 17 | btCollisionObject* _self; 18 | 19 | public: 20 | ClosestNotMeRayResultCallback(btCollisionObject* self, 21 | const btVector3& from, const btVector3& to) 22 | : ClosestRayResultCallback(from, to), _self(self) { 23 | } 24 | 25 | btScalar addSingleResult( 26 | btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override { 27 | if (rayResult.m_collisionObject == _self) { 28 | return 1.0; 29 | } 30 | return ClosestRayResultCallback::addSingleResult(rayResult, 31 | normalInWorldSpace); 32 | } 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /rwengine/src/engine/GameInputState.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RWENGINE_GAMEINPUTSTATE_HPP 2 | #define RWENGINE_GAMEINPUTSTATE_HPP 3 | 4 | struct GameInputState { 5 | static constexpr float kButtonOnThreshold = 0.1f; 6 | 7 | /// Inputs that can be controlled 8 | /// @todo find any sensible values 9 | enum Control { 10 | /* On Foot */ 11 | FireWeapon = 0, 12 | NextWeapon, 13 | LastWeapon, 14 | GoForward, 15 | GoBackwards, 16 | GoLeft, 17 | GoRight, 18 | ZoomIn, 19 | ZoomOut, 20 | EnterExitVehicle, 21 | ChangeCamera, 22 | Jump, 23 | Sprint, 24 | AimWeapon, 25 | Crouch, 26 | Walk, 27 | LookBehind, 28 | 29 | /* In Vehicle */ 30 | VehicleAccelerate, 31 | VehicleBrake, 32 | VehicleDown, 33 | VehicleUp, 34 | ChangeRadio, 35 | Horn, 36 | Submission, 37 | Handbrake, 38 | LookLeft, 39 | LookRight, 40 | VehicleAimLeft, 41 | VehicleAimRight, 42 | VehicleAimUp, 43 | VehicleAimDown, 44 | 45 | _MaxControls, 46 | 47 | NextTarget = NextWeapon, 48 | LastTarget = LastWeapon, 49 | VehicleLeft = GoLeft, 50 | VehicleRight = GoRight, 51 | VehicleFireWeapon = FireWeapon, 52 | }; 53 | 54 | /** 55 | * Current state of each control [0 to 1]. 56 | * 57 | * For buttons, this will result in either 0 or 1. 58 | */ 59 | float levels[_MaxControls] = {}; 60 | 61 | float operator[](Control c) const { 62 | return levels[c]; 63 | } 64 | 65 | /** 66 | * @return if cotrol is held down 67 | */ 68 | bool pressed(Control c) const { 69 | return levels[c] > kButtonOnThreshold; 70 | } 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /rwengine/src/engine/Payphone.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_PAYPHONE_HPP_ 2 | #define _RWENGINE_PAYPHONE_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace ai { 10 | class PlayerController; 11 | } // namespace ai 12 | 13 | class GameWorld; 14 | class GameState; 15 | 16 | class GameObject; 17 | class InstanceObject; 18 | class CharacterObject; 19 | 20 | class Payphone { 21 | private: 22 | InstanceObject* object; 23 | glm::vec3 position; 24 | GameWorld* engine; 25 | float callTimer = 0.f; 26 | std::string message; 27 | 28 | public: 29 | enum class State { Idle, Ringing, PickingUp, Talking, HangingUp }; 30 | 31 | State state = State::Idle; 32 | 33 | size_t id; 34 | 35 | size_t getScriptObjectID() const { 36 | return id; 37 | } 38 | 39 | Payphone(GameWorld* engine_, size_t id_, const glm::vec2& coord); 40 | ~Payphone() = default; 41 | 42 | // Makes a payphone ring 43 | void enable(); 44 | // Disables ringing 45 | void disable(); 46 | // Is currently used by player 47 | bool isTalking() const; 48 | // Sets a message and makes a payphone ring 49 | void setMessageAndStartRinging(const std::string& m); 50 | void tick(float dt); 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /rwengine/src/engine/SaveGame.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_SAVEGAME_HPP_ 2 | #define _RWENGINE_SAVEGAME_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct SaveGameInfo { 10 | std::string savePath; 11 | bool valid; 12 | BasicState basicState; 13 | }; 14 | 15 | /** 16 | * Reads and Writes GameStates to disk, restoring the required state information 17 | */ 18 | class SaveGame { 19 | public: 20 | /** 21 | * Writes the entire game state to a file format that closely approximates 22 | * the format used in GTA III 23 | */ 24 | static void writeGame(GameState& state, const std::string& file); 25 | 26 | /** 27 | * Loads an entire Game State from a file, using a format similar to the 28 | * format used by GTA III. 29 | * 30 | * It assumes that the state already has a world and script that have been 31 | * initalized to the same state as the game being loaded. 32 | * @return status, false if failure occured. 33 | */ 34 | static bool loadGame(GameState& state, const std::string& file); 35 | 36 | static bool getSaveInfo(const std::string& file, BasicState* outState); 37 | 38 | /** 39 | * Returns save game information for all found saves 40 | */ 41 | static std::vector getAllSaveGameInfo(); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /rwengine/src/items/Weapon.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_WEAPON_HPP_ 2 | #define _RWENGINE_WEAPON_HPP_ 3 | #include 4 | 5 | class CharacterObject; 6 | class GameObject; 7 | struct WeaponData; 8 | 9 | enum class ScanType { 10 | /** Instant-hit ray weapons */ 11 | HitScan, 12 | /** Area of effect attack */ 13 | Radius, 14 | }; 15 | 16 | /** 17 | * @brief simple object for performing weapon checks against the world 18 | */ 19 | struct WeaponScan { 20 | const ScanType type; 21 | 22 | float damage; 23 | 24 | glm::vec3 center{}; 25 | float radius; 26 | 27 | glm::vec3 end{}; 28 | 29 | WeaponData* weapon; 30 | GameObject* source; 31 | 32 | // Constructor for Radius 33 | WeaponScan(float damage, const glm::vec3& center, float radius, 34 | WeaponData* weapon = nullptr, GameObject* source = nullptr) 35 | : type(ScanType::Radius) 36 | , damage(damage) 37 | , center(center) 38 | , radius(radius) 39 | , weapon(weapon) 40 | , source(source) { 41 | } 42 | 43 | // Constructor for HitScan 44 | WeaponScan(float damage, const glm::vec3& start, const glm::vec3& end, 45 | WeaponData* weapon = nullptr, GameObject* source = nullptr) 46 | : type(ScanType::HitScan) 47 | , damage(damage) 48 | , center(start) 49 | , end(end) 50 | , weapon(weapon) 51 | , source(source) { 52 | } 53 | 54 | bool doesDamage(GameObject* target) const; 55 | }; 56 | 57 | namespace Weapon { 58 | void fireProjectile(WeaponData* weapon, CharacterObject* character, float force); 59 | void fireHitscan(WeaponData *weapon, CharacterObject* character); 60 | void meleeHit(WeaponData *weapon, CharacterObject* character); 61 | bool targetOnGround(WeaponData *weapon, CharacterObject* character); 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /rwengine/src/loaders/GenericDATLoader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_GENERICDATLOADER_HPP_ 2 | #define _RWENGINE_GENERICDATLOADER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct DynamicObjectData; 11 | struct WeaponData; 12 | struct VehicleInfo; 13 | 14 | class GenericDATLoader { 15 | public: 16 | void loadDynamicObjects( 17 | const std::string& name, 18 | std::unordered_map& data); 19 | 20 | void loadWeapons(const std::string& name, 21 | std::vector& weaponData); 22 | 23 | void loadHandling( 24 | const std::string& name, 25 | std::unordered_map& vehicleData); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderCOL.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOADERCOL_HPP_ 2 | #define _RWENGINE_LOADERCOL_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct CollisionModel; 9 | 10 | /** 11 | * @class LoaderCOL 12 | * Loads collision data from COL files 13 | */ 14 | class LoaderCOL { 15 | public: 16 | 17 | /// Load the COL data into memory 18 | bool load(const std::string& file); 19 | 20 | std::vector> collisions; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderCutsceneDAT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOADERCUTSCENEDAT_HPP_ 2 | #define _RWENGINE_LOADERCUTSCENEDAT_HPP_ 3 | 4 | #include 5 | 6 | struct CutsceneTracks; 7 | 8 | class LoaderCutsceneDAT { 9 | public: 10 | void load(CutsceneTracks& tracks, const FileContentsInfo& file); 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderGXT.cpp: -------------------------------------------------------------------------------- 1 | #include "loaders/LoaderGXT.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | void LoaderGXT::load(GameTexts &texts, const FileContentsInfo &file) { 12 | auto data = file.data.get(); 13 | 14 | data += 4; // TKEY 15 | 16 | std::uint32_t blocksize = *reinterpret_cast(data); 17 | 18 | data += 4; 19 | 20 | auto tdata = data + blocksize + 8; 21 | 22 | for (size_t t = 0; t < blocksize / 12; ++t) { 23 | size_t offset = *reinterpret_cast(data + (t * 12 + 0)); 24 | std::string id(data + (t * 12 + 4)); 25 | 26 | GameStringChar *stringSrc = 27 | reinterpret_cast(tdata + offset); 28 | GameString string(stringSrc); 29 | texts.addText(id, std::move(string)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderGXT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOADERGXT_HPP_ 2 | #define _RWENGINE_LOADERGXT_HPP_ 3 | 4 | #include 5 | 6 | class GameTexts; 7 | 8 | class LoaderGXT { 9 | public: 10 | void load(GameTexts& texts, const FileContentsInfo& file); 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderIDE.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOADERIDE_HPP_ 2 | #define _RWENGINE_LOADERIDE_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class LoaderIDE { 12 | public: 13 | enum SectionTypes { 14 | NONE, 15 | OBJS, 16 | TOBJ, 17 | PEDS, 18 | CARS, 19 | HIER, 20 | TWODFX, 21 | PATH, 22 | }; 23 | 24 | // Load the IDE data into memory 25 | bool load(const std::string& filename, const PedStatsList& stats); 26 | 27 | bool load(std::istream& data, const PedStatsList& stats); 28 | 29 | /** 30 | * @brief objects loaded during the call to load() 31 | */ 32 | std::map> objects; 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /rwengine/src/loaders/LoaderIPL.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_LOADERIPL_HPP_ 2 | #define _RWENGINE_LOADERIPL_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | struct InstanceData; 12 | 13 | /** 14 | \class LoaderIPL 15 | \brief Loads all data from a IPL file into memory 16 | */ 17 | class LoaderIPL { 18 | public: 19 | /// Load the IPL data from filename 20 | bool load(const std::string& filename); 21 | 22 | /// Parse IPL data from the stream 23 | bool load(std::istream& stream); 24 | 25 | /// The list of instances from the IPL file 26 | std::vector m_instances; 27 | 28 | /// List of Zones 29 | ZoneDataList zones; 30 | }; 31 | 32 | #endif // LoaderIPL_h__ 33 | -------------------------------------------------------------------------------- /rwengine/src/loaders/WeatherLoader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace { 10 | glm::vec3 readRGB(std::stringstream &ss) { 11 | int r, g, b; 12 | ss >> r >> g >> b; 13 | return {r/255.f, g/255.f, b/255.f}; 14 | } 15 | } 16 | 17 | bool WeatherLoader::load(const std::string& filename, Weather& outWeather) { 18 | std::ifstream fstream(filename.c_str()); 19 | 20 | if (!fstream.is_open()) return false; 21 | 22 | std::string line; 23 | while (std::getline(fstream, line)) { 24 | if (line[0] == '/') // Comment line 25 | continue; 26 | 27 | Weather::Entry weather; 28 | std::stringstream ss(line); 29 | 30 | weather.ambientColor = readRGB(ss); 31 | weather.directLightColor = readRGB(ss); 32 | weather.skyTopColor = readRGB(ss); 33 | weather.skyBottomColor = readRGB(ss); 34 | weather.sunCoreColor = readRGB(ss); 35 | weather.sunCoronaColor = readRGB(ss); 36 | 37 | ss >> weather.sunCoreSize; 38 | ss >> weather.sunCoronaSize; 39 | ss >> weather.sunBrightness; 40 | ss >> weather.shadowIntensity; 41 | ss >> weather.lightShading; 42 | ss >> weather.poleShading; 43 | ss >> weather.farClipping; 44 | ss >> weather.fogStart; 45 | ss >> weather.amountGroundLight; 46 | 47 | weather.lowCloudColor = readRGB(ss); 48 | weather.topCloudColor = readRGB(ss); 49 | weather.bottomCloudColor = readRGB(ss); 50 | 51 | int d; 52 | for (auto &i : weather.unknown) { 53 | ss >> d; 54 | i = d; 55 | } 56 | 57 | outWeather.entries.push_back(weather); 58 | } 59 | 60 | return true; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /rwengine/src/loaders/WeatherLoader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_WEATHERLOADER_HPP_ 2 | #define _RWENGINE_WEATHERLOADER_HPP_ 3 | 4 | #include 5 | 6 | class Weather; 7 | 8 | namespace WeatherLoader { 9 | bool load(const std::string &filename, Weather& outWeather); 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /rwengine/src/objects/CutsceneObject.cpp: -------------------------------------------------------------------------------- 1 | #include "objects/CutsceneObject.hpp" 2 | 3 | #include 4 | 5 | #include "data/ModelData.hpp" 6 | #include "engine/Animator.hpp" 7 | 8 | CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, 9 | const glm::quat &rot, const ClumpPtr& model, 10 | BaseModelInfo *modelinfo) 11 | : GameObject(engine, pos, rot, modelinfo) { 12 | if (model) { 13 | setModel(model->clone()); 14 | } 15 | else { 16 | setModel(getModelInfo()->getModel()->clone()); 17 | } 18 | animator = std::make_unique(getClump()); 19 | } 20 | 21 | void CutsceneObject::tick(float dt) { 22 | animator->tick(dt); 23 | } 24 | 25 | void CutsceneObject::setParentActor(GameObject *parent, ModelFrame *bone) { 26 | _parent = parent; 27 | _bone = bone; 28 | } 29 | -------------------------------------------------------------------------------- /rwengine/src/objects/CutsceneObject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_CUTSCENEOBJECT_HPP_ 2 | #define _RWENGINE_CUTSCENEOBJECT_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | class BaseModelInfo; 9 | class GameWorld; 10 | class ModelFrame; 11 | 12 | /** 13 | * @brief Object type used for cutscene animations. 14 | */ 15 | class CutsceneObject final : public GameObject { 16 | GameObject* _parent = nullptr; 17 | ModelFrame* _bone = nullptr; 18 | 19 | public: 20 | CutsceneObject(GameWorld* engine, const glm::vec3& pos, 21 | const glm::quat& rot, const ClumpPtr& model, 22 | BaseModelInfo* modelinfo); 23 | ~CutsceneObject() override = default; 24 | 25 | Type type() const override { 26 | return Cutscene; 27 | } 28 | 29 | void tick(float dt) override; 30 | 31 | void setParentActor(GameObject* parent, ModelFrame* bone); 32 | 33 | GameObject* getParentActor() const { 34 | return _parent; 35 | } 36 | 37 | ModelFrame* getParentFrame() const { 38 | return _bone; 39 | } 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /rwengine/src/objects/GameObject.cpp: -------------------------------------------------------------------------------- 1 | #include "objects/GameObject.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "engine/Animator.hpp" 10 | 11 | const AtomicPtr GameObject::NullAtomic; 12 | const ClumpPtr GameObject::NullClump; 13 | 14 | GameObject::~GameObject() { 15 | if (modelinfo_) { 16 | modelinfo_->removeReference(); 17 | } 18 | } 19 | 20 | void GameObject::setPosition(const glm::vec3& pos) { 21 | position = pos; 22 | } 23 | 24 | void GameObject::setRotation(const glm::quat& orientation) { 25 | rotation = orientation; 26 | } 27 | 28 | float GameObject::getHeading() const { 29 | auto hdg = glm::roll(getRotation()); 30 | return hdg / glm::pi() * 180.f; 31 | } 32 | 33 | void GameObject::setHeading(float heading) { 34 | auto hdg = (heading / 180.f) * glm::pi(); 35 | auto quat = glm::normalize(glm::quat(glm::vec3(0.f, 0.f, hdg))); 36 | setRotation(quat); 37 | } 38 | 39 | void GameObject::updateTransform(const glm::vec3& pos, const glm::quat& rot) { 40 | position = pos; 41 | rotation = rot; 42 | 43 | const auto& clump = getClump(); 44 | const auto& atomic = getAtomic(); 45 | if (clump) { 46 | clump->getFrame()->setRotation(glm::mat3_cast(rot)); 47 | clump->getFrame()->setTranslation(pos); 48 | } 49 | if (atomic) { 50 | atomic->getFrame()->setRotation(glm::mat3_cast(rot)); 51 | atomic->getFrame()->setTranslation(pos); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rwengine/src/objects/InstanceObject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_INSTANCEOBJECT_HPP_ 2 | #define _RWENGINE_INSTANCEOBJECT_HPP_ 3 | 4 | #include "objects/GameObject.hpp" 5 | 6 | #include 7 | 8 | #include 9 | 10 | class BaseModelInfo; 11 | class CollisionInstance; 12 | class GameWorld; 13 | 14 | /** 15 | * @struct InstanceObject 16 | * A simple object instance 17 | */ 18 | class InstanceObject final : public GameObject { 19 | float health = 100.f; 20 | bool visible =true; 21 | bool floating = false; 22 | bool static_ = false; 23 | bool usePhysics = false; 24 | int changeAtomic = -1; 25 | 26 | /** 27 | * The Atomic instance for this object 28 | */ 29 | AtomicPtr atomic_; 30 | 31 | public: 32 | glm::vec3 scale; 33 | std::unique_ptr body; 34 | DynamicObjectData* dynamics; 35 | 36 | InstanceObject(GameWorld* engine, const glm::vec3& pos, 37 | const glm::quat& rot, const glm::vec3& scale, 38 | BaseModelInfo* modelinfo, 39 | DynamicObjectData* dyn); 40 | ~InstanceObject() override; 41 | 42 | Type type() const override { 43 | return Instance; 44 | } 45 | 46 | const AtomicPtr& getAtomic() const { 47 | return atomic_; 48 | } 49 | 50 | void tick(float dt) override; 51 | 52 | void tickPhysics(float dt); 53 | 54 | void changeModel(BaseModelInfo* incoming, int atomicNumber = 0); 55 | 56 | void setPosition(const glm::vec3& pos) override; 57 | 58 | void setRotation(const glm::quat& r) override; 59 | 60 | bool takeDamage(const DamageInfo& damage) override; 61 | 62 | void setSolid(bool s); 63 | 64 | void setStatic(bool s); 65 | 66 | bool isStatic() const { 67 | return static_; 68 | } 69 | 70 | void setVisible(bool v) { 71 | visible = v; 72 | } 73 | 74 | bool isVisible() const { 75 | return visible; 76 | } 77 | 78 | void setFloating(bool f) { 79 | floating = f; 80 | } 81 | 82 | bool isFloating() const { 83 | return floating; 84 | } 85 | 86 | float getHealth() const { 87 | return health; 88 | } 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /rwengine/src/objects/ObjectTypes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_OBJECTTYPES_ 2 | #define _RWENGINE_OBJECTTYPES_ 3 | 4 | #include 5 | 6 | /** 7 | * all wordly GameObjects are associated with a 32-bit identifier 8 | */ 9 | typedef uint32_t GameObjectID; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /rwengine/src/objects/ProjectileObject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_PROJECTILEOBJECT_HPP_ 2 | #define _RWENGINE_PROJECTILEOBJECT_HPP_ 3 | 4 | #include 5 | #include 6 | #include "render/VisualFX.hpp" 7 | 8 | class GameWorld; 9 | class btPairCachingGhostObject; 10 | class btSphereShape; 11 | struct WeaponData; 12 | 13 | /** 14 | * @brief Implements weapon projectile (e.g. molotovs, RPGs etc.) 15 | */ 16 | class ProjectileObject final : public GameObject { 17 | public: 18 | enum ProjectileType { 19 | Grenade, 20 | Molotov, 21 | RPG, 22 | }; 23 | 24 | struct ProjectileInfo { 25 | ProjectileInfo(ProjectileType type, glm::vec3 direction, 26 | float velocity, float time, WeaponData* weapon) 27 | : type(type) 28 | , direction(direction) 29 | , velocity(velocity) 30 | , time(time) 31 | , weapon(weapon) { 32 | } 33 | ProjectileType type; 34 | glm::vec3 direction{}; 35 | float velocity; 36 | 37 | /** Time to dentonation or removal */ 38 | float time; 39 | 40 | WeaponData* weapon; 41 | }; 42 | 43 | private: 44 | ProjectileInfo _info; 45 | 46 | std::unique_ptr _shape; 47 | 48 | std::unique_ptr _body; 49 | 50 | /** Used for RPGs and Molotov collision detection */ 51 | std::unique_ptr _ghostBody; 52 | 53 | GameObjectMotionState _motionState; 54 | 55 | bool _exploded = false; 56 | 57 | void checkPhysicsContact(); 58 | void explode(); 59 | void cleanup(); 60 | 61 | public: 62 | /** 63 | * @brief ProjectileObject constructor 64 | */ 65 | ProjectileObject(GameWorld* world, const glm::vec3& position, 66 | const ProjectileInfo& info); 67 | 68 | ~ProjectileObject() override; 69 | 70 | void tick(float dt) override; 71 | 72 | Type type() const override { 73 | return Projectile; 74 | } 75 | 76 | const ProjectileInfo& getProjectileInfo() const { 77 | return _info; 78 | } 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /rwengine/src/render/DebugDraw.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_DEBUGDRAW_HPP_ 2 | #define _RWENGINE_DEBUGDRAW_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef _MSC_VER 8 | #pragma warning(disable : 4305) 9 | #endif 10 | #include 11 | #include 12 | #ifdef _MSC_VER 13 | #pragma warning(default : 4305) 14 | #endif 15 | 16 | #include "render/OpenGLRenderer.hpp" 17 | 18 | class btVector3; 19 | class DrawBuffer; 20 | class GameRenderer; 21 | class GeometryBuffer; 22 | struct GeometryVertex; 23 | 24 | class DebugDraw final : public btIDebugDraw { 25 | public: 26 | DebugDraw(); 27 | ~DebugDraw() override = default; 28 | 29 | void drawLine(const btVector3 &from, const btVector3 &to, 30 | const btVector3 &color) override; 31 | void drawLine(const glm::vec3 &from, const glm::vec3 &to, 32 | const glm::vec3 &color) { 33 | drawLine(btVector3{from.x, from.y, from.z}, 34 | btVector3{to.x, to.y, to.z}, 35 | btVector3{color.r, color.g, color.b}); 36 | } 37 | void drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB, 38 | btScalar distance, int lifeTime, 39 | const btVector3 &color) override; 40 | void reportErrorWarning(const char *warningString) override; 41 | void draw3dText(const btVector3 &location, const char *textString) override; 42 | void setDebugMode(int debugMode) override; 43 | int getDebugMode() const override; 44 | 45 | void flush(GameRenderer &renderer); 46 | 47 | void setShaderProgram(Renderer::ShaderProgram *shaderProgram) { 48 | this->shaderProgram = shaderProgram; 49 | } 50 | 51 | protected: 52 | int debugMode; 53 | 54 | std::vector lines; 55 | size_t maxlines; 56 | std::unique_ptr lineBuff = std::make_unique(); 57 | std::unique_ptr dbuff = std::make_unique(); 58 | 59 | //Ownership is handled by worldProg in renderer 60 | Renderer::ShaderProgram *shaderProgram = nullptr; 61 | 62 | GLuint texture; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /rwengine/src/render/MapRenderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_MAPRENDERER_HPP_ 2 | #define _RWENGINE_MAPRENDERER_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "render/OpenGLRenderer.hpp" 11 | 12 | class GameData; 13 | class GameWorld; 14 | 15 | #define MAP_BLOCK_SIZE 63 16 | 17 | /** 18 | * Utility class for rendering the world map, in the menu and radar. 19 | */ 20 | class MapRenderer { 21 | public: 22 | struct MapInfo { 23 | /// World coordinate center 24 | glm::vec2 worldCenter{}; 25 | /// World units to fit on the map 26 | float worldSize; 27 | 28 | /// yaw of the map 29 | float rotation = 0.f; 30 | 31 | glm::vec2 screenPosition{}; 32 | float screenSize; 33 | /// Make the map circular, or don't. 34 | bool clipToSize = true; 35 | }; 36 | 37 | MapRenderer(Renderer& renderer, GameData* data); 38 | 39 | void draw(GameWorld* world, const MapInfo& mi); 40 | void scaleHUD(const float scale); 41 | 42 | private: 43 | GameData* data; 44 | Renderer& renderer; 45 | 46 | GeometryBuffer rectGeom; 47 | DrawBuffer rect; 48 | 49 | GeometryBuffer circleGeom; 50 | DrawBuffer circle; 51 | 52 | float radarNorthBlipSize = 24.f; 53 | float defaultBlipSize = 18.f; 54 | float hudScale = 1.f; 55 | 56 | std::unique_ptr rectProg; 57 | 58 | void prepareBlip(const glm::vec2& coord, const glm::mat4& view, 59 | const MapInfo& mi, const std::string& texture, 60 | glm::vec4 colour, float size, float heading); 61 | void drawBlip(const glm::vec2& coord, const glm::mat4& view, 62 | const MapInfo& mi, const std::string& texture, 63 | glm::vec4 colour, float size, float heading = 0.0f); 64 | void drawBlip(const glm::vec2& coord, const glm::mat4& view, 65 | const MapInfo& mi, glm::vec4 colour, float size); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /rwengine/src/render/ViewCamera.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_VIEWCAMERA_HPP_ 2 | #define _RWENGINE_VIEWCAMERA_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include "render/ViewFrustum.hpp" 8 | 9 | class ViewCamera { 10 | public: 11 | ViewFrustum frustum{0.1f, 5000.f, glm::radians(45.f), 1.f}; 12 | 13 | glm::vec3 position; 14 | glm::quat rotation; 15 | 16 | ViewCamera(const glm::vec3& pos = {}, 17 | const glm::quat& rot = {1.0f,0.0f,0.0f,0.0f}) 18 | : position(pos) 19 | , rotation(rot) { 20 | } 21 | 22 | glm::mat4 getView() const { 23 | auto up = rotation * glm::vec3(0.f, 0.f, 1.f); 24 | return glm::lookAt(position, 25 | position + rotation * glm::vec3(1.f, 0.f, 0.f), up); 26 | } 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /rwengine/src/render/ViewFrustum.cpp: -------------------------------------------------------------------------------- 1 | #include "render/ViewFrustum.hpp" 2 | 3 | #include 4 | #include 5 | 6 | glm::mat4 ViewFrustum::projection() const { 7 | return glm::perspective(fov / aspectRatio, aspectRatio, near, far); 8 | } 9 | 10 | void ViewFrustum::update(const glm::mat4 &proj) { 11 | for (auto i = 0u; i < 6; ++i) { 12 | float sign = (i % 2 == 0) ? 1.f : -1.f; 13 | auto r = i / 2; 14 | planes[i].normal.x = proj[0][3] + proj[0][r] * sign; 15 | planes[i].normal.y = proj[1][3] + proj[1][r] * sign; 16 | planes[i].normal.z = proj[2][3] + proj[2][r] * sign; 17 | planes[i].distance = proj[3][3] + proj[3][r] * sign; 18 | 19 | auto l = glm::length(planes[i].normal); 20 | planes[i].normal /= l; 21 | planes[i].distance /= l; 22 | } 23 | } 24 | 25 | bool ViewFrustum::intersects(glm::vec3 center, float radius) const { 26 | float d; 27 | bool result = true; 28 | 29 | for (const auto &plane : planes) { 30 | d = glm::dot(plane.normal, center) + plane.distance; 31 | if (d < -radius) result = false; 32 | } 33 | 34 | return result; 35 | } 36 | -------------------------------------------------------------------------------- /rwengine/src/render/ViewFrustum.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_VIEWFRUSTUM_HPP_ 2 | #define _RWENGINE_VIEWFRUSTUM_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef RW_WINDOWS 8 | #include 9 | #endif 10 | 11 | class ViewFrustum { 12 | public: 13 | class ViewPlane { 14 | public: 15 | glm::vec3 normal{}; 16 | float distance{}; 17 | }; 18 | 19 | float near{}; 20 | float far{}; 21 | float fov{}; 22 | float aspectRatio{}; 23 | 24 | ViewPlane planes[6]{}; 25 | 26 | ViewFrustum(float near, float far, float fov, float aspect) 27 | : near(near), far(far), fov(fov), aspectRatio(aspect) { 28 | } 29 | 30 | glm::mat4 projection() const; 31 | 32 | void update(const glm::mat4& proj); 33 | 34 | bool intersects(glm::vec3 center, float radius) const; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /rwengine/src/render/VisualFX.cpp: -------------------------------------------------------------------------------- 1 | #include "render/VisualFX.hpp" 2 | -------------------------------------------------------------------------------- /rwengine/src/render/VisualFX.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_VISUALFX_HPP_ 2 | #define _RWENGINE_VISUALFX_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | enum EffectType { Light, Particle, Trail }; 11 | 12 | /** 13 | * Represents a scene effect: lighting, particles etc. 14 | */ 15 | struct VisualFX { 16 | VisualFX() = default; 17 | virtual ~VisualFX() = default; 18 | 19 | virtual EffectType getType() const = 0; 20 | 21 | /** Initial world position */ 22 | glm::vec3 position{}; 23 | }; 24 | 25 | struct LightFX final : public VisualFX { 26 | LightFX() = default; 27 | ~LightFX() override = default; 28 | 29 | EffectType getType() const override { 30 | return Light; 31 | } 32 | }; 33 | 34 | struct ParticleFX final : public VisualFX { 35 | /** Direction of particle */ 36 | glm::vec3 direction{}; 37 | 38 | /** Particle orientation modes */ 39 | enum Orientation { 40 | Free, /** faces direction using up */ 41 | Camera, /** Faces towards the camera @todo implement */ 42 | UpCamera /** Face closes point in camera's look direction */ 43 | }; 44 | Orientation orientation{Free}; 45 | 46 | /** Game time at particle instantiation */ 47 | float starttime{0.f}; 48 | /** Number of seconds particle should exist for, negative values = 49 | * forever */ 50 | float lifetime{-1.f}; 51 | 52 | /** Texture name */ 53 | TextureData* texture = nullptr; 54 | 55 | /** Size of particle */ 56 | glm::vec2 size{1.f, 1.f}; 57 | 58 | /** Up direction (only used in Free mode) */ 59 | glm::vec3 up{0.f, 0.f, 1.f}; 60 | 61 | /** Render tint colour */ 62 | glm::vec4 colour{1.f, 1.f, 1.f, 1.f}; 63 | 64 | /** Constructs a particle */ 65 | ParticleFX() = default; 66 | ~ParticleFX() override = default; 67 | 68 | EffectType getType() const override { 69 | return Particle; 70 | } 71 | }; 72 | 73 | struct TrailFX final : public VisualFX { 74 | TrailFX() = default; 75 | ~TrailFX() = default; 76 | 77 | EffectType getType() const override { 78 | return Trail; 79 | } 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /rwengine/src/render/WaterRenderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_WATERRENDERER_HPP_ 2 | #define _RWENGINE_WATERRENDERER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class GameRenderer; 14 | class GameWorld; 15 | 16 | /** 17 | * Implements the rendering routines for drawing the sea water. 18 | */ 19 | class WaterRenderer { 20 | public: 21 | WaterRenderer(GameRenderer& renderer); 22 | ~WaterRenderer() = default; 23 | 24 | /** 25 | * Creates the required data for rendering the water. Accepts 26 | * two arrays. waterHeights stores the real world heights which 27 | * are indexed into by the array tiles for each water tile. 28 | * 29 | * This data is used to create the internal stencil mask for clipping 30 | * the water rendering. 31 | */ 32 | void setWaterTable(const float* waterHeights, const unsigned int nHeights, 33 | const uint8_t* tiles, const unsigned int nTiles); 34 | 35 | void setDataTexture(GLuint fbBinding, GLuint dataTexture); 36 | 37 | /** 38 | * Render the water using the currently active render state 39 | */ 40 | void render(GameRenderer& renderer, GameWorld* world); 41 | 42 | private: 43 | std::unique_ptr waterProg = nullptr; 44 | std::unique_ptr maskProg = nullptr; 45 | 46 | DrawBuffer maskDraw{}; 47 | GeometryBuffer maskGeom{}; 48 | 49 | std::vector maskSizes; 50 | 51 | DrawBuffer gridDraw{}; 52 | GeometryBuffer gridGeom{}; 53 | 54 | GLuint fbOutput{}; 55 | GLuint dataTexture{}; 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /rwengine/src/rw_mingw.hpp: -------------------------------------------------------------------------------- 1 | #undef IGNORE 2 | #undef near 3 | #undef far 4 | -------------------------------------------------------------------------------- /rwengine/src/script/SCMFile.cpp: -------------------------------------------------------------------------------- 1 | #include "script/SCMFile.hpp" 2 | 3 | #include 4 | #include 5 | 6 | void SCMFile::loadFile(char *data, size_t size) { 7 | _data = std::make_unique(size); 8 | std::copy(data, data + size, _data.get()); 9 | 10 | // Bytes required to hop over a jump opcode. 11 | const unsigned int jumpOpSize = 2u + 1u + 4u; 12 | const unsigned int jumpParamSize = 2u + 1u; 13 | 14 | _target = static_cast(_data[jumpOpSize]); 15 | globalSectionOffset = jumpOpSize + 1u; 16 | modelSectionOffset = read(jumpParamSize) + jumpOpSize + 1u; 17 | missionSectionOffset = 18 | read(modelSectionOffset - jumpOpSize - 1u + jumpParamSize) + 19 | jumpOpSize + 1u; 20 | codeSectionOffset = 21 | read(missionSectionOffset - jumpOpSize - 1u + jumpParamSize); 22 | 23 | unsigned int model_count = read(modelSectionOffset); 24 | models.reserve(model_count); 25 | 26 | int i = modelSectionOffset + sizeof(uint32_t); 27 | for (unsigned int m = 0; m < model_count; ++m) { 28 | char model_name[24]; 29 | for (char &c : model_name) { 30 | c = read(i++); 31 | } 32 | models.emplace_back(model_name); 33 | } 34 | 35 | i = missionSectionOffset; 36 | mainSize = read(i); 37 | i += sizeof(uint32_t); 38 | missionLargestSize = read(i); 39 | i += sizeof(uint32_t); 40 | unsigned int missionCount = read(i); 41 | missionOffsets.reserve(missionCount); 42 | i += sizeof(uint32_t); 43 | 44 | for (unsigned int m = 0; m < missionCount; ++m) { 45 | missionOffsets.push_back(read(i)); 46 | i += sizeof(uint32_t); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rwengine/src/script/ScriptFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "script/ScriptMachine.hpp" 2 | 3 | #include "engine/GameWorld.hpp" 4 | #include "script/SCMFile.hpp" 5 | #include "script/ScriptFunctions.hpp" 6 | 7 | namespace { 8 | constexpr char const* sprite_names[] = { 9 | "", // 0 10 | "radar_asuka", 11 | "radar_bomb", 12 | "radar_cat", 13 | "radar_centre", 14 | "radar_copcar", 15 | "radar_don", 16 | "radar_eight", 17 | "radar_el", 18 | "radar_ice", 19 | "radar_joey", 20 | "radar_kenji", 21 | "radar_liz", 22 | "radar_luigi", 23 | "radar_north", 24 | "radar_ray", 25 | "radar_sal", 26 | "radar_save", 27 | "radar_spray", 28 | "radar_tony", 29 | "radar_weapon", 30 | }; 31 | } // namespace 32 | 33 | const char* script::getBlipSprite(ScriptRadarSprite sprite) { 34 | return sprite_names[sprite]; 35 | } 36 | 37 | ScriptModel script::getModel(const ScriptArguments& args, ScriptModel model) { 38 | if (model < 0) { 39 | /// @todo verify that this is how the game uses negative models 40 | const auto& m = args.getVM()->getFile().getModels()[-model]; 41 | return args.getWorld()->data->findModelObject(m); 42 | } 43 | return model; 44 | } 45 | -------------------------------------------------------------------------------- /rwengine/src/script/ScriptModule.cpp: -------------------------------------------------------------------------------- 1 | #include "script/ScriptModule.hpp" 2 | 3 | #include "script/ScriptMachine.hpp" 4 | #include "script/ScriptTypes.hpp" 5 | 6 | bool ScriptModule::findOpcode(ScriptFunctionID id, ScriptFunctionMeta** out) { 7 | auto it = functions.find(id); 8 | if (it == functions.end()) { 9 | return false; 10 | } 11 | *out = &functions[id]; 12 | return true; 13 | } 14 | -------------------------------------------------------------------------------- /rwengine/src/script/modules/GTA3Module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RWENGINE_GTA3MODULE_HPP_ 2 | #define _RWENGINE_GTA3MODULE_HPP_ 3 | #include