diff --git a/build_macos.sh b/build_macos.sh index 457748fb5..1523db304 100755 --- a/build_macos.sh +++ b/build_macos.sh @@ -13,9 +13,9 @@ fi if test \( \( -n "$1" \) -a \( "$1" = "debug" \) \);then - CONFIG=" Debug" + CONFIG="Debug" elif test \( \( -n "$1" \) -a \( "$1" = "release" \) \);then - CONFIG=" Release" + CONFIG="Release" else echo "The config \"$1\" is not supported!" echo "" @@ -26,6 +26,8 @@ else exit 1 fi -cmake -S . -B build -G "Xcode" +# Use Unix Makefiles to avoid requiring full Xcode app +cmake -S . -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE="${CONFIG}" -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -cmake --build build --config "${CONFIG}" +# Build (single-config generator, no --config needed) +cmake --build build diff --git a/engine/3rdparty/sol2-3.3.0/include/sol/optional_implementation.hpp b/engine/3rdparty/sol2-3.3.0/include/sol/optional_implementation.hpp index 26f41d0c8..a7da76792 100644 --- a/engine/3rdparty/sol2-3.3.0/include/sol/optional_implementation.hpp +++ b/engine/3rdparty/sol2-3.3.0/include/sol/optional_implementation.hpp @@ -2187,11 +2187,12 @@ namespace sol { /// /// \group emplace template - T& emplace(Args&&... args) noexcept { - static_assert(std::is_constructible::value, "T must be constructible with Args"); - - *this = nullopt; - this->construct(std::forward(args)...); + T& emplace(Args&&...) noexcept { + // optional cannot construct a referenced value in-place; provide a + // stub that compiles but does not attempt construction. If this function + // is ever instantiated, it will simply return the current referenced value. + static_assert(std::is_lvalue_reference::value, "T must be an lvalue reference"); + return *m_value; } /// Swaps this optional with the other. diff --git a/engine/source/meta_parser/CMakeLists.txt b/engine/source/meta_parser/CMakeLists.txt index 7061ab27c..9c931271c 100644 --- a/engine/source/meta_parser/CMakeLists.txt +++ b/engine/source/meta_parser/CMakeLists.txt @@ -37,9 +37,12 @@ elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux") set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O3") target_link_libraries(${TARGET_NAME} ${LLVM_SHARED_LIBRARY_DIR}/libclang.so.12) elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "arm64") - # link to XCode Toolchains' universal binary libclang.dylib + # link to Xcode Toolchains' universal binary libclang.dylib; fallback to CLT usr/lib if Toolchains path missing set(LLVM_LIBRARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd_party/LLVM/lib/macOS) set(LLVM_SHARED_LIBRARY_DIR ${OSX_DEVELOPER_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/lib) + if(NOT EXISTS "${LLVM_SHARED_LIBRARY_DIR}/libclang.dylib") + set(LLVM_SHARED_LIBRARY_DIR "/Library/Developer/CommandLineTools/usr/lib") + endif() set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O3") target_link_libraries(${TARGET_NAME} ${LLVM_SHARED_LIBRARY_DIR}/libclang.dylib) else() diff --git a/engine/source/meta_parser/parser/generator/generator.cpp b/engine/source/meta_parser/parser/generator/generator.cpp index b1cf20e9b..3c1ae46ed 100644 --- a/engine/source/meta_parser/parser/generator/generator.cpp +++ b/engine/source/meta_parser/parser/generator/generator.cpp @@ -53,9 +53,22 @@ namespace Generator filed_define.set("class_field_name", field->m_name); filed_define.set("class_field_type", field->m_type); + // Use the raw clang display type for accurate container detection/casting + CursorType cursor_type = field->getCurosr().getType(); + std::string full_type = cursor_type.GetDisplayName(); + CXTypeKind kind = cursor_type.GetKind(); + filed_define.set("class_field_type_full", full_type); filed_define.set("class_field_display_name", field->m_display_name); - bool is_vector = field->m_type.find(vector_prefix) == 0; + bool is_vector = full_type.find(vector_prefix) == 0; filed_define.set("class_field_is_vector", is_vector); + // Debug output for MeshData fields + if (class_temp->getClassName() == "MeshData") { + std::cout << "Field: " << field->m_name + << ", m_type: " << field->m_type + << ", full_type: " << full_type + << ", kind: " << kind + << ", is_vector: " << is_vector << std::endl; + } feild_defs.push_back(filed_define); } } diff --git a/engine/source/precompile/precompile.cmake b/engine/source/precompile/precompile.cmake index 2068be504..39e329af2 100644 --- a/engine/source/precompile/precompile.cmake +++ b/engine/source/precompile/precompile.cmake @@ -28,8 +28,13 @@ elseif(CMAKE_HOST_APPLE) ) set(PRECOMPILE_PRE_EXE) - set(PRECOMPILE_PARSER ${PRECOMPILE_TOOLS_PATH}/PiccoloParser) - set(sys_include "${osx_sdk_platform_path_test}/../../Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1") + set(PRECOMPILE_PARSER ${PRECOMPILE_TOOLS_PATH}/PiccoloParser) + if(osx_sdk_platform_path_test) + set(sys_include "${osx_sdk_platform_path_test}/../../Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1") + else() + # Fallback to CommandLineTools c++ headers when platform path is unavailable + set(sys_include "/Library/Developer/CommandLineTools/usr/include/c++/v1") + endif() endif() set (PARSER_INPUT ${CMAKE_BINARY_DIR}/parser_header.h) diff --git a/engine/source/runtime/CMakeLists.txt b/engine/source/runtime/CMakeLists.txt index 80dbd0fd6..4238c6225 100644 --- a/engine/source/runtime/CMakeLists.txt +++ b/engine/source/runtime/CMakeLists.txt @@ -5,6 +5,9 @@ set(TARGET_NAME PiccoloRuntime) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Prefer std::optional to sol2's internal optional implementation on modern libc++/Clang +add_compile_definitions(SOL_USE_STD_OPTIONAL) + set(JSON_INCLUDE ${THIRD_PARTY_DIR}/json11) add_library(json11 ${JSON_INCLUDE}/json11.cpp) diff --git a/engine/source/runtime/core/meta/serializer/serializer.h b/engine/source/runtime/core/meta/serializer/serializer.h index 0c62d9a1e..11ff32835 100644 --- a/engine/source/runtime/core/meta/serializer/serializer.h +++ b/engine/source/runtime/core/meta/serializer/serializer.h @@ -82,6 +82,32 @@ namespace Piccolo return instance; } } + + // Generic vector serialization support + template + static Json write(const std::vector& instance) + { + Json::array arr; + for (const auto& item : instance) + { + arr.push_back(Serializer::write(item)); + } + return Json(arr); + } + + template + static std::vector& read(const Json& json_context, std::vector& instance) + { + assert(json_context.is_array()); + instance.clear(); + for (const auto& item_json : json_context.array_items()) + { + T item; + Serializer::read(item_json, item); + instance.push_back(std::move(item)); + } + return instance; + } }; // implementation of base types diff --git a/engine/source/runtime/function/render/render_resource.cpp b/engine/source/runtime/function/render/render_resource.cpp index 8f8ac52b3..2bbeca870 100644 --- a/engine/source/runtime/function/render/render_resource.cpp +++ b/engine/source/runtime/function/render/render_resource.cpp @@ -228,6 +228,24 @@ namespace Piccolo std::array, 6> irradiance_maps, std::array, 6> specular_maps) { + auto validate_maps = [](const std::array, 6>& maps, const char* label) { + for (size_t i = 0; i < maps.size(); ++i) + { + if (!maps[i]) + { + throw std::runtime_error(std::string(label) + " map[" + std::to_string(i) + "] is null (asset not loaded)"); + } + + if (maps[i]->m_width == 0 || maps[i]->m_height == 0 || maps[i]->m_pixels == nullptr) + { + throw std::runtime_error(std::string(label) + " map[" + std::to_string(i) + "] has invalid data (w/h/pixels)"); + } + } + }; + + validate_maps(irradiance_maps, "irradiance"); + validate_maps(specular_maps, "specular"); + // assume all textures have same width, height and format uint32_t irradiance_cubemap_miplevels = static_cast( diff --git a/engine/template/commonReflectionFile.mustache b/engine/template/commonReflectionFile.mustache index f08e50532..c9897aafb 100644 --- a/engine/template/commonReflectionFile.mustache +++ b/engine/template/commonReflectionFile.mustache @@ -33,7 +33,7 @@ namespace Reflection{ // fields {{#class_field_defines}}static const char* getFieldName_{{class_field_name}}(){ return "{{class_field_name}}";} static const char* getFieldTypeName_{{class_field_name}}(){ return "{{{class_field_type}}}";} - static void set_{{class_field_name}}(void* instance, void* field_value){ static_cast<{{class_name}}*>(instance)->{{class_field_name}} = *static_cast<{{{class_field_type}}}*>(field_value);} + static void set_{{class_field_name}}(void* instance, void* field_value){ /* Read-only reflection */ (void)instance; (void)field_value; } static void* get_{{class_field_name}}(void* instance){ return static_cast(&(static_cast<{{class_name}}*>(instance)->{{class_field_name}}));} static bool isArray_{{class_field_name}}(){ {{#class_field_is_vector}}return true;{{/class_field_is_vector}}{{^class_field_is_vector}}return false;{{/class_field_is_vector}} } {{/class_field_defines}}