├── .dvc ├── .gitignore └── config ├── .gitignore ├── Assets └── Orbiter │ ├── Environment │ ├── Foam.jpg.dvc │ ├── Noise.png.dvc │ ├── Road │ │ ├── Road006_README.txt │ │ ├── RoadMarkings.png.dvc │ │ ├── Asphalt010_2K_Road_Color.jpg.dvc │ │ └── Asphalt010_2K_Road_Color_README.txt │ ├── Space │ │ ├── SunDisc.png.dvc │ │ ├── MoonDisc.jpg.dvc │ │ └── MoonDisc_README.txt │ ├── Concrete │ │ ├── Asphalt010_2K_Color_README.txt │ │ ├── Concrete010_2K_Color_README.txt │ │ ├── Concrete017_2K_Color_README.txt │ │ ├── Asphalt010_2K_Color.jpg.dvc │ │ ├── Concrete010_2K_Color.jpg.dvc │ │ ├── Concrete017_2K_Color.jpg.dvc │ │ ├── Concrete006_2K_Color_Brightened.jpg.dvc │ │ └── Concrete006_2K_Color_Brightened_README.txt │ ├── Facade │ │ ├── Facade001_2K_Color_README.txt │ │ ├── Facade006_2K_Color_README.txt │ │ ├── Facade001_2K_Color.jpg.dvc │ │ ├── Facade006_2K_Color.jpg.dvc │ │ ├── OpenGameArt │ │ │ ├── apartments1.jpg.dvc │ │ │ ├── apartments4.png.dvc │ │ │ ├── building_jmu2.png.dvc │ │ │ ├── apartment_block6.png.dvc │ │ │ ├── apartments2_side.png.dvc │ │ │ ├── building_office2.png.dvc │ │ │ ├── building_office4.png.dvc │ │ │ ├── building_office7.png.dvc │ │ │ ├── building_office8.png.dvc │ │ │ └── README.txt │ │ ├── photos_2017_7_6_fst_building-facade-windows.jpg.dvc │ │ └── photos_2017_7_6_fst_building-facade-windows_README.txt │ ├── Cloud │ │ ├── CloudVolumeBase.png.dvc │ │ ├── cloud_combined_8192.png.dvc │ │ └── cloud_combined_README.txt │ ├── Foam_README.txt │ ├── TerrainDetailNoise.png.dvc │ ├── Ground │ │ └── Ground026_1K_Color.jpg.dvc │ ├── Explosion01_light_nofire.png.dvc │ ├── Explosion01_light_nofire_README.txt │ ├── Forest │ │ ├── spruceAtlas_side_albedo.tga.dvc │ │ ├── spruceAtlas_side_normal.tga.dvc │ │ └── spruceAtlas_top_albedo.tga.dvc │ └── BuildingTypes.json │ └── package.json ├── .dvcignore ├── src └── OrbiterSkyboltClient │ ├── TextureGroup.cpp │ ├── TextureGroup.h │ ├── SkyboltClient.rc │ ├── CMakeLists.txt │ ├── OpenGlContext.h │ ├── OrbiterTextureIds.h │ ├── TextureProvider.h │ ├── TileSource │ ├── MemoryStreamBuf.h │ ├── OrbiterElevationTileSource.h │ ├── OrbiterImageTileSource.h │ ├── OrbiterTileSource.h │ ├── OrbiterImageTileSource.cpp │ ├── OrbiterTileSource.cpp │ └── OrbiterElevationTileSource.cpp │ ├── DistantCelestialBodyFactory.h │ ├── ObjectUtil.h │ ├── Exhaust.h │ ├── TextureBlitter.h │ ├── ObjectUtil.cpp │ ├── OverlayPanelFactory.h │ ├── SkyboltParticleStream.h │ ├── ModelFactory.h │ ├── OrbiterEntityFactory.h │ ├── VideoTab.h │ ├── OrbiterModel.h │ ├── Exhaust.cpp │ ├── TextureBlitter.cpp │ ├── ThirdParty │ ├── ztreemgr.h │ ├── nanovg │ │ ├── nanovg_gl_utils.h │ │ └── nanovg.h │ └── ztreemgr.cpp │ ├── OverlayPanelFactory.cpp │ ├── OsgSketchpad.h │ ├── DistantCelestialBodyFactory.cpp │ ├── SkyboltParticleStream.cpp │ ├── OpenGlContext.cpp │ ├── SkyboltClient.h │ ├── ModelFactory.cpp │ ├── OrbiterModel.cpp │ ├── OrbiterEntityFactory.cpp │ ├── VideoTab.cpp │ └── OsgSketchpad.cpp ├── CMake ├── AddSourceGroup.cmake └── FindOrbiter.cmake ├── License.txt ├── conanfile.py ├── CMakeLists.txt └── README.md /.dvc/.gitignore: -------------------------------------------------------------------------------- 1 | /config.local 2 | /tmp 3 | /cache 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ive 2 | *.jpg 3 | *.osgt 4 | *.png 5 | *.tga 6 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Foam.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 5f3adac7f7ac716402a240fd658318a6 3 | size: 494316 4 | path: Foam.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Noise.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 201d5d40263a054d4ee73bea9e88ded4 3 | size: 521526 4 | path: Noise.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Road/Road006_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Space/SunDisc.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 7a843a3e509ce2374c941bc136a55ec7 3 | size: 7798 4 | path: SunDisc.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Space/MoonDisc.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 3e0cacf8235f68d7645347a209ddde1e 3 | size: 24079 4 | path: MoonDisc.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Road/RoadMarkings.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 4b89f2e28aca9f33f49216d3aaab89bd 3 | size: 2316 4 | path: RoadMarkings.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Asphalt010_2K_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/Facade001_2K_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/Facade006_2K_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Cloud/CloudVolumeBase.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: aefe084b834555f66e8c0d9513aa70e3 3 | size: 1288152 4 | path: CloudVolumeBase.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete010_2K_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete017_2K_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Foam_README.txt: -------------------------------------------------------------------------------- 1 | Generated with Filter Forge v9 using "Sea Foam" filter by Logic Artists 2 | URL: https://filterforge.com/filters/13843.html -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/TerrainDetailNoise.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 6aafaa19ace19b217bd25fd90eee9365 3 | size: 171917 4 | path: TerrainDetailNoise.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/Facade001_2K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 0f1e1da478c1525a9003b54786a2114e 3 | size: 24793 4 | path: Facade001_2K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/Facade006_2K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: cca9f08c26b2fe48ce2b5718fbeb9204 3 | size: 35591 4 | path: Facade006_2K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/apartments1.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 071d1b96f049056252cad27eb40e0592 3 | size: 47719 4 | path: apartments1.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/apartments4.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 1df4d819d81a96013a45ddcb2568340a 3 | size: 147325 4 | path: apartments4.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Ground/Ground026_1K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: dcdf959a39936645cbde81bdeadc57ac 3 | size: 1539052 4 | path: Ground026_1K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Cloud/cloud_combined_8192.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 0034ca5212cd862a17233f36ef6bea17 3 | size: 18077363 4 | path: cloud_combined_8192.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Asphalt010_2K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: b1eae04b752b306a9738b89bea715b7d 3 | size: 64412 4 | path: Asphalt010_2K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete010_2K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 9b3b1f49e98c42c48e5eb11dafec938e 3 | size: 21230 4 | path: Concrete010_2K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete017_2K_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 616a69160d8533006c8836c4de09de5a 3 | size: 19389 4 | path: Concrete017_2K_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Explosion01_light_nofire.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 8a3ee0876c8eded87758ce03f84531c4 3 | size: 47209 4 | path: Explosion01_light_nofire.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/building_jmu2.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 092ffe634536871e6ab93e4ae6603d89 3 | size: 111636 4 | path: building_jmu2.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Space/MoonDisc_README.txt: -------------------------------------------------------------------------------- 1 | Author: Gregory H. Revera 2 | URL: https://en.wikipedia.org/wiki/Moon#/media/File:FullMoon2010.jpg 3 | License: CC BY-SA 3.0 -------------------------------------------------------------------------------- /Assets/Orbiter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Skybolt assets for Orbiter", 3 | "packageVersion": "1.0.0", 4 | "skyboltVersion": "1.2.0", 5 | "author": "Matthew Reid" 6 | } -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Explosion01_light_nofire_README.txt: -------------------------------------------------------------------------------- 1 | Author: Unity Labs Paris 2 | URL: https://blog.unity.com/technology/free-vfx-image-sequences-flipbooks 3 | License: CC0 -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/apartment_block6.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 23f71867e269974292bc44e2c8b9f499 3 | size: 146877 4 | path: apartment_block6.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/apartments2_side.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 21abfea3058d2b521f90bd3df81e30c3 3 | size: 117906 4 | path: apartments2_side.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/building_office2.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 438faca746c4f0cbb193671d7dd7abf4 3 | size: 102430 4 | path: building_office2.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/building_office4.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: f35527daee4c4e15118de5d121b3670c 3 | size: 102194 4 | path: building_office4.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/building_office7.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 2b999ff32956ba05226aa8735c64956b 3 | size: 127900 4 | path: building_office7.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/building_office8.png.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: f43b18af140e61293c15bae43864a76d 3 | size: 110743 4 | path: building_office8.png 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Forest/spruceAtlas_side_albedo.tga.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: e7bca0d6ff9726086a16269a55cd2473 3 | size: 2145628 4 | path: spruceAtlas_side_albedo.tga 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Forest/spruceAtlas_side_normal.tga.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: f6ab4ebf32db383d8291f5d707dabe8f 3 | size: 4194322 4 | path: spruceAtlas_side_normal.tga 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Forest/spruceAtlas_top_albedo.tga.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 374696288417095de64e94916b3108c0 3 | size: 132635 4 | path: spruceAtlas_top_albedo.tga 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Road/Asphalt010_2K_Road_Color.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 94b3f1386f06a91e83a52e0e2a3f811e 3 | size: 58668 4 | path: Asphalt010_2K_Road_Color.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete006_2K_Color_Brightened.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 57ece8d9cf2c0f376045e9afc34cc458 3 | size: 12021 4 | path: Concrete006_2K_Color_Brightened.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/OpenGameArt/README.txt: -------------------------------------------------------------------------------- 1 | Source: Open Game Art 2 | URL: https://opengameart.org/content/free-urban-textures-buildings-apartments-shop-fronts 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /.dvcignore: -------------------------------------------------------------------------------- 1 | # Add patterns of files dvc should ignore, which could improve 2 | # the performance. Learn more at 3 | # https://dvc.org/doc/user-guide/dvcignore 4 | 5 | *__pycache__ 6 | *.json 7 | *.py 8 | *.txt 9 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Concrete/Concrete006_2K_Color_Brightened_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License 4 | 5 | Modified to increase brightness. -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/photos_2017_7_6_fst_building-facade-windows.jpg.dvc: -------------------------------------------------------------------------------- 1 | outs: 2 | - md5: 603852c3537d940f5baffe22a473906e 3 | size: 130253 4 | path: photos_2017_7_6_fst_building-facade-windows.jpg 5 | -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Road/Asphalt010_2K_Road_Color_README.txt: -------------------------------------------------------------------------------- 1 | Source: CC0 Textures 2 | URL: https://cc0textures.com 3 | License: Creative Commons CC0 License 4 | Comments: Modified by Matthew Reid to add road streaks -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Facade/photos_2017_7_6_fst_building-facade-windows_README.txt: -------------------------------------------------------------------------------- 1 | Source: https://freestocktextures.com 2 | URL: https://freestocktextures.com/texture/facade-of-building-with-plenty-windows,867.html 3 | License: Creative Commons CC0 License -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/Cloud/cloud_combined_README.txt: -------------------------------------------------------------------------------- 1 | NASA Blue Marble: Clouds 2 | URL: https://visibleearth.nasa.gov/images/57747/blue-marble-clouds/57751l 3 | License: "freely available for re-publication or re-use, including commercial purposes". See https://visibleearth.nasa.gov/image-use-policy. -------------------------------------------------------------------------------- /.dvc/config: -------------------------------------------------------------------------------- 1 | [core] 2 | analytics = false 3 | remote = storage 4 | ['remote "storage"'] 5 | url = s3://skybolt/SkyboltAssets/dvc 6 | endpointurl = https://s3.us-west-000.backblazeb2.com 7 | access_key_id = 000dbf124f819b30000000003 8 | secret_access_key = "K000ZtTw1o53yO13LHssSiqLgYOAxZ0" -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TextureGroup.cpp: -------------------------------------------------------------------------------- 1 | #include "TextureGroup.h" 2 | 3 | std::filesystem::path addSuffixToBaseFilename(const std::filesystem::path& filename, const std::string& suffix) 4 | { 5 | std::filesystem::path result = filename; 6 | result.replace_extension(""); 7 | result += suffix; 8 | result.replace_extension(filename.extension()); 9 | return result; 10 | } 11 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TextureGroup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct TextureGroup 8 | { 9 | TextureGroup(const osg::ref_ptr& albedo) : albedo(albedo) {} 10 | TextureGroup() {} 11 | 12 | osg::ref_ptr albedo; //!< Never null 13 | osg::ref_ptr normal; //!< May be null 14 | osg::ref_ptr specular; //!< May be null 15 | }; 16 | 17 | //! @param suffix is a name to append to the filename base name, e.g appending "_spec" to "C:/mytex.dds" gives "C:/mytex_spec.dds" 18 | std::filesystem::path addSuffixToBaseFilename(const std::filesystem::path& filename, const std::string& suffix); 19 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/SkyboltClient.rc: -------------------------------------------------------------------------------- 1 | #define IDS_STRING1 1 2 | #define IDS_INFO 1000 3 | #define IDS_TYPE 1001 4 | 5 | ///////////////////////////////////////////////////////////////////////////// 6 | // 7 | // String Table 8 | // 9 | 10 | STRINGTABLE 11 | BEGIN 12 | IDS_STRING1 "Skybolt: An OpenGL Orbiter Graphics Client Plugin.\r\n\r\nDeveloped by Matthew Reid\r\n\r\n. The source code is available at https://github.com/Piraxus/OrbiterSkyboltClient" 13 | END 14 | 15 | STRINGTABLE 16 | BEGIN 17 | IDS_INFO "Skybolt Graphics Client:\r\n\r\nA render engine plugin for Orbiter." 18 | IDS_TYPE "Graphics engines" 19 | END 20 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_source_group_tree(. SOURCE) 2 | 3 | include_directories("../") 4 | 5 | find_package(Orbiter REQUIRED) 6 | include_directories(${Orbiter_INCLUDE_DIR}) 7 | 8 | find_package(Skybolt REQUIRED) 9 | include_directories(${Skybolt_INCLUDE_DIR}/Skybolt) 10 | 11 | find_package(OpenGL REQUIRED) 12 | 13 | find_package(GLEW REQUIRED) 14 | include_directories(${GLEW_INCLUDE_DIR}) 15 | 16 | OPTION(GLEW_STATIC_LIBS "GLEW use static libs") 17 | if (GLEW_STATIC_LIBS) 18 | add_definitions(-DGLEW_STATIC) 19 | endif() 20 | 21 | set(LIBS 22 | ${GLEW_LIBRARIES} 23 | ${Orbiter_LIBRARIES} 24 | ${OPENGL_LIBRARIES} 25 | ${Skybolt_LIBRARIES} 26 | ) 27 | 28 | add_library(OrbiterSkyboltClient SHARED ${SOURCE} SkyboltClient.rc) 29 | target_link_libraries (OrbiterSkyboltClient ${LIBS}) 30 | 31 | set(ORBITER_PLUGINS_DIRECTORY "" CACHE STRING "Orbiter Plugins Directory") 32 | 33 | install(TARGETS OrbiterSkyboltClient 34 | DESTINATION ${ORBITER_PLUGINS_DIRECTORY} 35 | ) -------------------------------------------------------------------------------- /CMake/AddSourceGroup.cmake: -------------------------------------------------------------------------------- 1 | macro(add_source_group path list) 2 | 3 | STRING(REPLACE "./" "Source Files/" GROUP_NAME ${path}) 4 | STRING(REPLACE "/" "\\" GROUP_NAME ${GROUP_NAME}) 5 | file(GLOB TMP_FILES "${path}/*.h" "${path}/*.cpp" "${path}/*.cc") 6 | source_group(${GROUP_NAME} FILES ${TMP_FILES}) 7 | 8 | set(${list} ${${list}} ${TMP_FILES}) 9 | 10 | endmacro() 11 | 12 | 13 | # path must be relative 14 | macro(add_source_group_tree path list) 15 | file(GLOB_RECURSE TMP_FILES "${path}/*") 16 | foreach(f ${TMP_FILES}) 17 | get_filename_component(BASE_PATH ${f} PATH) 18 | 19 | if(IS_DIRECTORY ${BASE_PATH}) 20 | if (NOT ${BASE_PATH} MATCHES "^.*.svn*") 21 | 22 | file(RELATIVE_PATH BASE_PATH "${CMAKE_CURRENT_LIST_DIR}/${path}" ${BASE_PATH}) 23 | set(TMP_PATHS ${TMP_PATHS} "${path}/${BASE_PATH}") 24 | endif() 25 | endif() 26 | endforeach() 27 | 28 | list(REMOVE_DUPLICATES TMP_PATHS) 29 | 30 | foreach(f ${TMP_PATHS}) 31 | add_source_group(${f} ${list}) 32 | endforeach() 33 | endmacro() 34 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2021 Matthew Reid 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conans import ConanFile, CMake 2 | import os 3 | 4 | class SkyboltConan(ConanFile): 5 | name = "orbiter-skybolt-client" 6 | version = "1.0.3" 7 | settings = "os", "compiler", "arch", "build_type" 8 | options = { 9 | "shared": [True, False] 10 | } 11 | default_options = { 12 | "shared": False, 13 | } 14 | generators = ["cmake_paths", "cmake_find_package"] 15 | exports_sources = "*" 16 | no_copy_source = True 17 | 18 | requires = [ 19 | "glew/2.2.0@_/_", 20 | "skybolt/1.4.1@_/_" 21 | ] 22 | 23 | def configure(self): 24 | self.options["skybolt"].shared_plugins = False 25 | 26 | def build(self): 27 | cmake = CMake(self) 28 | 29 | cmake.definitions["GLEW_STATIC_LIBS"] = str(not self.options["glew"].shared) 30 | cmake.definitions["CMAKE_TOOLCHAIN_FILE"] = "conan_paths.cmake" 31 | cmake.configure() 32 | cmake.build() 33 | 34 | def package(self): 35 | cmake = CMake(self) 36 | cmake.install() -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.3) 2 | project(OrbiterSkyboltClient) 3 | 4 | enable_testing() 5 | 6 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/" "${CMAKE_SOURCE_DIR}/CMake/Modules/") 7 | 8 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 9 | 10 | OPTION(DISABLE_OPTIMIZATION_RELWITHDEBINFO "Disable Optimization in RelWithDebInfo") 11 | if(DISABLE_OPTIMIZATION_RELWITHDEBINFO) 12 | if(WIN32) 13 | set(OPT_OFF Od) 14 | else() 15 | set(OPT_OFF O0) 16 | endif() 17 | 18 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "-${OPT_OFF} -Zi") 19 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-${OPT_OFF} -Zi") 20 | endif() 21 | 22 | set(CMAKE_CXX_STANDARD 17) 23 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 24 | 25 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 26 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 27 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 28 | 29 | OPTION(Boost_STATIC_LIBS "Boost use static libs") 30 | if (Boost_STATIC_LIBS) 31 | set(Boost_USE_STATIC_LIBS ON) 32 | endif() 33 | 34 | cmake_policy(SET CMP0020 NEW) 35 | 36 | include(AddSourceGroup) 37 | 38 | add_subdirectory (src/OrbiterSkyboltClient) 39 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OpenGlContext.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | 17 | HGLRC createOpenGlContext(HDC real_dc); -------------------------------------------------------------------------------- /CMake/FindOrbiter.cmake: -------------------------------------------------------------------------------- 1 | # This module defines 2 | # Orbiter_FOUND, if false, do not try to link 3 | # Orbiter_LIBRARY, the library to link against 4 | # Orbiter_INCLUDE_DIR, where to find headers 5 | 6 | 7 | FIND_PATH(Orbiter_INCLUDE_DIR GraphicsAPI.h 8 | PATHS 9 | $ENV{ORBITER_SDK_DIR} 10 | PATH_SUFFIXES 11 | include 12 | ) 13 | 14 | FIND_LIBRARY(Orbiter_LIBRARY_R 15 | NAMES Orbiter 16 | PATHS 17 | $ENV{ORBITER_SDK_DIR} 18 | PATH_SUFFIXES 19 | lib 20 | ) 21 | 22 | FIND_LIBRARY(Orbiter_LIBRARY_D 23 | NAMES Orbiterd Orbiter 24 | PATHS 25 | $ENV{ORBITER_SDK_DIR} 26 | PATH_SUFFIXES 27 | lib 28 | ) 29 | 30 | FIND_LIBRARY(Orbiter_SDK_LIBRARY_R 31 | NAMES Orbitersdk 32 | PATHS 33 | $ENV{ORBITER_SDK_DIR} 34 | PATH_SUFFIXES 35 | lib 36 | ) 37 | 38 | FIND_LIBRARY(Orbiter_SDK_LIBRARY_D 39 | NAMES Orbitersdkd Orbitersdk 40 | PATHS 41 | $ENV{ORBITER_SDK_DIR} 42 | PATH_SUFFIXES 43 | lib 44 | ) 45 | 46 | SET(Orbiter_LIBRARIES 47 | optimized ${Orbiter_LIBRARY_R} 48 | debug ${Orbiter_LIBRARY_D} 49 | optimized ${Orbiter_SDK_LIBRARY_R} 50 | debug ${Orbiter_SDK_LIBRARY_D} 51 | ) 52 | 53 | include(FindPackageHandleStandardArgs) 54 | find_package_handle_standard_args(Orbiter DEFAULT_MSG Orbiter_LIBRARIES Orbiter_INCLUDE_DIR) -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OrbiterTextureIds.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | const DWORD SPEC_DEFAULT = (DWORD)(-1); // "default" material/texture flag 15 | const DWORD SPEC_INHERIT = (DWORD)(-2); // "inherit" material/texture flag 16 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TextureProvider.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include "TextureGroup.h" 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | typedef void* SURFHANDLE; 18 | 19 | using TextureProvider = std::function(SURFHANDLE)>; //! Returns null if texture not found -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/MemoryStreamBuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | // From https://stackoverflow.com/questions/7781898/get-an-istream-from-a-char 17 | struct MemoryStreamBuf : std::streambuf 18 | { 19 | MemoryStreamBuf(char* buffer, std::size_t sizeBytes) 20 | { 21 | setg(buffer, buffer, buffer + sizeBytes); 22 | } 23 | }; -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/DistantCelestialBodyFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | typedef void* OBJHANDLE; 20 | 21 | struct DistantCelestialBodyCreationArgs 22 | { 23 | skybolt::vis::Scene* scene; 24 | OBJHANDLE objectHandle; 25 | osg::ref_ptr program; 26 | }; 27 | 28 | skybolt::sim::EntityPtr createDistantCelestialBody(const DistantCelestialBodyCreationArgs& args); 29 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ObjectUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "GraphicsAPI.h" 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | std::string getName(OBJHANDLE object); 21 | 22 | skybolt::sim::Vector3 orbiterToSkyboltVector3GlobalAxes(const VECTOR3& v); 23 | 24 | skybolt::sim::Vector3 orbiterToSkyboltVector3BodyAxes(const VECTOR3& v); 25 | 26 | osg::Vec3f orbiterToSkyboltVector3BodyAxes(const float* v); 27 | 28 | osg::Vec3f skyboltToOrbiterVector3BodyAxes(const osg::Vec3f& v); -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterElevationTileSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "OrbiterTileSource.h" 15 | 16 | class OrbiterElevationTileSource : public OrbiterTileSource 17 | { 18 | public: 19 | OrbiterElevationTileSource(const std::string& directory); 20 | ~OrbiterElevationTileSource() override = default; 21 | 22 | const std::string& getCacheSha() const override { static std::string s = "OrbiterElevationTileSource"; return s; } 23 | 24 | protected: 25 | osg::ref_ptr createImage(const std::uint8_t* buffer, std::size_t sizeBytes) const; 26 | }; -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterImageTileSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "OrbiterTileSource.h" 15 | 16 | class OrbiterImageTileSource : public OrbiterTileSource 17 | { 18 | public: 19 | enum class LayerType 20 | { 21 | Albedo, 22 | LandMask 23 | }; 24 | 25 | OrbiterImageTileSource(const std::string& directory, const LayerType& layerType); 26 | ~OrbiterImageTileSource() override = default; 27 | 28 | protected: 29 | osg::ref_ptr createImage(const std::uint8_t* buffer, std::size_t sizeBytes) const; 30 | 31 | private: 32 | bool mInterpretTextureAsDxt1Rgba; 33 | }; -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/Exhaust.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "TextureProvider.h" 14 | #include 15 | #include 16 | 17 | class VESSEL; 18 | 19 | class Exhaust : public skybolt::SimpleSimVisBinding 20 | { 21 | public: 22 | Exhaust(VESSEL* vessel, const skybolt::sim::Entity* entity, const skybolt::vis::BeamsPtr& beams, const TextureProvider& textureProvider); 23 | 24 | void syncVis(const skybolt::GeocentricToNedConverter& converter) override; 25 | 26 | private: 27 | TextureProvider mTextureProvider; 28 | VESSEL* mVessel; 29 | skybolt::vis::BeamsPtr mBeams; 30 | }; 31 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TextureBlitter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | class TextureBlitter : public osg::Camera::DrawCallback 21 | { 22 | public: 23 | bool blitTexture(const osg::Texture2D& src, osg::Texture2D& dst, const skybolt::Box2i& srcRect, const skybolt::Box2i& dstRect); 24 | 25 | private: 26 | void operator() (osg::RenderInfo& renderInfo) const override; 27 | 28 | private: 29 | using Operation = std::function; 30 | mutable std::vector mOperations; 31 | }; 32 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ObjectUtil.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ObjectUtil.h" 14 | 15 | using namespace skybolt; 16 | 17 | std::string getName(OBJHANDLE object) 18 | { 19 | char name[256]; 20 | int length = 256; 21 | oapiGetObjectName(object, name, length); 22 | return std::string(name); 23 | } 24 | 25 | sim::Vector3 orbiterToSkyboltVector3GlobalAxes(const VECTOR3& v) 26 | { 27 | return skybolt::sim::Vector3(v.x, v.z, v.y); 28 | } 29 | 30 | sim::Vector3 orbiterToSkyboltVector3BodyAxes(const VECTOR3& v) 31 | { 32 | return skybolt::sim::Vector3(v.z, v.x, -v.y); 33 | } 34 | 35 | osg::Vec3f orbiterToSkyboltVector3BodyAxes(const float* v) 36 | { 37 | return osg::Vec3f(v[2], v[0], -v[1]); 38 | } 39 | 40 | osg::Vec3f skyboltToOrbiterVector3BodyAxes(const osg::Vec3f& v) 41 | { 42 | return osg::Vec3f(v.y(), -v.z(), v.x()); 43 | } 44 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OverlayPanelFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "GraphicsAPI.h" 14 | #include "OrbiterTextureIds.h" 15 | #include "TextureProvider.h" 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | using WindowSizeProvider = std::function; 23 | using MfdSurfaceProvider = std::function; //! Returns null if MFD not found 24 | 25 | class OverlayPanelFactory 26 | { 27 | public: 28 | OverlayPanelFactory(WindowSizeProvider windowSizeProvider, TextureProvider textureProvider, MfdSurfaceProvider mfdSurfaceProvider); 29 | 30 | osg::ref_ptr createOverlayPanel(SURFHANDLE *hSurf, MESHHANDLE hMesh, MATRIX3 *T, float alpha, bool additive); 31 | 32 | private: 33 | WindowSizeProvider mWindowSizeProvider; 34 | TextureProvider mTextureProvider; 35 | MfdSurfaceProvider mMfdSurfaceProvider; 36 | }; 37 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/SkyboltParticleStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | class SkyboltParticleStream : public oapi::ParticleStream 21 | { 22 | public: 23 | using EntityFinder = std::function; 24 | using DestructionAction = std::function; 25 | SkyboltParticleStream(oapi::GraphicsClient* gc, PARTICLESTREAMSPEC *pss, 26 | const skybolt::EntityFactory& entityFactory, skybolt::sim::World* world, EntityFinder entityFinder, DestructionAction destructionAction); 27 | 28 | ~SkyboltParticleStream(); 29 | 30 | void update(); 31 | 32 | private: 33 | skybolt::sim::World* mWorld; 34 | EntityFinder mEntityFinder; 35 | DestructionAction mDestructionAction; 36 | skybolt::sim::EntityPtr mEntity; 37 | skybolt::sim::AttachmentComponentPtr mAttachmentComponent; 38 | skybolt::sim::ParticleEmitterPtr mParticleEmitter; 39 | }; 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Orbiter Skybolt Client 2 | A 3d graphics client plugin for the [Orbiter](https://github.com/orbitersim/orbiter) space flight simulator which allows Orbiter to render with the [Skybolt](https://github.com/Piraxus/Skybolt) engine. 3 | 4 | This project is in early development and many Orbiter graphics features are not yet supported. 5 | 6 | ## Build 7 | ### Using conan 8 | [Conan](https://conan.io) is a C++ package manager which makes builds easier. 9 | Currently, the build requires conan version 1.x. We plan to upgrade to 2.x in the future. 10 | If you do not already have conan 1.x installed, run `pip install conan==1.64.1` to install using [pip](https://pypi.org/project/pip). 11 | 12 | Build with the following commands: 13 | ``` 14 | git clone https://github.com/piraxus/Skybolt 15 | git -C Skybolt checkout v1.4.1 16 | conan export Skybolt 17 | 18 | git clone https://github.com/Piraxus/OrbiterSkyboltClient 19 | conan install OrbiterSkyboltClient --install-folder OrbiterSkyboltClientBuild --build=missing 20 | conan build OrbiterSkyboltClient --build-folder OrbiterSkyboltClientBuild 21 | ``` 22 | 23 | The plugin is built to `OrbiterSkyboltClientBuild/bin/Release/OrbiterSkyboltClient.dll`. 24 | 25 | ## Install 26 | 1. Copy `OrbiterSkyboltClient.dll` to `/Modules/Plugin` 27 | 2. Copy `/Assets/Core` to `/Modules/Plugin/OrbiterSkyboltClient/Assets/Core` 28 | 3. `cd` to the `SkyboltOrbiterClient` repository root and run `dvc pull` to fetch the remote binary assets (images etc required at runtime). If you do not already have DVC installed, first run `pip install dvc[s3]` to install with [pip](https://pypi.org/project/pip) 29 | 4. Copy all folders under `/Assets` to `/Modules/Plugin/OrbiterSkyboltClient/Assets` 30 | 31 | ## Contact 32 | Skybolt and the Orbiter Skybolt Client created and maintained by Matthew Reid. To submit a bug report, please [raise an issue on the GitHub repository](https://github.com/Piraxus/OrbiterSkyboltClient/issues). 33 | 34 | ## License 35 | This project is licensed under the MIT license - see the [License.txt](License.txt) file for details. -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterTileSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | class ZTreeMgr; 17 | 18 | class OrbiterTileSource : public skybolt::vis::TileSource 19 | { 20 | public: 21 | OrbiterTileSource(std::unique_ptr treeMgr); 22 | ~OrbiterTileSource() override; 23 | 24 | //!@ThreadSafe 25 | osg::ref_ptr createImage(const skybolt::QuadTreeTileKey& key, std::function cancelSupplier) const; 26 | 27 | //!@ThreadSafe 28 | bool hasAnyChildren(const skybolt::QuadTreeTileKey& key) const override; 29 | 30 | //! @returns the highest key with source data in the given key's ancestral hierarchy 31 | //!@ThreadSafe 32 | std::optional getHighestAvailableLevel(const skybolt::QuadTreeTileKey& key) const override; 33 | 34 | const std::string& getCacheSha() const override { static std::string s = "OrbiterTileSource"; return s; } 35 | 36 | protected: 37 | virtual osg::ref_ptr createImage(const std::uint8_t* buffer, std::size_t sizeBytes)const = 0; 38 | 39 | private: 40 | std::unique_ptr mTreeMgr; 41 | mutable std::mutex mTreeMgrMutex; 42 | }; -------------------------------------------------------------------------------- /Assets/Orbiter/Environment/BuildingTypes.json: -------------------------------------------------------------------------------- 1 | { 2 | "facades": [ 3 | { 4 | "albedoTexture": "Environment/Facade/Facade001_2K_Color.jpg", 5 | "storiesInTexture": 10, 6 | "horizontalSectionsInTexture": 16 7 | }, 8 | { 9 | "albedoTexture": "Environment/Facade/Facade006_2K_Color.jpg", 10 | "storiesInTexture": 8, 11 | "horizontalSectionsInTexture": 14 12 | }, 13 | { 14 | "albedoTexture": "Environment/Facade/photos_2017_7_6_fst_building-facade-windows.jpg", 15 | "storiesInTexture": 7, 16 | "horizontalSectionsInTexture": 7 17 | }, 18 | { 19 | "albedoTexture": "Environment/Facade/OpenGameArt/apartment_block6.png", 20 | "storiesInTexture": 5, 21 | "horizontalSectionsInTexture": 6 22 | }, 23 | { 24 | "albedoTexture": "Environment/Facade/OpenGameArt/apartments1.jpg", 25 | "storiesInTexture": 9, 26 | "horizontalSectionsInTexture": 19 27 | }, 28 | { 29 | "albedoTexture": "Environment/Facade/OpenGameArt/apartments2_side.png", 30 | "storiesInTexture": 3, 31 | "horizontalSectionsInTexture": 4 32 | }, 33 | { 34 | "albedoTexture": "Environment/Facade/OpenGameArt/apartments4.png", 35 | "storiesInTexture": 7, 36 | "horizontalSectionsInTexture": 9 37 | }, 38 | { 39 | "albedoTexture": "Environment/Facade/OpenGameArt/building_jmu2.png", 40 | "storiesInTexture": 7, 41 | "horizontalSectionsInTexture": 6 42 | }, 43 | { 44 | "albedoTexture": "Environment/Facade/OpenGameArt/building_office2.png", 45 | "storiesInTexture": 2, 46 | "horizontalSectionsInTexture": 6 47 | }, 48 | { "albedoTexture": "Environment/Facade/OpenGameArt/building_office4.png", 49 | "storiesInTexture": 2, 50 | "horizontalSectionsInTexture": 4 51 | }, 52 | { 53 | "albedoTexture": "Environment/Facade/OpenGameArt/building_office7.png", 54 | "storiesInTexture": 5, 55 | "horizontalSectionsInTexture": 3 56 | }, 57 | { 58 | "albedoTexture": "Environment/Facade/OpenGameArt/building_office8.png", 59 | "storiesInTexture": 5, 60 | "horizontalSectionsInTexture": 7 61 | } 62 | ], 63 | "roofs": [ 64 | { 65 | "albedoTexture": "Environment/Concrete/Concrete006_2K_Color_Brightened.jpg" 66 | }, 67 | { 68 | "albedoTexture": "Environment/Concrete/Concrete010_2K_Color.jpg" 69 | }, 70 | { 71 | "albedoTexture": "Environment/Concrete/Concrete017_2K_Color.jpg" 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ModelFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "GraphicsAPI.h" 14 | 15 | #include "OrbiterModel.h" 16 | #include "TextureProvider.h" 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | using SurfaceHandleFromTextureIdProvider = std::function; 26 | 27 | struct ModelFactoryConfig 28 | { 29 | SurfaceHandleFromTextureIdProvider surfaceHandleFromTextureIdProvider; 30 | TextureProvider textureProvider; 31 | osg::ref_ptr program; 32 | }; 33 | 34 | class ModelFactory 35 | { 36 | public: 37 | ModelFactory(const ModelFactoryConfig& config); 38 | std::unique_ptr createModel(MESHHANDLE hMesh, OBJHANDLE handle, int meshId, int meshVisibilityCategoryFlags) const; 39 | 40 | static osg::ref_ptr createGeometry(const MESHGROUP& data); 41 | 42 | private: 43 | struct CreateMeshResult 44 | { 45 | osg::ref_ptr node; 46 | std::vector> meshGroupData; 47 | }; 48 | ModelFactory::CreateMeshResult getOrCreateMesh(MESHHANDLE mesh) const; 49 | void prepareGeometryStateSet(osg::Geometry& geometry, MESHHANDLE mesh, const MESHGROUP& group) const; 50 | 51 | private: 52 | SurfaceHandleFromTextureIdProvider mSurfaceHandleFromTextureIdProvider; 53 | TextureProvider mTextureProvider; 54 | osg::ref_ptr mProgram; 55 | mutable std::map mMeshCache; 56 | }; 57 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OrbiterEntityFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "GraphicsAPI.h" 14 | 15 | #include "TextureProvider.h" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | class ModelFactory; 25 | class VESSEL; 26 | 27 | struct OrbiterEntityFactoryConfig 28 | { 29 | skybolt::EntityFactory* entityFactory; 30 | skybolt::vis::ScenePtr scene; 31 | std::shared_ptr modelFactory; 32 | oapi::GraphicsClient* graphicsClient; 33 | skybolt::vis::ShaderPrograms* shaderPrograms; 34 | TextureProvider textureProvider; 35 | }; 36 | 37 | class OrbiterEntityFactory 38 | { 39 | public: 40 | OrbiterEntityFactory(const OrbiterEntityFactoryConfig& config); 41 | ~OrbiterEntityFactory(); 42 | 43 | //! Returns null if entity could not be created 44 | skybolt::sim::EntityPtr createEntity(OBJHANDLE object) const; 45 | 46 | skybolt::sim::EntityPtr createVessel(OBJHANDLE object, VESSEL* vessel) const; 47 | 48 | skybolt::sim::EntityPtr createPlanet(OBJHANDLE object) const; 49 | 50 | skybolt::sim::EntityPtr createBase(OBJHANDLE object) const; 51 | 52 | skybolt::sim::EntityPtr createStar(OBJHANDLE object) const; 53 | 54 | private: 55 | skybolt::EntityFactory* mEntityFactory; 56 | skybolt::vis::ScenePtr mScene; 57 | std::shared_ptr mModelFactory; 58 | oapi::GraphicsClient* mGraphicsClient; 59 | skybolt::vis::ShaderPrograms* mShaderPrograms; 60 | TextureProvider mTextureProvider; 61 | }; 62 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterImageTileSource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "OrbiterImageTileSource.h" 13 | #include "MemoryStreamBuf.h" 14 | #include "OrbiterSkyboltClient/ThirdParty/ztreemgr.h" 15 | 16 | #include 17 | #include 18 | 19 | OrbiterImageTileSource::OrbiterImageTileSource(const std::string& directory, const LayerType& layerType) : 20 | OrbiterTileSource(std::make_unique(directory.c_str(), layerType == LayerType::LandMask ? ZTreeMgr::LAYER_MASK : ZTreeMgr::LAYER_SURF)), 21 | mInterpretTextureAsDxt1Rgba(layerType == LayerType::LandMask) 22 | { 23 | } 24 | 25 | osg::ref_ptr OrbiterImageTileSource::createImage(const std::uint8_t* buffer, std::size_t sizeBytes) const 26 | { 27 | MemoryStreamBuf membuf((char*)(buffer), sizeBytes); 28 | std::istream istream(&membuf); 29 | 30 | osgDB::ReaderWriter *rw = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); 31 | osgDB::ReaderWriter::ReadResult res = rw->readImage(istream); 32 | osg::ref_ptr image = res.getImage(); 33 | 34 | if (image) 35 | { 36 | if (mInterpretTextureAsDxt1Rgba) 37 | { 38 | // Orbiter land mask textures should be interpreted as having an alpha channel, but the texture headers incorrectly encode usingAlpha=false. 39 | // We work around this by forcing DXT1 RGBA format here. 40 | assert(image->getInternalTextureFormat() == GL_COMPRESSED_RGB_S3TC_DXT1_EXT); 41 | image->setInternalTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); 42 | image->setPixelFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); 43 | } 44 | 45 | image->flipVertical(); 46 | } 47 | 48 | return image; 49 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/VideoTab.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | 17 | namespace oapi { class SkyboltClient; } 18 | 19 | struct SkyboltDeviceInfo 20 | { 21 | struct FullscreenMode 22 | { 23 | int dwWidth; 24 | int dwHeight; 25 | }; 26 | 27 | FullscreenMode ddsdFullscreenMode; 28 | std::vector pddsdModes; 29 | bool bDesktopCompatible = true; 30 | }; 31 | 32 | class VideoTab 33 | { 34 | public: 35 | VideoTab (oapi::SkyboltClient* gc, HINSTANCE _hInst, HINSTANCE _hOrbiterInst, HWND hVideoTab); 36 | 37 | INT_PTR WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 38 | // Video tab message handler 39 | 40 | void UpdateConfigData (); 41 | // copy dialog state back to parameter structure 42 | 43 | protected: 44 | void Initialise (SkyboltDeviceInfo *dev); 45 | // Initialise dialog elements 46 | 47 | void SelectDevice (SkyboltDeviceInfo *dev); 48 | // Update dialog after user device selection 49 | 50 | void SelectDispmode (SkyboltDeviceInfo *dev, BOOL bWindow); 51 | // Update dialog after user fullscreen/window selection 52 | 53 | void SelectMode (SkyboltDeviceInfo *dev, DWORD idx); 54 | // Update dialog after fullscreen mode selection 55 | 56 | void SelectPageflip (); 57 | // Flip hardware pageflip on/off 58 | 59 | void SelectWidth (); 60 | // Update dialog after window width selection 61 | 62 | void SelectHeight (); 63 | // Update dialog after window height selection 64 | 65 | void SelectFixedAspect (); 66 | // Flip fixed window aspect ratio on/off 67 | 68 | private: 69 | oapi::SkyboltClient *gclient; 70 | HINSTANCE hOrbiterInst; // orbiter instance handle 71 | HINSTANCE hInst; // module instance handle 72 | HWND hTab; // window handle of the video tab 73 | int aspect_idx; // fixed aspect ratio index 74 | SkyboltDeviceInfo defaultDevice; 75 | }; 76 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OrbiterModel.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | #include "OrbiterAPI.h" 16 | 17 | #include 18 | 19 | #include 20 | 21 | struct MeshGroupData 22 | { 23 | int osgGeometryIndex; 24 | int orbiterMaterialIndex; 25 | int orbiterTextureIndex; 26 | 27 | static constexpr int userFlagNoShadow = 1; 28 | static constexpr int userFlagSkip = 2; 29 | int orbiterUserFlags; 30 | }; 31 | 32 | struct OrbiterModelConfig : public skybolt::vis::ModelConfig 33 | { 34 | OBJHANDLE owningObject; 35 | int meshId; 36 | int meshVisibilityCategoryFlags; 37 | std::vector> meshGroupData; 38 | }; 39 | 40 | class OrbiterModel : public skybolt::vis::Model 41 | { 42 | public: 43 | OrbiterModel(const OrbiterModelConfig& config); 44 | 45 | bool getMeshGroupData(int groupId, GROUPREQUESTSPEC& grs); 46 | bool setMeshGroupData(int groupId, GROUPEDITSPEC& ges); 47 | 48 | void setMeshTexture(int groupId, const osg::ref_ptr& texture); 49 | void useMeshAsMfd(int groupId, const osg::ref_ptr& program, bool alphaBlend); 50 | 51 | OBJHANDLE getOwningObject() const { return mOwningObject; } 52 | int getMeshId() const { return mMeshId; } 53 | 54 | //! Gets the orbiter visibility category flags for the mesh. Values can be MESHVIS_NEVER, MESHVIS_EXTERNAL etc. 55 | int getMeshVisibilityCategoryFlags() const { return mMeshVisibilityCategoryFlags; } 56 | 57 | private: 58 | std::optional getMeshGroupData(int groupId) const; 59 | osg::Drawable* getDrawable(const MeshGroupData& data) const; //!< Returns null if drawable not found for mesh group 60 | osg::Drawable* getDrawableForGroupId(int groupId) const; //!< Returns null if drawable not found for groupId 61 | 62 | private: 63 | OBJHANDLE mOwningObject; 64 | int mMeshId; 65 | int mMeshVisibilityCategoryFlags; 66 | std::vector> mMeshGroupData; 67 | std::set mMfdGroupIds; 68 | }; 69 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/Exhaust.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "Exhaust.h" 16 | #include "ObjectUtil.h" 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | using namespace skybolt; 25 | 26 | Exhaust::Exhaust(VESSEL* vessel, const sim::Entity* entity, const vis::BeamsPtr& beams, const TextureProvider& textureProvider) : 27 | SimpleSimVisBinding(entity), 28 | mTextureProvider(textureProvider), 29 | mVessel(vessel), 30 | mBeams(beams) 31 | { 32 | assert(mVessel); 33 | addVisObject(mBeams); 34 | } 35 | 36 | static osg::Vec3f toOsgVec3f(const sim::Vector3& v) 37 | { 38 | return osg::Vec3f(v.x, v.y, v.z); 39 | } 40 | 41 | void Exhaust::syncVis(const GeocentricToNedConverter& converter) 42 | { 43 | static osg::ref_ptr defaultTexture = vis::createSrgbTexture(osgDB::readImageFile("Textures/Exhaust.dds")); 44 | 45 | SimpleSimVisBinding::syncVis(converter); 46 | 47 | std::vector beamsParams; 48 | 49 | EXHAUSTSPEC es; 50 | for (DWORD i = 0; i < mVessel->GetExhaustCount(); i++) 51 | { 52 | if (double level = mVessel->GetExhaustLevel(i); level > 0.0) 53 | { 54 | mVessel->GetExhaustSpec(i, &es); 55 | 56 | const std::optional& textureGroup = es.tex ? mTextureProvider(es.tex) : defaultTexture; 57 | osg::ref_ptr texture = textureGroup ? textureGroup->albedo : defaultTexture; 58 | 59 | float alpha = std::min(1.0, *es.level); 60 | if (es.modulate > 0.0) 61 | { 62 | alpha *= ((1.f - float(es.modulate)) + (float)rand() * es.modulate/(float)RAND_MAX); 63 | } 64 | 65 | vis::Beams::BeamParams params; 66 | params.relPosition = toOsgVec3f(orbiterToSkyboltVector3BodyAxes(*es.lpos)); 67 | params.relDirection = -toOsgVec3f(orbiterToSkyboltVector3BodyAxes(*es.ldir)); 68 | params.length = es.lsize; 69 | params.radius = es.wsize * 0.5; 70 | params.alpha = alpha; 71 | params.texture = texture; 72 | 73 | beamsParams.push_back(params); 74 | } 75 | } 76 | 77 | mBeams->setBeams(beamsParams); 78 | } 79 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TextureBlitter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "OpenGlContext.h" 13 | #include "TextureBlitter.h" 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | bool TextureBlitter::blitTexture(const osg::Texture2D& src, osg::Texture2D& dst, const skybolt::Box2i& srcRect, const skybolt::Box2i& dstRect) 20 | { 21 | auto op = [src = &src, dst = &dst, srcRect, dstRect](osg::RenderInfo& renderInfo) { 22 | int context = renderInfo.getContextID(); 23 | auto srcObj = src->getTextureObject(context); 24 | auto dstObj = dst->getTextureObject(context); 25 | 26 | if (!srcObj) 27 | { 28 | // Load source on GPU if not already loaded. 29 | // This is needed in case the source is not rendered. 30 | src->apply(*renderInfo.getState()); 31 | srcObj = src->getTextureObject(context); 32 | } 33 | 34 | if (!dstObj) 35 | { 36 | // Load destination on GPU if not already loaded. 37 | // This is needed in case the destination is not rendered. 38 | dst->apply(*renderInfo.getState()); 39 | dstObj = src->getTextureObject(context); 40 | } 41 | 42 | if (!srcObj || !dstObj) 43 | { 44 | assert(!"Should not get here"); 45 | return false; 46 | } 47 | 48 | int srcName = srcObj->id(); 49 | int dstName = dstObj->id(); 50 | 51 | int srcLevel = 0; 52 | int dstLevel = 0; 53 | 54 | if (srcRect.size() != dstRect.size()) 55 | { 56 | return false; // TODO: how do we handle this case? 57 | } 58 | 59 | // TODO: meet alignment constraints if src and dst are compressed. 60 | // Currently blits fail on DDS textures because rects do not align with DDS format requirements (blocks of 4 pixels). 61 | 62 | glCopyImageSubData( 63 | srcName, 64 | GL_TEXTURE_2D, 65 | srcLevel, 66 | srcRect.minimum.x, 67 | srcRect.minimum.y, 68 | 0, 69 | dstName, 70 | GL_TEXTURE_2D, 71 | dstLevel, 72 | dstRect.minimum.x, 73 | dstRect.minimum.y, 74 | 0, 75 | srcRect.size().x, 76 | srcRect.size().y, 77 | 1); 78 | 79 | return true; 80 | }; 81 | 82 | mOperations.push_back(op); 83 | 84 | return true; 85 | } 86 | 87 | void TextureBlitter::operator() (osg::RenderInfo& renderInfo) const 88 | { 89 | for (const auto& op : mOperations) 90 | { 91 | op(renderInfo); 92 | } 93 | mOperations.clear(); 94 | } 95 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterTileSource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "OrbiterTileSource.h" 13 | #include "OrbiterSkyboltClient/ThirdParty/ztreemgr.h" 14 | 15 | #include 16 | #include 17 | 18 | using namespace skybolt; 19 | 20 | OrbiterTileSource::OrbiterTileSource(std::unique_ptr treeMgr) : 21 | mTreeMgr(std::move(treeMgr)) 22 | { 23 | if (mTreeMgr->TOC().size() == 0) // If load failed 24 | { 25 | mTreeMgr.reset(); 26 | } 27 | } 28 | 29 | OrbiterTileSource::~OrbiterTileSource() = default; 30 | 31 | constexpr int orbiterLevelZeroOffset = 4; // Orbiter tile level numbering is skybolt level numbering +4. 32 | 33 | osg::ref_ptr OrbiterTileSource::createImage(const skybolt::QuadTreeTileKey& key, std::function cancelSupplier) const 34 | { 35 | if (!mTreeMgr) 36 | { 37 | return nullptr; 38 | } 39 | 40 | BYTE *buf; 41 | 42 | // ReadData is not thread-safe, requiring threads to have exclusive access 43 | std::scoped_lock lock(mTreeMgrMutex); 44 | DWORD ndata = mTreeMgr->ReadData(key.level + orbiterLevelZeroOffset, key.y, key.x, &buf); 45 | 46 | if (ndata == 0) 47 | { 48 | return nullptr; 49 | } 50 | 51 | BOOST_SCOPE_EXIT(&mTreeMgr, &buf) 52 | { 53 | mTreeMgr->ReleaseData(buf); 54 | } BOOST_SCOPE_EXIT_END 55 | 56 | return createImage(buf, ndata); 57 | } 58 | 59 | bool OrbiterTileSource::hasAnyChildren(const skybolt::QuadTreeTileKey& key) const 60 | { 61 | if (mTreeMgr) 62 | { 63 | DWORD idx = mTreeMgr->Idx(key.level + orbiterLevelZeroOffset, key.y, key.x); 64 | if (idx != -1) 65 | { 66 | for (int c = 0; c < 4; ++c) 67 | { 68 | if (mTreeMgr->TOC()[idx].child[c] != -1) 69 | { 70 | return true; 71 | } 72 | } 73 | } 74 | } 75 | return false; 76 | } 77 | 78 | //! @return index of tile with the given key if it exists. Returns -1 if it does not exist. 79 | //! @param highestTileOut is the key for the highest available tile found in the given tile's ancestry. 80 | static DWORD getHighestAvailableTile(const ZTreeMgr& treeMgr, int lvl, int ilat, int ilng, skybolt::QuadTreeTileKey& highestTileOut) 81 | { 82 | int idx; 83 | if (lvl <= orbiterLevelZeroOffset) 84 | { 85 | idx = treeMgr.Idx(lvl, ilat, ilng); 86 | } 87 | else 88 | { 89 | // Get tile index from the parent 90 | int plvl = lvl-1; 91 | int pilat = ilat/2; 92 | int pilng = ilng/2; 93 | DWORD pidx = getHighestAvailableTile(treeMgr, plvl, pilat, pilng, highestTileOut); 94 | if (pidx == (DWORD)-1) 95 | { 96 | // The parent does not exist, therefore this tile does not exist 97 | return -1; 98 | } 99 | else 100 | { 101 | int cidx = ((ilat&1) << 1) + (ilng&1); 102 | idx = treeMgr.TOC()[pidx].child[cidx]; 103 | } 104 | } 105 | 106 | if (idx != -1) 107 | { 108 | highestTileOut.level = lvl; 109 | highestTileOut.x = ilng; 110 | highestTileOut.y = ilat; 111 | } 112 | 113 | return idx; 114 | } 115 | 116 | std::optional OrbiterTileSource::getHighestAvailableLevel(const skybolt::QuadTreeTileKey& key) const 117 | { 118 | if (mTreeMgr) 119 | { 120 | skybolt::QuadTreeTileKey result; 121 | result.level = -1; 122 | getHighestAvailableTile(*mTreeMgr, key.level + orbiterLevelZeroOffset, key.y, key.x, result); 123 | 124 | if (result.level != -1) 125 | { 126 | result.level -= orbiterLevelZeroOffset; 127 | return result; 128 | } 129 | } 130 | return std::nullopt; 131 | } 132 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ThirdParty/ztreemgr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Martin Schweiger 2 | // Licensed under the MIT License 3 | 4 | // ============================================================== 5 | // ORBITER VISUALISATION PROJECT (OVP) 6 | // D3D7 Client module 7 | // ============================================================== 8 | 9 | // -------------------------------------------------------------- 10 | // ztreemgr.h 11 | // Class ZTreeMgr (interface) 12 | // 13 | // Manage compressed and packed tile trees for planetary surface 14 | // and cloud layers. 15 | // -------------------------------------------------------------- 16 | 17 | #ifndef __ZTREEMGR_H 18 | #define __ZTREEMGR_H 19 | 20 | #include 21 | #include 22 | 23 | // ======================================================================= 24 | // Tree node structure 25 | 26 | struct TreeNode { 27 | __int64 pos; // file position of node data 28 | DWORD size; // data block size [bytes] 29 | DWORD child[4]; // array index positions of the children ((DWORD)-1=no child) 30 | 31 | TreeNode() { 32 | pos = 0; 33 | size = 0; 34 | for (int i = 0; i < 4; i++) child[i] = (DWORD)-1; 35 | } 36 | }; 37 | 38 | // ======================================================================= 39 | // File header for compressed tree files 40 | 41 | class TreeFileHeader { 42 | friend class ZTreeMgr; 43 | 44 | public: 45 | TreeFileHeader(); 46 | size_t TreeFileHeader::fwrite(FILE *f); 47 | bool TreeFileHeader::fread(FILE *f); 48 | 49 | private: 50 | BYTE magic[4]; // file ID and version 51 | DWORD size; // header size [bytes] 52 | DWORD flags; // bit flags 53 | DWORD dataOfs; // file offset of start of data block (header + TOC) 54 | __int64 dataLength; // total length of compressed data block 55 | DWORD nodeCount; // total number of tree nodes 56 | DWORD rootPos1; // index of level-1 tile ((DWORD)-1 for not present) 57 | DWORD rootPos2; // index of level-2 tile ((DWORD)-1 for not present) 58 | DWORD rootPos3; // index of level-3 tile ((DWORD)-1 for not present) 59 | DWORD rootPos4[2]; // index of the level-4 tiles (quadtree roots; (DWORD)-1 for not present) 60 | }; 61 | 62 | // ======================================================================= 63 | // Tree table of contents 64 | 65 | class TreeTOC { 66 | friend class ZTreeMgr; 67 | 68 | public: 69 | TreeTOC(); 70 | ~TreeTOC(); 71 | size_t fread(DWORD size, FILE *f); 72 | DWORD size() const { return ntree; } 73 | const TreeNode &operator[](int idx) const { return tree[idx]; } 74 | 75 | inline DWORD NodeSizeDeflated(DWORD idx) const 76 | { return (DWORD)((idx < ntree-1 ? tree[idx+1].pos : totlength) - tree[idx].pos); } 77 | 78 | inline DWORD NodeSizeInflated(DWORD idx) const 79 | { return tree[idx].size; } 80 | 81 | private: 82 | TreeNode *tree; // array containing all tree node entries 83 | DWORD ntree; // number of entries 84 | DWORD ntreebuf; // array size 85 | __int64 totlength; // total data size (deflated) 86 | }; 87 | 88 | // ======================================================================= 89 | // ZTreeMgr class: manage a single layer tree for a planet 90 | 91 | class ZTreeMgr { 92 | public: 93 | enum Layer { LAYER_SURF, LAYER_MASK, LAYER_ELEV, LAYER_ELEVMOD, LAYER_LABEL, LAYER_CLOUD }; 94 | static ZTreeMgr *CreateFromFile(const char *PlanetPath, Layer _layer); 95 | ZTreeMgr(const char *PlanetPath, Layer _layer); 96 | ~ZTreeMgr(); 97 | const TreeTOC &TOC() const { return toc; } 98 | 99 | // return the array index of an arbitrary tile ((DWORD)-1: not present) 100 | DWORD Idx(int lvl, int ilat, int ilng) const; 101 | 102 | DWORD ReadData(DWORD idx, BYTE **outp); 103 | 104 | inline DWORD ReadData(int lvl, int ilat, int ilng, BYTE **outp) 105 | { return ReadData(Idx(lvl, ilat, ilng), outp); } 106 | 107 | void ReleaseData(BYTE *data); 108 | 109 | inline DWORD NodeSizeDeflated(DWORD idx) const { return toc.NodeSizeDeflated(idx); } 110 | inline DWORD NodeSizeInflated(DWORD idx) const { return toc.NodeSizeInflated(idx); } 111 | 112 | protected: 113 | bool OpenArchive(); 114 | DWORD Inflate(const BYTE *inp, DWORD ninp, BYTE *outp, DWORD noutp); 115 | 116 | private: 117 | char *path; 118 | Layer layer; 119 | FILE *treef; 120 | TreeTOC toc; 121 | DWORD rootPos1; // index of level-1 tile ((DWORD)-1 for not present) 122 | DWORD rootPos2; // index of level-2 tile ((DWORD)-1 for not present) 123 | DWORD rootPos3; // index of level-3 tile ((DWORD)-1 for not present) 124 | DWORD rootPos4[2]; // index of the level-4 tiles (quadtree roots; (DWORD)-1 for not present) 125 | __int64 dofs; 126 | }; 127 | 128 | #endif // !__ZTREEMGR_H 129 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OverlayPanelFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include "OverlayPanelFactory.h" 12 | 13 | #include 14 | 15 | #include 16 | 17 | using namespace skybolt; 18 | 19 | static osg::ref_ptr create2dPanelGeometry(const MESHGROUP& data, const osg::Vec2f& scale, const osg::Vec2f& offset, bool flipV = false) 20 | { 21 | osg::ref_ptr geometry = new osg::Geometry(); 22 | 23 | osg::Vec3Array* vertices = new osg::Vec3Array(data.nVtx); 24 | osg::Vec2Array* uvs = new osg::Vec2Array(data.nVtx); 25 | osg::ref_ptr indexBuffer = new osg::UIntArray(data.nIdx); 26 | 27 | for (int i = 0; i < (int)data.nVtx; ++i) 28 | { 29 | const auto& v = data.Vtx[i]; 30 | (*vertices)[i] = osg::Vec3f(v.x * scale.x() + offset.x(), v.y * scale.y() + offset.y(), 0); 31 | (*uvs)[i] = osg::Vec2f(v.tu, flipV ? 1.f - v.tv : v.tv); 32 | } 33 | 34 | for (int i = 0; i < (int)data.nIdx; i += 3) 35 | { 36 | // Note swap of 2 and 3rd index to change winding from left-handed to right-handed 37 | (*indexBuffer)[i] = data.Idx[i]; 38 | (*indexBuffer)[i + 1] = data.Idx[i + 2]; 39 | (*indexBuffer)[i + 2] = data.Idx[i + 1]; 40 | } 41 | 42 | geometry->setVertexArray(vertices); 43 | geometry->setTexCoordArray(0, uvs); 44 | geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, indexBuffer->size(), (GLuint*)indexBuffer->getDataPointer())); 45 | vis::configureDrawable(*geometry); 46 | return geometry; 47 | } 48 | 49 | OverlayPanelFactory::OverlayPanelFactory(WindowSizeProvider windowSizeProvider, TextureProvider textureProvider, MfdSurfaceProvider mfdSurfaceProvider) : 50 | mWindowSizeProvider(std::move(windowSizeProvider)), 51 | mTextureProvider(std::move(textureProvider)), 52 | mMfdSurfaceProvider(std::move(mfdSurfaceProvider)) 53 | { 54 | } 55 | 56 | osg::ref_ptr OverlayPanelFactory::createOverlayPanel(SURFHANDLE *hSurf, MESHHANDLE hMesh, MATRIX3 *T, float alpha, bool additive) 57 | { 58 | // Calculate scale and offset to convert to OpenGL NDC coordinates 59 | osg::Vec2i windowSize = mWindowSizeProvider(); 60 | osg::Vec2f scale(float(T->m11) / windowSize.x(), -float(T->m22) / windowSize.y()); 61 | osg::Vec2f offset(float(T->m13) / windowSize.x(), 1.0f - float(T->m23) / windowSize.y()); 62 | 63 | osg::ref_ptr geode = new osg::Geode(); 64 | 65 | DWORD ngrp = oapiMeshGroupCount(hMesh); 66 | for (DWORD i = 0; i < ngrp; i++) { 67 | MESHGROUP *grp = oapiMeshGroup(hMesh, i); 68 | if (grp->UsrFlag & 2) continue; // skip this group 69 | 70 | bool flipV = false; 71 | 72 | SURFHANDLE newsurf = nullptr; 73 | if (grp->TexIdx == SPEC_DEFAULT) { 74 | newsurf = 0; 75 | } 76 | else if (grp->TexIdx == SPEC_INHERIT) { 77 | // nothing to do 78 | } 79 | else if (grp->TexIdx >= TEXIDX_MFD0) { 80 | int mfdidx = grp->TexIdx - TEXIDX_MFD0; 81 | newsurf = mMfdSurfaceProvider(mfdidx); 82 | flipV = true; // MFD V coordinates need to be flipped. TODO: investigate why. 83 | if (!newsurf) continue; 84 | } 85 | else if (hSurf) { 86 | newsurf = hSurf[grp->TexIdx]; 87 | } 88 | else { 89 | newsurf = oapiGetTextureHandle(hMesh, grp->TexIdx + 1); 90 | } 91 | 92 | osg::ref_ptr geometry = create2dPanelGeometry(*grp, scale, offset, flipV); 93 | geometry->setCullingActive(false); 94 | geode->addDrawable(geometry); 95 | 96 | auto texture = mTextureProvider(newsurf); 97 | if (texture) 98 | { 99 | geometry->getOrCreateStateSet()->setTextureAttribute(0, texture->albedo); 100 | } 101 | } 102 | 103 | return geode; 104 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OsgSketchpad.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "GraphicsAPI.h" 14 | 15 | #include 16 | 17 | inline osg::Vec4i rgbIntToVec4iColor(DWORD col) 18 | { 19 | unsigned char* c = reinterpret_cast(&col); 20 | return osg::Vec4i(c[0], c[1], c[2], 255); 21 | } 22 | 23 | struct OsgPen : public oapi::Pen 24 | { 25 | OsgPen() : oapi::Pen(0, 0, 0) {} // FIXME: oapi::Pen should not have a constructor 26 | 27 | enum class Style 28 | { 29 | Invisible, 30 | Solid, 31 | Dashed 32 | }; 33 | 34 | Style style; 35 | int width; 36 | osg::Vec4i color; // [0,255] per component 37 | 38 | static inline Style toStyle(int style) 39 | { 40 | return (Style)style; 41 | } 42 | }; 43 | 44 | struct OsgBrush : public oapi::Brush 45 | { 46 | OsgBrush() : oapi::Brush(0) {} // FIXME: oapi::Brush should not have a constructor 47 | 48 | osg::Vec4i color; // [0,255] per component 49 | }; 50 | 51 | struct OsgFont : public oapi::Font 52 | { 53 | OsgFont() : oapi::Font(0, false, "") {} // FIXME: oapi::Brush should not have a constructor 54 | std::string name; 55 | float heightPixels; 56 | float rotationRadians = 0; 57 | }; 58 | 59 | struct NVGcontext; 60 | std::shared_ptr CreateNanoVgContext(); // must be called within a valid OpenGL context 61 | 62 | class OsgSketchpad : public oapi::Sketchpad 63 | { 64 | public: 65 | OsgSketchpad(const osg::ref_ptr& camera, SURFHANDLE surface, const std::shared_ptr& context); 66 | ~OsgSketchpad(); 67 | 68 | void fillBackground(const osg::Vec4f& color); 69 | 70 | public: // oapi::Sketchpad interface 71 | 72 | oapi::Font *SetFont(oapi::Font *font) override; 73 | 74 | oapi::Pen *SetPen(oapi::Pen *pen) override; 75 | 76 | oapi::Brush *SetBrush(oapi::Brush *brush) override; 77 | 78 | void SetTextAlign(TAlign_horizontal tah = LEFT, TAlign_vertical tav = TOP) override; 79 | 80 | DWORD SetTextColor(DWORD col) override; 81 | 82 | DWORD SetBackgroundColor(DWORD col) override; 83 | 84 | void SetBackgroundMode(BkgMode mode) override; 85 | 86 | DWORD GetCharSize() override; 87 | 88 | DWORD GetTextWidth(const char *str, int len = 0) override; 89 | 90 | void SetOrigin(int x, int y) override { mOrigin = osg::Vec2i(x, y); } 91 | 92 | void GetOrigin(int *x, int *y) const override { *x = mOrigin.x(), *y = mOrigin.y(); } 93 | 94 | bool Text(int x, int y, const char *str, int len) override; 95 | 96 | bool TextW(int x, int y, const LPWSTR str, int len) override; 97 | 98 | void Pixel(int x, int y, DWORD col) override {} 99 | 100 | void MoveTo(int x, int y) override { mPenPosition = osg::Vec2i(x, y); } 101 | 102 | void LineTo(int x, int y) override; 103 | 104 | void Line(int x0, int y0, int x1, int y1) override; 105 | 106 | void Rectangle(int x0, int y0, int x1, int y1) override; 107 | 108 | void Ellipse(int x0, int y0, int x1, int y1) override; 109 | 110 | void Polygon(const oapi::IVECTOR2 *pt, int npt) override; 111 | 112 | void Polyline(const oapi::IVECTOR2 *pt, int npt) override; 113 | 114 | private: 115 | osg::ref_ptr mCamera; 116 | osg::ref_ptr mDrawable; 117 | mutable OsgFont* mFont = nullptr; 118 | mutable OsgPen* mPen = nullptr; 119 | mutable OsgBrush* mBrush = nullptr; 120 | DWORD mTextColor = 0; 121 | DWORD mTextBackgroundColor = 0; 122 | BkgMode mTextBackgroundMode = BK_TRANSPARENT; 123 | int mTextAlign = 0; // bitfield of enum type NVGalign 124 | osg::Vec2i mOrigin = osg::Vec2i(0, 0); 125 | osg::Vec2i mPenPosition = osg::Vec2i(0, 0); 126 | }; 127 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/DistantCelestialBodyFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "DistantCelestialBodyFactory.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "ObjectUtil.h" 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | using namespace skybolt; 33 | using namespace sim; 34 | 35 | class StartNodeUpdater : public sim::Component 36 | { 37 | public: 38 | StartNodeUpdater(sim::Entity* entity, OBJHANDLE objectHandle) : 39 | mEntity(entity), 40 | mObjectHandle(objectHandle) 41 | { 42 | assert(mEntity); 43 | } 44 | 45 | void updatePreDynamics(TimeReal dt, TimeReal dtWallClock) override 46 | { 47 | // Set sun position 48 | VECTOR3 sunPosition, cameraPosition; 49 | oapiGetGlobalPos(mObjectHandle, &sunPosition); 50 | oapiCameraGlobalPos(&cameraPosition); 51 | 52 | setPosition(*mEntity, orbiterToSkyboltVector3GlobalAxes(sunPosition)); 53 | 54 | // Set light direction 55 | VECTOR3 dir = sunPosition - cameraPosition; 56 | normalise(dir); 57 | 58 | sim::Vector3 lightDirection = orbiterToSkyboltVector3GlobalAxes(dir); 59 | glm::vec3 tangent, bitangent; 60 | math::getOrthonormalBasis(lightDirection, tangent, bitangent); 61 | glm::mat3 m(lightDirection, tangent, bitangent); 62 | setOrientation(*mEntity, glm::quat(m)); 63 | } 64 | 65 | private: 66 | sim::Entity* mEntity; 67 | OBJHANDLE mObjectHandle; 68 | }; 69 | 70 | EntityPtr createDistantCelestialBody(const DistantCelestialBodyCreationArgs& args) 71 | { 72 | osg::StateSet* ss = new osg::StateSet; 73 | ss->setAttribute(args.program); 74 | ss->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); 75 | ss->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); 76 | 77 | osg::Depth* depth = new osg::Depth; 78 | depth->setWriteMask(false); 79 | ss->setAttributeAndModes(depth, osg::StateAttribute::ON); 80 | 81 | osg::ref_ptr texture = vis::createSrgbTexture(osgDB::readImageFile("Textures/Star.dds")); 82 | ss->setTextureAttributeAndModes(0, texture); 83 | ss->addUniform(vis::createUniformSampler2d("albedoSampler", 0)); 84 | 85 | osg::ref_ptr blendFunc = new osg::BlendFunc; 86 | ss->setAttributeAndModes(blendFunc); 87 | 88 | EntityPtr entity(new Entity()); 89 | entity->addComponent(std::make_shared()); 90 | 91 | entity->addComponent(std::make_shared(entity.get(), args.objectHandle)); 92 | 93 | float diameterScale = 6.5f; // account for disk in texture image smaller than full image size 94 | float diameter = oapiGetSize(args.objectHandle) * diameterScale; 95 | vis::RootNodePtr node(new vis::Billboard(ss, diameter, diameter)); 96 | 97 | auto visObjectsComponent = std::make_shared(args.scene); 98 | entity->addComponent(visObjectsComponent); 99 | visObjectsComponent->addObject(node); 100 | 101 | vis::LightPtr light(new vis::Light(osg::Vec3f(-1,0,0))); 102 | visObjectsComponent->addObject(light); 103 | 104 | SimVisBindingsComponentPtr simVisBindingComponent(new SimVisBindingsComponent); 105 | entity->addComponent(simVisBindingComponent); 106 | 107 | auto binding = std::make_shared(entity.get()); 108 | binding->addVisObject(node); 109 | binding->addVisObject(light); 110 | simVisBindingComponent->bindings.push_back(binding); 111 | 112 | return entity; 113 | } 114 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/TileSource/OrbiterElevationTileSource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "OrbiterElevationTileSource.h" 13 | #include "OrbiterSkyboltClient/ThirdParty/ztreemgr.h" 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | using namespace skybolt; 21 | 22 | OrbiterElevationTileSource::OrbiterElevationTileSource(const std::string& directory) : 23 | OrbiterTileSource(std::make_unique(directory.c_str(), ZTreeMgr::LAYER_ELEV)) 24 | { 25 | } 26 | 27 | #pragma pack(push,1) 28 | //! From Orbiter developer documentation 'PlanetTextures.odt' 29 | struct ELEVFILEHEADER { // file header for patch elevation data file 30 | char id[4]; // ID string + version ('E','L','E',1) 31 | int hdrsize; // header size (100 expected) 32 | int dtype; // data format (0=flat, no data block; 33 | // 8=uint8; -8=int8; 16=uint16; -16=int16) 34 | int xgrd, ygrd; // data grid size (259 x 259 expected) 35 | int xpad, ypad; // horizontal, vertical padding width 36 | // (1, 1 expected) 37 | double scale; // data scaling factor (1.0 expected) 38 | double offset; // data offset (elevation = 39 | // raw value * scale + offset) 40 | double latmin, latmax; // latitude range [rad] 41 | double lngmin, lngmax; // longitude range [rad] 42 | double emin, emax, emean; // min, max, mean elevation [m] 43 | }; 44 | #pragma pack(pop) 45 | 46 | osg::ref_ptr OrbiterElevationTileSource::createImage(const std::uint8_t* buffer, std::size_t sizeBytes) const 47 | { 48 | if (sizeBytes < sizeof(ELEVFILEHEADER)) 49 | { 50 | return nullptr; 51 | } 52 | 53 | const ELEVFILEHEADER& header = reinterpret_cast(*buffer); 54 | 55 | // Orbiter elevation tiles are 259x259 pixels. The inner 257x257 is a tile with edges along the lat lon bounds. 56 | // We discard the outermost row and column, which is elevation data in the next adjacent tile. 57 | osg::ref_ptr image = new osg::Image(); 58 | image->allocateImage(257, 257, 1, GL_LUMINANCE, GL_UNSIGNED_SHORT); 59 | image->setInternalTextureFormat(GL_R16); 60 | uint16_t* ptr = (uint16_t*)image->getDataPointer(); 61 | 62 | constexpr int expectedWidth = 259; 63 | constexpr int expectedHeight = 259; 64 | if (header.xgrd != expectedWidth && header.ygrd != expectedHeight) 65 | { 66 | return nullptr; 67 | } 68 | 69 | if (header.dtype == 8) // uint8 70 | { 71 | if ((int)sizeBytes < header.hdrsize + expectedWidth * expectedHeight) 72 | { 73 | return nullptr; 74 | } 75 | 76 | const std::uint8_t* source = buffer + header.hdrsize; 77 | for (int y = 1; y <= 257; ++y) 78 | { 79 | for (int x = 1; x <= 257; ++x) 80 | { 81 | *ptr++ = int(source[y * 259 + x]) + 32768; 82 | } 83 | } 84 | } 85 | else if (header.dtype == -16) // int16 86 | { 87 | if ((int)sizeBytes < header.hdrsize + expectedWidth * expectedHeight * sizeof(std::int16_t)) 88 | { 89 | return nullptr; 90 | } 91 | 92 | const std::int16_t* source = reinterpret_cast(buffer + header.hdrsize); 93 | for (int y = 1; y <= 257; ++y) 94 | { 95 | for (int x = 1; x <= 257; ++x) 96 | { 97 | *ptr++ = int(source[y * 259 + x]) + 32768;; 98 | } 99 | } 100 | } 101 | else // if (header.dtype == 0) // flat 102 | { 103 | memset(ptr, 0, 257 * 257 * sizeof(std::uint16_t)); 104 | } 105 | 106 | vis::setHeightMapElevationBounds(*image, vis::HeightMapElevationBounds(header.emin, header.emax)); 107 | vis::setHeightMapElevationRerange(*image, vis::HeightMapElevationRerange(header.scale, header.offset - 32768)); 108 | 109 | return image; 110 | } 111 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/SkyboltParticleStream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "SkyboltParticleStream.h" 13 | #include "ObjectUtil.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | using namespace skybolt; 30 | using namespace sim; 31 | 32 | SkyboltParticleStream::SkyboltParticleStream(oapi::GraphicsClient* gc, PARTICLESTREAMSPEC* pss, 33 | const EntityFactory& entityFactory, World* world, EntityFinder entityFinder, DestructionAction destructionAction) : 34 | ParticleStream(gc, pss), 35 | mWorld(world), 36 | mEntityFinder(std::move(entityFinder)), 37 | mDestructionAction(std::move(destructionAction)) 38 | { 39 | double elevationAngleMin = math::halfPiD() - atan(0.5 * pss->srcspread); 40 | double elevationAngleMax = math::halfPiD(); 41 | 42 | // calculate automatic emission rate instead of using pss->srcrate 43 | // because pss->srcrate values are too low to give nice looking particle streams. 44 | double emissionRate = std::min(1000.0, 2.0 * pss->v0 / pss->srcsize); 45 | 46 | nlohmann::json particleSystemJson = { 47 | { "emissionRate", emissionRate }, 48 | { "radius", pss->srcsize * 0.5 }, 49 | { "elevationAngleMin", elevationAngleMin }, 50 | { "elevationAngleMax", elevationAngleMax }, 51 | { "speedMin", pss->v0 }, 52 | { "speedMax", pss->v0 }, 53 | { "upDirection", nlohmann::json::array({1, 0, 0}) }, 54 | { "lifetime", pss->lifetime }, 55 | { "radiusLinearGrowthPerSecond", pss->growthrate * 0.5 }, 56 | { "atmosphericSlowdownFactor", pss->atmslowdown }, 57 | { "zeroAtmosphericDensityAlpha", 0.0 }, 58 | { "earthSeaLevelAtmosphericDensityAlpha", 1.0 }, 59 | { "albedoTexture", "Environment/Explosion01_light_nofire.png" } 60 | }; 61 | 62 | // Orbiter has no concept of particle temperature, so assume particles are hot if they are emissive 63 | if (pss->ltype == PARTICLESTREAMSPEC::EMISSIVE) 64 | { 65 | particleSystemJson["initialTemperatureDegreesCelcius"] = 2000; 66 | particleSystemJson["heatTransferCoefficent"] = 4.0; 67 | } 68 | 69 | nlohmann::json json = { 70 | {"components", nlohmann::json::array({ 71 | {{"node", { 72 | }}}, 73 | {{"particleSystem", particleSystemJson}} 74 | })} 75 | }; 76 | 77 | std::string name = entityFactory.createUniqueObjectName("particles"); 78 | mEntity = entityFactory.createEntityFromJson(json, name, Vector3(), Quaternion()); 79 | 80 | AttachmentParams params; 81 | params.positionRelBody = Vector3(); 82 | params.orientationRelBody = Quaternion(0, 0, 0, 1); 83 | mAttachmentComponent = std::make_shared(params, mEntity.get()); 84 | mEntity->addComponent(mAttachmentComponent); 85 | 86 | world->addEntity(mEntity); 87 | 88 | auto particleSystem = mEntity->getFirstComponentRequired()->getParticleSystem(); 89 | mParticleEmitter = particleSystem->getOperationOfType(); 90 | } 91 | 92 | SkyboltParticleStream::~SkyboltParticleStream() 93 | { 94 | mWorld->removeEntity(mEntity.get()); 95 | mDestructionAction(this); 96 | } 97 | 98 | void SkyboltParticleStream::update() 99 | { 100 | auto entity = hRef ? mEntityFinder(hRef) : nullptr; 101 | mAttachmentComponent->resetTarget(entity.get()); 102 | mAttachmentComponent->setPositionRelBody(orbiterToSkyboltVector3BodyAxes(*pos)); 103 | mAttachmentComponent->setOrientationRelBody(getOrientationFromDirection(-orbiterToSkyboltVector3BodyAxes(*dir))); 104 | 105 | mParticleEmitter->setEmissionAlphaMultiplier((entity && level) ? *level : 0.0); 106 | mParticleEmitter->setEmissionRateMultiplier((entity && level && *level > 0.0) ? 1.0 : 0.0); 107 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ThirdParty/nanovg/nanovg_gl_utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org 3 | // 4 | // This software is provided 'as-is', without any express or implied 5 | // warranty. In no event will the authors be held liable for any damages 6 | // arising from the use of this software. 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 1. The origin of this software must not be misrepresented; you must not 11 | // claim that you wrote the original software. If you use this software 12 | // in a product, an acknowledgment in the product documentation would be 13 | // appreciated but is not required. 14 | // 2. Altered source versions must be plainly marked as such, and must not be 15 | // misrepresented as being the original software. 16 | // 3. This notice may not be removed or altered from any source distribution. 17 | // 18 | #ifndef NANOVG_GL_UTILS_H 19 | #define NANOVG_GL_UTILS_H 20 | 21 | struct NVGLUframebuffer { 22 | NVGcontext* ctx; 23 | GLuint fbo; 24 | GLuint rbo; 25 | GLuint texture; 26 | int image; 27 | }; 28 | typedef struct NVGLUframebuffer NVGLUframebuffer; 29 | 30 | // Helper function to create GL frame buffer to render to. 31 | void nvgluBindFramebuffer(NVGLUframebuffer* fb); 32 | NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags); 33 | void nvgluDeleteFramebuffer(NVGLUframebuffer* fb); 34 | 35 | #endif // NANOVG_GL_UTILS_H 36 | 37 | #ifdef NANOVG_GL_IMPLEMENTATION 38 | 39 | #if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3) 40 | // FBO is core in OpenGL 3>. 41 | # define NANOVG_FBO_VALID 1 42 | #elif defined(NANOVG_GL2) 43 | // On OS X including glext defines FBO on GL2 too. 44 | # ifdef __APPLE__ 45 | # include 46 | # define NANOVG_FBO_VALID 1 47 | # endif 48 | #endif 49 | 50 | static GLint defaultFBO = -1; 51 | 52 | NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags) 53 | { 54 | #ifdef NANOVG_FBO_VALID 55 | GLint defaultFBO; 56 | GLint defaultRBO; 57 | NVGLUframebuffer* fb = NULL; 58 | 59 | glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); 60 | glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO); 61 | 62 | fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer)); 63 | if (fb == NULL) goto error; 64 | memset(fb, 0, sizeof(NVGLUframebuffer)); 65 | 66 | fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL); 67 | 68 | #if defined NANOVG_GL2 69 | fb->texture = nvglImageHandleGL2(ctx, fb->image); 70 | #elif defined NANOVG_GL3 71 | fb->texture = nvglImageHandleGL3(ctx, fb->image); 72 | #elif defined NANOVG_GLES2 73 | fb->texture = nvglImageHandleGLES2(ctx, fb->image); 74 | #elif defined NANOVG_GLES3 75 | fb->texture = nvglImageHandleGLES3(ctx, fb->image); 76 | #endif 77 | 78 | fb->ctx = ctx; 79 | 80 | // frame buffer object 81 | glGenFramebuffers(1, &fb->fbo); 82 | glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); 83 | 84 | // render buffer object 85 | glGenRenderbuffers(1, &fb->rbo); 86 | glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo); 87 | glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h); 88 | 89 | // combine all 90 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); 91 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); 92 | 93 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 94 | #ifdef GL_DEPTH24_STENCIL8 95 | // If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback. 96 | // Some graphics cards require a depth buffer along with a stencil. 97 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); 98 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); 99 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); 100 | 101 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 102 | #endif // GL_DEPTH24_STENCIL8 103 | goto error; 104 | } 105 | 106 | glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); 107 | glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); 108 | return fb; 109 | error: 110 | glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); 111 | glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); 112 | nvgluDeleteFramebuffer(fb); 113 | return NULL; 114 | #else 115 | NVG_NOTUSED(ctx); 116 | NVG_NOTUSED(w); 117 | NVG_NOTUSED(h); 118 | NVG_NOTUSED(imageFlags); 119 | return NULL; 120 | #endif 121 | } 122 | 123 | void nvgluBindFramebuffer(NVGLUframebuffer* fb) 124 | { 125 | #ifdef NANOVG_FBO_VALID 126 | if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); 127 | glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO); 128 | #else 129 | NVG_NOTUSED(fb); 130 | #endif 131 | } 132 | 133 | void nvgluDeleteFramebuffer(NVGLUframebuffer* fb) 134 | { 135 | #ifdef NANOVG_FBO_VALID 136 | if (fb == NULL) return; 137 | if (fb->fbo != 0) 138 | glDeleteFramebuffers(1, &fb->fbo); 139 | if (fb->rbo != 0) 140 | glDeleteRenderbuffers(1, &fb->rbo); 141 | if (fb->image >= 0) 142 | nvgDeleteImage(fb->ctx, fb->image); 143 | fb->ctx = NULL; 144 | fb->fbo = 0; 145 | fb->rbo = 0; 146 | fb->texture = 0; 147 | fb->image = -1; 148 | free(fb); 149 | #else 150 | NVG_NOTUSED(fb); 151 | #endif 152 | } 153 | 154 | #endif // NANOVG_GL_IMPLEMENTATION 155 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ThirdParty/ztreemgr.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Martin Schweiger 2 | // Licensed under the MIT License 3 | 4 | // ============================================================== 5 | // ORBITER VISUALISATION PROJECT (OVP) 6 | // D3D7 Client module 7 | // Copyright (C) 2006-2016 Martin Schweiger 8 | // Dual licensed under GPL v3 and LGPL v3 9 | // ============================================================== 10 | 11 | // -------------------------------------------------------------- 12 | // ztreemgr.cpp 13 | // Class ZTreeMgr (implementation) 14 | // 15 | // Manage compressed and packed tile trees for planetary surface 16 | // and cloud layers. 17 | // -------------------------------------------------------------- 18 | 19 | #include "ztreemgr.h" 20 | #include "OrbiterAPI.h" 21 | 22 | // ======================================================================= 23 | // File header for compressed tree files 24 | 25 | TreeFileHeader::TreeFileHeader () 26 | { 27 | magic[0] = 'T'; 28 | magic[1] = 'X'; 29 | magic[2] = 1; 30 | magic[3] = 0; 31 | size = sizeof(TreeFileHeader); 32 | flags = 0; 33 | nodeCount = 0; 34 | dataOfs = size; 35 | dataLength = 0; 36 | rootPos1 = rootPos2 = rootPos3 = rootPos4[0] = rootPos4[1] = (DWORD)-1; 37 | } 38 | 39 | // ----------------------------------------------------------------------- 40 | 41 | size_t TreeFileHeader::fwrite(FILE *f) 42 | { 43 | return ::fwrite(this, sizeof(TreeFileHeader), 1, f); 44 | } 45 | 46 | // ----------------------------------------------------------------------- 47 | 48 | bool TreeFileHeader::fread(FILE *f) 49 | { 50 | BYTE buf[4]; 51 | DWORD sz, flags; 52 | if (::fread(buf, 1, 4, f) < 4 || memcmp(buf, magic, 4)) 53 | return false; 54 | if (::fread(&sz, sizeof(DWORD), 1, f) != 1 || sz != size) 55 | return false; 56 | ::fread(&flags, sizeof(DWORD), 1, f); 57 | ::fread(&dataOfs, sizeof(DWORD), 1, f); 58 | ::fread(&dataLength, sizeof(__int64), 1, f); 59 | ::fread(&nodeCount, sizeof(DWORD), 1, f); 60 | ::fread(&rootPos1, sizeof(DWORD), 1, f); 61 | ::fread(&rootPos2, sizeof(DWORD), 1, f); 62 | ::fread(&rootPos3, sizeof(DWORD), 1, f); 63 | ::fread(rootPos4, sizeof(DWORD), 2, f); 64 | return true; 65 | } 66 | 67 | // ======================================================================= 68 | // Tree table of contents 69 | 70 | TreeTOC::TreeTOC() 71 | { 72 | ntree = 0; 73 | ntreebuf = 0; 74 | tree = NULL; 75 | totlength = 0; 76 | } 77 | 78 | // ----------------------------------------------------------------------- 79 | 80 | TreeTOC::~TreeTOC() 81 | { 82 | if (ntreebuf) 83 | delete []tree; 84 | } 85 | 86 | // ----------------------------------------------------------------------- 87 | 88 | size_t TreeTOC::fread(DWORD size, FILE *f) 89 | { 90 | if (ntreebuf != size) { 91 | TreeNode *tmp = new TreeNode[size]; 92 | if (ntreebuf) delete []tree; 93 | tree = tmp; 94 | ntree = ntreebuf = size; 95 | } 96 | return ::fread(tree, sizeof(TreeNode), size, f); 97 | } 98 | 99 | // ======================================================================= 100 | // ZTreeMgr class: manage a single layer tree for a planet 101 | 102 | ZTreeMgr *ZTreeMgr::CreateFromFile(const char *PlanetPath, Layer _layer) 103 | { 104 | ZTreeMgr *mgr = new ZTreeMgr(PlanetPath, _layer); 105 | if (!mgr->TOC().size()) { 106 | delete mgr; 107 | mgr = 0; 108 | } 109 | return mgr; 110 | } 111 | 112 | // ----------------------------------------------------------------------- 113 | 114 | ZTreeMgr::ZTreeMgr(const char *PlanetPath, Layer _layer) 115 | { 116 | path = new char[strlen(PlanetPath)+1]; 117 | strcpy(path, PlanetPath); 118 | layer = _layer; 119 | treef = 0; 120 | OpenArchive(); 121 | } 122 | 123 | // ----------------------------------------------------------------------- 124 | 125 | ZTreeMgr::~ZTreeMgr() 126 | { 127 | delete []path; 128 | if (treef) fclose(treef); 129 | } 130 | 131 | // ----------------------------------------------------------------------- 132 | 133 | bool ZTreeMgr::OpenArchive() 134 | { 135 | const char *name[6] = { "Surf", "Mask", "Elev", "Elev_mod", "Label", "Cloud" }; 136 | char fname[256]; 137 | sprintf (fname, "%s\\Archive\\%s.tree", path, name[layer]); 138 | treef = fopen(fname, "rb"); 139 | if (!treef) return false; 140 | 141 | TreeFileHeader tfh; 142 | if (!tfh.fread(treef)) { 143 | fclose(treef); 144 | treef = 0; 145 | return false; 146 | } 147 | rootPos1 = tfh.rootPos1; 148 | rootPos2 = tfh.rootPos2; 149 | rootPos3 = tfh.rootPos3; 150 | for (int i = 0; i < 2; i++) 151 | rootPos4[i] = tfh.rootPos4[i]; 152 | dofs = (__int64)tfh.dataOfs; 153 | 154 | if (!toc.fread(tfh.nodeCount, treef)) { 155 | fclose(treef); 156 | treef = 0; 157 | return false; 158 | } 159 | toc.totlength = tfh.dataLength; 160 | 161 | return true; 162 | } 163 | 164 | // ----------------------------------------------------------------------- 165 | 166 | DWORD ZTreeMgr::Idx(int lvl, int ilat, int ilng) const 167 | { 168 | if (lvl <= 4) { 169 | return (lvl == 1 ? rootPos1 : lvl == 2 ? rootPos2 : lvl == 3 ? rootPos3 : rootPos4[ilng]); 170 | } else { 171 | int plvl = lvl-1; 172 | int pilat = ilat/2; 173 | int pilng = ilng/2; 174 | DWORD pidx = Idx(plvl, pilat, pilng); 175 | if (pidx == (DWORD)-1) 176 | return pidx; 177 | int cidx = ((ilat&1) << 1) + (ilng&1); 178 | return toc[pidx].child[cidx]; 179 | } 180 | } 181 | 182 | // ----------------------------------------------------------------------- 183 | 184 | DWORD ZTreeMgr::ReadData(DWORD idx, BYTE **outp) 185 | { 186 | if (idx == (DWORD)-1) return 0; // sanity check 187 | 188 | DWORD esize = NodeSizeInflated(idx); 189 | if (!esize) // node doesn't have data, but has descendants with data 190 | return 0; 191 | 192 | if (_fseeki64(treef, toc[idx].pos+dofs, SEEK_SET)) 193 | return 0; 194 | 195 | DWORD zsize = NodeSizeDeflated(idx); 196 | BYTE *zbuf = new BYTE[zsize]; 197 | fread(zbuf, 1, zsize, treef); 198 | 199 | BYTE *ebuf = new BYTE[esize]; 200 | 201 | DWORD ndata = Inflate(zbuf, zsize, ebuf, esize); 202 | delete []zbuf; 203 | 204 | if (!ndata) { 205 | delete []ebuf; 206 | ebuf = 0; 207 | } 208 | *outp = ebuf; 209 | return ndata; 210 | } 211 | 212 | // ----------------------------------------------------------------------- 213 | 214 | DWORD ZTreeMgr::Inflate(const BYTE *inp, DWORD ninp, BYTE *outp, DWORD noutp) 215 | { 216 | return oapiInflate(inp, ninp, outp, noutp); 217 | } 218 | 219 | // ----------------------------------------------------------------------- 220 | 221 | void ZTreeMgr::ReleaseData(BYTE *data) 222 | { 223 | delete []data; 224 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OpenGlContext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "OpenGlContext.h" 13 | 14 | #include 15 | 16 | // Code based on example from Nick Rolfe 17 | // https://gist.github.com/nickrolfe/1127313ed1dbf80254b614a721b3ee9c 18 | 19 | #define WGL_DRAW_TO_WINDOW_ARB 0x2001 20 | #define WGL_ACCELERATION_ARB 0x2003 21 | #define WGL_SUPPORT_OPENGL_ARB 0x2010 22 | #define WGL_DOUBLE_BUFFER_ARB 0x2011 23 | #define WGL_PIXEL_TYPE_ARB 0x2013 24 | #define WGL_COLOR_BITS_ARB 0x2014 25 | #define WGL_DEPTH_BITS_ARB 0x2022 26 | #define WGL_STENCIL_BITS_ARB 0x2023 27 | 28 | #define WGL_FULL_ACCELERATION_ARB 0x2027 29 | #define WGL_TYPE_RGBA_ARB 0x202B 30 | 31 | #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 32 | #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 33 | #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 34 | 35 | #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 36 | #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 37 | 38 | typedef HGLRC WINAPI wglCreateContextAttribsARB_type(HDC hdc, HGLRC hShareContext, const int *attribList); 39 | wglCreateContextAttribsARB_type *wglCreateContextAttribsARB; 40 | 41 | typedef BOOL WINAPI wglChoosePixelFormatARB_type(HDC hdc, const int *piAttribIList, 42 | const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); 43 | wglChoosePixelFormatARB_type *wglChoosePixelFormatARB; 44 | 45 | static WNDCLASSEX createDummyWindowClass() 46 | { 47 | // Before we can load extensions, we need a dummy OpenGL context, created using a dummy window. 48 | // We use a dummy window because you can only set the pixel format for a window once. For the 49 | // real window, we want to use wglChoosePixelFormatARB (so we can potentially specify options 50 | // that aren't available in PIXELFORMATDESCRIPTOR), but we can't load and use that before we 51 | // have a context. 52 | WNDCLASSEX windowClass = {0}; 53 | windowClass.cbSize = sizeof(windowClass); 54 | windowClass.hInstance = GetModuleHandle(0); 55 | windowClass.style = CS_OWNDC; 56 | windowClass.hIcon = LoadIcon(windowClass.hInstance, MAKEINTRESOURCE(129)); 57 | windowClass.lpfnWndProc = DefWindowProcA; 58 | windowClass.lpszClassName = "skyboltDummyWindow"; 59 | 60 | if (!RegisterClassEx(&windowClass)) 61 | { 62 | throw std::runtime_error("Failed to register dummy OpenGL window"); 63 | } 64 | 65 | return windowClass; 66 | } 67 | 68 | static void initOpenglExtensions() 69 | { 70 | static WNDCLASSEX windowClass = createDummyWindowClass(); 71 | 72 | HWND dummyWindow = CreateWindowEx(WS_EX_APPWINDOW, "skyboltDummyWindow", "temporary", WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, 0, 0, 0, 0, 0, 0, windowClass.hInstance, 0); 73 | 74 | if (!dummyWindow) 75 | { 76 | throw std::runtime_error("Failed to create dummy OpenGL window"); 77 | } 78 | 79 | HDC dummyDc = GetDC(dummyWindow); 80 | 81 | PIXELFORMATDESCRIPTOR pfd; 82 | pfd.nSize = sizeof(pfd); 83 | pfd.nVersion = 1; 84 | pfd.iPixelType = PFD_TYPE_RGBA; 85 | pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 86 | pfd.cColorBits = 32; 87 | pfd.cAlphaBits = 8; 88 | pfd.iLayerType = PFD_MAIN_PLANE; 89 | pfd.cDepthBits = 24; 90 | pfd.cStencilBits = 8; 91 | 92 | int pixel_format = ChoosePixelFormat(dummyDc, &pfd); 93 | if (!pixel_format) 94 | { 95 | throw std::runtime_error("Failed to find a suitable pixel format"); 96 | } 97 | if (!SetPixelFormat(dummyDc, pixel_format, &pfd)) 98 | { 99 | throw std::runtime_error("Failed to set the pixel format"); 100 | } 101 | 102 | HGLRC dummy_context = wglCreateContext(dummyDc); 103 | if (!dummy_context) { 104 | throw std::runtime_error("Failed to create a dummy OpenGL rendering context"); 105 | } 106 | 107 | if (!wglMakeCurrent(dummyDc, dummy_context)) { 108 | throw std::runtime_error("Failed to activate dummy OpenGL rendering context"); 109 | } 110 | 111 | wglCreateContextAttribsARB = (wglCreateContextAttribsARB_type*)wglGetProcAddress("wglCreateContextAttribsARB"); 112 | wglChoosePixelFormatARB = (wglChoosePixelFormatARB_type*)wglGetProcAddress("wglChoosePixelFormatARB"); 113 | 114 | GLenum err = glewInit(); 115 | if (GLEW_OK != err) 116 | { 117 | throw std::runtime_error("Error initializing GLEW: " + std::string((char*)glewGetErrorString(err))); 118 | } 119 | 120 | wglMakeCurrent(dummyDc, 0); 121 | wglDeleteContext(dummy_context); 122 | ReleaseDC(dummyWindow, dummyDc); 123 | DestroyWindow(dummyWindow); 124 | } 125 | 126 | HGLRC createOpenGlContext(HDC real_dc) 127 | { 128 | initOpenglExtensions(); 129 | 130 | int pixel_format_attribs[] = { 131 | WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, 132 | WGL_SUPPORT_OPENGL_ARB, GL_TRUE, 133 | WGL_DOUBLE_BUFFER_ARB, GL_TRUE, 134 | WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, 135 | WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, 136 | WGL_COLOR_BITS_ARB, 32, 137 | WGL_DEPTH_BITS_ARB, 24, 138 | WGL_STENCIL_BITS_ARB, 8, 139 | 0 140 | }; 141 | 142 | int pixel_format; 143 | UINT num_formats; 144 | wglChoosePixelFormatARB(real_dc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats); 145 | if (!num_formats) 146 | { 147 | throw std::runtime_error("Failed to set the OpenGL pixel format"); 148 | } 149 | 150 | PIXELFORMATDESCRIPTOR pfd; 151 | DescribePixelFormat(real_dc, pixel_format, sizeof(pfd), &pfd); 152 | if (!SetPixelFormat(real_dc, pixel_format, &pfd)) 153 | { 154 | throw std::runtime_error("Failed to set the OpenGL pixel format"); 155 | } 156 | 157 | int attributes[] = { 158 | WGL_CONTEXT_MAJOR_VERSION_ARB, 4, 159 | WGL_CONTEXT_MINOR_VERSION_ARB, 5, 160 | WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 161 | 0, 162 | }; 163 | 164 | HGLRC context = wglCreateContextAttribsARB(real_dc, 0, attributes); 165 | if (!context) 166 | { 167 | throw std::runtime_error("Failed to create OpenGL context"); 168 | } 169 | 170 | if (!wglMakeCurrent(real_dc, context)) 171 | { 172 | throw std::runtime_error("Failed to activate OpenGL rendering context"); 173 | } 174 | 175 | return context; 176 | } 177 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/SkyboltClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #pragma once 12 | 13 | #define OAPI_STATIC 14 | #include "GraphicsAPI.h" 15 | #include "TextureBlitter.h" 16 | #include "TextureGroup.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | class OrbiterEntityFactory; 29 | class OrbiterModel; 30 | class OsgSketchpad; 31 | class OverlayPanelFactory; 32 | class SkyboltParticleStream; 33 | class VideoTab; 34 | 35 | namespace oapi { 36 | 37 | class SkyboltClient : public GraphicsClient 38 | { 39 | public: 40 | SkyboltClient (HINSTANCE hInstance); 41 | ~SkyboltClient() override; 42 | 43 | bool clbkInitialise () override; 44 | 45 | void clbkRefreshVideoData() override; 46 | 47 | SURFHANDLE clbkLoadTexture (const char *fname, DWORD flags = 0) override; 48 | 49 | SURFHANDLE clbkLoadSurface (const char *fname, DWORD attrib, bool bPath = false) override; 50 | 51 | bool clbkSaveSurfaceToImage (SURFHANDLE surf, const char *fname, 52 | ImageFileFormat fmt, float quality=0.7f) override { return false; } 53 | 54 | void clbkReleaseTexture (SURFHANDLE hTex) override; 55 | 56 | bool clbkSetMeshTexture (DEVMESHHANDLE hMesh, DWORD texidx, SURFHANDLE tex) override { return false; } 57 | 58 | int clbkSetMeshMaterial (DEVMESHHANDLE hMesh, DWORD matidx, const MATERIAL *mat) override { return 2; } 59 | 60 | int clbkMeshMaterial (DEVMESHHANDLE hMesh, DWORD matidx, MATERIAL *mat) override { return 2; } 61 | 62 | bool clbkSetMeshProperty (DEVMESHHANDLE hMesh, DWORD property, DWORD value) override { return false; } 63 | 64 | int clbkVisEvent (OBJHANDLE hObj, VISHANDLE vis, DWORD msg, DWORD_PTR context) override; 65 | 66 | //! @return type is actually DEVMESHHANDLE since we are a graphics client. MESHHANDLE is a hangover from inline graphics. 67 | //! @idx is the mesh group index. 68 | MESHHANDLE clbkGetMesh(VISHANDLE vis, UINT idx) override; 69 | 70 | int clbkGetMeshGroup (DEVMESHHANDLE hMesh, DWORD grpidx, GROUPREQUESTSPEC *grs) override; 71 | 72 | int clbkEditMeshGroup (DEVMESHHANDLE hMesh, DWORD grpidx, GROUPEDITSPEC *ges) override; 73 | 74 | void clbkPreOpenPopup () override {} 75 | 76 | bool clbkFilterElevation(OBJHANDLE hPlanet, int ilat, int ilng, int lvl, double elev_res, INT16* elev) override { return false; } 77 | 78 | ParticleStream *clbkCreateParticleStream (PARTICLESTREAMSPEC *pss) override; 79 | 80 | ParticleStream *clbkCreateExhaustStream (PARTICLESTREAMSPEC *pss, 81 | OBJHANDLE hVessel, const double *lvl, const VECTOR3 *ref, const VECTOR3 *dir) override; 82 | 83 | ParticleStream *clbkCreateExhaustStream (PARTICLESTREAMSPEC *pss, 84 | OBJHANDLE hVessel, const double *lvl, const VECTOR3 &ref, const VECTOR3 &dir) override; 85 | 86 | ParticleStream *clbkCreateReentryStream (PARTICLESTREAMSPEC *pss, 87 | OBJHANDLE hVessel) override; 88 | 89 | ScreenAnnotation *clbkCreateAnnotation () override; 90 | 91 | LRESULT RenderWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 92 | 93 | INT_PTR LaunchpadVideoWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 94 | 95 | bool clbkFullscreenMode () const override; 96 | 97 | void clbkGetViewportSize (DWORD *width, DWORD *height) const override; 98 | 99 | bool clbkGetRenderParam (DWORD prm, DWORD *value) const override; 100 | 101 | void clbkRender2DPanel (SURFHANDLE *hSurf, MESHHANDLE hMesh, MATRIX3 *T, bool additive = false) override; 102 | 103 | void clbkRender2DPanel (SURFHANDLE *hSurf, MESHHANDLE hMesh, MATRIX3 *T, float alpha, bool additive = false) override; 104 | 105 | SURFHANDLE clbkCreateSurfaceEx(DWORD w, DWORD h, DWORD attrib) override; 106 | 107 | SURFHANDLE clbkCreateSurface(DWORD w, DWORD h, SURFHANDLE hTemplate = NULL) override; 108 | 109 | SURFHANDLE clbkCreateTexture (DWORD w, DWORD h) override { return NULL; } 110 | 111 | SURFHANDLE clbkCreateSurface (HBITMAP hBmp) override; 112 | 113 | void clbkIncrSurfaceRef (SURFHANDLE surf) override {} 114 | 115 | bool clbkReleaseSurface (SURFHANDLE surf) override { return false; } 116 | 117 | bool clbkGetSurfaceSize (SURFHANDLE surf, DWORD *w, DWORD *h) override { *w = *h = 0; return false; } 118 | 119 | bool clbkSetSurfaceColourKey (SURFHANDLE surf, DWORD ckey) override { return false; } 120 | 121 | DWORD clbkGetDeviceColour (BYTE r, BYTE g, BYTE b) override { return ((DWORD)r << 16) + ((DWORD)g << 8) + (DWORD)b; } 122 | 123 | bool clbkBlt(SURFHANDLE tgt, DWORD tgtx, DWORD tgty, SURFHANDLE src, DWORD flag = 0) const override; 124 | 125 | bool clbkBlt(SURFHANDLE tgt, DWORD tgtx, DWORD tgty, SURFHANDLE src, DWORD srcx, DWORD srcy, DWORD w, DWORD h, DWORD flag = 0) const override; 126 | 127 | bool clbkScaleBlt(SURFHANDLE tgt, DWORD tgtx, DWORD tgty, DWORD tgtw, DWORD tgth, 128 | SURFHANDLE src, DWORD srcx, DWORD srcy, DWORD srcw, DWORD srch, DWORD flag = 0) const override; 129 | 130 | int clbkBeginBltGroup (SURFHANDLE tgt) override; 131 | 132 | int clbkEndBltGroup () override; 133 | 134 | bool clbkFillSurface(SURFHANDLE surf, DWORD col) const override; 135 | 136 | bool clbkFillSurface(SURFHANDLE surf, DWORD tgtx, DWORD tgty, DWORD w, DWORD h, DWORD col) const override; 137 | 138 | bool clbkCopyBitmap (SURFHANDLE pdds, HBITMAP hbm, int x, int y, int dx, int dy) override; 139 | 140 | Sketchpad *clbkGetSketchpad(SURFHANDLE surf) override; 141 | 142 | void clbkReleaseSketchpad (Sketchpad *sp) override {} 143 | 144 | Font *clbkCreateFont(int height, bool prop, const char *face, FontStyle style = FontStyle::FONT_NORMAL, int orientation = 0) const override; 145 | 146 | void clbkReleaseFont(Font *font) const override; 147 | 148 | Pen *clbkCreatePen(int style, int width, DWORD col) const override; 149 | 150 | void clbkReleasePen(Pen *pen) const override; 151 | 152 | Brush *clbkCreateBrush(DWORD col) const override; 153 | 154 | void clbkReleaseBrush(Brush *brush) const override; 155 | 156 | HDC clbkGetSurfaceDC (SURFHANDLE surf) override { return NULL; } 157 | 158 | void clbkReleaseSurfaceDC (SURFHANDLE surf, HDC hDC) override {} 159 | 160 | bool clbkUseLaunchpadVideoTab () const override { return true; } 161 | 162 | HWND clbkCreateRenderWindow() override; 163 | 164 | void clbkPostCreation () override {} 165 | 166 | void clbkCloseSession (bool fastclose) override {} 167 | 168 | void clbkDestroyRenderWindow (bool fastclose) override; 169 | 170 | void clbkUpdate (bool running) override {} 171 | 172 | void clbkRenderScene () override; 173 | 174 | bool clbkDisplayFrame () override { return false; } 175 | 176 | bool clbkSplashLoadMsg (const char *msg, int line) override { return false; } 177 | 178 | void clbkStoreMeshPersistent(MESHHANDLE hMesh, const char *fname) override {} 179 | 180 | private: 181 | void updateVirtualCockpitTextures(OrbiterModel& model) const; 182 | void updateEntity(OBJHANDLE object, skybolt::sim::Entity& entity) const; 183 | void translateEntities(); 184 | SURFHANDLE getSurfaceHandleFromTextureId(MESHHANDLE mesh, int id) const; 185 | 186 | private: 187 | std::unique_ptr mEngineRoot; 188 | std::unique_ptr mEntityFactory; 189 | std::unique_ptr mOverlayPanelFactory; 190 | std::unique_ptr mWindow; 191 | skybolt::sim::EntityPtr mSimCamera; 192 | std::unique_ptr mVideoTab; 193 | std::shared_ptr m_nanoVgContext; 194 | 195 | osg::ref_ptr mPanelGroup; 196 | std::map mEntities; 197 | std::map mTextures; 198 | std::map> mSketchpads; 199 | std::set mParticleStreams; 200 | osg::ref_ptr mTextureBlitter; 201 | 202 | mutable std::map> mPens; 203 | mutable std::map> mBrushes; 204 | mutable std::map> mFonts; 205 | 206 | HDC mGldc = nullptr; 207 | 208 | }; // SkyboltClient 209 | 210 | }; // namespace oapi 211 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ModelFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include "ModelFactory.h" 12 | #include "ObjectUtil.h" 13 | #include "OrbiterModel.h" 14 | #include "OrbiterTextureIds.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | using namespace oapi; 30 | using namespace skybolt; 31 | 32 | ModelFactory::ModelFactory(const ModelFactoryConfig& config) : 33 | mSurfaceHandleFromTextureIdProvider(std::move(config.surfaceHandleFromTextureIdProvider)), 34 | mTextureProvider(std::move(config.textureProvider)), 35 | mProgram(config.program) 36 | { 37 | } 38 | 39 | std::unique_ptr ModelFactory::createModel(MESHHANDLE hMesh, OBJHANDLE handle, int meshId, int meshVisibilityCategoryFlags) const 40 | { 41 | auto result = getOrCreateMesh(hMesh); 42 | OrbiterModelConfig config; 43 | config.node = result.node; 44 | config.owningObject = handle; 45 | config.meshId = meshId; 46 | config.meshVisibilityCategoryFlags = meshVisibilityCategoryFlags; 47 | config.meshGroupData = result.meshGroupData; 48 | return std::make_unique(config); 49 | } 50 | 51 | static bool validateIndices(const MESHGROUP& data) 52 | { 53 | for (int i = 0; i < (int)data.nIdx; ++i) 54 | { 55 | if (data.Idx[i] >= data.nVtx) 56 | { 57 | return false; 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | osg::ref_ptr ModelFactory::createGeometry(const MESHGROUP& data) 64 | { 65 | assert(data.nVtx > 0); 66 | assert(data.nIdx > 0); 67 | 68 | osg::Geometry* geometry = new osg::Geometry(); 69 | 70 | osg::Vec3Array* vertices = new osg::Vec3Array(data.nVtx); 71 | osg::Vec3Array* normals = new osg::Vec3Array(data.nVtx); 72 | osg::Vec2Array* uvs = new osg::Vec2Array(data.nVtx); 73 | osg::ref_ptr indexBuffer = new osg::UIntArray(data.nIdx); 74 | 75 | osg::BoundingBox boundingBox; 76 | 77 | for (int i = 0; i < (int)data.nVtx; ++i) 78 | { 79 | const auto& v = data.Vtx[i]; 80 | // Note swap of coordinates from left-handed to right-handed 81 | osg::Vec3f pos = orbiterToSkyboltVector3BodyAxes(&v.x); 82 | boundingBox.expandBy(pos); 83 | 84 | (*vertices)[i] = pos; 85 | (*normals)[i] = orbiterToSkyboltVector3BodyAxes(&v.nx); 86 | (*uvs)[i] = osg::Vec2f(v.tu, v.tv); 87 | } 88 | 89 | for (int i = 0; i < (int)data.nIdx; i += 3) 90 | { 91 | // Note swap of 2nd and 3rd index to change winding from left-handed to right-handed 92 | (*indexBuffer)[i] = std::clamp((int)data.Idx[i], 0, (int)data.nVtx-1); 93 | (*indexBuffer)[i + 1] = std::clamp((int)data.Idx[i + 2], 0, (int)data.nVtx - 1); 94 | (*indexBuffer)[i + 2] = std::clamp((int)data.Idx[i + 1], 0, (int)data.nVtx - 1); 95 | } 96 | 97 | geometry->setVertexArray(vertices); 98 | geometry->setNormalArray(normals, osg::Array::Binding::BIND_PER_VERTEX); 99 | geometry->setTexCoordArray(0, uvs); 100 | geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, indexBuffer->size(), (GLuint*)indexBuffer->getDataPointer())); 101 | vis::configureDrawable(*geometry); 102 | 103 | geometry->setComputeBoundingBoxCallback(vis::createFixedBoundingBoxCallback(boundingBox)); 104 | 105 | return geometry; 106 | } 107 | 108 | ModelFactory::CreateMeshResult ModelFactory::getOrCreateMesh(MESHHANDLE mesh) const 109 | { 110 | auto i = mMeshCache.find(mesh); 111 | if (i != mMeshCache.end()) 112 | { 113 | return i->second; 114 | } 115 | else 116 | { 117 | osg::Geode* geode = new osg::Geode(); 118 | 119 | DWORD nGrp = oapiMeshGroupCount(mesh); 120 | 121 | ModelFactory::CreateMeshResult result; 122 | result.node = geode; 123 | result.meshGroupData.resize(nGrp); 124 | 125 | for (DWORD i = 0; i < nGrp; i++) 126 | { 127 | MESHGROUP* group = oapiMeshGroup(mesh, i); 128 | if (group->nVtx > 0 && group->nIdx > 0) 129 | { 130 | MeshGroupData data; 131 | data.osgGeometryIndex = geode->getNumDrawables(); 132 | data.orbiterMaterialIndex = group->MtrlIdx; 133 | data.orbiterTextureIndex = group->TexIdx; 134 | data.orbiterUserFlags = group->UsrFlag; 135 | result.meshGroupData[i] = data; 136 | 137 | auto geometry = createGeometry(*group); 138 | 139 | prepareGeometryStateSet(*geometry, mesh, *group); 140 | geode->addDrawable(geometry); 141 | } 142 | } 143 | 144 | geode->getOrCreateStateSet()->setAttribute(mProgram); 145 | 146 | mMeshCache[mesh] = result; 147 | return result; 148 | } 149 | } 150 | 151 | static osg::Vec4f toOsgVec4f(const COLOUR4& c) 152 | { 153 | return reinterpret_cast(c); 154 | } 155 | 156 | void ModelFactory::prepareGeometryStateSet(osg::Geometry& geometry, MESHHANDLE mesh, const MESHGROUP& group) const 157 | { 158 | if (group.TexIdx == SPEC_INHERIT) 159 | { 160 | return; 161 | } 162 | 163 | osg::StateSet& stateSet = *geometry.getOrCreateStateSet(); 164 | float specularity = 0.04; 165 | stateSet.addUniform(new osg::Uniform("specularity", osg::Vec3f(specularity, specularity, specularity))); 166 | stateSet.addUniform(new osg::Uniform("roughness", 0.5f)); 167 | stateSet.setDefine("ENABLE_SPECULAR"); 168 | 169 | if (group.TexIdx < TEXIDX_MFD0 || group.TexIdx == SPEC_DEFAULT) // not an MFD 170 | { 171 | std::optional textureGroup; 172 | if (group.TexIdx != SPEC_DEFAULT) 173 | { 174 | SURFHANDLE handle = mSurfaceHandleFromTextureIdProvider(mesh, group.TexIdx); 175 | textureGroup = mTextureProvider(handle); 176 | } 177 | 178 | if (textureGroup) 179 | { 180 | int unit = 0; 181 | stateSet.setTextureAttributeAndModes(unit, textureGroup->albedo); 182 | stateSet.addUniform(vis::createUniformSampler2d("albedoSampler", unit++)); 183 | 184 | if (textureGroup->normal) 185 | { 186 | stateSet.setTextureAttributeAndModes(unit, textureGroup->normal); 187 | stateSet.addUniform(vis::createUniformSampler2d("normalSampler", unit++)); 188 | stateSet.setDefine("ENABLE_NORMAL_MAP"); 189 | 190 | osg::ref_ptr tsg = new osgUtil::TangentSpaceGenerator(); 191 | tsg->generate(&geometry, 0); 192 | geometry.setNormalArray(tsg->getNormalArray(), osg::Array::Binding::BIND_PER_VERTEX); 193 | geometry.setTexCoordArray(1, tsg->getTangentArray()); 194 | } 195 | 196 | if (textureGroup->specular) 197 | { 198 | stateSet.setTextureAttributeAndModes(unit, textureGroup->specular); 199 | stateSet.addUniform(vis::createUniformSampler2d("specularSampler", unit++)); 200 | stateSet.setDefine("ENABLE_SPECULAR_MAP"); 201 | } 202 | 203 | // All textured models in orbiter are rendered with alpha blending. They should be drawn in creation order, not transparent sorted. 204 | // TODO: See if we can improve performance by disabling blending on models that don't need it. Unfortunatly orbiter doesn't 205 | // seem to provide this information. 206 | stateSet.setAttributeAndModes(new osg::BlendEquation(osg::BlendEquation::FUNC_ADD, osg::BlendEquation::FUNC_ADD)); 207 | stateSet.setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA)); 208 | } 209 | else 210 | { 211 | stateSet.setDefine("UNIFORM_ALBEDO"); 212 | 213 | MATERIAL* material = oapiMeshMaterial(mesh, group.MtrlIdx); 214 | osg::Vec4 albedo = material ? vis::srgbToLinear(toOsgVec4f((material->diffuse))) : osg::Vec4(0, 0, 0, 1); 215 | 216 | stateSet.addUniform(new osg::Uniform("albedoColor", albedo)); 217 | 218 | if (albedo.a() < 0.9999f) 219 | { 220 | vis::makeStateSetTransparent(stateSet, vis::TransparencyMode::Classic); 221 | } 222 | } 223 | } 224 | else // MFD 225 | { 226 | // MFD texture will be set later 227 | stateSet.addUniform(vis::createUniformSampler2d("albedoSampler", 0)); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OrbiterModel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include "OrbiterModel.h" 12 | #include "ObjectUtil.h" 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace skybolt; 21 | 22 | struct AlwyasCullCallback : public osg::DrawableCullCallback 23 | { 24 | bool cull(osg::NodeVisitor* nv, osg::Drawable* drawable, osg::RenderInfo* renderInfo) const override 25 | { 26 | return true; 27 | } 28 | }; 29 | 30 | static void applyOrbiterUserFlags(osg::Drawable& drawable, int flags) 31 | { 32 | if (flags & MeshGroupData::userFlagSkip) 33 | { 34 | drawable.setCullCallback(new AlwyasCullCallback()); 35 | } 36 | else 37 | { 38 | drawable.setCullCallback(nullptr); 39 | } 40 | } 41 | 42 | OrbiterModel::OrbiterModel(const OrbiterModelConfig& config) : 43 | Model(config), 44 | mOwningObject(config.owningObject), 45 | mMeshId(config.meshId), 46 | mMeshVisibilityCategoryFlags(config.meshVisibilityCategoryFlags), 47 | mMeshGroupData(config.meshGroupData) 48 | { 49 | for (const auto& data : mMeshGroupData) 50 | { 51 | osg::Geometry* geometry = getDrawable(*data)->asGeometry(); 52 | if (geometry) 53 | { 54 | applyOrbiterUserFlags(*geometry, data->orbiterUserFlags); 55 | } 56 | } 57 | } 58 | 59 | bool OrbiterModel::getMeshGroupData(int groupId, GROUPREQUESTSPEC& grs) 60 | { 61 | std::optional data = getMeshGroupData(groupId); 62 | if (data) 63 | { 64 | osg::Geometry* geometry = getDrawable(*data)->asGeometry(); 65 | if (geometry) 66 | { 67 | if (grs.Vtx) 68 | { 69 | auto vertices = reinterpret_cast(geometry->getVertexArray()->getDataPointer()); 70 | auto normals = reinterpret_cast(geometry->getNormalArray()->getDataPointer()); 71 | auto uvs = reinterpret_cast(geometry->getTexCoordArrayList().front()->getDataPointer()); 72 | 73 | for (DWORD index = 0; index < grs.nVtx; ++index) 74 | { 75 | int i = grs.VtxPerm ? grs.VtxPerm[index] : index; 76 | osg::Vec3f orbiterVertexPos = skyboltToOrbiterVector3BodyAxes(vertices[i]); 77 | osg::Vec3f orbiterNormal = skyboltToOrbiterVector3BodyAxes(normals[i]); 78 | 79 | NTVERTEX& dst = grs.Vtx[index]; 80 | dst.x = orbiterVertexPos.x(); 81 | dst.y = orbiterVertexPos.y(); 82 | dst.z = orbiterVertexPos.z(); 83 | dst.nx = orbiterNormal.x(); 84 | dst.ny = orbiterNormal.y(); 85 | dst.nz = orbiterNormal.z(); 86 | dst.tu = uvs[i].x(); 87 | dst.tv = uvs[i].y(); 88 | } 89 | } 90 | 91 | if (grs.Idx) 92 | { 93 | osg::Geometry::DrawElementsList elementsList; 94 | geometry->getDrawElementsList(elementsList); 95 | osg::DrawElements* elements = elementsList.front(); 96 | 97 | grs.nIdx = elements->getNumIndices(); 98 | { 99 | auto indices = reinterpret_cast(elements->getDataPointer()); 100 | 101 | for (DWORD index = 0; index < grs.nIdx; ++index) 102 | { 103 | int i = grs.VtxPerm ? grs.IdxPerm[index] : index; 104 | grs.Idx[index] = indices[i]; 105 | } 106 | } 107 | } 108 | 109 | grs.MtrlIdx = data->orbiterMaterialIndex; 110 | grs.TexIdx = data->orbiterTextureIndex; 111 | grs.IdxPerm = 0; 112 | grs.VtxPerm = 0; 113 | return true; 114 | } 115 | } 116 | return false; 117 | } 118 | 119 | bool OrbiterModel::setMeshGroupData(int groupId, GROUPEDITSPEC& ges) 120 | { 121 | osg::Drawable* drawable = getDrawableForGroupId(groupId); 122 | if (drawable) 123 | { 124 | osg::Geometry* geometry = drawable->asGeometry(); 125 | if (geometry) 126 | { 127 | DWORD flags = ges.flags; 128 | 129 | if (flags & (GRPEDIT_SETUSERFLAG | GRPEDIT_ADDUSERFLAG | GRPEDIT_DELUSERFLAG)) 130 | { 131 | int& userFlags = mMeshGroupData[groupId]->orbiterUserFlags; 132 | if (flags & GRPEDIT_SETUSERFLAG) userFlags = ges.UsrFlag; 133 | else if (flags & GRPEDIT_ADDUSERFLAG) userFlags |= ges.UsrFlag; 134 | else if (flags & GRPEDIT_DELUSERFLAG) userFlags &= ~ges.UsrFlag; 135 | 136 | applyOrbiterUserFlags(*geometry, userFlags); 137 | } 138 | 139 | if (flags & GRPEDIT_VTXMOD) 140 | { 141 | geometry->setDataVariance(osg::Object::DYNAMIC); 142 | 143 | auto& vertices = *reinterpret_cast(geometry->getVertexArray()); 144 | auto& normals = *reinterpret_cast(geometry->getNormalArray()); 145 | auto& uvs = *reinterpret_cast(geometry->getTexCoordArrayList().front().get()); 146 | 147 | for (DWORD index = 0; index < ges.nVtx; ++index) 148 | { 149 | const NTVERTEX& v = ges.Vtx[index]; 150 | int i = ges.vIdx ? ges.vIdx[index] : index; 151 | 152 | osg::Vec3f vertexPos = orbiterToSkyboltVector3BodyAxes(&v.x); 153 | osg::Vec3f normalPos = orbiterToSkyboltVector3BodyAxes(&v.nx); 154 | 155 | if (flags & GRPEDIT_VTXCRDX) vertices[i].x() = vertexPos.x(); 156 | else if (flags & GRPEDIT_VTXCRDADDX) vertices[i].x() += vertexPos.x(); 157 | if (flags & GRPEDIT_VTXCRDY) vertices[i].y() = vertexPos.y(); 158 | else if (flags & GRPEDIT_VTXCRDADDY) vertices[i].y() += vertexPos.y(); 159 | if (flags & GRPEDIT_VTXCRDZ) vertices[i].z() = vertexPos.z(); 160 | else if (flags & GRPEDIT_VTXCRDADDZ) vertices[i].z() += vertexPos.z(); 161 | if (flags & GRPEDIT_VTXNMLX) normals[i].x() = normalPos.x(); 162 | else if (flags & GRPEDIT_VTXNMLADDX) normals[i].x() += normalPos.x(); 163 | if (flags & GRPEDIT_VTXNMLY) normals[i].y() = normalPos.y(); 164 | else if (flags & GRPEDIT_VTXNMLADDY) normals[i].y() += normalPos.y(); 165 | if (flags & GRPEDIT_VTXNMLZ) normals[i].z() = normalPos.z(); 166 | else if (flags & GRPEDIT_VTXNMLADDZ) normals[i].z() += normalPos.z(); 167 | if (flags & GRPEDIT_VTXTEXU) uvs[i].x() = v.tu; 168 | else if (flags & GRPEDIT_VTXTEXADDU) uvs[i].x() += v.tu; 169 | if (flags & GRPEDIT_VTXTEXV) uvs[i].y() = v.tv; 170 | else if (flags & GRPEDIT_VTXTEXADDV) uvs[i].y() += v.tv; 171 | } 172 | 173 | if (ges.flags & GRPEDIT_VTXCRD) 174 | { 175 | vertices.dirty(); 176 | } 177 | 178 | if (ges.flags & GRPEDIT_VTXNML) 179 | { 180 | normals.dirty(); 181 | } 182 | 183 | if (ges.flags & GRPEDIT_VTXTEX) 184 | { 185 | uvs.dirty(); 186 | } 187 | } 188 | return true; 189 | } 190 | } 191 | return false; 192 | } 193 | 194 | void OrbiterModel::setMeshTexture(int groupId, const osg::ref_ptr& texture) 195 | { 196 | osg::Drawable* drawable = getDrawableForGroupId(groupId); 197 | if (drawable) 198 | { 199 | drawable->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture); 200 | } 201 | } 202 | 203 | void OrbiterModel::useMeshAsMfd(int groupId, const osg::ref_ptr& program, bool alphaBlend) 204 | { 205 | if (mMfdGroupIds.find(groupId) == mMfdGroupIds.end()) 206 | { 207 | std::optional groupData = getMeshGroupData(groupId); 208 | if (groupData) 209 | { 210 | osg::Drawable* drawable = getDrawable(*groupData); 211 | if (drawable) 212 | { 213 | osg::ref_ptr stateSet = new osg::StateSet(); 214 | stateSet->setAttribute(program, osg::StateAttribute::ON); 215 | stateSet->setDefine("FLIP_V"); 216 | stateSet->addUniform(vis::createUniformSampler2d("albedoSampler", 0)); 217 | if (alphaBlend) 218 | { 219 | vis::makeStateSetTransparent(*stateSet, vis::TransparencyMode::Classic); 220 | } 221 | else 222 | { 223 | stateSet->setDefine("OUTPUT_PREMULTIPLIED_ALPHA"); 224 | } 225 | drawable->setStateSet(stateSet); 226 | 227 | mMfdGroupIds.insert(groupId); 228 | 229 | // FIXME: Hack to make HUD visible. For some reason orbiter sets it to be invisible. 230 | { 231 | groupData->orbiterUserFlags &= ~MeshGroupData::userFlagSkip; 232 | applyOrbiterUserFlags(*drawable, groupData->orbiterUserFlags); 233 | } 234 | } 235 | } 236 | } 237 | } 238 | 239 | std::optional OrbiterModel::getMeshGroupData(int groupId) const 240 | { 241 | if (groupId >= 0 && groupId < int(mMeshGroupData.size())) 242 | { 243 | return mMeshGroupData[groupId]; 244 | } 245 | return std::nullopt; 246 | } 247 | 248 | osg::Drawable* OrbiterModel::getDrawable(const MeshGroupData& data) const 249 | { 250 | osg::Geode* geode = mNode->asGeode(); 251 | if (geode) 252 | { 253 | return geode->getDrawable(data.osgGeometryIndex); 254 | } 255 | return nullptr; 256 | } 257 | 258 | osg::Drawable* OrbiterModel::getDrawableForGroupId(int groupId) const 259 | { 260 | std::optional data = getMeshGroupData(groupId); 261 | if (data) 262 | { 263 | return getDrawable(*data); 264 | } 265 | return nullptr; 266 | } -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OrbiterEntityFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include "OrbiterEntityFactory.h" 15 | 16 | #include "DistantCelestialBodyFactory.h" 17 | #include "Exhaust.h" 18 | #include "ModelFactory.h" 19 | #include "OrbiterModel.h" 20 | #include "ObjectUtil.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace oapi; 35 | using namespace skybolt; 36 | 37 | OrbiterEntityFactory::OrbiterEntityFactory(const OrbiterEntityFactoryConfig& config) : 38 | mEntityFactory(config.entityFactory), 39 | mScene(config.scene), 40 | mModelFactory(config.modelFactory), 41 | mGraphicsClient(config.graphicsClient), 42 | mShaderPrograms(config.shaderPrograms), 43 | mTextureProvider(config.textureProvider) 44 | { 45 | assert(mEntityFactory); 46 | assert(mScene); 47 | assert(mModelFactory); 48 | assert(mGraphicsClient); 49 | assert(mShaderPrograms); 50 | assert(mTextureProvider); 51 | } 52 | 53 | OrbiterEntityFactory::~OrbiterEntityFactory() = default; 54 | 55 | sim::EntityPtr OrbiterEntityFactory::createEntity(OBJHANDLE object) const 56 | { 57 | switch (oapiGetObjectType(object)) 58 | { 59 | case OBJTP_VESSEL: 60 | return createVessel(object, oapiGetVesselInterface(object)); 61 | case OBJTP_PLANET: 62 | return createPlanet(object); 63 | case OBJTP_STAR: 64 | return createStar(object); 65 | case OBJTP_SURFBASE: 66 | return createBase(object); 67 | default: 68 | return nullptr; 69 | } 70 | } 71 | 72 | osg::Vec3d orbiterVector3ToOsg(const VECTOR3& v) 73 | { 74 | return osg::Vec3d(v.z, v.x, -v.y); 75 | } 76 | 77 | sim::EntityPtr OrbiterEntityFactory::createVessel(OBJHANDLE object, VESSEL* vessel) const 78 | { 79 | sim::EntityPtr entity = std::make_shared(); 80 | 81 | SimVisBindingsComponentPtr simVisBindingComponent(new SimVisBindingsComponent); 82 | entity->addComponent(simVisBindingComponent); 83 | 84 | VisObjectsComponentPtr visObjectsComponent(new VisObjectsComponent(mScene.get())); 85 | entity->addComponent(visObjectsComponent); 86 | 87 | entity->addComponent(std::make_shared()); 88 | 89 | int nmesh = (int)vessel->GetMeshCount(); 90 | 91 | for (int i = 0; i < nmesh; ++i) 92 | { 93 | if (auto hMesh = vessel->GetMeshTemplate(i); hMesh) 94 | { 95 | int visFlags = (int)vessel->GetMeshVisibilityMode(i); 96 | if (visFlags != MESHVIS_NEVER) 97 | { 98 | // Create model 99 | { 100 | VECTOR3 offset; 101 | vessel->GetMeshOffset(i, offset); 102 | 103 | vis::ModelPtr model = mModelFactory->createModel(hMesh, object, i, visFlags); 104 | visObjectsComponent->addObject(model); 105 | 106 | SimVisBindingPtr simVis(new SimpleSimVisBinding(entity.get(), model, 107 | orbiterVector3ToOsg(offset), 108 | osg::Quat() 109 | )); 110 | simVisBindingComponent->bindings.push_back(simVis); 111 | } 112 | 113 | // Create exhausts 114 | { 115 | vis::BeamsConfig beamsConfig; 116 | beamsConfig.program = mShaderPrograms->getRequiredProgram("beams"); 117 | beamsConfig.geometricParams.basePartBounds = vis::Box2f(osg::Vec2f(0.50390625f, 0.00390625f), osg::Vec2f(0.99609375f, 0.49609375f)); 118 | beamsConfig.geometricParams.extrusionPartBounds = vis::Box2f(osg::Vec2f(0.01f, 0), osg::Vec2f(0.24f, 1)); 119 | beamsConfig.geometricParams.extrusionOffsetFraction = -0.025f; 120 | beamsConfig.geometricParams.baseRadiusMultiplier = 1.5; 121 | auto beams = std::make_shared(beamsConfig); 122 | visObjectsComponent->addObject(beams); 123 | 124 | auto exhaust = std::make_shared(vessel, entity.get(), beams, mTextureProvider); 125 | simVisBindingComponent->bindings.push_back(exhaust); 126 | } 127 | } 128 | } 129 | } 130 | 131 | return entity; 132 | } 133 | 134 | extern Orbiter *g_pOrbiter; 135 | 136 | sim::EntityPtr OrbiterEntityFactory::createPlanet(OBJHANDLE object) const 137 | { 138 | std::string name = getName(object); 139 | 140 | double radius = oapiGetSize(object); 141 | 142 | char cbuf[256]; 143 | mGraphicsClient->PlanetTexturePath(name.c_str(), cbuf); 144 | std::string planetTexturePath = cbuf; 145 | 146 | nlohmann::json planetJson = { 147 | {"radius", radius}, 148 | {"ocean", false}, 149 | {"surface", { 150 | {"elevation", { 151 | {"format", "orbiterElevation"}, 152 | {"url", planetTexturePath}, 153 | {"maxLevel", 13}, // TODO: determine correct maximum for tile source used 154 | {"heightMapTexelsOnTileEdge", true} 155 | }}, 156 | {"albedo", { 157 | {"format", "orbiterImage"}, 158 | {"url", planetTexturePath}, 159 | {"layerType", "albedo"}, 160 | {"maxLevel", 13} 161 | }}, 162 | {"uniformDetail", { 163 | {"texture", "Environment/Ground/Ground026_1K_Color.jpg"} 164 | }}, 165 | }} 166 | }; 167 | 168 | if (oapiPlanetHasAtmosphere(object)) 169 | { 170 | // TODO: Map constants to our scattering model for planets other than Earth. 171 | // Earth should always use the most accurate parameters from Bruenton's model. 172 | //const ATMCONST* constants = oapiGetPlanetAtmConstants(object); 173 | 174 | if (name == "Earth") 175 | { 176 | planetJson["atmosphere"] = { 177 | {"earthReyleighScatteringCoefficient", 1.24062e-6}, 178 | {"rayleighScaleHeight", 8000.0}, 179 | {"mieScaleHeight", 1200.0}, 180 | {"mieAngstromAlpha", 0.0}, 181 | {"mieAngstromBeta", 5.328e-3}, 182 | {"mieSingleScatteringAlbedo", 0.9}, 183 | {"miePhaseFunctionG", 0.8}, 184 | {"useEarthOzone", true} 185 | }; 186 | 187 | planetJson["ocean"] = true; 188 | 189 | planetJson["clouds"] = { 190 | {"map", "Environment/Cloud/cloud_combined_8192.png"} 191 | }; 192 | 193 | planetJson["surface"]["landMask"] = { 194 | {"format", "orbiterImage"}, 195 | {"url", planetTexturePath}, 196 | {"layerType", "landMask"}, 197 | {"maxLevel", 13} 198 | }; 199 | } 200 | else if (name == "Mars") 201 | { 202 | planetJson["atmosphere"] = { 203 | {"reyleighScatteringCoefficientTable", { 204 | {"coefficients", {5.8e-6, 5.8e-6, 20.0e-6}}, 205 | {"wavelengthsNm", {440, 510, 680}}, 206 | }}, 207 | {"rayleighScaleHeight", 11000.0}, 208 | {"mieScaleHeight", 1600.0}, 209 | {"mieAngstromAlpha", 0.0}, 210 | {"mieAngstromBeta", 5.328e-3}, 211 | {"mieSingleScatteringAlbedo", 0.9}, 212 | {"miePhaseFunctionG", 0.8}, 213 | {"useEarthOzone", false}, 214 | {"bottomRadius", radius - 4000}, 215 | {"topRadius", radius + 75000}, 216 | }; 217 | } 218 | } 219 | 220 | nlohmann::json j = { 221 | {"components", {{ 222 | {"planet", planetJson} 223 | }}} 224 | }; 225 | 226 | sim::EntityPtr entity = mEntityFactory->createEntityFromJson(j, name, math::dvec3Zero(), math::dquatIdentity()); 227 | vis::Planet* planet = getFirstVisObject(*entity).get(); 228 | if (planet->getWaterMaterial()) 229 | { 230 | planet->getWaterMaterial()->setWaveHeight(10); 231 | } 232 | return entity; 233 | } 234 | 235 | sim::EntityPtr OrbiterEntityFactory::createBase(OBJHANDLE object) const 236 | { 237 | sim::EntityPtr entity = std::make_shared(); 238 | 239 | SimVisBindingsComponentPtr simVisBindingComponent(new SimVisBindingsComponent); 240 | entity->addComponent(simVisBindingComponent); 241 | 242 | VisObjectsComponentPtr visObjectsComponent(new VisObjectsComponent(mScene.get())); 243 | entity->addComponent(visObjectsComponent); 244 | 245 | entity->addComponent(std::make_shared()); 246 | 247 | MESHHANDLE *sbs, *sas; 248 | DWORD nsbs, nsas; 249 | mGraphicsClient->GetBaseStructures(object, &sbs, &nsbs, &sas, &nsas); 250 | 251 | for (int i = 0; i < (int)nsbs; i++) 252 | { 253 | MESHHANDLE mesh = sbs[i]; 254 | vis::ModelPtr model = mModelFactory->createModel(mesh, object, i, MESHVIS_EXTERNAL); 255 | visObjectsComponent->addObject(model); 256 | 257 | SimVisBindingPtr simVis(new SimpleSimVisBinding(entity.get(), model, 258 | osg::Vec3(), 259 | osg::Quat() 260 | )); 261 | simVisBindingComponent->bindings.push_back(simVis); 262 | } 263 | for (int i = 0; i < (int)nsas; i++) 264 | { 265 | MESHHANDLE mesh = sas[i]; 266 | vis::ModelPtr model = mModelFactory->createModel(mesh, object, i, MESHVIS_EXTERNAL); 267 | visObjectsComponent->addObject(model); 268 | 269 | SimVisBindingPtr simVis(new SimpleSimVisBinding(entity.get(), model, 270 | osg::Vec3(), 271 | osg::Quat() 272 | )); 273 | simVisBindingComponent->bindings.push_back(simVis); 274 | } 275 | 276 | return entity; 277 | } 278 | 279 | skybolt::sim::EntityPtr OrbiterEntityFactory::createStar(OBJHANDLE object) const 280 | { 281 | if (getName(object) == "Sun") 282 | { 283 | DistantCelestialBodyCreationArgs args; 284 | args.scene = mScene.get(); 285 | args.objectHandle = object; 286 | args.program = mShaderPrograms->getRequiredProgram("sun"); 287 | return createDistantCelestialBody(args); 288 | } 289 | return nullptr; 290 | } 291 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/VideoTab.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | */ 11 | 12 | #include "VideoTab.h" 13 | #include "SkyboltClient.h" 14 | 15 | #include 16 | 17 | using namespace oapi; 18 | 19 | VideoTab::VideoTab (SkyboltClient *gc, HINSTANCE _hInst, HINSTANCE _hOrbiterInst, HWND hVideoTab) 20 | { 21 | int width = GetSystemMetrics(SM_CXSCREEN); 22 | int height = GetSystemMetrics(SM_CYSCREEN); 23 | defaultDevice.ddsdFullscreenMode = {width, height}; 24 | defaultDevice.pddsdModes.push_back(defaultDevice.ddsdFullscreenMode); 25 | 26 | gclient = gc; 27 | hInst = _hInst; 28 | hOrbiterInst = _hOrbiterInst; 29 | hTab = hVideoTab; 30 | Initialise (&defaultDevice); 31 | } 32 | 33 | INT_PTR VideoTab::WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 34 | { 35 | switch (uMsg) { 36 | case WM_INITDIALOG: 37 | return TRUE; 38 | case WM_COMMAND: 39 | switch (LOWORD(wParam)) { 40 | case IDC_VID_DEVICE: 41 | if (HIWORD(wParam) == CBN_SELCHANGE) { 42 | DWORD idx = SendDlgItemMessage (hWnd, IDC_VID_DEVICE, CB_GETCURSEL, 0, 0); 43 | SkyboltDeviceInfo *dev = &defaultDevice; 44 | if (idx) { 45 | // gclient->SelectDevice (dev); // Skybolt does not support selecting video device 46 | SelectDevice (dev); 47 | } 48 | return TRUE; 49 | } 50 | break; 51 | case IDC_VID_MODE: 52 | if (HIWORD(wParam) == CBN_SELCHANGE) { 53 | DWORD idx; 54 | idx = SendDlgItemMessage (hWnd, IDC_VID_MODE, CB_GETCURSEL, 0, 0); 55 | SelectMode (&defaultDevice, idx); 56 | return TRUE; 57 | } 58 | break; 59 | case IDC_VID_PAGEFLIP: 60 | if (HIWORD(wParam) == BN_CLICKED) { 61 | SelectPageflip(); 62 | return TRUE; 63 | } 64 | break; 65 | case IDC_VID_FULL: 66 | if (HIWORD(wParam) == BN_CLICKED) { 67 | SelectDispmode (&defaultDevice, FALSE); 68 | return TRUE; 69 | } 70 | break; 71 | case IDC_VID_WINDOW: 72 | if (HIWORD(wParam) == BN_CLICKED) { 73 | SelectDispmode (&defaultDevice, TRUE); 74 | return TRUE; 75 | } 76 | break; 77 | case IDC_VID_WIDTH: 78 | if (HIWORD(wParam) == EN_CHANGE) { 79 | SelectWidth (); 80 | return TRUE; 81 | } 82 | break; 83 | case IDC_VID_HEIGHT: 84 | if (HIWORD(wParam) == EN_CHANGE) { 85 | SelectHeight (); 86 | return TRUE; 87 | } 88 | break; 89 | case IDC_VID_ASPECT: 90 | if (HIWORD(wParam) == BN_CLICKED) { 91 | SelectFixedAspect (); 92 | SelectWidth (); 93 | return TRUE; 94 | } 95 | break; 96 | case IDC_VID_4X3: 97 | case IDC_VID_16X10: 98 | case IDC_VID_16X9: 99 | if (HIWORD(wParam) == BN_CLICKED) { 100 | aspect_idx = LOWORD(wParam)-IDC_VID_4X3; 101 | SelectWidth (); 102 | return TRUE; 103 | } 104 | break; 105 | } 106 | break; 107 | } 108 | return FALSE; 109 | } 110 | 111 | void VideoTab::Initialise (SkyboltDeviceInfo *dev) 112 | { 113 | GraphicsClient::VIDEODATA *data = gclient->GetVideoData(); 114 | 115 | char cbuf[20]; 116 | DWORD i, ndev, idx; 117 | ndev = 1; 118 | const char* deviceName = "Default Device"; 119 | 120 | SendDlgItemMessage (hTab, IDC_VID_DEVICE, CB_RESETCONTENT, 0, 0); 121 | for (i = 0; i < ndev; i++) { 122 | SendMessage (GetDlgItem (hTab, IDC_VID_DEVICE), CB_ADDSTRING, 0, 123 | TEXT((LPARAM)deviceName)); 124 | } 125 | 126 | if (SendDlgItemMessage (hTab, IDC_VID_DEVICE, CB_SETCURSEL, data->deviceidx, 0) == CB_ERR) { 127 | if ((idx = SendDlgItemMessage (hTab, IDC_VID_DEVICE, CB_FINDSTRINGEXACT, -1, (LPARAM)deviceName)) == CB_ERR) 128 | idx = 0; 129 | SendDlgItemMessage (hTab, IDC_VID_DEVICE, CB_SETCURSEL, idx, 0); 130 | } 131 | SendDlgItemMessage (hTab, IDC_VID_ENUM, BM_SETCHECK, data->forceenum ? BST_CHECKED : BST_UNCHECKED, 0); 132 | SendDlgItemMessage (hTab, IDC_VID_STENCIL, BM_SETCHECK, data->trystencil ? BST_CHECKED : BST_UNCHECKED, 0); 133 | SendDlgItemMessage (hTab, IDC_VID_VSYNC, BM_SETCHECK, data->novsync ? BST_CHECKED : BST_UNCHECKED, 0); 134 | SendDlgItemMessage (hTab, IDC_VID_PAGEFLIP, BM_SETCHECK, data->pageflip ? BST_UNCHECKED : BST_CHECKED, 0); 135 | 136 | SetWindowText (GetDlgItem (hTab, IDC_VID_WIDTH), _itoa (data->winw, cbuf, 10)); 137 | SetWindowText (GetDlgItem (hTab, IDC_VID_HEIGHT), _itoa (data->winh, cbuf, 10)); 138 | 139 | if (data->winw == (4*data->winh)/3 || data->winh == (3*data->winw)/4) 140 | aspect_idx = 1; 141 | else if (data->winw == (16*data->winh)/10 || data->winh == (10*data->winw)/16) 142 | aspect_idx = 2; 143 | else if (data->winw == (16*data->winh)/9 || data->winh == (9*data->winw)/16) 144 | aspect_idx = 3; 145 | else 146 | aspect_idx = 0; 147 | SendDlgItemMessage (hTab, IDC_VID_ASPECT, BM_SETCHECK, aspect_idx ? BST_CHECKED : BST_UNCHECKED, 0); 148 | if (aspect_idx) aspect_idx--; 149 | SendDlgItemMessage (hTab, IDC_VID_4X3+aspect_idx, BM_SETCHECK, BST_CHECKED, 0); 150 | 151 | SelectDevice(dev); 152 | SendDlgItemMessage (hTab, data->fullscreen ? IDC_VID_FULL:IDC_VID_WINDOW, BM_CLICK, 0, 0); 153 | SelectDispmode (dev, data->fullscreen ? FALSE:TRUE); 154 | 155 | ShowWindow (GetDlgItem (hTab, IDC_VID_INFO), SW_HIDE); 156 | } 157 | 158 | void VideoTab::SelectDevice (SkyboltDeviceInfo *dev) 159 | { 160 | DWORD i, j; 161 | char cbuf[256]; 162 | SkyboltDeviceInfo::FullscreenMode &cmode = dev->ddsdFullscreenMode; 163 | DWORD nres = 0, *wres = new DWORD[dev->pddsdModes.size()], *hres = new DWORD[dev->pddsdModes.size()]; 164 | 165 | SendDlgItemMessage (hTab, IDC_VID_MODE, CB_RESETCONTENT, 0, 0); 166 | SendDlgItemMessage (hTab, IDC_VID_BPP, CB_RESETCONTENT, 0, 0); 167 | 168 | for (i = 0; i < dev->pddsdModes.size(); i++) { 169 | SkyboltDeviceInfo::FullscreenMode *ddsd = &dev->pddsdModes[i]; 170 | DWORD w = ddsd->dwWidth, h = ddsd->dwHeight; 171 | for (j = 0; j < nres; j++) if (wres[j] == w && hres[j] == h) break; 172 | if (j == nres) wres[nres] = w, hres[nres] = h, nres++; 173 | } 174 | for (i = 0; i < nres; i++) { 175 | sprintf (cbuf, "%d x %d", wres[i], hres[i]); 176 | SendDlgItemMessage (hTab, IDC_VID_MODE, CB_ADDSTRING, 0, (LPARAM)cbuf); 177 | SendDlgItemMessage (hTab, IDC_VID_MODE, CB_SETITEMDATA, i, (LPARAM)(hres[i]<<16 | wres[i])); 178 | if (wres[i] == cmode.dwWidth && hres[i] == cmode.dwHeight) 179 | SendDlgItemMessage (hTab, IDC_VID_MODE, CB_SETCURSEL, i, 0); 180 | } 181 | for (i = 0; i < 2; i++) 182 | EnableWindow (GetDlgItem (hTab, IDC_VID_FULL+i), TRUE); 183 | for (i = 0; i < 2; i++) 184 | EnableWindow (GetDlgItem (hTab, IDC_VID_FULL+i), dev->bDesktopCompatible); 185 | delete []wres; 186 | delete []hres; 187 | } 188 | 189 | // Respond to user selection of fullscreen/window mode 190 | void VideoTab::SelectDispmode (SkyboltDeviceInfo *dev, BOOL bWindow) 191 | { 192 | DWORD i; 193 | for (i = 0; i < 6; i++) 194 | EnableWindow (GetDlgItem (hTab, IDC_VID_STATIC5+i), !bWindow); 195 | for (i = 0; i < 9; i++) 196 | EnableWindow (GetDlgItem (hTab, IDC_VID_STATIC7+i), bWindow); 197 | if (!bWindow) { 198 | if (SendDlgItemMessage (hTab, IDC_VID_PAGEFLIP, BM_GETCHECK, 0, 0) == BST_CHECKED) 199 | EnableWindow (GetDlgItem (hTab, IDC_VID_VSYNC), FALSE); 200 | } else { 201 | if (SendDlgItemMessage (hTab, IDC_VID_ASPECT, BM_GETCHECK, 0, 0) != BST_CHECKED) { 202 | for (i = 0; i < 3; i++) 203 | EnableWindow (GetDlgItem (hTab, IDC_VID_4X3+i), FALSE); 204 | } 205 | } 206 | } 207 | 208 | // Respond to user selection of fullscreen resolution 209 | void VideoTab::SelectMode (SkyboltDeviceInfo *dev, DWORD idx) 210 | { 211 | DWORD data, w, h, bpp, usebpp; 212 | usebpp = 0; 213 | data = SendDlgItemMessage (hTab, IDC_VID_MODE, CB_GETITEMDATA, idx, 0); 214 | w = data & 0xFFFF; 215 | h = data >> 16; 216 | // check that this resolution is compatible with the current bpp setting 217 | idx = SendDlgItemMessage (hTab, IDC_VID_BPP, CB_GETCURSEL, 0, 0); 218 | bpp = SendDlgItemMessage (hTab, IDC_VID_BPP, CB_GETITEMDATA, idx, 0); 219 | 220 | // if a bpp change was required, notify the bpp control 221 | if (bpp != usebpp) { 222 | char cbuf[20]; 223 | SendDlgItemMessage (hTab, IDC_VID_BPP, CB_SELECTSTRING, -1, 224 | (LPARAM)_itoa (usebpp, cbuf, 10)); 225 | } 226 | } 227 | 228 | void VideoTab::SelectPageflip () 229 | { 230 | bool disable_pageflip = (SendDlgItemMessage (hTab, IDC_VID_PAGEFLIP, BM_GETCHECK, 0, 0) == BST_CHECKED); 231 | EnableWindow (GetDlgItem (hTab, IDC_VID_VSYNC), disable_pageflip ? FALSE:TRUE); 232 | } 233 | 234 | 235 | static int aspect_wfac[4] = {4,16,16}; 236 | static int aspect_hfac[4] = {3,10,9}; 237 | 238 | void VideoTab::SelectWidth () 239 | { 240 | if (SendDlgItemMessage (hTab, IDC_VID_ASPECT, BM_GETCHECK, 0, 0) == BST_CHECKED) { 241 | char cbuf[128]; 242 | int w, h, wfac = aspect_wfac[aspect_idx], hfac = aspect_hfac[aspect_idx]; 243 | GetWindowText (GetDlgItem (hTab, IDC_VID_WIDTH), cbuf, 127); w = atoi(cbuf); 244 | GetWindowText (GetDlgItem (hTab, IDC_VID_HEIGHT), cbuf, 127); h = atoi(cbuf); 245 | if (w != (wfac*h)/hfac) { 246 | h = (hfac*w)/wfac; 247 | SetWindowText (GetDlgItem (hTab, IDC_VID_HEIGHT), itoa (h, cbuf, 10)); 248 | } 249 | } 250 | } 251 | 252 | void VideoTab::SelectHeight () 253 | { 254 | if (SendDlgItemMessage (hTab, IDC_VID_ASPECT, BM_GETCHECK, 0, 0) == BST_CHECKED) { 255 | char cbuf[128]; 256 | int w, h, wfac = aspect_wfac[aspect_idx], hfac = aspect_hfac[aspect_idx]; 257 | GetWindowText (GetDlgItem (hTab, IDC_VID_WIDTH), cbuf, 127); w = atoi(cbuf); 258 | GetWindowText (GetDlgItem (hTab, IDC_VID_HEIGHT), cbuf, 127); h = atoi(cbuf); 259 | if (h != (hfac*w)/wfac) { 260 | w = (wfac*h)/hfac; 261 | SetWindowText (GetDlgItem (hTab, IDC_VID_WIDTH), itoa (w, cbuf, 10)); 262 | } 263 | } 264 | } 265 | 266 | void VideoTab::SelectFixedAspect () 267 | { 268 | bool fixed_aspect = (SendDlgItemMessage (hTab, IDC_VID_ASPECT, BM_GETCHECK, 0, 0) == BST_CHECKED); 269 | for (int i = 0; i < 3; i++) 270 | EnableWindow (GetDlgItem (hTab, IDC_VID_4X3+i), fixed_aspect ? TRUE:FALSE); 271 | } 272 | 273 | void VideoTab::UpdateConfigData () 274 | { 275 | char cbuf[128]; 276 | DWORD i, dat, w, h, bpp, ndev; 277 | ndev = 1; 278 | GraphicsClient::VIDEODATA *data = gclient->GetVideoData(); 279 | 280 | // device parameters 281 | i = SendDlgItemMessage (hTab, IDC_VID_DEVICE, CB_GETCURSEL, 0, 0); 282 | if (i >= ndev) i = 0; // should not happen 283 | data->deviceidx = i; 284 | i = SendDlgItemMessage (hTab, IDC_VID_MODE, CB_GETCURSEL, 0, 0); 285 | dat = SendDlgItemMessage (hTab, IDC_VID_MODE, CB_GETITEMDATA, i, 0); 286 | w = dat & 0xFFFF; 287 | h = dat >> 16; 288 | i = SendDlgItemMessage (hTab, IDC_VID_BPP, CB_GETCURSEL, 0, 0); 289 | bpp = SendDlgItemMessage (hTab, IDC_VID_BPP, CB_GETITEMDATA, i, 0); 290 | 291 | 292 | data->fullscreen = (SendDlgItemMessage (hTab, IDC_VID_FULL, BM_GETCHECK, 0, 0) == BST_CHECKED); 293 | data->novsync = (SendDlgItemMessage (hTab, IDC_VID_VSYNC, BM_GETCHECK, 0, 0) == BST_CHECKED); 294 | data->pageflip = (SendDlgItemMessage (hTab, IDC_VID_PAGEFLIP, BM_GETCHECK, 0, 0) != BST_CHECKED); 295 | data->trystencil = (SendDlgItemMessage (hTab, IDC_VID_STENCIL, BM_GETCHECK, 0, 0) == BST_CHECKED); 296 | data->forceenum = (SendDlgItemMessage (hTab, IDC_VID_ENUM, BM_GETCHECK, 0, 0) == BST_CHECKED); 297 | GetWindowText (GetDlgItem (hTab, IDC_VID_WIDTH), cbuf, 127); data->winw = atoi(cbuf); 298 | GetWindowText (GetDlgItem (hTab, IDC_VID_HEIGHT), cbuf, 127); data->winh = atoi(cbuf); 299 | } 300 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/OsgSketchpad.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Matthew Reid 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | */ 10 | 11 | #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 12 | 13 | #include "OpenGlContext.h" 14 | #include "OsgSketchpad.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | #include "ThirdParty/nanovg/nanovg.h" 24 | #define NANOVG_GL3_IMPLEMENTATION // Use GL2 implementation. 25 | #include "ThirdParty/nanovg/nanovg_gl.h" 26 | 27 | struct SketchpadCommand 28 | { 29 | virtual ~SketchpadCommand() = default; 30 | }; 31 | 32 | struct ClearCommand : SketchpadCommand 33 | { 34 | osg::Vec4f color; 35 | }; 36 | 37 | struct LineCommand : SketchpadCommand 38 | { 39 | osg::Vec2i p0; 40 | osg::Vec2i p1; 41 | OsgPen pen; 42 | }; 43 | 44 | struct RectangleCommand : SketchpadCommand 45 | { 46 | osg::Vec2i p0; 47 | osg::Vec2i p1; 48 | std::optional pen; 49 | std::optional brush; 50 | }; 51 | 52 | struct EllipseCommand : SketchpadCommand 53 | { 54 | osg::Vec2i p0; 55 | osg::Vec2i p1; 56 | std::optional pen; 57 | std::optional brush; 58 | }; 59 | 60 | struct PolygonCommand : SketchpadCommand 61 | { 62 | std::vector points; 63 | std::optional pen; 64 | std::optional brush; 65 | }; 66 | 67 | struct PolylineCommand : SketchpadCommand 68 | { 69 | std::vector points; 70 | OsgPen pen; 71 | }; 72 | 73 | struct TextCommand : SketchpadCommand 74 | { 75 | osg::Vec2i point; 76 | std::string text; 77 | osg::Vec4i color; 78 | std::optional backgroundColor; 79 | int align; 80 | OsgFont font; 81 | }; 82 | 83 | class SketchpadDrawable : public osg::Drawable 84 | { 85 | public: 86 | SketchpadDrawable(const std::shared_ptr& nvgContext) : m_nvgContext(nvgContext) 87 | { 88 | assert(m_nvgContext); 89 | } 90 | 91 | void drawImplementation(osg::RenderInfo& renderInfo) const override 92 | { 93 | auto vg = m_nvgContext.get(); 94 | 95 | auto camera = renderInfo.getCurrentCamera(); 96 | auto viewport = camera->getViewport(); 97 | nvgBeginFrame(vg, viewport->width(), viewport->height(), /* pxRatio */ 1.0); 98 | 99 | for (const auto& c : mCommands) 100 | { 101 | if (const auto clear = dynamic_cast(c.get()); clear) 102 | { 103 | glClearColor(clear->color.r(), clear->color.g(), clear->color.b(), clear->color.a()); 104 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 105 | } 106 | else if (const auto line = dynamic_cast(c.get()); line) 107 | { 108 | nvgBeginPath(vg); 109 | nvgMoveTo(vg, line->p0.x(), line->p0.y()); 110 | nvgLineTo(vg, line->p1.x(), line->p1.y()); 111 | 112 | nvgStrokeFromPen(vg, line->pen); 113 | } 114 | else if (const auto rectangle = dynamic_cast(c.get()); rectangle) 115 | { 116 | nvgBeginPath(vg); 117 | auto size = rectangle->p1 - rectangle->p0; 118 | nvgRect(vg, rectangle->p0.x(), rectangle->p0.y(), std::abs(size.x()), std::abs(size.y())); 119 | 120 | if (rectangle->brush) 121 | { 122 | nvgStrokeFromBrush(vg, *rectangle->brush); 123 | } 124 | 125 | if (rectangle->pen) 126 | { 127 | nvgStrokeFromPen(vg, *rectangle->pen); 128 | } 129 | } 130 | else if (const auto ellipse = dynamic_cast(c.get()); ellipse) 131 | { 132 | nvgBeginPath(vg); 133 | auto center = (ellipse->p0 + ellipse->p1) / 2; 134 | auto radius = (ellipse->p1 - ellipse->p0) / 2; 135 | nvgEllipse(vg, center.x(), center.y(), std::abs(radius.x()), std::abs(radius.y())); 136 | 137 | if (ellipse->brush) 138 | { 139 | nvgStrokeFromBrush(vg, *ellipse->brush); 140 | } 141 | 142 | if (ellipse->pen) 143 | { 144 | nvgStrokeFromPen(vg, *ellipse->pen); 145 | } 146 | } 147 | else if (const auto polygon = dynamic_cast(c.get()); polygon) 148 | { 149 | nvgBeginPath(vg); 150 | auto firstPoint = polygon->points.front(); 151 | nvgMoveTo(vg, firstPoint.x(), firstPoint.y()); 152 | 153 | for (size_t i = 1; i < polygon->points.size(); ++i) 154 | { 155 | auto point = polygon->points[i]; 156 | nvgLineTo(vg, point.x(), point.y()); 157 | } 158 | 159 | nvgClosePath(vg); 160 | 161 | if (polygon->brush) 162 | { 163 | nvgStrokeFromBrush(vg, *polygon->brush); 164 | } 165 | 166 | if (polygon->pen) 167 | { 168 | nvgStrokeFromPen(vg, *polygon->pen); 169 | } 170 | } 171 | else if (const auto polyline = dynamic_cast(c.get()); polyline) 172 | { 173 | nvgBeginPath(vg); 174 | auto firstPoint = polyline->points.front(); 175 | nvgMoveTo(vg, firstPoint.x(), firstPoint.y()); 176 | 177 | for (size_t i = 1; i < polyline->points.size(); ++i) 178 | { 179 | auto point = polyline->points[i]; 180 | nvgLineTo(vg, point.x(), point.y()); 181 | } 182 | 183 | nvgStrokeFromPen(vg, polyline->pen); 184 | } 185 | else if (const auto text = dynamic_cast(c.get()); text) 186 | { 187 | nvgFontSize(vg, text->font.heightPixels); 188 | nvgFontFace(vg, text->font.name.c_str()); 189 | nvgTextAlign(vg, text->align); 190 | 191 | nvgResetTransform(vg); 192 | nvgTranslate(vg, text->point.x(), text->point.y()); 193 | nvgRotate(vg, text->font.rotationRadians); 194 | 195 | if (text->backgroundColor) 196 | { 197 | float bounds[4]; 198 | nvgTextBounds(vg, 0, 0, text->text.c_str(), NULL, bounds); 199 | nvgBeginPath(vg); 200 | nvgRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); 201 | nvgFillColor(vg, nvgRGBA(text->backgroundColor->r(), text->backgroundColor->g(), text->backgroundColor->b(), text->backgroundColor->a())); 202 | nvgFill(vg); 203 | } 204 | 205 | nvgFillColor(vg, nvgRGBA(text->color.r(), text->color.g(), text->color.b(), text->color.a())); 206 | nvgText(vg, 0, 0, text->text.c_str(), nullptr); 207 | 208 | nvgResetTransform(vg); // undo rotation 209 | } 210 | } 211 | 212 | nvgEndFrame(vg); 213 | 214 | mCommands.clear(); 215 | 216 | // Cleanup OpenGL state after nanoVG 217 | glDisable(GL_BLEND); 218 | } 219 | 220 | void addCommand(std::shared_ptr command) 221 | { 222 | mCommands.emplace_back(std::move(command)); 223 | } 224 | 225 | private: 226 | static void nvgStrokeFromPen(NVGcontext* vg, const OsgPen& pen) 227 | { 228 | nvgStrokeWidth(vg, osg::maximum(1, pen.width)); 229 | nvgStrokeColor(vg, nvgRGBA(pen.color.r(), pen.color.g(), pen.color.b(), pen.color.a())); 230 | // TODO: add support for dashed lines. Not currently supported by nanoVG. 231 | nvgStroke(vg); 232 | } 233 | 234 | static void nvgStrokeFromBrush(NVGcontext* vg, const OsgBrush& brush) 235 | { 236 | nvgFillColor(vg, nvgRGBA(brush.color.r(), brush.color.g(), brush.color.b(), brush.color.a())); 237 | nvgFill(vg); 238 | } 239 | 240 | private: 241 | std::shared_ptr m_nvgContext; 242 | mutable std::vector> mCommands; 243 | }; 244 | 245 | std::shared_ptr CreateNanoVgContext() 246 | { 247 | std::shared_ptr context(nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES), [] (NVGcontext* vg) { 248 | nvgDeleteGL3(vg); 249 | }); 250 | nvgCreateFont(context.get(), "Fixed", "C:/Windows/Fonts/cour.ttf"); 251 | nvgCreateFont(context.get(), "Sans", "C:/Windows/Fonts/arial.ttf"); 252 | nvgCreateFont(context.get(), "Serif", "C:/Windows/Fonts/times.ttf"); 253 | return context; 254 | } 255 | 256 | OsgSketchpad::OsgSketchpad(const osg::ref_ptr& camera, SURFHANDLE surface, const std::shared_ptr& context) : 257 | oapi::Sketchpad(surface), 258 | mCamera(camera) 259 | { 260 | mDrawable = new SketchpadDrawable(context); 261 | mCamera->addChild(mDrawable); 262 | } 263 | 264 | OsgSketchpad::~OsgSketchpad() = default; 265 | 266 | void OsgSketchpad::fillBackground(const osg::Vec4f& color) 267 | { 268 | auto c = std::make_shared(); 269 | c->color = color; 270 | mDrawable->addCommand(c); 271 | 272 | // Hack to reset text alignment at start of frame. 273 | // Unfortunatly Orbiter doesn't reset text alignment explicitly. 274 | SetTextAlign(); 275 | } 276 | 277 | oapi::Font* OsgSketchpad::SetFont(oapi::Font* font) 278 | { 279 | oapi::Font* oldFont = mFont; 280 | mFont = dynamic_cast(font); 281 | return oldFont; 282 | } 283 | 284 | oapi::Pen* OsgSketchpad::SetPen(oapi::Pen* pen) 285 | { 286 | oapi::Pen* oldPen = mPen; 287 | mPen = dynamic_cast(pen); 288 | return oldPen; 289 | } 290 | 291 | oapi::Brush* OsgSketchpad::SetBrush(oapi::Brush* brush) 292 | { 293 | oapi::Brush* oldBrush = mBrush; 294 | mBrush = dynamic_cast(brush); 295 | return oldBrush; 296 | } 297 | 298 | static NVGalign toNvgAlign(OsgSketchpad::TAlign_horizontal tah) 299 | { 300 | switch (tah) 301 | { 302 | case OsgSketchpad::LEFT: 303 | return NVGalign::NVG_ALIGN_LEFT; 304 | case OsgSketchpad::CENTER: 305 | return NVGalign::NVG_ALIGN_CENTER; 306 | case OsgSketchpad::RIGHT: 307 | return NVGalign::NVG_ALIGN_RIGHT; 308 | } 309 | assert(!"Should not get here"); 310 | return NVGalign::NVG_ALIGN_LEFT; 311 | } 312 | 313 | static NVGalign toNvgAlign(OsgSketchpad::TAlign_vertical tav) 314 | { 315 | switch (tav) 316 | { 317 | case OsgSketchpad::TOP: 318 | return NVGalign::NVG_ALIGN_TOP; 319 | case OsgSketchpad::BASELINE: 320 | return NVGalign::NVG_ALIGN_BASELINE; 321 | case OsgSketchpad::BOTTOM: 322 | return NVGalign::NVG_ALIGN_BOTTOM; 323 | } 324 | assert(!"Should not get here"); 325 | return NVGalign::NVG_ALIGN_TOP; 326 | } 327 | 328 | void OsgSketchpad::SetTextAlign(TAlign_horizontal tah, TAlign_vertical tav) 329 | { 330 | mTextAlign = toNvgAlign(tah) | toNvgAlign(tav); 331 | } 332 | 333 | DWORD OsgSketchpad::SetTextColor(DWORD col) 334 | { 335 | DWORD oldTextColor = mTextColor; 336 | mTextColor = col; 337 | return oldTextColor; 338 | } 339 | 340 | DWORD OsgSketchpad::SetBackgroundColor(DWORD col) 341 | { 342 | DWORD oldTextBackgroundColor = mTextBackgroundColor; 343 | mTextBackgroundColor = col; 344 | return oldTextBackgroundColor; 345 | } 346 | 347 | void OsgSketchpad::SetBackgroundMode(BkgMode mode) 348 | { 349 | mTextBackgroundMode = mode; 350 | } 351 | 352 | static float getCharacterWidth(const OsgFont& font) 353 | { 354 | return font.heightPixels * 0.7f; 355 | } 356 | 357 | DWORD OsgSketchpad::GetCharSize() 358 | { 359 | if (mFont) 360 | { 361 | return MAKELONG(mFont->heightPixels, getCharacterWidth(*mFont)); 362 | } 363 | return MAKELONG(10, 7); 364 | } 365 | 366 | DWORD OsgSketchpad::GetTextWidth(const char *str, int len) 367 | { 368 | if (len == 0) 369 | { 370 | len = strlen(str); 371 | } 372 | 373 | if (mFont) 374 | { 375 | return getCharacterWidth(*mFont) * len; 376 | } 377 | return 7 * len; 378 | } 379 | 380 | // From https://stackoverflow.com/questions/4804298/how-to-convert-wstring-into-string 381 | static std::string wstringToString(const std::wstring& wstr) 382 | { 383 | using convert_typeX = std::codecvt_utf8; 384 | std::wstring_convert converterX; 385 | 386 | return converterX.to_bytes(wstr); 387 | } 388 | 389 | bool OsgSketchpad::Text(int x, int y, const char *str, int len) 390 | { 391 | if (mFont) 392 | { 393 | auto c = std::make_shared(); 394 | c->point = osg::Vec2i(x - mOrigin.x(), y - mOrigin.y()); 395 | c->text = std::string(str, len); 396 | c->color = rgbIntToVec4iColor(mTextColor); 397 | c->align = mTextAlign; 398 | c->font = *mFont; 399 | 400 | if (mTextBackgroundMode == BkgMode::BK_OPAQUE) 401 | { 402 | c->backgroundColor = rgbIntToVec4iColor(mTextBackgroundColor); 403 | } 404 | 405 | mDrawable->addCommand(c); 406 | return true; 407 | } 408 | return false; 409 | } 410 | 411 | bool OsgSketchpad::TextW(int x, int y, const LPWSTR wstr, int len) 412 | { 413 | std::string str = wstringToString(std::wstring(wstr, len)); 414 | return Text(x, y, str.c_str(), len); 415 | } 416 | 417 | void OsgSketchpad::LineTo(int x, int y) 418 | { 419 | Line(mPenPosition.x(), mPenPosition.y(), x, y); 420 | MoveTo(x, y); 421 | } 422 | 423 | void OsgSketchpad::Line(int x0, int y0, int x1, int y1) 424 | { 425 | if (mPen && mPen->style != OsgPen::Style::Invisible) 426 | { 427 | auto c = std::make_shared(); 428 | c->p0 = osg::Vec2i(x0 - mOrigin.x(), y0 - mOrigin.y()); 429 | c->p1 = osg::Vec2i(x1 - mOrigin.x(), y1 - mOrigin.y()); 430 | c->pen = *mPen; 431 | mDrawable->addCommand(c); 432 | MoveTo(x1, y1); 433 | } 434 | } 435 | 436 | void OsgSketchpad::Rectangle(int x0, int y0, int x1, int y1) 437 | { 438 | auto c = std::make_shared(); 439 | c->p0 = osg::Vec2i(x0 - mOrigin.x(), y0 - mOrigin.y()); 440 | c->p1 = osg::Vec2i(x1 - mOrigin.x(), y1 - mOrigin.y()); 441 | c->pen = mPen ? std::optional(*mPen) : std::nullopt; 442 | c->brush = mBrush ? std::optional(*mBrush) : std::nullopt; 443 | mDrawable->addCommand(c); 444 | } 445 | 446 | void OsgSketchpad::Ellipse(int x0, int y0, int x1, int y1) 447 | { 448 | auto c = std::make_shared(); 449 | c->p0 = osg::Vec2i(x0 - mOrigin.x(), y0 - mOrigin.y()); 450 | c->p1 = osg::Vec2i(x1 - mOrigin.x(), y1 - mOrigin.y()); 451 | c->pen = mPen ? std::optional(*mPen) : std::nullopt; 452 | c->brush = mBrush ? std::optional(*mBrush) : std::nullopt; 453 | mDrawable->addCommand(c); 454 | } 455 | 456 | void OsgSketchpad::Polygon(const oapi::IVECTOR2 *pt, int npt) 457 | { 458 | assert(npt > 0); 459 | auto c = std::make_shared(); 460 | for (int i = 0; i < npt; ++i) 461 | { 462 | const oapi::IVECTOR2& v = pt[i]; 463 | c->points.emplace_back(osg::Vec2i(v.x - mOrigin.x(), v.y - mOrigin.y())); 464 | } 465 | c->pen = mPen ? std::optional(*mPen) : std::nullopt; 466 | c->brush = mBrush ? std::optional(*mBrush) : std::nullopt; 467 | mDrawable->addCommand(c); 468 | } 469 | 470 | void OsgSketchpad::Polyline(const oapi::IVECTOR2 *pt, int npt) 471 | { 472 | if (mPen && mPen->style != OsgPen::Style::Invisible) 473 | { 474 | assert(npt > 0); 475 | auto c = std::make_shared(); 476 | for (int i = 0; i < npt; ++i) 477 | { 478 | const oapi::IVECTOR2& v = pt[i]; 479 | c->points.emplace_back(osg::Vec2i(v.x - mOrigin.x(), v.y - mOrigin.y())); 480 | } 481 | c->pen = *mPen; 482 | mDrawable->addCommand(c); 483 | } 484 | } 485 | -------------------------------------------------------------------------------- /src/OrbiterSkyboltClient/ThirdParty/nanovg/nanovg.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Mikko Mononen memon@inside.org 3 | // 4 | // This software is provided 'as-is', without any express or implied 5 | // warranty. In no event will the authors be held liable for any damages 6 | // arising from the use of this software. 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 1. The origin of this software must not be misrepresented; you must not 11 | // claim that you wrote the original software. If you use this software 12 | // in a product, an acknowledgment in the product documentation would be 13 | // appreciated but is not required. 14 | // 2. Altered source versions must be plainly marked as such, and must not be 15 | // misrepresented as being the original software. 16 | // 3. This notice may not be removed or altered from any source distribution. 17 | // 18 | 19 | #ifndef NANOVG_H 20 | #define NANOVG_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define NVG_PI 3.14159265358979323846264338327f 27 | 28 | #ifdef _MSC_VER 29 | #pragma warning(push) 30 | #pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union 31 | #endif 32 | 33 | typedef struct NVGcontext NVGcontext; 34 | 35 | struct NVGcolor { 36 | union { 37 | float rgba[4]; 38 | struct { 39 | float r,g,b,a; 40 | }; 41 | }; 42 | }; 43 | typedef struct NVGcolor NVGcolor; 44 | 45 | struct NVGpaint { 46 | float xform[6]; 47 | float extent[2]; 48 | float radius; 49 | float feather; 50 | NVGcolor innerColor; 51 | NVGcolor outerColor; 52 | int image; 53 | }; 54 | typedef struct NVGpaint NVGpaint; 55 | 56 | enum NVGwinding { 57 | NVG_CCW = 1, // Winding for solid shapes 58 | NVG_CW = 2, // Winding for holes 59 | }; 60 | 61 | enum NVGsolidity { 62 | NVG_SOLID = 1, // CCW 63 | NVG_HOLE = 2, // CW 64 | }; 65 | 66 | enum NVGlineCap { 67 | NVG_BUTT, 68 | NVG_ROUND, 69 | NVG_SQUARE, 70 | NVG_BEVEL, 71 | NVG_MITER, 72 | }; 73 | 74 | enum NVGalign { 75 | // Horizontal align 76 | NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left. 77 | NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center. 78 | NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right. 79 | // Vertical align 80 | NVG_ALIGN_TOP = 1<<3, // Align text vertically to top. 81 | NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle. 82 | NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. 83 | NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. 84 | }; 85 | 86 | enum NVGblendFactor { 87 | NVG_ZERO = 1<<0, 88 | NVG_ONE = 1<<1, 89 | NVG_SRC_COLOR = 1<<2, 90 | NVG_ONE_MINUS_SRC_COLOR = 1<<3, 91 | NVG_DST_COLOR = 1<<4, 92 | NVG_ONE_MINUS_DST_COLOR = 1<<5, 93 | NVG_SRC_ALPHA = 1<<6, 94 | NVG_ONE_MINUS_SRC_ALPHA = 1<<7, 95 | NVG_DST_ALPHA = 1<<8, 96 | NVG_ONE_MINUS_DST_ALPHA = 1<<9, 97 | NVG_SRC_ALPHA_SATURATE = 1<<10, 98 | }; 99 | 100 | enum NVGcompositeOperation { 101 | NVG_SOURCE_OVER, 102 | NVG_SOURCE_IN, 103 | NVG_SOURCE_OUT, 104 | NVG_ATOP, 105 | NVG_DESTINATION_OVER, 106 | NVG_DESTINATION_IN, 107 | NVG_DESTINATION_OUT, 108 | NVG_DESTINATION_ATOP, 109 | NVG_LIGHTER, 110 | NVG_COPY, 111 | NVG_XOR, 112 | }; 113 | 114 | struct NVGcompositeOperationState { 115 | int srcRGB; 116 | int dstRGB; 117 | int srcAlpha; 118 | int dstAlpha; 119 | }; 120 | typedef struct NVGcompositeOperationState NVGcompositeOperationState; 121 | 122 | struct NVGglyphPosition { 123 | const char* str; // Position of the glyph in the input string. 124 | float x; // The x-coordinate of the logical glyph position. 125 | float minx, maxx; // The bounds of the glyph shape. 126 | }; 127 | typedef struct NVGglyphPosition NVGglyphPosition; 128 | 129 | struct NVGtextRow { 130 | const char* start; // Pointer to the input text where the row starts. 131 | const char* end; // Pointer to the input text where the row ends (one past the last character). 132 | const char* next; // Pointer to the beginning of the next row. 133 | float width; // Logical width of the row. 134 | float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. 135 | }; 136 | typedef struct NVGtextRow NVGtextRow; 137 | 138 | enum NVGimageFlags { 139 | NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image. 140 | NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction. 141 | NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction. 142 | NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered. 143 | NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha. 144 | NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear 145 | }; 146 | 147 | // Begin drawing a new frame 148 | // Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() 149 | // nvgBeginFrame() defines the size of the window to render to in relation currently 150 | // set viewport (i.e. glViewport on GL backends). Device pixel ration allows to 151 | // control the rendering on Hi-DPI devices. 152 | // For example, GLFW returns two dimension for an opened window: window size and 153 | // frame buffer size. In that case you would set windowWidth/Height to the window size 154 | // devicePixelRatio to: frameBufferWidth / windowWidth. 155 | void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio); 156 | 157 | // Cancels drawing the current frame. 158 | void nvgCancelFrame(NVGcontext* ctx); 159 | 160 | // Ends drawing flushing remaining render state. 161 | void nvgEndFrame(NVGcontext* ctx); 162 | 163 | // 164 | // Composite operation 165 | // 166 | // The composite operations in NanoVG are modeled after HTML Canvas API, and 167 | // the blend func is based on OpenGL (see corresponding manuals for more info). 168 | // The colors in the blending state have premultiplied alpha. 169 | 170 | // Sets the composite operation. The op parameter should be one of NVGcompositeOperation. 171 | void nvgGlobalCompositeOperation(NVGcontext* ctx, int op); 172 | 173 | // Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor. 174 | void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor); 175 | 176 | // Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor. 177 | void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha); 178 | 179 | // 180 | // Color utils 181 | // 182 | // Colors in NanoVG are stored as unsigned ints in ABGR format. 183 | 184 | // Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f). 185 | NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b); 186 | 187 | // Returns a color value from red, green, blue values. Alpha will be set to 1.0f. 188 | NVGcolor nvgRGBf(float r, float g, float b); 189 | 190 | 191 | // Returns a color value from red, green, blue and alpha values. 192 | NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); 193 | 194 | // Returns a color value from red, green, blue and alpha values. 195 | NVGcolor nvgRGBAf(float r, float g, float b, float a); 196 | 197 | 198 | // Linearly interpolates from color c0 to c1, and returns resulting color value. 199 | NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u); 200 | 201 | // Sets transparency of a color value. 202 | NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a); 203 | 204 | // Sets transparency of a color value. 205 | NVGcolor nvgTransRGBAf(NVGcolor c0, float a); 206 | 207 | // Returns color value specified by hue, saturation and lightness. 208 | // HSL values are all in range [0..1], alpha will be set to 255. 209 | NVGcolor nvgHSL(float h, float s, float l); 210 | 211 | // Returns color value specified by hue, saturation and lightness and alpha. 212 | // HSL values are all in range [0..1], alpha in range [0..255] 213 | NVGcolor nvgHSLA(float h, float s, float l, unsigned char a); 214 | 215 | // 216 | // State Handling 217 | // 218 | // NanoVG contains state which represents how paths will be rendered. 219 | // The state contains transform, fill and stroke styles, text and font styles, 220 | // and scissor clipping. 221 | 222 | // Pushes and saves the current render state into a state stack. 223 | // A matching nvgRestore() must be used to restore the state. 224 | void nvgSave(NVGcontext* ctx); 225 | 226 | // Pops and restores current render state. 227 | void nvgRestore(NVGcontext* ctx); 228 | 229 | // Resets current render state to default values. Does not affect the render state stack. 230 | void nvgReset(NVGcontext* ctx); 231 | 232 | // 233 | // Render styles 234 | // 235 | // Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern. 236 | // Solid color is simply defined as a color value, different kinds of paints can be created 237 | // using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern(). 238 | // 239 | // Current render style can be saved and restored using nvgSave() and nvgRestore(). 240 | 241 | // Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default. 242 | void nvgShapeAntiAlias(NVGcontext* ctx, int enabled); 243 | 244 | // Sets current stroke style to a solid color. 245 | void nvgStrokeColor(NVGcontext* ctx, NVGcolor color); 246 | 247 | // Sets current stroke style to a paint, which can be a one of the gradients or a pattern. 248 | void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint); 249 | 250 | // Sets current fill style to a solid color. 251 | void nvgFillColor(NVGcontext* ctx, NVGcolor color); 252 | 253 | // Sets current fill style to a paint, which can be a one of the gradients or a pattern. 254 | void nvgFillPaint(NVGcontext* ctx, NVGpaint paint); 255 | 256 | // Sets the miter limit of the stroke style. 257 | // Miter limit controls when a sharp corner is beveled. 258 | void nvgMiterLimit(NVGcontext* ctx, float limit); 259 | 260 | // Sets the stroke width of the stroke style. 261 | void nvgStrokeWidth(NVGcontext* ctx, float size); 262 | 263 | // Sets how the end of the line (cap) is drawn, 264 | // Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE. 265 | void nvgLineCap(NVGcontext* ctx, int cap); 266 | 267 | // Sets how sharp path corners are drawn. 268 | // Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL. 269 | void nvgLineJoin(NVGcontext* ctx, int join); 270 | 271 | // Sets the transparency applied to all rendered shapes. 272 | // Already transparent paths will get proportionally more transparent as well. 273 | void nvgGlobalAlpha(NVGcontext* ctx, float alpha); 274 | 275 | // 276 | // Transforms 277 | // 278 | // The paths, gradients, patterns and scissor region are transformed by an transformation 279 | // matrix at the time when they are passed to the API. 280 | // The current transformation matrix is a affine matrix: 281 | // [sx kx tx] 282 | // [ky sy ty] 283 | // [ 0 0 1] 284 | // Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation. 285 | // The last row is assumed to be 0,0,1 and is not stored. 286 | // 287 | // Apart from nvgResetTransform(), each transformation function first creates 288 | // specific transformation matrix and pre-multiplies the current transformation by it. 289 | // 290 | // Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). 291 | 292 | // Resets current transform to a identity matrix. 293 | void nvgResetTransform(NVGcontext* ctx); 294 | 295 | // Premultiplies current coordinate system by specified matrix. 296 | // The parameters are interpreted as matrix as follows: 297 | // [a c e] 298 | // [b d f] 299 | // [0 0 1] 300 | void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f); 301 | 302 | // Translates current coordinate system. 303 | void nvgTranslate(NVGcontext* ctx, float x, float y); 304 | 305 | // Rotates current coordinate system. Angle is specified in radians. 306 | void nvgRotate(NVGcontext* ctx, float angle); 307 | 308 | // Skews the current coordinate system along X axis. Angle is specified in radians. 309 | void nvgSkewX(NVGcontext* ctx, float angle); 310 | 311 | // Skews the current coordinate system along Y axis. Angle is specified in radians. 312 | void nvgSkewY(NVGcontext* ctx, float angle); 313 | 314 | // Scales the current coordinate system. 315 | void nvgScale(NVGcontext* ctx, float x, float y); 316 | 317 | // Stores the top part (a-f) of the current transformation matrix in to the specified buffer. 318 | // [a c e] 319 | // [b d f] 320 | // [0 0 1] 321 | // There should be space for 6 floats in the return buffer for the values a-f. 322 | void nvgCurrentTransform(NVGcontext* ctx, float* xform); 323 | 324 | 325 | // The following functions can be used to make calculations on 2x3 transformation matrices. 326 | // A 2x3 matrix is represented as float[6]. 327 | 328 | // Sets the transform to identity matrix. 329 | void nvgTransformIdentity(float* dst); 330 | 331 | // Sets the transform to translation matrix matrix. 332 | void nvgTransformTranslate(float* dst, float tx, float ty); 333 | 334 | // Sets the transform to scale matrix. 335 | void nvgTransformScale(float* dst, float sx, float sy); 336 | 337 | // Sets the transform to rotate matrix. Angle is specified in radians. 338 | void nvgTransformRotate(float* dst, float a); 339 | 340 | // Sets the transform to skew-x matrix. Angle is specified in radians. 341 | void nvgTransformSkewX(float* dst, float a); 342 | 343 | // Sets the transform to skew-y matrix. Angle is specified in radians. 344 | void nvgTransformSkewY(float* dst, float a); 345 | 346 | // Sets the transform to the result of multiplication of two transforms, of A = A*B. 347 | void nvgTransformMultiply(float* dst, const float* src); 348 | 349 | // Sets the transform to the result of multiplication of two transforms, of A = B*A. 350 | void nvgTransformPremultiply(float* dst, const float* src); 351 | 352 | // Sets the destination to inverse of specified transform. 353 | // Returns 1 if the inverse could be calculated, else 0. 354 | int nvgTransformInverse(float* dst, const float* src); 355 | 356 | // Transform a point by given transform. 357 | void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); 358 | 359 | // Converts degrees to radians and vice versa. 360 | float nvgDegToRad(float deg); 361 | float nvgRadToDeg(float rad); 362 | 363 | // 364 | // Images 365 | // 366 | // NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering. 367 | // In addition you can upload your own image. The image loading is provided by stb_image. 368 | // The parameter imageFlags is combination of flags defined in NVGimageFlags. 369 | 370 | // Creates image by loading it from the disk from specified file name. 371 | // Returns handle to the image. 372 | int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags); 373 | 374 | // Creates image by loading it from the specified chunk of memory. 375 | // Returns handle to the image. 376 | int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata); 377 | 378 | // Creates image from specified image data. 379 | // Returns handle to the image. 380 | int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); 381 | 382 | // Updates image data specified by image handle. 383 | void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data); 384 | 385 | // Returns the dimensions of a created image. 386 | void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h); 387 | 388 | // Deletes created image. 389 | void nvgDeleteImage(NVGcontext* ctx, int image); 390 | 391 | // 392 | // Paints 393 | // 394 | // NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern. 395 | // These can be used as paints for strokes and fills. 396 | 397 | // Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates 398 | // of the linear gradient, icol specifies the start color and ocol the end color. 399 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 400 | NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey, 401 | NVGcolor icol, NVGcolor ocol); 402 | 403 | // Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering 404 | // drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle, 405 | // (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry 406 | // the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient. 407 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 408 | NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h, 409 | float r, float f, NVGcolor icol, NVGcolor ocol); 410 | 411 | // Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify 412 | // the inner and outer radius of the gradient, icol specifies the start color and ocol the end color. 413 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 414 | NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, 415 | NVGcolor icol, NVGcolor ocol); 416 | 417 | // Creates and returns an image pattern. Parameters (ox,oy) specify the left-top location of the image pattern, 418 | // (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. 419 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 420 | NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey, 421 | float angle, int image, float alpha); 422 | 423 | // 424 | // Scissoring 425 | // 426 | // Scissoring allows you to clip the rendering into a rectangle. This is useful for various 427 | // user interface cases like rendering a text edit or a timeline. 428 | 429 | // Sets the current scissor rectangle. 430 | // The scissor rectangle is transformed by the current transform. 431 | void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h); 432 | 433 | // Intersects current scissor rectangle with the specified rectangle. 434 | // The scissor rectangle is transformed by the current transform. 435 | // Note: in case the rotation of previous scissor rect differs from 436 | // the current one, the intersection will be done between the specified 437 | // rectangle and the previous scissor rectangle transformed in the current 438 | // transform space. The resulting shape is always rectangle. 439 | void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h); 440 | 441 | // Reset and disables scissoring. 442 | void nvgResetScissor(NVGcontext* ctx); 443 | 444 | // 445 | // Paths 446 | // 447 | // Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths. 448 | // Then you define one or more paths and sub-paths which describe the shape. The are functions 449 | // to draw common shapes like rectangles and circles, and lower level step-by-step functions, 450 | // which allow to define a path curve by curve. 451 | // 452 | // NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise 453 | // winding and holes should have counter clockwise order. To specify winding of a path you can 454 | // call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW. 455 | // 456 | // Finally you can fill the path using current fill style by calling nvgFill(), and stroke it 457 | // with current stroke style by calling nvgStroke(). 458 | // 459 | // The curve segments and sub-paths are transformed by the current transform. 460 | 461 | // Clears the current path and sub-paths. 462 | void nvgBeginPath(NVGcontext* ctx); 463 | 464 | // Starts new sub-path with specified point as first point. 465 | void nvgMoveTo(NVGcontext* ctx, float x, float y); 466 | 467 | // Adds line segment from the last point in the path to the specified point. 468 | void nvgLineTo(NVGcontext* ctx, float x, float y); 469 | 470 | // Adds cubic bezier segment from last point in the path via two control points to the specified point. 471 | void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y); 472 | 473 | // Adds quadratic bezier segment from last point in the path via a control point to the specified point. 474 | void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y); 475 | 476 | // Adds an arc segment at the corner defined by the last path point, and two specified points. 477 | void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius); 478 | 479 | // Closes current sub-path with a line segment. 480 | void nvgClosePath(NVGcontext* ctx); 481 | 482 | // Sets the current sub-path winding, see NVGwinding and NVGsolidity. 483 | void nvgPathWinding(NVGcontext* ctx, int dir); 484 | 485 | // Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, 486 | // and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW). 487 | // Angles are specified in radians. 488 | void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir); 489 | 490 | // Creates new rectangle shaped sub-path. 491 | void nvgRect(NVGcontext* ctx, float x, float y, float w, float h); 492 | 493 | // Creates new rounded rectangle shaped sub-path. 494 | void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r); 495 | 496 | // Creates new rounded rectangle shaped sub-path with varying radii for each corner. 497 | void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft); 498 | 499 | // Creates new ellipse shaped sub-path. 500 | void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry); 501 | 502 | // Creates new circle shaped sub-path. 503 | void nvgCircle(NVGcontext* ctx, float cx, float cy, float r); 504 | 505 | // Fills the current path with current fill style. 506 | void nvgFill(NVGcontext* ctx); 507 | 508 | // Fills the current path with current stroke style. 509 | void nvgStroke(NVGcontext* ctx); 510 | 511 | 512 | // 513 | // Text 514 | // 515 | // NanoVG allows you to load .ttf files and use the font to render text. 516 | // 517 | // The appearance of the text can be defined by setting the current text style 518 | // and by specifying the fill color. Common text and font settings such as 519 | // font size, letter spacing and text align are supported. Font blur allows you 520 | // to create simple text effects such as drop shadows. 521 | // 522 | // At render time the font face can be set based on the font handles or name. 523 | // 524 | // Font measure functions return values in local space, the calculations are 525 | // carried in the same resolution as the final rendering. This is done because 526 | // the text glyph positions are snapped to the nearest pixels sharp rendering. 527 | // 528 | // The local space means that values are not rotated or scale as per the current 529 | // transformation. For example if you set font size to 12, which would mean that 530 | // line height is 16, then regardless of the current scaling and rotation, the 531 | // returned line height is always 16. Some measures may vary because of the scaling 532 | // since aforementioned pixel snapping. 533 | // 534 | // While this may sound a little odd, the setup allows you to always render the 535 | // same way regardless of scaling. I.e. following works regardless of scaling: 536 | // 537 | // const char* txt = "Text me up."; 538 | // nvgTextBounds(vg, x,y, txt, NULL, bounds); 539 | // nvgBeginPath(vg); 540 | // nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); 541 | // nvgFill(vg); 542 | // 543 | // Note: currently only solid color fill is supported for text. 544 | 545 | // Creates font by loading it from the disk from specified file name. 546 | // Returns handle to the font. 547 | int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename); 548 | 549 | // fontIndex specifies which font face to load from a .ttf/.ttc file. 550 | int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex); 551 | 552 | // Creates font by loading it from the specified memory chunk. 553 | // Returns handle to the font. 554 | int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData); 555 | 556 | // fontIndex specifies which font face to load from a .ttf/.ttc file. 557 | int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex); 558 | 559 | // Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. 560 | int nvgFindFont(NVGcontext* ctx, const char* name); 561 | 562 | // Adds a fallback font by handle. 563 | int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont); 564 | 565 | // Adds a fallback font by name. 566 | int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont); 567 | 568 | // Resets fallback fonts by handle. 569 | void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont); 570 | 571 | // Resets fallback fonts by name. 572 | void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont); 573 | 574 | // Sets the font size of current text style. 575 | void nvgFontSize(NVGcontext* ctx, float size); 576 | 577 | // Sets the blur of current text style. 578 | void nvgFontBlur(NVGcontext* ctx, float blur); 579 | 580 | // Sets the letter spacing of current text style. 581 | void nvgTextLetterSpacing(NVGcontext* ctx, float spacing); 582 | 583 | // Sets the proportional line height of current text style. The line height is specified as multiple of font size. 584 | void nvgTextLineHeight(NVGcontext* ctx, float lineHeight); 585 | 586 | // Sets the text align of current text style, see NVGalign for options. 587 | void nvgTextAlign(NVGcontext* ctx, int align); 588 | 589 | // Sets the font face based on specified id of current text style. 590 | void nvgFontFaceId(NVGcontext* ctx, int font); 591 | 592 | // Sets the font face based on specified name of current text style. 593 | void nvgFontFace(NVGcontext* ctx, const char* font); 594 | 595 | // Draws text string at specified location. If end is specified only the sub-string up to the end is drawn. 596 | float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end); 597 | 598 | // Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. 599 | // White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. 600 | // Words longer than the max width are slit at nearest character (i.e. no hyphenation). 601 | void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end); 602 | 603 | // Measures the specified text string. Parameter bounds should be a pointer to float[4], 604 | // if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] 605 | // Returns the horizontal advance of the measured text (i.e. where the next character should drawn). 606 | // Measured values are returned in local coordinate space. 607 | float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds); 608 | 609 | // Measures the specified multi-text string. Parameter bounds should be a pointer to float[4], 610 | // if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] 611 | // Measured values are returned in local coordinate space. 612 | void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); 613 | 614 | // Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. 615 | // Measured values are returned in local coordinate space. 616 | int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions); 617 | 618 | // Returns the vertical metrics based on the current text style. 619 | // Measured values are returned in local coordinate space. 620 | void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh); 621 | 622 | // Breaks the specified text into lines. If end is specified only the sub-string will be used. 623 | // White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. 624 | // Words longer than the max width are slit at nearest character (i.e. no hyphenation). 625 | int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows); 626 | 627 | // 628 | // Internal Render API 629 | // 630 | enum NVGtexture { 631 | NVG_TEXTURE_ALPHA = 0x01, 632 | NVG_TEXTURE_RGBA = 0x02, 633 | }; 634 | 635 | struct NVGscissor { 636 | float xform[6]; 637 | float extent[2]; 638 | }; 639 | typedef struct NVGscissor NVGscissor; 640 | 641 | struct NVGvertex { 642 | float x,y,u,v; 643 | }; 644 | typedef struct NVGvertex NVGvertex; 645 | 646 | struct NVGpath { 647 | int first; 648 | int count; 649 | unsigned char closed; 650 | int nbevel; 651 | NVGvertex* fill; 652 | int nfill; 653 | NVGvertex* stroke; 654 | int nstroke; 655 | int winding; 656 | int convex; 657 | }; 658 | typedef struct NVGpath NVGpath; 659 | 660 | struct NVGparams { 661 | void* userPtr; 662 | int edgeAntiAlias; 663 | int (*renderCreate)(void* uptr); 664 | int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); 665 | int (*renderDeleteTexture)(void* uptr, int image); 666 | int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); 667 | int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); 668 | void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio); 669 | void (*renderCancel)(void* uptr); 670 | void (*renderFlush)(void* uptr); 671 | void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); 672 | void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths); 673 | void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts, float fringe); 674 | void (*renderDelete)(void* uptr); 675 | }; 676 | typedef struct NVGparams NVGparams; 677 | 678 | // Constructor and destructor, called by the render back-end. 679 | NVGcontext* nvgCreateInternal(NVGparams* params); 680 | void nvgDeleteInternal(NVGcontext* ctx); 681 | 682 | NVGparams* nvgInternalParams(NVGcontext* ctx); 683 | 684 | // Debug function to dump cached path data. 685 | void nvgDebugDumpPathCache(NVGcontext* ctx); 686 | 687 | #ifdef _MSC_VER 688 | #pragma warning(pop) 689 | #endif 690 | 691 | #define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; } 692 | 693 | #ifdef __cplusplus 694 | } 695 | #endif 696 | 697 | #endif // NANOVG_H 698 | --------------------------------------------------------------------------------