diff --git a/CMakeLists.txt b/CMakeLists.txt index 55bfc94..5c45f64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option(HG_ENABLE_ASAN "Harfang: Enable ASAN" OFF) # ----------------------------------------------------------------------------- # Build options # ----------------------------------------------------------------------------- +option(HG_BUILD_HARFANG_STATIC "Harfang: Build Harfang static" OFF) option(HG_BUILD_ASSIMP_CONVERTER "Harfang: Build Assimp converter" ON) option(HG_BUILD_FBX_CONVERTER "Harfang: Build FBX converter" ON) option(HG_BUILD_GLTF_EXPORTER "Harfang: Build GLTF exporter" ON) @@ -74,7 +75,7 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") message(STATUS "! Disabling GLFW since building for Emscripten") - set(HG_USE_GLFW OFF FORCE) + set(HG_USE_GLFW OFF CACHE BOOL "Harfang: Use GLFW backend" FORCE) endif() if(HG_ENABLE_SRANIPAL_API AND MSVC) @@ -105,18 +106,20 @@ if(MSVC) # Don't forget to remove this as soon as CMake is fixed. # Tells MSVC to update __cplusplus value, otherwise it will be stuck to 199711L and libraries like bx (if updated) won't compile anymore even if we set CMAKE_CXX_STANDARD to C++14. add_compile_options(/Zc:__cplusplus) +elseif(MINGW) + add_compile_options(-fpermissive -lstdc++ -lstdc++fs) elseif(ANDROID) add_compile_definitions(ANDROID) elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") message(STATUS "Emscripten sets") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --bind -fPIC -DEMSCRIPTEN -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s OFFSCREENCANVAS_SUPPORT=1 -s LLD_REPORT_UNDEFINED -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s FORCE_FILESYSTEM=1 -DBGFX_CONFIG_RENDERER_OPENGLES_MIN_VERSION=30") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --bind -fPIC -DEMSCRIPTEN -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s OFFSCREENCANVAS_SUPPORT=1 -s LLD_REPORT_UNDEFINED -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s FORCE_FILESYSTEM=1 -DBGFX_CONFIG_RENDERER_OPENGLES_MIN_VERSION=30") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --bind -fPIC -DEMSCRIPTEN -s MAX_WEBGL_VERSION=2 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s OFFSCREENCANVAS_SUPPORT=1 -s LLD_REPORT_UNDEFINED -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s FORCE_FILESYSTEM=1 -DBGFX_CONFIG_RENDERER_OPENGLES_MIN_VERSION=30") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --bind -fPIC -DEMSCRIPTEN -s MAX_WEBGL_VERSION=2 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s OFFSCREENCANVAS_SUPPORT=1 -s LLD_REPORT_UNDEFINED -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s FORCE_FILESYSTEM=1 -DBGFX_CONFIG_RENDERER_OPENGLES_MIN_VERSION=30") # without pthread and with wasm - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -s WASM=1 -Oz -DNDEBUG -s DISABLE_EXCEPTION_CATCHING=0 -s FORCE_FILESYSTEM=1") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -s WASM=1 -Oz -DNDEBUG -s DISABLE_EXCEPTION_CATCHING=0 -s FORCE_FILESYSTEM=1") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -s WASM=1 -O0 -DNDEBUG -g4 -s ASSERTIONS=2 -s DEMANGLE_SUPPORT=1 -s FORCE_FILESYSTEM=1") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -s WASM=1 -O0 -DNDEBUG -g4 -s ASSERTIONS=2 -s DEMANGLE_SUPPORT=1 -s FORCE_FILESYSTEM=1") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -s STANDALONE_WASM=1 -s WASM=1 -Oz -DNDEBUG -s DISABLE_EXCEPTION_CATCHING=0 -s FORCE_FILESYSTEM=1") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -s STANDALONE_WASM=1 -s WASM=1 -Oz -DNDEBUG -s DISABLE_EXCEPTION_CATCHING=0 -s FORCE_FILESYSTEM=1") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -s STANDALONE_WASM=1 -s WASM=1 -O0 -DNDEBUG -g4 -s ASSERTIONS=2 -s DEMANGLE_SUPPORT=1 -s FORCE_FILESYSTEM=1") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -s STANDALONE_WASM=1 -s WASM=1 -O0 -DNDEBUG -g4 -s ASSERTIONS=2 -s DEMANGLE_SUPPORT=1 -s FORCE_FILESYSTEM=1") else() set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(NOT APPLE) @@ -293,14 +296,16 @@ function(install_cppsdk_dependencies Destination) set(ComponentName ${Destination}) endif() - if(HG_USE_GLFW) - install(FILES $ DESTINATION ${Destination} COMPONENT ${ComponentName}) - endif() + if(NOT HG_BUILD_HARFANG_STATIC) + if(HG_USE_GLFW) + install(FILES $ DESTINATION ${Destination} COMPONENT ${ComponentName}) + endif() - install(FILES $ DESTINATION ${Destination} COMPONENT ${ComponentName}) - if(HG_ENABLE_OPENVR_API) - get_target_property(OpenVRTargetFiles OpenVR IMPORTED_LOCATION) - install(FILES ${OpenVRTargetFiles} DESTINATION ${Destination} COMPONENT ${ComponentName}) + install(FILES $ DESTINATION ${Destination} COMPONENT ${ComponentName}) + if(HG_ENABLE_OPENVR_API) + get_target_property(OpenVRTargetFiles OpenVR IMPORTED_LOCATION) + install(FILES ${OpenVRTargetFiles} DESTINATION ${Destination} COMPONENT ${ComponentName}) + endif() endif() if(HG_ENABLE_SRANIPAL_API) @@ -407,7 +412,9 @@ message(STATUS "") # ----------------------------------------------------------------------------- # [WARNING] Don't forget to add any new shared library target to this list! -set(HG_SHARED_LIBRARY_TARGETS "hg::glfw;hg::libluadll") +if(NOT HG_BUILD_HARFANG_STATIC) + set(HG_SHARED_LIBRARY_TARGETS "hg::glfw;hg::libluadll") +endif() if(HG_ENABLE_OPENVR_API) list(APPEND HG_SHARED_LIBRARY_TARGETS OpenVR) if(HG_ENABLE_SRANIPAL_API) diff --git a/binding/bind_harfang.py b/binding/bind_harfang.py index 0a9bc19..72bde5a 100644 --- a/binding/bind_harfang.py +++ b/binding/bind_harfang.py @@ -600,6 +600,7 @@ def bind_platform(gen): # hg::FileFilter file_filter = gen.begin_class('hg::FileFilter') + gen.bind_constructor(file_filter, []) gen.bind_members(file_filter, ['std::string name', 'std::string pattern']) gen.end_class(file_filter) @@ -1574,7 +1575,7 @@ def bind_bullet3_physics(gen): gen.bind_method(bullet, 'StepSimulation', 'void', ['hg::time_ns display_dt', '?hg::time_ns step_dt', '?int max_step']) - gen.bind_method(bullet, 'CollectCollisionEvents', 'void', ['const hg::Scene &scene', 'hg::NodePairContacts &node_pair_contacts']) + gen.bind_method(bullet, 'CollectCollisionEvents', 'void', ['const hg::Scene &scene', 'hg::NodePairContacts &node_pair_contacts'], {'arg_out': ['node_pair_contacts']}) gen.bind_method(bullet, 'SyncTransformsFromScene', 'void', ['const hg::Scene &scene']) gen.bind_method(bullet, 'SyncTransformsToScene', 'void', ['hg::Scene &scene']) @@ -4389,6 +4390,11 @@ def bind(gen): if not gen.embedded: insert_non_embedded_setup_free_code(gen) + if gen.get_language() == 'Go': + gen.set_compilation_directives("// #cgo linux pkg-config: gtk+-3.0\n" \ + "// #cgo linux LDFLAGS: -L${SRCDIR}/linux -lhg_go -lharfang -lm -lstdc++ -Wl,--no-as-needed -ldl -lGL -lXrandr -lXext -lX11 -lglib-2.0\n" \ + "// #cgo windows LDFLAGS: -L${SRCDIR}/windows -lhg_go -lharfang -lGdi32 -lDbghelp -lshell32 -loleaut32 -luuid -lcomdlg32 -lOle32 -lWinmm -lstdc++\n") + void_ptr = gen.bind_ptr('void *', bound_name='VoidPointer') gen.insert_binding_code('static void * _int_to_VoidPointer(intptr_t ptr) { return reinterpret_cast(ptr); }') gen.bind_function('int_to_VoidPointer', 'void *', ['intptr_t ptr'], {'route': route_lambda('_int_to_VoidPointer')}) diff --git a/doc/doc/man.Physics.md b/doc/doc/man.Physics.md index 489100e..81841ce 100644 --- a/doc/doc/man.Physics.md +++ b/doc/doc/man.Physics.md @@ -23,7 +23,7 @@ The rigid body intertia tensor is computed from its collision shape properties. ## Simulating Physics -Create a physics backend such as [SceneNewtonPhysics] and call [SceneBullet3Physics_SceneCreatePhysicsFromAssets] to create the physics states corresponding to the scene declaration. +Create a physics backend such as [SceneBullet3Physics] and call [SceneBullet3Physics_SceneCreatePhysicsFromAssets] to create the physics states corresponding to the scene declaration. *Note:* [SceneBullet3Physics_SceneCreatePhysicsFromAssets] means that if setting up the physics states requires access to an external resource, such as a mesh, it should be loaded from the assets system. If you are working from the filesystem, use [SceneBullet3Physics_SceneCreatePhysicsFromFile]. @@ -33,9 +33,9 @@ This involves 3 steps on each update: 1. Synchronize physics state with the scene declaration using [SceneBullet3Physics_SceneCreatePhysicsFromAssets]. Alternatively, you can use a more fine-grained approach using [SceneBullet3Physics_NodeCreatePhysicsFromAssets] to improve performance. 2. Step the simulation using [SceneBullet3Physics_StepSimulation]. -3. Synchronize the updated physics transformations to the scene using [SceneBullet3Physics_SyncDynamicBodiesToScene]. +3. Synchronize the updated physics transformations to the scene using [SceneBullet3Physics_SyncTransformsToScene]. -*Note:* If you are using kinematic bodies you will also need to synchronize them from their node transformation on each update using [SceneBullet3Physics_SyncKinematicBodiesFromScene]. +*Note:* If you are using kinematic bodies you will also need to synchronize them from their node transformation on each update using [SceneBullet3Physics_SyncTransformsFromScene]. ### The Easy Way diff --git a/doc/doc/man.Views.md b/doc/doc/man.Views.md index d8d6632..8350486 100644 --- a/doc/doc/man.Views.md +++ b/doc/doc/man.Views.md @@ -33,9 +33,9 @@ Views with no queued draw commands are skipped. If you need to force the process Draw commands queued on a view are processed according to the view mode, they are executed: - In submission order if the view mode is [VM_Sequential]. -- In ascending depth order if the view mode is [VM_Ascending]. -- In descending depth order if the view mode is [VM_Descending]. +- In ascending depth order if the view mode is [VM_DepthAscending]. +- In descending depth order if the view mode is [VM_DepthDescending]. -When the view mode is [VM_Ascending] or [VM_Descending], the depth value used to sort draw commands is derived from the draw call *depth* parameter. +When the view mode is [VM_DepthAscending] or [VM_DepthDescending], the depth value used to sort draw commands is derived from the draw call *depth* parameter. When no depth is specified, 0 is implied. diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 6e1f0dc..30fb84e 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -71,7 +71,11 @@ if(HG_USE_GLFW) if(HG_REBUILD_GLFW) # build it from sources - set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries" FORCE) + if(HG_BUILD_HARFANG_STATIC) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE) + else() + set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries" FORCE) + endif() set(GLFW_INSTALL OFF CACHE BOOL "") set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "") set(GLFW_BUILD_TESTS OFF CACHE BOOL "") @@ -121,7 +125,7 @@ install_cppsdk_external_target(nvtt) install_cppsdk_external_target(pvrtc) # Lua -if(UNIX AND NOT APPLE) +if(UNIX AND NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")) # lua links against libreadline but does not check for its availability. find_package(readline REQUIRED) endif() @@ -204,6 +208,7 @@ if(HG_BUILD_CPP_SDK) endif() # OpenAL soft +if(NOT (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")) message("Configuring OpenAL soft") set(ALSOFT_UTILS OFF CACHE BOOL "OpenAL soft: Build and install utility programs") @@ -225,6 +230,8 @@ set_property(TARGET OpenAL PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OpenAL_inclu install_cppsdk_external_target(OpenAL) +endif() + # json.hpp add_library(jsonhpp INTERFACE) target_include_directories(jsonhpp @@ -334,6 +341,7 @@ if(HG_ENABLE_RECAST_DETOUR_API) endif() # CMFT +if(NOT MINGW) add_executable(cmft cmft/src/cmft/common/stb_image.cpp cmft/src/cmft/common/print.cpp @@ -350,6 +358,7 @@ if(UNIX) target_compile_definitions(cmft PRIVATE linux) target_link_libraries(cmft pthread dl) endif() +endif() # meshoptimizer set(CMAKE_INSTALL_INCLUDEDIR ${CppSdkHeadersDestination}/extern) @@ -357,6 +366,15 @@ add_subdirectory(meshoptimizer EXCLUDE_FROM_ALL) set_target_properties(meshoptimizer PROPERTIES FOLDER "harfang/3rdparty") install_cppsdk_external_target(meshoptimizer) +# meshoptimizer: in emscripten remove some compile options flag +if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + get_target_property(_target_cxx_flags meshoptimizer COMPILE_OPTIONS) + if(_target_cxx_flags) + list(REMOVE_ITEM _target_cxx_flags -Wall -Wextra -Wshadow -Werror) + set_target_properties(meshoptimizer PROPERTIES COMPILE_OPTIONS "${_target_cxx_flags}") + endif() +endif() + # mikktspace add_library(mikktspace STATIC mikktspace/mikktspace.c mikktspace/mikktspace.h) target_include_directories(mikktspace PUBLIC $) diff --git a/extern/bgfx/bgfx.cmake b/extern/bgfx/bgfx.cmake index aed59d2..bfb0913 100644 --- a/extern/bgfx/bgfx.cmake +++ b/extern/bgfx/bgfx.cmake @@ -12,7 +12,7 @@ set( BGFX_SRCS bgfx/src/renderer_d3d12.cpp bgfx/src/topology.cpp bgfx/src/renderer_d3d9.cpp bgfx/src/vertexlayout.cpp bgfx/src/renderer_nvn.cpp bgfx/src/renderer_webgpu.cpp - bgfx/src/renderer_agc.cpp + bgfx/src/glcontext_html5.cpp bgfx/src/renderer_agc.cpp ) set( BGFX_HDRS @@ -35,6 +35,7 @@ set( BGFX_HDRS bgfx/src/glcontext_glx.h bgfx/src/vs_clear.bin.h bgfx/src/glcontext_nsgl.h bgfx/src/vs_debugfont.bin.h bgfx/src/glcontext_wgl.h bgfx/src/renderer_webgpu.h + bgfx/src/glcontext_html5.h bgfx/include/bgfx/bgfx.h bgfx/include/bgfx/embedded_shader.h bgfx/include/bgfx/defines.h bgfx/include/bgfx/platform.h @@ -46,6 +47,7 @@ add_library( bgfx ${BGFX_SRCS} ${BGFX_HDRS} ) set_property( TARGET bgfx PROPERTY PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/bgfx/include/bgfx/bgfx.h ${CMAKE_CURRENT_SOURCE_DIR}/bgfx/include/bgfx/defines.h + ${CMAKE_CURRENT_SOURCE_DIR}/bgfx/include/bgfx/platform.h ) target_include_directories( bgfx PRIVATE @@ -56,6 +58,8 @@ target_include_directories( bgfx $ ) +target_compile_definitions( bgfx PRIVATE BGFX_GL_CONFIG_TEXTURE_READ_BACK_EMULATION=1 ) +target_compile_definitions( bgfx PRIVATE BGFX_GL_CONFIG_BLIT_EMULATION=1 ) if( MSVC ) target_compile_definitions( bgfx PRIVATE "_CRT_SECURE_NO_WARNINGS" ) endif() diff --git a/extern/bgfx/tools.cmake b/extern/bgfx/tools.cmake index 707b98d..a42576e 100644 --- a/extern/bgfx/tools.cmake +++ b/extern/bgfx/tools.cmake @@ -21,9 +21,11 @@ list( APPEND SPIRV_OPT_SRCS ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/opcode.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/operand.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/parsed_operand.cpp + ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/pch_source.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/print.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/software_version.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/spirv_endian.cpp + ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/spirv_fuzzer_options.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/spirv_optimizer_options.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/spirv_reducer_options.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/spirv_target_env.cpp @@ -34,6 +36,7 @@ list( APPEND SPIRV_OPT_SRCS ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/util/bit_vector.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/util/parse_number.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/util/string_utils.cpp + ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/util/timer.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/val/basic_block.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/val/construct.cpp ${CMAKE_CURRENT_LIST_DIR}/bgfx/3rdparty/spirv-tools/source/val/function.cpp diff --git a/extern/lua/CMakeLists.txt b/extern/lua/CMakeLists.txt index 1548a5b..c305628 100644 --- a/extern/lua/CMakeLists.txt +++ b/extern/lua/CMakeLists.txt @@ -85,7 +85,11 @@ if (WIN32) target_compile_definitions(liblua PUBLIC _CRT_SECURE_NO_WARNINGS) endif() +if(HG_BUILD_HARFANG_STATIC) +add_library(libluadll STATIC ${SRC_CORE} ${SRC_LIB}) +else() add_library(libluadll SHARED ${SRC_CORE} ${SRC_LIB}) +endif() target_include_directories(libluadll PUBLIC $ @@ -96,7 +100,7 @@ if(WIN32) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") target_compile_definitions(libluadll PUBLIC LUA_USE_LINUX) endif() -set_target_properties(libluadll PROPERTIES OUTPUT_NAME lua53) +set_target_properties(libluadll PROPERTIES OUTPUT_NAME lua54) if(NOT WIN32) set(EXE_LIBS m readline dl) diff --git a/harfang/engine/audio.cpp b/harfang/engine/audio.cpp index 34438e1..a755887 100644 --- a/harfang/engine/audio.cpp +++ b/harfang/engine/audio.cpp @@ -10,6 +10,7 @@ #include "engine/ogg_audio_stream.h" #include "engine/wav_audio_stream.h" +#ifndef EMSCRIPTEN #include #include @@ -624,3 +625,4 @@ void StopAllSources() { } } // namespace hg +#endif \ No newline at end of file diff --git a/harfang/engine/create_geometry.cpp b/harfang/engine/create_geometry.cpp index cb85bdf..4b57efc 100644 --- a/harfang/engine/create_geometry.cpp +++ b/harfang/engine/create_geometry.cpp @@ -188,22 +188,23 @@ Model CreateConeModel(const bgfx::VertexLayout &decl, float radius, float height subdiv_x = 3; } + const float z = height / 2.f; std::vector ref(subdiv_x + 2); for (int i = 0; i < subdiv_x; i++) { float t = 2.f * Pi * i / static_cast(subdiv_x); float cs = Cos(t); float sn = Sin(t); float x = radius * cs, y = radius * sn; - ref[i + 1] = builder.AddVertex({{x, 0, y}, {cs, 0.f, sn}}); + ref[i + 1] = builder.AddVertex({{x, -z, y}, {cs, 0.f, sn}}); } ref[subdiv_x + 1] = ref[0]; - ref[0] = builder.AddVertex({{0, height, 0}, {0, 1, 0}}); + ref[0] = builder.AddVertex({{0, z, 0}, {0, 1, 0}}); builder.AddPolygon(ref); std::reverse(ref.begin() + 1, ref.end()); - ref[0] = builder.AddVertex({{0, 0, 0}, {0, -1, 0}}); + ref[0] = builder.AddVertex({{0, -z, 0}, {0, -1, 0}}); builder.AddPolygon(ref); builder.EndList(0); @@ -217,14 +218,14 @@ Model CreateCapsuleModel(const bgfx::VertexLayout &decl, float radius, float hei if (subdiv_y < 1) subdiv_y = 1; - if (height < (2.f * radius)) + if (height <= 0.f) return CreateSphereModel(decl, radius, subdiv_x, subdiv_y); ModelBuilder builder; // cylinder std::vector ref(subdiv_x * 2); - const float z = height / 2.f - radius; + const float z = height / 2.f; for (int i = 0; i < subdiv_x; i++) { float t = 2.f * Pi * i / static_cast(subdiv_x); float cs = Cos(t); @@ -245,8 +246,8 @@ Model CreateCapsuleModel(const bgfx::VertexLayout &decl, float radius, float hei b0 = c0; } - VtxIdxType top = builder.AddVertex({{0.f, height / 2.f, 0.f}, {0.f, 1.f, 0.f}}); - VtxIdxType bottom = builder.AddVertex({{0.f, -height / 2.f, 0.f}, {0.f, -1.f, 0.f}}); + VtxIdxType top = builder.AddVertex({{0.f, height / 2.f + radius, 0.f}, {0.f, 1.f, 0.f}}); + VtxIdxType bottom = builder.AddVertex({{0.f, -height / 2.f - radius, 0.f}, {0.f, -1.f, 0.f}}); std::vector fan(2 + subdiv_x); diff --git a/harfang/engine/font.cpp b/harfang/engine/font.cpp index f97e75e..e117ab5 100644 --- a/harfang/engine/font.cpp +++ b/harfang/engine/font.cpp @@ -179,7 +179,10 @@ static void DrawText(bgfx::ViewId view_id, const Font &font, const std::vectorsecond; stbtt_aligned_quad quad; - stbtt_packedchar pc = {glyph.pc.box.sx, glyph.pc.box.sy, glyph.pc.box.ex, glyph.pc.box.ey, glyph.pc.offsets[0].x, glyph.pc.offsets[0].y, + stbtt_packedchar pc = {(unsigned short)glyph.pc.box.sx, (unsigned short)glyph.pc.box.sy, (unsigned short)glyph.pc.box.ex, + (unsigned short)glyph.pc.box.ey, + glyph.pc.offsets[0].x, + glyph.pc.offsets[0].y, glyph.pc.advance, glyph.pc.offsets[1].x, glyph.pc.offsets[1].y}; stbtt_GetPackedQuad(&pc, font.resolution, font.resolution, 0, &pos.x, &pos.y, &quad, 1); diff --git a/harfang/engine/scene_bullet3_physics.cpp b/harfang/engine/scene_bullet3_physics.cpp index 0ed4814..38ac216 100644 --- a/harfang/engine/scene_bullet3_physics.cpp +++ b/harfang/engine/scene_bullet3_physics.cpp @@ -230,6 +230,7 @@ void SceneBullet3Physics::NodeCreatePhysics(const Node &node, const Reader &ir, auto &_node = nodes[node.ref]; if (_node.body) { + world->removeRigidBody(_node.body); __DeleteRigidBody(_node.body); _node.body = nullptr; } @@ -261,6 +262,8 @@ void SceneBullet3Physics::NodeCreatePhysics(const Node &node, const Reader &ir, } else if (type == CT_Mesh) { if (auto tree = LoadCollisionTree(ir, ip, col.GetCollisionResource().c_str())) shapes.push_back(tree); + } else { + error(format("Collision Type not implemented: %1").arg(type)); } shapes.back()->setUserIndex(node.ref.idx); // ref back to node diff --git a/harfang/engine/scene_bullet3_physics.h b/harfang/engine/scene_bullet3_physics.h index ab90917..224a0ac 100644 --- a/harfang/engine/scene_bullet3_physics.h +++ b/harfang/engine/scene_bullet3_physics.h @@ -18,7 +18,7 @@ class Scene; // struct Bullet3Node { - btRigidBody *body{}; + btRigidBody *body{nullptr}; Vec3 scl{Vec3::One}; Mat4 ref_mtx{Mat4::Identity}; }; diff --git a/harfang/foundation/CMakeLists.txt b/harfang/foundation/CMakeLists.txt index 5399b0c..f37e4ed 100644 --- a/harfang/foundation/CMakeLists.txt +++ b/harfang/foundation/CMakeLists.txt @@ -164,7 +164,9 @@ set_property(TARGET foundation PROPERTY PUBLIC_HEADER "${HDRS}") set_target_properties(foundation PROPERTIES FOLDER "harfang") if(NOT WIN32) - find_package(uuid REQUIRED) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + find_package(uuid REQUIRED) + endif() target_link_libraries(foundation PUBLIC uuid) else() target_link_libraries(foundation PUBLIC Iphlpapi) diff --git a/harfang/foundation/file.cpp b/harfang/foundation/file.cpp index 9da6255..e2a0c6e 100644 --- a/harfang/foundation/file.cpp +++ b/harfang/foundation/file.cpp @@ -12,10 +12,10 @@ #define WIN32_LEAN_AND_MEAN #include #else -#include #include #include #endif +#include #include #include @@ -216,7 +216,12 @@ FileInfo GetFileInfo(const char *path) { if (stat(path, &info) != 0) return {false, 0, 0, 0}; #endif + +#if defined __CYGWIN__ + return {S_ISREG(info.st_mode) ? true : false, size_t(info.st_size), time_ns(info.st_ctime), time_ns(info.st_mtime)}; +#else return {info.st_mode & S_IFREG ? true : false, size_t(info.st_size), time_ns(info.st_ctime), time_ns(info.st_mtime)}; +#endif } // @@ -231,8 +236,11 @@ bool IsFile(const char *path) { if (stat(path, &info) != 0) return false; #endif - +#if defined __CYGWIN__ + if (S_ISREG(info.st_mode)) +#else if (info.st_mode & S_IFREG) +#endif return true; return false; } diff --git a/harfang/platform/CMakeLists.txt b/harfang/platform/CMakeLists.txt index e57292d..8fa7198 100644 --- a/harfang/platform/CMakeLists.txt +++ b/harfang/platform/CMakeLists.txt @@ -66,8 +66,10 @@ else() ) elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") list(APPEND SRCS - sdl/input_system.cpp + sdl/input_system_sdl.cpp + sdl/input_system_sdl.h sdl/window_system.cpp + sdl/platform_sdl.cpp ) else() list(APPEND SRCS @@ -91,7 +93,7 @@ elseif(ANDROID) target_include_directories(platform PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue) target_link_libraries(platform foundation android log) elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - target_link_libraries(platform foundation GL drm dl) + target_link_libraries(platform foundation GL dl) else() target_include_directories(platform PUBLIC ${GLFW_INCLUDE_DIRS}) target_link_libraries(platform foundation glfw) diff --git a/harfang/platform/sdl/input_system_sdl.cpp b/harfang/platform/sdl/input_system_sdl.cpp new file mode 100644 index 0000000..7754b20 --- /dev/null +++ b/harfang/platform/sdl/input_system_sdl.cpp @@ -0,0 +1,328 @@ +// HARFANG(R) Copyright (C) 2019 Emmanuel Julien, Movida Production. Released under GPL/LGPL/Commercial Licence, see licence.txt for details. +#include "platform/sdl/input_system_sdl.h" +#include "platform/input_system.h" +#include "foundation/cext.h" +#include "foundation/log.h" +#include "foundation/format.h" +#include "foundation/utf8.h" +#include "platform/window_system.h" +#include +#include +#include +#include + +namespace hg { + +static double wheel = 0, hwheel = 0; +static int inhibit_click = 0; + +MouseState previous_state; + +static MouseState ReadMouse() { + MouseState state = previous_state; + + state.wheel = 0; + int w, h; + + auto win = GetWindowInFocus(); + if (!GetWindowClientSize(win, w, h)) { + inhibit_click = 3; + return {}; + } + + // ...and update it + SDL_Event event; + while (SDL_PollEvent(&event)) + switch (event.type) { + case SDL_FINGERMOTION: { + // use only if there is one finger + if (SDL_GetTouchFinger(event.tfinger.touchId, 1)) + break; + state.x = float(event.tfinger.x) * w; + state.y = float(1.f - event.tfinger.y) * h; + } break; + + case SDL_FINGERDOWN: { + // use only if there is one finger + if (SDL_GetTouchFinger(event.tfinger.touchId, 1)) + break; + state.button[0] = true; + state.x = float(event.tfinger.x) * w; + state.y = float(1.f - event.tfinger.y) * h; + } break; + + case SDL_MULTIGESTURE: // use this for pinch + { + if (fabs(event.mgesture.dDist) > 0.002f) { + //Pinch open + if (event.mgesture.dDist > 0) { + state.wheel = 1; + } + //Pinch close + else { + state.wheel = -1; + } + } + } break; + + case SDL_FINGERUP: + // use only if there is one finger + if (SDL_GetTouchFinger(event.tfinger.touchId, 1)) + break; + state.button[0] = false; + break; + + case SDL_MOUSEMOTION: { + state.x = float(event.motion.x); + state.y = float(h - event.motion.y); + } break; + + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + switch (event.button.button) { + case SDL_BUTTON_LEFT: + state.button[0] = (event.button.state == SDL_PRESSED); + break; + case SDL_BUTTON_MIDDLE: + state.button[2] = (event.button.state == SDL_PRESSED); + break; + case SDL_BUTTON_RIGHT: + state.button[1] = (event.button.state == SDL_PRESSED); + break; + } + break; + + case SDL_MOUSEWHEEL: + if (event.wheel.y >= 1) // scroll up + state.wheel = 1; + else if (event.wheel.y <= -1) // scroll down + state.wheel = -1; + break; + } + + previous_state = state; + return state; +} + +// Keyboard + +static KeyboardState ReadKeyboard() { + auto handle = GetWindowHandle(GetWindowInFocus()); + if (!handle) + return {}; + + KeyboardState state; + + // ...and update it. + const Uint8 *keys = SDL_GetKeyboardState(nullptr); + + state.key[K_Up] = keys[SDL_SCANCODE_UP]; + state.key[K_Down] = keys[SDL_SCANCODE_DOWN]; + state.key[K_Left] = keys[SDL_SCANCODE_LEFT]; + state.key[K_Right] = keys[SDL_SCANCODE_RIGHT]; + + state.key[K_Escape] = keys[SDL_SCANCODE_ESCAPE]; + + state.key[K_Add] = keys[SDL_SCANCODE_KP_PLUS]; + state.key[K_Sub] = keys[SDL_SCANCODE_KP_MINUS]; + state.key[K_Mul] = keys[SDL_SCANCODE_KP_MULTIPLY]; + state.key[K_Div] = keys[SDL_SCANCODE_KP_DIVIDE]; + state.key[K_Enter] = keys[SDL_SCANCODE_KP_ENTER]; + + state.key[K_PrintScreen] = keys[SDL_SCANCODE_PRINTSCREEN]; + state.key[K_ScrollLock] = keys[SDL_SCANCODE_SCROLLLOCK]; + state.key[K_Pause] = keys[SDL_SCANCODE_PAUSE]; + state.key[K_NumLock] = keys[SDL_SCANCODE_NUMLOCKCLEAR]; + state.key[K_Return] = keys[SDL_SCANCODE_RETURN]; + + state.key[K_LShift] = keys[SDL_SCANCODE_LSHIFT]; + state.key[K_RShift] = keys[SDL_SCANCODE_RSHIFT]; + state.key[K_LCtrl] = keys[SDL_SCANCODE_LCTRL]; + state.key[K_RCtrl] = keys[SDL_SCANCODE_RCTRL]; + state.key[K_LAlt] = keys[SDL_SCANCODE_LALT]; + state.key[K_RAlt] = keys[SDL_SCANCODE_RALT]; + state.key[K_LWin] = keys[SDL_SCANCODE_LGUI]; + state.key[K_RWin] = keys[SDL_SCANCODE_RGUI]; + + state.key[K_Tab] = keys[SDL_SCANCODE_TAB]; + state.key[K_CapsLock] = keys[SDL_SCANCODE_CAPSLOCK]; + state.key[K_Space] = keys[SDL_SCANCODE_SPACE]; + state.key[K_Backspace] = keys[SDL_SCANCODE_BACKSPACE]; + state.key[K_Insert] = keys[SDL_SCANCODE_INSERT]; + state.key[K_Suppr] = keys[SDL_SCANCODE_DELETE]; + state.key[K_Home] = keys[SDL_SCANCODE_HOME]; + state.key[K_End] = keys[SDL_SCANCODE_END]; + state.key[K_PageUp] = keys[SDL_SCANCODE_PAGEUP]; + state.key[K_PageDown] = keys[SDL_SCANCODE_PAGEDOWN]; + + state.key[K_F1] = keys[SDL_SCANCODE_F1]; + state.key[K_F2] = keys[SDL_SCANCODE_F2]; + state.key[K_F3] = keys[SDL_SCANCODE_F3]; + state.key[K_F4] = keys[SDL_SCANCODE_F4]; + state.key[K_F5] = keys[SDL_SCANCODE_F5]; + state.key[K_F6] = keys[SDL_SCANCODE_F6]; + state.key[K_F7] = keys[SDL_SCANCODE_F7]; + state.key[K_F8] = keys[SDL_SCANCODE_F8]; + state.key[K_F9] = keys[SDL_SCANCODE_F9]; + state.key[K_F10] = keys[SDL_SCANCODE_F10]; + state.key[K_F11] = keys[SDL_SCANCODE_F11]; + state.key[K_F12] = keys[SDL_SCANCODE_F12]; + + state.key[K_Numpad0] = keys[SDL_SCANCODE_KP_0]; + state.key[K_Numpad1] = keys[SDL_SCANCODE_KP_1]; + state.key[K_Numpad2] = keys[SDL_SCANCODE_KP_2]; + state.key[K_Numpad3] = keys[SDL_SCANCODE_KP_3]; + state.key[K_Numpad4] = keys[SDL_SCANCODE_KP_4]; + state.key[K_Numpad5] = keys[SDL_SCANCODE_KP_5]; + state.key[K_Numpad6] = keys[SDL_SCANCODE_KP_6]; + state.key[K_Numpad7] = keys[SDL_SCANCODE_KP_7]; + state.key[K_Numpad8] = keys[SDL_SCANCODE_KP_8]; + state.key[K_Numpad9] = keys[SDL_SCANCODE_KP_9]; + + state.key[K_A] = keys[SDL_SCANCODE_A]; + state.key[K_B] = keys[SDL_SCANCODE_B]; + state.key[K_C] = keys[SDL_SCANCODE_C]; + state.key[K_D] = keys[SDL_SCANCODE_D]; + state.key[K_E] = keys[SDL_SCANCODE_E]; + state.key[K_F] = keys[SDL_SCANCODE_F]; + state.key[K_G] = keys[SDL_SCANCODE_G]; + state.key[K_H] = keys[SDL_SCANCODE_H]; + state.key[K_I] = keys[SDL_SCANCODE_I]; + state.key[K_J] = keys[SDL_SCANCODE_J]; + state.key[K_K] = keys[SDL_SCANCODE_K]; + state.key[K_L] = keys[SDL_SCANCODE_L]; + state.key[K_M] = keys[SDL_SCANCODE_M]; + state.key[K_N] = keys[SDL_SCANCODE_N]; + state.key[K_O] = keys[SDL_SCANCODE_O]; + state.key[K_P] = keys[SDL_SCANCODE_P]; + state.key[K_Q] = keys[SDL_SCANCODE_Q]; + state.key[K_R] = keys[SDL_SCANCODE_R]; + state.key[K_S] = keys[SDL_SCANCODE_S]; + state.key[K_T] = keys[SDL_SCANCODE_T]; + state.key[K_U] = keys[SDL_SCANCODE_U]; + state.key[K_V] = keys[SDL_SCANCODE_V]; + state.key[K_W] = keys[SDL_SCANCODE_W]; + state.key[K_X] = keys[SDL_SCANCODE_X]; + state.key[K_Y] = keys[SDL_SCANCODE_Y]; + state.key[K_Z] = keys[SDL_SCANCODE_Z]; + return state; +} + + +static const char *GetKeyName(Key key) { + static std::map key_to_sdl = { + {K_LShift, SDL_SCANCODE_LSHIFT}, + {K_RShift, SDL_SCANCODE_RSHIFT}, + {K_LCtrl, SDL_SCANCODE_LCTRL}, + {K_RCtrl, SDL_SCANCODE_RCTRL}, + {K_LAlt, SDL_SCANCODE_LALT}, + {K_RAlt, SDL_SCANCODE_RALT}, + {K_LWin, SDL_SCANCODE_LGUI}, + {K_RWin, SDL_SCANCODE_RGUI}, + {K_Tab, SDL_SCANCODE_TAB}, + {K_CapsLock, SDL_SCANCODE_CAPSLOCK}, + {K_Space, SDL_SCANCODE_SPACE}, + {K_Backspace, SDL_SCANCODE_BACKSPACE}, + {K_Insert, SDL_SCANCODE_INSERT}, + {K_Suppr, SDL_SCANCODE_DELETE}, + {K_Home, SDL_SCANCODE_HOME}, + {K_End, SDL_SCANCODE_END}, + {K_PageUp, SDL_SCANCODE_PAGEUP}, + {K_PageDown, SDL_SCANCODE_PAGEDOWN}, + {K_Up, SDL_SCANCODE_UP}, + {K_Down, SDL_SCANCODE_DOWN}, + {K_Left, SDL_SCANCODE_LEFT}, + {K_Right, SDL_SCANCODE_RIGHT}, + {K_Escape, SDL_SCANCODE_ESCAPE}, + {K_F1, SDL_SCANCODE_F1}, + {K_F2, SDL_SCANCODE_F2}, + {K_F3, SDL_SCANCODE_F3}, + {K_F4, SDL_SCANCODE_F4}, + {K_F5, SDL_SCANCODE_F5}, + {K_F6, SDL_SCANCODE_F6}, + {K_F7, SDL_SCANCODE_F7}, + {K_F8, SDL_SCANCODE_F8}, + {K_F9, SDL_SCANCODE_F9}, + {K_F10, SDL_SCANCODE_F10}, + {K_F11, SDL_SCANCODE_F11}, + {K_F12, SDL_SCANCODE_F12}, + {K_PrintScreen, SDL_SCANCODE_PRINTSCREEN}, + {K_ScrollLock, SDL_SCANCODE_SCROLLLOCK}, + {K_Pause, SDL_SCANCODE_PAUSE}, + {K_NumLock, SDL_SCANCODE_NUMLOCKCLEAR}, + {K_Return, SDL_SCANCODE_RETURN}, + {K_0, SDL_SCANCODE_0}, + {K_1, SDL_SCANCODE_1}, + {K_2, SDL_SCANCODE_2}, + {K_3, SDL_SCANCODE_3}, + {K_4, SDL_SCANCODE_4}, + {K_5, SDL_SCANCODE_5}, + {K_6, SDL_SCANCODE_6}, + {K_7, SDL_SCANCODE_7}, + {K_8, SDL_SCANCODE_8}, + {K_9, SDL_SCANCODE_9}, + {K_Numpad0, SDL_SCANCODE_KP_0}, + {K_Numpad1, SDL_SCANCODE_KP_1}, + {K_Numpad2, SDL_SCANCODE_KP_2}, + {K_Numpad3, SDL_SCANCODE_KP_3}, + {K_Numpad4, SDL_SCANCODE_KP_4}, + {K_Numpad5, SDL_SCANCODE_KP_5}, + {K_Numpad6, SDL_SCANCODE_KP_6}, + {K_Numpad7, SDL_SCANCODE_KP_7}, + {K_Numpad8, SDL_SCANCODE_KP_8}, + {K_Numpad9, SDL_SCANCODE_KP_9}, + {K_Add, SDL_SCANCODE_KP_PLUS}, + {K_Sub, SDL_SCANCODE_KP_MINUS}, + {K_Mul, SDL_SCANCODE_KP_MULTIPLY}, + {K_Div, SDL_SCANCODE_KP_DIVIDE}, + {K_Enter, SDL_SCANCODE_KP_ENTER}, + {K_A, SDL_SCANCODE_A}, + {K_B, SDL_SCANCODE_B}, + {K_C, SDL_SCANCODE_C}, + {K_D, SDL_SCANCODE_D}, + {K_E, SDL_SCANCODE_E}, + {K_F, SDL_SCANCODE_F}, + {K_G, SDL_SCANCODE_G}, + {K_H, SDL_SCANCODE_H}, + {K_I, SDL_SCANCODE_I}, + {K_J, SDL_SCANCODE_J}, + {K_K, SDL_SCANCODE_K}, + {K_L, SDL_SCANCODE_L}, + {K_M, SDL_SCANCODE_M}, + {K_N, SDL_SCANCODE_N}, + {K_O, SDL_SCANCODE_O}, + {K_P, SDL_SCANCODE_P}, + {K_Q, SDL_SCANCODE_Q}, + {K_R, SDL_SCANCODE_R}, + {K_S, SDL_SCANCODE_S}, + {K_T, SDL_SCANCODE_T}, + {K_U, SDL_SCANCODE_U}, + {K_V, SDL_SCANCODE_V}, + {K_W, SDL_SCANCODE_W}, + {K_X, SDL_SCANCODE_X}, + {K_Y, SDL_SCANCODE_Y}, + {K_Z, SDL_SCANCODE_Z}, + {K_Plus, SDL_SCANCODE_EQUALS}, + {K_Comma, SDL_SCANCODE_COMMA}, + {K_Minus, SDL_SCANCODE_MINUS}, + {K_Period, SDL_SCANCODE_PERIOD}, + }; + + const auto i = key_to_sdl.find(key); + if (i != std::end(key_to_sdl)) + return SDL_GetKeyName(SDL_GetKeyFromScancode((SDL_Scancode)i->second)); + + return nullptr; +} + + +static Signal::Connection on_new_window_connection; + +void InputInit() { + AddMouseReader("default", ReadMouse); + AddKeyboardReader("default", ReadKeyboard, GetKeyName); +} + +void InputShutdown() { new_window_signal.Disconnect(on_new_window_connection); } + +} // namespace hg diff --git a/harfang/platform/sdl/input_system_sdl.h b/harfang/platform/sdl/input_system_sdl.h new file mode 100644 index 0000000..86ba48c --- /dev/null +++ b/harfang/platform/sdl/input_system_sdl.h @@ -0,0 +1,10 @@ +// HARFANG(R) Copyright (C) 2019 Emmanuel Julien, Movida Production. Released under GPL/LGPL/Commercial Licence, see licence.txt for details. + +#pragma once + +namespace hg { + +void RegisterSDLInputSystem(); +void UnregisterSDLInputSystem(); + +} // namespace hg diff --git a/harfang/platform/sdl/platform_sdl.cpp b/harfang/platform/sdl/platform_sdl.cpp new file mode 100644 index 0000000..b43fca3 --- /dev/null +++ b/harfang/platform/sdl/platform_sdl.cpp @@ -0,0 +1,35 @@ +// HARFANG(R) Copyright (C) 2019 Emmanuel Julien, Movida Production. Released under GPL/LGPL/Commercial Licence, see licence.txt for details. + +#include "foundation/assert.h" +#include "foundation/format.h" +#include "foundation/log.h" +#include "foundation/path_tools.h" +#include "foundation/string.h" +#include "platform/input_system.h" + +namespace hg { + +bool InitPlatform() { + return true; +} + +std::string GetPlatformLocale() { + return "fr"; +} + +bool OpenFolderDialog(const std::string &title, std::string &OUTPUT, const std::string &initial_dir) { + return false; +} + +bool OpenFileDialog(const std::string &title, const std::string &filter, std::string &OUTPUT, const std::string &initial_dir) { + return false; +} + +bool SaveFileDialog(const std::string &title, const std::string &filter, std::string &OUTPUT, const std::string &initial_dir) { + return false; +} + +void DebugBreak() { } + + +} // namespace hg diff --git a/harfang/platform/sdl/readme.txt b/harfang/platform/sdl/readme.txt index e966ae2..2b86899 100644 --- a/harfang/platform/sdl/readme.txt +++ b/harfang/platform/sdl/readme.txt @@ -1,2 +1,2 @@ -SDL based input system module for the GS framework. +SDL based input system module for the Harfang framework. Emmanuel Julien 2013 \ No newline at end of file diff --git a/harfang/platform/sdl/window_system.cpp b/harfang/platform/sdl/window_system.cpp index 36cd3a9..3304c96 100644 --- a/harfang/platform/sdl/window_system.cpp +++ b/harfang/platform/sdl/window_system.cpp @@ -1,6 +1,7 @@ // HARFANG(R) Copyright (C) 2021 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details. #include "platform/window_system.h" +#include "foundation/format.h" #include "foundation/log.h" #include #include @@ -8,174 +9,170 @@ namespace hg { //-- Monitor -struct Monitor::Impl { + +struct Monitor { std::string id; iRect rect; bool primary; }; -Monitor::Monitor() : impl_(new Monitor::Impl()) {} -Monitor::~Monitor() = default; -Monitor::Monitor(const Monitor &m) : impl_(new Monitor::Impl(*m.impl_)) {} -Monitor::Monitor(Monitor &&) noexcept = default; -Monitor &Monitor::operator=(const Monitor &m) { - if (this != &m) { - impl_.reset(new Monitor::Impl(*m.impl_)); - } - return *this; -} -Monitor &Monitor::operator=(Monitor &&) noexcept = default; - -std::vector GetMonitors() { - std::vector monitors; +std::vector GetMonitors() { + std::vector monitors; return monitors; } -iRect GetMonitorRect(const Monitor &m) { return m.impl_->rect; } +iRect GetMonitorRect(const Monitor *m) { return m->rect; } -bool IsPrimaryMonitor(const Monitor &m) { return m.impl_->primary; } +bool IsPrimaryMonitor(const Monitor *m) { return m->primary; } // TODO Return true if the monitor is connected. -bool IsMonitorConnected(const Monitor &monitor) { return true; } +bool IsMonitorConnected(const Monitor *monitor) { return true; } // TODO Return monitor name. -std::string GetMonitorName(const Monitor &monitor) { return "TODO IN SDL"; } +std::string GetMonitorName(const Monitor *monitor) { return "TODO IN SDL"; } // TODO Return monitor size in millimeters. -iVec2 GetMonitorSizeMM(const Monitor &monitor) { return iVec2(0, 0); } +hg::iVec2 GetMonitorSizeMM(const Monitor *monitor) { return hg::iVec2(0, 0); } // TODO Get the list of screen modes for a given monitor. -bool GetMonitorModes(const Monitor &monitor, std::vector &modes) { return true; } +bool GetMonitorModes(const Monitor *monitor, std::vector &modes) { return true; } //-- Window // -struct SDLWindow { +struct Window { SDL_Window *w{0}; bool is_foreign{false}; }; -void WindowSystemInit() { SDL_Init(SDL_INIT_VIDEO); } +static Window *window_in_focus; -Window NewWindow(int width, int height, int bpp, Window::Visibility visibility) { +Signal new_window_signal; +Signal window_focus_signal; +Signal close_window_signal; +Signal destroy_window_signal; - Window w; - static_assert(sizeof(SDLWindow) <= sizeof(Window), "Window OS object size exceeds generic object size"); - auto data = reinterpret_cast(w.data.data()); +void WindowSystemInit() { + SDL_Init(SDL_INIT_VIDEO); - uint window_flag = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + // DISABLE ALL TEXT KEYBOARD + SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); + SDL_EventState(SDL_KEYDOWN, SDL_DISABLE); + SDL_EventState(SDL_KEYUP, SDL_DISABLE); +} + +Window *NewWindow(int width, int height, int bpp, WindowVisibility visibility) { + + Window *w = new Window(); + + int window_flag = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN; switch (visibility) { - case Window::Fullscreen: + case WV_Fullscreen: window_flag |= SDL_WINDOW_FULLSCREEN; break; - case Window::Undecorated: + case WV_Undecorated: window_flag |= SDL_WINDOW_BORDERLESS; break; default: - case Window::Windowed: + case WV_Windowed: break; } - data->w = SDL_CreateWindow("Harfang", 0, 0, width, height, window_flag); - - SetWindowTitle(w, "Harfang"); + w->w = SDL_CreateWindow(nullptr, 0, 0, width, height, window_flag); UpdateWindow(w); - debug(format("NewWindow: %1").arg((void *)data->w)); + debug(format("NewWindow: %1").arg((void *)w->w)); return w; } -Window NewWindowFrom(void *handle) { - Window w; - auto data = reinterpret_cast(w.data.data()); +Window *NewWindow(const char *title, int width, int height, int bpp, WindowVisibility visibility) { + auto win = NewWindow(width, height, bpp, visibility); + SetWindowTitle(win, title); + return win; +} - data->is_foreign = true; - data->w = reinterpret_cast(handle); +Window *NewWindowFrom(void *handle) { + Window *w = new Window(); - SDL_CreateWindowFrom(data->w); + w->is_foreign = true; + w->w = reinterpret_cast(handle); + + SDL_CreateWindowFrom(w->w); return w; } // TODO Create a new fullscreen window on a specified monitor. -Window NewFullscreenWindow(const Monitor &monitor, int mode_index, MonitorRotation rotation) { return NewWindow(512, 512, 32, Window::Windowed); } +Window *NewFullscreenWindow(const Monitor *monitor, int mode_index, MonitorRotation rotation) { return NewWindow(512, 512, 32, WV_Windowed); } void *GetDisplay() { return nullptr; } -void *GetWindowHandle(const Window &w) { return reinterpret_cast(reinterpret_cast(w.data.data())->w); } +static const char *canvas_name = "canvas"; +void *GetWindowHandle(const Window *w) { + return (void *)canvas_name; + // return reinterpret_cast(w->w); +} -Window GetWindowInFocus() { return g_window_system.get().window_in_focus; } +Window *GetWindowInFocus() { return window_in_focus; } -bool DestroyWindow(Window &w) { - auto data = reinterpret_cast(w.data.data()); - - debug(format("DestroyWindow: %1").arg((void *)data->w)); - g_window_system.get().window_focus_signal.Emit(w, false); - SDL_DestroyWindow(data->w); - data->w = 0; +bool DestroyWindow(Window *w) { + debug(format("DestroyWindow: %1").arg((void *)w->w)); + window_focus_signal.Emit(w, false); + SDL_DestroyWindow(w->w); + w->w = 0; + delete w; return true; } // -bool UpdateWindow(const Window &w) { +bool UpdateWindow(const Window *w) { - auto data = reinterpret_cast(w.data.data()); - - if (SDL_GetWindowFlags(data->w) & SDL_WINDOW_INPUT_FOCUS) { + if (SDL_GetWindowFlags(w->w) & SDL_WINDOW_INPUT_FOCUS) { // in focus - if (!(g_window_system.get().window_in_focus == w)) { + if (!(window_in_focus == w)) { - g_window_system.get().window_in_focus = w; - g_window_system.get().window_focus_signal.Emit(w, true); + window_in_focus = (Window *)w; + window_focus_signal.Emit(w, true); } - } else if (g_window_system.get().window_in_focus == w) { + } else if (window_in_focus == w) { // not in focus - g_window_system.get().window_in_focus = Window(); // blank window - g_window_system.get().window_focus_signal.Emit(w, false); + window_in_focus = new Window(); // blank window + window_focus_signal.Emit(w, false); } return true; } // -bool GetWindowClientSize(const Window &w, int &width, int &height) { - auto data = reinterpret_cast(w.data.data()); - SDL_GetWindowSize(data->w, &width, &height); +bool GetWindowClientSize(const Window *w, int &width, int &height) { + if (!w) + return false; + SDL_GetWindowSize(w->w, &width, &height); return true; } -bool SetWindowClientSize(const Window &w, int width, int height) { - auto data = reinterpret_cast(w.data.data()); - SDL_SetWindowSize(data->w, width, height); +bool SetWindowClientSize(Window *w, int width, int height) { + if (!w) + return false; + SDL_SetWindowSize(w->w, width, height); return true; } -bool GetWindowTitle(const Window &w, std::string &title) { - auto data = reinterpret_cast(w.data.data()); - return true; -} +bool GetWindowTitle(const Window *w, std::string &title) { return true; } -bool SetWindowTitle(const Window &w, const std::string &title) { - auto data = reinterpret_cast(w.data.data()); - return true; -} +bool SetWindowTitle(Window *w, const std::string &title) { return true; } -bool WindowHasFocus(const Window &w) { - auto data = reinterpret_cast(w.data.data()); - return true; -} +bool WindowHasFocus(const Window *w) { return true; } -bool SetWindowPos(const Window &w, const iVec2 &v) { - auto data = reinterpret_cast(w.data.data()); - SDL_SetWindowPosition(data->w, v.x, v.y); +bool SetWindowPos(const Window *w, const hg::iVec2 &v) { + SDL_SetWindowPosition(w->w, v.x, v.y); UpdateWindow(w); // process messages on the spot return true; } -iVec2 GetWindowPos(const Window &w) { - auto data = reinterpret_cast(w.data.data()); +hg::iVec2 GetWindowPos(const Window *w) { UpdateWindow(w); - iVec2 pos; - SDL_GetWindowPosition(data->w, &pos.x, &pos.y); + hg::iVec2 pos; + SDL_GetWindowPosition(w->w, &pos.x, &pos.y); return pos; } diff --git a/harfang/version.txt b/harfang/version.txt index 06eda28..9b7a431 100644 --- a/harfang/version.txt +++ b/harfang/version.txt @@ -1 +1 @@ -3.2.3 \ No newline at end of file +3.2.4 \ No newline at end of file diff --git a/languages/hg_go/CMakeLists.txt b/languages/hg_go/CMakeLists.txt index 332afad..0dd7c5b 100644 --- a/languages/hg_go/CMakeLists.txt +++ b/languages/hg_go/CMakeLists.txt @@ -9,22 +9,24 @@ add_custom_command( ${CMAKE_CURRENT_BINARY_DIR}/binding/fabgen.h ${CMAKE_CURRENT_BINARY_DIR}/binding/go.mod COMMAND - ${Python3_EXECUTABLE} bind.py ${CMAKE_CURRENT_SOURCE_DIR}/../../binding/bind_harfang.py --go --out ${CMAKE_CURRENT_BINARY_DIR}/binding ${HG_BINDING_DEFINES} + ${Python3_EXECUTABLE} bind.py ${CMAKE_CURRENT_SOURCE_DIR}/../../binding/bind_harfang.py --go --out ${CMAKE_CURRENT_BINARY_DIR}/binding --doc_md_folder ${CMAKE_CURRENT_SOURCE_DIR}/../../doc/doc ${HG_BINDING_DEFINES} MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/../../binding/bind_harfang.py WORKING_DIRECTORY ${HG_FABGEN_PATH} COMMENT - "Generating Harfang binding for Go: go fabgen=${HG_FABGEN_PATH} srcdir=${CMAKE_SOURCE_DIR} dstdir=${CMAKE_CURRENT_BINARY_DIR}") + "Generating Harfang binding for Go: go fabgen=${HG_FABGEN_PATH} srcdir=${CMAKE_SOURCE_DIR} dstdir=${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS ${static_libs}) + -add_library(hg_go SHARED +add_library(hg_go STATIC ${CMAKE_CURRENT_BINARY_DIR}/binding/wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/binding/wrapper.h ${CMAKE_CURRENT_BINARY_DIR}/binding/fabgen.h) - -target_link_libraries(hg_go script engine foundation platform) + +target_link_libraries(hg_go PUBLIC script engine foundation platform) set_target_properties(hg_go PROPERTIES FOLDER "harfang/languages") -set_target_properties(hg_go PROPERTIES OUTPUT_NAME "harfang" ) + install(TARGETS hg_go RUNTIME DESTINATION hg_go @@ -42,6 +44,105 @@ install(FILES COMPONENT go ) +add_dependencies(hg_go bind_hg_lua) install_cppsdk_dependencies(hg_go go) +function(bundle_static_library tgt_name bundled_tgt_name) + list(APPEND static_libs ${tgt_name}) + + function(_recursively_collect_dependencies input_target) + set(_input_link_libraries LINK_LIBRARIES) + get_target_property(_input_type ${input_target} TYPE) + if (${_input_type} STREQUAL "INTERFACE_LIBRARY") + set(_input_link_libraries INTERFACE_LINK_LIBRARIES) + endif() + get_target_property(public_dependencies ${input_target} ${_input_link_libraries}) + foreach(dependency IN LISTS public_dependencies) + if(TARGET ${dependency}) + get_target_property(alias ${dependency} ALIASED_TARGET) + if (TARGET ${alias}) + set(dependency ${alias}) + endif() + get_target_property(_type ${dependency} TYPE) + if (${_type} STREQUAL "STATIC_LIBRARY") + list(APPEND static_libs ${dependency}) + endif() + + get_property(library_already_added + GLOBAL PROPERTY _${tgt_name}_static_bundle_${dependency}) + if (NOT library_already_added) + set_property(GLOBAL PROPERTY _${tgt_name}_static_bundle_${dependency} ON) + _recursively_collect_dependencies(${dependency}) + endif() + endif() + endforeach() + set(static_libs ${static_libs} PARENT_SCOPE) + endfunction() + + _recursively_collect_dependencies(${tgt_name}) + + list(REMOVE_DUPLICATES static_libs) + + set(bundled_tgt_full_name ${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${bundled_tgt_name}${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(bundled_tgt_full_name ${bundled_tgt_full_name} PARENT_SCOPE) + + if (CMAKE_CXX_COMPILER_ID MATCHES "^(Clang|GNU)$") + file(WRITE ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in + "CREATE ${bundled_tgt_full_name}\n" ) + + foreach(tgt IN LISTS static_libs) + file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in + "ADDLIB $\n") + endforeach() + + file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in "SAVE\n") + file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in "END\n") + + file(GENERATE + OUTPUT ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar + INPUT ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in) + + set(ar_tool ${CMAKE_AR}) + if (CMAKE_INTERPROCEDURAL_OPTIMIZATION) + set(ar_tool ${CMAKE_CXX_COMPILER_AR}) + endif() + + add_custom_command( + COMMAND ${ar_tool} -M < ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar + OUTPUT ${bundled_tgt_full_name} + COMMENT "Bundling ${bundled_tgt_name}" + VERBATIM) + elseif(MSVC) + find_program(lib_tool lib) + + foreach(tgt IN LISTS static_libs) + list(APPEND static_libs_full_names $) + endforeach() + + add_custom_command( + COMMAND ${lib_tool} /NOLOGO /OUT:${bundled_tgt_full_name} ${static_libs_full_names} + OUTPUT ${bundled_tgt_full_name} + COMMENT "Bundling ${bundled_tgt_name}" + VERBATIM) + else() + message(FATAL_ERROR "Unknown bundle scenario!") + endif() + + add_custom_target(bundling_target ALL DEPENDS ${bundled_tgt_full_name}) + add_dependencies(bundling_target ${tgt_name}) + + add_library(${bundled_tgt_name} STATIC IMPORTED) + set_target_properties(${bundled_tgt_name} + PROPERTIES + IMPORTED_LOCATION ${bundled_tgt_full_name} + INTERFACE_INCLUDE_DIRECTORIES $) + add_dependencies(${bundled_tgt_name} bundling_target) + set_target_properties(bundling_target PROPERTIES FOLDER "harfang/languages") + +endfunction() + +bundle_static_library(hg_go harfang) +install(FILES ${bundled_tgt_full_name} DESTINATION hg_go COMPONENT go) + + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF) \ No newline at end of file diff --git a/release-notes.md b/release-notes.md index 001ebce..2fa1467 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,3 +1,53 @@ +# [3.2.4] - 2022-09-27 + +This minor release provides minor corrections and fixes to specific issues: + - Fixed the OpenGL support of the rendering pipeline (see https://github.com/harfang3d/harfang-core-package). + - Improved the support of the Go language (see https://pkg.go.dev/github.com/harfang3d/harfang-go). + - Improved the Emscripten build. + +### Framework integration and source code maintenance + +- Ongoing effort to support the WASM / Emscripten target. + - Added a series of flags improve the compilation to WASM. + - Updated the SDL calls to support the latest inputs/windows system. + - :warning: Audio is disabled for now. + +### Binding / Golang support + +- Proper package of the Go binding. +- Added a _mingw_ build stage for the Windows lib part of HARFANG. +- Added a cmake flag `HG_BUILD_HARFANG_STATIC` to build HAFANG in static mode. +- Added a Go directive (based on FabGen merge request https://github.com/ejulien/FABGen/pull/60). +- Removed the non-mingw Go build from the Windows target. +- Updated cmake to build HARFANG Go as a monolithic lib. +- Reinstated the script support (to embed Lua in a Go project). +- The support for the _OpenVR_ API was (temporarily) removed. + +### Toolchain + +- **GLTF importer:** + - support for camera and lights (:warning: experimental) + - support for _point_, _directional_ and _spot_ types. + - support for the diffuse color and intensity (specular is not supported by the GLTF standard). + - Fixed a mislabelled _usage_. +- **Assetc:** added `jpeg` to the textures checklist. +- Fix #16 (lua53.dll should be lua54.dll). + +### Binding + +- Added a constructor to `FileFilter`. +- Fixed the arg out for `CollectCollisionEvents` to return a `NodePairContacts` properly. + +### Physics + +- Improved the ability of a node to change its collision shape component multiple times during runtime. +- Fix #17 Capsule / Cone model fix. + +### Documentation + +- Fixed a mention to `ViewMode` enums in the manual. +- Fixed the reference to 3 physics functions in the manual, `Bullet3Physics`, `SyncTransformsFromScene` and `SyncTransformsToScene`. + # [3.2.3] - 2022-07-13 This minor release brings several fixes to the rendering, physics, engine, foundation and tools. diff --git a/tools/assetc/assetc.cpp b/tools/assetc/assetc.cpp index 47705ce..bf61c73 100644 --- a/tools/assetc/assetc.cpp +++ b/tools/assetc/assetc.cpp @@ -1507,7 +1507,7 @@ struct AssetConfig { }; static AssetType GetAssetFileType(std::string path, const std::vector &all_files, std::vector &out_files) { - static const std::set texture_exts = {"bmp", "exr", "gif", "jpg", "hdr", "png", "psd", "tga"}; + static const std::set texture_exts = {"bmp", "exr", "gif", "jpg", "jpeg", "hdr", "png", "psd", "tga"}; static const std::set ignored_exts = {"tmp"}; const auto ext = tolower(GetFileExtension(path)); diff --git a/tools/gltf_converter/gltf_exporter.cpp b/tools/gltf_converter/gltf_exporter.cpp index 6ec91af..8cb0bca 100644 --- a/tools/gltf_converter/gltf_exporter.cpp +++ b/tools/gltf_converter/gltf_exporter.cpp @@ -917,6 +917,49 @@ static const size_t ExportObject(Model &model, const hg::Object &object, const C return id_mesh; } +static size_t ExportCamera(Model& model, const hg::Camera& cam) { + Camera gltf_camera; + + if (cam.GetIsOrthographic()) { + gltf_camera.type = "orthographic"; + gltf_camera.orthographic.znear = cam.GetZNear(); + gltf_camera.orthographic.zfar = cam.GetZFar(); + } else { + gltf_camera.type = "perspective"; + gltf_camera.perspective.znear = cam.GetZNear(); + gltf_camera.perspective.zfar = cam.GetZFar(); + gltf_camera.perspective.yfov = (double)cam.GetFov(); + } + + model.cameras.push_back(gltf_camera); + return model.cameras.size() - 1; +} + +static int ExportLight(Model &model, const hg::Light &light) { + Light gltf_light; + + gltf_light.color.push_back(light.GetDiffuseColor().r); + gltf_light.color.push_back(light.GetDiffuseColor().g); + gltf_light.color.push_back(light.GetDiffuseColor().b); + gltf_light.intensity = light.GetDiffuseIntensity(); + + gltf_light.spot.innerConeAngle = light.GetInnerAngle(); + gltf_light.spot.outerConeAngle = light.GetOuterAngle(); + + gltf_light.range = light.GetRadius(); + + if (light.GetType() == hg::LT_Point) { + gltf_light.type = "point"; + } else if (light.GetType() == hg::LT_Linear) { + gltf_light.type = "directional"; + } else if (light.GetType() == hg::LT_Spot) { + gltf_light.type = "spot"; + } + + model.lights.push_back(gltf_light); + return model.lights.size() - 1; +} + // static const int ExportNode(Model &model, const hg::NodeRef nodeRef, const std::vector &children, const hg::NodesChildren &nodes_children, const hg::Scene &scene, const Config &config, hg::PipelineResources &resources) { @@ -957,12 +1000,19 @@ static const int ExportNode(Model &model, const hg::NodeRef nodeRef, const std:: n.scale.push_back(s.y); n.scale.push_back(s.z); } - - /* + // is it a camera - if (gltf_node.camera >= 0) - ExportCamera(model, gltf_node, node, scene, config, resources); - */ + if (node.HasCamera()) { + n.camera = ExportCamera(model, node.GetCamera()); + } + + // is it a light + if (node.HasLight()) { + if (std::find(model.extensionsUsed.begin(), model.extensionsUsed.end(), "KHR_lights_punctual") == model.extensionsUsed.end()) + model.extensionsUsed.push_back("KHR_lights_punctual"); + n.extensions["KHR_lights_punctual"] = Value({{"light", Value(ExportLight(model, node.GetLight()))}}); + } + // if (node.HasObject()) { auto id_mesh = ExportObject(model, node.GetObject(), config, resources); diff --git a/tools/gltf_converter/gltf_importer.cpp b/tools/gltf_converter/gltf_importer.cpp index cab3f71..6f910ce 100644 --- a/tools/gltf_converter/gltf_importer.cpp +++ b/tools/gltf_converter/gltf_importer.cpp @@ -735,7 +735,7 @@ static hg::Material ExportMaterial(const Model &model, const Material &gltf_mat, hg::debug(hg::format(" - Using pipeline shader '%1'").arg(shader)); mat.program = resources.programs.Add(shader.c_str(), {}); - // FinalizeMaterial(mat, fbx_material->GetName(), geo_name); + // FinalizeMaterial(mat, gltf_material->GetName(), geo_name); return mat; } @@ -1313,7 +1313,6 @@ static void ExportObject(const Model &model, const Node &gltf_node, hg::Node &no static void ExportCamera(const Model &model, const Node &gltf_node, hg::Node &node, hg::Scene &scene, const Config &config, hg::PipelineResources &resources) { auto camera = scene.CreateCamera(); - node.SetCamera(camera); auto gltf_camera = model.cameras[gltf_node.camera]; @@ -1327,6 +1326,31 @@ static void ExportCamera(const Model &model, const Node &gltf_node, hg::Node &no camera.SetZFar(gltf_camera.orthographic.zfar); camera.SetIsOrthographic(true); } + node.SetCamera(camera); +} + +static void ExportLight(const Model &model, const size_t &id_light, hg::Node &node, hg::Scene &scene, const Config &config, hg::PipelineResources &resources) { + auto light = scene.CreateLight(); + + auto gltf_light = model.lights[id_light]; + + light.SetDiffuseColor(hg::Color(gltf_light.color[0], gltf_light.color[1], gltf_light.color[2])); + light.SetDiffuseIntensity(gltf_light.intensity); + + light.SetInnerAngle(gltf_light.spot.innerConeAngle); + light.SetOuterAngle(gltf_light.spot.outerConeAngle); + + light.SetRadius(gltf_light.range); + + if (gltf_light.type == "point") { + light.SetType(hg::LT_Point); + } else if (gltf_light.type == "directional") { + light.SetType(hg::LT_Linear); + } else if (gltf_light.type == "spot") { + light.SetType(hg::LT_Spot); + } + + node.SetLight(light); } // @@ -1378,6 +1402,15 @@ static hg::Node ExportNode(const Model &model, const int &gltf_id_node, hg::Scen if (gltf_node.camera >= 0) ExportCamera(model, gltf_node, node, scene, config, resources); + // is it a light + auto KHR_lights_punctual = gltf_node.extensions.find("KHR_lights_punctual"); + if (KHR_lights_punctual != gltf_node.extensions.end()) { + if (KHR_lights_punctual->second.Has("light")) { + auto id_light = KHR_lights_punctual->second.Get("light").Get(); + ExportLight(model, id_light, node, scene, config, resources); + } + } + // is it a mesh if (gltf_node.mesh >= 0 || gltf_node.skin >= 0) { // if the node doesn't have a name, give the geo name, if there is one @@ -1610,7 +1643,7 @@ int main(int argc, const char **argv) { {"-shader", "Material pipeline shader [default=core/shader/pbr.hps]", true}, }, { - {"input", "Input FBX file to convert"}, + {"input", "Input GLTF file to convert"}, }, { {"-o", "-out"},