From 80807601cea008ae60456bf14ac7c65ed3b74178 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 2 Sep 2023 23:53:09 +0200 Subject: [PATCH 01/52] Removed LLVM backend --- .github/workflows/build.yml | 7 - Apps/CLI/Src/main.cpp | 3 - Apps/Editor/Src/main.cpp | 3 - CMake/LLVM.cmake | 70 --- CMakeLists.txt | 1 - Extern/CMakeLists.txt | 1 - Libs/Backends/LLVM/CMakeLists.txt | 32 -- .../LLVMBackend/Components/CIRFunction.h | 23 - .../LLVMBackend/Components/CIRInstruction.h | 19 - .../LLVMBackend/Components/CIRModule.h | 18 - .../Include/LLVMBackend/Components/CIRType.h | 11 - .../Include/LLVMBackend/Components/CIRValue.h | 11 - .../Include/LLVMBackend/IRGeneration.h | 85 ---- .../Include/LLVMBackend/LLVMHelpers.h | 33 -- .../Compiler/Include/LLVMBackend/Linker.h | 10 - .../LLVM/Compiler/Include/LLVMBackendModule.h | 31 -- .../Compiler/Src/LLVMBackend/IRGeneration.cpp | 416 ------------------ .../LLVM/Compiler/Src/LLVMBackend/Linker.cpp | 87 ---- .../LLVM/Compiler/Src/LLVMBackendModule.cpp | 144 ------ Libs/Bindings/Native/CMakeLists.txt | 1 - .../Compiler/Src/NativeBindingModule.cpp | 37 +- Libs/CMakeLists.txt | 1 - Libs/Editor/CMakeLists.txt | 1 - Libs/Editor/Src/Systems/EditorSystem.cpp | 6 +- 24 files changed, 4 insertions(+), 1047 deletions(-) delete mode 100644 CMake/LLVM.cmake delete mode 100644 Libs/Backends/LLVM/CMakeLists.txt delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRFunction.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRInstruction.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRModule.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRType.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRValue.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/IRGeneration.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/LLVMHelpers.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Linker.h delete mode 100644 Libs/Backends/LLVM/Compiler/Include/LLVMBackendModule.h delete mode 100644 Libs/Backends/LLVM/Compiler/Src/LLVMBackend/IRGeneration.cpp delete mode 100644 Libs/Backends/LLVM/Compiler/Src/LLVMBackend/Linker.cpp delete mode 100644 Libs/Backends/LLVM/Compiler/Src/LLVMBackendModule.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 257a9fba..d0af0fc8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,16 +85,9 @@ jobs: directory: ${{ runner.temp }}/llvm cached: ${{ steps.cache-llvm.outputs.cache-hit }} - - - name: Download pre-built development LLVM for Rift - run: | - curl -L -o "${{ runner.temp }}/rift-llvm.zip" https://github.com/piperift/rift-llvm/releases/download/v14.0.5/llvm-${{ matrix.os-name }}-${{ matrix.config }}.zip - 7z x -o"${{ runner.temp }}/rift" "${{ runner.temp }}/rift-llvm.zip" - - name: Get CMake uses: lukka/get-cmake@latest - - name: Cache Build uses: actions/cache@v2 with: diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index a620b4d5..3ae68408 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,6 @@ #include - using namespace rift; @@ -67,7 +65,6 @@ int main(int argc, char** argv) { p::Initialize("Saved/Logs"); EnableModule(); - EnableModule(); EnableModule(); EnableModule(); diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index 82799da6..aa944ec5 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -6,14 +6,12 @@ #include #include #include -#include #include #include #include - using namespace rift; @@ -25,7 +23,6 @@ int RunEditor(StringView projectPath) { p::Initialize("Saved/Logs"); EnableModule(); - EnableModule(); EnableModule(); EnableModule(); diff --git a/CMake/LLVM.cmake b/CMake/LLVM.cmake deleted file mode 100644 index 6f7564fd..00000000 --- a/CMake/LLVM.cmake +++ /dev/null @@ -1,70 +0,0 @@ - -set(RIFT_DEFAULT_TO_INTERNAL_LLVM ${PLATFORM_WINDOWS} CACHE STRING "If true, use internal llvm build path. Default: true in Windows, false in Linux") -set(RIFT_INTERNAL_LLVM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Extern/rift-llvm") - -set(RIFT_LLVM_PATH_RELEASE "" CACHE STRING "Location of Rift LLVM installation to use on Release. CMake will try to find if this path is not set") -set(RIFT_LLVM_PATH_DEBUG "" CACHE STRING "Location of Rift LLVM installation to use on Debug. CMake will try to find if this path is not set") -set(RIFT_LLVM_PATH_MINSIZEREL "" CACHE STRING "Location of Rift LLVM installation to use on MinSizeRel. CMake will try to find if this path is not set") -set(RIFT_LLVM_PATH_RELWITHDEBINFO "" CACHE STRING "Location of Rift LLVM installation to use on RelWithDebInfo. CMake will try to find if this path is not set") -set(RIFT_LLVM_PATH "" CACHE STRING "Location of an external LLVM installation to use. Used if RIFT_LLVM_PATH_{CONFIG} is not set. If left empty, INTERNAL_RIFT_LLVM_PATH is used.") - -# Check if specific build type path is required -string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER) -if (RIFT_LLVM_PATH STREQUAL "" AND NOT ${RIFT_LLVM_PATH_${CMAKE_BUILD_TYPE_UPPER}} STREQUAL "") - message(STATUS "Using RIFT_LLVM_PATH_${CMAKE_BUILD_TYPE_UPPER}") - set(RIFT_LLVM_PATH ${RIFT_LLVM_PATH_${CMAKE_BUILD_TYPE_UPPER}}) -endif() - -# Check if RIFT_LLVM_PATH should be used -if (NOT RIFT_LLVM_PATH STREQUAL "") - message(STATUS "Provided explicit LLVM path: ${RIFT_LLVM_PATH}") - set(RIFT_LLVM_BIN_PATH ${RIFT_LLVM_PATH}) -elseif (RIFT_DEFAULT_TO_INTERNAL_LLVM AND NOT RIFT_INTERNAL_LLVM_PATH STREQUAL "") - set(RIFT_LLVM_PATH ${RIFT_INTERNAL_LLVM_PATH}/build) - message(STATUS "Provided internal LLVM path: ${RIFT_LLVM_PATH}") - set(RIFT_LLVM_BIN_PATH ${RIFT_LLVM_PATH}/${CMAKE_BUILD_TYPE}) -else() - message(STATUS "LLVM path not provided. Will be searched in the system") - set(RIFT_LLVM_BIN_PATH ${RIFT_LLVM_PATH}) -endif() - -set(LLVM_DIR "${RIFT_LLVM_PATH}/lib/cmake/llvm") -set(Clang_DIR "${RIFT_LLVM_PATH}/lib/cmake/clang") - -find_package(LLVM REQUIRED CONFIG) -list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") -include(AddLLVM) -message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") -message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - -find_package(Clang REQUIRED CONFIG) -list(APPEND CMAKE_MODULE_PATH "${CLANG_CMAKE_DIR}") -include(AddClang) -message(STATUS "Found CLANG ${CLANG_PACKAGE_VERSION}") -message(STATUS "Using CLANGConfig.cmake in: ${Clang_DIR}") - -separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) -message(STATUS "LLVM_LIBS: ${LLVM_AVAILABLE_LIBS}") -message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}") -# Copyright 2015-2023 Piperift - All rights reserved - -message(STATUS "LLVM_DEFINITIONS: ${LLVM_DEFINITIONS_LIST}") -message(STATUS "CLANG_LIBS: ${CLANG_EXPORTED_TARGETS}") - - -add_library(RiftLLVM INTERFACE) -target_include_directories(RiftLLVM INTERFACE ${LLVM_INCLUDE_DIRS}) -llvm_map_components_to_libnames(llvm_libs core support x86asmparser x86codegen) -target_link_libraries(RiftLLVM INTERFACE ${llvm_libs}) -target_compile_definitions(RiftLLVM INTERFACE ${LLVM_DEFINITIONS_LIST} -DNOMINMAX) -#if(COMPILER_CLANG) - #target_compile_options(RiftLLVM INTERFACE -fms-compatibility-version=14.20) -#endif() -pipe_target_disable_all_warnings(RiftLLVM INTERFACE) - -add_library(RiftClang INTERFACE) -target_include_directories(RiftClang INTERFACE ${CLANG_INCLUDE_DIRS}) -target_link_libraries(RiftClang INTERFACE libclang) -target_compile_definitions(RiftClang INTERFACE ${CLANG_DEFINITIONS_LIST} -DNOMINMAX) -target_link_libraries(RiftClang INTERFACE RiftLLVM) -pipe_target_disable_all_warnings(RiftClang INTERFACE) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3eb20fb..fc53df9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,6 @@ include(CMake/Util.cmake) include(CMake/SetIcon.cmake) include(CMake/CheckClangTools.cmake) -include(CMake/LLVM.cmake) add_subdirectory(Extern) add_subdirectory(Libs) diff --git a/Extern/CMakeLists.txt b/Extern/CMakeLists.txt index ca38d749..5852bbf2 100644 --- a/Extern/CMakeLists.txt +++ b/Extern/CMakeLists.txt @@ -85,4 +85,3 @@ endif() add_library(mir_static STATIC) target_link_libraries(mir_static PRIVATE mir) target_include_directories(mir_static PUBLIC mir) - diff --git a/Libs/Backends/LLVM/CMakeLists.txt b/Libs/Backends/LLVM/CMakeLists.txt deleted file mode 100644 index 8b0f9de6..00000000 --- a/Libs/Backends/LLVM/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015-2023 Piperift - All rights reserved - -add_library(RiftBackendLLVM STATIC) -rift_compiler_module(RiftBackendLLVM) - -target_link_libraries(RiftBackendLLVM PUBLIC RiftAST) -target_link_libraries(RiftBackendLLVM PRIVATE - RiftLLVM - RiftBindingNative -) - - -# LLVM linker -if (PLATFORM_WINDOWS) - set(RIFT_LLVM_LINKER lld-link.exe) -elseif(PLATFORM_LINUX) - set(RIFT_LLVM_LINKER ld.lld) -elseif(PLATFORM_MACOS) - set(RIFT_LLVM_LINKER ld64.lld) -endif() - -set(RIFT_LLVM_LINKER_PATH LLVM/${RIFT_LLVM_LINKER}) - -target_compile_definitions(RiftBackendLLVM PRIVATE RIFT_LLVM_LINKER="${RIFT_LLVM_LINKER}" RIFT_LLVM_LINKER_PATH="${RIFT_LLVM_LINKER_PATH}") - -add_custom_command(TARGET RiftBackendLLVM POST_BUILD COMMAND - ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/Bin/LLVM" -) -add_custom_command(TARGET RiftBackendLLVM POST_BUILD COMMAND - ${CMAKE_COMMAND} -E copy "${RIFT_LLVM_BIN_PATH}/bin/${RIFT_LLVM_LINKER}" "${CMAKE_BINARY_DIR}/Bin/LLVM/${RIFT_LLVM_LINKER}" -) - diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRFunction.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRFunction.h deleted file mode 100644 index 4659c790..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRFunction.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include -#include - - -namespace rift -{ - struct CIRFunction : public p::Struct - { - STRUCT(CIRFunction, p::Struct) - - llvm::Function* instance = nullptr; - - p::TArray inputs; - p::TArray inputIds; - - - CIRFunction() {} - }; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRInstruction.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRInstruction.h deleted file mode 100644 index 1329c6c3..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRInstruction.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include - - -namespace rift -{ - struct CIRInstruction : public p::Struct - { - STRUCT(CIRInstruction, p::Struct) - - llvm::Instruction* instance = nullptr; - - - CIRInstruction(llvm::Instruction* instance) : instance(instance) {} - }; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRModule.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRModule.h deleted file mode 100644 index f72e3a99..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRModule.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include - - -namespace rift -{ - struct CIRModule : public p::Struct - { - STRUCT(CIRModule, p::Struct) - - p::TOwnPtr instance; - - p::String objectFile; - }; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRType.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRType.h deleted file mode 100644 index 8fbb8118..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRType.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include - - -namespace rift -{ - using CIRType = llvm::Type*; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRValue.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRValue.h deleted file mode 100644 index ce142b53..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Components/CIRValue.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include - - -namespace rift -{ - using CIRValue = llvm::Value*; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/IRGeneration.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/IRGeneration.h deleted file mode 100644 index 8e565269..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/IRGeneration.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "LLVMBackend/Components/CIRFunction.h" -#include "LLVMBackend/Components/CIRModule.h" -#include "LLVMBackend/Components/CIRType.h" -#include "LLVMBackend/Components/CIRValue.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace rift -{ - struct CIRFunction; -} - -namespace rift -{ - struct Compiler; -} - -namespace rift::LLVM -{ - // Defines a single ecs access dfor the entire IR generation - using IRAccess = p::TAccessRef, p::TWrite, p::TWrite, AST::CLiteralBool, - AST::CLiteralIntegral, AST::CLiteralFloating, AST::CLiteralString>; - - struct ModuleIRGen - { - Compiler& compiler; - llvm::Module& module; - llvm::LLVMContext& llvm; - llvm::IRBuilder<>& builder; - }; - - void GenerateIR(Compiler& compiler, llvm::LLVMContext& llvm, llvm::IRBuilder<>& builder); - - void GenerateIRModule(Compiler& compiler, IRAccess access, AST::Id moduleId, - llvm::LLVMContext& llvm, llvm::IRBuilder<>& builder); - - void BindNativeTypes(llvm::LLVMContext& llvm, IRAccess access); - void GenerateLiterals(llvm::LLVMContext& llvm, IRAccess access); - - void DeclareStructs(ModuleIRGen& gen, IRAccess access, p::TView ids); - void DefineStructs(ModuleIRGen& gen, IRAccess access, p::TView ids); - void DeclareFunctions( - ModuleIRGen& gen, IRAccess access, p::TView ids, bool useFullName = true); - void DefineFunctions(ModuleIRGen& gen, IRAccess access, p::TView ids); - - void AddStmtBlock(ModuleIRGen& gen, IRAccess access, AST::Id firstStmtId, - llvm::BasicBlock* block, const CIRFunction& function); - llvm::Value* AddExpr(ModuleIRGen& gen, IRAccess access, const AST::ExprOutput& output); - llvm::BasicBlock* AddIf( - ModuleIRGen& gen, IRAccess access, AST::Id id, const CIRFunction& function); - void AddCall(ModuleIRGen& gen, AST::Id id, const AST::CExprCallId& call, IRAccess access); - - - AST::Id FindMainFunction(IRAccess access, p::TView functionIds); - - void CreateMain(ModuleIRGen& gen, IRAccess access, AST::Id functionId); -} // namespace rift::LLVM diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/LLVMHelpers.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/LLVMHelpers.h deleted file mode 100644 index 58e5ec19..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/LLVMHelpers.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include -#include -#include -#include - - -namespace rift::LLVM -{ - using namespace p::core; - - inline llvm::StringRef ToLLVM(p::StringView string) - { - return {string.data(), string.size()}; - } - inline llvm::StringRef ToLLVM(const p::String& string) - { - return ToLLVM(p::StringView{string}); - } - inline llvm::StringRef ToLLVM(p::Tag name) - { - return ToLLVM(p::StringView{name.AsString()}); - } - - template - inline llvm::ArrayRef ToLLVM(const p::IArray& array) - { - return {array.Data(), sizet(array.Size())}; - } -} // namespace rift::LLVM diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Linker.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Linker.h deleted file mode 100644 index 440ef013..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackend/Linker.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "Compiler/Compiler.h" - - -namespace rift::LLVM -{ - void Link(Compiler& compiler); -} // namespace rift::LLVM \ No newline at end of file diff --git a/Libs/Backends/LLVM/Compiler/Include/LLVMBackendModule.h b/Libs/Backends/LLVM/Compiler/Include/LLVMBackendModule.h deleted file mode 100644 index 388c295b..00000000 --- a/Libs/Backends/LLVM/Compiler/Include/LLVMBackendModule.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include -#include - - -namespace rift -{ - class LLVMBackendModule : public Module - { - CLASS(LLVMBackendModule, Module) - - public: - LLVMBackendModule(); - }; - - - class LLVMBackend : public Backend - { - CLASS(LLVMBackend, Backend) - - public: - Tag GetName() override - { - return "LLVM"; - } - - void Build(Compiler& compiler) override; - }; -} // namespace rift diff --git a/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/IRGeneration.cpp b/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/IRGeneration.cpp deleted file mode 100644 index a1bfd59b..00000000 --- a/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/IRGeneration.cpp +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved - -#include "LLVMBackend/IRGeneration.h" - -#include "Components/CDeclCStruct.h" -#include "LLVMBackend/Components/CIRFunction.h" -#include "LLVMBackend/LLVMHelpers.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace rift::LLVM -{ - void GenerateIR(Compiler& compiler, llvm::LLVMContext& llvm, llvm::IRBuilder<>& builder) - { - IRAccess access{compiler.ast}; - BindNativeTypes(llvm, access); - GenerateLiterals(llvm, access); - - for (AST::Id moduleId : FindAllIdsWith(access)) - { - GenerateIRModule(compiler, access, moduleId, llvm, builder); - } - } - - void GenerateIRModule(Compiler& compiler, IRAccess access, AST::Id moduleId, - llvm::LLVMContext& llvm, llvm::IRBuilder<>& builder) - { - ZoneScoped; - auto& ast = compiler.ast; - - const Tag name = AST::GetModuleName(compiler.ast, moduleId); - - const auto& module = compiler.ast.Get(moduleId); - CIRModule& irModule = compiler.ast.Add(moduleId); - irModule.instance = MakeOwned(ToLLVM(name), llvm); - - ModuleIRGen gen{compiler, *irModule.instance.Get(), llvm, builder}; - - AST::Id mainFunctionId = AST::NoId; - - // Get all rift types from the module - TArray typeIds; - GetChildren(ast, moduleId, typeIds); - ExcludeIdsWithout(ast, typeIds); - - { // Native declarations - TArray cStructIds = FindIdsWith(ast, typeIds); - TArray cStaticIds = FindIdsWith(ast, typeIds); - TArray cFunctionIds; - p::GetChildren(ast, cStaticIds, cFunctionIds); - ExcludeIdsWithout(ast, cFunctionIds); - DeclareStructs(gen, ast, cStructIds); - DeclareFunctions(gen, ast, cFunctionIds, false); - } - - TArray staticFunctionIds; - { // Rift declarations & definitions - TArray structIds = FindIdsWith(ast, typeIds); - TArray staticIds = FindIdsWith(ast, typeIds); - TArray classIds = FindIdsWith(ast, typeIds); - TArray classFunctionIds; - p::GetChildren(ast, staticIds, staticFunctionIds); - p::GetChildren(ast, classIds, classFunctionIds); - ExcludeIdsWithout(ast, staticFunctionIds); - ExcludeIdsWithout(ast, classFunctionIds); - TArray functionIds; - functionIds.Append(staticFunctionIds); - functionIds.Append(classFunctionIds); - - DeclareStructs(gen, ast, structIds); - DeclareStructs(gen, ast, classIds); - DeclareFunctions(gen, ast, functionIds); - - DefineStructs(gen, ast, structIds); - DefineStructs(gen, ast, classIds); - DefineFunctions(gen, ast, functionIds); - } - - if (module.target == AST::RiftModuleTarget::Executable) - { - mainFunctionId = FindMainFunction(access, staticFunctionIds); - CreateMain(gen, access, mainFunctionId); - } - } - - - void BindNativeTypes(llvm::LLVMContext& llvm, IRAccess access) - { - const auto& nativeTypes = static_cast(access.GetContext()).GetNativeTypes(); - access.Add(nativeTypes.boolId, CIRType{llvm::Type::getInt8Ty(llvm)}); - access.Add(nativeTypes.floatId, CIRType{llvm::Type::getFloatTy(llvm)}); - access.Add(nativeTypes.doubleId, CIRType{llvm::Type::getDoubleTy(llvm)}); - access.Add(nativeTypes.u8Id, CIRType{llvm::Type::getInt8Ty(llvm)}); - access.Add(nativeTypes.i8Id, CIRType{llvm::Type::getInt8Ty(llvm)}); - access.Add(nativeTypes.u16Id, CIRType{llvm::Type::getInt16Ty(llvm)}); - access.Add(nativeTypes.i16Id, CIRType{llvm::Type::getInt16Ty(llvm)}); - access.Add(nativeTypes.u32Id, CIRType{llvm::Type::getInt32Ty(llvm)}); - access.Add(nativeTypes.i32Id, CIRType{llvm::Type::getInt32Ty(llvm)}); - access.Add(nativeTypes.u64Id, CIRType{llvm::Type::getInt64Ty(llvm)}); - access.Add(nativeTypes.i64Id, CIRType{llvm::Type::getInt64Ty(llvm)}); - // access.Add(nativeTypes.stringId, {}); - } - - void GenerateLiterals(llvm::LLVMContext& llvm, IRAccess access) - { - for (AST::Id id : FindAllIdsWith(access)) - { - const auto& boolean = access.Get(id); - llvm::Value* value = llvm::ConstantInt::get(llvm, llvm::APInt(1, boolean.value, true)); - access.Add(id, CIRValue{value}); - } - for (AST::Id id : FindAllIdsWith(access)) - { - const auto& integral = access.Get(id); - llvm::Value* value = llvm::ConstantInt::get( - llvm, llvm::APInt(integral.GetSize(), integral.value, integral.IsSigned())); - access.Add(id, CIRValue{value}); - } - for (AST::Id id : FindAllIdsWith(access)) - { - const auto& floating = access.Get(id); - llvm::Value* value = - llvm::ConstantFP::get(llvm, llvm::APFloat(floating.type == AST::FloatingType::F32 - ? static_cast(floating.value) - : floating.value)); - access.Add(id, CIRValue{value}); - } - for (AST::Id id : FindAllIdsWith(access)) - { - const auto& string = access.Get(id); - access.Add( - id, CIRValue{llvm::ConstantDataArray::getString(llvm, ToLLVM(string.value))}); - } - } - - void DeclareStructs(ModuleIRGen& gen, IRAccess access, TView ids) - { - ZoneScoped; - for (AST::Id id : ids) - { - p::String name = AST::GetFullName(access, id); - access.Add(id, CIRType{llvm::StructType::create(gen.llvm, ToLLVM(name))}); - } - } - - void DefineStructs(ModuleIRGen& gen, IRAccess access, TView ids) - { - ZoneScoped; - TArray memberIds; - TArray memberTypes; - for (AST::Id id : ids) - { - auto* irStruct = static_cast(access.Get(id)); - - // Add members - memberIds.Clear(false); - memberTypes.Clear(false); - p::GetChildren(access, id, memberIds); - ExcludeIdsWithout(access, memberIds); - for (AST::Id memberId : memberIds) - { - const auto& var = access.Get(memberId); - if (auto* irType = access.TryGet(var.typeId)) - { - memberTypes.Add(*irType); - } - else - { - const Tag memberName = AST::GetName(access, memberId); - const Tag typeName = AST::GetName(access, id); - gen.compiler.AddError(Strings::Format( - "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); - } - } - irStruct->setBody(ToLLVM(memberTypes)); - } - } - - void DeclareFunctions(ModuleIRGen& gen, IRAccess access, TView ids, bool useFullName) - { - ZoneScoped; - TArray inputIds; - TArray inputTypes; - for (AST::Id id : ids) - { - auto& functionComp = access.Add(id); - - inputIds.Clear(false); - inputTypes.Clear(false); - if (auto* outputs = access.TryGet(id)) - { - for (i32 i = 0; i < outputs->pinIds.Size(); ++i) - { - AST::Id inputId = outputs->pinIds[i]; - if (access.Has(inputId)) - { - continue; - } - - inputIds.Add(inputId); - - AST::Id typeId = access.Get(inputId).id; - auto* irType = access.TryGet(typeId); - if (irType && *irType) - { - inputTypes.Add(*irType); - } - else - { - const Tag argName = AST::GetName(access, inputId); - const String functionName = AST::GetFullName(access, id); - gen.compiler.AddError(Strings::Format( - "Input '{}' in function '{}' has an invalid type. Using i32 instead.", - argName, functionName)); - inputTypes.Add(gen.builder.getInt32Ty()); - } - } - } - - // Create function - p::String name = useFullName ? AST::GetFullName(access, id) - : p::String{AST::GetName(access, id).AsString()}; - auto* functionType = - llvm::FunctionType::get(gen.builder.getVoidTy(), ToLLVM(inputTypes), false); - functionComp.instance = llvm::Function::Create( - functionType, llvm::Function::ExternalLinkage, ToLLVM(name), &gen.module); - - // Set argument names - i32 i = 0; - const auto& args = functionComp.instance->args(); - for (auto& arg : args) - { - Tag name = AST::GetName(access, inputIds[i++]); - arg.setName(ToLLVM(name)); - } - - // Cache final inputs - functionComp.inputs = {args.begin(), args.end()}; - functionComp.inputIds = inputIds; - inputIds.Clear(false); - inputTypes.Clear(false); - } - } - - void DefineFunctions(ModuleIRGen& gen, IRAccess access, TView ids) - { - ZoneScoped; - for (AST::Id id : ids) - { - const auto& irFunction = access.Get(id); - auto* block = llvm::BasicBlock::Create(gen.llvm, "entry", irFunction.instance); - - const auto& output = access.Get(id); - AddStmtBlock(gen, access, output.linkInputNode, block, irFunction); - - // Generate default return - gen.builder.CreateRet(nullptr); - - verifyFunction(*irFunction.instance); - } - } - - void AddStmtBlock(ModuleIRGen& gen, IRAccess access, AST::Id firstStmtId, - llvm::BasicBlock* block, const CIRFunction& function) - { - ZoneScoped; - gen.builder.SetInsertPoint(block); - - AST::Id splitId = AST::NoId; - TArray stmtIds; - AST::GetStmtChain(access, firstStmtId, stmtIds, splitId); - - for (AST::Id id : stmtIds) - { - if (const auto* call = access.TryGet(id)) - { - AddCall(gen, id, *call, access); - } - } - - if (splitId != AST::NoId) - { - if (access.Has(splitId)) - { - AddIf(gen, access, splitId, function); - } - } - // TODO: Resolve continuation block and generate it - } - - llvm::Value* AddExpr(ModuleIRGen& gen, IRAccess access, const AST::ExprOutput& output) - { - const auto* value = - !IsNone(output.pinId) ? access.TryGet(output.pinId) : nullptr; - if (value) - { - return *value; - } - return nullptr; - } - - llvm::BasicBlock* AddIf( - ModuleIRGen& gen, IRAccess access, AST::Id id, const CIRFunction& function) - { - const auto& outputs = access.Get(id); - const auto& connectedIds = outputs.linkInputNodes; - Check(connectedIds.Size() == 2); - const auto& exprInputs = access.Get(id); - Check(exprInputs.linkedOutputs.Size() == 1); - - llvm::Value* condV = AddExpr(gen, access, exprInputs.linkedOutputs.First()); - if (!condV) - { - // Assign false by default - condV = llvm::ConstantInt::get(gen.llvm, llvm::APInt(1, false, true)); - } - - auto* thenBlock = llvm::BasicBlock::Create(gen.llvm, "then"); - auto* elseBlock = llvm::BasicBlock::Create(gen.llvm, "else"); - auto* contBlock = llvm::BasicBlock::Create(gen.llvm, "continue"); - gen.builder.CreateCondBr(condV, thenBlock, elseBlock); - - function.instance->getBasicBlockList().push_back(thenBlock); - AddStmtBlock(gen, access, connectedIds[0], thenBlock, function); - gen.builder.CreateBr(contBlock); - - function.instance->getBasicBlockList().push_back(elseBlock); - AddStmtBlock(gen, access, connectedIds[1], elseBlock, function); - gen.builder.CreateBr(contBlock); - - function.instance->getBasicBlockList().push_back(contBlock); - return contBlock; - } - - void AddCall(ModuleIRGen& gen, AST::Id id, const AST::CExprCallId& call, IRAccess access) - { - const AST::Id functionId = call.functionId; - if (!access.IsValid(functionId)) - { - gen.compiler.AddError("Call to an unknown function"); - return; - } - const auto* function = access.TryGet(functionId); - if (!Ensure(function)) - { - gen.compiler.AddError(Strings::Format( - "Call to an invalid function: '{}'", AST::GetName(access, functionId))); - return; - } - - TArray args; - if (auto* inputs = access.TryGet(id)) - { - args.Reserve(inputs->linkedOutputs.Size()); - for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) - { - AST::ExprOutput output = inputs->linkedOutputs[i]; - if (!output.IsNone()) - { - args.Add(AddExpr(gen, access, output)); - } - } - } - gen.builder.CreateCall(function->instance, ToLLVM(args)); - } - - - AST::Id FindMainFunction(IRAccess access, p::TView functionIds) - { - static const p::Tag mainFunctionName{"Main"}; - - for (AST::Id id : functionIds) - { - const auto* ns = access.TryGet(id); - if (ns && ns->name == mainFunctionName) - { - return id; - } - } - return AST::NoId; - } - - void CreateMain(ModuleIRGen& gen, IRAccess access, AST::Id functionId) - { - if (p::IsNone(functionId)) - { - gen.compiler.AddError( - Strings::Format("Module is executable but has no \"Main\" function")); - return; - } - - auto* customMainFunction = access.Get(functionId).instance; - - auto* mainType = llvm::FunctionType::get(gen.builder.getInt32Ty(), false); - auto* function = - llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "Main", &gen.module); - - - auto* entry = llvm::BasicBlock::Create(gen.llvm, "entry", function); - gen.builder.SetInsertPoint(entry); - gen.builder.CreateCall(customMainFunction); - - gen.builder.CreateRet(llvm::ConstantInt::get(gen.llvm, llvm::APInt(32, 0))); - } -} // namespace rift::LLVM diff --git a/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/Linker.cpp b/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/Linker.cpp deleted file mode 100644 index a9dfa21b..00000000 --- a/Libs/Backends/LLVM/Compiler/Src/LLVMBackend/Linker.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved - -#include "LLVMBackend/Linker.h" - -#include "Components/CNativeBinding.h" -#include "LLVMBackend/Components/CIRModule.h" -#include "Pipe/Core/PlatformProcess.h" -#include "Pipe/Core/String.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace rift::LLVM -{ - void Link(Compiler& compiler) - { - String linkerPath{ - p::JoinPaths(PlatformProcess::GetExecutablePath(), RIFT_LLVM_LINKER_PATH)}; - - for (AST::Id moduleId : FindAllIdsWith(compiler.ast)) - { - p::Tag moduleName = AST::GetModuleName(compiler.ast, moduleId); - const auto& module = compiler.ast.Get(moduleId); - auto& irModule = compiler.ast.Get(moduleId); - if (p::files::Exists(irModule.objectFile)) - { - TArray command; - command.Add(linkerPath.c_str()); - - const char* extension = nullptr; - switch (module.target) - { - case AST::RiftModuleTarget::Executable: - command.Add("/entry:Main"); - command.Add("/subsystem:console"); - extension = "exe"; - break; - case AST::RiftModuleTarget::Shared: - command.Add("/dll"); - extension = "dll"; - break; - case AST::RiftModuleTarget::Static: - command.Add("/lib"); - extension = "lib"; - break; - } - - p::Path filePath = - compiler.config.binariesPath / Strings::Format("{}.{}", moduleName, extension); - String outParam = Strings::Format("/out:{}", p::ToString(filePath)); - p::Info("Linking '{}' from '{}'", p::ToString(filePath), irModule.objectFile); - - // Native Bindings - p::TArray binaryPaths; - if (auto* cBinding = compiler.ast.TryGet(moduleId)) - { - p::StringView modulePath = AST::GetModulePath(compiler.ast, moduleId); - p::String binaryPath; - for (const auto& nativeBinary : cBinding->binaries) - { - binaryPaths.Add(p::JoinPaths(modulePath, nativeBinary)); - command.Add(binaryPaths.Last().c_str()); - p::Info(" and '{}'", binaryPaths.Last().c_str()); - } - } - command.Add(irModule.objectFile.data()); - command.Add(outParam.data()); - - auto process = p::RunProcess(command, - SubprocessOptions::TerminateIfDestroyed | SubprocessOptions::CombinedOutErr); - i32 returnCode = 0; - p::WaitProcess(process.TryGet(), &returnCode); - if (returnCode != 0) - { - compiler.AddError("Linking failed"); - } - } - } - } -} // namespace rift::LLVM diff --git a/Libs/Backends/LLVM/Compiler/Src/LLVMBackendModule.cpp b/Libs/Backends/LLVM/Compiler/Src/LLVMBackendModule.cpp deleted file mode 100644 index ce8ee5b9..00000000 --- a/Libs/Backends/LLVM/Compiler/Src/LLVMBackendModule.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved - -#include "LLVMBackendModule.h" - -#include "LLVMBackend/Components/CIRModule.h" -#include "LLVMBackend/IRGeneration.h" -#include "LLVMBackend/Linker.h" -#include "LLVMBackend/LLVMHelpers.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if LLVM_VERSION_MAJOR >= 14 -# include -#else -# include -#endif -#include -#include -#include -#include -#include - - -namespace rift -{ - LLVMBackendModule::LLVMBackendModule() - { - AddDependency(); - } - - namespace LLVM - { - void SaveModuleObject(Compiler& compiler, AST::Id moduleId, - llvm::TargetMachine* targetMachine, StringView targetTriple) - { - ZoneScoped; - - p::String intermediatesPath = p::ToString(compiler.config.intermediatesPath); - // files::Delete(intermediatesPath, true, false); - files::CreateFolder(intermediatesPath, true); - - auto& irModule = compiler.ast.Get(moduleId); - irModule.objectFile = Strings::Format( - "{}/{}.o", intermediatesPath, AST::GetModuleName(compiler.ast, moduleId)); - p::Info("Creating object '{}'", irModule.objectFile); - - irModule.instance->setTargetTriple(ToLLVM(targetTriple)); - irModule.instance->setDataLayout(targetMachine->createDataLayout()); - - std::error_code ec; - llvm::raw_fd_ostream file(ToLLVM(irModule.objectFile), ec, llvm::sys::fs::OF_None); - if (ec) - { - compiler.AddError( - Strings::Format("Could not open new object file: {}", ec.message())); - irModule.objectFile = {}; // File not saved - return; - } - - llvm::legacy::PassManager pm; - if (targetMachine->addPassesToEmitFile(pm, file, nullptr, llvm::CGFT_ObjectFile)) - { - compiler.AddError("Target machine can't emit a file of this type"); - irModule.objectFile = {}; // File not saved - return; - } - - pm.run(*irModule.instance.Get()); - file.flush(); - } - - void CompileIR(Compiler& compiler, llvm::LLVMContext& llvm, llvm::IRBuilder<>& builder) - { - ZoneScoped; - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmParser(); - llvm::InitializeNativeTargetAsmPrinter(); - std::string targetTriple = llvm::sys::getDefaultTargetTriple(); - - std::string error; - const llvm::Target* target = llvm::TargetRegistry::lookupTarget(targetTriple, error); - if (!target) - { - compiler.AddError(error); - return; - } - - llvm::TargetOptions options; - auto* targetMachine = target->createTargetMachine( - targetTriple, "generic", "", options, llvm::Optional()); - - // Emit LLVM IR to console - for (AST::Id moduleId : FindAllIdsWith(compiler.ast)) - { - const auto& irModule = compiler.ast.Get(moduleId).instance; - irModule->print(llvm::outs(), nullptr); - } - - for (AST::Id moduleId : FindAllIdsWith(compiler.ast)) - { - LLVM::SaveModuleObject(compiler, moduleId, targetMachine, targetTriple); - } - } - } // namespace LLVM - - void LLVMBackend::Build(Compiler& compiler) - { - ZoneScopedN("Backend: LLVM"); - - llvm::LLVMContext llvm; - llvm::IRBuilder<> builder(llvm); - - p::Info("Generating LLVM IR"); - LLVM::GenerateIR(compiler, llvm, builder); - if (compiler.HasErrors()) - return; // TODO: Report errors here - - p::Info("Build IR"); - LLVM::CompileIR(compiler, llvm, builder); - if (compiler.HasErrors()) - return; // TODO: Report errors here - - LLVM::Link(compiler); - - compiler.ast.ClearPool(); - - if (!compiler.HasErrors()) - { - p::Info("Build complete."); - } - else - { - p::Info("Build failed: {} errors", compiler.GetErrors().Size()); - } - } -} // namespace rift \ No newline at end of file diff --git a/Libs/Bindings/Native/CMakeLists.txt b/Libs/Bindings/Native/CMakeLists.txt index f71a7696..b225264d 100644 --- a/Libs/Bindings/Native/CMakeLists.txt +++ b/Libs/Bindings/Native/CMakeLists.txt @@ -4,7 +4,6 @@ add_library(RiftBindingNative STATIC) target_link_libraries(RiftBindingNative PUBLIC RiftAST) -target_link_libraries(RiftBindingNative PRIVATE RiftClang) rift_compiler_module(RiftBindingNative) diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 818de8bd..5b67f60b 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -25,19 +24,8 @@ namespace rift { struct ParsedModule { - AST::Id id = AST::NoId; - CXIndex index = clang_createIndex(0, 0); + AST::Id id = AST::NoId; TArray headers; - TArray units; - - ~ParsedModule() - { - for (auto unit : units) - { - clang_disposeTranslationUnit(unit); - } - clang_disposeIndex(index); - } }; void NativeBindingModule::Load() @@ -75,28 +63,6 @@ namespace rift } } - void ParseHeaders(AST::Tree& ast, TView parsedModules) - { - for (auto& module : parsedModules) - { - for (i32 i = 0; i < module.headers.Size(); ++i) - { - const StringView include = module.headers[i]; - const CXTranslationUnit unit = - clang_parseTranslationUnit(module.index, include.data(), nullptr, 0, nullptr, 0, - CXTranslationUnit_DetailedPreprocessingRecord); - if (!unit) - { - module.headers.RemoveAt(i, false); - --i; - p::Error("Unable to parse module header '{}'", include); - continue; - } - module.units.Add(unit); - } - } - } - void NativeBindingModule::SyncIncludes(AST::Tree& ast) { TArray moduleIds; @@ -115,7 +81,6 @@ namespace rift parsed.id = moduleIds[i]; } FindHeaders(ast, parsedModules); - ParseHeaders(ast, parsedModules); // TODO: Generate Rift interface } } // namespace rift diff --git a/Libs/CMakeLists.txt b/Libs/CMakeLists.txt index 90036f0a..af69be59 100644 --- a/Libs/CMakeLists.txt +++ b/Libs/CMakeLists.txt @@ -1,7 +1,6 @@ # Copyright 2015-2023 Piperift - All rights reserved add_subdirectory(AST) -add_subdirectory(Backends/LLVM) add_subdirectory(Backends/MIR) add_subdirectory(Bindings/Native) diff --git a/Libs/Editor/CMakeLists.txt b/Libs/Editor/CMakeLists.txt index 514b0359..ae5b2d17 100644 --- a/Libs/Editor/CMakeLists.txt +++ b/Libs/Editor/CMakeLists.txt @@ -8,7 +8,6 @@ target_sources(RiftEditor PRIVATE ${RiftEditor_SOURCE_FILES}) target_link_libraries(RiftEditor PUBLIC RiftAST - RiftBackendLLVM RiftBackendMIR RiftUI CLI11 diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index 23ab782a..3885570e 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -322,13 +322,13 @@ namespace rift::Editor::EditorSystem { AST::Tree compileAST{ast}; // Intentional copy CompilerConfig config; - Build(compileAST, config); + Build(compileAST, config); } if (UI::MenuItem("Build all")) { AST::Tree compileAST{ast}; // Intentional copy CompilerConfig config; - Build(compileAST, config); + Build(compileAST, config); } UI::EndMenu(); } From 221fc7ffe0d3ff3b09ea383d9c659ff73b9023f7 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 3 Sep 2023 13:48:04 +0200 Subject: [PATCH 02/52] Updated Pipe --- .vscode/settings.json | 5 ++++- Extern/Pipe | 2 +- Libs/AST/Include/AST/Components/CDeclClass.h | 2 +- Libs/AST/Include/AST/Components/CDeclFunction.h | 2 +- Libs/AST/Include/AST/Components/CDeclNative.h | 2 +- Libs/AST/Include/AST/Components/CDeclRecord.h | 2 +- Libs/AST/Include/AST/Components/CDeclStatic.h | 2 +- Libs/AST/Include/AST/Components/CDeclStruct.h | 2 +- Libs/AST/Include/AST/Components/CDeclType.h | 4 ++-- Libs/AST/Include/AST/Components/CDeclVariable.h | 4 ++-- Libs/AST/Include/AST/Components/CDeclaration.h | 2 +- .../AST/Include/AST/Components/CExprBinaryOperator.h | 4 ++-- Libs/AST/Include/AST/Components/CExprCall.h | 8 ++++---- Libs/AST/Include/AST/Components/CExprDeclRef.h | 10 +++++----- Libs/AST/Include/AST/Components/CExprInputs.h | 12 ++++++------ Libs/AST/Include/AST/Components/CExprOutputs.h | 10 +++++----- Libs/AST/Include/AST/Components/CExprType.h | 12 ++++++------ Libs/AST/Include/AST/Components/CExprUnaryOperator.h | 4 ++-- Libs/AST/Include/AST/Components/CExpression.h | 2 +- Libs/AST/Include/AST/Components/CFileRef.h | 4 ++-- Libs/AST/Include/AST/Components/CLiteral.h | 2 +- Libs/AST/Include/AST/Components/CLiteralBool.h | 4 ++-- Libs/AST/Include/AST/Components/CLiteralFloating.h | 6 +++--- Libs/AST/Include/AST/Components/CLiteralIntegral.h | 6 +++--- Libs/AST/Include/AST/Components/CLiteralString.h | 4 ++-- Libs/AST/Include/AST/Components/CModule.h | 6 +++--- Libs/AST/Include/AST/Components/CNamespace.h | 6 +++--- Libs/AST/Include/AST/Components/CProject.h | 2 +- Libs/AST/Include/AST/Components/CStatement.h | 2 +- Libs/AST/Include/AST/Components/CStmtFor.h | 2 +- Libs/AST/Include/AST/Components/CStmtIf.h | 2 +- Libs/AST/Include/AST/Components/CStmtInput.h | 4 ++-- Libs/AST/Include/AST/Components/CStmtOutputs.h | 10 +++++----- Libs/AST/Include/AST/Components/CStmtReturn.h | 2 +- Libs/AST/Include/AST/Components/Tags/CChanged.h | 2 +- Libs/AST/Include/AST/Components/Tags/CDirty.h | 2 +- Libs/AST/Include/AST/Components/Tags/CInvalid.h | 2 +- Libs/AST/Include/AST/Components/Tags/CPendingLoad.h | 2 +- .../AST/Include/AST/Components/Views/CNodePosition.h | 4 ++-- Libs/AST/Include/AST/Statics/SLoadQueue.h | 2 +- Libs/AST/Include/AST/Statics/SModules.h | 2 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 2 +- Libs/AST/Include/AST/Statics/STypes.h | 2 +- Libs/AST/Include/ASTModule.h | 2 +- Libs/AST/Include/Compiler/Backend.h | 2 +- Libs/AST/Include/Compiler/Compiler.h | 6 +++--- Libs/AST/Include/Compiler/CompilerConfig.h | 2 +- Libs/AST/Include/Module.h | 2 +- Libs/AST/Include/View.h | 4 ++-- .../Backends/MIR/Compiler/Include/MIRBackendModule.h | 4 ++-- .../Compiler/Include/Components/CDeclCStatic.h | 2 +- .../Compiler/Include/Components/CDeclCStruct.h | 2 +- .../Compiler/Include/Components/CNativeBinding.h | 6 +++--- .../Native/Compiler/Include/NativeBindingModule.h | 2 +- .../Editor/Include/NativeBindingEditorModule.h | 2 +- Libs/Editor/Include/Components/CDeclRename.h | 2 +- Libs/Editor/Include/Components/CModuleEditor.h | 2 +- Libs/Editor/Include/Components/CTypeEditor.h | 2 +- Libs/Editor/Include/Statics/SEditor.h | 2 +- Libs/Views/Graph/Compiler/Include/GraphViewModule.h | 3 +-- .../Graph/Editor/Include/GraphViewEditorModule.h | 2 +- Tests/AST/Namespaces.spec.cpp | 1 - 62 files changed, 112 insertions(+), 111 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d2227d01..c989f1aa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -232,5 +232,8 @@ "LLVM" ] }, - "dotnet.defaultSolution": "disable" + "dotnet.defaultSolution": "disable", + "search.exclude": { + "**/.git": true + } } \ No newline at end of file diff --git a/Extern/Pipe b/Extern/Pipe index 918e8bfe..7e5a48c1 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 918e8bfec5c1aef487c7cea81704f31226d1d682 +Subproject commit 7e5a48c16da4e9b232fe062dc50607ff6ab3a5fa diff --git a/Libs/AST/Include/AST/Components/CDeclClass.h b/Libs/AST/Include/AST/Components/CDeclClass.h index 679f93f2..9bc6ecc1 100644 --- a/Libs/AST/Include/AST/Components/CDeclClass.h +++ b/Libs/AST/Include/AST/Components/CDeclClass.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclClass : public CDeclRecord { - STRUCT(CDeclClass, CDeclRecord) + P_STRUCT(CDeclClass, CDeclRecord) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclFunction.h b/Libs/AST/Include/AST/Components/CDeclFunction.h index 5cbcfd59..69991794 100644 --- a/Libs/AST/Include/AST/Components/CDeclFunction.h +++ b/Libs/AST/Include/AST/Components/CDeclFunction.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclFunction : public CDeclaration { - STRUCT(CDeclFunction, CDeclaration) + P_STRUCT(CDeclFunction, CDeclaration) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclNative.h b/Libs/AST/Include/AST/Components/CDeclNative.h index 257a0a79..5f55da9a 100644 --- a/Libs/AST/Include/AST/Components/CDeclNative.h +++ b/Libs/AST/Include/AST/Components/CDeclNative.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclNative : public CDeclRecord { - STRUCT(CDeclNative, CDeclRecord) + P_STRUCT(CDeclNative, CDeclRecord) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclRecord.h b/Libs/AST/Include/AST/Components/CDeclRecord.h index 39d93aec..d10016ce 100644 --- a/Libs/AST/Include/AST/Components/CDeclRecord.h +++ b/Libs/AST/Include/AST/Components/CDeclRecord.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclRecord : public CDeclaration { - STRUCT(CDeclRecord, CDeclaration) + P_STRUCT(CDeclRecord, CDeclaration) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclStatic.h b/Libs/AST/Include/AST/Components/CDeclStatic.h index 55f6523c..bc66e2b2 100644 --- a/Libs/AST/Include/AST/Components/CDeclStatic.h +++ b/Libs/AST/Include/AST/Components/CDeclStatic.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclStatic : public CDeclaration { - STRUCT(CDeclStatic, CDeclaration) + P_STRUCT(CDeclStatic, CDeclaration) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclStruct.h b/Libs/AST/Include/AST/Components/CDeclStruct.h index 341edc82..08d96334 100644 --- a/Libs/AST/Include/AST/Components/CDeclStruct.h +++ b/Libs/AST/Include/AST/Components/CDeclStruct.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CDeclStruct : public CDeclRecord { - STRUCT(CDeclStruct, CDeclRecord, ) + P_STRUCT(CDeclStruct, CDeclRecord, ) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclType.h b/Libs/AST/Include/AST/Components/CDeclType.h index 17da5c03..f2abf6ef 100644 --- a/Libs/AST/Include/AST/Components/CDeclType.h +++ b/Libs/AST/Include/AST/Components/CDeclType.h @@ -8,9 +8,9 @@ namespace rift::AST { struct CDeclType : public p::Struct { - STRUCT(CDeclType, p::Struct) + P_STRUCT(CDeclType, p::Struct) - PROP(typeId) + P_PROP(typeId) p::Tag typeId; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclVariable.h b/Libs/AST/Include/AST/Components/CDeclVariable.h index 1c45013c..3dbd317b 100644 --- a/Libs/AST/Include/AST/Components/CDeclVariable.h +++ b/Libs/AST/Include/AST/Components/CDeclVariable.h @@ -11,9 +11,9 @@ namespace rift::AST { struct CDeclVariable : public CDeclaration { - STRUCT(CDeclVariable, CDeclaration) + P_STRUCT(CDeclVariable, CDeclaration) - PROP(typeId, p::Prop_NotSerialized) + P_PROP(typeId, p::Prop_NotSerialized) Id typeId = NoId; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclaration.h b/Libs/AST/Include/AST/Components/CDeclaration.h index 0d4c5b48..8925ddb8 100644 --- a/Libs/AST/Include/AST/Components/CDeclaration.h +++ b/Libs/AST/Include/AST/Components/CDeclaration.h @@ -8,7 +8,7 @@ namespace rift::AST { struct CDeclaration : public p::Struct { - STRUCT(CDeclaration, p::Struct) + P_STRUCT(CDeclaration, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h b/Libs/AST/Include/AST/Components/CExprBinaryOperator.h index 1d5725f1..997d138e 100644 --- a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h +++ b/Libs/AST/Include/AST/Components/CExprBinaryOperator.h @@ -43,9 +43,9 @@ namespace rift::AST { struct CExprBinaryOperator : public CExpression { - STRUCT(CExprBinaryOperator, CExpression) + P_STRUCT(CExprBinaryOperator, CExpression) - PROP(type) + P_PROP(type) BinaryOperatorType type = BinaryOperatorType::Add; diff --git a/Libs/AST/Include/AST/Components/CExprCall.h b/Libs/AST/Include/AST/Components/CExprCall.h index 2ceda851..c2508c2f 100644 --- a/Libs/AST/Include/AST/Components/CExprCall.h +++ b/Libs/AST/Include/AST/Components/CExprCall.h @@ -13,9 +13,9 @@ namespace rift::AST { struct CExprCall : public CExpression { - STRUCT(CExprCall, CExpression) + P_STRUCT(CExprCall, CExpression) - PROP(function) + P_PROP(function) Namespace function; }; @@ -32,10 +32,10 @@ namespace rift::AST // Data pointing to the id of the function from CExprCall's type and function names struct CExprCallId : public CExpression { - STRUCT(CExprCallId, CExpression, p::Struct_NotSerialized) + P_STRUCT(CExprCallId, CExpression, p::Struct_NotSerialized) // Id pointing to the function declaration - PROP(functionId) + P_PROP(functionId) Id functionId = NoId; diff --git a/Libs/AST/Include/AST/Components/CExprDeclRef.h b/Libs/AST/Include/AST/Components/CExprDeclRef.h index 5a32c917..a1621e7f 100644 --- a/Libs/AST/Include/AST/Components/CExprDeclRef.h +++ b/Libs/AST/Include/AST/Components/CExprDeclRef.h @@ -8,20 +8,20 @@ namespace rift::AST { struct CExprDeclRef : public CExpression { - STRUCT(CExprDeclRef, CExpression) + P_STRUCT(CExprDeclRef, CExpression) - PROP(ownerName) + P_PROP(ownerName) p::Tag ownerName; - PROP(name) + P_PROP(name) p::Tag name; }; struct CExprDeclRefId : public CExpression { - STRUCT(CExprDeclRefId, CExpression) + P_STRUCT(CExprDeclRefId, CExpression) - PROP(declarationId) + P_PROP(declarationId) Id declarationId; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprInputs.h b/Libs/AST/Include/AST/Components/CExprInputs.h index 03107002..b58ed241 100644 --- a/Libs/AST/Include/AST/Components/CExprInputs.h +++ b/Libs/AST/Include/AST/Components/CExprInputs.h @@ -11,12 +11,12 @@ namespace rift::AST { struct ExprOutput : public p::Struct { - STRUCT(ExprOutput, p::Struct) + P_STRUCT(ExprOutput, p::Struct) - PROP(nodeId) + P_PROP(nodeId) AST::Id nodeId = AST::NoId; - PROP(pinId) + P_PROP(pinId) AST::Id pinId = AST::NoId; @@ -30,12 +30,12 @@ namespace rift::AST struct CExprInputs : public p::Struct { - STRUCT(CExprInputs, p::Struct) + P_STRUCT(CExprInputs, p::Struct) - PROP(linkedOutputs) + P_PROP(linkedOutputs) p::TArray linkedOutputs; - PROP(pinIds) + P_PROP(pinIds) p::TArray pinIds; diff --git a/Libs/AST/Include/AST/Components/CExprOutputs.h b/Libs/AST/Include/AST/Components/CExprOutputs.h index 46ec5976..d3d855b4 100644 --- a/Libs/AST/Include/AST/Components/CExprOutputs.h +++ b/Libs/AST/Include/AST/Components/CExprOutputs.h @@ -11,12 +11,12 @@ namespace rift::AST { struct ExprInput : public p::Struct { - STRUCT(ExprInput, p::Struct) + P_STRUCT(ExprInput, p::Struct) - PROP(nodeId) + P_PROP(nodeId) AST::Id nodeId = AST::NoId; - PROP(pinId) + P_PROP(pinId) AST::Id pinId = AST::NoId; @@ -30,9 +30,9 @@ namespace rift::AST struct CExprOutputs : public p::Struct { - STRUCT(CExprOutputs, p::Struct) + P_STRUCT(CExprOutputs, p::Struct) - PROP(pinIds) + P_PROP(pinIds) p::TArray pinIds; diff --git a/Libs/AST/Include/AST/Components/CExprType.h b/Libs/AST/Include/AST/Components/CExprType.h index 9c6245af..32f49994 100644 --- a/Libs/AST/Include/AST/Components/CExprType.h +++ b/Libs/AST/Include/AST/Components/CExprType.h @@ -23,12 +23,12 @@ namespace rift::AST { struct CExprType : public p::Struct { - STRUCT(CExprType, p::Struct) + P_STRUCT(CExprType, p::Struct) - PROP(type) + P_PROP(type) AST::Namespace type; - PROP(mode) + P_PROP(mode) TypeMode mode = TypeMode::Value; }; @@ -44,12 +44,12 @@ namespace rift::AST struct CExprTypeId : public p::Struct { - STRUCT(CExprTypeId, p::Struct) + P_STRUCT(CExprTypeId, p::Struct) - PROP(id, p::Prop_NotSerialized) + P_PROP(id, p::Prop_NotSerialized) AST::Id id = AST::NoId; - PROP(mode) + P_PROP(mode) TypeMode mode = TypeMode::Value; }; diff --git a/Libs/AST/Include/AST/Components/CExprUnaryOperator.h b/Libs/AST/Include/AST/Components/CExprUnaryOperator.h index bc28eb11..8d6fa78c 100644 --- a/Libs/AST/Include/AST/Components/CExprUnaryOperator.h +++ b/Libs/AST/Include/AST/Components/CExprUnaryOperator.h @@ -24,9 +24,9 @@ namespace rift::AST { struct CExprUnaryOperator : public CExpression { - STRUCT(CExprUnaryOperator, CExpression) + P_STRUCT(CExprUnaryOperator, CExpression) - PROP(type) + P_PROP(type) UnaryOperatorType type = UnaryOperatorType::Not; diff --git a/Libs/AST/Include/AST/Components/CExpression.h b/Libs/AST/Include/AST/Components/CExpression.h index 031b01ac..a229af20 100644 --- a/Libs/AST/Include/AST/Components/CExpression.h +++ b/Libs/AST/Include/AST/Components/CExpression.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CExpression : public p::Struct { - STRUCT(CExpression, p::Struct) + P_STRUCT(CExpression, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CFileRef.h b/Libs/AST/Include/AST/Components/CFileRef.h index a75d6452..e2a15c76 100644 --- a/Libs/AST/Include/AST/Components/CFileRef.h +++ b/Libs/AST/Include/AST/Components/CFileRef.h @@ -15,9 +15,9 @@ namespace rift::AST */ struct CFileRef : public p::Struct { - STRUCT(CFileRef, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CFileRef, p::Struct, p::Struct_NotSerialized) - PROP(path) + P_PROP(path) p::String path; diff --git a/Libs/AST/Include/AST/Components/CLiteral.h b/Libs/AST/Include/AST/Components/CLiteral.h index 76359982..eecc900d 100644 --- a/Libs/AST/Include/AST/Components/CLiteral.h +++ b/Libs/AST/Include/AST/Components/CLiteral.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CLiteral : public p::Struct { - STRUCT(CLiteral, p::Struct) + P_STRUCT(CLiteral, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralBool.h b/Libs/AST/Include/AST/Components/CLiteralBool.h index a2e5dd66..efe8abbe 100644 --- a/Libs/AST/Include/AST/Components/CLiteralBool.h +++ b/Libs/AST/Include/AST/Components/CLiteralBool.h @@ -8,9 +8,9 @@ namespace rift::AST { struct CLiteralBool : public CLiteral { - STRUCT(CLiteralBool, CLiteral) + P_STRUCT(CLiteralBool, CLiteral) - PROP(value) + P_PROP(value) bool value = false; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralFloating.h b/Libs/AST/Include/AST/Components/CLiteralFloating.h index 1ac88740..751d04b5 100644 --- a/Libs/AST/Include/AST/Components/CLiteralFloating.h +++ b/Libs/AST/Include/AST/Components/CLiteralFloating.h @@ -24,13 +24,13 @@ namespace rift::AST { struct CLiteralFloating : public CLiteral { - STRUCT(CLiteralFloating, CLiteral) + P_STRUCT(CLiteralFloating, CLiteral) - PROP(value) + P_PROP(value) double value = 0.; - PROP(type) + P_PROP(type) FloatingType type = FloatingType::F32; diff --git a/Libs/AST/Include/AST/Components/CLiteralIntegral.h b/Libs/AST/Include/AST/Components/CLiteralIntegral.h index b38e33d7..be10d5d0 100644 --- a/Libs/AST/Include/AST/Components/CLiteralIntegral.h +++ b/Libs/AST/Include/AST/Components/CLiteralIntegral.h @@ -40,13 +40,13 @@ namespace rift::AST { struct CLiteralIntegral : public CLiteral { - STRUCT(CLiteralIntegral, CLiteral) + P_STRUCT(CLiteralIntegral, CLiteral) - PROP(value) + P_PROP(value) u64 value = 0; - PROP(type) + P_PROP(type) IntegralType type = IntegralType::S32; diff --git a/Libs/AST/Include/AST/Components/CLiteralString.h b/Libs/AST/Include/AST/Components/CLiteralString.h index 965f21e7..befb91e9 100644 --- a/Libs/AST/Include/AST/Components/CLiteralString.h +++ b/Libs/AST/Include/AST/Components/CLiteralString.h @@ -10,9 +10,9 @@ namespace rift::AST { struct CLiteralString : public CLiteral { - STRUCT(CLiteralString, CLiteral) + P_STRUCT(CLiteralString, CLiteral) - PROP(value) + P_PROP(value) p::String value; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CModule.h b/Libs/AST/Include/AST/Components/CModule.h index 71d9dc74..69c5c4e5 100644 --- a/Libs/AST/Include/AST/Components/CModule.h +++ b/Libs/AST/Include/AST/Components/CModule.h @@ -22,12 +22,12 @@ namespace rift::AST struct CModule : public p::Struct { - STRUCT(CModule, p::Struct) + P_STRUCT(CModule, p::Struct) - PROP(target) + P_PROP(target) RiftModuleTarget target = RiftModuleTarget::Executable; - PROP(dependencies) + P_PROP(dependencies) p::TArray dependencies; }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index 4ec43fd7..ee91ace3 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -9,9 +9,9 @@ namespace rift::AST { struct CNamespace : public p::Struct { - STRUCT(CNamespace, p::Struct) + P_STRUCT(CNamespace, p::Struct) - PROP(name); + P_PROP(name); p::Tag name; @@ -40,7 +40,7 @@ namespace rift::AST struct Namespace : public p::Struct { - STRUCT(Namespace, p::Struct) + P_STRUCT(Namespace, p::Struct) static constexpr p::i32 scopeCount = 8; p::Tag scopes[scopeCount]; // TODO: Implement Inline arrays diff --git a/Libs/AST/Include/AST/Components/CProject.h b/Libs/AST/Include/AST/Components/CProject.h index 578eadeb..4d50210d 100644 --- a/Libs/AST/Include/AST/Components/CProject.h +++ b/Libs/AST/Include/AST/Components/CProject.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CProject : public p::Struct { - STRUCT(CProject, p::Struct) + P_STRUCT(CProject, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStatement.h b/Libs/AST/Include/AST/Components/CStatement.h index ed60d700..fd33f30d 100644 --- a/Libs/AST/Include/AST/Components/CStatement.h +++ b/Libs/AST/Include/AST/Components/CStatement.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CStatement : public p::Struct { - STRUCT(CStatement, p::Struct) + P_STRUCT(CStatement, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtFor.h b/Libs/AST/Include/AST/Components/CStmtFor.h index db8d4362..534b5676 100644 --- a/Libs/AST/Include/AST/Components/CStmtFor.h +++ b/Libs/AST/Include/AST/Components/CStmtFor.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CStmtFor : public p::Struct { - STRUCT(CStmtFor, p::Struct) + P_STRUCT(CStmtFor, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtIf.h b/Libs/AST/Include/AST/Components/CStmtIf.h index 3cbf34d6..81d75566 100644 --- a/Libs/AST/Include/AST/Components/CStmtIf.h +++ b/Libs/AST/Include/AST/Components/CStmtIf.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CStmtIf : public p::Struct { - STRUCT(CStmtIf, p::Struct) + P_STRUCT(CStmtIf, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtInput.h b/Libs/AST/Include/AST/Components/CStmtInput.h index e0ab9fd3..bb2a6c8f 100644 --- a/Libs/AST/Include/AST/Components/CStmtInput.h +++ b/Libs/AST/Include/AST/Components/CStmtInput.h @@ -12,9 +12,9 @@ namespace rift::AST struct CStmtInput : public Struct { - STRUCT(CStmtInput, Struct) + P_STRUCT(CStmtInput, Struct) - PROP(linkOutputNode) + P_PROP(linkOutputNode) Id linkOutputNode = NoId; }; diff --git a/Libs/AST/Include/AST/Components/CStmtOutputs.h b/Libs/AST/Include/AST/Components/CStmtOutputs.h index bd30e355..7373ca7c 100644 --- a/Libs/AST/Include/AST/Components/CStmtOutputs.h +++ b/Libs/AST/Include/AST/Components/CStmtOutputs.h @@ -14,21 +14,21 @@ namespace rift::AST struct CStmtOutput : public p::Struct { - STRUCT(CStmtOutput, p::Struct) + P_STRUCT(CStmtOutput, p::Struct) - PROP(linkInputNode) + P_PROP(linkInputNode) Id linkInputNode = NoId; }; struct CStmtOutputs : public p::Struct { - STRUCT(CStmtOutputs, p::Struct) + P_STRUCT(CStmtOutputs, p::Struct) // Both arrays keep the same index to the input node and the output pin - PROP(pinIds) + P_PROP(pinIds) TArray pinIds; - PROP(linkInputNodes) + P_PROP(linkInputNodes) TArray linkInputNodes; diff --git a/Libs/AST/Include/AST/Components/CStmtReturn.h b/Libs/AST/Include/AST/Components/CStmtReturn.h index 07e21fc3..8c91c72b 100644 --- a/Libs/AST/Include/AST/Components/CStmtReturn.h +++ b/Libs/AST/Include/AST/Components/CStmtReturn.h @@ -12,6 +12,6 @@ namespace rift::AST */ struct CStmtReturn : public CExpression { - STRUCT(CStmtReturn, CExpression) + P_STRUCT(CStmtReturn, CExpression) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Tags/CChanged.h b/Libs/AST/Include/AST/Components/Tags/CChanged.h index 802f8977..ed1d1823 100644 --- a/Libs/AST/Include/AST/Components/Tags/CChanged.h +++ b/Libs/AST/Include/AST/Components/Tags/CChanged.h @@ -10,6 +10,6 @@ namespace rift::AST // Gets cleared after one frame struct CChanged : public p::Struct { - STRUCT(CChanged, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CChanged, p::Struct, p::Struct_NotSerialized) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Tags/CDirty.h b/Libs/AST/Include/AST/Components/Tags/CDirty.h index 3179a868..5ff510a2 100644 --- a/Libs/AST/Include/AST/Components/Tags/CDirty.h +++ b/Libs/AST/Include/AST/Components/Tags/CDirty.h @@ -14,7 +14,7 @@ namespace rift::AST template struct TDirty : public p::Struct { - STRUCT(TDirty, p::Struct, p::Struct_NotSerialized) + P_STRUCT(TDirty, p::Struct, p::Struct_NotSerialized) }; using CDirty = TDirty; diff --git a/Libs/AST/Include/AST/Components/Tags/CInvalid.h b/Libs/AST/Include/AST/Components/Tags/CInvalid.h index 5c1d7753..7f93342f 100644 --- a/Libs/AST/Include/AST/Components/Tags/CInvalid.h +++ b/Libs/AST/Include/AST/Components/Tags/CInvalid.h @@ -8,6 +8,6 @@ namespace rift::AST { struct CInvalid : public p::Struct { - STRUCT(CInvalid, p::Struct) + P_STRUCT(CInvalid, p::Struct) }; } // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h index 3deba132..b5642003 100644 --- a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h +++ b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h @@ -8,6 +8,6 @@ namespace rift { struct CPendingLoad : public p::Struct { - STRUCT(CPendingLoad, p::Struct) + P_STRUCT(CPendingLoad, p::Struct) }; } // namespace rift diff --git a/Libs/AST/Include/AST/Components/Views/CNodePosition.h b/Libs/AST/Include/AST/Components/Views/CNodePosition.h index 8ee8d7d1..e167191d 100644 --- a/Libs/AST/Include/AST/Components/Views/CNodePosition.h +++ b/Libs/AST/Include/AST/Components/Views/CNodePosition.h @@ -9,9 +9,9 @@ namespace rift { struct CNodePosition : public p::Struct { - STRUCT(CNodePosition, p::Struct) + P_STRUCT(CNodePosition, p::Struct) - PROP(position) + P_PROP(position) p::v2 position; CNodePosition() = default; diff --git a/Libs/AST/Include/AST/Statics/SLoadQueue.h b/Libs/AST/Include/AST/Statics/SLoadQueue.h index 549774c1..e9b2544a 100644 --- a/Libs/AST/Include/AST/Statics/SLoadQueue.h +++ b/Libs/AST/Include/AST/Statics/SLoadQueue.h @@ -11,7 +11,7 @@ namespace rift::AST // Keeps a list of entities to load from disk struct SLoadQueue : public p::Struct { - STRUCT(SLoadQueue, p::Struct) + P_STRUCT(SLoadQueue, p::Struct) TArray pendingSyncLoad; TArray pendingAsyncLoad; diff --git a/Libs/AST/Include/AST/Statics/SModules.h b/Libs/AST/Include/AST/Statics/SModules.h index 8e7eade5..e6eed751 100644 --- a/Libs/AST/Include/AST/Statics/SModules.h +++ b/Libs/AST/Include/AST/Statics/SModules.h @@ -10,7 +10,7 @@ namespace rift::AST { struct SModules : public p::Struct { - STRUCT(SModules, p::Struct) + P_STRUCT(SModules, p::Struct) p::TMap modulesByPath; }; diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index 40ec97e7..0e1d9028 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -15,7 +15,7 @@ namespace rift::AST // Contains loaded string data from disk struct SStringLoad : public Struct { - STRUCT(SStringLoad, Struct) + P_STRUCT(SStringLoad, Struct) // This buffers are always in sync with size // They bind by array index an Id, path and loaded string diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index f05e953d..c3e5a5f4 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -13,7 +13,7 @@ namespace rift::AST struct STypes : public Struct { - STRUCT(STypes, Struct) + P_STRUCT(STypes, Struct) TMap typesByName; // TODO: Use StringView to point to CFileRef component's path. diff --git a/Libs/AST/Include/ASTModule.h b/Libs/AST/Include/ASTModule.h index 0bf2869d..5272f46a 100644 --- a/Libs/AST/Include/ASTModule.h +++ b/Libs/AST/Include/ASTModule.h @@ -14,7 +14,7 @@ namespace rift class ASTModule : public Module { - CLASS(ASTModule, Module) + P_CLASS(ASTModule, Module) public: static const p::Tag structType; diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index 1b08ca14..5a462a00 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -11,7 +11,7 @@ namespace rift { class Backend : public Class { - CLASS(Backend, Class) + P_CLASS(Backend, Class) public: virtual Tag GetName() diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index ff2f5911..469580e3 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -17,16 +17,16 @@ namespace rift struct CompileError : public p::Struct { - STRUCT(CompileError, p::Struct) + P_STRUCT(CompileError, p::Struct) - PROP(text) + P_PROP(text) String text; }; struct Compiler : public p::Struct { - STRUCT(Compiler, p::Struct) + P_STRUCT(Compiler, p::Struct) AST::Tree& ast; CompilerConfig config; diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index 36768dd7..ef91fe6e 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -15,7 +15,7 @@ namespace rift struct CompilerConfig : public p::Struct { - STRUCT(CompilerConfig, p::Struct) + P_STRUCT(CompilerConfig, p::Struct) String buildMode{"Release"}; diff --git a/Libs/AST/Include/Module.h b/Libs/AST/Include/Module.h index 8ceca8e0..dd3b16fb 100644 --- a/Libs/AST/Include/Module.h +++ b/Libs/AST/Include/Module.h @@ -16,7 +16,7 @@ namespace rift class Module : public Class { - CLASS(Module, Class) + P_CLASS(Module, Class) enum class State : u8 { diff --git a/Libs/AST/Include/View.h b/Libs/AST/Include/View.h index f660facd..9d92a8de 100644 --- a/Libs/AST/Include/View.h +++ b/Libs/AST/Include/View.h @@ -11,9 +11,9 @@ namespace rift { struct View : public p::Struct { - STRUCT(View, p::Struct) + P_STRUCT(View, p::Struct) - PROP(name) + P_PROP(name) p::Tag name; p::TArray supportedTypes; diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index 9be89901..44aa8e7a 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -9,7 +9,7 @@ namespace rift { class MIRBackendModule : public Module { - CLASS(MIRBackendModule, Module) + P_CLASS(MIRBackendModule, Module) public: MIRBackendModule(); @@ -18,7 +18,7 @@ namespace rift class MIRBackend : public Backend { - CLASS(MIRBackend, Backend) + P_CLASS(MIRBackend, Backend) public: Tag GetName() override diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h b/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h index 0b215665..f290285c 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h @@ -8,6 +8,6 @@ namespace rift { struct CDeclCStatic : public AST::CDeclRecord { - STRUCT(CDeclCStatic, CDeclRecord) + P_STRUCT(CDeclCStatic, CDeclRecord) }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h b/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h index f14cdfe7..d44cb6a6 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h @@ -8,6 +8,6 @@ namespace rift { struct CDeclCStruct : public AST::CDeclRecord { - STRUCT(CDeclCStruct, CDeclRecord) + P_STRUCT(CDeclCStruct, CDeclRecord) }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h index e646822c..4cff9d92 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h @@ -9,12 +9,12 @@ namespace rift { struct CNativeBinding : public p::Struct { - STRUCT(CNativeBinding, p::Struct) + P_STRUCT(CNativeBinding, p::Struct) - PROP(binaries) + P_PROP(binaries) p::TArray binaries; - PROP(autoGenerateDefinitions) + P_PROP(autoGenerateDefinitions) bool autoGenerateDefinitions = false; }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h index a07afca9..a44ff5b3 100644 --- a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h +++ b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h @@ -14,7 +14,7 @@ namespace rift class NativeBindingModule : public Module { - CLASS(NativeBindingModule, Module) + P_CLASS(NativeBindingModule, Module) void Load() override; void SyncIncludes(AST::Tree& ast); diff --git a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h index ca9dfc64..1a7a2bce 100644 --- a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h +++ b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h @@ -9,6 +9,6 @@ namespace rift { class NativeBindingEditorModule : public Module { - CLASS(NativeBindingEditorModule, Module) + P_CLASS(NativeBindingEditorModule, Module) }; } // namespace rift diff --git a/Libs/Editor/Include/Components/CDeclRename.h b/Libs/Editor/Include/Components/CDeclRename.h index 7fa7bfcc..13b1db0c 100644 --- a/Libs/Editor/Include/Components/CDeclRename.h +++ b/Libs/Editor/Include/Components/CDeclRename.h @@ -13,7 +13,7 @@ namespace rift::Editor { struct CDeclRename : public p::Struct { - STRUCT(CDeclRename, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CDeclRename, p::Struct, p::Struct_NotSerialized) // Renaming uses this buffer to temporarely store the name being edited p::String buffer; diff --git a/Libs/Editor/Include/Components/CModuleEditor.h b/Libs/Editor/Include/Components/CModuleEditor.h index cfab5b7f..8919405e 100644 --- a/Libs/Editor/Include/Components/CModuleEditor.h +++ b/Libs/Editor/Include/Components/CModuleEditor.h @@ -13,7 +13,7 @@ namespace rift::Editor { struct CModuleEditor : public p::Struct { - STRUCT(CModuleEditor, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CModuleEditor, p::Struct, p::Struct_NotSerialized) bool pendingFocus = false; }; diff --git a/Libs/Editor/Include/Components/CTypeEditor.h b/Libs/Editor/Include/Components/CTypeEditor.h index 96e7fd1e..e41574b2 100644 --- a/Libs/Editor/Include/Components/CTypeEditor.h +++ b/Libs/Editor/Include/Components/CTypeEditor.h @@ -13,7 +13,7 @@ namespace rift::Editor { struct CTypeEditor : public p::Struct { - STRUCT(CTypeEditor, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CTypeEditor, p::Struct, p::Struct_NotSerialized) static const Tag rightTopNode; static const Tag rightBottomNode; diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index d9530af8..e8d5aaf5 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -23,7 +23,7 @@ namespace rift::Editor struct SEditor : public Struct { - STRUCT(SEditor, Struct) + P_STRUCT(SEditor, Struct) ImGuiID dockspaceID = 0; DockSpaceLayout layout; diff --git a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h index 20e27bc6..c47dfa48 100644 --- a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h +++ b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h @@ -9,12 +9,11 @@ #include - namespace rift { class GraphViewModule : public Module { - CLASS(GraphViewModule, Module) + P_CLASS(GraphViewModule, Module) public: void Load() override; diff --git a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h index 9047608b..f419b09e 100644 --- a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h +++ b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h @@ -9,6 +9,6 @@ namespace rift { class GraphViewEditorModule : public Module { - CLASS(GraphViewEditorModule, Module) + P_CLASS(GraphViewEditorModule, Module) }; } // namespace rift diff --git a/Tests/AST/Namespaces.spec.cpp b/Tests/AST/Namespaces.spec.cpp index fe973c53..44ebcb7c 100644 --- a/Tests/AST/Namespaces.spec.cpp +++ b/Tests/AST/Namespaces.spec.cpp @@ -9,7 +9,6 @@ #include - using namespace snowhouse; using namespace bandit; using namespace rift; From fa66fda7578e8d838d03484baf75dfb3a887ddcb Mon Sep 17 00:00:00 2001 From: muit Date: Mon, 11 Sep 2023 00:23:00 +0200 Subject: [PATCH 03/52] Added initial C generation for MIR --- Extern/Pipe | 2 +- Libs/AST/Include/Compiler/Compiler.h | 2 +- Libs/AST/Src/Compiler/Compiler.cpp | 4 +- Libs/Backends/MIR/CMakeLists.txt | 1 - Libs/Backends/MIR/Compiler/Src/Components.h | 18 +- .../MIR/Compiler/Src/IRGeneration.cpp | 361 ++++++++++++++++-- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 46 ++- Tools/mir/b2m.exe | Bin 0 -> 646144 bytes Tools/mir/c2m.exe | Bin 0 -> 658432 bytes Tools/mir/m2b.exe | Bin 0 -> 646656 bytes 10 files changed, 383 insertions(+), 51 deletions(-) create mode 100644 Tools/mir/b2m.exe create mode 100644 Tools/mir/c2m.exe create mode 100644 Tools/mir/m2b.exe diff --git a/Extern/Pipe b/Extern/Pipe index 7e5a48c1..557dcfa4 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 7e5a48c16da4e9b232fe062dc50607ff6ab3a5fa +Subproject commit 557dcfa4d3689435338d16cd6d10c7ae05a55487 diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index 469580e3..e1e0b2b6 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -37,7 +37,7 @@ namespace rift Compiler(AST::Tree& ast, const CompilerConfig& config) : ast{ast}, config{config} {} // Errors - void AddError(StringView str); + void Error(StringView str); const TArray& GetErrors() const { return errors; diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 12734ffd..9b198850 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -15,7 +15,7 @@ namespace rift { - void Compiler::AddError(StringView str) + void Compiler::Error(StringView str) { p::Error(str); CompileError newError{}; @@ -31,7 +31,7 @@ namespace rift if (!backend) { - compiler.AddError("Invalid backend."); + compiler.Error("Invalid backend."); return; } diff --git a/Libs/Backends/MIR/CMakeLists.txt b/Libs/Backends/MIR/CMakeLists.txt index c2798038..6526ff53 100644 --- a/Libs/Backends/MIR/CMakeLists.txt +++ b/Libs/Backends/MIR/CMakeLists.txt @@ -8,4 +8,3 @@ target_link_libraries(RiftBackendMIR PRIVATE mir_static RiftBindingNative ) - diff --git a/Libs/Backends/MIR/Compiler/Src/Components.h b/Libs/Backends/MIR/Compiler/Src/Components.h index 22da0bdf..aa1b7678 100644 --- a/Libs/Backends/MIR/Compiler/Src/Components.h +++ b/Libs/Backends/MIR/Compiler/Src/Components.h @@ -7,6 +7,20 @@ namespace rift { - using CMIRModule = MIR_module_t; - using CMIRType = MIR_type_t; + struct CMIRModule + { + p::String code; + }; + struct CMIRType + { + p::Tag value; + }; + struct CMIRLiteral + { + p::Tag value; + }; + struct CMIRFunctionSignature + { + p::String value; + }; } // namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 349aec1e..4b8ee4f7 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -3,60 +3,365 @@ #include "IRGeneration.h" #include "mir.h" +#include "Pipe/Core/String.h" +#include "Pipe/Core/StringView.h" -#include #include #include #include #include -#include -#include namespace rift::MIR { - void GenerateIR(Compiler& compiler, MIR_context_t& ctx) + void Generate(Compiler& compiler, MIR_context_t& ctx) { MIRAccess access{compiler.ast}; - BindNativeTypes(ctx, access); - + CGenerator cGen{compiler, access}; + cGen.BindNativeTypes(); + cGen.GenerateLiterals(); for (AST::Id moduleId : FindAllIdsWith(access)) { - GenerateIRModule(compiler, access, moduleId, ctx); + cGen.GenerateModule(moduleId); } } - void GenerateIRModule( - Compiler& compiler, MIRAccess access, AST::Id moduleId, MIR_context_t& ctx) + void CGenerator::GenerateModule(AST::Id moduleId) { ZoneScoped; - auto& ast = compiler.ast; - const Tag name = AST::GetModuleName(compiler.ast, moduleId); + const Tag name = AST::GetModuleName(compiler.ast, moduleId); + CMIRModule& mirModule = compiler.ast.Add(moduleId); + code = &mirModule.code; - const auto& module = compiler.ast.Get(moduleId); - compiler.ast.Add(moduleId, MIR_new_module(ctx, name.AsString().data())); - // NOTE: Module generation here + // Get all rift types from the module + TArray typeIds; + GetChildren(access, moduleId, typeIds); + ExcludeIdsWithout(access, typeIds); - MIR_finish_module(ctx); - } + { // Native declarations + TArray cStructIds = FindIdsWith(access, typeIds); + TArray cStaticIds = FindIdsWith(access, typeIds); + TArray cFunctionIds; + p::GetChildren(access, cStaticIds, cFunctionIds); + ExcludeIdsWithout(access, cFunctionIds); + DeclareStructs(cStructIds); + DeclareFunctions(cFunctionIds, false); + } + + TArray staticFunctionIds; + { // Rift declarations & definitions + TArray structIds = FindIdsWith(access, typeIds); + TArray staticIds = FindIdsWith(access, typeIds); + TArray classIds = FindIdsWith(access, typeIds); + TArray classFunctionIds; + p::GetChildren(access, staticIds, staticFunctionIds); + p::GetChildren(access, classIds, classFunctionIds); + ExcludeIdsWithout(access, staticFunctionIds); + ExcludeIdsWithout(access, classFunctionIds); + TArray functionIds; + functionIds.Append(staticFunctionIds); + functionIds.Append(classFunctionIds); + DeclareStructs(structIds); + DeclareStructs(classIds); + DeclareFunctions(functionIds); - void BindNativeTypes(MIR_context_t& ctx, MIRAccess access) + DefineStructs(structIds); + DefineStructs(classIds); + DefineFunctions(functionIds); + } + + AST::Id mainFunctionId = AST::NoId; + const auto& module = compiler.ast.Get(moduleId); + if (module.target == AST::RiftModuleTarget::Executable) + { + mainFunctionId = FindMainFunction(staticFunctionIds); + CreateMain(mainFunctionId); + } + } + + void CGenerator::BindNativeTypes() { const auto& nativeTypes = static_cast(access.GetContext()).GetNativeTypes(); - access.Add(nativeTypes.boolId, CMIRType{MIR_T_I8}); - access.Add(nativeTypes.floatId, CMIRType{MIR_T_F}); - access.Add(nativeTypes.doubleId, CMIRType{MIR_T_D}); - access.Add(nativeTypes.u8Id, CMIRType{MIR_T_U8}); - access.Add(nativeTypes.i8Id, CMIRType{MIR_T_I8}); - access.Add(nativeTypes.u16Id, CMIRType{MIR_T_U16}); - access.Add(nativeTypes.i16Id, CMIRType{MIR_T_I16}); - access.Add(nativeTypes.u32Id, CMIRType{MIR_T_U32}); - access.Add(nativeTypes.i32Id, CMIRType{MIR_T_I32}); - access.Add(nativeTypes.u64Id, CMIRType{MIR_T_U64}); - access.Add(nativeTypes.i64Id, CMIRType{MIR_T_I64}); + access.Add(nativeTypes.boolId, CMIRType{"char"}); + access.Add(nativeTypes.floatId, CMIRType{"float"}); + access.Add(nativeTypes.doubleId, CMIRType{"double"}); + access.Add(nativeTypes.u8Id, CMIRType{"unsigned char"}); + access.Add(nativeTypes.i8Id, CMIRType{"char"}); + access.Add(nativeTypes.u16Id, CMIRType{"unsigned short"}); + access.Add(nativeTypes.i16Id, CMIRType{"short"}); + access.Add(nativeTypes.u32Id, CMIRType{"unsigned long"}); + access.Add(nativeTypes.i32Id, CMIRType{"long"}); + access.Add(nativeTypes.u64Id, CMIRType{"unsigned long long"}); + access.Add(nativeTypes.i64Id, CMIRType{"long long"}); // access.Add(nativeTypes.stringId, {}); } + + void CGenerator::GenerateLiterals() + { + for (AST::Id id : FindAllIdsWith(access)) + { + const auto& boolean = access.Get(id); + access.Add(id, CMIRLiteral{.value = boolean.value ? "true" : "false"}); + } + String strValue; + for (AST::Id id : FindAllIdsWith(access)) + { + strValue.clear(); + const auto& integral = access.Get(id); + Strings::ToString(strValue, integral.value); + access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); + } + for (AST::Id id : FindAllIdsWith(access)) + { + strValue.clear(); + const auto& floating = access.Get(id); + Strings::ToString(strValue, floating.value); + if (floating.type == AST::FloatingType::F32) + { + strValue.push_back('f'); + } + access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); + } + for (AST::Id id : FindAllIdsWith(access)) + { + strValue.clear(); + const auto& string = access.Get(id); + strValue.push_back('\"'); + strValue.append(string.value); + strValue.push_back('\"'); + access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); + } + } + + void CGenerator::DeclareStructs(TView ids) + { + ZoneScoped; + code->append("// Struct Declarations\n"); + for (AST::Id id : ids) + { + p::Tag name = AST::GetNameUnsafe(access, id); + access.Add(id, CMIRType{name}); + Strings::FormatTo(*code, "typedef struct {0} {0};\n", name); + } + code->push_back('\n'); + } + + void CGenerator::DefineStructs(TView ids) + { + ZoneScoped; + code->append("// Struct Definitions\n"); + p::String membersCode; + TArray memberIds; + for (AST::Id id : ids) + { + membersCode.clear(); + memberIds.Clear(false); + p::GetChildren(access, id, memberIds); + + ExcludeIdsWithout(access, memberIds); + for (AST::Id memberId : memberIds) + { + const auto& var = access.Get(memberId); + + const Tag memberName = AST::GetName(access, memberId); + if (auto* irType = access.TryGet(var.typeId)) + { + Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); + } + else + { + const Tag typeName = AST::GetName(access, id); + compiler.Error(Strings::Format( + "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); + } + } + + const auto& type = access.Get(id); + Strings::FormatTo(*code, "typedef struct {0} {0} {{\n{1}}}\n", type.value, membersCode); + } + code->push_back('\n'); + } + + void CGenerator::DeclareFunctions(TView ids, bool useFullName) + { + ZoneScoped; + code->append("// Function Declarations\n"); + + for (AST::Id id : ids) + { + auto& signature = access.Add(id).value; + + signature.append("void "); + const p::String name = useFullName ? AST::GetFullName(access, id) + : p::String{AST::GetName(access, id).AsString()}; + signature.append(name); + signature.push_back('('); + + if (auto* outputs = access.TryGet(id)) + { + for (i32 i = 0; i < outputs->pinIds.Size(); ++i) + { + AST::Id inputId = outputs->pinIds[i]; + if (access.Has(inputId)) + { + continue; + } + + Tag inputName = AST::GetName(access, inputId); + + AST::Id typeId = access.Get(inputId).id; + const auto* irType = access.TryGet(typeId); + if (irType) + { + Strings::FormatTo(signature, "{0} {1}, ", inputName, irType->value); + } + else + { + const String functionName = AST::GetFullName(access, id); + compiler.Error(Strings::Format( + "Input '{}' in function '{}' has an invalid type. Using i32 instead.", + inputName, functionName)); + } + } + Strings::RemoveFromEnd(signature, ", "); + } + signature.push_back(')'); + + // Create function + code->append(signature); + code->append(";\n"); + } + code->push_back('\n'); + } + + void CGenerator::DefineFunctions(TView ids) + { + ZoneScoped; + code->append("// Function Definitions\n"); + for (AST::Id id : ids) + { + const p::String& signature = access.Get(id).value; + code->append(signature); + code->append(" {\n"); + + const auto& output = access.Get(id); + AddStmtBlock(output.linkInputNode); + + code->append("}\n"); + } + code->push_back('\n'); + } + + void CGenerator::AddStmtBlock(AST::Id firstStmtId) + { + ZoneScoped; + + AST::Id splitId = AST::NoId; + TArray stmtIds; + AST::GetStmtChain(access, firstStmtId, stmtIds, splitId); + + for (AST::Id id : stmtIds) + { + if (const auto* call = access.TryGet(id)) + { + AddCall(id, *call); + } + } + + if (splitId != AST::NoId) + { + if (access.Has(splitId)) + { + AddStmtIf(splitId); + } + } + // TODO: Resolve continuation block and generate it + } + + void CGenerator::AddExpr(const AST::ExprOutput& output) + { + const auto* value = + !IsNone(output.pinId) ? access.TryGet(output.pinId) : nullptr; + // TODO + } + + void CGenerator::AddStmtIf(AST::Id id) + { + const auto& outputs = access.Get(id); + const auto& connectedIds = outputs.linkInputNodes; + Check(connectedIds.Size() == 2); + const auto& exprInputs = access.Get(id); + Check(exprInputs.linkedOutputs.Size() == 1); + + code->append("if ("); + AddExpr(exprInputs.linkedOutputs.First()); + code->append("){\n"); + AddStmtBlock(connectedIds[0]); + code->append("} else {\n"); + AddStmtBlock(connectedIds[1]); + code->append("}\n"); + } + + void CGenerator::AddCall(AST::Id id, const AST::CExprCallId& call) + { + /*const AST::Id functionId = call.functionId; + if (!access.IsValid(functionId)) + { + compiler.Error("Call to an unknown function"); + return; + } + const auto* function = access.TryGet(functionId); + if (!Ensure(function)) + { + compiler.Error(Strings::Format( + "Call to an invalid function: '{}'", AST::GetName(access, functionId))); + return; + } + + TArray args; + if (auto* inputs = access.TryGet(id)) + { + args.Reserve(inputs->linkedOutputs.Size()); + for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) + { + AST::ExprOutput output = inputs->linkedOutputs[i]; + if (!output.IsNone()) + { + args.Add(AddExpr(gen, access, output)); + } + } + } + builder.CreateCall(function->instance, ToLLVM(args));*/ + } + + void CGenerator::CreateMain(AST::Id functionId) + { + if (p::IsNone(functionId)) + { + compiler.Error(Strings::Format("Module is executable but has no \"Main\" function")); + return; + } + + // auto* customMainFunction = access.Get(functionId).instance; + + code->append("void main() {\nMain();\nreturn 0;\n}\n"); + } + + AST::Id CGenerator::FindMainFunction(p::TView functionIds) + { + static const p::Tag mainFunctionName{"Main"}; + + for (AST::Id id : functionIds) + { + const auto* ns = access.TryGet(id); + if (ns && ns->name == mainFunctionName) + { + return id; + } + } + return AST::NoId; + } } // namespace rift::MIR diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index 48b849ba..b075b51a 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -22,15 +22,13 @@ #include #include #include +#include +#include +#include #include #include -namespace rift -{ - struct CIRFunction; -} - namespace rift { struct Compiler; @@ -41,21 +39,37 @@ namespace rift::MIR // Defines a single ecs access dfor the entire IR generation using MIRAccess = p::TAccessRef, AST::CLiteralBool, AST::CLiteralIntegral, AST::CLiteralFloating, - AST::CLiteralString>; + AST::CDeclType, AST::CDeclVariable, AST::CDeclStruct, AST::CDeclClass, AST::CDeclStatic, + AST::CParent, AST::CInvalid, AST::CChild, AST::CModule, AST::CLiteralBool, + AST::CLiteralIntegral, AST::CLiteralFloating, AST::CLiteralString, AST::CDeclFunction, + CDeclCStruct, CDeclCStatic, p::TWrite, p::TWrite, + p::TWrite>; + + void Generate(Compiler& compiler, MIR_context_t& ctx); - struct ModuleIRGen + + struct CGenerator { Compiler& compiler; - MIR_context_t& ctx; - MIR_module_t& module; - }; + MIRAccess access; + p::String* code = nullptr; + + void GenerateModule(AST::Id moduleId); - void GenerateIR(Compiler& compiler, MIR_context_t& ctx); + void BindNativeTypes(); + void GenerateLiterals(); - void GenerateIRModule( - Compiler& compiler, MIRAccess access, AST::Id moduleId, MIR_context_t& ctx); + void DeclareStructs(p::TView ids); + void DefineStructs(p::TView ids); + void DeclareFunctions(p::TView ids, bool useFullName = true); + void DefineFunctions(p::TView ids); + + void AddStmtBlock(AST::Id firstStmtId); + void AddStmtIf(AST::Id id); + void AddExpr(const AST::ExprOutput& output); + void AddCall(AST::Id id, const AST::CExprCallId& call); + void CreateMain(AST::Id functionId); + AST::Id FindMainFunction(p::TView functionIds); + }; - void BindNativeTypes(MIR_context_t& ctx, MIRAccess access); } // namespace rift::MIR diff --git a/Tools/mir/b2m.exe b/Tools/mir/b2m.exe new file mode 100644 index 0000000000000000000000000000000000000000..00a456ea68b2046138eda808ec111850828b7e7d GIT binary patch literal 646144 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

S)Rerineo?Yp$KJ;0a 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

pw4CNdGdV9z zkl*(U&RF3@&l;EzFI~c{S`$J^!A4RgM3Q&g74!Ld&A8L-(=7b4Wq?T?%#@U6eq=Rl z#RvN`@=$~rrR!jL=)$6f2_;Jp_L-#3ea?E36&wsDz+Gb+@~TIg^E|&bmA7U^S5^9P z7se#p`^{nM>*&&Cd-N%od}OY}K6`i6Csn`@HB7#oBL3T+S7PV1KsRfFRw$!T>a?0E zEKgy53gjTaJ^=YI@60jVtZ?RtM+hM`#B=4d#2>rtN#EA|3E7{`2!_ZcwqPWytt6-h zOs^49^B3^Ot zOZy5NpH}O%?1l*F(Y8TibOtFb_zco|$?`cqk{o8!dsSbApvk5pDVNMXiDePY(jiX^ z;pX`YB}X;z+Jp1K!`zEHknP7Wnh%3~D3;sxXmG!=FIV^EJ41i*mWm_;I8(*HQhg1R zTnB%7DyNwoT|^p7?gmVg>;!pwa1LpGKw?9Wl_uiYK>1(t@>wWHiF(F@#>Y7QqP@L6 zQ+iJ07KDdI-OZY$epptvY)k70Rp*h9b#_&7aVsDNojX@M*Nmf^mR!uFuj&uuG@Rc= z01hB^bVDFLvOGH5e+mt5XFCeFdiU@Mvm72QZuKz!QtnYCx*1G%w^DU&S#(!~AG&L) zfD6d2g7F=Y`2@}&x58W!`NFZeQz$hTb;%W+L1fG@T9}+)3zMtDp5zcaEVkC?JuceXvb6`?4j?dCwmZMfgFg_Lb28G)&`?(NL6>19Mts;NHnDJ3Zpr_5zj%Y4LP?ZJ zsS5z~V<)}_1PmoUHW?8=Mk3zKZ?=#!O#Y#}h1F)51l9}6Gr!>}VVvQ_n}c7a>sqHd zgUl02KG24H=pZ-HL>d+LDmRd~ZgA6vdoV{GimNNzY47xWWW2W^mK)h2-=5-MEFM4! z#NZyHMQCbyFLrJShpyO}c9{l+2`y8Q5#_v>#t1e%wkmsYo_&ER8IRiZu34DhS2K5l zoO%V)VIq+mEA7+|(?l91&qzI<|#&xmmd%~hY?m3c^2 zPiFJ5A71B=Vv`oV@@4Kp77hQO?{_0M$#?!+%SAwn;N*jC*pYVi8M*4KX~c>s`Rp`4 z7RczZrEH~wacTXem0HIBHuWTjTzG{>#SZLZ$i_n$4^!>JCU zpjU*2ywr{zFyc+m;d!>M`Yq&g+%#I?P-A0cWq)I|BdpmFbx zB;GBNx08Kerj^}EFPB>u%sn2eduevoBt2nU{#5&6g$z~<(R!fUL&`_9Bb+jv+MJ0E zbcLUMe(MU=O-_sPEQ+N9g%));F?hKQQK2qqvo4IiKu1QU*$j24%qj9xM{eZQ9|I0{5oClxSq{7Gy&x;~hhTBsqTaU~k#v_w?wVjwIU8k!_ z#_0+j)mqcJ>vT0;iZ@T9Kn*!I!0r>4D56bFyD14dU%;epsWE>ElzUK#{?gAZP$>T# zzG$i%m*__Ji$*@v7G+_^LuH~T>k%6C!D|&~i~D&f6;is6SiOBPp%raZ7ZXGf?LJD4 z#t!6|Y)Y(jYF)y$V7cg+pZ;e0RvI4zh?|{msBcfahkXM~_n~^&;H6t>#L&xvy^)Uv(a8GEZ2 zZ_%+J4b!^3X>gf)fb6wdgRb7~2y=kk&L15hv;LVsKn~&KXA1J8-yU4+(Q!kSB*m;! zCB~uS`6PRkjmOE`uVHNL1~B#rqw$I)&S!Uf$OC`0G6eUMTNbKYHuGZQETsu}xm`;H z$)k)VVsNP?qE(iNhqHU;;{#-AXj>nljXfexjFIyajm;Zl??E=?%YPb|Wyn zWZTBqA+cO!nuIBV>@lVGqEdZ`kdFG+ns!5&FJ=k~gjq~tIQNW%o>@l*5pXa`DK;62 zyJ`ogzZj>)%T1(%>N`-Z462Yn*hAcHLUCQ!8%ldGOFhhwvS3>SNF{rI0Um6V|B56J zCXmFrLFF`A!UpMkqBXVI{fxb>|3{IjM423_$f9EtHR~D@8!@UmH`MWVLuxK$o%_j} z4G2elYZh#h9W3@L54I#Q$M#)qYE}fI-4p*nREl*?om}2D^^0-I0qX!7=_wGcbQZ1E zqg^9Y*T-8ok4t`kU7CF8o1H}`k!fQUTKD9TmCmBx3pN@{Me~<*uwawD{+R1fa-pH$ zF6JjsLcO{%UENbpCYtLW=Gwl6%$&qTdesSMJfU2nGTnMKUe{1w9=xt^55{Zq=GLtYC01Ykx~Fx~*sNrqsyLhIgY@*@h;Ln3 zZ)OoR%4>gx=>H}9 zqVnXS!NfQjWiFpn1&>coab`kwOWE^IrP5L4K%=hNq{ z2%`E|h*I=$Qm<^eiNm@)@ieKeFpc(Iecp=EJSH1t(QmyNBH(TIT6@BUipX9u|L>E3 z@>mHG%m@9_BQY zC7HtmXB-AFx_17s{qc@Ad(iA3_93D3Yoq6~j^yDIAz65Um0MHQGmUDQkkyAjV_2N} zM{!)|s&C+z^mSXfpWaRF07|OAll~EM)Y0>=JRo;il!=1!RDbm>MCS@_>nGlZ z({<@lx@jPYG2|ezaKg6y-p+^}TurSAtVY?_FVV2k|of{WA5#< z-P;P9;`Y7n?PJ{ABkk=w-P=Rl+ltm<4r=*>E`_`@1hR1*G>bq@_-h6NP;%h2{}X>U zbjdUNYvtkfVe?ag5r z+lqzh^wWFj6e4+UcEn;vT$bH$F?dmy-D7cg{n=%)&@tO{F&;8y*^0#`s|SJu2{{74 z*K9OYR))w|WO&W-X6QbNlI%AGt^_xy|pj0OM2kgHCK7c9E3_sgU{DT@y!9*I-2VK>s(7vd)YC` zZXcTTZe_gcwETx#NGM3r9Od{mi2o;xOX_%RdQ0bT+HuAwL`%0UdPEW%2!+`d+`(spP}6=dJmDpy!VjaJIuW2G{;#)&#n^yd+y|+ zw`$+eJ;y);fTot*!nfp;Fas@+=??5zvA)!V%lw6`Yt zA?@melynd2*MCY1#oju6Tr-!MjyHVM@sQpiwv-b9W$0Q>kS0;NDD*Tu_mphily2D;{A0 zYKPn*9LCM8Pzis%;6wRAqrWhz8SfNFlOS|4pI!^9HeUNSHS`@KA5B8Zkkt3t1N#3j zGBq1X9LA#+JSv=@#$#=>bL~Vmmb?^2`)Ql833fH5v|^|ikAY--l8zCag{-xv2_d(E zxX!xtyuK26$?CVcGMJjg)T3)`T-{Lj!Mr~7YSQDE1IJD~t8pHJs)1p+0w&;26 z2O1iC57)y6#)nsop>YcJHd;)RGEy$Ls&ngAKA)qHLe#h|u6#ar5OND@s>=}EZRPW< ziM^M1F7)5#$NYIPwO6;?GE?C8f5~pYM70t9cYFiP=M2c8f?+9lUQrfXgTqG!vK>hW zq)(-{e0IzSLaBk@d5P5-%NME9Owvt{wey$MJ#1!*UBw-DBSXehi=!8k2c z`p7k;#v{ppFmKoJRJ6hqUZ4;k9}nkbYb0w2Q~QCFB3LdLcIS_M+23iIpfB5J zY1Wpxg@K)hmzY@JtW6=S=U*#bx^FgVey<7r{{GxZXQPJtvt>X%Y4(ICLNip+k+pJNgd6dIz8DF=(G~C;1E4V-k3~5+V1ob{)X;xJa^J)o z{hvcF3$F{7zZ~qpzL5&SH!PI%vC;LQ()83ND~%DP`dxHA=j(ZD;6BVsyECzlz}9wW z;`p<^&P@D{=C)-f8gM}z^tGm=vHvDJ6OAovu?T&V`B>Xv!E#ZpVjV@EKe76W=^Vnr zBuDm!Bb@iU@=+qh5$ zRZLplMGnClq9g*r&~ud2z?NVvGd4vdn38X>VnBumE9u z4`hP*+ac#seh)4k8Ho{SRLBK3G%w!Rx3)+gXm@2+n3mmFB_+^dE~p5QF^1#L7$>(YgpfT1sCd zg>(EWij3Z}G_$DmWkprAGl=!xsI#S`KB)ZpqpWoisyXU_i7CM9`GGpAY^Sk$bRHp4rhn+Sy;pWl_f1v1t{7Ci! zC@n06UMnm6P7|9rzBK3jsMU;BEs+H)llhd3#f;WchXeRfyVC4^X^srCeZ&P>!t%qc z_xD<_qX0Tn4_Dc{<*C@dD240QV76M-;@{v~xqj=8=|>gV0p5&42qaG~rV=4M(&O<^ z>jwd+d4COmZTO3InY}e0kG4HU(xAfZfZ`b;R{rttOCN{6IHNN2pOUdR``^lsy+p>a+wblvN#cqx>`1ji|LfgWNPM=pJuWc|aBa#|+pR_-a!{}Aq) z8Q!?$2-Xj4UHX}2D0sJ?>HKp@`of-7}t6hyM^YV#7__ncs?hOxvH|O1Pp_ zUKW0VoA@7Dr2{6ldFuFnfKG%b{#{)>U!zbWgsw>;S0>F~6XIfWVmDO(^7snIudGx# zdKri0T_){;Q`HUED8vR6%eiLur5FrhzS;jt^+MCr`W-(XppA0>e!-}_c4#Z6}hm(^xc z<{r{!Ld?pqnSC`YUrWL#CZz60CgfC=Hec6H%8~6y2o}amutvf&cY^#0&ot8F3ChO3 z^(fJghaz$aT1HAn1k&6ZgE5EM9TUz6r1*DCUmmj7O=yO)1DoLB@;%8>pc{IBFO0?i z)f;BdS^pEW*BYG1b_~{KqI*$4<+`QrQ}cuebuT+Df8<_%4<=8bh#fLACYE*SaZ9}& z*p&Q@gi=gIjKb&W=p?lC7#nKvcARy3c81Ttq;2*|0k$3zHCBRuWquZ64!@(r>uubFjvMjAEo|6dEq>WJeatlID!E5$65(yyuEJbf2Hx-t#jG z&+FQIeqiDG?(ID{IgriKklBc6*rtCS&~E=PxA(kz;kgp-w)tL~8u$C#+IwDMo*&F8 zGjsjVwI8icsNOxz^4jg>eE$}jLIZghu4Lrt4UNe@jfv-j@qbj}7WHay!I!;x!)Y-| zjh(8XaUTiy>7EY5J>&wVSNh@Gq^3hir*On<>qp?Rn-b zq}&kOf9SDfZGy6$`2(mxX}-Z1P2>?FA)Bl#@iE2eUx>uPfK17Eliii`Z7k%>?OFL7 zorTW}QoW=cj(;(M8mlNxzNt34FOaScF4!c6Wpo-BJd$g)KkVMq>lnXp4vQDxgkJnqtzx3msN`<2>s73hgJDtp-(9#2R$p(Lj3YYWe2iF>EwOv9|$j z{+0XW4vS67IJ~{&Fd9!E`i%S1%S%qv?|t}_>4N zDmq-QKtjWzdLEQFuhLxEL@)?eTS8{)C`jXaQ2s>*mi&|`K;~#=WFF9z_$o+*VLr=3 zKCD`9-eYLgmgl&*vLUg#De-;--mwF`W(2Y=Wh76+hQxu!p;CER$Vgn9xTK#~#h@uU z3ti&p(J`)T$)F&?fUNTy*h>{EtZcB4Szbrs7PF2p89rPdV-P$>IpB_g**Kc*e+K^y zr&$kr7kff}Z z+*+%v6_M1a0aWUU)NOEDPDkL&oXUTmJ*{4?;3jaxJ=&b4iV7ur!d5BY4*8y8??h6U zoIsoDg*zMKs1GRRcdf{Q)6$c+u#=e@4o9ks$%GS(rD!L-q%&|WG{B`8O~WEiwrzZPmRdN}DnOiXs&k+n6(r5Kax*`)5BubYM)dKp5l)NF zI37dOSDR<}mFmYb^W!w*d9>t2v-fE*OmN5V`ss++Xqn7OTV*oG*1Bh}5pE`xN_baE*sg+k0@(tMB}W#Z=bZ((_;H$U!(c1<)xE09eWP z(LM3Ej}JQu??+ApZp1#xR_ZwurWpfoE~zr}{l%dcX_^nAY2(4V0iWW4qVwjk953l{ za_HQDbSc9`KT;GYZ?7Xo8{=#Dq@B`~Y^2UJiOCq;0NM(KaM7s8i(VcCNAF`1Xo?Vs zo4A{OkUmm)oV->zkDm++TsJBCWe2jWfW-J$TQt`^rD&+lgKozHwXkf z*o1fIg}W-2K}nnl^|K$IRKyX^ok!R}naI%i?AdwJ&rxmpy(Y`=DQxg`;Nnfg@Nw2y zVd~)dAPmBkomsaB)1JpOoK!jE9uwn&W{j>4nQN|@4`7m}utg)VhqT~mG4KY6B>IO} zxb|uja&swIogcaQ%OZAG##u8h`MJ>gxDcJ5z0@2y`Sss^_{Lpr;WLbF2jKnAfJXq0 z2c8Ixfz6K_17eX*af5VLBSG|*UIwuZWeg+#WE=cSfO=O;;%|IJ44}7$c;pbk1yJE_ zhFC9HF4|pW)eb6mRIH!yhf2KEhc!qlzsmHvP(gOqRcyHIgGKwve||6c@H)Q3kpV}K zk(k6o$pvO>u$LyYrzsC^sp}L=wpaJuLV~i7R8BWUUPGG(LW}3_ zrGJBlRn-BcAn;4%h5aqUQqOR}4 z5WJa3-D14GU&n-trl)3fXh^=6L*JT@L*=;jx$>58|0yWA&HnrSmEQi7Zo zVMH(X;9UkupMb9J&Jx3J{$&Y1eMv*Y%=|DZ#4X|Nm>Hzecrs^a08bXc-8u*Oah(G$ zz^7#H=9h`D+Fp23O!j`{(jG9l_J_ zc^xWWZM5@FA4XD4E5c+)Xt~$WvOK4bSLNFq$TEOK^|_UblZTJ)dYn!)>2E}ela;CC zbBQYRag>iKASj}WcSF^2$;ew9A{a0ti7Ax{DZ~1p8IqCoXcQn7wLc{x)(BtCu z>;$0c0_dj|odWa+AI_X&$^m=%Ubg#u88@pVcxDgH4EzT zcl}GAJ=o)tijd0xiouFA3{}c=(c_X6-T|dBIe--ke{Laot<0#^Y~m2ZBKJPtk7PNj zD}$Ui>bMj+Eq)2B$yOjQ=AL$GCV#swbIn4^35_^KxvE^d1(R3%3o8IFb#^BwISPj;^S z7Hdj&TOCOR5lOH(A8)vp%Rm_Ej~^z+*wQ0Pw@O-Q#~QOl@4D8QDH%!i1^%n8{=wK| zNLaTOd(8VY3n-TF)*57v5{iZEWSqFms1>qAFd49|P_&mzRt%rWWF4HjltIJjM&K$3 zW%q2$D+(u?$LS?d1|>s%k@PV>lBf%>7~2n^m=7sU=3qrF%tTOfRKg_TP(aU>JIa!} z5W{*fc^sxxnU^Gv8B3~xz*%?#PnD3XK08VIaf|6mQM$!2V@5^8cLKU#uUbK5uobaX z9Kjuo+xo|!dfFPz(H(Y}ns|nE- zNIy)~C;wBsGnSmmbfoLcB$Xl$ydq4w=1#m9DooSV!N5yaynm5A5yx^Kdv}R;O17W* z@vkLtn`POZ%#Wv*^yh~fB~6(2`RbB^e&2Jo@S`R%s?!Uiy7lE&@`d@x*MXA!%bkNcFmn z(iZr~6I{Hbnpx`7Z=_2pIG`x+R%&QllQqe^Ac!Q00l>6=p;Ti)H>MG@_70g$3iQI) zI0t=v)2UALT<`_!kkfK2{dnj5baFG7fPi8iB2J3oNMc%LP6%WPXohOlkT5oiCOeqZ zcB)uT{fcniir8^JVj3c`ae*%7XR&U}W|2U%lWgz;Imco1D(2fZoaTh_Z8pvO-g*YV zTm38I;&qKAyFDFAkT)(BW|~8lWDOa%Aa}T-p7^B4_JLoK zOmEdWvYLTS=(^&qUBrWhlR*+yMI^4RIDLHY+w53|C2S5b-Yt7Tet{={ zWfs`B=(JqNw|V_G-EN#iTOcdvLdCp2?KRk|LuW{EaX0!4KFD~>(p7Uc(&fB%9;GwF zb<3UROThv040fZtTjq49WhnQzK0Z27C2|K<@Zv8uz9%yHX?Sv-1u6 zhV>66==e$#&!qTJ%YKlBMC`|SkVFc=@lpVWodzl&>=;@RGzV}99wnSOt~NiCNmVKy z3QZyirQ7KEm0fiD-ojcW!$pU0z0Hg@>r_yzn7`i6{nK=jHy={2_~yftm6!{%4zhPh zM8f8El~U~~|D2Ww@we7QxRgA?=HRejEi&d#1;(x(LH7h`UV}O+bGlj9Ldz!i7K)rA zre#_Q(-KL{^Uqn5wX`gY$FJb(T*|L_Q#L7kf&cv5&iUH=LOWmTvV-aRlbNn(+Dunw zJ??INix(Qb9}Z z$)if&D`K={7GO3d(oI+uuiFA&mTUqgJYT>GoV2ChfQ|6627#ME*W^j1wxO9YKAJ8t z7@BUq0pX4zC~H*N!Rx;*|Ekn-)--%|sd=%gqSrJRA5MaCHND#=?e>widB&fNh4C4U z%5!qF`t8hHa+gR|T)>KY^!TG{d)+QQp3jSx9{&q>QA3a4WI9>z%tc^)VOk~gp`Fj1 zq-Ia$8{$)1N+_80cX<0jElg3FYq#FRi2@ADd-EI1fE7f$qX`jBA_dT9{>YKj`U#3^(vXkZk9 z>OR@VL^v1YZ#!rpZReUHc`*bSrn1^u)Dr)zH~b~dXav&3_R;;;)>M~aIDy=4l_#OX( zZDOB@Z&9rWC85$L-1*-{iwaN7qV|a-F0_lfi>sf}5Nn&LP@=uvc5U;%t?jNYi3O8? zk4VY=w_y4_Gdifx68&U~CDP0g5@$QW1s zi7{0Ty>Ti_a$FI3p?RY+IUT%fp|ZU?BCQnLedtIb%j_%8^jx*dhN50*&Oj-*0_ zW??1-p?1jD>#!Wp6Yxb=K>@BSnrDwBo6VeY3H<2og2oBVv=K&%cn@oibw8R@q?0I_ ze{a7d#sAKV=8Za+0n(|9qGI$+)}8D}43-&;>s73qt9#9_pqsq}! zS%C>DJ~<5u(v{?Id{w8ms|uB`#J#-d8DBw#^ae=?p~MCHgsAC{FJ`d3Mt%m{0taOJ zXKbnLwIqUIh)w;l29J_SC>F2=jsD;d0KfbTs{%QB7@YtS3q6 zv-<{(VvG4$zhoZkmVQG@9BIrRPk%@HAM1_UmN*plqrp$NUa98{x6(wDgQ5@DEH&70 zy{SYVVuvl}w{}~AUNp(`J{5AUFc$OzBYYv_Y@Npn&`XYSX{`e57G~IEO)cgV;+a<6JHvdU!F?DSh&*{!R5N2>7T#W9X z?Q_-XcDRN4-tP0j*LTTqJ30?sA7s1g`J}bJ^T4e}Uu$yt;GHT$MDh9bI@BIkXIoho zJr%W?62$K*4mH(l%+I@&Es>CH>7G=53+^s2%MQ_L=jYG74dYn_pkm7Z*=@DiI@SQ7 zeV;^o`E=_$Rd{1-N5;q>SE=g}+NJzux9+09SCqwerYu@-cl_~Omn%uR#ED)RpUW_B zOir#!PV3vciEX(){RR*~4&9+oxeJFZIVh#7?_gI#^T=u#B$>^kE56KSPJsQ$L;GE4 z(Hb@I3r#^{h1!(NSh+MDYwww&?l1FCZK8^WYuZzZ(h97_G;`n1DuvGwAGCrXQBF$sk900K_o$c zsT1gjVuRLJs%%_N%Ld+WGTN32t1EfRTc==bI$5KUT}S{lkzEy1V4ijLp5ddYVwJ?H ztnO#5MDfSrz+@)cxa4vg6`i@8OfaFXh0V>K=7ku@xgXb^?44!@esyw}vdp~#B{g&q z)iUBE%J7(@WzA~#JKWvFy^9uoqcs=w(n}E4jZ5Szm`)JV%@4!>%g3`2hLv~m*9Y%| zDNA1@`&VLP7W32gx-pi9=?&8{>GywEA8`%JNQFv3$Q`HUVxcj2!~G$u(heQ9|xacDTHVv1udMoR4#JHjg4jgde+ zUsH0xYfXtuszRj04HNKg7^zfs-&--up7(2|L&C(#AX`3);m=(?j{DkiR~U`6*+39k zbs9__D*h4G_M527m7welHX9~T)9nCt+mx(%lNu_eeLe7F`r3qhx%yhmAl<&+;J*5D zY+vdm$M}5qjmXO!?XZLiO6I02x~t$uyd*s~XgseBE5YNm%h+Dycqfi9bxaol3lGPm z-Y5M3L<^@HwpSCrEW9?#|0ZCL=*GO)~vtGF$? zy5+W^@l5DM=718f^fI5Xc!rO)IvG#@6G=$6v};!Wtgy?=nKhCn(>2=@hLO0B*bq0f zRxVeLT3lRES$PykY5tT)|B(&rs!MsaReu@HgPDoOHw`jy2{54>*g_g!c0eexGBe*` z+-ht|17d^ogUl^8dCAm(3JvXQ0Pu|^*+U;hS7CCBZ-gAk!6N@LDV_v{HTN7~XK^_b z41ka=fzp^bGINRov!p+%jZFd0H|-0lqr3Rd9}6}U)jxWyv2I!7^oX4^DlX7uZfW)< zS@f0E1hg=lJ`K4LjsRn38u#^ljqiE(WQN~Ac65$HoISl})ERrjvvY#qDEQohpt5w9 z->mb)W_L{Qe+)j~Kj8&6Jp9dyx1xf((5e7BckdtXQ9ZNZOCos87pv zR^V-JI6%uI%jWM!9PPh#i$7)@#GFm@VpF#M9!GEX6gJ?0u>TsVi)%Ez<~qP=ip(M9 zQ_RRtu_KG_uaEb3Nw>=nKPM0^KfH^%#BbXq3M|CyaQdF)rfv;F6NZ_B*VmbsiO+!v zzE{g5($|2@NUYAB0q`3r#vl~cb5%r3d-ZcP(9|_bfEV9T zHFIZG4(T=bR60rS)tc$2udy1}Mo5h&rX8VkirHMq`RJEiIsaLS_`~$ycnQw+`ecwK z`^R_}$(~H_o@9R+oZNIP*#{F}CBDq|3ATQ?Q>vSrFHYk8e%YX#Fi!c-qG&Bg&L3Sj za!c$5njx2ERl}A_{*P?w=k%x0vGs08h##gA&anev%S@Bx&L}*|{U_s6-ALjs$sJAB ztFfabdDjvcTYd2D0#_nQ>b5i^M$E6OzwTaLKDi(x5VAzsR>xQ9Xnr|J1n}g`SgrP5 z2yQAlAFW8FNUi5U#p4VofFK%NY*Gb0$h_y$zcV81(6w90#vpEL7{57O%&xXxF{A}p zp{cAIZPXWoI@<*6-E;v<)4zxt`3enbhZ4xOv>djosLP1o`X9_Hl1I1Wkvtk@U-)Nu z&4=M~((=C}b+`0SCS2JoLe@qBRVr{`OqaZl0?Lz*5>I9(m_1RbjcgQA%n-`8(({+Fyn0O_)ShOr?r)&(5NLT%<&F+*{s5xrR#a9HjMW1XuQfypv8-?<1^irx& zMv#>E%9`0s(7?5~nF)ILI3{S^O>OlV#(#)-cKnCJNDpv5GU)sKWBL$uDrK_IFJ_HD zko%9uMxR|}2I!d>tZueg#ve}55cs)uIp0iP`dr986L!g0?u3~@@Pfb{ZeR1h)!>{P z+M6gFoMYlSfB#c6PY)f-JbjIL&XTYktH<>7v;F`BH}*e4Fl+~rXCD7b5?VOp3Osb! z!WPdSJlVywA{2XB~x_9{g4 zTyVFIJtP}pSxxxNSc3D7WyWpKQ#E4@`JEJJ*{4j`{dSg`P8UIpNmB)b~)bSG{2}tw_a`-0Dextp4&lS zTh4_2plE4|3MB>g^hc&jB=rwq%;BRR9t%Xf2qF_lxtSeiI?)`clcNeVS58nb zGDt@0^78w&Eq&Tf{>xby)3M_5V8lnGqh3Y*q64El@<0A6n(xAl1#y2Im+Z-`5t~2; zc_ux+c|de(eDglBsgDd{xY^UTUppmlq+hNy3u}{Xyyp(epJd~ap|o!2=>>KsxcMlR zFU)j3sn?mo540dF=XAOtD2MV3GLLH%dVAnl&Vn2=27Y9`Z+^E|(bfi(-P-}hK;dOu zs&_4VXl^sl5GYxgY!5xdsjG3hpW{c*Wv12Yhbg1sL(kP#FD1;8OP^+A$?Q&N<2v8O z8+Y^M(4IG%+1R_0*%)qvj-z@x! z%$xe_X~RvtB5E}S4_qc)0&%8~$S+2l^zRl`u=ovs-kL1E?fUy!oy>>oQ0B9abi2XK zLv_Q~<5EkIp)Hr%Mw?oc;l(DJkVd~9s6&alm5&?=oS8Jc0o~lG{P_a}r1YP6-}~!5 z@6Yk$UH^aacO_%B`lEn3;r#le+SqxW>y9qPT?RB+{INlk==sH`Q~wwh8Mb~ht;inE z_jCAOdL8+>7i;LPi&Xmk|4JG#X3qiUQtVbh84cUW^X_47Y+g1hc*$y+&^SdR5edf*&xt3_`U4T))|dp4&o#XqlucsunS@jjOO%Er+ERW zWVENJIxROFim)~NFx|1=27W9$-0OS))e69ey!=&c zl#Z16YwLXX97&OwaD9kB;2k1&`#7TeI% zlB$D$D<`vHl{|7+!A`Uz^Y0d_dwSMs8RA9?`L>jDNAb=i-ZAmcN`xYLX)MCN{0U6~ zw=iWhlpwIG;*p~uFQlbYzj=p3wd*Vl(X6V&h3k&PpWV1JtO$O-yj-C-}F%Rl^S7u(Z@ z42WSk-zr8kv9;bdCBq-oG>aM#C4l_($ctM2IicE2TXygKU95Pn7vC~Xv854}Tq2q6 zm-QsG;v_fuk6+ctI;OL&d48ire=rSK2?~^}ZdSr5{8AN9f1p9g%_Dihc?)%Il$$HF z{rtWxBPnYKn62ZybhLx*{0=VnpNM&oiPJoIwh7Y5s)vwAJ2xIaa7{w1gWI9~7x@ z0wGs`s+g5QrBe5#)4a~mul%fGFoJ$5PNihvC4FXo48-{{Zv9;uQw^Q|_0!h33Jk+c zYFwzXTfJv18q9B_o#Vz{g=3@#cW<%g?+ATL9Q&q)l!|etp zAzV>fCQlipcmqS*p7CREy|7oKX;v~t>C$!VC8>RrcL@g@zZ+gLrXQn)&82ExVkWf7 zP5d;eN(tx^h1%jyVjbJrPr zEj~&s^YQxvu7I1qSe$0Pmg@ETe_V<^3AAWRd?5{Xk-o9`bSrg_wx^qMVwJ8b*w%;k zdZw?GU^6Y&KicHaDP3>n@4z-JhiK(!Yoh@CV3A{@G_QE~4i)pNy0`(_Jr! zUkg|hGwUoWPu*k;ZJVlR&r}8$99${}OUL7-YzdL*F&tlB8A|&6gx_PH!i&HFNDo8ThdM%NW{e%pX({ebU1sRBAXq z=LO(T^%`utgb6&rcDbal*_un!!!9tCCxeBoKqTAt(wDK52!~SFz7XJC%;9YUtmFB4D28 z25-Daqec+P$gJ1agd~#d@{}E>!1KApIt%YtGe*S&Epk)fF@ugve?*I(ueY-qFl$ec(lSZ!z9poo z_=-Y}9ib(eO(%g417A`x$D&9yy8-gzo-_cTgyN4gcAUl$hDPEKuwYYw8IFC=6RPTE z9`Wf7*)mwIkGH-EJTYNQy_OkaEj!rELb^AHu0a|(^C85EQnsILjn@76gy{`C0EoL) ze8QfIe$T_c&5Yw|(JRpKXciP}jufgNobMTQ^6@9d1|26MuH4e#)>&s} zFXI65#k-Wo?<;R)Z**do#LsJw#CJd3Bk?lkc3|Tn-*l;s#~kZ$>)=}y@48dEITH?p?|D@D1{ezycMJ0GkTucxe(X&6o=uG z;mklr@`+0?{-&G8Lr4BUH@yTk_y7AHH^1q>+ZlrLd3p8;xwM1|<_Xu!H$6{8Ej9E& zz%jlGJM$ZzwQ!_cYs6KY>4WQ9+RHV%^ump4<(>zFEyauA#PHD zrK(!_{y7E8n|A>(X8-yfWUyTaKBOwTy>98A7>|%r{GR6Ka&D^Z8|&oRq=%%LoIBrk8bJzQl!aTOAmK>XVHuXL=4 zaQ#=>Dk1>9@2gB%a^T-drj*^eZBSidgP5gIMgf*0V3%U|Z2$ati`Hakt;yxxbT+Ju zHD(5Av$eMpCI~OxD&OSr}kxb3Q(g+#p8e3e_QExbb=6#1`hnDjY<8eL*%I zI)nJeSF)d`iR7Vg&8LF2aywQs={&R?BWn1Y+PmguaY`>a&5wcQ3gRuS3wb}Fd8`%s z$piHfoK>$+U*diDoyt(%Kb)2W&1(8wCnFnOA7a~pA)2Qz@e$4O{0QQy))Cp1D%npq z|9YlJHuJIV#To%8@oPclMsCR$5Ifl?WMzV3?Rp59d=4#&CXFu@pEB=llO%f*Ipqn z#??XJWwutB_|~vLzIBz2T`m^RODUR!a~D*NpdH~n*3NFKH_NeR)=8N#Pj6})-)e+| zLV4+;`K_vm^tZdm^kyU2ZG+Cj&+@wmA;HG?W3@0DoQ>qzW|47nHT*zvd`V$z7_H-i z$5kvkzUd%mp{#hwv_Iq|%*(Wnm+!63+ajYew$I zH8^{u5>8bOJr0TQ+ph<4yUsC$E5E54tJ3~2U{zAIJ;hmgUj5QJI{Mb9KX{%r7<0L| z9iU$%&@X$SQ_%NUS1#y1xCZp2FEgM|I0(>9KK0W5xZU+H{;0iG0`GRf@_oT__uo5( zWum%qVNrx5u*{xrV7cx`Y$hP!lyWx3_0eu5_h|w%dzd*evII69o<+bX@8kTVr z9r}k$4J;3%ECH50|MrdH@#rPBNuZZU6aTt(6SEw@u`ka-MvyyLXa8ny!#i7RLnUgr z_Po7k4usCL50;$Ab95e0ag}NLi05P_iDxzjQ#Y;?>A{C(p^7K42lsdQGqvXrLgj06 zZ+nUXn8Zd7BHu}?y!=J6(C2E6*WcIa8sBD;oLSN{Ujeeoq025d>-^8}d~5qpk+*H} z)n=mZ43^a1$<@@VR#>mo@?V&9V-Yq^@=)e6SX5OrT@n#$^_#(Srr@dQ z9G*X+3-H$G7U>0&LtmU`;7RZEt-^D-I{NzSGez(W{Zpsw^Lj-Ap5=RQaSTW@%sKlUe_w4zt!h?_OH-YCg z!SmVgI)&#KKG~z$${s5ad4T7oJ-$_V;H28X!wG)hiacXetv5JoY8iSaWPjiZItU=- zFrT~?IS^bLEr&dKjYkb;6=kHwF@=l=*(i zWK)`?PuhwQRODIvdxBX(j)(ez9A6{;Yr8yaZTMi~OFT)Wu9||nsw9n)Np$m;7NbAF zW_Jal&U(T{sMt!~hh;8HzrNhq-;}Fie=f6s<_S#XEHhbqAI29_`n3!}?#TX#XH40W z-{g(OW}Sa;ewQ$qVBr^9lZ13>#aw2Ij}!?K!|~RDl4VV1kPk1HUU}&0XLTtn@}Ali z{A@~233y+732%kIqhh2KDamYW;W*<7z$5FplUWM{cKn;}*4AIY2jZ$Eajs^TIb#|-Cs40aSl z>E&K8ilMY=8hxC<$%sG_f=*V%BMwf>TxN|}bYz%~#KvI5avfLlY5x&+{Kc~(1R0Od zR@-ffyRt!;#9hV)?IRjkv;z?g>-AcPX=WYPr|-kJmED#(K)s~)zW;GH>R!4=cH2Qh z0YXe_@7uX;P;v_benze|uJE^>OC;j&oXB&&n9$1O*SUvI@BMYT-2I3}&L{TYUG87+ zcYA+N`Cs9E@A={6Jom2kw<}SV{@=QOo_lwa=iGmPCV4WCCVi*>Ug`BN*f`(iUy(kb zxPBj|r2)osGGDaGtd7wBG#&Dz^$6xhoR)q-e*9RPBZ%JZLn77%Uz$? z)>?htspfDY!KLfsH_vGvWh4RX;zyrscuGl8)hV%Y)NT-g*q)@{9FQKp*ti^Ieg+>` zkl)gK;^|_Og0?P|(;`WlKM{lMc@-Y>e+GL($-E08@+$|Hi80!`7gb^-X8Vry1vD5Iy9h%c8vir$@d81jKzulo_ zcmmWJj)f;&_k`1Ykzu&~(>~m*Vb-DJn%mlc9@D;6Yac$U{rW_#Z)Pv8yZU1tW-)-0 zb$It^uX5{NU_g*DK2a zo2e$AsBqVk0(rz}j}@~Et0Rg1!<52wy>~g*n-b@)NbZ}@kld$0|Cy&iAx$#E#Xs7Z8cpa%TXsxw zE(U!&@C3fB9b+TvWa|lha;Cv3;W=m8$&XArvJUejzuMEA;Zk?t|A)Af0h_AEcJa zdBUM5fY8e%S`PAqi z(oQJ%Egc~3?Mfh%O>nlM$pY(yUB2V{NhbSkgq(z&`J8w=GjwsN<8AWeJQ_-k8=URT zP8bqCYDazY_=lro{?_zzD84J}v|dO}(T-OJoiXP4b!! zF&{+*ci(+Llen#i=0(}AKO$}Y%krC|`Lh1fq_8K~I3qtD56&tv>rtV27xAz_UTV;c zFptJLZI>BoBm|g7jk%`MY10N`Eb-)-spC&4s4_O@>y=GMPD~B^ACU>%TyS&z3~6S} zPC284`qYh%l)oP%%WN$1IgaFNIz-n0&_bMKvo}UNUK{xPtP*JKoK#*Ge-)<^O?>iN zW~?hRW`1SU5jG-XkgfVD$ugva-$)rfppi6U)j- z?-Re1t1_W=Y#lT)HEuv8-dQrtv&RJ`Ve-M#W@5~iF$ZEr>geN z&z^~{ZSvCm8!UZeDbjSV`Ek~y%7H(+jK>w<6ncq zV~#(f`5EeDII$z_vIM1%FeuH4bZ$U$V!^NmsE2cMS)lL>Gefg|@H*?Xev=NxQWZx; z!SD=0fWdL)&67gea(qG}PW|JdWV8}4G$@=net%V?2s22x&Z`hqM`g=<@xsTQqOQol(k6#8&PIiyvBx%#_f0+wn=ER@TbGf1ezjzI z?x>nmPcTPc2i9iLM1_h$KY5IA8Or%eLJEuGb8b;ln`TP+ zcyDclZB(7~)4d=Kh54aN`MYrN$&f=p4qsUBhI$Tx`p$2J?EN4)xh$7%-K_y;@K z;psQ%tN>;P``i)@7ALOpOh-|OQY3Lo#5;Q}lF;h9&UaxniQr2^lqBMmoVvzZk8n%$lkp6e)BzHOeYwGZuevJqrfqb z{JEp0ry*@%@_}xERtw;%QdC=mi|81UpR*end+M`~+{fW#MgEkw6XIMZ;8Bt^}>h^LjCPlhWl7p2em9ZAI~h7c+xJ@rI;MQ@lW~ej90XKLD^|CXQ|Q%GEaW zw7-7(f=8?*@El>WI{pEEo)0k^Xt>?(ZtTsDYESH0z1SF;`Wx*62I!5pF^$DZ_Kr_t zyy$R!j(6b)UjP~e?mpIhXg|ZquZ&(@!>?nNoM4YR8(ZFd6|?N#CF_SU)V&`o` z#-`SEWx>is4_?@z2rMuMJNH8eMoZP*>BWwX!n=N z0c=*+I0_NClff&0&^CCMK0sa{)O4@bt_>v+rWb{b4IUzl?KH!A!!}vp$~iW_Veah# zX0P0)YOOV^4>!cQ!aA#-ekCng)YHe`iY4Cc)v7i8_9$!Gvus5ZZ^jbu>3gZ&i39!f zJ3`1CXsTYD*0A*+-7>|-;Pmw~qn-a5!VeHuG=~{l|{MG++e72gnInd$vX6FLf8!2J!KlmOh-v^P`Cf`Q^J|ON@n)1D^Vg(WwEMj|ViSZ!j zJUPs38`bA8(~5iL@|=|M+uz9O>}H1g7^6KR1G3$m7L~`}BK=yqE^{e}tuQ;}+rDVx z9<`B%Q-@!;Tv8U148}%clc=&ZGGPfIhmYfJ=FoioblY_|@S(n_Hb|SxDH82Hi>Mc2 zC$m(~s2+)ArF(<{-zs%>=91p*QMvf^UJvY=xU(DutfJ?ET|S}7)`QtGEkS=HB;Ot|QnUwB zDwoHAJB|-JWz=C}oVI=0K*=0bShtZ3(%10Z^N_Fwl_4%C0gviMkndjEteM`~DulOr zQ@n%IN^KVpQqC&s&Miy1N7sG%Jr1ui`LT=REv&tQ{2Bc!=w3TU^`B(nmX9YD|7r?g zH*NnVC}0yB_w;DN?s{TVxlqPk@C)JUN#CV-24h)1!qkI$$r_C$4vBP*H(N6jYa)q@ zSfja-_gJGcmL<7yb<(3gaz{_Y(`?p>sI&q1NCY9a!h*3oji}`ZW;Q z-_Pxt&-vP40uHT^BANd{=54Vka=-bUtw}DNcqW{9+@yLVS#djGLJB_r3quN=)}dOd zc~zNo&I3YY+@_&zS!dB^%7(~K*rwd9vE=>1wOk8xICF?DLW7A#;INyjvpE@EC*qjB z2a}{gn)GX*&YRP6(p>RcmMO)q<@wja3r;=N*p4Q>%Vg*P!Gd^`zeP8^87==CzV*sU z*8loeYI24A7s_*3CbWYC(PTb!-WnZAE4NhP8Vq=sAPVZ9W{2muhEF)-m`_g;Cc3FpJ(NS zeRq_$mF66&r+W*0ab;FG0AyC5*4Lbmbe3@Z0~f% zgLmP926aXoG5gPjh62*gAa*hbxkK4?xF<5xhJxIE2%o9ptv{Ar`K;5bgGP!?2OMzP zLrm}AZtyD{KT5^)I!}_Ep8h6pbNbN7vmaCqx)X#p+FA+Qac((M-X=clS#DU*TD&jH znrlQtlp@9b+#SLhZDnQl$BvJwc=#8N1w+tLFTI^t*2q$HRM*7h9&t@ZaG;cQp4}2!m|lgY$)FlQmmpq+NBO> zgtSdqUQfdEIz`LjEVQPwtPC|Gjru@V?)c-Ji#Ln=?JLisA4;hFzlY~3sbStGh`zvT z;v^0=Be1&Ag^CQUI_by^ys{BJF8$Gd46jG3hO@2dOMA{2qtO(Fn&(VkUURnMUD{7D zG*qT|ZC7VF2DmPOS214AMCOx<-JJftA(}YAxuD%)rxY;qNfizj7!WqtJ+&&vMTgF2 z%Xa}EuStKI4l+Z);w9q^shyR&YjW@QrT#5HAo0WHw;@sr-7;lW(j}?(& z*u6RLv26-9`z)xg#2#O&YRPq+O}dNKnI7)rsX?oLti@)D_04$x`oy~AXr8-yMfWQF z?k$s1J})hU&ulCmZyuIxEES&(sc;NoKCs4#TPH#)XVR(xI@wWXG0sjv6E3dBv&KoJxD^^6Pzx3Y09VC#jH4-oQ+dT;!EI`l~0^o z>I^ELwC*+Vf}HBlMmM|_Eq_+2%MiQ^7&ECXSxu#u|D^mW^9%w!dqbG+3nafaO!=8U zQN1YkR=%Y;?gltJAr0g>c{9}j&4`$jJ%Q>sys@*e4L#v3%~=IdwO&#_K%-`rbh}4| z%_>Q6H0a+iY>&b6)DyO;K{tphdpL9k-r+tDS=26)9cS_yJbL*19-2?5RhdkR4CkQI zm&{Nj0JJYBe2{`=6SsId+plkksjqn1uyb_`)Y)nKky!(~uk-|4>A_y5ZCCJJ`uF_P z=QLS*{=Ht|W43I*)&x;|h4=kc0s6Mn(cVCO=#TOs{wI$9{eZZP7yv;0rSEwl?goE* z1M&ODj<|bh1c(u!zPMz-VrwAc*(eau-F^dNun7=l92CgPaS%*8-4#CjIK7@^X&8oCA!7<#!E`PrjviJ=<n-_cl&L(;vsnbCB9hmAVpZvP30Buk}qmWU*#7p-zA6#lEVU8dBa7r&o}`!C)s zz^GEVKgLVGJ)Cb17nc6q1MYhpWGZ2E%CikCvnN>#vavj5KN`MUL1eON$U;^QML>4y z79bn`&jpeBXXN0-&LyH7JC_(COp==yH558Kk|xt^Jb1Xf#(OMjBTeEiU~oasYuuP5 z(s!vyYWR-{vZjJGStk&Lh4l3v^<;JUI+?}26m+rV93%Sj zL798_bQ#hgW25T(q~Y<)R7S`AgFH^j2EIJII^9l5=EnN_M)CKZyxmg)=AZ)9lY-*R zYSHE9Pa|}JhZ4Hh=(HgEiawEX1hFsE@!?*NB1k}=mwL)-crcYj=raN z+R{sDO;}Jzy(XPDxjOKxl*dL`l?voTYko(%))=CG={3LPdT?Csm-d1exQFI`vyoT*S#1KxR=nWp@g)7Kemn{cvzHm=`AtaX$Tg^T%X zn5Lp^5L|GB*&ECpnuGj%i5%ol;nsHnygz7M^cFt0oG**EE-yw_Xoctbe?Rr^uYu?L z&kC=9Kr&jSctB$R3ZMJ;pF@lB?+dSU`*^N07j@BTonMzcAd=kMJ?GQqWwq;wWnR*e zSc_%9M)}J8^JbE@jMbe)5mZl-#hej&u;K0Z9{I{~H-9z4QMYr?i?005tF^O^di}N< zS$J~xa_qQ~9V4O~=vclwmRKLzaT&P%_lDZlk@C)1?LXxVzGF)?u|8Vf97!cZorT~>!}dmiuMDv zmzDey5SbPT%kle9J|-CezZywwh?I9k;@gjnJnAE_!PnQKi49TSIDZ;n9og|}G_f%% zynCXdmeV)D;n(b!vDytL^k0WrM3U30u&0za58`l-%q8^+4*GcQBkoJ=ofBtP{J~VI z2BNj=Vp<Wy z#=9!!ewuTxg9Xce{ro^$oAPD?a`ea&f%VSKck!w|u_`ojqx!aELj%(h-#WM{P+Y#A z^*$`-5rk;=iRQPUFoWk3{@O|fRN*`@WEcy&gTq}O2oDoMSUZ}Bv0)+z-cwNo@2Mz) z_f#aodn%IPJrzw@JKEBO_03C#9A?}GF`0(;X!-hRtv}P{>tnUhidQMqQ2SA|mMPhm z!>3s7_W0_z;vejEZbA-*$8J-E2SkDxj)^-iUB!tMz2i;#RTCEvW|lTszCKKQrG7XC z^uEXXGr8tC>wdHmX2}qeoCWQPcLBRdrvV|qw&j0y#w8`_zX$=3l4V(2=T^E0(x+JR zAyZOEO~jIaFm)s^u8dzdth{-j_;odS3uz-&`fw0-6~Rm~4rNK$|1IiqZhM=5Nw~r5 zL`Qtfu6TF(O5Ss(`uetY^26osd9p*Ct^`x3c>bqPne)1zA`@!a5t)`59sFSGvWGwCfOpYHG-~17H+I&PLd0ik9hn2V9i^QHh>o9m% z+dsKY51i6Mgl9iZhT z#w|8^SwBU^xItXojMz_HK(eknzQDk2fnfF_Z9jTGHD=CT98EkE-SBp_{23zFcBv5> ztCO=%cKArskPb3d3@s6n>=OzvVBb!7AE?vtMUxo3Wbg)uYOtVCWk&Oy?E8)Pwc2tC;0iUou2Ta+OpcvyVP zN5~CM+YPk#&=CF+%5354+_sE=*{2A`yZ3QgpXNurd$<)fLWx!NiS?oQ=7D5*kxPp@ z>cmHbfl#LA{W90cKaCScvTK`2aIyFN_no_*nfq2~Wf@=zId?rV@0IMT%$8z$;|)`X zISEDSR%P?P*>Ldq%)tg9A7ZD0cIb=zad=UaSe^cFZW(gz#)q)#<1f+CRPzwK6J=vo zH61Br2avTdKuVn@tK+L3HJGD^4av(nBjv*^hnFVL1{0e{XD;^o@QbaxvU(l=(_)5H z*7TCfHE)V`o*Ce0S*Y_&ZFQGDsDE%MkIn38D1R)PeTo>}*xv1t4mZ%W5BIejqdT@` z28VUGV|#SuUvs!KrlHcgDG8~O6MFi0+=Sv=KdjxzP%^_je-yzlzUo7#^}nEC0^(r+ zao*lM&KzLkX&&;R`Q*F-*;OiVs0vi7z)->eW4~XlSz46;&WYm*n9Z(AH}Nl^5mmW) z3rZNv*aMBzda^VLt?9Pob=NsQ08q+0$LAqbn*~6z@=kzOKSG=e??Rq3=Y4{zaiIQKG^#d~BXyNMtPC-M??W|bKd5?TB{3}E_ zV1r(Z=>4s=RU)gJGcD1!SG6m+8+z{P05L`2=wNnt2eh2Pl(V#MYTM1qIhz`F{?wUV zG0j8Zy0c9OB6S^B&swO9e^h?M73ts5s&<)yV0g12cvc|fW7l8xMf1}opbM=~PixmT z%v>8QUl+-)gAK;^UTcwyd%>! z?gaVRFd}BT_bVF#S^eQ=Y09bW?*7(OX37Od10-Zv95H1x=937ihNq1)kM=W<_Fn<%Ez68F zSd}^2v|PdLm$%2;2W1YZZO`mq^sIuVQB$OE<<`O))L1P}4`xmKhLdL+T>oO`qDbO7 z+}qt5FA98T2jUM|@V!VMvdw=d#4$iG$~^k{u~A%{vHe4VZYcg5gCia3fm(#+H-<7N zdM%HDSf(OfKw(~Gr;;0$WsZbtG!Kic5R3s9^k6RwpM5*`5|cF`F^W}>@h*I0DFw{( ze>!yrEf1RKL~h4@zh0dgge@YhzUYwdv8lS{-^@+7^Q)VZy zxOu6_LnpPV1BMVBI>Mu>JKZYXdS#LeP*l3z7l)N2&S5KniJOl^y!@NM0M%xqr>!OF zbK?YX_A-eUUP>vWDi`xt$*10F@ihdy#}aF_v6y(Kfj$O+TB4Jck7yR5YFspOl7YB7 zzL%D+?OUImVCH&EW`+s*e#dQk0i!1GL;hO%hnehW2`34tzaek2eC*kdXY&NDGdVf_ ze@W2dwe2g_4GX%YzLui$&kp| zTlLOe@63Ibf8U)~0YQ5y?A-O};<;KB@gA$V}&=*-m#`vYg z*=9QO^_S=ik+7J|-y+Fth zJZMNfeP$|nI=W75%w;x#ff3swW3bH24iqDtfP^ZuEeQ-7$_X3046$`YecQ`@Brq7W ze>s%um5=1E!bjJ@ld1e_G8lM1ptkOPRJSQ&8lYc^tEu>e-DNPCcfQSDP?67GkQth@ zH<8YuihKpNe!hZ(Edn)QjO&n2mpm93U}8ww@rnCc?kn19ev=l$T zM73hR0&VRN0WK7tO@4|2hKB3Ytg70q$)*uXycA0OBNHrMKZN0iI^I&kfo1in;9jBZ zW1*}P4t$8d@N0}WzmAYe<9QNkG}T2qUa1I;nf}?b=09^{-)B)f$dp~wRnv~wo2KQF zRK;h-reo!9ELoO0kvsw?mN%bd@(5(fBhYE`2zZALC#DZCQ(bi&eK)+4?I=HWKsY!$ zmM8<|B1QIAU*9Ogw}o%iASOE_?+;dSjgib@4ls!&NZtu@m+bqg8bS9YPRW;I!U+viSm)4sKE%PDOU%`BXlC5GK3kwTGx?E(lQcAOK++(DazatQ>j4odzJg-RutElPm)q{VAC=2 zhYc*sSW5EYeO-gQqQwlZZRv?p^8@ zn8DtT5t{%{=Edg&MQi|o!Uk>)D!&tam!u<5HunIQ2fk?4Mc+`u*cAfyo0t~IPL+Nc z?So7hM8}c1h4nETWC&2&sfq=sJ0oumR;hC4qY(-;+Zn2-Ln$uTjz-`%l^%JO(h+Jm z(4z7X=*l4axf-|_H?z6n=su@WnzMvA&K5TX#kZe1gKI@`R(*xS@deXwxFw|Iz4(JDB z%zxdc?lM-vf=nr-w{b@L{qg!ozgkRx%u63*1QVVD3p;iL6QckKEX4J?*CR3t6lzNt zXF5{lcdYkD&=#>J)CHW8MU8#jaXLfq53X0|SfQJ_vOrz+0&r=rouRG4H~7uOXbeou zhy02F7ky;RswVhXh6J#Hyf5r`wIWAJm}2c|da~q+qO`H(h;XuHDV+=<111*Py9ts&HEVO|gC~hLJn2cI2O*+J6n&U9ERdCzx*&?i zQt-hToq1z3awxRI%si{4oyr+$y@I~d?g`7;8Deysc&bv1%-gN*`vP&NMN=Lbl(ndO zYj7#QIW)@|dUn7WDiUprMG}K`s~QN!KoAf)bbrd^8}DIDYR{~6s?M&?lURX57=Y3< zRa{4PJ5>`#J5`e+B0{E3tu>zGFKpM7C?CJs#r)2>-9)6*&?@&tj0GCODA9GX5m8$K zOna<5rZEAypVGg^Lb|WQT7|~(t~a`WLcW2&{6m22j)2(01$Q+TR->!Y?QL|2ZZo(^ z4DMF5yhOSLbkptyHKLm{oT>{bb1`M6i^rIQG`vBV47PNnzd9#3(uuYsXv1OoNkk+tiVXenbkYFz&p(hFZJ#(hj_h%`Q=n)$ zstr8|aK)tdzNgz51~ncY*b5alpe_M%Eb##h!7N&0kLK(F2lPy)|5Rexs-|FF7)S1@ zY7N%s@ux5>(UL-wgjZxz({X)h+q{$LDyrdT0YT!^W>Z`$uwpBtL39*hkD zC05VuJfT)Mhtg}&9BRI5#42B_7?!`-uJB2z7i`eF|f z1>HH}L+P!Ts!vkI2yNoZ+e;o8e)a zWth-A?h_Z#89uiLbe|?!8YyDo>bsKVN^vtytwEw0i&*N*{I&;iw+71!X^+}eb=!2! z(;mqDdOium8aHvJV$Bc}^$%U{4{qjSn6j>*MWBdMKyj~Y5T$_8u5tsAbq!A}nvn@6 z67O9XaQl7Q#5>gkZE7_I)u*+^eM%t5Ca}ui&$?XX4gA!6)`t1eYZiE=w$2?(yKV#1s;(ErH7_cV^7MB|RF)k}%{l zeF>H!Fh*SJwPp*b7N2=2xNPHOiw8^1tWBsfOV?ueV%}!dOKbDYoQNm zv-l|!`2{@~#lXwBQkwFG1ftH&p`mu?g&ix?y^=-k~7Vw5?p!Eu6wRTDz^A3Z{zm(u!%PGK=ls&aXwvu#F-38I^Vz;k`GuVOmDe`*=L#Zn&A@88`|5KV=#9 zKw#3%0>34CT9}J9NjY_)_j&bcQQs_s?c@TEac8iFT0KVf9Q0ZZ|E*0F@gDO^BF`d< zFlW}kE6nn~od@dKox1uwvq-1whhc(* zCX_@}v`#cJ(zmSOD|*F}t@I!>29MfDAouFMbKw1k5b#*w;i*)ryd2OPoX&55zFUK{ z&4?`#QE#Bo(?tl)ayEqSUY2vZGN@(Nz%q*>BwkZlyDr{!GEQ(>XLP?Nx7KoN%%=#V zFn8m)yoU>nR005`+g!V#(-u3FVLagJn-F~l2aaitHej}l4Yb^25wuhN z5j9W$hEGa}ZEZodyCb%iqN)EGd^CIM{|rGEu5Jh~_^kQpi}1!$623f(fmQES^ED`s zBJX@@5U)kkA@j^O*+k+uNr=92*g&UkJYymBn(66w?_?V|mO=nS$VOi?s*AYK{czga z_H=-vD_}NdnQF5|lo`6h>~8F1_BApCojDdvIGr6*rJgw~ z6~Q-Pz}!Qyj5}>6M;-aB;_bMYu(_tF8;=F+`~xi!LBFRtsrLn#XUgD-Ke3Wr6CLi8 zE!0zL4f3j&6sTr=>rkHzyvT5qZ*8*In(ci(Sn?u-wpYe{KD<%JMETU567dvyr*&LF zxQ5!TD&WGTbcPK-4AyW5AAXQK%ZDH0u7S-t+__4eAJEr!y30D`{J`FwxAlqh1ABLU zIX|p3&JTEc$e%B_x6ggf`GGq*KWyk*s40TU$DJ{A3T1w#y4{z*3uQauNO3Jh47iuM z5&d5-`Arr9w`HQ0=+^29hbxPJ>8&`c7FqhAN0gPl>r~b2^yhb-3%7~j7>f-kz8Z6L zylZb$lhb-pwG6=Q!CcPGJI;mVthhBe1A)gKOC#w^cp7v5gxtd8^|=oGGip1qt)K&X zs}5{d2QH!mMl4A-KphOx3I`*qWGb&Mk2XU&-y6z;f|^uBHO*2@!)#4-ALn{G3$HsI zqLX+dmb?~cCgNhperE+Z({w=S{WEJSn)ih?aTamwvHY!HEVY5<<`?Nn~41MlB zv(*TkuE02&7YNbt8)f{QW2o77oeqsxKmH?T;B0JLO~bd8`1*n;e2~0I`#jw=K^An1 z2G+m=v=>^#e1hMM&8RESBbtih{@jD-BJ60f8kK+r>& zG&TE6vc48$S)Nxs3Wv$rk=kA+<-9?Nx@zn7YkbP~<(oKeWtg4`E@Z|N8RLF>_EBoA zt~wnxHzgu$QLBYb#%PkPLv1T4!8NtkUVpHOYkKsEk2!#kUilczu4qAe$GmpC)2^c< ziO1!$vFiX_2Q&*}j!~x`2a5Btx@?pL{Y_8?=U5|k_|WvnwcYxFS3-0O(o{4W|uV`m^ z=%GQttKO-9vA%7iWrzI8gpo2-YZ#HD*q)+&R`?tJ;+3{MCUb9uWQrTiYvJnQDH1a0 z)qGQU1|#6P@U2udH~goBLHGcvN3)uFg}&=+A*IVnWGMQ!p6XeQW@~A?`?D*xJo7~9 zgcl)7IJ<3R$IG0ycB(Z=8hyTWm3>^JMl{(bv0u{Y44?ou)+>{F!-7&dNerlt5?b8> z1EUy7(qen=e*0@+?vg|FdWX6ooztw4?}|hvGG;~U%beVqU+`Lr%vn2C#ZWqo_2Srn z5$QAYQ+#WrgRchUXBh>JpmkV3>8;j`Ck>pcL-Tl~<>Wou`2u9knpKKgG!yNkZh=;b z0a>)>4_kX(N)lQHkIm-l&(}T1|y#9Mhhrx6vo92NmT3&`!2tv5>0KR8yn$cpvKCSg<(smq zOysUF0Hj|Uq3#uii7|jWvcX6Q`ap8syCGnw_T(bqa7VWP({elEs2{_H*em%pP#ns3k&$%Q1 zrwfbc`FMidqUvH}RynPAA4Y@i>VrC%Uc=8=^7=r7yrK4%u*6<^dH^?O8H==-OzW&L zIZMB8WC_^&%YF$x{S72dV^9CW+>j5_^kfczonQdlMeESj`)JX$%uh?*-I))or5IxB zf1N6L+cGStQIs|IL&2dyCHE<;6igAQ174D2F~Sb*Yi^*gefyU z;FX!eO$5T`mC<`iXqu_oqtugG)#+o+&6g{^Y4`_TW5hOrKI1F#NFgUs(s2(Srx^iP zz-*-3`%u9%gr^#l%H4d>kZfDdF!gSc-hIk@_Z|CAv#obCcqem#k>F>VrDWE^g0Fyo zb3u83L!6!BMqmU$X4HwZ)i7cb*Izu0dZnzrM!nI*TL|ZNF?~kuB;I58={M4;BCcEK zAI-{Iy^|wJJP0_g6~}9E9`8%GXo@Ibhn_!*;Cf{} zCZQKv*AgkOVa0&{IccDXwfHKqHLw``htc)GNAOSW=HxJtpWo>n$EmYs{xU3(99GOZ z%0Q$#eI++ufhP(J+~XJcwYh1AT;K%$Koy^*u#f-;8Pe%?jbLJ(sR~6KvstYEBF#`D6G-HY=$}Tm6`J>r#ILIaI5+c* z4LSSXQKjPW#~u5bfnA{6fbCuXWna zgXZNVUTL9DTOE(2hB|F0b5|tT(u+dAA(=X{GX{DJHMDXz!53ug7gwh*8X>LL@h4gt z;Y|&1jF(Q+!O)j@*Og9d2TSPG+bIhAbL&m8M$UOF=0QrlJ<`cPYUX_o?fJXQ?4;P) z#6FphieR88+^+r#Bocq*KXXT$5h|DRyayH12TKR3f7Y^K0jWWJpBdAdYu8&!EmGr& zP(ZXuUx*gnr|ZxtTUX`ADrvf=%6gJSJla#k7rt0de)TVQvp^fFdhN>swWbVK5?fry z>%;9{A0h>PP)YS+QN9m3yT7IC-~9%d1QwA3#%5;mp%<9NWheDBi?^#T(xBtK8Dq9_sj6(+PmWd1 z`y1nF=0KC1G&4l<=STYxxkNUS$^kdiGp0B^gtN-9W>i^UKP5mi8V$UA9Ak?_yPV5yl zHyvl3&&OA#&-HE!W^4}K%FUQytQniZH686)I8azv08`;A6()%w6ifl@Ib4Vo7S`xh zc(e+?&8jh`?!&RH^rhbU^0$$H1jdoA!4?hI7wXLqXs=a0=iHS- zt0q7(U4Cl2t{1v!%r;ou#YsQ-f|e!*DG7&Sjs-0s7OEDBg`2pF4jcCA+2-}kAipW& zn{pAnUrdLwaigq`BA4Z8BQhd0$T(FmGgSktB!;yFf8~fo$hy4bXq6`4j;DRO%w@LW zMd|=u6bZ@gbkm{RdCub%rZ2tkcc+U&tN+%vF24cCms)>&un%{xi7;yZ1sqZlMqko; zodKw<}CkYxDiH}O+zNF<=d17Kj!c(Jq&KDEg(d(Upy_??#5HgcY(E@ zT1Q?a(6B`#5HW)@RNW$esJh#A9qDfoNGvrCfRLuak+u_jEdcXYyU1DyRr(H$dYRwK zxCu!$Yype1!C*Gkg;+e+obq%tmt5W(gh-1c_)m@EU>R{vZvXasV0smnM}E622uh?~ zp)Q>+R+FreNE%)!VN|3K1hGBDfABs%4NC8Gn~lsM+-6m3*ty!^mVFu!l{;04FnP!* z|EUih&W^0&WVaF^0fr*8tUKj1>eP2^bjNoEPl`y0-39qezb45nZ)H{VsZKR(8tX2%FONG(RVsquuH z{05R@Qd*e67z;;;!1PGI;i-I5d1$brV3zOXF{{+z0PZLJO0U6eSZdBp++(n2cc#o7 zGRc(LgGwSaHC!*y;N$VGbAy~OVc}EXb-s>A=4H-}Jv>K!(K&r@wSk!oUw3~uZ}^f3 z!J}D^OYC|459LbuFI=^!Y!%vm=#K3Vk}~t5J@=!Z%E?V%Y&45q+cSYp&I2w%Q2lsu zNc0!#OKN_R_}K!2?8iE6<8`T3yY&UK81r2FK=LPDt1_*lK9%p7wl!|0E2S0Yr}yJB zsyyNLtWYg93JA0T^Z849wggcSdgi-sxs_}TTJ!lG@|(t(fyh&hJBy+Vxr-&|rIcIo*Vk>?m`hP6>283vXQJTd`CoNHW# zKV%htk)FY`2LUb;xL`f)z}~GxTj+bOqy=HH#RNF19d)8=FaZ=abwNK(O}7Ty7Bjui z`Lh5Dy3c&6aDyg?nmA2+65vZ;ws6z8JrFa$jD=vI+{6{b{%bVtJ`gbLOq_Sx-4=J2 zgA*W*h?m(0Jmy#-kcsJ7%PY^b0EZ6Y4pY8D*BlO+Hmncxh55R(|81tYlA>iz#=HDJ z&9P_NBJ9LeG@2@JYhOi=(tdvM9ASf)fq!DAFTg7iu@9K7t_iC;1#VqdR zvS2$MMUC_qPnl>U>kMV-4rK`s9qjLYL)c9|{ zgKg$&1q3-_mN%bjHWQmq?o%q!_OKk?r!X&uU3N~WqL#Ass5V? zr!6Dc+Gc&8Ud*i|)_^!3=D>$q^uziaPMg{TZPImGNSxVW02O-h^QQE3l946Hxl{2K zE!f?RqMMXa{R%a~R%g@Uq2&3a<6Fr?GNoxK_ciaYs%Wn4czsZOYk6XQEIG#8O!e*i zPU{Vlf5=dkUcimrBpoG8_mqP7%PQo%t;U-VM;nw}qyM;-RH*-I*QMDaWQ2oG`z3lO zU2W7LC^40*{%c6i4@6Q+%yW><-AM2lJ99s1r>ttxCW7~=89$#!yifI+p6Ron6nv(B zpy{?J+05cqi^9=7Jx?`vc>8JrW8TEFov@Z|#jmthF;YF(UZOS#2YSELJ1fP8+lyAF z#;XSbuC!=P>cYWP`yS(<4@~gLz3jpMkf_M?o5vl?zYR`!xN{`CM19JYdG?*&i?}yq zk;ee(ZzE|k4O{@f)j_tnM;GCR^-VrqL@%x1jsQbpld)768;DN<`u8z5Lh8iHIpCnKVfJ3~hovH^6oO~yf z?S~q83(l{a+naqj|K0wyVD#iVi`iHGSQBG5qUX}g?xEmqr+k`W=)?-a9{O>zzD?fz zG3QAM3H~AWRV<}Ay{*Lb)IkvSH`z4Cm*vcAlZ4!Q+ZEy5o1Zcwk`Ed{@d8gGi5w`N zvOjwP#aHgo7z_>BJs7ZoXaOFvhrKtcu%~@Y2ub96WaXZL$D=0qp0+1*Scu8fX`o;t zuTlkj3IxwH@sK_2qk!PFUMUs%<7?iHc{B!839t)~&LU zPlV!~@5j3ahMn;{KSBRm!?}HPGYAw$L*IpQCw)2HpihV;(bQFShT!H?Mi60vEdJ?v zBFuyo!-*ovs@TY#XQhVRNGhC)$Urw2nl@@(vk$vt+`iec6bu z2|BH}NXmmrRt_ac?aX0HlRaPpcO(nakRioaT({w)O{*BZ$t15D5J>k2axBYoU3 zPD8;f?T3aSLdj>JBH_nlEY@=^eE}hBa63uhIhUC&D{rSy?oS7c-m-wK0FfS!ykmC{ z_Qfgu6WKf{MN{`nW9ed_8c*NCs=A*-A2z~j+MRorfJs1HbB!Mi_nmLrV7PXpf98YX zeshq5;WGFpd=fi;-4p3Qp{$@!*&bylYDm21dE1!47|5>sRY{~w{&EKOpYL2zi2z!q zt9GtbY0@zXd$?uOVzZv0^sLvlx9Ik^{j@sFR@Jc}M#3%37fd#s#4By>xn0S0`mVJ) za`EcbmpNZQX<}P>*=5dGw)r@Oh+i)^TD#n}F175ElgUto?O&9DsY<52v1ruTwq{QAnWrbfWEnUA%sv^PhB;ikRG>qQI|J{~!Q8rd3b z;VsQB=Hi$Qts#QS68&Vycq!NPHHDwl?3vbW?KB12w%zsq=1etHWT!DEVl_9?tJ$Lv z=?OGjsJGpFH{3gA)j#(8+}pm`v#z|}1tIx2wZeqY$9a`g6l?^n2t=19!Coe$t?vIG z*iDuK(n(NU-f8R2dn2M>$g6(1ke8&%tg~)&CX_ad20>ONc63o6Zmmx12)WOuE;8P5 z%e}^t|4%iQj}LfurGZY>Sw&lodgEK-y_dzNjePS3oJ~%=Wv=#D()V&}9F9iP0aTNU zApgXIRs2hsZ!amX)(c>JJi`S(P7=vLIZ;h_4TkTYjpb)1{deO{j6Yw}GBkN1ijw*J zskv?F6fL-y-y}3(lSRwX+vV^L4TZj~xKCBa1}>P@aNPAUv{o-j2A8OAcNtZ*wHw#R z0cB+iCPou4l0IRe>a&KGQ?ma10X{z#gb0mrIYq@ha+tr8sJ6vnnWA6)ySSC~+F$ga* zhUrfIjfqea*_DhZI_SA+Z@XXaAzo0!hW-0+X%j)&?8#1v=S45|1E2x@S|G$?7(7 zmyQ;)$gYWP23rd0V>P!k3{s{hWcJZ2HIf5~4}p z6iF@?Iw4)S2SDm&&U@nfLQ-oxiZ2*FMQ0{hlP=>6$RS&$9{VPxpj#gzH5m^J{rK&& z-q!aDEpKvJGaVvKpFF($=@RwJ)59PebfTw1Qs0BxLeY0FcHbsdS^?bp^L7vnL?2jq zfxeXtzkbcm_x@X&JbYJM=#g;JxQEOpz;$wI;9fr4rtv0ilVl_0ZQ&{(cR(yEu8BgN zH-UF5g2f%t&Y*XdL1XKUMn?nuphNSkDTnuPy1NhrCkb{6BOLvPwP1ud5)}whiUM$u*q<$?%yK))>MSkzxbHULGjhSXg+YbE7{Oc7jkj_I zni?~(5%@()d{}D=@~~dUFG;edQ#3(4*u6`1rRP>+7bo8q!Mu6@`X87Dh-b1#WYpQ4 z9lVZv2tx(X@CnqPF-R2A3ExT@ODzjl8=Akx_lo8ltv@eT-onFourx5SPBGdncQw}h zX89)o8=WTC6C8I69M6?$X4t!?bCIO=K1)0&Fx)5tm$Kq?;%#}4o_f4cx5-;n_@^6} ztNx>5nIw&;7m~_AD}^KE4=^cnFW#H*r7Q_E9;`-w$>I(4M{cY)&sKHkZ76qwc1WIFCBOMAT1#81%Ykp zPxC_l?H@`qOhvBsT1hQxp)G!lriN7HI_`v3sYR?zJ#Obmy#4EbRX*i4noL^YAm*k< z%Xc(v!ADK^Z+mH`S<`x$V8OcXxs~?OBEC_Ol4{(>ea_+0*Tw8!tLOVM%2eQ?vuZQ` zL%QbBSs z^%;^E$K|x{iy)7v<;}p?P?g`bk%WI9D5w*+Hy&fgUh&b5wyfo}QzcPwk`U@yC*BFN zu!;5F!8ax=?)Vx6pB1!^^#2FVCjfM5NgFq+`FRI<6I0Q^=d6lm?z_KFq=MYqy{v zB4KJUw^Nx0_nQhkxHuq7x2+T%ej=EK~eRExUWqHEEhR+wUWEK&O^x!jcOe^6Q; z#e>@ZL2gh#yqT5#tboj@=2Y5IZ4fT-J7Rxp$|jjvESxff*`;bY2&zgnB4)K4kZMVa z>zlenLEQt7&BHO^wRkZtD%n&GVg+6-fL5Ss!u~_zV!b^Q%v`a zqgRVTI@3!gNlTZ>nWJlN8qE|~N3Uyk=HP!&8?}D`?-WB9#+d}~iI~!RQ%M8^Q#d$T zQ3Es7ev9cW)LEuVYbBa|j{R7#peKvDh=&=WV2RCwSCjWp-^Odm*JhQ1M!u|{OH6ug zf3^7?p)OO3x>Sm(e1nVhCe=ZXMIEk?m^3Ug6q_-4HBm{#10~M_KwY ze<<&Q;YHs#%)DR2`(mEtE(r=C;h@pN8bJ^%XL}?Sl{KHdqJ_7VoDF~$8%#1L^2mO| z$?aa)=IibskP^f}BdTj8-9|@j6x8&&nJ!HO_bh@-b6k)*Tj=j)&a=K)w`>mtx!#Rd zHB{t2H3HcX1&vdkoYn+SWQ|jwq+|!YJ|n0;hN_PQH+Z*QrI6#>N2Lb0P$w2%A(Z1; zIT^$_|8bfl?v_c3uq?1}w~+`dT2nl~mv8N$8>(Lm+y zp=zIZCr3*3ngz;7@OjBoQYfuP$pe{kQ2K(Q4b~h{I96kQzXKzU9(D+3M~BF+GrgdL{WwUtwn3*A#xEg2XIVu+cP2zL;aB0p?)R2{%|$@@dk-( z%}b;W3!hs}w-V-1DxL^S4?Q}BTIzN5>FsKhLDz6~Zu=4c zg5K&e!N`D%0CRKCQKB8(5GfRf=?Ret<*83R8H)dFVC_0(aMLq(8+UQC=<9%^q3wm{ zp=pj#N5a2JN%2w#o}yqw)ah@g2l$#w5vxON^9v~49E$}VQe_+uoto$OAK3^ zn7y_Vd|EpsoS06yb`IsjYlnH@Cbm0>hHp}NRyH4>Z4HJ^AFa*V2cj=P`?#N8O(EP; z_VMjTeHCpH>^p};S3*(^gPAA4OfF_gZ(Bwo;Q58Hy^P4ATuHj@z&A@qAv6qkEI*95g z6~)PxGWv|OAe+}jI?o8uPFd#}hw<1yS2b7H9;X-u(7hSYV~LH3!0vTBM5%j2gQue# z-inq#Juy}Bp1R>j=x2wI`n8V+^B}b*KEE$Cut_s=5!-BAu@9io{k)v*1?~IO)}Ygm zkJxEEeA1ud3M|rpMBNX?w|vMFz|Ubnp?bW7V+%e)c_N4(U&Fgr&l{wJH22RPr@M*+ zU^(gPKY96MEurrf)RMiri^%?*4?-6!n9@HWlgB)mr1$4rMfer*NE5l~W6=T>EanRod2k zo1kxqF0lo|iULKVhA$(hAG)`Pvh^9fe)|T*Cm~o44~uHJ%P)K4EYR1v#H+(z?m7oef5)yb1ns-d+$LO0}A6grQN)$8MB6m4=BQ|?0n** zZe|!vb9V2dR9+eYCwyt@$FQ2dH=+GN5MLO#!ntB-?TOa?O_qUa2_$`cf8I=CAq=Bd zQ0(C-hJAOY56u7>W0N6(Hh;9wSjgkUDyOT8lI6~ek~K{EWxr6IE(&;S)mt@6p^H2}bp<$ztSzW?5^E zO{n(gZI)hENkQpLgzu)$0cCxEzjlNJyGdcBTacL3MK2A;B;6XziMX$C zISFtt%Smp@n4J-Xx&_klPkv3^=xvMUACOODeL6OlI60QMp)zrG6}F*a;l$O|ni1Q^ zgu_@Mrils1XDWCX@Y$b_H@BMyPNhN%eT5b~}6jM~3 zN&^yt%_8#Mcy>#b+;7RlOO#=!yQK_M>Ih=Tp zjqZ;^&i5V*r6vcD$uSLMEh%Ceo6W-Y>?Xi@xuBY3FILsksBSmqil_Cx}`-2NS8+77%@q#M>vg}!n=Beyi5+XFw?xXZSwD2*R{r0fWp3ROO6Vq{g zx{2KEa&MNeRtjx1zH8U~%Y7#t4Igu$=Y#{H-^>HCOnvMZ68;tyYUDv7Usd6PQLdEk z>;5mtD}q>cl=Y9F_EZ=0`b8pb9xJ94s(|4DgShAC9eylCRj(G71#%l|wvHSA5Q zp$fU?W&a)pq*V>jk;;<1cgbNvrLT%6hM-9www}zH>|edm^yx@)Ae&oFhc_gDr9MRc za${n_%DLZ@w^dc<3BQBMs`Py{rfjZ*L=O`?;@wl429l&Kk}}d5^C|k#P9dmM?M6+I z)G+tz%T3H+>unX9Asj7ut(PnGa{E_R9Q4$-r+nw^9LANQ?lOMLwMl6dhHVn5Q{}l& zA1M5El0MDi=Oj^QZ1voA=^A~#(cg^YVDJ$vD4g!!zKn|#UI*=|3YqgdvcsqSSkCt; z5ezREowDCwAU;s{KKhfsnbQ5}w$soGecjg7 z;48)XY*WiMP(Sn7B7T^arfWgwF`V5rqoUt}G8xDU-20vQ#TqAIotUiHriH6%DoF8a zja_y#8HahiCRRm8KH&$G5-KNkS8LB{y;tK&onIaqYaJq;xJ)M?XLRJ_(d^@yul6(8 zt8d@!VAmH8Rshss+lvSLc+>HyHE6L>*6{DsBCgyQuvri`_e%(oM!kY6ymZFt z6!BW}O+TDdT%@kyCidsHc5_^fQ=c|bj3|iVWTc{j)fRxUu(fhUOMwE!wqxQIr7xWK z1*v8z90FlAOwNc=?zmSqQW&(JcmkB(YIbXM_4d6u5+a=?aH>eVdy5BR5TgpUyVsem zJysY`g^8qpLp6Abi|{lLD`c3zolI4tNXZ85pEe6fWbC&EAr?{7zLCTRxfCp)A+h_k zY0X3Nt*j%v_u!_%^0^$?gg?NW>4>Tqs@Y`}AH!lfR#l`L>Ll@K`9zc7DdQ4L*4ohT z-<2!)+exg7Zzc3QzB$n04oY-54|IrE792=xX{&0Gz%3keSDvQoZc%k6(&!x`jlNM3 zX|&G-dh10RUHt<|FWwT+!OYFaNwB+*Z==b>ur=2cIamR!KpD4w0P?C_^v@4LYWv!c zQBua*pwl`-tun!D#TU%3Cgn$)8Ntg(51}!$C?usvg*4BbbS?2|Rfw(VR(b*d#0>l` z&5tA#21CcJYZ?{bT+wu#&kWp!8x=l|Gp{f3Xfq^so}I$9vcW{hV9R-&n@B3pr);$a zOlsW>%cPX5N=#%bL=d|Y4y&9EuuptJ00*QN^Nt*LktBzix04mqJRqtF0=eV)(C^Aa z>SfuaU7t_{?%U1T&WpA^WW2< zc>hv=VqeULH(R%2@Wp+1{U_j7Ohq^w2(^ub;MC_(JC+#bEm>Bg)4Bx1n^vhDQHmF8 z)906y{D30Ym?8z};g+2vO5vdu>v%JMm+6TVvtP8G-s6j_&qnrSNjDRf7J9#fSeW^S zo19;lZYCK?c6dD#^wc!ocHCzFKKr9=_6hFwcQW@^@%I<*_4fex=cMf4TijpBz5Yhu z4q0Q*XBC9h{BeKuqTc`Z`!P=IY_xUWna#dIom-gZ-CbYw%K6v6${+mGZ1z0%Zl3;G zHhaa-?fu0|v)Rh;+rOXCSN&HhV z4bHUhgotIGcdonr8^*Y7B`s|GPTRwLO76??HJoU*K9a($jy#R2#J%jFUD?dVI$grh zF6h>2Np^OI%s=44vf-@ryE^86Hbc~7*T3f-Wc~f7EA^)Nb{~Cvj0(T<;8a_9-V3FL z9)F3YV{@!HRo2}p=Or)CwFxzb{6*rA&6#%bMXTxLd3cEBJNOFUXa3aV@mqTQo69b{ z>;&h?Rt8sACU`A;qlLRj;xB>`3VG#OTDNnG)2pBezTfqxd&9xe5fs|G804Ry-R^BL_)J)(Vw8$*NL#NdmEm+8HS3oJe00!zCz|npEA8YOKP}-Qa{bL=y+-h;Pzb zlaMu%I;V=Q*C@{;i2-D@s-jYctMu+T6D@qKg`a|=b7Wmv=z`D`i$g&9*;w*-b`Nq) zG5GQ3SAVsIDN|2u55n3^W&QnPOOe5o{c1)jwElg zqdcX@QP!#PA966McMz$|RwL?RM`n2Z10_&u7t!Z+GMidf?521pSr zE%8iD)fb8y2ndCuMl3kTv&u%UwaUgE33Dx!(vi2qMzU~B3GmM(!UZ{fIG;?`{q$TE zi`78E8dJEj$@uh@?`0*(%*or&V|LxDQSIyhi_M}E4X3oZJ`X@I!kXVli?QbD8x7V3 zbn&oejmS&lK=W@643jjV{1@c*d#bMfN(Ly z?H2ASkjJ?>g6s^f+E@a-vo4heed_dPl%!+GqrppCl~8kryMBERHJb?r5o)$mH|Uh_ zuka~!erWQP3(gneUIfy_63;ZSweKzEJB^MiEn}Nx+2ly5g^oj#>$0)5SYf+bPn(n? zx-{a{s$oJBjb4LYs;kF^s?HO_O%Cc`6Q(+}A}BkzDO2NpQ{&Y!^t^!M`JAO@R-&)R z+jqfu6$>$Ier+uIHC%cwuQ94^G~UHIL)!S3D~H)awB3`lN2|bBd;fb!totZ;JlLh)G-!f=;hb{&Uml^w#9L(2FxAcpp0R6K0pM#cu zEf5ZlRt~0rJ!^4r6u>E5D8S3Y%~z+)Tw4GMAxBF?Th2EP$*(hXPU&IfvPEdO&7ZcW z8$!tj0U(Ka((cb)YC>Mjd) z))zOTUia3*^jr&H3ac%hh`PSP`7MWP+KmZ?I6d(<0alU$*vsnDutAAg{^1oyk%AD; z;f2RR)BmDyzDCtHTAxwdw^SR|7$X#r-$qI4#+m_8 zE$DoN!6H|(6c8?p1_1*-GCzXHrho_LIOo=r=vyhJaoUblkK>)3@-PRqpJ33wX`fJX z5@_B$8e!U~qVDk%g>n;olxyPL-7a(P?t}pF1l1-KqgpR`jA-cL@!(>ds8SceiCN;= z$upT=A0KQMS;oDYHbnB)bG1bb26*rDP%{`X%G8&~0M#!H2{fHaA^C`Zt#a+viHh{;`_M@q8oO!xancLzbY>}DlUF>&osJtwFgbL9}tH2cR;%q)W zdGKVqk{+Z-g}pd3{f@erKhpC-2yxlS4e1xW$GQHFO>2ppieEH0RIEY|p20uqd-%r( z#b5Qh{WN;{!-A(zo2TP>+G3vCzCXpi?fcj3*cbY0Dq^3n&OQH{o;UcBZwikYOQfBLeb$Uu# zCLI`KD+^_wDr&1f^Kc>5Ci20^4VmSIpPZe!qwwdH%(n}FUYcG2i7$Ne<+R8@2hPbm z>(BiCi@y)}o5`I}krw+VBN{uc3Ge;Mxe_mTJa6Q1es9)9a@mG?K4XZrh$_jd+Y z{T0?-c<+DfU-R;IBe-OQZ4Q`uI+i@8o>SB!9Ku+&Pjd(|SRxqvJbNjC5&>AuRpd@r zL!^y=#Qp(rY4kwRx4n#6@F4TSDWEif_bLV(JfGBRYnK zV3qrDqkywN{>{l~MR`ZOyUuA<^DFB3XXM)0%yx0-8sR}!oTIsGn1j3ROFp__rK>(H6rgm^BT=@ zCf|fECWkG|oKcK`>F4?0Z2yrnOQ-!Em?RU>kokw={fmVNZ{D@@9G2pO$^b^|)Udtd ztC+q23~YfCu>BwE-UU9Y;_L%HAqj+=8!WNWdRaASkXrz&go|b&z**d2R8(qF2qYnq zki=vcf?5SP5!ZEF+N!l$TWW1Q=Ox^laC!6f%*Q3@CABd8Q4Zjm~%M%HY$5v4Yu}&gEg`PNGz?g%9Ke zSFPKR-~(D3RhaBxZP)(72-pXU>bnr-zRmdvjr_M9=i7`WD9knNi60EvgoRZ5C22n<7)r(>Rqh_$KLvzb}%%~hK&5Rq@)e#KzV&D(sDXTu-l z_HvH(H57HRs?!lcr)P!6yAYj3SZ~{V)eS6U$WH(-<8wC& zKzc>wo4A|Z{(kT>O6T41Fft_G}!Rr$l{ z&zLNiK;%P`i^;N|OvQISN@=rS0n7zf~rPlFfPTfdIS&C7J8+Ad;@gY`6i)9*-{zr2e`Qb)e6u~XpG~kD`!)~f!&}wcFupp8 zD8uc`RlBzyrs%;DVc1*h!&!#t8gund6`UJ(fZwfG+p^)=p@e+zm4|(i(I5OGiR%^0 zhka7or2XJ1m`@1g{TPSQNf(*xk|I5~V4+wu*oCS1htLg67*EGfl}Cm0blgb~jE=a@ z;bC~RB*KKPK0hE@1pDfYp|a*d0-AMlLkqr0a6S6>UbrVQ=p@r6%K2|6S62x+PF-6f0@ zWz#9SU>d3{>4Hg0$fHa*;yLvl5O3DYP_6814_kgygms}rj)Nr=-;F;Wk}kp)P;w9$8&o<53Zvhv%% zAu(HM+9$IT>TB5HZTL3&_B>yBzxs6V{(e8*yWf1eSB#-+6)`DeXET#qqD;Ap5LnsN4v_=`vAyNI6@6RBG6BD6jgJY@H6BE_y3D5eMAQe+9D2`1$2`?5(c-B*r zn#B^H@PqLAepd#10%PvgVhk0g5QS)X03pLK^jyo%{J+L@#-!?NS`A{NEWYA?YtVP3 z1}W3Isr=g5@Wz9w8WcGj%s>YApo$3L+kX352-nsVyRzqlr1Z+p=t-*6AF0|vog$IE zjr$adTlj%;E!p3RzXC%EKPs!fDVu+x7n6YL6VS*+x5>o5_=%E!i~GSXBUSksGA?m;f>1UiCd)W?t2jSHOJ4M=R5@fJbJFqk*ONf+p1*{8caR;* zJMp{9bZ@c|B&3Pxcj5^Q8!4ji;R7S0AAA_;^k>I|ifzV0BA-zTyn}Eq=laJ%fn{Ym zSpMN@?^F@Owt`Hu8{Nn_kw7GLHl4^n&?BJkmKeEF-DT6hi8a9J+alv(5T}Z z$V>2+$&t7B(}k2=tK4>_!%<2$!%te3l!UoP8-H{)|LB(~_TDue+U04~rArt=F+{v_ z@x>z*;mt*BNm{BxAY=SM8aFH4fd`+QQPV7KL5_%u6^VUW%43SiQlU!O$`WV14wZ>bx|IE=H-k=Z1tYqq)~r52ejvy%sudr9AA9 zzqA>fu%IWjC!mb7bY6q&4}Un&bKTbvcdCoP4cDA3$moaB9865_%IOIY=aC>(dRAO4 zanbc4Q?ks)e!;XA2s}1dp(+9Yk9MS67AAaq z;t#6+)KsQJwRPQqH>muX3a6_wYrAf^nbl4et7)@fT;S)aI`0VOs2PN>rSgv;6(=c0GAJ>t`w6#=oeAFNJG{@WouHHGjaa zxEy`qbgsF8daD;!;^=%B!-fzmV^7%@h~9r2LPE8k5-q`5=lQrROgYc8~8ScOt51e8Ny~TG6uVRk+wRlcpy61-U1C{!v~*mdi2%P z_o)?M*f`2L)XpWWdu~>;;QA_TD#XG{Y%n?!*8X=epQieOevG9DGSYq+%Q0@bfGb2stdG?_LX9dZqLtO1@ukXX^J}&Ot zq+;I6X{c};4miwDlg5cJF-MUqk#@5IjBk)h)z1l zID&6Gr7iCrjAmkHB9femXuFWTUco9l9GJ} zrypc%WKnR&a*?dbNv$8X+CRU@8Hj9GD}1r&U=j-s$3^hGCagd3v_FOC9GAP%F!i#7 zN(Agq;M3vU#L5hCUF_7;HMe`m8U*%BDj ztHCBTFC|gfzHx_s2eu;?NFDo`wFpeO&8!6jKkreP7>PE*LrJ=pE{ud6~cTGJ-3KMr1fAl4-}&7V*S12Y5xl*=?=s0E3tqnfHNOAk~&o5 zCnp_H+uwVX9~C6U@z>%W7=aJs_)F{zGdSL0I8KQQ-m4l8jqooS%U@sreyZuOAFG(I50&l2yUcJ2;$nuc{E5YVW%M>HOl*;)H%3r%VmzqfO44CC zq57Bw>_SXCK!3f6;slj2qmnaWW~S`ZW#)LK6EEn?%)?_qHyU$>$tF)S^Y%Ue$C)X% zGQ)(KnZnPI8FyoVH!BYCH*j zAv!eN^?b_=%TmwEXFi{Ta)_70f%GUt-+N3?oB6?Y4sAFRi2K~KkJK*QIJ9O&s- zfID@D09M#xBMRj1Odzm9snv1=JnJXJi~S+q^gwDpMFq(ATt@|@0$&k0J8=&B_rCSf zd5M zyw(Y+<3a+Fp1#=6MeJoN_PL0CIbv6@^yXkhpYM-&+}N=5)nNybu^7<=^RPB4n3s=_ zz2sr>TSJ}~`vmf!n6cmIn8=O(u16K+*%R@_*nwqOJLT?u#UHyE!!Ud?5n`GHqE>L@ zd3RT@oAtaK%i;2E)Vz^p*x&$a9)LdVM&=@o#Za3;z(O*k?+fW(X`2dU9W@9`T>jqI+aGB4HV+)iz)t4N?sOPp2 zX{W}FK1*R#+<01 zt!-!}$>3Ty+ChfULc^T9kvx339D)PnW5mM*pvE^8wIv?FQ;g?%9C5R0Qu;7>j6|0N zu<~jl&xTp6B1v$jbOUY!h{}zhdizH>5%-W8W$%ns!`Bu%o|`ehll#M9T9)~g#2g~a z$n7Q!Jeb?cTX-PEwS^Dhhz4xl%2rM0*SfqR4(8*Vg8xXMcu>R-;xzPab9#- zcX$m&K(;P{Vw6H&f*vg|FvJd@-R5Z@0Ax14GaC8O<)<~HR~EZTjMdLWy}2l_brN>F zsnbgTXI^aBzdyyn%|7wpv!Xfo8hewc9qUn&?uz)7 z(qkuto<-bVjDjX$0wOR0M*Rg7ifPW@$&{fvb}CnA1o@%b!XMj<$&VKp{TqoRf5r5h z{KRfn@6c$a^CdZnzW7*57L1fG85*M&p%ciErt_M#D}qLo0!m46+Z^ z$dY{&d-+f%@(K|T`q65Uf4vX)$(!{3iz`2A6C56`%;|WpZJ^urW;VJ_2!V5f z?+D^!2)-Pgt=cxw-xbg9&BlQ+ZuUj_four8(k-on9ziyey@QlJaMcl5N$i5SNk%2?c`?t^W!kgN7~u?U3hj0GQ$_k#r{_1j z6F*F~Ps_fu8@%z1eo!6!k4?AQ&f`Yc(U_x+bl14iwGL|}&r*vG`?BgRql@y;4V35g z9Y~K(g!MLa!}k)*Lhvk^i>JY+iyrPV=rE2fJl}!UdA{hyg;;#fkKfAT^JEX~obiXe zQ2e$heuN;b_|zZ+(KE2jj`}s)i0V}E(J-$1Qq==eAdV-V_WM;I#eIa3JUGC>3%Anb zptR6){qL}3+>MPzHvXF9hMy>&_&yH4PBegYEx&kl8hR`&dw(;2|70)_rkf=P%?7c_ zvUO8Mr9dTvzyXlW*mYCJj5hUJKH~oKWjhfWXP*&-8Zf05CkH#}j%FfIhcR`2bJ1EL zZpZsL>eFAE#G>3hoa6MOmX@($gU}&XqBpa@CaH&al*VP)h%y^nDwlo-0|RichtYvS zYzFi%p$i&sqZ{!-c!9&XCsCDjNBHw`(u7(;fpumOKzx%^CQD|cY`(A?LZ2VAe>dLj z;kat6oAm+XWdRsYLz<~_$$H04cDc!I;4}>0ue#Hq3C_S`bXA$6R~N_KXrOoxg&wJd zI#9gNjUJ00p|23eOyYdNHh*M)#pwO33Io|!vr9qw9N_6-mGKoAYx^TOUHjuBL(3JH zDh|h`I_4VcRhj;}NPIdLP?Gu^h{rflAS_`(vZRf!W(kK`OF*akjM~RX;+qV7W68sW zT&!hfr7J<%s8-=ssMH0fxDY2{urbV=a=411i(l#jl0z>Jh5lo%!@3UVOkw#D?B)P5 zvcQyt2Uh1OUqnAQzevk~EsdNcg z{#nu2dnha~g|O87uY*UcFrTwGL{EHqgW`YxjiM7dW}{Fw8;xQk{A!ym3Yl$67nqrw zjZcE1A<+ryF~6UxH+gR9i=OM}VZ{kQc+i6w&^$dCzmG2*Pkg(#xORh^-M|KIRku8x zLW(m3{iRQP!Xwnns3kmJWnS#`m59U%Wc|bK`dbcU)+A_Bs5fXSlW^WjaFQ1@A(M*z zrGE|09B;bO#d*=}dj^DN-;)(QQki;j%IKbW zQ6Z1RZ!KgUDPf9-5Qw@WsIL?H&Y=2)B>kh~tHzQ^Xu7Y*e?L&IM^O4RQ|MxDdk`a! zS&X=q$SRd+*n#kYuXp1^Ctv~Y_V=>~gccyKW^U?f--6KCp5jKec=UAe^e`rci8_c) zRqC&^F8*UUPb%CF087QcKa|b+i9{k>2}3=;z!@(%Z05P(@zDX{PK+6`$(DyRbF}yM zO;}XJ)Tk|7kxJMlqT6!Hu6 ze48;fMg+4UZtTILjqu@gq4-{`t4uBAlI~oEdN+W&%p$}0Xc2{VX4569Gn?>joxYSA ztEnxb1Q3d!r)v`qX!eiZ~gHf!I0rK~N(m;)p8f zVuwBjieES()6hCuym>ldV5q#03{tJ!v?R6i>Bktzu_E>$Wk{Joq^&aXO*Obfg<~Nq zUQ-oQRlBPFc?iB*w3&@ax_3H7l<`bpXWmB5MLqN4@Gtn^^kwW|q z{hk|}g{mFLhdTLM7SJe=vw={G98zZ#im4FdJ$O6}6j`(?qiRTWNzUpaT$yo3y zoSlbCwn!)2`wZFuv@4|&mpjM?*d2l8mgER9CANqw`Njs~CgF=s1rvYP3IA zhTO*ab)z0+(sSJq^?qE}m-u`~*22Aqhkh8RBEHJR-*NvKI#s8)@Uc8PBOX)x35Pt! z?U%jTo<|Qr5OW2=wZ;D{g<0Af7oS35p7g}wgc4Mv422o%aRzZs4)@kz?ha~nCy2Av zkv<*$W>txlRtw^NkjOKiCh>YGgh4Y$Mj33F(IziCd4N6=Y1wb zF=*0+=qiKeH{9q&UbIYpr$&E@#hmXfgKO(NueAL-)OIU)s8?zz_!C)giDPQ90{~q< zbkM7caSq|d7|c;T@=!r3|L+wglN_?Yf>=CXJp%zaUBLk5Fao{y5jGJ#oC_b8bnNWd zp;mNow-*;@41XCW@<43di*!8Y=qnc$)y2;J5JQ7aOkf!X=9o;zEd;`Yj00_V16<2~ z<3`@Y>79YdKY5CBrz>=W#%n1jPNpCBQ@=^|h9Sx>v(_I}8%Mo_ioO!1u6 zpQF5Gc98WYAHj)^>I8(w7$5mLJqe_REE)vXq`VWq>?J(|lm`Yw_oTWwCI%^D z1|}4l&8~<{dX~^bHqnEzjkY3{V|>+y0|-WP;8_-(RiriIUl$`7{kHc=&X@?S(K-v8}Ip&Fk&Av>sSZ!+C)^^*u5%;R39fDsVB#oL#QyR zCFfMUR=t>(Pmao%Q{PRWJ*QEap4m-Yt#jJ0z5&nNx)_;pw2K|4RNqG-?#vH0)R0_= zg>#}v6@kecb&OkQd=ns+m97<vxZ3kf4A!M_J^r{f;dW4RUOH{~A3k2r|)XX#q(FZ}O$y^t!0{^WeC!sEEScj7Ct9+fgAkCf@*`GNS98~=lf z0L{POir|mlsfsrCTWzxFJNliUl6&S*-w=DNl+}ZZmh}xW^{udxkQ&2waxuw>oSjN< zNEGz(w$Q;?5rvRC?Tni=Rf%*o;?CVZ%L_I;+h?h*jhpczM!`Ei_4m>+-Ey#Xs1uQ> z-PAmTAwCBjWW6Jbx$c2Dhj}M%39;Uq#=?rr#^R6uPVq?3ow=NDJ6!j)6V>?8-IL}G zy6J&r&cx2h6-J!;v@|`h2;DC`qKxj>bHZ9sgY#W+U=+-IIOh}HoZ$_F})h@#2Ui^t6?JP8sv5*vLB{V za}!LM+#`3*nBMb*f|e85g4E|aV!nNNrNtwmh6KmymoCIho*(So#O=%B-OlC9@w&0#* zz1SaqA}>(-kKk$^KcOoeKQs}Tf-ViVQLgKqQi=b8DN86M@eg&AOP#P-E_$&yfb-)j zvJyAI0E6JgAk&MUlndUlhWzl!WF(}4TX@4 zUcV7c4PX)P0KBsuFY;BTK)-@5*BK}CLZf>p-VGEny^W6m(7TylhCdMhId64*oY!K1 zb=B#V{ce`ALs2&GYB6^5sNIdr@~dS0PBZ3885Xao+@EkmooM;3hV`--!J*%Ldr z`oe3bToi)pwrZY+p2FJ-{iV;go(PlHJ}1~qYnc*& zsK8z=E|NPDU+=E%vpB*+t$-w8g6B+eqghDiNKB{ZSA*0n49cG+6p2OM7(Ietx)=?SQ0{NWBN~AIc5mGPat{-}vKX^})6OeCx-;CJ zrOv13`F|x4=W2L?BhJIu6lVob=6jF#z>_k;5h|V9Wy3+9eoFGHuEWVpN z$prg+Vrx8u(*^xp4+JSGr(YkfQp2YeuH`^xQx029c~Jl*!9%=W{Jb8;d>_rz^VQq& z6ap|1Nu&*6JhT7MvBSp~xg>oHR{e7bQ+O(ydcje2)ZyHE8W@MGP;_>|ln1#~jsr@e z6Yj>VKCILM;>zHrlO^8OlT9tX8}~5uCivNxjQa0`sUh-bGs@Z9uZH4}R$!gUJSebS z(^e4);j2y`%lIbJTORqyAH5KS^0Q7AaEE<^!?-w7^5d9bHEu-Zw4A;tyvS55pK*8n!_9ie&G>9D7f!9gK@M82Tn*9FpVfoQVU^hf!}Cf`+Ac}e z-^6nuNE-NU|HAiZK(;Im@U+iC=TH66(=i=)_SqtzSxLlE!R&P_k)m4bPd25_ki){= zg*br+;g3&z;7lWyREme8YK6X7$q1}(FoZeri_h%8D z|8KU>hOaEl_N-^q!U8)I2w`3Z8#z{W;h3^K;#k|kVfjn(LfDVhQVbs37QUtu%NuDE zj9#=5CnKW5Y1LEp>#TS2wyXCg*S2LX#v$G61!$tDMlZq&oc;ozV*WDD* z3l8zZG4evFHachFv{@yg%cxkQw;-+j+|ZiAXrEUXjdgmdtnG0cB7lMEBV@^ z$|5^@;*RO%I5IVM`i}6nA-%^usw}ggdo&M0dxt&B4yrfzQQF+pM+sE_zJX^3KJ^(c z7-BzD`1H76mUmxIi-Tturib~Y`#lJ6^c!pZ!?R1V-nTsRgg!4m5dFT`E1}`xWYmK2 zRYgw76DVyh4h=3{;q|l+1~dFH!?Eh)#3q_R&{n6j5U_G^@lW8OU+5-`@i82E;*%#m z`pNFTC!^%aKK*2mJmDaQ)e8q2<+*6KjEge?dUXKkMtTMRJf2oh>@n0rhGqXI^iV%Y zP(5O-;C~Q;@C9)VlWu=hcDrH@C=m7G@@A|LT7V&=@lMr6JM z+|fDIlNlV%l&xWpXF7Z}NI4K61CS$>B`lU3sFJ~)SH_Li*aU&)8ALE8RL8N@VeOAq z$C1?yoc>P4fBn&ZW!1Z1Wjb{pQ6l~!gesMeO{#n}n`wM}9Q`wuj(l*1KX!|xpH@3| zqN+P2Es)w96)o-hmLv_BdC`CP4yAjWomZkj4D4NgcprABsh{NdLtzv0NXjEn_jglyf z&4GI?n9&?jW^Uf!DfBQhGHoqg(9ua8bg7ac<5gnq+Q13=Zuy`DZ9SH_$v;fOdvZ$-0T7 zl5L{f_u&X02C;;e2+1%a=OHzU5DZ?ZQQfyqPhu6SH&IpSBDX!tMF$U;{G37;rQo1x z$oL#ZurGd}qEKpoF&<{t{z4)kEDtWT&S^otp%NnF;aiZ?_?K&#$9@i`diP59Wa}QM z2+go-WR5p1dlR?~dCTulMV^I`sR(QCwjfbR-$3*v*_wOscpz5rm!ny+?^WDq13dk} z{`75$Sjl2Gf+pf^UAhe_6&k{E3hVZ)Ao2l8U4l%3WvpP}7i$$g7(!}mCOuQ=>BbX` z+gvg%zzVqpPZpudHe+|(9N8VW4uN1hRJ-F!RMuXPztpO2ql_TcV4zS!muxS(nXw`c zBycxwq0&U|O*JJ}O-lGmwmU}0dd~XEI#Na&N~piB#fy~rI5sTtIPO)Yl*I2u;)bAw zg8Bbrg4z&6iXcWug6im|2vUt%1=9;1NV;m82)RLp%+x|ta}23m=-qE`T+T1usiqcz zet|rAnJ-EgmR<+WFJ#o2OjQc{O*T^%qo^X6gO>~XSPZ*1gi5=%459!Wl7~2%1~XRp z>Bv=*;fsCbzJy&>_<(tI7B+JgZNujnpo@e02=?I4DT-j{q&hr&E>8sD9srI&__g=B zg{($5%stlg(46CHBXf^~_kV8--)yWBD!gNo^G(?CHFiMq_UV(#$IkAt1I5#%-Y@`?{ZORLtFfTUpKGY|K<8W!7 z(lIe7jQUy(?S6`z^?m^R_5+a#vpe3#56{x`i)OjI~-W+7=2jLRZeSXh>iCEw92^0tFUs8PN= z?NAwYO82zlPyy`wiA~?hjpL)Y@iSXx>R7|xAz0rR-j0JKf`Rb0FqC1*#~{_0z%1k2 z#MpRh0$0GBOnE7e(Xh%SyW z%)|*5JfOlito+2JKbG^TFFNeeKTsL;Czr3{QmC#Op*b7qWl{`%Z5?)CA z0CKTJQxxOzL^=mLO(8CLOCXkm4~TT;^-jS62d5a%@FlTV5gMBh;UOdg+L!-y|(ULG_(JmM*Qc;vu#)@D^wJ-?vNYf#fHSl+*`2P|=;JjdPB z9tU@PkLKe)?3@#my(8W1EAwIF6bq*(yaSI|1I~#qDA{vvw5SB8wt-lR!_%6u0t*&R zWi1He>qfKGl+7iHYw${He}NyxL1Sg`NBEvtnQv{|(N5@lz28>7_)GCu-k`ZUHFFkx zSk3A@Xw8`Es`44u^!q)(c#217M6Z{;CPt&AVaP@8hfy@`paf+fPJOM4y>;g3!wj$e z;m7h>lROvfXoi-|o4jICh_nZ6J@Or~n( z50Wr85T)EDpq1te{?V_<_X|(gIz% z8LrY6$vRNI7XE_=7X1>r40%rx`Ouz25c%;#nMAU=(1yk7-swYGD|Tm1|yZmmzx4bC260roSnxQ#d}*$pgM zsD!MTG-2uYrEczIpuRyb$4o><>w%?tjo;b4RwXO1?aO=(!Q1kiahBv_;Jg0d58}=Vd)r->ce!7FS;hj7p>2$h^~>-oX25*F00ZP z@G)>7>@OQohn+*7=e(&5Pe;f1{@LBW1)?~K#naEf>5uG$sqXn6|K6Q}lLrPO1F@E? ztUT%;iBn+*1W&<#eyYTeZ{Ygz4P1PzhGOXMAqU6iiOGUAZd$ zA^?07B6KEggVE!L9F^rve1GDOBtEJMljfHAn)ml5)gq7-^5YGxe*5FEZij*L6gRpm zZ!?P0NftbVRVI)~PYh#Mf~nL!@v(33Pd-XkNA`G%Nkdpo8g7kWpvWlRBX8cU-`tEh z-}78k@CO{fh8Sx7o@;j2dWv7+%{%c|-`X#f6x<9d`?6V^>c26ahcz)HF<-W*D6eAj z%K<1eg@G~nD&EZJYXZ?@M^SgEnD%_@QMJBxuRD7xVs|*O@AliAJh4B~AXSR0+TjSZ-R)7ho zDRAP?f;;ge^ov7B(zF^nKYk4S@hbd-;cOT}z6pbB{60h#_wvaJ{P!*}B(|OCKmdq2 zH$ECM#Q(&{FXJEL8mP*DtNOe~{8eCJ3|FbdU&ZT_JMpx5tMdPfFWs)E67u-(;z@ZhSJnh{gB_R3A6G+YL`~g2%fkoED^layfGL zKMlEZx z&js7(Mi%*}?Ftq~=M4)?>uMQ-ogmp=foYvB5C&U{dtaUW99J>qOzP|%8NRZ}`3mob z+@IAu5bl6UY-feKo$bZKbX2kvQv_qIo7bD`PU{YioZPv`_55=9Bbl158?gE&mo4P?JtK0x$6sVMQF_>9meyU+$f-q9r_r<@~t=IUIl;rIX3VJ z-fr*IbjGjNp23rM#6!64ee*_;sGFyxw|2(ac-6V_#b8eRbD?4J`3Q!}J{QjYSqFt3 z$*?HZ$?aJJ?C1pl)P3F;`m_yAPGlzeC?g1sVGRH!73Kf2!^ z-4n&iP}uJVD*}#Ur#2!G-G*|DKJ7-gCkr0^4&uiMZy^S~m0Iq=Mu#;n*z3crE>4UE zv1|k2*I@MfkT}?7scN>ggDlXt947u3Ma{KS=v&JW#!GU zrKfcVkoc|mCm`iJRE<-lrDTPUb(i_3yV+gqrl__te6wyFIH36E&aIO=(Y68z;PX6G zo;MO(SyA^p3j^8R3Q%pOB9^nG0#*5V4D5%w({{BC^+kPXDeknLEd%}GuHxR;{L!wh zlNpuj1H2cy(YL@_+U6W*WFi?Y9TYgvlUK8lJmD0+WrA4RY0`xHgTd`gN`QcsaPo6wXf z%hbJ7mb#}ORpm7jmK^m{qys+2hVOzuajz=btxs)1L*S+4_3Ae;o(ks`#nBp(m%IVG z#$xFHYrKP!D9!zCa~2LK>D&tJm&A-49z`$wdI=$#3WfpR^4QF}_}7t?@+Aw701fZM ze4VAf2v_TwO&wpa*weBY?Il^zgUvjcrw^8H)>1hyG{IfwqONs|9QO9f;eznyb`X2S zs$t>H9KktgXCg$=i)fxC7K1X@q1f;*;SRib1u5t{m3JZ6@|S%8Qye}xo=cguncsa& z7Tkz1Y>Ck)pB}v#N`n)}8m=TWRQ*?T-U zW5k2yqD=I62%tt}$%2P*3o$$lT}WQc&5j?b%$DCN+6iW%?8viAx2n3=r>D75m}U2` zo3^ZVWl!kX@KuF5p`)S~cw^V~9BB9(mJqKhSa-lF`*v1vxDuX9xAZRF8vh&PgyM(I z$?-S!ef&C9Mky;Lq21VVi$6!|W-Nr$ixq|0tSkeQ1;yAv$#YlTX|J~6^wcdT}*8bmBZ6lfmC5YGXUo%*&;BTx6SONHZ)Hca`Ece@3l_`DQG4zKY=Y?wBp;>sMzz#dcg! zs-I2Dcs6LW4<-8aXp;txvl+nvQG6G(U=Z&7V>v!ri-bu@dkw>XGct{p0kaQ;^lVkZZHM`uCaEBZspXfMLCa2tjXTs#MxHn8@J;+aW z_4$)KC-3mwRUYk{JsF3i;WL7J8iO?rzIE@`H`e&eqfbWnOy1$c_Q=^ocY5yft$Sx~ zO=BpMQ#5<%F2s`)-H!&E7gAf!C{G6^wccpm=C;MO6thj!uJ)9}jn+#-;{_Ff(tej;u? z5C46nC;W8{3l%bOwzU<}XYF*mUiZ2~cVZbD#@ethdQaLqb!+J2 zXzm{`hv?|e+n&1(Hx!GJ+{ba}dw;7pI3?We-JW|NylA_4@H5e6b^+%v zIqI~Wbjv|<)KtrVzU7~1`7gKpOD+E;mVXNlD_2Ozs~YsY57|$|K*l{spYrnJKuUf?=$-C{J&(qZ{rw2JI3-KY59j({sET%fR$f6|8H8)U$^`(*?x@7(&@9)d)Iny z`#)=bTQbt`OZopFcj%AR?}cCFl~E@MXTwr}AMg3wEqF(+#s_HF`Lp2H57an&eEwb+ zeElGeV|1c^aVvf*0{p#g;Z!~Nd(Xl#bWy+k7LGBb`XwzKRuuIccz zgA1Qw&sD!k1{XfV?5uug3VyxB0~5OXO%r^*;28I*Uzy+?5Q`mr7kZ8pyjE~i-?;jTzlK!& zy1-7*u+wbeUcp0xcjW4XPZa!0!LJ{v6Fy1sYXx6FNN4zD!8@$@iv*8Y_$a}@D!57a z6v4kKxJma^!EY1Xq+2ZbcdhtG3x1b{pCiRSRD%_%|$kiQwNdxX@W8_#Flp zI+qImJ%bCK%LKpM;6i7$;6JwT8o_^N;kAPQ!orse{-D8y&N{(28C>YB7yP#d7dkH& zyi4$5qR6Ze{0W1Lp3@+Bw}r11{3#1>6#Q8WZxa0Z6s{9!7W|JEeudzFGPvZoMex@Q zF8OU0{BH)A{00So%ivNjA;I@p_$tBwZE#6zM+L7k zxX^i%;I#%9I%9&bFu2h9Rl%P19%n;=ixsj)mJ^n`|9L^K_3vYc3F1XN*{1uao^!fQ|7c66` zaW4I`Z_(DQ0eOQ7r~OoD?!YRPSKP>7{5Zy%v)`LdIQQYy-6nIF+^Oz3eTWG`t}@1) z9ySbMHqiv3tBC1)Jr$)tg;jFO%9ni3k3%*vN43!O#5xvkNxEf1&TQ06E zZb01m;#P`#fw(6APjWAm@Rx{tCbGM)1R%y zyXiEiKeK5bfUx`-H%EI_UU6Anvckeeg57%nN@% z)QvdE+@F3%_x5k|x7iGL9lcUVBI$G1$}L^%Dw*XtC9~zZIK=qVcoy!+ z?`&M;XZl5creEV5mN|7T&itmJx2CZvw7kx{vSwvd%NlQOQ;T<5u+14?)3~a>rKxdc zO=Hl3^jqA5=c{TK*EhB{PW7(FljYvpP~$RheXwSwQ(NCy-&*HgU02hn&|rO2qjyxR zx4zZeh$Qsmn(B;jE1RlA4K@9Rn$=QM6|6@B5=2GY+)}fuzA4mdzww03{^JR5>oW3^rw0oLo1hpC=k%pT+>q3SdE(62x5bw z78F)fjjpxJnp%*(=BCE#v=TB8Jz0YK4s?_8-iV_7Hl3%V9*9#8APh&7MXB2p1kdU=~d z!RAo#P_4xra~h9zQ>I4f{XnNX1S(Nl?ZOAfn=Iwg{yS^2M3ybP>RdY z;wFR|TfzBMa3@$-lYrm~E*whyr3rK_%3Qu<$2el`Mvg6Q?y-PzuZ!;v!N+WR)wl5N= zy1uryrUf$5+gg7mgh%nHhLCp^I)jGLXhzG}A!H;9{h~Bvh#k^|O5mJ7GjNXSg^esu z6G6ySsF4-L#FO@_rY)6$4C)l|q(J)O%!eX>CbvM!YEejnAz=ANpWv@*Tw_R6qGx&i zD)jWKv@V2nQ39Hkud!yeuF+L3En1Z@T{#LEQe9>A&~KnzO)OWj_{Zw1Fcy;eD=J<) z&a~P&0f8p8f;#kADw%^jTd;6hQ!~2~NCDIfrd8G4T+>*62(^X*pm%&i2t-%Y5|n(` zqL(sFS@i-+KVn4b!Isvb0jHXLU$|LyRgKGQKqX{!n-VEi-iD^CY81N2rBMwH)eioJ zoKfRXtEpB0`7cltaK?I_QLW>hsY9H>$lYMadoptgpO#Pnajzwrz8C4FJm{^Q!BAla zGjfE3S^<14Dse-#j-myA#yr>=RaXZh>gqs*x`7LS$SG+<=r*PcLZ%K@O&Xzb%PbCd z2BRaZYETHGLfoxW;etdE8e%h135Jkm1XI+aZ20OB6^Uj6iD|4h_oG^o?qc$HX{f#d zdISm#f@G?e07gc8S68)qs~S)ltJipq{7yAns1zA7FvY1#mjH#{y0llTpv~6Rw0Ntk zt07cc5BVC~Dc}8sWKk2nl%-O(iil7%bikU$6q-}L!KNnfN;W=ngbG$G#G+Qy&^(%! zX?>BM0XX1YTHja&6@FRMN>tj`R_bFlEiJ02@UCvDS4vi2xK9yNbxnF)x-+T+4{KUd zFO#L-RW&V44Lw#G9aH=IYv7=Q-H;<$)p2Q$m)vqxqim>JTGIecldYpq(RUhaphTJ` z0KPh@3eb0Fq*YzjDk`d86;)bDF9jF6e#2~4O{BX^^*x6oMFn8OeIZf0h^@6A9kt|% z)kY%Z?V;jQ&k&Vl%6P@KBb5fge5w#4lMl|NdTR1WkB}nTiQ=)`gY^ER(WN4~jxH57 z5Mot6+#4cCbdHVZknc2dIHi-~kV&PZ$4-Y$gh3i=8l6T+CUohw5=CnGqvA>V4w<@6 zI2BGQahb2;8R|3IUgq$`sC#JHyw0+ELr@)ulGBd*pQ^X2 z>S^e3RYr%vuuYFcgeaX*-!qlHP~(cmrqya32hpb`tMFP04WleyIRApm*|R8VsN0IV zL)E-$DeMeXz>Ms~z>;!HBI(ng`xMODl#-xH3O22P!UML28jUf-bP(x~2sE_rf~g&($t*cPrZZ+iyCgaG^v!*7_6$G z#wt+yf@qLc4Xg=xQ{G73*;P+oVi%Ae9p9EVE2J=l8OSJxfjvrOvB$`GH@LdVgfu*5 zkj&_aC^L(Jm3%%t2`Y#QuWM39!Uq#Afs}krCq7Nv=ttE^NnBxGnm%E1SGVc@6$s(1 zC3to3U})(ZIi@-dVYl+5zQRoBR4r}g5Ex~s((CgIeT!Gtw=5o2y%?k7@lZ~jbU!p# zXH^qS21=F}^LDiNs;>-jmM>f89f!Xr)b;WF=bd!cDHFY?oZ@X-dbt|RjT@&m=5ejC z4N(al&!N){gj8?nkkz4;&E9e2s;Vy!wFbwnT3Izi4^_P5V75cV)4VM!z2j&f(21a# zarj}Hk*-O4Ag^oF#b_u^t6RNoQ_dK7#_6j6Y&;bbGt{gk=StWn>YLH)h)q$w)apoR z(+y#;SB)^iIxrZDHr02P19TLb@1a3sPzj}0hU<0c($f9)Q=HHgr+(rYP6${1z>Q}WoA>Q#H!YGjc8mjpp?S&V@ z@Q(kW@1XO<)#^00;17ZVF0NLmp|y?|Y?!#gg|~Ree;C_dfj=Yww;ERi|25XI7iJ!r zMPU3F#2?;-OPi@vi<@eK>K~rt1x&^9;zPWN3lD3Y4Kqn{}7LQ&TuLo=11Kk4C7H*;{W=_ z1{nSwZDd442|CIMQ-%3KPDdekC`N5NrK5B!8dB-eA#lSmN}YFL5H-pfCS_m&PE-Ea zYG4xMkU`oz5T_24k(h|3PKSK(UoEVI$VZdPeS^5rCmi$?so;z0S=xl?De+D3gJHy> z=J~30suWGMu)=iK2{`#SZJ_qD9W4lbl73&Z3~RXqB_5%2~A3SybyR8dWm6 z36W2QMpQhibuQ`1ZcxynDUJroB4T!EGG}TK@Ov0x4G(j<$ zf`e^_o(ZXE)DAKSLC~aDDy~jdBSxre#Vw-|>r_rg6%!k6#0=UWMrzdPR6~T77`X$7 zP20AfC~e$nu7W9<)AJNH7)(Krsjgq9Cbf!XBm_~yP|y>=V=aV6W5G$cWQ-;fjYbLH)xQ@nk46ZNWIu_S)xbDW)-!J;U zUf1?DaZQ-p#s6Ik|B3j2ZsD87|EPuU5dSk4{wMLjZsB{x|8EO-_G&tF#5Ht!#6Qx) zPY{2Rg-;UynHD}%{H}#xB>qJfe!2LYE&M9+ue0#4iT@T0|AF{_V&M;p|6vR77XLHi za?KQfro8@S;ctrnpBC=y)BMa8cYuy270*!?eyaG#TKEj{&lERX;<-TlU$*dS@i$m_ zNc>;1@R;~-vG5;?|2}cQFX?uQf4hb67JrY0za#$r;&ROye}>t zCZ3%ZZqj{C@DWz{cP-qcn|(l+@8_)WBQ4y-KT7aI34ez8r;E$Jfj>iMm4%yhTLk~S z4(^zE@bOl)&Yk@Xe})hDSoqW8e?i=%bnsO8zgzgQ4ro1k+a8q7OEZp#6g@v2)T4Ujc59=-5l-DhSQ~%@7(D?%k zH|6zn3peGp*}@H-k6XAYujee>(Ai_*ro8?kIQ3Hg44ofZxZ&rJk9E15@TOb}E&LSm zkGJsY;y3ldsMjXlneyD=hCh`SZqmKX!W+aNv~ZKIsXx@Y`MXZS-6*cX?-2jp;!;27 z&xHTAg+DI-r^Tf%&z}kZCkr?6|3mN+9Xu7@NoqbD+{AyR;2az9S0sKzzrn`}Zs_MY zfYaoA?d=9G~!K!W;SxZsIreb1cK3DfhD^eS@3&=C^Ru zeivA{X%~wv+_c}77H-xCLTlQ2n#p-Ji)>Zo#QOr@N=5r9Jlgk z==58-;pYMiH~d^|;fBu3E!^<4&B6_x*IT&Z=goq1Y|Wpc^DYZF{JhV?4L>(oxS?~a zg&ThEvT#G^s}^qf`L^I3|MO?){J_EuKL=*%@-^WNKSx-&q4QV^H~c)!!VR5MEZp#O zj^JKJWgndjEWAei4dT*41Sm3v`g`4@NI(AF2$e0-xQoSDE^Mf*7+41a!Q z;U@k^E!@Pv!@^Dce-xZHKmJVof3ftp@}8+ztgxS^-c!VNt!3peyUVBvkH}o7oNYiP;8+ytt+|W~F;f9_YE!@!a3&H1G^t@og&TT0EZorZQwulrJS+Gzi=Ka3xS{8$BQ>2SyrE}` zg&TSu`LW>D7Clc{xS{7C7H;Ut|D2}N#AE3BqJj?w8F+@!l$@G2|(O%`s_{jK0jCA=x$w*+5q z#WVH`I$eXCbiX8cofZCi3peThM(}zo-ME&Ti9|B1NG7CoI7Zs>Wz!VNuf3pey6E!@y^)bTpsCS60%IKhJ! zJ>?c|=vipthMoosH}r%p+|YBog&TT)DR{`Dr`y5}J%6%rL(d)yH}niTLG!`HZ|FJR z!VNuN6nu?EPr$+rJxeUy&=a(9Lr>Jg4Lx^RxS?mW;8$Ao?6h!0&l?tQ=-FrCh8~Ys z^T)(*=sCs04LvgizsjO#frT4->MY#QbG3yVdcJAlhMu2VxS^*@@T)C)c3Zfi=Pe62 z^f)JKKA3n6J)gI5L(g~%H}uRFe62;#A`3V4G+Vf#r`^I0J$G2Rq2~b$H}vcfe4Ry4 zkA)k0{$=5Yp1hMZe@r}vo)awG&~t``8+s}Pzs{nk+QJPzZ5D3mxyix}JwLE;L(jt& zZs^%1c-W#RZsCTW4=vo#lYg@2kBP_7bE<_Kdd{+NL(heRuea!Fuy8}qS_?Py+-%{7 zo}XE`p=XPQ8+u+8{057jJr-{0$tlu&FyRe7g%)n;nPB0Do;en7=($wzh(%A(!VNt) zSh%6*I~H!}`IUtmdVX)=hMw01ztN&+pM@KGhK zs}?<1TezWTgM}MTezX;YzsH^ zTx8*fo|S@cu;^*Ga6`{+7H;Ud*TM}wTP@ts^OA)ddfpNI>lQtEr)vHf+|YBZg&TTG zEZopD*TM}wmsz->CnR{(qUR>TZ?fzS_e7B6yn>Pu^%v=PiQI5dSQ3ZxejJ_$$Q~Se?(x z`}yzb^+*QK!%aReFRt`^&i8Vzmae(VaPPy#Im%hMvTzN+#rFo|8iZ>gE*sC0XSr}0 zmSGs4zu4Qq-ne(${Y(PCFO?~$>}zFN19BKN^&6A^TYw{q)W&S?55W#H?xa~-gYz)V zF5l%fjW|XTyKaX#vv_iy__-HYcCg95;Hg8L^oYl((}?tGKk`mfOMhYXUK^h9RL!j@ zv*yhG6rnD-z=u$32O9Rf)MK|EHX5m$3>s$fNU+M5rsk^UYNPO>WB#O&b1#~I=$8-s zu$reRDHhi>)UP!Az;&+sd2!aP%0nk~*oTKp=&&!YtXftF-d$O9=!8?n(}2_AaNJpK z)1kw*)bK#6ej}69pY(?KenV)!d}4sZ<@FO^=B_GMHEg_UXj(p@rnw#t@}mlgJFC1i z)CR60j@N6~dEHE=^0_(>i@UCHDj+r%x6I%HX=8bg5$U+-cea*^ z{@@5wyTP29GrglGV~^SpbLV)A)xlyR9$kkWWHWf;X>Bu{(RkF*)YQ!Iqw#{*J8Ik) zv5U})VBQ++2gc!YDl(@SwanYPqP`igaQA)c>B$I+(?t=|%LC+Cc)a7i+B(XUV5fSq zp%R_i zHa5m-nz{SYi=Uju2YJVsxH~>Q6hnA@*wBr{TU)DCHm34uIhOj=QPtjYXYue_@l73~ z!Xr2QVb7*XKXwuFm6y~LfP_+)CRFlblgSsN9_*8RnMtu>Pt*&XnmOhFS zIpz>GN)w3#2pU-BWcMF)i)ipZY9$j_G1IFyJf>KZLYNmFMkS5IaPd63F_mgt5rd#0;tqjp{j5&@S0W>ziN&E zu&chlwqBo^r$8@%Xw1uaFdp)|bSd)B(CU}=fVBji#^z82;I>@kONR!x(9~Ac)HHLi zGeYPSNUSrtkUrxuf|eew2_C^7(& z>{KP@{vT#UE!l_j|Frim@O2&4z5mF1SawVhkbo%xHgTLNA-0bmmgU4Yk}N3_$hMH> zpb(QISvs~v^f>6@$R$uU|4_NMKzE!)alh1}w{0R&B{OM$9f+Pb%CtMUix z(!gI(XicGTziS?Q@3YT7veVwr{oi{(_~WhL+B0ir)~s2x=CRM7ot_xOzgxZNrj*|2 z{_T-^Nk2B4*tAQl&+Fk7jH5Um%NEk2iI+yy*=W0z>?e42n2|)Egkkg0Z}yHEKOk8V zJA6cVjk!tQ%p=^5wga8h7`Dz!=I@lFU2e!@V4`tYlbF@@h0E-E5X~DmJHm(h+?@7{@>uzQIr+ z-c3T~Gz-hA54MmnbFzR9H8+|U(m!e-i1mZ`M!?u;uj=CrMa|AENDc((O&_z&K>(V< z7p3%3i8#{KyS$AR32_r`_;#;zG(}rCG;G{N=gvPAtkvA&0P^!NTyRzpFWzr524%(! zJ8uxLq)CPcpJpud>3atT2X9mKO->J$VPup3hhP(O`VdEdj+ntotSOCC@5^>UZP=`b zeaNT;i=WTkoHo6AW8XWN!`cHhF+vf4ICLW2jv)NEALky(Fg5Q!;MuFJ9ll|RLK}rufxUG^#F7m-Fhd{w|a+gPC`lF zH(u=WtmURTX}Z3fZ^cFFb36Tv!m)m?jWU=>@x#*k+AtJH{L7K>a;~Y2I1_%a=%^3a z^r=GPL=leA;Y~QR!-E4j3o?^@)Ov4BcyE?$)BbHcNfPAxcCWV9<~mft zeNBybS5VMUB|)Kk1RG0`N21wlXcA!&PQof|SaT>$B&^XDG)xmNVNJj^;Sz2Og;h$4 zS`{Qj$bkd_yKAJbaz|LD)Sob2f5NE$T_RH@RY4(Iro*ba%G040)Kg13#0VUOQd_M| zUE@gNKGj?qP24AmU8qYugb(lMgrUX;Z_74m8g4uSb--3pkKw3NjoZE5+i&+mj8$2T zLN9QUM-1tRAraeEaT_TR&naEEpwX6V8{L2= zNVrV}^4z zLOEUg`RR9N*=+tLB($=@>rY6qX3?FsB~dL62K!bInogM$XZSQ5=_NVZ z71L{`Cs#?w#nT1%DF3cdR3%aFUPob#Tebc5ChWgji@wF%co**Y{O+k$+e9sV?I937 z2JG}^*JX|_=4kPemXw5JwL8Sm{_rH7eN zSX(QpY_z}WpZ(V~gaqkcGsY~|KieV8#j9JZTbRd%z|&u8 zBs7RXme8&1x&#faN%$e1{h3zQzG6VPE7n-8hirZ4{D|M?I*vP9*JbQTGKO>+n^txi zySs3k>o}d27_!TlRt~JxkXqt|GbST3W2ozrNGx-Lpo8i-Ut%4ni}5qY26P!(Vn1Ue zqs!Rcg(Y?w6Nkhu<1RNP6pfkLp_Z7o4EHPA&dG?xHCYntIA3BNrzN&?O;N0$F{I1b z$mlY5cVUTL#ztb7u^X$lnyHs`AKYay`7+^D!VQ+$jKM@JV64L4#kHF;o0M4r;jDZP zH_Vz*J(R@s>u5kY51+&3p#y}&6>FwR(SUFsK8MT0%#Cr%Jmi>30Nu5*$=e+s zdqdNMFi%r>;+TggYjT-~r#YODG*rJ#;~I58Wh@?&aV-?Yz{VoO_1gilNpt7S!cTdZ z&4d(8%R?#Lo$FJQ0zW1h8`3XBLQTJu^fH&0JCm_a;Yhy>m%^0cQkaZo5U^#)2w)|5 z!-lDc9vb{IbP7|3PGNF&DcqfrYMcRalsv2G`gG*V+cDSe;)8D21B;y^CzSAMpKch3 zR%G;N3e>BDy04U}ZVPc7nzwZYUfML2@zBZ{3$ydp=u-y1d{W>#E>n5Ok-yf)%Uq_q z#@$?|o-U^q>*sP>v0jlzmG+M`s^hTrisg_gSGZpBOp*4BXVN(Z^@?XQJ;raZ7$(;m z)>v2I$X_p~<-j~+vx(YeJk#atmD^r1Il0!b_1b;e_KM|*wpTn;q`l&qBK3-AinLb@ zQ>49C;IQo#%W(zua$2TQZEs&8r@#*5nJ!4A(nIiRy zVT!cZ3LLh*VmYp$Ub*eHLQX+@#WP*LUXk`{x@>#JazyJD&lG8|c&12u#WO|f6~h#1 zuN63Kd&P2GLA`R@YlWPG_KIh^e7z#=C6o4*$FEq9XuaZ@BJCB=6lt$`rbxYFm?G`9 z0*7s{SdJ^GS8jW)kWW z<+y@+<+j%fIR)(%&vf~EMcS+Jvh5Yi5v^A|Q>4A(nIi2K&lIUw3{#}NR^YJh70Yo2 z^~!Cp6>?N{y-NF+T_CPAx_tN_zUPHZirwQBMpkwvMNcC3DtoNzS6W*2t z8-{F>^r@JP(8P<$D9FJ*@B9zRlP{YWDGim%-uRR4KL6=oPzcX8_4Zz)*I4@>tZt6x z*;14psrt)kJ`lps!Bz4_=Mb;*|712VQW~q?D^~Q2mQL?W2Sz12t`r^f96>(>aMpY{ zWX+*8Qk}RoK|ADX@x}1x%m1=^X+{$~2^Irfxx7$i*l^LzH4y~_l?gFB$?`MD*ZfNP z^X30yYo5QnP-R@rx4oE}=Vy+u`IYj!nn(FxY|W$TW1G>{yz0f&JU?@M&99W-)jZ1o zVrw2vKd73vdxJ7A-Jq(sd;DO%)Bcd5zrh=VuCDN!aoSaipX>4vz#o&3CS@j zH)rzGD-*{k8;)ay){_c$+~R^G+%A)VyIKlx!2!1p&dob3IKoW@a-L(<>I4##^W-9k z3O!OlF7vD+6dOE4AlB?Ey4XC=Bf`-^YQznv&YnY=BrXhV5anmpHX>Ti%qW|i!on4C z+z}bF=clHzU6_?Y8-Qz{Kn53_J?nHi_?BX2$l?xU(7~?GX3yK?;KIT(gp47atE*Yi zHa6E-860;+23Kb*!){}f;pbenHq1A6D}xJ;=)nbN&$sO$l?z4U?mPe2dk}&(Sr?(>cIs^WN^U|J-FbA9(1s)v(-aZnAL*~isqX!!nmB9r^^x%Rc zdT_xJ8FX+&4_RSW4>l}ThFm>laR+*E!ErJ~^w1ci2OAcZ!39V3;DRH1aKRB7bZ|ru zSz%TWHY`?#Ts>rQ2YPV9aWX{oP!*#G8y1zp1xNJYf+Kox!4VmBa6}JTVO9?|ELMhG zJ!EkQdT_zfeHF`;Grj|?viz>C$ACmgY7Eom3yw+D#fsnt zevie{XA2LLEBKn??ke7el7If2c*7(2al>op?%g?wv__O!P(b>)feZ0TsKZ_JnW&bIovbO$<{lNBOUxPDq1iK(iLi@CF@V}I+u zy+lbxDk^g-BDt;Ia*MZrgg5E$*u9$<$@s46FsC{2?%utrWA}}W_KnHg*t{dp8|U&x zS)*<-e!kf%UtS;OD25k9$47Yy zjyOk#V&xS;HPMVyUqa%aVa4_XLB9zJnkECMSwfKIE4_W-M#ox4e%Hmmzk6V1k;wLQrp~cTzykPNfEPl)4 zKU@5P#Wl4?AL}f>!s4qfUT4v>xY6Qfi`5oyw^(Pf+2UI)?zecC#d|FFTO77{)Z%+A zK4|d+7C&t9w=B+DeAMDo7N4S^T=i7c73;;twqrZnt)1 z@#Pj@WAS>6H(RW-c)P_qi%k~ySnRNPr^UN1_E{XTIA-yFi*iMtCCB;JG7UpovVXO&U2PCnh$WjjZ4m7ma~@c=8`k<@8Rm^ z>ft)X)ypMke9O7T{akYHaGkvxE`vm??N+W`7PnZewz%7(@QTi}|1HU}SNdNxZg-^| z9i>mN;g$c;EK^>I-<&usqkXTu&TSZZ8Q&gGF)}J=1W1BBoIRssDWAt=oXwdw9Gkr6 z`qnlM+|iOS4H!>Nj&smNs`p;fyI3bcG+t!L&UOc91`IJ1*~IZbsa-bP)aWPzGf9!t zlJwj21Ecx`m$8wF(cYA&&ji|NjzQ6K_@`*OTIN*L$veb}M$wAKRd-{J9OSY?OR|fp zI`8iDC3arz=S^GvchG{t2@WnGZeqgS4hpgP7S2cEZ`%Q-h!_T;5O&OsPCe3;{r^g&E=mJ6A1lm!8n zT|!dB6GO>EJ!1pCNja+nUILG@(2&!c205>+^^U#!I+|3gYEx}(>VW)jQ_ZSTwKb~U zE&Q*j;ZIei+TYnB7q|T7zLofWd-l|;`n`?(SNl5lb*QGd61%6fsjIz1?QK$RovN)# z-O;J;Xj1k2_fwW?XzhGk>;9(X-hG`)E=kIjw9(|TufyGRamVFu+xE98E_d6(Etk8k zZzQ8eKcoEz8Wfj{-9yc|+-+m)or=rd?%CIoF;O=v{^CQb0} zeQ>ny-A&+b)y^s;DL0yskoq>!YO~tk`t~M3w2`#*?)v?mqPO;a2dH#gYiCnOeVf`{ zkJ9gG+S}C8y4#@$vv0R*C7ZXkcG47YYiUK9jr&wHYPn-y=RWe;+u6GJK$B`QH96lO$gR)@kqDCpJI^b@0H(L@l5WZX8jAbfbyXtscG7ERpD2rjO%y zrL(cdBG$t#vKSMJmDcz`uTVV`<0FC`WHK;Dw9xiUlED#<`;vRJfD(!$$wpJ-6DE_M zK~_rAeK~tfvXmtiD=XG~5^lRbQKm3uN*6!FQ7*&x_8bw3Ltcf9@FdhhPG{phAvu|d zJ6S9O$j9F-Kg0bY_C12IK6}KV_Ai_}l~Uq#oFpneK8nZWoHP!U!=VL~Y*--W=tQsY zvB*izOmyzfRKeri!qJ{%-rcxL?fz`^JIGe@@KiZNQqRzspYB#~^XAPrQ_{e&97H2W zf^jq2b6?nf5)!DA8{LM&W|yguZs{nj<0C@@y`h?_qay=->d?r@pkg~{6v_1ZRnrs0 z;k&W^kwc_B7ehF_-1in4;N9M71d zpWinymf9p6Mpk4G^POOG`%p>*q$=2N>WGy|>m#=^~KJhk6+ItRqNOa@uS`+dpvvnv(D zcwbb>e>wL{>Y-2xw;==3iVxb%#LGyg4+)OM%7|w&%%4NRbD3Ov(&@ngI)pe08N~ym zK%qz3`<2m`NRd6%VZ#O%@YyBw<j7;q549;<$i-4yW!5h4f9(@SFykl8t{Ew-KEFM4t|(1$KU5Vj@0G8?s|%Mw>RC zTxt;-pYFrE@(2xoFwPm4oLXs5!p4K+nMZmDXm&9$=@sMmjfmIK+@UP=`aOn!jESu4 z?YdG(2!W+>OPhD#L(sOL*k z8Rkn;72Ap!yJRwch3p~kpOd3J0F;A%ub15cnP?lot)+ESxgglLA}4`vn@~D!l!4pT zvqfgJOoa7x)sEgw@fj3{@!{Fwrm2GB?i=W%g>9kI8zSR>9A`>S6+fC%Kb;yK5uf8% zNU|~~MTg`yC8Q>MQz;%<4dCsywa`wkRghG-gkCprV_MV2%FygaIuX>LmdV7+?_U8+ zoSoBQNr{6r?jlH~ml-T3{6pXo%NR2jEnPi}!S*zLe6q~)WwUO8iQZ3RiD5>jz$2rq z%e=94s@F^$sbC;%Hgl+=T6^J~?9)AOY=R>y{Rqq-QJ5Cv9eWOO1olSOQ5dqBrG&bb zZ%ibW1s(L)7+W;D^N(}$aCM`l(Gmo446`P_y;3`}&B9PN$O>GtytQJWf(biK<@ zZ}dVcq&{(7(x(wuXO1Bo4ajUsudw2odo(*!G+9cSb836s{C3#4R0eE`*JG?KQ^V}o ztgora@FM)8b-lE`ug7G-F0J%WSqPX3sdjvJIWQJ!(uhCcNabLHei>djEp-bG=~&th z-WZUpk?MC*;%;uG-YGPzWlQI$s=e^qOkJxqRCAstu2X3b$q?57&+^jzk^GMKw5D;wNl=Vi9F^ao2Ke0u!S4I-QN3d&!a}9XCy65*t ze!Cf76YDAjL9!CoJN=j`^KOyW+=~|du`fLD*DQ9cdu66zuRkbHmgPA!UHv%2&L=Sz z*(B9s%2dz7t>-r~s#i0*;yC z(`7NLbo)jZ{egUD-;4M_4Z0(^9es5#?o`@kyyuAQ8ET`@zX3-i%}EO!9T=H#n;OO< zEO)kN{ktNWK>GEKf&5A>tw8vHcXcNb#wd)>w#IS02?CFobFg&t|G#W6Ezu6GB z55M(eO{?DU-cYzM%#_k8`I=w2E~Xx#1(FD)*Qb;m>Z0tvns1Bfr>NLTAN`Fd0pY+f zyH%0S#B9>&mhKRjA7E1j6Z8ECtsJ}QrvkCHuwovvSaY1@RT<_-dHNb%(e%Il9NA2{*#&pBFt;NWIrFZIdoU*RbY(gpw zUYcEMqbqLr|Hj6L#?=s87X$p9fqrEkR_F}$j8sovNYvY}f=#}_2=Qoc?~*wVeTVgt z5*hrBMJY6P6%fOgy_*#tTSJ>;;(6(~x`#+-=0lNebW=Tf(t&nx8S=A6aX@@MYGPP; z$NFh`iICCcy?h@@ZQ7*XxKnN7|1QOy+PPEhR6BO;RJ(Qw0!nV6Z&N!qDgx9kJJpt* zY9s%5sg1YsU;d~YcdGk$Dt=d>?%Ao{u#+FOzCqp2r&Y_M zKPnzg;Vao=kryctn%%zOTZ-^D?^3t%Uv1c+HmF-MSCP2s5pJ=omwTUx;=ou06dJ z%OCvvm^}67!Hst?WuL(HrzUxWrFUQmSE*;38+-M$utNh!c)2AKmzdl*8E%e)8+&)a zw5f042#+0h`3YGm$&*o+CCLW$S_6LeNo3!iO32)3^e9y`bFwTZv$t%8)?(?R0}Wvb z_VJOi9rs%iJ5`gpmhY?A@=Mg=qXRsZ6x-RQ`0WSpIBo7{dDf?UrXl5bNrsZ<5bwmD zp67z{h1Kyf6U|nNAsAx}fi*+OFJYN)1V0)cAGtR*tnGs@RoyDxjQ!xOz_n_FZcBbN zM}_2Jqr8DcFF-$hjPP)36p8Jm$*i)i(Z~-?^e;l}V^&vhzX$Ur(J_9VdO-2JT7~sN zgZyN2aPWXSz`XE2Uw_x=lA%D&KL1*I`W4D_yD3g(nd@_@?! zl~Ka-_3`@`ek{PtUDi~1z(NZC%99?;v;mzR=@~sF7E1RLS7dvf#6TkI#IT!SN|-{N>we^AUA|%0x`N$i3iPqoLTubG*o~cPN>Z6Nj5IqdZupyMjPbJ;rNo+(v=JONt!9<>Q z_j$K605~f;#BWxI^|K`u?G#6LJ*bjNV!&w4EtkcJqh%a8;TXz3s*wFr5>lc@nQqr^O zHD*C?ZPM7g#L!sUN}Jo0^3&{&dVaRt+_aaUneX1+w12l(H9RtLq@StmkvvRBezV6fsW)uU8kBW`KPwKcfv7So5B4=v-c9emN$qe^Bcr?6 zcpD$>@opCntvjkVIhTowZecU<=%2ybAM6D4!eDV?*RwKbjf*yYIBT!d1o?~86dPTv zm)IU3a{XpN3YGDg?vzaSjN>18&o-rhB?_AwJ2pJtGwGR^Sr`yeHQ)cV9niapmqBj6 z&5kchPZ0bGK``*!?RacfZIS)8jmrFfQn_cWy6!w;$i0CO`MF5wpTGQ@qNqDW4GyVT&L+>^3(Hj zenhW7k}V@|XlY{f?C(dbJ$z48b@0XSdbZ&A(sIv{@rH zf6HRggyCCn@fM4>S?sjWnKeJ1~xTfENVjTRFYUH-S(`!pe#{nsrnTfAg(6@4iDZ=Jn=rA5!;Ef%XS z)>(YB#ZHU&Saf;z+xzW+PuaoLieBg{%SGTO|uK;Ch3ap|JBPO!jfPmQu-WoN%PwVPjxu)D3^ zl@rsfpQ;S^9#h{d>KGr~-IJD_cJm8gRuAgmC9G{^N>ubShkkg zFq0z)SYo|%D6M!*k>vfFK7Aws(T7Kp{7`CqbmUl4FRj&fCBG#R*4y=RP15Xe3peJX zEZaB^EyY6+vw%~op53F-(cXTmw9>E;eiGPOm=L9iR8pqUeB}X|3#|PD6IqU*Ci;Ub!Hd<)4;^6M6QrD_v zFO4uTu3ibH3AG+-gf;pRY%Ix2e{|$NNeefvAR6fzPx9oy_g<4wz0QT|zPCa)FOR4bKGNlP}1 zWgeCrC2b`ZGn~3Fsg34UJcToTa=kh%ol(7-y;>9UQ|!kZvX7@cJ%c=d;3OKM()~T^ zUZ}y5`{b2cuk@Sano8qUJ|xtjSne+fH7wC<#Nv5C#N#U- z1@N;ktoGY#xMz4!WO>(^)b}3Y9v{I6B@K00aW;+)W4lJb!#_TP2K!7H&tOuHA{V@g zu}ae@`ezX-^%l;VXlkpf+$^fUb9cu9PO{k3R8gJK0X^w~O+#awaD1Dv+fBHNfssvv z6`LwH#m0}~f6?y>9G8jaQ;!J;FvnL;#S~5Lu>|(ufSpS7G`i$ z*A=m#s6Z7paJEoMp(<%ul`iOpUcXMQ?_aH6QSdUgE^$@++Vq<4(uI=6qNP>K1*?nH z>W;#Ma2C8|wR%aznnY=Ob$7{v#76RY%{uj({!;RJMQ%PXEmbcay(*ED_lIrXVR_aR zsWkh_X!aknko#W`G4tk#??P86jJyH_nC+bh;0%NufKDPt{u zGFnskT|QFJlaYE}Ridu?@alvsUGuVgQ6PC8%9EGGOP&va>q?8)6|PxD4bmmu#Y=_D z1?_&E@Cfgoc9xf|v z`=uqtrG>?-$RWL|+qPYUZQn4)$slFL={c&8aM^MBgyWsg97;VuN}GiHk!#0rSeOpy z7pAYY{eIH^SH15wh1LV5*LJU2SiNX^K6bNGo%885u71+jJ3@V3?kgkr(fF0_rEUeARY{__ z-S?xeZlbe8F*=Ldv98;-x$U{OM6In1ayB}s%H@mZ7pL!Ny;o|_e0mG($+lIiNE2-< z$@?=g^xt`q{Eh9P?jhB)$7!&^UXo>r4hT7aWm}GoUIlX2JNE9)uMR$qy0tv zZe?Vi;_?jZL$^iDJV%Ge%%f!d`ATT~kv4iDG#2V~x97I44&R;|o+C@lxEZyBd@^6X zT3y}0N|hc8$@kLL>ZOFOITVsHE-as2xUpx$OVx({BK6wIV)d%ydFD3ZxD}Q< zdE~RHaDL9GMf-2GEu;6Y{CqZ}_3`T5I_K*Q@dPYGs|G05FU*2)Nu1%vDoi~Ub zJYeTojyEcc+s+b-G+53bMc1ATzun8-?y=!LoX+^x0wUzS$;W>in^`q7|>-=KI_OR~r@rYeN5ZOBj z>nop3FE%_ZOI#a-%3WQT78dwxsLz_xO`P%-yq-GMxWgTcp;0 z$M(OdTyp=V&^}Hnd%xe|*`ciMJ`Bo!aKZZQJukvku7YeSv>mhAL8 zP0XBAhwsVFONYm->2-L_d_nAX4q3f7^`EYyc{I=xQ zA>96&CuR&-SEAPOdkMEwrS}KJ&wRpph<-b0pM2$s{Q1)AG)Hn})Ztrm!}In1xUpWZ zIlFV$oN;|h>dU&_9~-1EzMM6Q>yr*kR;iN8Rfz(z<7)lfFkRrn9FN5{FD+3o?OUT> zTCL{_>8asTwMy|Tw`8fhzPnVta>(GF(EXu%o1gg|MnirX)<`+m^9~C6%6l!Z?Xo-pQE{uPIg6^l^2rR@YFsYbwjqIrWd!F(>{djM>#|)JrN$+6&h3 zoThSBP>s_gb1m)bo>n z|BE!>bnf116Lew0*Kd1<`f94PJ};|7_!4UPle3exHOUB@3CiZ%ldRv;wOfAzUQ`Ymog-kbI9ULz6TxguA6n5F&`KIT0ns9*6YKfjF*vC&?8 z>bsKi^{lL1v$+oBW6M)G?6odWIZ}^92jo@g>~i^XvMp90ADA7<$CGVjwj|_SQ|+Px zC1f*+xPJM*h!F{dDGZh>)Pb>uy#0Ev4aM_au&Qt$;=U%_HF&$CH)RgF#d@)!V9Tt7@tv4Cur#Y_F`Ws@hhWsH&;mTD@)C*4o6jw(u9e zjb$3%a@$nq?iR0dg0Co5OoS_EZ8Xg9%b7QUFRdxSzs;M#m)<1sZ(|ee*Sa+lg)0!! z=KhwBPOA^i;Y1Fxpztt1=Pn&vJQtzDuriaB z5a!BLB3#nDFP~SKD=V*16`R}8XY1Z1U#G;l%Qsb2ZVlU!jz(}3T~QhC6cX3SaFq0F zA{p{s$ksjeZ8mm$Bz8|dZD2waqzMOBb!$T%D+_Wr(e*sjA&tSzEhxdu>IMa&skG*@lK|0gkY$s;x?FPgLRt zE4EctRaPge6E!qaOjd!Ov$IQ7SJxz}X`BQCCTbJ4)!Qm-s;a7LDrzfg$gMK9siFqK z*2+|egM&POK+}V-o+{uo#&6GMV2IPvcmtw+ExoOEFQZpzN}Lmr%o8F;63!-jdQ771 z0LdmUB%00M&QP{VNfj58l`5Isv!8coWXxhVsL%eqMZYrC_1Ml zlC#2OeBQs06XcRDew9K&ewZ9!c;k)X+hpop-izp^+vjTuB|r%Y>Kj|T zSmb2|x&h1!IqXev4#!1!vm|C<@$_&Vj3j=% zPDgyc^rj#fq9q0u2#b-Q%Z=~MC884zDcjCMBr0p%)ETfgNf2s5v!z&jnQ4p`0_yZe5xNjV;JZ&9JCbCPg~4VHL1 zM;94l%+8tiHn~<*29rxIv>%bEjASZlEK7D~d}X{z%**Cjo!!4ev5C#$Ngj1V7m-4I zZYjy#WEa$iQSi^}*Ll{ayvw?w2+$B|nmDU7+ZWzT+4pda^v*7BaTK8(0$=w{}!?gOtb)+0J-8uOJ`okEro zkp!HSprgw5Zt5*Jdx@-+R75fh^=q=@I|Ikc<>-oAy|K~Wn`Mo}&CPcw-r?=^$|VTW zsJ592tAD^L@0<6@XPTHa_IP*fJ>ZS$^GnR;tv_!iVz(Sy+SaV_jZ3(B>td=k{WWPP&kq!}>FS!uu)owW!HXPYg46nq@3Qd+_ zT-l2>8)%khF0WwaVx!r6k(HZ^ck3Cws`Dmb$|}x}4$2jt?1FtJDMF&NMew7uWf8`R zFp-KU2UC2*FH4?43{so;Y*|DEKPp>}?Bac%f59ggZr=OZPG{1TfjR8DlZIN4ITEFv=aG6#yv5yR*43)EH06=(&< zY|*kAbF;NVx&cz3m&0awa@?)8e9O6Oydfj@Hbq18++>Z7)0W#XzI39BX!8WZNo;N-1+r-k`_Eyrnko=Wm|_~NEz)3FB2`A4 zEnB9T#>*BeXu<=5RC*?=o5k5tTtglR3nmTOyiz+#q~DBjwan>4IzPW*uRO_%ZDA{R zYy&%~^EZuinoa?(Z^X$PXxMQ({l;_q9zr)rNY30=4-1;Fv7D%WZcf%KPT<7Nm%ta8 z`spV?+JnYbE~mBa1EYLBAS}DjdL?4u!}5D#+u>d2NUhl~-`b)=pY^h0Ah7;DN8S-3 zB8ShPUl3o@?m1z+vo(Fx&gb9e)<=F~KZKQwPbZUZM(?KJHmY@RG$GCFCzMAtenPX= z?C}V}tcGK9&{0&-FE=tQ?=C;uGdRH-NrPW9$#5h2BeCiHk=So`q@FAIc}uI-MmVw} z^Or11bBf-u;XqdMnBt?;5izP95wkLh<2WF5n%sr1zfO|J4z4lv7hxKkn!^h!`Cg0( z$}>G<@+Kd@xXk=aKB^XG(UU;?IZBzc>4yzr27iucmIU|7tXSd$Qy4icrxK1F)@$Nh zJq}wuB&X&1AGMVguPOFs??&ig>AY!IE_1Aw{K{u9LMLXF3je0(&=edMI=n{F^OGEkG}UpGzq9Wud{BRw%UuT?RhE z^#b%f_+_q3!UO(UrBdoW&|p!OQrAG2fz@2sLDzvF=j_89pclZ0YKeoM2Y>lCrP`n~ z;HSCzpclb=b|^In-3@l`;y1TKgCF9WhMoqWdlPjLe((oe^U$hJsRY+KXu*HyT9EL1 z!nwXI;o#j|&qH^Ef7_(gSD}}{tD2Qk??ryFj;j<}@FjOBRVLwJ9oG#K4!){Isav5v z@O^LQG*akk(0eO#LnpxJI;acuBG}TY)HrlIct6)e&{N>lok~3{H2Bcl(KYlmxZ!Tn zLnpv?t}jCi4styYod!Sp4&;Yk0I$7AsUJdnVEIRp|7S=Gc7F_+p#^_~s}?!~zTz3` z1MPv2oTCg02TPw-svo)x{1n$X^aA)BpFmdO0l&yK4ZR5dh-(H~eNw5-Tp8#Dc>Sl8 zniCp4@@b`>g-(Ot=lZhne@3YRuCGE*f$e{w)H1Z-&vO+`p$G5;R~hs?_-U^7(2LKZ z=Rf3vUI6R?w?EC@h0)CTgJ@hj8`hQ1<&>r{&u3G3t@ZCQ` zZ_rcVD^-E&5+3k#{N}x1c))++x*vKO+`qa&JqXnr@_x~y&&Nd)>fc?2)zV;X-|PF`+uOpd)`{0Jm_xl+g!EKs-r-CpQ|0Z zZhwJ#=on={PlJ;mLN@3rF!fM@dKfwl{_HOls9E6wt9}XDpzFZzei+%H)h~k&7pUi< z7s2~}g*fOb@SVR(eI6tq@ZY$ugH|&I>KD0gh0cJV<=O$g3|=@>pcPlIhAFHrN)?O@5d0(Bm`47}zG1!@V}1KYof zu7n31<+|p5pJK~@CRJw(CTXi>KDFVpc2s2;PHP%PNBi0-=KY=r@+-O&^FLz z;4ZHFq3ghZ{U+@zJl`r%A6+g`)6fgxv;SP6=7a_x{%(OW{#A{cn2PGUFy?K?I5gOci>nb%5T?Z~ztWxKo1~19x&&L)U@-P`gU)fL;b)vVE0mfi43-e%mV54!sC|;C5t& zo(8Yph1|jeCYn~M`=JGA?pUQBhR%QwwXRZ62tT;Y^>d&6`)LMd&*4H@TjNo(I3i z^@8w#4R1ky=ytHYrBIa~Cx7rjTcIk4?goq73soI-8CW}0sJfu*z<2+4p-Mwfffs+j zP(1{_48HZ*LNy274gNOQGtdiQ$tMcc0(2R8C)auCH2C+6g=!Ic8Ql5Th3W<9Zt&N+ ziatOc!B29PK`($?{C)e^;m`xN4!Nz|&kU(DUF2zf!2$p)=s8zFw&M zp%=iP`bMFeg7(1ie=1Zn&{N>Yzgei}g$Hc?7IH$jgM0tKLUloC@PpqgR9}Uj2H*QH zh3bdUQ(*JIBIgI;0qZXnsvDrY!CSsxsH&k8;LHySRU>o;y!+n^)j{C_dwzr*&}ne} z%Zt>5&>r~TxE_XH0;{emQnS!?;JdCZQsJOa(|CMVITJ;pEPYx8R z=Y= zNL_+%2M?X*oWozB?qKy9}lGBs|$J=oR~*u z=qYfXYY-d*CWvC8Fa!m2i*;J{7#X2MriQ*kE3(w z1o*OZ*fz8W{wvoHq1EpesolRvU4D@~!P`Gkq;7y-0>AJ{xxy!Ym3zsbT?T3x?(jAodEyn^~EX!y$Bxiiq$#jH2BIl6szZ;r@+Y##p-#X z!P{;qRu`d{ZY)-RcT=(YuF&8>d9f;*CM`I_yKrUD88Cet=z&jd?)q@fa{_u`s^)Pf@Yq5Iv?ZxU5=mqfAcOxgX2M%yO2b~5d4;HIM z=qd31@1Q*BY4H8`6st=@gTI@n<;9O6!s)e2hKX|BEwLwpVpPwpL z2cZ|i8-9*5pcCLI*EIAL*zkVp4BZZHJ5FBEbzs2QjWM{m&c;Hy4K`$Bu*OFl)LLYIL*;#&91*xo|1 zTK{S45AA{9`U7+Yy$t^8bH%D1dJ%lh=a5Huz#Be~JkSYn)fbA@ap*Ge(_D`TKd8Ql zu7n5tG}ki{4qpGK=uN`G-o;{d9y$%){Aa~#Ny5SFzFn-Ap*`^U_mJ~p^a*~8>jvm$ z@SpyrSS5r8|MXw6J?KU7=}Ytx=y~v=?-#3n=xK1FutePtEm&Mqq8^4$gOA=;qUMAj z{I5Go)PnGUw=|Tf3(yJhf!!r)8G0K0r9CBloP~A-KfJd@c|wD~a-c-j3Jw0koh7Or zdK!Gs+e%bF^b|PMRl=N_a>2U0O4JOrVB_170lFRhB4?tXgI)xiMoQG8go96VU4)(o z|7N^IeHVHO{J9CvI`{}>f#XM!2YL#8%Y7xP8oC{9xW7cT2@O8V)dxKfzI&=frG+27 z;b%+Kap(m2=Uk6KFM(fsphV3>FN2K_mZcx^(^!sPCB=rlNZ z{c81)(BO3&SF2fQ5B%)r)#_R3MQ|vwT3rwx@OQVaR?E-};6HP%`!C2)vs(4k@-8`a z8l2y=S|y+bzrfW7y$BxOw_0@y4>;bwT6IHDf#2KDJ+$I|^gp}{d4wOFzZ-d=1^?pU zYV{2C68PD7tX2!c1OC!ItJUYBGvFJ#SF7it6X47tZ_|&=_8Z{&VFsRx&e9~ zeD>?e3B3S*2&2zGN0!8o+wUvN!BFM%Jpo%GPt;D>gUs%L}- zU$YB&pgr(=To<61-&Cs3)|IM@(DUGTxGq6=*O#g@Tt&Z0IQUF+saglU0KTE6RNVlb z0FSpKC-gM<&wEQ%9kkk4s#-cqRTp$S_{~o054{XteJ5$4%fQ#)jhxUPSbdN(pzFZb zzN1u~hfaX+<+=dPcR5wfJ;?K0e76$h`<-eXv|ta{HPC(FB-axB4}lr3i_n6<$F&Uo zEchL+OVHm1)7_=&I?@V0z;zJ%LGUA7eb6)D(_Dkl^WZnQ#-Z2ulrpC&RrgCc_>Ww( z&@X^xhf38G(1LeyJp+9Zd>_}d(8s}7^p>jUpsxYPxjqjq_yMjZ=!d`su8Yuu%W^>r z7ICJ-C1}B0xm0G2#(L;d=ml^vg&fd=f5~+nw0F2v-OhCbbU%2K>sIJl@Oxa<(AON{ zyE%MYWe0R0_$jV7=mqeHTwTzDwFBq}dJ6nat~B&l!PmW$Hh`W73-2veQ_w}={2=WP zy$pVbYX-WEb1me|j107(oO97hy#(919)bSJzyGxwpk3<-qoqIO4!zeh+;oKXv9yg{G8UFzn!+vaxabTBF=?KgQSQ z_~zX)b4!5!ZX%y_>}ww#ILh}MkEF(2obdb6P5L`^WZsrKni}*5!ox<#hMy$4 z{f|yPI`ioKqvs!8di2txWsj9VR`*!fW9i3^KbCpy++&N6U3^SEzW(vV<1LSOKR)^R z^y71nFFbzX@#V)$pYWcjeWLw|{wJoMn0aFUiSth^J#p!YvM0-*tb4NS$@G)QpUgaY z?#aa`FFvWBTK`nysg|d@pPGDX`l-367M{BB)bdlMPkT?-KHdJbnr57oCOT1iqU^-_ z6CN5&oTx>MEhpO1WcP`Fv^jZV3XM*mm_e&^C+5-Y!in=}_ri%KG`xJ`5?U@jS%#*) zljUf;_GBFzZ$H_E*85MY`BK$Lo6XJ5Q~UGOe+dm-LI-7Np&UKbp@}YZkwzQG(MJZ2 zoI@vzXyqb$QIC~9wjSLi&`t~b=|)47=x7=(&7r3SG<5-8Eu*bc^yQ(kT6ETq*80)g z6q=hsck^iPJo;NggO|`@8Conyk9BCW3tgts=5h3yL8Ir;=^|Rah+fr`Wlye0w+Xb{ zf_}Tv@FY5(M$2>Pc>zsdK-bG?yA*wUXuKAkx1;rb^ge~=XVCpT+CPu}muP`Yv_ToI zP)1o<$fqB|0FjJOUpDE8I zGIg1jOjo8mlg>q*;5%SpRQtM#8upPV{*{N&8Z%*pwa=T4qKxp;EvfEV?Q;VlAoVs{w`IMS1on1fc%_e4RXIp05XS-+nXD4T; zW~XOoX6I(-XBTGA&t8~anq8i~G+TPQ?6h~f{B-TCEZ* z)8|f~KfQQ*>GZ|ZmrkoQWoOo(DL<1qQ+KB2OxKz2GwCyvXO5qlK9e~!cjnxgg)@t1 zE}Xe|X8DXdTY7f=S?_G(Z0*^Wv+ZZQ&-S04JUexE`s~cvxwG?U7tWqPd*STT+2ymB z&X&%V&3SX>bG37IbM13obNzGaxv9D1b2D=pZ1x;ByNJzR#AX#XyB?cOV6!dQY&SML ziOo)9vvb(&0ycXAn_b3cOR-rGo2|uW+p*bxY<3Epoxx`3vDx$3>=HJ6>9Nws%dpvU zY_<-Y?ZRf$*z9p^HiONc!)6z;*^Ah$!e-ZFvk7dr1)J^0W+$=PX>4{5n_a+WFJQCF z*lZ~_>tVCC*lasC+mFpoVY4&X>^wGm9-CdlW-mQi`cxSY#N(Aj?HGU z*>l+JA~t&wn^oBCdTcg<&9-2(-Pr6THam^Y&SA3)*z5&tc3Et8(b;S%HtS)twb*Ps zHrtQQPGPe%*z7zudmfuz!e%dJO7TMCgKF_W?f9R5ypQ-E@jT*p#OsL95sxGOM!b#q z8u2t~Jp6HddF*?w$x3Y(q5X6Lcl^VsYXHhbw* z>1-J`TaL}vVY6M>Y#N(Aj?HGU*>l+JA~t&wn^oBCdTcg<&9-2(-Pr6THam^Y&SA3) z*z5&tb{U&3#b!NhwicUh$7cJn*(q#x2AiG7X3t}@OW5qCGo@$Cu-S5Kwho)^!e-Oh z>~U;1gUz19W*4#9i`cBfX4hl032e3no9)JCC$ZUSY<3QtUBG59V6)5EY$-PDVY9W^ zY&$mFkIhbDvoqN2JT`kCn_a?YFFjg{r}gl(wRqZgJZ(Rob_!2BgQuOx)1JrEF5zh} z;c3h8wB>l(Iy`L`o;HoAJ&vc%;Azj{X&3Rd7xA>}iBfFV!)9x-*>-HUADf-RW@oV3 zd2IGPHoJt)UV5SwPwU}nYw@)0c-nqE?G&DN22VSWr#+9SUBc5|!qb-FY0L4nb$Hq? zJZ&0JdmK-j!PB0@(=Os^FXCy{)1}y~ht1Yvv+dYyKQ=ps&CX!6^VsZpY<3Boz4WwN zVoj*$7iCy%ITl-o#dcw_X)N|Q7MsCh&tb8PSnNeCR_Sq5M$J0>Y!`kujh{V^pUvQB z&*5hm@v|54vx+ftJ$^QUpOw+E8$UaVpPk0f&f#Yl@Us{2v&;C|Qv9rkpRL8uw&Q2} z@v~F-*%|!oJbv~(es&2zdkH^VhMz6R&(`5*yYRDV{Ooc3Yz9Aj4nMnypS_5mRi{g_ zSPzS>#bVpB*nTW_3X7e=V&}2g^H}T>7JG^LO&Jzjj>Xntv0Yef8jC%S#b&VBb6D&m z7JCtkRaoqLEH;6~wqUW{SnMPgJB`K8VX+HX>;)`#8H+8&Vm&Oj7K?4iV*9b!DJ*sd zi=D^I;xoK8>H^TBM|rWnNo{}A+5+da4K8RayrAu{%Z|ljBjVX)JQh0<@3yG@+ePi+ z6yvhki+H(&_H!-T({*cKH>thdwDxy%+T+PME%vjdE$EWAA@O{k_IeG8zB&2WdOZRq Z7=teAv4aS;R$U|D%bdu_?f;+u{s(#50+0Xz literal 0 HcmV?d00001 diff --git a/Tools/mir/c2m.exe b/Tools/mir/c2m.exe new file mode 100644 index 0000000000000000000000000000000000000000..e4d9ad8664f80bddbf8e53d01d59229537897486 GIT binary patch literal 658432 zcmeFad3;pW-S|HP0R}|wphRP(I@YlUwCQo+uU3Aq>UKv0C#ttd*dMWrwS+%Px^ zaC@DWw%XdKK9;sVt!;f;pVr3$E=<@GTv_UFEm~`592eXmpfcb0=iGZ|34yA8p5OQT z$1g92yPV~o^EsdM+0Qxg^B4L2KA*3GU+G_@^x**ai+Dfm*fqm^_YQvSxK)1hvE!!B zzG8l8?!2qNKJSt%Lo+YA>Z+>~p-V3h&1=0Xbj4Mn*yM9VS6+SD<)?*xzUD@s@3N(X zd^az9?=r9Yoxacc4(T_{=es%J^Ib2kqFu|l531XUdL#G!e7=F|Rq^U;9#ZH;f8UHH zULm(Ext&V9ixhX?sG3&YGT66M?rMhk?ouBb;@erJlAQk{Lws$Aa7(_CC9iwm&i&qC zpVLq$rRK+jearjz&Q*LqEphpx1dpHpw%bqXd#}L=`Ft}@n|IkIiA#LG*eDvek~}AI zUBR{FFXHn>PII#PHjE-+%V3|cn(G>_C4Uj0FMZlvC!^CxVD}j^yu4q&$Z0h-GiQC> z=c|+QA@Tux--mtVn>T;nOp+ArfT7B_udjTU&$*h63YNgsH&iO-TJjh1`Nowz{{OfC zixAM0uUG5VRy|dD&VK}a(N%(~`O0ZG5BAk=?nrC5bXwhdazpic?bvqJifPlG5>Hbi zR4Acad-9dXQRpF=Ivwf6NRkJrWWg7e+>c~Z4yoN`?UX9NcJX@czNUWd>BL)lva7## zY@2+bV$+!S7rda|H%QNSwWnKm=C;j}ztg<$+v7rdvL~=Gq^Ay*d8p5&k#(pGRjW_zf%WGp*5E^gJWhRi!Wa;7&3pMjKt57_Iy)Z@kB~ zUH>Kjq4CrLf9rdueN|PVe0@AH@B4<`7|h+PO;2mXm#(1vY9Ukk%CD&QbpfzdJky`n zBf!T+KM(j;EBu}o)a{2PX>~;9*CfAy_4BIN>s?UxESGLJ)TpGtLZ}RD(`p}s2cQgV ze9-6`9}pNCT?6G(gkeLSDss0|qy+jx*;fnS$yfe_%B2$BnhzWYjCjc}->Twv)DCqU z(z_a}X`WAYum6KmHg|?$J!Wiu!|*>gAvNMZCDpJeIq)4Hj9XU$U%D#b9oAK`LLixc zEODf1&#&_m>L&%}tugHJ!QAt@b*ygRq2N$OP5H_}PKN`k^>4!M4uAnJ(v%ifuNs1? zKp?jCAsp3q>pQul)FF}Zi

4XgP(mz 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


{}N=er{Xg7ZW4RW(@Q#H)1)z9p?W4ObI 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 z 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

  • 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 Tyo3*$e#FQS&urssj3%#+^~P>)yz!z; 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

    n-}J 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 literal 0 HcmV?d00001 diff --git a/Tools/mir/m2b.exe b/Tools/mir/m2b.exe new file mode 100644 index 0000000000000000000000000000000000000000..8a4cf31a2fb0f6336a4053bd70b5761e318ae139 GIT binary patch literal 646656 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"m8qZn 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

    Fk2c5c2kyqa_;RqECh#iOrPA-6sK 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

    q?WDc#_~Gt}liV|pA3i005~+KL;d9>c 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 H{`-Fbr>RH9 literal 0 HcmV?d00001 From 23b788698c4fe81730b011e4b1ed972b4b6529c9 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 18 Oct 2023 23:37:21 +0200 Subject: [PATCH 04/52] Added compile settings --- .clang-format | 2 +- .clang-tidy | 2 +- Apps/CLI/Src/main.cpp | 6 +- Apps/Editor/Src/main.cpp | 6 +- Extern/Pipe | 2 +- Libs/AST/Include/Compiler/CompilerConfig.h | 20 +- Libs/AST/Src/Compiler/CompilerConfig.cpp | 2 +- .../MIR/Compiler/Include/MIRBackendModule.h | 5 + .../MIR/Compiler/Src/IRGeneration.cpp | 45 +-- .../MIR/Compiler/Src/MIRBackendModule.cpp | 320 +++++++++++++++++- Tools/mir/test/test.c | 10 + Tools/mir/test/test.mir | 16 + 12 files changed, 404 insertions(+), 32 deletions(-) create mode 100644 Tools/mir/test/test.c create mode 100644 Tools/mir/test/test.mir diff --git a/.clang-format b/.clang-format index 5035fb7d..ceda188c 100644 --- a/.clang-format +++ b/.clang-format @@ -58,7 +58,7 @@ IndentCaseBlocks: false IndentCaseLabels: true IndentExternBlock: AfterExternBlock IndentGotoLabels: true -IndentPPDirectives: AfterHash +IndentPPDirectives: BeforeHash IndentRequires: true IndentWidth: 4 IndentWrappedFunctionNames: false diff --git a/.clang-tidy b/.clang-tidy index 9241f217..da83db9b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,5 @@ --- -Checks: '-*, readability-identifier-naming, clang-analyzer-*, clang-analyzer-cplusplus*, performance-*, bugprone-*, modernize-*, misc-unused-*,-bugprone-macro-parentheses, -modernize-use-trailing-return-type, -modernize-use-nodiscard, -modernize-use-default-member-init, -modernize-use-equals-default, -performance-unnecessary-value-param, -misc-unused-parameters, -bugprone-branch-clone, -modernize-avoid-c-arrays, -bugprone-easily-swappable-parameters' +Checks: '-*, readability-identifier-naming, clang-analyzer-*, clang-analyzer-cplusplus*, performance-*, bugprone-*, modernize-*, misc-unused-*,-bugprone-macro-parentheses, -modernize-use-trailing-return-type, -modernize-use-nodiscard, -modernize-use-default-member-init, -modernize-use-equals-default, -modernize-raw-string-literal -performance-unnecessary-value-param, -misc-unused-parameters, -bugprone-branch-clone, -modernize-avoid-c-arrays, -bugprone-easily-swappable-parameters' WarningsAsErrors: '' HeaderFilterRegex: 'Corresponding Header' FormatStyle: file diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index 3ae68408..16fa207e 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -68,9 +68,14 @@ int main(int argc, char** argv) EnableModule(); EnableModule(); + CompilerConfig config; + CLI::App app{"Rift compiler"}; String path; app.add_option("-p,--project", path, "Project path")->required(); + app.add_option("-v,--verbose", config.verbose, "Verbose")->required(); + app.add_flag("-O0{0},-O1{1},-O2{2},-O3{3}", config.optimization, "Optimization") + ->expected(0, 3); String selectedBackendStr; @@ -92,7 +97,6 @@ int main(int argc, char** argv) return 1; } - CompilerConfig config; Build(ast, config, backend); while (true) diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index aa944ec5..b51b8923 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -16,7 +16,7 @@ using namespace rift; #ifndef RUN_AS_CLI -# define RUN_AS_CLI 1 + #define RUN_AS_CLI 1 #endif int RunEditor(StringView projectPath) @@ -32,8 +32,8 @@ int RunEditor(StringView projectPath) } #if PLATFORM_WINDOWS && !RUN_AS_CLI -# pragma comment(linker, "/subsystem:windows") -# include + #pragma comment(linker, "/subsystem:windows") + #include int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) { return RunEditor(__argc > 1 ? __argv[1] : StringView{}); diff --git a/Extern/Pipe b/Extern/Pipe index 557dcfa4..faee426e 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 557dcfa4d3689435338d16cd6d10c7ae05a55487 +Subproject commit faee426e87abc22525ea5611f44a0e881164add8 diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index ef91fe6e..8bc94777 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -3,7 +3,9 @@ #pragma once #include "AST/Tree.h" +#include "Pipe/Core/Platform.h" +#include #include #include @@ -12,18 +14,32 @@ namespace rift { using namespace p; + enum class OptimizationLevel : p::u8 + { + Zero = 0, // Only register allocator and machine code generator work + One = 1, // Additional code selection task. On this level more compact and faster code is + // generated than on zero level with practically on the same speed + Two = 2, // (Default) Additional common sub-expression elimination and sparse conditional + // constant propagation. This level is valuable if you generate bad input MIR + // code with a lot of redundancy and constants. The generation speed on level 1 + // is ~50% faster than on level 2 + Three = 3, // Additional register renaming and loop invariant code motion. The generation + // speed on level 2 is ~50% faster than on level 3 + }; struct CompilerConfig : public p::Struct { P_STRUCT(CompilerConfig, p::Struct) - String buildMode{"Release"}; + OptimizationLevel optimization = OptimizationLevel::Two; + + bool verbose = false; Path buildPath; Path intermediatesPath; Path binariesPath; - void Init(AST::Tree& ast); }; } // namespace rift +ENUM(rift::OptimizationLevel); diff --git a/Libs/AST/Src/Compiler/CompilerConfig.cpp b/Libs/AST/Src/Compiler/CompilerConfig.cpp index adb688be..795bd17e 100644 --- a/Libs/AST/Src/Compiler/CompilerConfig.cpp +++ b/Libs/AST/Src/Compiler/CompilerConfig.cpp @@ -11,6 +11,6 @@ namespace rift { buildPath = p::JoinPaths(AST::GetProjectPath(ast), "Build"); intermediatesPath = buildPath / "Intermediates"; - binariesPath = buildPath / buildMode; + binariesPath = buildPath / "Binaries"; } } // namespace rift diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index 44aa8e7a..97099638 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -4,9 +4,11 @@ #include #include +struct MIR_context; namespace rift { + struct Input; class MIRBackendModule : public Module { P_CLASS(MIRBackendModule, Module) @@ -27,5 +29,8 @@ namespace rift } void Build(Compiler& compiler) override; + + protected: + void CToMIR(Compiler& compiler, Input& input, MIR_context* ctx); }; } // namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 4b8ee4f7..619ea8a9 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -226,7 +226,7 @@ namespace rift::MIR inputName, functionName)); } } - Strings::RemoveFromEnd(signature, ", "); + Strings::RemoveFromEnd(signature, ','); } signature.push_back(')'); @@ -293,7 +293,7 @@ namespace rift::MIR const auto& outputs = access.Get(id); const auto& connectedIds = outputs.linkInputNodes; Check(connectedIds.Size() == 2); - const auto& exprInputs = access.Get(id); + const auto& exprInputs = access.Get(id); Check(exprInputs.linkedOutputs.Size() == 1); code->append("if ("); @@ -307,34 +307,37 @@ namespace rift::MIR void CGenerator::AddCall(AST::Id id, const AST::CExprCallId& call) { - /*const AST::Id functionId = call.functionId; + const AST::Id functionId = call.functionId; if (!access.IsValid(functionId)) { - compiler.Error("Call to an unknown function"); - return; + compiler.Error("Call to an unknown function"); + return; } - const auto* function = access.TryGet(functionId); - if (!Ensure(function)) + if (!Ensure(access.Has(functionId))) { - compiler.Error(Strings::Format( - "Call to an invalid function: '{}'", AST::GetName(access, functionId))); - return; + compiler.Error(Strings::Format( + "Call to an invalid function: '{}'", AST::GetName(access, functionId))); + return; } - TArray args; if (auto* inputs = access.TryGet(id)) { - args.Reserve(inputs->linkedOutputs.Size()); - for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) - { - AST::ExprOutput output = inputs->linkedOutputs[i]; - if (!output.IsNone()) - { - args.Add(AddExpr(gen, access, output)); - } - } + for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) + { + AST::ExprOutput output = inputs->linkedOutputs[i]; + if (!output.IsNone()) + { + AddExpr(output); + code->push_back(','); + } + else + { + // TODO: Error? or assign default value? + } + } + Strings::RemoveFromEnd(*code, ", "); } - builder.CreateCall(function->instance, ToLLVM(args));*/ + code->push_back(')'); } void CGenerator::CreateMain(AST::Id functionId) diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 0c51fc83..6221a653 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -2,25 +2,295 @@ #include "MIRBackendModule.h" +#include "Compiler/CompilerConfig.h" + #include +#include +#include #include #include #include #include +#include +#include +#include + + +#ifndef _WIN32 + #include + #if defined(__unix__) || defined(__APPLE__) + #include + #endif +#else + #define WIN32_LEAN_AND_MEAN + #include +#endif namespace rift { + struct Lib + { + char* name = nullptr; + void* handler = nullptr; + }; + + struct Input + { + const char* name = nullptr; + p::u8* currentChar = nullptr; + p::TArray code; + struct c2mir_options options; + }; + + + // clang-format off + static Lib gStdLibs[] { + #if defined(_WIN32) + {"C:\\Windows\\System32\\msvcrt.dll"}, + {"C:\\Windows\\System32\\kernel32.dll"}, + {"C:\\Windows\\System32\\ucrtbase.dll"}, + #elif defined(__APPLE__) + {"/usr/lib/libc.dylib"}, + {"/usr/lib/libm.dylib"}, + #elif defined(__unix__) + #if UINTPTR_MAX == 0xffffffff + {"/lib/libc.so.6"}, + {"/lib32/libc.so.6"}, + {"/lib/libm.so.6"}, + {"/lib32/libm.so.6"}, + {"/lib/libpthread.so.0"}, + {"/lib32/libpthread.so.0"}, + #elif UINTPTR_MAX == 0xffffffffffffffff + #if defined(__x86_64__) + {"/lib64/libc.so.6"}, + {"/lib/x86_64-linux-gnu/libc.so.6"}, + {"/lib64/libm.so.6"}, + {"/lib/x86_64-linux-gnu/libm.so.6"}, + {"/usr/lib64/libpthread.so.0"}, + {"/lib/x86_64-linux-gnu/libpthread.so.0"}, + {"/usr/lib/libc.so"}, + #elif (__aarch64__) + {"/lib64/libc.so.6"}, {"/lib/aarch64-linux-gnu/libc.so.6"}, + {"/lib64/libm.so.6"}, + {"/lib/aarch64-linux-gnu/libm.so.6"}, + {"/lib64/libpthread.so.0"}, + {"/lib/aarch64-linux-gnu/libpthread.so.0"}, + #elif (__PPC64__) + {"/lib64/libc.so.6"}, + {"/lib64/libm.so.6"}, + {"/lib64/libpthread.so.0"}, + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + {"/lib/powerpc64le-linux-gnu/libc.so.6"}, + {"/lib/powerpc64le-linux-gnu/libm.so.6"}, + {"/lib/powerpc64le-linux-gnu/libpthread.so.0"}, + #else + {"/lib/powerpc64-linux-gnu/libc.so.6"}, + {"/lib/powerpc64-linux-gnu/libm.so.6"}, + {"/lib/powerpc64-linux-gnu/libpthread.so.0"}, + #endif + #elif (__s390x__) + {"/lib64/libc.so.6"}, + {"/lib/s390x-linux-gnu/libc.so.6"}, + {"/lib64/libm.so.6"}, + {"/lib/s390x-linux-gnu/libm.so.6"}, + {"/lib64/libpthread.so.0"}, + {"/lib/s390x-linux-gnu/libpthread.so.0"}, + #elif (__riscv) + {"/lib64/libc.so.6"}, + {"/lib/riscv64-linux-gnu/libc.so.6"}, + {"/lib64/libm.so.6"}, + {"/lib/riscv64-linux-gnu/libm.so.6"}, + {"/lib64/libpthread.so.0"}, + {"/lib/riscv64-linux-gnu/libpthread.so.0"}, + #else + #error Cannot recognize 32- or 64-bit target + #endif + #endif + #endif + }; + + #if defined(__unix__) + static const char* gStdLibDirs[] + { + #if UINTPTR_MAX == 0xffffffff + "/lib", + "/lib32" + #elif UINTPTR_MAX == 0xffffffffffffffff + #if defined(__x86_64__) + "/lib64", + "/lib/x86_64-linux-gnu" + #elif (__aarch64__) + "/lib64", + "/lib/aarch64-linux-gnu" + #elif (__PPC64__) + "/lib64", + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + "/lib/powerpc64le-linux-gnu", + #else + "/lib/powerpc64-linux-gnu", + #endif + #elif (__s390x__) + "/lib64", + "/lib/s390x-linux-gnu" + #elif (__riscv) + "/lib64", + "/lib/riscv64-linux-gnu" + #endif + #endif + }; + static const char* gLibSuffix = ".so"; + #elif defined(__APPLE__) + static const char* gStdLibDirs[]{"/usr/lib"}; + static const char* gLibSuffix = ".dylib"; + #elif defined(_WIN32) + static const char* gStdLibDirs[]{"C:\\Windows\\System32"}; + static const char* gLibSuffix = ".dll"; + #define dlopen(n, f) LoadLibrary(n) + #define dlclose(h) FreeLibrary(HMODULE(h)) + #define dlsym(h, s) GetProcAddress(HMODULE(h), s) + #endif + // clang-format on + + + static void OpenSTDLibs() + { + for (Lib& stdLib : gStdLibs) + { + stdLib.handler = dlopen(stdLib.name, RTLD_LAZY); + } + } + + static void CloseSTDLibs() + { + for (Lib& stdLib : gStdLibs) + { + if (stdLib.handler) + { + dlclose(stdLib.handler); + } + } + } + + static void* ImportResolver(const char* name) + { + void *handler, *sym = nullptr; + + for (Lib& stdLib : gStdLibs) + { + handler = stdLib.handler; + if (handler) + { + sym = dlsym(handler, name); + if (sym) + { + break; + } + } + } + + if (sym == nullptr) + { +#ifdef _WIN32 + if (strcmp(name, "LoadLibrary") == 0) + return LoadLibrary; + if (strcmp(name, "FreeLibrary") == 0) + return FreeLibrary; + if (strcmp(name, "GetProcAddress") == 0) + return GetProcAddress; +#else + if (strcmp(name, "dlopen") == 0) + return dlopen; + if (strcmp(name, "dlerror") == 0) + return dlerror; + if (strcmp(name, "dlclose") == 0) + return dlclose; + if (strcmp(name, "dlsym") == 0) + return dlsym; + if (strcmp(name, "stat") == 0) + return stat; + if (strcmp(name, "lstat") == 0) + return lstat; + if (strcmp(name, "fstat") == 0) + return fstat; + #if defined(__APPLE__) && defined(__aarch64__) + if (strcmp(name, "__nan") == 0) + return __nan; + if (strcmp(name, "_MIR_set_code") == 0) + return _MIR_set_code; + #endif +#endif + fprintf(stderr, "can not load symbol %s\n", name); + CloseSTDLibs(); + exit(1); + } + return sym; + } + + MIRBackendModule::MIRBackendModule() { AddDependency(); } + using EntryFunctionPtr = p::i32 (*)(); void MIRBackend::Build(Compiler& compiler) { ZoneScopedN("Backend: MIR"); - MIR_context_t ctx = MIR_init(); + MIR_context* ctx = MIR_init(); + c2mir_init(ctx); + + c2mir_options options; + + + p::i32 nGen = 1; + MIR_item_t func, mainFunc = nullptr; + + { // Find main + for (MIR_module_t module = DLIST_HEAD(MIR_module_t, *MIR_get_module_list(ctx)); + module != nullptr; module = DLIST_NEXT(MIR_module_t, module)) + { + for (func = DLIST_HEAD(MIR_item_t, module->items); func != nullptr; + func = DLIST_NEXT(MIR_item_t, func)) + { + if (func->item_type == MIR_func_item && strcmp(func->u.func->name, "main") == 0) + { + mainFunc = func; + } + } + MIR_load_module(ctx, module); + } + } + + OpenSTDLibs(); + MIR_gen_init(ctx, nGen); + for (p::i32 i = 0; i < nGen; ++i) + { + if (compiler.config.optimization != OptimizationLevel::Zero) + { + MIR_gen_set_optimize_level(ctx, i, (unsigned)compiler.config.optimization); + } + // if (gen_debug_level >= 0) + //{ + // MIR_gen_set_debug_file(ctx, i, stderr); + // MIR_gen_set_debug_level(ctx, i, gen_debug_level); + // } + } + MIR_link( + ctx, nGen > 1 ? MIR_set_parallel_gen_interface : MIR_set_gen_interface, ImportResolver); + + auto entry = EntryFunctionPtr(nGen > 1 ? MIR_gen(ctx, 0, mainFunc) : mainFunc->addr); + + p::DateTime startTime = p::DateTime::Now(); + p::i32 resultCode = entry(); // Run! + if (compiler.config.verbose) + { + p::Info(" execution -- {:.3f}s\n", + (p::DateTime::Now() - startTime).GetTotalSeconds()); + p::Info("exit code: {}\n", resultCode); + } + MIR_gen_finish(ctx); if (!compiler.HasErrors()) { @@ -31,6 +301,54 @@ namespace rift p::Info("Build failed: {} errors", compiler.GetErrors().Size()); } + CloseSTDLibs(); + c2mir_finish(ctx); MIR_finish(ctx); } + + void MIRBackend::CToMIR(Compiler& compiler, Input& input, MIR_context* ctx) + { + auto getc = [](void* data) -> p::u8 { + Input* input = static_cast(data); + if (input->currentChar < input->code.EndData()) + { + return *(input->currentChar++); + } + return EOF; + }; + + if (!c2mir_compile(ctx, &input.options, getc, &input, input.input_name, nullptr)) + { + compiler.Error("C to MIR compilation failed"); + } + } + + void InitCToMIROptions(c2mir_options& options) + { + int incl_p, ldir_p = FALSE; /* to remove an uninitialized warning */ + + options.message_file = stderr; + options.debug_p = options.verbose_p = options.ignore_warnings_p = FALSE; + options.asm_p = options.object_p = options.no_prepro_p = options.prepro_only_p = FALSE; + options.syntax_only_p = options.pedantic_p = FALSE; + curr_input.code = NULL; + else if ((incl_p = strncmp(argv[i], "-I", 2) == 0) + || (ldir_p = strncmp(argv[i], "-L", 2) == 0) || strncmp(argv[i], "-l", 2) == 0) + { + char* arg; + const char* dir = strlen(argv[i]) == 2 && i + 1 < argc ? argv[++i] : argv[i] + 2; + + if (*dir == '\0') + continue; + arg = reg_malloc(strlen(dir) + 1); + strcpy(arg, dir); + if (incl_p || ldir_p) + VARR_PUSH(char_ptr_t, incl_p ? headers : lib_dirs, arg); + else + process_cmdline_lib(arg); + } + + options.options.macro_commands = nullptr; + options.macro_commands_num = 0; + } } // namespace rift \ No newline at end of file diff --git a/Tools/mir/test/test.c b/Tools/mir/test/test.c new file mode 100644 index 00000000..b38f78ff --- /dev/null +++ b/Tools/mir/test/test.c @@ -0,0 +1,10 @@ + +#include + +void main() +{ + bool a = true; + int q = sizeof(int); + int nn = 2433; + printf("%i", q + nn); +} diff --git a/Tools/mir/test/test.mir b/Tools/mir/test/test.mir new file mode 100644 index 00000000..8d578ddd --- /dev/null +++ b/Tools/mir/test/test.mir @@ -0,0 +1,16 @@ +M0: module +proto0: proto i32, ... + import printf +main: func + local i64:u0_a, i64:I_0, i64:i0_q, i64:i0_nn, i64:i_1, i64:i_2 +# 0 args, 6 locals + uext8 I_0, 1 + mov u0_a, I_0 + mov i0_q, 4 + mov i0_nn, 2433 + adds i_2, i0_q, i0_nn + call proto0, printf, i_1, "%i\000", i_2 + ret + endfunc + export main + endmodule From fcc52b46c467893fe471a689e710114e000a25bf Mon Sep 17 00:00:00 2001 From: muit Date: Fri, 20 Oct 2023 16:40:35 +0200 Subject: [PATCH 05/52] Updated Pipe 1/2 --- Apps/CLI/Src/main.cpp | 5 +-- Apps/Editor/Src/main.cpp | 2 +- Extern/CMakeLists.txt | 8 +--- Extern/Pipe | 2 +- .../AST/Components/CExprBinaryOperator.h | 3 -- Libs/AST/Include/AST/Components/CExprInputs.h | 3 +- .../AST/Include/AST/Components/CExprOutputs.h | 3 +- .../Include/AST/Components/CLiteralFloating.h | 2 - .../Include/AST/Components/CLiteralIntegral.h | 2 - Libs/AST/Include/AST/Components/CNamespace.h | 2 +- .../AST/Include/AST/Components/CStmtOutputs.h | 3 -- .../AST/Components/Views/CNodePosition.h | 3 +- Libs/AST/Include/AST/Id.h | 3 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 2 - Libs/AST/Include/AST/Statics/STypes.h | 2 - .../AST/Include/AST/Systems/FunctionsSystem.h | 4 +- Libs/AST/Include/AST/Systems/LoadSystem.h | 4 +- Libs/AST/Include/AST/Systems/TypeSystem.h | 2 +- Libs/AST/Include/AST/Tree.h | 2 +- Libs/AST/Include/AST/Utils/Expressions.h | 4 +- Libs/AST/Include/AST/Utils/ModuleUtils.h | 6 +-- Libs/AST/Include/AST/Utils/Namespaces.h | 4 +- Libs/AST/Include/AST/Utils/Statements.h | 4 +- Libs/AST/Include/AST/Utils/TransactionUtils.h | 2 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 2 +- Libs/AST/Include/Compiler/Compiler.h | 1 - Libs/AST/Include/Rift.h | 3 +- Libs/AST/Src/AST/Components/CNamespace.cpp | 2 +- Libs/AST/Src/AST/Systems/FunctionsSystem.cpp | 12 +++--- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 17 +------- Libs/AST/Src/AST/Systems/TypeSystem.cpp | 4 +- Libs/AST/Src/AST/Tree.cpp | 2 +- Libs/AST/Src/AST/Utils/Expressions.cpp | 4 +- Libs/AST/Src/AST/Utils/ModuleUtils.cpp | 5 +-- Libs/AST/Src/AST/Utils/Namespaces.cpp | 10 ++--- Libs/AST/Src/AST/Utils/Statements.cpp | 4 +- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 4 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 43 ++++++++----------- Libs/AST/Src/Compiler/Compiler.cpp | 3 -- Libs/Backends/MIR/CMakeLists.txt | 2 +- .../MIR/Compiler/Src/IRGeneration.cpp | 18 +++----- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 2 +- .../MIR/Compiler/Src/MIRBackendModule.cpp | 35 ++++----------- .../Compiler/Src/NativeBindingModule.cpp | 4 +- Libs/Editor/Include/Editor.h | 2 +- .../Editor/Include/Panels/FileExplorerPanel.h | 4 +- Libs/Editor/Include/Statics/SEditor.h | 4 -- Libs/Editor/Include/Tools/ASTDebugger.h | 4 +- .../Include/Tools/BigBestFitArenaDebugger.h | 3 +- Libs/Editor/Include/Tools/MemoryDebugger.h | 3 +- Libs/Editor/Include/Utils/DetailsPanel.h | 2 +- Libs/Editor/Include/Utils/EditorStyle.h | 3 +- Libs/Editor/Include/Utils/ElementsPanel.h | 2 +- Libs/Editor/Include/Utils/FunctionGraph.h | 2 +- .../Include/Utils/FunctionGraphContextMenu.h | 2 +- Libs/Editor/Include/Utils/Nodes.h | 6 +-- Libs/Editor/Include/Utils/NodesInternal.h | 4 +- Libs/Editor/Include/Utils/NodesMiniMap.h | 2 +- Libs/Editor/Include/Utils/TypeUtils.h | 2 +- Libs/Editor/Include/Utils/Widgets.h | 2 +- Libs/Editor/Src/Editor.cpp | 2 - Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 8 +--- Libs/Editor/Src/Systems/EditorSystem.cpp | 18 ++------ Libs/Editor/Src/Tools/ASTDebugger.cpp | 8 ++-- .../Src/Tools/BigBestFitArenaDebugger.cpp | 10 ++--- Libs/Editor/Src/Tools/MemoryDebugger.cpp | 6 +-- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 3 -- Libs/Editor/Src/Utils/DetailsPanel.cpp | 2 +- Libs/Editor/Src/Utils/ElementsPanel.cpp | 8 ++-- Libs/Editor/Src/Utils/FunctionGraph.cpp | 12 +++--- .../Src/Utils/FunctionGraphContextMenu.cpp | 4 +- Libs/Editor/Src/Utils/Nodes.cpp | 6 +-- Libs/Editor/Src/Utils/NodesMiniMap.cpp | 6 +-- Libs/Editor/Src/Utils/ProjectManager.cpp | 4 +- Libs/Editor/Src/Utils/TypeUtils.cpp | 2 +- Libs/UI/Include/UI/Style.h | 2 +- Libs/UI/Include/UI/UIImgui.h | 18 ++++---- Libs/UI/Src/Inspection.cpp | 2 +- Libs/UI/Src/Notify.cpp | 5 +-- Libs/UI/Src/Style.cpp | 10 ++--- Libs/UI/Src/Widgets.cpp | 7 ++- Libs/UI/Src/Window.cpp | 10 ++--- Tests/AST/Namespaces.spec.cpp | 9 ++-- Tests/main.cpp | 2 +- 84 files changed, 181 insertions(+), 284 deletions(-) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index 16fa207e..66825851 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -9,9 +9,8 @@ #include #include #include -#include +#include #include -#include #include #include @@ -86,8 +85,6 @@ int main(int argc, char** argv) TPtr backend = FindBackendByName(availableBackends, Tag(selectedBackendStr)); - ZoneScopedNC("CLI Execution", 0x459bd1); - AST::Tree ast; AST::OpenProject(ast, path); diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index b51b8923..58c4925b 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include diff --git a/Extern/CMakeLists.txt b/Extern/CMakeLists.txt index 5852bbf2..1512a4ce 100644 --- a/Extern/CMakeLists.txt +++ b/Extern/CMakeLists.txt @@ -56,7 +56,8 @@ include(FindThreads) if(Threads_FOUND) link_libraries(${CMAKE_THREAD_LIBS_INIT}) endif() -add_library(mir OBJECT mir/mir.c mir/mir-gen.c mir/c2mir/c2mir.c mir/mir.h mir/mir-gen.h mir/c2mir/c2mir.h) +add_library(mir STATIC) +target_sources(mir PRIVATE mir/mir.c mir/mir-gen.c mir/c2mir/c2mir.c) target_include_directories(mir PUBLIC mir) if(Threads_FOUND) target_compile_definitions(mir PUBLIC "MIR_PARALLEL_GEN") @@ -80,8 +81,3 @@ if(CMAKE_COMPILER_IS_GNUCC) target_compile_options(mir PRIVATE -fno-ipa-cp-clone) endif() endif() - -# ------------------ LIBMIR ----------------------- -add_library(mir_static STATIC) -target_link_libraries(mir_static PRIVATE mir) -target_include_directories(mir_static PUBLIC mir) diff --git a/Extern/Pipe b/Extern/Pipe index faee426e..bb80d9a2 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit faee426e87abc22525ea5611f44a0e881164add8 +Subproject commit bb80d9a2890be0bdda7778e758f5c1f850bd2cf5 diff --git a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h b/Libs/AST/Include/AST/Components/CExprBinaryOperator.h index 997d138e..9bea5616 100644 --- a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h +++ b/Libs/AST/Include/AST/Components/CExprBinaryOperator.h @@ -8,9 +8,6 @@ namespace rift::AST { - using namespace p::core; - - enum class BinaryOperatorType : u8 { // Mathematic diff --git a/Libs/AST/Include/AST/Components/CExprInputs.h b/Libs/AST/Include/AST/Components/CExprInputs.h index b58ed241..a2e61b66 100644 --- a/Libs/AST/Include/AST/Components/CExprInputs.h +++ b/Libs/AST/Include/AST/Components/CExprInputs.h @@ -3,8 +3,9 @@ #include "AST/Id.h" -#include #include +#include + namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprOutputs.h b/Libs/AST/Include/AST/Components/CExprOutputs.h index d3d855b4..c273e0e8 100644 --- a/Libs/AST/Include/AST/Components/CExprOutputs.h +++ b/Libs/AST/Include/AST/Components/CExprOutputs.h @@ -3,8 +3,9 @@ #include "AST/Id.h" -#include #include +#include + namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralFloating.h b/Libs/AST/Include/AST/Components/CLiteralFloating.h index 751d04b5..372e0cc2 100644 --- a/Libs/AST/Include/AST/Components/CLiteralFloating.h +++ b/Libs/AST/Include/AST/Components/CLiteralFloating.h @@ -9,8 +9,6 @@ namespace rift::AST { - using namespace p::core; - enum class FloatingType : u8 { F32 = 32, diff --git a/Libs/AST/Include/AST/Components/CLiteralIntegral.h b/Libs/AST/Include/AST/Components/CLiteralIntegral.h index be10d5d0..b219d4fb 100644 --- a/Libs/AST/Include/AST/Components/CLiteralIntegral.h +++ b/Libs/AST/Include/AST/Components/CLiteralIntegral.h @@ -9,8 +9,6 @@ namespace rift::AST { - using namespace p::core; - static constexpr u8 literalUnsignedMask = 1 << 7; // Last bit marks type as unsigned enum class IntegralType : u8 diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index ee91ace3..a51ee271 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -57,7 +57,7 @@ namespace rift::AST Namespace(const p::String& value) : Namespace(p::StringView{value}) {} Namespace(std::initializer_list values) { - const p::i32 size = p::math::Min(p::i32(values.size()), scopeCount); + const p::i32 size = p::Min(p::i32(values.size()), scopeCount); for (p::i32 i = 0; i < size; ++i) { scopes[i] = *(values.begin() + i); diff --git a/Libs/AST/Include/AST/Components/CStmtOutputs.h b/Libs/AST/Include/AST/Components/CStmtOutputs.h index 7373ca7c..ec248698 100644 --- a/Libs/AST/Include/AST/Components/CStmtOutputs.h +++ b/Libs/AST/Include/AST/Components/CStmtOutputs.h @@ -9,9 +9,6 @@ namespace rift::AST { - using namespace p::core; - - struct CStmtOutput : public p::Struct { P_STRUCT(CStmtOutput, p::Struct) diff --git a/Libs/AST/Include/AST/Components/Views/CNodePosition.h b/Libs/AST/Include/AST/Components/Views/CNodePosition.h index e167191d..93e5bb5f 100644 --- a/Libs/AST/Include/AST/Components/Views/CNodePosition.h +++ b/Libs/AST/Include/AST/Components/Views/CNodePosition.h @@ -1,8 +1,9 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include #include +#include + namespace rift diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index a5608684..aeef6e47 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -2,10 +2,9 @@ #pragma once #include -#include -#include #include #include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index 0e1d9028..087b09b4 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -10,8 +10,6 @@ namespace rift::AST { - using namespace p::core; - // Contains loaded string data from disk struct SStringLoad : public Struct { diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index c3e5a5f4..e81d837e 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -9,8 +9,6 @@ namespace rift::AST { - using namespace p::core; - struct STypes : public Struct { P_STRUCT(STypes, Struct) diff --git a/Libs/AST/Include/AST/Systems/FunctionsSystem.h b/Libs/AST/Include/AST/Systems/FunctionsSystem.h index 5b1abd14..fa62abdd 100644 --- a/Libs/AST/Include/AST/Systems/FunctionsSystem.h +++ b/Libs/AST/Include/AST/Systems/FunctionsSystem.h @@ -9,8 +9,8 @@ #include "AST/Components/Tags/CInvalid.h" #include "AST/Tree.h" -#include -#include +#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Systems/LoadSystem.h b/Libs/AST/Include/AST/Systems/LoadSystem.h index 99f7c698..8586345d 100644 --- a/Libs/AST/Include/AST/Systems/LoadSystem.h +++ b/Libs/AST/Include/AST/Systems/LoadSystem.h @@ -4,8 +4,8 @@ #include "AST/Components/CFileRef.h" #include "AST/Tree.h" -#include -#include +#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Systems/TypeSystem.h b/Libs/AST/Include/AST/Systems/TypeSystem.h index 09533dd5..1793e15e 100644 --- a/Libs/AST/Include/AST/Systems/TypeSystem.h +++ b/Libs/AST/Include/AST/Systems/TypeSystem.h @@ -11,7 +11,7 @@ #include "AST/Components/CExprUnaryOperator.h" #include "AST/Components/Tags/CChanged.h" -#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index 28b08617..f00103ab 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -6,7 +6,7 @@ #include #include -#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Utils/Expressions.h b/Libs/AST/Include/AST/Utils/Expressions.h index d74dcc1e..6f91b633 100644 --- a/Libs/AST/Include/AST/Utils/Expressions.h +++ b/Libs/AST/Include/AST/Utils/Expressions.h @@ -8,8 +8,8 @@ #include "AST/Id.h" #include "AST/Tree.h" -#include -#include +#include +#include // NOTE: In expression graphs, the Link Id is the Input Pin Id diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index 22fb89ba..dc20eae8 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -8,7 +8,7 @@ #include "AST/Tree.h" #include -#include +#include namespace rift::AST @@ -38,10 +38,6 @@ namespace rift::AST } }; - - using namespace p::core; - using namespace p::files; - bool CreateProject(Tree& ast, StringView path); bool OpenProject(Tree& ast, StringView path); void CloseProject(Tree& ast); diff --git a/Libs/AST/Include/AST/Utils/Namespaces.h b/Libs/AST/Include/AST/Utils/Namespaces.h index 40695071..5a00c908 100644 --- a/Libs/AST/Include/AST/Utils/Namespaces.h +++ b/Libs/AST/Include/AST/Utils/Namespaces.h @@ -6,9 +6,9 @@ #include "AST/Id.h" #include -#include -#include #include +#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Utils/Statements.h b/Libs/AST/Include/AST/Utils/Statements.h index 8dbac2d0..ff87d54b 100644 --- a/Libs/AST/Include/AST/Utils/Statements.h +++ b/Libs/AST/Include/AST/Utils/Statements.h @@ -7,8 +7,8 @@ #include "AST/Tree.h" #include "AST/Utils/Statements.h" -#include -#include +#include +#include // NOTE: In statement graphs, the Link Id is the Input Node Id diff --git a/Libs/AST/Include/AST/Utils/TransactionUtils.h b/Libs/AST/Include/AST/Utils/TransactionUtils.h index 80d722a6..e256177d 100644 --- a/Libs/AST/Include/AST/Utils/TransactionUtils.h +++ b/Libs/AST/Include/AST/Utils/TransactionUtils.h @@ -6,7 +6,7 @@ #include "AST/Components/Tags/CChanged.h" #include "AST/Components/Tags/CDirty.h" -#include +#include namespace rift::AST diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index 8245c285..13af9345 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -18,7 +18,7 @@ #include "AST/Tree.h" #include "AST/TypeRef.h" -#include +#include namespace rift::AST diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index e1e0b2b6..77f94ddb 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -4,7 +4,6 @@ #include "Compiler/CompilerConfig.h" -#include #include #include #include diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index c37ce9e6..ec27dc81 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -8,9 +8,10 @@ #include "View.h" #include -#include #include #include +#include + namespace rift diff --git a/Libs/AST/Src/AST/Components/CNamespace.cpp b/Libs/AST/Src/AST/Components/CNamespace.cpp index d8154c07..db14e002 100644 --- a/Libs/AST/Src/AST/Components/CNamespace.cpp +++ b/Libs/AST/Src/AST/Components/CNamespace.cpp @@ -104,7 +104,7 @@ namespace rift::AST { p::u32 size = 0; ct.BeginArray(size); - size = p::math::Min(size, p::u32(Namespace::scopeCount)); + size = p::Min(size, p::u32(Namespace::scopeCount)); for (p::u32 i = 0; i < size; ++i) { ct.Next(scopes[i]); diff --git a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp index 10ea7fb7..8a0e2179 100644 --- a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp +++ b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp @@ -10,7 +10,7 @@ #include "AST/Utils/Namespaces.h" #include "AST/Utils/TypeUtils.h" -#include +#include namespace rift::AST::FunctionsSystem @@ -169,7 +169,7 @@ namespace rift::AST::FunctionsSystem { Id id = ast.Create(); access.Add(id, *name); - p::Attach(ast, call.id, id); + p::AttachId(ast, call.id, id); callOutputs.Add(id); } else @@ -188,7 +188,7 @@ namespace rift::AST::FunctionsSystem { Id id = ast.Create(); access.Add(id, *name); - p::Attach(ast, call.id, id); + p::AttachId(ast, call.id, id); callOutputs.Insert(i, id); } else if (callPinIdx > i) @@ -240,7 +240,7 @@ namespace rift::AST::FunctionsSystem { Id id = ast.Create(); access.Add(id, *name); - p::Attach(ast, call.id, id); + p::AttachId(ast, call.id, id); callInputs.Add(id); } else @@ -259,7 +259,7 @@ namespace rift::AST::FunctionsSystem { Id id = ast.Create(); access.Add(id, *name); - p::Attach(ast, call.id, id); + p::AttachId(ast, call.id, id); callInputs.Insert(i, id); } else if (callPinIdx > i) @@ -329,7 +329,7 @@ namespace rift::AST::FunctionsSystem TArray pinsToRemove = FindAllIdsWith(access); ExcludeIdsWith(access, pinsToRemove); - p::Remove(access, pinsToRemove); + p::RemoveId(access, pinsToRemove); access.GetPool()->Clear(); } diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index af8c5027..604ac73c 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -18,7 +18,6 @@ #include "AST/Utils/TypeUtils.h" #include "Pipe/Files/Paths.h" -#include #include #include @@ -65,8 +64,6 @@ namespace rift::AST::LoadSystem void ScanSubmodules(Tree& ast, TArray& paths) { - ZoneScoped; - paths.Clear(); Id projectId = GetProjectId(ast); @@ -79,8 +76,6 @@ namespace rift::AST::LoadSystem void ScanTypes(Tree& ast, TArray& pathsByModule) { - ZoneScoped; - pathsByModule.Clear(false); // Cache module paths in a Set @@ -103,7 +98,6 @@ namespace rift::AST::LoadSystem Path path = AST::GetModulePath(access, moduleId); auto& paths = pathsByModule.AddRef({moduleId}).paths; - ZoneScopedN("Iterate module files"); // Iterate all types ignoring other module paths for (const auto& typePath : AST::TypeIterator(path /*TODO: Ignore paths | , &modulePaths*/)) @@ -119,8 +113,6 @@ namespace rift::AST::LoadSystem void CreateModulesFromPaths(Tree& ast, TArray& paths, TArray& ids) { - ZoneScoped; - TAccess, TWrite, TWrite, CProject, TWrite, TWrite> access{ast}; @@ -154,13 +146,11 @@ namespace rift::AST::LoadSystem // Link modules to the project const Id projectId = GetProjectId(access); - p::Attach(access, projectId, ids); + p::AttachId(access, projectId, ids); } void CreateTypesFromPaths(Tree& ast, TView pathsByModule, TArray& ids) { - ZoneScoped; - auto* types = ast.TryGetStatic(); if (!types) { @@ -191,14 +181,13 @@ namespace rift::AST::LoadSystem ast.Add(id, CFileRef{Move(path)}); } - p::Attach(ast, modulePaths.moduleId, typeIds); + p::AttachId(ast, modulePaths.moduleId, typeIds); ids.Append(typeIds); } } void LoadFileStrings(TAccessRef access, TView nodes, TArray& strings) { - ZoneScoped; strings.Resize(nodes.Size()); for (i32 i = 0; i < nodes.Size(); ++i) { @@ -215,7 +204,6 @@ namespace rift::AST::LoadSystem void DeserializeModules(Tree& ast, TView moduleIds, TView strings) { - ZoneScoped; Check(moduleIds.Size() == strings.Size()); for (i32 i = 0; i < moduleIds.Size(); ++i) @@ -226,7 +214,6 @@ namespace rift::AST::LoadSystem void DeserializeTypes(Tree& ast, TView typeIds, TView strings) { - ZoneScoped; Check(typeIds.Size() == strings.Size()); for (i32 i = 0; i < typeIds.Size(); ++i) diff --git a/Libs/AST/Src/AST/Systems/TypeSystem.cpp b/Libs/AST/Src/AST/Systems/TypeSystem.cpp index b053bd11..73e3f32b 100644 --- a/Libs/AST/Src/AST/Systems/TypeSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TypeSystem.cpp @@ -10,7 +10,7 @@ #include "AST/Utils/Namespaces.h" #include "AST/Utils/TypeUtils.h" -#include +#include namespace rift::AST::TypeSystem @@ -90,7 +90,7 @@ namespace rift::AST::TypeSystem TArray dirtyTypeIds = FindAllIdsWith(access); TArray dirtyNodeIds; - p::GetChildren(access, dirtyTypeIds, dirtyNodeIds); + p::GetIdChildren(access, dirtyTypeIds, dirtyNodeIds); // Make sure the nodes have inputs and outputs ExcludeIdsWithout(access, dirtyNodeIds); diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index 27010dac..b5217941 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -8,7 +8,7 @@ #include "AST/Statics/SModules.h" #include "AST/Statics/STypes.h" -#include +#include namespace rift::AST diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index d86eb5eb..0bea52ad 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -171,7 +171,7 @@ namespace rift::AST input.nodeId = pinId; if (!IsNone(input.nodeId) && !access.Has(input.nodeId)) { - input.nodeId = p::GetParent(access, pinId); + input.nodeId = p::GetIdParent(access, pinId); } return input; } @@ -184,7 +184,7 @@ namespace rift::AST output.nodeId = pinId; if (!IsNone(output.nodeId) && !access.Has(output.nodeId)) { - output.nodeId = p::GetParent(access, pinId); + output.nodeId = p::GetIdParent(access, pinId); } return output; } diff --git a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp index c7f9cc40..90fa981c 100644 --- a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp +++ b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp @@ -9,11 +9,10 @@ #include "AST/Systems/LoadSystem.h" #include "AST/Systems/TypeSystem.h" -#include #include #include -#include #include +#include namespace rift::AST @@ -199,7 +198,6 @@ namespace rift::AST void SerializeModule(AST::Tree& ast, AST::Id id, String& data) { - ZoneScoped; JsonFormatWriter writer{}; p::EntityWriter w{writer.GetWriter(), ast}; w.BeginObject(); @@ -210,7 +208,6 @@ namespace rift::AST void DeserializeModule(AST::Tree& ast, AST::Id id, const String& data) { - ZoneScoped; JsonFormatReader formatReader{data}; if (formatReader.IsValid()) { diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index 495fe54a..68e47976 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -6,8 +6,8 @@ #include "AST/Id.h" #include "Pipe/Core/StringView.h" -#include -#include +#include +#include namespace rift::AST @@ -25,7 +25,7 @@ namespace rift::AST { break; } - id = p::GetParent(access, id); + id = p::GetIdParent(access, id); } i32 i, scopeIndex = 0; @@ -42,7 +42,7 @@ namespace rift::AST { if (!IsNone(id)) { - return GetNamespace(access, p::GetParent(access, id)); + return GetNamespace(access, p::GetIdParent(access, id)); } return {}; } @@ -84,7 +84,7 @@ namespace rift::AST if (!IsNone(foundScopeId)) { // Found matching name, check next scope - scopeIds = p::GetChildren(access, foundScopeId); + scopeIds = p::GetIdChildren(access, foundScopeId); ++depth; } else diff --git a/Libs/AST/Src/AST/Utils/Statements.cpp b/Libs/AST/Src/AST/Utils/Statements.cpp index 31ca1dba..73ae6e42 100644 --- a/Libs/AST/Src/AST/Utils/Statements.cpp +++ b/Libs/AST/Src/AST/Utils/Statements.cpp @@ -38,7 +38,7 @@ namespace rift::AST } else { - outputNode = p::GetParent(ast, outputPin); + outputNode = p::GetIdParent(ast, outputPin); if (IsNone(outputNode)) { return false; @@ -148,7 +148,7 @@ namespace rift::AST } bool DisconnectStmtFromNext(Tree& ast, AST::Id outputPin) { - return DisconnectStmtFromNext(ast, outputPin, p::GetParent(ast, outputPin)); + return DisconnectStmtFromNext(ast, outputPin, p::GetIdParent(ast, outputPin)); } bool WouldStmtLoop(const Tree& ast, Id outputNode, Id outputPin, Id inputNode) diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index 48ef94d9..d165391c 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -4,7 +4,7 @@ #include "AST/Components/CDeclType.h" -#include +#include namespace rift::AST::Transactions @@ -41,7 +41,7 @@ namespace rift::AST::Transactions // Mark files dirty TArray parentIds; - p::GetAllParents(access, entityIds, parentIds); + p::GetAllIdParents(access, entityIds, parentIds); parentIds.Append(entityIds); access.AddN(parentIds); diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index b36862ab..bca63038 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -31,10 +31,9 @@ #include "Rift.h" #include -#include #include -#include #include +#include namespace rift::AST @@ -94,13 +93,11 @@ namespace rift::AST } } } - p::Remove(access, typeIds, true); + p::RemoveId(access, typeIds, true); } void SerializeType(Tree& ast, Id id, String& data) { - ZoneScoped; - if (!Ensure(ast.Has(id))) { return; @@ -118,8 +115,6 @@ namespace rift::AST void DeserializeType(Tree& ast, Id id, const String& data) { - ZoneScoped; - JsonFormatReader reader{data}; if (!reader.IsValid()) { @@ -203,7 +198,7 @@ namespace rift::AST if (type) { - p::Attach(ast, type, id); + p::AttachId(ast, type, id); } return id; } @@ -219,7 +214,7 @@ namespace rift::AST if (type) { - p::Attach(ast, type, id); + p::AttachId(ast, type, id); } return id; } @@ -236,7 +231,7 @@ namespace rift::AST if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -247,7 +242,7 @@ namespace rift::AST ast.Add(id, name); ast.Add(id); ast.Add(id); - p::Attach(ast, functionId, id); + p::AttachId(ast, functionId, id); ast.GetOrAdd(functionId).Add(id); return id; } @@ -258,7 +253,7 @@ namespace rift::AST ast.Add(id, name); ast.Add(id); ast.Add(id); - p::Attach(ast, functionId, id); + p::AttachId(ast, functionId, id); ast.GetOrAdd(functionId).Add(id); return id; } @@ -274,17 +269,17 @@ namespace rift::AST const Id valueId = ast.Create(); ast.Add(valueId, {.id = ast.GetNativeTypes().boolId}); ast.Add(id).type = GetNamespace(ast, ast.GetNativeTypes().boolId); - p::Attach(ast, id, valueId); + p::AttachId(ast, id, valueId); ast.Add(id).Add(valueId); TArray outIds(2); ast.Create(outIds); - p::Attach(ast, id, outIds); + p::AttachId(ast, id, outIds); ast.Add(id, Move(outIds)); if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -297,7 +292,7 @@ namespace rift::AST ast.Add(returnId); if (type) { - p::Attach(ast, type.GetId(), returnId); + p::AttachId(ast, type.GetId(), returnId); } return returnId; } @@ -382,7 +377,7 @@ namespace rift::AST if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -395,7 +390,7 @@ namespace rift::AST ast.Add(id); ast.Add(id).Add(id); // Types gets resolved by a system later - const Id typeId = p::GetParent(ast, declId); + const Id typeId = p::GetIdParent(ast, declId); Check(!IsNone(typeId)); auto& declRefExpr = ast.Add(id); declRefExpr.ownerName = ast.Get(typeId).name; @@ -405,7 +400,7 @@ namespace rift::AST if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -419,7 +414,7 @@ namespace rift::AST ast.Add(id).Add(id); if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -434,10 +429,10 @@ namespace rift::AST auto& inputs = ast.Add(id); inputs.Resize(2); ast.Create(inputs.pinIds); - p::Attach(ast, id, inputs.pinIds); + p::AttachId(ast, id, inputs.pinIds); if (type) { - p::Attach(ast, type.GetId(), id); + p::AttachId(ast, type.GetId(), id); } return id; } @@ -447,7 +442,7 @@ namespace rift::AST if (!IsNone(ownerId)) { TArray children; - p::GetChildren(access, ownerId, children); + p::GetIdChildren(access, ownerId, children); for (Id childId : children) { const auto* ns = access.TryGet(childId); @@ -463,7 +458,7 @@ namespace rift::AST void RemoveNodes(const RemoveAccess& access, TView ids) { ScopedChange(access, ids); - p::Remove(access, ids, true); + p::RemoveId(access, ids, true); } bool CopyExpressionType(TAccessRef> access, Id sourcePinId, Id targetPinId) diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 9b198850..882b9a7b 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -26,7 +26,6 @@ namespace rift void Build(AST::Tree& ast, const CompilerConfig& config, TPtr backend) { - ZoneScoped; Compiler compiler{ast, config}; if (!backend) @@ -36,8 +35,6 @@ namespace rift } { - ZoneScopedN("Frontend"); - if (!AST::HasProject(ast)) { p::Error("No existing project to build."); diff --git a/Libs/Backends/MIR/CMakeLists.txt b/Libs/Backends/MIR/CMakeLists.txt index 6526ff53..d14ea7ca 100644 --- a/Libs/Backends/MIR/CMakeLists.txt +++ b/Libs/Backends/MIR/CMakeLists.txt @@ -5,6 +5,6 @@ rift_compiler_module(RiftBackendMIR) target_link_libraries(RiftBackendMIR PUBLIC RiftAST) target_link_libraries(RiftBackendMIR PRIVATE - mir_static + mir RiftBindingNative ) diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 619ea8a9..32e0318c 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -28,8 +28,6 @@ namespace rift::MIR void CGenerator::GenerateModule(AST::Id moduleId) { - ZoneScoped; - const Tag name = AST::GetModuleName(compiler.ast, moduleId); CMIRModule& mirModule = compiler.ast.Add(moduleId); code = &mirModule.code; @@ -37,14 +35,14 @@ namespace rift::MIR // Get all rift types from the module TArray typeIds; - GetChildren(access, moduleId, typeIds); + p::GetIdChildren(access, moduleId, typeIds); ExcludeIdsWithout(access, typeIds); { // Native declarations TArray cStructIds = FindIdsWith(access, typeIds); TArray cStaticIds = FindIdsWith(access, typeIds); TArray cFunctionIds; - p::GetChildren(access, cStaticIds, cFunctionIds); + p::GetIdChildren(access, cStaticIds, cFunctionIds); ExcludeIdsWithout(access, cFunctionIds); DeclareStructs(cStructIds); DeclareFunctions(cFunctionIds, false); @@ -56,8 +54,8 @@ namespace rift::MIR TArray staticIds = FindIdsWith(access, typeIds); TArray classIds = FindIdsWith(access, typeIds); TArray classFunctionIds; - p::GetChildren(access, staticIds, staticFunctionIds); - p::GetChildren(access, classIds, classFunctionIds); + p::GetIdChildren(access, staticIds, staticFunctionIds); + p::GetIdChildren(access, classIds, classFunctionIds); ExcludeIdsWithout(access, staticFunctionIds); ExcludeIdsWithout(access, classFunctionIds); TArray functionIds; @@ -138,7 +136,6 @@ namespace rift::MIR void CGenerator::DeclareStructs(TView ids) { - ZoneScoped; code->append("// Struct Declarations\n"); for (AST::Id id : ids) { @@ -151,7 +148,6 @@ namespace rift::MIR void CGenerator::DefineStructs(TView ids) { - ZoneScoped; code->append("// Struct Definitions\n"); p::String membersCode; TArray memberIds; @@ -159,7 +155,7 @@ namespace rift::MIR { membersCode.clear(); memberIds.Clear(false); - p::GetChildren(access, id, memberIds); + p::GetIdChildren(access, id, memberIds); ExcludeIdsWithout(access, memberIds); for (AST::Id memberId : memberIds) @@ -187,7 +183,6 @@ namespace rift::MIR void CGenerator::DeclareFunctions(TView ids, bool useFullName) { - ZoneScoped; code->append("// Function Declarations\n"); for (AST::Id id : ids) @@ -239,7 +234,6 @@ namespace rift::MIR void CGenerator::DefineFunctions(TView ids) { - ZoneScoped; code->append("// Function Definitions\n"); for (AST::Id id : ids) { @@ -257,8 +251,6 @@ namespace rift::MIR void CGenerator::AddStmtBlock(AST::Id firstStmtId) { - ZoneScoped; - AST::Id splitId = AST::NoId; TArray stmtIds; AST::GetStmtChain(access, firstStmtId, stmtIds, splitId); diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index b075b51a..112d55cb 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 6221a653..be5fb8ec 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -11,8 +11,7 @@ #include #include #include -#include -#include +#include #include @@ -31,8 +30,8 @@ namespace rift { struct Lib { - char* name = nullptr; - void* handler = nullptr; + const char* name = nullptr; + void* handler = nullptr; }; struct Input @@ -236,8 +235,6 @@ namespace rift using EntryFunctionPtr = p::i32 (*)(); void MIRBackend::Build(Compiler& compiler) { - ZoneScopedN("Backend: MIR"); - MIR_context* ctx = MIR_init(); c2mir_init(ctx); @@ -308,8 +305,8 @@ namespace rift void MIRBackend::CToMIR(Compiler& compiler, Input& input, MIR_context* ctx) { - auto getc = [](void* data) -> p::u8 { - Input* input = static_cast(data); + auto getc = [](void* data) -> p::i32 { + auto* input = static_cast(data); if (input->currentChar < input->code.EndData()) { return *(input->currentChar++); @@ -317,7 +314,7 @@ namespace rift return EOF; }; - if (!c2mir_compile(ctx, &input.options, getc, &input, input.input_name, nullptr)) + if (!c2mir_compile(ctx, &input.options, getc, &input, input.name, nullptr)) { compiler.Error("C to MIR compilation failed"); } @@ -331,24 +328,8 @@ namespace rift options.debug_p = options.verbose_p = options.ignore_warnings_p = FALSE; options.asm_p = options.object_p = options.no_prepro_p = options.prepro_only_p = FALSE; options.syntax_only_p = options.pedantic_p = FALSE; - curr_input.code = NULL; - else if ((incl_p = strncmp(argv[i], "-I", 2) == 0) - || (ldir_p = strncmp(argv[i], "-L", 2) == 0) || strncmp(argv[i], "-l", 2) == 0) - { - char* arg; - const char* dir = strlen(argv[i]) == 2 && i + 1 < argc ? argv[++i] : argv[i] + 2; - - if (*dir == '\0') - continue; - arg = reg_malloc(strlen(dir) + 1); - strcpy(arg, dir); - if (incl_p || ldir_p) - VARR_PUSH(char_ptr_t, incl_p ? headers : lib_dirs, arg); - else - process_cmdline_lib(arg); - } - options.options.macro_commands = nullptr; - options.macro_commands_num = 0; + options.macro_commands = nullptr; + options.macro_commands_num = 0; } } // namespace rift \ No newline at end of file diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 5b67f60b..ff027d70 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include // P_OVERRIDE_NEW_DELETE diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index 0067fa9f..551d8720 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace rift::Editor diff --git a/Libs/Editor/Include/Panels/FileExplorerPanel.h b/Libs/Editor/Include/Panels/FileExplorerPanel.h index 1fab7ea0..d03cf0e7 100644 --- a/Libs/Editor/Include/Panels/FileExplorerPanel.h +++ b/Libs/Editor/Include/Panels/FileExplorerPanel.h @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include namespace rift::Editor diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index e8d5aaf5..332be780 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -17,10 +17,6 @@ namespace rift::Editor { - using namespace p::core; - using namespace p::files; - - struct SEditor : public Struct { P_STRUCT(SEditor, Struct) diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 315eddc1..a85c9f11 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -8,10 +8,10 @@ #include #include #include -#include #include #include -#include +#include +#include #include diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index c64fe6a8..5757ed11 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -3,9 +3,10 @@ #include #include -#include #include #include +#include + namespace rift::Editor diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index 3337310f..e330545a 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -3,9 +3,10 @@ #include #include -#include #include #include +#include + namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/DetailsPanel.h b/Libs/Editor/Include/Utils/DetailsPanel.h index 5876d605..5ef0bb8a 100644 --- a/Libs/Editor/Include/Utils/DetailsPanel.h +++ b/Libs/Editor/Include/Utils/DetailsPanel.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/EditorStyle.h b/Libs/Editor/Include/Utils/EditorStyle.h index a2bf9f5e..e661cb2f 100644 --- a/Libs/Editor/Include/Utils/EditorStyle.h +++ b/Libs/Editor/Include/Utils/EditorStyle.h @@ -3,11 +3,12 @@ #pragma once #include -#include #include +#include #include + namespace rift::Editor { using namespace p; diff --git a/Libs/Editor/Include/Utils/ElementsPanel.h b/Libs/Editor/Include/Utils/ElementsPanel.h index cb4e27c1..3483120f 100644 --- a/Libs/Editor/Include/Utils/ElementsPanel.h +++ b/Libs/Editor/Include/Utils/ElementsPanel.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/FunctionGraph.h b/Libs/Editor/Include/Utils/FunctionGraph.h index 8a732931..32c812e7 100644 --- a/Libs/Editor/Include/Utils/FunctionGraph.h +++ b/Libs/Editor/Include/Utils/FunctionGraph.h @@ -5,7 +5,7 @@ #include "Components/CTypeEditor.h" #include -#include +#include namespace rift diff --git a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h index 9e99fa4c..d6737f86 100644 --- a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h +++ b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h @@ -2,7 +2,7 @@ #pragma once #include -#include +#include namespace rift::Editor::Graph diff --git a/Libs/Editor/Include/Utils/Nodes.h b/Libs/Editor/Include/Utils/Nodes.h index e33f70dd..24323a22 100644 --- a/Libs/Editor/Include/Utils/Nodes.h +++ b/Libs/Editor/Include/Utils/Nodes.h @@ -3,13 +3,13 @@ #include #include -#include -#include +#include +#include #include #ifdef IMNODES_USER_CONFIG -# include IMNODES_USER_CONFIG + #include IMNODES_USER_CONFIG #endif struct ImGuiContext; diff --git a/Libs/Editor/Include/Utils/NodesInternal.h b/Libs/Editor/Include/Utils/NodesInternal.h index 2ad7be87..d5c3ef7a 100644 --- a/Libs/Editor/Include/Utils/NodesInternal.h +++ b/Libs/Editor/Include/Utils/NodesInternal.h @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include +#include // the structure of this file: diff --git a/Libs/Editor/Include/Utils/NodesMiniMap.h b/Libs/Editor/Include/Utils/NodesMiniMap.h index 5e87965b..28c0026e 100644 --- a/Libs/Editor/Include/Utils/NodesMiniMap.h +++ b/Libs/Editor/Include/Utils/NodesMiniMap.h @@ -4,7 +4,7 @@ #include #include -#include +#include namespace rift::Nodes diff --git a/Libs/Editor/Include/Utils/TypeUtils.h b/Libs/Editor/Include/Utils/TypeUtils.h index fc02b5ce..50cbee44 100644 --- a/Libs/Editor/Include/Utils/TypeUtils.h +++ b/Libs/Editor/Include/Utils/TypeUtils.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/Widgets.h b/Libs/Editor/Include/Utils/Widgets.h index 9eadc326..190dcf0e 100644 --- a/Libs/Editor/Include/Utils/Widgets.h +++ b/Libs/Editor/Include/Utils/Widgets.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace rift::Editor diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index dac535b6..0150d6c7 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -73,7 +72,6 @@ namespace rift::Editor UI::Render(); frameTime.PostTick(); - FrameMark; } Graph::Shutdown(); diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index 76d54509..c7094028 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -70,7 +69,6 @@ namespace rift::Editor void FileExplorerPanel::DrawList(AST::Tree& ast) { - ZoneScoped; // if (dirty) { CacheProjectFiles(ast); @@ -85,7 +83,6 @@ namespace rift::Editor } { - ZoneScopedN("Draw Files"); for (auto& item : folders[{}].items) { DrawItem(ast, item); @@ -215,7 +212,6 @@ namespace rift::Editor void FileExplorerPanel::CacheProjectFiles( TAccessRef access) { - ZoneScoped; dirty = false; folders.Clear(); @@ -371,7 +367,7 @@ namespace rift::Editor } else if (Strings::EndsWith(fileName, ".rf")) { - text = Strings::Format(ICON_FA_FILE_CODE " {}", fileName.data()); + text = Strings::Format(ICON_FA_FILE_CODE " {}", fileName); } else { @@ -401,7 +397,7 @@ namespace rift::Editor const StringView parsedNewName = Strings::RemoveFromEnd(renameBuffer, ".rf"); const bool nameIsEmpty = parsedNewName.empty(); const Id sameNameFuncId = - AST::FindChildByName(ast, p::GetParent(ast, item.id), Tag{parsedNewName}); + AST::FindChildByName(ast, p::GetIdParent(ast, item.id), Tag{parsedNewName}); if (nameIsEmpty || (!IsNone(sameNameFuncId) && item.id != sameNameFuncId)) { UI::PushTextColor(LinearColor::Red()); diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index 3885570e..fe501ed5 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -28,8 +28,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -120,8 +120,6 @@ namespace rift::Editor::EditorSystem void Draw(AST::Tree& ast) { - ZoneScoped; - if (AST::HasProject(ast)) { DrawProject(ast); @@ -158,7 +156,6 @@ namespace rift::Editor::EditorSystem void CreateRootDockspace(SEditor& editor) { - ZoneScoped; ImGuiDockNodeFlags dockingFlags = ImGuiDockNodeFlags_None; const auto& viewport = UI::GetMainViewport(); @@ -193,7 +190,6 @@ namespace rift::Editor::EditorSystem void CreateTypeDockspace(CTypeEditor& editor, const char* id) { - ZoneScoped; ImGuiDockNodeFlags dockingFlags = ImGuiDockNodeFlags_None; editor.dockspaceID = UI::GetID(id); @@ -221,8 +217,6 @@ namespace rift::Editor::EditorSystem void DrawProject(AST::Tree& ast) { - ZoneScoped; - if (!Ensure(ast.HasStatic())) { return; @@ -230,7 +224,7 @@ namespace rift::Editor::EditorSystem auto& editor = ast.GetStatic(); const auto& path = AST::GetProjectPath(ast); - UI::PushID(Hash()(path)); + UI::PushID(p::GetHash(path)); DrawProjectMenuBar(ast, editor); @@ -414,8 +408,6 @@ namespace rift::Editor::EditorSystem for (AST::Id moduleId : FindAllIdsWith(moduleEditors)) { - ZoneScopedN("Draw Type"); - auto& moduleEditor = moduleEditors.Get(moduleId); const auto& file = moduleEditors.Get(moduleId); @@ -527,13 +519,9 @@ namespace rift::Editor::EditorSystem void DrawTypes(AST::Tree& ast, SEditor& editor) { - ZoneScoped; - TAccess, AST::CDeclType, AST::CFileRef> access{ast}; for (AST::Id typeId : FindAllIdsWith(access)) { - ZoneScopedN("Draw Type"); - auto& typeEditor = access.Get(typeId); const auto& file = access.Get(typeId); diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index def818d3..b3dfb9a9 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -15,8 +15,6 @@ namespace rift::Editor { - using namespace p::core; - void DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open = nullptr) { p::String name = "Entity Inspector"; @@ -77,7 +75,7 @@ namespace rift::Editor if (auto* types = ast.TryGetStatic()) { UI::BeginChild("typesTableChild", - ImVec2(0.f, p::math::Min(250.f, UI::GetContentRegionAvail().y - 20.f))); + ImVec2(0.f, p::Min(250.f, UI::GetContentRegionAvail().y - 20.f))); if (UI::BeginTable("typesTable", 2, flags, ImVec2(0.f, UI::GetContentRegionAvail().y))) { UI::TableSetupColumn("Name"); @@ -156,7 +154,7 @@ namespace rift::Editor if (showHierarchy && !filter.IsActive()) { p::TArray roots; - p::GetRoots(access, roots); + p::GetRootIds(access, roots); for (auto root : roots) { DrawNode(access, root, true); @@ -256,7 +254,7 @@ namespace rift::Editor } bool open = false; - static Tag font{"WorkSans"}; + static p::Tag font{"WorkSans"}; UI::PushFont(font, UI::FontMode::Bold); if (hasChildren) { diff --git a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp index 2bcd69bb..7a738139 100644 --- a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp +++ b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp @@ -3,8 +3,8 @@ #include "Tools/BigBestFitArenaDebugger.h" #include -#include #include +#include #include @@ -51,7 +51,7 @@ namespace rift::Editor } grid.UpdateGridScale(graphSize.x); - graphSize.y = math::Max(graphSize.y, grid.GetHeight()); + graphSize.y = p::Max(graphSize.y, grid.GetHeight()); const ImRect frameBox(window->DC.CursorPos, ImVec2(v2(window->DC.CursorPos) + graphSize)); @@ -85,7 +85,7 @@ namespace rift::Editor const u32 startX = grid.GetX(startOffset); const u32 endX = grid.GetX(endOffset); const u32 startY = grid.GetY(startOffset); - const u32 endY = math::Min(grid.GetY(endOffset), grid.numRows - 1); + const u32 endY = p::Min(grid.GetY(endOffset), grid.numRows - 1); // Draw incomplete rows if (startY != endY) @@ -134,11 +134,11 @@ namespace rift::Editor void MemoryGrid::Draw(const TArray& freeSlots) { String scaleStr = Strings::ParseMemorySize(memoryScale); - u32 scaleMultiplier = u32(math::Log2(memoryScale)); + u32 scaleMultiplier = u32(p::Log2(memoryScale)); static const u32 min = 2, max = 8; UI::SliderScalar( "Scale", ImGuiDataType_U32, (void*)&scaleMultiplier, &min, &max, scaleStr.c_str()); - memoryScale = math::Pow(2, scaleMultiplier); + memoryScale = p::Pow(2, scaleMultiplier); UI::BeginChild("##memoryblock", ImVec2(0.f, 450.f), false); UI::SetNextItemWidth(-FLT_MIN); diff --git a/Libs/Editor/Src/Tools/MemoryDebugger.cpp b/Libs/Editor/Src/Tools/MemoryDebugger.cpp index 4cb7be8e..21e4eb75 100644 --- a/Libs/Editor/Src/Tools/MemoryDebugger.cpp +++ b/Libs/Editor/Src/Tools/MemoryDebugger.cpp @@ -3,9 +3,9 @@ #include "Tools/MemoryDebugger.h" #include -#include #include #include +#include #include #include @@ -37,7 +37,7 @@ namespace rift::Editor if (UI::BeginChild("Allocations")) { - const i32 shown = math::Min(10000, i32(stats->allocations.Size())); + const i32 shown = p::Min(10000, i32(stats->allocations.Size())); for (i32 i = 0; i < shown; ++i) { const auto& allocation = stats->allocations[i]; @@ -46,7 +46,7 @@ namespace rift::Editor if (UI::TreeNodeEx(label.c_str())) { label.clear(); - Strings::FormatTo(label, "Address: {}, Size: {}", allocation.ptr, + Strings::FormatTo(label, "Address: {}, Size: {}", (void*)allocation.ptr, Strings::ParseMemorySize(allocation.size)); UI::Text(label.c_str()); diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index f3f44187..02450787 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -14,9 +14,6 @@ namespace rift::Editor { - // using namespace p::core::EnumOperators; - - ReflectionDebugger::ReflectionDebugger() {} void ReflectionDebugger::Draw() diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index 484a4c34..272e60cf 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index ffa6b9da..0b864acc 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include @@ -178,7 +178,7 @@ namespace rift::Editor { UI::Indent(10.f); TArray variableIds; - p::GetChildren(access, typeId, variableIds); + p::GetIdChildren(access, typeId, variableIds); ExcludeIdsWithout(access, variableIds); UI::PushStyleVar(ImGuiStyleVar_CellPadding, {1.f, 3.f}); @@ -223,7 +223,7 @@ namespace rift::Editor UI::Indent(10.f); TArray functionIds; - p::GetChildren(ast, typeId, functionIds); + p::GetIdChildren(ast, typeId, functionIds); ExcludeIdsWithout(ast, functionIds); for (AST::Id functionId : functionIds) { @@ -280,7 +280,7 @@ namespace rift::Editor // If pin has not been marked for removal, destroy the entity if (!removedPin) { - p::Remove(ast, editor.pendingDeletePropertyId, true); + p::RemoveId(ast, editor.pendingDeletePropertyId, true); editor.pendingDeletePropertyId = AST::NoId; } } diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 547dc0e8..139c8532 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -282,7 +282,7 @@ namespace rift::Editor::Graph char buf[64]; UI::DataTypeFormatString(buf, IM_ARRAYSIZE(buf), dataType, &value.value, format); - UI::SetNextItemWidth(5.f + math::Max(UI::CalcTextSize(buf).x, 20.f)); + UI::SetNextItemWidth(5.f + p::Max(UI::CalcTextSize(buf).x, 20.f)); UI::InputScalar("##value", dataType, &value.value, nullptr, nullptr, format); PopInnerNodeStyle(); @@ -305,7 +305,7 @@ namespace rift::Editor::Graph const ImGuiDataType dataType = isDouble ? ImGuiDataType_Double : ImGuiDataType_Float; char buf[64]; UI::DataTypeFormatString(buf, IM_ARRAYSIZE(buf), dataType, &value.value, "%.15g"); - UI::SetNextItemWidth(5.f + math::Max(UI::CalcTextSize(buf).x, 20.f)); + UI::SetNextItemWidth(5.f + p::Max(UI::CalcTextSize(buf).x, 20.f)); UI::InputScalar("##value", dataType, &value.value, nullptr, nullptr, "%.15g"); PopInnerNodeStyle(); @@ -327,7 +327,7 @@ namespace rift::Editor::Graph ImGuiStyle& style = ImGui::GetStyle(); const ImVec2 textSize = ImGui::CalcTextSize(value.data(), value.data() + value.size()); const v2 minSize{settings.GetGridSize() * 4.f, settings.GetGridSize()}; - const v2 size{math::Max(minSize.x, textSize.x), math::Max(minSize.y, textSize.y)}; + const v2 size{p::Max(minSize.x, textSize.x), p::Max(minSize.y, textSize.y)}; UI::InputTextMultiline("##value", value, v2(size - settings.GetContentPadding())); PopInnerNodeStyle(); EndExprOutput(false); @@ -699,7 +699,7 @@ namespace rift::Editor::Graph BeginNode(access, id); { pinIds.Clear(false); - p::GetChildren(access, id, pinIds); + p::GetIdChildren(access, id, pinIds); if (!Ensure(pinIds.Size() >= 2)) { continue; @@ -852,7 +852,7 @@ namespace rift::Editor::Graph } TArray children; - p::GetChildren(ast, typeId, children); + p::GetIdChildren(ast, typeId, children); // Nodes DrawFunctionDecls(ast, FindIdsWith(ast, children)); diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index cf65d796..7e7dc925 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -195,7 +195,7 @@ namespace rift::Editor::Graph { Tag name = access.Get(functionId).name; label.clear(); - AST::Id funcTypeId = GetParent(access, functionId); + AST::Id funcTypeId = p::GetIdParent(access, functionId); if (!IsNone(funcTypeId) && access.Has(funcTypeId)) { Strings::FormatTo(label, "{} ({})", name, @@ -222,7 +222,7 @@ namespace rift::Editor::Graph { Tag name = access.Get(variableId).name; label.clear(); - AST::Id typeId = p::GetParent(access, variableId); + AST::Id typeId = p::GetIdParent(access, variableId); if (!IsNone(typeId) && access.Has(typeId)) { Strings::FormatTo( diff --git a/Libs/Editor/Src/Utils/Nodes.cpp b/Libs/Editor/Src/Utils/Nodes.cpp index 937aef8c..9bf83807 100644 --- a/Libs/Editor/Src/Utils/Nodes.cpp +++ b/Libs/Editor/Src/Utils/Nodes.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include // strlen, strncmp @@ -87,8 +87,8 @@ namespace rift::Nodes Rect GetContainingRectForCubicBezier(const CubicBezier& cb) { - const v2 min = v2(math::Min(cb.p0.x, cb.p3.x), math::Min(cb.p0.y, cb.p3.y)); - const v2 max = v2(math::Max(cb.p0.x, cb.p3.x), math::Max(cb.p0.y, cb.p3.y)); + const v2 min = v2(p::Min(cb.p0.x, cb.p3.x), p::Min(cb.p0.y, cb.p3.y)); + const v2 max = v2(p::Max(cb.p0.x, cb.p3.x), p::Max(cb.p0.y, cb.p3.y)); const float hoverDistance = gNodes->style.LinkHoverDistance; diff --git a/Libs/Editor/Src/Utils/NodesMiniMap.cpp b/Libs/Editor/Src/Utils/NodesMiniMap.cpp index 8aba780f..d77ec1ac 100644 --- a/Libs/Editor/Src/Utils/NodesMiniMap.cpp +++ b/Libs/Editor/Src/Utils/NodesMiniMap.cpp @@ -5,8 +5,8 @@ #include "Utils/Nodes.h" #include "Utils/NodesInternal.h" -#include -#include +#include +#include namespace rift::Nodes @@ -95,7 +95,7 @@ namespace rift::Nodes ScreenToMiniMapPosition(editor, node.rect.max)}; // Round to near whole pixel value for corner-rounding to prevent visual glitches - const float miniMapNodeRounding = math::Floor(node.LayoutStyle.CornerRounding * scaling); + const float miniMapNodeRounding = p::Floor(node.LayoutStyle.CornerRounding * scaling); Color miniMapNodeBackground; if (editor.clickInteraction.type == ClickInteractionType_None diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index b797a868..7017e01e 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -17,8 +17,8 @@ namespace rift::Editor v2 viewportSize = UI::GetMainViewport()->Size; v2 modalSize = v2{600.f, 400.f}; - modalSize.x = math::Min(modalSize.x, viewportSize.x - 20.f); - modalSize.y = math::Min(modalSize.y, viewportSize.y - 20.f); + modalSize.x = p::Min(modalSize.x, viewportSize.x - 20.f); + modalSize.y = p::Min(modalSize.y, viewportSize.y - 20.f); UI::SetNextWindowSize(modalSize, ImGuiCond_Always); diff --git a/Libs/Editor/Src/Utils/TypeUtils.cpp b/Libs/Editor/Src/Utils/TypeUtils.cpp index 61dd6e46..836c36cc 100644 --- a/Libs/Editor/Src/Utils/TypeUtils.cpp +++ b/Libs/Editor/Src/Utils/TypeUtils.cpp @@ -3,7 +3,7 @@ #include "Utils/TypeUtils.h" #include -#include +#include namespace rift::Editor diff --git a/Libs/UI/Include/UI/Style.h b/Libs/UI/Include/UI/Style.h index 2b718460..66b8751b 100644 --- a/Libs/UI/Include/UI/Style.h +++ b/Libs/UI/Include/UI/Style.h @@ -2,7 +2,7 @@ #pragma once #include -#include +#include namespace rift::UI diff --git a/Libs/UI/Include/UI/UIImgui.h b/Libs/UI/Include/UI/UIImgui.h index 70a27fb9..33b3d6e3 100644 --- a/Libs/UI/Include/UI/UIImgui.h +++ b/Libs/UI/Include/UI/UIImgui.h @@ -3,15 +3,16 @@ #include #include -#include -#include +#include +#include -#define IM_VEC2_CLASS_EXTRA \ - constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) {} \ - constexpr operator p::v2() const \ - { \ - return p::v2{x, y}; \ +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) \ + {} \ + constexpr operator p::v2() const \ + { \ + return p::v2{x, y}; \ } #define IM_VEC4_CLASS_EXTRA \ @@ -21,7 +22,8 @@ { \ return p::LinearColor{x, y, z, w}; \ } \ - constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) {} \ + constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) \ + {} \ constexpr operator p::v4() const \ { \ return p::v4{x, y, z, w}; \ diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 19e77b50..2e577300 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -376,7 +376,7 @@ namespace rift::UI UI::AlignTextToFramePadding(); UI::Text(label); UI::TableSetColumnIndex(1); - UI::SetNextItemWidth(math::Min(300.f, UI::GetContentRegionAvail().x)); + UI::SetNextItemWidth(p::Min(300.f, UI::GetContentRegionAvail().x)); String str = ToString(*path); if (UI::InputText("##value", str)) { diff --git a/Libs/UI/Src/Notify.cpp b/Libs/UI/Src/Notify.cpp index c3dac932..369b6744 100644 --- a/Libs/UI/Src/Notify.cpp +++ b/Libs/UI/Src/Notify.cpp @@ -7,9 +7,8 @@ #include #include -#include -#include -#include +#include +#include #define NOTIFY_USE_SEPARATOR diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index 9ae896fe..9dea372b 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -8,10 +8,10 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include namespace rift::UI @@ -26,7 +26,7 @@ namespace rift::UI void Add(float size, ImFont* imFont) { if (sizes.Contains([size](const auto& font) { - return math::NearlyEqual(font.first, size); + return p::NearlyEqual(font.first, size); })) { p::Error( @@ -48,7 +48,7 @@ namespace rift::UI return sizes.First().second; } const TPair* foundFont = sizes.Find([desiredSize](const auto& font) { - return math::NearlyEqual(font.first, desiredSize); + return p::NearlyEqual(font.first, desiredSize); }); return foundFont ? foundFont->second : nullptr; } diff --git a/Libs/UI/Src/Widgets.cpp b/Libs/UI/Src/Widgets.cpp index aa4cce28..11dc7ec2 100644 --- a/Libs/UI/Src/Widgets.cpp +++ b/Libs/UI/Src/Widgets.cpp @@ -3,15 +3,14 @@ #include "UI/Widgets.h" #include -#include -#include +#include namespace rift::UI { void AnimatedSprite::SetAnimation(u32 id) { - currentFrame = {0, math::Clamp(id, 0u, u32(numFrames.Size() - 1))}; + currentFrame = {0, p::Clamp(id, 0u, u32(numFrames.Size() - 1))}; currentFrameRemainingTime = rate; } @@ -127,7 +126,7 @@ namespace rift::UI const float minX = window->ParentWorkRect.Min.x; const float maxX = window->ParentWorkRect.Max.x; - const ImVec2 size{math::Max(desiredSize.x, maxX - minX), desiredSize.y}; + const ImVec2 size{p::Max(desiredSize.x, maxX - minX), desiredSize.y}; ImRect bb{minX, pos.y, minX + size.x, pos.y + size.y}; if (addhalfItemSpacing) diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index e1b6864c..34a29899 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -16,20 +16,19 @@ // Include glfw3.h after our OpenGL definitions #include #include -#include -#include +#include namespace rift::UI { - using namespace p::math; + using namespace p; static GLFWwindow* gWindow = nullptr; void OnGl3WError(int error, const char* description) { - p::Error("Glfw Error {}: {}", error, description); + p::Error("Glfw Error {}: {}", error, p::StringView{description}); } bool Init() @@ -117,7 +116,6 @@ namespace rift::UI void PreFrame() { - ZoneScopedN("PreFrame"); glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); @@ -127,8 +125,6 @@ namespace rift::UI void Render() { - ZoneScopedC(0xA245D1); - ImGui::Render(); i32 displayW, displayH; glfwGetFramebufferSize(gWindow, &displayW, &displayH); diff --git a/Tests/AST/Namespaces.spec.cpp b/Tests/AST/Namespaces.spec.cpp index 44ebcb7c..75a9da27 100644 --- a/Tests/AST/Namespaces.spec.cpp +++ b/Tests/AST/Namespaces.spec.cpp @@ -12,7 +12,6 @@ using namespace snowhouse; using namespace bandit; using namespace rift; -using namespace p::core; go_bandit([]() { @@ -36,7 +35,7 @@ go_bandit([]() { ast.Add(parentC); ast.Add(parentC, AST::CNamespace{"SomeScope"}); AST::Id classCId = AST::CreateType(ast, ASTModule::classType, "TestClass"); - p::Attach(ast, parentC, classCId); + p::AttachId(ast, parentC, classCId); AST::Id functionCId = AST::AddFunction({ast, classCId}, "TestFunction"); AssertThat(AST::GetNamespace(ast, functionCId).ToString().c_str(), Equals("@SomeScope.TestClass.TestFunction")); @@ -51,7 +50,7 @@ go_bandit([]() { ast.Add(parent); ast.Add(parent, AST::CNamespace{"SomeModule"}); AST::Id classId = AST::CreateType(ast, ASTModule::classType, "TestClass"); - p::Attach(ast, parent, classId); + p::AttachId(ast, parent, classId); AST::Id functionId = AST::AddFunction({ast, classId}, "TestFunction"); p::String ns = AST::GetNamespace(ast, functionId).ToString(true); AssertThat(ns.c_str(), Equals("TestClass.TestFunction")); @@ -106,10 +105,10 @@ go_bandit([]() { ast.Add(parent, AST::CNamespace{"A"}); AST::Id classId = AST::CreateType(ast, ASTModule::classType, "B"); - p::Attach(ast, parent, classId); + p::AttachId(ast, parent, classId); AST::Id class2Id = AST::CreateType(ast, ASTModule::classType, "B2"); - p::Attach(ast, parent, class2Id); + p::AttachId(ast, parent, class2Id); AST::Id functionId = AST::AddFunction({ast, classId}, "C"); AST::Id function2Id = AST::AddFunction({ast, classId}, "C2"); diff --git a/Tests/main.cpp b/Tests/main.cpp index 9617fd27..7d4b5aaa 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -4,7 +4,7 @@ // Override as first include #include -#include +#include int main(int argc, char* argv[]) From c98d9f9803c02f1304b850d9206fd0d0691e8b74 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 2 Dec 2023 23:52:25 +0100 Subject: [PATCH 06/52] Pipe format fixes --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index bb80d9a2..62f032cd 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit bb80d9a2890be0bdda7778e758f5c1f850bd2cf5 +Subproject commit 62f032cd0d0bc24c2a060bc825d3bd3173781605 From 705f3c7abda309001e17cdb2e76e465daa7e6a17 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 6 Dec 2023 20:28:31 +0100 Subject: [PATCH 07/52] Fix mir compilation issue --- Extern/CMakeLists.txt | 32 +++++++++---------- Libs/Backends/MIR/CMakeLists.txt | 7 ++-- .../MIR/Compiler/Src/MIRBackendModule.cpp | 9 ++++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Extern/CMakeLists.txt b/Extern/CMakeLists.txt index 1512a4ce..ab31a8ed 100644 --- a/Extern/CMakeLists.txt +++ b/Extern/CMakeLists.txt @@ -52,16 +52,16 @@ pipe_target_disable_all_warnings(Taskflow INTERFACE) # MIR -include(FindThreads) -if(Threads_FOUND) - link_libraries(${CMAKE_THREAD_LIBS_INIT}) -endif() add_library(mir STATIC) target_sources(mir PRIVATE mir/mir.c mir/mir-gen.c mir/c2mir/c2mir.c) -target_include_directories(mir PUBLIC mir) +target_include_directories(mir PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/mir) + +include(FindThreads) if(Threads_FOUND) + target_link_libraries(mir PUBLIC ${CMAKE_THREAD_LIBS_INIT}) target_compile_definitions(mir PUBLIC "MIR_PARALLEL_GEN") endif() + if(NOT WIN32) target_compile_options(mir PRIVATE $<$:-O3> @@ -70,14 +70,14 @@ if(NOT WIN32) target_compile_options(mir PRIVATE -std=gnu11 -Wno-abi -fsigned-char -fPIC) endif() -include(CheckCCompilerFlag) -if(CMAKE_COMPILER_IS_GNUCC) - check_c_compiler_flag(-fno-tree-sra NO_TREE_SRA) - if (NO_TREE_SRA) - target_compile_options(mir PRIVATE -fno-tree-sra) - endif() - check_c_compiler_flag(-fno-ipa-cp-clone NO_IPA_CP_CLONE) - if (NO_IPA_CP_CLONE) - target_compile_options(mir PRIVATE -fno-ipa-cp-clone) - endif() -endif() +#include(CheckCCompilerFlag) +#if(CMAKE_COMPILER_IS_GNUCC) +# check_c_compiler_flag(-fno-tree-sra NO_TREE_SRA) +# if (NO_TREE_SRA) +# target_compile_options(mir PRIVATE -fno-tree-sra) +# endif() +# check_c_compiler_flag(-fno-ipa-cp-clone NO_IPA_CP_CLONE) +# if (NO_IPA_CP_CLONE) +# target_compile_options(mir PRIVATE -fno-ipa-cp-clone) +# endif() +#endif() diff --git a/Libs/Backends/MIR/CMakeLists.txt b/Libs/Backends/MIR/CMakeLists.txt index d14ea7ca..760846e0 100644 --- a/Libs/Backends/MIR/CMakeLists.txt +++ b/Libs/Backends/MIR/CMakeLists.txt @@ -1,10 +1,7 @@ # Copyright 2015-2023 Piperift - All rights reserved add_library(RiftBackendMIR STATIC) +target_link_libraries(RiftBackendMIR PUBLIC RiftAST) +target_link_libraries(RiftBackendMIR PRIVATE RiftBindingNative mir) rift_compiler_module(RiftBackendMIR) -target_link_libraries(RiftBackendMIR PUBLIC RiftAST) -target_link_libraries(RiftBackendMIR PRIVATE - mir - RiftBindingNative -) diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index be5fb8ec..56a1a18d 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -5,14 +5,17 @@ #include "Compiler/CompilerConfig.h" #include -#include -#include -#include #include #include #include #include #include +extern "C" +{ +#include +#include +#include +} #ifndef _WIN32 From 45a44ed3923ca1bd987e81c316a4a85267a83cbe Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 6 Dec 2023 23:04:02 +0100 Subject: [PATCH 08/52] C2MIR Changes --- .../MIR/Compiler/Include/MIRBackendModule.h | 5 +- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 59 +++++++++++++++++++ Libs/Backends/MIR/Compiler/Src/C2MIR.h | 44 ++++++++++++++ .../MIR/Compiler/Src/IRGeneration.cpp | 3 +- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 3 +- .../MIR/Compiler/Src/MIRBackendModule.cpp | 39 +++--------- 6 files changed, 114 insertions(+), 39 deletions(-) create mode 100644 Libs/Backends/MIR/Compiler/Src/C2MIR.cpp create mode 100644 Libs/Backends/MIR/Compiler/Src/C2MIR.h diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index 97099638..d5559832 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -5,6 +5,8 @@ #include struct MIR_context; +struct c2mir_options; + namespace rift { @@ -29,8 +31,5 @@ namespace rift } void Build(Compiler& compiler) override; - - protected: - void CToMIR(Compiler& compiler, Input& input, MIR_context* ctx); }; } // namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp new file mode 100644 index 00000000..21aaa968 --- /dev/null +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -0,0 +1,59 @@ +// Copyright 2015-2023 Piperift - All rights reserved + +#include "C2MIR.h" + +#include +#include +extern "C" +{ +#include +} + +namespace rift::MIR +{ + void InitCToMIROptions(c2mir_options& options) + { + int inclP, ldirP = FALSE; /* to remove an uninitialized warning */ + + options.message_file = stderr; + options.debug_p = options.verbose_p = options.ignore_warnings_p = FALSE; + options.asm_p = options.object_p = options.no_prepro_p = options.prepro_only_p = FALSE; + options.syntax_only_p = options.pedantic_p = FALSE; + + options.macro_commands = nullptr; + options.macro_commands_num = 0; + } + + void CToMIR(Compiler& compiler, MIR_context* ctx) + { + c2mir_options options; + InitCToMIROptions(options); + + for (AST::Id moduleId : FindAllIdsWith(compiler.ast)) + { + p::Tag name = AST::GetModuleName(compiler.ast, moduleId); + auto& mirModule = compiler.ast.Get(moduleId); + CToMIRModule(compiler, ctx, options, name, mirModule); + } + } + + void CToMIRModule(Compiler& compiler, MIR_context* ctx, c2mir_options& options, p::Tag name, + const CMIRModule& module) + { + auto getCode = [](void* data) -> p::i32 { + auto* codeLeft = static_cast(data); + if (codeLeft->size() > 0) + { + *codeLeft = Strings::RemoveFromStart(*codeLeft, 1); + return *codeLeft->data(); + } + return EOF; + }; + + StringView code = module.code; + if (!c2mir_compile(ctx, &options, getCode, &code, name.Data(), nullptr)) + { + compiler.Error("C to MIR compilation failed"); + } + } +} // namespace rift::MIR diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.h b/Libs/Backends/MIR/Compiler/Src/C2MIR.h new file mode 100644 index 00000000..f5e101a8 --- /dev/null +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.h @@ -0,0 +1,44 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include "Components.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct c2mir_options; + +namespace rift +{ + struct Compiler; +} + +namespace rift::MIR +{ + void CToMIR(Compiler& compiler, MIR_context* ctx); + void CToMIRModule(Compiler& compiler, MIR_context* ctx, c2mir_options& options, p::Tag name, + const CMIRModule& module); +} // namespace rift::MIR diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 32e0318c..a15fc2c7 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -2,7 +2,6 @@ #include "IRGeneration.h" -#include "mir.h" #include "Pipe/Core/String.h" #include "Pipe/Core/StringView.h" @@ -14,7 +13,7 @@ namespace rift::MIR { - void Generate(Compiler& compiler, MIR_context_t& ctx) + void Generate(Compiler& compiler) { MIRAccess access{compiler.ast}; CGenerator cGen{compiler, access}; diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index 112d55cb..a754b6b8 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -25,7 +25,6 @@ #include #include #include -#include #include @@ -45,7 +44,7 @@ namespace rift::MIR CDeclCStruct, CDeclCStatic, p::TWrite, p::TWrite, p::TWrite>; - void Generate(Compiler& compiler, MIR_context_t& ctx); + void Generate(Compiler& compiler); struct CGenerator diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 56a1a18d..e38b6895 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -2,7 +2,9 @@ #include "MIRBackendModule.h" +#include "C2MIR.h" #include "Compiler/CompilerConfig.h" +#include "IRGeneration.h" #include #include @@ -10,6 +12,8 @@ #include #include #include + + extern "C" { #include @@ -238,11 +242,12 @@ namespace rift using EntryFunctionPtr = p::i32 (*)(); void MIRBackend::Build(Compiler& compiler) { + MIR::Generate(compiler); + MIR_context* ctx = MIR_init(); c2mir_init(ctx); - c2mir_options options; - + MIR::CToMIR(compiler, ctx); p::i32 nGen = 1; MIR_item_t func, mainFunc = nullptr; @@ -305,34 +310,4 @@ namespace rift c2mir_finish(ctx); MIR_finish(ctx); } - - void MIRBackend::CToMIR(Compiler& compiler, Input& input, MIR_context* ctx) - { - auto getc = [](void* data) -> p::i32 { - auto* input = static_cast(data); - if (input->currentChar < input->code.EndData()) - { - return *(input->currentChar++); - } - return EOF; - }; - - if (!c2mir_compile(ctx, &input.options, getc, &input, input.name, nullptr)) - { - compiler.Error("C to MIR compilation failed"); - } - } - - void InitCToMIROptions(c2mir_options& options) - { - int incl_p, ldir_p = FALSE; /* to remove an uninitialized warning */ - - options.message_file = stderr; - options.debug_p = options.verbose_p = options.ignore_warnings_p = FALSE; - options.asm_p = options.object_p = options.no_prepro_p = options.prepro_only_p = FALSE; - options.syntax_only_p = options.pedantic_p = FALSE; - - options.macro_commands = nullptr; - options.macro_commands_num = 0; - } } // namespace rift \ No newline at end of file From bbb3a4ff5cc16a8165dc8307b31c77b8f7045311 Mon Sep 17 00:00:00 2001 From: muit Date: Fri, 8 Dec 2023 09:48:54 +0100 Subject: [PATCH 09/52] Updated Imgui to 1.90 --- Extern/Pipe | 2 +- Extern/imgui | 2 +- Libs/AST/Src/Compiler/Compiler.cpp | 38 +++++++++---------- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 4 ++ .../MIR/Compiler/Src/IRGeneration.cpp | 2 +- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 2 +- .../MIR/Compiler/Src/MIRBackendModule.cpp | 14 +------ Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 4 +- .../Src/Tools/BigBestFitArenaDebugger.cpp | 6 +-- Libs/Editor/Src/Utils/DetailsPanel.cpp | 7 ++-- Libs/Editor/Src/Utils/ElementsPanel.cpp | 5 +-- Libs/Editor/Src/Utils/FunctionGraph.cpp | 3 +- Libs/UI/Src/Inspection.cpp | 4 +- 13 files changed, 41 insertions(+), 52 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 62f032cd..f25626b0 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 62f032cd0d0bc24c2a060bc825d3bd3173781605 +Subproject commit f25626b02e50c6cd6fe1bee97c892bfe6153aec4 diff --git a/Extern/imgui b/Extern/imgui index bac748fa..ce0d0ac8 160000 --- a/Extern/imgui +++ b/Extern/imgui @@ -1 +1 @@ -Subproject commit bac748fa95ac003c7b354139980f8b4b7f6ac5da +Subproject commit ce0d0ac8298ce164b5d862577e8b087d92f6e90e diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 882b9a7b..2dffe997 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -34,28 +34,28 @@ namespace rift return; } + if (!AST::HasProject(ast)) { - if (!AST::HasProject(ast)) - { - p::Error("No existing project to build."); - return; - } - compiler.config.Init(ast); - - if (auto* nativeBindings = GetModule().Get()) - { - p::Info("Interpret native modules"); - nativeBindings->SyncIncludes(ast); - } - - p::Info("Loading files"); - AST::LoadSystem::Run(ast); - - OptimizationSystem::PruneDisconnectedExpressions(ast); - AST::TypeSystem::PropagateVariableTypes(ast); - AST::TypeSystem::PropagateExpressionTypes(ast); + p::Error("No existing project to build."); + return; + } + + compiler.config.Init(ast); + + if (auto* nativeBindings = GetModule().Get()) + { + p::Info("Interpret native modules"); + nativeBindings->SyncIncludes(ast); } + p::Info("Loading files"); + AST::LoadSystem::Run(ast); + + OptimizationSystem::PruneDisconnectedExpressions(ast); + AST::TypeSystem::PropagateVariableTypes(ast); + AST::TypeSystem::PropagateExpressionTypes(ast); + + p::Info("Building project '{}'", AST::GetProjectName(compiler.ast)); // Clean build folders p::Info("Cleaning previous build"); diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index 21aaa968..40bbb8c6 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -26,6 +26,8 @@ namespace rift::MIR void CToMIR(Compiler& compiler, MIR_context* ctx) { + c2mir_init(ctx); + c2mir_options options; InitCToMIROptions(options); @@ -35,6 +37,8 @@ namespace rift::MIR auto& mirModule = compiler.ast.Get(moduleId); CToMIRModule(compiler, ctx, options, name, mirModule); } + + c2mir_finish(ctx); } void CToMIRModule(Compiler& compiler, MIR_context* ctx, c2mir_options& options, p::Tag name, diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index a15fc2c7..2e499998 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -13,7 +13,7 @@ namespace rift::MIR { - void Generate(Compiler& compiler) + void GenerateC(Compiler& compiler) { MIRAccess access{compiler.ast}; CGenerator cGen{compiler, access}; diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index a754b6b8..0bf04f73 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -44,7 +44,7 @@ namespace rift::MIR CDeclCStruct, CDeclCStatic, p::TWrite, p::TWrite, p::TWrite>; - void Generate(Compiler& compiler); + void GenerateC(Compiler& compiler); struct CGenerator diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index e38b6895..8dd1362b 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -16,7 +16,6 @@ extern "C" { -#include #include #include } @@ -41,15 +40,6 @@ namespace rift void* handler = nullptr; }; - struct Input - { - const char* name = nullptr; - p::u8* currentChar = nullptr; - p::TArray code; - struct c2mir_options options; - }; - - // clang-format off static Lib gStdLibs[] { #if defined(_WIN32) @@ -242,10 +232,9 @@ namespace rift using EntryFunctionPtr = p::i32 (*)(); void MIRBackend::Build(Compiler& compiler) { - MIR::Generate(compiler); + MIR::GenerateC(compiler); MIR_context* ctx = MIR_init(); - c2mir_init(ctx); MIR::CToMIR(compiler, ctx); @@ -307,7 +296,6 @@ namespace rift } CloseSTDLibs(); - c2mir_finish(ctx); MIR_finish(ctx); } } // namespace rift \ No newline at end of file diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index c7094028..33654423 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -378,7 +378,7 @@ namespace rift::Editor { UI::TreeNodeEx( text.c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen); - if (UI::IsItemHovered() && UI::IsKeyReleased(GLFW_KEY_F2)) + if (UI::IsItemHovered() && UI::IsKeyReleased(ImGuiKey_F2)) { renameId = item.id; renameBuffer = Strings::RemoveFromEnd(fileName, ".rf"); @@ -458,7 +458,7 @@ namespace rift::Editor if (IsTypeOpen(ast, item.id)) { - UI::SameLine(ImGui::GetContentRegionAvailWidth(), 0); + UI::SameLine(ImGui::GetContentRegionAvail().x, 0); UI::Bullet(); UI::NewLine(); } diff --git a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp index 7a738139..2f37619c 100644 --- a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp +++ b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp @@ -64,7 +64,7 @@ namespace rift::Editor { return -1; } - const bool hovered = UI::ItemHoverable(frameBox, id); + const bool hovered = UI::ItemHoverable(frameBox, id, ImGuiItemFlags_None); UI::RenderFrame(frameBox.Min, frameBox.Max, UI::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); @@ -196,13 +196,13 @@ namespace rift::Editor const String usedPctLabel = Strings::Format("{:.0f}%% used ({})", usedPct * 100.f, used); const float pctFontSize = (UI::GetFontSize() * usedPctLabel.size()) / 2.f; - UI::SameLine(UI::GetWindowContentRegionWidth() / 2 - pctFontSize / 2, + UI::SameLine(UI::GetContentRegionAvail().x / 2 - pctFontSize / 2, UI::GetStyle().ItemInnerSpacing.x / 2); UI::Text(usedPctLabel); UI::SetItemAllowOverlap(); const float usedFontSize = (UI::GetFontSize() * size.size()) / 2.f; - UI::SameLine(UI::GetWindowContentRegionWidth() - usedFontSize); + UI::SameLine(UI::GetContentRegionAvail().x - usedFontSize); UI::Text(size); UI::PopStyleColor(2); diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index 272e60cf..c32d98b4 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -81,7 +80,7 @@ namespace rift::Editor if (hovered) { - if (UI::IsKeyReleased(GLFW_KEY_DELETE)) + if (UI::IsKeyReleased(ImGuiKey_Delete)) { removePin = true; } @@ -148,7 +147,7 @@ namespace rift::Editor } UI::PushStyleCompact(); UI::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.5f}); - UI::SetNextItemWidth(UI::GetContentRegionAvailWidth()); + UI::SetNextItemWidth(UI::GetContentRegionAvail().x); if (UI::Selectable(ICON_FA_PLUS "##AddInput")) { ScopedChange(ast, id); @@ -175,7 +174,7 @@ namespace rift::Editor } UI::PushStyleCompact(); UI::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f)); - UI::SetNextItemWidth(UI::GetContentRegionAvailWidth()); + UI::SetNextItemWidth(UI::GetContentRegionAvail().x); if (UI::Selectable(ICON_FA_PLUS "##AddOutput")) { ScopedChange(ast, id); diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 0b864acc..9fd4944e 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -61,7 +60,7 @@ namespace rift::Editor { editor.selectedPropertyId = variableId; - if (UI::IsKeyReleased(GLFW_KEY_DELETE)) + if (UI::IsKeyReleased(ImGuiKey_Delete)) { editor.pendingDeletePropertyId = variableId; } @@ -254,7 +253,7 @@ namespace rift::Editor const String windowName = Strings::Format("Elements##{}", typeId); if (UI::Begin(windowName.c_str(), &editor.showElements)) { - UI::SetNextItemWidth(UI::GetContentRegionAvailWidth()); + UI::SetNextItemWidth(UI::GetContentRegionAvail().x); editor.elementsFilter.Draw("##filter"); if (AST::HasVariables(ast, typeId)) diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 139c8532..aefc603f 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -872,7 +871,7 @@ namespace rift::Editor::Graph Nodes::DrawMiniMap(0.2f, Nodes::MiniMapCorner::TopRight); PopNodeStyle(); - if (UI::IsKeyReleased(GLFW_KEY_DELETE)) + if (UI::IsKeyReleased(ImGuiKey_Delete)) { AST::RemoveNodes(ast, Nodes::GetSelectedNodes()); } diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 2e577300..d5ab1fa0 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -138,7 +138,7 @@ namespace rift::UI // Ignore indent on buttons const float widthAvailable = - ImGui::GetContentRegionAvailWidth() + UI::GetCurrentWindow()->DC.Indent.x; + ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; UI::SameLine(widthAvailable - 50.f); UI::PushStyleCompact(); if (UI::Button(ICON_FA_PLUS "##AddItem", v2(16.f, 18.f))) @@ -156,7 +156,7 @@ namespace rift::UI void DrawArrayItemButtons(const ArrayProperty& property, void* instance, i32 index) { const float widthAvailable = - ImGui::GetContentRegionAvailWidth() + UI::GetCurrentWindow()->DC.Indent.x; + ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; UI::SameLine(widthAvailable - 50.f); UI::PushStyleCompact(); static String label; From 9144b90a203810e53ef9ab27b9ccb496f42a3266 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 9 Dec 2023 16:38:47 +0100 Subject: [PATCH 10/52] Debug tool fixes --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Tree.h | 2 + ...{ModuleIterator.h => ModuleFileIterator.h} | 8 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 4 +- Libs/AST/Src/AST/Tree.cpp | 10 ++ Libs/Editor/Include/Tools/ASTDebugger.h | 8 + Libs/Editor/Src/Editor.cpp | 13 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 10 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 5 +- Libs/UI/Include/UI/Inspection.h | 12 +- Libs/UI/Src/Inspection.cpp | 143 ++++++++---------- 11 files changed, 116 insertions(+), 101 deletions(-) rename Libs/AST/Include/AST/Utils/{ModuleIterator.h => ModuleFileIterator.h} (65%) diff --git a/Extern/Pipe b/Extern/Pipe index f25626b0..96d6eaf5 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit f25626b02e50c6cd6fe1bee97c892bfe6153aec4 +Subproject commit 96d6eaf5a19f03b3e53159350688d2b2ee51d011 diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index f00103ab..f5f21639 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -51,6 +51,8 @@ namespace rift::AST static const p::TBroadcast& OnInit(); + String Dump(); + private: void CopyFrom(const Tree& other); void MoveFrom(Tree&& other); diff --git a/Libs/AST/Include/AST/Utils/ModuleIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h similarity index 65% rename from Libs/AST/Include/AST/Utils/ModuleIterator.h rename to Libs/AST/Include/AST/Utils/ModuleFileIterator.h index 568e6033..5ff28fab 100644 --- a/Libs/AST/Include/AST/Utils/ModuleIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -9,14 +9,14 @@ namespace rift::AST { - class ModuleIterator : public p::LambdaFileIterator + class ModuleFileIterator : public p::LambdaFileIterator { using Super = p::LambdaFileIterator; public: using Super::Super; - explicit ModuleIterator(const p::Path& path) + explicit ModuleFileIterator(const p::Path& path) : Super(path, [](const auto& path) { return path.filename() == moduleFilename; }) @@ -24,12 +24,12 @@ namespace rift::AST }; - inline ModuleIterator begin(ModuleIterator it) noexcept + inline ModuleFileIterator begin(ModuleFileIterator it) noexcept { return it; } - inline ModuleIterator end(ModuleIterator) noexcept + inline ModuleFileIterator end(ModuleFileIterator) noexcept { return {}; } diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index 604ac73c..ba6cf366 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -12,7 +12,7 @@ #include "AST/Statics/SModules.h" #include "AST/Statics/SStringLoad.h" #include "AST/Statics/STypes.h" -#include "AST/Utils/ModuleIterator.h" +#include "AST/Utils/ModuleFileIterator.h" #include "AST/Utils/ModuleUtils.h" #include "AST/Utils/TypeIterator.h" #include "AST/Utils/TypeUtils.h" @@ -68,7 +68,7 @@ namespace rift::AST::LoadSystem Id projectId = GetProjectId(ast); auto& projectFile = ast.Get(projectId); - for (const auto& modulePath : ModuleIterator(p::GetParentPath(projectFile.path))) + for (const auto& modulePath : ModuleFileIterator(p::GetParentPath(projectFile.path))) { paths.Add(p::ToString(modulePath)); } diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index b5217941..0b43fd66 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -122,4 +122,14 @@ namespace rift::AST { nativeTypes = other.nativeTypes; } + + String Tree::Dump() + { + String text; + + text.append("Pools: "); + for (const auto& Pool : GetPools()) {} + + return text; + } } // namespace rift::AST diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index a85c9f11..bde90110 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -17,6 +17,12 @@ namespace rift::Editor { + struct EntityInspector + { + static p::i32 IndexCounter; + p::i32 InternalIndex = ++IndexCounter; + }; + struct ASTDebugger { bool open = false; @@ -25,6 +31,8 @@ namespace rift::Editor AST::Id selectedNode = AST::NoId; ImGuiTextFilter filter; + p::TArray EntityInspectors; + ASTDebugger(); diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 0150d6c7..b0e4eab0 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -25,7 +25,18 @@ namespace rift::Editor void RegisterKeyValueInspections() { UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { - UI::DrawKeyValue(label, data, GetType::Entity>()); + auto* id = static_cast(data); + // UI::DrawKeyValue(label, data, GetType::Entity>()); + UI::TableNextRow(); + UI::TableSetColumnIndex(0); + UI::AlignTextToFramePadding(); + UI::Text(label); + UI::TableSetColumnIndex(1); + String asString = p::ToString(*id); + if (UI::InputText("##value", asString)) + { + *id = p::IdFromString(asString); + } }); UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index fe501ed5..da687f5a 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -439,17 +439,17 @@ namespace rift::Editor::EditorSystem auto& module = moduleEditors.Get(moduleId); UI::InspectStruct(&module); - if (UI::BeginInspectHeader("Bindings")) + if (UI::BeginCategory("Bindings", true)) { for (const auto& binding : AST::GetModuleBindings()) { auto* pool = ast.GetPool(binding.tagType->GetId()); if (void* data = pool ? pool->TryGetVoid(moduleId) : nullptr) { - if (UI::BeginInspectHeader(binding.displayName)) + if (UI::BeginCategory(binding.displayName, true)) { - UI::InspectProperties(data, binding.tagType); - UI::EndInspectHeader(); + UI::InspectChildrenProperties({data, binding.tagType}); + UI::EndCategory(); } } else @@ -467,7 +467,7 @@ namespace rift::Editor::EditorSystem UI::PopStyleCompact(); } } - UI::EndInspectHeader(); + UI::EndCategory(); } UI::EndInspector(); } diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index b3dfb9a9..15461548 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -15,6 +15,9 @@ namespace rift::Editor { + p::i32 EntityInspector::IndexCounter = 0; + + void DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open = nullptr) { p::String name = "Entity Inspector"; @@ -52,7 +55,7 @@ namespace rift::Editor auto* dataType = Cast(type); if (data && dataType && UI::BeginInspector("EntityInspector")) { - UI::InspectProperties(data, dataType); + UI::InspectChildrenProperties({data, dataType}); UI::EndInspector(); } UI::Unindent(); diff --git a/Libs/UI/Include/UI/Inspection.h b/Libs/UI/Include/UI/Inspection.h index f72bf02e..b9e48e47 100644 --- a/Libs/UI/Include/UI/Inspection.h +++ b/Libs/UI/Include/UI/Inspection.h @@ -34,12 +34,12 @@ namespace rift::UI void DrawNativeValue(void* data, NativeType* type); void DrawKeyValue(StringView label, void* data, Type* type); - void InspectProperty(const PropertyHandle& property); - void InspectProperties(void* container, DataType* type); + void InspectProperty(const ValueHandle& handle); + void InspectChildrenProperties(const ValueHandle& handle); inline void InspectStruct(Struct* data, StructType* type) { - InspectProperties(data, type); + // InspectChildrenProperties(data, type); } template inline void InspectStruct(T* data) @@ -49,11 +49,11 @@ namespace rift::UI } inline void InspectClass(Class* data, ClassType* type) { - InspectProperties(data, type); + // InspectChildrenProperties(data, type); } - bool BeginInspectHeader(StringView label, bool isLeaf = false); - void EndInspectHeader(); + bool BeginCategory(StringView name, bool isLeaf); + void EndCategory(); bool BeginInspector(const char* name, v2 size = v2{0.f, 0.f}); void EndInspector(); diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index d5ab1fa0..57e703f0 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -132,7 +132,7 @@ namespace rift::UI } } - void DrawArrayValue(bool open, const ArrayProperty& property, void* instance) + void DrawArrayValue(const ArrayProperty& property, void* instance) { UI::Text(Strings::Format("{} items", property.GetSize(instance))); @@ -153,7 +153,7 @@ namespace rift::UI UI::PopStyleCompact(); } - void DrawArrayItemButtons(const ArrayProperty& property, void* instance, i32 index) + void DrawArrayItemButtons(const ValueHandle& handle) { const float widthAvailable = ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; @@ -161,70 +161,15 @@ namespace rift::UI UI::PushStyleCompact(); static String label; label.clear(); - Strings::FormatTo(label, ICON_FA_TIMES "##removeItem_{}", index); + Strings::FormatTo(label, ICON_FA_TIMES "##removeItem_{}", handle.GetIndex()); if (UI::Button(label.c_str(), v2(18.f, 18.f))) { - property.RemoveItem(instance, index); + handle.GetArrayProperty()->RemoveItem(handle.GetContainerPtr(), handle.GetIndex()); } UI::PopStyleCompact(); } - void InspectArrayProperty(const ArrayProperty& property, void* instance) - { - const i32 size = property.GetSize(instance); - const bool open = BeginInspectHeader(property.GetDisplayName().data(), size <= 0); - UI::TableSetColumnIndex(1); - DrawArrayValue(open, property, instance); - if (open) - { - auto* type = property.GetType(); - static String label; - if (auto* structType = Cast(type)) - { - for (i32 i = 0; i < size; ++i) - { - label.clear(); - Strings::FormatTo(label, "{}", i); - const bool open = BeginInspectHeader(label); - if (open) - { - UI::Unindent(); - } - UI::TableSetColumnIndex(1); - DrawArrayItemButtons(property, instance, i); - if (open) - { - UI::Indent(); - InspectProperties(property.GetItem(instance, i), structType); - EndInspectHeader(); - } - } - } - else if (auto* custom = gCustomKeyValues.Find(type)) - { - for (i32 i = 0; i < size; ++i) - { - label.clear(); - Strings::FormatTo(label, "{}", i); - (*custom)(label, property.GetItem(instance, i), type); - DrawArrayItemButtons(property, instance, i); - } - } - else - { - for (i32 i = 0; i < size; ++i) - { - label.clear(); - Strings::FormatTo(label, "{}", i); - DrawKeyValue(label, property.GetItem(instance, i), type); - DrawArrayItemButtons(property, instance, i); - } - } - EndInspectHeader(); - } - } - - void InspectProperty(const PropertyHandle& handle) + void InspectProperty(const ValueHandle& handle) { auto* type = handle.GetType(); if (!type) @@ -234,30 +179,52 @@ namespace rift::UI void* instance = handle.GetPtr(); UI::PushID(instance); - if (auto* arrayProperty = handle.GetArrayProperty()) + + bool isLeaf = false; + if (handle.IsArray()) { - InspectArrayProperty(*arrayProperty, instance); + isLeaf = handle.GetArrayProperty()->GetSize(instance) > 0; } else if (auto* custom = gCustomKeyValues.Find(type)) { (*custom)(handle.GetDisplayName(), instance, type); + UI::PopID(); + return; } else if (auto* structType = Cast(type)) { - if (BeginInspectHeader(handle.GetDisplayName())) - { - InspectProperties(instance, structType); - EndInspectHeader(); - } + isLeaf = !structType->IsEmpty(); } else { DrawKeyValue(handle.GetDisplayName(), instance, type); + UI::PopID(); + return; + } + + bool bOpen = BeginCategory(handle.GetDisplayName(), isLeaf); + + if (handle.IsArray()) + { + UI::TableSetColumnIndex(1); + DrawArrayValue(*handle.GetArrayProperty(), instance); + } + + if (handle.GetIndex()) + { + DrawArrayItemButtons(handle); + } + + + if (bOpen) + { + InspectChildrenProperties(handle); + EndCategory(); } UI::PopID(); } - void InspectProperties(void* container, DataType* type) + void InspectChildrenProperties(const ValueHandle& handle) { if (!EnsureMsg(gCurrentInspector, "Make sure to call Begin/EndInspector around reflection widgets.")) @@ -265,34 +232,48 @@ namespace rift::UI return; } - UI::PushID(container); - - TArray properties; - type->GetProperties(properties); - for (auto* prop : properties) + const auto* type = handle.GetType(); + if (!type) { - InspectProperty(PropertyHandle{*prop, container}); + return; } - UI::PopID(); + if (auto* structType = Cast(type)) + { + void* instance = handle.GetPtr(); + TArray properties; + structType->GetProperties(properties); + for (auto* prop : properties) + { + InspectProperty({instance, prop}); + } + } + else if (handle.IsArray()) + { + auto* arrayProperty = handle.GetArrayProperty(); + void* instance = handle.GetPtr(); + const i32 size = arrayProperty->GetSize(instance); + for (i32 i = 0; i < size; ++i) + { + InspectProperty({handle, i}); + } + } } - bool BeginInspectHeader(StringView label, bool isLeaf) + bool BeginCategory(StringView name, bool isLeaf) { UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::PushHeaderColor(UI::GetNeutralColor(1)); - UI::AlignTextToFramePadding(); const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_AllowItemOverlap | (isLeaf ? ImGuiTreeNodeFlags_Leaf : 0); - const bool isOpen = UI::TreeNodeEx(label.data(), ImGuiTreeNodeFlags_AllowItemOverlap); + bool bOpen = UI::TreeNodeEx(name.data(), ImGuiTreeNodeFlags_AllowItemOverlap); UI::PopHeaderColor(); - return isOpen; + return bOpen; } - - void EndInspectHeader() + void EndCategory() { UI::TreePop(); } From 8199bea1afd2efab3722ac168a363c65167e4dba Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 10 Dec 2023 00:08:12 +0100 Subject: [PATCH 11/52] Improved entity inspectors --- Extern/Pipe | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 14 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 189 +++++++++++++++++------- Libs/UI/Include/UI/Widgets.h | 29 +++- Libs/UI/Src/Inspection.cpp | 14 +- 5 files changed, 170 insertions(+), 78 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 96d6eaf5..7a6542d9 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 96d6eaf5a19f03b3e53159350688d2b2ee51d011 +Subproject commit 7a6542d93dee77a3d82832ab215bc6fb3d84c165 diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index bde90110..10c0a89a 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -17,12 +17,6 @@ namespace rift::Editor { - struct EntityInspector - { - static p::i32 IndexCounter; - p::i32 InternalIndex = ++IndexCounter; - }; - struct ASTDebugger { bool open = false; @@ -31,7 +25,9 @@ namespace rift::Editor AST::Id selectedNode = AST::NoId; ImGuiTextFilter filter; - p::TArray EntityInspectors; + // First inspector is the main inspector + p::TArray inspectorIds{}; + p::i32 pendingInspectorFocusIndex = p::NO_INDEX; ASTDebugger(); @@ -42,5 +38,9 @@ namespace rift::Editor using DrawNodeAccess = p::TAccessRef; void DrawNode(DrawNodeAccess access, AST::Id nodeId, bool showChildren); + + void OnInspectEntity(AST::Id id); + + void DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open = nullptr); }; } // namespace rift::Editor diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 15461548..c3ac38b6 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -2,12 +2,16 @@ #include "Tools/ASTDebugger.h" +#include "imgui.h" +#include "UI/Widgets.h" + #include #include #include #include #include #include +#include #include #include #include @@ -15,56 +19,6 @@ namespace rift::Editor { - p::i32 EntityInspector::IndexCounter = 0; - - - void DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open = nullptr) - { - p::String name = "Entity Inspector"; - if (!IsNone(entityId)) - p::Strings::FormatTo(name, " (id:{})", entityId); - p::Strings::FormatTo(name, "###Entity Inspector"); - UI::Begin(name.c_str(), open); - if (IsNone(entityId)) - { - UI::End(); - return; - } - - const auto& registry = AST::TypeRegistry::Get(); - for (const auto& poolInstance : ast.GetPools()) - { - AST::Type* type = registry.FindType(poolInstance.componentId); - if (!type || !poolInstance.GetPool()->Has(entityId)) - { - continue; - } - - void* data = poolInstance.GetPool()->TryGetVoid(entityId); - static p::String typeName; - typeName = type->GetName(); - - ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen; - if (!data) - { - flags |= ImGuiTreeNodeFlags_Leaf; - } - if (UI::CollapsingHeader(typeName.c_str(), flags)) - { - UI::Indent(); - auto* dataType = Cast(type); - if (data && dataType && UI::BeginInspector("EntityInspector")) - { - UI::InspectChildrenProperties({data, dataType}); - UI::EndInspector(); - } - UI::Unindent(); - } - } - - UI::End(); - } - void DrawTypesDebug(AST::Tree& ast) { if (!UI::CollapsingHeader("Types")) @@ -115,6 +69,7 @@ namespace rift::Editor return; } + ImGui::SetNextWindowSize(ImVec2(400, 700), ImGuiCond_FirstUseEver); UI::Begin("Abstract Syntax Tree", &open); DrawTypesDebug(ast); @@ -184,7 +139,23 @@ namespace rift::Editor } UI::End(); - DrawEntityInspector(ast, selectedNode, &open); + // Inspectors + for (p::i32 i = 0; i < inspectorIds.Size(); ++i) + { + if (pendingInspectorFocusIndex == i) + { + ImGui::SetNextWindowFocus(); + pendingInspectorFocusIndex = p::NO_INDEX; + } + + bool inspectorOpen = true; + DrawEntityInspector(ast, inspectorIds[i], &inspectorOpen); + if (!inspectorOpen) + { + inspectorIds.RemoveAtUnsafe(i, false); + --i; + } + } } void ASTDebugger::DrawNode(DrawNodeAccess access, AST::Id nodeId, bool showChildren) @@ -231,16 +202,18 @@ namespace rift::Editor ImGui::TableNextColumn(); static p::String inspectLabel; inspectLabel.clear(); - p::Strings::FormatTo(inspectLabel, ICON_FA_SEARCH "##{}", nodeId); + + const bool inspected = inspectorIds.Contains(nodeId); + const char* icon = inspected ? ICON_FA_EYE : ICON_FA_EYE_SLASH; + p::Strings::FormatTo(inspectLabel, "{}##{}", icon, nodeId); + UI::PushTextColor(inspected ? UI::whiteTextColor : UI::whiteTextColor.Translucency(0.3f)); UI::PushButtonColor(UI::GetNeutralColor(1)); - UI::PushTextColor( - selectedNode == nodeId ? UI::whiteTextColor : UI::whiteTextColor.Translucency(0.3f)); if (UI::Button(inspectLabel.c_str())) { - selectedNode = nodeId; + OnInspectEntity(nodeId); } - UI::PopTextColor(); UI::PopButtonColor(); + UI::PopTextColor(); ImGui::TableNextColumn(); @@ -299,4 +272,108 @@ namespace rift::Editor UI::TreePop(); } } + + void ASTDebugger::OnInspectEntity(AST::Id id) + { + bool bOpenNewInspector = false; + if (ImGui::GetIO().KeyCtrl) // Inspector found and Ctrl? Open a new one + { + bOpenNewInspector = true; + } + else + { + p::i32 inspectorIndex = inspectorIds.FindIndex(id); + if (inspectorIndex != p::NO_INDEX) // At least one inspector has this entity + { + if (ImGui::GetIO().KeyCtrl) // Inspector found and Ctrl? Open a new one + { + pendingInspectorFocusIndex = inspectorIndex; + } + else + { + inspectorIds.RemoveAtUnsafe(inspectorIndex, false); + } + } + else // Inspector not found + { + bOpenNewInspector = true; + } + } + + + if (bOpenNewInspector) + { + inspectorIds.Add(id); + } + } + + void ASTDebugger::DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open) + { + const bool valid = ast.IsValid(entityId); + const bool removed = ast.WasRemoved(entityId); + + p::String name = "Inspector: "; + p::Strings::FormatTo(name, "{0}{1}###{0}", entityId, removed ? " (removed)" : ""); + + + UI::SetNextWindowPos(ImGui::GetCursorScreenPos() + ImVec2(20, 20), ImGuiCond_Appearing); + UI::SetNextWindowSizeConstraints(ImVec2(300.f, 200.f), ImVec2(800, FLT_MAX)); + UI::BeginOuterStyle(); + UI::PushTextColor(valid && !removed ? UI::whiteTextColor : UI::errorColor); + ImGui::Begin(name.c_str(), open, ImGuiWindowFlags_MenuBar); + UI::PopTextColor(); + UI::BeginInnerStyle(); + + if (ImGui::BeginMenuBar()) + { + // if (ImGui::MenuItem("Clone")) + //{ + // inspectorIds.Add(entityId); + // } + + if (ImGui::BeginMenu("Settings")) + { + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + if (!valid) + { + UI::End(); + return; + } + + const auto& registry = AST::TypeRegistry::Get(); + for (const auto& poolInstance : ast.GetPools()) + { + AST::Type* type = registry.FindType(poolInstance.componentId); + if (!type || !poolInstance.GetPool()->Has(entityId)) + { + continue; + } + + void* data = poolInstance.GetPool()->TryGetVoid(entityId); + static p::String typeName; + typeName = type->GetName(); + + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen; + if (!data) + { + flags |= ImGuiTreeNodeFlags_Leaf; + } + if (UI::CollapsingHeader(typeName.c_str(), flags)) + { + UI::Indent(); + auto* dataType = Cast(type); + if (data && dataType && UI::BeginInspector("EntityInspector")) + { + UI::InspectChildrenProperties({data, dataType}); + UI::EndInspector(); + } + UI::Unindent(); + } + } + UI::End(); + } } // namespace rift::Editor diff --git a/Libs/UI/Include/UI/Widgets.h b/Libs/UI/Include/UI/Widgets.h index 1a44d695..3642e7a1 100644 --- a/Libs/UI/Include/UI/Widgets.h +++ b/Libs/UI/Include/UI/Widgets.h @@ -63,8 +63,7 @@ namespace rift::UI ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* userData = nullptr); - - static bool Begin(const char* name, bool* pOpen = nullptr, ImGuiWindowFlags flags = 0) + static void BeginOuterStyle() { LinearColor titleColor = UI::GetNeutralColor(0); UI::PushStyleColor(ImGuiCol_TitleBg, titleColor); @@ -79,20 +78,34 @@ namespace rift::UI UI::PushStyleColor(ImGuiCol_TabUnfocusedActive, tabColorActive); UI::PushStyleColor(ImGuiCol_TabHovered, UI::Hovered(tabColorActive)); UI::PushTextColor(UI::GetNeutralTextColor(1)); + } + static void BeginInnerStyle() + { + UI::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.f, 3.f)); + } + static void EndOuterStyle() + { + UI::PopTextColor(); + UI::PopStyleColor(8); + } + static void EndInnerStyle() + { + UI::PopStyleVar(); + } + static bool Begin(const char* name, bool* pOpen = nullptr, ImGuiWindowFlags flags = 0) + { + BeginOuterStyle(); const bool value = ImGui::Begin(name, pOpen, flags); - - UI::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.f, 3.f)); + BeginInnerStyle(); return value; } static void End() { - UI::PopStyleVar(); + EndInnerStyle(); ImGui::End(); - UI::PopTextColor(); - UI::PopStyleColor(5); - UI::PopStyleColor(3); + EndOuterStyle(); } ImRect GetWorkRect(v2 desiredSize, bool addhalfItemSpacing = true, v2 extent = v2::Zero()); diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 57e703f0..a3b78fe6 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -188,6 +188,10 @@ namespace rift::UI else if (auto* custom = gCustomKeyValues.Find(type)) { (*custom)(handle.GetDisplayName(), instance, type); + if (handle.IsArrayItem()) + { + DrawArrayItemButtons(handle); + } UI::PopID(); return; } @@ -198,6 +202,10 @@ namespace rift::UI else { DrawKeyValue(handle.GetDisplayName(), instance, type); + if (handle.IsArrayItem()) + { + DrawArrayItemButtons(handle); + } UI::PopID(); return; } @@ -210,12 +218,6 @@ namespace rift::UI DrawArrayValue(*handle.GetArrayProperty(), instance); } - if (handle.GetIndex()) - { - DrawArrayItemButtons(handle); - } - - if (bOpen) { InspectChildrenProperties(handle); From d782aa89fcdd82fb97de6f4900cdfcc88986893c Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 10 Dec 2023 23:03:51 +0100 Subject: [PATCH 12/52] AST debugger improvements --- Extern/Pipe | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 21 ++- Libs/Editor/Src/Tools/ASTDebugger.cpp | 180 ++++++++++++++---------- 3 files changed, 126 insertions(+), 77 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 7a6542d9..fc1dcd27 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 7a6542d93dee77a3d82832ab215bc6fb3d84c165 +Subproject commit fc1dcd27aab132bf42c008820ce4ebdd5045437a diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 10c0a89a..79dafaaa 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -17,6 +17,18 @@ namespace rift::Editor { + struct InspectorPanel + { + AST::Id id = AST::NoId; + bool pendingFocus = true; + bool open = true; + + bool operator==(const InspectorPanel& other) const + { + return id == other.id; + } + }; + struct ASTDebugger { bool open = false; @@ -26,8 +38,8 @@ namespace rift::Editor ImGuiTextFilter filter; // First inspector is the main inspector - p::TArray inspectorIds{}; - p::i32 pendingInspectorFocusIndex = p::NO_INDEX; + InspectorPanel mainInspector; + p::TArray secondaryInspectors; ASTDebugger(); @@ -41,6 +53,9 @@ namespace rift::Editor void OnInspectEntity(AST::Id id); - void DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open = nullptr); + void DrawEntityInspector(p::StringView label, p::StringView id, AST::Tree& ast, + InspectorPanel& inspector, bool* open = nullptr); + + void OpenAvailableSecondaryInspector(AST::Id id); }; } // namespace rift::Editor diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index c3ac38b6..454eb491 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -70,7 +70,7 @@ namespace rift::Editor } ImGui::SetNextWindowSize(ImVec2(400, 700), ImGuiCond_FirstUseEver); - UI::Begin("Abstract Syntax Tree", &open); + UI::Begin(" " ICON_FA_BUG " Abstract Syntax Tree", &open); DrawTypesDebug(ast); @@ -140,20 +140,17 @@ namespace rift::Editor UI::End(); // Inspectors - for (p::i32 i = 0; i < inspectorIds.Size(); ++i) - { - if (pendingInspectorFocusIndex == i) - { - ImGui::SetNextWindowFocus(); - pendingInspectorFocusIndex = p::NO_INDEX; - } + DrawEntityInspector( + " " ICON_FA_LIST_ALT " Inspector", "MainInspector", ast, mainInspector, nullptr); - bool inspectorOpen = true; - DrawEntityInspector(ast, inspectorIds[i], &inspectorOpen); - if (!inspectorOpen) + for (p::i32 i = 0; i < secondaryInspectors.Size(); ++i) + { + InspectorPanel& inspector = secondaryInspectors[i]; + if (inspector.open) { - inspectorIds.RemoveAtUnsafe(i, false); - --i; + p::String id = p::Strings::Format("SecondaryInspector{}", i); + p::String name = p::Strings::Format(" " ICON_FA_LIST " Inspector {}", i + 1); + DrawEntityInspector(name, id, ast, inspector, &inspector.open); } } } @@ -203,8 +200,9 @@ namespace rift::Editor static p::String inspectLabel; inspectLabel.clear(); - const bool inspected = inspectorIds.Contains(nodeId); - const char* icon = inspected ? ICON_FA_EYE : ICON_FA_EYE_SLASH; + const bool inspected = + mainInspector.id == nodeId || secondaryInspectors.Contains(InspectorPanel{nodeId}); + const char* icon = inspected ? ICON_FA_EYE : ICON_FA_EYE_SLASH; p::Strings::FormatTo(inspectLabel, "{}##{}", icon, nodeId); UI::PushTextColor(inspected ? UI::whiteTextColor : UI::whiteTextColor.Translucency(0.3f)); UI::PushButtonColor(UI::GetNeutralColor(1)); @@ -278,43 +276,44 @@ namespace rift::Editor bool bOpenNewInspector = false; if (ImGui::GetIO().KeyCtrl) // Inspector found and Ctrl? Open a new one { - bOpenNewInspector = true; + OpenAvailableSecondaryInspector(id); } else { - p::i32 inspectorIndex = inspectorIds.FindIndex(id); - if (inspectorIndex != p::NO_INDEX) // At least one inspector has this entity + bool wasInspected = secondaryInspectors.RemoveIf([id](const auto& inspector) { + return inspector.id == id; + }) > 0; + if (mainInspector.id == id) { - if (ImGui::GetIO().KeyCtrl) // Inspector found and Ctrl? Open a new one - { - pendingInspectorFocusIndex = inspectorIndex; - } - else - { - inspectorIds.RemoveAtUnsafe(inspectorIndex, false); - } + mainInspector.id = AST::NoId; + wasInspected = true; } - else // Inspector not found + + if (!wasInspected) { - bOpenNewInspector = true; + mainInspector.id = id; + mainInspector.pendingFocus = true; } } - - - if (bOpenNewInspector) - { - inspectorIds.Add(id); - } } - void ASTDebugger::DrawEntityInspector(AST::Tree& ast, AST::Id entityId, bool* open) + void ASTDebugger::DrawEntityInspector(p::StringView label, p::StringView id, AST::Tree& ast, + InspectorPanel& inspector, bool* open) { - const bool valid = ast.IsValid(entityId); - const bool removed = ast.WasRemoved(entityId); + const bool valid = ast.IsValid(inspector.id); + const bool removed = ast.WasRemoved(inspector.id); + bool clone = false; + AST::Id changedId = inspector.id; - p::String name = "Inspector: "; - p::Strings::FormatTo(name, "{0}{1}###{0}", entityId, removed ? " (removed)" : ""); + p::String name; + p::Strings::FormatTo( + name, "{}: {}{}###{}", label, inspector.id, removed ? " (removed)" : "", id); + if (inspector.pendingFocus) + { + ImGui::SetNextWindowFocus(); + inspector.pendingFocus = false; + } UI::SetNextWindowPos(ImGui::GetCursorScreenPos() + ImVec2(20, 20), ImGuiCond_Appearing); UI::SetNextWindowSizeConstraints(ImVec2(300.f, 200.f), ImVec2(800, FLT_MAX)); @@ -322,58 +321,93 @@ namespace rift::Editor UI::PushTextColor(valid && !removed ? UI::whiteTextColor : UI::errorColor); ImGui::Begin(name.c_str(), open, ImGuiWindowFlags_MenuBar); UI::PopTextColor(); - UI::BeginInnerStyle(); if (ImGui::BeginMenuBar()) { - // if (ImGui::MenuItem("Clone")) - //{ - // inspectorIds.Add(entityId); - // } - - if (ImGui::BeginMenu("Settings")) + if (ImGui::BeginMenu(ICON_FA_BARS)) { + ImGui::AlignTextToFramePadding(); + ImGui::Text("Id"); + ImGui::SameLine(); + p::String asString = p::ToString(inspector.id); + ImGui::SetNextItemWidth(100.f); + if (UI::InputText("##IdValue", asString, + ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll)) + { + changedId = p::IdFromString(asString); + } ImGui::EndMenu(); } + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 40.f); + if (ImGui::MenuItem("Clone")) + { + clone = true; + } ImGui::EndMenuBar(); } - if (!valid) - { - UI::End(); - return; - } + UI::BeginInnerStyle(); - const auto& registry = AST::TypeRegistry::Get(); - for (const auto& poolInstance : ast.GetPools()) + if (valid) { - AST::Type* type = registry.FindType(poolInstance.componentId); - if (!type || !poolInstance.GetPool()->Has(entityId)) + const auto& registry = AST::TypeRegistry::Get(); + for (const auto& poolInstance : ast.GetPools()) { - continue; - } + AST::Type* type = registry.FindType(poolInstance.componentId); + if (!type || !poolInstance.GetPool()->Has(inspector.id)) + { + continue; + } - void* data = poolInstance.GetPool()->TryGetVoid(entityId); - static p::String typeName; - typeName = type->GetName(); + void* data = poolInstance.GetPool()->TryGetVoid(inspector.id); + static p::String typeName; + typeName = type->GetName(); - ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen; - if (!data) - { - flags |= ImGuiTreeNodeFlags_Leaf; - } - if (UI::CollapsingHeader(typeName.c_str(), flags)) - { - UI::Indent(); - auto* dataType = Cast(type); - if (data && dataType && UI::BeginInspector("EntityInspector")) + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen; + if (!data) { - UI::InspectChildrenProperties({data, dataType}); - UI::EndInspector(); + flags |= ImGuiTreeNodeFlags_Leaf; + } + if (UI::CollapsingHeader(typeName.c_str(), flags)) + { + UI::Indent(); + auto* dataType = Cast(type); + if (data && dataType && UI::BeginInspector("EntityInspector")) + { + UI::InspectChildrenProperties({data, dataType}); + UI::EndInspector(); + } + UI::Unindent(); } - UI::Unindent(); } } UI::End(); + + // Update after drawing + if (changedId != inspector.id) + { + inspector.id = changedId; + } + + if (clone) + { + OpenAvailableSecondaryInspector(inspector.id); + } + } + + void ASTDebugger::OpenAvailableSecondaryInspector(AST::Id id) + { + p::i32 availableIndex = secondaryInspectors.FindIndex([](const auto& inspector) { + return !inspector.open || inspector.id == AST::NoId; + }); + if (availableIndex != p::NO_INDEX) + { + secondaryInspectors[availableIndex] = {id}; + } + else + { + secondaryInspectors.Add({id}); + } } } // namespace rift::Editor From 5b7bcafff204848cceade55bd0bc5cd4eefd9587 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 6 Jan 2024 12:04:36 +0100 Subject: [PATCH 13/52] Fixes for Ubuntu/GCC/Clang --- .devcontainer/devcontainer.json | 22 ++ Apps/CLI/Src/main.cpp | 1 + CMakeCache.txt | 362 ++++++++++++++++++ CMakeLists.txt | 5 +- Extern/CMakeLists.txt | 62 +-- Extern/Pipe | 2 +- Libs/AST/Include/AST/Utils/ModuleUtils.h | 1 + .../MIR/Compiler/Src/MIRBackendModule.cpp | 14 +- Tools/InitSubmodules.sh | 3 + Tools/Setup.sh | 2 +- 10 files changed, 434 insertions(+), 40 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 CMakeCache.txt create mode 100644 Tools/InitSubmodules.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b332f39d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "Ubuntu", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:jammy" + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index 66825851..b4b03ca3 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -14,6 +14,7 @@ #include #include +#include #include diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 00000000..f5e9e7da --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,362 @@ +# This is the CMakeCache file. +# For build in directory: /home/deck/Documents/rift +# It was generated by CMake: /home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING= + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=CMAKE_CXX_COMPILER-NOTFOUND + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING= + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING= + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING= + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING= + +//C compiler +CMAKE_C_COMPILER:FILEPATH=CMAKE_C_COMPILER-NOTFOUND + +//Flags used by the C compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the C compiler during DEBUG builds. +CMAKE_C_FLAGS_DEBUG:STRING= + +//Flags used by the C compiler during MINSIZEREL builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING= + +//Flags used by the C compiler during RELEASE builds. +CMAKE_C_FLAGS_RELEASE:STRING= + +//Flags used by the C compiler during RELWITHDEBINFO builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/deck/Documents/rift/CMakeFiles/pkgRedirects + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Program used to build from build.ninja files. +CMAKE_MAKE_PROGRAM:FILEPATH=/home/linuxbrew/.linuxbrew/bin/ninja + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=Rift + +//Value Computed by CMake +CMAKE_PROJECT_VERSION:STATIC=0.1 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_MAJOR:STATIC=0 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_MINOR:STATIC=1 + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_PATCH:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_VERSION_TWEAK:STATIC= + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Path to a program. +CMAKE_READELF:FILEPATH=/usr/bin/readelf + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//Path to a program. +CMAKE_TAPI:FILEPATH=CMAKE_TAPI-NOTFOUND + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Value Computed by CMake +Rift_BINARY_DIR:STATIC=/home/deck/Documents/rift + +//Value Computed by CMake +Rift_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +Rift_SOURCE_DIR:STATIC=/home/deck/Documents/rift + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_ADDR2LINE +CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/deck/Documents/rift +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=28 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_DLLTOOL +CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 +//Path to cache edit program executable. +CMAKE_EDIT_COMMAND:INTERNAL=/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/bin/ccmake +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=Unknown +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Ninja +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/deck/Documents/rift +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=0 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_READELF +CMAKE_READELF-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/home/linuxbrew/.linuxbrew/Cellar/cmake/3.28.1/share/cmake +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_TAPI +CMAKE_TAPI-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/usr/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//linker supports push/pop state +_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=TRUE + diff --git a/CMakeLists.txt b/CMakeLists.txt index fc53df9e..8acc9544 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ else() endif() option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(BUILD_STATIC_LIBS "Build static libraries" ON) +option(RIFT_BUILD_EDITOR "Build Editor" ON) option(RIFT_BUILD_TESTS "Build Rift and Core tests" ${RIFT_IS_PROJECT}) @@ -42,7 +43,9 @@ add_subdirectory(Libs) # Executables add_subdirectory(Apps/CLI) -add_subdirectory(Apps/Editor) +if (RIFT_BUILD_EDITOR) + add_subdirectory(Apps/Editor) +endif() # Tests if(BUILD_TESTING AND RIFT_BUILD_TESTS) diff --git a/Extern/CMakeLists.txt b/Extern/CMakeLists.txt index ab31a8ed..d64738fc 100644 --- a/Extern/CMakeLists.txt +++ b/Extern/CMakeLists.txt @@ -13,36 +13,38 @@ set(CLI11_BUILD_TESTS OFF CACHE BOOL "Build CLI11 tests") set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) add_subdirectory(CLI11) -find_package(OpenGL REQUIRED) -add_library(gl3w STATIC gl3w/GL/gl3w.c) -target_include_directories(gl3w PUBLIC gl3w) -target_link_libraries(gl3w INTERFACE OpenGL::GL OpenGL::GLU) - -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "Build the GLFW example programs") -set(GLFW_BUILD_TESTS OFF CACHE BOOL "Build the GLFW test programs") -set(GLFW_BUILD_DOCS OFF CACHE BOOL "Build the GLFW documentation") -add_subdirectory(glfw) - -# Imgui -add_library(imgui STATIC) -target_include_directories(imgui PUBLIC imgui) -target_sources(imgui PRIVATE - imgui/imgui.cpp - imgui/imgui_demo.cpp - imgui/imgui_draw.cpp - imgui/imgui_tables.cpp - imgui/imgui_widgets.cpp - imgui/misc/cpp/imgui_stdlib.cpp - imgui/misc/fonts/binary_to_compressed_c.cpp - imgui/backends/imgui_impl_glfw.cpp - imgui/backends/imgui_impl_opengl3.cpp -) -pipe_target_enable_CPP20(imgui) -set_target_properties (imgui PROPERTIES FOLDER Extern) -target_link_libraries(imgui PRIVATE glfw gl3w) - -add_library(IconFontCppHeaders INTERFACE) -target_include_directories(IconFontCppHeaders INTERFACE IconFontCppHeaders) + +if (RIFT_BUILD_EDITOR) + find_package(OpenGL REQUIRED) + add_library(gl3w STATIC gl3w/GL/gl3w.c) + target_include_directories(gl3w PUBLIC gl3w) + target_link_libraries(gl3w INTERFACE OpenGL::GL OpenGL::GLU) + + set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "Build the GLFW example programs") + set(GLFW_BUILD_TESTS OFF CACHE BOOL "Build the GLFW test programs") + set(GLFW_BUILD_DOCS OFF CACHE BOOL "Build the GLFW documentation") + add_subdirectory(glfw) + + # Imgui + add_library(imgui STATIC) + target_include_directories(imgui PUBLIC imgui) + target_sources(imgui PRIVATE + imgui/imgui.cpp + imgui/imgui_demo.cpp + imgui/imgui_draw.cpp + imgui/imgui_tables.cpp + imgui/imgui_widgets.cpp + imgui/misc/fonts/binary_to_compressed_c.cpp + imgui/backends/imgui_impl_glfw.cpp + imgui/backends/imgui_impl_opengl3.cpp + ) + pipe_target_enable_CPP20(imgui) + set_target_properties (imgui PROPERTIES FOLDER Extern) + target_link_libraries(imgui PRIVATE glfw gl3w) + + add_library(IconFontCppHeaders INTERFACE) + target_include_directories(IconFontCppHeaders INTERFACE IconFontCppHeaders) +endif() set(TF_BUILD_TESTS OFF CACHE BOOL "Enables builds of tests") diff --git a/Extern/Pipe b/Extern/Pipe index fc1dcd27..6b3e8902 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit fc1dcd27aab132bf42c008820ce4ebdd5045437a +Subproject commit 6b3e8902f49386faf6c93d613ba42bb15957c76c diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index dc20eae8..cac9ffa8 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -8,6 +8,7 @@ #include "AST/Tree.h" #include +#include #include diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 8dd1362b..2092503e 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -196,19 +196,19 @@ namespace rift return GetProcAddress; #else if (strcmp(name, "dlopen") == 0) - return dlopen; + return (void*)dlopen; if (strcmp(name, "dlerror") == 0) - return dlerror; + return (void*)dlerror; if (strcmp(name, "dlclose") == 0) - return dlclose; + return (void*)dlclose; if (strcmp(name, "dlsym") == 0) - return dlsym; + return (void*)dlsym; if (strcmp(name, "stat") == 0) - return stat; + return (void*)stat; if (strcmp(name, "lstat") == 0) - return lstat; + return (void*)lstat; if (strcmp(name, "fstat") == 0) - return fstat; + return (void*)fstat; #if defined(__APPLE__) && defined(__aarch64__) if (strcmp(name, "__nan") == 0) return __nan; diff --git a/Tools/InitSubmodules.sh b/Tools/InitSubmodules.sh new file mode 100644 index 00000000..85080ca5 --- /dev/null +++ b/Tools/InitSubmodules.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +git submodule update --init --recursive diff --git a/Tools/Setup.sh b/Tools/Setup.sh index e2ab3455..d10f182a 100644 --- a/Tools/Setup.sh +++ b/Tools/Setup.sh @@ -10,4 +10,4 @@ sudo apt -y install libx11-dev xorg-dev xlibmesa-glu-dev #libglu1-mesa-devz sudo apt -y install gdb -sudo apt -y install cmake +sudo apt -y install cmake ninja-build From ed216c8f5f838f4211b96d3920fbc4630911d523 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 6 Jan 2024 12:29:12 +0100 Subject: [PATCH 14/52] [CICD] Use GCC 13 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0af0fc8..022aefb4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,8 +45,8 @@ jobs: os: ubuntu-latest os-name: linux compiler: gcc - cxx: g++-10 - cc: gcc-10 + cxx: g++-13 + cc: gcc-13 - name: macos-clang os: macos-latest os-name: macos From 04543958ec1d1472cbb590fffa87df9511193b8f Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 14 Jan 2024 23:15:57 +0100 Subject: [PATCH 15/52] Implemented dumping basic pool info --- .devcontainer/devcontainer.json | 22 ---------------------- Examples/Project/imgui.ini | 12 ------------ Libs/AST/Include/AST/Tree.h | 2 +- Libs/AST/Src/AST/Tree.cpp | 11 ++++++++--- Libs/AST/Src/Compiler/Compiler.cpp | 1 + 5 files changed, 10 insertions(+), 38 deletions(-) delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 Examples/Project/imgui.ini diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index b332f39d..00000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,22 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu -{ - "name": "Ubuntu", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:jammy" - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} diff --git a/Examples/Project/imgui.ini b/Examples/Project/imgui.ini deleted file mode 100644 index 575ebe25..00000000 --- a/Examples/Project/imgui.ini +++ /dev/null @@ -1,12 +0,0 @@ -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][Project Manager] -Pos=340,250 -Size=600,400 -Collapsed=0 - -[Docking][Data] - diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index f5f21639..be70f2cc 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -51,7 +51,7 @@ namespace rift::AST static const p::TBroadcast& OnInit(); - String Dump(); + String DumpPools(); private: void CopyFrom(const Tree& other); diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index 0b43fd66..a6fa64a8 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -123,12 +123,17 @@ namespace rift::AST nativeTypes = other.nativeTypes; } - String Tree::Dump() + String Tree::DumpPools() { String text; - text.append("Pools: "); - for (const auto& Pool : GetPools()) {} + text.append("Pools: \n"); + for (const auto& pool : GetPools()) + { + p::Type* type = p::TypeRegistry::Get().FindType(pool.GetId()); + p::Strings::FormatTo(text, "- {} x{}\n", + type ? type->GetName() : p::StringView{"NotReflected"}, pool.GetPool()->Size()); + } return text; } diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 2dffe997..d91559c6 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -52,6 +52,7 @@ namespace rift AST::LoadSystem::Run(ast); OptimizationSystem::PruneDisconnectedExpressions(ast); + p::Info(ast.DumpPools()); AST::TypeSystem::PropagateVariableTypes(ast); AST::TypeSystem::PropagateExpressionTypes(ast); From 28273b590f5f63d480e544d13fae2a9ecb9a3ae8 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 17 Jan 2024 23:54:06 +0100 Subject: [PATCH 16/52] Fixed two build crashes --- Examples/Project/Welcome.rf | 7 ++++--- Extern/Pipe | 2 +- Libs/AST/Src/Compiler/Compiler.cpp | 1 - Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp | 9 +++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Examples/Project/Welcome.rf b/Examples/Project/Welcome.rf index 0383c77c..2fc8d84b 100644 --- a/Examples/Project/Welcome.rf +++ b/Examples/Project/Welcome.rf @@ -118,10 +118,11 @@ "9": [ "U32" ], - "10": [], + "10": [ + "String" + ], "11": [ - "TestProject", - "TestStruct" + "String" ] }, "CNodePosition": { diff --git a/Extern/Pipe b/Extern/Pipe index 6b3e8902..aa56c609 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 6b3e8902f49386faf6c93d613ba42bb15957c76c +Subproject commit aa56c60974191d813dcdb44e5fd8198d89e8176c diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index d91559c6..2dffe997 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -52,7 +52,6 @@ namespace rift AST::LoadSystem::Run(ast); OptimizationSystem::PruneDisconnectedExpressions(ast); - p::Info(ast.DumpPools()); AST::TypeSystem::PropagateVariableTypes(ast); AST::TypeSystem::PropagateExpressionTypes(ast); diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 2e499998..0b9369e8 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -206,9 +206,10 @@ namespace rift::MIR Tag inputName = AST::GetName(access, inputId); - AST::Id typeId = access.Get(inputId).id; - const auto* irType = access.TryGet(typeId); - if (irType) + auto* exprId = access.TryGet(inputId); + const auto* irType = + exprId ? access.TryGet(exprId->id) : nullptr; + if (irType) [[likely]] { Strings::FormatTo(signature, "{0} {1}, ", inputName, irType->value); } @@ -220,7 +221,7 @@ namespace rift::MIR inputName, functionName)); } } - Strings::RemoveFromEnd(signature, ','); + Strings::RemoveCharFromEnd(signature, ','); } signature.push_back(')'); From c7aa0ca0adc6586deda2f3ae47a820dddf19b1f6 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 31 Jan 2024 22:15:59 +0100 Subject: [PATCH 17/52] Simplified component declarations --- Extern/IconFontCppHeaders | 2 +- Libs/AST/Include/AST/Components/CDeclClass.h | 13 - .../Include/AST/Components/CDeclFunction.h | 13 - Libs/AST/Include/AST/Components/CDeclNative.h | 13 - Libs/AST/Include/AST/Components/CDeclRecord.h | 13 - Libs/AST/Include/AST/Components/CDeclStatic.h | 13 - Libs/AST/Include/AST/Components/CDeclStruct.h | 13 - Libs/AST/Include/AST/Components/CDeclType.h | 16 - .../Include/AST/Components/CDeclVariable.h | 19 -- .../AST/Include/AST/Components/CDeclaration.h | 23 -- .../AST/Components/CExprBinaryOperator.h | 52 ---- Libs/AST/Include/AST/Components/CExprCall.h | 44 --- .../AST/Include/AST/Components/CExprDeclRef.h | 27 -- Libs/AST/Include/AST/Components/CExprInputs.h | 70 ----- .../AST/Include/AST/Components/CExprOutputs.h | 64 ---- Libs/AST/Include/AST/Components/CExprType.h | 56 ---- .../AST/Components/CExprUnaryOperator.h | 36 --- Libs/AST/Include/AST/Components/CExpression.h | 13 - Libs/AST/Include/AST/Components/CLiteral.h | 13 - .../AST/Include/AST/Components/CLiteralBool.h | 16 - .../Include/AST/Components/CLiteralFloating.h | 40 --- .../Include/AST/Components/CLiteralIntegral.h | 60 ---- .../Include/AST/Components/CLiteralString.h | 18 -- Libs/AST/Include/AST/Components/CStatement.h | 13 - Libs/AST/Include/AST/Components/CStmtFor.h | 13 - Libs/AST/Include/AST/Components/CStmtIf.h | 13 - Libs/AST/Include/AST/Components/CStmtInput.h | 29 -- .../AST/Include/AST/Components/CStmtOutputs.h | 45 --- Libs/AST/Include/AST/Components/CStmtReturn.h | 17 - .../AST/Include/AST/Components/Declarations.h | 62 ++++ Libs/AST/Include/AST/Components/Expressions.h | 291 ++++++++++++++++++ Libs/AST/Include/AST/Components/Literals.h | 104 +++++++ Libs/AST/Include/AST/Components/Statements.h | 83 +++++ Libs/AST/Include/AST/Components/Tags/CDirty.h | 3 +- .../AST/Include/AST/Systems/FunctionsSystem.h | 6 +- Libs/AST/Include/AST/Systems/TypeSystem.h | 10 +- Libs/AST/Include/AST/TypeRef.h | 2 +- Libs/AST/Include/AST/Utils/Expressions.h | 5 +- Libs/AST/Include/AST/Utils/Statements.h | 4 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 13 +- Libs/AST/Include/Rift.h | 3 +- Libs/AST/Include/View.h | 2 +- Libs/AST/Src/AST/Systems/FunctionsSystem.cpp | 5 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 6 +- Libs/AST/Src/AST/Tree.cpp | 4 +- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 2 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 22 +- Libs/AST/Src/ASTModule.cpp | 5 +- Libs/Backends/MIR/Compiler/Src/C2MIR.h | 24 +- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 24 +- .../Include/Components/CDeclCStatic.h | 13 - .../{CDeclCStruct.h => Declarations.h} | 7 +- .../Compiler/Src/NativeBindingModule.cpp | 4 +- .../Editor/Include/Panels/FileExplorerPanel.h | 3 +- Libs/Editor/Include/Utils/DetailsPanel.h | 10 +- Libs/Editor/Include/Utils/ElementsPanel.h | 10 +- Libs/Editor/Include/Utils/TypeUtils.h | 5 +- Libs/Editor/Include/Utils/Widgets.h | 6 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 3 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 2 +- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 2 +- Libs/Editor/Src/Utils/EditorStyle.cpp | 4 +- Libs/Editor/Src/Utils/FunctionGraph.cpp | 23 +- .../Src/Utils/FunctionGraphContextMenu.cpp | 6 +- 64 files changed, 612 insertions(+), 943 deletions(-) delete mode 100644 Libs/AST/Include/AST/Components/CDeclClass.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclFunction.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclNative.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclRecord.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclStatic.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclStruct.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclType.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclVariable.h delete mode 100644 Libs/AST/Include/AST/Components/CDeclaration.h delete mode 100644 Libs/AST/Include/AST/Components/CExprBinaryOperator.h delete mode 100644 Libs/AST/Include/AST/Components/CExprCall.h delete mode 100644 Libs/AST/Include/AST/Components/CExprDeclRef.h delete mode 100644 Libs/AST/Include/AST/Components/CExprInputs.h delete mode 100644 Libs/AST/Include/AST/Components/CExprOutputs.h delete mode 100644 Libs/AST/Include/AST/Components/CExprType.h delete mode 100644 Libs/AST/Include/AST/Components/CExprUnaryOperator.h delete mode 100644 Libs/AST/Include/AST/Components/CExpression.h delete mode 100644 Libs/AST/Include/AST/Components/CLiteral.h delete mode 100644 Libs/AST/Include/AST/Components/CLiteralBool.h delete mode 100644 Libs/AST/Include/AST/Components/CLiteralFloating.h delete mode 100644 Libs/AST/Include/AST/Components/CLiteralIntegral.h delete mode 100644 Libs/AST/Include/AST/Components/CLiteralString.h delete mode 100644 Libs/AST/Include/AST/Components/CStatement.h delete mode 100644 Libs/AST/Include/AST/Components/CStmtFor.h delete mode 100644 Libs/AST/Include/AST/Components/CStmtIf.h delete mode 100644 Libs/AST/Include/AST/Components/CStmtInput.h delete mode 100644 Libs/AST/Include/AST/Components/CStmtOutputs.h delete mode 100644 Libs/AST/Include/AST/Components/CStmtReturn.h create mode 100644 Libs/AST/Include/AST/Components/Declarations.h create mode 100644 Libs/AST/Include/AST/Components/Expressions.h create mode 100644 Libs/AST/Include/AST/Components/Literals.h create mode 100644 Libs/AST/Include/AST/Components/Statements.h delete mode 100644 Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h rename Libs/Bindings/Native/Compiler/Include/Components/{CDeclCStruct.h => Declarations.h} (60%) diff --git a/Extern/IconFontCppHeaders b/Extern/IconFontCppHeaders index 8a7a57fa..6a2e60d2 160000 --- a/Extern/IconFontCppHeaders +++ b/Extern/IconFontCppHeaders @@ -1 +1 @@ -Subproject commit 8a7a57fa7b4b39b9f8436e3227ced13624028568 +Subproject commit 6a2e60d2b270e41a711612cc2a1eb4c9bde701a9 diff --git a/Libs/AST/Include/AST/Components/CDeclClass.h b/Libs/AST/Include/AST/Components/CDeclClass.h deleted file mode 100644 index 9bc6ecc1..00000000 --- a/Libs/AST/Include/AST/Components/CDeclClass.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclRecord.h" - - -namespace rift::AST -{ - struct CDeclClass : public CDeclRecord - { - P_STRUCT(CDeclClass, CDeclRecord) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclFunction.h b/Libs/AST/Include/AST/Components/CDeclFunction.h deleted file mode 100644 index 69991794..00000000 --- a/Libs/AST/Include/AST/Components/CDeclFunction.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclaration.h" - - -namespace rift::AST -{ - struct CDeclFunction : public CDeclaration - { - P_STRUCT(CDeclFunction, CDeclaration) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclNative.h b/Libs/AST/Include/AST/Components/CDeclNative.h deleted file mode 100644 index 5f55da9a..00000000 --- a/Libs/AST/Include/AST/Components/CDeclNative.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclRecord.h" - - -namespace rift::AST -{ - struct CDeclNative : public CDeclRecord - { - P_STRUCT(CDeclNative, CDeclRecord) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclRecord.h b/Libs/AST/Include/AST/Components/CDeclRecord.h deleted file mode 100644 index d10016ce..00000000 --- a/Libs/AST/Include/AST/Components/CDeclRecord.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclaration.h" - - -namespace rift::AST -{ - struct CDeclRecord : public CDeclaration - { - P_STRUCT(CDeclRecord, CDeclaration) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclStatic.h b/Libs/AST/Include/AST/Components/CDeclStatic.h deleted file mode 100644 index bc66e2b2..00000000 --- a/Libs/AST/Include/AST/Components/CDeclStatic.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclaration.h" - - -namespace rift::AST -{ - struct CDeclStatic : public CDeclaration - { - P_STRUCT(CDeclStatic, CDeclaration) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclStruct.h b/Libs/AST/Include/AST/Components/CDeclStruct.h deleted file mode 100644 index 08d96334..00000000 --- a/Libs/AST/Include/AST/Components/CDeclStruct.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclRecord.h" - - -namespace rift::AST -{ - struct CDeclStruct : public CDeclRecord - { - P_STRUCT(CDeclStruct, CDeclRecord, ) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclType.h b/Libs/AST/Include/AST/Components/CDeclType.h deleted file mode 100644 index f2abf6ef..00000000 --- a/Libs/AST/Include/AST/Components/CDeclType.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CDeclType : public p::Struct - { - P_STRUCT(CDeclType, p::Struct) - - P_PROP(typeId) - p::Tag typeId; - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclVariable.h b/Libs/AST/Include/AST/Components/CDeclVariable.h deleted file mode 100644 index 3dbd317b..00000000 --- a/Libs/AST/Include/AST/Components/CDeclVariable.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CDeclaration.h" -#include "AST/Id.h" - -#include - - -namespace rift::AST -{ - struct CDeclVariable : public CDeclaration - { - P_STRUCT(CDeclVariable, CDeclaration) - - P_PROP(typeId, p::Prop_NotSerialized) - Id typeId = NoId; - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CDeclaration.h b/Libs/AST/Include/AST/Components/CDeclaration.h deleted file mode 100644 index 8925ddb8..00000000 --- a/Libs/AST/Include/AST/Components/CDeclaration.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CDeclaration : public p::Struct - { - P_STRUCT(CDeclaration, p::Struct) - }; - -} // namespace rift::AST - -namespace std -{ - template T> - struct is_empty - { - static constexpr bool value = false; - }; -} // namespace std diff --git a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h b/Libs/AST/Include/AST/Components/CExprBinaryOperator.h deleted file mode 100644 index 9bea5616..00000000 --- a/Libs/AST/Include/AST/Components/CExprBinaryOperator.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include - - -namespace rift::AST -{ - enum class BinaryOperatorType : u8 - { - // Mathematic - Add, // + - Sub, // - - Mul, // * - Div, // / - Mod, // % - - // Comparison - Equal, // == - NotEqual, // != - Greater, // > - Less, // < - GreaterOrEqual, // >= - LessOrEqual, // <= - - // Logical - And, // && - Or, // || - BitAnd, // & - BitOr, // | - Xor // ^ - }; -} // namespace rift::AST -ENUM(rift::AST::BinaryOperatorType) - - -namespace rift::AST -{ - struct CExprBinaryOperator : public CExpression - { - P_STRUCT(CExprBinaryOperator, CExpression) - - P_PROP(type) - BinaryOperatorType type = BinaryOperatorType::Add; - - - CExprBinaryOperator() = default; - CExprBinaryOperator(BinaryOperatorType type) : type{type} {} - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprCall.h b/Libs/AST/Include/AST/Components/CExprCall.h deleted file mode 100644 index c2508c2f..00000000 --- a/Libs/AST/Include/AST/Components/CExprCall.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CExpression.h" -#include "AST/Components/CNamespace.h" -#include "AST/Id.h" - -#include -#include - - -namespace rift::AST -{ - struct CExprCall : public CExpression - { - P_STRUCT(CExprCall, CExpression) - - P_PROP(function) - Namespace function; - }; - - inline void Read(p::Reader& ct, CExprCall& val) - { - ct.Serialize(val.function); - } - inline void Write(p::Writer& ct, const CExprCall& val) - { - ct.Serialize(val.function); - } - - - // Data pointing to the id of the function from CExprCall's type and function names - struct CExprCallId : public CExpression - { - P_STRUCT(CExprCallId, CExpression, p::Struct_NotSerialized) - - // Id pointing to the function declaration - P_PROP(functionId) - Id functionId = NoId; - - - CExprCallId(Id functionId = NoId) : functionId{functionId} {} - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprDeclRef.h b/Libs/AST/Include/AST/Components/CExprDeclRef.h deleted file mode 100644 index a1621e7f..00000000 --- a/Libs/AST/Include/AST/Components/CExprDeclRef.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CExpression.h" - - -namespace rift::AST -{ - struct CExprDeclRef : public CExpression - { - P_STRUCT(CExprDeclRef, CExpression) - - P_PROP(ownerName) - p::Tag ownerName; - - P_PROP(name) - p::Tag name; - }; - - struct CExprDeclRefId : public CExpression - { - P_STRUCT(CExprDeclRefId, CExpression) - - P_PROP(declarationId) - Id declarationId; - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprInputs.h b/Libs/AST/Include/AST/Components/CExprInputs.h deleted file mode 100644 index a2e61b66..00000000 --- a/Libs/AST/Include/AST/Components/CExprInputs.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include -#include - - - -namespace rift::AST -{ - struct ExprOutput : public p::Struct - { - P_STRUCT(ExprOutput, p::Struct) - - P_PROP(nodeId) - AST::Id nodeId = AST::NoId; - - P_PROP(pinId) - AST::Id pinId = AST::NoId; - - - ExprOutput() = default; - - bool IsNone() const - { - return p::IsNone(nodeId) || p::IsNone(pinId); - } - }; - - struct CExprInputs : public p::Struct - { - P_STRUCT(CExprInputs, p::Struct) - - P_PROP(linkedOutputs) - p::TArray linkedOutputs; - - P_PROP(pinIds) - p::TArray pinIds; - - - CExprInputs& Add(AST::Id pinId) - { - linkedOutputs.Add(); - pinIds.Add(pinId); - return *this; - } - - CExprInputs& Insert(p::i32 index, AST::Id pinId) - { - pinIds.Insert(index, pinId); - linkedOutputs.Insert(index); - return *this; - } - - CExprInputs& Swap(p::i32 firstIndex, p::i32 secondIndex) - { - pinIds.Swap(firstIndex, secondIndex); - linkedOutputs.Swap(firstIndex, secondIndex); - return *this; - } - - void Resize(p::i32 count) - { - linkedOutputs.Resize(count); - pinIds.Resize(count, AST::NoId); - } - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprOutputs.h b/Libs/AST/Include/AST/Components/CExprOutputs.h deleted file mode 100644 index c273e0e8..00000000 --- a/Libs/AST/Include/AST/Components/CExprOutputs.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include -#include - - - -namespace rift::AST -{ - struct ExprInput : public p::Struct - { - P_STRUCT(ExprInput, p::Struct) - - P_PROP(nodeId) - AST::Id nodeId = AST::NoId; - - P_PROP(pinId) - AST::Id pinId = AST::NoId; - - - ExprInput() = default; - - bool IsNone() const - { - return p::IsNone(nodeId) || p::IsNone(pinId); - } - }; - - struct CExprOutputs : public p::Struct - { - P_STRUCT(CExprOutputs, p::Struct) - - P_PROP(pinIds) - p::TArray pinIds; - - - CExprOutputs() {} - CExprOutputs(AST::Id pinId) - { - Add(pinId); - } - - CExprOutputs& Add(AST::Id pinId) - { - pinIds.Add(pinId); - return *this; - } - - CExprOutputs& Insert(p::i32 index, AST::Id pinId) - { - pinIds.Insert(index, pinId); - return *this; - } - - CExprOutputs& Swap(p::i32 firstIndex, p::i32 secondIndex) - { - pinIds.Swap(firstIndex, secondIndex); - return *this; - } - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprType.h b/Libs/AST/Include/AST/Components/CExprType.h deleted file mode 100644 index 32f49994..00000000 --- a/Libs/AST/Include/AST/Components/CExprType.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CNamespace.h" -#include "AST/Id.h" - -#include - - -namespace rift::AST -{ - enum class TypeMode - { - Value, - Pointer, - PointerToPointer - }; -} // namespace rift::AST -ENUM(rift::AST::TypeMode) - - -namespace rift::AST -{ - struct CExprType : public p::Struct - { - P_STRUCT(CExprType, p::Struct) - - P_PROP(type) - AST::Namespace type; - - P_PROP(mode) - TypeMode mode = TypeMode::Value; - }; - - static void Read(p::Reader& ct, CExprType& val) - { - ct.Serialize(val.type); - } - static void Write(p::Writer& ct, const CExprType& val) - { - ct.Serialize(val.type); - } - - - struct CExprTypeId : public p::Struct - { - P_STRUCT(CExprTypeId, p::Struct) - - P_PROP(id, p::Prop_NotSerialized) - AST::Id id = AST::NoId; - - P_PROP(mode) - TypeMode mode = TypeMode::Value; - }; - -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExprUnaryOperator.h b/Libs/AST/Include/AST/Components/CExprUnaryOperator.h deleted file mode 100644 index 8d6fa78c..00000000 --- a/Libs/AST/Include/AST/Components/CExprUnaryOperator.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include - - -namespace rift::AST -{ - enum class UnaryOperatorType : p::u8 - { - Not, // ! - Negation, // - - Increment, // ++ - Decrement, // -- - BitNot, // ~ - }; -} // namespace rift::AST -ENUM(rift::AST::UnaryOperatorType) - - -namespace rift::AST -{ - struct CExprUnaryOperator : public CExpression - { - P_STRUCT(CExprUnaryOperator, CExpression) - - P_PROP(type) - UnaryOperatorType type = UnaryOperatorType::Not; - - - CExprUnaryOperator() = default; - CExprUnaryOperator(UnaryOperatorType type) : type{type} {} - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CExpression.h b/Libs/AST/Include/AST/Components/CExpression.h deleted file mode 100644 index a229af20..00000000 --- a/Libs/AST/Include/AST/Components/CExpression.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CExpression : public p::Struct - { - P_STRUCT(CExpression, p::Struct) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteral.h b/Libs/AST/Include/AST/Components/CLiteral.h deleted file mode 100644 index eecc900d..00000000 --- a/Libs/AST/Include/AST/Components/CLiteral.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CLiteral : public p::Struct - { - P_STRUCT(CLiteral, p::Struct) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralBool.h b/Libs/AST/Include/AST/Components/CLiteralBool.h deleted file mode 100644 index efe8abbe..00000000 --- a/Libs/AST/Include/AST/Components/CLiteralBool.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CLiteral.h" - - -namespace rift::AST -{ - struct CLiteralBool : public CLiteral - { - P_STRUCT(CLiteralBool, CLiteral) - - P_PROP(value) - bool value = false; - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralFloating.h b/Libs/AST/Include/AST/Components/CLiteralFloating.h deleted file mode 100644 index 372e0cc2..00000000 --- a/Libs/AST/Include/AST/Components/CLiteralFloating.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CLiteral.h" - -#include -#include - - -namespace rift::AST -{ - enum class FloatingType : u8 - { - F32 = 32, - F64 = 64 - }; -} // namespace rift::AST -ENUM(rift::AST::FloatingType) - - -namespace rift::AST -{ - struct CLiteralFloating : public CLiteral - { - P_STRUCT(CLiteralFloating, CLiteral) - - - P_PROP(value) - double value = 0.; - - P_PROP(type) - FloatingType type = FloatingType::F32; - - - u8 GetSize() const - { - return static_cast>(type); - } - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralIntegral.h b/Libs/AST/Include/AST/Components/CLiteralIntegral.h deleted file mode 100644 index b219d4fb..00000000 --- a/Libs/AST/Include/AST/Components/CLiteralIntegral.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CLiteral.h" - -#include -#include - - -namespace rift::AST -{ - static constexpr u8 literalUnsignedMask = 1 << 7; // Last bit marks type as unsigned - - enum class IntegralType : u8 - { - S8 = 8, - S16 = 16, - S32 = 32, - S64 = 64, - U8 = S8 | literalUnsignedMask, - U16 = S16 | literalUnsignedMask, - U32 = S32 | literalUnsignedMask, - U64 = S64 | literalUnsignedMask - }; -} // namespace rift::AST -ENUM(rift::AST::IntegralType) -template<> -struct magic_enum::customize::enum_range -{ - static constexpr int min = 0; - static constexpr int max = 256; - // static constexpr bool is_flags = true; - // (max - min) must be less than UINT16_MAX. -}; - - -namespace rift::AST -{ - struct CLiteralIntegral : public CLiteral - { - P_STRUCT(CLiteralIntegral, CLiteral) - - - P_PROP(value) - u64 value = 0; - - P_PROP(type) - IntegralType type = IntegralType::S32; - - - bool IsSigned() const - { - return u8(type) & literalUnsignedMask == literalUnsignedMask; - } - u8 GetSize() const - { - return u8(type) & ~literalUnsignedMask; - } - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CLiteralString.h b/Libs/AST/Include/AST/Components/CLiteralString.h deleted file mode 100644 index befb91e9..00000000 --- a/Libs/AST/Include/AST/Components/CLiteralString.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CLiteral.h" - -#include - - -namespace rift::AST -{ - struct CLiteralString : public CLiteral - { - P_STRUCT(CLiteralString, CLiteral) - - P_PROP(value) - p::String value; - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStatement.h b/Libs/AST/Include/AST/Components/CStatement.h deleted file mode 100644 index fd33f30d..00000000 --- a/Libs/AST/Include/AST/Components/CStatement.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CStatement : public p::Struct - { - P_STRUCT(CStatement, p::Struct) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtFor.h b/Libs/AST/Include/AST/Components/CStmtFor.h deleted file mode 100644 index 534b5676..00000000 --- a/Libs/AST/Include/AST/Components/CStmtFor.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CStmtFor : public p::Struct - { - P_STRUCT(CStmtFor, p::Struct) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtIf.h b/Libs/AST/Include/AST/Components/CStmtIf.h deleted file mode 100644 index 81d75566..00000000 --- a/Libs/AST/Include/AST/Components/CStmtIf.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift::AST -{ - struct CStmtIf : public p::Struct - { - P_STRUCT(CStmtIf, p::Struct) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtInput.h b/Libs/AST/Include/AST/Components/CStmtInput.h deleted file mode 100644 index bb2a6c8f..00000000 --- a/Libs/AST/Include/AST/Components/CStmtInput.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include - - -namespace rift::AST -{ - using namespace p; - - struct CStmtInput : public Struct - { - P_STRUCT(CStmtInput, Struct) - - P_PROP(linkOutputNode) - Id linkOutputNode = NoId; - }; - - static void Read(Reader& ct, CStmtInput& val) - { - ct.Serialize(val.linkOutputNode); - } - static void Write(Writer& ct, const CStmtInput& val) - { - ct.Serialize(val.linkOutputNode); - } -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtOutputs.h b/Libs/AST/Include/AST/Components/CStmtOutputs.h deleted file mode 100644 index ec248698..00000000 --- a/Libs/AST/Include/AST/Components/CStmtOutputs.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Id.h" - -#include -#include - - -namespace rift::AST -{ - struct CStmtOutput : public p::Struct - { - P_STRUCT(CStmtOutput, p::Struct) - - P_PROP(linkInputNode) - Id linkInputNode = NoId; - }; - - - struct CStmtOutputs : public p::Struct - { - P_STRUCT(CStmtOutputs, p::Struct) - - // Both arrays keep the same index to the input node and the output pin - P_PROP(pinIds) - TArray pinIds; - P_PROP(linkInputNodes) - TArray linkInputNodes; - - - CStmtOutputs() = default; - CStmtOutputs(p::TArray pins) : pinIds{Move(pins)}, linkInputNodes(pinIds.Size(), NoId) - {} - }; - - static void Read(Reader& ct, CStmtOutput& val) - { - ct.Serialize(val.linkInputNode); - } - static void Write(Writer& ct, const CStmtOutput& val) - { - ct.Serialize(val.linkInputNode); - } -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/CStmtReturn.h b/Libs/AST/Include/AST/Components/CStmtReturn.h deleted file mode 100644 index 8c91c72b..00000000 --- a/Libs/AST/Include/AST/Components/CStmtReturn.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include "AST/Components/CExpression.h" - - -namespace rift::AST -{ - /** Represents a return expression of a function - * Return arguments are dynamically populated depending on the function this expression is - * connected to. - */ - struct CStmtReturn : public CExpression - { - P_STRUCT(CStmtReturn, CExpression) - }; -} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Declarations.h b/Libs/AST/Include/AST/Components/Declarations.h new file mode 100644 index 00000000..02fb48eb --- /dev/null +++ b/Libs/AST/Include/AST/Components/Declarations.h @@ -0,0 +1,62 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include +#include + + +namespace rift::AST +{ + struct CDeclStatic : public p::Struct + { + P_STRUCT(CDeclStatic, p::Struct) + }; + + + struct CDeclRecord : public p::Struct + { + P_STRUCT(CDeclRecord, p::Struct) + }; + + + struct CDeclStruct : public CDeclRecord + { + P_STRUCT(CDeclStruct, CDeclRecord, ) + }; + + + struct CDeclClass : public CDeclRecord + { + P_STRUCT(CDeclClass, CDeclRecord) + }; + + + struct CDeclType : public p::Struct + { + P_STRUCT(CDeclType, p::Struct) + + P_PROP(typeId) + p::Tag typeId; + }; + + + struct CDeclNative : public CDeclRecord + { + P_STRUCT(CDeclNative, CDeclRecord) + }; + + + struct CDeclFunction : public p::Struct + { + P_STRUCT(CDeclFunction, p::Struct) + }; + + + struct CDeclVariable : public p::Struct + { + P_STRUCT(CDeclVariable, p::Struct) + + P_PROP(typeId, p::Prop_NotSerialized) + p::Id typeId = p::NoId; + }; +} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Expressions.h b/Libs/AST/Include/AST/Components/Expressions.h new file mode 100644 index 00000000..afba41ff --- /dev/null +++ b/Libs/AST/Include/AST/Components/Expressions.h @@ -0,0 +1,291 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include "AST/Components/CNamespace.h" + +#include +#include + + +namespace rift::AST +{ + enum class UnaryOperatorType : p::u8 + { + Not, // ! + Negation, // - + Increment, // ++ + Decrement, // -- + BitNot, // ~ + }; + + enum class BinaryOperatorType : p::u8 + { + // Mathematic + Add, // + + Sub, // - + Mul, // * + Div, // / + Mod, // % + + // Comparison + Equal, // == + NotEqual, // != + Greater, // > + Less, // < + GreaterOrEqual, // >= + LessOrEqual, // <= + + // Logical + And, // && + Or, // || + BitAnd, // & + BitOr, // | + Xor // ^ + }; + + enum class TypeMode + { + Value, + Pointer, + PointerToPointer + }; +} // namespace rift::AST +ENUM(rift::AST::UnaryOperatorType) +ENUM(rift::AST::BinaryOperatorType) +ENUM(rift::AST::TypeMode) + + +namespace rift::AST +{ + struct CExpression : public p::Struct + { + P_STRUCT(CExpression, p::Struct) + }; + + + struct CExprCall : public CExpression + { + P_STRUCT(CExprCall, CExpression) + + P_PROP(function) + Namespace function; + }; + + + // Data pointing to the id of the function from CExprCall's type and function names + struct CExprCallId : public CExpression + { + P_STRUCT(CExprCallId, CExpression, p::Struct_NotSerialized) + + // Id pointing to the function declaration + P_PROP(functionId) + p::Id functionId = p::NoId; + + + CExprCallId(p::Id functionId = p::NoId) : functionId{functionId} {} + }; + + + struct CExprUnaryOperator : public CExpression + { + P_STRUCT(CExprUnaryOperator, CExpression) + + P_PROP(type) + UnaryOperatorType type = UnaryOperatorType::Not; + + + CExprUnaryOperator() = default; + CExprUnaryOperator(UnaryOperatorType type) : type{type} {} + }; + + + struct CExprBinaryOperator : public CExpression + { + P_STRUCT(CExprBinaryOperator, CExpression) + + P_PROP(type) + BinaryOperatorType type = BinaryOperatorType::Add; + + + CExprBinaryOperator() = default; + CExprBinaryOperator(BinaryOperatorType type) : type{type} {} + }; + + + struct CExprDeclRef : public CExpression + { + P_STRUCT(CExprDeclRef, CExpression) + + P_PROP(ownerName) + p::Tag ownerName; + + P_PROP(name) + p::Tag name; + }; + + + struct CExprDeclRefId : public CExpression + { + P_STRUCT(CExprDeclRefId, CExpression) + + P_PROP(declarationId) + p::Id declarationId = p::NoId; + }; + + + struct ExprInput : public p::Struct + { + P_STRUCT(ExprInput, p::Struct) + + P_PROP(nodeId) + p::Id nodeId = p::NoId; + + P_PROP(pinId) + p::Id pinId = p::NoId; + + + ExprInput() = default; + + bool IsNone() const + { + return p::IsNone(nodeId) || p::IsNone(pinId); + } + }; + + + struct ExprOutput : public p::Struct + { + P_STRUCT(ExprOutput, p::Struct) + + P_PROP(nodeId) + p::Id nodeId = p::NoId; + + P_PROP(pinId) + p::Id pinId = p::NoId; + + + ExprOutput() = default; + + bool IsNone() const + { + return p::IsNone(nodeId) || p::IsNone(pinId); + } + }; + + + struct CExprInputs : public p::Struct + { + P_STRUCT(CExprInputs, p::Struct) + + P_PROP(linkedOutputs) + p::TArray linkedOutputs; + + P_PROP(pinIds) + p::TArray pinIds; + + + CExprInputs& Add(p::Id pinId) + { + linkedOutputs.Add(); + pinIds.Add(pinId); + return *this; + } + + CExprInputs& Insert(p::i32 index, p::Id pinId) + { + pinIds.Insert(index, pinId); + linkedOutputs.Insert(index); + return *this; + } + + CExprInputs& Swap(p::i32 firstIndex, p::i32 secondIndex) + { + pinIds.Swap(firstIndex, secondIndex); + linkedOutputs.Swap(firstIndex, secondIndex); + return *this; + } + + void Resize(p::i32 count) + { + linkedOutputs.Resize(count); + pinIds.Resize(count, p::NoId); + } + }; + + + struct CExprOutputs : public p::Struct + { + P_STRUCT(CExprOutputs, p::Struct) + + P_PROP(pinIds) + p::TArray pinIds; + + + CExprOutputs() {} + CExprOutputs(p::Id pinId) + { + Add(pinId); + } + + CExprOutputs& Add(p::Id pinId) + { + pinIds.Add(pinId); + return *this; + } + + CExprOutputs& Insert(p::i32 index, p::Id pinId) + { + pinIds.Insert(index, pinId); + return *this; + } + + CExprOutputs& Swap(p::i32 firstIndex, p::i32 secondIndex) + { + pinIds.Swap(firstIndex, secondIndex); + return *this; + } + }; + + + struct CExprType : public p::Struct + { + P_STRUCT(CExprType, p::Struct) + + P_PROP(type) + Namespace type; + + P_PROP(mode) + TypeMode mode = TypeMode::Value; + }; + + + struct CExprTypeId : public p::Struct + { + P_STRUCT(CExprTypeId, p::Struct) + + P_PROP(id, p::Prop_NotSerialized) + p::Id id = p::NoId; + + P_PROP(mode) + TypeMode mode = TypeMode::Value; + }; + + + static void Read(p::Reader& ct, CExprCall& val) + { + ct.Serialize(val.function); + } + static void Write(p::Writer& ct, const CExprCall& val) + { + ct.Serialize(val.function); + } + + static void Read(p::Reader& ct, CExprType& val) + { + ct.Serialize(val.type); + } + static void Write(p::Writer& ct, const CExprType& val) + { + ct.Serialize(val.type); + } +} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Literals.h b/Libs/AST/Include/AST/Components/Literals.h new file mode 100644 index 00000000..afae1411 --- /dev/null +++ b/Libs/AST/Include/AST/Components/Literals.h @@ -0,0 +1,104 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include +#include + + +namespace rift::AST +{ + enum class FloatingType : p::u8 + { + F32 = 32, + F64 = 64 + }; + + + static constexpr p::u8 literalUnsignedMask = 1 << 7; // Last bit marks type as unsigned + enum class IntegralType : p::u8 + { + S8 = 8, + S16 = 16, + S32 = 32, + S64 = 64, + U8 = S8 | literalUnsignedMask, + U16 = S16 | literalUnsignedMask, + U32 = S32 | literalUnsignedMask, + U64 = S64 | literalUnsignedMask + }; +} // namespace rift::AST + +ENUM(rift::AST::FloatingType) +ENUM(rift::AST::IntegralType) + +template<> +struct magic_enum::customize::enum_range +{ + static constexpr int min = 0; + static constexpr int max = 256; + // static constexpr bool is_flags = true; + // (max - min) must be less than UINT16_MAX. +}; + + +namespace rift::AST +{ + struct CLiteralBool : public p::Struct + { + P_STRUCT(CLiteralBool, p::Struct) + + P_PROP(value) + bool value = false; + }; + + + struct CLiteralFloating : public p::Struct + { + P_STRUCT(CLiteralFloating, p::Struct) + + + P_PROP(value) + double value = 0.; + + P_PROP(type) + FloatingType type = FloatingType::F32; + + + p::u8 GetSize() const + { + return static_cast>(type); + } + }; + + + struct CLiteralIntegral : public p::Struct + { + P_STRUCT(CLiteralIntegral, p::Struct) + + + P_PROP(value) + p::u64 value = 0; + + P_PROP(type) + IntegralType type = IntegralType::S32; + + + bool IsSigned() const + { + return p::u8(type) & literalUnsignedMask == literalUnsignedMask; + } + p::u8 GetSize() const + { + return p::u8(type) & ~literalUnsignedMask; + } + }; + + + struct CLiteralString : public p::Struct + { + P_STRUCT(CLiteralString, p::Struct) + + P_PROP(value) + p::String value; + }; +} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Statements.h b/Libs/AST/Include/AST/Components/Statements.h new file mode 100644 index 00000000..3be97765 --- /dev/null +++ b/Libs/AST/Include/AST/Components/Statements.h @@ -0,0 +1,83 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include +#include + + +namespace rift::AST +{ + struct CStmtFor : public p::Struct + { + P_STRUCT(CStmtFor, p::Struct) + }; + + + struct CStmtIf : public p::Struct + { + P_STRUCT(CStmtIf, p::Struct) + }; + + + struct CStmtInput : public p::Struct + { + P_STRUCT(CStmtInput, p::Struct) + + P_PROP(linkOutputNode) + p::Id linkOutputNode = p::NoId; + }; + + + struct CStmtOutput : public p::Struct + { + P_STRUCT(CStmtOutput, p::Struct) + + P_PROP(linkInputNode) + p::Id linkInputNode = p::NoId; + }; + + + struct CStmtOutputs : public p::Struct + { + P_STRUCT(CStmtOutputs, p::Struct) + + // Both arrays keep the same index to the input node and the output pin + P_PROP(pinIds) + p::TArray pinIds; + P_PROP(linkInputNodes) + p::TArray linkInputNodes; + + + CStmtOutputs() = default; + CStmtOutputs(p::TArray pins) + : pinIds{Move(pins)}, linkInputNodes(pinIds.Size(), p::NoId) + {} + }; + + /** Represents a return expression of a function + * Return arguments are dynamically populated depending on the function this expression is + * connected to. + */ + struct CStmtReturn : public p::Struct + { + P_STRUCT(CStmtReturn, p::Struct) + }; + + + static void Read(p::Reader& ct, CStmtInput& val) + { + ct.Serialize(val.linkOutputNode); + } + static void Write(p::Writer& ct, const CStmtInput& val) + { + ct.Serialize(val.linkOutputNode); + } + static void Read(p::Reader& ct, CStmtOutput& val) + { + ct.Serialize(val.linkInputNode); + } + static void Write(p::Writer& ct, const CStmtOutput& val) + { + ct.Serialize(val.linkInputNode); + } +} // namespace rift::AST diff --git a/Libs/AST/Include/AST/Components/Tags/CDirty.h b/Libs/AST/Include/AST/Components/Tags/CDirty.h index 5ff510a2..189f59a0 100644 --- a/Libs/AST/Include/AST/Components/Tags/CDirty.h +++ b/Libs/AST/Include/AST/Components/Tags/CDirty.h @@ -1,12 +1,13 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CExprCall.h" #include "AST/Components/CFileRef.h" +#include "AST/Components/Expressions.h" #include + namespace rift::AST { // Dirty tags are cleaned manually by the respective systems. CChanged instead gets cleared diff --git a/Libs/AST/Include/AST/Systems/FunctionsSystem.h b/Libs/AST/Include/AST/Systems/FunctionsSystem.h index fa62abdd..7f91dc48 100644 --- a/Libs/AST/Include/AST/Systems/FunctionsSystem.h +++ b/Libs/AST/Include/AST/Systems/FunctionsSystem.h @@ -1,11 +1,9 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CDeclFunction.h" -#include "AST/Components/CExprCall.h" -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" #include "AST/Components/CNamespace.h" +#include "AST/Components/Declarations.h" +#include "AST/Components/Expressions.h" #include "AST/Components/Tags/CInvalid.h" #include "AST/Tree.h" diff --git a/Libs/AST/Include/AST/Systems/TypeSystem.h b/Libs/AST/Include/AST/Systems/TypeSystem.h index 1793e15e..e7796123 100644 --- a/Libs/AST/Include/AST/Systems/TypeSystem.h +++ b/Libs/AST/Include/AST/Systems/TypeSystem.h @@ -1,14 +1,8 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CDeclType.h" -#include "AST/Components/CDeclVariable.h" -#include "AST/Components/CExprBinaryOperator.h" -#include "AST/Components/CExprDeclRef.h" -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" -#include "AST/Components/CExprType.h" -#include "AST/Components/CExprUnaryOperator.h" +#include "AST/Components/Declarations.h" +#include "AST/Components/Expressions.h" #include "AST/Components/Tags/CChanged.h" #include diff --git a/Libs/AST/Include/AST/TypeRef.h b/Libs/AST/Include/AST/TypeRef.h index 50810d98..681ec30d 100644 --- a/Libs/AST/Include/AST/TypeRef.h +++ b/Libs/AST/Include/AST/TypeRef.h @@ -1,7 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CDeclType.h" +#include "AST/Components/Declarations.h" #include "AST/Tree.h" #include diff --git a/Libs/AST/Include/AST/Utils/Expressions.h b/Libs/AST/Include/AST/Utils/Expressions.h index 6f91b633..528b66b0 100644 --- a/Libs/AST/Include/AST/Utils/Expressions.h +++ b/Libs/AST/Include/AST/Utils/Expressions.h @@ -1,9 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" -#include "AST/Components/CExprType.h" +#include "AST/Components/Expressions.h" #include "AST/Components/Tags/CInvalid.h" #include "AST/Id.h" #include "AST/Tree.h" @@ -12,6 +10,7 @@ #include + // NOTE: In expression graphs, the Link Id is the Input Pin Id namespace rift::AST { diff --git a/Libs/AST/Include/AST/Utils/Statements.h b/Libs/AST/Include/AST/Utils/Statements.h index ff87d54b..4dfa7c20 100644 --- a/Libs/AST/Include/AST/Utils/Statements.h +++ b/Libs/AST/Include/AST/Utils/Statements.h @@ -1,8 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CStmtInput.h" -#include "AST/Components/CStmtOutputs.h" +#include "AST/Components/Statements.h" #include "AST/Id.h" #include "AST/Tree.h" #include "AST/Utils/Statements.h" @@ -11,6 +10,7 @@ #include + // NOTE: In statement graphs, the Link Id is the Input Node Id namespace rift::AST { diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index 13af9345..f7dc5f26 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -2,17 +2,11 @@ #pragma once -#include "AST/Components/CDeclFunction.h" -#include "AST/Components/CDeclType.h" -#include "AST/Components/CExprBinaryOperator.h" -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" -#include "AST/Components/CExprType.h" -#include "AST/Components/CExprUnaryOperator.h" #include "AST/Components/CFileRef.h" #include "AST/Components/CNamespace.h" -#include "AST/Components/CStmtInput.h" -#include "AST/Components/CStmtOutputs.h" +#include "AST/Components/Declarations.h" +#include "AST/Components/Expressions.h" +#include "AST/Components/Statements.h" #include "AST/Components/Tags/CChanged.h" #include "AST/Components/Tags/CDirty.h" #include "AST/Tree.h" @@ -21,6 +15,7 @@ #include + namespace rift::AST { struct RiftTypeSettings diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index ec27dc81..5aa4f1e1 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -2,7 +2,7 @@ #pragma once -#include "AST/Components/CDeclType.h" +#include "AST/Components/Declarations.h" #include "AST/Id.h" #include "AST/Tree.h" #include "View.h" @@ -13,7 +13,6 @@ #include - namespace rift { void EnableModule(p::ClassType* type); diff --git a/Libs/AST/Include/View.h b/Libs/AST/Include/View.h index 9d92a8de..6c483cc5 100644 --- a/Libs/AST/Include/View.h +++ b/Libs/AST/Include/View.h @@ -1,7 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "AST/Components/CDeclType.h" +#include "AST/Components/Declarations.h" #include #include diff --git a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp index 8a0e2179..97253c32 100644 --- a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp +++ b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp @@ -2,9 +2,7 @@ #include "AST/Systems/FunctionsSystem.h" -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" -#include "AST/Components/CExprType.h" +#include "AST/Components/Expressions.h" #include "AST/Components/Tags/CChanged.h" #include "AST/Components/Tags/CDirty.h" #include "AST/Utils/Namespaces.h" @@ -13,6 +11,7 @@ #include + namespace rift::AST::FunctionsSystem { struct CallToSync diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index ba6cf366..22610cf6 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -2,12 +2,9 @@ #include "AST/Systems/LoadSystem.h" -#include "AST/Components/CDeclClass.h" -#include "AST/Components/CDeclStatic.h" -#include "AST/Components/CDeclStruct.h" -#include "AST/Components/CDeclType.h" #include "AST/Components/CModule.h" #include "AST/Components/CNamespace.h" +#include "AST/Components/Declarations.h" #include "AST/Statics/SLoadQueue.h" #include "AST/Statics/SModules.h" #include "AST/Statics/SStringLoad.h" @@ -22,6 +19,7 @@ #include + namespace rift::AST::LoadSystem { void Init(Tree& ast) diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index a6fa64a8..8bdb7604 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -2,15 +2,15 @@ #include "AST/Tree.h" -#include "AST/Components/CDeclNative.h" -#include "AST/Components/CDeclType.h" #include "AST/Components/CNamespace.h" +#include "AST/Components/Declarations.h" #include "AST/Statics/SModules.h" #include "AST/Statics/STypes.h" #include + namespace rift::AST { TBroadcast Tree::onInit{}; diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index d165391c..f1abc2a4 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -2,7 +2,7 @@ #include "AST/Utils/TransactionUtils.h" -#include "AST/Components/CDeclType.h" +#include "AST/Components/Declarations.h" #include diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index bca63038..76c4fad9 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -2,26 +2,12 @@ #include "AST/Utils/TypeUtils.h" -#include "AST/Components/CDeclClass.h" -#include "AST/Components/CDeclStatic.h" -#include "AST/Components/CDeclStruct.h" -#include "AST/Components/CDeclType.h" -#include "AST/Components/CDeclVariable.h" -#include "AST/Components/CExprCall.h" -#include "AST/Components/CExprDeclRef.h" -#include "AST/Components/CExprInputs.h" -#include "AST/Components/CExprOutputs.h" -#include "AST/Components/CExprType.h" #include "AST/Components/CFileRef.h" -#include "AST/Components/CLiteralBool.h" -#include "AST/Components/CLiteralFloating.h" -#include "AST/Components/CLiteralIntegral.h" -#include "AST/Components/CLiteralString.h" #include "AST/Components/CNamespace.h" -#include "AST/Components/CStmtIf.h" -#include "AST/Components/CStmtInput.h" -#include "AST/Components/CStmtOutputs.h" -#include "AST/Components/CStmtReturn.h" +#include "AST/Components/Declarations.h" +#include "AST/Components/Expressions.h" +#include "AST/Components/Literals.h" +#include "AST/Components/Statements.h" #include "AST/Components/Views/CNodePosition.h" #include "AST/Statics/STypes.h" #include "AST/Utils/Namespaces.h" diff --git a/Libs/AST/Src/ASTModule.cpp b/Libs/AST/Src/ASTModule.cpp index 39542e49..a748b0df 100644 --- a/Libs/AST/Src/ASTModule.cpp +++ b/Libs/AST/Src/ASTModule.cpp @@ -2,15 +2,14 @@ #include "ASTModule.h" -#include "AST/Components/CDeclClass.h" -#include "AST/Components/CDeclStatic.h" -#include "AST/Components/CDeclStruct.h" #include "AST/Components/CModule.h" #include "AST/Components/CNamespace.h" +#include "AST/Components/Declarations.h" #include "AST/Utils/ModuleUtils.h" #include "AST/Utils/TypeUtils.h" + namespace rift { const p::Tag ASTModule::structType = "Struct"; diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.h b/Libs/Backends/MIR/Compiler/Src/C2MIR.h index f5e101a8..ee3545a9 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.h +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.h @@ -3,32 +3,18 @@ #include "Components.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include +#include +#include +#include #include #include -#include -#include +#include #include #include + struct c2mir_options; namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index 0bf04f73..7d5619b1 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -3,31 +3,17 @@ #include "Components.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include +#include +#include +#include #include #include -#include -#include +#include #include + namespace rift { struct Compiler; diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h b/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h deleted file mode 100644 index f290285c..00000000 --- a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStatic.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2023 Piperift - All rights reserved -#pragma once - -#include - - -namespace rift -{ - struct CDeclCStatic : public AST::CDeclRecord - { - P_STRUCT(CDeclCStatic, CDeclRecord) - }; -} // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h similarity index 60% rename from Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h rename to Libs/Bindings/Native/Compiler/Include/Components/Declarations.h index d44cb6a6..22eb4d20 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CDeclCStruct.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h @@ -1,7 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include +#include namespace rift @@ -10,4 +10,9 @@ namespace rift { P_STRUCT(CDeclCStruct, CDeclRecord) }; + + struct CDeclCStatic : public AST::CDeclRecord + { + P_STRUCT(CDeclCStatic, CDeclRecord) + }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index ff027d70..4b57a1ef 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -2,9 +2,8 @@ #include "NativeBindingModule.h" -#include "Components/CDeclCStatic.h" -#include "Components/CDeclCStruct.h" #include "Components/CNativeBinding.h" +#include "Components/Declarations.h" #include "HeaderIterator.h" #include @@ -17,6 +16,7 @@ #include + // P_OVERRIDE_NEW_DELETE diff --git a/Libs/Editor/Include/Panels/FileExplorerPanel.h b/Libs/Editor/Include/Panels/FileExplorerPanel.h index d03cf0e7..62eae5c4 100644 --- a/Libs/Editor/Include/Panels/FileExplorerPanel.h +++ b/Libs/Editor/Include/Panels/FileExplorerPanel.h @@ -3,16 +3,17 @@ #include "AST/Components/CProject.h" -#include #include #include #include +#include #include #include #include #include + namespace rift::Editor { // Forward declarations diff --git a/Libs/Editor/Include/Utils/DetailsPanel.h b/Libs/Editor/Include/Utils/DetailsPanel.h index 5ef0bb8a..ab92ea8a 100644 --- a/Libs/Editor/Include/Utils/DetailsPanel.h +++ b/Libs/Editor/Include/Utils/DetailsPanel.h @@ -2,15 +2,9 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include #include #include diff --git a/Libs/Editor/Include/Utils/ElementsPanel.h b/Libs/Editor/Include/Utils/ElementsPanel.h index 3483120f..143f8883 100644 --- a/Libs/Editor/Include/Utils/ElementsPanel.h +++ b/Libs/Editor/Include/Utils/ElementsPanel.h @@ -2,15 +2,9 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include #include #include diff --git a/Libs/Editor/Include/Utils/TypeUtils.h b/Libs/Editor/Include/Utils/TypeUtils.h index 50cbee44..cc852c20 100644 --- a/Libs/Editor/Include/Utils/TypeUtils.h +++ b/Libs/Editor/Include/Utils/TypeUtils.h @@ -4,9 +4,8 @@ #include "Components/CTypeEditor.h" -#include -#include -#include +#include +#include #include #include diff --git a/Libs/Editor/Include/Utils/Widgets.h b/Libs/Editor/Include/Utils/Widgets.h index 190dcf0e..d52e0347 100644 --- a/Libs/Editor/Include/Utils/Widgets.h +++ b/Libs/Editor/Include/Utils/Widgets.h @@ -2,16 +2,14 @@ #pragma once -#include -#include -#include -#include #include +#include #include #include #include + namespace rift::Editor { bool TypeCombo(AST::TAccessRef #include #include +#include #include #include #include @@ -36,6 +36,7 @@ #include + namespace rift::Editor::EditorSystem { void OnProjectEditorOpen(AST::Tree& ast) diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 454eb491..f0d4a296 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -5,7 +5,7 @@ #include "imgui.h" #include "UI/Widgets.h" -#include +#include #include #include #include diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index 02450787..5fd6638d 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -2,7 +2,7 @@ #include "Tools/ReflectionDebugger.h" -#include +#include #include #include #include diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index 76a158b0..d350ead8 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -2,13 +2,13 @@ #include "Utils/EditorStyle.h" -#include "AST/Components/CDeclClass.h" -#include "AST/Components/CDeclStruct.h" +#include "AST/Components/Declarations.h" #include #include + namespace rift::Editor { const Color GetTypeColor(const AST::Tree& ast, AST::Id id) diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index aefc603f..ec8cbf19 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -9,25 +9,11 @@ #include "Utils/FunctionGraphContextMenu.h" #include "Utils/TypeUtils.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -40,6 +26,7 @@ #include + namespace rift::Editor::Graph { static CNodePosition* currentNodeTransform = nullptr; diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index 7e7dc925..5be3dfcc 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -11,11 +11,9 @@ #include "Utils/TypeUtils.h" #include "Utils/Widgets.h" -#include -#include -#include -#include #include +#include +#include #include #include #include From d7124914cb36842d2df357c24624ce61a0e77cf3 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 31 Jan 2024 22:32:54 +0100 Subject: [PATCH 18/52] AST namespace is now ast --- Apps/CLI/Src/main.cpp | 9 +- Libs/AST/Include/AST/Components/CFileRef.h | 4 +- Libs/AST/Include/AST/Components/CModule.h | 10 +- Libs/AST/Include/AST/Components/CNamespace.h | 4 +- Libs/AST/Include/AST/Components/CProject.h | 4 +- .../AST/Include/AST/Components/Declarations.h | 4 +- Libs/AST/Include/AST/Components/Expressions.h | 14 +- Libs/AST/Include/AST/Components/Literals.h | 14 +- Libs/AST/Include/AST/Components/Statements.h | 4 +- .../Include/AST/Components/Tags/CChanged.h | 4 +- Libs/AST/Include/AST/Components/Tags/CDirty.h | 5 +- .../Include/AST/Components/Tags/CInvalid.h | 4 +- .../AST/Components/Views/CNodePosition.h | 3 +- Libs/AST/Include/AST/Id.h | 4 +- Libs/AST/Include/AST/Statics/SLoadQueue.h | 4 +- Libs/AST/Include/AST/Statics/SModules.h | 6 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 4 +- Libs/AST/Include/AST/Statics/STypes.h | 4 +- .../AST/Include/AST/Systems/FunctionsSystem.h | 6 +- Libs/AST/Include/AST/Systems/LoadSystem.h | 6 +- .../Include/AST/Systems/TransactionSystem.h | 6 +- Libs/AST/Include/AST/Systems/TypeSystem.h | 6 +- Libs/AST/Include/AST/Tree.h | 30 +- Libs/AST/Include/AST/TypeRef.h | 12 +- Libs/AST/Include/AST/Utils/Expressions.h | 5 +- .../Include/AST/Utils/ModuleFileIterator.h | 4 +- Libs/AST/Include/AST/Utils/ModuleUtils.h | 16 +- Libs/AST/Include/AST/Utils/Namespaces.h | 6 +- Libs/AST/Include/AST/Utils/Statements.h | 29 +- Libs/AST/Include/AST/Utils/TransactionUtils.h | 6 +- Libs/AST/Include/AST/Utils/TypeIterator.h | 4 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 7 +- Libs/AST/Include/ASTModule.h | 2 +- Libs/AST/Include/Compiler/Compiler.h | 10 +- Libs/AST/Include/Compiler/CompilerConfig.h | 2 +- .../Compiler/Systems/OptimizationSystem.h | 6 +- Libs/AST/Src/AST/Components/CNamespace.cpp | 4 +- Libs/AST/Src/AST/Systems/FunctionsSystem.cpp | 5 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 9 +- .../AST/Src/AST/Systems/TransactionSystem.cpp | 4 +- Libs/AST/Src/AST/Systems/TypeSystem.cpp | 4 +- Libs/AST/Src/AST/Tree.cpp | 5 +- Libs/AST/Src/AST/Utils/Expressions.cpp | 4 +- Libs/AST/Src/AST/Utils/ModuleUtils.cpp | 12 +- Libs/AST/Src/AST/Utils/Namespaces.cpp | 4 +- Libs/AST/Src/AST/Utils/Statements.cpp | 34 +-- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 4 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 8 +- Libs/AST/Src/ASTModule.cpp | 11 +- Libs/AST/Src/Compiler/Compiler.cpp | 14 +- Libs/AST/Src/Compiler/CompilerConfig.cpp | 4 +- .../Compiler/Systems/OptimizationSystem.cpp | 4 +- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 4 +- .../MIR/Compiler/Src/IRGeneration.cpp | 152 +++++----- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 35 ++- .../Include/Components/Declarations.h | 4 +- .../Compiler/Include/NativeBindingModule.h | 4 +- .../Compiler/Src/NativeBindingModule.cpp | 29 +- Libs/Editor/Include/Components/CTypeEditor.h | 4 +- Libs/Editor/Include/Editor.h | 4 +- .../Editor/Include/Panels/FileExplorerPanel.h | 25 +- Libs/Editor/Include/Statics/SEditor.h | 4 +- Libs/Editor/Include/Systems/EditorSystem.h | 4 +- Libs/Editor/Include/Tools/ASTDebugger.h | 16 +- Libs/Editor/Include/Tools/GraphPlayground.h | 2 +- Libs/Editor/Include/Utils/DetailsPanel.h | 2 +- Libs/Editor/Include/Utils/EditorStyle.h | 3 +- Libs/Editor/Include/Utils/ElementsPanel.h | 12 +- Libs/Editor/Include/Utils/FunctionGraph.h | 16 +- .../Include/Utils/FunctionGraphContextMenu.h | 6 +- Libs/Editor/Include/Utils/ModuleUtils.h | 6 +- Libs/Editor/Include/Utils/Nodes.h | 38 +-- Libs/Editor/Include/Utils/NodesInternal.h | 46 ++-- Libs/Editor/Include/Utils/NodesMiniMap.h | 4 +- Libs/Editor/Include/Utils/ProjectManager.h | 2 +- Libs/Editor/Include/Utils/TypeUtils.h | 98 +++---- Libs/Editor/Include/Utils/Widgets.h | 9 +- Libs/Editor/Src/Editor.cpp | 46 ++-- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 74 ++--- Libs/Editor/Src/Systems/EditorSystem.cpp | 117 ++++---- Libs/Editor/Src/Tools/ASTDebugger.cpp | 48 ++-- Libs/Editor/Src/Tools/GraphPlayground.cpp | 10 +- Libs/Editor/Src/Utils/DetailsPanel.cpp | 38 +-- Libs/Editor/Src/Utils/EditorStyle.cpp | 7 +- Libs/Editor/Src/Utils/ElementsPanel.cpp | 56 ++-- Libs/Editor/Src/Utils/FunctionGraph.cpp | 259 +++++++++--------- .../Src/Utils/FunctionGraphContextMenu.cpp | 104 +++---- Libs/Editor/Src/Utils/ModuleUtils.cpp | 10 +- Libs/Editor/Src/Utils/Nodes.cpp | 96 +++---- Libs/Editor/Src/Utils/NodesMiniMap.cpp | 4 +- Libs/Editor/Src/Utils/ProjectManager.cpp | 2 +- Libs/Editor/Src/Utils/TypeUtils.cpp | 10 +- Libs/Editor/Src/Utils/Widgets.cpp | 26 +- Tests/AST/Expressions.spec.cpp | 26 +- Tests/AST/Namespaces.spec.cpp | 86 +++--- Tests/AST/Statements.spec.cpp | 70 ++--- Tests/Project.spec.cpp | 28 +- 97 files changed, 1015 insertions(+), 1029 deletions(-) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index b4b03ca3..1ae06d2e 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -14,8 +14,9 @@ #include #include -#include #include +#include + using namespace rift; @@ -86,10 +87,10 @@ int main(int argc, char** argv) TPtr backend = FindBackendByName(availableBackends, Tag(selectedBackendStr)); - AST::Tree ast; - AST::OpenProject(ast, path); + ast::Tree ast; + ast::OpenProject(ast, path); - if (!AST::HasProject(ast)) + if (!ast::HasProject(ast)) { p::Error("Couldn't open project '{}'", p::ToString(path)); return 1; diff --git a/Libs/AST/Include/AST/Components/CFileRef.h b/Libs/AST/Include/AST/Components/CFileRef.h index e2a15c76..cc21ea65 100644 --- a/Libs/AST/Include/AST/Components/CFileRef.h +++ b/Libs/AST/Include/AST/Components/CFileRef.h @@ -6,7 +6,7 @@ #include -namespace rift::AST +namespace rift::ast { /** * This component points an AST node to a file. @@ -24,4 +24,4 @@ namespace rift::AST CFileRef() {} CFileRef(p::StringView path) : path{path} {} }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/CModule.h b/Libs/AST/Include/AST/Components/CModule.h index 69c5c4e5..02962510 100644 --- a/Libs/AST/Include/AST/Components/CModule.h +++ b/Libs/AST/Include/AST/Components/CModule.h @@ -4,7 +4,7 @@ #include #include -namespace rift::AST +namespace rift::ast { enum class RiftModuleTarget : p::u8 { @@ -12,11 +12,11 @@ namespace rift::AST Shared, Static }; -} // namespace rift::AST -ENUM(rift::AST::RiftModuleTarget) +} // namespace rift::ast +ENUM(rift::ast::RiftModuleTarget) -namespace rift::AST +namespace rift::ast { static constexpr p::StringView moduleFilename = "__module__.rf"; @@ -30,4 +30,4 @@ namespace rift::AST P_PROP(dependencies) p::TArray dependencies; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index a51ee271..68e075d9 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -5,7 +5,7 @@ #include -namespace rift::AST +namespace rift::ast { struct CNamespace : public p::Struct { @@ -123,4 +123,4 @@ namespace rift::AST void Read(p::Reader& ct); void Write(p::Writer& ct) const; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/CProject.h b/Libs/AST/Include/AST/Components/CProject.h index 4d50210d..3ee75798 100644 --- a/Libs/AST/Include/AST/Components/CProject.h +++ b/Libs/AST/Include/AST/Components/CProject.h @@ -4,10 +4,10 @@ #include -namespace rift::AST +namespace rift::ast { struct CProject : public p::Struct { P_STRUCT(CProject, p::Struct) }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Declarations.h b/Libs/AST/Include/AST/Components/Declarations.h index 02fb48eb..322608ab 100644 --- a/Libs/AST/Include/AST/Components/Declarations.h +++ b/Libs/AST/Include/AST/Components/Declarations.h @@ -5,7 +5,7 @@ #include -namespace rift::AST +namespace rift::ast { struct CDeclStatic : public p::Struct { @@ -59,4 +59,4 @@ namespace rift::AST P_PROP(typeId, p::Prop_NotSerialized) p::Id typeId = p::NoId; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Expressions.h b/Libs/AST/Include/AST/Components/Expressions.h index afba41ff..1b085caa 100644 --- a/Libs/AST/Include/AST/Components/Expressions.h +++ b/Libs/AST/Include/AST/Components/Expressions.h @@ -7,7 +7,7 @@ #include -namespace rift::AST +namespace rift::ast { enum class UnaryOperatorType : p::u8 { @@ -49,13 +49,13 @@ namespace rift::AST Pointer, PointerToPointer }; -} // namespace rift::AST -ENUM(rift::AST::UnaryOperatorType) -ENUM(rift::AST::BinaryOperatorType) -ENUM(rift::AST::TypeMode) +} // namespace rift::ast +ENUM(rift::ast::UnaryOperatorType) +ENUM(rift::ast::BinaryOperatorType) +ENUM(rift::ast::TypeMode) -namespace rift::AST +namespace rift::ast { struct CExpression : public p::Struct { @@ -288,4 +288,4 @@ namespace rift::AST { ct.Serialize(val.type); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Literals.h b/Libs/AST/Include/AST/Components/Literals.h index afae1411..876bb94e 100644 --- a/Libs/AST/Include/AST/Components/Literals.h +++ b/Libs/AST/Include/AST/Components/Literals.h @@ -5,7 +5,7 @@ #include -namespace rift::AST +namespace rift::ast { enum class FloatingType : p::u8 { @@ -26,13 +26,13 @@ namespace rift::AST U32 = S32 | literalUnsignedMask, U64 = S64 | literalUnsignedMask }; -} // namespace rift::AST +} // namespace rift::ast -ENUM(rift::AST::FloatingType) -ENUM(rift::AST::IntegralType) +ENUM(rift::ast::FloatingType) +ENUM(rift::ast::IntegralType) template<> -struct magic_enum::customize::enum_range +struct magic_enum::customize::enum_range { static constexpr int min = 0; static constexpr int max = 256; @@ -41,7 +41,7 @@ struct magic_enum::customize::enum_range }; -namespace rift::AST +namespace rift::ast { struct CLiteralBool : public p::Struct { @@ -101,4 +101,4 @@ namespace rift::AST P_PROP(value) p::String value; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Statements.h b/Libs/AST/Include/AST/Components/Statements.h index 3be97765..f3a8b846 100644 --- a/Libs/AST/Include/AST/Components/Statements.h +++ b/Libs/AST/Include/AST/Components/Statements.h @@ -5,7 +5,7 @@ #include -namespace rift::AST +namespace rift::ast { struct CStmtFor : public p::Struct { @@ -80,4 +80,4 @@ namespace rift::AST { ct.Serialize(val.linkInputNode); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Tags/CChanged.h b/Libs/AST/Include/AST/Components/Tags/CChanged.h index ed1d1823..f3eafac9 100644 --- a/Libs/AST/Include/AST/Components/Tags/CChanged.h +++ b/Libs/AST/Include/AST/Components/Tags/CChanged.h @@ -4,7 +4,7 @@ #include -namespace rift::AST +namespace rift::ast { // Asigned to entities that have been modified during the last frame // Gets cleared after one frame @@ -12,4 +12,4 @@ namespace rift::AST { P_STRUCT(CChanged, p::Struct, p::Struct_NotSerialized) }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Tags/CDirty.h b/Libs/AST/Include/AST/Components/Tags/CDirty.h index 189f59a0..215789e6 100644 --- a/Libs/AST/Include/AST/Components/Tags/CDirty.h +++ b/Libs/AST/Include/AST/Components/Tags/CDirty.h @@ -7,8 +7,7 @@ #include - -namespace rift::AST +namespace rift::ast { // Dirty tags are cleaned manually by the respective systems. CChanged instead gets cleared // after one frame @@ -25,4 +24,4 @@ namespace rift::AST // Marks a type as dirty, meaning is has been modified using CCallDirty = TDirty; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Tags/CInvalid.h b/Libs/AST/Include/AST/Components/Tags/CInvalid.h index 7f93342f..ee40a885 100644 --- a/Libs/AST/Include/AST/Components/Tags/CInvalid.h +++ b/Libs/AST/Include/AST/Components/Tags/CInvalid.h @@ -4,10 +4,10 @@ #include -namespace rift::AST +namespace rift::ast { struct CInvalid : public p::Struct { P_STRUCT(CInvalid, p::Struct) }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Views/CNodePosition.h b/Libs/AST/Include/AST/Components/Views/CNodePosition.h index 93e5bb5f..5a7ee61a 100644 --- a/Libs/AST/Include/AST/Components/Views/CNodePosition.h +++ b/Libs/AST/Include/AST/Components/Views/CNodePosition.h @@ -5,7 +5,6 @@ #include - namespace rift { struct CNodePosition : public p::Struct @@ -18,6 +17,8 @@ namespace rift CNodePosition() = default; CNodePosition(p::v2 position) : position{position} {} }; + + static void Read(p::Reader& ct, CNodePosition& val) { ct.Serialize(val.position); diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index aeef6e47..417c85c8 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -7,7 +7,7 @@ #include -namespace rift::AST +namespace rift::ast { using namespace p; using Id = p::Id; @@ -15,4 +15,4 @@ namespace rift::AST using CParent = p::CParent; using CChild = p::CChild; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/SLoadQueue.h b/Libs/AST/Include/AST/Statics/SLoadQueue.h index e9b2544a..18dca457 100644 --- a/Libs/AST/Include/AST/Statics/SLoadQueue.h +++ b/Libs/AST/Include/AST/Statics/SLoadQueue.h @@ -6,7 +6,7 @@ #include -namespace rift::AST +namespace rift::ast { // Keeps a list of entities to load from disk struct SLoadQueue : public p::Struct @@ -16,4 +16,4 @@ namespace rift::AST TArray pendingSyncLoad; TArray pendingAsyncLoad; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/SModules.h b/Libs/AST/Include/AST/Statics/SModules.h index e6eed751..a300e96c 100644 --- a/Libs/AST/Include/AST/Statics/SModules.h +++ b/Libs/AST/Include/AST/Statics/SModules.h @@ -6,12 +6,12 @@ #include -namespace rift::AST +namespace rift::ast { struct SModules : public p::Struct { P_STRUCT(SModules, p::Struct) - p::TMap modulesByPath; + p::TMap modulesByPath; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index 087b09b4..c86a00f3 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -8,7 +8,7 @@ #include -namespace rift::AST +namespace rift::ast { // Contains loaded string data from disk struct SStringLoad : public Struct @@ -21,4 +21,4 @@ namespace rift::AST TArray paths; TArray strings; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index e81d837e..9fdda5bd 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -7,7 +7,7 @@ #include -namespace rift::AST +namespace rift::ast { struct STypes : public Struct { @@ -18,4 +18,4 @@ namespace rift::AST // Current TMap lookup of stringviews seems unconsistent TMap typesByPath; }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Systems/FunctionsSystem.h b/Libs/AST/Include/AST/Systems/FunctionsSystem.h index 7f91dc48..d71c0899 100644 --- a/Libs/AST/Include/AST/Systems/FunctionsSystem.h +++ b/Libs/AST/Include/AST/Systems/FunctionsSystem.h @@ -11,12 +11,12 @@ #include -namespace rift::AST +namespace rift::ast { struct Tree; } -namespace rift::AST::FunctionsSystem +namespace rift::ast::FunctionsSystem { struct CTmpInvalidKeep {}; @@ -35,4 +35,4 @@ namespace rift::AST::FunctionsSystem p::TWrite, p::TWrite, p::TWrite>; void RemoveInvalidDisconnectedArgs(InvalidDisconnectedPinAccess access); void ClearAddedTags(Tree& ast); -} // namespace rift::AST::FunctionsSystem +} // namespace rift::ast::FunctionsSystem diff --git a/Libs/AST/Include/AST/Systems/LoadSystem.h b/Libs/AST/Include/AST/Systems/LoadSystem.h index 8586345d..5d096461 100644 --- a/Libs/AST/Include/AST/Systems/LoadSystem.h +++ b/Libs/AST/Include/AST/Systems/LoadSystem.h @@ -8,12 +8,12 @@ #include -namespace rift::AST +namespace rift::ast { struct Tree; } -namespace rift::AST::LoadSystem +namespace rift::ast::LoadSystem { struct ModuleTypePaths { @@ -44,4 +44,4 @@ namespace rift::AST::LoadSystem void DeserializeModules(Tree& ast, TView moduleIds, TView strings); void DeserializeTypes(Tree& ast, TView typeIds, TView strings); -} // namespace rift::AST::LoadSystem +} // namespace rift::ast::LoadSystem diff --git a/Libs/AST/Include/AST/Systems/TransactionSystem.h b/Libs/AST/Include/AST/Systems/TransactionSystem.h index f5e9d167..43895a3a 100644 --- a/Libs/AST/Include/AST/Systems/TransactionSystem.h +++ b/Libs/AST/Include/AST/Systems/TransactionSystem.h @@ -4,14 +4,14 @@ #include "AST/Tree.h" -namespace rift::AST +namespace rift::ast { struct Tree; } -namespace rift::AST::TransactionSystem +namespace rift::ast::TransactionSystem { void Init(Tree& ast); void ClearTags(Tree& ast); -} // namespace rift::AST::TransactionSystem +} // namespace rift::ast::TransactionSystem diff --git a/Libs/AST/Include/AST/Systems/TypeSystem.h b/Libs/AST/Include/AST/Systems/TypeSystem.h index e7796123..716ad1ab 100644 --- a/Libs/AST/Include/AST/Systems/TypeSystem.h +++ b/Libs/AST/Include/AST/Systems/TypeSystem.h @@ -8,12 +8,12 @@ #include -namespace rift::AST +namespace rift::ast { struct Tree; } -namespace rift::AST::TypeSystem +namespace rift::ast::TypeSystem { using namespace p; @@ -30,4 +30,4 @@ namespace rift::AST::TypeSystem void ResolveExprTypeIds( TAccessRef, CExprType, CNamespace, CParent, CChild> access); -} // namespace rift::AST::TypeSystem +} // namespace rift::ast::TypeSystem diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index be70f2cc..24ef919f 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -9,23 +9,23 @@ #include -namespace rift::AST +namespace rift::ast { struct NativeTypeIds { - AST::Id voidId = AST::NoId; - AST::Id boolId = AST::NoId; - AST::Id floatId = AST::NoId; - AST::Id doubleId = AST::NoId; - AST::Id u8Id = AST::NoId; - AST::Id i8Id = AST::NoId; - AST::Id u16Id = AST::NoId; - AST::Id i16Id = AST::NoId; - AST::Id u32Id = AST::NoId; - AST::Id i32Id = AST::NoId; - AST::Id u64Id = AST::NoId; - AST::Id i64Id = AST::NoId; - AST::Id stringId = AST::NoId; + ast::Id voidId = ast::NoId; + ast::Id boolId = ast::NoId; + ast::Id floatId = ast::NoId; + ast::Id doubleId = ast::NoId; + ast::Id u8Id = ast::NoId; + ast::Id i8Id = ast::NoId; + ast::Id u16Id = ast::NoId; + ast::Id i16Id = ast::NoId; + ast::Id u32Id = ast::NoId; + ast::Id i32Id = ast::NoId; + ast::Id u64Id = ast::NoId; + ast::Id i64Id = ast::NoId; + ast::Id stringId = ast::NoId; }; @@ -68,4 +68,4 @@ namespace rift::AST (ast.AssurePool(), ...); }); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/TypeRef.h b/Libs/AST/Include/AST/TypeRef.h index 681ec30d..408bbf3d 100644 --- a/Libs/AST/Include/AST/TypeRef.h +++ b/Libs/AST/Include/AST/TypeRef.h @@ -7,16 +7,16 @@ #include -namespace rift::AST +namespace rift::ast { struct TypeRef { private: Tree& ast; - AST::Id typeId = AST::NoId; + ast::Id typeId = ast::NoId; public: - TypeRef(Tree& ast, AST::Id typeId) : ast(ast), typeId(typeId) + TypeRef(Tree& ast, ast::Id typeId) : ast(ast), typeId(typeId) { if (!IsNone(typeId)) { @@ -33,7 +33,7 @@ namespace rift::AST return ast; } - AST::Id GetId() const + ast::Id GetId() const { return typeId; } @@ -44,7 +44,7 @@ namespace rift::AST } - operator AST::Id() const + operator ast::Id() const { return typeId; } @@ -53,4 +53,4 @@ namespace rift::AST return IsValid(); } }; -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/Expressions.h b/Libs/AST/Include/AST/Utils/Expressions.h index 528b66b0..f12b13d6 100644 --- a/Libs/AST/Include/AST/Utils/Expressions.h +++ b/Libs/AST/Include/AST/Utils/Expressions.h @@ -10,9 +10,8 @@ #include - // NOTE: In expression graphs, the Link Id is the Input Pin Id -namespace rift::AST +namespace rift::ast { bool CanConnectExpr(TAccessRef access, ExprOutput output, ExprInput input); @@ -35,4 +34,4 @@ namespace rift::AST ExprInput GetExprInputFromPin(TAccessRef access, Id pinId); ExprOutput GetExprOutputFromPin(TAccessRef access, Id pinId); -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h index 5ff28fab..0e1b23a2 100644 --- a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -7,7 +7,7 @@ #include -namespace rift::AST +namespace rift::ast { class ModuleFileIterator : public p::LambdaFileIterator { @@ -33,4 +33,4 @@ namespace rift::AST { return {}; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index cac9ffa8..a2902720 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -7,17 +7,17 @@ #include "AST/Components/CProject.h" #include "AST/Tree.h" -#include #include +#include #include -namespace rift::AST +namespace rift::ast { struct CModule; } -namespace rift::AST +namespace rift::ast { struct ModuleBinding { @@ -59,15 +59,15 @@ namespace rift::AST // Resolve a module's name p::StringView GetModulePath(p::TAccessRef access, Id moduleId); - void SerializeModule(AST::Tree& ast, AST::Id id, String& data); - void DeserializeModule(AST::Tree& ast, AST::Id id, const String& data); + void SerializeModule(ast::Tree& ast, ast::Id id, String& data); + void DeserializeModule(ast::Tree& ast, ast::Id id, const String& data); const TBroadcast& OnReadModulePools(); const TBroadcast& OnWriteModulePools(); void RegisterModuleBinding(ModuleBinding binding); void UnregisterModuleBinding(p::Tag bindingId); - void AddBindingToModule(AST::Tree& ast, AST::Id id, p::Tag bindingId); - void RemoveBindingFromModule(AST::Tree& ast, AST::Id id, p::Tag bindingId); + void AddBindingToModule(ast::Tree& ast, ast::Id id, p::Tag bindingId); + void RemoveBindingFromModule(ast::Tree& ast, ast::Id id, p::Tag bindingId); const ModuleBinding* FindModuleBinding(p::Tag id); p::TView GetModuleBindings(); @@ -81,4 +81,4 @@ namespace rift::AST OnReadModulePools().Bind(components); OnWriteModulePools().Bind(components); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/Namespaces.h b/Libs/AST/Include/AST/Utils/Namespaces.h index 5a00c908..c5e78b77 100644 --- a/Libs/AST/Include/AST/Utils/Namespaces.h +++ b/Libs/AST/Include/AST/Utils/Namespaces.h @@ -11,7 +11,7 @@ #include -namespace rift::AST +namespace rift::ast { Namespace GetNamespace(p::TAccessRef access, Id id); Namespace GetParentNamespace(p::TAccessRef access, Id id); @@ -30,13 +30,13 @@ namespace rift::AST p::Tag GetNameUnsafe(p::TAccessRef access, Id id); p::String GetFullName( p::TAccessRef access, Id id, bool localNamespace = false); -} // namespace rift::AST +} // namespace rift::ast namespace p { template<> - struct TFlags : public DefaultTFlags + struct TFlags : public DefaultTFlags { enum { diff --git a/Libs/AST/Include/AST/Utils/Statements.h b/Libs/AST/Include/AST/Utils/Statements.h index 4dfa7c20..ef4f97f3 100644 --- a/Libs/AST/Include/AST/Utils/Statements.h +++ b/Libs/AST/Include/AST/Utils/Statements.h @@ -10,18 +10,17 @@ #include - // NOTE: In statement graphs, the Link Id is the Input Node Id -namespace rift::AST +namespace rift::ast { bool CanConnectStmt(const Tree& ast, Id outputNode, Id outputPin, Id inputNode); - bool TryConnectStmt(Tree& ast, AST::Id outputPin, AST::Id inputNode); + bool TryConnectStmt(Tree& ast, ast::Id outputPin, ast::Id inputNode); // Disconnects a particular link. (Note: link ids are the same as input nodes) - bool DisconnectStmtLink(Tree& ast, AST::Id linkId); - bool DisconnectStmtFromPrevious(Tree& ast, AST::Id inputPin); - bool DisconnectStmtFromNext(Tree& ast, AST::Id outputPin, AST::Id outputNode); - bool DisconnectStmtFromNext(Tree& ast, AST::Id outputPin); + bool DisconnectStmtLink(Tree& ast, ast::Id linkId); + bool DisconnectStmtFromPrevious(Tree& ast, ast::Id inputPin); + bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin, ast::Id outputNode); + bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin); /** * @brief Disconnects all inputs and outputs from this ids and the children nodes @@ -29,16 +28,16 @@ namespace rift::AST * @param ids * @param ignoreRoot ignore ids's inputs and outputs and only remove from children */ - void DisconnectAllStmtDeep(Tree& ast, TView ids, bool ignoreRoot = false); + void DisconnectAllStmtDeep(Tree& ast, TView ids, bool ignoreRoot = false); // TODO /** Check that a and b are connected (in any direction) */ - // bool AreNodesConnected(const Tree& ast, AST::Id outputNode, AST::Id inputNode); - // bool ArePinsConnected(const Tree& ast, AST::Id outputPin, AST::Id inputPin); - // bool IsOutputPinConnected(const Tree& ast, AST::Id outputPin); - // bool IsOutputPinConnected(const Tree& ast, AST::Id outputPin, AST::Id outputNode); - // bool IsInputPinConnected(const Tree& ast, AST::Id inputPin); - // bool IsInputPinConnected(const Tree& ast, AST::Id inputPin /*unused*/, AST::Id inputNode); + // bool AreNodesConnected(const Tree& ast, ast::Id outputNode, ast::Id inputNode); + // bool ArePinsConnected(const Tree& ast, ast::Id outputPin, ast::Id inputPin); + // bool IsOutputPinConnected(const Tree& ast, ast::Id outputPin); + // bool IsOutputPinConnected(const Tree& ast, ast::Id outputPin, ast::Id outputNode); + // bool IsInputPinConnected(const Tree& ast, ast::Id inputPin); + // bool IsInputPinConnected(const Tree& ast, ast::Id inputPin /*unused*/, ast::Id inputNode); /** Look for invalid ids and set them to NoId */ void CleanInvalidStmtIds(Tree& ast); @@ -55,4 +54,4 @@ namespace rift::AST void GetStmtChain(TAccessRef access, Id firstStmtId, TArray& stmtIds, Id& splitStmtId); -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/TransactionUtils.h b/Libs/AST/Include/AST/Utils/TransactionUtils.h index e256177d..f5ef716a 100644 --- a/Libs/AST/Include/AST/Utils/TransactionUtils.h +++ b/Libs/AST/Include/AST/Utils/TransactionUtils.h @@ -9,7 +9,7 @@ #include -namespace rift::AST +namespace rift::ast { using TransactionAccess = TAccessRef, TWrite, CChild, CFileRef>; @@ -34,7 +34,7 @@ namespace rift::AST bool PreChange(const TransactionAccess& access, TView entityIds); void PostChange(); } // namespace Transactions -} // namespace rift::AST +} // namespace rift::ast #define ScopedChange(access, entityIds) \ - rift::AST::Transactions::ScopedTransaction _transaction{access, entityIds}; + rift::ast::Transactions::ScopedTransaction _transaction{access, entityIds}; diff --git a/Libs/AST/Include/AST/Utils/TypeIterator.h b/Libs/AST/Include/AST/Utils/TypeIterator.h index 0b23e8d7..f57b7340 100644 --- a/Libs/AST/Include/AST/Utils/TypeIterator.h +++ b/Libs/AST/Include/AST/Utils/TypeIterator.h @@ -7,7 +7,7 @@ #include -namespace rift::AST +namespace rift::ast { class TypeIterator : public p::files::LambdaFileIterator { @@ -33,4 +33,4 @@ namespace rift::AST { return {}; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index f7dc5f26..6fa265d9 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -15,8 +15,7 @@ #include - -namespace rift::AST +namespace rift::ast { struct RiftTypeSettings { @@ -95,7 +94,7 @@ namespace rift::AST p::TView GetFileTypes(); const RiftType* FindFileType(p::Tag typeId); - const RiftType* FindFileType(p::TAccessRef access, AST::Id typeId); + const RiftType* FindFileType(p::TAccessRef access, ast::Id typeId); template void RegisterFileType(p::Tag typeId, RiftTypeSettings settings) @@ -103,4 +102,4 @@ namespace rift::AST RegisterFileType( {.id = typeId, .tagType = TagType::GetStaticType(), .settings = p::Move(settings)}); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Include/ASTModule.h b/Libs/AST/Include/ASTModule.h index 5272f46a..9d330972 100644 --- a/Libs/AST/Include/ASTModule.h +++ b/Libs/AST/Include/ASTModule.h @@ -7,7 +7,7 @@ namespace rift { - namespace AST + namespace ast { class Tree; } diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index 77f94ddb..97d7377a 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -27,13 +27,13 @@ namespace rift { P_STRUCT(Compiler, p::Struct) - AST::Tree& ast; + ast::Tree& ast; CompilerConfig config; TArray errors; public: - Compiler(AST::Tree& ast, const CompilerConfig& config) : ast{ast}, config{config} {} + Compiler(ast::Tree& ast, const CompilerConfig& config) : ast{ast}, config{config} {} // Errors void Error(StringView str); @@ -48,12 +48,12 @@ namespace rift }; - void Build(AST::Tree& tree, const CompilerConfig& config, TPtr backend); + void Build(ast::Tree& tree, const CompilerConfig& config, TPtr backend); - void Build(AST::Tree& ast, const CompilerConfig& config, ClassType* backendType); + void Build(ast::Tree& ast, const CompilerConfig& config, ClassType* backendType); template - void Build(AST::Tree& ast, const CompilerConfig& config) + void Build(ast::Tree& ast, const CompilerConfig& config) { Build(ast, config, T::GetStaticType()); } diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index 8bc94777..0921b691 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -39,7 +39,7 @@ namespace rift Path intermediatesPath; Path binariesPath; - void Init(AST::Tree& ast); + void Init(ast::Tree& ast); }; } // namespace rift ENUM(rift::OptimizationLevel); diff --git a/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h b/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h index cb5b4a5c..fd126808 100644 --- a/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h +++ b/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h @@ -1,13 +1,13 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -namespace rift::AST +namespace rift::ast { struct Tree; } namespace rift::OptimizationSystem { - void PruneDisconnectedStatements(AST::Tree& ast); - void PruneDisconnectedExpressions(AST::Tree& ast); + void PruneDisconnectedStatements(ast::Tree& ast); + void PruneDisconnectedExpressions(ast::Tree& ast); } // namespace rift::OptimizationSystem diff --git a/Libs/AST/Src/AST/Components/CNamespace.cpp b/Libs/AST/Src/AST/Components/CNamespace.cpp index db14e002..1af84283 100644 --- a/Libs/AST/Src/AST/Components/CNamespace.cpp +++ b/Libs/AST/Src/AST/Components/CNamespace.cpp @@ -3,7 +3,7 @@ #include "AST/Components/CNamespace.h" -namespace rift::AST +namespace rift::ast { Namespace::Namespace(p::StringView value) { @@ -120,4 +120,4 @@ namespace rift::AST ct.Next(scopes[i]); } } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp index 97253c32..530b9649 100644 --- a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp +++ b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp @@ -11,8 +11,7 @@ #include - -namespace rift::AST::FunctionsSystem +namespace rift::ast::FunctionsSystem { struct CallToSync { @@ -337,4 +336,4 @@ namespace rift::AST::FunctionsSystem { ast.AssurePool().Clear(); } -} // namespace rift::AST::FunctionsSystem +} // namespace rift::ast::FunctionsSystem diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index 22610cf6..e485a816 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -19,8 +19,7 @@ #include - -namespace rift::AST::LoadSystem +namespace rift::ast::LoadSystem { void Init(Tree& ast) { @@ -93,12 +92,12 @@ namespace rift::AST::LoadSystem pathsByModule.Reserve(modules.Size()); for (Id moduleId : modules) { - Path path = AST::GetModulePath(access, moduleId); + Path path = ast::GetModulePath(access, moduleId); auto& paths = pathsByModule.AddRef({moduleId}).paths; // Iterate all types ignoring other module paths for (const auto& typePath : - AST::TypeIterator(path /*TODO: Ignore paths | , &modulePaths*/)) + ast::TypeIterator(path /*TODO: Ignore paths | , &modulePaths*/)) { p::String path = p::ToString(typePath); if (p::GetStem(path) != "__module__") // Ignore module files @@ -219,4 +218,4 @@ namespace rift::AST::LoadSystem DeserializeType(ast, typeIds[i], strings[i]); } } -} // namespace rift::AST::LoadSystem +} // namespace rift::ast::LoadSystem diff --git a/Libs/AST/Src/AST/Systems/TransactionSystem.cpp b/Libs/AST/Src/AST/Systems/TransactionSystem.cpp index b3144127..0a67d0a0 100644 --- a/Libs/AST/Src/AST/Systems/TransactionSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TransactionSystem.cpp @@ -5,11 +5,11 @@ #include "AST/Components/Tags/CChanged.h" -namespace rift::AST::TransactionSystem +namespace rift::ast::TransactionSystem { void Init(Tree& ast) {} void ClearTags(Tree& ast) { ast.AssurePool().Clear(); } -} // namespace rift::AST::TransactionSystem +} // namespace rift::ast::TransactionSystem diff --git a/Libs/AST/Src/AST/Systems/TypeSystem.cpp b/Libs/AST/Src/AST/Systems/TypeSystem.cpp index 73e3f32b..a9af8ee1 100644 --- a/Libs/AST/Src/AST/Systems/TypeSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TypeSystem.cpp @@ -13,7 +13,7 @@ #include -namespace rift::AST::TypeSystem +namespace rift::ast::TypeSystem { void Init(Tree& ast) { @@ -149,4 +149,4 @@ namespace rift::AST::TypeSystem } } } -} // namespace rift::AST::TypeSystem +} // namespace rift::ast::TypeSystem diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index 8bdb7604..87c380c1 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -10,8 +10,7 @@ #include - -namespace rift::AST +namespace rift::ast { TBroadcast Tree::onInit{}; @@ -137,4 +136,4 @@ namespace rift::AST return text; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index 0bea52ad..62da6842 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -5,7 +5,7 @@ #include "AST/Id.h" -namespace rift::AST +namespace rift::ast { bool WouldExprLoop( TAccessRef access, Id outputNodeId, Id inputNodeId) @@ -188,4 +188,4 @@ namespace rift::AST } return output; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp index 90fa981c..65816e84 100644 --- a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp +++ b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp @@ -15,7 +15,7 @@ #include -namespace rift::AST +namespace rift::ast { static p::TArray gModuleBindings; TBroadcast gOnReadModulePools; @@ -196,7 +196,7 @@ namespace rift::AST return {}; } - void SerializeModule(AST::Tree& ast, AST::Id id, String& data) + void SerializeModule(ast::Tree& ast, ast::Id id, String& data) { JsonFormatWriter writer{}; p::EntityWriter w{writer.GetWriter(), ast}; @@ -206,7 +206,7 @@ namespace rift::AST data = writer.ToString(); } - void DeserializeModule(AST::Tree& ast, AST::Id id, const String& data) + void DeserializeModule(ast::Tree& ast, ast::Id id, const String& data) { JsonFormatReader formatReader{data}; if (formatReader.IsValid()) @@ -234,14 +234,14 @@ namespace rift::AST { gModuleBindings.RemoveSorted(bindingId); } - void AddBindingToModule(AST::Tree& ast, AST::Id id, p::Tag bindingId) + void AddBindingToModule(ast::Tree& ast, ast::Id id, p::Tag bindingId) { if (const auto* binding = FindModuleBinding(bindingId)) { ast.AddDefault(binding->tagType->GetId(), id); } } - void RemoveBindingFromModule(AST::Tree& ast, AST::Id id, p::Tag bindingId) + void RemoveBindingFromModule(ast::Tree& ast, ast::Id id, p::Tag bindingId) { if (const auto* binding = FindModuleBinding(bindingId)) { @@ -259,4 +259,4 @@ namespace rift::AST { return gModuleBindings; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index 68e47976..1f099044 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -10,7 +10,7 @@ #include -namespace rift::AST +namespace rift::ast { Namespace GetNamespace(TAccessRef access, Id id) { @@ -111,4 +111,4 @@ namespace rift::AST return GetNamespace(access, id).ToString(localNamespace); } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/Statements.cpp b/Libs/AST/Src/AST/Utils/Statements.cpp index 73ae6e42..bf84004c 100644 --- a/Libs/AST/Src/AST/Utils/Statements.cpp +++ b/Libs/AST/Src/AST/Utils/Statements.cpp @@ -5,7 +5,7 @@ #include "AST/Id.h" -namespace rift::AST +namespace rift::ast { bool CanConnectStmt(const Tree& ast, Id outputNode, Id outputPin, Id inputNode) { @@ -31,7 +31,7 @@ namespace rift::AST } // Resolve output node. Sometimes the output pin itself is the node - Id outputNode = AST::NoId; + Id outputNode = ast::NoId; if (ast.Has(outputPin)) { outputNode = outputPin; @@ -52,16 +52,16 @@ namespace rift::AST auto& inputComp = ast.Get(inputNode); - if (inputComp.linkOutputNode != AST::NoId) + if (inputComp.linkOutputNode != ast::NoId) { // Disconnect previous output connected to input if any if (auto* lastOutputComp = ast.TryGet(inputComp.linkOutputNode)) { - lastOutputComp->linkInputNode = AST::NoId; + lastOutputComp->linkInputNode = ast::NoId; } else if (auto* lastOutputsComp = ast.TryGet(inputComp.linkOutputNode)) { - lastOutputsComp->linkInputNodes.FindRef(inputNode) = AST::NoId; + lastOutputsComp->linkInputNodes.FindRef(inputNode) = ast::NoId; } } inputComp.linkOutputNode = outputNode; @@ -72,9 +72,9 @@ namespace rift::AST // Connect if single output Id& lastInputNode = outputComp->linkInputNode; // Disconnect previous input connected to output if any - if (lastInputNode != AST::NoId && ast.Has(lastInputNode)) + if (lastInputNode != ast::NoId && ast.Has(lastInputNode)) { - ast.Get(lastInputNode).linkOutputNode = AST::NoId; + ast.Get(lastInputNode).linkOutputNode = ast::NoId; } lastInputNode = inputNode; } @@ -86,9 +86,9 @@ namespace rift::AST { Id& lastInputNode = outputsComp->linkInputNodes[pinIndex]; // Disconnect previous input connected to output if any - if (lastInputNode != AST::NoId && ast.Has(lastInputNode)) + if (lastInputNode != ast::NoId && ast.Has(lastInputNode)) { - ast.Get(lastInputNode).linkOutputNode = AST::NoId; + ast.Get(lastInputNode).linkOutputNode = ast::NoId; } lastInputNode = inputNode; } @@ -119,20 +119,20 @@ namespace rift::AST auto& outputsComp = ast.Get(inputComp->linkOutputNode); if (Id* lastInputNode = outputsComp.linkInputNodes.Find(linkId)) [[likely]] { - *lastInputNode = AST::NoId; + *lastInputNode = ast::NoId; } - inputComp->linkOutputNode = AST::NoId; + inputComp->linkOutputNode = ast::NoId; return true; } return false; } - bool DisconnectStmtFromPrevious(Tree& ast, AST::Id inputPin) + bool DisconnectStmtFromPrevious(Tree& ast, ast::Id inputPin) { // NOTE: Input pin ids equal input node ids return DisconnectStmtLink(ast, inputPin); } - bool DisconnectStmtFromNext(Tree& ast, AST::Id outputPin, AST::Id outputNode) + bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin, ast::Id outputNode) { // NOTE: Can be optimized if needed since outputs is accessed twice counting // Disconnect() @@ -146,14 +146,14 @@ namespace rift::AST } return false; } - bool DisconnectStmtFromNext(Tree& ast, AST::Id outputPin) + bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin) { return DisconnectStmtFromNext(ast, outputPin, p::GetIdParent(ast, outputPin)); } bool WouldStmtLoop(const Tree& ast, Id outputNode, Id outputPin, Id inputNode) { - AST::Id currentNode = outputNode; + ast::Id currentNode = outputNode; while (!IsNone(currentNode)) { const auto* input = ast.TryGet(currentNode); @@ -218,7 +218,7 @@ namespace rift::AST TArray& stmtIds, Id& splitStmtId) { Id id = firstStmtId; - while (id != AST::NoId && access.Has(id)) + while (id != ast::NoId && access.Has(id)) { stmtIds.Add(id); id = access.Get(id).linkInputNode; @@ -229,4 +229,4 @@ namespace rift::AST splitStmtId = id; } } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index f1abc2a4..5fc9c6df 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -7,7 +7,7 @@ #include -namespace rift::AST::Transactions +namespace rift::ast::Transactions { // Transaction being recorded static Transaction gActiveTransaction = {}; @@ -65,4 +65,4 @@ namespace rift::AST::Transactions gActiveTransaction = {}; } } -} // namespace rift::AST::Transactions +} // namespace rift::ast::Transactions diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 76c4fad9..5c89e426 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -22,7 +22,7 @@ #include -namespace rift::AST +namespace rift::ast { static p::TArray gFileTypes; @@ -489,12 +489,12 @@ namespace rift::AST return index != NO_INDEX ? gFileTypes.Data() + index : nullptr; } - const RiftType* FindFileType(p::TAccessRef access, AST::Id typeId) + const RiftType* FindFileType(p::TAccessRef access, ast::Id typeId) { - if (const auto* type = access.TryGet(typeId)) + if (const auto* type = access.TryGet(typeId)) { return FindFileType(type->typeId); } return nullptr; } -} // namespace rift::AST +} // namespace rift::ast diff --git a/Libs/AST/Src/ASTModule.cpp b/Libs/AST/Src/ASTModule.cpp index a748b0df..a8281208 100644 --- a/Libs/AST/Src/ASTModule.cpp +++ b/Libs/AST/Src/ASTModule.cpp @@ -9,7 +9,6 @@ #include "AST/Utils/TypeUtils.h" - namespace rift { const p::Tag ASTModule::structType = "Struct"; @@ -19,14 +18,14 @@ namespace rift void ASTModule::Load() { - AST::RegisterFileType( + ast::RegisterFileType( structType, {.displayName = "Struct", .hasVariables = true, .hasFunctions = false}); - AST::RegisterFileType( + ast::RegisterFileType( classType, {.displayName = "Class", .hasVariables = true, .hasFunctions = true}); - AST::RegisterFileType( + ast::RegisterFileType( staticType, {.displayName = "Static", .hasVariables = true, .hasFunctions = true}); - AST::PreAllocPools(); + ast::PreAllocPools(); - AST::RegisterSerializedModulePools(); + ast::RegisterSerializedModulePools(); } } // namespace rift diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 2dffe997..c45df267 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -24,7 +24,7 @@ namespace rift } - void Build(AST::Tree& ast, const CompilerConfig& config, TPtr backend) + void Build(ast::Tree& ast, const CompilerConfig& config, TPtr backend) { Compiler compiler{ast, config}; @@ -34,7 +34,7 @@ namespace rift return; } - if (!AST::HasProject(ast)) + if (!ast::HasProject(ast)) { p::Error("No existing project to build."); return; @@ -49,14 +49,14 @@ namespace rift } p::Info("Loading files"); - AST::LoadSystem::Run(ast); + ast::LoadSystem::Run(ast); OptimizationSystem::PruneDisconnectedExpressions(ast); - AST::TypeSystem::PropagateVariableTypes(ast); - AST::TypeSystem::PropagateExpressionTypes(ast); + ast::TypeSystem::PropagateVariableTypes(ast); + ast::TypeSystem::PropagateExpressionTypes(ast); - p::Info("Building project '{}'", AST::GetProjectName(compiler.ast)); + p::Info("Building project '{}'", ast::GetProjectName(compiler.ast)); // Clean build folders p::Info("Cleaning previous build"); files::Delete(compiler.config.binariesPath, true, false); @@ -65,7 +65,7 @@ namespace rift backend->Build(compiler); } - void Build(AST::Tree& ast, const CompilerConfig& config, ClassType* backendType) + void Build(ast::Tree& ast, const CompilerConfig& config, ClassType* backendType) { if (backendType) { diff --git a/Libs/AST/Src/Compiler/CompilerConfig.cpp b/Libs/AST/Src/Compiler/CompilerConfig.cpp index 795bd17e..fe8d09bf 100644 --- a/Libs/AST/Src/Compiler/CompilerConfig.cpp +++ b/Libs/AST/Src/Compiler/CompilerConfig.cpp @@ -7,9 +7,9 @@ namespace rift { - void CompilerConfig::Init(AST::Tree& ast) + void CompilerConfig::Init(ast::Tree& ast) { - buildPath = p::JoinPaths(AST::GetProjectPath(ast), "Build"); + buildPath = p::JoinPaths(ast::GetProjectPath(ast), "Build"); intermediatesPath = buildPath / "Intermediates"; binariesPath = buildPath / "Binaries"; } diff --git a/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp b/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp index 1e2a666b..62b745fc 100644 --- a/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp +++ b/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp @@ -5,12 +5,12 @@ namespace rift::OptimizationSystem { - void PruneDisconnectedStatements(AST::Tree& ast) + void PruneDisconnectedStatements(ast::Tree& ast) { // TODO } - void PruneDisconnectedExpressions(AST::Tree& ast) + void PruneDisconnectedExpressions(ast::Tree& ast) { // TODO } diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index 40bbb8c6..4a260315 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -31,9 +31,9 @@ namespace rift::MIR c2mir_options options; InitCToMIROptions(options); - for (AST::Id moduleId : FindAllIdsWith(compiler.ast)) + for (ast::Id moduleId : FindAllIdsWith(compiler.ast)) { - p::Tag name = AST::GetModuleName(compiler.ast, moduleId); + p::Tag name = ast::GetModuleName(compiler.ast, moduleId); auto& mirModule = compiler.ast.Get(moduleId); CToMIRModule(compiler, ctx, options, name, mirModule); } diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 0b9369e8..3a8a9a2a 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -19,45 +19,45 @@ namespace rift::MIR CGenerator cGen{compiler, access}; cGen.BindNativeTypes(); cGen.GenerateLiterals(); - for (AST::Id moduleId : FindAllIdsWith(access)) + for (ast::Id moduleId : FindAllIdsWith(access)) { cGen.GenerateModule(moduleId); } } - void CGenerator::GenerateModule(AST::Id moduleId) + void CGenerator::GenerateModule(ast::Id moduleId) { - const Tag name = AST::GetModuleName(compiler.ast, moduleId); + const Tag name = ast::GetModuleName(compiler.ast, moduleId); CMIRModule& mirModule = compiler.ast.Add(moduleId); code = &mirModule.code; // Get all rift types from the module - TArray typeIds; + TArray typeIds; p::GetIdChildren(access, moduleId, typeIds); - ExcludeIdsWithout(access, typeIds); + ExcludeIdsWithout(access, typeIds); { // Native declarations - TArray cStructIds = FindIdsWith(access, typeIds); - TArray cStaticIds = FindIdsWith(access, typeIds); - TArray cFunctionIds; + TArray cStructIds = FindIdsWith(access, typeIds); + TArray cStaticIds = FindIdsWith(access, typeIds); + TArray cFunctionIds; p::GetIdChildren(access, cStaticIds, cFunctionIds); - ExcludeIdsWithout(access, cFunctionIds); + ExcludeIdsWithout(access, cFunctionIds); DeclareStructs(cStructIds); DeclareFunctions(cFunctionIds, false); } - TArray staticFunctionIds; + TArray staticFunctionIds; { // Rift declarations & definitions - TArray structIds = FindIdsWith(access, typeIds); - TArray staticIds = FindIdsWith(access, typeIds); - TArray classIds = FindIdsWith(access, typeIds); - TArray classFunctionIds; + TArray structIds = FindIdsWith(access, typeIds); + TArray staticIds = FindIdsWith(access, typeIds); + TArray classIds = FindIdsWith(access, typeIds); + TArray classFunctionIds; p::GetIdChildren(access, staticIds, staticFunctionIds); p::GetIdChildren(access, classIds, classFunctionIds); - ExcludeIdsWithout(access, staticFunctionIds); - ExcludeIdsWithout(access, classFunctionIds); - TArray functionIds; + ExcludeIdsWithout(access, staticFunctionIds); + ExcludeIdsWithout(access, classFunctionIds); + TArray functionIds; functionIds.Append(staticFunctionIds); functionIds.Append(classFunctionIds); @@ -70,9 +70,9 @@ namespace rift::MIR DefineFunctions(functionIds); } - AST::Id mainFunctionId = AST::NoId; - const auto& module = compiler.ast.Get(moduleId); - if (module.target == AST::RiftModuleTarget::Executable) + ast::Id mainFunctionId = ast::NoId; + const auto& module = compiler.ast.Get(moduleId); + if (module.target == ast::RiftModuleTarget::Executable) { mainFunctionId = FindMainFunction(staticFunctionIds); CreateMain(mainFunctionId); @@ -81,7 +81,7 @@ namespace rift::MIR void CGenerator::BindNativeTypes() { - const auto& nativeTypes = static_cast(access.GetContext()).GetNativeTypes(); + const auto& nativeTypes = static_cast(access.GetContext()).GetNativeTypes(); access.Add(nativeTypes.boolId, CMIRType{"char"}); access.Add(nativeTypes.floatId, CMIRType{"float"}); access.Add(nativeTypes.doubleId, CMIRType{"double"}); @@ -98,34 +98,34 @@ namespace rift::MIR void CGenerator::GenerateLiterals() { - for (AST::Id id : FindAllIdsWith(access)) + for (ast::Id id : FindAllIdsWith(access)) { - const auto& boolean = access.Get(id); + const auto& boolean = access.Get(id); access.Add(id, CMIRLiteral{.value = boolean.value ? "true" : "false"}); } String strValue; - for (AST::Id id : FindAllIdsWith(access)) + for (ast::Id id : FindAllIdsWith(access)) { strValue.clear(); - const auto& integral = access.Get(id); + const auto& integral = access.Get(id); Strings::ToString(strValue, integral.value); access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); } - for (AST::Id id : FindAllIdsWith(access)) + for (ast::Id id : FindAllIdsWith(access)) { strValue.clear(); - const auto& floating = access.Get(id); + const auto& floating = access.Get(id); Strings::ToString(strValue, floating.value); - if (floating.type == AST::FloatingType::F32) + if (floating.type == ast::FloatingType::F32) { strValue.push_back('f'); } access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); } - for (AST::Id id : FindAllIdsWith(access)) + for (ast::Id id : FindAllIdsWith(access)) { strValue.clear(); - const auto& string = access.Get(id); + const auto& string = access.Get(id); strValue.push_back('\"'); strValue.append(string.value); strValue.push_back('\"'); @@ -133,42 +133,42 @@ namespace rift::MIR } } - void CGenerator::DeclareStructs(TView ids) + void CGenerator::DeclareStructs(TView ids) { code->append("// Struct Declarations\n"); - for (AST::Id id : ids) + for (ast::Id id : ids) { - p::Tag name = AST::GetNameUnsafe(access, id); + p::Tag name = ast::GetNameUnsafe(access, id); access.Add(id, CMIRType{name}); Strings::FormatTo(*code, "typedef struct {0} {0};\n", name); } code->push_back('\n'); } - void CGenerator::DefineStructs(TView ids) + void CGenerator::DefineStructs(TView ids) { code->append("// Struct Definitions\n"); p::String membersCode; - TArray memberIds; - for (AST::Id id : ids) + TArray memberIds; + for (ast::Id id : ids) { membersCode.clear(); memberIds.Clear(false); p::GetIdChildren(access, id, memberIds); - ExcludeIdsWithout(access, memberIds); - for (AST::Id memberId : memberIds) + ExcludeIdsWithout(access, memberIds); + for (ast::Id memberId : memberIds) { - const auto& var = access.Get(memberId); + const auto& var = access.Get(memberId); - const Tag memberName = AST::GetName(access, memberId); + const Tag memberName = ast::GetName(access, memberId); if (auto* irType = access.TryGet(var.typeId)) { Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); } else { - const Tag typeName = AST::GetName(access, id); + const Tag typeName = ast::GetName(access, id); compiler.Error(Strings::Format( "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); } @@ -180,33 +180,33 @@ namespace rift::MIR code->push_back('\n'); } - void CGenerator::DeclareFunctions(TView ids, bool useFullName) + void CGenerator::DeclareFunctions(TView ids, bool useFullName) { code->append("// Function Declarations\n"); - for (AST::Id id : ids) + for (ast::Id id : ids) { auto& signature = access.Add(id).value; signature.append("void "); - const p::String name = useFullName ? AST::GetFullName(access, id) - : p::String{AST::GetName(access, id).AsString()}; + const p::String name = useFullName ? ast::GetFullName(access, id) + : p::String{ast::GetName(access, id).AsString()}; signature.append(name); signature.push_back('('); - if (auto* outputs = access.TryGet(id)) + if (auto* outputs = access.TryGet(id)) { for (i32 i = 0; i < outputs->pinIds.Size(); ++i) { - AST::Id inputId = outputs->pinIds[i]; - if (access.Has(inputId)) + ast::Id inputId = outputs->pinIds[i]; + if (access.Has(inputId)) { continue; } - Tag inputName = AST::GetName(access, inputId); + Tag inputName = ast::GetName(access, inputId); - auto* exprId = access.TryGet(inputId); + auto* exprId = access.TryGet(inputId); const auto* irType = exprId ? access.TryGet(exprId->id) : nullptr; if (irType) [[likely]] @@ -215,7 +215,7 @@ namespace rift::MIR } else { - const String functionName = AST::GetFullName(access, id); + const String functionName = ast::GetFullName(access, id); compiler.Error(Strings::Format( "Input '{}' in function '{}' has an invalid type. Using i32 instead.", inputName, functionName)); @@ -232,16 +232,16 @@ namespace rift::MIR code->push_back('\n'); } - void CGenerator::DefineFunctions(TView ids) + void CGenerator::DefineFunctions(TView ids) { code->append("// Function Definitions\n"); - for (AST::Id id : ids) + for (ast::Id id : ids) { const p::String& signature = access.Get(id).value; code->append(signature); code->append(" {\n"); - const auto& output = access.Get(id); + const auto& output = access.Get(id); AddStmtBlock(output.linkInputNode); code->append("}\n"); @@ -249,23 +249,23 @@ namespace rift::MIR code->push_back('\n'); } - void CGenerator::AddStmtBlock(AST::Id firstStmtId) + void CGenerator::AddStmtBlock(ast::Id firstStmtId) { - AST::Id splitId = AST::NoId; - TArray stmtIds; - AST::GetStmtChain(access, firstStmtId, stmtIds, splitId); + ast::Id splitId = ast::NoId; + TArray stmtIds; + ast::GetStmtChain(access, firstStmtId, stmtIds, splitId); - for (AST::Id id : stmtIds) + for (ast::Id id : stmtIds) { - if (const auto* call = access.TryGet(id)) + if (const auto* call = access.TryGet(id)) { AddCall(id, *call); } } - if (splitId != AST::NoId) + if (splitId != ast::NoId) { - if (access.Has(splitId)) + if (access.Has(splitId)) { AddStmtIf(splitId); } @@ -273,19 +273,19 @@ namespace rift::MIR // TODO: Resolve continuation block and generate it } - void CGenerator::AddExpr(const AST::ExprOutput& output) + void CGenerator::AddExpr(const ast::ExprOutput& output) { const auto* value = !IsNone(output.pinId) ? access.TryGet(output.pinId) : nullptr; // TODO } - void CGenerator::AddStmtIf(AST::Id id) + void CGenerator::AddStmtIf(ast::Id id) { - const auto& outputs = access.Get(id); + const auto& outputs = access.Get(id); const auto& connectedIds = outputs.linkInputNodes; Check(connectedIds.Size() == 2); - const auto& exprInputs = access.Get(id); + const auto& exprInputs = access.Get(id); Check(exprInputs.linkedOutputs.Size() == 1); code->append("if ("); @@ -297,9 +297,9 @@ namespace rift::MIR code->append("}\n"); } - void CGenerator::AddCall(AST::Id id, const AST::CExprCallId& call) + void CGenerator::AddCall(ast::Id id, const ast::CExprCallId& call) { - const AST::Id functionId = call.functionId; + const ast::Id functionId = call.functionId; if (!access.IsValid(functionId)) { compiler.Error("Call to an unknown function"); @@ -308,15 +308,15 @@ namespace rift::MIR if (!Ensure(access.Has(functionId))) { compiler.Error(Strings::Format( - "Call to an invalid function: '{}'", AST::GetName(access, functionId))); + "Call to an invalid function: '{}'", ast::GetName(access, functionId))); return; } - if (auto* inputs = access.TryGet(id)) + if (auto* inputs = access.TryGet(id)) { for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) { - AST::ExprOutput output = inputs->linkedOutputs[i]; + ast::ExprOutput output = inputs->linkedOutputs[i]; if (!output.IsNone()) { AddExpr(output); @@ -332,7 +332,7 @@ namespace rift::MIR code->push_back(')'); } - void CGenerator::CreateMain(AST::Id functionId) + void CGenerator::CreateMain(ast::Id functionId) { if (p::IsNone(functionId)) { @@ -345,18 +345,18 @@ namespace rift::MIR code->append("void main() {\nMain();\nreturn 0;\n}\n"); } - AST::Id CGenerator::FindMainFunction(p::TView functionIds) + ast::Id CGenerator::FindMainFunction(p::TView functionIds) { static const p::Tag mainFunctionName{"Main"}; - for (AST::Id id : functionIds) + for (ast::Id id : functionIds) { - const auto* ns = access.TryGet(id); + const auto* ns = access.TryGet(id); if (ns && ns->name == mainFunctionName) { return id; } } - return AST::NoId; + return ast::NoId; } } // namespace rift::MIR diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index 7d5619b1..a17ca3f0 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -13,7 +13,6 @@ #include - namespace rift { struct Compiler; @@ -22,11 +21,11 @@ namespace rift namespace rift::MIR { // Defines a single ecs access dfor the entire IR generation - using MIRAccess = p::TAccessRef, p::TWrite, p::TWrite>; @@ -39,22 +38,22 @@ namespace rift::MIR MIRAccess access; p::String* code = nullptr; - void GenerateModule(AST::Id moduleId); + void GenerateModule(ast::Id moduleId); void BindNativeTypes(); void GenerateLiterals(); - void DeclareStructs(p::TView ids); - void DefineStructs(p::TView ids); - void DeclareFunctions(p::TView ids, bool useFullName = true); - void DefineFunctions(p::TView ids); - - void AddStmtBlock(AST::Id firstStmtId); - void AddStmtIf(AST::Id id); - void AddExpr(const AST::ExprOutput& output); - void AddCall(AST::Id id, const AST::CExprCallId& call); - void CreateMain(AST::Id functionId); - AST::Id FindMainFunction(p::TView functionIds); + void DeclareStructs(p::TView ids); + void DefineStructs(p::TView ids); + void DeclareFunctions(p::TView ids, bool useFullName = true); + void DefineFunctions(p::TView ids); + + void AddStmtBlock(ast::Id firstStmtId); + void AddStmtIf(ast::Id id); + void AddExpr(const ast::ExprOutput& output); + void AddCall(ast::Id id, const ast::CExprCallId& call); + void CreateMain(ast::Id functionId); + ast::Id FindMainFunction(p::TView functionIds); }; } // namespace rift::MIR diff --git a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h index 22eb4d20..80385ed1 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h @@ -6,12 +6,12 @@ namespace rift { - struct CDeclCStruct : public AST::CDeclRecord + struct CDeclCStruct : public ast::CDeclRecord { P_STRUCT(CDeclCStruct, CDeclRecord) }; - struct CDeclCStatic : public AST::CDeclRecord + struct CDeclCStatic : public ast::CDeclRecord { P_STRUCT(CDeclCStatic, CDeclRecord) }; diff --git a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h index a44ff5b3..f8ffea9f 100644 --- a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h +++ b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h @@ -7,7 +7,7 @@ namespace rift { - namespace AST + namespace ast { class Tree; } @@ -17,6 +17,6 @@ namespace rift P_CLASS(NativeBindingModule, Module) void Load() override; - void SyncIncludes(AST::Tree& ast); + void SyncIncludes(ast::Tree& ast); }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 4b57a1ef..6b8ca1dc 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -16,7 +16,6 @@ #include - // P_OVERRIDE_NEW_DELETE @@ -24,38 +23,38 @@ namespace rift { struct ParsedModule { - AST::Id id = AST::NoId; + ast::Id id = ast::NoId; TArray headers; }; void NativeBindingModule::Load() { // Register types - AST::RiftTypeSettings typeSettings{.category = "Bindings"}; + ast::RiftTypeSettings typeSettings{.category = "Bindings"}; typeSettings.displayName = "C Struct"; typeSettings.hasVariables = true; typeSettings.hasFunctions = false; - AST::RegisterFileType("CStruct", typeSettings); + ast::RegisterFileType("CStruct", typeSettings); typeSettings.displayName = "C Static"; typeSettings.hasVariables = true; typeSettings.hasFunctions = true; typeSettings.hasFunctionBodies = false; - AST::RegisterFileType("CStatic", typeSettings); - AST::PreAllocPools(); + ast::RegisterFileType("CStatic", typeSettings); + ast::PreAllocPools(); // Register module binding - AST::RegisterModuleBinding( + ast::RegisterModuleBinding( {.id = "C", .tagType = CNativeBinding::GetStaticType(), .displayName = "C"}); - AST::RegisterSerializedModulePools(); - AST::PreAllocPools(); + ast::RegisterSerializedModulePools(); + ast::PreAllocPools(); } - void FindHeaders(AST::Tree& ast, TView parsedModules) + void FindHeaders(ast::Tree& ast, TView parsedModules) { - p::TAccess access{ast}; + p::TAccess access{ast}; for (auto& module : parsedModules) { - Path path = AST::GetModulePath(access, module.id); + Path path = ast::GetModulePath(access, module.id); for (const auto& headerPath : HeaderIterator(path)) { module.headers.Add(p::ToString(headerPath)); @@ -63,10 +62,10 @@ namespace rift } } - void NativeBindingModule::SyncIncludes(AST::Tree& ast) + void NativeBindingModule::SyncIncludes(ast::Tree& ast) { - TArray moduleIds; - p::FindAllIdsWith(ast, moduleIds); + TArray moduleIds; + p::FindAllIdsWith(ast, moduleIds); // Only use automatic native bindings on modules marked as such moduleIds.RemoveIfSwap([ast](auto id) { diff --git a/Libs/Editor/Include/Components/CTypeEditor.h b/Libs/Editor/Include/Components/CTypeEditor.h index e41574b2..d734b757 100644 --- a/Libs/Editor/Include/Components/CTypeEditor.h +++ b/Libs/Editor/Include/Components/CTypeEditor.h @@ -27,8 +27,8 @@ namespace rift::Editor bool showElements = true; bool showDetails = true; - AST::Id selectedPropertyId = AST::NoId; - AST::Id pendingDeletePropertyId = AST::NoId; + ast::Id selectedPropertyId = ast::NoId; + ast::Id pendingDeletePropertyId = ast::NoId; Nodes::EditorContext nodesEditor; ImGuiTextFilter elementsFilter; diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index 551d8720..767070b8 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -17,7 +17,7 @@ namespace rift::Editor bool configFileChanged = false; String configFile; - AST::Tree ast; + ast::Tree ast; public: #if P_DEBUG @@ -44,7 +44,7 @@ namespace rift::Editor return instance; } - static AST::Tree& GetContext() + static ast::Tree& GetContext() { return Get().ast; } diff --git a/Libs/Editor/Include/Panels/FileExplorerPanel.h b/Libs/Editor/Include/Panels/FileExplorerPanel.h index 62eae5c4..15326197 100644 --- a/Libs/Editor/Include/Panels/FileExplorerPanel.h +++ b/Libs/Editor/Include/Panels/FileExplorerPanel.h @@ -13,7 +13,6 @@ #include - namespace rift::Editor { // Forward declarations @@ -33,7 +32,7 @@ namespace rift::Editor struct Item { - AST::Id id = AST::NoId; + ast::Id id = ast::NoId; p::String path; bool isFolder = false; }; @@ -44,14 +43,14 @@ namespace rift::Editor }; private: - AST::Id projectModuleId = AST::NoId; + ast::Id projectModuleId = ast::NoId; p::TMap folders; bool open = true; bool dirty = true; Filter filter = Filter::All; - AST::Id renameId = AST::NoId; + ast::Id renameId = ast::NoId; p::String renameBuffer; bool renameHasFocused = false; @@ -62,26 +61,26 @@ namespace rift::Editor FileExplorerPanel() {} void BuildLayout(); - void Draw(AST::Tree& ast); + void Draw(ast::Tree& ast); - void DrawList(AST::Tree& ast); + void DrawList(ast::Tree& ast); - void DrawContextMenu(AST::Tree& ast, p::StringView path, AST::Id itemId); + void DrawContextMenu(ast::Tree& ast, p::StringView path, ast::Id itemId); void CacheProjectFiles( - p::TAccessRef access); + p::TAccessRef access); void SortFolder(Folder& folder); private: void InsertItem(const Item& item); - void DrawItem(AST::Tree& ast, const Item& item); - // void DrawFile(AST::Tree& ast, File& file); + void DrawItem(ast::Tree& ast, const Item& item); + // void DrawFile(ast::Tree& ast, File& file); - void DrawModuleActions(AST::Id id, struct AST::CModule& module); - void DrawTypeActions(AST::Id id, struct AST::CDeclType& type); + void DrawModuleActions(ast::Id id, struct ast::CModule& module); + void DrawTypeActions(ast::Id id, struct ast::CDeclType& type); - void CreateType(AST::Tree& ast, p::StringView title, p::Tag typeId, p::StringView path); + void CreateType(ast::Tree& ast, p::StringView title, p::Tag typeId, p::StringView path); }; diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index 332be780..ad165b45 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -27,13 +27,13 @@ namespace rift::Editor static const Tag centralNode; String currentProjectPath; - TArray pendingTypesToClose; + TArray pendingTypesToClose; FileWatcher fileWatcher; FileExplorerPanel fileExplorer{}; ReflectionDebugger reflectionDebugger; - ASTDebugger astDebugger; + ASTDebugger ASTDebugger; MemoryDebugger memoryDebugger; GraphPlayground graphPlayground; diff --git a/Libs/Editor/Include/Systems/EditorSystem.h b/Libs/Editor/Include/Systems/EditorSystem.h index 821f7931..791da7a0 100644 --- a/Libs/Editor/Include/Systems/EditorSystem.h +++ b/Libs/Editor/Include/Systems/EditorSystem.h @@ -6,6 +6,6 @@ namespace rift::Editor::EditorSystem { - void Init(AST::Tree& ast); - void Draw(AST::Tree& ast); + void Init(ast::Tree& ast); + void Draw(ast::Tree& ast); } // namespace rift::Editor::EditorSystem diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 79dafaaa..8d39c43e 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -19,7 +19,7 @@ namespace rift::Editor { struct InspectorPanel { - AST::Id id = AST::NoId; + ast::Id id = ast::NoId; bool pendingFocus = true; bool open = true; @@ -34,7 +34,7 @@ namespace rift::Editor bool open = false; bool showHierarchy = true; - AST::Id selectedNode = AST::NoId; + ast::Id selectedNode = ast::NoId; ImGuiTextFilter filter; // First inspector is the main inspector @@ -44,18 +44,18 @@ namespace rift::Editor ASTDebugger(); - void Draw(AST::Tree& ast); + void Draw(ast::Tree& ast); private: using DrawNodeAccess = - p::TAccessRef; - void DrawNode(DrawNodeAccess access, AST::Id nodeId, bool showChildren); + p::TAccessRef; + void DrawNode(DrawNodeAccess access, ast::Id nodeId, bool showChildren); - void OnInspectEntity(AST::Id id); + void OnInspectEntity(ast::Id id); - void DrawEntityInspector(p::StringView label, p::StringView id, AST::Tree& ast, + void DrawEntityInspector(p::StringView label, p::StringView id, ast::Tree& ast, InspectorPanel& inspector, bool* open = nullptr); - void OpenAvailableSecondaryInspector(AST::Id id); + void OpenAvailableSecondaryInspector(ast::Id id); }; } // namespace rift::Editor diff --git a/Libs/Editor/Include/Tools/GraphPlayground.h b/Libs/Editor/Include/Tools/GraphPlayground.h index 493a4568..9f57a3a3 100644 --- a/Libs/Editor/Include/Tools/GraphPlayground.h +++ b/Libs/Editor/Include/Tools/GraphPlayground.h @@ -18,6 +18,6 @@ namespace rift::Editor GraphPlayground() {} - void Draw(AST::Tree& ast, struct DockSpaceLayout& layout); + void Draw(ast::Tree& ast, struct DockSpaceLayout& layout); }; } // namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/DetailsPanel.h b/Libs/Editor/Include/Utils/DetailsPanel.h index ab92ea8a..d016ce3a 100644 --- a/Libs/Editor/Include/Utils/DetailsPanel.h +++ b/Libs/Editor/Include/Utils/DetailsPanel.h @@ -13,5 +13,5 @@ namespace rift::Editor { - void DrawDetailsPanel(AST::Tree& ast, AST::Id typeId); + void DrawDetailsPanel(ast::Tree& ast, ast::Id typeId); } // namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/EditorStyle.h b/Libs/Editor/Include/Utils/EditorStyle.h index e661cb2f..4c82d9b7 100644 --- a/Libs/Editor/Include/Utils/EditorStyle.h +++ b/Libs/Editor/Include/Utils/EditorStyle.h @@ -8,7 +8,6 @@ #include - namespace rift::Editor { using namespace p; @@ -57,7 +56,7 @@ namespace rift::Editor return Color::Gray(); }; - const Color GetTypeColor(const AST::Tree& ast, AST::Id id); + const Color GetTypeColor(const ast::Tree& ast, ast::Id id); void PushNodeTitleColor(Color color); diff --git a/Libs/Editor/Include/Utils/ElementsPanel.h b/Libs/Editor/Include/Utils/ElementsPanel.h index 143f8883..220fe315 100644 --- a/Libs/Editor/Include/Utils/ElementsPanel.h +++ b/Libs/Editor/Include/Utils/ElementsPanel.h @@ -23,14 +23,14 @@ namespace rift::Editor }; using TVariableAccessRef = - p::TAccessRef, p::TWrite, AST::CDeclType, - AST::CDeclNative, AST::CDeclStruct, AST::CDeclClass, AST::CParent>; + p::TAccessRef, p::TWrite, ast::CDeclType, + ast::CDeclNative, ast::CDeclStruct, ast::CDeclClass, ast::CParent>; - void DrawField(AST::Tree& ast, CTypeEditor& editor, AST::Id functionId, AST::Id fieldId, + void DrawField(ast::Tree& ast, CTypeEditor& editor, ast::Id functionId, ast::Id fieldId, DrawFieldFlags flags = DrawFieldFlags::None); - void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, AST::Id variableId); - void DrawFunction(AST::Tree& ast, CTypeEditor& editor, AST::Id functionId); + void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, ast::Id variableId); + void DrawFunction(ast::Tree& ast, CTypeEditor& editor, ast::Id functionId); - void DrawElementsPanel(AST::Tree& ast, AST::Id typeId); + void DrawElementsPanel(ast::Tree& ast, ast::Id typeId); } // namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/FunctionGraph.h b/Libs/Editor/Include/Utils/FunctionGraph.h index 32c812e7..6e74f6ce 100644 --- a/Libs/Editor/Include/Utils/FunctionGraph.h +++ b/Libs/Editor/Include/Utils/FunctionGraph.h @@ -37,12 +37,12 @@ namespace rift::Editor::Graph inline Settings settings{}; - void DrawLiteralBool(AST::Tree& ast, AST::Id id, bool& value); - void DrawLiteralInt(AST::Tree& ast, AST::Id id, String& value); - void DrawLiteralString(AST::Tree& ast, AST::Id id, String& value); + void DrawLiteralBool(ast::Tree& ast, ast::Id id, bool& value); + void DrawLiteralInt(ast::Tree& ast, ast::Id id, String& value); + void DrawLiteralString(ast::Tree& ast, ast::Id id, String& value); - void DrawFunctionDecl(AST::Tree& ast, AST::Id functionId); - void DrawCallNode(AST::Tree& ast, AST::Id id, StringView name, StringView ownerName); + void DrawFunctionDecl(ast::Tree& ast, ast::Id functionId); + void DrawCallNode(ast::Tree& ast, ast::Id id, StringView name, StringView ownerName); void Init(); void Shutdown(); @@ -52,10 +52,10 @@ namespace rift::Editor::Graph void PushInnerNodeStyle(); void PopInnerNodeStyle(); - void DrawTypeGraph(AST::Tree& ast, AST::Id typeId, CTypeEditor& typeEditor); + void DrawTypeGraph(ast::Tree& ast, ast::Id typeId, CTypeEditor& typeEditor); - void SetNodePosition(AST::Id id, v2 position); - v2 GetNodePosition(AST::Id id); + void SetNodePosition(ast::Id id, v2 position); + v2 GetNodePosition(ast::Id id); void SnapNodeDimensionsToGrid(); } // namespace rift::Editor::Graph diff --git a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h index d6737f86..3cb93e21 100644 --- a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h +++ b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h @@ -7,8 +7,8 @@ namespace rift::Editor::Graph { - void DrawNodesContextMenu(AST::Tree& ast, AST::Id typeId, p::TView nodeIds); - void DrawGraphContextMenu(AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId); + void DrawNodesContextMenu(ast::Tree& ast, ast::Id typeId, p::TView nodeIds); + void DrawGraphContextMenu(ast::Tree& ast, ast::Id typeId, ast::Id hoveredNodeId); void DrawContextMenu( - AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId, AST::Id hoveredLinkId); + ast::Tree& ast, ast::Id typeId, ast::Id hoveredNodeId, ast::Id hoveredLinkId); } // namespace rift::Editor::Graph diff --git a/Libs/Editor/Include/Utils/ModuleUtils.h b/Libs/Editor/Include/Utils/ModuleUtils.h index 1a828b1c..a7ccc0aa 100644 --- a/Libs/Editor/Include/Utils/ModuleUtils.h +++ b/Libs/Editor/Include/Utils/ModuleUtils.h @@ -11,7 +11,7 @@ namespace rift::Editor { - void OpenModuleEditor(TAccessRef, AST::CModule> access, AST::Id id); - void CloseModuleEditor(TAccessRef, AST::CModule> access, AST::Id id); - bool IsEditingModule(TAccessRef access, AST::Id id); + void OpenModuleEditor(TAccessRef, ast::CModule> access, ast::Id id); + void CloseModuleEditor(TAccessRef, ast::CModule> access, ast::Id id); + bool IsEditingModule(TAccessRef access, ast::Id id); } // namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/Nodes.h b/Libs/Editor/Include/Utils/Nodes.h index 24323a22..2eff88c6 100644 --- a/Libs/Editor/Include/Utils/Nodes.h +++ b/Libs/Editor/Include/Utils/Nodes.h @@ -298,7 +298,7 @@ namespace rift::Nodes void SetEditorContext(EditorContext*); v2 GetPanning(); void ResetPanning(const v2& pos); - void MoveToNode(AST::Id nodeId, v2 offset = v2::Zero()); + void MoveToNode(ast::Id nodeId, v2 offset = v2::Zero()); IO& GetIO(); @@ -339,10 +339,10 @@ namespace rift::Nodes // id can be any positive or negative integer, but INT_MIN is currently reserved for // internal use. - void BeginNode(AST::Id id); + void BeginNode(ast::Id id); void EndNode(); - v2 GetNodeDimensions(AST::Id id); + v2 GetNodeDimensions(ast::Id id); // Place your node title bar content (such as the node title, using ImGui::Text) between the // following function calls. These functions have to be called before adding any attributes, @@ -390,22 +390,22 @@ namespace rift::Nodes // Use the following functions to get and set the node's coordinates in these coordinate // systems. - void SetNodeScreenSpacePos(AST::Id nodeId, const v2& screen_space_pos); - void SetNodeEditorSpacePos(AST::Id nodeId, const v2& editor_space_pos); - void SetNodeGridSpacePos(AST::Id nodeId, const v2& grid_pos); + void SetNodeScreenSpacePos(ast::Id nodeId, const v2& screen_space_pos); + void SetNodeEditorSpacePos(ast::Id nodeId, const v2& editor_space_pos); + void SetNodeGridSpacePos(ast::Id nodeId, const v2& grid_pos); - v2 GetNodeScreenSpacePos(AST::Id nodeId); - v2 GetNodeEditorSpacePos(AST::Id nodeId); - v2 GetNodeGridSpacePos(AST::Id nodeId); + v2 GetNodeScreenSpacePos(ast::Id nodeId); + v2 GetNodeEditorSpacePos(ast::Id nodeId); + v2 GetNodeGridSpacePos(ast::Id nodeId); // Returns true if the current node editor canvas is being hovered over by the mouse, and is // not blocked by any other windows. bool IsEditorHovered(); - AST::Id GetHoveredNode(); - AST::Id GetHoveredLink(); + ast::Id GetHoveredNode(); + ast::Id GetHoveredLink(); - bool IsNodeHovered(AST::Id nodeId); - bool IsLinkHovered(AST::Id linkId); + bool IsNodeHovered(ast::Id nodeId); + bool IsLinkHovered(ast::Id linkId); bool IsPinHovered(Id* attributeId); // Use The following two functions to query the number of selected nodes or links in the @@ -414,8 +414,8 @@ namespace rift::Nodes // Get the selected node/link ids. The pointer argument should point to an integer array // with at least as many elements as the respective NumSelectedNodes/NumSelectedLinks // function call returned. - const TArray& GetSelectedNodes(); - bool GetSelectedLinks(TArray& linkIds); + const TArray& GetSelectedNodes(); + bool GetSelectedLinks(TArray& linkIds); // Clears the list of selected nodes/links. Useful if you want to delete a selected node or // link. void ClearNodeSelection(); @@ -426,11 +426,11 @@ namespace rift::Nodes // considered unselected. Clear-functions has the precondition that the object is currently // considered selected. Preconditions listed above can be checked via // IsNodeSelected/IsLinkSelected if not already known. - void ClearNodeSelection(AST::Id nodeId); + void ClearNodeSelection(ast::Id nodeId); void ClearLinkSelection(Id linkId); - void SelectNode(AST::Id nodeId); + void SelectNode(ast::Id nodeId); void SelectLink(Id linkId); - bool IsNodeSelected(AST::Id nodeId); + bool IsNodeSelected(ast::Id nodeId); bool IsLinkSelected(Id linkId); bool IsLinkSelectedByIdx(i32 linkIdx); @@ -456,7 +456,7 @@ namespace rift::Nodes Id* outputId = nullptr, Id* inputId = nullptr, bool includingDetachedLinks = true); // Did the user finish creating a new link? bool IsLinkCreated(Id& outputPinId, Id& inputPinId, bool* createdFromSnap = nullptr); - bool IsLinkCreated(AST::Id& outputNodeId, Id& outputPinId, AST::Id& inputNodeId, Id& inputPinId, + bool IsLinkCreated(ast::Id& outputNodeId, Id& outputPinId, ast::Id& inputNodeId, Id& inputPinId, bool* createdFromSnap = nullptr); // Was an existing link detached from a pin by the user? The detached link's id is assigned diff --git a/Libs/Editor/Include/Utils/NodesInternal.h b/Libs/Editor/Include/Utils/NodesInternal.h index d5c3ef7a..deaf3adf 100644 --- a/Libs/Editor/Include/Utils/NodesInternal.h +++ b/Libs/Editor/Include/Utils/NodesInternal.h @@ -91,18 +91,18 @@ namespace rift::Nodes template struct TIndexedArray { - using Iterator = TArray::Iterator; - using ConstIterator = TArray::ConstIterator; + using Iterator = TArray::Iterator; + using ConstIterator = TArray::ConstIterator; - TArray frameIds; + TArray frameIds; TArray data; - TArray lastFrameIds; - TArray invalidIds; + TArray lastFrameIds; + TArray invalidIds; public: - T& GetOrAdd(AST::Id id, bool* outAdded = nullptr) + T& GetOrAdd(ast::Id id, bool* outAdded = nullptr) { const u32 index = GetIdIndex(id); bool added; @@ -125,17 +125,17 @@ namespace rift::Nodes return *GetByIndex(index); } - T& Get(AST::Id id) + T& Get(ast::Id id) { return *GetByIndex(GetIdIndex(id)); } - const T& Get(AST::Id id) const + const T& Get(ast::Id id) const { return const_cast*>(this)->Get(id); } - T* TryGet(AST::Id id) + T* TryGet(ast::Id id) { if (Contains(id)) { @@ -144,16 +144,16 @@ namespace rift::Nodes return nullptr; } - bool Contains(AST::Id id) const + bool Contains(ast::Id id) const { return frameIds.ContainsSorted(id); } - T& operator[](AST::Id id) + T& operator[](ast::Id id) { return Get(id); } - const T& operator[](AST::Id id) const + const T& operator[](ast::Id id) const { return Get(id); } @@ -161,7 +161,7 @@ namespace rift::Nodes void CacheInvalidIds() { invalidIds.Clear(false); - for (AST::Id id : lastFrameIds) + for (ast::Id id : lastFrameIds) { if (!frameIds.ContainsSorted(id)) { @@ -198,10 +198,10 @@ namespace rift::Nodes template struct NodeArray : public TIndexedArray { - TArray depthOrder; + TArray depthOrder; - T& GetOrAdd(AST::Id id, bool* outAdded = nullptr) + T& GetOrAdd(ast::Id id, bool* outAdded = nullptr) { bool added = false; T& node = TIndexedArray::GetOrAdd(id, &added); @@ -217,7 +217,7 @@ namespace rift::Nodes return node; } - void PushToTheFront(AST::Id id) + void PushToTheFront(ast::Id id) { depthOrder.Remove(id, false); depthOrder.Add(id); @@ -225,7 +225,7 @@ namespace rift::Nodes void ClearDepthOrder() { - depthOrder.RemoveIf([this](AST::Id id) { + depthOrder.RemoveIf([this](ast::Id id) { return TIndexedArray::invalidIds.ContainsSorted(id); }); } @@ -316,7 +316,7 @@ namespace rift::Nodes struct PinData { Id id; - AST::Id parentNodeId = AST::NoId; + ast::Id parentNodeId = ast::NoId; Rect rect; PinShape Shape = PinShape_CircleFilled; v2 position; // screen-space coordinates @@ -405,7 +405,7 @@ namespace rift::Nodes // Nodes::EndNode() call. Rect gridContentBounds; - TArray selectedNodeIds; + TArray selectedNodeIds; ImVector selectedLinkIndices; // Relative origins of selected nodes for snapping of dragged nodes @@ -458,8 +458,8 @@ namespace rift::Nodes // Canvas draw list and helper state ImDrawList* CanvasDrawList; ImGuiStorage NodeIdxToSubmissionIdx; - ImVector nodeSubmissionOrder; - ImVector nodeIdsOverlappingWithMouse; + ImVector nodeSubmissionOrder; + ImVector nodeIdsOverlappingWithMouse; ImVector occludedPinIndices; // Canvas extents @@ -480,11 +480,11 @@ namespace rift::Nodes ImVector pinFlagStack; // UI element state - AST::Id currentNodeId; + ast::Id currentNodeId; PinIdx CurrentPinIdx; i32 CurrentPinId; - AST::Id hoveredNodeId; + ast::Id hoveredNodeId; OptionalIndex HoveredLinkIdx; PinIdx HoveredPinIdx; diff --git a/Libs/Editor/Include/Utils/NodesMiniMap.h b/Libs/Editor/Include/Utils/NodesMiniMap.h index 28c0026e..fb91903c 100644 --- a/Libs/Editor/Include/Utils/NodesMiniMap.h +++ b/Libs/Editor/Include/Utils/NodesMiniMap.h @@ -24,7 +24,7 @@ namespace rift::Nodes struct MiniMap { - using NodeHoveringCallback = void (*)(AST::Id, void*); + using NodeHoveringCallback = void (*)(ast::Id, void*); using NodeHoveringCallbackUserData = void*; @@ -44,7 +44,7 @@ namespace rift::Nodes bool IsHovered() const; void CalculateLayout(); - void DrawNode(EditorContext& editor, const AST::Id nodeId); + void DrawNode(EditorContext& editor, const ast::Id nodeId); void DrawLink(EditorContext& editor, const i32 linkIdx); void Update(); }; diff --git a/Libs/Editor/Include/Utils/ProjectManager.h b/Libs/Editor/Include/Utils/ProjectManager.h index e3834b2c..74ec6dc7 100644 --- a/Libs/Editor/Include/Utils/ProjectManager.h +++ b/Libs/Editor/Include/Utils/ProjectManager.h @@ -7,6 +7,6 @@ namespace rift::Editor { - void DrawProjectManager(AST::Tree& ast); + void DrawProjectManager(ast::Tree& ast); void OpenProjectManager(); } // namespace rift::Editor diff --git a/Libs/Editor/Include/Utils/TypeUtils.h b/Libs/Editor/Include/Utils/TypeUtils.h index cc852c20..7b0bce03 100644 --- a/Libs/Editor/Include/Utils/TypeUtils.h +++ b/Libs/Editor/Include/Utils/TypeUtils.h @@ -12,84 +12,84 @@ namespace rift::Editor { - void OpenType(TAccessRef, AST::CDeclType> access, AST::Id id); - void CloseType(TAccessRef, AST::CDeclType> access, AST::Id id); - bool IsTypeOpen(TAccessRef access, AST::Id id); + void OpenType(TAccessRef, ast::CDeclType> access, ast::Id id); + void CloseType(TAccessRef, ast::CDeclType> access, ast::Id id); + bool IsTypeOpen(TAccessRef access, ast::Id id); - constexpr StringView GetUnaryOperatorName(AST::UnaryOperatorType type) + constexpr StringView GetUnaryOperatorName(ast::UnaryOperatorType type) { switch (type) { - case AST::UnaryOperatorType::Not: return "!"; - case AST::UnaryOperatorType::Negation: return "-"; - case AST::UnaryOperatorType::Increment: return "++"; - case AST::UnaryOperatorType::Decrement: return "--"; - case AST::UnaryOperatorType::BitNot: return "~"; + case ast::UnaryOperatorType::Not: return "!"; + case ast::UnaryOperatorType::Negation: return "-"; + case ast::UnaryOperatorType::Increment: return "++"; + case ast::UnaryOperatorType::Decrement: return "--"; + case ast::UnaryOperatorType::BitNot: return "~"; } return ""; } - constexpr StringView GetUnaryOperatorLongName(AST::UnaryOperatorType type) + constexpr StringView GetUnaryOperatorLongName(ast::UnaryOperatorType type) { switch (type) { - case AST::UnaryOperatorType::Not: return "not"; - case AST::UnaryOperatorType::Negation: return "negation"; - case AST::UnaryOperatorType::Increment: return "increment"; - case AST::UnaryOperatorType::Decrement: return "decrement"; - case AST::UnaryOperatorType::BitNot: return "bitwise not / one's complement"; + case ast::UnaryOperatorType::Not: return "not"; + case ast::UnaryOperatorType::Negation: return "negation"; + case ast::UnaryOperatorType::Increment: return "increment"; + case ast::UnaryOperatorType::Decrement: return "decrement"; + case ast::UnaryOperatorType::BitNot: return "bitwise not / one's complement"; } return ""; } - constexpr StringView GetBinaryOperatorName(AST::BinaryOperatorType type) + constexpr StringView GetBinaryOperatorName(ast::BinaryOperatorType type) { switch (type) { - case AST::BinaryOperatorType::Add: return "+"; - case AST::BinaryOperatorType::Sub: return "-"; - case AST::BinaryOperatorType::Mul: return "*"; - case AST::BinaryOperatorType::Div: return "/"; - case AST::BinaryOperatorType::Mod: return "%"; + case ast::BinaryOperatorType::Add: return "+"; + case ast::BinaryOperatorType::Sub: return "-"; + case ast::BinaryOperatorType::Mul: return "*"; + case ast::BinaryOperatorType::Div: return "/"; + case ast::BinaryOperatorType::Mod: return "%"; - case AST::BinaryOperatorType::Equal: return "=="; - case AST::BinaryOperatorType::NotEqual: return "!="; - case AST::BinaryOperatorType::Greater: return ">"; - case AST::BinaryOperatorType::Less: return "<"; - case AST::BinaryOperatorType::GreaterOrEqual: return ">="; - case AST::BinaryOperatorType::LessOrEqual: return "<="; + case ast::BinaryOperatorType::Equal: return "=="; + case ast::BinaryOperatorType::NotEqual: return "!="; + case ast::BinaryOperatorType::Greater: return ">"; + case ast::BinaryOperatorType::Less: return "<"; + case ast::BinaryOperatorType::GreaterOrEqual: return ">="; + case ast::BinaryOperatorType::LessOrEqual: return "<="; - case AST::BinaryOperatorType::And: return "&&"; - case AST::BinaryOperatorType::Or: return "||"; - case AST::BinaryOperatorType::BitAnd: return "&"; - case AST::BinaryOperatorType::BitOr: return "|"; - case AST::BinaryOperatorType::Xor: return "^"; + case ast::BinaryOperatorType::And: return "&&"; + case ast::BinaryOperatorType::Or: return "||"; + case ast::BinaryOperatorType::BitAnd: return "&"; + case ast::BinaryOperatorType::BitOr: return "|"; + case ast::BinaryOperatorType::Xor: return "^"; } return ""; } - constexpr StringView GetBinaryOperatorLongName(AST::BinaryOperatorType type) + constexpr StringView GetBinaryOperatorLongName(ast::BinaryOperatorType type) { switch (type) { - case AST::BinaryOperatorType::Add: return "add"; - case AST::BinaryOperatorType::Sub: return "subtract"; - case AST::BinaryOperatorType::Mul: return "multiply"; - case AST::BinaryOperatorType::Div: return "divide"; - case AST::BinaryOperatorType::Mod: return "module"; + case ast::BinaryOperatorType::Add: return "add"; + case ast::BinaryOperatorType::Sub: return "subtract"; + case ast::BinaryOperatorType::Mul: return "multiply"; + case ast::BinaryOperatorType::Div: return "divide"; + case ast::BinaryOperatorType::Mod: return "module"; - case AST::BinaryOperatorType::Equal: return "equal"; - case AST::BinaryOperatorType::NotEqual: return "not equal"; - case AST::BinaryOperatorType::Greater: return "greater"; - case AST::BinaryOperatorType::Less: return "less"; - case AST::BinaryOperatorType::GreaterOrEqual: return "greater or equal"; - case AST::BinaryOperatorType::LessOrEqual: return "less or equal"; + case ast::BinaryOperatorType::Equal: return "equal"; + case ast::BinaryOperatorType::NotEqual: return "not equal"; + case ast::BinaryOperatorType::Greater: return "greater"; + case ast::BinaryOperatorType::Less: return "less"; + case ast::BinaryOperatorType::GreaterOrEqual: return "greater or equal"; + case ast::BinaryOperatorType::LessOrEqual: return "less or equal"; - case AST::BinaryOperatorType::And: return "and"; - case AST::BinaryOperatorType::Or: return "or"; - case AST::BinaryOperatorType::BitAnd: return "bitwise and"; - case AST::BinaryOperatorType::BitOr: return "bitwise or"; - case AST::BinaryOperatorType::Xor: return "exclusive or"; + case ast::BinaryOperatorType::And: return "and"; + case ast::BinaryOperatorType::Or: return "or"; + case ast::BinaryOperatorType::BitAnd: return "bitwise and"; + case ast::BinaryOperatorType::BitOr: return "bitwise or"; + case ast::BinaryOperatorType::Xor: return "exclusive or"; } return ""; } diff --git a/Libs/Editor/Include/Utils/Widgets.h b/Libs/Editor/Include/Utils/Widgets.h index d52e0347..cec02a88 100644 --- a/Libs/Editor/Include/Utils/Widgets.h +++ b/Libs/Editor/Include/Utils/Widgets.h @@ -9,13 +9,12 @@ #include - namespace rift::Editor { - bool TypeCombo(AST::TAccessRef + bool TypeCombo(ast::TAccessRef access, - p::StringView label, AST::Id& selectedTypeId); + p::StringView label, ast::Id& selectedTypeId); - bool InputLiteralValue(AST::Tree& ast, p::StringView label, AST::Id literalId); + bool InputLiteralValue(ast::Tree& ast, p::StringView label, ast::Id literalId); } // namespace rift::Editor diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index b0e4eab0..3c899a34 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -24,9 +24,9 @@ namespace rift::Editor { void RegisterKeyValueInspections() { - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { - auto* id = static_cast(data); - // UI::DrawKeyValue(label, data, GetType::Entity>()); + UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + auto* id = static_cast(data); + // UI::DrawKeyValue(label, data, GetType::Entity>()); UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); @@ -39,17 +39,17 @@ namespace rift::Editor } }); - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); UI::Text(label); UI::TableSetColumnIndex(1); - auto* ns = static_cast(data); + auto* ns = static_cast(data); String asString = ns->ToString(); if (UI::InputText("##value", asString)) { - *ns = AST::Namespace{asString}; + *ns = ast::Namespace{asString}; } }); } @@ -97,21 +97,21 @@ namespace rift::Editor void Editor::Tick() { - if (AST::HasProject(ast)) + if (ast::HasProject(ast)) { - AST::FunctionsSystem::ClearAddedTags(ast); - AST::TransactionSystem::ClearTags(ast); + ast::FunctionsSystem::ClearAddedTags(ast); + ast::TransactionSystem::ClearTags(ast); - AST::LoadSystem::Run(ast); - AST::FunctionsSystem::ResolveCallFunctionIds(ast); - AST::TypeSystem::ResolveExprTypeIds(ast); + ast::LoadSystem::Run(ast); + ast::FunctionsSystem::ResolveCallFunctionIds(ast); + ast::TypeSystem::ResolveExprTypeIds(ast); EditorSystem::Draw(ast); - AST::TypeSystem::PropagateVariableTypes(ast); - AST::FunctionsSystem::PropagateDirtyIntoCalls(ast); - AST::FunctionsSystem::PushInvalidPinsBack(ast); - AST::FunctionsSystem::SyncCallPinsFromFunction(ast); - AST::TypeSystem::PropagateExpressionTypes(ast); + ast::TypeSystem::PropagateVariableTypes(ast); + ast::FunctionsSystem::PropagateDirtyIntoCalls(ast); + ast::FunctionsSystem::PushInvalidPinsBack(ast); + ast::FunctionsSystem::SyncCallPinsFromFunction(ast); + ast::TypeSystem::PropagateExpressionTypes(ast); } else { @@ -131,16 +131,16 @@ namespace rift::Editor bool Editor::CreateProject(p::StringView path, bool closeFirst) { - if (!closeFirst && AST::HasProject(ast)) + if (!closeFirst && ast::HasProject(ast)) { return false; } - if (AST::CreateProject(ast, path) && AST::OpenProject(ast, path)) + if (ast::CreateProject(ast, path) && ast::OpenProject(ast, path)) { ast.SetStatic(); EditorSystem::Init(ast); - SetUIConfigFile(p::JoinPaths(AST::GetProjectPath(ast), "Saved/UI.ini")); + SetUIConfigFile(p::JoinPaths(ast::GetProjectPath(ast), "Saved/UI.ini")); return true; } return false; @@ -148,16 +148,16 @@ namespace rift::Editor bool Editor::OpenProject(p::StringView path, bool closeFirst) { - if (!closeFirst && AST::HasProject(ast)) + if (!closeFirst && ast::HasProject(ast)) { return false; } - if (AST::OpenProject(ast, path)) + if (ast::OpenProject(ast, path)) { ast.SetStatic(); EditorSystem::Init(ast); - SetUIConfigFile(p::JoinPaths(AST::GetProjectPath(ast), "Saved/UI.ini")); + SetUIConfigFile(p::JoinPaths(ast::GetProjectPath(ast), "Saved/UI.ini")); return true; } return false; diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index 33654423..f1b4aee1 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -31,12 +31,12 @@ namespace rift::Editor { - void FileExplorerPanel::Draw(AST::Tree& ast) + void FileExplorerPanel::Draw(ast::Tree& ast) { // Open recently created types if (!pendingOpenCreatedPath.empty()) { - AST::Id typeId = AST::FindTypeByPath(ast, pendingOpenCreatedPath); + ast::Id typeId = ast::FindTypeByPath(ast, pendingOpenCreatedPath); if (!IsNone(typeId)) { OpenType(ast, typeId); @@ -67,7 +67,7 @@ namespace rift::Editor UI::End(); } - void FileExplorerPanel::DrawList(AST::Tree& ast) + void FileExplorerPanel::DrawList(ast::Tree& ast) { // if (dirty) { @@ -77,8 +77,8 @@ namespace rift::Editor UI::BeginChild("Files"); if (UI::BeginPopupContextWindow()) { - String projectPath{AST::GetProjectPath(ast)}; - DrawContextMenu(ast, projectPath, AST::NoId); + String projectPath{ast::GetProjectPath(ast)}; + DrawContextMenu(ast, projectPath, ast::NoId); UI::EndPopup(); } @@ -91,11 +91,11 @@ namespace rift::Editor UI::EndChild(); } - void FileExplorerPanel::DrawContextMenu(AST::Tree& ast, StringView path, AST::Id itemId) + void FileExplorerPanel::DrawContextMenu(ast::Tree& ast, StringView path, ast::Id itemId) { const bool hasId = ast.IsValid(itemId); - const bool isType = hasId && ast.Has(itemId); - const bool isModule = hasId && ast.Has(itemId); + const bool isType = hasId && ast.Has(itemId); + const bool isModule = hasId && ast.Has(itemId); if (hasId) { @@ -122,7 +122,7 @@ namespace rift::Editor if (isType && UI::MenuItem("Delete")) { - AST::RemoveTypes(ast, itemId, true); + ast::RemoveTypes(ast, itemId, true); } UI::Separator(); @@ -132,9 +132,9 @@ namespace rift::Editor { if (UI::BeginMenu("Create type")) { - TArray types; - types.Reserve(AST::GetFileTypes().Size()); - for (const auto& type : AST::GetFileTypes()) + TArray types; + types.Reserve(ast::GetFileTypes().Size()); + for (const auto& type : ast::GetFileTypes()) { types.Add(&type); } @@ -198,7 +198,7 @@ namespace rift::Editor parentPath = p::GetParentPath(parentPath); parentName = p::Tag{parentPath}; - const Item newItem{.id = AST::NoId, .path = p::String{lastPath}, .isFolder = true}; + const Item newItem{.id = ast::NoId, .path = p::String{lastPath}, .isFolder = true}; if (Folder* parent = folders.Find(parentName)) { parent->items.Add(newItem); @@ -210,7 +210,7 @@ namespace rift::Editor } void FileExplorerPanel::CacheProjectFiles( - TAccessRef access) + TAccessRef access) { dirty = false; @@ -219,27 +219,27 @@ namespace rift::Editor // Set root folder (not displayed) folders.InsertDefaulted({}); - projectModuleId = AST::GetProjectId(access); + projectModuleId = ast::GetProjectId(access); // Create module folders - TArray modules = FindAllIdsWith(access); - TMap moduleFolders; + TArray modules = FindAllIdsWith(access); + TMap moduleFolders; moduleFolders.Reserve(modules.Size()); - for (AST::Id moduleId : modules) + for (ast::Id moduleId : modules) { - auto& file = access.Get(moduleId); + auto& file = access.Get(moduleId); p::StringView folderPath = p::GetParentPath(file.path); folders.InsertDefaulted(p::Tag{folderPath}); moduleFolders.Insert(moduleId, folderPath); } // Create folders between modules - for (AST::Id oneId : modules) + for (ast::Id oneId : modules) { bool insideOther = false; const p::StringView path = moduleFolders[oneId]; - for (AST::Id otherId : modules) + for (ast::Id otherId : modules) { if (oneId != otherId && Strings::StartsWith(path, moduleFolders[otherId])) // Is relative @@ -262,9 +262,9 @@ namespace rift::Editor } // Create items - for (AST::Id typeId : FindAllIdsWith(access)) + for (ast::Id typeId : FindAllIdsWith(access)) { - auto& file = access.Get(typeId); + auto& file = access.Get(typeId); if (!file.path.empty()) { InsertItem(Item{typeId, file.path}); @@ -284,7 +284,7 @@ namespace rift::Editor }); } - void FileExplorerPanel::DrawItem(AST::Tree& ast, const Item& item) + void FileExplorerPanel::DrawItem(ast::Tree& ast, const Item& item) { const String path = p::ToString(item.path); const StringView fileName = p::GetFilename(path); @@ -297,7 +297,7 @@ namespace rift::Editor flags |= ImGuiTreeNodeFlags_Bullet; } - auto* module = item.id != AST::NoId ? ast.TryGet(item.id) : nullptr; + auto* module = item.id != ast::NoId ? ast.TryGet(item.id) : nullptr; if (module) { // TODO: Display module name @@ -361,7 +361,7 @@ namespace rift::Editor else { String text; - if (fileName == AST::moduleFilename) + if (fileName == ast::moduleFilename) { text = Strings::Format(ICON_FA_FILE_ALT " {}", fileName); } @@ -397,7 +397,7 @@ namespace rift::Editor const StringView parsedNewName = Strings::RemoveFromEnd(renameBuffer, ".rf"); const bool nameIsEmpty = parsedNewName.empty(); const Id sameNameFuncId = - AST::FindChildByName(ast, p::GetIdParent(ast, item.id), Tag{parsedNewName}); + ast::FindChildByName(ast, p::GetIdParent(ast, item.id), Tag{parsedNewName}); if (nameIsEmpty || (!IsNone(sameNameFuncId) && item.id != sameNameFuncId)) { UI::PushTextColor(LinearColor::Red()); @@ -416,25 +416,25 @@ namespace rift::Editor // manual steps if (files::Rename(p::ToPath(path), destination)) { - if (auto* file = ast.TryGet(item.id)) + if (auto* file = ast.TryGet(item.id)) { file->path = destination; } - auto& types = ast.GetOrSetStatic(); + auto& types = ast.GetOrSetStatic(); types.typesByPath.Remove(p::Tag{item.path}); types.typesByPath.Insert(p::Tag{destination}, item.id); - ast.Add(item.id, Tag{parsedNewName}); + ast.Add(item.id, Tag{parsedNewName}); } - renameId = AST::NoId; + renameId = ast::NoId; renameBuffer = ""; renameHasFocused = false; } else if (UI::IsItemDeactivated()) { - renameId = AST::NoId; + renameId = ast::NoId; renameBuffer = ""; renameHasFocused = false; } @@ -465,11 +465,11 @@ namespace rift::Editor } } - void FileExplorerPanel::DrawModuleActions(AST::Id id, AST::CModule& module) {} - void FileExplorerPanel::DrawTypeActions(AST::Id id, AST::CDeclType& type) {} + void FileExplorerPanel::DrawModuleActions(ast::Id id, ast::CModule& module) {} + void FileExplorerPanel::DrawTypeActions(ast::Id id, ast::CDeclType& type) {} void FileExplorerPanel::CreateType( - AST::Tree& ast, StringView title, p::Tag typeId, p::StringView folderPath) + ast::Tree& ast, StringView title, p::Tag typeId, p::StringView folderPath) { const p::String path = files::SaveFileDialog(title, folderPath, { @@ -477,10 +477,10 @@ namespace rift::Editor }, true); - AST::Id id = AST::CreateType(ast, typeId, Tag::None(), path); + ast::Id id = ast::CreateType(ast, typeId, Tag::None(), path); String data; - AST::SerializeType(ast, id, data); + ast::SerializeType(ast, id, data); files::SaveStringFile(path, data); // Destroy the temporal type after saving it diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index e6f93a0e..cc4761db 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -36,10 +36,9 @@ #include - namespace rift::Editor::EditorSystem { - void OnProjectEditorOpen(AST::Tree& ast) + void OnProjectEditorOpen(ast::Tree& ast) { auto& editor = ast.GetStatic(); editor.layout.OnBuild([](auto& builder) { @@ -62,7 +61,7 @@ namespace rift::Editor::EditorSystem editor.layout.Reset(); } - void OnTypeEditorOpen(AST::Tree& ast, AST::Id typeId) + void OnTypeEditorOpen(ast::Tree& ast, ast::Id typeId) { auto& typeEditor = ast.Get(typeId); typeEditor.layout.OnBuild([](auto& builder) { @@ -90,13 +89,13 @@ namespace rift::Editor::EditorSystem typeEditor.layout.Reset(); } - void Init(AST::Tree& ast) + void Init(ast::Tree& ast) { OnProjectEditorOpen(ast); ast.OnAdd().Bind([](auto& ast, auto ids) { - for (AST::Id id : ids) + for (ast::Id id : ids) { - OnTypeEditorOpen(static_cast(ast), id); + OnTypeEditorOpen(static_cast(ast), id); } }); } @@ -105,23 +104,23 @@ namespace rift::Editor::EditorSystem void CreateRootDockspace(SEditor& editor); void CreateTypeDockspace(CTypeEditor& editor, const char* id); void CreateModuleDockspace(CModuleEditor& editor, const char* id); - void DrawMenuBar(AST::Tree& ast); + void DrawMenuBar(ast::Tree& ast); // Project Editor - void DrawProject(AST::Tree& ast); - void DrawProjectMenuBar(AST::Tree& ast, SEditor& editorData); + void DrawProject(ast::Tree& ast); + void DrawProjectMenuBar(ast::Tree& ast, SEditor& editorData); // Module Editors - void DrawModuleEditors(AST::Tree& ast, SEditor& editor); + void DrawModuleEditors(ast::Tree& ast, SEditor& editor); // Type Editors - void DrawTypeMenuBar(AST::Tree& ast, AST::Id typeId); - void DrawTypes(AST::Tree& ast, SEditor& editor); + void DrawTypeMenuBar(ast::Tree& ast, ast::Id typeId); + void DrawTypes(ast::Tree& ast, SEditor& editor); - void Draw(AST::Tree& ast) + void Draw(ast::Tree& ast) { - if (AST::HasProject(ast)) + if (ast::HasProject(ast)) { DrawProject(ast); } @@ -198,7 +197,7 @@ namespace rift::Editor::EditorSystem UI::DockSpace(editor.dockspaceID, ImVec2(0.0f, 0.0f), dockingFlags, nullptr); } - void DrawMenuBar(AST::Tree& ast) + void DrawMenuBar(ast::Tree& ast) { if (UI::BeginMainMenuBar()) { @@ -216,7 +215,7 @@ namespace rift::Editor::EditorSystem } } - void DrawProject(AST::Tree& ast) + void DrawProject(ast::Tree& ast) { if (!Ensure(ast.HasStatic())) { @@ -224,7 +223,7 @@ namespace rift::Editor::EditorSystem } auto& editor = ast.GetStatic(); - const auto& path = AST::GetProjectPath(ast); + const auto& path = ast::GetProjectPath(ast); UI::PushID(p::GetHash(path)); DrawProjectMenuBar(ast, editor); @@ -242,7 +241,7 @@ namespace rift::Editor::EditorSystem DrawTypes(ast, editor); editor.reflectionDebugger.Draw(); - editor.astDebugger.Draw(ast); + editor.ASTDebugger.Draw(ast); editor.memoryDebugger.Draw(); editor.fileExplorer.Draw(ast); editor.graphPlayground.Draw(ast, editor.layout); @@ -250,7 +249,7 @@ namespace rift::Editor::EditorSystem UI::PopID(); } - void DrawProjectMenuBar(AST::Tree& ast, SEditor& editorData) + void DrawProjectMenuBar(ast::Tree& ast, SEditor& editorData) { if (UI::BeginMainMenuBar()) { @@ -267,7 +266,7 @@ namespace rift::Editor::EditorSystem } if (UI::MenuItem("Close current")) { - AST::CloseProject(ast); + ast::CloseProject(ast); editorData.skipFrameAfterMenu = true; } UI::Separator(); @@ -277,23 +276,23 @@ namespace rift::Editor::EditorSystem TArray> fileDatas; auto dirtyTypeIds = - FindAllIdsWith( + FindAllIdsWith( ast); - for (AST::Id typeId : dirtyTypeIds) + for (ast::Id typeId : dirtyTypeIds) { - auto& file = ast.Get(typeId); + auto& file = ast.Get(typeId); auto& fileData = fileDatas.AddRef({file.path, ""}); - AST::SerializeType(ast, typeId, fileData.second); + ast::SerializeType(ast, typeId, fileData.second); } auto dirtyModuleIds = - FindAllIdsWith( + FindAllIdsWith( ast); - for (AST::Id moduleId : dirtyModuleIds) + for (ast::Id moduleId : dirtyModuleIds) { - auto& file = ast.Get(moduleId); + auto& file = ast.Get(moduleId); auto& fileData = fileDatas.AddRef({file.path, ""}); - AST::SerializeModule(ast, moduleId, fileData.second); + ast::SerializeModule(ast, moduleId, fileData.second); } for (auto& fileData : fileDatas) @@ -301,8 +300,8 @@ namespace rift::Editor::EditorSystem files::SaveStringFile(fileData.first, fileData.second); } - ast.Remove(dirtyTypeIds); - ast.Remove(dirtyModuleIds); + ast.Remove(dirtyTypeIds); + ast.Remove(dirtyModuleIds); UI::AddNotification({UI::ToastType::Success, 1.f, !fileDatas.IsEmpty() ? Strings::Format("Saved {} files", fileDatas.Size()) @@ -315,13 +314,13 @@ namespace rift::Editor::EditorSystem { if (UI::MenuItem("Build current")) { - AST::Tree compileAST{ast}; // Intentional copy + ast::Tree compileAST{ast}; // Intentional copy CompilerConfig config; Build(compileAST, config); } if (UI::MenuItem("Build all")) { - AST::Tree compileAST{ast}; // Intentional copy + ast::Tree compileAST{ast}; // Intentional copy CompilerConfig config; Build(compileAST, config); } @@ -356,7 +355,7 @@ namespace rift::Editor::EditorSystem if (UI::BeginMenu("Debug")) { UI::MenuItem("Reflection", nullptr, &editorData.reflectionDebugger.open); - UI::MenuItem("Abstract Syntax Tree", nullptr, &editorData.astDebugger.open); + UI::MenuItem("Abstract Syntax Tree", nullptr, &editorData.ASTDebugger.open); UI::MenuItem("Memory", nullptr, &editorData.memoryDebugger.open); UI::MenuItem("Graph Playground", nullptr, &editorData.graphPlayground.open); UI::EndMenu(); @@ -370,7 +369,7 @@ namespace rift::Editor::EditorSystem { editorData.layout.Reset(); - for (AST::Id typeId : FindAllIdsWith(ast)) + for (ast::Id typeId : FindAllIdsWith(ast)) { auto& editor = ast.Get(typeId); editor.layout.Reset(); @@ -382,18 +381,18 @@ namespace rift::Editor::EditorSystem } } - void DrawModuleMenuBar(AST::Tree& ast, AST::Id moduleId) + void DrawModuleMenuBar(ast::Tree& ast, ast::Id moduleId) { if (UI::BeginMenuBar()) { if (UI::MenuItem(ICON_FA_SAVE, "CTRL+S")) { - auto& file = ast.Get(moduleId); + auto& file = ast.Get(moduleId); String data; - AST::SerializeModule(ast, moduleId, data); + ast::SerializeModule(ast, moduleId, data); files::SaveStringFile(file.path, data); - ast.Remove(moduleId); + ast.Remove(moduleId); UI::AddNotification({UI::ToastType::Success, 1.f, Strings::Format("Saved file {}", p::GetFilename(file.path))}); @@ -402,20 +401,20 @@ namespace rift::Editor::EditorSystem } } - void DrawModuleEditors(AST::Tree& ast, SEditor& editor) + void DrawModuleEditors(ast::Tree& ast, SEditor& editor) { - TAccess, TWrite, TWrite, AST::CFileRef> + TAccess, TWrite, TWrite, ast::CFileRef> moduleEditors{ast}; - for (AST::Id moduleId : - FindAllIdsWith(moduleEditors)) + for (ast::Id moduleId : + FindAllIdsWith(moduleEditors)) { auto& moduleEditor = moduleEditors.Get(moduleId); - const auto& file = moduleEditors.Get(moduleId); + const auto& file = moduleEditors.Get(moduleId); bool isOpen = true; const String path = p::ToString(file.path); const StringView filename = p::GetFilename(path); - const StringView dirty = ast.Has(moduleId) ? "*" : ""; + const StringView dirty = ast.Has(moduleId) ? "*" : ""; const String windowName = Strings::Format("{}{}###{}", filename, dirty, moduleId); if (moduleEditor.pendingFocus) @@ -437,12 +436,12 @@ namespace rift::Editor::EditorSystem if (UI::BeginInspector("ModuleInspector")) { - auto& module = moduleEditors.Get(moduleId); + auto& module = moduleEditors.Get(moduleId); UI::InspectStruct(&module); if (UI::BeginCategory("Bindings", true)) { - for (const auto& binding : AST::GetModuleBindings()) + for (const auto& binding : ast::GetModuleBindings()) { auto* pool = ast.GetPool(binding.tagType->GetId()); if (void* data = pool ? pool->TryGetVoid(moduleId) : nullptr) @@ -463,7 +462,7 @@ namespace rift::Editor::EditorSystem if (UI::Button(addText.c_str(), ImVec2(-FLT_MIN, 0.0f))) { ScopedChange(ast, moduleId); - AST::AddBindingToModule(ast, moduleId, binding.id); + ast::AddBindingToModule(ast, moduleId, binding.id); } UI::PopStyleCompact(); } @@ -486,19 +485,19 @@ namespace rift::Editor::EditorSystem } } - void DrawTypeMenuBar(AST::Tree& ast, AST::Id typeId) + void DrawTypeMenuBar(ast::Tree& ast, ast::Id typeId) { auto& typeEditor = ast.Get(typeId); if (UI::BeginMenuBar()) { if (UI::MenuItem(ICON_FA_SAVE, "CTRL+S")) { - auto& file = ast.Get(typeId); + auto& file = ast.Get(typeId); String data; - AST::SerializeType(ast, typeId, data); + ast::SerializeType(ast, typeId, data); files::SaveStringFile(file.path, data); - ast.Remove(typeId); + ast.Remove(typeId); UI::AddNotification({UI::ToastType::Success, 1.f, Strings::Format("Saved file {}", p::GetFilename(file.path))}); @@ -506,7 +505,7 @@ namespace rift::Editor::EditorSystem if (UI::BeginMenu("View")) { - if (AST::HasFunctions(ast, typeId)) + if (ast::HasFunctions(ast, typeId)) { UI::MenuItem("Graph", nullptr, &typeEditor.showGraph); } @@ -518,18 +517,18 @@ namespace rift::Editor::EditorSystem } } - void DrawTypes(AST::Tree& ast, SEditor& editor) + void DrawTypes(ast::Tree& ast, SEditor& editor) { - TAccess, AST::CDeclType, AST::CFileRef> access{ast}; - for (AST::Id typeId : FindAllIdsWith(access)) + TAccess, ast::CDeclType, ast::CFileRef> access{ast}; + for (ast::Id typeId : FindAllIdsWith(access)) { auto& typeEditor = access.Get(typeId); - const auto& file = access.Get(typeId); + const auto& file = access.Get(typeId); bool isOpen = true; const String path = p::ToString(file.path); const StringView filename = p::GetFilename(path); - const StringView dirty = ast.Has(typeId) ? "*" : ""; + const StringView dirty = ast.Has(typeId) ? "*" : ""; const String windowName = Strings::Format("{}{}###{}", filename, dirty, typeId); if (typeEditor.pendingFocus) @@ -551,12 +550,12 @@ namespace rift::Editor::EditorSystem CreateTypeDockspace(typeEditor, windowName.c_str()); - if (AST::HasFunctionBodies(ast, typeId)) + if (ast::HasFunctionBodies(ast, typeId)) { Graph::DrawTypeGraph(ast, typeId, typeEditor); } - if (AST::HasVariables(ast, typeId) || AST::HasFunctions(ast, typeId)) + if (ast::HasVariables(ast, typeId) || ast::HasFunctions(ast, typeId)) { typeEditor.layout.BindNextWindowToNode( CTypeEditor::rightBottomNode, ImGuiCond_Appearing); diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index f0d4a296..883228fa 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -19,7 +19,7 @@ namespace rift::Editor { - void DrawTypesDebug(AST::Tree& ast) + void DrawTypesDebug(ast::Tree& ast) { if (!UI::CollapsingHeader("Types")) { @@ -29,7 +29,7 @@ namespace rift::Editor static const ImGuiTableFlags flags = ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingStretchProp; - if (auto* types = ast.TryGetStatic()) + if (auto* types = ast.TryGetStatic()) { UI::BeginChild("typesTableChild", ImVec2(0.f, p::Min(250.f, UI::GetContentRegionAvail().y - 20.f))); @@ -62,7 +62,7 @@ namespace rift::Editor ASTDebugger::ASTDebugger() {} - void ASTDebugger::Draw(AST::Tree& ast) + void ASTDebugger::Draw(ast::Tree& ast) { if (!open) { @@ -111,16 +111,16 @@ namespace rift::Editor DrawNodeAccess access{ast}; if (showHierarchy && !filter.IsActive()) { - p::TArray roots; + p::TArray roots; p::GetRootIds(access, roots); for (auto root : roots) { DrawNode(access, root, true); } - p::TArray orphans = p::FindAllIdsWith(access); - p::ExcludeIdsWith(access, orphans); - p::ExcludeIdsWith(access, orphans); + p::TArray orphans = p::FindAllIdsWith(access); + p::ExcludeIdsWith(access, orphans); + p::ExcludeIdsWith(access, orphans); for (auto orphan : orphans) { DrawNode(access, orphan, true); @@ -128,7 +128,7 @@ namespace rift::Editor } else { - ast.Each([this, &access](AST::Id id) { + ast.Each([this, &access](ast::Id id) { DrawNode(access, id, false); }); } @@ -155,11 +155,11 @@ namespace rift::Editor } } - void ASTDebugger::DrawNode(DrawNodeAccess access, AST::Id nodeId, bool showChildren) + void ASTDebugger::DrawNode(DrawNodeAccess access, ast::Id nodeId, bool showChildren) { static p::String idText; idText.clear(); - if (nodeId == AST::NoId) + if (nodeId == ast::NoId) { idText = "No Id"; } @@ -174,14 +174,14 @@ namespace rift::Editor static p::String name; name.clear(); - if (const auto* id = access.TryGet(nodeId)) + if (const auto* id = access.TryGet(nodeId)) { name = id->name.AsString(); } static p::String path; path.clear(); - if (const auto* file = access.TryGet(nodeId)) + if (const auto* file = access.TryGet(nodeId)) { path = p::ToString(file->path); @@ -216,10 +216,10 @@ namespace rift::Editor ImGui::TableNextColumn(); bool hasChildren; - const AST::CParent* parent = nullptr; + const ast::CParent* parent = nullptr; if (showChildren) { - parent = access.TryGet(nodeId); + parent = access.TryGet(nodeId); hasChildren = parent && !parent->children.IsEmpty(); } else @@ -256,13 +256,13 @@ namespace rift::Editor if (ImGui::TableNextColumn()) { - UI::Text(AST::GetParentNamespace(access, nodeId).ToString()); + UI::Text(ast::GetParentNamespace(access, nodeId).ToString()); } if (hasChildren && open) { - for (AST::Id child : parent->children) + for (ast::Id child : parent->children) { DrawNode(access, child, true); } @@ -271,7 +271,7 @@ namespace rift::Editor } } - void ASTDebugger::OnInspectEntity(AST::Id id) + void ASTDebugger::OnInspectEntity(ast::Id id) { bool bOpenNewInspector = false; if (ImGui::GetIO().KeyCtrl) // Inspector found and Ctrl? Open a new one @@ -285,7 +285,7 @@ namespace rift::Editor }) > 0; if (mainInspector.id == id) { - mainInspector.id = AST::NoId; + mainInspector.id = ast::NoId; wasInspected = true; } @@ -297,13 +297,13 @@ namespace rift::Editor } } - void ASTDebugger::DrawEntityInspector(p::StringView label, p::StringView id, AST::Tree& ast, + void ASTDebugger::DrawEntityInspector(p::StringView label, p::StringView id, ast::Tree& ast, InspectorPanel& inspector, bool* open) { const bool valid = ast.IsValid(inspector.id); const bool removed = ast.WasRemoved(inspector.id); bool clone = false; - AST::Id changedId = inspector.id; + ast::Id changedId = inspector.id; p::String name; p::Strings::FormatTo( @@ -351,10 +351,10 @@ namespace rift::Editor if (valid) { - const auto& registry = AST::TypeRegistry::Get(); + const auto& registry = ast::TypeRegistry::Get(); for (const auto& poolInstance : ast.GetPools()) { - AST::Type* type = registry.FindType(poolInstance.componentId); + ast::Type* type = registry.FindType(poolInstance.componentId); if (!type || !poolInstance.GetPool()->Has(inspector.id)) { continue; @@ -396,10 +396,10 @@ namespace rift::Editor } } - void ASTDebugger::OpenAvailableSecondaryInspector(AST::Id id) + void ASTDebugger::OpenAvailableSecondaryInspector(ast::Id id) { p::i32 availableIndex = secondaryInspectors.FindIndex([](const auto& inspector) { - return !inspector.open || inspector.id == AST::NoId; + return !inspector.open || inspector.id == ast::NoId; }); if (availableIndex != p::NO_INDEX) { diff --git a/Libs/Editor/Src/Tools/GraphPlayground.cpp b/Libs/Editor/Src/Tools/GraphPlayground.cpp index b9e15c3a..5a5b355a 100644 --- a/Libs/Editor/Src/Tools/GraphPlayground.cpp +++ b/Libs/Editor/Src/Tools/GraphPlayground.cpp @@ -14,7 +14,7 @@ namespace rift::Editor { using namespace Nodes; - void GraphPlayground::Draw(AST::Tree& ast, DockSpaceLayout& layout) + void GraphPlayground::Draw(ast::Tree& ast, DockSpaceLayout& layout) { if (!open) { @@ -31,15 +31,15 @@ namespace rift::Editor if (UI::IsWindowAppearing()) { - Graph::SetNodePosition(AST::Id(0), v2::Zero()); + Graph::SetNodePosition(ast::Id(0), v2::Zero()); } static bool boolValue = false; - // Graph::Literals::DrawBoolNode(AST::Id(0), boolValue); + // Graph::Literals::DrawBoolNode(ast::Id(0), boolValue); static String stringValue; - // Graph::Literals::DrawStringNode(AST::Id(1), stringValue); + // Graph::Literals::DrawStringNode(ast::Id(1), stringValue); - // Graph::DrawCallNode({}, AST::Id(958), "ApplyDamage", "DamageSystem"); + // Graph::DrawCallNode({}, ast::Id(958), "ApplyDamage", "DamageSystem"); Nodes::DrawMiniMap(0.2f, MiniMapCorner::TopRight); Nodes::EndNodeEditor(); diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index c32d98b4..bb77f486 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -23,10 +23,10 @@ namespace rift::Editor { - void EditFunctionPin(AST::Tree& ast, AST::Id ownerId, AST::Id id) + void EditFunctionPin(ast::Tree& ast, ast::Id ownerId, ast::Id id) { - auto* ns = ast.TryGet(id); - auto* type = ast.TryGet(id); + auto* ns = ast.TryGet(id); + auto* type = ast.TryGet(id); if (!ns || !type) { return; @@ -40,7 +40,7 @@ namespace rift::Editor popupName.clear(); Strings::FormatTo(popupName, "##PinContextMenu_{}", id); - AST::Id typeId = AST::FindIdFromNamespace(ast, type->type); + ast::Id typeId = ast::FindIdFromNamespace(ast, type->type); UI::TableNextRow(); const Color color = GetTypeColor(ast, typeId); @@ -69,8 +69,8 @@ namespace rift::Editor if (Editor::TypeCombo(ast, labelId, typeId)) { ScopedChange(ast, id); - ast.GetOrAdd(id).id = typeId; - type->type = AST::GetNamespace(ast, typeId); + ast.GetOrAdd(id).id = typeId; + type->type = ast::GetNamespace(ast, typeId); } UI::PopStyleVar(); if (UI::IsItemHovered()) @@ -99,14 +99,14 @@ namespace rift::Editor } if (removePin) { - AST::RemoveExprInputPin(ast, AST::GetExprInputFromPin(ast, id)); - AST::RemoveExprOutputPin(ast, AST::GetExprOutputFromPin(ast, id)); + ast::RemoveExprInputPin(ast, ast::GetExprInputFromPin(ast, id)); + ast::RemoveExprOutputPin(ast, ast::GetExprOutputFromPin(ast, id)); } } - void DrawFunction(AST::Tree& ast, AST::Id typeId, AST::Id id) + void DrawFunction(ast::Tree& ast, ast::Id typeId, ast::Id id) { - auto* ns = ast.TryGet(id); + auto* ns = ast.TryGet(id); if (!ns) { return; @@ -116,7 +116,7 @@ namespace rift::Editor UI::SetNextItemWidth(UI::GetContentRegionAvail().x); if (UI::InputText("##name", functionName, ImGuiInputTextFlags_AutoSelectAll)) { - Id sameNameFuncId = AST::FindChildByName(ast, typeId, Tag{functionName}); + Id sameNameFuncId = ast::FindChildByName(ast, typeId, Tag{functionName}); if (!IsNone(sameNameFuncId) && id != sameNameFuncId) { UI::PushTextColor(LinearColor::Red()); @@ -136,9 +136,9 @@ namespace rift::Editor { UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); - if (const auto* exprOutputs = ast.TryGet(id)) + if (const auto* exprOutputs = ast.TryGet(id)) { - for (AST::Id pinId : exprOutputs->pinIds) + for (ast::Id pinId : exprOutputs->pinIds) { EditFunctionPin(ast, id, pinId); } @@ -151,7 +151,7 @@ namespace rift::Editor if (UI::Selectable(ICON_FA_PLUS "##AddInput")) { ScopedChange(ast, id); - AST::AddFunctionInput(ast, id); + ast::AddFunctionInput(ast, id); } UI::HelpTooltip("Adds a new input parameter to a function"); UI::PopStyleVar(); @@ -163,9 +163,9 @@ namespace rift::Editor { UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); - if (const auto* exprInputs = ast.TryGet(id)) + if (const auto* exprInputs = ast.TryGet(id)) { - for (AST::Id pinId : exprInputs->pinIds) + for (ast::Id pinId : exprInputs->pinIds) { EditFunctionPin(ast, id, pinId); } @@ -178,7 +178,7 @@ namespace rift::Editor if (UI::Selectable(ICON_FA_PLUS "##AddOutput")) { ScopedChange(ast, id); - AST::AddFunctionOutput(ast, id); + ast::AddFunctionOutput(ast, id); } UI::HelpTooltip("Adds a new output parameter to a function"); UI::PopStyleVar(); @@ -186,7 +186,7 @@ namespace rift::Editor UI::Spacing(); } - void DrawDetailsPanel(AST::Tree& ast, AST::Id typeId) + void DrawDetailsPanel(ast::Tree& ast, ast::Id typeId) { auto& editor = ast.Get(typeId); @@ -204,7 +204,7 @@ namespace rift::Editor return; } - if (ast.Has(editor.selectedPropertyId)) + if (ast.Has(editor.selectedPropertyId)) { DrawFunction(ast, typeId, editor.selectedPropertyId); } diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index d350ead8..25def6c4 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -8,10 +8,9 @@ #include - namespace rift::Editor { - const Color GetTypeColor(const AST::Tree& ast, AST::Id id) + const Color GetTypeColor(const ast::Tree& ast, ast::Id id) { if (!ast.IsValid(id)) { @@ -44,11 +43,11 @@ namespace rift::Editor { return GetTypeColor(); } - else if (ast.Has(id)) + else if (ast.Has(id)) { return GetTypeColor(); } - else if (ast.Has(id)) + else if (ast.Has(id)) { return GetTypeColor(); } diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 9fd4944e..3706f9f1 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -25,10 +25,10 @@ namespace rift::Editor { // using namespace EnumOperators; - void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, AST::Id variableId) + void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, ast::Id variableId) { - auto* ns = access.TryGet(variableId); - auto* variableDecl = access.TryGet(variableId); + auto* ns = access.TryGet(variableId); + auto* variableDecl = access.TryGet(variableId); if (!ns || !variableDecl) { return; @@ -42,7 +42,7 @@ namespace rift::Editor ImGui::PushID(ns); const Color color = - GetTypeColor(static_cast(access.GetContext()), variableDecl->typeId); + GetTypeColor(static_cast(access.GetContext()), variableDecl->typeId); static constexpr float frameHeight = 20.f; UI::TableNextColumn(); @@ -67,7 +67,7 @@ namespace rift::Editor } else if (editor.selectedPropertyId == variableId) // If not selected but WAS selected { - editor.selectedPropertyId = AST::NoId; + editor.selectedPropertyId = ast::NoId; } Color bgColor = color; @@ -126,9 +126,9 @@ namespace rift::Editor UI::PopID(); } - void DrawFunction(AST::Tree& ast, CTypeEditor& editor, AST::Id typeId, AST::Id id) + void DrawFunction(ast::Tree& ast, CTypeEditor& editor, ast::Id typeId, ast::Id id) { - auto* ns = ast.TryGet(id); + auto* ns = ast.TryGet(id); if (!ns) { return; @@ -170,15 +170,15 @@ namespace rift::Editor } } - void DrawVariables(TVariableAccessRef access, AST::TransactionAccess transAccess, - CTypeEditor& editor, AST::Id typeId) + void DrawVariables(TVariableAccessRef access, ast::TransactionAccess transAccess, + CTypeEditor& editor, ast::Id typeId) { if (UI::CollapsingHeader("Variables", ImGuiTreeNodeFlags_DefaultOpen)) { UI::Indent(10.f); - TArray variableIds; + TArray variableIds; p::GetIdChildren(access, typeId, variableIds); - ExcludeIdsWithout(access, variableIds); + ExcludeIdsWithout(access, variableIds); UI::PushStyleVar(ImGuiStyleVar_CellPadding, {1.f, 3.f}); bool showTable = UI::BeginTable("##variableTable", 3, ImGuiTableFlags_SizingFixedFit); @@ -188,9 +188,9 @@ namespace rift::Editor ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch, 0.45f); ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch, 0.25f); ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch, 0.30f); - for (AST::Id child : variableIds) + for (ast::Id child : variableIds) { - if (access.Has(child)) + if (access.Has(child)) { UI::TableNextRow(); DrawVariable(access, editor, child); @@ -203,8 +203,8 @@ namespace rift::Editor if (UI::Button(ICON_FA_PLUS "##Variable", ImVec2(-FLT_MIN, 0.0f))) { ScopedChange(transAccess, typeId); - AST::AddVariable( - {static_cast(access.GetContext()), typeId}, "NewVariable"); + ast::AddVariable( + {static_cast(access.GetContext()), typeId}, "NewVariable"); } UI::PopStyleCompact(); UI::Unindent(10.f); @@ -212,7 +212,7 @@ namespace rift::Editor } } - void DrawFunctions(AST::Tree& ast, CTypeEditor& editor, AST::Id typeId) + void DrawFunctions(ast::Tree& ast, CTypeEditor& editor, ast::Id typeId) { const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowItemOverlap @@ -221,10 +221,10 @@ namespace rift::Editor { UI::Indent(10.f); - TArray functionIds; + TArray functionIds; p::GetIdChildren(ast, typeId, functionIds); - ExcludeIdsWithout(ast, functionIds); - for (AST::Id functionId : functionIds) + ExcludeIdsWithout(ast, functionIds); + for (ast::Id functionId : functionIds) { DrawFunction(ast, editor, typeId, functionId); } @@ -233,7 +233,7 @@ namespace rift::Editor if (UI::Button(ICON_FA_PLUS "##Function", ImVec2(-FLT_MIN, 0.0f))) { ScopedChange(ast, typeId); - AST::AddFunction({ast, typeId}, "NewFunction"); + ast::AddFunction({ast, typeId}, "NewFunction"); } UI::PopStyleCompact(); UI::Unindent(10.f); @@ -241,7 +241,7 @@ namespace rift::Editor } } - void DrawElementsPanel(AST::Tree& ast, AST::Id typeId) + void DrawElementsPanel(ast::Tree& ast, ast::Id typeId) { auto& editor = ast.Get(typeId); @@ -256,12 +256,12 @@ namespace rift::Editor UI::SetNextItemWidth(UI::GetContentRegionAvail().x); editor.elementsFilter.Draw("##filter"); - if (AST::HasVariables(ast, typeId)) + if (ast::HasVariables(ast, typeId)) { DrawVariables(ast, ast, editor, typeId); } - if (AST::HasFunctions(ast, typeId)) + if (ast::HasFunctions(ast, typeId)) { DrawFunctions(ast, editor, typeId); } @@ -271,16 +271,16 @@ namespace rift::Editor if (!IsNone(editor.pendingDeletePropertyId)) { ScopedChange(ast, editor.pendingDeletePropertyId); - bool removedPin = AST::RemoveExprInputPin( - ast, AST::GetExprInputFromPin(ast, editor.pendingDeletePropertyId)); - removedPin |= AST::RemoveExprOutputPin( - ast, AST::GetExprOutputFromPin(ast, editor.pendingDeletePropertyId)); + bool removedPin = ast::RemoveExprInputPin( + ast, ast::GetExprInputFromPin(ast, editor.pendingDeletePropertyId)); + removedPin |= ast::RemoveExprOutputPin( + ast, ast::GetExprOutputFromPin(ast, editor.pendingDeletePropertyId)); // If pin has not been marked for removal, destroy the entity if (!removedPin) { p::RemoveId(ast, editor.pendingDeletePropertyId, true); - editor.pendingDeletePropertyId = AST::NoId; + editor.pendingDeletePropertyId = ast::NoId; } } } diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index ec8cbf19..167d2fe1 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -26,7 +26,6 @@ #include - namespace rift::Editor::Graph { static CNodePosition* currentNodeTransform = nullptr; @@ -63,14 +62,14 @@ namespace rift::Editor::Graph return Nodes::ScreenToGridPosition(screenPosition) * GetInvGridSize(); } - void BeginExprInput(TAccessRef access, AST::Id id, const bool& invalid) + void BeginExprInput(TAccessRef access, ast::Id id, const bool& invalid) { bool isPointer = false; - AST::Id typeId = AST::NoId; - if (auto* type = access.TryGet(id)) + ast::Id typeId = ast::NoId; + if (auto* type = access.TryGet(id)) { typeId = type->id; - isPointer = type->mode != AST::TypeMode::Value; + isPointer = type->mode != ast::TypeMode::Value; } Color pinColor = GetTypeColor(); @@ -81,7 +80,7 @@ namespace rift::Editor::Graph } else { - pinColor = GetTypeColor(static_cast(access.GetContext()), typeId); + pinColor = GetTypeColor(static_cast(access.GetContext()), typeId); } Nodes::PushStyleColor(Nodes::ColorVar_Pin, pinColor); @@ -91,14 +90,14 @@ namespace rift::Editor::Graph i32(id), isPointer ? Nodes::PinShape_DiamondFilled : Nodes::PinShape_CircleFilled); } - void BeginExprOutput(TAccessRef access, AST::Id id, const bool& invalid) + void BeginExprOutput(TAccessRef access, ast::Id id, const bool& invalid) { bool isPointer = false; - AST::Id typeId = AST::NoId; - if (auto* type = access.TryGet(id)) + ast::Id typeId = ast::NoId; + if (auto* type = access.TryGet(id)) { typeId = type->id; - isPointer = type->mode != AST::TypeMode::Value; + isPointer = type->mode != ast::TypeMode::Value; } Color pinColor = GetTypeColor(); @@ -109,7 +108,7 @@ namespace rift::Editor::Graph } else { - pinColor = GetTypeColor(static_cast(access.GetContext()), typeId); + pinColor = GetTypeColor(static_cast(access.GetContext()), typeId); } Nodes::PushStyleColor(Nodes::ColorVar_Pin, pinColor); @@ -139,39 +138,39 @@ namespace rift::Editor::Graph } } - void DrawInputs(TAccessRef access, - const AST::CExprInputs& inputs) + void DrawInputs(TAccessRef access, + const ast::CExprInputs& inputs) { - for (AST::Id pinId : inputs.pinIds) + for (ast::Id pinId : inputs.pinIds) { if (access.IsValid(pinId)) { - const bool invalid = access.Has(pinId); + const bool invalid = access.Has(pinId); BeginExprInput(access, pinId, invalid); - auto* ns = access.TryGet(pinId); + auto* ns = access.TryGet(pinId); UI::Text(ns ? ns->name.AsString() : "none"); EndExprInput(invalid); } } } - void DrawOutputs(TAccessRef access, - const AST::CExprOutputs& outputs) + void DrawOutputs(TAccessRef access, + const ast::CExprOutputs& outputs) { - for (AST::Id pinId : outputs.pinIds) + for (ast::Id pinId : outputs.pinIds) { if (access.IsValid(pinId)) { - const bool invalid = access.Has(pinId); + const bool invalid = access.Has(pinId); BeginExprOutput(access, pinId, invalid); - auto* ns = access.TryGet(pinId); + auto* ns = access.TryGet(pinId); UI::Text(ns ? ns->name.AsString() : "none"); EndExprOutput(invalid); } } } - void BeginNode(TAccessRef> access, AST::Id id) + void BeginNode(TAccessRef> access, ast::Id id) { currentNodeTransform = &access.GetOrAdd(id); auto* context = Nodes::GetCurrentContext(); @@ -186,7 +185,7 @@ namespace rift::Editor::Graph Nodes::BeginNode(id); } - void EndNode(const AST::TransactionAccess& access) + void EndNode(const ast::TransactionAccess& access) { // Selection outline const auto* context = Nodes::GetCurrentContext(); @@ -200,7 +199,7 @@ namespace rift::Editor::Graph if (currentNodeTransform && context->leftMouseReleased) { - const AST::Id id = context->currentNodeId; + const ast::Id id = context->currentNodeId; v2 newPosition = GetNodePosition(id); if (!newPosition.Equals(currentNodeTransform->position, 0.1f)) { @@ -223,7 +222,7 @@ namespace rift::Editor::Graph Nodes::PopStyleColor(2); } - void DrawLiteralBool(AST::Tree& ast, AST::Id id, bool& value) + void DrawLiteralBool(ast::Tree& ast, ast::Id id, bool& value) { static constexpr Color color = GetTypeColor(); @@ -241,7 +240,7 @@ namespace rift::Editor::Graph PopNodeBackgroundColor(); } - void DrawLiteralIntegral(AST::Tree& ast, AST::Id id, AST::CLiteralIntegral& value) + void DrawLiteralIntegral(ast::Tree& ast, ast::Id id, ast::CLiteralIntegral& value) { const bool isSigned = value.IsSigned(); const Color color = isSigned ? GetTypeColor() : GetTypeColor(); @@ -255,14 +254,14 @@ namespace rift::Editor::Graph ImGuiDataType dataType = ImGuiDataType_COUNT; switch (value.type) { - case AST::IntegralType::S8: dataType = ImGuiDataType_S8; break; - case AST::IntegralType::S16: dataType = ImGuiDataType_S16; break; - case AST::IntegralType::S32: dataType = ImGuiDataType_S32; break; - case AST::IntegralType::S64: dataType = ImGuiDataType_S64; break; - case AST::IntegralType::U8: dataType = ImGuiDataType_U8; break; - case AST::IntegralType::U16: dataType = ImGuiDataType_U16; break; - case AST::IntegralType::U32: dataType = ImGuiDataType_U32; break; - case AST::IntegralType::U64: dataType = ImGuiDataType_U64; break; + case ast::IntegralType::S8: dataType = ImGuiDataType_S8; break; + case ast::IntegralType::S16: dataType = ImGuiDataType_S16; break; + case ast::IntegralType::S32: dataType = ImGuiDataType_S32; break; + case ast::IntegralType::S64: dataType = ImGuiDataType_S64; break; + case ast::IntegralType::U8: dataType = ImGuiDataType_U8; break; + case ast::IntegralType::U16: dataType = ImGuiDataType_U16; break; + case ast::IntegralType::U32: dataType = ImGuiDataType_U32; break; + case ast::IntegralType::U64: dataType = ImGuiDataType_U64; break; } const char* format = value.IsSigned() ? "%i" : "%iu"; @@ -278,9 +277,9 @@ namespace rift::Editor::Graph PopNodeBackgroundColor(); } - void DrawLiteralFloating(AST::Tree& ast, AST::Id id, AST::CLiteralFloating& value) + void DrawLiteralFloating(ast::Tree& ast, ast::Id id, ast::CLiteralFloating& value) { - const bool isDouble = value.type == AST::FloatingType::F64; + const bool isDouble = value.type == ast::FloatingType::F64; const Color color = isDouble ? GetTypeColor() : GetTypeColor(); PushNodeBackgroundColor(color); BeginNode(ast, id); @@ -301,7 +300,7 @@ namespace rift::Editor::Graph PopNodeBackgroundColor(); } - void DrawLiteralString(AST::Tree& ast, AST::Id id, String& value) + void DrawLiteralString(ast::Tree& ast, ast::Id id, String& value) { static constexpr Color color = GetTypeColor(); PushNodeBackgroundColor(color); @@ -323,15 +322,15 @@ namespace rift::Editor::Graph PopNodeBackgroundColor(); } - using FunctionDeclsAccess = p::TAccessRef, p::TWrite, AST::CChild, - AST::CFileRef, p::TWrite>; - void DrawFunctionDecls(FunctionDeclsAccess access, const TArray& functionDecls) + using FunctionDeclsAccess = p::TAccessRef, p::TWrite, ast::CChild, + ast::CFileRef, p::TWrite>; + void DrawFunctionDecls(FunctionDeclsAccess access, const TArray& functionDecls) { - for (AST::Id functionId : functionDecls) + for (ast::Id functionId : functionDecls) { Tag name; - if (auto* ns = access.TryGet(functionId)) + if (auto* ns = access.TryGet(functionId)) { name = ns->name; } @@ -353,7 +352,7 @@ namespace rift::Editor::Graph } Nodes::EndNodeTitleBar(); - if (auto* outputs = access.TryGet(functionId)) + if (auto* outputs = access.TryGet(functionId)) { DrawOutputs(access, *outputs); } @@ -364,10 +363,10 @@ namespace rift::Editor::Graph } } - void DrawReturnNode(TAccessRef, TWrite, - TWrite, AST::CChild, AST::CFileRef> + void DrawReturnNode(TAccessRef, TWrite, + TWrite, ast::CChild, ast::CFileRef> access, - AST::Id id) + ast::Id id) { PushNodeBackgroundColor(rift::UI::GetNeutralColor(0)); PushNodeTitleColor(returnColor); @@ -393,14 +392,14 @@ namespace rift::Editor::Graph PopNodeBackgroundColor(); } - using CallsAccess = TAccessRef, TWrite, AST::CChild, - AST::CFileRef, AST::CExprCall, AST::CExprInputs, AST::CExprOutputs, AST::CNamespace, - AST::CExprTypeId, AST::CInvalid, TWrite, AST::CDeclType>; - void DrawCalls(CallsAccess access, AST::Id typeId, const TArray& childrenIds) + using CallsAccess = TAccessRef, TWrite, ast::CChild, + ast::CFileRef, ast::CExprCall, ast::CExprInputs, ast::CExprOutputs, ast::CNamespace, + ast::CExprTypeId, ast::CInvalid, TWrite, ast::CDeclType>; + void DrawCalls(CallsAccess access, ast::Id typeId, const TArray& childrenIds) { - for (AST::Id id : childrenIds) + for (ast::Id id : childrenIds) { - if (auto* call = access.TryGet(id)) + if (auto* call = access.TryGet(id)) { StringView functionName = call->function.Last().AsString(); @@ -432,7 +431,7 @@ namespace rift::Editor::Graph // Inputs UI::BeginGroup(); - if (const auto* inputs = access.TryGet(id)) + if (const auto* inputs = access.TryGet(id)) { DrawInputs(access, *inputs); } @@ -441,7 +440,7 @@ namespace rift::Editor::Graph // Outputs UI::BeginGroup(); - if (const auto* outputs = access.TryGet(id)) + if (const auto* outputs = access.TryGet(id)) { DrawOutputs(access, *outputs); } @@ -505,49 +504,49 @@ namespace rift::Editor::Graph ImGui::PopStyleVar(2); } - void DrawReturns(TAccessRef, TWrite, - TWrite, AST::CChild, AST::CFileRef, AST::CStmtReturn> + void DrawReturns(TAccessRef, TWrite, + TWrite, ast::CChild, ast::CFileRef, ast::CStmtReturn> access, - const TArray& children) + const TArray& children) { - for (AST::Id id : FindIdsWith(access, children)) + for (ast::Id id : FindIdsWith(access, children)) { DrawReturnNode(access, id); } } - void DrawLiterals(AST::Tree& ast, const TArray& children) + void DrawLiterals(ast::Tree& ast, const TArray& children) { - for (AST::Id id : FindIdsWith(ast, children)) + for (ast::Id id : FindIdsWith(ast, children)) { - DrawLiteralBool(ast, id, ast.Get(id).value); + DrawLiteralBool(ast, id, ast.Get(id).value); } - for (AST::Id id : FindIdsWith(ast, children)) + for (ast::Id id : FindIdsWith(ast, children)) { - DrawLiteralIntegral(ast, id, ast.Get(id)); + DrawLiteralIntegral(ast, id, ast.Get(id)); } - for (AST::Id id : FindIdsWith(ast, children)) + for (ast::Id id : FindIdsWith(ast, children)) { - DrawLiteralFloating(ast, id, ast.Get(id)); + DrawLiteralFloating(ast, id, ast.Get(id)); } - for (AST::Id id : FindIdsWith(ast, children)) + for (ast::Id id : FindIdsWith(ast, children)) { - DrawLiteralString(ast, id, ast.Get(id).value); + DrawLiteralString(ast, id, ast.Get(id).value); } } - void DrawVariableRefs(AST::Tree& ast, const TArray& children) + void DrawVariableRefs(ast::Tree& ast, const TArray& children) { String name; - for (AST::Id id : FindIdsWith(ast, children)) + for (ast::Id id : FindIdsWith(ast, children)) { - AST::Id variableId = ast.Get(id).declarationId; + ast::Id variableId = ast.Get(id).declarationId; - const AST::CExprTypeId* exprType = ast.TryGet(id); - AST::Id typeId = exprType ? exprType->id : AST::NoId; + const ast::CExprTypeId* exprType = ast.TryGet(id); + ast::Id typeId = exprType ? exprType->id : ast::NoId; const Color color = GetTypeColor(ast, typeId); PushNodeBackgroundColor(color); @@ -557,9 +556,9 @@ namespace rift::Editor::Graph BeginExprOutput(ast, id, false); PushInnerNodeStyle(); StringView name = "Invalid"; - if (ast.IsValid(variableId) && ast.Has(variableId)) + if (ast.IsValid(variableId) && ast.Has(variableId)) { - name = ast.Get(variableId).name.AsString(); + name = ast.Get(variableId).name.AsString(); } UI::Text(name); PopInnerNodeStyle(); @@ -571,16 +570,16 @@ namespace rift::Editor::Graph } } - void DrawIfs(TAccessRef, TWrite, TWrite, - AST::CChild, AST::CFileRef, AST::CStmtIf, AST::CStmtOutputs, AST::CExprInputs, - AST::CParent, AST::CExprTypeId> + void DrawIfs(TAccessRef, TWrite, TWrite, + ast::CChild, ast::CFileRef, ast::CStmtIf, ast::CStmtOutputs, ast::CExprInputs, + ast::CParent, ast::CExprTypeId> access, - const TArray& children) + const TArray& children) { PushNodeBackgroundColor(UI::GetNeutralColor(0)); PushNodeTitleColor(flowColor); - for (AST::Id id : - FindIdsWith(access, children)) + for (ast::Id id : + FindIdsWith(access, children)) { BeginNode(access, id); { @@ -594,7 +593,7 @@ namespace rift::Editor::Graph Nodes::EndInput(); PopExecutionPinStyle(); - auto& inputs = access.Get(id); + auto& inputs = access.Get(id); if (!Ensure(inputs.pinIds.Size() == 1)) { continue; @@ -613,7 +612,7 @@ namespace rift::Editor::Graph UI::SameLine(); UI::BeginGroup(); { - auto& outputs = access.Get(id); + auto& outputs = access.Get(id); if (!Ensure(outputs.pinIds.Size() == 2)) { continue; @@ -638,12 +637,12 @@ namespace rift::Editor::Graph } void DrawUnaryOperators( - TAccessRef, TWrite, TWrite, - AST::CChild, AST::CParent, AST::CFileRef, AST::CExprUnaryOperator, AST::CExprTypeId> + TAccessRef, TWrite, TWrite, + ast::CChild, ast::CParent, ast::CFileRef, ast::CExprUnaryOperator, ast::CExprTypeId> access, - const TArray& children) + const TArray& children) { - for (AST::Id id : FindIdsWith(access, children)) + for (ast::Id id : FindIdsWith(access, children)) { static constexpr Color color = UI::GetNeutralColor(0); @@ -656,7 +655,7 @@ namespace rift::Editor::Graph EndExprInput(false); UI::SameLine(); - const auto& op = access.Get(id); + const auto& op = access.Get(id); StringView shortName = Editor::GetUnaryOperatorName(op.type); UI::Text(shortName); @@ -671,13 +670,13 @@ namespace rift::Editor::Graph } void DrawBinaryOperators( - TAccessRef, TWrite, TWrite, - AST::CChild, AST::CParent, AST::CFileRef, AST::CExprBinaryOperator, AST::CExprTypeId> + TAccessRef, TWrite, TWrite, + ast::CChild, ast::CParent, ast::CFileRef, ast::CExprBinaryOperator, ast::CExprTypeId> access, - const TArray& children) + const TArray& children) { - TArray pinIds; - for (AST::Id id : FindIdsWith(access, children)) + TArray pinIds; + for (ast::Id id : FindIdsWith(access, children)) { static constexpr Color color = UI::GetNeutralColor(0); PushNodeBackgroundColor(color); @@ -701,7 +700,7 @@ namespace rift::Editor::Graph UI::EndGroup(); UI::SameLine(); - const auto& op = access.Get(id); + const auto& op = access.Get(id); StringView shortName = Editor::GetBinaryOperatorName(op.type); UI::Text(shortName); @@ -715,17 +714,17 @@ namespace rift::Editor::Graph } } - void DrawStatementLinks(TAccessRef& access, - const TArray& children) + void DrawStatementLinks(TAccessRef& access, + const TArray& children) { Nodes::PushStyleVar(Nodes::StyleVar_LinkThickness, 2.f); Nodes::PushStyleColor(Nodes::ColorVar_Link, executionColor); Nodes::PushStyleColor(Nodes::ColorVar_LinkHovered, UI::Hovered(executionColor)); Nodes::PushStyleColor(Nodes::ColorVar_LinkSelected, selectedColor); - for (AST::Id outputId : FindIdsWith(access, children)) + for (ast::Id outputId : FindIdsWith(access, children)) { - const auto* output = access.TryGet(outputId); + const auto* output = access.TryGet(outputId); if (output && access.IsValid(output->linkInputNode)) { // Input pin ids equal input node ids @@ -734,17 +733,17 @@ namespace rift::Editor::Graph } } - for (AST::Id outputId : FindIdsWith(access, children)) + for (ast::Id outputId : FindIdsWith(access, children)) { - if (const auto* outputs = access.TryGet(outputId)) + if (const auto* outputs = access.TryGet(outputId)) { if (EnsureMsg(outputs->linkInputNodes.Size() == outputs->pinIds.Size(), "Inputs and pins must match. Graph might be corrupted.")) { for (i32 i = 0; i < outputs->linkInputNodes.Size(); ++i) { - const AST::Id outputPinId = outputs->pinIds[i]; - const AST::Id inputNodeId = outputs->linkInputNodes[i]; + const ast::Id outputPinId = outputs->pinIds[i]; + const ast::Id inputNodeId = outputs->linkInputNodes[i]; if (access.IsValid(outputPinId) && access.IsValid(inputNodeId)) { // Input pin ids equal input node ids @@ -761,15 +760,15 @@ namespace rift::Editor::Graph } void DrawExpressionLinks( - TAccessRef& access, - const TArray& children) + TAccessRef& access, + const TArray& children) { Nodes::PushStyleVar(Nodes::StyleVar_LinkThickness, 1.5f); Nodes::PushStyleColor(Nodes::ColorVar_LinkSelected, selectedColor); - for (AST::Id nodeId : FindIdsWith(access, children)) + for (ast::Id nodeId : FindIdsWith(access, children)) { - const auto& inputs = access.Get(nodeId); + const auto& inputs = access.Get(nodeId); if (!EnsureMsg(inputs.pinIds.Size() == inputs.linkedOutputs.Size(), "Inputs are invalid. The graph might be corrupted.")) [[likely]] { @@ -778,25 +777,25 @@ namespace rift::Editor::Graph for (i32 i = 0; i < inputs.linkedOutputs.Size(); ++i) { - AST::Id inputId = inputs.pinIds[i]; - AST::ExprOutput output = inputs.linkedOutputs[i]; + ast::Id inputId = inputs.pinIds[i]; + ast::ExprOutput output = inputs.linkedOutputs[i]; if (!access.IsValid(inputId) || !access.IsValid(output.pinId)) { continue; } Color color = GetTypeColor(); - if (access.Has(inputId) || access.Has(output.pinId)) + if (access.Has(inputId) || access.Has(output.pinId)) { color = invalidColor; } - else if (const auto* type = access.TryGet(output.pinId)) + else if (const auto* type = access.TryGet(output.pinId)) { - color = GetTypeColor(static_cast(access.GetContext()), type->id); + color = GetTypeColor(static_cast(access.GetContext()), type->id); } - else if (const auto* type = access.TryGet(inputId)) + else if (const auto* type = access.TryGet(inputId)) { - color = GetTypeColor(static_cast(access.GetContext()), type->id); + color = GetTypeColor(static_cast(access.GetContext()), type->id); } Nodes::PushStyleColor(Nodes::ColorVar_Link, color); @@ -811,7 +810,7 @@ namespace rift::Editor::Graph Nodes::PopStyleVar(); } - void DrawTypeGraph(AST::Tree& ast, AST::Id typeId, CTypeEditor& typeEditor) + void DrawTypeGraph(ast::Tree& ast, ast::Id typeId, CTypeEditor& typeEditor) { if (!typeEditor.showGraph) { @@ -827,7 +826,7 @@ namespace rift::Editor::Graph if (UI::Begin(graphId.c_str(), &typeEditor.showGraph, ImGuiWindowFlags_NoCollapse)) { Nodes::SetEditorContext(&typeEditor.nodesEditor); - Nodes::GetCurrentContext()->canCreateLinks = AST::HasFunctionBodies(ast, typeId); + Nodes::GetCurrentContext()->canCreateLinks = ast::HasFunctionBodies(ast, typeId); Nodes::BeginNodeEditor(); PushNodeStyle(); @@ -837,11 +836,11 @@ namespace rift::Editor::Graph wantsToOpenContextMenu = true; } - TArray children; + TArray children; p::GetIdChildren(ast, typeId, children); // Nodes - DrawFunctionDecls(ast, FindIdsWith(ast, children)); + DrawFunctionDecls(ast, FindIdsWith(ast, children)); DrawReturns(ast, children); DrawCalls(ast, typeId, children); DrawLiterals(ast, children); @@ -860,7 +859,7 @@ namespace rift::Editor::Graph if (UI::IsKeyReleased(ImGuiKey_Delete)) { - AST::RemoveNodes(ast, Nodes::GetSelectedNodes()); + ast::RemoveNodes(ast, Nodes::GetSelectedNodes()); } Nodes::EndNodeEditor(); @@ -869,30 +868,30 @@ namespace rift::Editor::Graph Nodes::Id inputPin; if (Nodes::IsLinkCreated(outputPin, inputPin)) { - AST::Id pinIds[2]{AST::Id(outputPin), AST::Id(inputPin)}; + ast::Id pinIds[2]{ast::Id(outputPin), ast::Id(inputPin)}; ScopedChange(ast, pinIds); - AST::TryConnectStmt(ast, AST::Id(outputPin), AST::Id(inputPin)); - AST::TryConnectExpr(ast, AST::GetExprOutputFromPin(ast, AST::Id(outputPin)), - AST::GetExprInputFromPin(ast, AST::Id(inputPin))); + ast::TryConnectStmt(ast, ast::Id(outputPin), ast::Id(inputPin)); + ast::TryConnectExpr(ast, ast::GetExprOutputFromPin(ast, ast::Id(outputPin)), + ast::GetExprInputFromPin(ast, ast::Id(inputPin))); } Nodes::Id linkId; if (Nodes::IsLinkDestroyed(linkId)) { - ScopedChange(ast, AST::Id(linkId)); + ScopedChange(ast, ast::Id(linkId)); // linkId is always the outputId - AST::DisconnectStmtLink(ast, AST::Id(linkId)); - AST::DisconnectExpr(ast, AST::GetExprInputFromPin(ast, AST::Id(linkId))); + ast::DisconnectStmtLink(ast, ast::Id(linkId)); + ast::DisconnectExpr(ast, ast::GetExprInputFromPin(ast, ast::Id(linkId))); } - AST::Id hoveredNodeId = Nodes::GetHoveredNode(); + ast::Id hoveredNodeId = Nodes::GetHoveredNode(); if (!IsNone(hoveredNodeId) && Nodes::IsNodeSelected(hoveredNodeId) && UI::IsMouseClicked(ImGuiMouseButton_Left)) { typeEditor.selectedPropertyId = Nodes::GetHoveredNode(); } - static AST::Id contextHoveredNodeId = AST::NoId; - static AST::Id contextHoveredLinkId = AST::NoId; + static ast::Id contextHoveredNodeId = ast::NoId; + static ast::Id contextHoveredLinkId = ast::NoId; if (wantsToOpenContextMenu) { contextHoveredNodeId = Nodes::GetHoveredNode(); @@ -904,13 +903,13 @@ namespace rift::Editor::Graph UI::End(); } - void SetNodePosition(AST::Id id, v2 position) + void SetNodePosition(ast::Id id, v2 position) { position *= settings.GetGridSize(); Nodes::SetNodeGridSpacePos(id, position); } - v2 GetNodePosition(AST::Id id) + v2 GetNodePosition(ast::Id id) { const v2 pos = Nodes::GetNodeGridSpacePos(id); return v2{pos.x * settings.GetInvGridSize(), pos.y * settings.GetInvGridSize()}.Floor(); diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index 5be3dfcc..235dc990 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -26,7 +26,7 @@ namespace rift::Editor::Graph { - void SetPositionAndConnect(AST::Tree& ast, AST::Id id, v2 position) + void SetPositionAndConnect(ast::Tree& ast, ast::Id id, v2 position) { if (!IsNone(id)) { @@ -34,18 +34,18 @@ namespace rift::Editor::Graph // TODO: Improve nodes input to handle this correctly TPair linkPin = Nodes::GetDraggedOriginPin(); - const auto linkPinId = AST::Id(linkPin.first); + const auto linkPinId = ast::Id(linkPin.first); switch (linkPin.second) { case Nodes::PinType::Output: - AST::TryConnectStmt(ast, linkPinId, id); - AST::TryConnectExpr(ast, AST::GetExprOutputFromPin(ast, linkPinId), - AST::GetExprInputFromPin(ast, id)); + ast::TryConnectStmt(ast, linkPinId, id); + ast::TryConnectExpr(ast, ast::GetExprOutputFromPin(ast, linkPinId), + ast::GetExprInputFromPin(ast, id)); break; case Nodes::PinType::Input: - AST::TryConnectStmt(ast, id, linkPinId); - AST::TryConnectExpr(ast, AST::GetExprOutputFromPin(ast, id), - AST::GetExprInputFromPin(ast, linkPinId)); + ast::TryConnectStmt(ast, id, linkPinId); + ast::TryConnectExpr(ast, ast::GetExprOutputFromPin(ast, id), + ast::GetExprInputFromPin(ast, linkPinId)); break; default: break; } @@ -79,61 +79,61 @@ namespace rift::Editor::Graph return false; } - void DrawNodesContextMenu(AST::Tree& ast, AST::Id typeId, TView nodeIds) + void DrawNodesContextMenu(ast::Tree& ast, ast::Id typeId, TView nodeIds) { Check(!nodeIds.IsEmpty()); - const bool canEditBody = AST::HasFunctionBodies(ast, typeId); + const bool canEditBody = ast::HasFunctionBodies(ast, typeId); - AST::Id firstNodeId = nodeIds[0]; + ast::Id firstNodeId = nodeIds[0]; - if (nodeIds.Size() == 1 && ast.Has(firstNodeId)) + if (nodeIds.Size() == 1 && ast.Has(firstNodeId)) { if (canEditBody && UI::MenuItem("Add return node")) { - AST::Id newId = AST::AddReturn({ast, typeId}); + ast::Id newId = ast::AddReturn({ast, typeId}); if (!IsNone(newId)) { v2 position = ast.Get(firstNodeId).position; ast.Add(newId, position + v2{10.f, 0.f}); - AST::TryConnectStmt(ast, firstNodeId, newId); + ast::TryConnectStmt(ast, firstNodeId, newId); } } } - TArray calls = FindIdsWith(ast, nodeIds); + TArray calls = FindIdsWith(ast, nodeIds); if (!calls.IsEmpty() && UI::MenuItem("Refresh")) { - ast.AddN(calls); + ast.AddN(calls); } if (canEditBody && UI::MenuItem("Delete")) { - AST::RemoveNodes(ast, nodeIds); + ast::RemoveNodes(ast, nodeIds); } } - void DrawLinksContextMenu(AST::Tree& ast, AST::Id typeId, TView linkIds) + void DrawLinksContextMenu(ast::Tree& ast, ast::Id typeId, TView linkIds) { Check(!linkIds.IsEmpty()); - const bool canEditBody = AST::HasFunctionBodies(ast, typeId); + const bool canEditBody = ast::HasFunctionBodies(ast, typeId); - AST::Id firstLinkId = linkIds[0]; + ast::Id firstLinkId = linkIds[0]; if (canEditBody && UI::MenuItem("Delete")) { ScopedChange(ast, linkIds); - for (AST::Id linkId : linkIds) + for (ast::Id linkId : linkIds) { - AST::DisconnectExpr(ast, AST::GetExprInputFromPin(ast, firstLinkId)); - AST::DisconnectStmtLink(ast, firstLinkId); + ast::DisconnectExpr(ast, ast::GetExprInputFromPin(ast, firstLinkId)); + ast::DisconnectStmtLink(ast, firstLinkId); } } } - void DrawGraphContextMenu(AST::Tree& ast, AST::Id typeId) + void DrawGraphContextMenu(ast::Tree& ast, ast::Id typeId) { static ImGuiTextFilter filter; - const bool canEditBody = AST::HasFunctionBodies(ast, typeId); + const bool canEditBody = ast::HasFunctionBodies(ast, typeId); if (UI::IsWindowAppearing()) { @@ -153,12 +153,12 @@ namespace rift::Editor::Graph { if (ContextItem("Return", filter)) { - AST::Id newId = AST::AddReturn({ast, typeId}); + ast::Id newId = ast::AddReturn({ast, typeId}); SetPositionAndConnect(ast, newId, gridPos); } if (ContextItem("If", filter)) { - AST::Id newId = AST::AddIf({ast, typeId}); + ast::Id newId = ast::AddIf({ast, typeId}); SetPositionAndConnect(ast, newId, gridPos); } ContextTreePop(filter); @@ -167,17 +167,17 @@ namespace rift::Editor::Graph if (ContextTreeNode("Constructors", filter)) { String makeStr{}; - auto& typeList = ast.GetStatic(); - TAccess typesAccess{ast}; - for (Id typeId : FindAllIdsWith(typesAccess)) + auto& typeList = ast.GetStatic(); + TAccess typesAccess{ast}; + for (Id typeId : FindAllIdsWith(typesAccess)) { - if (auto* ns = typesAccess.TryGet(typeId)) + if (auto* ns = typesAccess.TryGet(typeId)) { makeStr.clear(); Strings::FormatTo(makeStr, "Make {}", ns->name); if (ContextItem(makeStr, filter)) { - AST::Id newId = AST::AddLiteral({ast, typeId}, typeId); + ast::Id newId = ast::AddLiteral({ast, typeId}, typeId); SetPositionAndConnect(ast, newId, gridPos); } } @@ -188,16 +188,16 @@ namespace rift::Editor::Graph if (ContextTreeNode("Functions", filter)) { static String label; - TAccess access{ast}; - for (AST::Id functionId : FindAllIdsWith(access)) + TAccess access{ast}; + for (ast::Id functionId : FindAllIdsWith(access)) { - Tag name = access.Get(functionId).name; + Tag name = access.Get(functionId).name; label.clear(); - AST::Id funcTypeId = p::GetIdParent(access, functionId); - if (!IsNone(funcTypeId) && access.Has(funcTypeId)) + ast::Id funcTypeId = p::GetIdParent(access, functionId); + if (!IsNone(funcTypeId) && access.Has(funcTypeId)) { Strings::FormatTo(label, "{} ({})", name, - access.Get(funcTypeId).name); + access.Get(funcTypeId).name); } else { @@ -205,7 +205,7 @@ namespace rift::Editor::Graph } if (ContextItem(label, filter)) { - AST::Id newId = AST::AddCall({ast, typeId}, functionId); + ast::Id newId = ast::AddCall({ast, typeId}, functionId); SetPositionAndConnect(ast, newId, gridPos); } } @@ -215,16 +215,16 @@ namespace rift::Editor::Graph if (ContextTreeNode("Variables", filter)) { static String label; - TAccess access{ast}; - for (AST::Id variableId : FindAllIdsWith(access)) + TAccess access{ast}; + for (ast::Id variableId : FindAllIdsWith(access)) { - Tag name = access.Get(variableId).name; + Tag name = access.Get(variableId).name; label.clear(); - AST::Id typeId = p::GetIdParent(access, variableId); - if (!IsNone(typeId) && access.Has(typeId)) + ast::Id typeId = p::GetIdParent(access, variableId); + if (!IsNone(typeId) && access.Has(typeId)) { Strings::FormatTo( - label, "{} ({})", name, access.Get(typeId).name); + label, "{} ({})", name, access.Get(typeId).name); } else { @@ -232,7 +232,7 @@ namespace rift::Editor::Graph } if (ContextItem(label, filter)) { - AST::Id newId = AST::AddDeclarationReference({ast, typeId}, variableId); + ast::Id newId = ast::AddDeclarationReference({ast, typeId}, variableId); SetPositionAndConnect(ast, newId, gridPos); } } @@ -243,7 +243,7 @@ namespace rift::Editor::Graph { static String name; // Unary operators - for (auto type : GetEnumValues()) + for (auto type : GetEnumValues()) { name.clear(); StringView shortName = GetUnaryOperatorName(type); @@ -251,12 +251,12 @@ namespace rift::Editor::Graph Strings::FormatTo(name, "{} ({})", shortName, longName); if (ContextItem(name, filter)) { - AST::Id newId = AST::AddUnaryOperator({ast, typeId}, type); + ast::Id newId = ast::AddUnaryOperator({ast, typeId}, type); SetPositionAndConnect(ast, newId, gridPos); } } // Binary operators - for (auto type : GetEnumValues()) + for (auto type : GetEnumValues()) { name.clear(); StringView shortName = GetBinaryOperatorName(type); @@ -264,7 +264,7 @@ namespace rift::Editor::Graph Strings::FormatTo(name, "{} ({})", shortName, longName); if (ContextItem(name, filter)) { - AST::Id newId = AST::AddBinaryOperator({ast, typeId}, type); + ast::Id newId = ast::AddBinaryOperator({ast, typeId}, type); SetPositionAndConnect(ast, newId, gridPos); } } @@ -275,7 +275,7 @@ namespace rift::Editor::Graph void DrawLinkContextMenu() {} void DrawContextMenu( - AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId, AST::Id hoveredLinkId) + ast::Tree& ast, ast::Id typeId, ast::Id hoveredNodeId, ast::Id hoveredLinkId) { if (UI::BeginPopup("ContextMenu")) { @@ -292,7 +292,7 @@ namespace rift::Editor::Graph } else if (!IsNone(hoveredLinkId)) { - TArray selectedLinkIds; + TArray selectedLinkIds; if (Nodes::GetSelectedLinks(selectedLinkIds)) { DrawLinksContextMenu(ast, typeId, selectedLinkIds); diff --git a/Libs/Editor/Src/Utils/ModuleUtils.cpp b/Libs/Editor/Src/Utils/ModuleUtils.cpp index cf5f57b6..f1022083 100644 --- a/Libs/Editor/Src/Utils/ModuleUtils.cpp +++ b/Libs/Editor/Src/Utils/ModuleUtils.cpp @@ -7,9 +7,9 @@ namespace rift::Editor { - void OpenModuleEditor(TAccessRef, AST::CModule> access, AST::Id id) + void OpenModuleEditor(TAccessRef, ast::CModule> access, ast::Id id) { - Check(access.Has(id)); + Check(access.Has(id)); if (auto* editor = access.TryGet(id)) { editor->pendingFocus = true; @@ -20,13 +20,13 @@ namespace rift::Editor } } - void CloseModuleEditor(TAccessRef, AST::CModule> access, AST::Id id) + void CloseModuleEditor(TAccessRef, ast::CModule> access, ast::Id id) { - Check(access.Has(id)); + Check(access.Has(id)); access.Remove(id); } - bool IsEditingModule(TAccessRef access, AST::Id id) + bool IsEditingModule(TAccessRef access, ast::Id id) { return access.Has(id); } diff --git a/Libs/Editor/Src/Utils/Nodes.cpp b/Libs/Editor/Src/Utils/Nodes.cpp index 9bf83807..8e48d1ee 100644 --- a/Libs/Editor/Src/Utils/Nodes.cpp +++ b/Libs/Editor/Src/Utils/Nodes.cpp @@ -389,7 +389,7 @@ namespace rift::Nodes // | | // ----------------------- - void DrawListAddNode(AST::Id nodeId) + void DrawListAddNode(ast::Id nodeId) { gNodes->NodeIdxToSubmissionIdx.SetInt( static_cast(GetIdIndex(nodeId)), gNodes->nodeSubmissionOrder.Size); @@ -429,7 +429,7 @@ namespace rift::Nodes gNodes->CanvasDrawList, foregroundChannelIdx); } - void DrawListActivateNodeBackground(AST::Id nodeId) + void DrawListActivateNodeBackground(ast::Id nodeId) { const i32 submissionIdx = gNodes->NodeIdxToSubmissionIdx.GetInt(static_cast(GetIdIndex(nodeId)), -1); @@ -461,7 +461,7 @@ namespace rift::Nodes gNodes->CanvasDrawList->_Splitter, lhsForegroundChannelIdx, rhsForegroundChannelIdx); } - void DrawListSortChannelsByDepth(const TArray& nodeDepthOrder) + void DrawListSortChannelsByDepth(const TArray& nodeDepthOrder) { if (gNodes->NodeIdxToSubmissionIdx.Data.Size < 2) { @@ -485,7 +485,7 @@ namespace rift::Nodes for (i32 depthIdx = startIdx; depthIdx > 0; --depthIdx) { - const AST::Id nodeId = nodeDepthOrder[depthIdx]; + const ast::Id nodeId = nodeDepthOrder[depthIdx]; // Find the current index of the nodeIdx in the submission order array i32 submissionIdx = -1; @@ -536,7 +536,7 @@ namespace rift::Nodes && gNodes->CanvasRectScreenSpace.Contains(ImGui::GetMousePos()); } - void BeginNodeSelection(EditorContext& editor, AST::Id nodeId) + void BeginNodeSelection(EditorContext& editor, ast::Id nodeId) { // Don't start selecting a node if we are e.g. already creating and dragging // a new link! New link creation can happen when the mouse is clicked over @@ -581,7 +581,7 @@ namespace rift::Nodes refOrigin + gNodes->CanvasOriginScreenSpace + editor.panning - gNodes->mousePosition; editor.SelectedNodeOrigins.clear(); - for (AST::Id id : editor.selectedNodeIds) + for (ast::Id id : editor.selectedNodeIds) { const v2 nodeOrigin = editor.nodes.Get(id).Origin - refOrigin; editor.SelectedNodeOrigins.push_back(nodeOrigin); @@ -722,7 +722,7 @@ namespace rift::Nodes // Test for overlap against node rectangles - for (AST::Id nodeId : editor.nodes) + for (ast::Id nodeId : editor.nodes) { NodeData& node = editor.nodes.Get(nodeId); if (boxRect.Overlaps(node.rect)) @@ -850,7 +850,7 @@ namespace rift::Nodes for (i32 i = 0; i < editor.selectedNodeIds.Size(); ++i) { const v2 nodeRel = editor.SelectedNodeOrigins[i]; - const AST::Id nodeId = editor.selectedNodeIds[i]; + const ast::Id nodeId = editor.selectedNodeIds[i]; NodeData& node = editor.nodes[nodeId]; if (node.Draggable) { @@ -885,8 +885,8 @@ namespace rift::Nodes if (gNodes->leftMouseReleased) { - TArray& depthStack = editor.nodes.depthOrder; - const TArray& selectedIds = editor.selectedNodeIds; + TArray& depthStack = editor.nodes.depthOrder; + const TArray& selectedIds = editor.selectedNodeIds; // Bump the selected node indices, in order, to the top of the depth stack. // NOTE: this algorithm has worst case time complexity of O(N^2), if the @@ -898,7 +898,7 @@ namespace rift::Nodes i32 numMoved = 0; for (i32 i = 0; i < depthStack.Size() - selectedIds.Size(); ++i) { - for (AST::Id nodeId = depthStack[i]; selectedIds.Contains(nodeId); + for (ast::Id nodeId = depthStack[i]; selectedIds.Contains(nodeId); nodeId = depthStack[i]) { depthStack.RemoveAt(i, false); @@ -1050,7 +1050,7 @@ namespace rift::Nodes void ResolveOccludedPins(const EditorContext& editor, ImVector& occludedPinIndices) { - const TArray& depthStack = editor.nodes.depthOrder; + const TArray& depthStack = editor.nodes.depthOrder; occludedPinIndices.resize(0); @@ -1131,11 +1131,11 @@ namespace rift::Nodes return {pinIdxWithSmallestDistance, type}; } - AST::Id ResolveHoveredNode(const TArray& depthStack) + ast::Id ResolveHoveredNode(const TArray& depthStack) { if (gNodes->nodeIdsOverlappingWithMouse.size() == 0) { - return AST::NoId; + return ast::NoId; } if (gNodes->nodeIdsOverlappingWithMouse.size() == 1) @@ -1144,9 +1144,9 @@ namespace rift::Nodes } i32 largestDepthIdx = -1; - AST::Id nodeIdOnTop = AST::NoId; + ast::Id nodeIdOnTop = ast::NoId; - for (AST::Id nodeId : gNodes->nodeIdsOverlappingWithMouse) + for (ast::Id nodeId : gNodes->nodeIdsOverlappingWithMouse) { for (i32 depthIdx = 0; depthIdx < depthStack.Size(); ++depthIdx) { @@ -1158,7 +1158,7 @@ namespace rift::Nodes } } - assert(nodeIdOnTop != AST::NoId); + assert(nodeIdOnTop != ast::NoId); return nodeIdOnTop; } @@ -1416,7 +1416,7 @@ namespace rift::Nodes DrawPinShape(pinData.position, pinData, pinColor); } - void DrawNode(EditorContext& editor, const AST::Id nodeId) + void DrawNode(EditorContext& editor, const ast::Id nodeId) { const NodeData& node = editor.nodes[nodeId]; ImGui::SetCursorPos(node.Origin + editor.panning); @@ -1525,7 +1525,7 @@ namespace rift::Nodes cubicBezier.numSegments); } - void BeginPin(const i32 id, const PinType type, const PinShape shape, AST::Id nodeId) + void BeginPin(const i32 id, const PinType type, const PinShape shape, ast::Id nodeId) { // Make sure to call BeginNode() before calling // BeginPin() @@ -1584,7 +1584,7 @@ namespace rift::Nodes context->currentScope = Scope::None; context->CurrentPinIdx = PinIdx::Invalid(); - context->currentNodeId = AST::NoId; + context->currentNodeId = ast::NoId; context->DefaultEditorCtx = EditorContextCreate(); SetEditorContext(gNodes->DefaultEditorCtx); @@ -1697,7 +1697,7 @@ namespace rift::Nodes editor.panning = pos; } - void MoveToNode(AST::Id nodeId, v2 offset) + void MoveToNode(ast::Id nodeId, v2 offset) { EditorContext& editor = GetEditorContext(); NodeData& node = editor.nodes.Get(nodeId); @@ -1861,7 +1861,7 @@ namespace rift::Nodes ObjectPoolReset(editor.outputs); ObjectPoolReset(editor.links); - gNodes->hoveredNodeId = AST::NoId; + gNodes->hoveredNodeId = ast::NoId; gNodes->HoveredLinkIdx.Reset(); gNodes->HoveredPinIdx = PinIdx::Invalid(); gNodes->DeletedLinkIdx.Reset(); @@ -1979,7 +1979,7 @@ namespace rift::Nodes } } - for (AST::Id nodeId : editor.nodes) + for (ast::Id nodeId : editor.nodes) { DrawListActivateNodeBackground(nodeId); DrawNode(editor, nodeId); @@ -2053,7 +2053,7 @@ namespace rift::Nodes // At this point, draw commands have been issued for all nodes (and pins). Update the // node pool to detect unused node slots and remove those indices from the depth stack // before sorting the node draw commands by depth. - for (AST::Id nodeId : editor.nodes) + for (ast::Id nodeId : editor.nodes) { auto& node = editor.nodes[nodeId]; node.inputs.clear(); @@ -2081,7 +2081,7 @@ namespace rift::Nodes ImGui::EndGroup(); } - void BeginNode(const AST::Id nodeId) + void BeginNode(const ast::Id nodeId) { // Remember to call BeginNodeEditor before calling BeginNode assert(gNodes->currentScope == Scope::Editor); @@ -2140,7 +2140,7 @@ namespace rift::Nodes } } - v2 GetNodeDimensions(AST::Id nodeId) + v2 GetNodeDimensions(ast::Id nodeId) { assert(!IsNone(nodeId)); EditorContext& editor = GetEditorContext(); @@ -2349,35 +2349,35 @@ namespace rift::Nodes } } - void SetNodeScreenSpacePos(AST::Id nodeId, const v2& screenSpacePos) + void SetNodeScreenSpacePos(ast::Id nodeId, const v2& screenSpacePos) { EditorContext& editor = GetEditorContext(); NodeData& node = editor.nodes.GetOrAdd(nodeId); node.Origin = ScreenToGridPosition(editor, screenSpacePos); } - void SetNodeEditorSpacePos(AST::Id nodeId, const v2& editorSpacePos) + void SetNodeEditorSpacePos(ast::Id nodeId, const v2& editorSpacePos) { EditorContext& editor = GetEditorContext(); NodeData& node = editor.nodes.GetOrAdd(nodeId); node.Origin = EditorToGridPosition(editor, editorSpacePos); } - void SetNodeGridSpacePos(AST::Id nodeId, const v2& gridPos) + void SetNodeGridSpacePos(ast::Id nodeId, const v2& gridPos) { EditorContext& editor = GetEditorContext(); NodeData& node = editor.nodes.GetOrAdd(nodeId); node.Origin = gridPos; } - void SetNodeDraggable(AST::Id nodeId, const bool draggable) + void SetNodeDraggable(ast::Id nodeId, const bool draggable) { EditorContext& editor = GetEditorContext(); NodeData& node = editor.nodes.GetOrAdd(nodeId); node.Draggable = draggable; } - v2 GetNodeScreenSpacePos(AST::Id nodeId) + v2 GetNodeScreenSpacePos(ast::Id nodeId) { assert(!IsNone(nodeId)); EditorContext& editor = GetEditorContext(); @@ -2385,7 +2385,7 @@ namespace rift::Nodes return GridToScreenPosition(editor, node.Origin); } - v2 GetNodeEditorSpacePos(AST::Id nodeId) + v2 GetNodeEditorSpacePos(ast::Id nodeId) { assert(!IsNone(nodeId)); EditorContext& editor = GetEditorContext(); @@ -2393,7 +2393,7 @@ namespace rift::Nodes return GridToEditorPosition(editor, node.Origin); } - v2 GetNodeGridSpacePos(AST::Id nodeId) + v2 GetNodeGridSpacePos(ast::Id nodeId) { assert(!IsNone(nodeId)); EditorContext& editor = GetEditorContext(); @@ -2406,34 +2406,34 @@ namespace rift::Nodes return IsMouseInCanvas(); } - AST::Id GetHoveredNode() + ast::Id GetHoveredNode() { return gNodes->hoveredNodeId; } - AST::Id GetHoveredLink() + ast::Id GetHoveredLink() { if (gNodes->HoveredLinkIdx.IsValid()) { const EditorContext& editor = GetEditorContext(); - return AST::Id(editor.links.pool[gNodes->HoveredLinkIdx.Value()].id); + return ast::Id(editor.links.pool[gNodes->HoveredLinkIdx.Value()].id); } - return AST::NoId; + return ast::NoId; } - bool IsNodeHovered(AST::Id nodeId) + bool IsNodeHovered(ast::Id nodeId) { assert(gNodes->currentScope != Scope::None); - return gNodes->hoveredNodeId == nodeId && gNodes->hoveredNodeId != AST::NoId; + return gNodes->hoveredNodeId == nodeId && gNodes->hoveredNodeId != ast::NoId; } - bool IsLinkHovered(AST::Id linkId) + bool IsLinkHovered(ast::Id linkId) { assert(gNodes->currentScope != Scope::None); const EditorContext& editor = GetEditorContext(); return gNodes->HoveredLinkIdx.IsValid() - && linkId == AST::Id(editor.links.pool[gNodes->HoveredLinkIdx.Value()].id); + && linkId == ast::Id(editor.links.pool[gNodes->HoveredLinkIdx.Value()].id); } bool IsPinHovered(Id* const pin) @@ -2465,20 +2465,20 @@ namespace rift::Nodes return editor.selectedLinkIndices.size(); } - const TArray& GetSelectedNodes() + const TArray& GetSelectedNodes() { const EditorContext& editor = GetEditorContext(); return editor.selectedNodeIds; } - bool GetSelectedLinks(TArray& linkIds) + bool GetSelectedLinks(TArray& linkIds) { const EditorContext& editor = GetEditorContext(); linkIds.Resize(editor.selectedLinkIndices.size()); for (i32 i = 0; i < editor.selectedLinkIndices.size(); ++i) { const i32 linkIdx = editor.selectedLinkIndices[i]; - linkIds[i] = AST::Id(editor.links.pool[linkIdx].id); + linkIds[i] = ast::Id(editor.links.pool[linkIdx].id); } return !linkIds.IsEmpty(); } @@ -2489,7 +2489,7 @@ namespace rift::Nodes editor.selectedNodeIds.Clear(); } - void ClearNodeSelection(AST::Id nodeId) + void ClearNodeSelection(ast::Id nodeId) { EditorContext& editor = GetEditorContext(); editor.selectedNodeIds.Remove(nodeId); @@ -2510,7 +2510,7 @@ namespace rift::Nodes editor.selectedLinkIndices.find_erase_unsorted(idx); } - void SelectNode(AST::Id nodeId) + void SelectNode(ast::Id nodeId) { EditorContext& editor = GetEditorContext(); editor.selectedNodeIds.AddUnique(nodeId); @@ -2525,7 +2525,7 @@ namespace rift::Nodes editor.selectedLinkIndices.push_back(idx); } - bool IsNodeSelected(AST::Id nodeId) + bool IsNodeSelected(ast::Id nodeId) { EditorContext& editor = GetEditorContext(); return editor.selectedNodeIds.Contains(nodeId); @@ -2651,7 +2651,7 @@ namespace rift::Nodes return false; } - bool IsLinkCreated(AST::Id& outputNodeId, Id& outputPinId, AST::Id& inputNodeId, Id& inputPinId, + bool IsLinkCreated(ast::Id& outputNodeId, Id& outputPinId, ast::Id& inputNodeId, Id& inputPinId, bool* createdFromSnap) { Check(gNodes->currentScope == Scope::None); diff --git a/Libs/Editor/Src/Utils/NodesMiniMap.cpp b/Libs/Editor/Src/Utils/NodesMiniMap.cpp index d77ec1ac..e1874d49 100644 --- a/Libs/Editor/Src/Utils/NodesMiniMap.cpp +++ b/Libs/Editor/Src/Utils/NodesMiniMap.cpp @@ -87,7 +87,7 @@ namespace rift::Nodes scaling = miniMapScaling; } - void MiniMap::DrawNode(EditorContext& editor, const AST::Id nodeId) + void MiniMap::DrawNode(EditorContext& editor, const ast::Id nodeId) { const NodeData& node = editor.nodes[nodeId]; @@ -199,7 +199,7 @@ namespace rift::Nodes } } - for (AST::Id nodeId : editor.nodes) + for (ast::Id nodeId : editor.nodes) { DrawNode(editor, nodeId); } diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 7017e01e..8486f102 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -10,7 +10,7 @@ namespace rift::Editor { - void DrawProjectManager(AST::Tree& ast) + void DrawProjectManager(ast::Tree& ast) { // Center modal when appearing UI::SetNextWindowPos(UI::GetMainViewport()->GetCenter(), ImGuiCond_Always, {0.5f, 0.5f}); diff --git a/Libs/Editor/Src/Utils/TypeUtils.cpp b/Libs/Editor/Src/Utils/TypeUtils.cpp index 836c36cc..12a11f0b 100644 --- a/Libs/Editor/Src/Utils/TypeUtils.cpp +++ b/Libs/Editor/Src/Utils/TypeUtils.cpp @@ -8,9 +8,9 @@ namespace rift::Editor { - void OpenType(TAccessRef, AST::CDeclType> access, AST::Id id) + void OpenType(TAccessRef, ast::CDeclType> access, ast::Id id) { - Check(access.Has(id)); + Check(access.Has(id)); if (auto* editor = access.TryGet(id)) { editor->pendingFocus = true; @@ -21,13 +21,13 @@ namespace rift::Editor } } - void CloseType(TAccessRef, AST::CDeclType> access, AST::Id id) + void CloseType(TAccessRef, ast::CDeclType> access, ast::Id id) { - Check(access.Has(id)); + Check(access.Has(id)); access.Remove(id); } - bool IsTypeOpen(TAccessRef access, AST::Id id) + bool IsTypeOpen(TAccessRef access, ast::Id id) { return access.Has(id); } diff --git a/Libs/Editor/Src/Utils/Widgets.cpp b/Libs/Editor/Src/Utils/Widgets.cpp index eb5d355b..a95dec39 100644 --- a/Libs/Editor/Src/Utils/Widgets.cpp +++ b/Libs/Editor/Src/Utils/Widgets.cpp @@ -7,12 +7,12 @@ namespace rift::Editor { - void ListTypesFromFilter(p::TAccessRef access, p::TArray typeIds, - AST::Id& selectedId, ImGuiTextFilter& searchFilter) + void ListTypesFromFilter(p::TAccessRef access, p::TArray typeIds, + ast::Id& selectedId, ImGuiTextFilter& searchFilter) { - for (AST::Id id : typeIds) + for (ast::Id id : typeIds) { - const auto& type = access.Get(id); + const auto& type = access.Get(id); p::StringView name = type.name.AsString(); if (!searchFilter.PassFilter(name.data(), name.data() + name.size())) @@ -29,18 +29,18 @@ namespace rift::Editor } } - bool TypeCombo(p::TAccessRef + bool TypeCombo(p::TAccessRef access, - p::StringView label, AST::Id& selectedId) + p::StringView label, ast::Id& selectedId) { p::Tag ownerName; if (!IsNone(selectedId)) { - ownerName = access.Get(selectedId).name; + ownerName = access.Get(selectedId).name; } - AST::Id lastId = selectedId; + ast::Id lastId = selectedId; if (UI::BeginCombo(label.data(), ownerName.AsString().data())) { static ImGuiTextFilter filter; @@ -52,11 +52,11 @@ namespace rift::Editor filter.Draw("##Filter"); auto nativeIds = - p::FindAllIdsWith(access); + p::FindAllIdsWith(access); auto structIds = - p::FindAllIdsWith(access); + p::FindAllIdsWith(access); auto classIds = - p::FindAllIdsWith(access); + p::FindAllIdsWith(access); if (filter.IsActive()) { if (UI::TreeNodeEx("Native##Filtered", ImGuiTreeNodeFlags_DefaultOpen)) @@ -98,7 +98,7 @@ namespace rift::Editor return selectedId != lastId; } - bool InputLiteralValue(AST::Tree& ast, p::StringView label, AST::Id literalId) + bool InputLiteralValue(ast::Tree& ast, p::StringView label, ast::Id literalId) { return false; } diff --git a/Tests/AST/Expressions.spec.cpp b/Tests/AST/Expressions.spec.cpp index 668cb109..134a0798 100644 --- a/Tests/AST/Expressions.spec.cpp +++ b/Tests/AST/Expressions.spec.cpp @@ -14,21 +14,21 @@ using namespace rift; go_bandit([]() { describe("AST.Expressions", []() { it("Initializes inputs & outputs correctly", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id id = AST::AddBinaryOperator({ast, AST::NoId}, AST::BinaryOperatorType::Div); - AssertThat(ast.Has(id), Equals(true)); - AssertThat(ast.Has(id), Equals(true)); - AssertThat(ast.Get(id).linkedOutputs.Size(), Equals(2)); - AssertThat(ast.Get(id).linkedOutputs.Size(), - Equals(ast.Get(id).pinIds.Size())); + ast::Id id = ast::AddBinaryOperator({ast, ast::NoId}, ast::BinaryOperatorType::Div); + AssertThat(ast.Has(id), Equals(true)); + AssertThat(ast.Has(id), Equals(true)); + AssertThat(ast.Get(id).linkedOutputs.Size(), Equals(2)); + AssertThat(ast.Get(id).linkedOutputs.Size(), + Equals(ast.Get(id).pinIds.Size())); - AST::Id id2 = AST::AddUnaryOperator({ast, AST::NoId}, AST::UnaryOperatorType::Not); - AssertThat(ast.Has(id2), Equals(true)); - AssertThat(ast.Has(id2), Equals(true)); - AssertThat(ast.Get(id2).linkedOutputs.Size(), Equals(1)); - AssertThat(ast.Get(id2).linkedOutputs.Size(), - Equals(ast.Get(id2).pinIds.Size())); + ast::Id id2 = ast::AddUnaryOperator({ast, ast::NoId}, ast::UnaryOperatorType::Not); + AssertThat(ast.Has(id2), Equals(true)); + AssertThat(ast.Has(id2), Equals(true)); + AssertThat(ast.Get(id2).linkedOutputs.Size(), Equals(1)); + AssertThat(ast.Get(id2).linkedOutputs.Size(), + Equals(ast.Get(id2).pinIds.Size())); }); }); }); diff --git a/Tests/AST/Namespaces.spec.cpp b/Tests/AST/Namespaces.spec.cpp index 75a9da27..ff9257a3 100644 --- a/Tests/AST/Namespaces.spec.cpp +++ b/Tests/AST/Namespaces.spec.cpp @@ -17,58 +17,58 @@ using namespace rift; go_bandit([]() { describe("AST.Namespaces", []() { it("Can get namespaces", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id functionId = AST::AddFunction({ast, AST::NoId}, "TestFunction"); + ast::Id functionId = ast::AddFunction({ast, ast::NoId}, "TestFunction"); AssertThat( - AST::GetNamespace(ast, functionId).ToString().c_str(), Equals("@TestFunction")); - AssertThat(AST::GetParentNamespace(ast, functionId).ToString().c_str(), Equals("")); + ast::GetNamespace(ast, functionId).ToString().c_str(), Equals("@TestFunction")); + AssertThat(ast::GetParentNamespace(ast, functionId).ToString().c_str(), Equals("")); - AST::Id classBId = AST::CreateType(ast, ASTModule::classType, "TestClass"); - AST::Id functionBId = AST::AddFunction({ast, classBId}, "TestFunction"); - AssertThat(AST::GetNamespace(ast, functionBId).ToString().c_str(), + ast::Id classBId = ast::CreateType(ast, ASTModule::classType, "TestClass"); + ast::Id functionBId = ast::AddFunction({ast, classBId}, "TestFunction"); + AssertThat(ast::GetNamespace(ast, functionBId).ToString().c_str(), Equals("@TestClass.TestFunction")); AssertThat( - AST::GetParentNamespace(ast, functionBId).ToString().c_str(), Equals("@TestClass")); + ast::GetParentNamespace(ast, functionBId).ToString().c_str(), Equals("@TestClass")); - AST::Id parentC = ast.Create(); - ast.Add(parentC); - ast.Add(parentC, AST::CNamespace{"SomeScope"}); - AST::Id classCId = AST::CreateType(ast, ASTModule::classType, "TestClass"); + ast::Id parentC = ast.Create(); + ast.Add(parentC); + ast.Add(parentC, ast::CNamespace{"SomeScope"}); + ast::Id classCId = ast::CreateType(ast, ASTModule::classType, "TestClass"); p::AttachId(ast, parentC, classCId); - AST::Id functionCId = AST::AddFunction({ast, classCId}, "TestFunction"); - AssertThat(AST::GetNamespace(ast, functionCId).ToString().c_str(), + ast::Id functionCId = ast::AddFunction({ast, classCId}, "TestFunction"); + AssertThat(ast::GetNamespace(ast, functionCId).ToString().c_str(), Equals("@SomeScope.TestClass.TestFunction")); - AssertThat(AST::GetParentNamespace(ast, functionCId).ToString().c_str(), + AssertThat(ast::GetParentNamespace(ast, functionCId).ToString().c_str(), Equals("@SomeScope.TestClass")); }); it("Can get local namespaces", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id parent = ast.Create(); - ast.Add(parent); - ast.Add(parent, AST::CNamespace{"SomeModule"}); - AST::Id classId = AST::CreateType(ast, ASTModule::classType, "TestClass"); + ast::Id parent = ast.Create(); + ast.Add(parent); + ast.Add(parent, ast::CNamespace{"SomeModule"}); + ast::Id classId = ast::CreateType(ast, ASTModule::classType, "TestClass"); p::AttachId(ast, parent, classId); - AST::Id functionId = AST::AddFunction({ast, classId}, "TestFunction"); - p::String ns = AST::GetNamespace(ast, functionId).ToString(true); + ast::Id functionId = ast::AddFunction({ast, classId}, "TestFunction"); + p::String ns = ast::GetNamespace(ast, functionId).ToString(true); AssertThat(ns.c_str(), Equals("TestClass.TestFunction")); }); it("Can initialize", [&]() { - AST::Namespace ns0{}; + ast::Namespace ns0{}; AssertThat(ns0.scopes[0].IsNone(), Equals(true)); AssertThat(ns0.Size(), Equals(0)); AssertThat(ns0.IsEmpty(), Equals(true)); - AST::Namespace ns1{"A"}; + ast::Namespace ns1{"A"}; AssertThat(ns1.scopes[0].AsString().data(), Equals("A")); AssertThat(ns1.scopes[1].IsNone(), Equals(true)); AssertThat(ns1.Size(), Equals(1)); AssertThat(ns1.IsEmpty(), Equals(false)); - AST::Namespace ns2{"A", "B"}; + ast::Namespace ns2{"A", "B"}; AssertThat(ns2.scopes[0].AsString().data(), Equals("A")); AssertThat(ns2.scopes[1].AsString().data(), Equals("B")); AssertThat(ns2.scopes[2].IsNone(), Equals(true)); @@ -77,19 +77,19 @@ go_bandit([]() { }); it("Can iterate", [&]() { - AST::Namespace ns0{}; + ast::Namespace ns0{}; for (const Tag& name : ns0) { Assert(); } - AST::Namespace ns1{"C"}; + ast::Namespace ns1{"C"}; for (const Tag& name : ns1) { AssertThat(name.AsString().data(), Equals("C")); } - AST::Namespace ns2{"A", "B"}; + ast::Namespace ns2{"A", "B"}; i32 i = 0; for (const Tag& name : ns2) { @@ -99,29 +99,29 @@ go_bandit([]() { }); it("Can find id from namespace", [&]() { - AST::Tree ast; - AST::Id parent = ast.Create(); - ast.Add(parent); - ast.Add(parent, AST::CNamespace{"A"}); + ast::Tree ast; + ast::Id parent = ast.Create(); + ast.Add(parent); + ast.Add(parent, ast::CNamespace{"A"}); - AST::Id classId = AST::CreateType(ast, ASTModule::classType, "B"); + ast::Id classId = ast::CreateType(ast, ASTModule::classType, "B"); p::AttachId(ast, parent, classId); - AST::Id class2Id = AST::CreateType(ast, ASTModule::classType, "B2"); + ast::Id class2Id = ast::CreateType(ast, ASTModule::classType, "B2"); p::AttachId(ast, parent, class2Id); - AST::Id functionId = AST::AddFunction({ast, classId}, "C"); - AST::Id function2Id = AST::AddFunction({ast, classId}, "C2"); + ast::Id functionId = ast::AddFunction({ast, classId}, "C"); + ast::Id function2Id = ast::AddFunction({ast, classId}, "C2"); - AssertThat(AST::FindIdFromNamespace(ast, {"A"}), Equals(parent)); - AssertThat(AST::FindIdFromNamespace(ast, {"A", "B"}), Equals(classId)); - AssertThat(AST::FindIdFromNamespace(ast, {"A", "B2"}), Equals(class2Id)); - AssertThat(AST::FindIdFromNamespace(ast, {"A", "B", "C"}), Equals(functionId)); - AssertThat(AST::FindIdFromNamespace(ast, {"A", "B", "C2"}), Equals(function2Id)); + AssertThat(ast::FindIdFromNamespace(ast, {"A"}), Equals(parent)); + AssertThat(ast::FindIdFromNamespace(ast, {"A", "B"}), Equals(classId)); + AssertThat(ast::FindIdFromNamespace(ast, {"A", "B2"}), Equals(class2Id)); + AssertThat(ast::FindIdFromNamespace(ast, {"A", "B", "C"}), Equals(functionId)); + AssertThat(ast::FindIdFromNamespace(ast, {"A", "B", "C2"}), Equals(function2Id)); - AssertThat(AST::FindIdFromNamespace(ast, {"N"}), Equals(AST::NoId)); - AssertThat(AST::FindIdFromNamespace(ast, {"A", "N"}), Equals(AST::NoId)); + AssertThat(ast::FindIdFromNamespace(ast, {"N"}), Equals(ast::NoId)); + AssertThat(ast::FindIdFromNamespace(ast, {"A", "N"}), Equals(ast::NoId)); }); }); }); diff --git a/Tests/AST/Statements.spec.cpp b/Tests/AST/Statements.spec.cpp index 9c7d8874..737dc69c 100644 --- a/Tests/AST/Statements.spec.cpp +++ b/Tests/AST/Statements.spec.cpp @@ -14,77 +14,77 @@ using namespace rift; go_bandit([]() { describe("AST.Statements", []() { it("Initializes outputs correctly", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id functionId = AST::AddFunction({ast, AST::NoId}, "TestFunction"); - AssertThat(ast.Has(functionId), Equals(true)); + ast::Id functionId = ast::AddFunction({ast, ast::NoId}, "TestFunction"); + AssertThat(ast.Has(functionId), Equals(true)); - AST::Id callId = AST::AddCall({ast, AST::NoId}, functionId); - AssertThat(ast.Has(callId), Equals(true)); + ast::Id callId = ast::AddCall({ast, ast::NoId}, functionId); + AssertThat(ast.Has(callId), Equals(true)); - AST::Id ifId = AST::AddIf({ast, AST::NoId}); - AssertThat(ast.Has(ifId), Equals(true)); - AssertThat(ast.Get(ifId).pinIds.Size(), Equals(2)); + ast::Id ifId = ast::AddIf({ast, ast::NoId}); + AssertThat(ast.Has(ifId), Equals(true)); + AssertThat(ast.Get(ifId).pinIds.Size(), Equals(2)); }); it("Initializes inputs correctly", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id functionId = AST::AddFunction({ast, AST::NoId}, "TestFunction"); - AssertThat(ast.Has(functionId), Equals(false)); + ast::Id functionId = ast::AddFunction({ast, ast::NoId}, "TestFunction"); + AssertThat(ast.Has(functionId), Equals(false)); - AST::Id callId = AST::AddCall({ast, AST::NoId}, functionId); - AssertThat(ast.Has(callId), Equals(true)); + ast::Id callId = ast::AddCall({ast, ast::NoId}, functionId); + AssertThat(ast.Has(callId), Equals(true)); - AST::Id ifId = AST::AddIf({ast, AST::NoId}); - AssertThat(ast.Has(ifId), Equals(true)); + ast::Id ifId = ast::AddIf({ast, ast::NoId}); + AssertThat(ast.Has(ifId), Equals(true)); }); it("Can connect with single output", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id functionId = AST::AddFunction({ast, AST::NoId}, "TestFunction"); - AST::Id callId = AST::AddCall({ast, AST::NoId}, functionId); - AST::Id ifId = AST::AddIf({ast, AST::NoId}); + ast::Id functionId = ast::AddFunction({ast, ast::NoId}, "TestFunction"); + ast::Id callId = ast::AddCall({ast, ast::NoId}, functionId); + ast::Id ifId = ast::AddIf({ast, ast::NoId}); - AssertThat(AST::TryConnectStmt(ast, functionId, callId), Equals(true)); + AssertThat(ast::TryConnectStmt(ast, functionId, callId), Equals(true)); // Can't connect to self - AssertThat(AST::TryConnectStmt(ast, functionId, functionId), Equals(false)); + AssertThat(ast::TryConnectStmt(ast, functionId, functionId), Equals(false)); // Can't connect in loops - AssertThat(AST::TryConnectStmt(ast, callId, ifId), Equals(true)); - AssertThat(AST::TryConnectStmt(ast, ifId, callId), Equals(false)); + AssertThat(ast::TryConnectStmt(ast, callId, ifId), Equals(true)); + AssertThat(ast::TryConnectStmt(ast, ifId, callId), Equals(false)); // Can replace a connection - AssertThat(AST::TryConnectStmt(ast, functionId, ifId), Equals(true)); + AssertThat(ast::TryConnectStmt(ast, functionId, ifId), Equals(true)); }); it("Can connect with multiple outputs", [&]() { - AST::Tree ast; + ast::Tree ast; - AST::Id functionId = AST::AddFunction({ast, AST::NoId}, "TestFunction"); + ast::Id functionId = ast::AddFunction({ast, ast::NoId}, "TestFunction"); - AST::Id ifId = AST::AddIf({ast, AST::NoId}); - AST::Id call1Id = AST::AddCall({ast, AST::NoId}, functionId); - AST::Id call2Id = AST::AddCall({ast, AST::NoId}, functionId); + ast::Id ifId = ast::AddIf({ast, ast::NoId}); + ast::Id call1Id = ast::AddCall({ast, ast::NoId}, functionId); + ast::Id call2Id = ast::AddCall({ast, ast::NoId}, functionId); AssertThat( - AST::TryConnectStmt(ast, ast.Get(ifId).pinIds[0], call2Id), + ast::TryConnectStmt(ast, ast.Get(ifId).pinIds[0], call2Id), Equals(true)); - AssertThat(ast.Get(ifId).linkInputNodes[0], Equals(call2Id)); + AssertThat(ast.Get(ifId).linkInputNodes[0], Equals(call2Id)); // Can replace a connection AssertThat( - AST::TryConnectStmt(ast, ast.Get(ifId).pinIds[0], call1Id), + ast::TryConnectStmt(ast, ast.Get(ifId).pinIds[0], call1Id), Equals(true)); - AssertThat(ast.Get(ifId).linkInputNodes[0], Equals(call1Id)); + AssertThat(ast.Get(ifId).linkInputNodes[0], Equals(call1Id)); // Can connect to a different pin AssertThat( - AST::TryConnectStmt(ast, ast.Get(ifId).pinIds[1], call2Id), + ast::TryConnectStmt(ast, ast.Get(ifId).pinIds[1], call2Id), Equals(true)); - AssertThat(ast.Get(ifId).linkInputNodes[1], Equals(call2Id)); + AssertThat(ast.Get(ifId).linkInputNodes[1], Equals(call2Id)); }); }); }); diff --git a/Tests/Project.spec.cpp b/Tests/Project.spec.cpp index df168573..e3ac75d5 100644 --- a/Tests/Project.spec.cpp +++ b/Tests/Project.spec.cpp @@ -37,23 +37,23 @@ go_bandit([]() { }); it("Can load empty descriptor", [&]() { - files::SaveStringFile(p::JoinPaths(testProjectPath, AST::moduleFilename), "{}"); + files::SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); - AST::Tree ast; - bool result = AST::OpenProject(ast, testProjectPath); + ast::Tree ast; + bool result = ast::OpenProject(ast, testProjectPath); AssertThat(result, Equals(true)); - AssertThat(AST::HasProject(ast), Equals(true)); + AssertThat(ast::HasProject(ast), Equals(true)); }); it("Project name equals the folder", [&]() { - files::SaveStringFile(p::JoinPaths(testProjectPath, AST::moduleFilename), "{}"); + files::SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); - AST::Tree ast; - bool result = AST::OpenProject(ast, testProjectPath); + ast::Tree ast; + bool result = ast::OpenProject(ast, testProjectPath); AssertThat(result, Equals(true)); - AssertThat(AST::HasProject(ast), Equals(true)); + AssertThat(ast::HasProject(ast), Equals(true)); - StringView projectName = AST::GetProjectName(ast).AsString(); + StringView projectName = ast::GetProjectName(ast).AsString(); AssertThat(projectName, Equals("TestProject")); }); @@ -61,14 +61,14 @@ go_bandit([]() { // the file it("Project name can be overriden", [&]() { files::SaveStringFile( - p::JoinPaths(testProjectPath, AST::moduleFilename), "{\"name\": \"SomeProject\"}"); + p::JoinPaths(testProjectPath, ast::moduleFilename), "{\"name\": \"SomeProject\"}"); - AST::Tree ast; - bool result = AST::OpenProject(ast, testProjectPath); + ast::Tree ast; + bool result = ast::OpenProject(ast, testProjectPath); AssertThat(result, Equals(true)); - AssertThat(AST::HasProject(ast), Equals(true)); + AssertThat(ast::HasProject(ast), Equals(true)); - StringView projectName = AST::GetProjectName(ast).AsString(); + StringView projectName = ast::GetProjectName(ast).AsString(); AssertThat(projectName, Equals("SomeProject")); }); }); From 022acca3b5d9873a5d72a1c3f7de6c0ed23444d3 Mon Sep 17 00:00:00 2001 From: muit Date: Thu, 1 Feb 2024 23:37:33 +0100 Subject: [PATCH 19/52] Elements panel improvements --- Examples/Project/Main.rf | 49 +++++++++++ Examples/Project/Welcome.rf | 4 +- .../MIR/Compiler/Src/MIRBackendModule.cpp | 5 ++ Libs/Editor/Src/Utils/ElementsPanel.cpp | 84 ++++++++++++++----- 4 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 Examples/Project/Main.rf diff --git a/Examples/Project/Main.rf b/Examples/Project/Main.rf new file mode 100644 index 00000000..22362c41 --- /dev/null +++ b/Examples/Project/Main.rf @@ -0,0 +1,49 @@ +{ + "type": "Static", + "count": 4, + "components": { + "CChild": { + "0": -1, + "1": 0, + "2": 0, + "3": 0 + }, + "CDeclVariable": { + "2": {} + }, + "CDeclFunction": { + "1": {}, + "3": {} + }, + "CNodePosition": { + "1": { + "x": 0.0, + "y": 0.0 + }, + "3": { + "x": 0.0, + "y": 3.0 + } + }, + "CNamespace": { + "0": "Main", + "1": "Main", + "2": "NewVariable", + "3": "NewFunction" + }, + "CParent": { + "0": [ + 1, + 2, + 3 + ], + "1": [], + "2": [], + "3": [] + }, + "CStmtOutput": { + "1": -1, + "3": -1 + } + } +} \ No newline at end of file diff --git a/Examples/Project/Welcome.rf b/Examples/Project/Welcome.rf index 2fc8d84b..51cf7927 100644 --- a/Examples/Project/Welcome.rf +++ b/Examples/Project/Welcome.rf @@ -119,10 +119,10 @@ "U32" ], "10": [ - "String" + "I64" ], "11": [ - "String" + "I64" ] }, "CNodePosition": { diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 2092503e..06c2876d 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -234,6 +234,11 @@ namespace rift { MIR::GenerateC(compiler); + if (compiler.HasErrors()) + { + return; + } + MIR_context* ctx = MIR_init(); MIR::CToMIR(compiler, ctx); diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 3706f9f1..32165933 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -25,6 +25,48 @@ namespace rift::Editor { // using namespace EnumOperators; + bool CollapsingHeaderWithButton(p::StringView label, bool* add, ImGuiTreeNodeFlags flags) + { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(label.data()); + flags |= ImGuiTreeNodeFlags_CollapsingHeader; + if (add) + flags |= + ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool is_open = ImGui::TreeNodeBehavior(id, flags, label.data()); + if (add != nullptr) + { + // Create a small overlapping close button + // FIXME: We can evolve this into user accessible helpers to add extra buttons on title + // bars, headers, etc. + // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. + ImGuiContext& g = *GImGui; + ImGuiLastItemData last_item_backup = g.LastItemData; + UI::PushID(id); + const float widthAvailable = + ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; + ImGui::SameLine(widthAvailable - 25.f); + UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.f); + UI::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f)); + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + if (ImGui::ButtonEx( + ICON_FA_PLUS, ImVec2(18.f, 14.f), ImGuiButtonFlags_AlignTextBaseLine)) + { + *add = true; + } + g.Style.FramePadding.y = backup_padding_y; + UI::PopStyleVar(2); + UI::PopID(); + g.LastItemData = last_item_backup; + } + + return is_open; + } + void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, ast::Id variableId) { auto* ns = access.TryGet(variableId); @@ -140,7 +182,7 @@ namespace rift::Editor } UI::PushHeaderColor(callColor); - UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.f); + UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.f); static String headerId; headerId.clear(); Strings::FormatTo(headerId, "{}###{}", name, id); @@ -173,7 +215,8 @@ namespace rift::Editor void DrawVariables(TVariableAccessRef access, ast::TransactionAccess transAccess, CTypeEditor& editor, ast::Id typeId) { - if (UI::CollapsingHeader("Variables", ImGuiTreeNodeFlags_DefaultOpen)) + bool add = false; + if (CollapsingHeaderWithButton("Variables", &add, ImGuiTreeNodeFlags_DefaultOpen)) { UI::Indent(10.f); TArray variableIds; @@ -198,26 +241,24 @@ namespace rift::Editor } UI::EndTable(); } - - UI::PushStyleCompact(); - if (UI::Button(ICON_FA_PLUS "##Variable", ImVec2(-FLT_MIN, 0.0f))) - { - ScopedChange(transAccess, typeId); - ast::AddVariable( - {static_cast(access.GetContext()), typeId}, "NewVariable"); - } - UI::PopStyleCompact(); UI::Unindent(10.f); UI::Dummy(ImVec2(0.0f, 10.0f)); } + + if (add) + { + ScopedChange(transAccess, typeId); + ast::AddVariable({static_cast(access.GetContext()), typeId}, "NewVariable"); + } } void DrawFunctions(ast::Tree& ast, CTypeEditor& editor, ast::Id typeId) { - const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen - | ImGuiTreeNodeFlags_AllowItemOverlap - | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; - if (UI::CollapsingHeader("Functions", flags)) + const ImGuiTreeNodeFlags flags = + ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowItemOverlap; + + bool add = false; + if (CollapsingHeaderWithButton("Functions", &add, flags)) { UI::Indent(10.f); @@ -229,16 +270,15 @@ namespace rift::Editor DrawFunction(ast, editor, typeId, functionId); } - UI::PushStyleCompact(); - if (UI::Button(ICON_FA_PLUS "##Function", ImVec2(-FLT_MIN, 0.0f))) - { - ScopedChange(ast, typeId); - ast::AddFunction({ast, typeId}, "NewFunction"); - } - UI::PopStyleCompact(); UI::Unindent(10.f); UI::Dummy(ImVec2(0.0f, 10.0f)); } + + if (add) + { + ScopedChange(ast, typeId); + ast::AddFunction({ast, typeId}, "NewFunction"); + } } void DrawElementsPanel(ast::Tree& ast, ast::Id typeId) From f9df66a0f869503ac78a5d59582ae8578845e6e4 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 3 Feb 2024 00:43:08 +0100 Subject: [PATCH 20/52] Multiple UI and AST fixes --- Extern/Pipe | 2 +- Libs/AST/Src/AST/Utils/Expressions.cpp | 4 +- .../MIR/Compiler/Src/IRGeneration.cpp | 1 + Libs/Editor/Src/Utils/DetailsPanel.cpp | 68 ++++++++++--------- Libs/Editor/Src/Utils/ElementsPanel.cpp | 61 +++-------------- .../Src/Utils/FunctionGraphContextMenu.cpp | 11 ++- Libs/UI/Include/UI/Widgets.h | 6 ++ Libs/UI/Src/Widgets.cpp | 51 ++++++++++++++ 8 files changed, 111 insertions(+), 93 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index aa56c609..1a3a62eb 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit aa56c60974191d813dcdb44e5fd8198d89e8176c +Subproject commit 1a3a62ebc936f80449b25a39bb9daa823573ca74 diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index 62da6842..2d616a15 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -123,9 +123,7 @@ namespace rift::ast auto& inputs = ast.Get(input.nodeId); // Find pin index - const i32 index = inputs.pinIds.FindIndex([&input](Id pinId) { - return input.pinId == pinId; - }); + const i32 index = inputs.pinIds.FindIndex(input.pinId); if (index != NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) [[likely]] { ExprOutput& linked = inputs.linkedOutputs[index]; diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 3a8a9a2a..e8d7e054 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -77,6 +77,7 @@ namespace rift::MIR mainFunctionId = FindMainFunction(staticFunctionIds); CreateMain(mainFunctionId); } + p::Info(*code); } void CGenerator::BindNativeTypes() diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index bb77f486..f8b67b70 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -25,6 +25,11 @@ namespace rift::Editor { void EditFunctionPin(ast::Tree& ast, ast::Id ownerId, ast::Id id) { + if (!ast.IsValid(id)) + { + return; + } + auto* ns = ast.TryGet(id); auto* type = ast.TryGet(id); if (!ns || !type) @@ -114,7 +119,8 @@ namespace rift::Editor String functionName{ns->name.AsString()}; UI::SetNextItemWidth(UI::GetContentRegionAvail().x); - if (UI::InputText("##name", functionName, ImGuiInputTextFlags_AutoSelectAll)) + if (UI::InputTextWithHint( + "##name", "name...", functionName, ImGuiInputTextFlags_AutoSelectAll)) { Id sameNameFuncId = ast::FindChildByName(ast, typeId, Tag{functionName}); if (!IsNone(sameNameFuncId) && id != sameNameFuncId) @@ -131,58 +137,58 @@ namespace rift::Editor } UI::Spacing(); - UI::Text("Inputs"); - if (UI::BeginTable("##fields", 2, ImGuiTableFlags_SizingFixedFit)) + bool addInput = false; + if (UI::CollapsingHeaderWithButton( + "Inputs", ImGuiTreeNodeFlags_DefaultOpen, addInput, ICON_FA_PLUS)) { - UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); - UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); - if (const auto* exprOutputs = ast.TryGet(id)) + UI::Indent(); + if (UI::BeginTable("##fields", 2, ImGuiTableFlags_SizingFixedFit)) { - for (ast::Id pinId : exprOutputs->pinIds) + UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); + UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); + if (const auto* exprOutputs = ast.TryGet(id)) { - EditFunctionPin(ast, id, pinId); + for (ast::Id pinId : exprOutputs->pinIds) + { + EditFunctionPin(ast, id, pinId); + } } + UI::EndTable(); } - UI::EndTable(); + UI::Unindent(); } - UI::PushStyleCompact(); - UI::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.5f}); - UI::SetNextItemWidth(UI::GetContentRegionAvail().x); - if (UI::Selectable(ICON_FA_PLUS "##AddInput")) + if (addInput) { ScopedChange(ast, id); ast::AddFunctionInput(ast, id); } - UI::HelpTooltip("Adds a new input parameter to a function"); - UI::PopStyleVar(); - UI::PopStyleCompact(); UI::Spacing(); - UI::Text("Outputs"); - if (UI::BeginTable("##fields", 2, ImGuiTableFlags_SizingFixedFit)) + bool addOutput = false; + if (UI::CollapsingHeaderWithButton( + "Outputs", ImGuiTreeNodeFlags_DefaultOpen, addOutput, ICON_FA_PLUS)) { - UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); - UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); - if (const auto* exprInputs = ast.TryGet(id)) + UI::Indent(); + if (UI::BeginTable("##fields", 2, ImGuiTableFlags_SizingFixedFit)) { - for (ast::Id pinId : exprInputs->pinIds) + UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.9f); + UI::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 1.f); + if (const auto* exprInputs = ast.TryGet(id)) { - EditFunctionPin(ast, id, pinId); + for (ast::Id pinId : exprInputs->pinIds) + { + EditFunctionPin(ast, id, pinId); + } } + UI::EndTable(); } - UI::EndTable(); + UI::Unindent(); } - UI::PushStyleCompact(); - UI::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f)); - UI::SetNextItemWidth(UI::GetContentRegionAvail().x); - if (UI::Selectable(ICON_FA_PLUS "##AddOutput")) + if (addOutput) { ScopedChange(ast, id); ast::AddFunctionOutput(ast, id); } - UI::HelpTooltip("Adds a new output parameter to a function"); - UI::PopStyleVar(); - UI::PopStyleCompact(); UI::Spacing(); } diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 32165933..3e734d4d 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -23,50 +23,6 @@ namespace rift::Editor { - // using namespace EnumOperators; - - bool CollapsingHeaderWithButton(p::StringView label, bool* add, ImGuiTreeNodeFlags flags) - { - ImGuiWindow* window = ImGui::GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiID id = window->GetID(label.data()); - flags |= ImGuiTreeNodeFlags_CollapsingHeader; - if (add) - flags |= - ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; - bool is_open = ImGui::TreeNodeBehavior(id, flags, label.data()); - if (add != nullptr) - { - // Create a small overlapping close button - // FIXME: We can evolve this into user accessible helpers to add extra buttons on title - // bars, headers, etc. - // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. - ImGuiContext& g = *GImGui; - ImGuiLastItemData last_item_backup = g.LastItemData; - UI::PushID(id); - const float widthAvailable = - ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; - ImGui::SameLine(widthAvailable - 25.f); - UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.f); - UI::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f)); - float backup_padding_y = g.Style.FramePadding.y; - g.Style.FramePadding.y = 0.0f; - if (ImGui::ButtonEx( - ICON_FA_PLUS, ImVec2(18.f, 14.f), ImGuiButtonFlags_AlignTextBaseLine)) - { - *add = true; - } - g.Style.FramePadding.y = backup_padding_y; - UI::PopStyleVar(2); - UI::PopID(); - g.LastItemData = last_item_backup; - } - - return is_open; - } - void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, ast::Id variableId) { auto* ns = access.TryGet(variableId); @@ -203,11 +159,11 @@ namespace rift::Editor if (ImGui::BeginPopupContextItem()) { - Graph::DrawNodesContextMenu(ast, typeId, id); if (UI::MenuItem("Show in Graph")) { Nodes::MoveToNode(id, v2{150.f, 150.f}); } + Graph::DrawNodesContextMenu(ast, typeId, id); ImGui::EndPopup(); } } @@ -216,9 +172,10 @@ namespace rift::Editor CTypeEditor& editor, ast::Id typeId) { bool add = false; - if (CollapsingHeaderWithButton("Variables", &add, ImGuiTreeNodeFlags_DefaultOpen)) + if (UI::CollapsingHeaderWithButton( + "Variables", ImGuiTreeNodeFlags_DefaultOpen, add, ICON_FA_PLUS)) { - UI::Indent(10.f); + UI::Indent(); TArray variableIds; p::GetIdChildren(access, typeId, variableIds); ExcludeIdsWithout(access, variableIds); @@ -241,7 +198,7 @@ namespace rift::Editor } UI::EndTable(); } - UI::Unindent(10.f); + UI::Unindent(); UI::Dummy(ImVec2(0.0f, 10.0f)); } @@ -258,9 +215,9 @@ namespace rift::Editor ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowItemOverlap; bool add = false; - if (CollapsingHeaderWithButton("Functions", &add, flags)) + if (UI::CollapsingHeaderWithButton("Functions", flags, add, ICON_FA_PLUS)) { - UI::Indent(10.f); + UI::Indent(); TArray functionIds; p::GetIdChildren(ast, typeId, functionIds); @@ -270,7 +227,7 @@ namespace rift::Editor DrawFunction(ast, editor, typeId, functionId); } - UI::Unindent(10.f); + UI::Unindent(); UI::Dummy(ImVec2(0.0f, 10.0f)); } @@ -294,7 +251,7 @@ namespace rift::Editor if (UI::Begin(windowName.c_str(), &editor.showElements)) { UI::SetNextItemWidth(UI::GetContentRegionAvail().x); - editor.elementsFilter.Draw("##filter"); + UI::DrawFilterWithHint(editor.elementsFilter, "##filter", "Search..."); if (ast::HasVariables(ast, typeId)) { diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index 235dc990..1c332b39 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -84,8 +84,12 @@ namespace rift::Editor::Graph Check(!nodeIds.IsEmpty()); const bool canEditBody = ast::HasFunctionBodies(ast, typeId); - ast::Id firstNodeId = nodeIds[0]; + if (canEditBody && UI::MenuItem("Delete")) + { + ast::RemoveNodes(ast, nodeIds); + } + ast::Id firstNodeId = nodeIds[0]; if (nodeIds.Size() == 1 && ast.Has(firstNodeId)) { if (canEditBody && UI::MenuItem("Add return node")) @@ -105,11 +109,6 @@ namespace rift::Editor::Graph { ast.AddN(calls); } - - if (canEditBody && UI::MenuItem("Delete")) - { - ast::RemoveNodes(ast, nodeIds); - } } void DrawLinksContextMenu(ast::Tree& ast, ast::Id typeId, TView linkIds) diff --git a/Libs/UI/Include/UI/Widgets.h b/Libs/UI/Include/UI/Widgets.h index 3642e7a1..c79a5152 100644 --- a/Libs/UI/Include/UI/Widgets.h +++ b/Libs/UI/Include/UI/Widgets.h @@ -114,4 +114,10 @@ namespace rift::UI void HelpTooltip(p::StringView text, float delay = 1.f); void HelpMarker(p::StringView text); + + bool DrawFilterWithHint(ImGuiTextFilter& filter, const char* label = "Filter (inc,-exc)", + const char* hint = "...", float width = 0.0f); + + bool CollapsingHeaderWithButton(p::StringView label, ImGuiTreeNodeFlags flags, + bool& buttonClicked, p::StringView buttonLabel, p::v2 buttonSize = p::v2(18.f, 14.f)); } // namespace rift::UI diff --git a/Libs/UI/Src/Widgets.cpp b/Libs/UI/Src/Widgets.cpp index 11dc7ec2..dc45a30e 100644 --- a/Libs/UI/Src/Widgets.cpp +++ b/Libs/UI/Src/Widgets.cpp @@ -212,4 +212,55 @@ namespace rift::UI ImGui::TextDisabled(ICON_FA_QUESTION_CIRCLE); HelpTooltip(text, 0.f); } + + bool DrawFilterWithHint( + ImGuiTextFilter& filter, const char* label, const char* hint, float width) + { + if (width != 0.0f) + ImGui::SetNextItemWidth(width); + bool value_changed = + ImGui::InputTextWithHint(label, hint, filter.InputBuf, IM_ARRAYSIZE(filter.InputBuf)); + if (value_changed) + filter.Build(); + return value_changed; + } + + bool CollapsingHeaderWithButton(p::StringView label, ImGuiTreeNodeFlags flags, + bool& buttonClicked, p::StringView buttonLabel, p::v2 buttonSize) + { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(label.data()); + flags |= ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_AllowOverlap + | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool isOpen = ImGui::TreeNodeBehavior(id, flags, label.data()); + + + // Create a small overlapping close button + // FIXME: We can evolve this into user accessible helpers to add extra buttons on title + // bars, headers, etc. + // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. + ImGuiContext& g = *GImGui; + ImGuiLastItemData last_item_backup = g.LastItemData; + UI::PushID(id); + const float widthAvailable = + ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; + ImGui::SameLine(widthAvailable - 25.f); + UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.f); + UI::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f)); + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + if (ImGui::ButtonEx(buttonLabel.data(), buttonSize, ImGuiButtonFlags_AlignTextBaseLine)) + { + buttonClicked = true; + } + g.Style.FramePadding.y = backup_padding_y; + UI::PopStyleVar(2); + UI::PopID(); + g.LastItemData = last_item_backup; + + return isOpen; + } } // namespace rift::UI From 327d898a13beb93c1b9b75cb85d3d75c0c840aff Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 3 Feb 2024 19:42:24 +0100 Subject: [PATCH 21/52] Watch for changes in project folder --- Examples/Project/newtype.rf | 9 +++++++++ Extern/Pipe | 2 +- Libs/Editor/Include/Editor.h | 5 +++++ Libs/Editor/Include/Statics/SEditor.h | 1 - Libs/Editor/Src/Editor.cpp | 19 ++++++++++++++++--- 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 Examples/Project/newtype.rf diff --git a/Examples/Project/newtype.rf b/Examples/Project/newtype.rf new file mode 100644 index 00000000..d6195007 --- /dev/null +++ b/Examples/Project/newtype.rf @@ -0,0 +1,9 @@ +{ + "type": "Class", + "count": 1, + "components": { + "CNamespace": { + "0": "newtype" + } + } +} \ No newline at end of file diff --git a/Extern/Pipe b/Extern/Pipe index 1a3a62eb..34786232 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 1a3a62ebc936f80449b25a39bb9daa823573ca74 +Subproject commit 34786232399ac76bcdea827c3cbd14ce26e45cff diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index 767070b8..74cab53e 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -1,6 +1,8 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once +#include "Pipe/Files/FileWatcher.h" + #include #include #include @@ -19,7 +21,10 @@ namespace rift::Editor ast::Tree ast; + FileWatcher fileWatcher; + public: + bool bFilesDirty = true; #if P_DEBUG bool showDemo = false; bool showMetrics = false; diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index ad165b45..578b7af0 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -29,7 +29,6 @@ namespace rift::Editor String currentProjectPath; TArray pendingTypesToClose; - FileWatcher fileWatcher; FileExplorerPanel fileExplorer{}; ReflectionDebugger reflectionDebugger; diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 3c899a34..d7666cc8 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -56,7 +56,7 @@ namespace rift::Editor int Editor::Run(StringView projectPath) { - FileWatcher::StartAsync(); + fileWatcher.StartAsync(); // Setup window p::Info("Initializing editor..."); @@ -102,7 +102,11 @@ namespace rift::Editor ast::FunctionsSystem::ClearAddedTags(ast); ast::TransactionSystem::ClearTags(ast); - ast::LoadSystem::Run(ast); + if (bFilesDirty) + { + ast::LoadSystem::Run(ast); + bFilesDirty = false; + } ast::FunctionsSystem::ResolveCallFunctionIds(ast); ast::TypeSystem::ResolveExprTypeIds(ast); @@ -157,7 +161,16 @@ namespace rift::Editor { ast.SetStatic(); EditorSystem::Init(ast); - SetUIConfigFile(p::JoinPaths(ast::GetProjectPath(ast), "Saved/UI.ini")); + auto projectPath = ast::GetProjectPath(ast); + SetUIConfigFile(p::JoinPaths(projectPath, "Saved/UI.ini")); + + // Start watching the project folder for file changes + ast.Add(GetProjectId(ast), fileWatcher.ListenPath(projectPath, true, + [](StringView path, StringView filename, + FileWatchAction action, StringView oldFilename) { + Editor::Get().bFilesDirty = true; + })); + return true; } return false; From ddd2311c36d311266926c1b1ab4a50b09073cbaa Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 3 Feb 2024 19:55:36 +0100 Subject: [PATCH 22/52] Stop watching project folder on close --- Extern/Pipe | 2 +- Libs/Editor/Include/Editor.h | 14 ++++++------ Libs/Editor/Src/Editor.cpp | 13 +++++++++++ Libs/Editor/Src/Systems/EditorSystem.cpp | 2 +- Libs/Editor/Src/Utils/ProjectManager.cpp | 28 ++++++++++++------------ 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 34786232..652a0ece 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 34786232399ac76bcdea827c3cbd14ce26e45cff +Subproject commit 652a0eced0b5552fe80d40f79ba1c5e3d1c92292 diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index 74cab53e..bdf10b29 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -10,18 +10,16 @@ namespace rift::Editor { - using namespace p; - class Editor { - FrameTime frameTime; + p::FrameTime frameTime; bool configFileChanged = false; - String configFile; + p::String configFile; ast::Tree ast; - FileWatcher fileWatcher; + p::FileWatcher fileWatcher; public: bool bFilesDirty = true; @@ -37,11 +35,11 @@ namespace rift::Editor ~Editor(); - int Run(StringView projectPath = {}); + int Run(p::StringView projectPath = {}); void Tick(); - void SetUIConfigFile(Path path); + void SetUIConfigFile(p::Path path); static Editor& Get() { @@ -56,7 +54,9 @@ namespace rift::Editor bool CreateProject(p::StringView path, bool closeFirst = true); bool OpenProject(p::StringView path, bool closeFirst = true); + void CloseProject(); + // Close the editor void Close(); protected: diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index d7666cc8..ba5ca473 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -85,6 +85,9 @@ namespace rift::Editor frameTime.PostTick(); } + // Close the current project (if any) + CloseProject(); + Graph::Shutdown(); UI::Shutdown(); return 0; @@ -176,6 +179,16 @@ namespace rift::Editor return false; } + void Editor::CloseProject() + { + Id id = GetProjectId(ast); + if (ast.IsValid(id) && ast.Has(id)) + { + fileWatcher.StopListening(ast.Get(id)); + } + ast::CloseProject(ast); + } + void Editor::Close() { rift::UI::Close(); diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index cc4761db..934c0004 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -266,7 +266,7 @@ namespace rift::Editor::EditorSystem } if (UI::MenuItem("Close current")) { - ast::CloseProject(ast); + Editor::Get().CloseProject(); editorData.skipFrameAfterMenu = true; } UI::Separator(); diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 8486f102..921c3b89 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -15,10 +15,10 @@ namespace rift::Editor // Center modal when appearing UI::SetNextWindowPos(UI::GetMainViewport()->GetCenter(), ImGuiCond_Always, {0.5f, 0.5f}); - v2 viewportSize = UI::GetMainViewport()->Size; - v2 modalSize = v2{600.f, 400.f}; - modalSize.x = p::Min(modalSize.x, viewportSize.x - 20.f); - modalSize.y = p::Min(modalSize.y, viewportSize.y - 20.f); + p::v2 viewportSize = UI::GetMainViewport()->Size; + p::v2 modalSize = p::v2{600.f, 400.f}; + modalSize.x = p::Min(modalSize.x, viewportSize.x - 20.f); + modalSize.y = p::Min(modalSize.y, viewportSize.y - 20.f); UI::SetNextWindowSize(modalSize, ImGuiCond_Always); @@ -31,10 +31,10 @@ namespace rift::Editor UI::Separator(); UI::Spacing(); - if (UI::Button("Open", v2{-FLT_MIN, 0.0f})) + if (UI::Button("Open", p::v2{-FLT_MIN, 0.0f})) { - String folder = - files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + p::String folder = + p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); if (Editor::Get().OpenProject(folder)) { UI::CloseCurrentPopup(); @@ -42,7 +42,7 @@ namespace rift::Editor else { UI::AddNotification({UI::ToastType::Error, 1.f, - Strings::Format("Failed to open project at '{}'", p::ToString(folder))}); + p::Strings::Format("Failed to open project at '{}'", p::ToString(folder))}); } } UI::SetItemDefaultFocus(); @@ -87,19 +87,19 @@ namespace rift::Editor UI::AlignTextToFramePadding(); UI::Text("Destination"); UI::SameLine(); - static String folder; + static p::String folder; UI::PushItemWidth(-32.f); UI::InputText("##path", folder); UI::PopItemWidth(); UI::SameLine(); - if (UI::Button("...", v2{24.f, 0.f})) + if (UI::Button("...", p::v2{24.f, 0.f})) { - Path selectedFolder = - files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + p::Path selectedFolder = + p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); folder = p::ToString(selectedFolder); } - if (UI::Button("Create", v2{-FLT_MIN, 0.0f})) + if (UI::Button("Create", p::v2{-FLT_MIN, 0.0f})) { if (Editor::Get().CreateProject(folder)) { @@ -109,7 +109,7 @@ namespace rift::Editor else { UI::AddNotification({UI::ToastType::Error, 1.f, - Strings::Format("Failed to create project at '{}'", folder)}); + p::Strings::Format("Failed to create project at '{}'", folder)}); } } From 369a3ca3ea09808b4c329d977d0099ed314ff588 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 3 Feb 2024 21:06:56 +0100 Subject: [PATCH 23/52] Added icons for file types --- Examples/Project/Main.rf | 24 ++++++-------------- Examples/Project/TestStruct.rf | 6 ++--- Examples/Project/newtype.rf | 9 -------- Extern/Pipe | 2 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 12 +++++----- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 18 +++++++-------- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 24 ++++++++++++-------- Libs/Editor/Src/Systems/EditorSystem.cpp | 23 +++++++++++++++---- 8 files changed, 59 insertions(+), 59 deletions(-) delete mode 100644 Examples/Project/newtype.rf diff --git a/Examples/Project/Main.rf b/Examples/Project/Main.rf index 22362c41..a52d1890 100644 --- a/Examples/Project/Main.rf +++ b/Examples/Project/Main.rf @@ -1,49 +1,39 @@ { "type": "Static", - "count": 4, + "count": 3, "components": { "CChild": { "0": -1, "1": 0, - "2": 0, - "3": 0 + "2": 0 }, "CDeclVariable": { "2": {} }, "CDeclFunction": { - "1": {}, - "3": {} + "1": {} }, "CNodePosition": { "1": { "x": 0.0, "y": 0.0 - }, - "3": { - "x": 0.0, - "y": 3.0 } }, "CNamespace": { "0": "Main", "1": "Main", - "2": "NewVariable", - "3": "NewFunction" + "2": "NewVariable" }, "CParent": { "0": [ 1, - 2, - 3 + 2 ], "1": [], - "2": [], - "3": [] + "2": [] }, "CStmtOutput": { - "1": -1, - "3": -1 + "1": -1 } } } \ No newline at end of file diff --git a/Examples/Project/TestStruct.rf b/Examples/Project/TestStruct.rf index 46464437..ba274ed7 100644 --- a/Examples/Project/TestStruct.rf +++ b/Examples/Project/TestStruct.rf @@ -1,15 +1,15 @@ { "type": "Struct", "count": 1, - "roots": [ - 0 - ], "components": { "CChild": { "0": -1 }, "CNamespace": { "0": "TestStruct" + }, + "CParent": { + "0": [] } } } \ No newline at end of file diff --git a/Examples/Project/newtype.rf b/Examples/Project/newtype.rf deleted file mode 100644 index d6195007..00000000 --- a/Examples/Project/newtype.rf +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "Class", - "count": 1, - "components": { - "CNamespace": { - "0": "newtype" - } - } -} \ No newline at end of file diff --git a/Extern/Pipe b/Extern/Pipe index 652a0ece..1094f09c 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 652a0eced0b5552fe80d40f79ba1c5e3d1c92292 +Subproject commit 1094f09cc8549aae10fb5e3f8da1e190423521a0 diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index 6fa265d9..0104ae9d 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -58,12 +58,12 @@ namespace rift::ast void DeserializeType(Tree& ast, Id id, const String& data); Id FindTypeByPath(Tree& ast, p::StringView path); - bool IsClassType(const Tree& ast, Id typeId); - bool IsStructType(const Tree& ast, Id typeId); - bool IsStaticType(const Tree& ast, Id typeId); - bool HasVariables(TAccess access, Id typeId); - bool HasFunctions(TAccess access, Id typeId); - bool HasFunctionBodies(TAccess access, Id typeId); + bool IsClassType(TAccessRef access, Id typeId); + bool IsStructType(TAccessRef access, Id typeId); + bool IsStaticType(TAccessRef access, Id typeId); + bool HasVariables(TAccessRef access, Id typeId); + bool HasFunctions(TAccessRef access, Id typeId); + bool HasFunctionBodies(TAccessRef access, Id typeId); Id AddVariable(TypeRef type, Tag name); Id AddFunction(TypeRef type, Tag name); diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 5c89e426..84bbd43e 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -131,22 +131,22 @@ namespace rift::ast return NoId; } - bool IsClassType(const Tree& ast, Id typeId) + bool IsClassType(TAccessRef access, Id typeId) { - return ast.Has(typeId); + return access.Has(typeId); } - bool IsStructType(const Tree& ast, Id typeId) + bool IsStructType(TAccessRef access, Id typeId) { - return ast.Has(typeId); + return access.Has(typeId); } - bool IsStaticType(const Tree& ast, Id typeId) + bool IsStaticType(TAccessRef access, Id typeId) { - return ast.Has(typeId); + return access.Has(typeId); } - bool HasVariables(TAccess access, Id typeId) + bool HasVariables(TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { @@ -155,7 +155,7 @@ namespace rift::ast return false; } - bool HasFunctions(TAccess access, Id typeId) + bool HasFunctions(TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { @@ -164,7 +164,7 @@ namespace rift::ast return false; } - bool HasFunctionBodies(TAccess access, Id typeId) + bool HasFunctionBodies(TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index f1b4aee1..6d3fdd1d 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -289,21 +289,19 @@ namespace rift::Editor const String path = p::ToString(item.path); const StringView fileName = p::GetFilename(path); + const StringView dirty = + (item.id != ast::NoId && ast.Has(item.id)) ? " *" : ""; + if (Folder* folder = folders.Find(p::Tag{item.path})) { ImGuiTreeNodeFlags flags = 0; - if (folder->items.IsEmpty()) - { - flags |= ImGuiTreeNodeFlags_Bullet; - } - auto* module = item.id != ast::NoId ? ast.TryGet(item.id) : nullptr; if (module) { // TODO: Display module name - const String text = Strings::Format(ICON_FA_BOX " {}", fileName); + const String text = Strings::Format(ICON_FA_TH_LARGE " {}{}", fileName, dirty); - UI::PushHeaderColor(UI::primaryColor); + UI::PushHeaderColor(UI::GetNeutralColor(1)); UI::PushStyleCompact(); const bool isProject = item.id == projectModuleId; if (item.id == projectModuleId) // Is project @@ -363,11 +361,19 @@ namespace rift::Editor String text; if (fileName == ast::moduleFilename) { - text = Strings::Format(ICON_FA_FILE_ALT " {}", fileName); + text = Strings::Format(ICON_FA_TH_LARGE " {}{}", fileName, dirty); } else if (Strings::EndsWith(fileName, ".rf")) { - text = Strings::Format(ICON_FA_FILE_CODE " {}", fileName); + StringView icon; + if (ast::IsStructType(ast, item.id)) + icon = ICON_FA_FILE_ALT; + else if (ast::IsClassType(ast, item.id)) + icon = ICON_FA_FILE_INVOICE; + else if (ast::IsStaticType(ast, item.id)) + icon = ICON_FA_FILE_WORD; + + text = Strings::Format("{} {}{}", icon, fileName, dirty); } else { diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index 934c0004..ffd1c18c 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -414,8 +414,9 @@ namespace rift::Editor::EditorSystem bool isOpen = true; const String path = p::ToString(file.path); const StringView filename = p::GetFilename(path); - const StringView dirty = ast.Has(moduleId) ? "*" : ""; - const String windowName = Strings::Format("{}{}###{}", filename, dirty, moduleId); + const StringView dirty = ast.Has(moduleId) ? " *" : ""; + const String windowName = + Strings::Format(ICON_FA_TH_LARGE " {}{}###{}", filename, dirty, moduleId); if (moduleEditor.pendingFocus) { @@ -519,17 +520,29 @@ namespace rift::Editor::EditorSystem void DrawTypes(ast::Tree& ast, SEditor& editor) { - TAccess, ast::CDeclType, ast::CFileRef> access{ast}; + TAccess, ast::CDeclType, ast::CFileRef, ast::CDeclClass, + ast::CDeclStruct, ast::CDeclStatic> + access{ast}; for (ast::Id typeId : FindAllIdsWith(access)) { auto& typeEditor = access.Get(typeId); const auto& file = access.Get(typeId); + + StringView icon; + if (ast::IsStructType(access, typeId)) + icon = ICON_FA_FILE_ALT; + else if (ast::IsClassType(access, typeId)) + icon = ICON_FA_FILE_INVOICE; + else if (ast::IsStaticType(access, typeId)) + icon = ICON_FA_FILE_WORD; + bool isOpen = true; const String path = p::ToString(file.path); const StringView filename = p::GetFilename(path); - const StringView dirty = ast.Has(typeId) ? "*" : ""; - const String windowName = Strings::Format("{}{}###{}", filename, dirty, typeId); + const StringView dirty = ast.Has(typeId) ? " *" : ""; + const String windowName = + Strings::Format("{} {}{}###{}", icon, filename, dirty, typeId); if (typeEditor.pendingFocus) { From 7924ed503b54ff14b18cbce7b752e66f5c9a9d5d Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 4 Feb 2024 01:07:38 +0100 Subject: [PATCH 24/52] Many IR generation fixes - Corrected struct declarations - Corrected function names - Corrected function declarations - Other fixes --- Examples/Project/Welcome.rf | 4 +- Extern/Pipe | 2 +- Libs/AST/Include/AST/Components/CNamespace.h | 2 +- Libs/AST/Include/AST/Utils/Namespaces.h | 4 +- Libs/AST/Include/Compiler/CompilerConfig.h | 1 + Libs/AST/Src/AST/Components/CNamespace.cpp | 12 ++-- Libs/AST/Src/AST/Utils/Namespaces.cpp | 4 +- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 58 +++++++++++++++---- .../MIR/Compiler/Src/IRGeneration.cpp | 50 ++++++++++------ Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 4 ++ Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 5 +- 11 files changed, 105 insertions(+), 41 deletions(-) diff --git a/Examples/Project/Welcome.rf b/Examples/Project/Welcome.rf index 51cf7927..97598d4e 100644 --- a/Examples/Project/Welcome.rf +++ b/Examples/Project/Welcome.rf @@ -166,8 +166,8 @@ "CNamespace": { "0": "Welcome", "1": "Print", - "10": "class", - "11": "struct" + "10": "in1", + "11": "in2" }, "CParent": { "0": [ diff --git a/Extern/Pipe b/Extern/Pipe index 1094f09c..8318c2b4 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 1094f09cc8549aae10fb5e3f8da1e190423521a0 +Subproject commit 8318c2b4456912d284ed8f5ab7baf71bf5ce9e7d diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index 68e075d9..aee191c3 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -68,7 +68,7 @@ namespace rift::ast bool IsEmpty() const; p::i32 Size() const; bool Contains(const Namespace& other) const; - p::String ToString(bool isLocal = false) const; + p::String ToString(bool isLocal = false, char separator = '.') const; p::Tag& First() { return scopes[0]; diff --git a/Libs/AST/Include/AST/Utils/Namespaces.h b/Libs/AST/Include/AST/Utils/Namespaces.h index c5e78b77..e5d14898 100644 --- a/Libs/AST/Include/AST/Utils/Namespaces.h +++ b/Libs/AST/Include/AST/Utils/Namespaces.h @@ -28,8 +28,8 @@ namespace rift::ast p::Tag GetName(p::TAccessRef access, Id id); p::Tag GetNameUnsafe(p::TAccessRef access, Id id); - p::String GetFullName( - p::TAccessRef access, Id id, bool localNamespace = false); + p::String GetFullName(p::TAccessRef access, Id id, + bool localNamespace = false, char separator = '.'); } // namespace rift::ast diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index 0921b691..e952ee3f 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -33,6 +33,7 @@ namespace rift OptimizationLevel optimization = OptimizationLevel::Two; + bool debug = true; bool verbose = false; Path buildPath; diff --git a/Libs/AST/Src/AST/Components/CNamespace.cpp b/Libs/AST/Src/AST/Components/CNamespace.cpp index 1af84283..40173a73 100644 --- a/Libs/AST/Src/AST/Components/CNamespace.cpp +++ b/Libs/AST/Src/AST/Components/CNamespace.cpp @@ -69,19 +69,23 @@ namespace rift::ast return size; } - p::String Namespace::ToString(bool isLocal) const + p::String Namespace::ToString(bool isLocal, char separator) const { p::String ns; if (!isLocal) { - ns.append("@"); const p::Tag firstScope = scopes[0]; if (!firstScope.IsNone()) { ns.append(firstScope.AsString()); - ns.append("."); + ns.push_back(separator); } } + else + { + ns.push_back('#'); + } + for (p::i32 i = 1; i < scopeCount; ++i) { const p::Tag scope = scopes[i]; @@ -90,7 +94,7 @@ namespace rift::ast break; } ns.append(scope.AsString()); - ns.append("."); + ns.push_back(separator); } if (!ns.empty()) // Remove last dot diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index 1f099044..1ef524fe 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -106,9 +106,9 @@ namespace rift::ast } p::String GetFullName( - TAccessRef access, Id id, bool localNamespace) + TAccessRef access, Id id, bool localNamespace, char separator) { - return GetNamespace(access, id).ToString(localNamespace); + return GetNamespace(access, id).ToString(localNamespace, separator); } } // namespace rift::ast diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index 4a260315..d9368dcf 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -11,27 +11,65 @@ extern "C" namespace rift::MIR { - void InitCToMIROptions(c2mir_options& options) + struct OptionsData { - int inclP, ldirP = FALSE; /* to remove an uninitialized warning */ + TArray headers; + TArray definitions; + }; - options.message_file = stderr; - options.debug_p = options.verbose_p = options.ignore_warnings_p = FALSE; - options.asm_p = options.object_p = options.no_prepro_p = options.prepro_only_p = FALSE; - options.syntax_only_p = options.pedantic_p = FALSE; + void InitCToMIROptions( + const CompilerConfig& config, OptionsData& optionsData, c2mir_options& options) + { + // Fill defaults + options.message_file = stderr; + options.debug_p = false; + options.verbose_p = false; + options.ignore_warnings_p = false; + options.no_prepro_p = false; + options.prepro_only_p = false; + options.syntax_only_p = false; + options.pedantic_p = false; + options.asm_p = false; + options.object_p = false; + options.module_num = 0; + options.prepro_output_file = nullptr; + options.output_file_name = nullptr; - options.macro_commands = nullptr; options.macro_commands_num = 0; + options.macro_commands = nullptr; + + options.include_dirs_num = 0; + options.include_dirs = nullptr; + + // Fill from config + // options.debug_p = config.debug; + options.verbose_p = config.verbose; + + if (options.output_file_name == nullptr && options.prepro_only_p) + { + options.prepro_output_file = stdout; + } + + // TODO: Fill headers. No headers needed for now + // TODO: Fill definitions. No definitions needed for now + + options.include_dirs_num = optionsData.headers.Size(); + options.include_dirs = optionsData.headers.Data(); + options.macro_commands_num = optionsData.definitions.Size(); + options.macro_commands = optionsData.definitions.Data(); } void CToMIR(Compiler& compiler, MIR_context* ctx) { c2mir_init(ctx); + auto moduleIds = p::FindAllIdsWith(compiler.ast); + + OptionsData optionsData; c2mir_options options; - InitCToMIROptions(options); + InitCToMIROptions(compiler.config, optionsData, options); - for (ast::Id moduleId : FindAllIdsWith(compiler.ast)) + for (ast::Id moduleId : moduleIds) { p::Tag name = ast::GetModuleName(compiler.ast, moduleId); auto& mirModule = compiler.ast.Get(moduleId); @@ -46,7 +84,7 @@ namespace rift::MIR { auto getCode = [](void* data) -> p::i32 { auto* codeLeft = static_cast(data); - if (codeLeft->size() > 0) + if (codeLeft->size() > -1) { *codeLeft = Strings::RemoveFromStart(*codeLeft, 1); return *codeLeft->data(); diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index e8d7e054..736416c4 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -2,17 +2,19 @@ #include "IRGeneration.h" -#include "Pipe/Core/String.h" -#include "Pipe/Core/StringView.h" - #include #include #include #include +#include +#include namespace rift::MIR { + const p::TSet CGenerator::reservedNames{"class", "struct"}; + + void GenerateC(Compiler& compiler) { MIRAccess access{compiler.ast}; @@ -163,20 +165,27 @@ namespace rift::MIR const auto& var = access.Get(memberId); const Tag memberName = ast::GetName(access, memberId); - if (auto* irType = access.TryGet(var.typeId)) + auto* irType = access.TryGet(var.typeId); + if (!irType) [[unlikely]] { - Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); + const Tag typeName = ast::GetName(access, id); + compiler.Error(Strings::Format( + "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); } - else + else if (reservedNames.Contains(memberName)) [[unlikely]] { const Tag typeName = ast::GetName(access, id); compiler.Error(Strings::Format( - "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); + "Variable name '{}' not allowed in struct '{}' ", memberName, typeName)); + } + else + { + Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); } } const auto& type = access.Get(id); - Strings::FormatTo(*code, "typedef struct {0} {0} {{\n{1}}}\n", type.value, membersCode); + Strings::FormatTo(*code, "struct {0} {{\n{1}}};\n", type.value, membersCode); } code->push_back('\n'); } @@ -190,7 +199,7 @@ namespace rift::MIR auto& signature = access.Add(id).value; signature.append("void "); - const p::String name = useFullName ? ast::GetFullName(access, id) + const p::String name = useFullName ? ast::GetFullName(access, id, false, '_') : p::String{ast::GetName(access, id).AsString()}; signature.append(name); signature.push_back('('); @@ -210,19 +219,26 @@ namespace rift::MIR auto* exprId = access.TryGet(inputId); const auto* irType = exprId ? access.TryGet(exprId->id) : nullptr; - if (irType) [[likely]] - { - Strings::FormatTo(signature, "{0} {1}, ", inputName, irType->value); - } - else + if (!irType) [[unlikely]] { const String functionName = ast::GetFullName(access, id); compiler.Error(Strings::Format( "Input '{}' in function '{}' has an invalid type. Using i32 instead.", inputName, functionName)); } + else if (reservedNames.Contains(inputName)) [[unlikely]] + { + const String functionName = ast::GetFullName(access, id); + compiler.Error( + Strings::Format("Input name '{}' not allowed in function '{}' ", + inputName, functionName)); + } + else + { + Strings::FormatTo(signature, "{0} {1}, ", irType->value, inputName); + } } - Strings::RemoveCharFromEnd(signature, ','); + Strings::RemoveFromEnd(signature, ", "); } signature.push_back(')'); @@ -309,7 +325,7 @@ namespace rift::MIR if (!Ensure(access.Has(functionId))) { compiler.Error(Strings::Format( - "Call to an invalid function: '{}'", ast::GetName(access, functionId))); + "Call to an invalid function: '{}'", ast::GetFullName(access, functionId))); return; } @@ -343,7 +359,7 @@ namespace rift::MIR // auto* customMainFunction = access.Get(functionId).instance; - code->append("void main() {\nMain();\nreturn 0;\n}\n"); + code->append("int main() {\nProject_Main_Main();\nreturn 0;\n}\n"); } ast::Id CGenerator::FindMainFunction(p::TView functionIds) diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index a17ca3f0..10b9b6ce 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -34,10 +35,13 @@ namespace rift::MIR struct CGenerator { + static const p::TSet reservedNames; + Compiler& compiler; MIRAccess access; p::String* code = nullptr; + void GenerateModule(ast::Id moduleId); void BindNativeTypes(); diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index 6d3fdd1d..3965f0cf 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -400,8 +400,9 @@ namespace rift::Editor } UI::InputText("##newname", renameBuffer, ImGuiInputTextFlags_AutoSelectAll); - const StringView parsedNewName = Strings::RemoveFromEnd(renameBuffer, ".rf"); - const bool nameIsEmpty = parsedNewName.empty(); + const StringView parsedNewName = + Strings::RemoveFromEnd(p::StringView{renameBuffer}, ".rf"); + const bool nameIsEmpty = parsedNewName.empty(); const Id sameNameFuncId = ast::FindChildByName(ast, p::GetIdParent(ast, item.id), Tag{parsedNewName}); if (nameIsEmpty || (!IsNone(sameNameFuncId) && item.id != sameNameFuncId)) From af62f96eea7d1cfd9d7d653236b92ddc1f3b31e0 Mon Sep 17 00:00:00 2001 From: muit Date: Mon, 5 Feb 2024 23:17:49 +0100 Subject: [PATCH 25/52] =?UTF-8?q?Fixes=20to=20MIR=20JIT.=20JIT=20executes?= =?UTF-8?q?=20now=20=F0=9F=8E=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Examples/Project/stdio.rf | 9 +++++ .../MIR/Compiler/Include/MIRBackendModule.h | 2 + Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 11 +++-- .../MIR/Compiler/Src/MIRBackendModule.cpp | 27 ++++++++++--- Tools/mir/test/test.c | 40 ++++++++++++++++--- 5 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 Examples/Project/stdio.rf diff --git a/Examples/Project/stdio.rf b/Examples/Project/stdio.rf new file mode 100644 index 00000000..3dae6375 --- /dev/null +++ b/Examples/Project/stdio.rf @@ -0,0 +1,9 @@ +{ + "type": "CStatic", + "count": 1, + "components": { + "CNamespace": { + "0": "stdio" + } + } +} \ No newline at end of file diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index d5559832..93e858b3 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -31,5 +31,7 @@ namespace rift } void Build(Compiler& compiler) override; + + void PrintBuildFinish(Compiler& compiler) const; }; } // namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index d9368dcf..d754ef4e 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -83,16 +83,15 @@ namespace rift::MIR const CMIRModule& module) { auto getCode = [](void* data) -> p::i32 { - auto* codeLeft = static_cast(data); - if (codeLeft->size() > -1) + const char*& codeLeft = *static_cast(data); + if (*codeLeft == '\0') { - *codeLeft = Strings::RemoveFromStart(*codeLeft, 1); - return *codeLeft->data(); + return EOF; } - return EOF; + return *(codeLeft++); }; - StringView code = module.code; + const char* code = module.code.data(); if (!c2mir_compile(ctx, &options, getCode, &code, name.Data(), nullptr)) { compiler.Error("C to MIR compilation failed"); diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index 06c2876d..e94e17c5 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -236,6 +236,7 @@ namespace rift if (compiler.HasErrors()) { + PrintBuildFinish(compiler); return; } @@ -260,6 +261,17 @@ namespace rift } MIR_load_module(ctx, module); } + + if (!mainFunc) + { + compiler.Error("Main function not found in MIR generated code."); + } + } + + if (compiler.HasErrors()) + { + PrintBuildFinish(compiler); + return; } OpenSTDLibs(); @@ -283,24 +295,29 @@ namespace rift p::DateTime startTime = p::DateTime::Now(); p::i32 resultCode = entry(); // Run! + MIR_gen_finish(ctx); + if (compiler.config.verbose) { p::Info(" execution -- {:.3f}s\n", (p::DateTime::Now() - startTime).GetTotalSeconds()); p::Info("exit code: {}\n", resultCode); } - MIR_gen_finish(ctx); + PrintBuildFinish(compiler); + + CloseSTDLibs(); + MIR_finish(ctx); + } + void MIRBackend::PrintBuildFinish(Compiler& compiler) const + { if (!compiler.HasErrors()) { p::Info("Build complete."); } else { - p::Info("Build failed: {} errors", compiler.GetErrors().Size()); + p::Error("Build failed: {} errors", compiler.GetErrors().Size()); } - - CloseSTDLibs(); - MIR_finish(ctx); } } // namespace rift \ No newline at end of file diff --git a/Tools/mir/test/test.c b/Tools/mir/test/test.c index b38f78ff..4b09ba1f 100644 --- a/Tools/mir/test/test.c +++ b/Tools/mir/test/test.c @@ -1,10 +1,38 @@ -#include +// Struct Declarations -void main() +// Function Declarations + +// Struct Declarations +typedef struct TestStruct TestStruct; + +// Struct Declarations +typedef struct Welcome Welcome; +typedef struct TestClass TestClass; + +// Function Declarations +void Project_Main_Main(); +void Project_Welcome_Print(long long in1, long long in2); + +// Struct Definitions +struct TestStruct +{}; + +// Struct Definitions +struct Welcome +{}; +struct TestClass +{}; + +// Function Definitions +void Project_Main_Main() +{ + printf("hola"); +} +void Project_Welcome_Print(long long in1, long long in2) {} + +int main() { - bool a = true; - int q = sizeof(int); - int nn = 2433; - printf("%i", q + nn); + Project_Main_Main(); + return 0; } From 5e96ff36e413182335acaf80bd52b933fe2a7af2 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 7 Feb 2024 00:32:49 +0100 Subject: [PATCH 26/52] Added icon to editor window, use new logo in exe files --- Apps/CLI/CMakeLists.txt | 2 +- Apps/CLI/Icon.ico | Bin 67646 -> 102097 bytes Apps/Editor/Icon.ico | Bin 67646 -> 102097 bytes Extern/CMakeLists.txt | 4 + Extern/stb/stb_image.h | 7985 +++++++++++++++++++ Libs/Editor/CMakeLists.txt | 1 - Libs/Editor/Resources/Editor/Icons/Icon.png | Bin 4686 -> 1482 bytes Libs/UI/CMakeLists.txt | 1 + Libs/UI/Include/UI/Window.h | 2 + Libs/UI/Src/Window.cpp | 22 + Tests/CMakeLists.txt | 2 + Tests/Icon.ico | Bin 0 -> 102097 bytes 12 files changed, 8017 insertions(+), 2 deletions(-) create mode 100644 Extern/stb/stb_image.h create mode 100644 Tests/Icon.ico diff --git a/Apps/CLI/CMakeLists.txt b/Apps/CLI/CMakeLists.txt index e2da1fb6..7871c578 100644 --- a/Apps/CLI/CMakeLists.txt +++ b/Apps/CLI/CMakeLists.txt @@ -14,4 +14,4 @@ target_link_libraries(RiftCLIExe PUBLIC rift_module(RiftCLIExe) set_target_properties(RiftCLIExe PROPERTIES OUTPUT_NAME "Rift") -set_icon(RiftCLIExe ../../Resources/Icon.ico) +set_icon(RiftCLIExe Icon.ico) diff --git a/Apps/CLI/Icon.ico b/Apps/CLI/Icon.ico index 290fdaa580d922bc17a0a48157a25fe97c089c9f..11b4a0778ab81aa3fd170d3058ff1d65805ffd84 100644 GIT binary patch literal 102097 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 literal 67646 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 E12Q{{WdHyG diff --git a/Apps/Editor/Icon.ico b/Apps/Editor/Icon.ico index 290fdaa580d922bc17a0a48157a25fe97c089c9f..11b4a0778ab81aa3fd170d3058ff1d65805ffd84 100644 GIT binary patch literal 102097 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 literal 67646 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 E12Q{{WdHyG diff --git a/Extern/CMakeLists.txt b/Extern/CMakeLists.txt index d64738fc..8e1f8547 100644 --- a/Extern/CMakeLists.txt +++ b/Extern/CMakeLists.txt @@ -15,6 +15,10 @@ add_subdirectory(CLI11) if (RIFT_BUILD_EDITOR) + add_library(stb_image INTERFACE) + target_include_directories(stb_image INTERFACE stb) + + find_package(OpenGL REQUIRED) add_library(gl3w STATIC gl3w/GL/gl3w.c) target_include_directories(gl3w PUBLIC gl3w) diff --git a/Extern/stb/stb_image.h b/Extern/stb/stb_image.h new file mode 100644 index 00000000..a632d543 --- /dev/null +++ b/Extern/stb/stb_image.h @@ -0,0 +1,7985 @@ +/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/Libs/Editor/CMakeLists.txt b/Libs/Editor/CMakeLists.txt index ae5b2d17..19f80f07 100644 --- a/Libs/Editor/CMakeLists.txt +++ b/Libs/Editor/CMakeLists.txt @@ -15,4 +15,3 @@ target_link_libraries(RiftEditor PUBLIC rift_module(RiftEditor) rift_enable_module_resources(RiftEditor) -set_icon(RiftEditor ../../Resources/Icon.ico) diff --git a/Libs/Editor/Resources/Editor/Icons/Icon.png b/Libs/Editor/Resources/Editor/Icons/Icon.png index 838837b57449f1efeab2b194370effa05682102c..ac590cff3f6da02f0143f0b3702dde6565f8e5b7 100644 GIT binary patch literal 1482 zcmb_cYcv#i9Q}`B7!0GtU_w!e*36Jc@*3|cCXa+YEE38}UTKyLgQHl_M3HB@@Z56Bs9Pn3FcFsiLe(X>gC=DVG?%xYb;RaSa5A{|3VX zX=h|ImE7aT`|bF)9^9y}?Q=O|_Ny~vHBd~|4lpkKIJoN$$<2dGWWK6zS=C*IJhLSS zyR=9s7U5FZ@aQ#-gh1G0eAOvsofeKVkjaO*>WK`|M1k>4v*hZwwiT#sM}fKjf$;$o zlt4-IoD?ib^`{bnu^%Wne%eE^xV;YNcwqe9J-g&50sVcKVq%~aESM|I3-Rct(}|2_ zM5rYe$SaMhg^%cO^*RJ`2LsB7oB`T}ddF{2-Vp?Apc3HN6pKF7O zR@sIT7MbR;(pgYUU+btIIV96vI(?N+HMq^zM`mq-NjX9v?emK-?5DV$Q&JR@dUMrJ zP^_^bzomaU{JzwV{_bNwPnc{WXtQW!FT>^e#5uP*-kBM=P?%-^cHb2x$eL!UaJB~D zqp8J8vep4s+V;msHJpu4Su{kD9XZ{VDX6`P03dFyQm&o7cU2dNsJB%_c|K#KigDo0 zryY9Ex6u19zR`Ja-C)!}?ut_@e0|mB6Mn=WE4b=4aFTDF`{S`H)X`^ksPgB6m4)5T zZXg?4cVkMJC>&5fj=-6uK{RIaC=YPxNX1PGW%GBW6x6W;!?WvO$0EY%`sB*DWru`@ zXZ=SWu_mrz?i`4@V9Mcsamq(Oxh9t*B?Om=-_kBmZFnfHMylh#t;V;CdrOY8TI~|F z?Kf0_U&r;L@+!xqCHB3{`LK*m4|yq*$kA0{-5yKS=V2N|eye92E-eyElh(xaY9y+I!SSv=gedJL~pD1vBPzpzzvaA8FDBDDhnHw!+ZCSOyn zIfk5WGSnyI4AgHjqYng|i7Y{gM1B9 zu+yv(v=sdxSjaP?I4s1nmZcMIYPEV-D$WpqHM{Cb0m@(4q4ekRB~l!b~5s{;wa=Yav7J--lL;9 z^N^J?qON58{Qh{J=db7WJg?{d?1byr3}KvNoB#kA+DPBxNaFra?5sz;P20H-0DeKV z{uRqG#~*oIo5D8*yFM1aC}hWzzm~XJKK0Udb>?(8eXZ61Lbo#~SmwTM)VN-d?(I9R zWg^(p9&Y!C?Iy9sR9E919i6^*E|7EYWiB2Qv(MrO4V&uaWl{O>Pbg(_2O zO1FP4A=1bWwVFWR$c%z1v2lUHXTd~5Eh0HXnLtRGIJ+8%mW5BBUTwzjZhi3)fCNMn zw(v46>DtnN%0Fy>z_xiHC~@UALAVc*aSh8*lRW z8UHBb0IFtGWwbE*e#8&NeOyZ(K9d!zqc@uQjT1M9Zq%n*Bl7I*S80mBvk4nUyJZBe z(6@gcl=}gS@!=DKECR+j!z!;;ne|SG3TyFe!@RQ18)X4e@CYVep= z!pcm*u{--O;FghbPcb;Dkq$gb$p6&eff|5wW$QFM7qzNaWjfWf zk^Zjd*LWYG{0B#6wa@Z2q*HF-ZH)h}CEbGJRQKP)UqaNsIx=|zWr$b{M*}nE$g?cv zeh!bkt9W>oboWEM1zmk2pb(V);tKT^F}R*H`!I!f266!B%}B)?HGfaL%<+aZ)J8Rh z^F|X;wWEH(cM2{QZo6pkhZ*sU-jEmaB{+aIy21y~;mP_QYDzAQiL z4RchVixvnTF;%HkZP@$S_p4uNXcSk`icFJF7(uBBvVb+Mo)l;h!)A*M%E~?bomLyN zm~lJr!&NRJWV7yzA_8K)f29fwewTh8UkW^hG9@h@1& zwD&vrptaXi@&Ww~IpLK72&g5PWhg$WnaEZ4vhbcaySyJZj$x6MR<-$H6D-zq<; z+hJCq?J(wW&tVc-g~UoCZ`D_w`wa=q?jb>kpn&JjUOQ>7Jl{31t9xPX9@-NEJ|Fu> zFUDuml4gYfJd_?@?)&Z1k*%TG3mi?jY2ASzQFZuEqx%Sq5DC;fQa{@!-~4-s$wYpN z<`4*;PgsmS{e|dI@wvi!ZExGV;H$Es#gdpO6#O4cc^-7U>#Q4=jQK=}Zjpi|*{buv(pefy_jvRKJN zipC(vkjB0BQIhW@GduT10IGIF(4HImy-Yfi=tCkVsUSl0ij&a^f7^ojw zKc7+eypuM_S6NFNDh^83{MjuBMJ0Q@1HW6UyDW^pU!17(&La8G$~7M#i;_duzSuTo z+Lp&(vLgGM>~Ikvz>sNql#J&X5uy$G(`pQSM&`eKUy-Wf0!--%k3F_|Iu{kYBu1F* z9hrb&Y#xVT*KS)n!2L~vTqzTh|JobTC%kvmZoL*dldYV#mZjYosi4f(-%*LBKE%U< zp>KO>K;Sa(sH>zg24;^XD1hy7vB}3XBkx+4|GI<$}G2hH@$+2GP6H4jE zud{nn{nk9$1|T9-fSq_>?cn3kmk$|6nMsvH$cuY!5DL3`Pl$K(eVKvIh{PO^pS7fr zcXiHfv6--E23{o0$*~#_uqUVLaTAu zgtB^)h;D5a9^m>DqO9|UH<0eVtx$xqBZ$5!PoyD(7MnW~Zm(IfGG8JagfqB7k%LW5 zrB$xdzxjWv4!if)$PS#I#w zYt{|mF1|>RZwrhX-Gnnm!`}x*0fn1XUvn7UmrbXO2*Fv!cm8qks_@hhNkGEP?;Hb- zp-j%OO;>cmS&ZkWPzNY>fA<#(JYQ^#Ijr)2aUjNxL$vH;rhRZth={@-fMZ;^_5NLx z*NDsyTJ5X8x~TvVd_t1T8<6#8?l7`mLR#q|bB!e*;A25;5XuP_{fH(n;MemIGjdVq z`QfRf6zC2@sYn2a28c6ECnVuhGf)VeZ?__Cd@{V@(VLIwuB_)!tgJyEYnNtIkga87 zpsp2KJEAXJEpvkUyq<^6|NN}5{yVn=^88d_^Z_o<*o1qjC3HMy{PBc2AIQ!Oq|)C= zlf?}`6YLB8HlyI{RuF@_>1=}fPGoFb}p)!HE>V^DP=$wciP6pX0; zhBUD}WIg7jk&YF(q2T)tip!9-CNlJO)jE?KA+~ zYU-lLaN!lynzpn-Bn1N!P%Jxz77qbSh|Czp?qGuCj7YcDzbrjlH~Gu>WXsu6(i*Z9#I0Sg@-b z-(;d}w&v&eyzk+le7aqZw>rj?62f9F#(ipp&Cv9d3r`5Z4KV3n5^#E?D$u|L+F7IS z@bN6AofVUoz4tanObP}(<&~Kmo|qqPSJiX$33zmN5_ZzXtlnQT{43vw-8gEvOBA|OGi{JgOOLuOKqLavzLA`JY#o9#j&9-gKYx;nU_y28` zMmyUE2DSS})J4;}1$cNonEzXv|6*~#E9EmoR#VD$ov3C3>n;(en{%Q7 z9)kx{yB0;Obu+nF!U0yMFIPmjq_eWb`3=I<=6I?tsA4%z4vdd^t6f=dImMuhf&{O* zO{=CTY4gXlrRf(>Pu~7Xzih<01BU>?)FtV$VVTn++P>ix4Cf=#!|4|RDhEk>WB zm%h);F1`d5U9Pb$%132%?Z`=^B$_CfPOEAr01B(7dzg$;_UL9&-;EdyaK_@L8mW1A z%%x88hEiKw>NC_fhSVO3U#MoW-*By8(a#SE5RyNcg*%yrZii43PtYe=+0EF`L~Y8D zZuCoQdj0uM`xm#(AsD=gVRwwM<9M-C z7AV|$gH20BU{|Rnm97DTx!}ouBwGE&$d5qRp7W$_HMB}t-u`uuz%#Mq3pca}(`+$` zCrM{Haa#*rj4Fruqf(NL%$*FCEpD~$q$qyI7jSaN_g3^o1!Z1hpg6J2**dyOCX-3n5`9La5XX@KKT21b>*gya&qH& zAktjz!0qqzcoEt4O^w9zlRm9xaGNt;P)4Yr+TalI`pCG zVh6DV|A`&D&q^o2PTC$4J=>eZD-P2Ux8z;ktv0uXS^YXZ0fN&tmj`FR|NQA`$H=*q zFKlGs%4LwGlR7s^c2OA8_^3UjyeE#{kng=o+i-p{bhJ!=7xOvC3o_-MW+rxT+Kjij z+i1BQc*)b`Af+$~&PYavx}VZSy@$_qFWDQ4yIEmXC!v-<{oWwfte0Vf&fOsukwKyP zI=_sa&4bpGerlRk{COAF3z4N&WUd)J?ykf8^Q5u5K_`N6bV`11(?mQ<@pL29x7xp_IGu`Vf zURb11DNBp6p~^p1{=x%R{2vom4b+LdCj>&TDjh5Ob?ar@;-)akHNB1tu(qO#D;sM~ zPk)D6^mxy|mp`T5yBok|;~WIRsTl1>5pHna{S;mu&zzsOlTX*b_l#k`Q4he6G=GvV zRh;WCHC!>3IX^Qv6W;p4_n9o9FsJjf1HHK3bdVmI4?iH8%0Yk<5-On>iE?}8E2II7 zhU;7$;~>h+F7hACFG+{*+wn(ge7(l>^>#opS7hEZZx~iYT*8wnAhF+Q0(akn(++bN~0%$@)rJ(CXU7ri~gGzpG!#5sip!B6M7dCzCW)AmC~k6yb1wRjFkz zPMtHu_?XG=fZN}72i`_BU{BrempaGvL+7Ey=^D<~_~MBXE&SQG!4RM1qEaTQ^Iz{i zdA&e;94cZ#MF!kF>!kL=%w#tL@oS-y7R3V0ADj0-Q3}d+`)c@7_5fzecW|O!dr#+e z##^<$wlhPb8hCkYw#(U&_{nFfHt_M JPt?Ue`5(?~p$-55 diff --git a/Libs/UI/CMakeLists.txt b/Libs/UI/CMakeLists.txt index bb5a56fb..95def659 100644 --- a/Libs/UI/CMakeLists.txt +++ b/Libs/UI/CMakeLists.txt @@ -13,6 +13,7 @@ target_link_libraries(RiftUI PUBLIC imgui IconFontCppHeaders ) +target_link_libraries(RiftUI PRIVATE stb_image) target_compile_definitions(RiftUI PRIVATE NOMINMAX) rift_module(RiftUI) diff --git a/Libs/UI/Include/UI/Window.h b/Libs/UI/Include/UI/Window.h index 01e12673..424dfbe1 100644 --- a/Libs/UI/Include/UI/Window.h +++ b/Libs/UI/Include/UI/Window.h @@ -22,4 +22,6 @@ namespace rift::UI bool WantsToClose(); GLFWwindow* GetWindow(); + + void SetWindowIcon(); }; // namespace rift::UI diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index 34a29899..a295da3c 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -16,8 +16,12 @@ // Include glfw3.h after our OpenGL definitions #include #include +#include #include +#define STB_IMAGE_IMPLEMENTATION +#include + namespace rift::UI { @@ -94,6 +98,8 @@ namespace rift::UI ImGui_ImplGlfw_InitForOpenGL(gWindow, true); ImGui_ImplOpenGL3_Init(glslVersion); + SetWindowIcon(); + RegisterCoreKeyValueInspections(); return true; } @@ -164,4 +170,20 @@ namespace rift::UI { return gWindow; } + + void SetWindowIcon() + { + p::String iconPath = p::JoinPaths(p::GetBasePath(), "Resources/Editor/Icons/Icon.png"); + GLFWimage image; + image.pixels = stbi_load( + iconPath.c_str(), &image.width, &image.height, nullptr, 0); // rgba channels + if (image.pixels == nullptr) + { + p::Error("Window icon couldn't be loaded"); + return; + } + glfwSetWindowIcon(gWindow, 1, &image); + + stbi_image_free(image.pixels); + } } // namespace rift::UI diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 84c8b53b..bc853fd8 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -8,3 +8,5 @@ target_include_directories(RiftTests PUBLIC .) target_link_libraries(RiftTests PUBLIC RiftAST Bandit) add_test(NAME RiftTests COMMAND $) + +set_icon(RiftTests Icon.ico) diff --git a/Tests/Icon.ico b/Tests/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..11b4a0778ab81aa3fd170d3058ff1d65805ffd84 GIT binary patch literal 102097 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 literal 0 HcmV?d00001 From 21d15f7d3bbffb343652b4219384f20e416f4719 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 7 Feb 2024 00:57:27 +0100 Subject: [PATCH 27/52] Added multiple resolution window icons --- .../Editor/Icons/{Icon.png => Logo_128.png} | Bin .../Resources/Editor/Icons/Logo_256.png | Bin 0 -> 2936 bytes .../Editor/Resources/Editor/Icons/Logo_64.png | Bin 0 -> 751 bytes Libs/UI/Src/Window.cpp | 24 +++++++++++++----- 4 files changed, 17 insertions(+), 7 deletions(-) rename Libs/Editor/Resources/Editor/Icons/{Icon.png => Logo_128.png} (100%) create mode 100644 Libs/Editor/Resources/Editor/Icons/Logo_256.png create mode 100644 Libs/Editor/Resources/Editor/Icons/Logo_64.png diff --git a/Libs/Editor/Resources/Editor/Icons/Icon.png b/Libs/Editor/Resources/Editor/Icons/Logo_128.png similarity index 100% rename from Libs/Editor/Resources/Editor/Icons/Icon.png rename to Libs/Editor/Resources/Editor/Icons/Logo_128.png diff --git a/Libs/Editor/Resources/Editor/Icons/Logo_256.png b/Libs/Editor/Resources/Editor/Icons/Logo_256.png new file mode 100644 index 0000000000000000000000000000000000000000..64b6bcc6f4987a26cef2aeaf85bc844878205a7f GIT binary patch literal 2936 zcmd5;c~lbE8owYaCZ>($QWTnF6KNw#ji^mXHJZ6^nM+C9NT!u(E~Nox%X74}G1QdQ z%n~s(bJSc)OwDq^+k-#y>Gzwdm>ZZ7s3 z>o%_g0BATIKI8!aL}5YzTt%S*A{ikHr5176HwplC?X?8~Idr`>NR)^D0q~TK6et`R ziQr5Cpdw9OdQw?|(r`FL@QQ;>b6n2{4CuGbjMi3Pm}RR* zMI-0$k~aSO#cDL3T^sxLup;|E39$#JKQR2^bSd*k^rIMAs~ZCVq95R`xoUn1Om-{GZcl0)`}Y_RMYDK)Y-;)@kt~ z%*p@AR+9~w4b+}L8WFNgs$k0}c)+t~NX9AK-|K?J!7+n&-<)m@E$OqSrsQQ*U+lAu zr=kAXH&bKse$w*^$)JE|1LGng1vY%426A=Bv5~9y<&J z8K*ASg>QhcmTspl3?l`(Hvthj{x1qGaWo)6m0DR>GBBWykc9-RP<30~N3}u#?&b5r zNyhngSU`8-a=Mi$o|xWY}1$?gq0y=X9ece36%40eFoyFOTu!ic!^zk^!HUsK_=IQo9=t3 z;;$7XdPJM;E+va=T=*hBJ`@J$Wcf!3!3;a? z5oy*nY1XS5!ufRhNVoh~5k}~8rOdOVw&GP|NyLa$?{Ax3| zj&1uScd?BFZ};P~eSrp7uP~VSB{gx#4NSXG16q zB!xQ5?Ufj%6BZ~4lz04yXD#jxi-$jH4TZ64^thU+z#gki~zTY5=m~ zn)Y&Sw72LT97?UAeU^^%rznN<_58_^I2Z^{Ig%T>qv&)HHXRTX3 zlI0mApy%UAuIi8YFEr;f$A? zBl)E`$G>1XAMI1j>KM%O8;Ud?e5JjzopDEX@@yciW5RQ!^rBaEba(B(*u6*y>jP5@ zpMf>>s<)s5Vz?@Py=qc%Ut&@->g=I3MWDGP;y26jLwPchZ?;Sq2DC54xlO-)XUcQ$ zt^TWWmX*|fOP|B;`zdPc)OlLRt>fv6*w)748XyL>n;PsmPV;^s^z;3euP8G^9`JcC z1M#EsY`;9WF|clTuqliss_%JYNfU9BDALf5-d4hRZ9-I8AB~^`W_v^?vK=njanSC5OH(6aU*aaEg{urHXB;IkaLd^3vLJ{CQd;qhqC zz}D$bRI)y72@a)h4 zKno|5C^6NasJAKsnx<=!n^^2)^5))&uA@Ko^vb7poq=xb&Ig@I zjej?cO|;qP1`V{vfWCygiImC!4(ZZE(IqG4g0~w^k89A+!N-0RXWU&`9;!ty=NAu5 zmz6ycMv{$Bs9`_0p|>P>drxnbT5=bx#je@vtmN;mCgg;flwV*^nhou3eAwB5u$x@& z2o!AFytnc4kQYh%Gb z2rCF1e=xoB!)}m z{;GsQ&Z+LI(dj70A(KM)(IP3xlY*Sea^d3ejX*?%FV1N_Nz#J!xJpt zqow0PqKEYQZAqwZj}u!A&n$BAbDL*2gk%uODwvO-zIla<$6DvIeCDg?jS~f+p|U4z zx6dVU@z^93m=&3--TvJ=(-PjLQh;1WZJjcCEY)*-|FXgALxr_Are4+U@hXCxy1RRu zz2o5wCl%r!$$dH){pqnC&j}NmfWlo$s9ZO&8~l1_ zsh3PGF}AIJoz|2ViY_l})8uC&%&|&(d9&&(M_Cs&GJWQmG+*jHeb#diAJ$x%Z;o(H4L3N87KJ=5=I6GqEE1pMH~Ij;FKV|c6_Hj zd~DO+0EtpM984JL;pW4~_83gc&2`_gzPXHyY~08)``-^JrZA!basOud$4V_~Jaocv zue@qV3X0;%SREt5W|!7UEF>$92J`YBRgVm)hpw z(;8wB^1Z{ndw(@TF}a;g&fw}`lnhZ3rpQ%w><|Qz1$DUZL4x#|?<}wAdEN)})P>Se zo$fLS`q40S2f8FbD@WH`bBlf4uW#d{kk^D6#NrIhO0*$|zH1Vn`QS%?Tu@=%9 Zl7rxoz3Ax&etMO$s`k6T}BV+NH598mI#j zD{+CO2G8S-AyQ%`O5WJ9N1pjf{v+>>we#(IJoB_b6h$E;D3zT~3ZjqlHiKV=VBXEg z<66_G2`!>M_}6)>E63KB*Id&mfnFE>%An*Dz*>m`AaF4N1TF@Ez{LO%xEKHe7X!e0 zsiCw^0UXO?7fSkiz%npb3DM9npIp05t2NB4>KICX1t1-l=WT6OXCD3pz}%OP7g#bs z#sH$hDmriZa0S#brhnPSNAJpP!lsKPxpQuVF(-tiI(nTCF$aBBcyp7nNcQZHM%%L= zKYU+qkint6O|STdniD+x{wn_l2dn=H7;`ZD(fzldy3+ZtxVrOJYWIC0R|*`gK7dy1 z+?kV0K5Zn8Jt!rF!?Y;d%4Vw%VD`UzLgpo|cjjlcZ{41@Rq<~o$jMW z?1|Myh(mX^yl+YTj+d$NyRE7TY4Qp<0C zU>Lb;=c6c!)D@w#b~S?t43V6{e(71R@ Date: Wed, 7 Feb 2024 02:08:16 +0100 Subject: [PATCH 28/52] Improved project manager --- Libs/Editor/Src/Utils/ProjectManager.cpp | 126 ++++++++++++----------- Libs/UI/Src/Style.cpp | 2 + 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 921c3b89..f54df91e 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -10,27 +10,87 @@ namespace rift::Editor { + void TextCentered(const char* text) + { + auto windowWidth = ImGui::GetWindowSize().x; + auto textWidth = ImGui::CalcTextSize(text).x; + + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::Text(text); + } + void DrawProjectManager(ast::Tree& ast) { // Center modal when appearing UI::SetNextWindowPos(UI::GetMainViewport()->GetCenter(), ImGuiCond_Always, {0.5f, 0.5f}); p::v2 viewportSize = UI::GetMainViewport()->Size; - p::v2 modalSize = p::v2{600.f, 400.f}; + p::v2 modalSize = p::v2{600.f, 0.f}; modalSize.x = p::Min(modalSize.x, viewportSize.x - 20.f); modalSize.y = p::Min(modalSize.y, viewportSize.y - 20.f); UI::SetNextWindowSize(modalSize, ImGuiCond_Always); if (UI::BeginPopupModal("Project Manager", nullptr, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) { - UI::PushFont("WorkSans", UI::FontMode::Regular, 18.f); - UI::Text("Projects"); + UI::PushFont("WorkSans", UI::FontMode::Regular, 24.f); + TextCentered("Projects"); UI::PopFont(); - UI::Separator(); + + UI::Spacing(); UI::Spacing(); + static p::String folder; + + ImGui::BeginTable("table", 2); + ImGui::TableNextColumn(); + { + UI::PushFont("WorkSans", UI::FontMode::Regular, 18.f); + UI::Text("Open"); + UI::PopFont(); + UI::Separator(); + UI::Spacing(); + + UI::SetItemDefaultFocus(); + { + UI::Text("Recent projects:"); + static const char* recentProjects[]{"Project.rift"}; + static int selectedN = 0; + UI::SetNextItemWidth(-FLT_MIN); + + for (int n = 0; n < IM_ARRAYSIZE(recentProjects); ++n) + { + const bool isSelected = (selectedN == n); + UI::BulletText(recentProjects[n]); + UI::SameLine(ImGui::GetContentRegionAvail().x - 30.f); + if (UI::SmallButton("open")) {} + } + } + UI::Dummy({10.f, 40.f}); + } + ImGui::TableNextColumn(); + { + UI::PushFont("WorkSans", UI::FontMode::Regular, 18.f); + UI::Text("Create"); + UI::PopFont(); + UI::Separator(); + UI::Spacing(); + + UI::PushItemWidth(-32.f); + UI::InputTextWithHint("##path", "project path...", folder); + UI::PopItemWidth(); + UI::SameLine(); + if (UI::Button("...", p::v2{24.f, 0.f})) + { + p::Path selectedFolder = + p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + folder = p::ToString(selectedFolder); + } + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); if (UI::Button("Open", p::v2{-FLT_MIN, 0.0f})) { p::String folder = @@ -45,60 +105,7 @@ namespace rift::Editor p::Strings::Format("Failed to open project at '{}'", p::ToString(folder))}); } } - UI::SetItemDefaultFocus(); - { - UI::Text("Recent Projects"); - static const char* recentProjects[]{"One recent project"}; - static int selectedN = 0; - UI::SetNextItemWidth(-FLT_MIN); - if (UI::BeginListBox("##RecentProjects")) - { - for (int n = 0; n < IM_ARRAYSIZE(recentProjects); ++n) - { - const bool isSelected = (selectedN == n); - if (UI::Selectable(recentProjects[n], isSelected)) - { - selectedN = n; - } - - // Set the initial focus when opening the combo (scrolling + keyboard - // navigation focus) - if (isSelected) - { - UI::SetItemDefaultFocus(); - } - } - UI::EndListBox(); - } - } - - - UI::Spacing(); - UI::Spacing(); - UI::Spacing(); - UI::Spacing(); - - UI::PushFont("WorkSans", UI::FontMode::Regular, 18.f); - UI::Text("New"); - UI::PopFont(); - UI::Separator(); - UI::Spacing(); - - UI::AlignTextToFramePadding(); - UI::Text("Destination"); - UI::SameLine(); - static p::String folder; - UI::PushItemWidth(-32.f); - UI::InputText("##path", folder); - UI::PopItemWidth(); - UI::SameLine(); - if (UI::Button("...", p::v2{24.f, 0.f})) - { - p::Path selectedFolder = - p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); - folder = p::ToString(selectedFolder); - } - + ImGui::TableNextColumn(); if (UI::Button("Create", p::v2{-FLT_MIN, 0.0f})) { if (Editor::Get().CreateProject(folder)) @@ -112,6 +119,7 @@ namespace rift::Editor p::Strings::Format("Failed to create project at '{}'", folder)}); } } + ImGui::EndTable(); UI::EndPopup(); } diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index 9dea372b..a20f8111 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -120,6 +120,8 @@ namespace rift::UI "WorkSans", UI::FontMode::Regular, 14.f, resources / "Fonts/WorkSans-Regular.ttf"); AddTextFont( "WorkSans", UI::FontMode::Regular, 18.f, resources / "Fonts/WorkSans-Regular.ttf"); + AddTextFont( + "WorkSans", UI::FontMode::Regular, 24.f, resources / "Fonts/WorkSans-Regular.ttf"); // Karla AddTextFont("Karla", UI::FontMode::Bold, 14.f, resources / "Fonts/Karla-Bold.ttf"); From 0cc63e32c3d0e1075a0e4a8d07ab0ab6049f7acf Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 24 Feb 2024 21:33:09 +0100 Subject: [PATCH 29/52] Updated Pipe --- .github/workflows/build.yml | 57 +++++++------------ .gitignore | 1 - Apps/CLI/Src/main.cpp | 2 +- Extern/Pipe | 2 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 10 ++-- .../Include/AST/Utils/ModuleFileIterator.h | 6 +- Libs/AST/Include/AST/Utils/TypeIterator.h | 10 ++-- Libs/AST/Include/Compiler/CompilerConfig.h | 6 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 2 +- Libs/AST/Src/Compiler/CompilerConfig.cpp | 4 +- .../Native/Compiler/Include/HeaderIterator.h | 6 +- .../Compiler/Src/NativeBindingModule.cpp | 2 +- Libs/Editor/Include/Editor.h | 2 +- Libs/Editor/Src/Editor.cpp | 4 +- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 6 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 6 +- Libs/Editor/Src/Utils/ProjectManager.cpp | 2 +- Libs/UI/Include/UI/Paths.h | 5 +- Libs/UI/Src/Inspection.cpp | 2 +- Libs/UI/Src/Paths.cpp | 7 ++- Libs/UI/Src/Style.cpp | 55 ++++++++++-------- Tools/SetupLLVM.py | 39 ------------- imgui.ini | 17 ++++++ 23 files changed, 109 insertions(+), 144 deletions(-) delete mode 100644 Tools/SetupLLVM.py create mode 100644 imgui.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 022aefb4..2ad7e2c8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,9 +10,6 @@ on: pull_request: workflow_call: -env: - cache-version: 0 - jobs: Build: name: ${{ matrix.os-name }} (${{ matrix.compiler }}, ${{ matrix.config }}) @@ -32,34 +29,33 @@ jobs: - name: windows-clang os: windows-latest os-name: windows - compiler: clang + compiler: clang-16 cxx: clang-cl cc: clang-cl - name: linux-clang os: ubuntu-latest os-name: linux - compiler: clang + compiler: clang-16 cxx: clang++ cc: clang - name: linux-gcc os: ubuntu-latest os-name: linux - compiler: gcc - cxx: g++-13 - cc: gcc-13 + compiler: gcc-13 + cxx: g++ + cc: gcc - name: macos-clang - os: macos-latest + os: macos-14 os-name: macos - compiler: clang + compiler: clang-16 cxx: clang++ cc: clang steps: - name: Checkout repository - uses: actions/checkout@v2 - - - name: Init Submodules - uses: snickerbockers/submodules-init@v4 + uses: actions/checkout@v3 + with: + submodules: 'recursive' - name: Install dependencies if: ${{ matrix.os-name == 'linux'}} @@ -67,42 +63,29 @@ jobs: sudo apt-get update sudo apt-get install -y build-essential xz-utils curl libx11-dev xorg-dev libglu1-mesa-dev - - uses: ilammy/msvc-dev-cmd@v1 - if: ${{ matrix.compiler == 'msvc' }} - - - name: Cache LLVM - if: ${{ matrix.compiler == 'clang' }} - id: cache-llvm - uses: actions/cache@v2 - with: - path: ${{ runner.temp }}/llvm - key: llvm-15.0-${{ matrix.os-name }} - - name: Install LLVM - if: ${{ matrix.compiler == 'clang' }} - uses: KyleMayes/install-llvm-action@v1 + - name: Setup Cpp + uses: aminya/setup-cpp@v1 with: - version: "15.0" - directory: ${{ runner.temp }}/llvm - cached: ${{ steps.cache-llvm.outputs.cache-hit }} - - - name: Get CMake - uses: lukka/get-cmake@latest + compiler: ${{ matrix.compiler }} + vcvarsall: ${{ matrix.os-name == 'windows' }} + cmake: true + ninja: true - name: Cache Build - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: Build key: ${{ matrix.os-name }}-${{ matrix.compiler }}-${{ matrix.config }}-build-${{ secrets.VCACHE}} - name: Configure - run: cmake -S . -B Build -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DRIFT_LLVM_PATH='${{ runner.temp }}/rift/llvm' + run: cmake -GNinja -S . -B Build -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DRIFT_LLVM_PATH='${{ runner.temp }}/rift/llvm' - name: Build run: cmake --build Build --config ${{ matrix.config }} - name: Upload binaries as artifacts - uses: actions/upload-artifact@v2 - if: ${{ matrix.config == 'Release' && matrix.compiler == 'clang' }} # Only clang artifacts are stored + uses: actions/upload-artifact@v3 + if: ${{ matrix.config == 'Release' && contains(matrix.compiler, 'clang') }} # Only clang artifacts are stored with: name: rift-${{ matrix.os-name }} path: Build/Bin diff --git a/.gitignore b/.gitignore index 4d074fe4..6b99fa29 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ Build Saved Testing -Extern/rift-llvm .vscode/c_cpp_properties.json /compile_commands.json diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index 1ae06d2e..2bd9487d 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -18,7 +18,6 @@ #include - using namespace rift; @@ -65,6 +64,7 @@ namespace rift int main(int argc, char** argv) { p::Initialize("Saved/Logs"); + p::Info(p::GetUserSettingsPath()); EnableModule(); EnableModule(); EnableModule(); diff --git a/Extern/Pipe b/Extern/Pipe index 8318c2b4..e0281533 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 8318c2b4456912d284ed8f5ab7baf71bf5ce9e7d +Subproject commit e02815332bc95b683c9af607addc27f4104d250f diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index c86a00f3..affdf907 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -11,14 +11,14 @@ namespace rift::ast { // Contains loaded string data from disk - struct SStringLoad : public Struct + struct SStringLoad : public p::Struct { - P_STRUCT(SStringLoad, Struct) + P_STRUCT(SStringLoad, p::Struct) // This buffers are always in sync with size // They bind by array index an Id, path and loaded string - TArray entities; - TArray paths; - TArray strings; + TArray entities; + TArray paths; + TArray strings; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h index 0e1b23a2..463f2026 100644 --- a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -16,9 +16,9 @@ namespace rift::ast public: using Super::Super; - explicit ModuleFileIterator(const p::Path& path) - : Super(path, [](const auto& path) { - return path.filename() == moduleFilename; + explicit ModuleFileIterator(p::StringView path) + : Super(path, [](p::StringView path) { + return p::GetFilename(path) == moduleFilename; }) {} }; diff --git a/Libs/AST/Include/AST/Utils/TypeIterator.h b/Libs/AST/Include/AST/Utils/TypeIterator.h index f57b7340..f4313b53 100644 --- a/Libs/AST/Include/AST/Utils/TypeIterator.h +++ b/Libs/AST/Include/AST/Utils/TypeIterator.h @@ -9,16 +9,16 @@ namespace rift::ast { - class TypeIterator : public p::files::LambdaFileIterator + class TypeIterator : public p::LambdaFileIterator { - using Super = p::files::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; - explicit TypeIterator(const p::Path& path) - : Super(path, [](const auto& path) { - return path.extension() == Paths::typeExtension; + explicit TypeIterator(p::StringView path) + : Super(path, [](p::StringView path) { + return p::GetExtension(path) == Paths::typeExtension; }) {} }; diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index e952ee3f..0bd2044b 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -36,9 +36,9 @@ namespace rift bool debug = true; bool verbose = false; - Path buildPath; - Path intermediatesPath; - Path binariesPath; + String buildPath; + String intermediatesPath; + String binariesPath; void Init(ast::Tree& ast); }; diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index e485a816..3eb45768 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -92,7 +92,7 @@ namespace rift::ast::LoadSystem pathsByModule.Reserve(modules.Size()); for (Id moduleId : modules) { - Path path = ast::GetModulePath(access, moduleId); + p::StringView path = ast::GetModulePath(access, moduleId); auto& paths = pathsByModule.AddRef({moduleId}).paths; // Iterate all types ignoring other module paths diff --git a/Libs/AST/Src/Compiler/CompilerConfig.cpp b/Libs/AST/Src/Compiler/CompilerConfig.cpp index fe8d09bf..89f0ff9b 100644 --- a/Libs/AST/Src/Compiler/CompilerConfig.cpp +++ b/Libs/AST/Src/Compiler/CompilerConfig.cpp @@ -10,7 +10,7 @@ namespace rift void CompilerConfig::Init(ast::Tree& ast) { buildPath = p::JoinPaths(ast::GetProjectPath(ast), "Build"); - intermediatesPath = buildPath / "Intermediates"; - binariesPath = buildPath / "Binaries"; + intermediatesPath = p::JoinPaths(buildPath, "Intermediates"); + binariesPath = p::JoinPaths(buildPath, "Binaries"); } } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h index 5d59a0c3..46018ffd 100644 --- a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h +++ b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h @@ -18,9 +18,9 @@ namespace rift static constexpr p::StringView headerExtension = ".h"; - explicit HeaderIterator(const p::Path& path) - : Super(path, [](const auto& path) { - return path.extension() == headerExtension; + explicit HeaderIterator(StringView path) + : Super(path, [](StringView path) { + return p::GetExtension(path) == headerExtension; }) {} }; diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 6b8ca1dc..281374ec 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -54,7 +54,7 @@ namespace rift p::TAccess access{ast}; for (auto& module : parsedModules) { - Path path = ast::GetModulePath(access, module.id); + StringView path = ast::GetModulePath(access, module.id); for (const auto& headerPath : HeaderIterator(path)) { module.headers.Add(p::ToString(headerPath)); diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index bdf10b29..b62ab703 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -39,7 +39,7 @@ namespace rift::Editor void Tick(); - void SetUIConfigFile(p::Path path); + void SetUIConfigFile(p::StringView path); static Editor& Get() { diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index ba5ca473..8964655f 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -126,12 +126,12 @@ namespace rift::Editor } } - void Editor::SetUIConfigFile(Path path) + void Editor::SetUIConfigFile(p::StringView path) { if (UI::GetWindow()) { configFileChanged = true; - configFile = p::ToString(path); + configFile = path; ImGui::GetIO().IniFilename = configFile.c_str(); } } diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index 3965f0cf..cd0ba285 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -169,7 +169,7 @@ namespace rift::Editor if (UI::MenuItem("Create folder")) { - p::CreateFolder(p::ToPath(path) / "NewFolder"); + p::CreateFolder(p::JoinPaths(path, "NewFolder")); } } @@ -421,7 +421,7 @@ namespace rift::Editor p::ReplaceExtension(destination, "rf"); // TODO: Move this into systems. Renaming a type shouldnt require so many // manual steps - if (files::Rename(p::ToPath(path), destination)) + if (files::Rename(path, destination)) { if (auto* file = ast.TryGet(item.id)) { @@ -488,7 +488,7 @@ namespace rift::Editor String data; ast::SerializeType(ast, id, data); - files::SaveStringFile(path, data); + files::SaveStringFile(StringView{path}, data); // Destroy the temporal type after saving it ast.Destroy(id); diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index ffd1c18c..fb9618b7 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -273,7 +273,7 @@ namespace rift::Editor::EditorSystem if (UI::MenuItem("Open File")) {} if (UI::MenuItem(ICON_FA_SAVE " Save All", "CTRL+SHFT+S")) { - TArray> fileDatas; + TArray> fileDatas; // Path to file data auto dirtyTypeIds = FindAllIdsWith( @@ -391,7 +391,7 @@ namespace rift::Editor::EditorSystem String data; ast::SerializeModule(ast, moduleId, data); - files::SaveStringFile(file.path, data); + files::SaveStringFile(StringView(file.path), data); ast.Remove(moduleId); UI::AddNotification({UI::ToastType::Success, 1.f, @@ -497,7 +497,7 @@ namespace rift::Editor::EditorSystem String data; ast::SerializeType(ast, typeId, data); - files::SaveStringFile(file.path, data); + files::SaveStringFile(StringView(file.path), data); ast.Remove(typeId); UI::AddNotification({UI::ToastType::Success, 1.f, diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index f54df91e..42a26bac 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -83,7 +83,7 @@ namespace rift::Editor UI::SameLine(); if (UI::Button("...", p::v2{24.f, 0.f})) { - p::Path selectedFolder = + p::String selectedFolder = p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); folder = p::ToString(selectedFolder); } diff --git a/Libs/UI/Include/UI/Paths.h b/Libs/UI/Include/UI/Paths.h index bff1bd11..df4e11b5 100644 --- a/Libs/UI/Include/UI/Paths.h +++ b/Libs/UI/Include/UI/Paths.h @@ -7,8 +7,5 @@ namespace rift::Paths { - using namespace p; - - - Path GetResourcesPath(); + p::String GetResourcesPath(); }; // namespace rift::Paths diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index a3b78fe6..e91be384 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -363,7 +363,7 @@ namespace rift::UI String str = ToString(*path); if (UI::InputText("##value", str)) { - *path = p::ToPath(str); + *path = p::ToSTDPath(str); } }); } diff --git a/Libs/UI/Src/Paths.cpp b/Libs/UI/Src/Paths.cpp index 679769f7..f0c9fe38 100644 --- a/Libs/UI/Src/Paths.cpp +++ b/Libs/UI/Src/Paths.cpp @@ -2,11 +2,12 @@ #include "UI/Paths.h" + namespace rift::Paths { - Path GetResourcesPath() + p::String GetResourcesPath() { - static p::Path relativeResourcesPath{"./Resources"}; - return GetBasePath() / relativeResourcesPath; + static p::StringView relativeResourcesPath{"./Resources"}; + return p::JoinPaths(p::GetBasePath(), relativeResourcesPath); } }; // namespace rift::Paths diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index a20f8111..bad08c6c 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -71,14 +71,14 @@ namespace rift::UI static TMap gFonts{}; - ImFont* AddFont(Path file, float size, const ImFontConfig* fontConfig = nullptr, + ImFont* AddFont(p::StringView file, float size, const ImFontConfig* fontConfig = nullptr, const ImWchar* glyphRanges = nullptr) { auto& io = ImGui::GetIO(); - return io.Fonts->AddFontFromFileTTF(ToString(file).data(), size, fontConfig, glyphRanges); + return io.Fonts->AddFontFromFileTTF(file.data(), size, fontConfig, glyphRanges); } - void AddTextFont(Tag name, UI::FontMode mode, float size, p::Path file) + void AddTextFont(Tag name, UI::FontMode mode, float size, p::StringView file) { FontDescriptor* font = gFonts.Find(name); if (!font) @@ -87,7 +87,7 @@ namespace rift::UI font = &gFonts[name]; } - ImFont* imFont = AddFont(ToString(file).data(), size); + ImFont* imFont = AddFont(file.data(), size); (*font)[mode].Add(size, imFont); // Add Font Awesome icons @@ -97,7 +97,8 @@ namespace rift::UI iconsConfig.PixelSnapH = true; iconsConfig.GlyphMinAdvanceX = 14.f; // use FONT_ICON_FILE_NAME_FAR if you want regular instead of solid - AddFont(file.parent_path() / FONT_ICON_FILE_NAME_FAS, 14.0f, &iconsConfig, iconsRanges); + p::String path = p::JoinPaths(p::GetParentPath(file), FONT_ICON_FILE_NAME_FAS); + AddFont(path, 14.0f, &iconsConfig, iconsRanges); } void LoadFonts() @@ -105,33 +106,39 @@ namespace rift::UI auto& io = ImGui::GetIO(); io.Fonts->AddFontDefault(); - auto resources = rift::Paths::GetResourcesPath() / "Editor"; + auto resources = p::JoinPaths(rift::Paths::GetResourcesPath(), "Editor"); // Work Sans - AddTextFont("WorkSans", UI::FontMode::Bold, 14.f, resources / "Fonts/WorkSans-Bold.ttf"); + AddTextFont("WorkSans", UI::FontMode::Bold, 14.f, + p::JoinPaths(resources, "Fonts/WorkSans-Bold.ttf")); AddTextFont("WorkSans", UI::FontMode::BoldItalic, 14.f, - resources / "Fonts/WorkSans-BoldItalic.ttf"); - AddTextFont( - "WorkSans", UI::FontMode::Italic, 14.f, resources / "Fonts/WorkSans-Italic.ttf"); - AddTextFont("WorkSans", UI::FontMode::Light, 14.f, resources / "Fonts/WorkSans-Light.ttf"); + p::JoinPaths(resources, "Fonts/WorkSans-BoldItalic.ttf")); + AddTextFont("WorkSans", UI::FontMode::Italic, 14.f, + p::JoinPaths(resources, "Fonts/WorkSans-Italic.ttf")); + AddTextFont("WorkSans", UI::FontMode::Light, 14.f, + p::JoinPaths(resources, "Fonts/WorkSans-Light.ttf")); AddTextFont("WorkSans", UI::FontMode::LightItalic, 14.f, - resources / "Fonts/WorkSans-LightItalic.ttf"); - AddTextFont( - "WorkSans", UI::FontMode::Regular, 14.f, resources / "Fonts/WorkSans-Regular.ttf"); - AddTextFont( - "WorkSans", UI::FontMode::Regular, 18.f, resources / "Fonts/WorkSans-Regular.ttf"); - AddTextFont( - "WorkSans", UI::FontMode::Regular, 24.f, resources / "Fonts/WorkSans-Regular.ttf"); + p::JoinPaths(resources, "Fonts/WorkSans-LightItalic.ttf")); + AddTextFont("WorkSans", UI::FontMode::Regular, 14.f, + p::JoinPaths(resources, "Fonts/WorkSans-Regular.ttf")); + AddTextFont("WorkSans", UI::FontMode::Regular, 18.f, + p::JoinPaths(resources, "Fonts/WorkSans-Regular.ttf")); + AddTextFont("WorkSans", UI::FontMode::Regular, 24.f, + p::JoinPaths(resources, "Fonts/WorkSans-Regular.ttf")); // Karla - AddTextFont("Karla", UI::FontMode::Bold, 14.f, resources / "Fonts/Karla-Bold.ttf"); AddTextFont( - "Karla", UI::FontMode::BoldItalic, 14.f, resources / "Fonts/Karla-BoldItalic.ttf"); - AddTextFont("Karla", UI::FontMode::Italic, 14.f, resources / "Fonts/Karla-Italic.ttf"); - AddTextFont("Karla", UI::FontMode::Light, 14.f, resources / "Fonts/Karla-Light.ttf"); + "Karla", UI::FontMode::Bold, 14.f, p::JoinPaths(resources, "Fonts/Karla-Bold.ttf")); + AddTextFont("Karla", UI::FontMode::BoldItalic, 14.f, + p::JoinPaths(resources, "Fonts/Karla-BoldItalic.ttf")); + AddTextFont( + "Karla", UI::FontMode::Italic, 14.f, p::JoinPaths(resources, "Fonts/Karla-Italic.ttf")); AddTextFont( - "Karla", UI::FontMode::LightItalic, 14.f, resources / "Fonts/Karla-LightItalic.ttf"); - AddTextFont("Karla", UI::FontMode::Regular, 14.f, resources / "Fonts/Karla-Regular.ttf"); + "Karla", UI::FontMode::Light, 14.f, p::JoinPaths(resources, "Fonts/Karla-Light.ttf")); + AddTextFont("Karla", UI::FontMode::LightItalic, 14.f, + p::JoinPaths(resources, "Fonts/Karla-LightItalic.ttf")); + AddTextFont("Karla", UI::FontMode::Regular, 14.f, + p::JoinPaths(resources, "Fonts/Karla-Regular.ttf")); io.Fonts->Build(); } diff --git a/Tools/SetupLLVM.py b/Tools/SetupLLVM.py deleted file mode 100644 index 0765dd25..00000000 --- a/Tools/SetupLLVM.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import subprocess -import sys -import argparse - - -def main(argv): - rift_llvm_version = 'v15.0.6' - - this_file_path = os.path.dirname(__file__) - rift_path = os.path.dirname(this_file_path) - - parser = argparse.ArgumentParser(description = "Setup Rift's LLVM toolchain", formatter_class=argparse.ArgumentDefaultsHelpFormatter) - args = parser.parse_args() - - rift_llvm_relpath = 'Extern/rift-llvm' - rift_llvm_path = os.path.join(rift_path, rift_llvm_relpath) - - if not os.path.exists(rift_llvm_path): - print('> Downloading rift-llvm') - subprocess.run('git clone -s --depth 1 --branch {} https://github.com/PipeRift/rift-llvm.git {}'.format(rift_llvm_version, rift_llvm_path), shell=True, check=True) - os.chdir(rift_llvm_path) - else: - print('> Updating rift-llvm') - os.chdir(rift_llvm_path) - os.system('git pull origin {}'.format(rift_llvm_version)) - - print('\n> Init LLVM') - os.system('python3 init.py') - - print('\n> Build LLVM') - os.system('python3 build.py --config Debug') - os.system('python3 build.py --config Release') - os.system('python3 build.py --config RelWithDebInfo') - os.system('python3 build.py --config MinSizeRel') - -if __name__ == "__main__": - main(sys.argv[1:]) - diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 00000000..446db75d --- /dev/null +++ b/imgui.ini @@ -0,0 +1,17 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Project Manager] +Pos=340,355 +Size=600,189 +Collapsed=0 + +[Window][##Notification_0] +Pos=1058,850 +Size=202,30 +Collapsed=0 + +[Docking][Data] + From a4d6e5db6a41a498121ab1e80092e5648432223e Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 24 Feb 2024 21:33:53 +0100 Subject: [PATCH 30/52] Small change --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index e0281533..cf14a81d 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit e02815332bc95b683c9af607addc27f4104d250f +Subproject commit cf14a81d45647e87363ea2d382cde3770d2223a7 From 99c3517b7dc00cd4650a2d793cd9007c08fbda86 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 25 Feb 2024 23:54:56 +0100 Subject: [PATCH 31/52] Updated Pipe --- Apps/CLI/Src/main.cpp | 4 +++- Extern/Pipe | 2 +- Libs/AST/Include/AST/Utils/ModuleFileIterator.h | 4 ++-- Libs/AST/Include/AST/Utils/TypeIterator.h | 4 ++-- .../Native/Compiler/Include/HeaderIterator.h | 4 ++-- Libs/Editor/Include/Editor.h | 2 +- Libs/Editor/Include/Statics/SEditor.h | 3 ++- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 8 ++++---- Libs/Editor/Src/Systems/EditorSystem.cpp | 7 ++++--- Libs/Editor/Src/Utils/ProjectManager.cpp | 11 ++++++----- Libs/UI/Include/UI/Paths.h | 1 + Libs/UI/Src/Paths.cpp | 12 ++++++++++-- Libs/UI/Src/Window.cpp | 9 ++++++--- Tests/Project.spec.cpp | 4 +++- 14 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index 2bd9487d..b27106dc 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ #include + using namespace rift; @@ -64,7 +66,7 @@ namespace rift int main(int argc, char** argv) { p::Initialize("Saved/Logs"); - p::Info(p::GetUserSettingsPath()); + p::Info(p::PlatformPaths::GetUserSettingsPath()); EnableModule(); EnableModule(); EnableModule(); diff --git a/Extern/Pipe b/Extern/Pipe index cf14a81d..bd62c813 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit cf14a81d45647e87363ea2d382cde3770d2223a7 +Subproject commit bd62c813a1b277e1500f9aab169d11c8877a0784 diff --git a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h index 463f2026..f76341ac 100644 --- a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -9,9 +9,9 @@ namespace rift::ast { - class ModuleFileIterator : public p::LambdaFileIterator + class ModuleFileIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/AST/Include/AST/Utils/TypeIterator.h b/Libs/AST/Include/AST/Utils/TypeIterator.h index f4313b53..3ed526cf 100644 --- a/Libs/AST/Include/AST/Utils/TypeIterator.h +++ b/Libs/AST/Include/AST/Utils/TypeIterator.h @@ -9,9 +9,9 @@ namespace rift::ast { - class TypeIterator : public p::LambdaFileIterator + class TypeIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h index 46018ffd..ada4bb47 100644 --- a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h +++ b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h @@ -9,9 +9,9 @@ namespace rift { - class HeaderIterator : public p::LambdaFileIterator + class HeaderIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index b62ab703..fdd0008b 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -1,7 +1,7 @@ // Copyright 2015-2023 Piperift - All rights reserved #pragma once -#include "Pipe/Files/FileWatcher.h" +#include "PipeFiles.h" #include #include diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index 578b7af0..d3acf628 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -9,12 +9,13 @@ #include "Tools/MemoryDebugger.h" #include "Tools/ReflectionDebugger.h" -#include #include #include +#include #include + namespace rift::Editor { struct SEditor : public Struct diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index cd0ba285..c6030b70 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -18,12 +18,12 @@ #include #include #include -#include #include -#include #include #include +#include #include +#include #include #include #include @@ -175,7 +175,7 @@ namespace rift::Editor if (UI::MenuItem("Show in Explorer")) { - PlatformProcess::ShowFolder(path); + PlatformPaths::ShowFolder(path); } } @@ -478,7 +478,7 @@ namespace rift::Editor void FileExplorerPanel::CreateType( ast::Tree& ast, StringView title, p::Tag typeId, p::StringView folderPath) { - const p::String path = files::SaveFileDialog(title, folderPath, + const p::String path = p::SaveFileDialog(title, folderPath, { {"Rift Type", Strings::Format("*.{}", Paths::typeExtension)} }, diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index fb9618b7..0db7461e 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -26,10 +26,11 @@ #include #include #include -#include #include +#include #include #include +#include #include #include #include @@ -257,8 +258,8 @@ namespace rift::Editor::EditorSystem { if (UI::MenuItem("Open Project")) { - const p::String folder = - files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + const p::String folder = p::SelectFolderDialog( + "Select project folder", p::PlatformPaths::GetCurrentPath()); if (Editor::Get().OpenProject(folder)) { editorData.skipFrameAfterMenu = true; diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 42a26bac..55a0274b 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -3,7 +3,8 @@ #include "Editor.h" #include "Utils/ElementsPanel.h" -#include +#include +#include #include #include @@ -83,8 +84,8 @@ namespace rift::Editor UI::SameLine(); if (UI::Button("...", p::v2{24.f, 0.f})) { - p::String selectedFolder = - p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + p::String selectedFolder = p::SelectFolderDialog( + "Select project folder", p::PlatformPaths::GetCurrentPath()); folder = p::ToString(selectedFolder); } } @@ -93,8 +94,8 @@ namespace rift::Editor ImGui::TableNextColumn(); if (UI::Button("Open", p::v2{-FLT_MIN, 0.0f})) { - p::String folder = - p::files::SelectFolderDialog("Select project folder", p::GetCurrentPath()); + p::String folder = p::SelectFolderDialog( + "Select project folder", p::PlatformPaths::GetCurrentPath()); if (Editor::Get().OpenProject(folder)) { UI::CloseCurrentPopup(); diff --git a/Libs/UI/Include/UI/Paths.h b/Libs/UI/Include/UI/Paths.h index df4e11b5..8605df1a 100644 --- a/Libs/UI/Include/UI/Paths.h +++ b/Libs/UI/Include/UI/Paths.h @@ -8,4 +8,5 @@ namespace rift::Paths { p::String GetResourcesPath(); + p::String GetUserSettingsPath(); }; // namespace rift::Paths diff --git a/Libs/UI/Src/Paths.cpp b/Libs/UI/Src/Paths.cpp index f0c9fe38..d1c72f99 100644 --- a/Libs/UI/Src/Paths.cpp +++ b/Libs/UI/Src/Paths.cpp @@ -2,12 +2,20 @@ #include "UI/Paths.h" +#include + namespace rift::Paths { p::String GetResourcesPath() { - static p::StringView relativeResourcesPath{"./Resources"}; - return p::JoinPaths(p::GetBasePath(), relativeResourcesPath); + static p::StringView relativeResourcesPath{"Resources"}; + return p::JoinPaths(p::PlatformPaths::GetBasePath(), relativeResourcesPath); + } + + p::String GetUserSettingsPath() + { + static p::StringView relativeSettingsPath{"Rift"}; + return p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath); } }; // namespace rift::Paths diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index c96d7a3d..b638cd09 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -17,8 +17,10 @@ #include #include #include +#include #include + #define STB_IMAGE_IMPLEMENTATION #include @@ -173,11 +175,12 @@ namespace rift::UI void SetWindowIcon() { - p::String icon64Path = p::JoinPaths(p::GetBasePath(), "Resources/Editor/Icons/Logo_64.png"); + p::String icon64Path = + p::JoinPaths(p::PlatformPaths::GetBasePath(), "Resources/Editor/Icons/Logo_64.png"); p::String icon128Path = - p::JoinPaths(p::GetBasePath(), "Resources/Editor/Icons/Logo_128.png"); + p::JoinPaths(p::PlatformPaths::GetBasePath(), "Resources/Editor/Icons/Logo_128.png"); p::String icon256Path = - p::JoinPaths(p::GetBasePath(), "Resources/Editor/Icons/Logo_256.png"); + p::JoinPaths(p::PlatformPaths::GetBasePath(), "Resources/Editor/Icons/Logo_256.png"); GLFWimage images[3]; images[0].pixels = stbi_load(icon64Path.c_str(), &images[0].width, &images[0].height, nullptr, 0); diff --git a/Tests/Project.spec.cpp b/Tests/Project.spec.cpp index e3ac75d5..aee24b86 100644 --- a/Tests/Project.spec.cpp +++ b/Tests/Project.spec.cpp @@ -6,19 +6,21 @@ #include #include #include +#include #include #include #include + using namespace snowhouse; using namespace bandit; using namespace rift; using namespace p; using namespace std::chrono_literals; -String testProjectPath = p::JoinPaths(GetCurrentPath(), "TestProject"); +String testProjectPath = p::JoinPaths(PlatformPaths::GetCurrentPath(), "TestProject"); go_bandit([]() { From 6b5c0da681b6cc88bb900ec505ed27cc76d6d2ef Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 28 Feb 2024 23:57:50 +0100 Subject: [PATCH 32/52] Fix pipe namespaces --- Apps/Editor/Src/main.cpp | 2 +- Extern/Pipe | 2 +- Libs/AST/Include/AST/Id.h | 1 - Libs/AST/Include/AST/Statics/SLoadQueue.h | 4 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 6 +- Libs/AST/Include/AST/Statics/STypes.h | 8 +- Libs/AST/Include/AST/Systems/LoadSystem.h | 16 ++-- Libs/AST/Include/AST/Systems/TypeSystem.h | 11 +-- Libs/AST/Include/AST/Tree.h | 2 +- Libs/AST/Include/AST/Utils/Expressions.h | 15 ++-- Libs/AST/Include/AST/Utils/ModuleUtils.h | 18 ++-- Libs/AST/Include/AST/Utils/Settings.h | 34 ++++++++ Libs/AST/Include/AST/Utils/Statements.h | 36 ++++---- Libs/AST/Include/AST/Utils/TransactionUtils.h | 7 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 44 +++++----- Libs/AST/Include/Compiler/Backend.h | 8 +- Libs/AST/Include/Compiler/Compiler.h | 12 +-- Libs/AST/Include/Compiler/CompilerConfig.h | 8 +- .../AST/Include/Compiler/Utils/BackendUtils.h | 4 +- Libs/AST/Src/AST/Systems/FunctionsSystem.cpp | 67 +++++++-------- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 60 ++++++------- Libs/AST/Src/AST/Systems/TypeSystem.cpp | 24 +++--- Libs/AST/Src/AST/Tree.cpp | 22 ++--- Libs/AST/Src/AST/Utils/Expressions.cpp | 31 +++---- Libs/AST/Src/AST/Utils/ModuleUtils.cpp | 62 +++++++------- Libs/AST/Src/AST/Utils/Namespaces.cpp | 36 ++++---- Libs/AST/Src/AST/Utils/Settings.cpp | 16 ++++ Libs/AST/Src/AST/Utils/Statements.cpp | 21 ++--- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 7 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 21 ++--- Libs/AST/Src/Compiler/Compiler.cpp | 4 +- Libs/AST/Src/Compiler/Utils/BackendUtils.cpp | 15 ++-- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 4 +- .../MIR/Compiler/Src/IRGeneration.cpp | 84 +++++++++---------- Libs/Editor/Include/Components/CDeclRename.h | 4 +- .../Editor/Include/Components/CModuleEditor.h | 4 +- Libs/Editor/Include/Components/CTypeEditor.h | 4 +- Libs/Editor/Include/DockSpaceLayout.h | 4 +- Libs/Editor/Include/Editor.h | 4 +- .../Editor/Include/Panels/FileExplorerPanel.h | 4 +- Libs/Editor/Include/Statics/SEditor.h | 5 +- Libs/Editor/Include/Systems/EditorSystem.h | 4 +- Libs/Editor/Include/Tools/ASTDebugger.h | 4 +- .../Include/Tools/BigBestFitArenaDebugger.h | 5 +- Libs/Editor/Include/Tools/GraphPlayground.h | 4 +- Libs/Editor/Include/Tools/MemoryDebugger.h | 5 +- .../Editor/Include/Tools/ReflectionDebugger.h | 4 +- Libs/Editor/Include/UserSettings.h | 18 ++++ Libs/Editor/Include/Utils/DetailsPanel.h | 4 +- Libs/Editor/Include/Utils/EditorStyle.h | 4 +- Libs/Editor/Include/Utils/ElementsPanel.h | 4 +- Libs/Editor/Include/Utils/FunctionGraph.h | 4 +- .../Include/Utils/FunctionGraphContextMenu.h | 4 +- Libs/Editor/Include/Utils/ModuleUtils.h | 10 +-- Libs/Editor/Include/Utils/ProjectManager.h | 4 +- Libs/Editor/Include/Utils/TypeUtils.h | 10 +-- Libs/Editor/Include/Utils/Widgets.h | 6 +- Libs/Editor/Src/DockSpaceLayout.cpp | 4 +- Libs/Editor/Src/Editor.cpp | 6 +- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 8 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 10 +-- Libs/Editor/Src/Tools/ASTDebugger.cpp | 8 +- .../Src/Tools/BigBestFitArenaDebugger.cpp | 4 +- Libs/Editor/Src/Tools/GraphPlayground.cpp | 4 +- Libs/Editor/Src/Tools/MemoryDebugger.cpp | 4 +- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 4 +- Libs/Editor/Src/Utils/DetailsPanel.cpp | 6 +- Libs/Editor/Src/Utils/EditorStyle.cpp | 4 +- Libs/Editor/Src/Utils/ElementsPanel.cpp | 6 +- Libs/Editor/Src/Utils/FunctionGraph.cpp | 31 +++---- .../Src/Utils/FunctionGraphContextMenu.cpp | 4 +- Libs/Editor/Src/Utils/ModuleUtils.cpp | 10 +-- Libs/Editor/Src/Utils/ProjectManager.cpp | 4 +- Libs/Editor/Src/Utils/TypeUtils.cpp | 10 +-- Libs/Editor/Src/Utils/Widgets.cpp | 4 +- Libs/UI/Include/UI/Inspection.h | 15 ++-- Libs/UI/Include/UI/Paths.h | 1 - Libs/UI/Include/UI/Style.h | 57 ++++++------- Libs/UI/Src/Paths.cpp | 6 -- Libs/UI/Src/Style.cpp | 3 - Libs/UI/Src/Window.cpp | 3 - Tests/Project.spec.cpp | 15 ++-- 82 files changed, 559 insertions(+), 507 deletions(-) create mode 100644 Libs/AST/Include/AST/Utils/Settings.h create mode 100644 Libs/AST/Src/AST/Utils/Settings.cpp create mode 100644 Libs/Editor/Include/UserSettings.h diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index 58c4925b..4fc2bfa4 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -26,7 +26,7 @@ int RunEditor(StringView projectPath) EnableModule(); EnableModule(); - const int result = Editor::Editor::Get().Run(projectPath); + const int result = editor::Editor::Get().Run(projectPath); p::Shutdown(); return result; } diff --git a/Extern/Pipe b/Extern/Pipe index bd62c813..54e26582 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit bd62c813a1b277e1500f9aab169d11c8877a0784 +Subproject commit 54e2658265dfeaa0f06fd2394567b3eab0a2dbf2 diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index 417c85c8..cd148aa4 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -9,7 +9,6 @@ namespace rift::ast { - using namespace p; using Id = p::Id; constexpr Id NoId = p::NoId; diff --git a/Libs/AST/Include/AST/Statics/SLoadQueue.h b/Libs/AST/Include/AST/Statics/SLoadQueue.h index 18dca457..e2d4f1f5 100644 --- a/Libs/AST/Include/AST/Statics/SLoadQueue.h +++ b/Libs/AST/Include/AST/Statics/SLoadQueue.h @@ -13,7 +13,7 @@ namespace rift::ast { P_STRUCT(SLoadQueue, p::Struct) - TArray pendingSyncLoad; - TArray pendingAsyncLoad; + p::TArray pendingSyncLoad; + p::TArray pendingAsyncLoad; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index affdf907..4c079ee3 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -17,8 +17,8 @@ namespace rift::ast // This buffers are always in sync with size // They bind by array index an Id, path and loaded string - TArray entities; - TArray paths; - TArray strings; + p::TArray entities; + p::TArray paths; + p::TArray strings; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index 9fdda5bd..c74a0401 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -9,13 +9,13 @@ namespace rift::ast { - struct STypes : public Struct + struct STypes : public p::Struct { - P_STRUCT(STypes, Struct) + P_STRUCT(STypes, p::Struct) - TMap typesByName; + p::TMap typesByName; // TODO: Use StringView to point to CFileRef component's path. // Current TMap lookup of stringviews seems unconsistent - TMap typesByPath; + p::TMap typesByPath; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Systems/LoadSystem.h b/Libs/AST/Include/AST/Systems/LoadSystem.h index 5d096461..397a7de4 100644 --- a/Libs/AST/Include/AST/Systems/LoadSystem.h +++ b/Libs/AST/Include/AST/Systems/LoadSystem.h @@ -30,18 +30,20 @@ namespace rift::ast::LoadSystem /** * @param paths of all currently unloaded modules */ - void ScanSubmodules(Tree& ast, TArray& paths); + void ScanSubmodules(Tree& ast, p::TArray& paths); /** * @param paths of all currently unloaded types */ - void ScanTypes(Tree& ast, TArray& pathsByModule); + void ScanTypes(Tree& ast, p::TArray& pathsByModule); - void CreateModulesFromPaths(Tree& ast, TArray& paths, TArray& ids); - void CreateTypesFromPaths(Tree& ast, TView pathsByModule, TArray& ids); + void CreateModulesFromPaths(Tree& ast, p::TArray& paths, p::TArray& ids); + void CreateTypesFromPaths( + Tree& ast, p::TView pathsByModule, p::TArray& ids); - void LoadFileStrings(TAccessRef access, TView nodes, TArray& strings); + void LoadFileStrings( + p::TAccessRef access, p::TView nodes, p::TArray& strings); - void DeserializeModules(Tree& ast, TView moduleIds, TView strings); - void DeserializeTypes(Tree& ast, TView typeIds, TView strings); + void DeserializeModules(Tree& ast, p::TView moduleIds, p::TView strings); + void DeserializeTypes(Tree& ast, p::TView typeIds, p::TView strings); } // namespace rift::ast::LoadSystem diff --git a/Libs/AST/Include/AST/Systems/TypeSystem.h b/Libs/AST/Include/AST/Systems/TypeSystem.h index 716ad1ab..4c7a9bae 100644 --- a/Libs/AST/Include/AST/Systems/TypeSystem.h +++ b/Libs/AST/Include/AST/Systems/TypeSystem.h @@ -15,19 +15,16 @@ namespace rift::ast namespace rift::ast::TypeSystem { - using namespace p; - - void Init(Tree& ast); using PropagateVariableTypesAccess = - TAccessRef>; + p::TAccessRef>; void PropagateVariableTypes(PropagateVariableTypesAccess access); - using PropagateExpressionTypesAccess = TAccessRef, CExprUnaryOperator, CExprBinaryOperator, CParent>; + using PropagateExpressionTypesAccess = p::TAccessRef, CExprUnaryOperator, CExprBinaryOperator, p::CParent>; void PropagateExpressionTypes(PropagateExpressionTypesAccess access); void ResolveExprTypeIds( - TAccessRef, CExprType, CNamespace, CParent, CChild> access); + p::TAccessRef, CExprType, CNamespace, p::CParent, p::CChild> access); } // namespace rift::ast::TypeSystem diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index 24ef919f..abb46cdd 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -51,7 +51,7 @@ namespace rift::ast static const p::TBroadcast& OnInit(); - String DumpPools(); + p::String DumpPools(); private: void CopyFrom(const Tree& other); diff --git a/Libs/AST/Include/AST/Utils/Expressions.h b/Libs/AST/Include/AST/Utils/Expressions.h index f12b13d6..8eb1f0ec 100644 --- a/Libs/AST/Include/AST/Utils/Expressions.h +++ b/Libs/AST/Include/AST/Utils/Expressions.h @@ -13,10 +13,10 @@ // NOTE: In expression graphs, the Link Id is the Input Pin Id namespace rift::ast { - bool CanConnectExpr(TAccessRef access, + bool CanConnectExpr(p::TAccessRef access, ExprOutput output, ExprInput input); - bool TryConnectExpr(TAccessRef, CExprOutputs, CExprTypeId> access, + bool TryConnectExpr(p::TAccessRef, CExprOutputs, CExprTypeId> access, ExprOutput output, ExprInput input); // Disconnects a particular link. (Note: link ids are the same as input nodes) bool DisconnectExpr(Tree& ast, ExprInput input); @@ -27,11 +27,12 @@ namespace rift::ast * @param ids * @param ignoreRoot ignore ids's inputs and outputs and only remove from children */ - void DisconnectAllExprDeep(Tree& ast, TView ids, bool ignoreRoot = false); + void DisconnectAllExprDeep(Tree& ast, p::TView ids, bool ignoreRoot = false); - bool RemoveExprInputPin(TAccessRef> access, ExprInput id); - bool RemoveExprOutputPin(TAccessRef> access, ExprOutput id); + bool RemoveExprInputPin(p::TAccessRef> access, ExprInput id); + bool RemoveExprOutputPin( + p::TAccessRef> access, ExprOutput id); - ExprInput GetExprInputFromPin(TAccessRef access, Id pinId); - ExprOutput GetExprOutputFromPin(TAccessRef access, Id pinId); + ExprInput GetExprInputFromPin(p::TAccessRef access, Id pinId); + ExprOutput GetExprOutputFromPin(p::TAccessRef access, Id pinId); } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index a2902720..720627c0 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -39,30 +39,30 @@ namespace rift::ast } }; - bool CreateProject(Tree& ast, StringView path); - bool OpenProject(Tree& ast, StringView path); + bool CreateProject(Tree& ast, p::StringView path); + bool OpenProject(Tree& ast, p::StringView path); void CloseProject(Tree& ast); - Id CreateModule(Tree& ast, StringView path); + Id CreateModule(Tree& ast, p::StringView path); Id GetProjectId(p::TAccessRef access); - Tag GetProjectName(p::TAccessRef access); + p::Tag GetProjectName(p::TAccessRef access); p::StringView GetProjectPath(p::TAccessRef access); CModule* GetProjectModule(p::TAccessRef> access); bool HasProject(Tree& ast); // Resolve a module's name - Tag GetModuleName(p::TAccessRef access, Id moduleId); + p::Tag GetModuleName(p::TAccessRef access, Id moduleId); // Resolve a module's name p::StringView GetModulePath(p::TAccessRef access, Id moduleId); - void SerializeModule(ast::Tree& ast, ast::Id id, String& data); - void DeserializeModule(ast::Tree& ast, ast::Id id, const String& data); - const TBroadcast& OnReadModulePools(); - const TBroadcast& OnWriteModulePools(); + void SerializeModule(ast::Tree& ast, ast::Id id, p::String& data); + void DeserializeModule(ast::Tree& ast, ast::Id id, const p::String& data); + const p::TBroadcast& OnReadModulePools(); + const p::TBroadcast& OnWriteModulePools(); void RegisterModuleBinding(ModuleBinding binding); void UnregisterModuleBinding(p::Tag bindingId); diff --git a/Libs/AST/Include/AST/Utils/Settings.h b/Libs/AST/Include/AST/Utils/Settings.h new file mode 100644 index 00000000..1409568e --- /dev/null +++ b/Libs/AST/Include/AST/Utils/Settings.h @@ -0,0 +1,34 @@ +// Copyright 2015-2023 Piperift - All rights reserved + +#pragma once + +#include "AST/Tree.h" +#include "AST/TypeRef.h" + +#include +#include +#include + + +namespace rift::ast +{ + p::String GetUserSettingsPath(); + + template + T* GetUserSettings() + { + static TOwnPtr instance; + if (!instance) + { + p::String path = GetUserSettingsPath(); + String data; + // if (p::LoadStringFile(path, data)) + //{ + // instance = MakeOwned(); + // p::JsonFormatReader reader{data}; + // reader.GetReader().Serialize(*instance); + // } + } + return instance.Get(); + } +} // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/Statements.h b/Libs/AST/Include/AST/Utils/Statements.h index ef4f97f3..d3988dab 100644 --- a/Libs/AST/Include/AST/Utils/Statements.h +++ b/Libs/AST/Include/AST/Utils/Statements.h @@ -15,12 +15,12 @@ namespace rift::ast { bool CanConnectStmt(const Tree& ast, Id outputNode, Id outputPin, Id inputNode); - bool TryConnectStmt(Tree& ast, ast::Id outputPin, ast::Id inputNode); + bool TryConnectStmt(Tree& ast, Id outputPin, Id inputNode); // Disconnects a particular link. (Note: link ids are the same as input nodes) - bool DisconnectStmtLink(Tree& ast, ast::Id linkId); - bool DisconnectStmtFromPrevious(Tree& ast, ast::Id inputPin); - bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin, ast::Id outputNode); - bool DisconnectStmtFromNext(Tree& ast, ast::Id outputPin); + bool DisconnectStmtLink(Tree& ast, Id linkId); + bool DisconnectStmtFromPrevious(Tree& ast, Id inputPin); + bool DisconnectStmtFromNext(Tree& ast, Id outputPin, Id outputNode); + bool DisconnectStmtFromNext(Tree& ast, Id outputPin); /** * @brief Disconnects all inputs and outputs from this ids and the children nodes @@ -28,16 +28,16 @@ namespace rift::ast * @param ids * @param ignoreRoot ignore ids's inputs and outputs and only remove from children */ - void DisconnectAllStmtDeep(Tree& ast, TView ids, bool ignoreRoot = false); + void DisconnectAllStmtDeep(Tree& ast, p::TView ids, bool ignoreRoot = false); // TODO /** Check that a and b are connected (in any direction) */ - // bool AreNodesConnected(const Tree& ast, ast::Id outputNode, ast::Id inputNode); - // bool ArePinsConnected(const Tree& ast, ast::Id outputPin, ast::Id inputPin); - // bool IsOutputPinConnected(const Tree& ast, ast::Id outputPin); - // bool IsOutputPinConnected(const Tree& ast, ast::Id outputPin, ast::Id outputNode); - // bool IsInputPinConnected(const Tree& ast, ast::Id inputPin); - // bool IsInputPinConnected(const Tree& ast, ast::Id inputPin /*unused*/, ast::Id inputNode); + // bool AreNodesConnected(const Tree& ast, Id outputNode, Id inputNode); + // bool ArePinsConnected(const Tree& ast, Id outputPin, Id inputPin); + // bool IsOutputPinConnected(const Tree& ast, Id outputPin); + // bool IsOutputPinConnected(const Tree& ast, Id outputPin, Id outputNode); + // bool IsInputPinConnected(const Tree& ast, Id inputPin); + // bool IsInputPinConnected(const Tree& ast, Id inputPin /*unused*/, Id inputNode); /** Look for invalid ids and set them to NoId */ void CleanInvalidStmtIds(Tree& ast); @@ -45,13 +45,13 @@ namespace rift::ast // If two pins were to be connected, would they create a loop? bool WouldStmtLoop(const Tree& ast, Id outputNode, Id outputPin, Id inputNode); - Id GetPreviousStmt(TAccessRef access, Id stmtId); + Id GetPreviousStmt(p::TAccessRef access, Id stmtId); void GetPreviousStmts( - TAccessRef access, TView stmtIds, TArray& prevStmtIds); - TView GetNextStmts(TAccessRef access, Id stmtId); + p::TAccessRef access, p::TView stmtIds, p::TArray& prevStmtIds); + p::TView GetNextStmts(p::TAccessRef access, Id stmtId); void GetNextStmts( - TAccessRef access, TView stmtIds, TArray& nextStmtIds); + p::TAccessRef access, p::TView stmtIds, p::TArray& nextStmtIds); - void GetStmtChain(TAccessRef access, Id firstStmtId, - TArray& stmtIds, Id& splitStmtId); + void GetStmtChain(p::TAccessRef access, Id firstStmtId, + p::TArray& stmtIds, Id& splitStmtId); } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/TransactionUtils.h b/Libs/AST/Include/AST/Utils/TransactionUtils.h index f5ef716a..577a5383 100644 --- a/Libs/AST/Include/AST/Utils/TransactionUtils.h +++ b/Libs/AST/Include/AST/Utils/TransactionUtils.h @@ -11,7 +11,8 @@ namespace rift::ast { - using TransactionAccess = TAccessRef, TWrite, CChild, CFileRef>; + using TransactionAccess = + p::TAccessRef, p::TWrite, CChild, CFileRef>; namespace Transactions { @@ -25,13 +26,13 @@ namespace rift::ast bool active = false; ScopedTransaction() {} - ScopedTransaction(const TransactionAccess& access, TView entityIds); + ScopedTransaction(const TransactionAccess& access, p::TView entityIds); ScopedTransaction(ScopedTransaction&& other) noexcept; ~ScopedTransaction(); }; - bool PreChange(const TransactionAccess& access, TView entityIds); + bool PreChange(const TransactionAccess& access, p::TView entityIds); void PostChange(); } // namespace Transactions } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index 0104ae9d..b8992398 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -49,28 +49,28 @@ namespace rift::ast void InitTypeFromFileType(Tree& ast, Id id, p::Tag typeId); - Id CreateType(Tree& ast, p::Tag typeId, Tag name = Tag::None(), StringView path = {}); + Id CreateType(Tree& ast, p::Tag typeId, p::Tag name = p::Tag::None(), p::StringView path = {}); - void RemoveTypes(TAccessRef, TWrite, CFileRef> access, TView types, - bool removeFromDisk = false); + void RemoveTypes(p::TAccessRef, p::TWrite, CFileRef> access, + p::TView types, bool removeFromDisk = false); - void SerializeType(Tree& ast, Id id, String& data); - void DeserializeType(Tree& ast, Id id, const String& data); + void SerializeType(Tree& ast, p::Id id, p::String& data); + void DeserializeType(Tree& ast, p::Id id, const p::String& data); Id FindTypeByPath(Tree& ast, p::StringView path); - bool IsClassType(TAccessRef access, Id typeId); - bool IsStructType(TAccessRef access, Id typeId); - bool IsStaticType(TAccessRef access, Id typeId); - bool HasVariables(TAccessRef access, Id typeId); - bool HasFunctions(TAccessRef access, Id typeId); - bool HasFunctionBodies(TAccessRef access, Id typeId); + bool IsClassType(p::TAccessRef access, Id typeId); + bool IsStructType(p::TAccessRef access, Id typeId); + bool IsStaticType(p::TAccessRef access, Id typeId); + bool HasVariables(p::TAccessRef access, Id typeId); + bool HasFunctions(p::TAccessRef access, Id typeId); + bool HasFunctionBodies(p::TAccessRef access, Id typeId); - Id AddVariable(TypeRef type, Tag name); - Id AddFunction(TypeRef type, Tag name); + Id AddVariable(TypeRef type, p::Tag name); + Id AddFunction(TypeRef type, p::Tag name); Id AddCall(TypeRef type, Id targetFunctionId); - Id AddFunctionInput(Tree& ast, Id functionId, Tag name = Tag::None()); - Id AddFunctionOutput(Tree& ast, Id functionId, Tag name = Tag::None()); + Id AddFunctionInput(Tree& ast, Id functionId, p::Tag name = p::Tag::None()); + Id AddFunctionOutput(Tree& ast, Id functionId, p::Tag name = p::Tag::None()); Id AddIf(TypeRef type); Id AddReturn(TypeRef type); @@ -80,13 +80,15 @@ namespace rift::ast Id AddUnaryOperator(TypeRef type, UnaryOperatorType operatorType); Id AddBinaryOperator(TypeRef type, BinaryOperatorType operatorType); - Id FindChildByName(TAccessRef access, Id ownerId, Tag functionName); + Id FindChildByName(p::TAccessRef access, Id ownerId, p::Tag functionName); - using RemoveAccess = TAccess, TWrite, TWrite, - TWrite, TWrite, TWrite, CFileRef>; - void RemoveNodes(const RemoveAccess& access, TView ids); + using RemoveAccess = + p::TAccess, p::TWrite, p::TWrite, + p::TWrite, p::TWrite, p::TWrite, CFileRef>; + void RemoveNodes(const RemoveAccess& access, p::TView ids); - bool CopyExpressionType(TAccessRef> access, Id sourcePinId, Id targetPinId); + bool CopyExpressionType( + p::TAccessRef> access, Id sourcePinId, Id targetPinId); void RegisterFileType(RiftType&& descriptor); @@ -94,7 +96,7 @@ namespace rift::ast p::TView GetFileTypes(); const RiftType* FindFileType(p::Tag typeId); - const RiftType* FindFileType(p::TAccessRef access, ast::Id typeId); + const RiftType* FindFileType(p::TAccessRef access, ast::Id typeId); template void RegisterFileType(p::Tag typeId, RiftTypeSettings settings) diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index 5a462a00..71e25e96 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -9,14 +9,14 @@ namespace rift { - class Backend : public Class + class Backend : public p::Class { - P_CLASS(Backend, Class) + P_CLASS(Backend, p::Class) public: - virtual Tag GetName() + virtual p::Tag GetName() { - return Tag::None(); + return p::Tag::None(); } virtual void Build(Compiler& compiler) diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index 97d7377a..97f66b2f 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -19,7 +19,7 @@ namespace rift P_STRUCT(CompileError, p::Struct) P_PROP(text) - String text; + p::String text; }; @@ -29,15 +29,15 @@ namespace rift ast::Tree& ast; CompilerConfig config; - TArray errors; + p::TArray errors; public: Compiler(ast::Tree& ast, const CompilerConfig& config) : ast{ast}, config{config} {} // Errors - void Error(StringView str); - const TArray& GetErrors() const + void Error(p::StringView str); + const p::TArray& GetErrors() const { return errors; } @@ -48,9 +48,9 @@ namespace rift }; - void Build(ast::Tree& tree, const CompilerConfig& config, TPtr backend); + void Build(ast::Tree& tree, const CompilerConfig& config, p::TPtr backend); - void Build(ast::Tree& ast, const CompilerConfig& config, ClassType* backendType); + void Build(ast::Tree& ast, const CompilerConfig& config, p::ClassType* backendType); template void Build(ast::Tree& ast, const CompilerConfig& config) diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index 0bd2044b..a3d668d1 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -12,8 +12,6 @@ namespace rift { - using namespace p; - enum class OptimizationLevel : p::u8 { Zero = 0, // Only register allocator and machine code generator work @@ -36,9 +34,9 @@ namespace rift bool debug = true; bool verbose = false; - String buildPath; - String intermediatesPath; - String binariesPath; + p::String buildPath; + p::String intermediatesPath; + p::String binariesPath; void Init(ast::Tree& ast); }; diff --git a/Libs/AST/Include/Compiler/Utils/BackendUtils.h b/Libs/AST/Include/Compiler/Utils/BackendUtils.h index 193bd40e..c741d965 100644 --- a/Libs/AST/Include/Compiler/Utils/BackendUtils.h +++ b/Libs/AST/Include/Compiler/Utils/BackendUtils.h @@ -11,6 +11,6 @@ namespace rift { - TArray GetBackendTypes(); - TArray> CreateBackends(); + p::TArray GetBackendTypes(); + p::TArray> CreateBackends(); } // namespace rift diff --git a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp index 530b9649..7c4291e6 100644 --- a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp +++ b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp @@ -21,10 +21,10 @@ namespace rift::ast::FunctionsSystem CExprInputs* functionInputs; CExprOutputs* functionOutputs; - TArray inputArgs; - TArray outputArgs; - TArray invalidArgs; - TArray unrelatedCallChildren; + p::TArray inputArgs; + p::TArray outputArgs; + p::TArray invalidArgs; + p::TArray unrelatedCallChildren; }; @@ -36,7 +36,7 @@ namespace rift::ast::FunctionsSystem } void ResolveCallFunctionIds( - TAccessRef, CExprCall, CDeclFunction, CNamespace, CParent, CChild> + p::TAccessRef, CExprCall, CDeclFunction, CNamespace, CParent, CChild> access) { auto callExprs = FindAllIdsWith(access); @@ -54,14 +54,14 @@ namespace rift::ast::FunctionsSystem void PropagateDirtyIntoCalls(Tree& ast) { - TAccess> access{ast}; + p::TAccess> access{ast}; if (access.Size() <= 0) { return; } - TArray callExprIds = FindAllIdsWith(access); - ExcludeIdsWith(access, callExprIds); + p::TArray callExprIds = p::FindAllIdsWith(access); + p::ExcludeIdsWith(access, callExprIds); for (Id id : callExprIds) { const Id functionId = access.Get(id).functionId; @@ -72,13 +72,14 @@ namespace rift::ast::FunctionsSystem } } - void PushInvalidPinsBack(TAccessRef, TWrite, CInvalid> access) + void PushInvalidPinsBack( + p::TAccessRef, p::TWrite, CInvalid> access) { - for (Id inputsId : FindAllIdsWith(access)) + for (Id inputsId : p::FindAllIdsWith(access)) { - auto& inputs = access.Get(inputsId); - i32 validSize = inputs.pinIds.Size(); - for (i32 i = 0; i < validSize;) + auto& inputs = access.Get(inputsId); + p::i32 validSize = inputs.pinIds.Size(); + for (p::i32 i = 0; i < validSize;) { Id id = inputs.pinIds[i]; if (access.Has(id)) @@ -97,11 +98,11 @@ namespace rift::ast::FunctionsSystem } } - for (Id outputsId : FindAllIdsWith(access)) + for (Id outputsId : p::FindAllIdsWith(access)) { - auto& outputs = access.Get(outputsId); - i32 validSize = outputs.pinIds.Size(); - for (i32 i = 0; i < validSize;) + auto& outputs = access.Get(outputsId); + p::i32 validSize = outputs.pinIds.Size(); + for (p::i32 i = 0; i < validSize;) { Id id = outputs.pinIds[i]; if (access.Has(id)) @@ -120,11 +121,11 @@ namespace rift::ast::FunctionsSystem void SyncCallPinsFromFunction(Tree& ast) { - TArray calls; - TAccess, TWrite, - TWrite, TWrite, TWrite> + p::TArray calls; + p::TAccess, p::TWrite, + p::TWrite, p::TWrite, p::TWrite> access{ast}; - for (Id id : FindAllIdsWith(access)) + for (Id id : p::FindAllIdsWith(access)) { const auto& call = access.Get(id); if (IsNone(call.functionId)) @@ -147,8 +148,8 @@ namespace rift::ast::FunctionsSystem // For each function pin - i32 validSize = call.functionInputs->pinIds.Size(); - for (i32 i = 0; i < validSize; ++i) + p::i32 validSize = call.functionInputs->pinIds.Size(); + for (p::i32 i = 0; i < validSize; ++i) { const Id pinId = call.functionInputs->pinIds[i]; if (access.Has(pinId)) @@ -173,7 +174,7 @@ namespace rift::ast::FunctionsSystem else { // Search matching pin to 'pinId' from i to end - i32 callPinIdx = i; + p::i32 callPinIdx = i; while (callPinIdx < callOutputs.pinIds.Size()) { const Id outputPinId = callOutputs.pinIds[callPinIdx]; @@ -201,12 +202,12 @@ namespace rift::ast::FunctionsSystem } // Mark as invalid all after N function params, and valid those before - const i32 firstInvalid = validSize; + const p::i32 firstInvalid = validSize; if (firstInvalid > 0) { access.Remove({callOutputs.pinIds.Data(), firstInvalid}); } - const i32 count = callOutputs.pinIds.Size() - validSize; + const p::i32 count = callOutputs.pinIds.Size() - validSize; if (count > 0) { access.AddN({callOutputs.pinIds.Data() + firstInvalid, count}); @@ -218,8 +219,8 @@ namespace rift::ast::FunctionsSystem { auto& callInputs = access.GetOrAdd(call.id); // For each function pin - i32 validSize = call.functionOutputs->pinIds.Size(); - for (i32 i = 0; i < validSize; ++i) + p::i32 validSize = call.functionOutputs->pinIds.Size(); + for (p::i32 i = 0; i < validSize; ++i) { const Id pinId = call.functionOutputs->pinIds[i]; if (access.Has(pinId)) @@ -244,7 +245,7 @@ namespace rift::ast::FunctionsSystem else { // Search matching pin to 'pinId' from i to end - i32 callPinIdx = i; + p::i32 callPinIdx = i; while (callPinIdx < callInputs.pinIds.Size()) { const Id pinId = callInputs.pinIds[callPinIdx]; @@ -272,12 +273,12 @@ namespace rift::ast::FunctionsSystem } // Mark as invalid all after N function params, and valid those before - const i32 firstInvalid = validSize; + const p::i32 firstInvalid = validSize; if (firstInvalid > 0) { access.Remove({callInputs.pinIds.Data(), firstInvalid}); } - const i32 count = callInputs.pinIds.Size() - validSize; + const p::i32 count = callInputs.pinIds.Size() - validSize; if (count > 0) { access.AddN({callInputs.pinIds.Data() + firstInvalid, count}); @@ -298,7 +299,7 @@ namespace rift::ast::FunctionsSystem for (Id id : FindAllIdsWith(access)) { const auto& inputs = access.Get(id); - for (i32 i = 0; i < inputs.pinIds.Size(); ++i) + for (p::i32 i = 0; i < inputs.pinIds.Size(); ++i) { Id pinId = inputs.pinIds[i]; const ExprOutput& output = inputs.linkedOutputs[i]; @@ -325,7 +326,7 @@ namespace rift::ast::FunctionsSystem } } - TArray pinsToRemove = FindAllIdsWith(access); + p::TArray pinsToRemove = p::FindAllIdsWith(access); ExcludeIdsWith(access, pinsToRemove); p::RemoveId(access, pinsToRemove); diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index 3eb45768..725da7ef 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -35,31 +35,31 @@ namespace rift::ast::LoadSystem void LoadSubmodules(Tree& ast) { - TArray paths; + p::TArray paths; ScanSubmodules(ast, paths); - TArray idsToLoad; + p::TArray idsToLoad; CreateModulesFromPaths(ast, paths, idsToLoad); - TArray strings; + p::TArray strings; LoadFileStrings(ast, idsToLoad, strings); DeserializeModules(ast, idsToLoad, strings); } void LoadTypes(Tree& ast) { - TArray pathsByModule; + p::TArray pathsByModule; ScanTypes(ast, pathsByModule); - TArray idsToLoad; + p::TArray idsToLoad; CreateTypesFromPaths(ast, pathsByModule, idsToLoad); - TArray strings; + p::TArray strings; LoadFileStrings(ast, idsToLoad, strings); DeserializeTypes(ast, idsToLoad, strings); } - void ScanSubmodules(Tree& ast, TArray& paths) + void ScanSubmodules(Tree& ast, p::TArray& paths) { paths.Clear(); @@ -71,14 +71,14 @@ namespace rift::ast::LoadSystem } } - void ScanTypes(Tree& ast, TArray& pathsByModule) + void ScanTypes(Tree& ast, p::TArray& pathsByModule) { pathsByModule.Clear(false); // Cache module paths in a Set - TSet modulePaths; + p::TSet modulePaths; - TAccess access{ast}; + p::TAccess access{ast}; auto modules = FindAllIdsWith(access); modulePaths.Reserve(modules.Size()); @@ -108,14 +108,14 @@ namespace rift::ast::LoadSystem } } - void CreateModulesFromPaths(Tree& ast, TArray& paths, TArray& ids) + void CreateModulesFromPaths(Tree& ast, p::TArray& paths, p::TArray& ids) { - TAccess, TWrite, TWrite, CProject, TWrite, - TWrite> + p::TAccess, p::TWrite, p::TWrite, CProject, + p::TWrite, p::TWrite> access{ast}; // Remove existing module paths - auto moduleIds = FindAllIdsWith(access); + auto moduleIds = p::FindAllIdsWith(access); paths.RemoveIfSwap([&access, &moduleIds](const p::String& path) { bool moduleExists = false; for (Id id : moduleIds) @@ -132,13 +132,13 @@ namespace rift::ast::LoadSystem ids.Resize(paths.Size()); access.GetContext().Create(ids); - for (i32 i = 0; i < ids.Size(); ++i) + for (p::i32 i = 0; i < ids.Size(); ++i) { Id id = ids[i]; p::String& path = paths[i]; access.Add(id); access.Add(id, CNamespace{p::GetFilename(p::GetParentPath(path))}); - access.Add(id, CFileRef{Move(path)}); + access.Add(id, CFileRef{p::Move(path)}); } // Link modules to the project @@ -146,7 +146,8 @@ namespace rift::ast::LoadSystem p::AttachId(access, projectId, ids); } - void CreateTypesFromPaths(Tree& ast, TView pathsByModule, TArray& ids) + void CreateTypesFromPaths( + Tree& ast, p::TView pathsByModule, p::TArray& ids) { auto* types = ast.TryGetStatic(); if (!types) @@ -163,19 +164,19 @@ namespace rift::ast::LoadSystem } // Create type entities - TArray typeIds; + p::TArray typeIds; for (ModuleTypePaths& modulePaths : pathsByModule) { typeIds.Resize(modulePaths.paths.Size()); ast.Create(typeIds); - for (i32 i = 0; i < typeIds.Size(); ++i) + for (p::i32 i = 0; i < typeIds.Size(); ++i) { - const Id id = typeIds[i]; - String& path = modulePaths.paths[i]; + const Id id = typeIds[i]; + p::String& path = modulePaths.paths[i]; types->typesByPath.Insert(p::Tag{path}, id); - ast.Add(id, CFileRef{Move(path)}); + ast.Add(id, CFileRef{p::Move(path)}); } p::AttachId(ast, modulePaths.moduleId, typeIds); @@ -183,14 +184,15 @@ namespace rift::ast::LoadSystem } } - void LoadFileStrings(TAccessRef access, TView nodes, TArray& strings) + void LoadFileStrings( + p::TAccessRef access, p::TView nodes, p::TArray& strings) { strings.Resize(nodes.Size()); - for (i32 i = 0; i < nodes.Size(); ++i) + for (p::i32 i = 0; i < nodes.Size(); ++i) { if (auto* file = access.TryGet(nodes[i])) [[likely]] { - if (!files::LoadStringFile(file->path, strings[i], 4)) + if (!p::LoadStringFile(file->path, strings[i], 4)) { p::Error("File could not be loaded from disk ({})", file->path); continue; @@ -199,21 +201,21 @@ namespace rift::ast::LoadSystem } } - void DeserializeModules(Tree& ast, TView moduleIds, TView strings) + void DeserializeModules(Tree& ast, p::TView moduleIds, p::TView strings) { Check(moduleIds.Size() == strings.Size()); - for (i32 i = 0; i < moduleIds.Size(); ++i) + for (p::i32 i = 0; i < moduleIds.Size(); ++i) { DeserializeModule(ast, moduleIds[i], strings[i]); } } - void DeserializeTypes(Tree& ast, TView typeIds, TView strings) + void DeserializeTypes(Tree& ast, p::TView typeIds, p::TView strings) { Check(typeIds.Size() == strings.Size()); - for (i32 i = 0; i < typeIds.Size(); ++i) + for (p::i32 i = 0; i < typeIds.Size(); ++i) { DeserializeType(ast, typeIds[i], strings[i]); } diff --git a/Libs/AST/Src/AST/Systems/TypeSystem.cpp b/Libs/AST/Src/AST/Systems/TypeSystem.cpp index a9af8ee1..7a620df8 100644 --- a/Libs/AST/Src/AST/Systems/TypeSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TypeSystem.cpp @@ -17,7 +17,7 @@ namespace rift::ast::TypeSystem { void Init(Tree& ast) { - TAccess access{ast}; + p::TAccess access{ast}; ast.OnAdd().Bind([](auto& ast, auto ids) { auto& types = ast.template GetOrSetStatic(); @@ -57,7 +57,7 @@ namespace rift::ast::TypeSystem } } - bool PropagateUnaryOperator(TAccess> access, Id nodeId) + bool PropagateUnaryOperator(p::TAccess> access, Id nodeId) { const Id outputId = nodeId; // Output in unary operator is same as the node itself const auto& inputs = access.Get(nodeId); @@ -69,7 +69,7 @@ namespace rift::ast::TypeSystem return false; } - bool PropagateBinaryOperator(TAccess> access, Id nodeId) + bool PropagateBinaryOperator(p::TAccess> access, Id nodeId) { const auto& inputs = access.Get(nodeId); Id outputId = nodeId; // Output in binary operator is same as the node itself @@ -87,16 +87,16 @@ namespace rift::ast::TypeSystem void PropagateExpressionTypes(PropagateExpressionTypesAccess access) { - TArray dirtyTypeIds = FindAllIdsWith(access); + p::TArray dirtyTypeIds = p::FindAllIdsWith(access); - TArray dirtyNodeIds; + p::TArray dirtyNodeIds; p::GetIdChildren(access, dirtyTypeIds, dirtyNodeIds); // Make sure the nodes have inputs and outputs - ExcludeIdsWithout(access, dirtyNodeIds); + p::ExcludeIdsWithout(access, dirtyNodeIds); // Only Unary and Binary operators propagate as of right now - ExcludeIdsWith(dirtyNodeIds, [&access](Id id) { + p::ExcludeIdsWith(dirtyNodeIds, [&access](Id id) { return !access.Has(id) && !access.Has(id); }); @@ -105,7 +105,7 @@ namespace rift::ast::TypeSystem { bool anyPropagated = false; // Propagate all dirty nodes, remove successfully propagated ones - for (i32 i = dirtyNodeIds.Size() - 1; i >= 0; --i) + for (p::i32 i = dirtyNodeIds.Size() - 1; i >= 0; --i) { const Id nodeId = dirtyNodeIds[i]; @@ -135,15 +135,15 @@ namespace rift::ast::TypeSystem } void ResolveExprTypeIds( - TAccessRef, CExprType, CNamespace, CParent, CChild> access) + p::TAccessRef, CExprType, CNamespace, CParent, CChild> access) { - auto callExprs = FindAllIdsWith(access); - ExcludeIdsWith(access, callExprs); + auto callExprs = p::FindAllIdsWith(access); + p::ExcludeIdsWith(access, callExprs); for (Id id : callExprs) { auto& expr = access.Get(id); const Id typeId = FindIdFromNamespace(access, expr.type); - if (!IsNone(typeId)) + if (!p::IsNone(typeId)) { access.Add(id, CExprTypeId{.id = typeId, .mode = expr.mode}); } diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index 87c380c1..b40b6cec 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -12,7 +12,7 @@ namespace rift::ast { - TBroadcast Tree::onInit{}; + p::TBroadcast Tree::onInit{}; Tree::Tree() @@ -21,28 +21,28 @@ namespace rift::ast onInit(*this); } - Tree::Tree(const Tree& other) noexcept : EntityContext(other) + Tree::Tree(const Tree& other) noexcept : p::EntityContext(other) { CopyFrom(other); } - Tree::Tree(Tree&& other) noexcept : EntityContext(Move(other)) + Tree::Tree(Tree&& other) noexcept : p::EntityContext(p::Move(other)) { - MoveFrom(Move(other)); + MoveFrom(p::Move(other)); } Tree& Tree::operator=(const Tree& other) noexcept { - EntityContext::operator=(other); + p::EntityContext::operator=(other); CopyFrom(other); return *this; } Tree& Tree::operator=(Tree&& other) noexcept { - EntityContext::operator=(Move(other)); - MoveFrom(Move(other)); + EntityContext::operator=(p::Move(other)); + MoveFrom(p::Move(other)); return *this; } - const TBroadcast& Tree::OnInit() + const p::TBroadcast& Tree::OnInit() { return onInit; } @@ -50,7 +50,7 @@ namespace rift::ast void Tree::SetupNativeTypes() { // Remove any previous native types - Destroy(FindAllIdsWith(*this)); + Destroy(p::FindAllIdsWith(*this)); nativeTypes.boolId = Create(); Add(nativeTypes.boolId); @@ -122,9 +122,9 @@ namespace rift::ast nativeTypes = other.nativeTypes; } - String Tree::DumpPools() + p::String Tree::DumpPools() { - String text; + p::String text; text.append("Pools: \n"); for (const auto& pool : GetPools()) diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index 2d616a15..8deba6ea 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -7,11 +7,11 @@ namespace rift::ast { - bool WouldExprLoop( - TAccessRef access, Id outputNodeId, Id inputNodeId) + bool WouldExprLoop(p::TAccessRef access, + Id outputNodeId, Id inputNodeId) { - TArray currentNodeIds{outputNodeId}; - TArray nextNodeIds{}; + p::TArray currentNodeIds{outputNodeId}; + p::TArray nextNodeIds{}; while (!currentNodeIds.IsEmpty()) { for (Id id : currentNodeIds) @@ -38,7 +38,7 @@ namespace rift::ast return false; } - bool CanConnectExpr(TAccessRef access, + bool CanConnectExpr(p::TAccessRef access, ExprOutput output, ExprInput input) { if (output.IsNone() || input.IsNone()) @@ -91,7 +91,7 @@ namespace rift::ast return !WouldExprLoop(access, output.nodeId, input.nodeId); } - bool TryConnectExpr(TAccessRef, CExprOutputs, CExprTypeId> access, + bool TryConnectExpr(p::TAccessRef, CExprOutputs, CExprTypeId> access, ExprOutput output, ExprInput input) { if (!CanConnectExpr(access, output, input)) @@ -102,10 +102,10 @@ namespace rift::ast auto& inputs = access.Get(input.nodeId); // Find pin index - const i32 index = inputs.pinIds.FindIndex([&input](Id pinId) { + const p::i32 index = inputs.pinIds.FindIndex([&input](Id pinId) { return input.pinId == pinId; }); - if (index != NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) + if (index != p::NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) { inputs.linkedOutputs[index] = output; return true; @@ -123,8 +123,8 @@ namespace rift::ast auto& inputs = ast.Get(input.nodeId); // Find pin index - const i32 index = inputs.pinIds.FindIndex(input.pinId); - if (index != NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) [[likely]] + const p::i32 index = inputs.pinIds.FindIndex(input.pinId); + if (index != p::NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) [[likely]] { ExprOutput& linked = inputs.linkedOutputs[index]; linked = {}; @@ -134,12 +134,12 @@ namespace rift::ast } - bool RemoveExprInputPin(TAccessRef> access, ExprInput input) + bool RemoveExprInputPin(p::TAccessRef> access, ExprInput input) { if (!input.IsNone()) { const auto* inputs = access.TryGet(input.nodeId); - if (inputs && inputs->pinIds.FindIndex(input.pinId) != NO_INDEX) + if (inputs && inputs->pinIds.FindIndex(input.pinId) != p::NO_INDEX) { access.Add(input.pinId); return true; @@ -148,7 +148,8 @@ namespace rift::ast return false; } - bool RemoveExprOutputPin(TAccessRef> access, ExprOutput output) + bool RemoveExprOutputPin( + p::TAccessRef> access, ExprOutput output) { if (!output.IsNone()) { @@ -161,7 +162,7 @@ namespace rift::ast return false; } - ExprInput GetExprInputFromPin(TAccessRef access, Id pinId) + ExprInput GetExprInputFromPin(p::TAccessRef access, Id pinId) { ExprInput input{}; input.pinId = pinId; @@ -174,7 +175,7 @@ namespace rift::ast return input; } - ExprOutput GetExprOutputFromPin(TAccessRef access, Id pinId) + ExprOutput GetExprOutputFromPin(p::TAccessRef access, Id pinId) { ExprOutput output{}; output.pinId = pinId; diff --git a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp index 65816e84..9e772e10 100644 --- a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp +++ b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp @@ -18,8 +18,8 @@ namespace rift::ast { static p::TArray gModuleBindings; - TBroadcast gOnReadModulePools; - TBroadcast gOnWriteModulePools; + p::TBroadcast gOnReadModulePools; + p::TBroadcast gOnWriteModulePools; bool ValidateModulePath(p::String& path, p::String& error) @@ -30,7 +30,7 @@ namespace rift::ast return false; } - if (files::IsFile(path)) + if (p::IsFile(path)) { if (p::GetFilename(path) != moduleFilename) { @@ -53,22 +53,22 @@ namespace rift::ast bool OpenProject(Tree& ast, p::StringView path) { - String validatedPath{path}; - String error; + p::String validatedPath{path}; + p::String error; if (!ValidateModulePath(validatedPath, error)) { p::Error("Can't open project: {}", error); return false; } - if (!files::ExistsAsFolder(validatedPath)) + if (!p::ExistsAsFolder(validatedPath)) { p::Error("Can't open project: Folder doesn't exist"); return false; } const p::String filePath = p::JoinPaths(validatedPath, moduleFilename); - if (!files::ExistsAsFile(filePath)) + if (!p::ExistsAsFile(filePath)) { p::Error("Can't open project: Folder doesn't contain a '{}' file", moduleFilename); return false; @@ -88,7 +88,7 @@ namespace rift::ast ast.Add(projectId, CFileRef{filePath}); // Load project module - TArray strings; + p::TArray strings; LoadSystem::LoadFileStrings(ast, projectId, strings); LoadSystem::DeserializeModules(ast, projectId, strings); return true; @@ -101,22 +101,22 @@ namespace rift::ast Id CreateModule(Tree& ast, p::StringView path) { - String validatedPath{path}; + p::String validatedPath{path}; - String error; + p::String error; if (!ValidateModulePath(validatedPath, error)) { p::Error("Can't create module: {}", error); return NoId; } - if (!files::ExistsAsFolder(validatedPath)) + if (!p::ExistsAsFolder(validatedPath)) { - files::CreateFolder(validatedPath, true); + p::CreateFolder(validatedPath, true); } const p::String filePath = p::JoinPaths(validatedPath, moduleFilename); - if (files::ExistsAsFile(filePath)) + if (p::ExistsAsFile(filePath)) { p::Error("Can't create module: Folder already contains a '{}' file", moduleFilename); return NoId; @@ -129,27 +129,27 @@ namespace rift::ast p::String data; SerializeModule(ast, moduleId, data); - files::SaveStringFile(filePath, data); + p::SaveStringFile(filePath, data); return moduleId; } - Id GetProjectId(TAccessRef access) + Id GetProjectId(p::TAccessRef access) { return GetFirstId(access); } - Tag GetProjectName(TAccessRef access) + p::Tag GetProjectName(p::TAccessRef access) { Id moduleId = GetProjectId(access); return GetModuleName(access, moduleId); } - p::StringView GetProjectPath(TAccessRef access) + p::StringView GetProjectPath(p::TAccessRef access) { return GetModulePath(access, GetProjectId(access)); } - CModule* GetProjectModule(TAccessRef> access) + CModule* GetProjectModule(p::TAccessRef> access) { const Id projectId = GetProjectId(access); if (projectId != NoId) @@ -164,7 +164,7 @@ namespace rift::ast return GetProjectId(ast) != NoId; } - Tag GetModuleName(TAccessRef access, Id moduleId) + p::Tag GetModuleName(p::TAccessRef access, Id moduleId) { if (!access.IsValid(moduleId)) { @@ -181,13 +181,13 @@ namespace rift::ast if (file && !file->path.empty()) { // Obtain name from project file name - const String fileName = p::ToString(file->path); - return Tag{p::GetFilename(p::GetParentPath(fileName))}; // Folder name + const p::String fileName = p::ToString(file->path); + return p::Tag{p::GetFilename(p::GetParentPath(fileName))}; // Folder name } return {}; } - p::StringView GetModulePath(TAccessRef access, Id moduleId) + p::StringView GetModulePath(p::TAccessRef access, Id moduleId) { if (const auto* file = access.TryGet(moduleId)) { @@ -196,9 +196,9 @@ namespace rift::ast return {}; } - void SerializeModule(ast::Tree& ast, ast::Id id, String& data) + void SerializeModule(ast::Tree& ast, ast::Id id, p::String& data) { - JsonFormatWriter writer{}; + p::JsonFormatWriter writer{}; p::EntityWriter w{writer.GetWriter(), ast}; w.BeginObject(); w.SerializeSingleEntity(id, gOnWriteModulePools); @@ -206,9 +206,9 @@ namespace rift::ast data = writer.ToString(); } - void DeserializeModule(ast::Tree& ast, ast::Id id, const String& data) + void DeserializeModule(ast::Tree& ast, ast::Id id, const p::String& data) { - JsonFormatReader formatReader{data}; + p::JsonFormatReader formatReader{data}; if (formatReader.IsValid()) { p::EntityReader r{formatReader, ast}; @@ -216,11 +216,11 @@ namespace rift::ast r.SerializeSingleEntity(id, gOnReadModulePools); } } - const TBroadcast& OnReadModulePools() + const p::TBroadcast& OnReadModulePools() { return gOnReadModulePools; } - const TBroadcast& OnWriteModulePools() + const p::TBroadcast& OnWriteModulePools() { return gOnWriteModulePools; } @@ -228,7 +228,7 @@ namespace rift::ast void RegisterModuleBinding(ModuleBinding binding) { - gModuleBindings.AddUniqueSorted(Move(binding)); + gModuleBindings.AddUniqueSorted(p::Move(binding)); } void UnregisterModuleBinding(p::Tag bindingId) { @@ -251,8 +251,8 @@ namespace rift::ast const ModuleBinding* FindModuleBinding(p::Tag id) { - const i32 index = gModuleBindings.FindSortedEqual(id); - return index != NO_INDEX ? gModuleBindings.Data() + index : nullptr; + const p::i32 index = gModuleBindings.FindSortedEqual(id); + return index != p::NO_INDEX ? gModuleBindings.Data() + index : nullptr; } p::TView GetModuleBindings() diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index 1ef524fe..88f70430 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -12,10 +12,10 @@ namespace rift::ast { - Namespace GetNamespace(TAccessRef access, Id id) + Namespace GetNamespace(p::TAccessRef access, Id id) { Namespace ns; - TArray idChain; + p::TArray idChain; idChain.Reserve(Namespace::scopeCount); while (!IsNone(id)) @@ -28,7 +28,7 @@ namespace rift::ast id = p::GetIdParent(access, id); } - i32 i, scopeIndex = 0; + p::i32 i, scopeIndex = 0; for (i = idChain.Size() - 1; i >= 0 && scopeIndex < Namespace::scopeCount; --i) { ns.scopes[scopeIndex] = GetName(access, idChain[i]); @@ -38,7 +38,7 @@ namespace rift::ast return ns; } - Namespace GetParentNamespace(TAccessRef access, Id id) + Namespace GetParentNamespace(p::TAccessRef access, Id id) { if (!IsNone(id)) { @@ -47,21 +47,21 @@ namespace rift::ast return {}; } - Id FindIdFromNamespace(TAccessRef access, const Namespace& ns, - const TArray* rootIds) + Id FindIdFromNamespace(p::TAccessRef access, const Namespace& ns, + const p::TArray* rootIds) { - TArray localRoots; + p::TArray localRoots; if (!rootIds) { - localRoots = FindAllIdsWith(access); - ExcludeIdsWith(access, localRoots); + localRoots = p::FindAllIdsWith(access); + p::ExcludeIdsWith(access, localRoots); rootIds = &localRoots; } - const TArray* scopeIds = rootIds; - Id foundScopeId = NoId; - Tag scopeName; - i32 depth = 0; + const p::TArray* scopeIds = rootIds; + Id foundScopeId = NoId; + p::Tag scopeName; + p::i32 depth = 0; while (scopeIds && depth < Namespace::scopeCount) { scopeName = ns[depth]; @@ -95,18 +95,18 @@ namespace rift::ast return foundScopeId; } - Tag GetName(TAccessRef access, Id id) + p::Tag GetName(p::TAccessRef access, Id id) { auto* ns = access.TryGet(id); - return ns ? ns->name : Tag::None(); + return ns ? ns->name : p::Tag::None(); } - Tag GetNameUnsafe(TAccessRef access, Id id) + p::Tag GetNameUnsafe(p::TAccessRef access, Id id) { return access.Get(id).name; } - p::String GetFullName( - TAccessRef access, Id id, bool localNamespace, char separator) + p::String GetFullName(p::TAccessRef access, Id id, + bool localNamespace, char separator) { return GetNamespace(access, id).ToString(localNamespace, separator); } diff --git a/Libs/AST/Src/AST/Utils/Settings.cpp b/Libs/AST/Src/AST/Utils/Settings.cpp new file mode 100644 index 00000000..b8f8ea74 --- /dev/null +++ b/Libs/AST/Src/AST/Utils/Settings.cpp @@ -0,0 +1,16 @@ +// Copyright 2015-2023 Piperift - All rights reserved + +#include "AST/Utils/Settings.h" + +#include +#include + + +namespace rift::ast +{ + p::String GetUserSettingsPath() + { + static p::StringView relativeSettingsPath{"Rift"}; + return p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath); + } +} // namespace rift::ast diff --git a/Libs/AST/Src/AST/Utils/Statements.cpp b/Libs/AST/Src/AST/Utils/Statements.cpp index bf84004c..c79d91d1 100644 --- a/Libs/AST/Src/AST/Utils/Statements.cpp +++ b/Libs/AST/Src/AST/Utils/Statements.cpp @@ -3,6 +3,7 @@ #include "AST/Utils/Statements.h" #include "AST/Id.h" +#include "PipeECS.h" namespace rift::ast @@ -81,8 +82,8 @@ namespace rift::ast else if (auto* outputsComp = ast.TryGet(outputNode)) { // Connect if multiple output - const i32 pinIndex = outputsComp->pinIds.FindIndex(outputPin); - if (pinIndex != NO_INDEX) + const p::i32 pinIndex = outputsComp->pinIds.FindIndex(outputPin); + if (pinIndex != p::NO_INDEX) { Id& lastInputNode = outputsComp->linkInputNodes[pinIndex]; // Disconnect previous input connected to output if any @@ -138,8 +139,8 @@ namespace rift::ast // Disconnect() if (auto* outputsComp = ast.TryGet(outputNode)) { - i32 pinIndex = outputsComp->pinIds.FindIndex(outputPin); - if (pinIndex != NO_INDEX) [[likely]] + p::i32 pinIndex = outputsComp->pinIds.FindIndex(outputPin); + if (pinIndex != p::NO_INDEX) [[likely]] { return DisconnectStmtLink(ast, outputsComp->linkInputNodes[pinIndex]); } @@ -170,7 +171,7 @@ namespace rift::ast return false; } - Id GetPreviousStmt(TAccessRef access, Id stmtIds) + Id GetPreviousStmt(p::TAccessRef access, Id stmtIds) { if (const auto* input = access.TryGet(stmtIds)) { @@ -180,7 +181,7 @@ namespace rift::ast } void GetPreviousStmts( - TAccessRef access, TView stmtIds, TArray& prevStmtIds) + p::TAccessRef access, p::TView stmtIds, p::TArray& prevStmtIds) { prevStmtIds.ReserveMore(stmtIds.Size()); for (const Id stmtId : stmtIds) @@ -192,7 +193,7 @@ namespace rift::ast } } - TView GetNextStmts(TAccessRef access, Id stmtIds) + p::TView GetNextStmts(p::TAccessRef access, Id stmtIds) { if (const auto* output = access.TryGet(stmtIds)) { @@ -202,7 +203,7 @@ namespace rift::ast } void GetNextStmts( - TAccessRef access, TView stmtIds, TArray& nextStmtIds) + p::TAccessRef access, p::TView stmtIds, p::TArray& nextStmtIds) { nextStmtIds.ReserveMore(stmtIds.Size()); for (const Id stmtId : stmtIds) @@ -214,8 +215,8 @@ namespace rift::ast } } - void GetStmtChain(TAccessRef access, Id firstStmtId, - TArray& stmtIds, Id& splitStmtId) + void GetStmtChain(p::TAccessRef access, Id firstStmtId, + p::TArray& stmtIds, Id& splitStmtId) { Id id = firstStmtId; while (id != ast::NoId && access.Has(id)) diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index 5fc9c6df..c3ed6a27 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -12,7 +12,8 @@ namespace rift::ast::Transactions // Transaction being recorded static Transaction gActiveTransaction = {}; - ScopedTransaction::ScopedTransaction(const TransactionAccess& access, TView entityIds) + ScopedTransaction::ScopedTransaction( + const TransactionAccess& access, p::TView entityIds) { active = PreChange(access, entityIds); } @@ -29,7 +30,7 @@ namespace rift::ast::Transactions } } - bool PreChange(const TransactionAccess& access, TView entityIds) + bool PreChange(const TransactionAccess& access, p::TView entityIds) { if (!EnsureMsg(!gActiveTransaction.active, "Tried to record a transaction while another is already being recorded")) @@ -40,7 +41,7 @@ namespace rift::ast::Transactions gActiveTransaction = Transaction{true}; // Mark files dirty - TArray parentIds; + p::TArray parentIds; p::GetAllIdParents(access, entityIds, parentIds); parentIds.Append(entityIds); diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 84bbd43e..43bbaec7 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -66,7 +66,7 @@ namespace rift::ast return id; } - void RemoveTypes(TAccessRef, TWrite, CFileRef> access, + void RemoveTypes(p::TAccessRef, TWrite, CFileRef> access, TView typeIds, bool removeFromDisk) { if (removeFromDisk) @@ -75,7 +75,7 @@ namespace rift::ast { if (const auto* file = access.TryGet(id)) { - files::Delete(file->path, true, false); + Delete(file->path, true, false); } } } @@ -131,22 +131,22 @@ namespace rift::ast return NoId; } - bool IsClassType(TAccessRef access, Id typeId) + bool IsClassType(p::TAccessRef access, Id typeId) { return access.Has(typeId); } - bool IsStructType(TAccessRef access, Id typeId) + bool IsStructType(p::TAccessRef access, Id typeId) { return access.Has(typeId); } - bool IsStaticType(TAccessRef access, Id typeId) + bool IsStaticType(p::TAccessRef access, Id typeId) { return access.Has(typeId); } - bool HasVariables(TAccessRef access, Id typeId) + bool HasVariables(p::TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { @@ -155,7 +155,7 @@ namespace rift::ast return false; } - bool HasFunctions(TAccessRef access, Id typeId) + bool HasFunctions(p::TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { @@ -164,7 +164,7 @@ namespace rift::ast return false; } - bool HasFunctionBodies(TAccessRef access, Id typeId) + bool HasFunctionBodies(p::TAccessRef access, Id typeId) { if (const RiftType* fileType = FindFileType(access, typeId)) { @@ -423,7 +423,7 @@ namespace rift::ast return id; } - Id FindChildByName(TAccessRef access, Id ownerId, Tag functionName) + Id FindChildByName(p::TAccessRef access, Id ownerId, Tag functionName) { if (!IsNone(ownerId)) { @@ -447,7 +447,8 @@ namespace rift::ast p::RemoveId(access, ids, true); } - bool CopyExpressionType(TAccessRef> access, Id sourcePinId, Id targetPinId) + bool CopyExpressionType( + p::TAccessRef> access, Id sourcePinId, Id targetPinId) { auto* sourceType = access.TryGet(sourcePinId); auto* targetType = access.TryGet(targetPinId); diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index c45df267..62ec3ee0 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -59,8 +59,8 @@ namespace rift p::Info("Building project '{}'", ast::GetProjectName(compiler.ast)); // Clean build folders p::Info("Cleaning previous build"); - files::Delete(compiler.config.binariesPath, true, false); - files::CreateFolder(compiler.config.binariesPath, true); + Delete(compiler.config.binariesPath, true, false); + CreateFolder(compiler.config.binariesPath, true); backend->Build(compiler); } diff --git a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp index 4119a47f..dddcc6bb 100644 --- a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp +++ b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp @@ -5,24 +5,23 @@ namespace rift { - TArray GetBackendTypes() + p::TArray GetBackendTypes() { - TArray types = Backend::GetStaticType()->GetChildren(); - types.RemoveIf([](ClassType* type) { - return !type || type->HasFlag(Class_Abstract); + p::TArray types = Backend::GetStaticType()->GetChildren(); + types.RemoveIf([](p::ClassType* type) { + return !type || type->HasFlag(p::Class_Abstract); }); return Move(types); } - TArray> CreateBackends() + p::TArray> CreateBackends() { - TArray> backends; - + p::TArray> backends; auto types = GetBackendTypes(); backends.Reserve(types.Size()); for (auto* type : types) { - backends.Add(MakeOwned(type)); + backends.Add(p::MakeOwned(type)); } return Move(backends); } diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index d754ef4e..2c2a03bb 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -13,8 +13,8 @@ namespace rift::MIR { struct OptionsData { - TArray headers; - TArray definitions; + p::TArray headers; + p::TArray definitions; }; void InitCToMIROptions( diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 736416c4..1a52bd4d 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -29,37 +29,37 @@ namespace rift::MIR void CGenerator::GenerateModule(ast::Id moduleId) { - const Tag name = ast::GetModuleName(compiler.ast, moduleId); + const p::Tag name = ast::GetModuleName(compiler.ast, moduleId); CMIRModule& mirModule = compiler.ast.Add(moduleId); code = &mirModule.code; // Get all rift types from the module - TArray typeIds; + p::TArray typeIds; p::GetIdChildren(access, moduleId, typeIds); ExcludeIdsWithout(access, typeIds); { // Native declarations - TArray cStructIds = FindIdsWith(access, typeIds); - TArray cStaticIds = FindIdsWith(access, typeIds); - TArray cFunctionIds; + p::TArray cStructIds = p::FindIdsWith(access, typeIds); + p::TArray cStaticIds = p::FindIdsWith(access, typeIds); + p::TArray cFunctionIds; p::GetIdChildren(access, cStaticIds, cFunctionIds); ExcludeIdsWithout(access, cFunctionIds); DeclareStructs(cStructIds); DeclareFunctions(cFunctionIds, false); } - TArray staticFunctionIds; + p::TArray staticFunctionIds; { // Rift declarations & definitions - TArray structIds = FindIdsWith(access, typeIds); - TArray staticIds = FindIdsWith(access, typeIds); - TArray classIds = FindIdsWith(access, typeIds); - TArray classFunctionIds; + p::TArray structIds = p::FindIdsWith(access, typeIds); + p::TArray staticIds = p::FindIdsWith(access, typeIds); + p::TArray classIds = p::FindIdsWith(access, typeIds); + p::TArray classFunctionIds; p::GetIdChildren(access, staticIds, staticFunctionIds); p::GetIdChildren(access, classIds, classFunctionIds); ExcludeIdsWithout(access, staticFunctionIds); ExcludeIdsWithout(access, classFunctionIds); - TArray functionIds; + p::TArray functionIds; functionIds.Append(staticFunctionIds); functionIds.Append(classFunctionIds); @@ -106,19 +106,19 @@ namespace rift::MIR const auto& boolean = access.Get(id); access.Add(id, CMIRLiteral{.value = boolean.value ? "true" : "false"}); } - String strValue; + p::String strValue; for (ast::Id id : FindAllIdsWith(access)) { strValue.clear(); const auto& integral = access.Get(id); - Strings::ToString(strValue, integral.value); + p::Strings::ToString(strValue, integral.value); access.Add(id, CMIRLiteral{.value = p::Tag{strValue}}); } for (ast::Id id : FindAllIdsWith(access)) { strValue.clear(); const auto& floating = access.Get(id); - Strings::ToString(strValue, floating.value); + p::Strings::ToString(strValue, floating.value); if (floating.type == ast::FloatingType::F32) { strValue.push_back('f'); @@ -136,61 +136,61 @@ namespace rift::MIR } } - void CGenerator::DeclareStructs(TView ids) + void CGenerator::DeclareStructs(p::TView ids) { code->append("// Struct Declarations\n"); for (ast::Id id : ids) { p::Tag name = ast::GetNameUnsafe(access, id); access.Add(id, CMIRType{name}); - Strings::FormatTo(*code, "typedef struct {0} {0};\n", name); + p::Strings::FormatTo(*code, "typedef struct {0} {0};\n", name); } code->push_back('\n'); } - void CGenerator::DefineStructs(TView ids) + void CGenerator::DefineStructs(p::TView ids) { code->append("// Struct Definitions\n"); p::String membersCode; - TArray memberIds; + p::TArray memberIds; for (ast::Id id : ids) { membersCode.clear(); memberIds.Clear(false); p::GetIdChildren(access, id, memberIds); - ExcludeIdsWithout(access, memberIds); + p::ExcludeIdsWithout(access, memberIds); for (ast::Id memberId : memberIds) { const auto& var = access.Get(memberId); - const Tag memberName = ast::GetName(access, memberId); - auto* irType = access.TryGet(var.typeId); + const p::Tag memberName = ast::GetName(access, memberId); + auto* irType = access.TryGet(var.typeId); if (!irType) [[unlikely]] { - const Tag typeName = ast::GetName(access, id); - compiler.Error(Strings::Format( + const p::Tag typeName = ast::GetName(access, id); + compiler.Error(p::Strings::Format( "Variable '{}' in struct '{}' has an invalid type", memberName, typeName)); } else if (reservedNames.Contains(memberName)) [[unlikely]] { - const Tag typeName = ast::GetName(access, id); - compiler.Error(Strings::Format( + const p::Tag typeName = ast::GetName(access, id); + compiler.Error(p::Strings::Format( "Variable name '{}' not allowed in struct '{}' ", memberName, typeName)); } else { - Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); + p::Strings::FormatTo(membersCode, "{} {};\n", irType->value, memberName); } } const auto& type = access.Get(id); - Strings::FormatTo(*code, "struct {0} {{\n{1}}};\n", type.value, membersCode); + p::Strings::FormatTo(*code, "struct {0} {{\n{1}}};\n", type.value, membersCode); } code->push_back('\n'); } - void CGenerator::DeclareFunctions(TView ids, bool useFullName) + void CGenerator::DeclareFunctions(p::TView ids, bool useFullName) { code->append("// Function Declarations\n"); @@ -206,7 +206,7 @@ namespace rift::MIR if (auto* outputs = access.TryGet(id)) { - for (i32 i = 0; i < outputs->pinIds.Size(); ++i) + for (p::i32 i = 0; i < outputs->pinIds.Size(); ++i) { ast::Id inputId = outputs->pinIds[i]; if (access.Has(inputId)) @@ -214,31 +214,31 @@ namespace rift::MIR continue; } - Tag inputName = ast::GetName(access, inputId); + p::Tag inputName = ast::GetName(access, inputId); auto* exprId = access.TryGet(inputId); const auto* irType = exprId ? access.TryGet(exprId->id) : nullptr; if (!irType) [[unlikely]] { - const String functionName = ast::GetFullName(access, id); - compiler.Error(Strings::Format( + const p::String functionName = ast::GetFullName(access, id); + compiler.Error(p::Strings::Format( "Input '{}' in function '{}' has an invalid type. Using i32 instead.", inputName, functionName)); } else if (reservedNames.Contains(inputName)) [[unlikely]] { - const String functionName = ast::GetFullName(access, id); + const p::String functionName = ast::GetFullName(access, id); compiler.Error( - Strings::Format("Input name '{}' not allowed in function '{}' ", + p::Strings::Format("Input name '{}' not allowed in function '{}' ", inputName, functionName)); } else { - Strings::FormatTo(signature, "{0} {1}, ", irType->value, inputName); + p::Strings::FormatTo(signature, "{0} {1}, ", irType->value, inputName); } } - Strings::RemoveFromEnd(signature, ", "); + p::Strings::RemoveFromEnd(signature, ", "); } signature.push_back(')'); @@ -249,7 +249,7 @@ namespace rift::MIR code->push_back('\n'); } - void CGenerator::DefineFunctions(TView ids) + void CGenerator::DefineFunctions(p::TView ids) { code->append("// Function Definitions\n"); for (ast::Id id : ids) @@ -269,7 +269,7 @@ namespace rift::MIR void CGenerator::AddStmtBlock(ast::Id firstStmtId) { ast::Id splitId = ast::NoId; - TArray stmtIds; + p::TArray stmtIds; ast::GetStmtChain(access, firstStmtId, stmtIds, splitId); for (ast::Id id : stmtIds) @@ -324,14 +324,14 @@ namespace rift::MIR } if (!Ensure(access.Has(functionId))) { - compiler.Error(Strings::Format( + compiler.Error(p::Strings::Format( "Call to an invalid function: '{}'", ast::GetFullName(access, functionId))); return; } if (auto* inputs = access.TryGet(id)) { - for (i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) + for (p::i32 i = 0; i < inputs->linkedOutputs.Size(); ++i) { ast::ExprOutput output = inputs->linkedOutputs[i]; if (!output.IsNone()) @@ -344,7 +344,7 @@ namespace rift::MIR // TODO: Error? or assign default value? } } - Strings::RemoveFromEnd(*code, ", "); + p::Strings::RemoveFromEnd(*code, ", "); } code->push_back(')'); } @@ -353,7 +353,7 @@ namespace rift::MIR { if (p::IsNone(functionId)) { - compiler.Error(Strings::Format("Module is executable but has no \"Main\" function")); + compiler.Error(p::Strings::Format("Module is executable but has no \"Main\" function")); return; } diff --git a/Libs/Editor/Include/Components/CDeclRename.h b/Libs/Editor/Include/Components/CDeclRename.h index 13b1db0c..48e7e5e7 100644 --- a/Libs/Editor/Include/Components/CDeclRename.h +++ b/Libs/Editor/Include/Components/CDeclRename.h @@ -9,7 +9,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct CDeclRename : public p::Struct { @@ -18,4 +18,4 @@ namespace rift::Editor // Renaming uses this buffer to temporarely store the name being edited p::String buffer; }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Components/CModuleEditor.h b/Libs/Editor/Include/Components/CModuleEditor.h index 8919405e..5ea5e5fb 100644 --- a/Libs/Editor/Include/Components/CModuleEditor.h +++ b/Libs/Editor/Include/Components/CModuleEditor.h @@ -9,7 +9,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct CModuleEditor : public p::Struct { @@ -17,4 +17,4 @@ namespace rift::Editor bool pendingFocus = false; }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Components/CTypeEditor.h b/Libs/Editor/Include/Components/CTypeEditor.h index d734b757..a2285a32 100644 --- a/Libs/Editor/Include/Components/CTypeEditor.h +++ b/Libs/Editor/Include/Components/CTypeEditor.h @@ -9,7 +9,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct CTypeEditor : public p::Struct { @@ -37,4 +37,4 @@ namespace rift::Editor inline const Tag CTypeEditor::rightTopNode{"rightTopNode"}; inline const Tag CTypeEditor::rightBottomNode{"rightBottomNode"}; inline const Tag CTypeEditor::centralNode{"centralNode"}; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/DockSpaceLayout.h b/Libs/Editor/Include/DockSpaceLayout.h index 58ded73b..741ce919 100644 --- a/Libs/Editor/Include/DockSpaceLayout.h +++ b/Libs/Editor/Include/DockSpaceLayout.h @@ -7,7 +7,7 @@ #include -namespace rift::Editor +namespace rift::editor { using namespace p; @@ -75,4 +75,4 @@ namespace rift::Editor return idPtr ? *idPtr : 0; } }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index fdd0008b..12014008 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -8,7 +8,7 @@ #include -namespace rift::Editor +namespace rift::editor { class Editor { @@ -62,4 +62,4 @@ namespace rift::Editor protected: void UpdateConfig(); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Panels/FileExplorerPanel.h b/Libs/Editor/Include/Panels/FileExplorerPanel.h index 15326197..a4129ce5 100644 --- a/Libs/Editor/Include/Panels/FileExplorerPanel.h +++ b/Libs/Editor/Include/Panels/FileExplorerPanel.h @@ -13,7 +13,7 @@ #include -namespace rift::Editor +namespace rift::editor { // Forward declarations class ProjectEditor; @@ -88,4 +88,4 @@ namespace rift::Editor { return static_cast(filter); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index d3acf628..e3274353 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -15,8 +15,7 @@ #include - -namespace rift::Editor +namespace rift::editor { struct SEditor : public Struct { @@ -42,4 +41,4 @@ namespace rift::Editor inline const Tag SEditor::leftNode{"leftNode"}; inline const Tag SEditor::centralNode{"centralNode"}; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Systems/EditorSystem.h b/Libs/Editor/Include/Systems/EditorSystem.h index 791da7a0..38295797 100644 --- a/Libs/Editor/Include/Systems/EditorSystem.h +++ b/Libs/Editor/Include/Systems/EditorSystem.h @@ -4,8 +4,8 @@ #include -namespace rift::Editor::EditorSystem +namespace rift::editor::EditorSystem { void Init(ast::Tree& ast); void Draw(ast::Tree& ast); -} // namespace rift::Editor::EditorSystem +} // namespace rift::editor::EditorSystem diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 8d39c43e..f46dd759 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -15,7 +15,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct InspectorPanel { @@ -58,4 +58,4 @@ namespace rift::Editor void OpenAvailableSecondaryInspector(ast::Id id); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index 5757ed11..0be4ca35 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -8,8 +8,7 @@ #include - -namespace rift::Editor +namespace rift::editor { using namespace p; @@ -61,4 +60,4 @@ namespace rift::Editor BigBestFitArenaDebugger(); void Draw(); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Tools/GraphPlayground.h b/Libs/Editor/Include/Tools/GraphPlayground.h index 9f57a3a3..521e1aaf 100644 --- a/Libs/Editor/Include/Tools/GraphPlayground.h +++ b/Libs/Editor/Include/Tools/GraphPlayground.h @@ -7,7 +7,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct GraphPlayground { @@ -20,4 +20,4 @@ namespace rift::Editor void Draw(ast::Tree& ast, struct DockSpaceLayout& layout); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index e330545a..f95c2565 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -8,8 +8,7 @@ #include - -namespace rift::Editor +namespace rift::editor { using namespace p; @@ -22,4 +21,4 @@ namespace rift::Editor MemoryDebugger(); void Draw(); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Tools/ReflectionDebugger.h b/Libs/Editor/Include/Tools/ReflectionDebugger.h index 905d5f78..23ea10f5 100644 --- a/Libs/Editor/Include/Tools/ReflectionDebugger.h +++ b/Libs/Editor/Include/Tools/ReflectionDebugger.h @@ -6,7 +6,7 @@ #include -namespace rift::Editor +namespace rift::editor { using namespace p; @@ -27,4 +27,4 @@ namespace rift::Editor private: void DrawType(Type* type); }; -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/UserSettings.h b/Libs/Editor/Include/UserSettings.h new file mode 100644 index 00000000..df9cb538 --- /dev/null +++ b/Libs/Editor/Include/UserSettings.h @@ -0,0 +1,18 @@ + +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include + + +namespace rift +{ + + class UserSettings : p::Class + { + private: + static TOwnPtr instance; + + static UserSettings* Get(); + }; +} // namespace rift diff --git a/Libs/Editor/Include/Utils/DetailsPanel.h b/Libs/Editor/Include/Utils/DetailsPanel.h index d016ce3a..d3757e46 100644 --- a/Libs/Editor/Include/Utils/DetailsPanel.h +++ b/Libs/Editor/Include/Utils/DetailsPanel.h @@ -11,7 +11,7 @@ #include -namespace rift::Editor +namespace rift::editor { void DrawDetailsPanel(ast::Tree& ast, ast::Id typeId); -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/EditorStyle.h b/Libs/Editor/Include/Utils/EditorStyle.h index 4c82d9b7..04789bea 100644 --- a/Libs/Editor/Include/Utils/EditorStyle.h +++ b/Libs/Editor/Include/Utils/EditorStyle.h @@ -8,7 +8,7 @@ #include -namespace rift::Editor +namespace rift::editor { using namespace p; @@ -64,4 +64,4 @@ namespace rift::Editor void PushNodeBackgroundColor(Color color); void PopNodeBackgroundColor(); -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/ElementsPanel.h b/Libs/Editor/Include/Utils/ElementsPanel.h index 220fe315..5fa94c90 100644 --- a/Libs/Editor/Include/Utils/ElementsPanel.h +++ b/Libs/Editor/Include/Utils/ElementsPanel.h @@ -11,7 +11,7 @@ #include -namespace rift::Editor +namespace rift::editor { struct CTypeEditor; @@ -33,4 +33,4 @@ namespace rift::Editor void DrawFunction(ast::Tree& ast, CTypeEditor& editor, ast::Id functionId); void DrawElementsPanel(ast::Tree& ast, ast::Id typeId); -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/FunctionGraph.h b/Libs/Editor/Include/Utils/FunctionGraph.h index 6e74f6ce..d81be5db 100644 --- a/Libs/Editor/Include/Utils/FunctionGraph.h +++ b/Libs/Editor/Include/Utils/FunctionGraph.h @@ -13,7 +13,7 @@ namespace rift struct DockSpaceLayout; } -namespace rift::Editor::Graph +namespace rift::editor::Graph { struct Settings { @@ -58,4 +58,4 @@ namespace rift::Editor::Graph v2 GetNodePosition(ast::Id id); void SnapNodeDimensionsToGrid(); -} // namespace rift::Editor::Graph +} // namespace rift::editor::Graph diff --git a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h index 3cb93e21..ade77082 100644 --- a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h +++ b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h @@ -5,10 +5,10 @@ #include -namespace rift::Editor::Graph +namespace rift::editor::Graph { void DrawNodesContextMenu(ast::Tree& ast, ast::Id typeId, p::TView nodeIds); void DrawGraphContextMenu(ast::Tree& ast, ast::Id typeId, ast::Id hoveredNodeId); void DrawContextMenu( ast::Tree& ast, ast::Id typeId, ast::Id hoveredNodeId, ast::Id hoveredLinkId); -} // namespace rift::Editor::Graph +} // namespace rift::editor::Graph diff --git a/Libs/Editor/Include/Utils/ModuleUtils.h b/Libs/Editor/Include/Utils/ModuleUtils.h index a7ccc0aa..fc9595c6 100644 --- a/Libs/Editor/Include/Utils/ModuleUtils.h +++ b/Libs/Editor/Include/Utils/ModuleUtils.h @@ -9,9 +9,9 @@ #include -namespace rift::Editor +namespace rift::editor { - void OpenModuleEditor(TAccessRef, ast::CModule> access, ast::Id id); - void CloseModuleEditor(TAccessRef, ast::CModule> access, ast::Id id); - bool IsEditingModule(TAccessRef access, ast::Id id); -} // namespace rift::Editor + void OpenModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id); + void CloseModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id); + bool IsEditingModule(p::TAccessRef access, ast::Id id); +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/ProjectManager.h b/Libs/Editor/Include/Utils/ProjectManager.h index 74ec6dc7..0f8efe4f 100644 --- a/Libs/Editor/Include/Utils/ProjectManager.h +++ b/Libs/Editor/Include/Utils/ProjectManager.h @@ -5,8 +5,8 @@ #include -namespace rift::Editor +namespace rift::editor { void DrawProjectManager(ast::Tree& ast); void OpenProjectManager(); -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/TypeUtils.h b/Libs/Editor/Include/Utils/TypeUtils.h index 7b0bce03..c00b7e7c 100644 --- a/Libs/Editor/Include/Utils/TypeUtils.h +++ b/Libs/Editor/Include/Utils/TypeUtils.h @@ -10,11 +10,11 @@ #include -namespace rift::Editor +namespace rift::editor { - void OpenType(TAccessRef, ast::CDeclType> access, ast::Id id); - void CloseType(TAccessRef, ast::CDeclType> access, ast::Id id); - bool IsTypeOpen(TAccessRef access, ast::Id id); + void OpenType(p::TAccessRef, ast::CDeclType> access, ast::Id id); + void CloseType(p::TAccessRef, ast::CDeclType> access, ast::Id id); + bool IsTypeOpen(p::TAccessRef access, ast::Id id); constexpr StringView GetUnaryOperatorName(ast::UnaryOperatorType type) { @@ -93,4 +93,4 @@ namespace rift::Editor } return ""; } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/Widgets.h b/Libs/Editor/Include/Utils/Widgets.h index cec02a88..5eaaaf24 100644 --- a/Libs/Editor/Include/Utils/Widgets.h +++ b/Libs/Editor/Include/Utils/Widgets.h @@ -9,12 +9,12 @@ #include -namespace rift::Editor +namespace rift::editor { - bool TypeCombo(ast::TAccessRef access, p::StringView label, ast::Id& selectedTypeId); bool InputLiteralValue(ast::Tree& ast, p::StringView label, ast::Id literalId); -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/DockSpaceLayout.cpp b/Libs/Editor/Src/DockSpaceLayout.cpp index 4fb96fe5..39dd08d2 100644 --- a/Libs/Editor/Src/DockSpaceLayout.cpp +++ b/Libs/Editor/Src/DockSpaceLayout.cpp @@ -7,7 +7,7 @@ #include -namespace rift::Editor +namespace rift::editor { const Tag DockSpaceLayout::rootNodeId{"root"}; @@ -103,4 +103,4 @@ namespace rift::Editor } ImGui::DockBuilderFinish(dockSpaceID); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 8964655f..efa13163 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -20,7 +20,7 @@ #include -namespace rift::Editor +namespace rift::editor { void RegisterKeyValueInspections() { @@ -204,7 +204,7 @@ namespace rift::Editor return; } - if (files::ExistsAsFile(configFile)) + if (ExistsAsFile(configFile)) { // FIX: Delay this until new frame (essentially, not while already drawing) ImGui::LoadIniSettingsFromDisk(configFile.c_str()); @@ -216,4 +216,4 @@ namespace rift::Editor configFileChanged = false; } } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index c6030b70..0e12bdc0 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -29,7 +29,7 @@ #include -namespace rift::Editor +namespace rift::editor { void FileExplorerPanel::Draw(ast::Tree& ast) { @@ -421,7 +421,7 @@ namespace rift::Editor p::ReplaceExtension(destination, "rf"); // TODO: Move this into systems. Renaming a type shouldnt require so many // manual steps - if (files::Rename(path, destination)) + if (Rename(path, destination)) { if (auto* file = ast.TryGet(item.id)) { @@ -488,7 +488,7 @@ namespace rift::Editor String data; ast::SerializeType(ast, id, data); - files::SaveStringFile(StringView{path}, data); + SaveStringFile(StringView{path}, data); // Destroy the temporal type after saving it ast.Destroy(id); @@ -496,4 +496,4 @@ namespace rift::Editor // Mark path to be opened later once the type has loaded pendingOpenCreatedPath = path; } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index 0db7461e..f4bbe10f 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -37,7 +37,7 @@ #include -namespace rift::Editor::EditorSystem +namespace rift::editor::EditorSystem { void OnProjectEditorOpen(ast::Tree& ast) { @@ -298,7 +298,7 @@ namespace rift::Editor::EditorSystem for (auto& fileData : fileDatas) { - files::SaveStringFile(fileData.first, fileData.second); + SaveStringFile(fileData.first, fileData.second); } ast.Remove(dirtyTypeIds); @@ -392,7 +392,7 @@ namespace rift::Editor::EditorSystem String data; ast::SerializeModule(ast, moduleId, data); - files::SaveStringFile(StringView(file.path), data); + SaveStringFile(StringView(file.path), data); ast.Remove(moduleId); UI::AddNotification({UI::ToastType::Success, 1.f, @@ -498,7 +498,7 @@ namespace rift::Editor::EditorSystem String data; ast::SerializeType(ast, typeId, data); - files::SaveStringFile(StringView(file.path), data); + SaveStringFile(StringView(file.path), data); ast.Remove(typeId); UI::AddNotification({UI::ToastType::Success, 1.f, @@ -592,4 +592,4 @@ namespace rift::Editor::EditorSystem } } } -} // namespace rift::Editor::EditorSystem +} // namespace rift::editor::EditorSystem diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 883228fa..00f89824 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -17,7 +17,7 @@ #include -namespace rift::Editor +namespace rift::editor { void DrawTypesDebug(ast::Tree& ast) { @@ -351,10 +351,10 @@ namespace rift::Editor if (valid) { - const auto& registry = ast::TypeRegistry::Get(); + const auto& registry = p::TypeRegistry::Get(); for (const auto& poolInstance : ast.GetPools()) { - ast::Type* type = registry.FindType(poolInstance.componentId); + p::Type* type = registry.FindType(poolInstance.componentId); if (!type || !poolInstance.GetPool()->Has(inspector.id)) { continue; @@ -410,4 +410,4 @@ namespace rift::Editor secondaryInspectors.Add({id}); } } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp index 2f37619c..ecf40923 100644 --- a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp +++ b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp @@ -12,7 +12,7 @@ #include -namespace rift::Editor +namespace rift::editor { static constexpr Color gFreeColor{210, 56, 41}; // Red static constexpr Color gUsedColor{56, 210, 41}; // Green @@ -216,4 +216,4 @@ namespace rift::Editor UI::End(); } } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Tools/GraphPlayground.cpp b/Libs/Editor/Src/Tools/GraphPlayground.cpp index 5a5b355a..cb7ed52f 100644 --- a/Libs/Editor/Src/Tools/GraphPlayground.cpp +++ b/Libs/Editor/Src/Tools/GraphPlayground.cpp @@ -10,7 +10,7 @@ #include -namespace rift::Editor +namespace rift::editor { using namespace Nodes; @@ -47,4 +47,4 @@ namespace rift::Editor } UI::End(); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Tools/MemoryDebugger.cpp b/Libs/Editor/Src/Tools/MemoryDebugger.cpp index 21e4eb75..30ca7198 100644 --- a/Libs/Editor/Src/Tools/MemoryDebugger.cpp +++ b/Libs/Editor/Src/Tools/MemoryDebugger.cpp @@ -14,7 +14,7 @@ #include -namespace rift::Editor +namespace rift::editor { static constexpr Color gFreeColor{210, 56, 41}; // Red static constexpr Color gUsedColor{56, 210, 41}; // Green @@ -72,4 +72,4 @@ namespace rift::Editor } UI::End(); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index 5fd6638d..68dff217 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -12,7 +12,7 @@ #include -namespace rift::Editor +namespace rift::editor { ReflectionDebugger::ReflectionDebugger() {} @@ -107,4 +107,4 @@ namespace rift::Editor } } } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index f8b67b70..30be06f1 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -21,7 +21,7 @@ #include -namespace rift::Editor +namespace rift::editor { void EditFunctionPin(ast::Tree& ast, ast::Id ownerId, ast::Id id) { @@ -71,7 +71,7 @@ namespace rift::Editor labelId.clear(); Strings::FormatTo(labelId, "##Type_{}", id); UI::SetNextItemWidth(-FLT_MIN); - if (Editor::TypeCombo(ast, labelId, typeId)) + if (editor::TypeCombo(ast, labelId, typeId)) { ScopedChange(ast, id); ast.GetOrAdd(id).id = typeId; @@ -217,4 +217,4 @@ namespace rift::Editor } UI::End(); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index 25def6c4..728cd552 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -8,7 +8,7 @@ #include -namespace rift::Editor +namespace rift::editor { const Color GetTypeColor(const ast::Tree& ast, ast::Id id) { @@ -78,4 +78,4 @@ namespace rift::Editor { Nodes::PopStyleColor(3); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 3e734d4d..ca235074 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -21,7 +21,7 @@ #include -namespace rift::Editor +namespace rift::editor { void DrawVariable(TVariableAccessRef access, CTypeEditor& editor, ast::Id variableId) { @@ -107,7 +107,7 @@ namespace rift::Editor { UI::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.f); UI::SetNextItemWidth(-FLT_MIN); - Editor::TypeCombo(access, "##type", variableDecl->typeId); + editor::TypeCombo(access, "##type", variableDecl->typeId); UI::PopStyleVar(); } @@ -281,4 +281,4 @@ namespace rift::Editor } } } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 167d2fe1..15bf3911 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -26,7 +26,7 @@ #include -namespace rift::Editor::Graph +namespace rift::editor::Graph { static CNodePosition* currentNodeTransform = nullptr; @@ -62,7 +62,7 @@ namespace rift::Editor::Graph return Nodes::ScreenToGridPosition(screenPosition) * GetInvGridSize(); } - void BeginExprInput(TAccessRef access, ast::Id id, const bool& invalid) + void BeginExprInput(p::TAccessRef access, ast::Id id, const bool& invalid) { bool isPointer = false; ast::Id typeId = ast::NoId; @@ -90,7 +90,7 @@ namespace rift::Editor::Graph i32(id), isPointer ? Nodes::PinShape_DiamondFilled : Nodes::PinShape_CircleFilled); } - void BeginExprOutput(TAccessRef access, ast::Id id, const bool& invalid) + void BeginExprOutput(p::TAccessRef access, ast::Id id, const bool& invalid) { bool isPointer = false; ast::Id typeId = ast::NoId; @@ -138,7 +138,7 @@ namespace rift::Editor::Graph } } - void DrawInputs(TAccessRef access, + void DrawInputs(p::TAccessRef access, const ast::CExprInputs& inputs) { for (ast::Id pinId : inputs.pinIds) @@ -154,7 +154,7 @@ namespace rift::Editor::Graph } } - void DrawOutputs(TAccessRef access, + void DrawOutputs(p::TAccessRef access, const ast::CExprOutputs& outputs) { for (ast::Id pinId : outputs.pinIds) @@ -170,7 +170,7 @@ namespace rift::Editor::Graph } } - void BeginNode(TAccessRef> access, ast::Id id) + void BeginNode(p::TAccessRef> access, ast::Id id) { currentNodeTransform = &access.GetOrAdd(id); auto* context = Nodes::GetCurrentContext(); @@ -363,7 +363,7 @@ namespace rift::Editor::Graph } } - void DrawReturnNode(TAccessRef, TWrite, + void DrawReturnNode(p::TAccessRef, TWrite, TWrite, ast::CChild, ast::CFileRef> access, ast::Id id) @@ -504,7 +504,7 @@ namespace rift::Editor::Graph ImGui::PopStyleVar(2); } - void DrawReturns(TAccessRef, TWrite, + void DrawReturns(p::TAccessRef, TWrite, TWrite, ast::CChild, ast::CFileRef, ast::CStmtReturn> access, const TArray& children) @@ -570,9 +570,9 @@ namespace rift::Editor::Graph } } - void DrawIfs(TAccessRef, TWrite, TWrite, - ast::CChild, ast::CFileRef, ast::CStmtIf, ast::CStmtOutputs, ast::CExprInputs, - ast::CParent, ast::CExprTypeId> + void DrawIfs(p::TAccessRef, TWrite, + TWrite, ast::CChild, ast::CFileRef, ast::CStmtIf, + ast::CStmtOutputs, ast::CExprInputs, ast::CParent, ast::CExprTypeId> access, const TArray& children) { @@ -656,7 +656,7 @@ namespace rift::Editor::Graph UI::SameLine(); const auto& op = access.Get(id); - StringView shortName = Editor::GetUnaryOperatorName(op.type); + StringView shortName = editor::GetUnaryOperatorName(op.type); UI::Text(shortName); UI::SameLine(); @@ -701,7 +701,7 @@ namespace rift::Editor::Graph UI::SameLine(); const auto& op = access.Get(id); - StringView shortName = Editor::GetBinaryOperatorName(op.type); + StringView shortName = editor::GetBinaryOperatorName(op.type); UI::Text(shortName); UI::SameLine(); @@ -714,7 +714,8 @@ namespace rift::Editor::Graph } } - void DrawStatementLinks(TAccessRef& access, + void DrawStatementLinks( + p::TAccessRef& access, const TArray& children) { Nodes::PushStyleVar(Nodes::StyleVar_LinkThickness, 2.f); @@ -914,4 +915,4 @@ namespace rift::Editor::Graph const v2 pos = Nodes::GetNodeGridSpacePos(id); return v2{pos.x * settings.GetInvGridSize(), pos.y * settings.GetInvGridSize()}.Floor(); } -} // namespace rift::Editor::Graph +} // namespace rift::editor::Graph diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index 1c332b39..4d056273 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -24,7 +24,7 @@ #include -namespace rift::Editor::Graph +namespace rift::editor::Graph { void SetPositionAndConnect(ast::Tree& ast, ast::Id id, v2 position) { @@ -308,4 +308,4 @@ namespace rift::Editor::Graph UI::EndPopup(); } } -} // namespace rift::Editor::Graph +} // namespace rift::editor::Graph diff --git a/Libs/Editor/Src/Utils/ModuleUtils.cpp b/Libs/Editor/Src/Utils/ModuleUtils.cpp index f1022083..5dd3b740 100644 --- a/Libs/Editor/Src/Utils/ModuleUtils.cpp +++ b/Libs/Editor/Src/Utils/ModuleUtils.cpp @@ -5,9 +5,9 @@ #include -namespace rift::Editor +namespace rift::editor { - void OpenModuleEditor(TAccessRef, ast::CModule> access, ast::Id id) + void OpenModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id) { Check(access.Has(id)); if (auto* editor = access.TryGet(id)) @@ -20,14 +20,14 @@ namespace rift::Editor } } - void CloseModuleEditor(TAccessRef, ast::CModule> access, ast::Id id) + void CloseModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id) { Check(access.Has(id)); access.Remove(id); } - bool IsEditingModule(TAccessRef access, ast::Id id) + bool IsEditingModule(p::TAccessRef access, ast::Id id) { return access.Has(id); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 55a0274b..74245d7c 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -9,7 +9,7 @@ #include -namespace rift::Editor +namespace rift::editor { void TextCentered(const char* text) { @@ -130,4 +130,4 @@ namespace rift::Editor { UI::OpenPopup("Project Manager"); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/TypeUtils.cpp b/Libs/Editor/Src/Utils/TypeUtils.cpp index 12a11f0b..e9a7870c 100644 --- a/Libs/Editor/Src/Utils/TypeUtils.cpp +++ b/Libs/Editor/Src/Utils/TypeUtils.cpp @@ -6,9 +6,9 @@ #include -namespace rift::Editor +namespace rift::editor { - void OpenType(TAccessRef, ast::CDeclType> access, ast::Id id) + void OpenType(p::TAccessRef, ast::CDeclType> access, ast::Id id) { Check(access.Has(id)); if (auto* editor = access.TryGet(id)) @@ -21,14 +21,14 @@ namespace rift::Editor } } - void CloseType(TAccessRef, ast::CDeclType> access, ast::Id id) + void CloseType(p::TAccessRef, ast::CDeclType> access, ast::Id id) { Check(access.Has(id)); access.Remove(id); } - bool IsTypeOpen(TAccessRef access, ast::Id id) + bool IsTypeOpen(p::TAccessRef access, ast::Id id) { return access.Has(id); } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/Widgets.cpp b/Libs/Editor/Src/Utils/Widgets.cpp index a95dec39..ca0b6a21 100644 --- a/Libs/Editor/Src/Utils/Widgets.cpp +++ b/Libs/Editor/Src/Utils/Widgets.cpp @@ -5,7 +5,7 @@ #include -namespace rift::Editor +namespace rift::editor { void ListTypesFromFilter(p::TAccessRef access, p::TArray typeIds, ast::Id& selectedId, ImGuiTextFilter& searchFilter) @@ -102,4 +102,4 @@ namespace rift::Editor { return false; } -} // namespace rift::Editor +} // namespace rift::editor diff --git a/Libs/UI/Include/UI/Inspection.h b/Libs/UI/Include/UI/Inspection.h index b9e48e47..5aa40942 100644 --- a/Libs/UI/Include/UI/Inspection.h +++ b/Libs/UI/Include/UI/Inspection.h @@ -16,11 +16,8 @@ namespace rift::UI { - using namespace p; - - // label, data, type - using CustomKeyValue = TFunction; + using CustomKeyValue = TFunction; void RegisterCustomInspection(Type* typeId, const CustomKeyValue& custom); @@ -30,9 +27,9 @@ namespace rift::UI RegisterCustomInspection(GetType(), custom); } - void DrawEnumValue(void* data, EnumType* type); - void DrawNativeValue(void* data, NativeType* type); - void DrawKeyValue(StringView label, void* data, Type* type); + void DrawEnumValue(void* data, p::EnumType* type); + void DrawNativeValue(void* data, p::NativeType* type); + void DrawKeyValue(p::StringView label, void* data, p::Type* type); void InspectProperty(const ValueHandle& handle); void InspectChildrenProperties(const ValueHandle& handle); @@ -52,10 +49,10 @@ namespace rift::UI // InspectChildrenProperties(data, type); } - bool BeginCategory(StringView name, bool isLeaf); + bool BeginCategory(p::StringView name, bool isLeaf); void EndCategory(); - bool BeginInspector(const char* name, v2 size = v2{0.f, 0.f}); + bool BeginInspector(const char* name, p::v2 size = p::v2{0.f, 0.f}); void EndInspector(); void RegisterCoreKeyValueInspections(); diff --git a/Libs/UI/Include/UI/Paths.h b/Libs/UI/Include/UI/Paths.h index 8605df1a..df4e11b5 100644 --- a/Libs/UI/Include/UI/Paths.h +++ b/Libs/UI/Include/UI/Paths.h @@ -8,5 +8,4 @@ namespace rift::Paths { p::String GetResourcesPath(); - p::String GetUserSettingsPath(); }; // namespace rift::Paths diff --git a/Libs/UI/Include/UI/Style.h b/Libs/UI/Include/UI/Style.h index 66b8751b..9733149d 100644 --- a/Libs/UI/Include/UI/Style.h +++ b/Libs/UI/Include/UI/Style.h @@ -7,39 +7,36 @@ namespace rift::UI { - using namespace p; + constexpr p::LinearColor primaryColor = p::LinearColor::FromHEX(0xD6863B); + constexpr p::LinearColor whiteTextColor = p::LinearColor::White().Shade(0.05f); + constexpr p::LinearColor blackTextColor = p::LinearColor::Black().Tint(0.05f); - constexpr LinearColor primaryColor = LinearColor::FromHEX(0xD6863B); + constexpr p::LinearColor infoColor = p::LinearColor::FromHEX(0x2B8ED6); + constexpr p::LinearColor successColor = p::LinearColor::FromHEX(0x4DD62B); + constexpr p::LinearColor warningColor = p::LinearColor::FromHEX(0xD6AB2B); + constexpr p::LinearColor errorColor = p::LinearColor::FromHEX(0xD62B2B); - constexpr LinearColor whiteTextColor = LinearColor::White().Shade(0.05f); - constexpr LinearColor blackTextColor = LinearColor::Black().Tint(0.05f); - constexpr LinearColor infoColor = LinearColor::FromHEX(0x2B8ED6); - constexpr LinearColor successColor = LinearColor::FromHEX(0x4DD62B); - constexpr LinearColor warningColor = LinearColor::FromHEX(0xD6AB2B); - constexpr LinearColor errorColor = LinearColor::FromHEX(0xD62B2B); - - - constexpr LinearColor GetNeutralColor(u8 level) + constexpr p::LinearColor GetNeutralColor(p::u8 level) { switch (level) { default: - case 0: return LinearColor::FromHEX(0x222222); - case 1: return LinearColor::FromHEX(0x3B3B3B); - case 2: return LinearColor::FromHEX(0x464646); - case 3: return LinearColor::FromHEX(0x515151); - case 4: return LinearColor::FromHEX(0x626262); - case 5: return LinearColor::FromHEX(0x6E6E6E); - case 6: return LinearColor::FromHEX(0x9E9E9E); - case 7: return LinearColor::FromHEX(0xB1B1B1); - case 8: return LinearColor::FromHEX(0xCFCFCF); - case 9: return LinearColor::FromHEX(0xE1E1E1); - case 10: return LinearColor::FromHEX(0xF7F7F7); + case 0: return p::LinearColor::FromHEX(0x222222); + case 1: return p::LinearColor::FromHEX(0x3B3B3B); + case 2: return p::LinearColor::FromHEX(0x464646); + case 3: return p::LinearColor::FromHEX(0x515151); + case 4: return p::LinearColor::FromHEX(0x626262); + case 5: return p::LinearColor::FromHEX(0x6E6E6E); + case 6: return p::LinearColor::FromHEX(0x9E9E9E); + case 7: return p::LinearColor::FromHEX(0xB1B1B1); + case 8: return p::LinearColor::FromHEX(0xCFCFCF); + case 9: return p::LinearColor::FromHEX(0xE1E1E1); + case 10: return p::LinearColor::FromHEX(0xF7F7F7); } } - inline LinearColor GetNeutralTextColor(u8 level) + inline p::LinearColor GetNeutralTextColor(p::u8 level) { return level <= 5 ? whiteTextColor : blackTextColor; } @@ -76,24 +73,24 @@ namespace rift::UI void PushStyleCompact(); void PopStyleCompact(); - void PushFrameBgColor(LinearColor color); + void PushFrameBgColor(p::LinearColor color); void PopFrameBgColor(); - void PushButtonColor(LinearColor color); + void PushButtonColor(p::LinearColor color); void PopButtonColor(); - void PushHeaderColor(LinearColor color = GetNeutralColor(2)); + void PushHeaderColor(p::LinearColor color = GetNeutralColor(2)); void PopHeaderColor(); - void PushTextColor(LinearColor color); + void PushTextColor(p::LinearColor color); void PopTextColor(); template - TColor Hovered(const TColor& color) + p::TColor Hovered(const p::TColor& color) { return color.Shade(0.1f); } - template - TColor Disabled(const TColor& color) + template + p::TColor Disabled(const p::TColor& color) { return color.Shade(0.2f); } diff --git a/Libs/UI/Src/Paths.cpp b/Libs/UI/Src/Paths.cpp index d1c72f99..f49b8bf5 100644 --- a/Libs/UI/Src/Paths.cpp +++ b/Libs/UI/Src/Paths.cpp @@ -12,10 +12,4 @@ namespace rift::Paths static p::StringView relativeResourcesPath{"Resources"}; return p::JoinPaths(p::PlatformPaths::GetBasePath(), relativeResourcesPath); } - - p::String GetUserSettingsPath() - { - static p::StringView relativeSettingsPath{"Rift"}; - return p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath); - } }; // namespace rift::Paths diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index bad08c6c..5d3187e6 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -16,9 +16,6 @@ namespace rift::UI { - using namespace p; - - struct FontType { TArray> sizes{}; diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index b638cd09..955f981f 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -27,9 +27,6 @@ namespace rift::UI { - using namespace p; - - static GLFWwindow* gWindow = nullptr; void OnGl3WError(int error, const char* description) diff --git a/Tests/Project.spec.cpp b/Tests/Project.spec.cpp index aee24b86..7a0b557f 100644 --- a/Tests/Project.spec.cpp +++ b/Tests/Project.spec.cpp @@ -13,7 +13,6 @@ #include - using namespace snowhouse; using namespace bandit; using namespace rift; @@ -26,20 +25,20 @@ String testProjectPath = p::JoinPaths(PlatformPaths::GetCurrentPath(), "TestProj go_bandit([]() { describe("Project", []() { before_each([]() { - files::Delete(testProjectPath, true, false); + Delete(testProjectPath, true, false); - if (!files::ExistsAsFolder(testProjectPath)) + if (!ExistsAsFolder(testProjectPath)) { - files::CreateFolder(testProjectPath); + CreateFolder(testProjectPath); } }); after_each([]() { - files::Delete(testProjectPath); + Delete(testProjectPath); }); it("Can load empty descriptor", [&]() { - files::SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); + SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); ast::Tree ast; bool result = ast::OpenProject(ast, testProjectPath); @@ -48,7 +47,7 @@ go_bandit([]() { }); it("Project name equals the folder", [&]() { - files::SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); + SaveStringFile(p::JoinPaths(testProjectPath, ast::moduleFilename), "{}"); ast::Tree ast; bool result = ast::OpenProject(ast, testProjectPath); @@ -62,7 +61,7 @@ go_bandit([]() { // TODO: Fix module loading. They can't load from CFileRef pointing to the folder and not // the file it("Project name can be overriden", [&]() { - files::SaveStringFile( + SaveStringFile( p::JoinPaths(testProjectPath, ast::moduleFilename), "{\"name\": \"SomeProject\"}"); ast::Tree ast; From 9c6d4557940c9c69d2ab8c5c156a94078bef20df Mon Sep 17 00:00:00 2001 From: muit Date: Thu, 29 Feb 2024 23:56:35 +0100 Subject: [PATCH 33/52] Load User Settings --- Libs/AST/Include/AST/Utils/Settings.h | 42 +++++++++++++------- Libs/AST/Src/AST/Utils/Settings.cpp | 4 +- Libs/Editor/Include/Statics/EditorSettings.h | 16 ++++++++ Libs/Editor/Src/Utils/ProjectManager.cpp | 24 ++++++++--- 4 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 Libs/Editor/Include/Statics/EditorSettings.h diff --git a/Libs/AST/Include/AST/Utils/Settings.h b/Libs/AST/Include/AST/Utils/Settings.h index 1409568e..05b2a920 100644 --- a/Libs/AST/Include/AST/Utils/Settings.h +++ b/Libs/AST/Include/AST/Utils/Settings.h @@ -2,33 +2,45 @@ #pragma once -#include "AST/Tree.h" -#include "AST/TypeRef.h" - #include +#include +#include #include #include -namespace rift::ast +namespace rift { p::String GetUserSettingsPath(); template - T* GetUserSettings() + T& GetUserSettings() { - static TOwnPtr instance; + static p::TOwnPtr instance; if (!instance) { + instance = p::MakeOwned(); + p::String path = GetUserSettingsPath(); - String data; - // if (p::LoadStringFile(path, data)) - //{ - // instance = MakeOwned(); - // p::JsonFormatReader reader{data}; - // reader.GetReader().Serialize(*instance); - // } + if (!p::Exists(path)) + { + p::CreateFolder(path); + } + + p::AppendToPath(path, p::GetTypeName(false)); + path.append(".json"); + if (!p::Exists(path)) + { + p::SaveStringFile(path, "{}"); + } + + p::String data; + if (p::LoadStringFile(path, data)) + { + p::JsonFormatReader reader{data}; + reader.GetReader().Serialize(*instance); + } } - return instance.Get(); + return *instance.Get(); } -} // namespace rift::ast +} // namespace rift diff --git a/Libs/AST/Src/AST/Utils/Settings.cpp b/Libs/AST/Src/AST/Utils/Settings.cpp index b8f8ea74..67cb9f59 100644 --- a/Libs/AST/Src/AST/Utils/Settings.cpp +++ b/Libs/AST/Src/AST/Utils/Settings.cpp @@ -6,11 +6,11 @@ #include -namespace rift::ast +namespace rift { p::String GetUserSettingsPath() { static p::StringView relativeSettingsPath{"Rift"}; return p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath); } -} // namespace rift::ast +} // namespace rift diff --git a/Libs/Editor/Include/Statics/EditorSettings.h b/Libs/Editor/Include/Statics/EditorSettings.h new file mode 100644 index 00000000..f2d2ae6e --- /dev/null +++ b/Libs/Editor/Include/Statics/EditorSettings.h @@ -0,0 +1,16 @@ +// Copyright 2015-2023 Piperift - All rights reserved +#pragma once + +#include + + +namespace rift::editor +{ + struct EditorSettings : public p::Struct + { + P_STRUCT(EditorSettings, p::Struct) + + P_PROP(recentProjects) + p::TArray recentProjects; + }; +} // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index 74245d7c..c495261c 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -1,8 +1,10 @@ // Copyright 2015-2023 Piperift - All rights reserved #include "Editor.h" +#include "Statics/EditorSettings.h" #include "Utils/ElementsPanel.h" +#include #include #include #include @@ -56,16 +58,29 @@ namespace rift::editor UI::SetItemDefaultFocus(); { UI::Text("Recent projects:"); + auto& editorSettings = rift::GetUserSettings(); static const char* recentProjects[]{"Project.rift"}; static int selectedN = 0; UI::SetNextItemWidth(-FLT_MIN); - for (int n = 0; n < IM_ARRAYSIZE(recentProjects); ++n) + for (int n = 0; n < editorSettings.recentProjects.Size(); ++n) { const bool isSelected = (selectedN == n); - UI::BulletText(recentProjects[n]); + p::StringView path = editorSettings.recentProjects[n]; + UI::BulletText(path.data()); UI::SameLine(ImGui::GetContentRegionAvail().x - 30.f); - if (UI::SmallButton("open")) {} + if (UI::SmallButton("open")) + { + if (Editor::Get().OpenProject(path)) + { + UI::CloseCurrentPopup(); + } + else + { + UI::AddNotification({UI::ToastType::Error, 1.f, + p::Strings::Format("Failed to open project at '{}'", path)}); + } + } } } UI::Dummy({10.f, 40.f}); @@ -84,9 +99,8 @@ namespace rift::editor UI::SameLine(); if (UI::Button("...", p::v2{24.f, 0.f})) { - p::String selectedFolder = p::SelectFolderDialog( + folder = p::SelectFolderDialog( "Select project folder", p::PlatformPaths::GetCurrentPath()); - folder = p::ToString(selectedFolder); } } From c7818be33ebe06e9b0a9b61d40586e316d132e42 Mon Sep 17 00:00:00 2001 From: muit Date: Fri, 1 Mar 2024 21:43:58 +0100 Subject: [PATCH 34/52] Implemented saving settings --- Libs/AST/Include/AST/Utils/Settings.h | 46 +++++++++++++++++---------- Libs/AST/Src/AST/Utils/Settings.cpp | 7 ++-- Libs/Editor/Src/Editor.cpp | 6 ++++ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Libs/AST/Include/AST/Utils/Settings.h b/Libs/AST/Include/AST/Utils/Settings.h index 05b2a920..f04a377a 100644 --- a/Libs/AST/Include/AST/Utils/Settings.h +++ b/Libs/AST/Include/AST/Utils/Settings.h @@ -2,6 +2,9 @@ #pragma once +#include "AST/Utils/Settings.h" +#include "Pipe/Files/Paths.h" + #include #include #include @@ -11,7 +14,7 @@ namespace rift { - p::String GetUserSettingsPath(); + p::String GetUserSettingsPath(p::StringView name); template T& GetUserSettings() @@ -21,26 +24,37 @@ namespace rift { instance = p::MakeOwned(); - p::String path = GetUserSettingsPath(); - if (!p::Exists(path)) - { - p::CreateFolder(path); - } - - p::AppendToPath(path, p::GetTypeName(false)); - path.append(".json"); - if (!p::Exists(path)) + p::String filePath = GetUserSettingsPath(p::GetTypeName(false)); + if (!p::Exists(filePath)) { - p::SaveStringFile(path, "{}"); + SaveUserSettings(); } - - p::String data; - if (p::LoadStringFile(path, data)) + else { - p::JsonFormatReader reader{data}; - reader.GetReader().Serialize(*instance); + p::String data; + if (p::LoadStringFile(filePath, data)) + { + p::JsonFormatReader reader{data}; + reader.GetReader().Serialize(*instance); + } } } return *instance.Get(); } + + template + void SaveUserSettings() + { + auto& instance = GetUserSettings(); + p::JsonFormatWriter writer{}; + writer.GetWriter().Serialize(instance); + + p::String filePath = GetUserSettingsPath(p::GetTypeName(false)); + p::StringView folderPath = p::GetParentPath(filePath); + if (!p::Exists(folderPath)) + { + p::CreateFolder(folderPath); + } + p::SaveStringFile(filePath, writer.ToString()); + } } // namespace rift diff --git a/Libs/AST/Src/AST/Utils/Settings.cpp b/Libs/AST/Src/AST/Utils/Settings.cpp index 67cb9f59..41a1b898 100644 --- a/Libs/AST/Src/AST/Utils/Settings.cpp +++ b/Libs/AST/Src/AST/Utils/Settings.cpp @@ -8,9 +8,12 @@ namespace rift { - p::String GetUserSettingsPath() + p::String GetUserSettingsPath(p::StringView name) { static p::StringView relativeSettingsPath{"Rift"}; - return p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath); + p::String path = + p::JoinPaths(p::PlatformPaths::GetUserSettingsPath(), relativeSettingsPath, name); + path.append(".json"); + return p::Move(path); } } // namespace rift diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index efa13163..8852b8aa 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -4,6 +4,8 @@ #include "AST/Systems/FunctionsSystem.h" #include "AST/Utils/Namespaces.h" +#include "AST/Utils/Settings.h" +#include "Statics/EditorSettings.h" #include "Statics/SEditor.h" #include "Systems/EditorSystem.h" #include "Utils/FunctionGraph.h" @@ -174,6 +176,10 @@ namespace rift::editor Editor::Get().bFilesDirty = true; })); + + auto& editorSettings = GetUserSettings(); + editorSettings.recentProjects.AddUnique(p::String(projectPath)); + SaveUserSettings(); return true; } return false; From a6c89495367ec2e0b5c819cedb0b6b6189c9e067 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 28 Apr 2024 19:26:08 +0200 Subject: [PATCH 35/52] Updated Pipe --- Apps/CLI/Src/main.cpp | 3 +- Apps/Editor/Src/main.cpp | 2 +- Examples/CodeGuidelines.cpp | 2 +- Examples/CodeGuidelines.h | 2 +- Extern/IconFontCppHeaders | 2 +- Extern/Pipe | 2 +- Extern/glfw | 2 +- Extern/imgui | 2 +- Libs/AST/Include/AST/Components/CFileRef.h | 2 +- Libs/AST/Include/AST/Components/CModule.h | 2 +- Libs/AST/Include/AST/Components/CNamespace.h | 2 +- Libs/AST/Include/AST/Components/CProject.h | 2 +- .../AST/Include/AST/Components/Declarations.h | 2 +- Libs/AST/Include/AST/Components/Expressions.h | 2 +- Libs/AST/Include/AST/Components/Literals.h | 2 +- Libs/AST/Include/AST/Components/Statements.h | 3 +- .../Include/AST/Components/Tags/CChanged.h | 2 +- Libs/AST/Include/AST/Components/Tags/CDirty.h | 2 +- .../Include/AST/Components/Tags/CInvalid.h | 2 +- .../AST/Components/Tags/CPendingLoad.h | 2 +- .../AST/Components/Views/CNodePosition.h | 2 +- Libs/AST/Include/AST/Id.h | 3 +- Libs/AST/Include/AST/Statics/SLoadQueue.h | 2 +- Libs/AST/Include/AST/Statics/SModules.h | 2 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 2 +- Libs/AST/Include/AST/Statics/STypes.h | 2 +- .../AST/Include/AST/Systems/FunctionsSystem.h | 2 +- Libs/AST/Include/AST/Systems/LoadSystem.h | 2 +- .../Include/AST/Systems/TransactionSystem.h | 2 +- Libs/AST/Include/AST/Systems/TypeSystem.h | 2 +- Libs/AST/Include/AST/Tree.h | 2 +- Libs/AST/Include/AST/TypeRef.h | 2 +- Libs/AST/Include/AST/Utils/Expressions.h | 2 +- .../Include/AST/Utils/ModuleFileIterator.h | 2 +- Libs/AST/Include/AST/Utils/ModuleUtils.h | 2 +- Libs/AST/Include/AST/Utils/Namespaces.h | 2 +- Libs/AST/Include/AST/Utils/Paths.h | 2 +- Libs/AST/Include/AST/Utils/Settings.h | 5 ++- Libs/AST/Include/AST/Utils/Statements.h | 2 +- Libs/AST/Include/AST/Utils/TransactionUtils.h | 2 +- Libs/AST/Include/AST/Utils/TypeIterator.h | 2 +- Libs/AST/Include/AST/Utils/TypeUtils.h | 2 +- Libs/AST/Include/ASTModule.h | 2 +- Libs/AST/Include/Compiler/Backend.h | 2 +- Libs/AST/Include/Compiler/Compiler.h | 2 +- Libs/AST/Include/Compiler/CompilerConfig.h | 2 +- .../Compiler/Systems/OptimizationSystem.h | 2 +- .../AST/Include/Compiler/Utils/BackendUtils.h | 2 +- Libs/AST/Include/Module.h | 2 +- Libs/AST/Include/Rift.h | 2 +- Libs/AST/Include/View.h | 2 +- Libs/AST/Src/AST/Components/CNamespace.cpp | 2 +- Libs/AST/Src/AST/Systems/FunctionsSystem.cpp | 2 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 5 ++- .../AST/Src/AST/Systems/TransactionSystem.cpp | 2 +- Libs/AST/Src/AST/Systems/TypeSystem.cpp | 2 +- Libs/AST/Src/AST/Tree.cpp | 2 +- Libs/AST/Src/AST/Utils/Expressions.cpp | 2 +- Libs/AST/Src/AST/Utils/ModuleUtils.cpp | 3 +- Libs/AST/Src/AST/Utils/Namespaces.cpp | 2 +- Libs/AST/Src/AST/Utils/Settings.cpp | 2 +- Libs/AST/Src/AST/Utils/Statements.cpp | 2 +- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 2 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 3 +- Libs/AST/Src/ASTModule.cpp | 2 +- Libs/AST/Src/Compiler/Compiler.cpp | 2 +- Libs/AST/Src/Compiler/CompilerConfig.cpp | 2 +- .../Compiler/Systems/OptimizationSystem.cpp | 2 +- Libs/AST/Src/Compiler/Utils/BackendUtils.cpp | 2 +- Libs/AST/Src/Module.cpp | 2 +- Libs/AST/Src/Rift.cpp | 2 +- .../MIR/Compiler/Include/MIRBackendModule.h | 2 +- Libs/Backends/MIR/Compiler/Src/C2MIR.cpp | 2 +- Libs/Backends/MIR/Compiler/Src/C2MIR.h | 3 +- Libs/Backends/MIR/Compiler/Src/Components.h | 2 +- .../MIR/Compiler/Src/IRGeneration.cpp | 2 +- Libs/Backends/MIR/Compiler/Src/IRGeneration.h | 2 +- .../MIR/Compiler/Src/MIRBackendModule.cpp | 2 +- .../Include/Components/CNativeBinding.h | 2 +- .../Include/Components/Declarations.h | 2 +- .../Native/Compiler/Include/HeaderIterator.h | 2 +- .../Compiler/Include/NativeBindingModule.h | 2 +- .../Compiler/Src/NativeBindingModule.cpp | 2 +- .../Include/NativeBindingEditorModule.h | 2 +- .../Editor/Src/NativeBindingEditorModule.cpp | 2 +- Libs/Editor/Include/Components/CDeclRename.h | 2 +- .../Editor/Include/Components/CModuleEditor.h | 2 +- Libs/Editor/Include/Components/CTypeEditor.h | 2 +- Libs/Editor/Include/DockSpaceLayout.h | 2 +- Libs/Editor/Include/Editor.h | 2 +- .../Editor/Include/Panels/FileExplorerPanel.h | 2 +- Libs/Editor/Include/Statics/EditorSettings.h | 2 +- Libs/Editor/Include/Statics/SEditor.h | 2 +- Libs/Editor/Include/Systems/EditorSystem.h | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 2 +- .../Include/Tools/BigBestFitArenaDebugger.h | 2 +- Libs/Editor/Include/Tools/GraphPlayground.h | 2 +- Libs/Editor/Include/Tools/MemoryDebugger.h | 2 +- .../Editor/Include/Tools/ReflectionDebugger.h | 2 +- Libs/Editor/Include/UserSettings.h | 2 +- Libs/Editor/Include/Utils/DetailsPanel.h | 2 +- Libs/Editor/Include/Utils/EditorStyle.h | 26 +++++++------- Libs/Editor/Include/Utils/ElementsPanel.h | 2 +- Libs/Editor/Include/Utils/FunctionGraph.h | 2 +- .../Include/Utils/FunctionGraphContextMenu.h | 2 +- Libs/Editor/Include/Utils/ModuleUtils.h | 2 +- Libs/Editor/Include/Utils/Nodes.h | 2 +- Libs/Editor/Include/Utils/NodesInternal.h | 2 +- Libs/Editor/Include/Utils/NodesMiniMap.h | 2 +- Libs/Editor/Include/Utils/ProjectManager.h | 2 +- Libs/Editor/Include/Utils/TypeUtils.h | 2 +- Libs/Editor/Include/Utils/Widgets.h | 2 +- Libs/Editor/Src/DockSpaceLayout.cpp | 2 +- Libs/Editor/Src/Editor.cpp | 2 +- Libs/Editor/Src/Panels/FileExplorerPanel.cpp | 2 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 2 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 2 +- .../Src/Tools/BigBestFitArenaDebugger.cpp | 2 +- Libs/Editor/Src/Tools/GraphPlayground.cpp | 2 +- Libs/Editor/Src/Tools/MemoryDebugger.cpp | 2 +- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 2 +- Libs/Editor/Src/Utils/DetailsPanel.cpp | 2 +- Libs/Editor/Src/Utils/EditorStyle.cpp | 2 +- Libs/Editor/Src/Utils/ElementsPanel.cpp | 2 +- Libs/Editor/Src/Utils/FunctionGraph.cpp | 2 +- .../Src/Utils/FunctionGraphContextMenu.cpp | 2 +- Libs/Editor/Src/Utils/ModuleUtils.cpp | 2 +- Libs/Editor/Src/Utils/Nodes.cpp | 2 +- Libs/Editor/Src/Utils/NodesMiniMap.cpp | 2 +- Libs/Editor/Src/Utils/ProjectManager.cpp | 2 +- Libs/Editor/Src/Utils/TypeUtils.cpp | 2 +- Libs/Editor/Src/Utils/Widgets.cpp | 2 +- Libs/Runtimes/Std/Include/IO.h | 2 +- Libs/Runtimes/Std/Include/Math.h | 2 +- Libs/Runtimes/Std/Src/IO.cpp | 2 +- Libs/Runtimes/Std/Src/Math.cpp | 2 +- Libs/UI/Include/UI/Inspection.h | 2 +- Libs/UI/Include/UI/Notify.h | 2 +- Libs/UI/Include/UI/Paths.h | 2 +- Libs/UI/Include/UI/Style.h | 35 ++++++++++--------- Libs/UI/Include/UI/UI.h | 2 +- Libs/UI/Include/UI/UIImgui.h | 2 +- Libs/UI/Include/UI/Widgets.h | 2 +- Libs/UI/Include/UI/Window.h | 2 +- Libs/UI/Src/Inspection.cpp | 2 +- Libs/UI/Src/Notify.cpp | 2 +- Libs/UI/Src/Paths.cpp | 2 +- Libs/UI/Src/Style.cpp | 3 +- Libs/UI/Src/Widgets.cpp | 2 +- Libs/UI/Src/Window.cpp | 2 +- .../Graph/Compiler/Include/GraphViewModule.h | 2 +- .../Graph/Compiler/Src/GraphViewModule.cpp | 2 +- .../Editor/Include/GraphViewEditorModule.h | 2 +- .../Editor/Src/GraphViewEditorModule.cpp | 2 +- Tests/AST/Expressions.spec.cpp | 2 +- Tests/AST/Namespaces.spec.cpp | 2 +- Tests/AST/Statements.spec.cpp | 2 +- Tests/Project.spec.cpp | 2 +- Tests/main.cpp | 2 +- imgui.ini | 4 +-- 160 files changed, 194 insertions(+), 198 deletions(-) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index b27106dc..ce3bed69 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include // Override as first include @@ -19,7 +19,6 @@ #include - using namespace rift; diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index 4fc2bfa4..4e972b61 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include // Override as first include diff --git a/Examples/CodeGuidelines.cpp b/Examples/CodeGuidelines.cpp index f14a37a7..d886e9d8 100644 --- a/Examples/CodeGuidelines.cpp +++ b/Examples/CodeGuidelines.cpp @@ -1,2 +1,2 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved // Coding standards for Rift and Rift-Core diff --git a/Examples/CodeGuidelines.h b/Examples/CodeGuidelines.h index ca2377f0..5800a972 100644 --- a/Examples/CodeGuidelines.h +++ b/Examples/CodeGuidelines.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved // Coding standards for Rift and Rift-Core // [header.format] Use .h for header files and .cpp for source files diff --git a/Extern/IconFontCppHeaders b/Extern/IconFontCppHeaders index 6a2e60d2..96c8d39d 160000 --- a/Extern/IconFontCppHeaders +++ b/Extern/IconFontCppHeaders @@ -1 +1 @@ -Subproject commit 6a2e60d2b270e41a711612cc2a1eb4c9bde701a9 +Subproject commit 96c8d39dee3eb33a64e42eee0d8f3ca40320df78 diff --git a/Extern/Pipe b/Extern/Pipe index 54e26582..83a6946e 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 54e2658265dfeaa0f06fd2394567b3eab0a2dbf2 +Subproject commit 83a6946e13f9dae2521f782214e44cb9e2b484cd diff --git a/Extern/glfw b/Extern/glfw index b43c122d..7b6aead9 160000 --- a/Extern/glfw +++ b/Extern/glfw @@ -1 +1 @@ -Subproject commit b43c122dd194d74996d76c574a46d4bc23d6c7b0 +Subproject commit 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 diff --git a/Extern/imgui b/Extern/imgui index ce0d0ac8..1db579d4 160000 --- a/Extern/imgui +++ b/Extern/imgui @@ -1 +1 @@ -Subproject commit ce0d0ac8298ce164b5d862577e8b087d92f6e90e +Subproject commit 1db579d458da29fa43376af9d88d486910d9406a diff --git a/Libs/AST/Include/AST/Components/CFileRef.h b/Libs/AST/Include/AST/Components/CFileRef.h index cc21ea65..2c8d6a8f 100644 --- a/Libs/AST/Include/AST/Components/CFileRef.h +++ b/Libs/AST/Include/AST/Components/CFileRef.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/CModule.h b/Libs/AST/Include/AST/Components/CModule.h index 02962510..e4be9333 100644 --- a/Libs/AST/Include/AST/Components/CModule.h +++ b/Libs/AST/Include/AST/Components/CModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index aee191c3..e77e4b38 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/CProject.h b/Libs/AST/Include/AST/Components/CProject.h index 3ee75798..c471a420 100644 --- a/Libs/AST/Include/AST/Components/CProject.h +++ b/Libs/AST/Include/AST/Components/CProject.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Declarations.h b/Libs/AST/Include/AST/Components/Declarations.h index 322608ab..4d1d08f8 100644 --- a/Libs/AST/Include/AST/Components/Declarations.h +++ b/Libs/AST/Include/AST/Components/Declarations.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Expressions.h b/Libs/AST/Include/AST/Components/Expressions.h index 1b085caa..4cbcaf0e 100644 --- a/Libs/AST/Include/AST/Components/Expressions.h +++ b/Libs/AST/Include/AST/Components/Expressions.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CNamespace.h" diff --git a/Libs/AST/Include/AST/Components/Literals.h b/Libs/AST/Include/AST/Components/Literals.h index 876bb94e..ac0c6668 100644 --- a/Libs/AST/Include/AST/Components/Literals.h +++ b/Libs/AST/Include/AST/Components/Literals.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Statements.h b/Libs/AST/Include/AST/Components/Statements.h index f3a8b846..91abc554 100644 --- a/Libs/AST/Include/AST/Components/Statements.h +++ b/Libs/AST/Include/AST/Components/Statements.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include @@ -54,6 +54,7 @@ namespace rift::ast {} }; + /** Represents a return expression of a function * Return arguments are dynamically populated depending on the function this expression is * connected to. diff --git a/Libs/AST/Include/AST/Components/Tags/CChanged.h b/Libs/AST/Include/AST/Components/Tags/CChanged.h index f3eafac9..9027a49a 100644 --- a/Libs/AST/Include/AST/Components/Tags/CChanged.h +++ b/Libs/AST/Include/AST/Components/Tags/CChanged.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Tags/CDirty.h b/Libs/AST/Include/AST/Components/Tags/CDirty.h index 215789e6..a0563aa8 100644 --- a/Libs/AST/Include/AST/Components/Tags/CDirty.h +++ b/Libs/AST/Include/AST/Components/Tags/CDirty.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CFileRef.h" diff --git a/Libs/AST/Include/AST/Components/Tags/CInvalid.h b/Libs/AST/Include/AST/Components/Tags/CInvalid.h index ee40a885..84bf80e0 100644 --- a/Libs/AST/Include/AST/Components/Tags/CInvalid.h +++ b/Libs/AST/Include/AST/Components/Tags/CInvalid.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h index b5642003..16f2f331 100644 --- a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h +++ b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Components/Views/CNodePosition.h b/Libs/AST/Include/AST/Components/Views/CNodePosition.h index 5a7ee61a..620906a2 100644 --- a/Libs/AST/Include/AST/Components/Views/CNodePosition.h +++ b/Libs/AST/Include/AST/Components/Views/CNodePosition.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index cd148aa4..ac8cd1ca 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -1,9 +1,8 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include #include -#include #include diff --git a/Libs/AST/Include/AST/Statics/SLoadQueue.h b/Libs/AST/Include/AST/Statics/SLoadQueue.h index e2d4f1f5..90c6fac9 100644 --- a/Libs/AST/Include/AST/Statics/SLoadQueue.h +++ b/Libs/AST/Include/AST/Statics/SLoadQueue.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/AST/Include/AST/Statics/SModules.h b/Libs/AST/Include/AST/Statics/SModules.h index a300e96c..9193f4e5 100644 --- a/Libs/AST/Include/AST/Statics/SModules.h +++ b/Libs/AST/Include/AST/Statics/SModules.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index 4c079ee3..cadfcd54 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index c74a0401..25c8cf40 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/AST/Include/AST/Systems/FunctionsSystem.h b/Libs/AST/Include/AST/Systems/FunctionsSystem.h index d71c0899..acc26e9d 100644 --- a/Libs/AST/Include/AST/Systems/FunctionsSystem.h +++ b/Libs/AST/Include/AST/Systems/FunctionsSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CNamespace.h" diff --git a/Libs/AST/Include/AST/Systems/LoadSystem.h b/Libs/AST/Include/AST/Systems/LoadSystem.h index 397a7de4..d1453319 100644 --- a/Libs/AST/Include/AST/Systems/LoadSystem.h +++ b/Libs/AST/Include/AST/Systems/LoadSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CFileRef.h" diff --git a/Libs/AST/Include/AST/Systems/TransactionSystem.h b/Libs/AST/Include/AST/Systems/TransactionSystem.h index 43895a3a..51f7efa9 100644 --- a/Libs/AST/Include/AST/Systems/TransactionSystem.h +++ b/Libs/AST/Include/AST/Systems/TransactionSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Tree.h" diff --git a/Libs/AST/Include/AST/Systems/TypeSystem.h b/Libs/AST/Include/AST/Systems/TypeSystem.h index 4c7a9bae..905b1825 100644 --- a/Libs/AST/Include/AST/Systems/TypeSystem.h +++ b/Libs/AST/Include/AST/Systems/TypeSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/Declarations.h" diff --git a/Libs/AST/Include/AST/Tree.h b/Libs/AST/Include/AST/Tree.h index abb46cdd..6102bf95 100644 --- a/Libs/AST/Include/AST/Tree.h +++ b/Libs/AST/Include/AST/Tree.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/AST/Include/AST/TypeRef.h b/Libs/AST/Include/AST/TypeRef.h index 408bbf3d..f41758ba 100644 --- a/Libs/AST/Include/AST/TypeRef.h +++ b/Libs/AST/Include/AST/TypeRef.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/Declarations.h" diff --git a/Libs/AST/Include/AST/Utils/Expressions.h b/Libs/AST/Include/AST/Utils/Expressions.h index 8eb1f0ec..8f46aaed 100644 --- a/Libs/AST/Include/AST/Utils/Expressions.h +++ b/Libs/AST/Include/AST/Utils/Expressions.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/Expressions.h" diff --git a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h index f76341ac..ab7303dd 100644 --- a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CModule.h" diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index 720627c0..be4bbf56 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/AST/Utils/Namespaces.h b/Libs/AST/Include/AST/Utils/Namespaces.h index e5d14898..756399d1 100644 --- a/Libs/AST/Include/AST/Utils/Namespaces.h +++ b/Libs/AST/Include/AST/Utils/Namespaces.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CModule.h" diff --git a/Libs/AST/Include/AST/Utils/Paths.h b/Libs/AST/Include/AST/Utils/Paths.h index 2d7254c9..38948f74 100644 --- a/Libs/AST/Include/AST/Utils/Paths.h +++ b/Libs/AST/Include/AST/Utils/Paths.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/AST/Utils/Settings.h b/Libs/AST/Include/AST/Utils/Settings.h index f04a377a..0fb7c72f 100644 --- a/Libs/AST/Include/AST/Utils/Settings.h +++ b/Libs/AST/Include/AST/Utils/Settings.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once @@ -7,9 +7,8 @@ #include #include -#include -#include #include +#include namespace rift diff --git a/Libs/AST/Include/AST/Utils/Statements.h b/Libs/AST/Include/AST/Utils/Statements.h index d3988dab..75fc658a 100644 --- a/Libs/AST/Include/AST/Utils/Statements.h +++ b/Libs/AST/Include/AST/Utils/Statements.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/Statements.h" diff --git a/Libs/AST/Include/AST/Utils/TransactionUtils.h b/Libs/AST/Include/AST/Utils/TransactionUtils.h index 577a5383..7b8b23df 100644 --- a/Libs/AST/Include/AST/Utils/TransactionUtils.h +++ b/Libs/AST/Include/AST/Utils/TransactionUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/AST/Utils/TypeIterator.h b/Libs/AST/Include/AST/Utils/TypeIterator.h index 3ed526cf..5d44076b 100644 --- a/Libs/AST/Include/AST/Utils/TypeIterator.h +++ b/Libs/AST/Include/AST/Utils/TypeIterator.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Utils/Paths.h" diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index b8992398..dd0a0856 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/ASTModule.h b/Libs/AST/Include/ASTModule.h index 9d330972..3c6a1721 100644 --- a/Libs/AST/Include/ASTModule.h +++ b/Libs/AST/Include/ASTModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index 71e25e96..bca26a93 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index 97f66b2f..f594691f 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index a3d668d1..d00214e4 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h b/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h index fd126808..0b1c03c4 100644 --- a/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h +++ b/Libs/AST/Include/Compiler/Systems/OptimizationSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once namespace rift::ast diff --git a/Libs/AST/Include/Compiler/Utils/BackendUtils.h b/Libs/AST/Include/Compiler/Utils/BackendUtils.h index c741d965..25e9656d 100644 --- a/Libs/AST/Include/Compiler/Utils/BackendUtils.h +++ b/Libs/AST/Include/Compiler/Utils/BackendUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Module.h b/Libs/AST/Include/Module.h index dd3b16fb..495af2cd 100644 --- a/Libs/AST/Include/Module.h +++ b/Libs/AST/Include/Module.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index 5aa4f1e1..bc67e688 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/AST/Include/View.h b/Libs/AST/Include/View.h index 6c483cc5..85547487 100644 --- a/Libs/AST/Include/View.h +++ b/Libs/AST/Include/View.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/Declarations.h" diff --git a/Libs/AST/Src/AST/Components/CNamespace.cpp b/Libs/AST/Src/AST/Components/CNamespace.cpp index 40173a73..9c5052a1 100644 --- a/Libs/AST/Src/AST/Components/CNamespace.cpp +++ b/Libs/AST/Src/AST/Components/CNamespace.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Components/CNamespace.h" diff --git a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp index 7c4291e6..6e0155b8 100644 --- a/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp +++ b/Libs/AST/Src/AST/Systems/FunctionsSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Systems/FunctionsSystem.h" diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index 725da7ef..c9e7e596 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Systems/LoadSystem.h" @@ -13,10 +13,9 @@ #include "AST/Utils/ModuleUtils.h" #include "AST/Utils/TypeIterator.h" #include "AST/Utils/TypeUtils.h" -#include "Pipe/Files/Paths.h" #include -#include +#include namespace rift::ast::LoadSystem diff --git a/Libs/AST/Src/AST/Systems/TransactionSystem.cpp b/Libs/AST/Src/AST/Systems/TransactionSystem.cpp index 0a67d0a0..c5cf5eb3 100644 --- a/Libs/AST/Src/AST/Systems/TransactionSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TransactionSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Systems/TransactionSystem.h" diff --git a/Libs/AST/Src/AST/Systems/TypeSystem.cpp b/Libs/AST/Src/AST/Systems/TypeSystem.cpp index 7a620df8..d5f649af 100644 --- a/Libs/AST/Src/AST/Systems/TypeSystem.cpp +++ b/Libs/AST/Src/AST/Systems/TypeSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Systems/TypeSystem.h" diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index b40b6cec..3927b683 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Tree.h" diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index 8deba6ea..9e91b91d 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/Expressions.h" diff --git a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp index 9e772e10..522a93da 100644 --- a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp +++ b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/ModuleUtils.h" @@ -11,7 +11,6 @@ #include #include -#include #include diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index 88f70430..ccf26394 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/Namespaces.h" diff --git a/Libs/AST/Src/AST/Utils/Settings.cpp b/Libs/AST/Src/AST/Utils/Settings.cpp index 41a1b898..4d8f182f 100644 --- a/Libs/AST/Src/AST/Utils/Settings.cpp +++ b/Libs/AST/Src/AST/Utils/Settings.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/Settings.h" diff --git a/Libs/AST/Src/AST/Utils/Statements.cpp b/Libs/AST/Src/AST/Utils/Statements.cpp index c79d91d1..6cfec7a5 100644 --- a/Libs/AST/Src/AST/Utils/Statements.cpp +++ b/Libs/AST/Src/AST/Utils/Statements.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/Statements.h" diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index c3ed6a27..d37c099d 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/TransactionUtils.h" diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 43bbaec7..807c7114 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Utils/TypeUtils.h" @@ -18,7 +18,6 @@ #include #include -#include #include diff --git a/Libs/AST/Src/ASTModule.cpp b/Libs/AST/Src/ASTModule.cpp index a8281208..6a53e31d 100644 --- a/Libs/AST/Src/ASTModule.cpp +++ b/Libs/AST/Src/ASTModule.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "ASTModule.h" diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 62ec3ee0..58528611 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Compiler/Compiler.h" diff --git a/Libs/AST/Src/Compiler/CompilerConfig.cpp b/Libs/AST/Src/Compiler/CompilerConfig.cpp index 89f0ff9b..c195e6c7 100644 --- a/Libs/AST/Src/Compiler/CompilerConfig.cpp +++ b/Libs/AST/Src/Compiler/CompilerConfig.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Compiler/CompilerConfig.h" diff --git a/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp b/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp index 62b745fc..35ea25eb 100644 --- a/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp +++ b/Libs/AST/Src/Compiler/Systems/OptimizationSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Compiler/Systems/OptimizationSystem.h" diff --git a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp index dddcc6bb..d8817138 100644 --- a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp +++ b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Compiler/Utils/BackendUtils.h" diff --git a/Libs/AST/Src/Module.cpp b/Libs/AST/Src/Module.cpp index 32bbff30..212a4ba4 100644 --- a/Libs/AST/Src/Module.cpp +++ b/Libs/AST/Src/Module.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Module.h" diff --git a/Libs/AST/Src/Rift.cpp b/Libs/AST/Src/Rift.cpp index c475a62c..9f598853 100644 --- a/Libs/AST/Src/Rift.cpp +++ b/Libs/AST/Src/Rift.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Rift.h" diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index 93e858b3..cc72b5ad 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp index 2c2a03bb..2df9cac2 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "C2MIR.h" diff --git a/Libs/Backends/MIR/Compiler/Src/C2MIR.h b/Libs/Backends/MIR/Compiler/Src/C2MIR.h index ee3545a9..bb6a6b15 100644 --- a/Libs/Backends/MIR/Compiler/Src/C2MIR.h +++ b/Libs/Backends/MIR/Compiler/Src/C2MIR.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "Components.h" @@ -14,7 +14,6 @@ #include - struct c2mir_options; namespace rift diff --git a/Libs/Backends/MIR/Compiler/Src/Components.h b/Libs/Backends/MIR/Compiler/Src/Components.h index aa1b7678..87ed8374 100644 --- a/Libs/Backends/MIR/Compiler/Src/Components.h +++ b/Libs/Backends/MIR/Compiler/Src/Components.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 1a52bd4d..98726c46 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "IRGeneration.h" diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h index 10b9b6ce..00e64a2f 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.h +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "Components.h" diff --git a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp index e94e17c5..42413da6 100644 --- a/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp +++ b/Libs/Backends/MIR/Compiler/Src/MIRBackendModule.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "MIRBackendModule.h" diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h index 4cff9d92..1ca2ca61 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h index 80385ed1..fd6fc81c 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h index ada4bb47..038c3fcb 100644 --- a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h +++ b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Utils/Paths.h" diff --git a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h index f8ffea9f..711ae3e8 100644 --- a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h +++ b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 281374ec..cc93cfd2 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "NativeBindingModule.h" diff --git a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h index 1a7a2bce..cecdd1b3 100644 --- a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h +++ b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Bindings/Native/Editor/Src/NativeBindingEditorModule.cpp b/Libs/Bindings/Native/Editor/Src/NativeBindingEditorModule.cpp index bc871902..6bad9b90 100644 --- a/Libs/Bindings/Native/Editor/Src/NativeBindingEditorModule.cpp +++ b/Libs/Bindings/Native/Editor/Src/NativeBindingEditorModule.cpp @@ -1,3 +1,3 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "NativeBindingEditorModule.h" diff --git a/Libs/Editor/Include/Components/CDeclRename.h b/Libs/Editor/Include/Components/CDeclRename.h index 48e7e5e7..a54684a3 100644 --- a/Libs/Editor/Include/Components/CDeclRename.h +++ b/Libs/Editor/Include/Components/CDeclRename.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "Assets/TypePropertiesPanel.h" diff --git a/Libs/Editor/Include/Components/CModuleEditor.h b/Libs/Editor/Include/Components/CModuleEditor.h index 5ea5e5fb..5fd93988 100644 --- a/Libs/Editor/Include/Components/CModuleEditor.h +++ b/Libs/Editor/Include/Components/CModuleEditor.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "DockSpaceLayout.h" diff --git a/Libs/Editor/Include/Components/CTypeEditor.h b/Libs/Editor/Include/Components/CTypeEditor.h index a2285a32..8b8ad2c5 100644 --- a/Libs/Editor/Include/Components/CTypeEditor.h +++ b/Libs/Editor/Include/Components/CTypeEditor.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "DockSpaceLayout.h" diff --git a/Libs/Editor/Include/DockSpaceLayout.h b/Libs/Editor/Include/DockSpaceLayout.h index 741ce919..1b365a29 100644 --- a/Libs/Editor/Include/DockSpaceLayout.h +++ b/Libs/Editor/Include/DockSpaceLayout.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index 12014008..e9dd14ab 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "PipeFiles.h" diff --git a/Libs/Editor/Include/Panels/FileExplorerPanel.h b/Libs/Editor/Include/Panels/FileExplorerPanel.h index a4129ce5..5a50e165 100644 --- a/Libs/Editor/Include/Panels/FileExplorerPanel.h +++ b/Libs/Editor/Include/Panels/FileExplorerPanel.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Components/CProject.h" diff --git a/Libs/Editor/Include/Statics/EditorSettings.h b/Libs/Editor/Include/Statics/EditorSettings.h index f2d2ae6e..8e9005a3 100644 --- a/Libs/Editor/Include/Statics/EditorSettings.h +++ b/Libs/Editor/Include/Statics/EditorSettings.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index e3274353..e77e36aa 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Id.h" diff --git a/Libs/Editor/Include/Systems/EditorSystem.h b/Libs/Editor/Include/Systems/EditorSystem.h index 38295797..1f45e9b0 100644 --- a/Libs/Editor/Include/Systems/EditorSystem.h +++ b/Libs/Editor/Include/Systems/EditorSystem.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index f46dd759..31eeb95e 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Tree.h" diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index 0be4ca35..c2964978 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Tools/GraphPlayground.h b/Libs/Editor/Include/Tools/GraphPlayground.h index 521e1aaf..d19734a8 100644 --- a/Libs/Editor/Include/Tools/GraphPlayground.h +++ b/Libs/Editor/Include/Tools/GraphPlayground.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Tree.h" diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index f95c2565..3b50865d 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Tools/ReflectionDebugger.h b/Libs/Editor/Include/Tools/ReflectionDebugger.h index 23ea10f5..21f73000 100644 --- a/Libs/Editor/Include/Tools/ReflectionDebugger.h +++ b/Libs/Editor/Include/Tools/ReflectionDebugger.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "AST/Tree.h" diff --git a/Libs/Editor/Include/UserSettings.h b/Libs/Editor/Include/UserSettings.h index df9cb538..cf16cffc 100644 --- a/Libs/Editor/Include/UserSettings.h +++ b/Libs/Editor/Include/UserSettings.h @@ -1,5 +1,5 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Utils/DetailsPanel.h b/Libs/Editor/Include/Utils/DetailsPanel.h index d3757e46..ac02d1c8 100644 --- a/Libs/Editor/Include/Utils/DetailsPanel.h +++ b/Libs/Editor/Include/Utils/DetailsPanel.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/EditorStyle.h b/Libs/Editor/Include/Utils/EditorStyle.h index 04789bea..d49bcbd4 100644 --- a/Libs/Editor/Include/Utils/EditorStyle.h +++ b/Libs/Editor/Include/Utils/EditorStyle.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once @@ -13,45 +13,45 @@ namespace rift::editor using namespace p; - constexpr Color selectedColor{Color::FromHEX(0xdba43f)}; - constexpr Color executionColor{Color::FromHEX(0xdbdbdb)}; + constexpr Color selectedColor{Color::FromHex(0xdba43f)}; + constexpr Color executionColor{Color::FromHex(0xdbdbdb)}; - constexpr Color functionColor{Color::FromHEX(0xCC3D33)}; + constexpr Color functionColor{Color::FromHex(0xCC3D33)}; constexpr Color returnColor{functionColor.Shade(0.1f)}; - constexpr Color callColor{Color::FromHEX(0x3366CC)}; + constexpr Color callColor{Color::FromHex(0x3366CC)}; constexpr Color flowColor{UI::GetNeutralColor(4)}; - constexpr Color invalidColor{Color::FromHEX(0xF95040)}; + constexpr Color invalidColor{Color::FromHex(0xF95040)}; template constexpr Color GetTypeColor() { if constexpr (IsSame) { - return Color::FromHEX(0xBF4A41); + return Color::FromHex(0xBF4A41); } else if constexpr (FloatingPoint) { - return Color::FromHEX(0x54BFA6); + return Color::FromHex(0x54BFA6); } else if constexpr (SignedIntegral) { - return Color::FromHEX(0x63BF54); + return Color::FromHex(0x63BF54); } else if constexpr (UnsignedIntegral) { - return Color::FromHEX(0x54BF79); + return Color::FromHex(0x54BF79); } else if constexpr (IsSame) { - return Color::FromHEX(0xBF54AE); + return Color::FromHex(0xBF54AE); } else if constexpr (IsSame) { - return Color::FromHEX(0x545FBF); + return Color::FromHex(0x545FBF); } else if constexpr (IsSame) { - return Color::FromHEX(0x548CBF); + return Color::FromHex(0x548CBF); } return Color::Gray(); }; diff --git a/Libs/Editor/Include/Utils/ElementsPanel.h b/Libs/Editor/Include/Utils/ElementsPanel.h index 5fa94c90..0877e7e4 100644 --- a/Libs/Editor/Include/Utils/ElementsPanel.h +++ b/Libs/Editor/Include/Utils/ElementsPanel.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/FunctionGraph.h b/Libs/Editor/Include/Utils/FunctionGraph.h index d81be5db..658ec124 100644 --- a/Libs/Editor/Include/Utils/FunctionGraph.h +++ b/Libs/Editor/Include/Utils/FunctionGraph.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h index ade77082..8e92fcb9 100644 --- a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h +++ b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Utils/ModuleUtils.h b/Libs/Editor/Include/Utils/ModuleUtils.h index fc9595c6..0a4a11ed 100644 --- a/Libs/Editor/Include/Utils/ModuleUtils.h +++ b/Libs/Editor/Include/Utils/ModuleUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/Nodes.h b/Libs/Editor/Include/Utils/Nodes.h index 2eff88c6..163f8502 100644 --- a/Libs/Editor/Include/Utils/Nodes.h +++ b/Libs/Editor/Include/Utils/Nodes.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/Editor/Include/Utils/NodesInternal.h b/Libs/Editor/Include/Utils/NodesInternal.h index deaf3adf..6bcd50c9 100644 --- a/Libs/Editor/Include/Utils/NodesInternal.h +++ b/Libs/Editor/Include/Utils/NodesInternal.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "UI/UIImgui.h" diff --git a/Libs/Editor/Include/Utils/NodesMiniMap.h b/Libs/Editor/Include/Utils/NodesMiniMap.h index fb91903c..9ebbbd4d 100644 --- a/Libs/Editor/Include/Utils/NodesMiniMap.h +++ b/Libs/Editor/Include/Utils/NodesMiniMap.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/ProjectManager.h b/Libs/Editor/Include/Utils/ProjectManager.h index 0f8efe4f..47fb0d9b 100644 --- a/Libs/Editor/Include/Utils/ProjectManager.h +++ b/Libs/Editor/Include/Utils/ProjectManager.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/ElementsPanel.h" diff --git a/Libs/Editor/Include/Utils/TypeUtils.h b/Libs/Editor/Include/Utils/TypeUtils.h index c00b7e7c..3aa0258f 100644 --- a/Libs/Editor/Include/Utils/TypeUtils.h +++ b/Libs/Editor/Include/Utils/TypeUtils.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Include/Utils/Widgets.h b/Libs/Editor/Include/Utils/Widgets.h index 5eaaaf24..05677d96 100644 --- a/Libs/Editor/Include/Utils/Widgets.h +++ b/Libs/Editor/Include/Utils/Widgets.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Editor/Src/DockSpaceLayout.cpp b/Libs/Editor/Src/DockSpaceLayout.cpp index 39dd08d2..bae013c9 100644 --- a/Libs/Editor/Src/DockSpaceLayout.cpp +++ b/Libs/Editor/Src/DockSpaceLayout.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "DockSpaceLayout.h" diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 8852b8aa..b0f72622 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Editor.h" diff --git a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp index 0e12bdc0..8e5faa37 100644 --- a/Libs/Editor/Src/Panels/FileExplorerPanel.cpp +++ b/Libs/Editor/Src/Panels/FileExplorerPanel.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Panels/FileExplorerPanel.h" diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index f4bbe10f..bb4af8e2 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Systems/EditorSystem.h" diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 00f89824..5f2256d9 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Tools/ASTDebugger.h" diff --git a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp index ecf40923..75ce3d9d 100644 --- a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp +++ b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Tools/BigBestFitArenaDebugger.h" diff --git a/Libs/Editor/Src/Tools/GraphPlayground.cpp b/Libs/Editor/Src/Tools/GraphPlayground.cpp index cb7ed52f..f1e57eed 100644 --- a/Libs/Editor/Src/Tools/GraphPlayground.cpp +++ b/Libs/Editor/Src/Tools/GraphPlayground.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Tools/GraphPlayground.h" diff --git a/Libs/Editor/Src/Tools/MemoryDebugger.cpp b/Libs/Editor/Src/Tools/MemoryDebugger.cpp index 30ca7198..4ea66ff6 100644 --- a/Libs/Editor/Src/Tools/MemoryDebugger.cpp +++ b/Libs/Editor/Src/Tools/MemoryDebugger.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Tools/MemoryDebugger.h" diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index 68dff217..95ec3d33 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Tools/ReflectionDebugger.h" diff --git a/Libs/Editor/Src/Utils/DetailsPanel.cpp b/Libs/Editor/Src/Utils/DetailsPanel.cpp index 30be06f1..006c1543 100644 --- a/Libs/Editor/Src/Utils/DetailsPanel.cpp +++ b/Libs/Editor/Src/Utils/DetailsPanel.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "AST/Id.h" #include "AST/Utils/Namespaces.h" diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index 728cd552..8a60c757 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/EditorStyle.h" diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index ca235074..98d90777 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/ElementsPanel.h" diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 15bf3911..f81aaa86 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/FunctionGraph.h" diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index 4d056273..de32bc90 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/FunctionGraphContextMenu.h" diff --git a/Libs/Editor/Src/Utils/ModuleUtils.cpp b/Libs/Editor/Src/Utils/ModuleUtils.cpp index 5dd3b740..7450c24d 100644 --- a/Libs/Editor/Src/Utils/ModuleUtils.cpp +++ b/Libs/Editor/Src/Utils/ModuleUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/ModuleUtils.h" diff --git a/Libs/Editor/Src/Utils/Nodes.cpp b/Libs/Editor/Src/Utils/Nodes.cpp index 8e48d1ee..6edad7e1 100644 --- a/Libs/Editor/Src/Utils/Nodes.cpp +++ b/Libs/Editor/Src/Utils/Nodes.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved // the structure of this file: // diff --git a/Libs/Editor/Src/Utils/NodesMiniMap.cpp b/Libs/Editor/Src/Utils/NodesMiniMap.cpp index e1874d49..cfc4f186 100644 --- a/Libs/Editor/Src/Utils/NodesMiniMap.cpp +++ b/Libs/Editor/Src/Utils/NodesMiniMap.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/NodesMiniMap.h" diff --git a/Libs/Editor/Src/Utils/ProjectManager.cpp b/Libs/Editor/Src/Utils/ProjectManager.cpp index c495261c..5636ef25 100644 --- a/Libs/Editor/Src/Utils/ProjectManager.cpp +++ b/Libs/Editor/Src/Utils/ProjectManager.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Editor.h" #include "Statics/EditorSettings.h" diff --git a/Libs/Editor/Src/Utils/TypeUtils.cpp b/Libs/Editor/Src/Utils/TypeUtils.cpp index e9a7870c..6ca063be 100644 --- a/Libs/Editor/Src/Utils/TypeUtils.cpp +++ b/Libs/Editor/Src/Utils/TypeUtils.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/TypeUtils.h" diff --git a/Libs/Editor/Src/Utils/Widgets.cpp b/Libs/Editor/Src/Utils/Widgets.cpp index ca0b6a21..98ff1c0d 100644 --- a/Libs/Editor/Src/Utils/Widgets.cpp +++ b/Libs/Editor/Src/Utils/Widgets.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "Utils/Widgets.h" diff --git a/Libs/Runtimes/Std/Include/IO.h b/Libs/Runtimes/Std/Include/IO.h index 4f388ce8..f30d902c 100644 --- a/Libs/Runtimes/Std/Include/IO.h +++ b/Libs/Runtimes/Std/Include/IO.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once extern "C" diff --git a/Libs/Runtimes/Std/Include/Math.h b/Libs/Runtimes/Std/Include/Math.h index c7803966..f30dbd42 100644 --- a/Libs/Runtimes/Std/Include/Math.h +++ b/Libs/Runtimes/Std/Include/Math.h @@ -1,2 +1,2 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Runtimes/Std/Src/IO.cpp b/Libs/Runtimes/Std/Src/IO.cpp index be6e0410..bc43e1f0 100644 --- a/Libs/Runtimes/Std/Src/IO.cpp +++ b/Libs/Runtimes/Std/Src/IO.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "IO.h" diff --git a/Libs/Runtimes/Std/Src/Math.cpp b/Libs/Runtimes/Std/Src/Math.cpp index 4cec711e..c78a1582 100644 --- a/Libs/Runtimes/Std/Src/Math.cpp +++ b/Libs/Runtimes/Std/Src/Math.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved // Dummy const char* gA = ""; diff --git a/Libs/UI/Include/UI/Inspection.h b/Libs/UI/Include/UI/Inspection.h index 5aa40942..74c792b2 100644 --- a/Libs/UI/Include/UI/Inspection.h +++ b/Libs/UI/Include/UI/Inspection.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/UI/Include/UI/Notify.h b/Libs/UI/Include/UI/Notify.h index 3a048b10..46016c4d 100644 --- a/Libs/UI/Include/UI/Notify.h +++ b/Libs/UI/Include/UI/Notify.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/UI/Include/UI/Paths.h b/Libs/UI/Include/UI/Paths.h index df4e11b5..d4ebce02 100644 --- a/Libs/UI/Include/UI/Paths.h +++ b/Libs/UI/Include/UI/Paths.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/UI/Include/UI/Style.h b/Libs/UI/Include/UI/Style.h index 9733149d..a9bd216d 100644 --- a/Libs/UI/Include/UI/Style.h +++ b/Libs/UI/Include/UI/Style.h @@ -1,21 +1,22 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include +#include #include namespace rift::UI { - constexpr p::LinearColor primaryColor = p::LinearColor::FromHEX(0xD6863B); + constexpr p::LinearColor primaryColor = p::LinearColor::FromHex(0xD6863B); constexpr p::LinearColor whiteTextColor = p::LinearColor::White().Shade(0.05f); constexpr p::LinearColor blackTextColor = p::LinearColor::Black().Tint(0.05f); - constexpr p::LinearColor infoColor = p::LinearColor::FromHEX(0x2B8ED6); - constexpr p::LinearColor successColor = p::LinearColor::FromHEX(0x4DD62B); - constexpr p::LinearColor warningColor = p::LinearColor::FromHEX(0xD6AB2B); - constexpr p::LinearColor errorColor = p::LinearColor::FromHEX(0xD62B2B); + constexpr p::LinearColor infoColor = p::LinearColor::FromHex(0x2B8ED6); + constexpr p::LinearColor successColor = p::LinearColor::FromHex(0x4DD62B); + constexpr p::LinearColor warningColor = p::LinearColor::FromHex(0xD6AB2B); + constexpr p::LinearColor errorColor = p::LinearColor::FromHex(0xD62B2B); constexpr p::LinearColor GetNeutralColor(p::u8 level) @@ -23,17 +24,17 @@ namespace rift::UI switch (level) { default: - case 0: return p::LinearColor::FromHEX(0x222222); - case 1: return p::LinearColor::FromHEX(0x3B3B3B); - case 2: return p::LinearColor::FromHEX(0x464646); - case 3: return p::LinearColor::FromHEX(0x515151); - case 4: return p::LinearColor::FromHEX(0x626262); - case 5: return p::LinearColor::FromHEX(0x6E6E6E); - case 6: return p::LinearColor::FromHEX(0x9E9E9E); - case 7: return p::LinearColor::FromHEX(0xB1B1B1); - case 8: return p::LinearColor::FromHEX(0xCFCFCF); - case 9: return p::LinearColor::FromHEX(0xE1E1E1); - case 10: return p::LinearColor::FromHEX(0xF7F7F7); + case 0: return p::LinearColor::FromHex(0x222222); + case 1: return p::LinearColor::FromHex(0x3B3B3B); + case 2: return p::LinearColor::FromHex(0x464646); + case 3: return p::LinearColor::FromHex(0x515151); + case 4: return p::LinearColor::FromHex(0x626262); + case 5: return p::LinearColor::FromHex(0x6E6E6E); + case 6: return p::LinearColor::FromHex(0x9E9E9E); + case 7: return p::LinearColor::FromHex(0xB1B1B1); + case 8: return p::LinearColor::FromHex(0xCFCFCF); + case 9: return p::LinearColor::FromHex(0xE1E1E1); + case 10: return p::LinearColor::FromHex(0xF7F7F7); } } inline p::LinearColor GetNeutralTextColor(p::u8 level) diff --git a/Libs/UI/Include/UI/UI.h b/Libs/UI/Include/UI/UI.h index 7b6b0432..89fcc390 100644 --- a/Libs/UI/Include/UI/UI.h +++ b/Libs/UI/Include/UI/UI.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include "UI/Style.h" diff --git a/Libs/UI/Include/UI/UIImgui.h b/Libs/UI/Include/UI/UIImgui.h index 33b3d6e3..6ca6a977 100644 --- a/Libs/UI/Include/UI/UIImgui.h +++ b/Libs/UI/Include/UI/UIImgui.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once #include diff --git a/Libs/UI/Include/UI/Widgets.h b/Libs/UI/Include/UI/Widgets.h index c79a5152..a1067b47 100644 --- a/Libs/UI/Include/UI/Widgets.h +++ b/Libs/UI/Include/UI/Widgets.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/UI/Include/UI/Window.h b/Libs/UI/Include/UI/Window.h index 424dfbe1..5d4cf09f 100644 --- a/Libs/UI/Include/UI/Window.h +++ b/Libs/UI/Include/UI/Window.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index e91be384..d5baec6c 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Inspection.h" diff --git a/Libs/UI/Src/Notify.cpp b/Libs/UI/Src/Notify.cpp index 369b6744..7a5b32d6 100644 --- a/Libs/UI/Src/Notify.cpp +++ b/Libs/UI/Src/Notify.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Notify.h" diff --git a/Libs/UI/Src/Paths.cpp b/Libs/UI/Src/Paths.cpp index f49b8bf5..483c2c34 100644 --- a/Libs/UI/Src/Paths.cpp +++ b/Libs/UI/Src/Paths.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Paths.h" diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index 5d3187e6..a9edb24c 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Style.h" @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/Libs/UI/Src/Widgets.cpp b/Libs/UI/Src/Widgets.cpp index dc45a30e..248f7563 100644 --- a/Libs/UI/Src/Widgets.cpp +++ b/Libs/UI/Src/Widgets.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Widgets.h" diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index 955f981f..5df77cbb 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "UI/Window.h" diff --git a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h index c47dfa48..583361bb 100644 --- a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h +++ b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Views/Graph/Compiler/Src/GraphViewModule.cpp b/Libs/Views/Graph/Compiler/Src/GraphViewModule.cpp index d65e5ea2..cf03f24e 100644 --- a/Libs/Views/Graph/Compiler/Src/GraphViewModule.cpp +++ b/Libs/Views/Graph/Compiler/Src/GraphViewModule.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "GraphViewModule.h" diff --git a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h index f419b09e..050193de 100644 --- a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h +++ b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #pragma once diff --git a/Libs/Views/Graph/Editor/Src/GraphViewEditorModule.cpp b/Libs/Views/Graph/Editor/Src/GraphViewEditorModule.cpp index 304c6af9..81fdf709 100644 --- a/Libs/Views/Graph/Editor/Src/GraphViewEditorModule.cpp +++ b/Libs/Views/Graph/Editor/Src/GraphViewEditorModule.cpp @@ -1,3 +1,3 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include "GraphViewEditorModule.h" diff --git a/Tests/AST/Expressions.spec.cpp b/Tests/AST/Expressions.spec.cpp index 134a0798..4fd1132a 100644 --- a/Tests/AST/Expressions.spec.cpp +++ b/Tests/AST/Expressions.spec.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include #include diff --git a/Tests/AST/Namespaces.spec.cpp b/Tests/AST/Namespaces.spec.cpp index ff9257a3..0cae17d4 100644 --- a/Tests/AST/Namespaces.spec.cpp +++ b/Tests/AST/Namespaces.spec.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include #include diff --git a/Tests/AST/Statements.spec.cpp b/Tests/AST/Statements.spec.cpp index 737dc69c..967ecafb 100644 --- a/Tests/AST/Statements.spec.cpp +++ b/Tests/AST/Statements.spec.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include #include diff --git a/Tests/Project.spec.cpp b/Tests/Project.spec.cpp index 7a0b557f..e9e5b2a6 100644 --- a/Tests/Project.spec.cpp +++ b/Tests/Project.spec.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include #include diff --git a/Tests/main.cpp b/Tests/main.cpp index 7d4b5aaa..9ee8ab4d 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2023 Piperift - All rights reserved +// Copyright 2015-2024 Piperift - All rights reserved #include // Override as first include diff --git a/imgui.ini b/imgui.ini index 446db75d..c3e27ceb 100644 --- a/imgui.ini +++ b/imgui.ini @@ -4,8 +4,8 @@ Size=400,400 Collapsed=0 [Window][Project Manager] -Pos=340,355 -Size=600,189 +Pos=340,364 +Size=600,171 Collapsed=0 [Window][##Notification_0] From 34f0fd9863f46c002c4c55b26dfc92a217bc9958 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 4 May 2024 19:31:29 +0200 Subject: [PATCH 36/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Components/CNamespace.h | 2 +- Libs/AST/Include/AST/TypeRef.h | 2 +- Libs/AST/Include/Compiler/Backend.h | 2 +- Libs/AST/Include/Module.h | 2 +- Libs/AST/Src/AST/Systems/LoadSystem.cpp | 4 ++-- Libs/AST/Src/AST/Utils/Expressions.cpp | 4 ++-- Libs/AST/Src/AST/Utils/Namespaces.cpp | 2 +- Libs/AST/Src/AST/Utils/Statements.cpp | 4 ++-- Libs/AST/Src/AST/Utils/TransactionUtils.cpp | 4 ++-- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 4 ++-- Libs/AST/Src/Rift.cpp | 2 +- .../Backends/MIR/Compiler/Src/IRGeneration.cpp | 6 +++--- Libs/Editor/Include/Utils/NodesInternal.h | 4 ++-- Libs/Editor/Src/DockSpaceLayout.cpp | 4 ++-- Libs/Editor/Src/Systems/EditorSystem.cpp | 2 +- Libs/Editor/Src/Utils/FunctionGraph.cpp | 10 +++++----- .../Src/Utils/FunctionGraphContextMenu.cpp | 4 ++-- Libs/Editor/Src/Utils/ModuleUtils.cpp | 4 ++-- Libs/Editor/Src/Utils/Nodes.cpp | 18 +++++++++--------- Libs/Editor/Src/Utils/TypeUtils.cpp | 4 ++-- Libs/UI/Src/Inspection.cpp | 6 +++--- 22 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 83a6946e..3b877348 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 83a6946e13f9dae2521f782214e44cb9e2b484cd +Subproject commit 3b877348ee1e0103611cb874eb542c323068f1f1 diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index e77e4b38..9348a907 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -95,7 +95,7 @@ namespace rift::ast } p::Tag operator[](p::i32 index) const { - Check(index >= 0 && index < scopeCount); + P_Check(index >= 0 && index < scopeCount); return scopes[index]; } operator bool() const diff --git a/Libs/AST/Include/AST/TypeRef.h b/Libs/AST/Include/AST/TypeRef.h index f41758ba..d44336bf 100644 --- a/Libs/AST/Include/AST/TypeRef.h +++ b/Libs/AST/Include/AST/TypeRef.h @@ -20,7 +20,7 @@ namespace rift::ast { if (!IsNone(typeId)) { - Ensure(ast.Has(typeId)); + P_Ensure(ast.Has(typeId)); } } diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index bca26a93..09fa15bd 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -21,7 +21,7 @@ namespace rift virtual void Build(Compiler& compiler) { - CheckMsg(false, "Backend '{}' tried to run but Build() is not implemented.", + P_CheckMsg(false, "Backend '{}' tried to run but Build() is not implemented.", GetName().AsString()); } }; diff --git a/Libs/AST/Include/Module.h b/Libs/AST/Include/Module.h index 495af2cd..313ef030 100644 --- a/Libs/AST/Include/Module.h +++ b/Libs/AST/Include/Module.h @@ -43,7 +43,7 @@ namespace rift template void AddDependency() { - EnsureMsg(state == State::Uninitialized, + P_EnsureMsg(state == State::Uninitialized, "Should not add dependencies outside of the constructor"); EnableModule(); diff --git a/Libs/AST/Src/AST/Systems/LoadSystem.cpp b/Libs/AST/Src/AST/Systems/LoadSystem.cpp index c9e7e596..c04cca1b 100644 --- a/Libs/AST/Src/AST/Systems/LoadSystem.cpp +++ b/Libs/AST/Src/AST/Systems/LoadSystem.cpp @@ -202,7 +202,7 @@ namespace rift::ast::LoadSystem void DeserializeModules(Tree& ast, p::TView moduleIds, p::TView strings) { - Check(moduleIds.Size() == strings.Size()); + P_Check(moduleIds.Size() == strings.Size()); for (p::i32 i = 0; i < moduleIds.Size(); ++i) { @@ -212,7 +212,7 @@ namespace rift::ast::LoadSystem void DeserializeTypes(Tree& ast, p::TView typeIds, p::TView strings) { - Check(typeIds.Size() == strings.Size()); + P_Check(typeIds.Size() == strings.Size()); for (p::i32 i = 0; i < typeIds.Size(); ++i) { diff --git a/Libs/AST/Src/AST/Utils/Expressions.cpp b/Libs/AST/Src/AST/Utils/Expressions.cpp index 9e91b91d..b6142336 100644 --- a/Libs/AST/Src/AST/Utils/Expressions.cpp +++ b/Libs/AST/Src/AST/Utils/Expressions.cpp @@ -105,7 +105,7 @@ namespace rift::ast const p::i32 index = inputs.pinIds.FindIndex([&input](Id pinId) { return input.pinId == pinId; }); - if (index != p::NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) + if (index != p::NO_INDEX && P_Ensure(index < inputs.linkedOutputs.Size())) { inputs.linkedOutputs[index] = output; return true; @@ -124,7 +124,7 @@ namespace rift::ast // Find pin index const p::i32 index = inputs.pinIds.FindIndex(input.pinId); - if (index != p::NO_INDEX && Ensure(index < inputs.linkedOutputs.Size())) [[likely]] + if (index != p::NO_INDEX && P_Ensure(index < inputs.linkedOutputs.Size())) [[likely]] { ExprOutput& linked = inputs.linkedOutputs[index]; linked = {}; diff --git a/Libs/AST/Src/AST/Utils/Namespaces.cpp b/Libs/AST/Src/AST/Utils/Namespaces.cpp index ccf26394..9284ac90 100644 --- a/Libs/AST/Src/AST/Utils/Namespaces.cpp +++ b/Libs/AST/Src/AST/Utils/Namespaces.cpp @@ -34,7 +34,7 @@ namespace rift::ast ns.scopes[scopeIndex] = GetName(access, idChain[i]); ++scopeIndex; } - CheckMsg(i < 0, "Not enough scopes to cover this namespace"); + P_CheckMsg(i < 0, "Not enough scopes to cover this namespace"); return ns; } diff --git a/Libs/AST/Src/AST/Utils/Statements.cpp b/Libs/AST/Src/AST/Utils/Statements.cpp index 6cfec7a5..5bb0a1e4 100644 --- a/Libs/AST/Src/AST/Utils/Statements.cpp +++ b/Libs/AST/Src/AST/Utils/Statements.cpp @@ -26,7 +26,7 @@ namespace rift::ast bool TryConnectStmt(Tree& ast, Id outputPin, Id inputNode) { - if (!Ensure(!IsNone(outputPin) && !IsNone(inputNode))) + if (!P_Ensure(!IsNone(outputPin) && !IsNone(inputNode))) { return false; } @@ -113,7 +113,7 @@ namespace rift::ast // Input node is always the same id as linkId auto* inputComp = ast.TryGet(linkId); if (inputComp - && EnsureMsg(!IsNone(inputComp->linkOutputNode), + && P_EnsureMsg(!IsNone(inputComp->linkOutputNode), "Trying to disconnect a unexistant link")) [[likely]] { // We expect the other side to have outputs component diff --git a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp index d37c099d..4d484167 100644 --- a/Libs/AST/Src/AST/Utils/TransactionUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TransactionUtils.cpp @@ -32,7 +32,7 @@ namespace rift::ast::Transactions bool PreChange(const TransactionAccess& access, p::TView entityIds) { - if (!EnsureMsg(!gActiveTransaction.active, + if (!P_EnsureMsg(!gActiveTransaction.active, "Tried to record a transaction while another is already being recorded")) { return false; @@ -60,7 +60,7 @@ namespace rift::ast::Transactions void PostChange() { - if (EnsureMsg(gActiveTransaction.active, + if (P_EnsureMsg(gActiveTransaction.active, "Cant finish a transaction while none is being recorded")) { gActiveTransaction = {}; diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 807c7114..4a562dc3 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -83,7 +83,7 @@ namespace rift::ast void SerializeType(Tree& ast, Id id, String& data) { - if (!Ensure(ast.Has(id))) + if (!P_Ensure(ast.Has(id))) { return; } @@ -376,7 +376,7 @@ namespace rift::ast ast.Add(id).Add(id); // Types gets resolved by a system later const Id typeId = p::GetIdParent(ast, declId); - Check(!IsNone(typeId)); + P_Check(!IsNone(typeId)); auto& declRefExpr = ast.Add(id); declRefExpr.ownerName = ast.Get(typeId).name; declRefExpr.name = ast.Get(declId).name; diff --git a/Libs/AST/Src/Rift.cpp b/Libs/AST/Src/Rift.cpp index 9f598853..633d5322 100644 --- a/Libs/AST/Src/Rift.cpp +++ b/Libs/AST/Src/Rift.cpp @@ -13,7 +13,7 @@ namespace rift void EnableModule(p::ClassType* type) { - Check(Module::GetStaticType()->IsParentOf(type)); + P_Check(Module::GetStaticType()->IsParentOf(type)); if (!gModules.Contains(type)) { diff --git a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp index 98726c46..8ac0936c 100644 --- a/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp +++ b/Libs/Backends/MIR/Compiler/Src/IRGeneration.cpp @@ -301,9 +301,9 @@ namespace rift::MIR { const auto& outputs = access.Get(id); const auto& connectedIds = outputs.linkInputNodes; - Check(connectedIds.Size() == 2); + P_Check(connectedIds.Size() == 2); const auto& exprInputs = access.Get(id); - Check(exprInputs.linkedOutputs.Size() == 1); + P_Check(exprInputs.linkedOutputs.Size() == 1); code->append("if ("); AddExpr(exprInputs.linkedOutputs.First()); @@ -322,7 +322,7 @@ namespace rift::MIR compiler.Error("Call to an unknown function"); return; } - if (!Ensure(access.Has(functionId))) + if (!P_Ensure(access.Has(functionId))) { compiler.Error(p::Strings::Format( "Call to an invalid function: '{}'", ast::GetFullName(access, functionId))); diff --git a/Libs/Editor/Include/Utils/NodesInternal.h b/Libs/Editor/Include/Utils/NodesInternal.h index 6bcd50c9..117591c3 100644 --- a/Libs/Editor/Include/Utils/NodesInternal.h +++ b/Libs/Editor/Include/Utils/NodesInternal.h @@ -190,7 +190,7 @@ namespace rift::Nodes private: T* GetByIndex(u32 index) { - Check(data.IsValidIndex(index)); + P_Check(data.IsValidIndex(index)); return data.Data() + index; } }; @@ -561,7 +561,7 @@ namespace rift::Nodes if (objects.availableIds.IsEmpty()) { index = objects.pool.Size(); - Check(objects.pool.Size() == objects.inUse.Size()); + P_Check(objects.pool.Size() == objects.inUse.Size()); const i32 newSize = objects.pool.Size() + 1; objects.pool.Resize(newSize); objects.inUse.Resize(newSize); diff --git a/Libs/Editor/Src/DockSpaceLayout.cpp b/Libs/Editor/Src/DockSpaceLayout.cpp index bae013c9..cbbfcb71 100644 --- a/Libs/Editor/Src/DockSpaceLayout.cpp +++ b/Libs/Editor/Src/DockSpaceLayout.cpp @@ -34,14 +34,14 @@ namespace rift::editor ImGuiDockNodeFlags& DockSpaceLayout::Builder::GetNodeLocalFlags(Tag nodeId) { const ImGuiID dockNodeId = layout.GetDockNodeId(nodeId); - Check(dockNodeId > 0); + P_Check(dockNodeId > 0); return ImGui::DockBuilderGetNode(dockNodeId)->LocalFlags; } ImGuiDockNodeFlags& DockSpaceLayout::Builder::GetNodeSharedFlags(Tag nodeId) { const ImGuiID dockNodeId = layout.GetDockNodeId(nodeId); - Check(dockNodeId > 0); + P_Check(dockNodeId > 0); return ImGui::DockBuilderGetNode(dockNodeId)->SharedFlags; } diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index bb4af8e2..f2ed2502 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -218,7 +218,7 @@ namespace rift::editor::EditorSystem void DrawProject(ast::Tree& ast) { - if (!Ensure(ast.HasStatic())) + if (!P_Ensure(ast.HasStatic())) { return; } diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index f81aaa86..8e59c494 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -594,7 +594,7 @@ namespace rift::editor::Graph PopExecutionPinStyle(); auto& inputs = access.Get(id); - if (!Ensure(inputs.pinIds.Size() == 1)) + if (!P_Ensure(inputs.pinIds.Size() == 1)) { continue; } @@ -613,7 +613,7 @@ namespace rift::editor::Graph UI::BeginGroup(); { auto& outputs = access.Get(id); - if (!Ensure(outputs.pinIds.Size() == 2)) + if (!P_Ensure(outputs.pinIds.Size() == 2)) { continue; } @@ -685,7 +685,7 @@ namespace rift::editor::Graph { pinIds.Clear(false); p::GetIdChildren(access, id, pinIds); - if (!Ensure(pinIds.Size() >= 2)) + if (!P_Ensure(pinIds.Size() >= 2)) { continue; } @@ -738,7 +738,7 @@ namespace rift::editor::Graph { if (const auto* outputs = access.TryGet(outputId)) { - if (EnsureMsg(outputs->linkInputNodes.Size() == outputs->pinIds.Size(), + if (P_EnsureMsg(outputs->linkInputNodes.Size() == outputs->pinIds.Size(), "Inputs and pins must match. Graph might be corrupted.")) { for (i32 i = 0; i < outputs->linkInputNodes.Size(); ++i) @@ -770,7 +770,7 @@ namespace rift::editor::Graph for (ast::Id nodeId : FindIdsWith(access, children)) { const auto& inputs = access.Get(nodeId); - if (!EnsureMsg(inputs.pinIds.Size() == inputs.linkedOutputs.Size(), + if (!P_EnsureMsg(inputs.pinIds.Size() == inputs.linkedOutputs.Size(), "Inputs are invalid. The graph might be corrupted.")) [[likely]] { continue; diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp index de32bc90..642a8873 100644 --- a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -81,7 +81,7 @@ namespace rift::editor::Graph void DrawNodesContextMenu(ast::Tree& ast, ast::Id typeId, TView nodeIds) { - Check(!nodeIds.IsEmpty()); + P_Check(!nodeIds.IsEmpty()); const bool canEditBody = ast::HasFunctionBodies(ast, typeId); if (canEditBody && UI::MenuItem("Delete")) @@ -113,7 +113,7 @@ namespace rift::editor::Graph void DrawLinksContextMenu(ast::Tree& ast, ast::Id typeId, TView linkIds) { - Check(!linkIds.IsEmpty()); + P_Check(!linkIds.IsEmpty()); const bool canEditBody = ast::HasFunctionBodies(ast, typeId); ast::Id firstLinkId = linkIds[0]; diff --git a/Libs/Editor/Src/Utils/ModuleUtils.cpp b/Libs/Editor/Src/Utils/ModuleUtils.cpp index 7450c24d..5c977791 100644 --- a/Libs/Editor/Src/Utils/ModuleUtils.cpp +++ b/Libs/Editor/Src/Utils/ModuleUtils.cpp @@ -9,7 +9,7 @@ namespace rift::editor { void OpenModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id) { - Check(access.Has(id)); + P_Check(access.Has(id)); if (auto* editor = access.TryGet(id)) { editor->pendingFocus = true; @@ -22,7 +22,7 @@ namespace rift::editor void CloseModuleEditor(p::TAccessRef, ast::CModule> access, ast::Id id) { - Check(access.Has(id)); + P_Check(access.Has(id)); access.Remove(id); } diff --git a/Libs/Editor/Src/Utils/Nodes.cpp b/Libs/Editor/Src/Utils/Nodes.cpp index 6edad7e1..ede70dca 100644 --- a/Libs/Editor/Src/Utils/Nodes.cpp +++ b/Libs/Editor/Src/Utils/Nodes.cpp @@ -29,7 +29,7 @@ namespace rift::Nodes EditorContext& GetEditorContext() { // No editor context was set! Did you forget to call Nodes::CreateContext()? - Check(gNodes->EditorCtx != nullptr); + P_Check(gNodes->EditorCtx != nullptr); return *gNodes->EditorCtx; } @@ -58,7 +58,7 @@ namespace rift::Nodes // Calculates the closest point along each bezier curve segment. v2 GetClosestPointOnCubicBezier(const i32 numSegments, const v2& p, const CubicBezier& cb) { - Ensure(numSegments > 0); + P_Ensure(numSegments > 0); v2 pLast = cb.p0; v2 pClosest; float pClosestDist = FLT_MAX; @@ -2545,7 +2545,7 @@ namespace rift::Nodes bool IsPinActive() { - Check(HasFlag(gNodes->currentScope, Scope::Node)); + P_Check(HasFlag(gNodes->currentScope, Scope::Node)); if (!gNodes->activePin) { @@ -2557,7 +2557,7 @@ namespace rift::Nodes bool IsAnyPinActive(Id* const pinId) { - Check(!HasAnyFlags(gNodes->currentScope, (Scope::Node | Scope::Pin))); + P_Check(!HasAnyFlags(gNodes->currentScope, (Scope::Node | Scope::Pin))); if (!gNodes->activePin) { @@ -2599,8 +2599,8 @@ namespace rift::Nodes bool IsLinkDropped(Id* outputId, Id* inputId, bool includingDetachedLinks) { // Call this function after EndNodeEditor()! - Check(gNodes->currentScope != Scope::None); - Check(outputId != nullptr); + P_Check(gNodes->currentScope != Scope::None); + P_Check(outputId != nullptr); const EditorContext& editor = GetEditorContext(); @@ -2628,7 +2628,7 @@ namespace rift::Nodes bool IsLinkCreated(Id& outputPinId, Id& inputPinId, bool* createdFromSnap) { - Check(gNodes->currentScope == Scope::None); + P_Check(gNodes->currentScope == Scope::None); if ((gNodes->UIState & UIState_LinkCreated) != 0) { @@ -2654,7 +2654,7 @@ namespace rift::Nodes bool IsLinkCreated(ast::Id& outputNodeId, Id& outputPinId, ast::Id& inputNodeId, Id& inputPinId, bool* createdFromSnap) { - Check(gNodes->currentScope == Scope::None); + P_Check(gNodes->currentScope == Scope::None); if ((gNodes->UIState & UIState_LinkCreated) != 0) { @@ -2681,7 +2681,7 @@ namespace rift::Nodes bool IsLinkDestroyed(Id& linkId) { - Check(gNodes->currentScope == Scope::None); + P_Check(gNodes->currentScope == Scope::None); const bool linkDestroyed = gNodes->DeletedLinkIdx.IsValid(); if (linkDestroyed) diff --git a/Libs/Editor/Src/Utils/TypeUtils.cpp b/Libs/Editor/Src/Utils/TypeUtils.cpp index 6ca063be..f39bcb22 100644 --- a/Libs/Editor/Src/Utils/TypeUtils.cpp +++ b/Libs/Editor/Src/Utils/TypeUtils.cpp @@ -10,7 +10,7 @@ namespace rift::editor { void OpenType(p::TAccessRef, ast::CDeclType> access, ast::Id id) { - Check(access.Has(id)); + P_Check(access.Has(id)); if (auto* editor = access.TryGet(id)) { editor->pendingFocus = true; @@ -23,7 +23,7 @@ namespace rift::editor void CloseType(p::TAccessRef, ast::CDeclType> access, ast::Id id) { - Check(access.Has(id)); + P_Check(access.Has(id)); access.Remove(id); } diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index d5baec6c..55062ddd 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -228,7 +228,7 @@ namespace rift::UI void InspectChildrenProperties(const ValueHandle& handle) { - if (!EnsureMsg(gCurrentInspector, + if (!P_EnsureMsg(gCurrentInspector, "Make sure to call Begin/EndInspector around reflection widgets.")) { return; @@ -282,7 +282,7 @@ namespace rift::UI bool BeginInspector(const char* label, v2 size) { - if (!EnsureMsg(!gCurrentInspector, + if (!P_EnsureMsg(!gCurrentInspector, "Called BeginInspector() twice without calling EndInspector() first.")) { return false; @@ -302,7 +302,7 @@ namespace rift::UI void EndInspector() { - if (!EnsureMsg(gCurrentInspector, "Called EndInspector() but no inspector was drawing.")) + if (!P_EnsureMsg(gCurrentInspector, "Called EndInspector() but no inspector was drawing.")) { return; } From 15efa02209affc950681d7703ce3973f091e3de9 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 5 May 2024 22:57:48 +0200 Subject: [PATCH 37/52] Fix IO warning --- Libs/Runtimes/Std/Src/IO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/Runtimes/Std/Src/IO.cpp b/Libs/Runtimes/Std/Src/IO.cpp index bc43e1f0..474504f8 100644 --- a/Libs/Runtimes/Std/Src/IO.cpp +++ b/Libs/Runtimes/Std/Src/IO.cpp @@ -9,7 +9,7 @@ extern "C" { void Print(const char* text) { - printf(text); + printf("%s", text); } void PrintHelloWorld() From bcba5734d646e2d6815265e3032f7045cf145588 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 15 May 2024 17:59:47 +0200 Subject: [PATCH 38/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Components/CFileRef.h | 6 +- Libs/AST/Include/AST/Components/CModule.h | 9 +- Libs/AST/Include/AST/Components/CNamespace.h | 10 +- Libs/AST/Include/AST/Components/CProject.h | 7 +- .../AST/Include/AST/Components/Declarations.h | 34 +-- Libs/AST/Include/AST/Components/Expressions.h | 56 +++-- Libs/AST/Include/AST/Components/Literals.h | 22 +- Libs/AST/Include/AST/Components/Statements.h | 27 ++- .../Include/AST/Components/Tags/CChanged.h | 7 +- Libs/AST/Include/AST/Components/Tags/CDirty.h | 6 +- .../Include/AST/Components/Tags/CInvalid.h | 6 +- .../AST/Components/Tags/CPendingLoad.h | 6 +- .../AST/Components/Views/CNodePosition.h | 7 +- Libs/AST/Include/AST/Id.h | 1 - Libs/AST/Include/AST/Statics/SLoadQueue.h | 6 +- Libs/AST/Include/AST/Statics/SModules.h | 6 +- Libs/AST/Include/AST/Statics/SStringLoad.h | 6 +- Libs/AST/Include/AST/Statics/STypes.h | 6 +- Libs/AST/Include/AST/Utils/ModuleUtils.h | 2 +- Libs/AST/Include/AST/Utils/Namespaces.h | 1 - Libs/AST/Include/AST/Utils/TypeUtils.h | 4 +- Libs/AST/Include/ASTModule.h | 4 +- Libs/AST/Include/Compiler/Backend.h | 7 +- Libs/AST/Include/Compiler/Compiler.h | 15 +- Libs/AST/Include/Compiler/CompilerConfig.h | 10 +- .../AST/Include/Compiler/Utils/BackendUtils.h | 4 +- Libs/AST/Include/Module.h | 7 +- Libs/AST/Include/Rift.h | 14 +- Libs/AST/Include/View.h | 6 +- Libs/AST/Src/AST/Tree.cpp | 5 +- Libs/AST/Src/AST/Utils/ModuleUtils.cpp | 6 +- Libs/AST/Src/AST/Utils/TypeUtils.cpp | 4 +- Libs/AST/Src/Compiler/Compiler.cpp | 10 +- Libs/AST/Src/Compiler/Utils/BackendUtils.cpp | 12 +- Libs/AST/Src/Rift.cpp | 10 +- .../MIR/Compiler/Include/MIRBackendModule.h | 7 +- Libs/Backends/MIR/Compiler/Src/Components.h | 2 +- .../Include/Components/CNativeBinding.h | 6 +- .../Include/Components/Declarations.h | 7 +- .../Compiler/Include/NativeBindingModule.h | 4 +- .../Compiler/Src/NativeBindingModule.cpp | 2 +- .../Include/NativeBindingEditorModule.h | 4 +- Libs/Editor/Include/Components/CDeclRename.h | 6 +- .../Editor/Include/Components/CModuleEditor.h | 6 +- Libs/Editor/Include/Components/CTypeEditor.h | 6 +- Libs/Editor/Include/Statics/EditorSettings.h | 6 +- Libs/Editor/Include/Statics/SEditor.h | 5 +- .../Editor/Include/Tools/ReflectionDebugger.h | 7 +- Libs/Editor/Include/Utils/EditorStyle.h | 8 +- Libs/Editor/Src/Editor.cpp | 5 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 2 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 31 ++- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 70 +++--- Libs/Editor/Src/Utils/EditorStyle.cpp | 4 +- Libs/UI/Include/UI/Inspection.h | 136 +++++++++-- Libs/UI/Include/UI/UIImgui.h | 14 +- Libs/UI/Src/Inspection.cpp | 223 +++++++++--------- Libs/UI/Src/Style.cpp | 3 +- .../Graph/Compiler/Include/GraphViewModule.h | 4 +- .../Editor/Include/GraphViewEditorModule.h | 4 +- imgui.ini | 4 +- 62 files changed, 538 insertions(+), 389 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 3b877348..6cd31e3a 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 3b877348ee1e0103611cb874eb542c323068f1f1 +Subproject commit 6cd31e3adc96e39bb11ff87f13d99e7b28254f4f diff --git a/Libs/AST/Include/AST/Components/CFileRef.h b/Libs/AST/Include/AST/Components/CFileRef.h index 2c8d6a8f..b67c9699 100644 --- a/Libs/AST/Include/AST/Components/CFileRef.h +++ b/Libs/AST/Include/AST/Components/CFileRef.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace rift::ast @@ -13,9 +13,9 @@ namespace rift::ast * Some examples are Class, p::Struct and Function Library declarations pointing to their * files */ - struct CFileRef : public p::Struct + struct CFileRef { - P_STRUCT(CFileRef, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CFileRef, p::TF_NotSerialized) P_PROP(path) p::String path; diff --git a/Libs/AST/Include/AST/Components/CModule.h b/Libs/AST/Include/AST/Components/CModule.h index e4be9333..26f409e7 100644 --- a/Libs/AST/Include/AST/Components/CModule.h +++ b/Libs/AST/Include/AST/Components/CModule.h @@ -2,7 +2,8 @@ #pragma once #include -#include +#include + namespace rift::ast { @@ -13,16 +14,16 @@ namespace rift::ast Static }; } // namespace rift::ast -ENUM(rift::ast::RiftModuleTarget) +P_ENUM(rift::ast::RiftModuleTarget) namespace rift::ast { static constexpr p::StringView moduleFilename = "__module__.rf"; - struct CModule : public p::Struct + struct CModule { - P_STRUCT(CModule, p::Struct) + P_STRUCT(CModule) P_PROP(target) RiftModuleTarget target = RiftModuleTarget::Executable; diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index 9348a907..1b2ddb53 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -2,14 +2,14 @@ #pragma once #include -#include +#include namespace rift::ast { - struct CNamespace : public p::Struct + struct CNamespace { - P_STRUCT(CNamespace, p::Struct) + P_STRUCT(CNamespace) P_PROP(name); p::Tag name; @@ -38,9 +38,9 @@ namespace rift::ast } - struct Namespace : public p::Struct + struct Namespace { - P_STRUCT(Namespace, p::Struct) + P_STRUCT(Namespace) static constexpr p::i32 scopeCount = 8; p::Tag scopes[scopeCount]; // TODO: Implement Inline arrays diff --git a/Libs/AST/Include/AST/Components/CProject.h b/Libs/AST/Include/AST/Components/CProject.h index c471a420..9792659e 100644 --- a/Libs/AST/Include/AST/Components/CProject.h +++ b/Libs/AST/Include/AST/Components/CProject.h @@ -1,13 +1,12 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include - +#include namespace rift::ast { - struct CProject : public p::Struct + struct CProject { - P_STRUCT(CProject, p::Struct) + P_STRUCT(CProject) }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Declarations.h b/Libs/AST/Include/AST/Components/Declarations.h index 4d1d08f8..47be6032 100644 --- a/Libs/AST/Include/AST/Components/Declarations.h +++ b/Libs/AST/Include/AST/Components/Declarations.h @@ -1,39 +1,42 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include + #include +#include namespace rift::ast { - struct CDeclStatic : public p::Struct + struct CDeclStatic { - P_STRUCT(CDeclStatic, p::Struct) + P_STRUCT(CDeclStatic) }; - struct CDeclRecord : public p::Struct + struct CDeclRecord { - P_STRUCT(CDeclRecord, p::Struct) + P_STRUCT(CDeclRecord) }; struct CDeclStruct : public CDeclRecord { - P_STRUCT(CDeclStruct, CDeclRecord, ) + using Super = CDeclRecord; + P_STRUCT(CDeclStruct) }; struct CDeclClass : public CDeclRecord { - P_STRUCT(CDeclClass, CDeclRecord) + using Super = CDeclRecord; + P_STRUCT(CDeclClass) }; - struct CDeclType : public p::Struct + struct CDeclType { - P_STRUCT(CDeclType, p::Struct) + P_STRUCT(CDeclType) P_PROP(typeId) p::Tag typeId; @@ -42,21 +45,22 @@ namespace rift::ast struct CDeclNative : public CDeclRecord { - P_STRUCT(CDeclNative, CDeclRecord) + using Super = CDeclRecord; + P_STRUCT(CDeclNative) }; - struct CDeclFunction : public p::Struct + struct CDeclFunction { - P_STRUCT(CDeclFunction, p::Struct) + P_STRUCT(CDeclFunction) }; - struct CDeclVariable : public p::Struct + struct CDeclVariable { - P_STRUCT(CDeclVariable, p::Struct) + P_STRUCT(CDeclVariable) - P_PROP(typeId, p::Prop_NotSerialized) + P_PROP(typeId, p::PF_NotSerialized) p::Id typeId = p::NoId; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Expressions.h b/Libs/AST/Include/AST/Components/Expressions.h index 4cbcaf0e..11d48195 100644 --- a/Libs/AST/Include/AST/Components/Expressions.h +++ b/Libs/AST/Include/AST/Components/Expressions.h @@ -3,8 +3,8 @@ #include "AST/Components/CNamespace.h" -#include #include +#include namespace rift::ast @@ -50,22 +50,23 @@ namespace rift::ast PointerToPointer }; } // namespace rift::ast -ENUM(rift::ast::UnaryOperatorType) -ENUM(rift::ast::BinaryOperatorType) -ENUM(rift::ast::TypeMode) +P_ENUM(rift::ast::UnaryOperatorType) +P_ENUM(rift::ast::BinaryOperatorType) +P_ENUM(rift::ast::TypeMode) namespace rift::ast { - struct CExpression : public p::Struct + struct CExpression { - P_STRUCT(CExpression, p::Struct) + P_STRUCT(CExpression) }; struct CExprCall : public CExpression { - P_STRUCT(CExprCall, CExpression) + using Super = CExpression; + P_STRUCT(CExprCall) P_PROP(function) Namespace function; @@ -75,7 +76,8 @@ namespace rift::ast // Data pointing to the id of the function from CExprCall's type and function names struct CExprCallId : public CExpression { - P_STRUCT(CExprCallId, CExpression, p::Struct_NotSerialized) + using Super = CExpression; + P_STRUCT(CExprCallId, p::TF_NotSerialized) // Id pointing to the function declaration P_PROP(functionId) @@ -88,7 +90,8 @@ namespace rift::ast struct CExprUnaryOperator : public CExpression { - P_STRUCT(CExprUnaryOperator, CExpression) + using Super = CExpression; + P_STRUCT(CExprUnaryOperator) P_PROP(type) UnaryOperatorType type = UnaryOperatorType::Not; @@ -101,7 +104,8 @@ namespace rift::ast struct CExprBinaryOperator : public CExpression { - P_STRUCT(CExprBinaryOperator, CExpression) + using Super = CExpression; + P_STRUCT(CExprBinaryOperator) P_PROP(type) BinaryOperatorType type = BinaryOperatorType::Add; @@ -114,7 +118,8 @@ namespace rift::ast struct CExprDeclRef : public CExpression { - P_STRUCT(CExprDeclRef, CExpression) + using Super = CExpression; + P_STRUCT(CExprDeclRef) P_PROP(ownerName) p::Tag ownerName; @@ -126,16 +131,17 @@ namespace rift::ast struct CExprDeclRefId : public CExpression { - P_STRUCT(CExprDeclRefId, CExpression) + using Super = CExpression; + P_STRUCT(CExprDeclRefId) P_PROP(declarationId) p::Id declarationId = p::NoId; }; - struct ExprInput : public p::Struct + struct ExprInput { - P_STRUCT(ExprInput, p::Struct) + P_STRUCT(ExprInput) P_PROP(nodeId) p::Id nodeId = p::NoId; @@ -153,9 +159,9 @@ namespace rift::ast }; - struct ExprOutput : public p::Struct + struct ExprOutput { - P_STRUCT(ExprOutput, p::Struct) + P_STRUCT(ExprOutput) P_PROP(nodeId) p::Id nodeId = p::NoId; @@ -173,9 +179,9 @@ namespace rift::ast }; - struct CExprInputs : public p::Struct + struct CExprInputs { - P_STRUCT(CExprInputs, p::Struct) + P_STRUCT(CExprInputs) P_PROP(linkedOutputs) p::TArray linkedOutputs; @@ -213,9 +219,9 @@ namespace rift::ast }; - struct CExprOutputs : public p::Struct + struct CExprOutputs { - P_STRUCT(CExprOutputs, p::Struct) + P_STRUCT(CExprOutputs) P_PROP(pinIds) p::TArray pinIds; @@ -247,9 +253,9 @@ namespace rift::ast }; - struct CExprType : public p::Struct + struct CExprType { - P_STRUCT(CExprType, p::Struct) + P_STRUCT(CExprType) P_PROP(type) Namespace type; @@ -259,11 +265,11 @@ namespace rift::ast }; - struct CExprTypeId : public p::Struct + struct CExprTypeId { - P_STRUCT(CExprTypeId, p::Struct) + P_STRUCT(CExprTypeId) - P_PROP(id, p::Prop_NotSerialized) + P_PROP(id, p::PF_NotSerialized) p::Id id = p::NoId; P_PROP(mode) diff --git a/Libs/AST/Include/AST/Components/Literals.h b/Libs/AST/Include/AST/Components/Literals.h index ac0c6668..9c821a53 100644 --- a/Libs/AST/Include/AST/Components/Literals.h +++ b/Libs/AST/Include/AST/Components/Literals.h @@ -2,7 +2,7 @@ #pragma once #include -#include +#include namespace rift::ast @@ -28,8 +28,8 @@ namespace rift::ast }; } // namespace rift::ast -ENUM(rift::ast::FloatingType) -ENUM(rift::ast::IntegralType) +P_ENUM(rift::ast::FloatingType) +P_ENUM(rift::ast::IntegralType) template<> struct magic_enum::customize::enum_range @@ -43,18 +43,18 @@ struct magic_enum::customize::enum_range namespace rift::ast { - struct CLiteralBool : public p::Struct + struct CLiteralBool { - P_STRUCT(CLiteralBool, p::Struct) + P_STRUCT(CLiteralBool) P_PROP(value) bool value = false; }; - struct CLiteralFloating : public p::Struct + struct CLiteralFloating { - P_STRUCT(CLiteralFloating, p::Struct) + P_STRUCT(CLiteralFloating) P_PROP(value) @@ -71,9 +71,9 @@ namespace rift::ast }; - struct CLiteralIntegral : public p::Struct + struct CLiteralIntegral { - P_STRUCT(CLiteralIntegral, p::Struct) + P_STRUCT(CLiteralIntegral) P_PROP(value) @@ -94,9 +94,9 @@ namespace rift::ast }; - struct CLiteralString : public p::Struct + struct CLiteralString { - P_STRUCT(CLiteralString, p::Struct) + P_STRUCT(CLiteralString) P_PROP(value) p::String value; diff --git a/Libs/AST/Include/AST/Components/Statements.h b/Libs/AST/Include/AST/Components/Statements.h index 91abc554..1060e858 100644 --- a/Libs/AST/Include/AST/Components/Statements.h +++ b/Libs/AST/Include/AST/Components/Statements.h @@ -1,45 +1,46 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include + #include +#include namespace rift::ast { - struct CStmtFor : public p::Struct + struct CStmtFor { - P_STRUCT(CStmtFor, p::Struct) + P_STRUCT(CStmtFor) }; - struct CStmtIf : public p::Struct + struct CStmtIf { - P_STRUCT(CStmtIf, p::Struct) + P_STRUCT(CStmtIf) }; - struct CStmtInput : public p::Struct + struct CStmtInput { - P_STRUCT(CStmtInput, p::Struct) + P_STRUCT(CStmtInput) P_PROP(linkOutputNode) p::Id linkOutputNode = p::NoId; }; - struct CStmtOutput : public p::Struct + struct CStmtOutput { - P_STRUCT(CStmtOutput, p::Struct) + P_STRUCT(CStmtOutput) P_PROP(linkInputNode) p::Id linkInputNode = p::NoId; }; - struct CStmtOutputs : public p::Struct + struct CStmtOutputs { - P_STRUCT(CStmtOutputs, p::Struct) + P_STRUCT(CStmtOutputs) // Both arrays keep the same index to the input node and the output pin P_PROP(pinIds) @@ -59,9 +60,9 @@ namespace rift::ast * Return arguments are dynamically populated depending on the function this expression is * connected to. */ - struct CStmtReturn : public p::Struct + struct CStmtReturn { - P_STRUCT(CStmtReturn, p::Struct) + P_STRUCT(CStmtReturn) }; diff --git a/Libs/AST/Include/AST/Components/Tags/CChanged.h b/Libs/AST/Include/AST/Components/Tags/CChanged.h index 9027a49a..4f59bed8 100644 --- a/Libs/AST/Include/AST/Components/Tags/CChanged.h +++ b/Libs/AST/Include/AST/Components/Tags/CChanged.h @@ -1,15 +1,14 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include - +#include namespace rift::ast { // Asigned to entities that have been modified during the last frame // Gets cleared after one frame - struct CChanged : public p::Struct + struct CChanged { - P_STRUCT(CChanged, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CChanged, p::TF_NotSerialized) }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Tags/CDirty.h b/Libs/AST/Include/AST/Components/Tags/CDirty.h index a0563aa8..56034557 100644 --- a/Libs/AST/Include/AST/Components/Tags/CDirty.h +++ b/Libs/AST/Include/AST/Components/Tags/CDirty.h @@ -4,7 +4,7 @@ #include "AST/Components/CFileRef.h" #include "AST/Components/Expressions.h" -#include +#include namespace rift::ast @@ -12,9 +12,9 @@ namespace rift::ast // Dirty tags are cleaned manually by the respective systems. CChanged instead gets cleared // after one frame template - struct TDirty : public p::Struct + struct TDirty { - P_STRUCT(TDirty, p::Struct, p::Struct_NotSerialized) + P_STRUCT(TDirty, p::TF_NotSerialized) }; using CDirty = TDirty; diff --git a/Libs/AST/Include/AST/Components/Tags/CInvalid.h b/Libs/AST/Include/AST/Components/Tags/CInvalid.h index 84bf80e0..fa963f7d 100644 --- a/Libs/AST/Include/AST/Components/Tags/CInvalid.h +++ b/Libs/AST/Include/AST/Components/Tags/CInvalid.h @@ -1,13 +1,13 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include +#include namespace rift::ast { - struct CInvalid : public p::Struct + struct CInvalid { - P_STRUCT(CInvalid, p::Struct) + P_STRUCT(CInvalid) }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h index 16f2f331..52be4ba4 100644 --- a/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h +++ b/Libs/AST/Include/AST/Components/Tags/CPendingLoad.h @@ -1,13 +1,13 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include +#include namespace rift { - struct CPendingLoad : public p::Struct + struct CPendingLoad { - P_STRUCT(CPendingLoad, p::Struct) + P_STRUCT(CPendingLoad) }; } // namespace rift diff --git a/Libs/AST/Include/AST/Components/Views/CNodePosition.h b/Libs/AST/Include/AST/Components/Views/CNodePosition.h index 620906a2..678aeb32 100644 --- a/Libs/AST/Include/AST/Components/Views/CNodePosition.h +++ b/Libs/AST/Include/AST/Components/Views/CNodePosition.h @@ -1,15 +1,16 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include + +#include #include namespace rift { - struct CNodePosition : public p::Struct + struct CNodePosition { - P_STRUCT(CNodePosition, p::Struct) + P_STRUCT(CNodePosition) P_PROP(position) p::v2 position; diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index ac8cd1ca..babe9575 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -2,7 +2,6 @@ #pragma once #include -#include #include diff --git a/Libs/AST/Include/AST/Statics/SLoadQueue.h b/Libs/AST/Include/AST/Statics/SLoadQueue.h index 90c6fac9..2c6a4d40 100644 --- a/Libs/AST/Include/AST/Statics/SLoadQueue.h +++ b/Libs/AST/Include/AST/Statics/SLoadQueue.h @@ -3,15 +3,15 @@ #include "AST/Id.h" -#include +#include namespace rift::ast { // Keeps a list of entities to load from disk - struct SLoadQueue : public p::Struct + struct SLoadQueue { - P_STRUCT(SLoadQueue, p::Struct) + P_STRUCT(SLoadQueue) p::TArray pendingSyncLoad; p::TArray pendingAsyncLoad; diff --git a/Libs/AST/Include/AST/Statics/SModules.h b/Libs/AST/Include/AST/Statics/SModules.h index 9193f4e5..144ce7c0 100644 --- a/Libs/AST/Include/AST/Statics/SModules.h +++ b/Libs/AST/Include/AST/Statics/SModules.h @@ -3,14 +3,14 @@ #include "AST/Id.h" -#include +#include namespace rift::ast { - struct SModules : public p::Struct + struct SModules { - P_STRUCT(SModules, p::Struct) + P_STRUCT(SModules) p::TMap modulesByPath; }; diff --git a/Libs/AST/Include/AST/Statics/SStringLoad.h b/Libs/AST/Include/AST/Statics/SStringLoad.h index cadfcd54..ab8921e0 100644 --- a/Libs/AST/Include/AST/Statics/SStringLoad.h +++ b/Libs/AST/Include/AST/Statics/SStringLoad.h @@ -5,15 +5,15 @@ #include #include -#include +#include namespace rift::ast { // Contains loaded string data from disk - struct SStringLoad : public p::Struct + struct SStringLoad { - P_STRUCT(SStringLoad, p::Struct) + P_STRUCT(SStringLoad) // This buffers are always in sync with size // They bind by array index an Id, path and loaded string diff --git a/Libs/AST/Include/AST/Statics/STypes.h b/Libs/AST/Include/AST/Statics/STypes.h index 25c8cf40..2fc60fec 100644 --- a/Libs/AST/Include/AST/Statics/STypes.h +++ b/Libs/AST/Include/AST/Statics/STypes.h @@ -4,14 +4,14 @@ #include "AST/Id.h" #include -#include +#include namespace rift::ast { - struct STypes : public p::Struct + struct STypes { - P_STRUCT(STypes, p::Struct) + P_STRUCT(STypes) p::TMap typesByName; // TODO: Use StringView to point to CFileRef component's path. diff --git a/Libs/AST/Include/AST/Utils/ModuleUtils.h b/Libs/AST/Include/AST/Utils/ModuleUtils.h index be4bbf56..e22ae556 100644 --- a/Libs/AST/Include/AST/Utils/ModuleUtils.h +++ b/Libs/AST/Include/AST/Utils/ModuleUtils.h @@ -22,7 +22,7 @@ namespace rift::ast struct ModuleBinding { p::Tag id; - p::StructType* tagType = nullptr; + p::TypeId tagType; p::String displayName; bool operator<(const ModuleBinding& other) const diff --git a/Libs/AST/Include/AST/Utils/Namespaces.h b/Libs/AST/Include/AST/Utils/Namespaces.h index 756399d1..80def00f 100644 --- a/Libs/AST/Include/AST/Utils/Namespaces.h +++ b/Libs/AST/Include/AST/Utils/Namespaces.h @@ -6,7 +6,6 @@ #include "AST/Id.h" #include -#include #include #include diff --git a/Libs/AST/Include/AST/Utils/TypeUtils.h b/Libs/AST/Include/AST/Utils/TypeUtils.h index dd0a0856..e7ec4e05 100644 --- a/Libs/AST/Include/AST/Utils/TypeUtils.h +++ b/Libs/AST/Include/AST/Utils/TypeUtils.h @@ -29,7 +29,7 @@ namespace rift::ast struct RiftType { p::Tag id; - p::StructType* tagType = nullptr; + p::TypeId tagType; RiftTypeSettings settings; bool operator<(const RiftType& other) const @@ -102,6 +102,6 @@ namespace rift::ast void RegisterFileType(p::Tag typeId, RiftTypeSettings settings) { RegisterFileType( - {.id = typeId, .tagType = TagType::GetStaticType(), .settings = p::Move(settings)}); + {.id = typeId, .tagType = p::GetTypeId(), .settings = p::Move(settings)}); } } // namespace rift::ast diff --git a/Libs/AST/Include/ASTModule.h b/Libs/AST/Include/ASTModule.h index 3c6a1721..150a3b2e 100644 --- a/Libs/AST/Include/ASTModule.h +++ b/Libs/AST/Include/ASTModule.h @@ -14,7 +14,9 @@ namespace rift class ASTModule : public Module { - P_CLASS(ASTModule, Module) + public: + using Super = Module; + P_CLASS(ASTModule) public: static const p::Tag structType; diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index 09fa15bd..68d0ec76 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -4,14 +4,15 @@ #include "Compiler/Compiler.h" -#include +#include namespace rift { - class Backend : public p::Class + class Backend : public p::Object { - P_CLASS(Backend, p::Class) + using Super = p::Object; + P_CLASS(Backend) public: virtual p::Tag GetName() diff --git a/Libs/AST/Include/Compiler/Compiler.h b/Libs/AST/Include/Compiler/Compiler.h index f594691f..c039ad2b 100644 --- a/Libs/AST/Include/Compiler/Compiler.h +++ b/Libs/AST/Include/Compiler/Compiler.h @@ -5,8 +5,7 @@ #include "Compiler/CompilerConfig.h" #include -#include -#include +#include namespace rift @@ -14,18 +13,18 @@ namespace rift class Backend; - struct CompileError : public p::Struct + struct CompileError { - P_STRUCT(CompileError, p::Struct) + P_STRUCT(CompileError) P_PROP(text) p::String text; }; - struct Compiler : public p::Struct + struct Compiler { - P_STRUCT(Compiler, p::Struct) + P_STRUCT(Compiler) ast::Tree& ast; CompilerConfig config; @@ -50,11 +49,11 @@ namespace rift void Build(ast::Tree& tree, const CompilerConfig& config, p::TPtr backend); - void Build(ast::Tree& ast, const CompilerConfig& config, p::ClassType* backendType); + void Build(ast::Tree& ast, const CompilerConfig& config, p::TypeId backendType); template void Build(ast::Tree& ast, const CompilerConfig& config) { - Build(ast, config, T::GetStaticType()); + Build(ast, config, p::GetTypeId()); } } // namespace rift diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index d00214e4..78d09087 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -5,9 +5,7 @@ #include "AST/Tree.h" #include "Pipe/Core/Platform.h" -#include -#include -#include +#include namespace rift @@ -25,9 +23,9 @@ namespace rift // speed on level 2 is ~50% faster than on level 3 }; - struct CompilerConfig : public p::Struct + struct CompilerConfig { - P_STRUCT(CompilerConfig, p::Struct) + P_STRUCT(CompilerConfig) OptimizationLevel optimization = OptimizationLevel::Two; @@ -41,4 +39,4 @@ namespace rift void Init(ast::Tree& ast); }; } // namespace rift -ENUM(rift::OptimizationLevel); +P_ENUM(rift::OptimizationLevel); diff --git a/Libs/AST/Include/Compiler/Utils/BackendUtils.h b/Libs/AST/Include/Compiler/Utils/BackendUtils.h index 25e9656d..0e2a8118 100644 --- a/Libs/AST/Include/Compiler/Utils/BackendUtils.h +++ b/Libs/AST/Include/Compiler/Utils/BackendUtils.h @@ -6,11 +6,11 @@ #include "Compiler/Compiler.h" #include -#include +#include namespace rift { - p::TArray GetBackendTypes(); + p::TArray GetBackendTypes(); p::TArray> CreateBackends(); } // namespace rift diff --git a/Libs/AST/Include/Module.h b/Libs/AST/Include/Module.h index 313ef030..d56b0c1d 100644 --- a/Libs/AST/Include/Module.h +++ b/Libs/AST/Include/Module.h @@ -6,7 +6,7 @@ #include "Rift.h" #include -#include +#include namespace rift @@ -14,9 +14,10 @@ namespace rift using namespace p; - class Module : public Class + class Module : public Object { - P_CLASS(Module, Class) + using Super = Object; + P_CLASS(Module) enum class State : u8 { diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index bc67e688..c8b15183 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -8,32 +8,30 @@ #include "View.h" #include -#include -#include #include namespace rift { - void EnableModule(p::ClassType* type); - void DisableModule(p::ClassType* type); - p::TPtr GetModule(p::ClassType* type); + void EnableModule(p::TypeId type); + void DisableModule(p::TypeId type); + p::TPtr GetModule(p::TypeId type); template void EnableModule() { - EnableModule(T::GetStaticType()); + EnableModule(GetTypeId()); } template void DisableModule() { - DisableModule(T::GetStaticType()); + DisableModule(GetTypeId()); } template p::TPtr GetModule() { - return GetModule(T::GetStaticType()).template Cast(); + return GetModule(GetTypeId()).template Cast(); } void RegisterView(View view); diff --git a/Libs/AST/Include/View.h b/Libs/AST/Include/View.h index 85547487..d1b0c0dd 100644 --- a/Libs/AST/Include/View.h +++ b/Libs/AST/Include/View.h @@ -4,14 +4,14 @@ #include "AST/Components/Declarations.h" #include -#include +#include namespace rift { - struct View : public p::Struct + struct View { - P_STRUCT(View, p::Struct) + P_STRUCT(View) P_PROP(name) p::Tag name; diff --git a/Libs/AST/Src/AST/Tree.cpp b/Libs/AST/Src/AST/Tree.cpp index 3927b683..e438c06d 100644 --- a/Libs/AST/Src/AST/Tree.cpp +++ b/Libs/AST/Src/AST/Tree.cpp @@ -129,9 +129,10 @@ namespace rift::ast text.append("Pools: \n"); for (const auto& pool : GetPools()) { - p::Type* type = p::TypeRegistry::Get().FindType(pool.GetId()); + p::TypeId type = pool.GetId(); p::Strings::FormatTo(text, "- {} x{}\n", - type ? type->GetName() : p::StringView{"NotReflected"}, pool.GetPool()->Size()); + type.IsValid() ? GetTypeName(type) : p::StringView{"NotReflected"}, + pool.GetPool()->Size()); } return text; diff --git a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp index 522a93da..616c33bb 100644 --- a/Libs/AST/Src/AST/Utils/ModuleUtils.cpp +++ b/Libs/AST/Src/AST/Utils/ModuleUtils.cpp @@ -237,20 +237,20 @@ namespace rift::ast { if (const auto* binding = FindModuleBinding(bindingId)) { - ast.AddDefault(binding->tagType->GetId(), id); + ast.AddDefault(binding->tagType, id); } } void RemoveBindingFromModule(ast::Tree& ast, ast::Id id, p::Tag bindingId) { if (const auto* binding = FindModuleBinding(bindingId)) { - ast.Remove(binding->tagType->GetId(), id); + ast.Remove(binding->tagType, id); } } const ModuleBinding* FindModuleBinding(p::Tag id) { - const p::i32 index = gModuleBindings.FindSortedEqual(id); + const p::i32 index = gModuleBindings.FindSorted(id); return index != p::NO_INDEX ? gModuleBindings.Data() + index : nullptr; } diff --git a/Libs/AST/Src/AST/Utils/TypeUtils.cpp b/Libs/AST/Src/AST/Utils/TypeUtils.cpp index 4a562dc3..2b9ab5f1 100644 --- a/Libs/AST/Src/AST/Utils/TypeUtils.cpp +++ b/Libs/AST/Src/AST/Utils/TypeUtils.cpp @@ -45,7 +45,7 @@ namespace rift::ast if (auto* fileType = FindFileType(typeId)) { - ast.AddDefault(fileType->tagType->GetId(), id); + ast.AddDefault(fileType->tagType, id); } } @@ -485,7 +485,7 @@ namespace rift::ast const RiftType* FindFileType(p::Tag typeId) { - const i32 index = gFileTypes.FindSortedEqual(typeId); + const i32 index = gFileTypes.FindSorted(typeId); return index != NO_INDEX ? gFileTypes.Data() + index : nullptr; } diff --git a/Libs/AST/Src/Compiler/Compiler.cpp b/Libs/AST/Src/Compiler/Compiler.cpp index 58528611..daaa69c4 100644 --- a/Libs/AST/Src/Compiler/Compiler.cpp +++ b/Libs/AST/Src/Compiler/Compiler.cpp @@ -15,7 +15,7 @@ namespace rift { - void Compiler::Error(StringView str) + void Compiler::Error(p::StringView str) { p::Error(str); CompileError newError{}; @@ -24,7 +24,7 @@ namespace rift } - void Build(ast::Tree& ast, const CompilerConfig& config, TPtr backend) + void Build(ast::Tree& ast, const CompilerConfig& config, p::TPtr backend) { Compiler compiler{ast, config}; @@ -65,11 +65,11 @@ namespace rift backend->Build(compiler); } - void Build(ast::Tree& ast, const CompilerConfig& config, ClassType* backendType) + void Build(ast::Tree& ast, const CompilerConfig& config, p::TypeId backendType) { - if (backendType) + if (backendType.IsValid()) { - TOwnPtr backend = MakeOwned(backendType); + p::TOwnPtr backend = p::MakeOwned(backendType); Build(ast, config, backend); } } diff --git a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp index d8817138..e8eb64e6 100644 --- a/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp +++ b/Libs/AST/Src/Compiler/Utils/BackendUtils.cpp @@ -2,14 +2,16 @@ #include "Compiler/Utils/BackendUtils.h" +#include "PipeReflect.h" + namespace rift { - p::TArray GetBackendTypes() + p::TArray GetBackendTypes() { - p::TArray types = Backend::GetStaticType()->GetChildren(); - types.RemoveIf([](p::ClassType* type) { - return !type || type->HasFlag(p::Class_Abstract); + p::TArray types; // = Backend::GetStaticType()->GetChildren(); + types.RemoveIf([](p::TypeId type) { + return !type.IsValid() || p::HasTypeFlags(type, p::TF_Abstract); }); return Move(types); } @@ -19,7 +21,7 @@ namespace rift p::TArray> backends; auto types = GetBackendTypes(); backends.Reserve(types.Size()); - for (auto* type : types) + for (p::TypeId type : types) { backends.Add(p::MakeOwned(type)); } diff --git a/Libs/AST/Src/Rift.cpp b/Libs/AST/Src/Rift.cpp index 633d5322..335a0874 100644 --- a/Libs/AST/Src/Rift.cpp +++ b/Libs/AST/Src/Rift.cpp @@ -7,13 +7,13 @@ namespace rift { - static p::TMap> gModules{}; + static p::TMap> gModules{}; static p::TArray gViews{}; - void EnableModule(p::ClassType* type) + void EnableModule(p::TypeId type) { - P_Check(Module::GetStaticType()->IsParentOf(type)); + P_Check(IsTypeParentOf(GetTypeId(), type)); if (!gModules.Contains(type)) { @@ -23,12 +23,12 @@ namespace rift } } - void DisableModule(p::ClassType* type) + void DisableModule(p::TypeId type) { gModules.Remove(type); } - p::TPtr GetModule(p::ClassType* type) + p::TPtr GetModule(p::TypeId type) { if (auto* module = gModules.Find(type)) { diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index cc72b5ad..95a13f1d 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -13,7 +13,9 @@ namespace rift struct Input; class MIRBackendModule : public Module { - P_CLASS(MIRBackendModule, Module) + public: + using Super = Module; + P_CLASS(MIRBackendModule) public: MIRBackendModule(); @@ -22,7 +24,8 @@ namespace rift class MIRBackend : public Backend { - P_CLASS(MIRBackend, Backend) + using Super = Backend; + P_CLASS(MIRBackend) public: Tag GetName() override diff --git a/Libs/Backends/MIR/Compiler/Src/Components.h b/Libs/Backends/MIR/Compiler/Src/Components.h index 87ed8374..ddf9c9d5 100644 --- a/Libs/Backends/MIR/Compiler/Src/Components.h +++ b/Libs/Backends/MIR/Compiler/Src/Components.h @@ -2,7 +2,7 @@ #pragma once #include -#include +#include namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h index 1ca2ca61..5a65b40a 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/CNativeBinding.h @@ -2,14 +2,14 @@ #pragma once #include -#include +#include namespace rift { - struct CNativeBinding : public p::Struct + struct CNativeBinding { - P_STRUCT(CNativeBinding, p::Struct) + P_STRUCT(CNativeBinding) P_PROP(binaries) p::TArray binaries; diff --git a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h index fd6fc81c..4e4afbbb 100644 --- a/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h +++ b/Libs/Bindings/Native/Compiler/Include/Components/Declarations.h @@ -2,17 +2,20 @@ #pragma once #include +#include namespace rift { struct CDeclCStruct : public ast::CDeclRecord { - P_STRUCT(CDeclCStruct, CDeclRecord) + using Super = CDeclRecord; + P_STRUCT(CDeclCStruct) }; struct CDeclCStatic : public ast::CDeclRecord { - P_STRUCT(CDeclCStatic, CDeclRecord) + using Super = CDeclRecord; + P_STRUCT(CDeclCStatic) }; } // namespace rift diff --git a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h index 711ae3e8..866a5ecd 100644 --- a/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h +++ b/Libs/Bindings/Native/Compiler/Include/NativeBindingModule.h @@ -14,7 +14,9 @@ namespace rift class NativeBindingModule : public Module { - P_CLASS(NativeBindingModule, Module) + public: + using Super = Module; + P_CLASS(NativeBindingModule) void Load() override; void SyncIncludes(ast::Tree& ast); diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index cc93cfd2..42475825 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -44,7 +44,7 @@ namespace rift // Register module binding ast::RegisterModuleBinding( - {.id = "C", .tagType = CNativeBinding::GetStaticType(), .displayName = "C"}); + {.id = "C", .tagType = p::GetTypeId(), .displayName = "C"}); ast::RegisterSerializedModulePools(); ast::PreAllocPools(); } diff --git a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h index cecdd1b3..fe64df1a 100644 --- a/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h +++ b/Libs/Bindings/Native/Editor/Include/NativeBindingEditorModule.h @@ -9,6 +9,8 @@ namespace rift { class NativeBindingEditorModule : public Module { - P_CLASS(NativeBindingEditorModule, Module) + public: + using Super = Module; + P_CLASS(NativeBindingEditorModule) }; } // namespace rift diff --git a/Libs/Editor/Include/Components/CDeclRename.h b/Libs/Editor/Include/Components/CDeclRename.h index a54684a3..cc7d44ea 100644 --- a/Libs/Editor/Include/Components/CDeclRename.h +++ b/Libs/Editor/Include/Components/CDeclRename.h @@ -5,15 +5,15 @@ #include "DockSpaceLayout.h" #include "NodeGraph/NodeGraphPanel.h" -#include #include + namespace rift::editor { - struct CDeclRename : public p::Struct + struct CDeclRename { - P_STRUCT(CDeclRename, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CDeclRename, p::TF_NotSerialized) // Renaming uses this buffer to temporarely store the name being edited p::String buffer; diff --git a/Libs/Editor/Include/Components/CModuleEditor.h b/Libs/Editor/Include/Components/CModuleEditor.h index 5fd93988..43df7b7d 100644 --- a/Libs/Editor/Include/Components/CModuleEditor.h +++ b/Libs/Editor/Include/Components/CModuleEditor.h @@ -4,16 +4,16 @@ #include "DockSpaceLayout.h" #include -#include #include #include + namespace rift::editor { - struct CModuleEditor : public p::Struct + struct CModuleEditor { - P_STRUCT(CModuleEditor, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CModuleEditor, p::TF_NotSerialized) bool pendingFocus = false; }; diff --git a/Libs/Editor/Include/Components/CTypeEditor.h b/Libs/Editor/Include/Components/CTypeEditor.h index 8b8ad2c5..2e945820 100644 --- a/Libs/Editor/Include/Components/CTypeEditor.h +++ b/Libs/Editor/Include/Components/CTypeEditor.h @@ -4,16 +4,16 @@ #include "DockSpaceLayout.h" #include -#include +#include #include #include namespace rift::editor { - struct CTypeEditor : public p::Struct + struct CTypeEditor { - P_STRUCT(CTypeEditor, p::Struct, p::Struct_NotSerialized) + P_STRUCT(CTypeEditor, p::TF_NotSerialized) static const Tag rightTopNode; static const Tag rightBottomNode; diff --git a/Libs/Editor/Include/Statics/EditorSettings.h b/Libs/Editor/Include/Statics/EditorSettings.h index 8e9005a3..50490fc9 100644 --- a/Libs/Editor/Include/Statics/EditorSettings.h +++ b/Libs/Editor/Include/Statics/EditorSettings.h @@ -1,14 +1,14 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include +#include namespace rift::editor { - struct EditorSettings : public p::Struct + struct EditorSettings { - P_STRUCT(EditorSettings, p::Struct) + P_STRUCT(EditorSettings) P_PROP(recentProjects) p::TArray recentProjects; diff --git a/Libs/Editor/Include/Statics/SEditor.h b/Libs/Editor/Include/Statics/SEditor.h index e77e36aa..69a5c1a0 100644 --- a/Libs/Editor/Include/Statics/SEditor.h +++ b/Libs/Editor/Include/Statics/SEditor.h @@ -10,16 +10,15 @@ #include "Tools/ReflectionDebugger.h" #include -#include #include #include namespace rift::editor { - struct SEditor : public Struct + struct SEditor { - P_STRUCT(SEditor, Struct) + P_STRUCT(SEditor) ImGuiID dockspaceID = 0; DockSpaceLayout layout; diff --git a/Libs/Editor/Include/Tools/ReflectionDebugger.h b/Libs/Editor/Include/Tools/ReflectionDebugger.h index 21f73000..8d00ce83 100644 --- a/Libs/Editor/Include/Tools/ReflectionDebugger.h +++ b/Libs/Editor/Include/Tools/ReflectionDebugger.h @@ -2,6 +2,7 @@ #pragma once #include "AST/Tree.h" +#include "PipeReflect.h" #include @@ -15,9 +16,9 @@ namespace rift::editor { bool open = false; - Type* selectedType = nullptr; + TypeId selectedType; ImGuiTextFilter filter; - TypeCategory categoryFilter = TypeCategory::All; + TypeFlags typeFlagsFilter = p::TF_Native | p::TF_Enum | p::TF_Struct | p::TF_Object; ReflectionDebugger(); @@ -25,6 +26,6 @@ namespace rift::editor void Draw(); private: - void DrawType(Type* type); + void DrawType(TypeId type); }; } // namespace rift::editor diff --git a/Libs/Editor/Include/Utils/EditorStyle.h b/Libs/Editor/Include/Utils/EditorStyle.h index d49bcbd4..06539cb0 100644 --- a/Libs/Editor/Include/Utils/EditorStyle.h +++ b/Libs/Editor/Include/Utils/EditorStyle.h @@ -2,9 +2,11 @@ #pragma once +#include "Pipe/Core/TypeTraits.h" + #include -#include #include +#include #include @@ -45,11 +47,11 @@ namespace rift::editor { return Color::FromHex(0xBF54AE); } - else if constexpr (IsSame) + else if constexpr (IsObject) { return Color::FromHex(0x545FBF); } - else if constexpr (IsSame) + else if constexpr (IsStructOrClass) { return Color::FromHex(0x548CBF); } diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index b0f72622..2b2eac71 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -26,7 +26,7 @@ namespace rift::editor { void RegisterKeyValueInspections() { - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](p::StringView label, void* data, p::TypeId type) { auto* id = static_cast(data); // UI::DrawKeyValue(label, data, GetType::Entity>()); UI::TableNextRow(); @@ -41,7 +41,8 @@ namespace rift::editor } }); - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection( + [](p::StringView label, void* data, p::TypeId type) { UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index f2ed2502..6a014312 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -445,7 +445,7 @@ namespace rift::editor::EditorSystem { for (const auto& binding : ast::GetModuleBindings()) { - auto* pool = ast.GetPool(binding.tagType->GetId()); + auto* pool = ast.GetPool(binding.tagType); if (void* data = pool ? pool->TryGetVoid(moduleId) : nullptr) { if (UI::BeginCategory(binding.displayName, true)) diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 5f2256d9..8326ee04 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -3,6 +3,7 @@ #include "Tools/ASTDebugger.h" #include "imgui.h" +#include "PipeReflect.h" #include "UI/Widgets.h" #include @@ -12,11 +13,15 @@ #include #include #include -#include #include #include +#define P_IMGUI_IMPLEMENTATION +#define P_DEBUG_IMPLEMENTATION +#include + + namespace rift::editor { void DrawTypesDebug(ast::Tree& ast) @@ -143,6 +148,17 @@ namespace rift::editor DrawEntityInspector( " " ICON_FA_LIST_ALT " Inspector", "MainInspector", ast, mainInspector, nullptr); + + { + static p::ECSDebugContext testContext; + testContext.ctx = * + p::BeginECSDebug(testContext); + static p::ECSDebugInspector testInspector; + testInspector.id = mainInspector.id; + p::DrawEntityInspector("Test", testInspector); + p::EndECSDebug(); + } + for (p::i32 i = 0; i < secondaryInspectors.Size(); ++i) { InspectorPanel& inspector = secondaryInspectors[i]; @@ -351,18 +367,17 @@ namespace rift::editor if (valid) { - const auto& registry = p::TypeRegistry::Get(); for (const auto& poolInstance : ast.GetPools()) { - p::Type* type = registry.FindType(poolInstance.componentId); - if (!type || !poolInstance.GetPool()->Has(inspector.id)) + p::TypeId type = poolInstance.componentId; + if (!type.IsValid() || !poolInstance.GetPool()->Has(inspector.id)) { continue; } void* data = poolInstance.GetPool()->TryGetVoid(inspector.id); static p::String typeName; - typeName = type->GetName(); + typeName = p::GetTypeName(type); ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen; if (!data) @@ -372,10 +387,10 @@ namespace rift::editor if (UI::CollapsingHeader(typeName.c_str(), flags)) { UI::Indent(); - auto* dataType = Cast(type); - if (data && dataType && UI::BeginInspector("EntityInspector")) + if (p::HasTypeFlags(type, p::TF_Struct) + && UI::BeginInspector("EntityInspector")) { - UI::InspectChildrenProperties({data, dataType}); + UI::InspectChildrenProperties({data, type}); UI::EndInspector(); } UI::Unindent(); diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index 95ec3d33..92e148bc 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -2,12 +2,13 @@ #include "Tools/ReflectionDebugger.h" +#include "PipeReflect.h" + #include #include #include #include #include -#include #include #include @@ -23,16 +24,15 @@ namespace rift::editor return; } - const auto& registry = TypeRegistry::Get(); - UI::Begin("Reflection", &open); if (UI::BeginPopup("Filter")) { - UI::CheckboxFlags("Native", (u32*)&categoryFilter, u32(TypeCategory::Native)); - UI::CheckboxFlags("Enum", (u32*)&categoryFilter, u32(TypeCategory::Enum)); - UI::CheckboxFlags("Class", (u32*)&categoryFilter, u32(TypeCategory::Class)); - UI::CheckboxFlags("Struct", (u32*)&categoryFilter, u32(TypeCategory::Struct)); + UI::CheckboxFlags("Native", &typeFlagsFilter, u64(p::TF_Native)); + UI::CheckboxFlags("Enum", &typeFlagsFilter, u64(p::TF_Enum)); + UI::CheckboxFlags("Struct", &typeFlagsFilter, u64(p::TF_Struct)); + UI::CheckboxFlags("Object", &typeFlagsFilter, u64(p::TF_Object)); + UI::CheckboxFlags("Container", &typeFlagsFilter, u64(p::TF_Container)); UI::EndPopup(); } if (UI::Button("Filter")) @@ -50,14 +50,14 @@ namespace rift::editor if (UI::BeginTable("typesTable", 4, flags)) { UI::TableSetupColumn("Id", ImGuiTableColumnFlags_IndentEnable); - UI::TableSetupColumn("Category"); UI::TableSetupColumn("Name"); + UI::TableSetupColumn("Flags"); UI::TableSetupColumn("Parent"); UI::TableHeadersRow(); - for (auto it : registry) + for (p::TypeId type : p::GetRegisteredTypeIds()) { - DrawType(it.second); + DrawType(type); } UI::EndTable(); } @@ -66,20 +66,20 @@ namespace rift::editor UI::End(); } - void ReflectionDebugger::DrawType(Type* type) + void ReflectionDebugger::DrawType(TypeId type) { - if (!HasAllFlags(categoryFilter, type->GetCategory())) + if (!HasAnyTypeFlags(type, typeFlagsFilter)) { return; } static String idText; idText.clear(); - Strings::FormatTo(idText, "{}", type->GetId()); + Strings::FormatTo(idText, "{}", type); - StringView name = type->GetName(); + StringView rawName = p::GetTypeName(type); if (!filter.PassFilter(idText.c_str(), idText.c_str() + idText.size()) - && !filter.PassFilter(name.data(), name.data() + name.size())) + && !filter.PassFilter(rawName.data(), rawName.data() + rawName.size())) { return; } @@ -89,22 +89,36 @@ namespace rift::editor UI::TableSetColumnIndex(0); // Id UI::Text(idText); - UI::TableSetColumnIndex(1); // Category - static String categories; - categories.clear(); - GetEnumFlagName(type->GetCategory(), categories); - UI::Text(categories); - - UI::TableSetColumnIndex(2); // Name + UI::TableSetColumnIndex(1); // Name + StringView ns; + StringView name = p::RemoveNamespace(rawName, ns); + UI::PushStyleCompact(); + UI::PushTextColor(UI::GetNeutralTextColor(1).Shade(0.3f)); + UI::Text(ns); + UI::PopTextColor(); + UI::PopStyleCompact(); + UI::SameLine(0, 10.f); UI::Text(name); - if (const auto* dataType = Cast(type)) + UI::TableSetColumnIndex(2); // Flags + static String flags; + flags.clear(); + GetEnumFlagName(TypeFlags_(GetTypeFlags(type)), flags); + UI::Text(flags); + + TypeId parentId = p::GetTypeParent(type); + if (parentId.IsValid()) { - if (const DataType* parent = dataType->GetParent()) - { - UI::TableSetColumnIndex(3); // Parent - UI::Text(parent->GetName()); - } + UI::TableSetColumnIndex(3); // Parent + rawName = p::GetTypeName(parentId); + name = p::RemoveNamespace(rawName, ns); + UI::PushStyleCompact(); + UI::PushTextColor(UI::GetNeutralTextColor(1).Shade(0.3f)); + UI::Text(ns); + UI::PopTextColor(); + UI::PopStyleCompact(); + UI::SameLine(0, 10.f); + UI::Text(name); } } } // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index 8a60c757..9d6cbb93 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -45,11 +45,11 @@ namespace rift::editor } else if (ast.Has(id)) { - return GetTypeColor(); + return GetTypeColor(); } else if (ast.Has(id)) { - return GetTypeColor(); + return GetTypeColor(); // Pass any struct to get struct color } return GetTypeColor(); } diff --git a/Libs/UI/Include/UI/Inspection.h b/Libs/UI/Include/UI/Inspection.h index 74c792b2..2d997fe2 100644 --- a/Libs/UI/Include/UI/Inspection.h +++ b/Libs/UI/Include/UI/Inspection.h @@ -6,47 +6,141 @@ #include "UI/UIImgui.h" #include "UI/Widgets.h" -#include -#include -#include -#include -#include -#include +#include namespace rift::UI { - // label, data, type - using CustomKeyValue = TFunction; + struct ValueHandle + { + protected: + void* container = nullptr; + TypeId containerType; + const TypeProperty* property = nullptr; + i32 index = NO_INDEX; + + + public: + ValueHandle(void* container, TypeId containerType) + : container{container}, containerType{containerType} + {} + ValueHandle(void* container, TypeId containerType, const TypeProperty& property) + : container{container}, containerType{containerType}, property{&property} + {} + ValueHandle(void* data, const TypeProperty* property, i32 index) + : container{data}, property{property}, index{index} + { + // P_Check(GetArrayProperty()); + } + ValueHandle(const ValueHandle& container, i32 index) + : ValueHandle(container.GetPtr(), container.GetProperty(), index) + {} + + ValueHandle(const ValueHandle& other) = default; + ValueHandle& operator=(const ValueHandle& other) = default; + + const TypeProperty* GetProperty() const + { + return property; + } + + bool IsArray() const + { + return !IsArrayItem() && property && property->HasFlag(PF_Array); + } + bool IsArrayItem() const + { + return index != NO_INDEX; + } + + // const ArrayProperty* GetArrayProperty() const + //{ + // if (property && property->HasFlag(PF_Array)) + // { + // return static_cast(property); + // } + // return nullptr; + // } + + virtual void GetDisplayName(String& name) const + { + if (index != NO_INDEX) + { + Strings::FormatTo(name, "{}", index); + } + else if (property) + { + name.append(Strings::ToSentenceCase(property->name.AsString())); + } + } + + TypeId GetType() const + { + return containerType; + } + void* GetContainer() const + { + P_Check(index != NO_INDEX); + return container; + } - void RegisterCustomInspection(Type* typeId, const CustomKeyValue& custom); + i32 GetIndex() const + { + return index; + } + + void* GetPtr() const + { + // const auto* arrayProp = GetArrayProperty(); + // if (arrayProp && index != NO_INDEX) + //{ + // return arrayProp->GetItem(container, index); + // } + return container; + } + + bool IsValid() const + { + return container != nullptr; + } + + operator bool() const + { + return IsValid(); + } + }; + + + using CustomKeyValue = TFunction; + + + void RegisterCustomInspection(p::TypeId type, const CustomKeyValue& custom); template void RegisterCustomInspection(const CustomKeyValue& custom) { - RegisterCustomInspection(GetType(), custom); + RegisterCustomInspection(GetTypeId(), custom); } - void DrawEnumValue(void* data, p::EnumType* type); - void DrawNativeValue(void* data, p::NativeType* type); - void DrawKeyValue(p::StringView label, void* data, p::Type* type); + void DrawEnumValue(void* data, p::TypeId type); + void DrawNativeValue(void* data, p::TypeId type); + void DrawKeyValue(p::StringView label, void* data, p::TypeId type); void InspectProperty(const ValueHandle& handle); void InspectChildrenProperties(const ValueHandle& handle); - inline void InspectStruct(Struct* data, StructType* type) + inline void InspectStruct(void* data, p::TypeId type) { - // InspectChildrenProperties(data, type); + if (p::HasTypeFlags(type, TF_Struct)) + { + InspectChildrenProperties({data, type}); + } } template inline void InspectStruct(T* data) - requires(Derived) - { - InspectStruct(data, T::GetStaticType()); - } - inline void InspectClass(Class* data, ClassType* type) + requires(p::IsStructOrClass) { - // InspectChildrenProperties(data, type); + InspectStruct(data, GetTypeId()); } bool BeginCategory(p::StringView name, bool isLeaf); diff --git a/Libs/UI/Include/UI/UIImgui.h b/Libs/UI/Include/UI/UIImgui.h index 6ca6a977..e16a8d91 100644 --- a/Libs/UI/Include/UI/UIImgui.h +++ b/Libs/UI/Include/UI/UIImgui.h @@ -7,12 +7,11 @@ #include -#define IM_VEC2_CLASS_EXTRA \ - constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) \ - {} \ - constexpr operator p::v2() const \ - { \ - return p::v2{x, y}; \ +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) {} \ + constexpr operator p::v2() const \ + { \ + return p::v2{x, y}; \ } #define IM_VEC4_CLASS_EXTRA \ @@ -22,8 +21,7 @@ { \ return p::LinearColor{x, y, z, w}; \ } \ - constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) \ - {} \ + constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) {} \ constexpr operator p::v4() const \ { \ return p::v4{x, y, z, w}; \ diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 55062ddd..456df70e 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -5,136 +5,133 @@ #include "imgui.h" #include +#include #include #include -#include -#include namespace rift::UI { static const char* gCurrentInspector = nullptr; - static TMap gCustomKeyValues; + static TMap gCustomKeyValues; - void RegisterCustomInspection(Type* typeId, const CustomKeyValue& custom) + void RegisterCustomInspection(p::TypeId type, const CustomKeyValue& custom) { if (custom) { - gCustomKeyValues.Insert(typeId, custom); + gCustomKeyValues.Insert(type, custom); } } - void DrawEnumValue(void* data, EnumType* type) + void DrawEnumValue(void* data, p::TypeId type) { static String label; label.clear(); Strings::FormatTo(label, "##{}", sizet(data)); - + /* const i32 currentIndex = type->GetIndexFromValue(data); if (UI::BeginCombo(label.c_str(), type->GetNameByIndex(currentIndex).AsString().data())) { - for (i32 i = 0; i < type->Size(); ++i) - { - const bool isSelected = currentIndex == i; + for (i32 i = 0; i < type->Size(); ++i) + { + const bool isSelected = currentIndex == i; - if (UI::Selectable(type->GetNameByIndex(i).AsString().data(), isSelected)) - { - type->SetValueFromIndex(data, i); - } + if (UI::Selectable(type->GetNameByIndex(i).AsString().data(), isSelected)) + { + type->SetValueFromIndex(data, i); + } - // Set the initial focus when opening the combo - if (isSelected) - { - UI::SetItemDefaultFocus(); - } - } - UI::EndCombo(); + // Set the initial focus when opening the combo + if (isSelected) + { + UI::SetItemDefaultFocus(); + } + } + UI::EndCombo(); } + */ } - void DrawNativeValue(void* data, NativeType* type) + void DrawNativeValue(void* data, p::TypeId type) { static String label; label.clear(); Strings::FormatTo(label, "##{}", sizet(data)); - if (type == GetType()) - { - UI::Checkbox(label.c_str(), static_cast(data)); - } - else if (type == GetType()) - { - UI::InputText(label.c_str(), *static_cast(data)); - } - else if (type == GetType()) - { - Tag& name = *static_cast(data); - String text{name.AsString()}; - if (UI::InputText(label.c_str(), text)) - { - name = Tag{text}; + switch (type.GetId()) + { + case GetTypeId().GetId(): + UI::Checkbox(label.c_str(), static_cast(data)); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_U8, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_S32, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_U32, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_S64, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_U64, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_Float, data); + break; + case GetTypeId().GetId(): + UI::InputScalar(label.c_str(), ImGuiDataType_Double, data); + break; + case GetTypeId().GetId(): + UI::InputFloat2(label.c_str(), static_cast(data)); + break; + case GetTypeId().GetId(): + UI::InputFloat3(label.c_str(), static_cast(data)); + break; + case GetTypeId().GetId(): + UI::InputText(label.c_str(), *static_cast(data)); + break; + case GetTypeId().GetId(): { + Tag& name = *static_cast(data); + String text{name.AsString()}; + if (UI::InputText(label.c_str(), text)) + { + name = Tag{text}; + } } } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_U8, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_S32, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_U32, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_S64, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_U64, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_Float, data); - } - else if (type == GetType()) - { - UI::InputScalar(label.c_str(), ImGuiDataType_Double, data); - } - else if (type == GetType()) - { - UI::InputFloat2(label.c_str(), static_cast(data)); - } - else if (type == GetType()) - { - UI::InputFloat3(label.c_str(), static_cast(data)); - } } - void DrawKeyValue(StringView label, void* data, Type* type) + void DrawKeyValue(StringView label, void* data, p::TypeId type) { UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); UI::Text(label); UI::TableSetColumnIndex(1); - if (auto* nativeType = Cast(type)) + if (p::HasTypeFlags(type, TF_Native)) { - DrawNativeValue(data, nativeType); + DrawNativeValue(data, type); } - else if (auto* enumType = Cast(type)) + else if (p::HasTypeFlags(type, TF_Enum)) { - DrawEnumValue(data, enumType); + DrawEnumValue(data, type); } } - void DrawArrayValue(const ArrayProperty& property, void* instance) + void DrawArrayValue(p::TypeId type, void* instance) { - UI::Text(Strings::Format("{} items", property.GetSize(instance))); + const ContainerTypeOps* ops = p::GetTypeContainerOps(type); + if (!ops) + { + return; + } + + UI::Text(Strings::Format("{} items", ops->GetSize(instance))); // Ignore indent on buttons const float widthAvailable = @@ -143,12 +140,12 @@ namespace rift::UI UI::PushStyleCompact(); if (UI::Button(ICON_FA_PLUS "##AddItem", v2(16.f, 18.f))) { - property.AddItem(instance, nullptr); + ops->AddItem(instance, nullptr); } UI::SameLine(); if (UI::Button(ICON_FA_TRASH_ALT "##Empty", v2(16.f, 18.f))) { - property.Clear(instance); + ops->Clear(instance); } UI::PopStyleCompact(); } @@ -164,15 +161,15 @@ namespace rift::UI Strings::FormatTo(label, ICON_FA_TIMES "##removeItem_{}", handle.GetIndex()); if (UI::Button(label.c_str(), v2(18.f, 18.f))) { - handle.GetArrayProperty()->RemoveItem(handle.GetContainerPtr(), handle.GetIndex()); + // handle.GetArrayProperty()->RemoveItem(handle.GetContainerPtr(), handle.GetIndex()); } UI::PopStyleCompact(); } void InspectProperty(const ValueHandle& handle) { - auto* type = handle.GetType(); - if (!type) + p::TypeId type = handle.GetType(); + if (!type.IsValid()) { return; } @@ -180,14 +177,17 @@ namespace rift::UI void* instance = handle.GetPtr(); UI::PushID(instance); + String displayName; + handle.GetDisplayName(displayName); + bool isLeaf = false; if (handle.IsArray()) { - isLeaf = handle.GetArrayProperty()->GetSize(instance) > 0; + // isLeaf = handle.GetArrayProperty()->GetSize(instance) > 0; } else if (auto* custom = gCustomKeyValues.Find(type)) { - (*custom)(handle.GetDisplayName(), instance, type); + (*custom)(displayName, instance, type); if (handle.IsArrayItem()) { DrawArrayItemButtons(handle); @@ -195,13 +195,13 @@ namespace rift::UI UI::PopID(); return; } - else if (auto* structType = Cast(type)) + else if (p::HasTypeFlags(type, p::TF_Struct)) { - isLeaf = !structType->IsEmpty(); + isLeaf = !GetTypeProperties(type).IsEmpty(); } else { - DrawKeyValue(handle.GetDisplayName(), instance, type); + DrawKeyValue(displayName, instance, type); if (handle.IsArrayItem()) { DrawArrayItemButtons(handle); @@ -210,12 +210,12 @@ namespace rift::UI return; } - bool bOpen = BeginCategory(handle.GetDisplayName(), isLeaf); + bool bOpen = BeginCategory(displayName, isLeaf); if (handle.IsArray()) { - UI::TableSetColumnIndex(1); - DrawArrayValue(*handle.GetArrayProperty(), instance); + // UI::TableSetColumnIndex(1); + // DrawArrayValue(*handle.GetArrayProperty(), instance); } if (bOpen) @@ -234,31 +234,30 @@ namespace rift::UI return; } - const auto* type = handle.GetType(); - if (!type) + const p::TypeId type = handle.GetType(); + if (!type.IsValid()) { return; } - if (auto* structType = Cast(type)) + if (p::HasTypeFlags(type, TF_Struct)) { - void* instance = handle.GetPtr(); - TArray properties; - structType->GetProperties(properties); - for (auto* prop : properties) + void* instance = handle.GetPtr(); + p::TView properties = p::GetTypeProperties(type); + for (const auto& prop : properties) { - InspectProperty({instance, prop}); + InspectProperty({instance, type, prop}); } } else if (handle.IsArray()) { - auto* arrayProperty = handle.GetArrayProperty(); - void* instance = handle.GetPtr(); - const i32 size = arrayProperty->GetSize(instance); - for (i32 i = 0; i < size; ++i) - { - InspectProperty({handle, i}); - } + // auto* arrayProperty = handle.GetArrayProperty(); + // void* instance = handle.GetPtr(); + // const i32 size = arrayProperty->GetSize(instance); + // for (i32 i = 0; i < size; ++i) + //{ + // InspectProperty({handle, i}); + // } } } @@ -325,12 +324,12 @@ namespace rift::UI void RegisterCoreKeyValueInspections() { - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { DrawColorKeyValue(label, *reinterpret_cast(data), ImGuiColorEditFlags_Float | ImGuiColorEditFlags_AlphaPreviewHalf); }); - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { auto* color = reinterpret_cast(data); LinearColor lColor{*color}; if (DrawColorKeyValue(label, lColor, @@ -341,7 +340,7 @@ namespace rift::UI } }); - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { auto* color = reinterpret_cast(data); LinearColor lColor{*color}; if (DrawColorKeyValue(label, lColor, @@ -352,7 +351,7 @@ namespace rift::UI } }); - UI::RegisterCustomInspection([](StringView label, void* data, Type* type) { + UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { auto* path = reinterpret_cast(data); UI::TableNextRow(); UI::TableSetColumnIndex(0); diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index a9edb24c..c756d682 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -8,11 +8,12 @@ #include #include #include +#include #include #include -#include #include #include +#include namespace rift::UI diff --git a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h index 583361bb..4ec60cbf 100644 --- a/Libs/Views/Graph/Compiler/Include/GraphViewModule.h +++ b/Libs/Views/Graph/Compiler/Include/GraphViewModule.h @@ -13,7 +13,9 @@ namespace rift { class GraphViewModule : public Module { - P_CLASS(GraphViewModule, Module) + public: + using Super = Module; + P_CLASS(GraphViewModule) public: void Load() override; diff --git a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h index 050193de..d4c4bfdf 100644 --- a/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h +++ b/Libs/Views/Graph/Editor/Include/GraphViewEditorModule.h @@ -9,6 +9,8 @@ namespace rift { class GraphViewEditorModule : public Module { - P_CLASS(GraphViewEditorModule, Module) + public: + using Super = Module; + P_CLASS(GraphViewEditorModule) }; } // namespace rift diff --git a/imgui.ini b/imgui.ini index c3e27ceb..446db75d 100644 --- a/imgui.ini +++ b/imgui.ini @@ -4,8 +4,8 @@ Size=400,400 Collapsed=0 [Window][Project Manager] -Pos=340,364 -Size=600,171 +Pos=340,355 +Size=600,189 Collapsed=0 [Window][##Notification_0] From 21f84199af9d5e918b1d50d1510a479f2f5e8a93 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 22 May 2024 00:15:09 +0200 Subject: [PATCH 39/52] Added ECS & reflection debugging from Pipe --- Extern/Pipe | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 4 - .../Editor/Include/Tools/ReflectionDebugger.h | 5 +- Libs/Editor/Src/Systems/EditorSystem.cpp | 5 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 220 +----------------- Libs/Editor/Src/Tools/ReflectionDebugger.cpp | 104 +-------- Libs/Editor/Src/Utils/EditorStyle.cpp | 4 +- Libs/Editor/Src/Utils/ElementsPanel.cpp | 4 +- Libs/Editor/Src/Utils/FunctionGraph.cpp | 14 +- Libs/UI/Include/UI/Inspection.h | 40 ++-- Libs/UI/Include/UI/Notify.h | 6 +- Libs/UI/Include/UI/Style.h | 25 -- Libs/UI/Include/UI/UIImgui.h | 115 +-------- Libs/UI/Include/UI/Widgets.h | 29 +-- Libs/UI/Src/Inspection.cpp | 104 +++++---- Libs/UI/Src/Notify.cpp | 54 ++--- Libs/UI/Src/Style.cpp | 100 ++------ Libs/UI/Src/UIImgui.cpp | 6 + Libs/UI/Src/Widgets.cpp | 44 ++-- Libs/UI/Src/Window.cpp | 4 +- 20 files changed, 208 insertions(+), 681 deletions(-) create mode 100644 Libs/UI/Src/UIImgui.cpp diff --git a/Extern/Pipe b/Extern/Pipe index 6cd31e3a..cded2de0 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 6cd31e3adc96e39bb11ff87f13d99e7b28254f4f +Subproject commit cded2de079206210766d76ce990bfcc0b01feaf6 diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 31eeb95e..68c90b4c 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -47,10 +47,6 @@ namespace rift::editor void Draw(ast::Tree& ast); private: - using DrawNodeAccess = - p::TAccessRef; - void DrawNode(DrawNodeAccess access, ast::Id nodeId, bool showChildren); - void OnInspectEntity(ast::Id id); void DrawEntityInspector(p::StringView label, p::StringView id, ast::Tree& ast, diff --git a/Libs/Editor/Include/Tools/ReflectionDebugger.h b/Libs/Editor/Include/Tools/ReflectionDebugger.h index 8d00ce83..a6c2bcff 100644 --- a/Libs/Editor/Include/Tools/ReflectionDebugger.h +++ b/Libs/Editor/Include/Tools/ReflectionDebugger.h @@ -23,9 +23,6 @@ namespace rift::editor ReflectionDebugger(); - void Draw(); - - private: - void DrawType(TypeId type); + void Draw(ast::Tree& ast); }; } // namespace rift::editor diff --git a/Libs/Editor/Src/Systems/EditorSystem.cpp b/Libs/Editor/Src/Systems/EditorSystem.cpp index 6a014312..85fdd95e 100644 --- a/Libs/Editor/Src/Systems/EditorSystem.cpp +++ b/Libs/Editor/Src/Systems/EditorSystem.cpp @@ -241,7 +241,7 @@ namespace rift::editor::EditorSystem DrawModuleEditors(ast, editor); DrawTypes(ast, editor); - editor.reflectionDebugger.Draw(); + editor.reflectionDebugger.Draw(ast); editor.ASTDebugger.Draw(ast); editor.memoryDebugger.Draw(); editor.fileExplorer.Draw(ast); @@ -356,7 +356,8 @@ namespace rift::editor::EditorSystem if (UI::BeginMenu("Debug")) { UI::MenuItem("Reflection", nullptr, &editorData.reflectionDebugger.open); - UI::MenuItem("Abstract Syntax Tree", nullptr, &editorData.ASTDebugger.open); + UI::MenuItem( + " " ICON_FA_BUG " AST Debugger", nullptr, &editorData.ASTDebugger.open); UI::MenuItem("Memory", nullptr, &editorData.memoryDebugger.open); UI::MenuItem("Graph Playground", nullptr, &editorData.graphPlayground.open); UI::EndMenu(); diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 8326ee04..c6d46c49 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -17,7 +17,6 @@ #include -#define P_IMGUI_IMPLEMENTATION #define P_DEBUG_IMPLEMENTATION #include @@ -74,217 +73,14 @@ namespace rift::editor return; } - ImGui::SetNextWindowSize(ImVec2(400, 700), ImGuiCond_FirstUseEver); - UI::Begin(" " ICON_FA_BUG " Abstract Syntax Tree", &open); - - DrawTypesDebug(ast); - - if (UI::CollapsingHeader("Nodes")) - { - if (ImGui::BeginPopup("Options")) - { - ImGui::Checkbox("Show hierarchy", &showHierarchy); - ImGui::EndPopup(); - } - - if (UI::Button("Options")) - { - UI::OpenPopup("Options"); - } - UI::SameLine(); - filter.Draw("##Filter", -100.0f); - - - static ImGuiTableFlags flags = ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable - | ImGuiTableFlags_Hideable - | ImGuiTableFlags_SizingStretchProp; - ImGui::BeginChild("nodesTableChild", {0.f, UI::GetContentRegionAvail().y - 20.f}); - if (UI::BeginTable("nodesTable", 5, flags)) - { - UI::TableSetupColumn("", ImGuiTableColumnFlags_IndentDisable - | ImGuiTableColumnFlags_WidthFixed - | ImGuiTableColumnFlags_NoResize); // Inspect - UI::TableSetupColumn( - "Id", ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_IndentEnable); - UI::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 1.f); - UI::TableSetupColumn("Path", - ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide, 1.2f); - UI::TableSetupColumn("Namespace", - ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide, 1.2f); - UI::TableHeadersRow(); - - DrawNodeAccess access{ast}; - if (showHierarchy && !filter.IsActive()) - { - p::TArray roots; - p::GetRootIds(access, roots); - for (auto root : roots) - { - DrawNode(access, root, true); - } - - p::TArray orphans = p::FindAllIdsWith(access); - p::ExcludeIdsWith(access, orphans); - p::ExcludeIdsWith(access, orphans); - for (auto orphan : orphans) - { - DrawNode(access, orphan, true); - } - } - else - { - ast.Each([this, &access](ast::Id id) { - DrawNode(access, id, false); - }); - } - UI::EndTable(); - } - UI::EndChild(); - UI::Separator(); - } - UI::End(); - - // Inspectors - DrawEntityInspector( - " " ICON_FA_LIST_ALT " Inspector", "MainInspector", ast, mainInspector, nullptr); - - - { - static p::ECSDebugContext testContext; - testContext.ctx = * - p::BeginECSDebug(testContext); - static p::ECSDebugInspector testInspector; - testInspector.id = mainInspector.id; - p::DrawEntityInspector("Test", testInspector); - p::EndECSDebug(); - } - - for (p::i32 i = 0; i < secondaryInspectors.Size(); ++i) - { - InspectorPanel& inspector = secondaryInspectors[i]; - if (inspector.open) - { - p::String id = p::Strings::Format("SecondaryInspector{}", i); - p::String name = p::Strings::Format(" " ICON_FA_LIST " Inspector {}", i + 1); - DrawEntityInspector(name, id, ast, inspector, &inspector.open); - } - } - } - - void ASTDebugger::DrawNode(DrawNodeAccess access, ast::Id nodeId, bool showChildren) - { - static p::String idText; - idText.clear(); - if (nodeId == ast::NoId) - { - idText = "No Id"; - } - else if (auto version = p::GetIdVersion(nodeId); version > 0) - { - p::Strings::FormatTo(idText, "{} (v{})", p::GetIdIndex(nodeId), version); - } - else - { - p::Strings::FormatTo(idText, "{}", p::GetIdIndex(nodeId)); - } - - static p::String name; - name.clear(); - if (const auto* id = access.TryGet(nodeId)) - { - name = id->name.AsString(); - } - - static p::String path; - path.clear(); - if (const auto* file = access.TryGet(nodeId)) - { - path = p::ToString(file->path); - - p::StringView filename = p::GetFilename(path); - p::Strings::FormatTo(name, name.empty() ? "file: {}" : " (file: {})", filename); - } - - if (!filter.PassFilter(idText.c_str(), idText.c_str() + idText.size()) - && !filter.PassFilter(name.c_str(), name.c_str() + name.size())) - { - return; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - static p::String inspectLabel; - inspectLabel.clear(); - - const bool inspected = - mainInspector.id == nodeId || secondaryInspectors.Contains(InspectorPanel{nodeId}); - const char* icon = inspected ? ICON_FA_EYE : ICON_FA_EYE_SLASH; - p::Strings::FormatTo(inspectLabel, "{}##{}", icon, nodeId); - UI::PushTextColor(inspected ? UI::whiteTextColor : UI::whiteTextColor.Translucency(0.3f)); - UI::PushButtonColor(UI::GetNeutralColor(1)); - if (UI::Button(inspectLabel.c_str())) - { - OnInspectEntity(nodeId); - } - UI::PopButtonColor(); - UI::PopTextColor(); - - - ImGui::TableNextColumn(); - bool hasChildren; - const ast::CParent* parent = nullptr; - if (showChildren) - { - parent = access.TryGet(nodeId); - hasChildren = parent && !parent->children.IsEmpty(); - } - else - { - hasChildren = false; - } - - bool open = false; - static p::Tag font{"WorkSans"}; - UI::PushFont(font, UI::FontMode::Bold); - if (hasChildren) - { - open = UI::TreeNodeEx(idText.c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - } - else - { - UI::Indent(10.f); - UI::Text(idText); - UI::Unindent(10.f); - } - UI::PopFont(); - - - ImGui::TableNextColumn(); - UI::Text(name); - - - if (ImGui::TableNextColumn()) - { - UI::PushFont("WorkSans", UI::FontMode::Italic); - UI::Text(path); - UI::PopFont(); - } - - if (ImGui::TableNextColumn()) - { - UI::Text(ast::GetParentNamespace(access, nodeId).ToString()); - } - - - if (hasChildren && open) - { - for (ast::Id child : parent->children) - { - DrawNode(access, child, true); - } - - UI::TreePop(); - } + auto& dbgContext = ast.GetOrSetStatic(); + dbgContext.ctx = * + p::BeginDebug(dbgContext); + p::DrawIdRegistry(" " ICON_FA_BUG " AST Debugger", &open); + static p::ECSDebugInspector testInspector; + testInspector.id = mainInspector.id; + p::DrawEntityInspector("Test", testInspector); + p::EndDebug(); } void ASTDebugger::OnInspectEntity(ast::Id id) diff --git a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp index 92e148bc..00d0faf8 100644 --- a/Libs/Editor/Src/Tools/ReflectionDebugger.cpp +++ b/Libs/Editor/Src/Tools/ReflectionDebugger.cpp @@ -2,13 +2,12 @@ #include "Tools/ReflectionDebugger.h" -#include "PipeReflect.h" - #include #include #include #include #include +#include #include #include @@ -17,108 +16,19 @@ namespace rift::editor { ReflectionDebugger::ReflectionDebugger() {} - void ReflectionDebugger::Draw() + void ReflectionDebugger::Draw(ast::Tree& ast) { if (!open) { return; } - UI::Begin("Reflection", &open); - - if (UI::BeginPopup("Filter")) - { - UI::CheckboxFlags("Native", &typeFlagsFilter, u64(p::TF_Native)); - UI::CheckboxFlags("Enum", &typeFlagsFilter, u64(p::TF_Enum)); - UI::CheckboxFlags("Struct", &typeFlagsFilter, u64(p::TF_Struct)); - UI::CheckboxFlags("Object", &typeFlagsFilter, u64(p::TF_Object)); - UI::CheckboxFlags("Container", &typeFlagsFilter, u64(p::TF_Container)); - UI::EndPopup(); - } - if (UI::Button("Filter")) - { - UI::OpenPopup("Filter"); - } - - UI::SameLine(); - filter.Draw("##Filter", -100.0f); - - - static ImGuiTableFlags flags = ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable - | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingStretchProp; - ImGui::BeginChild("typesTableChild", ImVec2(0.f, UI::GetContentRegionAvail().y)); - if (UI::BeginTable("typesTable", 4, flags)) - { - UI::TableSetupColumn("Id", ImGuiTableColumnFlags_IndentEnable); - UI::TableSetupColumn("Name"); - UI::TableSetupColumn("Flags"); - UI::TableSetupColumn("Parent"); - UI::TableHeadersRow(); - - for (p::TypeId type : p::GetRegisteredTypeIds()) - { - DrawType(type); - } - UI::EndTable(); - } - UI::EndChild(); - - UI::End(); - } - - void ReflectionDebugger::DrawType(TypeId type) - { - if (!HasAnyTypeFlags(type, typeFlagsFilter)) - { - return; - } - - static String idText; - idText.clear(); - Strings::FormatTo(idText, "{}", type); - - StringView rawName = p::GetTypeName(type); - if (!filter.PassFilter(idText.c_str(), idText.c_str() + idText.size()) - && !filter.PassFilter(rawName.data(), rawName.data() + rawName.size())) - { - return; - } - - UI::TableNextRow(); - - UI::TableSetColumnIndex(0); // Id - UI::Text(idText); - - UI::TableSetColumnIndex(1); // Name - StringView ns; - StringView name = p::RemoveNamespace(rawName, ns); - UI::PushStyleCompact(); - UI::PushTextColor(UI::GetNeutralTextColor(1).Shade(0.3f)); - UI::Text(ns); - UI::PopTextColor(); - UI::PopStyleCompact(); - UI::SameLine(0, 10.f); - UI::Text(name); - - UI::TableSetColumnIndex(2); // Flags - static String flags; - flags.clear(); - GetEnumFlagName(TypeFlags_(GetTypeFlags(type)), flags); - UI::Text(flags); - - TypeId parentId = p::GetTypeParent(type); - if (parentId.IsValid()) + auto& dbgContext = ast.GetOrSetStatic(); + dbgContext.ctx = * + if (p::BeginDebug(dbgContext)) { - UI::TableSetColumnIndex(3); // Parent - rawName = p::GetTypeName(parentId); - name = p::RemoveNamespace(rawName, ns); - UI::PushStyleCompact(); - UI::PushTextColor(UI::GetNeutralTextColor(1).Shade(0.3f)); - UI::Text(ns); - UI::PopTextColor(); - UI::PopStyleCompact(); - UI::SameLine(0, 10.f); - UI::Text(name); + p::DrawReflection("Reflection", &open); + p::EndDebug(); } } } // namespace rift::editor diff --git a/Libs/Editor/Src/Utils/EditorStyle.cpp b/Libs/Editor/Src/Utils/EditorStyle.cpp index 9d6cbb93..271fbe1c 100644 --- a/Libs/Editor/Src/Utils/EditorStyle.cpp +++ b/Libs/Editor/Src/Utils/EditorStyle.cpp @@ -58,7 +58,7 @@ namespace rift::editor void PushNodeTitleColor(Color color) { Nodes::PushStyleColor(Nodes::ColorVar_TitleBar, color); - Nodes::PushStyleColor(Nodes::ColorVar_TitleBarHovered, UI::Hovered(color)); + Nodes::PushStyleColor(Nodes::ColorVar_TitleBarHovered, UI::ToHovered(color)); Nodes::PushStyleColor(Nodes::ColorVar_TitleBarSelected, color); } @@ -70,7 +70,7 @@ namespace rift::editor void PushNodeBackgroundColor(Color color) { Nodes::PushStyleColor(Nodes::ColorVar_NodeBackground, color); - Nodes::PushStyleColor(Nodes::ColorVar_NodeBackgroundHovered, UI::Hovered(color)); + Nodes::PushStyleColor(Nodes::ColorVar_NodeBackgroundHovered, UI::ToHovered(color)); Nodes::PushStyleColor(Nodes::ColorVar_NodeBackgroundSelected, color); } diff --git a/Libs/Editor/Src/Utils/ElementsPanel.cpp b/Libs/Editor/Src/Utils/ElementsPanel.cpp index 98d90777..657d9535 100644 --- a/Libs/Editor/Src/Utils/ElementsPanel.cpp +++ b/Libs/Editor/Src/Utils/ElementsPanel.cpp @@ -75,7 +75,7 @@ namespace rift::editor } else if (UI::IsItemHovered()) { - bgColor = UI::Hovered(color); + bgColor = UI::ToHovered(color); } UI::RenderFrame(bb.Min, bb.Max, bgColor.DWColor(), false, 2.f); @@ -180,7 +180,7 @@ namespace rift::editor p::GetIdChildren(access, typeId, variableIds); ExcludeIdsWithout(access, variableIds); - UI::PushStyleVar(ImGuiStyleVar_CellPadding, {1.f, 3.f}); + UI::PushStyleVar(ImGuiStyleVar_CellPadding, p::v2{1.f, 3.f}); bool showTable = UI::BeginTable("##variableTable", 3, ImGuiTableFlags_SizingFixedFit); UI::PopStyleVar(); if (showTable) diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 8e59c494..46ea0b74 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -84,7 +84,7 @@ namespace rift::editor::Graph } Nodes::PushStyleColor(Nodes::ColorVar_Pin, pinColor); - Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::Hovered(pinColor)); + Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::ToHovered(pinColor)); Nodes::BeginInput( i32(id), isPointer ? Nodes::PinShape_DiamondFilled : Nodes::PinShape_CircleFilled); @@ -112,7 +112,7 @@ namespace rift::editor::Graph } Nodes::PushStyleColor(Nodes::ColorVar_Pin, pinColor); - Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::Hovered(pinColor)); + Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::ToHovered(pinColor)); Nodes::BeginOutput( i32(id), isPointer ? Nodes::PinShape_DiamondFilled : Nodes::PinShape_CircleFilled); @@ -214,7 +214,7 @@ namespace rift::editor::Graph { static constexpr Color color = executionColor; Nodes::PushStyleColor(Nodes::ColorVar_Pin, color); - Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::Hovered(color)); + Nodes::PushStyleColor(Nodes::ColorVar_PinHovered, UI::ToHovered(color)); } void PopExecutionPinStyle() @@ -494,9 +494,9 @@ namespace rift::editor::Graph const float padding = (settings.GetSpaceHeight(1) - GImGui->FontSize) * 0.5f - settings.verticalPadding; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {style.FramePadding.x, padding}); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, p::v2{style.FramePadding.x, padding}); ImGui::PushStyleVar( - ImGuiStyleVar_ItemSpacing, {style.ItemSpacing.x, settings.verticalPadding}); + ImGuiStyleVar_ItemSpacing, p::v2{style.ItemSpacing.x, settings.verticalPadding}); } void PopInnerNodeStyle() @@ -720,7 +720,7 @@ namespace rift::editor::Graph { Nodes::PushStyleVar(Nodes::StyleVar_LinkThickness, 2.f); Nodes::PushStyleColor(Nodes::ColorVar_Link, executionColor); - Nodes::PushStyleColor(Nodes::ColorVar_LinkHovered, UI::Hovered(executionColor)); + Nodes::PushStyleColor(Nodes::ColorVar_LinkHovered, UI::ToHovered(executionColor)); Nodes::PushStyleColor(Nodes::ColorVar_LinkSelected, selectedColor); for (ast::Id outputId : FindIdsWith(access, children)) @@ -800,7 +800,7 @@ namespace rift::editor::Graph } Nodes::PushStyleColor(Nodes::ColorVar_Link, color); - Nodes::PushStyleColor(Nodes::ColorVar_LinkHovered, UI::Hovered(color)); + Nodes::PushStyleColor(Nodes::ColorVar_LinkHovered, UI::ToHovered(color)); Nodes::Link(i32(inputId), i32(output.pinId), i32(inputId)); diff --git a/Libs/UI/Include/UI/Inspection.h b/Libs/UI/Include/UI/Inspection.h index 2d997fe2..98947262 100644 --- a/Libs/UI/Include/UI/Inspection.h +++ b/Libs/UI/Include/UI/Inspection.h @@ -15,42 +15,42 @@ namespace rift::UI { protected: void* container = nullptr; - TypeId containerType; - const TypeProperty* property = nullptr; - i32 index = NO_INDEX; + p::TypeId containerType; + const p::TypeProperty* property = nullptr; + p::i32 index = p::NO_INDEX; public: - ValueHandle(void* container, TypeId containerType) + ValueHandle(void* container, p::TypeId containerType) : container{container}, containerType{containerType} {} - ValueHandle(void* container, TypeId containerType, const TypeProperty& property) + ValueHandle(void* container, p::TypeId containerType, const p::TypeProperty& property) : container{container}, containerType{containerType}, property{&property} {} - ValueHandle(void* data, const TypeProperty* property, i32 index) + ValueHandle(void* data, const p::TypeProperty* property, p::i32 index) : container{data}, property{property}, index{index} { // P_Check(GetArrayProperty()); } - ValueHandle(const ValueHandle& container, i32 index) + ValueHandle(const ValueHandle& container, p::i32 index) : ValueHandle(container.GetPtr(), container.GetProperty(), index) {} ValueHandle(const ValueHandle& other) = default; ValueHandle& operator=(const ValueHandle& other) = default; - const TypeProperty* GetProperty() const + const p::TypeProperty* GetProperty() const { return property; } bool IsArray() const { - return !IsArrayItem() && property && property->HasFlag(PF_Array); + return !IsArrayItem() && property && property->HasFlag(p::PF_Array); } bool IsArrayItem() const { - return index != NO_INDEX; + return index != p::NO_INDEX; } // const ArrayProperty* GetArrayProperty() const @@ -62,30 +62,30 @@ namespace rift::UI // return nullptr; // } - virtual void GetDisplayName(String& name) const + virtual void GetDisplayName(p::String& name) const { - if (index != NO_INDEX) + if (index != p::NO_INDEX) { - Strings::FormatTo(name, "{}", index); + p::Strings::FormatTo(name, "{}", index); } else if (property) { - name.append(Strings::ToSentenceCase(property->name.AsString())); + name.append(p::Strings::ToSentenceCase(property->name.AsString())); } } - TypeId GetType() const + p::TypeId GetType() const { return containerType; } void* GetContainer() const { - P_Check(index != NO_INDEX); + P_Check(index != p::NO_INDEX); return container; } - i32 GetIndex() const + p::i32 GetIndex() const { return index; } @@ -112,14 +112,14 @@ namespace rift::UI }; - using CustomKeyValue = TFunction; + using CustomKeyValue = p::TFunction; void RegisterCustomInspection(p::TypeId type, const CustomKeyValue& custom); template void RegisterCustomInspection(const CustomKeyValue& custom) { - RegisterCustomInspection(GetTypeId(), custom); + RegisterCustomInspection(p::GetTypeId(), custom); } void DrawEnumValue(void* data, p::TypeId type); @@ -131,7 +131,7 @@ namespace rift::UI inline void InspectStruct(void* data, p::TypeId type) { - if (p::HasTypeFlags(type, TF_Struct)) + if (p::HasTypeFlags(type, p::TF_Struct)) { InspectChildrenProperties({data, type}); } diff --git a/Libs/UI/Include/UI/Notify.h b/Libs/UI/Include/UI/Notify.h index 46016c4d..6b882032 100644 --- a/Libs/UI/Include/UI/Notify.h +++ b/Libs/UI/Include/UI/Notify.h @@ -9,7 +9,7 @@ namespace rift::UI { - enum class ToastType : u8 + enum class ToastType : p::u8 { None = 0, Success, @@ -22,8 +22,8 @@ namespace rift::UI { ToastType type = ToastType::None; float durationTime = 3.f; - String title; - String message; + p::String title; + p::String message; }; void AddNotification(Toast toast); diff --git a/Libs/UI/Include/UI/Style.h b/Libs/UI/Include/UI/Style.h index a9bd216d..5a7266de 100644 --- a/Libs/UI/Include/UI/Style.h +++ b/Libs/UI/Include/UI/Style.h @@ -70,29 +70,4 @@ namespace rift::UI void PushGeneralStyle(); void PopGeneralStyle(); - - void PushStyleCompact(); - void PopStyleCompact(); - - void PushFrameBgColor(p::LinearColor color); - void PopFrameBgColor(); - void PushButtonColor(p::LinearColor color); - void PopButtonColor(); - void PushHeaderColor(p::LinearColor color = GetNeutralColor(2)); - void PopHeaderColor(); - - void PushTextColor(p::LinearColor color); - void PopTextColor(); - - template - p::TColor Hovered(const p::TColor& color) - { - return color.Shade(0.1f); - } - - template - p::TColor Disabled(const p::TColor& color) - { - return color.Shade(0.2f); - } }; // namespace rift::UI diff --git a/Libs/UI/Include/UI/UIImgui.h b/Libs/UI/Include/UI/UIImgui.h index e16a8d91..a91d5e17 100644 --- a/Libs/UI/Include/UI/UIImgui.h +++ b/Libs/UI/Include/UI/UIImgui.h @@ -7,11 +7,12 @@ #include -#define IM_VEC2_CLASS_EXTRA \ - constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) {} \ - constexpr operator p::v2() const \ - { \ - return p::v2{x, y}; \ +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(p::v2 other) : x(other.x), y(other.y) \ + {} \ + constexpr operator p::v2() const \ + { \ + return p::v2{x, y}; \ } #define IM_VEC4_CLASS_EXTRA \ @@ -21,7 +22,8 @@ { \ return p::LinearColor{x, y, z, w}; \ } \ - constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) {} \ + constexpr ImVec4(const p::v4& other) : x(other.x), y(other.y), z(other.z), w(other.w) \ + {} \ constexpr operator p::v4() const \ { \ return p::v4{x, y, z, w}; \ @@ -31,109 +33,10 @@ #define IMGUI_DEFINE_MATH_OPERATORS #include #include +#include namespace rift::UI { - using namespace p; using namespace ImGui; - - // Begin ImGui API override - // Push string into the ID stack (will hash string) - inline void PushID(const char* str_id) - { - ImGui::PushID(str_id); - } - // Push string into the ID stack (will hash string) - inline void PushID(const char* str_id_begin, const char* str_id_end) - { - ImGui::PushID(str_id_begin, str_id_end); - } - // Push pointer into the ID stack (will hash pointer) - inline void PushID(const void* ptr_id) - { - ImGui::PushID(ptr_id); - } - - inline ImGuiID GetID(const char* str_id) - { - return ImGui::GetID(str_id); - } - inline ImGuiID GetID(const char* str_id_begin, const char* str_id_end) - { - return ImGui::GetID(str_id_begin, str_id_end); - } - inline ImGuiID GetID(const void* ptr_id) - { - return ImGui::GetID(ptr_id); - } - inline void PushStyleColor(ImGuiCol idx, u32 col) - { - ImGui::PushStyleColor(idx, col); - } - inline void PushStyleColor(ImGuiCol idx, const ImVec4& col) - { - ImGui::PushStyleColor(idx, col); - } - // End ImGui API override - - - inline void PushID(StringView id) - { - UI::PushID(id.data(), id.data() + id.size()); - } - - template - inline void PushID(T id) - { - UI::PushID(reinterpret_cast(sizet(id))); - } - - inline ImGuiID GetID(StringView id) - { - return UI::GetID(id.data(), id.data() + id.size()); - } - - inline void PushStyleColor(ImGuiCol idx, Color color) - { - ImGui::PushStyleColor(idx, color.DWColor()); - } - - inline void PushStyleColor(ImGuiCol idx, const LinearColor& color) - { - ImGui::PushStyleColor(idx, color); - } - - inline void Text(const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - TextV(fmt, args); - va_end(args); - } - inline void Text(StringView text) - { - TextUnformatted(text.data(), text.data() + text.size()); - } - - inline void TextColoredUnformatted( - const LinearColor& color, const char* text, const char* textEnd = nullptr) - { - PushStyleColor(ImGuiCol_Text, color); - TextUnformatted(text, textEnd); - PopStyleColor(); - } - - inline void TextColored(const LinearColor& color, const char* fmt, ...) - { - va_list args; - va_start(args, fmt); - TextColoredV(ImVec4(color), fmt, args); - va_end(args); - } - inline void TextColored(const LinearColor& color, StringView text) - { - TextColoredUnformatted(color, text.data(), text.data() + text.size()); - } - } // namespace rift::UI diff --git a/Libs/UI/Include/UI/Widgets.h b/Libs/UI/Include/UI/Widgets.h index a1067b47..6cf61698 100644 --- a/Libs/UI/Include/UI/Widgets.h +++ b/Libs/UI/Include/UI/Widgets.h @@ -15,23 +15,23 @@ namespace rift::UI struct AnimatedSprite { ImTextureID textureId; - v2 size{}; + p::v2 size{}; float rate = 1.f / 24.f; // Number of frames in each row - TArray numFrames{}; + p::TArray numFrames{}; - v2_u32 currentFrame{}; + p::v2_u32 currentFrame{}; float currentFrameRemainingTime = 0.f; - void SetAnimation(u32 id); + void SetAnimation(p::u32 id); void NextFrame(float deltaTime); - v2 GetUV() const; + p::v2 GetUV() const; }; - static bool SpriteButton(AnimatedSprite& sprite, i32 framePadding, const LinearColor& bgColor, - const LinearColor& tintColor); + static bool SpriteButton(AnimatedSprite& sprite, p::i32 framePadding, + const p::LinearColor& bgColor, const p::LinearColor& tintColor); inline bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, @@ -59,24 +59,24 @@ namespace rift::UI bool InputTextMultiline(const char* label, p::String& str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* userData = nullptr); - bool InputTextWithHint(const char* label, const char* hint, String& str, + bool InputTextWithHint(const char* label, const char* hint, p::String& str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* userData = nullptr); static void BeginOuterStyle() { - LinearColor titleColor = UI::GetNeutralColor(0); + p::LinearColor titleColor = UI::GetNeutralColor(0); UI::PushStyleColor(ImGuiCol_TitleBg, titleColor); UI::PushStyleColor(ImGuiCol_TitleBgActive, titleColor); - UI::PushStyleColor(ImGuiCol_TitleBgCollapsed, UI::Disabled(titleColor)); + UI::PushStyleColor(ImGuiCol_TitleBgCollapsed, UI::ToDisabled(titleColor)); - LinearColor tabColorActive = UI::GetNeutralColor(1); - LinearColor tabColor = UI::Disabled(tabColorActive); + p::LinearColor tabColorActive = UI::GetNeutralColor(1); + p::LinearColor tabColor = UI::ToDisabled(tabColorActive); UI::PushStyleColor(ImGuiCol_Tab, tabColor); UI::PushStyleColor(ImGuiCol_TabActive, tabColorActive); UI::PushStyleColor(ImGuiCol_TabUnfocused, tabColor); UI::PushStyleColor(ImGuiCol_TabUnfocusedActive, tabColorActive); - UI::PushStyleColor(ImGuiCol_TabHovered, UI::Hovered(tabColorActive)); + UI::PushStyleColor(ImGuiCol_TabHovered, UI::ToHovered(tabColorActive)); UI::PushTextColor(UI::GetNeutralTextColor(1)); } static void BeginInnerStyle() @@ -108,7 +108,8 @@ namespace rift::UI EndOuterStyle(); } - ImRect GetWorkRect(v2 desiredSize, bool addhalfItemSpacing = true, v2 extent = v2::Zero()); + ImRect GetWorkRect( + p::v2 desiredSize, bool addhalfItemSpacing = true, p::v2 extent = p::v2::Zero()); bool MutableText(p::StringView label, p::String& text, ImGuiInputTextFlags flags = 0); diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 456df70e..61f5d3a1 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -14,7 +14,7 @@ namespace rift::UI { static const char* gCurrentInspector = nullptr; - static TMap gCustomKeyValues; + static p::TMap gCustomKeyValues; void RegisterCustomInspection(p::TypeId type, const CustomKeyValue& custom) @@ -27,9 +27,9 @@ namespace rift::UI void DrawEnumValue(void* data, p::TypeId type) { - static String label; + static p::String label; label.clear(); - Strings::FormatTo(label, "##{}", sizet(data)); + p::Strings::FormatTo(label, "##{}", p::sizet(data)); /* const i32 currentIndex = type->GetIndexFromValue(data); if (UI::BeginCombo(label.c_str(), type->GetNameByIndex(currentIndex).AsString().data())) @@ -56,68 +56,68 @@ namespace rift::UI void DrawNativeValue(void* data, p::TypeId type) { - static String label; + static p::String label; label.clear(); - Strings::FormatTo(label, "##{}", sizet(data)); + p::Strings::FormatTo(label, "##{}", p::sizet(data)); switch (type.GetId()) { - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::Checkbox(label.c_str(), static_cast(data)); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_U8, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_S32, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_U32, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_S64, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_U64, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_Float, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputScalar(label.c_str(), ImGuiDataType_Double, data); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputFloat2(label.c_str(), static_cast(data)); break; - case GetTypeId().GetId(): + case p::GetTypeId().GetId(): UI::InputFloat3(label.c_str(), static_cast(data)); break; - case GetTypeId().GetId(): - UI::InputText(label.c_str(), *static_cast(data)); + case p::GetTypeId().GetId(): + UI::InputText(label.c_str(), *static_cast(data)); break; - case GetTypeId().GetId(): { - Tag& name = *static_cast(data); - String text{name.AsString()}; + case p::GetTypeId().GetId(): { + auto& name = *static_cast(data); + p::String text{name.AsString()}; if (UI::InputText(label.c_str(), text)) { - name = Tag{text}; + name = p::Tag{text}; } } } } - void DrawKeyValue(StringView label, void* data, p::TypeId type) + void DrawKeyValue(p::StringView label, void* data, p::TypeId type) { UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); UI::Text(label); UI::TableSetColumnIndex(1); - if (p::HasTypeFlags(type, TF_Native)) + if (p::HasTypeFlags(type, p::TF_Native)) { DrawNativeValue(data, type); } - else if (p::HasTypeFlags(type, TF_Enum)) + else if (p::HasTypeFlags(type, p::TF_Enum)) { DrawEnumValue(data, type); } @@ -125,25 +125,25 @@ namespace rift::UI void DrawArrayValue(p::TypeId type, void* instance) { - const ContainerTypeOps* ops = p::GetTypeContainerOps(type); + const p::ContainerTypeOps* ops = p::GetTypeContainerOps(type); if (!ops) { return; } - UI::Text(Strings::Format("{} items", ops->GetSize(instance))); + UI::Text(p::Strings::Format("{} items", ops->GetSize(instance))); // Ignore indent on buttons const float widthAvailable = ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; UI::SameLine(widthAvailable - 50.f); UI::PushStyleCompact(); - if (UI::Button(ICON_FA_PLUS "##AddItem", v2(16.f, 18.f))) + if (UI::Button(ICON_FA_PLUS "##AddItem", p::v2(16.f, 18.f))) { ops->AddItem(instance, nullptr); } UI::SameLine(); - if (UI::Button(ICON_FA_TRASH_ALT "##Empty", v2(16.f, 18.f))) + if (UI::Button(ICON_FA_TRASH_ALT "##Empty", p::v2(16.f, 18.f))) { ops->Clear(instance); } @@ -156,10 +156,10 @@ namespace rift::UI ImGui::GetContentRegionAvail().x + UI::GetCurrentWindow()->DC.Indent.x; UI::SameLine(widthAvailable - 50.f); UI::PushStyleCompact(); - static String label; + static p::String label; label.clear(); - Strings::FormatTo(label, ICON_FA_TIMES "##removeItem_{}", handle.GetIndex()); - if (UI::Button(label.c_str(), v2(18.f, 18.f))) + p::Strings::FormatTo(label, ICON_FA_TIMES "##removeItem_{}", handle.GetIndex()); + if (UI::Button(label.c_str(), p::v2(18.f, 18.f))) { // handle.GetArrayProperty()->RemoveItem(handle.GetContainerPtr(), handle.GetIndex()); } @@ -177,7 +177,7 @@ namespace rift::UI void* instance = handle.GetPtr(); UI::PushID(instance); - String displayName; + p::String displayName; handle.GetDisplayName(displayName); bool isLeaf = false; @@ -240,10 +240,10 @@ namespace rift::UI return; } - if (p::HasTypeFlags(type, TF_Struct)) + if (p::HasTypeFlags(type, p::TF_Struct)) { - void* instance = handle.GetPtr(); - p::TView properties = p::GetTypeProperties(type); + void* instance = handle.GetPtr(); + p::TView properties = p::GetTypeProperties(type); for (const auto& prop : properties) { InspectProperty({instance, type, prop}); @@ -261,7 +261,7 @@ namespace rift::UI } } - bool BeginCategory(StringView name, bool isLeaf) + bool BeginCategory(p::StringView name, bool isLeaf) { UI::TableNextRow(); UI::TableSetColumnIndex(0); @@ -279,7 +279,7 @@ namespace rift::UI UI::TreePop(); } - bool BeginInspector(const char* label, v2 size) + bool BeginInspector(const char* label, p::v2 size) { if (!P_EnsureMsg(!gCurrentInspector, "Called BeginInspector() twice without calling EndInspector() first.")) @@ -310,7 +310,7 @@ namespace rift::UI } - bool DrawColorKeyValue(StringView label, LinearColor& color, ImGuiColorEditFlags flags) + bool DrawColorKeyValue(p::StringView label, p::LinearColor& color, ImGuiColorEditFlags flags) { auto* data = reinterpret_cast(&color); // LinearColor* can be interpreted as float* @@ -324,42 +324,44 @@ namespace rift::UI void RegisterCoreKeyValueInspections() { - UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { - DrawColorKeyValue(label, *reinterpret_cast(data), + UI::RegisterCustomInspection( + [](p::StringView label, void* data, p::TypeId type) { + DrawColorKeyValue(label, *reinterpret_cast(data), ImGuiColorEditFlags_Float | ImGuiColorEditFlags_AlphaPreviewHalf); }); - UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { - auto* color = reinterpret_cast(data); - LinearColor lColor{*color}; + UI::RegisterCustomInspection( + [](p::StringView label, void* data, p::TypeId type) { + auto* color = reinterpret_cast(data); + p::LinearColor lColor{*color}; if (DrawColorKeyValue(label, lColor, ImGuiColorEditFlags_Float | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_AlphaPreviewHalf)) { - *color = HSVColor{lColor}; + *color = p::HSVColor{lColor}; } }); - UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { - auto* color = reinterpret_cast(data); - LinearColor lColor{*color}; + UI::RegisterCustomInspection([](p::StringView label, void* data, p::TypeId type) { + auto* color = reinterpret_cast(data); + p::LinearColor lColor{*color}; if (DrawColorKeyValue(label, lColor, ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_AlphaPreviewHalf)) { - *color = Color{lColor}; + *color = p::Color{lColor}; } }); - UI::RegisterCustomInspection([](StringView label, void* data, p::TypeId type) { - auto* path = reinterpret_cast(data); + UI::RegisterCustomInspection([](p::StringView label, void* data, p::TypeId type) { + auto* path = reinterpret_cast(data); UI::TableNextRow(); UI::TableSetColumnIndex(0); UI::AlignTextToFramePadding(); UI::Text(label); UI::TableSetColumnIndex(1); UI::SetNextItemWidth(p::Min(300.f, UI::GetContentRegionAvail().x)); - String str = ToString(*path); + p::String str = p::ToString(*path); if (UI::InputText("##value", str)) { *path = p::ToSTDPath(str); diff --git a/Libs/UI/Src/Notify.cpp b/Libs/UI/Src/Notify.cpp index 7a5b32d6..f6a7f64a 100644 --- a/Libs/UI/Src/Notify.cpp +++ b/Libs/UI/Src/Notify.cpp @@ -18,14 +18,14 @@ namespace rift::UI { struct Notification { - enum class Phase : u8 + enum class Phase : p::u8 { FadeIn, Wait, FadeOut, Expired }; - enum class Corner : u8 + enum class Corner : p::u8 { TopLeft, TopRight, @@ -35,12 +35,12 @@ namespace rift::UI Toast toast; - DateTime creationTime = DateTime::Now(); + p::DateTime creationTime = p::DateTime::Now(); static constexpr float opacity = 1.f; static constexpr float fadeInDuration = 0.1f; static constexpr float fadeOutDuration = 0.15f; - static constexpr v2 padding{20.f, 20.f}; + static constexpr p::v2 padding{20.f, 20.f}; static constexpr Corner corner = Corner::BottomRight; static constexpr float separationY = 10.f; // Padding between notifications static constexpr ImGuiWindowFlags flags = @@ -70,9 +70,9 @@ namespace rift::UI } } - Timespan GetElapsedTime() const + p::Timespan GetElapsedTime() const { - return DateTime::Now() - creationTime; + return p::DateTime::Now() - creationTime; } const char* GetIcon() const @@ -88,7 +88,7 @@ namespace rift::UI } } - Color GetColor() + p::Color GetColor() { switch (toast.type) { @@ -97,7 +97,7 @@ namespace rift::UI case ToastType::Error: return UI::errorColor; case ToastType::Info: return UI::infoColor; case ToastType::None: - default: return Color::White(); + default: return p::Color::White(); } } @@ -120,21 +120,23 @@ namespace rift::UI return 1.f * opacity; } - void GetPositionAndPivot(float height, v2& position, v2& pivot) + void GetPositionAndPivot(float height, p::v2& position, p::v2& pivot) { - v2 pad{padding.x, padding.y + height}; + p::v2 pad{padding.x, padding.y + height}; const ImGuiViewport* viewport = ImGui::GetMainViewport(); - v2 workPos = viewport->WorkPos; - v2 workSize = viewport->WorkSize; - position.x = (u8(corner) & 1) ? (workPos.x + workSize.x - pad.x) : (workPos.x + pad.x); - position.y = (u8(corner) & 2) ? (workPos.y + workSize.y - pad.y) : (workPos.y + pad.y); - pivot.x = (u8(corner) & 1) ? 1.0f : 0.0f; - pivot.y = (u8(corner) & 2) ? 1.0f : 0.0f; + p::v2 workPos = viewport->WorkPos; + p::v2 workSize = viewport->WorkSize; + position.x = + (p::u8(corner) & 1) ? (workPos.x + workSize.x - pad.x) : (workPos.x + pad.x); + position.y = + (p::u8(corner) & 2) ? (workPos.y + workSize.y - pad.y) : (workPos.y + pad.y); + pivot.x = (p::u8(corner) & 1) ? 1.0f : 0.0f; + pivot.y = (p::u8(corner) & 2) ? 1.0f : 0.0f; } }; - static TArray gNotifications; + static p::TArray gNotifications; void AddNotification(Toast toast) @@ -148,7 +150,7 @@ namespace rift::UI ImGui::PushStyleColor(ImGuiCol_WindowBg, UI::GetNeutralColor(0)); float height = 0.f; - for (i32 i = 0; i < gNotifications.Size(); ++i) + for (p::i32 i = 0; i < gNotifications.Size(); ++i) { auto& notification = gNotifications[i]; @@ -160,17 +162,17 @@ namespace rift::UI continue; } - const float opacity = notification.GetFadePercent(); - LinearColor textColor = notification.GetColor(); - textColor.a = opacity; + const float opacity = notification.GetFadePercent(); + p::LinearColor textColor = notification.GetColor(); + textColor.a = opacity; // ImGui::PushStyleColor(ImGuiCol_Text, textColor); ImGui::SetNextWindowBgAlpha(opacity); - v2 position, pivot; + p::v2 position, pivot; notification.GetPositionAndPivot(height, position, pivot); ImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot); - String windowName = Strings::Format("##Notification_{}", i); + p::String windowName = p::Strings::Format("##Notification_{}", i); ImGui::Begin(windowName.c_str(), nullptr, Notification::flags); // Here we render the toast content @@ -178,7 +180,7 @@ namespace rift::UI // We want to support multi-line text, this will // wrap the text after 1/3 of the screen width - const v2 workSize = UI::GetMainViewport()->WorkSize; + const p::v2 workSize = UI::GetMainViewport()->WorkSize; ImGui::PushTextWrapPos(workSize.x / 3.f); bool wasTitleRendered = false; @@ -191,7 +193,7 @@ namespace rift::UI } // If a title is set - const String& title = notification.toast.title; + const p::String& title = notification.toast.title; if (!title.empty()) { // If a title and an icon is set, we want to render on same line @@ -206,7 +208,7 @@ namespace rift::UI // In case ANYTHING was rendered in the top, we want to add a small padding // so the text (or icon) looks centered vertically - const String& message = notification.toast.message; + const p::String& message = notification.toast.message; if (wasTitleRendered && !message.empty()) { ImGui::SetCursorPosY( diff --git a/Libs/UI/Src/Style.cpp b/Libs/UI/Src/Style.cpp index c756d682..040556c1 100644 --- a/Libs/UI/Src/Style.cpp +++ b/Libs/UI/Src/Style.cpp @@ -20,7 +20,7 @@ namespace rift::UI { struct FontType { - TArray> sizes{}; + p::TArray> sizes{}; void Add(float size, ImFont* imFont) { @@ -46,7 +46,7 @@ namespace rift::UI { return sizes.First().second; } - const TPair* foundFont = sizes.Find([desiredSize](const auto& font) { + const p::TPair* foundFont = sizes.Find([desiredSize](const auto& font) { return p::NearlyEqual(font.first, desiredSize); }); return foundFont ? foundFont->second : nullptr; @@ -55,19 +55,19 @@ namespace rift::UI struct FontDescriptor { - std::array()> modes{}; + std::array()> modes{}; FontType& operator[](UI::FontMode mode) { - return modes[u8(mode)]; + return modes[p::u8(mode)]; } const FontType& operator[](UI::FontMode mode) const { - return modes[u8(mode)]; + return modes[p::u8(mode)]; } }; - static TMap gFonts{}; + static p::TMap gFonts{}; ImFont* AddFont(p::StringView file, float size, const ImFontConfig* fontConfig = nullptr, @@ -77,7 +77,7 @@ namespace rift::UI return io.Fonts->AddFontFromFileTTF(file.data(), size, fontConfig, glyphRanges); } - void AddTextFont(Tag name, UI::FontMode mode, float size, p::StringView file) + void AddTextFont(p::Tag name, UI::FontMode mode, float size, p::StringView file) { FontDescriptor* font = gFonts.Find(name); if (!font) @@ -142,13 +142,13 @@ namespace rift::UI io.Fonts->Build(); } - ImFont* FindFont(Tag name, UI::FontMode mode, float size) + ImFont* FindFont(p::Tag name, UI::FontMode mode, float size) { const FontDescriptor* const font = gFonts.Find(name); return font ? (*font)[mode].Get(size) : nullptr; } - void SetDefaultFont(Tag name, UI::FontMode mode, float size) + void SetDefaultFont(p::Tag name, UI::FontMode mode, float size) { ImFont* font = FindFont(name, mode, size); if (!font && !name.IsNone()) @@ -158,13 +158,13 @@ namespace rift::UI ImGui::GetIO().FontDefault = font; } - void PushFont(Tag name, UI::FontMode mode, float size) + void PushFont(p::Tag name, UI::FontMode mode, float size) { ImFont* font = FindFont(name, mode, size); if (!font && !name.IsNone()) { p::Error("Tried to push inexistent font '{}' (mode: {}, size: {})", name, - GetEnumName(mode), size); + p::GetEnumName(mode), size); } ImGui::PushFont(font); } @@ -189,10 +189,10 @@ namespace rift::UI ImVec4* colors = style.Colors; - LinearColor titleColor = UI::GetNeutralColor(0); + p::LinearColor titleColor = UI::GetNeutralColor(0); colors[ImGuiCol_TitleBg] = titleColor.Shade(0.2f); colors[ImGuiCol_TitleBgActive] = titleColor; - colors[ImGuiCol_TitleBgCollapsed] = UI::Disabled(titleColor); + colors[ImGuiCol_TitleBgCollapsed] = UI::ToDisabled(titleColor); colors[ImGuiCol_WindowBg] = UI::GetNeutralColor(1); colors[ImGuiCol_Border] = UI::GetNeutralColor(0); @@ -202,17 +202,17 @@ namespace rift::UI colors[ImGuiCol_SliderGrab] = UI::GetNeutralColor(4); - LinearColor separatorColor = UI::GetNeutralColor(1); - colors[ImGuiCol_SeparatorHovered] = UI::Hovered(separatorColor); + p::LinearColor separatorColor = UI::GetNeutralColor(1); + colors[ImGuiCol_SeparatorHovered] = UI::ToHovered(separatorColor); colors[ImGuiCol_SeparatorActive] = separatorColor; - LinearColor resizeGripColor = UI::GetNeutralColor(1); + p::LinearColor resizeGripColor = UI::GetNeutralColor(1); colors[ImGuiCol_ResizeGrip] = resizeGripColor.Shade(0.3f); - colors[ImGuiCol_ResizeGripHovered] = UI::Hovered(resizeGripColor); + colors[ImGuiCol_ResizeGripHovered] = UI::ToHovered(resizeGripColor); colors[ImGuiCol_ResizeGripActive] = resizeGripColor; colors[ImGuiCol_DockingPreview] = UI::GetNeutralColor(2); - colors[ImGuiCol_DockingEmptyBg] = LinearColor::White().Shade(0.97f); + colors[ImGuiCol_DockingEmptyBg] = p::LinearColor::White().Shade(0.97f); colors[ImGuiCol_TextSelectedBg] = UI::primaryColor.Shade(0.1f); colors[ImGuiCol_NavHighlight] = UI::primaryColor; @@ -229,73 +229,11 @@ namespace rift::UI UI::PushButtonColor(UI::GetNeutralColor(3)); UI::PushFrameBgColor(UI::GetNeutralColor(2)); - UI::PushHeaderColor(); + UI::PushHeaderColor(UI::GetNeutralColor(2)); LoadFonts(); UI::SetDefaultFont("WorkSans"); } void PopGeneralStyle() {} - - // Make the UI compact because there are so many fields - void PushStyleCompact() - { - ImGuiStyle& style = ImGui::GetStyle(); - UI::PushStyleVar(ImGuiStyleVar_FramePadding, - ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); - UI::PushStyleVar(ImGuiStyleVar_ItemSpacing, - ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); - } - - void PopStyleCompact() - { - UI::PopStyleVar(2); - } - - void PushFrameBgColor(LinearColor color) - { - UI::PushStyleColor(ImGuiCol_FrameBg, color.Shade(0.3f)); - UI::PushStyleColor(ImGuiCol_FrameBgHovered, UI::Hovered(color)); - UI::PushStyleColor(ImGuiCol_FrameBgActive, color); - } - - void PopFrameBgColor() - { - UI::PopStyleColor(3); - } - - void PushButtonColor(LinearColor color) - { - UI::PushStyleColor(ImGuiCol_Button, color); - UI::PushStyleColor(ImGuiCol_ButtonHovered, UI::Hovered(color)); - UI::PushStyleColor(ImGuiCol_ButtonActive, color.Tint(0.1f)); - } - - void PopButtonColor() - { - UI::PopStyleColor(3); - } - - void PushHeaderColor(LinearColor color) - { - UI::PushStyleColor(ImGuiCol_Header, color); - UI::PushStyleColor(ImGuiCol_HeaderHovered, UI::Hovered(color)); - UI::PushStyleColor(ImGuiCol_HeaderActive, color.Tint(0.1f)); - } - - void PopHeaderColor() - { - UI::PopStyleColor(3); - } - - void PushTextColor(LinearColor color) - { - UI::PushStyleColor(ImGuiCol_Text, color); - UI::PushStyleColor(ImGuiCol_TextDisabled, color.Shade(0.15f)); - } - - void PopTextColor() - { - UI::PopStyleColor(2); - } } // namespace rift::UI diff --git a/Libs/UI/Src/UIImgui.cpp b/Libs/UI/Src/UIImgui.cpp new file mode 100644 index 00000000..2ff0ecca --- /dev/null +++ b/Libs/UI/Src/UIImgui.cpp @@ -0,0 +1,6 @@ +// Copyright 2015-2024 Piperift - All rights reserved + +#include "UI/UIImgui.h" + +#define P_IMGUI_IMPLEMENTATION +#include diff --git a/Libs/UI/Src/Widgets.cpp b/Libs/UI/Src/Widgets.cpp index 248f7563..49b06353 100644 --- a/Libs/UI/Src/Widgets.cpp +++ b/Libs/UI/Src/Widgets.cpp @@ -8,9 +8,9 @@ namespace rift::UI { - void AnimatedSprite::SetAnimation(u32 id) + void AnimatedSprite::SetAnimation(p::u32 id) { - currentFrame = {0, p::Clamp(id, 0u, u32(numFrames.Size() - 1))}; + currentFrame = {0, p::Clamp(id, 0u, p::u32(numFrames.Size() - 1))}; currentFrameRemainingTime = rate; } @@ -21,7 +21,7 @@ namespace rift::UI if (currentFrameRemainingTime <= 0.f) { ++currentFrame.x; - if (currentFrame.x >= numFrames[i32(currentFrame.y)]) + if (currentFrame.x >= numFrames[p::i32(currentFrame.y)]) { currentFrame.x = 0; } @@ -29,16 +29,16 @@ namespace rift::UI } } - v2 AnimatedSprite::GetUV() const + p::v2 AnimatedSprite::GetUV() const { return size * currentFrame; } - bool SpriteButton(AnimatedSprite& sprite, i32 framePadding, const LinearColor& bgColor, - const LinearColor& tintColor) + bool SpriteButton(AnimatedSprite& sprite, p::i32 framePadding, const p::LinearColor& bgColor, + const p::LinearColor& tintColor) { - const v2 uv = sprite.GetUV(); + const p::v2 uv = sprite.GetUV(); return UI::ImageButton( sprite.textureId, sprite.size, uv, uv + sprite.size, framePadding, bgColor, tintColor); } @@ -46,7 +46,7 @@ namespace rift::UI struct InputTextCallbackStringUserData { - String* str; + p::String* str; ImGuiInputTextCallback chainCallback; void* chainCallbackUserData; }; @@ -59,7 +59,7 @@ namespace rift::UI // Resize string callback // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we // need to set them back to what we want. - String* str = userData->str; + p::String* str = userData->str; IM_ASSERT(data->Buf == str->c_str()); str->resize(data->BufTextLen); data->Buf = (char*)str->c_str(); @@ -74,7 +74,7 @@ namespace rift::UI } - bool InputText(const char* label, String& str, ImGuiInputTextFlags flags, + bool InputText(const char* label, p::String& str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* userData) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); @@ -88,7 +88,7 @@ namespace rift::UI label, (char*)str.c_str(), str.capacity() + 1, flags, InputTextCallback, &cbUserData); } - bool InputTextMultiline(const char* label, String& str, const ImVec2& size, + bool InputTextMultiline(const char* label, p::String& str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* userData) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); @@ -102,7 +102,7 @@ namespace rift::UI InputTextCallback, &cbUserData); } - bool InputTextWithHint(const char* label, const char* hint, String& str, + bool InputTextWithHint(const char* label, const char* hint, p::String& str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* userData) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); @@ -116,7 +116,7 @@ namespace rift::UI InputTextCallback, &cbUserData); } - ImRect GetWorkRect(v2 desiredSize, bool addhalfItemSpacing, v2 extent) + ImRect GetWorkRect(p::v2 desiredSize, bool addhalfItemSpacing, p::v2 extent) { auto& style = ImGui::GetStyle(); auto* window = UI::GetCurrentWindow(); @@ -149,13 +149,13 @@ namespace rift::UI static ImGuiID gPendingEditingId = 0; - bool MutableText(StringView label, String& text, ImGuiInputTextFlags flags) + bool MutableText(p::StringView label, p::String& text, ImGuiInputTextFlags flags) { const ImGuiID id = UI::GetID(label); const bool isEditing = UI::GetActiveID() == id; if (!isEditing) // Is editing { - UI::PushStyleColor(ImGuiCol_FrameBg, LinearColor::Transparent()); + UI::PushStyleColor(ImGuiCol_FrameBg, p::LinearColor::Transparent()); } const bool valueChanged = UI::InputText(label.data(), text, flags); @@ -166,7 +166,7 @@ namespace rift::UI return valueChanged; } - void HelpTooltip(StringView text, float delay) + void HelpTooltip(p::StringView text, float delay) { static ImGuiID currentHelpItemId = 0; @@ -176,8 +176,8 @@ namespace rift::UI bool show = true; if (delay > 0.f) { - static DateTime hoverStartTime; - const DateTime now = DateTime::Now(); + static p::DateTime hoverStartTime; + const p::DateTime now = p::DateTime::Now(); if (itemId != currentHelpItemId) { // Reset help tooltip countdown @@ -189,12 +189,12 @@ namespace rift::UI if (show) { - UI::PushStyleVar(ImGuiStyleVar_WindowPadding, v2{4.f, 3.f}); + UI::PushStyleVar(ImGuiStyleVar_WindowPadding, p::v2{4.f, 3.f}); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - static String finalText; + static p::String finalText; finalText.clear(); - Strings::FormatTo(finalText, "{} {}", ICON_FA_QUESTION_CIRCLE, text); + p::Strings::FormatTo(finalText, "{} {}", ICON_FA_QUESTION_CIRCLE, text); UI::AlignTextToFramePadding(); ImGui::TextUnformatted(finalText.c_str()); ImGui::PopTextWrapPos(); @@ -207,7 +207,7 @@ namespace rift::UI currentHelpItemId = 0; } } - void HelpMarker(StringView text) + void HelpMarker(p::StringView text) { ImGui::TextDisabled(ICON_FA_QUESTION_CIRCLE); HelpTooltip(text, 0.f); diff --git a/Libs/UI/Src/Window.cpp b/Libs/UI/Src/Window.cpp index 5df77cbb..c3c5032b 100644 --- a/Libs/UI/Src/Window.cpp +++ b/Libs/UI/Src/Window.cpp @@ -131,11 +131,11 @@ namespace rift::UI void Render() { ImGui::Render(); - i32 displayW, displayH; + p::i32 displayW, displayH; glfwGetFramebufferSize(gWindow, &displayW, &displayH); glViewport(0, 0, displayW, displayH); - static constexpr LinearColor clearColor{0.1f, 0.1f, 0.1f, 1.00f}; + static constexpr p::LinearColor clearColor{0.1f, 0.1f, 0.1f, 1.00f}; glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); From 610c18d60cfd90bb98135d2d0ebea73d929be4ac Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 22 May 2024 21:54:56 +0200 Subject: [PATCH 40/52] Improved Pipe ECS & Refelction debug --- Extern/Pipe | 2 +- Extern/imgui | 2 +- Libs/Editor/Src/Editor.cpp | 2 +- Libs/Editor/Src/Tools/ASTDebugger.cpp | 5 +---- imgui.ini | 17 ----------------- 5 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 imgui.ini diff --git a/Extern/Pipe b/Extern/Pipe index cded2de0..5305f0ad 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit cded2de079206210766d76ce990bfcc0b01feaf6 +Subproject commit 5305f0ad0e0cbc8fd48711506429cb3b07ace5fe diff --git a/Extern/imgui b/Extern/imgui index 1db579d4..e391fe2e 160000 --- a/Extern/imgui +++ b/Extern/imgui @@ -1 +1 @@ -Subproject commit 1db579d458da29fa43376af9d88d486910d9406a +Subproject commit e391fe2e66eb1c96b1624ae8444dc64c23146ef4 diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 2b2eac71..00823d4c 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -37,7 +37,7 @@ namespace rift::editor String asString = p::ToString(*id); if (UI::InputText("##value", asString)) { - *id = p::IdFromString(asString); + *id = p::IdFromString(asString, nullptr); } }); diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index c6d46c49..143eee2d 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -77,9 +77,6 @@ namespace rift::editor dbgContext.ctx = * p::BeginDebug(dbgContext); p::DrawIdRegistry(" " ICON_FA_BUG " AST Debugger", &open); - static p::ECSDebugInspector testInspector; - testInspector.id = mainInspector.id; - p::DrawEntityInspector("Test", testInspector); p::EndDebug(); } @@ -146,7 +143,7 @@ namespace rift::editor if (UI::InputText("##IdValue", asString, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll)) { - changedId = p::IdFromString(asString); + changedId = p::IdFromString(asString, &ast); } ImGui::EndMenu(); } diff --git a/imgui.ini b/imgui.ini deleted file mode 100644 index 446db75d..00000000 --- a/imgui.ini +++ /dev/null @@ -1,17 +0,0 @@ -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][Project Manager] -Pos=340,355 -Size=600,189 -Collapsed=0 - -[Window][##Notification_0] -Pos=1058,850 -Size=202,30 -Collapsed=0 - -[Docking][Data] - From 29407115373841276fd86fd51385fd7d919d5929 Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 22 May 2024 22:05:55 +0200 Subject: [PATCH 41/52] Updated Pipe --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index 5305f0ad..e961abee 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 5305f0ad0e0cbc8fd48711506429cb3b07ace5fe +Subproject commit e961abeef6fce754860400ccac25d219ed0f7ac6 From 114b174ff9619612fa76c3c05fcae0604c1cdf97 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 30 Jun 2024 23:53:42 +0200 Subject: [PATCH 42/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Components/CModule.h | 2 +- Libs/AST/Include/AST/Components/CNamespace.h | 2 +- Libs/Editor/Src/Tools/MemoryDebugger.cpp | 3 ++- Libs/UI/Include/UI/Widgets.h | 3 --- Libs/UI/Src/Inspection.cpp | 8 ++++---- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index e961abee..bce1f9a7 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit e961abeef6fce754860400ccac25d219ed0f7ac6 +Subproject commit bce1f9a70fd2e0f650de7ca5a763bad95effd047 diff --git a/Libs/AST/Include/AST/Components/CModule.h b/Libs/AST/Include/AST/Components/CModule.h index 26f409e7..fe2bf980 100644 --- a/Libs/AST/Include/AST/Components/CModule.h +++ b/Libs/AST/Include/AST/Components/CModule.h @@ -28,7 +28,7 @@ namespace rift::ast P_PROP(target) RiftModuleTarget target = RiftModuleTarget::Executable; - P_PROP(dependencies) + P_PROP(dependencies, p::PF_Edit) p::TArray dependencies; }; } // namespace rift::ast diff --git a/Libs/AST/Include/AST/Components/CNamespace.h b/Libs/AST/Include/AST/Components/CNamespace.h index 1b2ddb53..78b55066 100644 --- a/Libs/AST/Include/AST/Components/CNamespace.h +++ b/Libs/AST/Include/AST/Components/CNamespace.h @@ -11,7 +11,7 @@ namespace rift::ast { P_STRUCT(CNamespace) - P_PROP(name); + P_PROP(name, p::PF_Edit); p::Tag name; diff --git a/Libs/Editor/Src/Tools/MemoryDebugger.cpp b/Libs/Editor/Src/Tools/MemoryDebugger.cpp index 4ea66ff6..803a9958 100644 --- a/Libs/Editor/Src/Tools/MemoryDebugger.cpp +++ b/Libs/Editor/Src/Tools/MemoryDebugger.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,7 @@ namespace rift::editor if (UI::Begin("Memory", &open)) { String label; - auto* stats = GetHeapStats(); + auto* stats = GetHeapArena().GetStats(); UI::Text(Strings::Format("Used: {}", Strings::ParseMemorySize(stats->used))); if (UI::BeginChild("Allocations")) diff --git a/Libs/UI/Include/UI/Widgets.h b/Libs/UI/Include/UI/Widgets.h index 6cf61698..1da1ad13 100644 --- a/Libs/UI/Include/UI/Widgets.h +++ b/Libs/UI/Include/UI/Widgets.h @@ -113,9 +113,6 @@ namespace rift::UI bool MutableText(p::StringView label, p::String& text, ImGuiInputTextFlags flags = 0); - void HelpTooltip(p::StringView text, float delay = 1.f); - void HelpMarker(p::StringView text); - bool DrawFilterWithHint(ImGuiTextFilter& filter, const char* label = "Filter (inc,-exc)", const char* hint = "...", float width = 0.0f); diff --git a/Libs/UI/Src/Inspection.cpp b/Libs/UI/Src/Inspection.cpp index 61f5d3a1..10762a51 100644 --- a/Libs/UI/Src/Inspection.cpp +++ b/Libs/UI/Src/Inspection.cpp @@ -242,11 +242,11 @@ namespace rift::UI if (p::HasTypeFlags(type, p::TF_Struct)) { - void* instance = handle.GetPtr(); - p::TView properties = p::GetTypeProperties(type); - for (const auto& prop : properties) + void* instance = handle.GetPtr(); + p::TView properties = p::GetTypeProperties(type); + for (const auto* prop : properties) { - InspectProperty({instance, type, prop}); + InspectProperty({instance, type, *prop}); } } else if (handle.IsArray()) From 910f38d234e7b7c80b15676bd06ed4db3e7016ed Mon Sep 17 00:00:00 2001 From: muit Date: Wed, 3 Jul 2024 08:23:37 +0200 Subject: [PATCH 43/52] Updated Pipe --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index bce1f9a7..5b8ec90b 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit bce1f9a70fd2e0f650de7ca5a763bad95effd047 +Subproject commit 5b8ec90b93bbf2a2eece659da28e6f998a2173cd From 8a4cf1e1e5f47e33a591c4c0d020d23c28cf5c91 Mon Sep 17 00:00:00 2001 From: muit Date: Mon, 8 Jul 2024 22:19:53 +0200 Subject: [PATCH 44/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Utils/Settings.h | 4 ++++ Libs/AST/Include/Rift.h | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 5b8ec90b..b5fb3c6e 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 5b8ec90b93bbf2a2eece659da28e6f998a2173cd +Subproject commit b5fb3c6e5d733bdf38534eccadcb0a96dab7b73b diff --git a/Libs/AST/Include/AST/Utils/Settings.h b/Libs/AST/Include/AST/Utils/Settings.h index 0fb7c72f..26164a19 100644 --- a/Libs/AST/Include/AST/Utils/Settings.h +++ b/Libs/AST/Include/AST/Utils/Settings.h @@ -13,6 +13,10 @@ namespace rift { + template + void SaveUserSettings(); + + p::String GetUserSettingsPath(p::StringView name); template diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index c8b15183..9b03b87a 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -21,17 +21,17 @@ namespace rift template void EnableModule() { - EnableModule(GetTypeId()); + EnableModule(p::GetTypeId()); } template void DisableModule() { - DisableModule(GetTypeId()); + DisableModule(p::GetTypeId()); } template p::TPtr GetModule() { - return GetModule(GetTypeId()).template Cast(); + return GetModule(p::GetTypeId()).template Cast(); } void RegisterView(View view); From bb4722e524d04307f800860178e60aa19914d67f Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 5 Oct 2024 15:57:20 +0200 Subject: [PATCH 45/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/AST/Include/AST/Utils/ModuleFileIterator.h | 4 ++-- Libs/AST/Include/AST/Utils/TypeIterator.h | 4 ++-- .../Native/Compiler/Include/HeaderIterator.h | 4 ++-- Libs/Editor/Include/Editor.h | 2 +- Libs/Editor/Src/Editor.cpp | 14 +++++++------- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index b5fb3c6e..641e492e 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit b5fb3c6e5d733bdf38534eccadcb0a96dab7b73b +Subproject commit 641e492ecb4779a49991f33b49d4deb85047b2c4 diff --git a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h index ab7303dd..62aac452 100644 --- a/Libs/AST/Include/AST/Utils/ModuleFileIterator.h +++ b/Libs/AST/Include/AST/Utils/ModuleFileIterator.h @@ -9,9 +9,9 @@ namespace rift::ast { - class ModuleFileIterator : public p::LambdaFileIterator + class ModuleFileIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/AST/Include/AST/Utils/TypeIterator.h b/Libs/AST/Include/AST/Utils/TypeIterator.h index 5d44076b..b385679c 100644 --- a/Libs/AST/Include/AST/Utils/TypeIterator.h +++ b/Libs/AST/Include/AST/Utils/TypeIterator.h @@ -9,9 +9,9 @@ namespace rift::ast { - class TypeIterator : public p::LambdaFileIterator + class TypeIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h index 038c3fcb..fff1716d 100644 --- a/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h +++ b/Libs/Bindings/Native/Compiler/Include/HeaderIterator.h @@ -9,9 +9,9 @@ namespace rift { - class HeaderIterator : public p::LambdaFileIterator + class HeaderIterator : public p::LambdaFileIterator { - using Super = p::LambdaFileIterator; + using Super = p::LambdaFileIterator; public: using Super::Super; diff --git a/Libs/Editor/Include/Editor.h b/Libs/Editor/Include/Editor.h index e9dd14ab..e2ce1992 100644 --- a/Libs/Editor/Include/Editor.h +++ b/Libs/Editor/Include/Editor.h @@ -22,7 +22,7 @@ namespace rift::editor p::FileWatcher fileWatcher; public: - bool bFilesDirty = true; + bool filesDirty = true; #if P_DEBUG bool showDemo = false; bool showMetrics = false; diff --git a/Libs/Editor/Src/Editor.cpp b/Libs/Editor/Src/Editor.cpp index 00823d4c..4eac0127 100644 --- a/Libs/Editor/Src/Editor.cpp +++ b/Libs/Editor/Src/Editor.cpp @@ -59,7 +59,7 @@ namespace rift::editor int Editor::Run(StringView projectPath) { - fileWatcher.StartAsync(); + fileWatcher.StartWatchingAsync(); // Setup window p::Info("Initializing editor..."); @@ -108,10 +108,10 @@ namespace rift::editor ast::FunctionsSystem::ClearAddedTags(ast); ast::TransactionSystem::ClearTags(ast); - if (bFilesDirty) + if (filesDirty) { ast::LoadSystem::Run(ast); - bFilesDirty = false; + filesDirty = false; } ast::FunctionsSystem::ResolveCallFunctionIds(ast); ast::TypeSystem::ResolveExprTypeIds(ast); @@ -172,9 +172,9 @@ namespace rift::editor // Start watching the project folder for file changes ast.Add(GetProjectId(ast), fileWatcher.ListenPath(projectPath, true, - [](StringView path, StringView filename, + [](FileWatchId id, StringView path, StringView filename, FileWatchAction action, StringView oldFilename) { - Editor::Get().bFilesDirty = true; + Editor::Get().filesDirty = true; })); @@ -189,9 +189,9 @@ namespace rift::editor void Editor::CloseProject() { Id id = GetProjectId(ast); - if (ast.IsValid(id) && ast.Has(id)) + if (ast.IsValid(id) && ast.Has(id)) { - fileWatcher.StopListening(ast.Get(id)); + fileWatcher.StopListening(ast.Get(id)); } ast::CloseProject(ast); } From 4a0c0e4124cf1a776b052dbde900bc50fcfc8640 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 5 Oct 2024 15:57:47 +0200 Subject: [PATCH 46/52] Updated Pipe --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index 641e492e..c16e8a80 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 641e492ecb4779a49991f33b49d4deb85047b2c4 +Subproject commit c16e8a80a560512ad0ad87bd72eb96947cd79c84 From 9d2315ecb1cc882db12a145754ab4e2ca033c3b0 Mon Sep 17 00:00:00 2001 From: muit Date: Sat, 30 Nov 2024 15:13:16 +0100 Subject: [PATCH 47/52] Renamed modules & updated Pipe --- .clang-format | 5 ++-- Apps/CLI/CMakeLists.txt | 16 ++++++------ Apps/CLI/Src/main.cpp | 25 +++++++++++++++++-- Apps/Editor/CMakeLists.txt | 17 ++++++------- Apps/Editor/Src/main.cpp | 24 ++++++++++++++++-- Extern/Pipe | 2 +- Libs/AST/CMakeLists.txt | 14 +++++------ Libs/AST/Include/Rift.h | 3 ++- Libs/AST/Src/AST/Components/CNamespace.cpp | 6 ++--- Libs/Backends/MIR/CMakeLists.txt | 9 +++---- Libs/Bindings/Native/CMakeLists.txt | 12 ++++----- .../Compiler/Src/NativeBindingModule.cpp | 3 --- Libs/Editor/CMakeLists.txt | 21 ++++++++-------- Libs/UI/CMakeLists.txt | 14 +++++------ Libs/Views/Graph/CMakeLists.txt | 12 ++++----- Tests/CMakeLists.txt | 2 +- 16 files changed, 112 insertions(+), 73 deletions(-) diff --git a/.clang-format b/.clang-format index ceda188c..679bbe1d 100644 --- a/.clang-format +++ b/.clang-format @@ -26,8 +26,7 @@ BinPackArguments: true BinPackParameters: true BitFieldColonSpacing: None BreakBeforeBinaryOperators: NonAssignment -BreakBeforeBraces: Custom -BreakBeforeConceptDeclarations: false +BreakBeforeConceptDeclarations: true BreakConstructorInitializers: BeforeComma BreakInheritanceList: AfterComma BreakStringLiterals: true @@ -62,6 +61,7 @@ IndentPPDirectives: BeforeHash IndentRequires: true IndentWidth: 4 IndentWrappedFunctionNames: false +InsertBraces: true KeepEmptyLinesAtTheStartOfBlocks: false LambdaBodyIndentation: OuterScope MaxEmptyLinesToKeep: 2 @@ -78,6 +78,7 @@ PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left ReferenceAlignment: Left ReflowComments: true +RequiresClausePosition: WithPreceding SortIncludes: CaseInsensitive SortUsingDeclarations: true SpaceAfterCStyleCast: false diff --git a/Apps/CLI/CMakeLists.txt b/Apps/CLI/CMakeLists.txt index 7871c578..cc882cfa 100644 --- a/Apps/CLI/CMakeLists.txt +++ b/Apps/CLI/CMakeLists.txt @@ -1,17 +1,17 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_executable(RiftCLIExe Src/main.cpp) +add_executable(RiftCLI Src/main.cpp) -target_include_directories(RiftCLIExe PUBLIC Include) +target_include_directories(RiftCLI PUBLIC Include) file(GLOB_RECURSE CLI_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) -target_sources(RiftCLIExe PRIVATE ${CLI_SOURCE_FILES}) +target_sources(RiftCLI PRIVATE ${CLI_SOURCE_FILES}) -target_link_libraries(RiftCLIExe PUBLIC +target_link_libraries(RiftCLI PUBLIC CLI11 - RiftAST + RiftASTLib RiftCompilerModules ) -rift_module(RiftCLIExe) -set_target_properties(RiftCLIExe PROPERTIES OUTPUT_NAME "Rift") -set_icon(RiftCLIExe Icon.ico) +rift_module(RiftCLI) +set_target_properties(RiftCLI PROPERTIES OUTPUT_NAME "Rift") +set_icon(RiftCLI Icon.ico) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index ce3bed69..bbf27b72 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,7 @@ namespace rift const Tag def = backends.IsEmpty() ? Tag::None() : backends[0]->GetName(); selected = def.AsString(); - auto stdDesc = Strings::Convert(desc); + auto stdDesc = Strings::Convert(desc); app.add_option("-b,--backend", selected, stdDesc, true); } @@ -64,7 +65,27 @@ namespace rift int main(int argc, char** argv) { - p::Initialize("Saved/Logs"); + p::Logger logger = p::Logger{.infoCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Info] {}\n", msg); + std::cout << text; + }, .warningCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Warning] {}\n", msg); + std::cout << text; + }, .errorCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Error] {}\n", msg); + std::cout << text; + }}; + + p::Initialize(&logger); p::Info(p::PlatformPaths::GetUserSettingsPath()); EnableModule(); EnableModule(); diff --git a/Apps/Editor/CMakeLists.txt b/Apps/Editor/CMakeLists.txt index f0c6150b..adc4a86f 100644 --- a/Apps/Editor/CMakeLists.txt +++ b/Apps/Editor/CMakeLists.txt @@ -1,18 +1,17 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_executable(RiftEditorExe Src/main.cpp) +add_executable(RiftEditor Src/main.cpp) -target_include_directories(RiftEditorExe PUBLIC Include) +target_include_directories(RiftEditor PUBLIC Include) file(GLOB_RECURSE RiftEditor_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) -target_sources(RiftEditorExe PRIVATE ${RiftEditor_SOURCE_FILES}) +target_sources(RiftEditor PRIVATE ${RiftEditor_SOURCE_FILES}) -target_link_libraries(RiftEditorExe PUBLIC +target_link_libraries(RiftEditor PUBLIC RiftCompilerModules - RiftEditor + RiftEditorLib RiftEditorModules ) -target_compile_definitions(RiftEditorExe PUBLIC RIFT_EDITOR=1) +target_compile_definitions(RiftEditor PUBLIC RIFT_EDITOR=1) -rift_module(RiftEditorExe) -set_target_properties(RiftEditorExe PROPERTIES OUTPUT_NAME "RiftEditor") -set_icon(RiftEditorExe Icon.ico) +rift_module(RiftEditor) +set_icon(RiftEditor Icon.ico) diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index 4e972b61..9c4db9d2 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -8,20 +8,40 @@ #include #include #include +#include #include using namespace rift; - #ifndef RUN_AS_CLI #define RUN_AS_CLI 1 #endif int RunEditor(StringView projectPath) { - p::Initialize("Saved/Logs"); + p::Logger logger = p::Logger{.infoCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Info] {}\n", msg); + std::cout << text; + }, .warningCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Warning] {}\n", msg); + std::cout << text; + }, .errorCallback = [](StringView msg) { + String text; + auto now = p::DateTime::Now(); + now.ToString("[%Y/%m/%d %H:%M:%S]", text); + p::Strings::FormatTo(text, "[Error] {}\n", msg); + std::cout << text; + }}; + + p::Initialize(&logger); EnableModule(); EnableModule(); EnableModule(); diff --git a/Extern/Pipe b/Extern/Pipe index c16e8a80..1d06d1a2 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit c16e8a80a560512ad0ad87bd72eb96947cd79c84 +Subproject commit 1d06d1a2237f7b87504b421fd45596c37ff71ff8 diff --git a/Libs/AST/CMakeLists.txt b/Libs/AST/CMakeLists.txt index 23829d36..df09e114 100644 --- a/Libs/AST/CMakeLists.txt +++ b/Libs/AST/CMakeLists.txt @@ -1,16 +1,16 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftAST STATIC) -target_include_directories(RiftAST PUBLIC Include) +add_library(RiftASTLib STATIC) +target_include_directories(RiftASTLib PUBLIC Include) file(GLOB_RECURSE AST_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) -target_sources(RiftAST PRIVATE ${AST_SOURCE_FILES}) +target_sources(RiftASTLib PRIVATE ${AST_SOURCE_FILES}) -target_link_libraries(RiftAST PUBLIC +target_link_libraries(RiftASTLib PUBLIC Pipe Taskflow - RiftBindingNative + RiftBindingNativeLib ) -rift_module(RiftAST) -set_target_properties (RiftAST PROPERTIES FOLDER Rift) +rift_module(RiftASTLib) +set_target_properties (RiftASTLib PROPERTIES FOLDER Rift) diff --git a/Libs/AST/Include/Rift.h b/Libs/AST/Include/Rift.h index 9b03b87a..dfb12a43 100644 --- a/Libs/AST/Include/Rift.h +++ b/Libs/AST/Include/Rift.h @@ -9,6 +9,7 @@ #include #include +#include namespace rift @@ -31,7 +32,7 @@ namespace rift template p::TPtr GetModule() { - return GetModule(p::GetTypeId()).template Cast(); + return Cast(GetModule(p::GetTypeId())); } void RegisterView(View view); diff --git a/Libs/AST/Src/AST/Components/CNamespace.cpp b/Libs/AST/Src/AST/Components/CNamespace.cpp index 9c5052a1..c7155215 100644 --- a/Libs/AST/Src/AST/Components/CNamespace.cpp +++ b/Libs/AST/Src/AST/Components/CNamespace.cpp @@ -8,13 +8,13 @@ namespace rift::ast Namespace::Namespace(p::StringView value) { p::i32 size = 0; - const p::TChar* last = value.data() + value.size(); - const p::TChar* curr = value.data(); + const char* last = value.data() + value.size(); + const char* curr = value.data(); if (curr != last && *curr == '@') ++curr; - const p::TChar* scopeStart = curr; + const char* scopeStart = curr; while (curr != last && size < scopeCount) { if (*curr == '.') diff --git a/Libs/Backends/MIR/CMakeLists.txt b/Libs/Backends/MIR/CMakeLists.txt index 760846e0..4363c9c9 100644 --- a/Libs/Backends/MIR/CMakeLists.txt +++ b/Libs/Backends/MIR/CMakeLists.txt @@ -1,7 +1,6 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftBackendMIR STATIC) -target_link_libraries(RiftBackendMIR PUBLIC RiftAST) -target_link_libraries(RiftBackendMIR PRIVATE RiftBindingNative mir) -rift_compiler_module(RiftBackendMIR) - +add_library(RiftBackendMIRLib STATIC) +target_link_libraries(RiftBackendMIRLib PUBLIC RiftASTLib) +target_link_libraries(RiftBackendMIRLib PRIVATE RiftBindingNativeLib mir) +rift_compiler_module(RiftBackendMIRLib) diff --git a/Libs/Bindings/Native/CMakeLists.txt b/Libs/Bindings/Native/CMakeLists.txt index b225264d..ad5ac041 100644 --- a/Libs/Bindings/Native/CMakeLists.txt +++ b/Libs/Bindings/Native/CMakeLists.txt @@ -1,12 +1,12 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftBindingNative STATIC) +add_library(RiftBindingNativeLib STATIC) -target_link_libraries(RiftBindingNative PUBLIC RiftAST) +target_link_libraries(RiftBindingNativeLib PUBLIC RiftASTLib) -rift_compiler_module(RiftBindingNative) +rift_compiler_module(RiftBindingNativeLib) -add_library(RiftBindingNativeEditor STATIC) -rift_editor_module(RiftBindingNativeEditor) -target_link_libraries(RiftBindingNativeEditor PUBLIC RiftEditor RiftBindingNative) +add_library(RiftBindingNativeEditorLib STATIC) +rift_editor_module(RiftBindingNativeEditorLib) +target_link_libraries(RiftBindingNativeEditorLib PUBLIC RiftEditorLib RiftBindingNativeLib) diff --git a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp index 42475825..2a221d49 100644 --- a/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp +++ b/Libs/Bindings/Native/Compiler/Src/NativeBindingModule.cpp @@ -16,9 +16,6 @@ #include -// P_OVERRIDE_NEW_DELETE - - namespace rift { struct ParsedModule diff --git a/Libs/Editor/CMakeLists.txt b/Libs/Editor/CMakeLists.txt index 19f80f07..6614b82d 100644 --- a/Libs/Editor/CMakeLists.txt +++ b/Libs/Editor/CMakeLists.txt @@ -1,17 +1,18 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftEditor STATIC) +add_library(RiftEditorLib STATIC) -target_include_directories(RiftEditor PUBLIC Include) -file(GLOB_RECURSE RiftEditor_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) -target_sources(RiftEditor PRIVATE ${RiftEditor_SOURCE_FILES}) +target_include_directories(RiftEditorLib PUBLIC Include) +file(GLOB_RECURSE RiftEditorLib_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) +target_sources(RiftEditorLib PRIVATE ${RiftEditorLib_SOURCE_FILES}) -target_link_libraries(RiftEditor PUBLIC - RiftAST - RiftBackendMIR - RiftUI +target_link_libraries(RiftEditorLib PUBLIC + RiftASTLib + RiftBackendMIRLib + RiftUILib CLI11 ) -rift_module(RiftEditor) -rift_enable_module_resources(RiftEditor) +rift_module(RiftEditorLib) +rift_enable_module_resources(RiftEditorLib) +set_target_properties(RiftEditorLib PROPERTIES OUTPUT_NAME "RiftEditor") diff --git a/Libs/UI/CMakeLists.txt b/Libs/UI/CMakeLists.txt index 95def659..cbb67938 100644 --- a/Libs/UI/CMakeLists.txt +++ b/Libs/UI/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftUI STATIC) +add_library(RiftUILib STATIC) -target_include_directories(RiftUI PUBLIC Include) +target_include_directories(RiftUILib PUBLIC Include) file(GLOB_RECURSE UI_SOURCE_FILES CONFIGURE_DEPENDS Src/*.cpp Src/*.h) -target_sources(RiftUI PRIVATE ${UI_SOURCE_FILES}) +target_sources(RiftUILib PRIVATE ${UI_SOURCE_FILES}) -target_link_libraries(RiftUI PUBLIC +target_link_libraries(RiftUILib PUBLIC Pipe glfw gl3w imgui IconFontCppHeaders ) -target_link_libraries(RiftUI PRIVATE stb_image) -target_compile_definitions(RiftUI PRIVATE NOMINMAX) +target_link_libraries(RiftUILib PRIVATE stb_image) +target_compile_definitions(RiftUILib PRIVATE NOMINMAX) -rift_module(RiftUI) +rift_module(RiftUILib) diff --git a/Libs/Views/Graph/CMakeLists.txt b/Libs/Views/Graph/CMakeLists.txt index 81ae9962..782c3678 100644 --- a/Libs/Views/Graph/CMakeLists.txt +++ b/Libs/Views/Graph/CMakeLists.txt @@ -1,9 +1,9 @@ # Copyright 2015-2023 Piperift - All rights reserved -add_library(RiftViewGraph STATIC) -rift_compiler_module(RiftViewGraph) -target_link_libraries(RiftViewGraph PUBLIC RiftAST) +add_library(RiftViewGraphLib STATIC) +rift_compiler_module(RiftViewGraphLib) +target_link_libraries(RiftViewGraphLib PUBLIC RiftASTLib) -add_library(RiftViewGraphEditor STATIC) -rift_editor_module(RiftViewGraphEditor) -target_link_libraries(RiftViewGraphEditor PUBLIC RiftEditor RiftViewGraph) +add_library(RiftViewGraphEditorLib STATIC) +rift_editor_module(RiftViewGraphEditorLib) +target_link_libraries(RiftViewGraphEditorLib PUBLIC RiftEditorLib RiftViewGraphLib) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index bc853fd8..70dc30a1 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -5,7 +5,7 @@ add_executable(RiftTests ${TESTS_SOURCE_FILES}) rift_module(RiftTests) pipe_target_shared_output_directory(RiftTests) target_include_directories(RiftTests PUBLIC .) -target_link_libraries(RiftTests PUBLIC RiftAST Bandit) +target_link_libraries(RiftTests PUBLIC RiftASTLib Bandit) add_test(NAME RiftTests COMMAND $) From 018123b685e576af1938bb93301378091fdcc659 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 1 Dec 2024 23:27:50 +0100 Subject: [PATCH 48/52] Updated Pipe --- .vscode/settings.json | 6 +++++- Extern/Pipe | 2 +- Libs/AST/Include/AST/Id.h | 2 +- Libs/AST/Include/Compiler/CompilerConfig.h | 2 +- Libs/AST/Include/Module.h | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 3 ++- Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h | 3 ++- Libs/Editor/Include/Tools/MemoryDebugger.h | 2 +- Libs/Editor/Include/Utils/NodesMiniMap.h | 2 +- Libs/UI/Include/UI/Style.h | 2 +- Libs/UI/Include/UI/UIImgui.h | 2 +- Libs/UI/Include/UI/Window.h | 2 +- 12 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c989f1aa..c2e5bc00 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,7 @@ "cmake.configureOnOpen": true, "cmake.buildDirectory": "${workspaceFolder}/Build", "files.associations": { + "*.tmpl": "html", "cmath": "cpp", "algorithm": "cpp", "any": "cpp", @@ -155,7 +156,10 @@ "splines": "cpp", "typeindex": "cpp", "qtalignedmalloc": "cpp", - "*.traits": "cpp" + "*.traits": "cpp", + "span": "cpp", + "stdfloat": "cpp", + "cuchar": "cpp" }, "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "banditTestExplorer.testsuites": [ diff --git a/Extern/Pipe b/Extern/Pipe index 1d06d1a2..31629043 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 1d06d1a2237f7b87504b421fd45596c37ff71ff8 +Subproject commit 31629043670de2445952f87d324f1ecb60443f8a diff --git a/Libs/AST/Include/AST/Id.h b/Libs/AST/Include/AST/Id.h index babe9575..3fed6daf 100644 --- a/Libs/AST/Include/AST/Id.h +++ b/Libs/AST/Include/AST/Id.h @@ -1,8 +1,8 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include #include +#include namespace rift::ast diff --git a/Libs/AST/Include/Compiler/CompilerConfig.h b/Libs/AST/Include/Compiler/CompilerConfig.h index 78d09087..0791348e 100644 --- a/Libs/AST/Include/Compiler/CompilerConfig.h +++ b/Libs/AST/Include/Compiler/CompilerConfig.h @@ -3,8 +3,8 @@ #pragma once #include "AST/Tree.h" -#include "Pipe/Core/Platform.h" +#include #include diff --git a/Libs/AST/Include/Module.h b/Libs/AST/Include/Module.h index d56b0c1d..636338e2 100644 --- a/Libs/AST/Include/Module.h +++ b/Libs/AST/Include/Module.h @@ -2,7 +2,7 @@ #pragma once -#include "Pipe/Core/Platform.h" +#include "PipePlatform.h" #include "Rift.h" #include diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index 68c90b4c..add82af9 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -6,15 +6,16 @@ #include #include #include -#include #include #include #include #include +#include #include #include + namespace rift::editor { struct InspectorPanel diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index c2964978..abe15aed 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -1,13 +1,14 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include #include #include #include +#include #include + namespace rift::editor { using namespace p; diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index 3b50865d..a8505457 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -1,10 +1,10 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include #include #include #include +#include #include diff --git a/Libs/Editor/Include/Utils/NodesMiniMap.h b/Libs/Editor/Include/Utils/NodesMiniMap.h index 9ebbbd4d..4442eab3 100644 --- a/Libs/Editor/Include/Utils/NodesMiniMap.h +++ b/Libs/Editor/Include/Utils/NodesMiniMap.h @@ -3,7 +3,7 @@ #pragma once #include -#include +#include #include diff --git a/Libs/UI/Include/UI/Style.h b/Libs/UI/Include/UI/Style.h index 5a7266de..bc4dd35b 100644 --- a/Libs/UI/Include/UI/Style.h +++ b/Libs/UI/Include/UI/Style.h @@ -1,9 +1,9 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include #include #include +#include namespace rift::UI diff --git a/Libs/UI/Include/UI/UIImgui.h b/Libs/UI/Include/UI/UIImgui.h index a91d5e17..a50f317e 100644 --- a/Libs/UI/Include/UI/UIImgui.h +++ b/Libs/UI/Include/UI/UIImgui.h @@ -1,9 +1,9 @@ // Copyright 2015-2024 Piperift - All rights reserved #pragma once -#include #include #include +#include #include diff --git a/Libs/UI/Include/UI/Window.h b/Libs/UI/Include/UI/Window.h index 5d4cf09f..688d1ede 100644 --- a/Libs/UI/Include/UI/Window.h +++ b/Libs/UI/Include/UI/Window.h @@ -3,8 +3,8 @@ #pragma once #include -#include #include +#include struct GLFWwindow; From be5ab7754d7a560ee344c90b3b8b4e584fc1d6a0 Mon Sep 17 00:00:00 2001 From: muit Date: Sun, 1 Dec 2024 23:50:06 +0100 Subject: [PATCH 49/52] Updated Pipe --- Extern/Pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extern/Pipe b/Extern/Pipe index 31629043..70e3dbaf 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 31629043670de2445952f87d324f1ecb60443f8a +Subproject commit 70e3dbafe7612fb9f0089186642451f64ac3b32d From 241789adc467321fe6a2d920a404642536ddc068 Mon Sep 17 00:00:00 2001 From: muit Date: Thu, 5 Dec 2024 09:22:09 +0100 Subject: [PATCH 50/52] Updated Pipe --- Extern/Pipe | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 2 -- Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h | 4 +--- Libs/Editor/Include/Tools/MemoryDebugger.h | 3 ++- Libs/Editor/Src/Tools/ASTDebugger.cpp | 2 +- Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp | 3 ++- Libs/Editor/Src/Tools/MemoryDebugger.cpp | 3 +-- 7 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Extern/Pipe b/Extern/Pipe index 70e3dbaf..3c1632f0 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 70e3dbafe7612fb9f0089186642451f64ac3b32d +Subproject commit 3c1632f04b4a6dc038b8a87dcb4c3625950a98eb diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index add82af9..b6673c01 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #include - namespace rift::editor { struct InspectorPanel diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index abe15aed..72fb4032 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -2,13 +2,11 @@ #pragma once #include -#include -#include +#include #include #include - namespace rift::editor { using namespace p; diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index a8505457..f1b7fed0 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -2,12 +2,13 @@ #pragma once #include -#include #include +#include #include #include + namespace rift::editor { using namespace p; diff --git a/Libs/Editor/Src/Tools/ASTDebugger.cpp b/Libs/Editor/Src/Tools/ASTDebugger.cpp index 143eee2d..982e9efc 100644 --- a/Libs/Editor/Src/Tools/ASTDebugger.cpp +++ b/Libs/Editor/Src/Tools/ASTDebugger.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp index 75ce3d9d..e616e0b6 100644 --- a/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp +++ b/Libs/Editor/Src/Tools/BigBestFitArenaDebugger.cpp @@ -3,11 +3,12 @@ #include "Tools/BigBestFitArenaDebugger.h" #include -#include #include +#include #include + // External #include diff --git a/Libs/Editor/Src/Tools/MemoryDebugger.cpp b/Libs/Editor/Src/Tools/MemoryDebugger.cpp index 803a9958..da7f28cd 100644 --- a/Libs/Editor/Src/Tools/MemoryDebugger.cpp +++ b/Libs/Editor/Src/Tools/MemoryDebugger.cpp @@ -3,10 +3,9 @@ #include "Tools/MemoryDebugger.h" #include -#include -#include #include #include +#include #include #include From cc8bb14ede24b01641cc310086283cb981822f0a Mon Sep 17 00:00:00 2001 From: muit Date: Fri, 6 Dec 2024 23:15:10 +0100 Subject: [PATCH 51/52] Updated Pipe --- Apps/CLI/Src/main.cpp | 2 +- Apps/Editor/Src/main.cpp | 2 +- Extern/Pipe | 2 +- Libs/Editor/Include/Tools/ASTDebugger.h | 2 +- Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h | 10 +++++----- Libs/Editor/Include/Tools/MemoryDebugger.h | 2 -- Tests/main.cpp | 2 +- 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Apps/CLI/Src/main.cpp b/Apps/CLI/Src/main.cpp index bbf27b72..35673652 100644 --- a/Apps/CLI/Src/main.cpp +++ b/Apps/CLI/Src/main.cpp @@ -1,6 +1,6 @@ // Copyright 2015-2024 Piperift - All rights reserved -#include +#include // Override as first include #include diff --git a/Apps/Editor/Src/main.cpp b/Apps/Editor/Src/main.cpp index 9c4db9d2..aafc9486 100644 --- a/Apps/Editor/Src/main.cpp +++ b/Apps/Editor/Src/main.cpp @@ -1,6 +1,6 @@ // Copyright 2015-2024 Piperift - All rights reserved -#include +#include // Override as first include #include diff --git a/Extern/Pipe b/Extern/Pipe index 3c1632f0..f4800f4d 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit 3c1632f04b4a6dc038b8a87dcb4c3625950a98eb +Subproject commit f4800f4d11a315770524e5da62e237a2d2d7aee6 diff --git a/Libs/Editor/Include/Tools/ASTDebugger.h b/Libs/Editor/Include/Tools/ASTDebugger.h index b6673c01..d1c36da9 100644 --- a/Libs/Editor/Include/Tools/ASTDebugger.h +++ b/Libs/Editor/Include/Tools/ASTDebugger.h @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h index 72fb4032..0024ae0d 100644 --- a/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h +++ b/Libs/Editor/Include/Tools/BigBestFitArenaDebugger.h @@ -15,11 +15,11 @@ namespace rift::editor { static constexpr v2 unitSize{4.f, 4.f}; // Size of each grid point - u32 memoryScale = 8; // Each gridpoint will equal N bytes - u32 numColumns = 0; - u32 bytesPerRow = 0; - u32 numRows = 0; - const p::Memory::Block* block = nullptr; + u32 memoryScale = 8; // Each gridpoint will equal N bytes + u32 numColumns = 0; + u32 bytesPerRow = 0; + u32 numRows = 0; + const p::ArenaBlock* block = nullptr; MemoryGrid() = default; diff --git a/Libs/Editor/Include/Tools/MemoryDebugger.h b/Libs/Editor/Include/Tools/MemoryDebugger.h index f1b7fed0..d56f0e21 100644 --- a/Libs/Editor/Include/Tools/MemoryDebugger.h +++ b/Libs/Editor/Include/Tools/MemoryDebugger.h @@ -2,13 +2,11 @@ #pragma once #include -#include #include #include #include - namespace rift::editor { using namespace p; diff --git a/Tests/main.cpp b/Tests/main.cpp index 9ee8ab4d..23968e73 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -1,6 +1,6 @@ // Copyright 2015-2024 Piperift - All rights reserved -#include +#include // Override as first include #include From d4daf852b872e3cc898975ab1f4ca6faa7099d87 Mon Sep 17 00:00:00 2001 From: muit Date: Fri, 13 Dec 2024 17:19:50 +0100 Subject: [PATCH 52/52] Fixed Backend reflection --- CMake/Util.cmake | 1 + Extern/Pipe | 2 +- Libs/AST/Include/Compiler/Backend.h | 2 +- Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMake/Util.cmake b/CMake/Util.cmake index e4d2a97d..0d3cf469 100644 --- a/CMake/Util.cmake +++ b/CMake/Util.cmake @@ -4,6 +4,7 @@ function(rift_module target) pipe_target_define_platform(${target}) pipe_target_shared_output_directory(${target}) pipe_target_enable_CPP20(${target}) + pipe_target_disable_rtti(${target} PRIVATE) set_target_properties(${target} PROPERTIES FOLDER Rift) endfunction(rift_module) diff --git a/Extern/Pipe b/Extern/Pipe index f4800f4d..ff33f777 160000 --- a/Extern/Pipe +++ b/Extern/Pipe @@ -1 +1 @@ -Subproject commit f4800f4d11a315770524e5da62e237a2d2d7aee6 +Subproject commit ff33f777a8260e1b3ba1ad04dc7e43a0b6b8bcb3 diff --git a/Libs/AST/Include/Compiler/Backend.h b/Libs/AST/Include/Compiler/Backend.h index 68d0ec76..18940865 100644 --- a/Libs/AST/Include/Compiler/Backend.h +++ b/Libs/AST/Include/Compiler/Backend.h @@ -11,10 +11,10 @@ namespace rift { class Backend : public p::Object { + public: using Super = p::Object; P_CLASS(Backend) - public: virtual p::Tag GetName() { return p::Tag::None(); diff --git a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h index 95a13f1d..7def1abf 100644 --- a/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h +++ b/Libs/Backends/MIR/Compiler/Include/MIRBackendModule.h @@ -24,6 +24,7 @@ namespace rift class MIRBackend : public Backend { + public: using Super = Backend; P_CLASS(MIRBackend)