From 4680579899f348598fa5c09b826b1b8ab987f96f Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 13:47:29 -0400 Subject: [PATCH 01/12] Remove macOS Cocoa and Metal backends --- CMakeLists.txt | 4 +- engine/gfx/metal/CMakeLists.txt | 29 - engine/gfx/metal/include/gfx_metal.hpp | 70 -- engine/gfx/metal/src/gfx_metal.mm | 1115 ----------------- engine/gfx/metal/src/gfx_metal_buffer.hpp | 19 - .../gfx/metal/src/gfx_metal_framebuffer.hpp | 13 - engine/gfx/metal/src/gfx_metal_pipeline.hpp | 32 - engine/gfx/metal/src/gfx_metal_renderpass.hpp | 10 - engine/gfx/metal/src/gfx_metal_sampler.hpp | 10 - engine/gfx/metal/src/gfx_metal_texture.hpp | 16 - platforms/CMakeLists.txt | 2 +- platforms/mac/CMakeLists.txt | 29 - platforms/mac/file.mm | 42 - platforms/mac/main.mm.in | 634 ---------- platforms/sdl/CMakeLists.txt | 3 + platforms/{mac => sdl}/Info.plist.in | 0 16 files changed, 7 insertions(+), 2021 deletions(-) delete mode 100755 engine/gfx/metal/CMakeLists.txt delete mode 100755 engine/gfx/metal/include/gfx_metal.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal.mm delete mode 100755 engine/gfx/metal/src/gfx_metal_buffer.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal_framebuffer.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal_pipeline.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal_renderpass.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal_sampler.hpp delete mode 100755 engine/gfx/metal/src/gfx_metal_texture.hpp delete mode 100755 platforms/mac/CMakeLists.txt delete mode 100755 platforms/mac/file.mm delete mode 100755 platforms/mac/main.mm.in rename platforms/{mac => sdl}/Info.plist.in (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 480f011..c5c24d5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,9 @@ endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) message("macOS build detected!") - set(ENABLE_METAL TRUE) + find_package(SDL2 REQUIRED) + + set(ENABLE_VULKAN TRUE) set(ENABLE_DARWIN TRUE) set(ENABLE_MACOS TRUE) diff --git a/engine/gfx/metal/CMakeLists.txt b/engine/gfx/metal/CMakeLists.txt deleted file mode 100755 index c2c9841..0000000 --- a/engine/gfx/metal/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -set(SRC - include/gfx_metal.hpp - - src/gfx_metal.mm - src/gfx_metal_buffer.hpp - src/gfx_metal_pipeline.hpp - src/gfx_metal_texture.hpp - src/gfx_metal_framebuffer.hpp - src/gfx_metal_renderpass.hpp - src/gfx_metal_sampler.hpp) - -add_library(GFXMetal STATIC - ${SRC}) - -set_target_properties(GFXMetal PROPERTIES - FRAMEWORK TRUE - FRAMEWORK_VERSION OBJC - PUBLIC_HEADER "${HEADERS}" -) -target_link_libraries(GFXMetal PUBLIC - GFX - Core - Log - "-framework Metal") -target_include_directories(GFXMetal PUBLIC - include - PRIVATE - src) -set_engine_properties(GFXMetal) diff --git a/engine/gfx/metal/include/gfx_metal.hpp b/engine/gfx/metal/include/gfx_metal.hpp deleted file mode 100755 index 143a268..0000000 --- a/engine/gfx/metal/include/gfx_metal.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include - -#include "gfx.hpp" - -class GFXMetal : public GFX { -public: - bool is_supported() override; - GFXContext required_context() override { return GFXContext::Metal; } - ShaderLanguage accepted_shader_language() override { return ShaderLanguage::MSL; } - const char* get_name() override; - - bool supports_feature(const GFXFeature feature) override; - - bool initialize(const GFXCreateInfo& createInfo) override; - - void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override; - void remove_view(const int identifier) override; - - // buffer operations - GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage usage) override; - void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override; - - void* get_buffer_contents(GFXBuffer* buffer) override; - - // texture operations - GFXTexture* create_texture(const GFXTextureCreateInfo& info) override; - void copy_texture(GFXTexture* texture, void* data, GFXSize size) override; - void copy_texture(GFXTexture* from, GFXTexture* to) override; - void copy_texture(GFXTexture* from, GFXBuffer* to) override; - - // sampler opeations - GFXSampler* create_sampler(const GFXSamplerCreateInfo& info) override; - - // framebuffer operations - GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override; - - // render pass operations - GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override; - - // pipeline operations - GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override; - GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override; - - GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override; - - void submit(GFXCommandBuffer* command_buffer, const int window = -1) override; - -private: - struct NativeMTLView { - int identifier = -1; - CAMetalLayer* layer = nullptr; - }; - - std::vector nativeViews; - - NativeMTLView* getNativeView(int identifier) { - for(auto& view : nativeViews) { - if(view->identifier == identifier) - return view; - } - - return nullptr; - } - - id device = nil; - id command_queue = nil; -}; diff --git a/engine/gfx/metal/src/gfx_metal.mm b/engine/gfx/metal/src/gfx_metal.mm deleted file mode 100755 index 37c6c16..0000000 --- a/engine/gfx/metal/src/gfx_metal.mm +++ /dev/null @@ -1,1115 +0,0 @@ -#include "gfx_metal.hpp" - -#include "gfx_metal_buffer.hpp" -#include "gfx_metal_pipeline.hpp" -#include "gfx_commandbuffer.hpp" -#include "gfx_metal_texture.hpp" -#include "gfx_metal_renderpass.hpp" -#include "gfx_metal_framebuffer.hpp" -#include "gfx_metal_sampler.hpp" -#include "file.hpp" -#include "log.hpp" -#include "utility.hpp" -#include "string_utils.hpp" - -static inline bool debug_enabled = false; - -static inline std::array command_buffers; -static inline std::array free_command_buffers; - -MTLPixelFormat toPixelFormat(GFXPixelFormat format) { - switch(format) { - case GFXPixelFormat::R_32F: - return MTLPixelFormatR32Float; - case GFXPixelFormat::R_16F: - return MTLPixelFormatR16Float; - case GFXPixelFormat::RGBA_32F: - return MTLPixelFormatRGBA32Float; - case GFXPixelFormat::RGBA8_UNORM: - return MTLPixelFormatRGBA8Unorm; - case GFXPixelFormat::R8_UNORM: - return MTLPixelFormatR8Unorm; - case GFXPixelFormat::R8G8_UNORM: - return MTLPixelFormatRG8Unorm; - case GFXPixelFormat::R8G8_SFLOAT: - return MTLPixelFormatRG16Float; - case GFXPixelFormat::R8G8B8A8_UNORM: - return MTLPixelFormatRGBA8Unorm; - case GFXPixelFormat::R16G16B16A16_SFLOAT: - return MTLPixelFormatRGBA16Float; - case GFXPixelFormat::DEPTH_32F: - return MTLPixelFormatDepth32Float; - } -} - -MTLBlendFactor toBlendFactor(GFXBlendFactor factor) { - switch(factor) { - case GFXBlendFactor::One: - return MTLBlendFactorOne; - case GFXBlendFactor::Zero: - return MTLBlendFactorZero; - case GFXBlendFactor::SrcColor: - return MTLBlendFactorSourceColor; - case GFXBlendFactor::DstColor: - return MTLBlendFactorDestinationColor; - case GFXBlendFactor::SrcAlpha: - return MTLBlendFactorSourceAlpha; - case GFXBlendFactor::DstAlpha: - return MTLBlendFactorDestinationAlpha; - case GFXBlendFactor::OneMinusSrcAlpha: - return MTLBlendFactorOneMinusSourceAlpha; - case GFXBlendFactor::OneMinusSrcColor: - return MTLBlendFactorOneMinusSourceColor; - } -} - -MTLSamplerAddressMode toSamplingMode(SamplingMode mode) { - switch(mode) { - case SamplingMode::Repeat: - return MTLSamplerAddressModeRepeat; - case SamplingMode::ClampToEdge: - return MTLSamplerAddressModeClampToEdge; - case SamplingMode::ClampToBorder: - { -#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) - return MTLSamplerAddressModeRepeat; -#else - return MTLSamplerAddressModeClampToBorderColor; -#endif - } - } -} - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) -MTLSamplerBorderColor toBorderColor(GFXBorderColor color) { - switch(color) { - case GFXBorderColor::OpaqueWhite: - return MTLSamplerBorderColorOpaqueWhite; - case GFXBorderColor::OpaqueBlack: - return MTLSamplerBorderColorOpaqueBlack; - } -} -#endif - -MTLCompareFunction toCompare(GFXCompareFunction function) { - switch(function) { - case GFXCompareFunction::Never: - return MTLCompareFunctionNever; - case GFXCompareFunction::Less: - return MTLCompareFunctionLess; - case GFXCompareFunction::Equal: - return MTLCompareFunctionEqual; - case GFXCompareFunction::LessOrEqual: - return MTLCompareFunctionLessEqual; - case GFXCompareFunction::Greater: - return MTLCompareFunctionGreater; - case GFXCompareFunction::NotEqual: - return MTLCompareFunctionNotEqual; - case GFXCompareFunction::GreaterOrEqual: - return MTLCompareFunctionGreaterEqual; - case GFXCompareFunction::Always: - return MTLCompareFunctionAlways; - } -} - -MTLSamplerMinMagFilter toFilter(GFXFilter filter) { - switch(filter) { - case GFXFilter::Nearest: - return MTLSamplerMinMagFilterNearest; - case GFXFilter::Linear: - return MTLSamplerMinMagFilterLinear; - } -} - -MTLWinding toWinding(GFXWindingMode mode) { - switch(mode) { - case GFXWindingMode::Clockwise: - return MTLWindingClockwise; - case GFXWindingMode::CounterClockwise: - return MTLWindingCounterClockwise; - } -} - -bool GFXMetal::is_supported() { - return true; -} - -bool GFXMetal::initialize(const GFXCreateInfo& createInfo) { - debug_enabled = createInfo.api_validation_enabled; - - device = MTLCreateSystemDefaultDevice(); - if(device) { - command_queue = [device newCommandQueue]; - - for(int i = 0; i < 15; i++) { - command_buffers[i] = new GFXCommandBuffer(); - free_command_buffers[i] = true; - } - - return true; - } else { - return false; - } -} - -const char* GFXMetal::get_name() { - return "Metal"; -} - -bool GFXMetal::supports_feature(const GFXFeature feature) { - if(feature == GFXFeature::CubemapArray) { -#if defined(PLATFORM_TVOS) - return false; -#else - return true; -#endif - } - - return false; -} - -void GFXMetal::initialize_view(void* native_handle, const int identifier, const uint32_t, const uint32_t) { - NativeMTLView* native = new NativeMTLView(); - native->identifier = identifier; - - native->layer = (CAMetalLayer*)native_handle; - native->layer.device = device; - - native->layer.allowsNextDrawableTimeout = true; - - nativeViews.push_back(native); -} - -void GFXMetal::remove_view(const int identifier) { - utility::erase_if(nativeViews, [identifier](NativeMTLView* view) { - return view->identifier == identifier; - }); -} - -GFXBuffer* GFXMetal::create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage) { - GFXMetalBuffer* buffer = new GFXMetalBuffer(); - buffer->dynamicData = dynamicData; - - if(buffer->dynamicData) { - for(int i = 0; i < 3; i++) { - if(data == nullptr) { - buffer->handles[i] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; - } else { - buffer->handles[i] = [device newBufferWithBytes:data - length:(NSUInteger)size - options:MTLResourceStorageModeShared]; - } - } - } else { - if(data == nullptr) { - buffer->handles[0] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; - } else { - buffer->handles[0] = [device newBufferWithBytes:data - length:(NSUInteger)size - options:MTLResourceStorageModeShared]; - } - } - - return buffer; -} - -int currentFrameIndex = 0; - -void GFXMetal::copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) { - GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; - - const unsigned char * src = reinterpret_cast(data); - unsigned char * dest = reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); - if(dest != nullptr) - memcpy(dest + offset, src, size); -} - -void* GFXMetal::get_buffer_contents(GFXBuffer* buffer) { - GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; - - return reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); -} - -GFXTexture* GFXMetal::create_texture(const GFXTextureCreateInfo& info) { - GFXMetalTexture* texture = new GFXMetalTexture(); - - MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; - - MTLPixelFormat mtlFormat = toPixelFormat(info.format); - - switch(info.type) { - case GFXTextureType::Single2D: - textureDescriptor.textureType = MTLTextureType2D; - break; - case GFXTextureType::Array2D: - textureDescriptor.textureType = MTLTextureType2DArray; - break; - case GFXTextureType::Cubemap: - { - textureDescriptor.textureType = MTLTextureTypeCube; - texture->is_cubemap = true; - } - break; - case GFXTextureType::CubemapArray: - { - textureDescriptor.textureType = MTLTextureTypeCubeArray; - texture->is_cubemap = true; - } - break; - } - - if((info.usage & GFXTextureUsage::Attachment) == GFXTextureUsage::Attachment) { - textureDescriptor.storageMode = MTLStorageModePrivate; - textureDescriptor.usage |= MTLTextureUsageRenderTarget; - } else { -#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) - textureDescriptor.storageMode = MTLStorageModeShared; -#else - textureDescriptor.storageMode = MTLStorageModeManaged; -#endif - } - - if((info.usage & GFXTextureUsage::Sampled) == GFXTextureUsage::Sampled) { - textureDescriptor.usage |= MTLTextureUsageShaderRead; - } - - if((info.usage & GFXTextureUsage::ShaderWrite) == GFXTextureUsage::ShaderWrite) { - textureDescriptor.usage |= MTLTextureUsageShaderWrite; - } - - textureDescriptor.pixelFormat = mtlFormat; - textureDescriptor.width = info.width; - textureDescriptor.height = info.height; - textureDescriptor.arrayLength = info.array_length; - - texture->array_length = info.array_length; - - textureDescriptor.mipmapLevelCount = info.mip_count; - - texture->format = mtlFormat; - - texture->handle = [device newTextureWithDescriptor:textureDescriptor]; - - texture->width = info.width; - texture->height = info.height; - - MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; - samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear; - samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear; - samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; - samplerDescriptor.maxAnisotropy = 16; - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) - samplerDescriptor.borderColor = toBorderColor(info.border_color); -#endif - - if(info.compare_enabled) - samplerDescriptor.compareFunction = toCompare(info.compare_function); - - texture->sampler = [device newSamplerStateWithDescriptor:samplerDescriptor]; - - return texture; -} - -void GFXMetal::copy_texture(GFXTexture* texture, void* data, const GFXSize) { - GFXMetalTexture* metalTexture = (GFXMetalTexture*)texture; - - MTLRegion region = { - { 0, 0, 0 }, - { - static_cast(texture->width), - static_cast(texture->height), - 1 - } - }; - - NSUInteger byteSize = 1; - if(metalTexture->format == MTLPixelFormatRGBA8Unorm) - byteSize = 4; - else if(metalTexture->format == MTLPixelFormatRG8Unorm) - byteSize = 2; - - [metalTexture->handle replaceRegion:region mipmapLevel:0 withBytes:data bytesPerRow:(NSUInteger)texture->width * byteSize]; -} - -void GFXMetal::copy_texture(GFXTexture* from, GFXTexture* to) { - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; - GFXMetalTexture* metalToTexture = (GFXMetalTexture*)to; - - id commandBuffer = [command_queue commandBuffer]; - id commandEncoder = [commandBuffer blitCommandEncoder]; - [commandEncoder copyFromTexture:metalFromTexture->handle toTexture:metalToTexture->handle]; - [commandEncoder endEncoding]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; -} - -void GFXMetal::copy_texture(GFXTexture* from, GFXBuffer* to) { - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; - GFXMetalBuffer* metalToBuffer = (GFXMetalBuffer*)to; - - MTLOrigin origin; - origin.x = 0; - origin.y = 0; - origin.z = 0; - - MTLSize size; - size.width = from->width; - size.height = from->height; - size.depth = 1; - - NSUInteger byteSize = 1; - if(metalFromTexture->format == MTLPixelFormatRGBA8Unorm) - byteSize = 4; - - id commandBuffer = [command_queue commandBuffer]; - id commandEncoder = [commandBuffer blitCommandEncoder]; - [commandEncoder copyFromTexture:metalFromTexture->handle - sourceSlice:0 - sourceLevel:0 - sourceOrigin:origin - sourceSize:size - toBuffer:metalToBuffer->get(currentFrameIndex) - destinationOffset:0 - destinationBytesPerRow:(NSUInteger)metalFromTexture->width * byteSize - destinationBytesPerImage:0]; - [commandEncoder endEncoding]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; -} - -GFXSampler* GFXMetal::create_sampler(const GFXSamplerCreateInfo& info) { - GFXMetalSampler* sampler = new GFXMetalSampler(); - - MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; - samplerDescriptor.minFilter = toFilter(info.min_filter); - samplerDescriptor.magFilter = toFilter(info.mag_filter); - samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; - samplerDescriptor.maxAnisotropy = 16; - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) - samplerDescriptor.borderColor = toBorderColor(info.border_color); -#endif - - if(info.compare_enabled) - samplerDescriptor.compareFunction = toCompare(info.compare_function); - - sampler->handle = [device newSamplerStateWithDescriptor:samplerDescriptor]; - - return sampler; -} - -GFXFramebuffer* GFXMetal::create_framebuffer(const GFXFramebufferCreateInfo& info) { - GFXMetalFramebuffer* framebuffer = new GFXMetalFramebuffer(); - - for(auto& attachment : info.attachments) - framebuffer->attachments.push_back((GFXMetalTexture*)attachment); - - return framebuffer; -} - -GFXRenderPass* GFXMetal::create_render_pass(const GFXRenderPassCreateInfo& info) { - GFXMetalRenderPass* renderPass = new GFXMetalRenderPass(); - - for(const auto& attachment : info.attachments) - renderPass->attachments.push_back(toPixelFormat(attachment)); - - return renderPass; -} - -MTLFunctionConstantValues* get_constant_values(GFXShaderConstants constants) { - MTLFunctionConstantValues* constantValues = [MTLFunctionConstantValues new]; - - for(auto& constant : constants) { - switch(constant.type) { - case GFXShaderConstant::Type::Integer: - [constantValues setConstantValue:&constant.value type:MTLDataTypeInt atIndex:constant.index]; - break; - } - } - - return constantValues; -} - -GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) { - GFXMetalPipeline* pipeline = new GFXMetalPipeline(); - - NSError* error = nil; - - MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new]; - - const bool has_vertex_stage = !info.shaders.vertex_src.empty(); - const bool has_fragment_stage = !info.shaders.fragment_src.empty(); - - if(has_vertex_stage) { - id vertexLibrary; - { - std::string vertex_src; - if(info.shaders.vertex_src.is_string()) { - vertex_src = info.shaders.vertex_src.as_string(); - } else { - const auto vertex_path = info.shaders.vertex_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / vertex_path); - if(file != std::nullopt) { - vertex_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load vertex shader from {}!", vertex_path.data()); - } - } - - vertexLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", vertex_src.c_str()] options:nil error:&error]; - if(!vertexLibrary) - NSLog(@"%@", error.debugDescription); - - auto vertex_constants = get_constant_values(info.shaders.vertex_constants); - - id vertexFunc = [vertexLibrary newFunctionWithName:@"main0" constantValues:vertex_constants error:nil]; - - if(debug_enabled && info.shaders.vertex_src.is_path()) - vertexFunc.label = [NSString stringWithFormat:@"%s", info.shaders.vertex_src.as_path().string().data()]; - - pipelineDescriptor.vertexFunction = vertexFunc; - } - } - - if(has_fragment_stage) { - id fragmentLibrary; - { - std::string fragment_src; - if(info.shaders.fragment_src.is_string()) { - fragment_src = info.shaders.fragment_src.as_string(); - } else { - const auto fragment_path = info.shaders.fragment_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / fragment_path); - if(file != std::nullopt) { - fragment_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load fragment shader from {}!", fragment_path.data()); - } - } - - fragmentLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", fragment_src.c_str()] options:nil error:&error]; - if(!fragmentLibrary) - NSLog(@"%@", error.debugDescription); - } - - auto fragment_constants = get_constant_values(info.shaders.fragment_constants); - - id fragmentFunc = [fragmentLibrary newFunctionWithName:@"main0" constantValues:fragment_constants error:nil]; - - if(debug_enabled && info.shaders.fragment_src.is_path()) - fragmentFunc.label = [NSString stringWithFormat:@"%s", info.shaders.fragment_src.as_path().string().data()]; - - pipelineDescriptor.fragmentFunction = fragmentFunc; - } - - MTLVertexDescriptor* descriptor = [MTLVertexDescriptor new]; - - for(auto input : info.vertex_input.inputs) { - descriptor.layouts[input.location].stride = (NSUInteger)input.stride; - descriptor.layouts[input.location].stepFunction = MTLVertexStepFunctionPerVertex; - - GFXMetalPipeline::VertexStride vs; - vs.location = input.location; - vs.stride = input.stride; - - pipeline->vertexStrides.push_back(vs); - } - - for(auto attribute : info.vertex_input.attributes) { - NSUInteger format = MTLVertexFormatFloat3; - switch(attribute.format) { - case GFXVertexFormat::FLOAT2: - format = MTLVertexFormatFloat2; - break; - case GFXVertexFormat::FLOAT3: - format = MTLVertexFormatFloat3; - break; - case GFXVertexFormat::FLOAT4: - format = MTLVertexFormatFloat4; - break; - case GFXVertexFormat::INT: - format = MTLVertexFormatInt; - break; - case GFXVertexFormat::UNORM4: - format = MTLVertexFormatUChar4Normalized; - break; - case GFXVertexFormat::INT4: - format = MTLVertexFormatInt4; - break; - } - - descriptor.attributes[attribute.location].format = (MTLVertexFormat)format; - descriptor.attributes[attribute.location].bufferIndex = (NSUInteger)attribute.binding; - descriptor.attributes[attribute.location].offset = (NSUInteger)attribute.offset; - } - - if(info.render_pass != nullptr) { - GFXMetalRenderPass* metalRenderPass = (GFXMetalRenderPass*)info.render_pass; - - unsigned int i = 0; - for(const auto& attachment : metalRenderPass->attachments) { - if(attachment != MTLPixelFormatDepth32Float) { - pipelineDescriptor.colorAttachments[i].pixelFormat = attachment; - pipelineDescriptor.colorAttachments[i].blendingEnabled = info.blending.enable_blending; - - pipelineDescriptor.colorAttachments[i].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); - pipelineDescriptor.colorAttachments[i].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); - - pipelineDescriptor.colorAttachments[i].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); - pipelineDescriptor.colorAttachments[i].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); - - i++; - } else { - pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; - } - } - } else { - pipelineDescriptor.colorAttachments[0].pixelFormat = [nativeViews[0]->layer pixelFormat]; - pipelineDescriptor.colorAttachments[0].blendingEnabled = info.blending.enable_blending; - - pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); - pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); - - pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); - pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); - } - - pipelineDescriptor.vertexDescriptor = descriptor; - - if(debug_enabled) { - pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()]; - pipeline->label = info.label; - } - - pipeline->handle = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if(!pipeline->handle) - NSLog(@"%@", error.debugDescription); - - switch(info.rasterization.primitive_type) { - case GFXPrimitiveType::Triangle: - pipeline->primitiveType = MTLPrimitiveTypeTriangle; - break; - case GFXPrimitiveType::TriangleStrip: - pipeline->primitiveType = MTLPrimitiveTypeTriangleStrip; - break; - } - - for(auto& binding : info.shader_input.bindings) { - if(binding.type == GFXBindingType::PushConstant) - pipeline->pushConstantIndex = binding.binding; - } - - pipeline->winding_mode = info.rasterization.winding_mode; - - MTLDepthStencilDescriptor* depthStencil = [MTLDepthStencilDescriptor new]; - - if(info.depth.depth_mode != GFXDepthMode::None) { - switch(info.depth.depth_mode) { - case GFXDepthMode::Less: - depthStencil.depthCompareFunction = MTLCompareFunctionLess; - break; - case GFXDepthMode::LessOrEqual: - depthStencil.depthCompareFunction = MTLCompareFunctionLessEqual; - break; - case GFXDepthMode::Greater: - depthStencil.depthCompareFunction = MTLCompareFunctionGreater; - break; - } - depthStencil.depthWriteEnabled = true; - } - - pipeline->depthStencil = [device newDepthStencilStateWithDescriptor:depthStencil]; - - switch(info.rasterization.culling_mode) { - case GFXCullingMode::Frontface: - pipeline->cullMode = MTLCullModeFront; - break; - case GFXCullingMode::Backface: - pipeline->cullMode = MTLCullModeBack; - break; - case GFXCullingMode::None: - pipeline->cullMode = MTLCullModeNone; - break; - } - - if(info.rasterization.polygon_type == GFXPolygonType::Line) - pipeline->renderWire = true; - - return pipeline; -} - -GFXPipeline* GFXMetal::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) { - GFXMetalPipeline* pipeline = new GFXMetalPipeline(); - - NSError* error = nil; - - // vertex - id computeLibrary; - { - std::string compute_src; - if(info.compute_src.is_string()) { - compute_src = info.compute_src.as_string(); - } else { - const auto compute_path = info.compute_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / compute_path); - if(file != std::nullopt) { - compute_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load compute shader from {}!", compute_path.data()); - } - } - - computeLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", compute_src.c_str()] options:nil error:&error]; - if(!computeLibrary) - NSLog(@"%@", error.debugDescription); - } - - id computeFunc = [computeLibrary newFunctionWithName:@"main0"]; - - MTLComputePipelineDescriptor* pipelineDescriptor = [MTLComputePipelineDescriptor new]; - pipelineDescriptor.computeFunction = computeFunc; - - pipeline->threadGroupSize = MTLSizeMake(info.workgroup_size_x, info.workgroup_size_y, info.workgroup_size_z); - - if(debug_enabled) { - pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()]; - pipeline->label = info.label; - } - - pipeline->compute_handle = [device newComputePipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if(!pipeline->handle) - NSLog(@"%@", error.debugDescription); - - for(auto& binding : info.shader_input.bindings) { - if(binding.type == GFXBindingType::PushConstant) - pipeline->pushConstantIndex = binding.binding; - } - - [computeLibrary release]; - - return pipeline; -} - -GFXCommandBuffer* GFXMetal::acquire_command_buffer(bool for_presentation_use) { - GFXCommandBuffer* cmdbuf = nullptr; - while(cmdbuf == nullptr) { - for(const auto [i, buffer_status] : utility::enumerate(free_command_buffers)) { - if(buffer_status) { - GFXCommandBuffer* buffer = command_buffers[i]; - - free_command_buffers[i] = false; - - buffer->commands.clear(); - - return buffer; - } - } - } - - return cmdbuf; -} - -void GFXMetal::submit(GFXCommandBuffer* command_buffer, const int window) { - @autoreleasepool { - NativeMTLView* native = getNativeView(window); - id drawable = nil; - if(native != nullptr) - drawable = [native->layer nextDrawable]; - - id commandBuffer = [command_queue commandBuffer]; - - id renderEncoder = nil; - id computeEncoder = nil; - id blitEncoder = nil; - - GFXMetalRenderPass* currentRenderPass = nullptr; - GFXMetalFramebuffer* currentFramebuffer = nullptr; - GFXMetalPipeline* currentPipeline = nullptr; - GFXMetalBuffer* currentIndexBuffer = nullptr; - IndexType currentIndextype = IndexType::UINT32; - MTLViewport currentViewport = MTLViewport(); - MTLClearColor currentClearColor; - - enum class CurrentEncoder { - None, - Render, - Compute, - Blit - } current_encoder = CurrentEncoder::None; - - const auto needEncoder = [&](CurrentEncoder encoder, bool needs_reset = false) { - if(encoder != current_encoder || needs_reset) { - if(renderEncoder != nil) - [renderEncoder endEncoding]; - - if(computeEncoder != nil) - [computeEncoder endEncoding]; - - if(blitEncoder != nil) - [blitEncoder endEncoding]; - - renderEncoder = nil; - computeEncoder = nil; - blitEncoder = nil; - } - - if(current_encoder == encoder && !needs_reset) - return; - - switch(encoder) { - case CurrentEncoder::None: - break; - case CurrentEncoder::Render: - { - MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor new]; - - if(currentRenderPass != nullptr && currentFramebuffer != nullptr) { - unsigned int i = 0; - for(const auto& attachment : currentFramebuffer->attachments) { - if(attachment->format == MTLPixelFormatDepth32Float) { - descriptor.depthAttachment.texture = attachment->handle; - descriptor.depthAttachment.loadAction = MTLLoadActionClear; - descriptor.depthAttachment.storeAction = MTLStoreActionStore; - } else { - descriptor.colorAttachments[i].texture = attachment->handle; - descriptor.colorAttachments[i].loadAction = MTLLoadActionClear; - descriptor.colorAttachments[i].storeAction = MTLStoreActionStore; - descriptor.colorAttachments[i].clearColor = currentClearColor; - - i++; - } - } - - renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; - } else { - descriptor.colorAttachments[0].texture = drawable.texture; - descriptor.colorAttachments[0].loadAction = MTLLoadActionClear; - descriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0,0.0,0.0,1.0); - - renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; - } - - if(currentViewport.width != 0.0f && currentViewport.height != 0.0f) - [renderEncoder setViewport:currentViewport]; - - [descriptor release]; - } - break; - case CurrentEncoder::Compute: - { - computeEncoder = [commandBuffer computeCommandEncoder]; - } - break; - case CurrentEncoder::Blit: - { - blitEncoder = [commandBuffer blitCommandEncoder]; - } - break; - } - - current_encoder = encoder; - }; - - for(auto command : command_buffer->commands) { - switch(command.type) { - case GFXCommandType::Invalid: - break; - case GFXCommandType::SetRenderPass: - { - currentClearColor = MTLClearColorMake(command.data.set_render_pass.clear_color.r, - command.data.set_render_pass.clear_color.g, - command.data.set_render_pass.clear_color.b, - command.data.set_render_pass.clear_color.a ); - - currentFramebuffer = (GFXMetalFramebuffer*)command.data.set_render_pass.framebuffer; - currentRenderPass = (GFXMetalRenderPass*)command.data.set_render_pass.render_pass; - - currentViewport = MTLViewport(); - - needEncoder(CurrentEncoder::Render, true); - } - break; - case GFXCommandType::SetGraphicsPipeline: - { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setRenderPipelineState:((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->handle]; - - currentPipeline = (GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline; - - [renderEncoder setDepthStencilState:currentPipeline->depthStencil]; - - [renderEncoder setCullMode:((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->cullMode]; - [renderEncoder setFrontFacingWinding:toWinding(((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->winding_mode)]; - - if(currentPipeline->renderWire) - [renderEncoder setTriangleFillMode:MTLTriangleFillModeLines]; - else - [renderEncoder setTriangleFillMode:MTLTriangleFillModeFill]; - } - break; - case GFXCommandType::SetComputePipeline: - { - needEncoder(CurrentEncoder::Compute); - - currentPipeline = (GFXMetalPipeline*)command.data.set_compute_pipeline.pipeline; - - [computeEncoder setComputePipelineState:((GFXMetalPipeline*)command.data.set_compute_pipeline.pipeline)->compute_handle]; - - } - break; - case GFXCommandType::SetVertexBuffer: - { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.set_vertex_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.set_vertex_buffer.offset atIndex:(NSUInteger)command.data.set_vertex_buffer.index ]; - } - break; - case GFXCommandType::SetIndexBuffer: - { - currentIndexBuffer = (GFXMetalBuffer*)command.data.set_index_buffer.buffer; - currentIndextype = command.data.set_index_buffer.index_type; - } - break; - case GFXCommandType::SetPushConstant: - { - if(currentPipeline == nullptr) - continue; - - if(current_encoder == CurrentEncoder::Render) { - [renderEncoder setVertexBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - [renderEncoder setFragmentBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - } - } - break; - case GFXCommandType::BindShaderBuffer: - { - if(current_encoder == CurrentEncoder::Render) { - [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - - [renderEncoder setFragmentBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - } - } - break; - case GFXCommandType::BindTexture: - { - if(current_encoder == CurrentEncoder::Render) { - if(command.data.bind_texture.texture != nullptr) { - [renderEncoder setVertexSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setVertexTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - } else { - [renderEncoder setVertexTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; - } - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - } - } - break; - case GFXCommandType::BindSampler: - { - needEncoder(CurrentEncoder::Render); - - if(command.data.bind_sampler.sampler != nullptr) { - [renderEncoder setFragmentSamplerState:((GFXMetalSampler*)command.data.bind_sampler.sampler)->handle atIndex:(NSUInteger)command.data.bind_sampler.index]; - } else { - [renderEncoder setFragmentSamplerState:nil atIndex:(NSUInteger)command.data.bind_sampler.index]; - } - } - break; - case GFXCommandType::Draw: - { - needEncoder(CurrentEncoder::Render); - - if(currentPipeline == nullptr) - continue; - - [renderEncoder drawPrimitives:currentPipeline->primitiveType vertexStart:(NSUInteger)command.data.draw.vertex_offset vertexCount:(NSUInteger)command.data.draw.vertex_count instanceCount:(NSUInteger)command.data.draw.instance_count - baseInstance:(NSUInteger)command.data.draw.base_instance]; - } - break; - case GFXCommandType::DrawIndexed: - { - needEncoder(CurrentEncoder::Render); - - if(currentIndexBuffer == nullptr) - continue; - - if(currentPipeline == nullptr) - continue; - - MTLIndexType indexType; - int indexSize; - switch(currentIndextype) { - case IndexType::UINT16: - { - indexType = MTLIndexTypeUInt16; - indexSize = sizeof(uint16_t); - } - break; - case IndexType::UINT32: - { - indexType = MTLIndexTypeUInt32; - indexSize = sizeof(uint32_t); - } - break; - } - - for(auto& stride : currentPipeline->vertexStrides) - [renderEncoder setVertexBufferOffset:(NSUInteger)command.data.draw_indexed.vertex_offset * stride.stride atIndex:stride.location]; - - [renderEncoder - drawIndexedPrimitives:currentPipeline->primitiveType - indexCount:(NSUInteger)command.data.draw_indexed.index_count - indexType:indexType - indexBuffer:currentIndexBuffer->get(currentFrameIndex) - indexBufferOffset:(NSUInteger)command.data.draw_indexed.first_index * indexSize]; - } - break; - case GFXCommandType::MemoryBarrier: - { - needEncoder(CurrentEncoder::Render); - - #ifdef PLATFORM_MACOS - [renderEncoder memoryBarrierWithScope:MTLBarrierScopeTextures afterStages:MTLRenderStageFragment beforeStages:MTLRenderStageFragment]; - #endif - } - break; - case GFXCommandType::CopyTexture: - { - needEncoder(CurrentEncoder::Blit); - - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)command.data.copy_texture.src; - GFXMetalTexture* metalToTexture = (GFXMetalTexture*)command.data.copy_texture.dst; - if(metalFromTexture != nullptr && metalToTexture != nullptr) { - const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6; - - [blitEncoder - copyFromTexture:metalFromTexture->handle - sourceSlice:0 - sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(command.data.copy_texture.width, command.data.copy_texture.height, 1) - toTexture:metalToTexture->handle - destinationSlice: slice_offset - destinationLevel:command.data.copy_texture.to_level - destinationOrigin: MTLOriginMake(0, 0, 0)]; - } - } - break; - case GFXCommandType::SetViewport: - { - MTLViewport viewport; - viewport.originX = command.data.set_viewport.viewport.x; - viewport.originY = command.data.set_viewport.viewport.y; - viewport.width = command.data.set_viewport.viewport.width; - viewport.height = command.data.set_viewport.viewport.height; - viewport.znear = command.data.set_viewport.viewport.min_depth; - viewport.zfar = command.data.set_viewport.viewport.max_depth; - - if(renderEncoder != nil) - [renderEncoder setViewport:viewport]; - - currentViewport = viewport; - } - break; - case GFXCommandType::SetScissor: - { - needEncoder(CurrentEncoder::Render); - - MTLScissorRect rect; - rect.x = (NSUInteger)command.data.set_scissor.rect.offset.x; - rect.y = (NSUInteger)command.data.set_scissor.rect.offset.y; - rect.width = (NSUInteger)command.data.set_scissor.rect.extent.width; - rect.height = (NSUInteger)command.data.set_scissor.rect.extent.height; - - [renderEncoder setScissorRect:rect]; - } - break; - case GFXCommandType::GenerateMipmaps: { - needEncoder(CurrentEncoder::Blit); - - GFXMetalTexture* metalTexture = (GFXMetalTexture*)command.data.generate_mipmaps.texture; - - [blitEncoder generateMipmapsForTexture: metalTexture->handle]; - } - break; - case GFXCommandType::SetDepthBias: { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setDepthBias:command.data.set_depth_bias.constant - slopeScale:command.data.set_depth_bias.slope_factor - clamp:command.data.set_depth_bias.clamp]; - } - break; - case GFXCommandType::PushGroup: { - [commandBuffer pushDebugGroup:[NSString stringWithUTF8String:command.data.push_group.name.data()]]; - } - break; - case GFXCommandType::PopGroup: { - [commandBuffer popDebugGroup]; - } - break; - case GFXCommandType::InsertLabel: { - switch(current_encoder) { - case CurrentEncoder::Render: - [renderEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; - break; - case CurrentEncoder::Blit: - [blitEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; - break; - default: - break; - } - } - break; - case GFXCommandType::Dispatch: { - needEncoder(CurrentEncoder::Compute); - - [computeEncoder dispatchThreadgroups:MTLSizeMake(command.data.dispatch.group_count_x, command.data.dispatch.group_count_y, command.data.dispatch.group_count_z) threadsPerThreadgroup:currentPipeline->threadGroupSize]; - } - break; - } - } - - if(renderEncoder != nil) - [renderEncoder endEncoding]; - - if(blitEncoder != nil) - [blitEncoder endEncoding]; - - [commandBuffer addCompletedHandler:^(id _Nonnull) { - for(auto [i, buffer] : utility::enumerate(command_buffers)) { - if(buffer == command_buffer) - free_command_buffers[i] = true; - } - }]; - - if(window != -1) { - [commandBuffer presentDrawable:drawable]; - [commandBuffer commit]; - - currentFrameIndex = (currentFrameIndex + 1) % 3; - } else { - [commandBuffer commit]; - } - } -} diff --git a/engine/gfx/metal/src/gfx_metal_buffer.hpp b/engine/gfx/metal/src/gfx_metal_buffer.hpp deleted file mode 100755 index 670b8a9..0000000 --- a/engine/gfx/metal/src/gfx_metal_buffer.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "gfx_buffer.hpp" - -class GFXMetalBuffer : public GFXBuffer { -public: - id handles[3] = {nil, nil, nil}; - bool dynamicData = false; - - id get(int frameIndex) { - if(dynamicData) { - return handles[frameIndex]; - } else { - return handles[0]; - } - } -}; diff --git a/engine/gfx/metal/src/gfx_metal_framebuffer.hpp b/engine/gfx/metal/src/gfx_metal_framebuffer.hpp deleted file mode 100755 index 9c0eeb0..0000000 --- a/engine/gfx/metal/src/gfx_metal_framebuffer.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -#include "gfx_framebuffer.hpp" - -class GFXMetalTexture; - -class GFXMetalFramebuffer : public GFXFramebuffer { -public: - std::vector attachments; -}; diff --git a/engine/gfx/metal/src/gfx_metal_pipeline.hpp b/engine/gfx/metal/src/gfx_metal_pipeline.hpp deleted file mode 100755 index 8c94c96..0000000 --- a/engine/gfx/metal/src/gfx_metal_pipeline.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "gfx_pipeline.hpp" - -class GFXMetalPipeline : public GFXPipeline { -public: - std::string label; - - id handle = nil; - id compute_handle = nil; - - MTLSize threadGroupSize; - - id depthStencil = nil; - MTLPrimitiveType primitiveType; - - MTLCullMode cullMode; - GFXWindingMode winding_mode; - - struct VertexStride { - int location, stride; - }; - - std::vector vertexStrides; - - int pushConstantSize = 0; - int pushConstantIndex = 0; - - bool renderWire = false; -}; diff --git a/engine/gfx/metal/src/gfx_metal_renderpass.hpp b/engine/gfx/metal/src/gfx_metal_renderpass.hpp deleted file mode 100755 index d793af9..0000000 --- a/engine/gfx/metal/src/gfx_metal_renderpass.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include "gfx_renderpass.hpp" - -class GFXMetalRenderPass : public GFXRenderPass { -public: - std::vector attachments; -}; diff --git a/engine/gfx/metal/src/gfx_metal_sampler.hpp b/engine/gfx/metal/src/gfx_metal_sampler.hpp deleted file mode 100755 index aadef10..0000000 --- a/engine/gfx/metal/src/gfx_metal_sampler.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include "gfx_sampler.hpp" - -class GFXMetalSampler : public GFXSampler { -public: - id handle = nil; -}; diff --git a/engine/gfx/metal/src/gfx_metal_texture.hpp b/engine/gfx/metal/src/gfx_metal_texture.hpp deleted file mode 100755 index 8eecab3..0000000 --- a/engine/gfx/metal/src/gfx_metal_texture.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include "gfx_texture.hpp" - -class GFXMetalTexture : public GFXTexture { -public: - id handle = nil; - id sampler = nil; - - int array_length = 1; - bool is_cubemap = false; - - MTLPixelFormat format; -}; diff --git a/platforms/CMakeLists.txt b/platforms/CMakeLists.txt index 19230f2..31b1272 100755 --- a/platforms/CMakeLists.txt +++ b/platforms/CMakeLists.txt @@ -7,7 +7,7 @@ if(ENABLE_LINUX) endif() if(ENABLE_MACOS) - add_subdirectory(mac) + add_subdirectory(sdl) endif() if(ENABLE_IOS) diff --git a/platforms/mac/CMakeLists.txt b/platforms/mac/CMakeLists.txt deleted file mode 100755 index b68280d..0000000 --- a/platforms/mac/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -include(../../cmake/AddPlatformExecutable.cmake) - -add_platform( - MAIN_FILE - main.mm.in - SRC - ${CMAKE_CURRENT_SOURCE_DIR}/file.mm - EXECUTABLE_PROPERTIES - MACOSX_BUNDLE ON - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" - LINK_LIBRARIES - Core - GFXMetal - "-framework Cocoa" - "-framework QuartzCore" - "-framework GameController" - COMPILE_OPTIONS - -std=c++17 -) - -function(add_platform_commands target) - target_link_options(${target} BEFORE PRIVATE -pagezero_size 10000 -image_base 100000000 -) - if(NOT SKIP_DATA) - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/../Resources/data) - endif() - - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/../Resources/shaders) -endfunction() diff --git a/platforms/mac/file.mm b/platforms/mac/file.mm deleted file mode 100755 index 14af39e..0000000 --- a/platforms/mac/file.mm +++ /dev/null @@ -1,42 +0,0 @@ -#include "file.hpp" - -#import -#include - -#import - -#include "string_utils.hpp" - -#include "log.hpp" - -inline std::string clean_path(const std::string_view path) { - auto p = replace_substring(path, "%20", " "); - - // this is a path returned by an editor, so skip it - // TODO: find a better way to do this!! NOO!! - if(p.find("file:///") != std::string::npos) - return p.substr(7, p.length()); - else - return p; -} - -void prism::set_domain_path(const prism::domain domain, const prism::path path) { - NSBundle* bundle = [NSBundle mainBundle]; - NSString* resourceFolderPath = [bundle resourcePath]; - - std::string s = std::string(path); - s = replace_substring(s, "{resource_dir}", [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]); - - // basically, if we pass a relative path this will convert it to an absolute one, making get_relative_path functional. - NSURL * bundleURL = [[bundle bundleURL] URLByDeletingLastPathComponent]; - NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%s", s.c_str()] relativeToURL:bundleURL]; - - domain_data[static_cast(domain)] = clean_path([[[url absoluteURL] absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]); -} - -prism::path prism::get_writeable_directory() { - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString* resourceFolderPath = paths[0]; - - return [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]; -} diff --git a/platforms/mac/main.mm.in b/platforms/mac/main.mm.in deleted file mode 100755 index 402ba69..0000000 --- a/platforms/mac/main.mm.in +++ /dev/null @@ -1,634 +0,0 @@ -#import -#import -#import -#include -#include -#include -#include -#include -#include -#include - -#include <@APP_INCLUDE@> - -uint64_t last_time = 0; -bool is_qutting = false; - -static std::map inputToKeyCode = { { - {InputButton::C, 8}, - {InputButton::V, 9}, - {InputButton::X, 7}, - {InputButton::Q, 12}, - {InputButton::Y, 16}, - {InputButton::Z, 6}, - {InputButton::Backspace, 51}, - {InputButton::Enter, 36}, - {InputButton::Space, 49}, - {InputButton::Shift, 10}, - {InputButton::A, 0}, - {InputButton::W, 13}, - {InputButton::S, 1}, - {InputButton::D, 2}, - {InputButton::Escape, 53}, - {InputButton::Tab, 48}, - {InputButton::LeftArrow, 123}, - {InputButton::RightArrow, 124} -}}; - -struct NativeWindow; - -const char* platform::get_name() { - return "macOS"; -} - -int platform::get_keycode(InputButton key) { - if(inputToKeyCode.count(key)) - return inputToKeyCode[key]; - else - return -1; -} - -GFX* interface = nullptr; - -@APP_CLASS@* app = nullptr; - -float scrollX = 0.0f, scrollY = 0.0f; - -std::array inputKeys; - -float rightX = 0.0f, rightY = 0.0f; -float leftX = 0.0f, leftY = 0.0f; - -@interface GameView : NSObject - -@property NativeWindow *native; - -@end - -struct NativeWindow { - int index = 0; - NSWindow* window; - GameView* delegate; - CAMetalLayer* layer; - bool willCaptureMouse = false; - - int currentWidth = 0, currentHeight = 0; - int timeout = 0; - - NSPoint currentMousePos; - bool showingCursor = true; - bool inFocus = true; -}; - -std::vector windows; - -NativeWindow* get_window(const int index) { - for(auto& window : windows) { - if(window->index == index) - return window; - } - - return nullptr; -} - -@implementation GameView - -- (void)gameQuit { - engine->prepare_quit(); -} -- (void)gameFocus { - if(![self native]->showingCursor) - [NSCursor hide]; - - [self native]->inFocus = true; -} -- (void)gameLostFocus { - if(![self native]->showingCursor) - [NSCursor unhide]; - - [self native]->inFocus = false; -} - -const double NANOSECONDS_TO_MILLISECONDS = 1.0 / 1000000000.0; - -- (void)update { - const bool is_main_window = [self native]->index == 0; - - if(is_main_window) { - if([self native]->willCaptureMouse && [self native]->timeout > 5 && [self native]->inFocus) { - NSPoint point; - point.x = [self native]->window.frame.origin.x + ([self native]->currentWidth / 2); - point.y = [NSScreen mainScreen].frame.size.height - ([self native]->window.frame.origin.y + ([self native]->currentHeight / 2)); - - CGWarpMouseCursorPosition(point); - CGAssociateMouseAndMouseCursorPosition(true); - - [self native]->currentMousePos.x = [self native]->currentWidth / 2; - [self native]->currentMousePos.y = [self native]->currentHeight / 2; - - [self native]->timeout = 0; - } - - [self native]->timeout++; - } -} - -- (void)render { - engine->render([self native]->index); -} - -- (void)windowDidResize:(NSNotification *)notification { - [self native]->currentWidth = [self native]->window.contentView.frame.size.width; - [self native]->currentHeight = [self native]->window.contentView.frame.size.height; - - NSRect bounds = [[self native]->layer bounds]; - bounds = [[self native]->window convertRectToBacking:bounds]; - - [self native]->layer.drawableSize = NSSizeToCGSize(bounds.size);; - - engine->resize([self native]->index, {static_cast([self native]->currentWidth), static_cast([self native]->currentHeight)}); -} - --(void)windowWillClose:(NSNotification *)notification { - if([self native]->index == 0) - is_qutting = app->should_quit(); -} - -- (void) controllerConnected { - GCController* controller = [GCController controllers][0]; - [[controller extendedGamepad] setValueChangedHandler:^(GCExtendedGamepad * _Nonnull gamepad, GCControllerElement * _Nonnull element) { - const auto& handle_element = [element](int index, GCControllerElement* e) { - if(element == e) - inputKeys[index] = [(GCControllerButtonInput*)e value] == 1.0f; - }; - - handle_element(0, [[controller extendedGamepad] buttonA]); - handle_element(1, [[controller extendedGamepad] buttonB]); - handle_element(2, [[controller extendedGamepad] buttonX]); - handle_element(3, [[controller extendedGamepad] buttonY]); - - if(element == [[controller extendedGamepad] dpad]) { - inputKeys[4] = [[[[controller extendedGamepad] dpad] up] value] == 1.0f; - inputKeys[5] = [[[[controller extendedGamepad] dpad] down] value] == 1.0f; - inputKeys[6] = [[[[controller extendedGamepad] dpad] left] value] == 1.0f; - inputKeys[7] = [[[[controller extendedGamepad] dpad] right] value] == 1.0f; - } - - if(element == [[controller extendedGamepad] leftThumbstick]) { - leftX = [[[[controller extendedGamepad] leftThumbstick] xAxis] value]; - leftY = [[[[controller extendedGamepad] leftThumbstick] yAxis] value]; - } - - if(element == [[controller extendedGamepad] rightThumbstick]) { - rightX = [[[[controller extendedGamepad] rightThumbstick] xAxis] value]; - rightY = [[[[controller extendedGamepad] rightThumbstick] yAxis] value]; - } - }]; -} - -@end - -std::map pressed; -NSString* currentCharString = nil; - -bool platform::supports_feature(const PlatformFeature feature) { - switch(feature) { - case PlatformFeature::Windowing: - return true; - } - - return false; -} - -bool platform::get_key_down(const InputButton key) { - if(key == InputButton::ButtonA) - return inputKeys[0]; - - if(key == InputButton::ButtonB) - return inputKeys[1]; - - if(key == InputButton::ButtonX) - return inputKeys[2]; - - if(key == InputButton::ButtonY) - return inputKeys[3]; - - if(key == InputButton::DPadUp) - return inputKeys[4]; - - if(key == InputButton::DPadDown) - return inputKeys[5]; - - if(key == InputButton::DPadLeft) - return inputKeys[6]; - - if(key == InputButton::DPadRight) - return inputKeys[7]; - - if(inputToKeyCode.count(key)) - return pressed[inputToKeyCode[key]]; - else - return false; -} - -char* platform::translate_keycode(const unsigned int keycode) { - return const_cast([currentCharString UTF8String]); -} - -inline std::string clean_path(const std::string_view path) { - auto p = replace_substring(path, "%20", " "); - - // this is a path returned by an editor, so skip it - // TODO: find a better way to do this!! NOO!! - if(p.find("file:///") != std::string::npos) - return p.substr(7, p.length()); - else - return p; -} - -void platform::open_dialog(const bool existing, std::function returnFunction, bool openDirectory) { - NSOpenPanel* openDlg = [NSOpenPanel openPanel]; - - [openDlg setCanChooseFiles:YES]; - - [openDlg setAllowsMultipleSelection:NO]; - - [openDlg setCanChooseDirectories:openDirectory]; - - [openDlg setCanChooseFiles:!openDirectory]; - - if([openDlg runModal] == NSModalResponseOK) - returnFunction(clean_path([openDlg.URLs[0].absoluteString UTF8String])); -} - -void platform::save_dialog(std::function returnFunction) { - NSSavePanel* openDlg = [NSSavePanel savePanel]; - - if ([openDlg runModal] == NSModalResponseOK) - returnFunction(clean_path([openDlg.URL.absoluteString UTF8String])); -} - -void platform::capture_mouse(const bool capture) { - windows[0]->willCaptureMouse = capture; - - if(windows[0]->showingCursor && capture) { - [NSCursor hide]; - windows[0]->showingCursor = false; - } else if(!windows[0]->showingCursor && !capture) { - [NSCursor unhide]; - windows[0]->showingCursor = true; - } -} - -float platform::get_window_dpi(const int index) { - auto window = get_window(index); - return [window->window backingScaleFactor]; -} - -float platform::get_monitor_dpi() { - return [[NSScreen mainScreen] backingScaleFactor]; -} - -CGRect toTopLeftSpace(NSRect frame) { - frame.origin.y = NSMaxY([[NSScreen mainScreen] frame]) - NSMaxY(frame); - return NSRectToCGRect(frame); -} - -prism::Rectangle platform::get_monitor_resolution() { - auto frame = toTopLeftSpace([[NSScreen mainScreen] frame]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y), static_cast(frame.size.width), static_cast(frame.size.height)}; -} - -prism::Rectangle platform::get_monitor_work_area() { - auto frame = toTopLeftSpace([[NSScreen mainScreen] visibleFrame]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y), static_cast(frame.size.width), static_cast(frame.size.height)}; -} - -NSPoint get_fixed_cursor_point(NSPoint point) { - return {point.x, std::max(windows[0]->currentHeight - point.y, 0.0)}; -} - -prism::Offset platform::get_cursor_position() { - return {static_cast(windows[0]->currentMousePos.x), static_cast(windows[0]->currentMousePos.y)}; -} - -prism::Offset platform::get_screen_cursor_position() { - return {static_cast([NSEvent mouseLocation].x), static_cast([[NSScreen mainScreen] frame].size.height - [NSEvent mouseLocation].y)}; -} - -std::tuple platform::get_wheel_delta() { - return {scrollX, scrollY}; -} - -std::tuple platform::get_left_stick_position() { - return {leftX, leftY}; -} - -std::tuple platform::get_right_stick_position() { - return {rightX, rightY}; -} - -prism::Extent platform::get_window_size(const int index) { - auto window = get_window(index); - return {static_cast(window->currentWidth), static_cast(window->currentHeight)}; -} - -prism::Extent platform::get_window_drawable_size(const int index) { - auto window = get_window(index); - return {static_cast(window->currentWidth * window->window.backingScaleFactor), static_cast(window->currentHeight * window->window.backingScaleFactor)}; -} - -prism::Offset platform::get_window_position(const int index) { - auto window = get_window(index); - - auto frame = toTopLeftSpace([window->window contentRectForFrameRect:[window->window frame]]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y)}; -} - -bool platform::is_window_focused(const int index) { - auto window = get_window(index); - - return [window->window isKeyWindow]; -} - -void platform::set_window_focused(const int index) { - auto window = get_window(index); - [window->window makeKeyWindow]; -} - -bool platform::get_mouse_button_down(const int button) { - return (button + 1) & [NSEvent pressedMouseButtons]; -} - -void platform::set_window_position(const int index, const prism::Offset offset) { - auto window = get_window(index); - - NSPoint p; - p.x = offset.x; - p.y = [[NSScreen mainScreen] frame].size.height - offset.y; - - [window->window setFrameTopLeftPoint:p]; -} - -void platform::set_window_size(const int index, const prism::Extent extent) { - auto window = get_window(index); - - NSSize size; - size.width = extent.width; - size.height = extent.height; - - [window->window setContentSize:size]; -} - -void platform::set_window_title(const int index, const std::string_view title) { - auto window = get_window(index); - [window->window setTitle:[NSString stringWithUTF8String:title.data()]]; -} - -void platform::mute_output() {} -void platform::unmute_output() {} - -PlatformTheme platform::get_theme() { - auto str = [[[NSApplication sharedApplication] effectiveAppearance] name]; - - if(str == NSAppearanceNameAqua) - return PlatformTheme::Light; - else if(str == NSAppearanceNameDarkAqua) - return PlatformTheme::Dark; - - return PlatformTheme::Light; -} - -int platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) { - NativeWindow* native = new NativeWindow(); - native->index = windows.size(); - GameView* del = [[GameView alloc] init]; - native->delegate = del; - windows.push_back(native); - - NSRect nrect = NSMakeRect(rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height); - - NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled - | NSWindowStyleMaskClosable - | NSWindowStyleMaskMiniaturizable; - - if(flags == WindowFlags::Resizable) - windowStyle |= NSWindowStyleMaskResizable; - else if(flags == WindowFlags::Borderless) - windowStyle = NSWindowStyleMaskBorderless; - - native->window = [[NSWindow alloc] - initWithContentRect: nrect - styleMask:windowStyle - backing: NSBackingStoreBuffered - defer: NO]; - - native->currentWidth = rect.extent.width; - native->currentHeight = rect.extent.height; - - native->layer = [CAMetalLayer layer]; - - NSView* view = [[NSView alloc] init]; - view.wantsLayer = YES; - view.layer = native->layer; - - native->layer.contentsScale = [native->window backingScaleFactor]; - - engine->add_window(view.layer, native->index, rect.extent); - - [native->window setContentView:view]; - - if(native->index == 0) - app->initialize_render(); - - [native->window setTitle:[NSString stringWithUTF8String:title.data()]]; - - [del setNative:native]; - - [native->window setDelegate:del]; - [native->window orderFrontRegardless]; - - if(native->index == 0) { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:del - selector:@selector(gameQuit) - name:NSApplicationWillTerminateNotification - object:nil]; - - [nc addObserver:del - selector:@selector(gameFocus) - name:NSApplicationDidBecomeActiveNotification - object:nil]; - - [nc addObserver:del - selector:@selector(gameLostFocus) - name:NSApplicationDidResignActiveNotification - object:nil]; - - [nc addObserver:del - selector:@selector(controllerConnected) - name:GCControllerDidConnectNotification - object:nil]; - } - - return native->index; -} - -void platform::close_window(const int index) { - auto window = get_window(index); - - engine->remove_window(window->index); - - [window->window close]; - - utility::erase(windows, window); -} - -void platform::force_quit() { - [NSApp terminate:nil]; -} - -int main(int argc, char* argv[]) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - NSApp = [NSApplication sharedApplication]; - - engine = new prism::engine(argc, argv); - - app = new @APP_CLASS@(); - engine->set_app(app); - - GFXCreateInfo createInfo = {}; - createInfo.api_validation_enabled = true; - - interface = new GFXMetal(); - if(interface->initialize(createInfo)) { - engine->set_gfx(interface); - } else { - NSLog(@"Failed to create Metal context!"); - - return -1; - } - - app_main(engine); - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) { - pressed[event.keyCode] = true; - currentCharString = event.characters; - - engine->process_key_down(event.keyCode); - - return (NSEvent*)nil; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:^(NSEvent *event) { - pressed[event.keyCode] = false; - - engine->process_key_up(event.keyCode); - - return (NSEvent*)nil; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^(NSEvent *event) { - auto point = get_fixed_cursor_point(event.locationInWindow); - engine->process_mouse_down(0, {static_cast(point.x), static_cast(point.y)}); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDown handler:^(NSEvent *event) { - auto point = get_fixed_cursor_point(event.locationInWindow); - engine->process_mouse_down(1, {static_cast(point.x), static_cast(point.y)}); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDragged handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDragged handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel handler:^(NSEvent *event) { - double wheel_dx = 0.0; - double wheel_dy = 0.0; - - wheel_dx = [event scrollingDeltaX]; - wheel_dy = [event scrollingDeltaY]; - if ([event hasPreciseScrollingDeltas]) - { - wheel_dx *= 0.1; - wheel_dy *= 0.1; - } - - scrollX += wheel_dx * 0.1f; - scrollY += wheel_dy * 0.1f; - - return event; - }]; - - last_time = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - - while (!is_qutting) { - @autoreleasepool { - NSEvent* event = nullptr; - do { - event = [NSApp nextEventMatchingMask: NSEventMaskAny - untilDate: nil - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if(event) - [NSApp sendEvent: event]; - } while(event); - - const uint64_t current = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - const uint64_t elapsed = current - last_time; - - if(engine->is_quitting()) - is_qutting = true; - - for(auto& window : windows) { - if(window != nullptr) - [window->delegate update]; - } - - engine->update(elapsed * NANOSECONDS_TO_MILLISECONDS); - - engine->begin_frame(elapsed * NANOSECONDS_TO_MILLISECONDS); - - for(auto& window : windows) { - if(window != nullptr) - [window->delegate render]; - } - - engine->end_frame(); - - scrollX = 0.0f; - scrollY = 0.0f; - - last_time = current; - } - } - - app->prepare_quit(); - - [NSApp release]; - [pool release]; - - return 0; -} diff --git a/platforms/sdl/CMakeLists.txt b/platforms/sdl/CMakeLists.txt index 0b4d79c..788c264 100644 --- a/platforms/sdl/CMakeLists.txt +++ b/platforms/sdl/CMakeLists.txt @@ -4,6 +4,9 @@ add_platform( SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp MAIN_FILE main.cpp.in + EXECUTABLE_PROPERTIES + MACOSX_BUNDLE ON + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" LINK_LIBRARIES SDL2::Main Core diff --git a/platforms/mac/Info.plist.in b/platforms/sdl/Info.plist.in similarity index 100% rename from platforms/mac/Info.plist.in rename to platforms/sdl/Info.plist.in From f6df3d23b37c801c8be72c20ef862900a3c755bd Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 13:47:42 -0400 Subject: [PATCH 02/12] Fix Vulkan queue creation on macOS --- engine/gfx/vulkan/include/gfx_vulkan.hpp | 7 ---- engine/gfx/vulkan/src/gfx_vulkan.cpp | 48 +++++++++++++----------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/engine/gfx/vulkan/include/gfx_vulkan.hpp b/engine/gfx/vulkan/include/gfx_vulkan.hpp index 5205199..e3484ee 100755 --- a/engine/gfx/vulkan/include/gfx_vulkan.hpp +++ b/engine/gfx/vulkan/include/gfx_vulkan.hpp @@ -1,12 +1,5 @@ #pragma once -#ifdef PLATFORM_WINDOWS -#define NOMINMAX // donut define max in windows.h -#define VK_USE_PLATFORM_WIN32_KHR -#else -#define VK_USE_PLATFORM_XCB_KHR -#endif - #include #include diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp index 687e6f3..14ca96a 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan.cpp +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "gfx_vulkan_buffer.hpp" #include "gfx_vulkan_pipeline.hpp" @@ -20,11 +19,6 @@ #include -#ifdef PLATFORM_LINUX -#include - -#endif - VkFormat toVkFormat(GFXPixelFormat format) { switch (format) { case GFXPixelFormat::R_32F: @@ -1789,7 +1783,33 @@ void GFXVulkan::createLogicalDevice(std::vector extensions) { queueCreateInfo.pQueuePriorities = &queuePriority; queueCreateInfos.push_back(queueCreateInfo); - } + } else { + // graphics + { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } + + // present + { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = presentFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } + } VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -1823,23 +1843,9 @@ void GFXVulkan::createLogicalDevice(std::vector extensions) { } void GFXVulkan::createSwapchain(NativeSurface* native_surface, VkSwapchainKHR oldSwapchain) { - -#ifdef PLATFORM_WINDOWS_OLD - // create win32 surface - if(native_surface->surface == VK_NULL_HANDLE) - { - VkWin32SurfaceCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - createInfo.hwnd = (HWND)native_surface->windowNativeHandle; - createInfo.hinstance = GetModuleHandle(nullptr); - - vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &native_surface->surface); - } -#else if(native_surface->surface == VK_NULL_HANDLE) { native_surface->surface = (VkSurfaceKHR)platform::create_native_surface(native_surface->identifier, (void*)instance); } -#endif // TODO: fix this pls VkBool32 supported; From 45977b4ac1e4714e91dca05643b911c7a49634ed Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 13:51:36 -0400 Subject: [PATCH 03/12] Emit SPIR-V shaders on macOS --- tools/shadercompiler/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tools/shadercompiler/main.cpp b/tools/shadercompiler/main.cpp index d3ddc12..4ce5bdd 100755 --- a/tools/shadercompiler/main.cpp +++ b/tools/shadercompiler/main.cpp @@ -42,14 +42,8 @@ int main(int argc, char* argv[]) { ShaderLanguage language; CompileOptions options; -#ifdef PLATFORM_MACOS - options.is_apple_mobile = (bool)argv[3]; - - language = ShaderLanguage::MSL; -#else language = ShaderLanguage::SPIRV; -#endif - + const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options); if(!compiled_source.has_value()) { prism::log::error(System::Core, "Error when compiling {}!", source_path); From f213d3d548bda291dd14a25a64846deaf1d07223 Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 17:19:59 -0400 Subject: [PATCH 04/12] Fix resource path handling on macOS --- example/src/example.cpp | 6 +++--- platforms/sdl/CMakeLists.txt | 22 +++++++++++++++++----- platforms/sdl/file.cpp | 4 ++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/example/src/example.cpp b/example/src/example.cpp index 1577b56..4e836ac 100644 --- a/example/src/example.cpp +++ b/example/src/example.cpp @@ -8,7 +8,7 @@ #include "path.hpp" void app_main(prism::engine* engine) { - prism::set_domain_path(prism::domain::app, "data"); + prism::set_domain_path(prism::domain::app, "{resource_dir}/data"); prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders"); platform::open_window("Example", {-1, -1, 1280, 720}, WindowFlags::Resizable); @@ -30,8 +30,8 @@ void ExampleApp::initialize_render() { auto sphere_obj = scene->add_object(); auto& sphere_render = scene->add(sphere_obj); - sphere_render.mesh = assetm->get(prism::path("data/models/sphere.model")); - sphere_render.materials = { assetm->get(prism::path("data/materials/Material.material")) }; + sphere_render.mesh = assetm->get(prism::path(prism::app_domain / "models/sphere.model")); + sphere_render.materials = { assetm->get(prism::path(prism::app_domain / "materials/Material.material")) }; auto probe_obj = scene->add_object(); scene->add(probe_obj); diff --git a/platforms/sdl/CMakeLists.txt b/platforms/sdl/CMakeLists.txt index 788c264..7097698 100644 --- a/platforms/sdl/CMakeLists.txt +++ b/platforms/sdl/CMakeLists.txt @@ -15,7 +15,11 @@ add_platform( function(add_platform_commands target) if(NOT SKIP_DATA) - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/data) + if(ENABLE_MACOS) + add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/../Resources/data) + else() + add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/data) + endif() endif() # we HAVE to create this dummy target to convince CMake to properly copy over shader files. @@ -27,10 +31,18 @@ function(add_platform_commands target) add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/dummy) - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy - COMMAND ${CMAKE_COMMAND} -E make_directory $/shaders - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/shaders - ) + if(ENABLE_MACOS) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy + COMMAND ${CMAKE_COMMAND} -E make_directory $/../Resources/shaders + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/../Resources/shaders + ) + else() + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/dummy + COMMAND ${CMAKE_COMMAND} -E make_directory $/shaders + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/shaders + ) + endif() + add_dependencies(${target} ${DUMMY_NAME}) endfunction() diff --git a/platforms/sdl/file.cpp b/platforms/sdl/file.cpp index e1ad9f2..3d18fbb 100644 --- a/platforms/sdl/file.cpp +++ b/platforms/sdl/file.cpp @@ -3,7 +3,11 @@ #include "string_utils.hpp" void prism::set_domain_path(const prism::domain domain, const prism::path path) { +#ifdef PLATFORM_MACOS + domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}/", "../Resources/"); +#else domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}/", ""); +#endif } prism::path prism::get_writeable_directory() { From b61eb986485063a273943df557b48956f8f3e8bc Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 22:53:42 -0400 Subject: [PATCH 05/12] Fixes some clang-tidy warnings, remove fpermissive --- cmake/Common.cmake | 5 -- engine/core/include/imgui_utility.hpp | 2 +- engine/core/src/engine.cpp | 2 + engine/gfx/vulkan/include/gfx_vulkan.hpp | 25 +++++---- engine/gfx/vulkan/src/gfx_vulkan.cpp | 67 ++++++++++++++---------- 5 files changed, 55 insertions(+), 46 deletions(-) diff --git a/cmake/Common.cmake b/cmake/Common.cmake index 672d5f1..30da139 100755 --- a/cmake/Common.cmake +++ b/cmake/Common.cmake @@ -1,11 +1,6 @@ macro(set_engine_properties target) target_compile_features(${target} PUBLIC cxx_std_17) set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF) - - if(ENABLE_MACOS OR ENABLE_LINUX) - target_compile_options(${target} PUBLIC - -fpermissive) # ew but required for now TODO: remove and test! - endif() if(ENABLE_MACOS) target_compile_definitions(${target} PUBLIC PLATFORM_MACOS) diff --git a/engine/core/include/imgui_utility.hpp b/engine/core/include/imgui_utility.hpp index c31b92f..d866c47 100755 --- a/engine/core/include/imgui_utility.hpp +++ b/engine/core/include/imgui_utility.hpp @@ -37,7 +37,7 @@ namespace ImGui { ImGui::ProgressBar(progress_saturated, ImVec2(0.0f, 0.0f), buf); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::Text(label); + ImGui::Text("%s", label); } inline bool DragQuat(const char* label, Quaternion* quat) { diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp index 0d4709a..18486b9 100755 --- a/engine/core/src/engine.cpp +++ b/engine/core/src/engine.cpp @@ -94,6 +94,8 @@ void engine::quit() { bool engine::is_quitting() const { if(!windows.empty()) return windows[0]->quit_requested; + + return false; } void engine::prepare_quit() { diff --git a/engine/gfx/vulkan/include/gfx_vulkan.hpp b/engine/gfx/vulkan/include/gfx_vulkan.hpp index e3484ee..c5df577 100755 --- a/engine/gfx/vulkan/include/gfx_vulkan.hpp +++ b/engine/gfx/vulkan/include/gfx_vulkan.hpp @@ -11,7 +11,6 @@ struct NativeSurface { int identifier = -1; - void* windowNativeHandle; uint32_t surfaceWidth = -1, surfaceHeight = -1; std::vector imageAvailableSemaphores; @@ -36,28 +35,28 @@ class GFXVulkanPipeline; class GFXVulkan : public GFX { public: - bool is_supported() { return true; } + bool is_supported() override { return true; } ShaderLanguage accepted_shader_language() override { return ShaderLanguage::SPIRV; } - GFXContext required_context() { return GFXContext::Vulkan; } + GFXContext required_context() override { return GFXContext::Vulkan; } const char* get_name() override; - bool supports_feature(const GFXFeature feature) override; + bool supports_feature(GFXFeature feature) override; bool initialize(const GFXCreateInfo& info) override; - void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override; - void recreate_view(const int identifier, const uint32_t width, const uint32_t height) override; + void initialize_view(void* native_handle, int identifier, uint32_t width, uint32_t height) override; + void recreate_view(int identifier, uint32_t width, uint32_t height) override; // buffer operations - GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) override; - void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override; + GFXBuffer* create_buffer(void* data, GFXSize size, bool dynamic_data, GFXBufferUsage usage) override; + void copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) override; void* get_buffer_contents(GFXBuffer* buffer) override; void release_buffer_contents(GFXBuffer* buffer, void* handle) override; // texture operations GFXTexture* create_texture(const GFXTextureCreateInfo& info) override; - void copy_texture(GFXTexture* texture, void* data, const GFXSize size) override; + void copy_texture(GFXTexture* texture, void* data, GFXSize size) override; void copy_texture(GFXTexture* from, GFXTexture* to) override; void copy_texture(GFXTexture* from, GFXBuffer* to) override; @@ -75,11 +74,11 @@ public: GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override; // misc operations - GFXSize get_alignment(const GFXSize size) override; + GFXSize get_alignment(GFXSize size) override; - GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override; + GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use) override; - void submit(GFXCommandBuffer* command_buffer, const int identifier) override; + void submit(GFXCommandBuffer* command_buffer, int identifier) override; private: void createInstance(std::vector layers, std::vector extensions); @@ -104,7 +103,7 @@ private: VkImageLayout newLayout, VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - VkShaderModule createShaderModule(const uint32_t* code, const int length); + VkShaderModule createShaderModule(const uint32_t* code, int length); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp index 14ca96a..bd12ce7 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan.cpp +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -76,6 +76,8 @@ VkFormat toVkFormat(GFXVertexFormat format) { VkBlendFactor toVkFactor(GFXBlendFactor factor) { switch (factor) { + case GFXBlendFactor::Zero: + return VK_BLEND_FACTOR_ZERO; case GFXBlendFactor::One: return VK_BLEND_FACTOR_ONE; case GFXBlendFactor::OneMinusSrcAlpha: @@ -84,6 +86,12 @@ VkBlendFactor toVkFactor(GFXBlendFactor factor) { return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; case GFXBlendFactor::SrcAlpha: return VK_BLEND_FACTOR_SRC_ALPHA; + case GFXBlendFactor::DstAlpha: + return VK_BLEND_FACTOR_DST_ALPHA; + case GFXBlendFactor::SrcColor: + return VK_BLEND_FACTOR_SRC_COLOR; + case GFXBlendFactor::DstColor: + return VK_BLEND_FACTOR_DST_COLOR; } return VK_BLEND_FACTOR_ONE; @@ -223,11 +231,10 @@ bool GFXVulkan::initialize(const GFXCreateInfo& info) { void GFXVulkan::initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) { vkDeviceWaitIdle(device); - NativeSurface* surface = new NativeSurface(); + auto surface = new NativeSurface(); surface->identifier = identifier; surface->surfaceWidth = width; surface->surfaceHeight = height; - surface->windowNativeHandle = native_handle; createSwapchain(surface); createSyncPrimitives(surface); @@ -253,7 +260,7 @@ void GFXVulkan::recreate_view(const int identifier, const uint32_t width, const } GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) { - GFXVulkanBuffer* buffer = new GFXVulkanBuffer(); + auto buffer = new GFXVulkanBuffer(); vkDeviceWaitIdle(device); @@ -301,7 +308,7 @@ GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool d } void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) { - GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + auto vulkanBuffer = (GFXVulkanBuffer*)buffer; void* mapped_data = nullptr; vkMapMemory(device, vulkanBuffer->memory, offset, vulkanBuffer->size - offset, 0, &mapped_data); @@ -321,7 +328,7 @@ void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSi } void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) { - GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + auto vulkanBuffer = (GFXVulkanBuffer*)buffer; void* mapped_data; vkMapMemory(device, vulkanBuffer->memory, 0, VK_WHOLE_SIZE, 0, &mapped_data); @@ -330,7 +337,7 @@ void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) { } void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) { - GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + auto vulkanBuffer = (GFXVulkanBuffer*)buffer; VkMappedMemoryRange range = {}; range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; @@ -343,7 +350,7 @@ void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) { } GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { - GFXVulkanTexture* texture = new GFXVulkanTexture(); + auto texture = new GFXVulkanTexture(); vkDeviceWaitIdle(device); @@ -508,7 +515,7 @@ GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { } void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) { - GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)texture; + auto vulkanTexture = (GFXVulkanTexture*)texture; vkDeviceWaitIdle(device); @@ -577,8 +584,8 @@ void GFXVulkan::copy_texture(GFXTexture* from, GFXTexture* to) { } void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) { - GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)from; - GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)to; + auto vulkanTexture = (GFXVulkanTexture*)from; + auto vulkanBuffer = (GFXVulkanBuffer*)to; VkCommandBuffer commandBuffer = beginSingleTimeCommands(); @@ -599,7 +606,7 @@ void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) { } GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) { - GFXVulkanSampler* sampler = new GFXVulkanSampler(); + auto sampler = new GFXVulkanSampler(); const VkSamplerAddressMode samplerMode = toSamplerMode(info.samplingMode); @@ -623,15 +630,15 @@ GFXSampler* GFXVulkan::create_sampler(const GFXSamplerCreateInfo& info) { } GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& info) { - GFXVulkanFramebuffer* framebuffer = new GFXVulkanFramebuffer(); + auto framebuffer = new GFXVulkanFramebuffer(); vkDeviceWaitIdle(device); - GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)info.render_pass; + auto renderPass = (GFXVulkanRenderPass*)info.render_pass; std::vector attachments; for (auto& attachment : info.attachments) { - GFXVulkanTexture* texture = (GFXVulkanTexture*)attachment; + auto texture = (GFXVulkanTexture*)attachment; attachments.push_back(texture->view); VkImageLayout expectedLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -667,7 +674,7 @@ GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& in } GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info) { - GFXVulkanRenderPass* renderPass = new GFXVulkanRenderPass(); + auto renderPass = new GFXVulkanRenderPass(); vkDeviceWaitIdle(device); @@ -756,7 +763,7 @@ GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info } GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) { - GFXVulkanPipeline* pipeline = new GFXVulkanPipeline(); + auto pipeline = new GFXVulkanPipeline(); vkDeviceWaitIdle(device); @@ -929,6 +936,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate case GFXDepthMode::Greater: depthStencil.depthCompareOp = VK_COMPARE_OP_GREATER; break; + case GFXDepthMode::None: + break; } } @@ -982,6 +991,8 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate case GFXBindingType::Sampler: descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; break; + case GFXBindingType::PushConstant: + break; } VkDescriptorSetLayoutBinding layoutBinding = {}; @@ -1045,7 +1056,7 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate } GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) { - GFXVulkanPipeline* pipeline = new GFXVulkanPipeline(); + auto pipeline = new GFXVulkanPipeline(); vkDeviceWaitIdle(device); @@ -1117,6 +1128,8 @@ GFXPipeline* GFXVulkan::create_compute_pipeline(const GFXComputePipelineCreateIn case GFXBindingType::Sampler: descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; break; + case GFXBindingType::PushConstant: + break; } VkDescriptorSetLayoutBinding layoutBinding = {}; @@ -1170,7 +1183,7 @@ GFXSize GFXVulkan::get_alignment(GFXSize size) { } GFXCommandBuffer* GFXVulkan::acquire_command_buffer(bool for_presentation_use) { - GFXVulkanCommandBuffer* cmdbuf = new GFXVulkanCommandBuffer(); + auto cmdbuf = new GFXVulkanCommandBuffer(); if(!for_presentation_use) { VkCommandBufferAllocateInfo info = {}; @@ -1203,7 +1216,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { VkCommandBuffer cmd = VK_NULL_HANDLE; - GFXVulkanCommandBuffer* cmdbuf = (GFXVulkanCommandBuffer*)command_buffer; + auto cmdbuf = (GFXVulkanCommandBuffer*)command_buffer; if(cmdbuf->handle != VK_NULL_HANDLE) cmd = cmdbuf->handle; else if(current_surface != nullptr) @@ -1252,8 +1265,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { vkCmdEndRenderPass(cmd); } - GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass; - GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer; + auto renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass; + auto framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer; if (renderPass != nullptr) { currentRenderPass = renderPass->handle; @@ -1423,8 +1436,8 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { break; case GFXCommandType::CopyTexture: { - GFXVulkanTexture* src = (GFXVulkanTexture*)command.data.copy_texture.src; - GFXVulkanTexture* dst = (GFXVulkanTexture*)command.data.copy_texture.dst; + auto src = (GFXVulkanTexture*)command.data.copy_texture.src; + auto dst = (GFXVulkanTexture*)command.data.copy_texture.dst; const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6; @@ -1528,7 +1541,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { break; case GFXCommandType::GenerateMipmaps: { - auto texture = static_cast(command.data.generate_mipmaps.texture); + auto texture = dynamic_cast(command.data.generate_mipmaps.texture); for(int l = 0; l < texture->range.layerCount; l++) { int mip_width = texture->width; @@ -2089,7 +2102,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe // update set for (auto [i, buffer] : utility::enumerate(boundShaderBuffers)) { if (buffer.buffer != nullptr) { - GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer; + auto vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer; VkDescriptorBufferInfo bufferInfo = {}; bufferInfo.buffer = vulkanBuffer->handle; // will this break? @@ -2110,7 +2123,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe for (auto [i, texture] : utility::enumerate(boundTextures)) { if (texture != nullptr) { - GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*) texture; + auto vulkanTexture = (GFXVulkanTexture*) texture; VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -2146,7 +2159,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe for (auto [i, sampler] : utility::enumerate(boundSamplers)) { if (sampler != nullptr) { - GFXVulkanSampler* vulkanSampler = (GFXVulkanSampler*) sampler; + auto vulkanSampler = (GFXVulkanSampler*) sampler; VkDescriptorImageInfo imageInfo = {}; imageInfo.sampler = vulkanSampler->sampler; From 648d2968d4a267bacec172a66df65d24ee1193dc Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 22:59:56 -0400 Subject: [PATCH 06/12] Update Info.plist --- platforms/sdl/Info.plist.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platforms/sdl/Info.plist.in b/platforms/sdl/Info.plist.in index 80e4a27..67e5935 100644 --- a/platforms/sdl/Info.plist.in +++ b/platforms/sdl/Info.plist.in @@ -3,7 +3,7 @@ CFBundleDisplayName - Fantasy\U00A0app + ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleDevelopmentRegion English CFBundleExecutable @@ -19,7 +19,7 @@ CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName - Project Shopkeep + ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundlePackageType APPL CFBundleShortVersionString @@ -31,7 +31,7 @@ CSResourcesFileMapped NSHumanReadableCopyright - (c)2020 Blinding Light Games + (c) 2021 NSHighResolutionCapable From 626e314ec2afb175063ba99eaafd628d2c02446b Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 23:10:26 -0400 Subject: [PATCH 07/12] Completely remove the defunct UI system --- engine/core/CMakeLists.txt | 3 - engine/core/include/components.hpp | 11 -- engine/core/include/engine.hpp | 48 ------ engine/core/include/scene.hpp | 2 +- engine/core/include/screen.hpp | 43 ------ engine/core/include/uielement.hpp | 67 -------- engine/core/src/engine.cpp | 68 --------- engine/core/src/scene.cpp | 20 +-- engine/core/src/screen.cpp | 191 ----------------------- engine/renderer/include/renderer.hpp | 9 -- engine/renderer/src/renderer.cpp | 190 +---------------------- tools/common/src/commoneditor.cpp | 25 +-- tools/editor/CMakeLists.txt | 2 - tools/editor/include/uieditor.hpp | 27 ---- tools/editor/src/prismeditor.cpp | 19 --- tools/editor/src/uieditor.cpp | 218 --------------------------- 16 files changed, 4 insertions(+), 939 deletions(-) delete mode 100755 engine/core/include/screen.hpp delete mode 100755 engine/core/include/uielement.hpp delete mode 100755 engine/core/src/screen.cpp delete mode 100755 tools/editor/include/uieditor.hpp delete mode 100755 tools/editor/src/uieditor.cpp diff --git a/engine/core/CMakeLists.txt b/engine/core/CMakeLists.txt index 782a34c..e841389 100755 --- a/engine/core/CMakeLists.txt +++ b/engine/core/CMakeLists.txt @@ -6,8 +6,6 @@ set(SRC include/physics.hpp include/scene.hpp include/imgui_backend.hpp - include/uielement.hpp - include/screen.hpp include/object.hpp include/debug.hpp include/components.hpp @@ -19,7 +17,6 @@ set(SRC src/input.cpp src/physics.cpp src/imgui_backend.cpp - src/screen.cpp src/scene.cpp src/debug.cpp src/console.cpp) diff --git a/engine/core/include/components.hpp b/engine/core/include/components.hpp index 8da2a60..5e081ac 100755 --- a/engine/core/include/components.hpp +++ b/engine/core/include/components.hpp @@ -103,17 +103,6 @@ struct Camera { Matrix4x4 view, perspective; }; -namespace ui { - class Screen; -} - -struct UI { - int width = 1920, height = 1080; - - std::string ui_path; - ui::Screen* screen = nullptr; -}; - struct EnvironmentProbe { bool is_sized = true; prism::float3 size = prism::float3(10); diff --git a/engine/core/include/engine.hpp b/engine/core/include/engine.hpp index 1267318..47bd8c1 100755 --- a/engine/core/include/engine.hpp +++ b/engine/core/include/engine.hpp @@ -10,11 +10,6 @@ #include "path.hpp" class GFX; - -namespace ui { - class Screen; -} - class Scene; class RenderTarget; class Physics; @@ -141,22 +136,6 @@ namespace prism { */ void save_scene(std::string_view path); - /** Load a UI screen from disk. This will not change the current screen. - @param path The screen file path. - @return Returns a instance of the screen if successful, and nullptr on failure. - */ - ui::Screen* load_screen(const prism::path& path); - - /** Set the current screen. - @param screen The screen object to set as current. Can be null. - */ - void set_screen(ui::Screen* screen); - - /** Gets the current screen. - @return The current screen. Can be null. - */ - [[nodiscard]] ui::Screen* get_screen() const; - /** Load a prefab from disk. @param scene The scene to add the prefab to. @param path The prefab file path. @@ -231,31 +210,6 @@ namespace prism { */ void process_mouse_down(int button, prism::Offset offset); - /** Pushes a UI event for the current screen. Does nothing if there is no screen set. - @param name The name of the event. - @param data Data for the event. Defaulted to an empty string. - */ - void push_event(std::string_view name, std::string_view data = ""); - - /** Load a localization file from disk. This will change the current localization. - @param path The localization file path. - */ - void load_localization(std::string_view path); - - /** Queries whether or not the current localization loaded has a key. - @param id The key to query. - @return Whether or not the locale has the key specified. - @note Having no localization loaded will always return false. - */ - [[nodiscard]] bool has_localization(std::string_view id) const; - - /** Localizes a string. - @param id The locale key to use. - @return A localized string if the key is found, or an empty string if not found. - @note Having no localization loaded will always return a empty string. - */ - std::string localize(const std::string& id); - /** Adds a timer to the list of timers. @param timer The timer to add. @note The timer instance is passed by reference. Use this to keep track of your timers without having to query it's state back. @@ -335,8 +289,6 @@ namespace prism { bool paused = false; - ui::Screen* current_screen = nullptr; - Scene* current_scene = nullptr; std::vector> scenes; std::map path_to_scene; diff --git a/engine/core/include/scene.hpp b/engine/core/include/scene.hpp index 8a6df7c..2a4fcd6 100755 --- a/engine/core/include/scene.hpp +++ b/engine/core/include/scene.hpp @@ -201,7 +201,7 @@ class GFXFramebuffer; class GFXTexture; /// Represents a scene consisting of Objects with varying Components. -class Scene : public ObjectComponents { +class Scene : public ObjectComponents { public: /// If loaded from disk, the path to the scene file this originated from. std::string path; diff --git a/engine/core/include/screen.hpp b/engine/core/include/screen.hpp deleted file mode 100755 index 2ee05dd..0000000 --- a/engine/core/include/screen.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "uielement.hpp" -#include "file.hpp" -#include "common.hpp" - -class GFXBuffer; - -namespace ui { - class Screen { - public: - Screen() {} - Screen(const prism::path path); - - void process_event(const std::string& type, std::string data = ""); - - void process_mouse(const int x, const int y); - void calculate_sizes(); - - std::vector elements; - - UIElement* find_element(const std::string& id); - - using CallbackFunction = std::function; - std::map listeners; - - bool blurs_background = false; - - void add_listener(const std::string& id, std::function callback); - - prism::Extent extent; - bool view_changed = false; - - GFXBuffer* glyph_buffer = nullptr; - GFXBuffer* instance_buffer = nullptr; - GFXBuffer* elements_buffer = nullptr; - }; -} diff --git a/engine/core/include/uielement.hpp b/engine/core/include/uielement.hpp deleted file mode 100755 index f26c39c..0000000 --- a/engine/core/include/uielement.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include - -#include "assetptr.hpp" - -enum class MetricType { - Absolute, - Relative, - Offset -}; - -struct Color { - Color() : r(1.0f), g(1.0f), b(1.0f), a(1.0f) {} - - Color(const float v) : r(v), g(v), b(v), a(1.0f) {} - - union { - struct { - float r, g, b, a; - }; - - float v[4]; - }; -}; - -class GFXTexture; -class Texture; - -class UIElement { -public: - struct Metrics { - struct Metric { - MetricType type = MetricType::Absolute; - int value = 0; - }; - - Metric x, y, width, height; - } metrics; - - struct Background { - Color color = Color(0.0f); - std::string image; - - AssetPtr texture; - } background; - - enum class TextLocation { - TopLeft, - Center - } text_location = TextLocation::TopLeft; - - std::string id, text, parent; - - bool wrap_text = false; - - float absolute_x = 0.0f, absolute_y = 0.0f, absolute_width = 0.0f, absolute_height = 0.0f; - float text_x = 0.0f, text_y = 0.0f; - - bool visible = true; - - std::string on_click_script; -}; - -inline bool operator==(const UIElement& a, const UIElement& b) { - return a.id == b.id; -} diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp index 18486b9..69f4e0d 100755 --- a/engine/core/src/engine.cpp +++ b/engine/core/src/engine.cpp @@ -11,7 +11,6 @@ #include "json_conversions.hpp" #include "app.hpp" #include "assertions.hpp" -#include "screen.hpp" #include "renderer.hpp" #include "gfx.hpp" #include "imgui_backend.hpp" @@ -60,26 +59,12 @@ prism::app* engine::get_app() const { return app; } -void engine::load_localization(const std::string_view path) { - Expects(!path.empty()); - - auto file = prism::open_file(prism::app_domain / path); - if(file.has_value()) { - nlohmann::json j; - file->read_as_stream() >> j; - - strings = j["strings"].get>(); - } -} - void engine::pause() { paused = true; - push_event("engine_pause"); } void engine::unpause() { paused = false; - push_event("engine_unpause"); } bool engine::is_paused() const { @@ -193,25 +178,6 @@ void engine::save_scene(const std::string_view path) { out << j; } -ui::Screen* engine::load_screen(const prism::path& path) { - Expects(!path.empty()); - - return new ui::Screen(path); -} - -void engine::set_screen(ui::Screen* screen) { - current_screen = screen; - - screen->extent = windows[0]->extent; - screen->calculate_sizes(); - - get_renderer()->set_screen(screen); -} - -ui::Screen* engine::get_screen() const { - return current_screen; -} - AnimationChannel engine::load_animation(nlohmann::json a) { AnimationChannel animation; @@ -454,13 +420,6 @@ void engine::resize(const int identifier, const prism::Extent extent) { gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height); renderer->resize_render_target(*window->render_target, drawable_extent); - - if(identifier == 0) { - if(current_screen != nullptr) { - current_screen->extent = extent; - current_screen->calculate_sizes(); - } - } } void engine::process_key_down(const unsigned int keyCode) { @@ -479,31 +438,9 @@ void engine::process_key_up(const unsigned int keyCode) { } void engine::process_mouse_down(const int button, const prism::Offset offset) { - if(current_screen != nullptr && button == 0) - current_screen->process_mouse(offset.x, offset.y); - imgui->process_mouse_down(button); } -void engine::push_event(const std::string_view name, const std::string_view data) { - Expects(!name.empty()); - - if(current_screen != nullptr) - current_screen->process_event(name.data(), data.data()); -} - -bool engine::has_localization(const std::string_view id) const { - Expects(!id.empty()); - - return strings.count(id.data()); -} - -std::string engine::localize(const std::string& id) { - Expects(!id.empty()); - - return strings[id]; -} - void engine::calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone) { if(part.offset_matrices.empty()) return; @@ -769,11 +706,6 @@ void engine::render(const int index) { GFXCommandBuffer* commandbuffer = gfx->acquire_command_buffer(true); if(index == 0) { - if(current_screen != nullptr && current_screen->view_changed) { - renderer->update_screen(); - current_screen->view_changed = false; - } - imgui->render(0); app->render(commandbuffer); diff --git a/engine/core/src/scene.cpp b/engine/core/src/scene.cpp index 05c55d3..879302e 100755 --- a/engine/core/src/scene.cpp +++ b/engine/core/src/scene.cpp @@ -65,12 +65,6 @@ void load_rigidbody_component(nlohmann::json j, Rigidbody& rigidbody) { rigidbody.mass = j["mass"]; } -void load_ui_component(nlohmann::json j, UI& ui) { - ui.width = j["width"]; - ui.height = j["height"]; - ui.ui_path = j["path"]; -} - void load_probe_component(nlohmann::json j, EnvironmentProbe& probe) { if(j.contains("size")) probe.size = j["size"]; @@ -104,9 +98,6 @@ Object load_object(Scene& scene, const nlohmann::json obj) { if(obj.contains("rigidbody")) load_rigidbody_component(obj["rigidbody"], scene.add(o)); - - if(obj.contains("ui")) - load_ui_component(obj["ui"], scene.add(o)); if(obj.contains("environment_probe")) load_probe_component(obj["environment_probe"], scene.add(o)); @@ -158,12 +149,6 @@ void save_rigidbody_component(nlohmann::json& j, const Rigidbody& rigidbody) { j["mass"] = rigidbody.mass; } -void save_ui_component(nlohmann::json& j, const UI& ui) { - j["width"] = ui.width; - j["height"] = ui.height; - j["path"] = ui.ui_path; -} - void save_probe_component(nlohmann::json& j, const EnvironmentProbe& probe) { j["size"] = probe.size; j["is_sized"] = probe.is_sized; @@ -198,10 +183,7 @@ nlohmann::json save_object(Object obj) { if(scene->has(obj)) save_rigidbody_component(j["rigidbody"], scene->get(obj)); - - if(scene->has(obj)) - save_ui_component(j["ui"], scene->get(obj)); - + if(scene->has(obj)) save_probe_component(j["environment_probe"], scene->get(obj)); diff --git a/engine/core/src/screen.cpp b/engine/core/src/screen.cpp deleted file mode 100755 index 9b10da6..0000000 --- a/engine/core/src/screen.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "screen.hpp" - -#include -#include -#include - -#include "file.hpp" -#include "font.hpp" -#include "engine.hpp" -#include "string_utils.hpp" -#include "log.hpp" -#include "assertions.hpp" -#include "uielement.hpp" - -void ui::Screen::calculate_sizes() { - unsigned int numChildren = 0; - - int actualWidth = extent.width, actualHeight = extent.height; - int offsetX = 0, offsetY = 0; - - for(size_t i = 0; i < elements.size(); i++) { - auto& element = elements[i]; - - auto id = "ui_" + element.id; - //if(engine->has_localization(id)) - // element.text = engine->localize(id); - - UIElement* parent = nullptr; - if(!element.parent.empty()) - parent = find_element(element.parent); - - const auto& fillAbsolute = [parent](const auto& metric, auto& absolute, auto base, auto offset) { - switch(metric.type) { - case MetricType::Absolute: - absolute = offset + metric.value; - break; - case MetricType::Relative: - absolute = offset + ((base - offset) * (metric.value / 100.0f)); - break; - case MetricType::Offset: - { - if(parent == nullptr) - absolute = base - metric.value; - else - absolute = parent->absolute_height - metric.value; - } - break; - } - }; - - fillAbsolute(element.metrics.x, element.absolute_x, offsetX + actualWidth, offsetX); - fillAbsolute(element.metrics.y, element.absolute_y, offsetY + actualHeight, offsetY); - - fillAbsolute(element.metrics.width, element.absolute_width, actualWidth, 0); - fillAbsolute(element.metrics.height, element.absolute_height, actualHeight, 0); - - if(parent) { - const float heightPerRow = actualWidth / (float)elements.size(); - - element.absolute_x = (float)numChildren * heightPerRow; - element.absolute_y = actualHeight - 50.0f; - element.absolute_width = (float)heightPerRow; - element.absolute_height = (float)50.0f; - - numChildren++; - } - - if(element.text_location == UIElement::TextLocation::Center) { - if(get_string_width(element.text) < element.absolute_width) - element.text_x = (element.absolute_width / 2.0f) - (get_string_width(element.text) / 2.0f); - - if(get_font_height() < element.absolute_height) - element.text_y = (element.absolute_height / 2.0f) - (get_font_height() / 2.0f); - } - } -} - -void ui::Screen::process_mouse(const int x, const int y) { - Expects(x >= 0); - Expects(y >= 0); -} - -UIElement* ui::Screen::find_element(const std::string& id) { - Expects(!id.empty()); - - UIElement* foundElement = nullptr; - for(auto& element : elements) { - if(element.id == id) - foundElement = &element; - } - - Expects(foundElement != nullptr); - - return foundElement; -} - -ui::Screen::Screen(const prism::path path) { - auto file = prism::open_file(path); - if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load UI from {}!", path); - return; - } - - nlohmann::json j; - file->read_as_stream() >> j; - - for(auto& element : j["elements"]) { - UIElement ue; - ue.id = element["id"]; - - if(element.contains("on_click")) - ue.on_click_script = element["on_click"]; - - if(element.contains("text")) - ue.text = element["text"]; - - if(element.contains("parent")) - ue.parent = element["parent"]; - - if(element.contains("metrics")) { - const auto& metrics = element["metrics"]; - - const auto parseMetric = [](const std::string& str) { - UIElement::Metrics::Metric m; - - if(string_contains(str, "px")) { - auto v = remove_substring(str, "px"); - - if(string_contains(str, "@")) { - m.type = MetricType::Offset; - m.value = std::stoi(remove_substring(v, "@")); - } else { - m.type = MetricType::Absolute; - m.value = std::stoi(v); - } - } else if(string_contains(str, "%")) { - m.type = MetricType::Relative; - m.value = std::stoi(remove_substring(str, "%")); - } - - return m; - }; - - if(metrics.contains("x")) - ue.metrics.x = parseMetric(metrics["x"]); - - if(metrics.contains("y")) - ue.metrics.y = parseMetric(metrics["y"]); - - if(metrics.contains("width")) - ue.metrics.width = parseMetric(metrics["width"]); - - if(metrics.contains("height")) - ue.metrics.height = parseMetric(metrics["height"]); - } - - if(element.contains("background")) { - if(element["background"].contains("color")) { - auto tokens = tokenize(element["background"]["color"].get(), ","); - ue.background.color.r = std::stof(tokens[0]); - ue.background.color.g = std::stof(tokens[1]); - ue.background.color.b = std::stof(tokens[2]); - ue.background.color.a = std::stof(tokens[3]); - } - - if(element["background"].contains("image")) { - ue.background.image = element["background"]["image"]; - } - } - - if(element.contains("wrap")) - ue.wrap_text = element["wrap"]; - - if(element.contains("textLocation")) { - if(element["textLocation"] == "topLeft") - ue.text_location = UIElement::TextLocation::TopLeft; - else if(element["textLocation"] == "center") - ue.text_location = UIElement::TextLocation::Center; - } - - elements.push_back(ue); - } -} - -void ui::Screen::add_listener(const std::string& id, std::function callback) { - listeners[id] = callback; -} - -void ui::Screen::process_event(const std::string& type, const std::string data) { - -} diff --git a/engine/renderer/include/renderer.hpp b/engine/renderer/include/renderer.hpp index 982e5f8..ef18cc2 100755 --- a/engine/renderer/include/renderer.hpp +++ b/engine/renderer/include/renderer.hpp @@ -55,21 +55,12 @@ namespace prism { void recreate_all_render_targets(); - void set_screen(ui::Screen* screen); - - void init_screen(ui::Screen* screen); - - void update_screen(); - struct controller_continuity { int elementOffset = 0; }; void render(GFXCommandBuffer* command_buffer, Scene* scene, RenderTarget& target, int index); - void render_screen(GFXCommandBuffer* commandBuffer, ui::Screen* screen, prism::Extent extent, - controller_continuity& continuity, render_screen_options options = render_screen_options()); - void render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera, prism::Extent extent, RenderTarget& target, controller_continuity &continuity); diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp index 3c437c4..0f1660c 100755 --- a/engine/renderer/src/renderer.cpp +++ b/engine/renderer/src/renderer.cpp @@ -4,7 +4,6 @@ #include "gfx_commandbuffer.hpp" #include "math.hpp" -#include "screen.hpp" #include "file.hpp" #include "scene.hpp" #include "font.hpp" @@ -185,48 +184,6 @@ void renderer::recreate_all_render_targets() { } -void renderer::set_screen(ui::Screen* screen) { - Expects(screen != nullptr); - - current_screen = screen; - - init_screen(screen); - - update_screen(); -} - -void renderer::init_screen(ui::Screen* screen) { - Expects(screen != nullptr); - - std::array metrics = {}; - for(int i = 0; i < numGlyphs; i++) { - GylphMetric& metric = metrics[i]; - metric.x0_y0 = utility::pack_u32(font.sizes[fontSize][i].x0, font.sizes[fontSize][i].y0); - metric.x1_y1 = utility::pack_u32(font.sizes[fontSize][i].x1, font.sizes[fontSize][i].y1); - metric.xoff = font.sizes[fontSize][i].xoff; - metric.yoff = font.sizes[fontSize][i].yoff; - metric.xoff2 = font.sizes[fontSize][i].xoff2; - metric.yoff2 = font.sizes[fontSize][i].yoff2; - } - - screen->glyph_buffer = gfx->create_buffer(nullptr, instance_alignment + (sizeof(GylphMetric) * numGlyphs), false, GFXBufferUsage::Storage); - - gfx->copy_buffer(screen->glyph_buffer, metrics.data(), instance_alignment, sizeof(GylphMetric) * numGlyphs); - - screen->elements_buffer = gfx->create_buffer(nullptr, sizeof(ElementInstance) * 50, true, GFXBufferUsage::Storage); - - screen->instance_buffer = gfx->create_buffer(nullptr, sizeof(StringInstance) * 50, true, GFXBufferUsage::Storage); -} - -void renderer::update_screen() { - if(current_screen != nullptr) { - for(auto& element : current_screen->elements) { - if(!element.background.image.empty()) - element.background.texture = assetm->get(prism::app_domain / element.background.image); - } - } -} - void renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarget& target, int index) { const auto extent = target.extent; const auto render_extent = target.get_render_extent(); @@ -403,10 +360,7 @@ void renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarge commandbuffer->draw(0, 4, 0, 1); commandbuffer->pop_group(); - - if(current_screen != nullptr) - render_screen(commandbuffer, current_screen, extent, continuity); - + commandbuffer->push_group("Extra Passes"); for(auto& pass : passes) @@ -533,18 +487,6 @@ void renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Obj } } - const auto& screens = scene.get_all(); - for(const auto& [obj, screen] : screens) { - if(!screen.screen) - continue; - - render_screen_options options = {}; - options.render_world = true; - options.mvp = camera.perspective * camera.view * scene.get(obj).model; - - render_screen(command_buffer, screen.screen, extent, continuity, options); - } - SkyPushConstant pc; pc.view = matrix_from_quat(scene.get(camera_object).rotation); pc.aspect = static_cast(extent.width) / static_cast(extent.height); @@ -568,136 +510,6 @@ void renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Obj gfx->copy_buffer(target.sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation)); } -void renderer::render_screen(GFXCommandBuffer *commandbuffer, ui::Screen* screen, prism::Extent extent, controller_continuity& continuity, render_screen_options options) { - std::array instances; - std::vector elementInstances; - std::array stringInstances = {}; - - int stringLen = 0; - int numElements = 0; - - for(auto [i, element] : utility::enumerate(screen->elements)) { - if(!element.visible) - continue; - - ElementInstance instance; - - instance.position = utility::pack_u32(utility::to_fixed(element.absolute_x), utility::to_fixed(element.absolute_y)); - instance.size = utility::pack_u32(utility::to_fixed(element.absolute_width), utility::to_fixed(element.absolute_height)); - instance.color[0] = element.background.color.r; - instance.color[1] = element.background.color.g; - instance.color[2] = element.background.color.b; - instance.color[3] = element.background.color.a; - - elementInstances.push_back(instance); - - stringInstances[i].xy = utility::pack_u32(utility::to_fixed(element.absolute_x + element.text_x), utility::to_fixed(element.absolute_y + element.text_y)); - - float advance = 0.0f; - float yadvance = 0.0f; - - bool do_y_advance = false; // so we can not advance the text by a space if we're wrapping per word - - for(size_t j = 0; j < element.text.length(); j++) { - auto index = element.text[j] - 32; - - if(do_y_advance) { - advance = 0.0f; - yadvance += font.ascentSizes[fontSize]; - do_y_advance = false; - } - - if(element.wrap_text) { - if(element.text[j] == ' ') { - std::string t; - float temp_advance = 0.0f; - for(size_t k = j + 1; k < element.text.length() + j; k++) { - t += element.text[k]; - auto index = element.text[k] - 32; - temp_advance += font.sizes[fontSize][index].xadvance; - - if(element.text[k] == ' ') - break; - } - - if((temp_advance + advance) >= element.absolute_width) - do_y_advance = true; - } - } - - GlyphInstance& instance = instances[stringLen + j]; - instance.position = utility::pack_u32(utility::to_fixed(advance), utility::to_fixed(yadvance)); - instance.index = utility::pack_u32(index, 0); - instance.instance = i; - - advance += font.sizes[fontSize][index].xadvance; - - if(element.text[j] == '\n') { - advance = 0.0f; - yadvance += font.ascentSizes[fontSize]; - } - } - - stringLen += static_cast(element.text.length()); - numElements++; - } - - gfx->copy_buffer(screen->glyph_buffer, instances.data(), 0, instance_alignment); - gfx->copy_buffer(screen->instance_buffer, stringInstances.data(), 0, sizeof(StringInstance) * 50); - gfx->copy_buffer(screen->elements_buffer, elementInstances.data(), sizeof(ElementInstance) * continuity.elementOffset, sizeof(ElementInstance) * elementInstances.size()); - - const prism::float2 windowSize = {static_cast(extent.width), static_cast(extent.height)}; - - for(auto [i, element] : utility::enumerate(screen->elements)) { - if(!element.visible) - continue; - - UIPushConstant pc; - pc.screenSize = windowSize; - - if(options.render_world) { - commandbuffer->set_graphics_pipeline(world_general_pipeline); - pc.mvp = options.mvp; - } else { - commandbuffer->set_graphics_pipeline(general_pipeline); - } - - if (element.background.texture) { - commandbuffer->bind_texture(element.background.texture->handle, 2); - } - else { - commandbuffer->bind_texture(dummy_texture, 2); - } - - commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant)); - - commandbuffer->bind_shader_buffer(screen->elements_buffer, 0, 0, sizeof(ElementInstance) * 50); - commandbuffer->draw(0, 4, i + continuity.elementOffset, 1); - } - - UIPushConstant pc; - pc.screenSize = windowSize; - - if(options.render_world) { - commandbuffer->set_graphics_pipeline(world_text_pipeline); - pc.mvp = options.mvp; - } else { - commandbuffer->set_graphics_pipeline(text_pipeline); - } - - commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant)); - - commandbuffer->bind_shader_buffer(screen->glyph_buffer, 0, 0, instance_alignment); - commandbuffer->bind_shader_buffer(screen->glyph_buffer, instance_alignment, 1, sizeof(GylphMetric) * numGlyphs); - commandbuffer->bind_shader_buffer(screen->instance_buffer, 0, 2, sizeof(StringInstance) * 50); - commandbuffer->bind_texture(font_texture, 3); - - if(stringLen > 0) - commandbuffer->draw(0, 4, 0, stringLen); - - continuity.elementOffset += numElements; -} - void renderer::create_mesh_pipeline(Material& material) const { GFXShaderConstant materials_constant = {}; materials_constant.type = GFXShaderConstant::Type::Integer; diff --git a/tools/common/src/commoneditor.cpp b/tools/common/src/commoneditor.cpp index b1df649..07e52bd 100755 --- a/tools/common/src/commoneditor.cpp +++ b/tools/common/src/commoneditor.cpp @@ -18,7 +18,6 @@ #include "gfx.hpp" #include "gfx_commandbuffer.hpp" #include "imgui_utility.hpp" -#include "screen.hpp" #include "console.hpp" #include "input.hpp" #include "scenecapture.hpp" @@ -459,20 +458,6 @@ void editRigidbody(Rigidbody& rigidbody) { ImGui::DragInt("Mass", &rigidbody.mass); } -void editUI(UI& ui) { - ImGui::DragInt("Width", &ui.width); - ImGui::DragInt("Height", &ui.height); - ImGui::InputText("Path", &ui.ui_path); - - if(ImGui::Button("Reload")) { - ui.screen = engine->load_screen(prism::app_domain / ui.ui_path); - engine->get_renderer()->init_screen(ui.screen); - ui.screen->extent.width = ui.width; - ui.screen->extent.height = ui.height; - ui.screen->calculate_sizes(); - } -} - void editProbe(EnvironmentProbe& probe) { ImGui::Checkbox("Is Sized", &probe.is_sized); if(probe.is_sized) @@ -608,11 +593,6 @@ void CommonEditor::drawPropertyEditor() { ImGui::CloseCurrentPopup(); } - if(ImGui::Selectable("UI")) { - scene->add(selected_object); - ImGui::CloseCurrentPopup(); - } - if(ImGui::Selectable("Environment Probe")) { scene->add(selected_object); ImGui::CloseCurrentPopup(); @@ -638,10 +618,7 @@ void CommonEditor::drawPropertyEditor() { if(componentHeader(*scene, selected_object, "Rigidbody")) editRigidbody(scene->get(selected_object)); - - if(componentHeader(*scene, selected_object, "UI")) - editUI(scene->get(selected_object)); - + if(componentHeader(*scene, selected_object, "Environment Probe")) editProbe(scene->get(selected_object)); } diff --git a/tools/editor/CMakeLists.txt b/tools/editor/CMakeLists.txt index 215fc86..69b6670 100755 --- a/tools/editor/CMakeLists.txt +++ b/tools/editor/CMakeLists.txt @@ -2,13 +2,11 @@ set(SRC include/prismeditor.hpp include/materialeditor.hpp include/sceneeditor.hpp - include/uieditor.hpp include/prefabeditor.hpp src/prismeditor.cpp src/materialeditor.cpp src/sceneeditor.cpp - src/uieditor.cpp src/prefabeditor.cpp) add_platform_executable( diff --git a/tools/editor/include/uieditor.hpp b/tools/editor/include/uieditor.hpp deleted file mode 100755 index 9b25033..0000000 --- a/tools/editor/include/uieditor.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "prismeditor.hpp" - -#include "screen.hpp" - -class UIEditor : public Editor { -public: - UIEditor(); - - ui::Screen* screen = nullptr; - UIElement* current_element = nullptr; - - bool has_menubar() const override; - std::string get_title() const override; - - Scene* get_scene() const override; - - void setup_windows(ImGuiID dockspace) override; - - void edit_metric(const char* label, UIElement::Metrics::Metric* metric); - std::string save_metric(UIElement::Metrics::Metric metric); - - void save(std::string path); - - void draw(CommonEditor* editor) override; -}; diff --git a/tools/editor/src/prismeditor.cpp b/tools/editor/src/prismeditor.cpp index def208a..1af48d9 100755 --- a/tools/editor/src/prismeditor.cpp +++ b/tools/editor/src/prismeditor.cpp @@ -11,11 +11,9 @@ #include "json_conversions.hpp" #include "platform.hpp" #include "string_utils.hpp" -#include "screen.hpp" #include "sceneeditor.hpp" #include "materialeditor.hpp" #include "prefabeditor.hpp" -#include "uieditor.hpp" #include "log.hpp" std::string get_filename(const std::string path) { @@ -164,15 +162,6 @@ void PrismEditor::open_asset(const prism::path path) { editor->scene = engine->get_scene(); - editors.push_back(editor); - } else if(path.extension() == ".json") { - UIEditor* editor = new UIEditor(); - editor->path = path.string(); - setup_editor(editor); - - editor->screen = engine->load_screen(path); - editor->screen->calculate_sizes(); - editors.push_back(editor); } } @@ -233,14 +222,6 @@ void PrismEditor::drawUI() { editors.push_back(editor); } - if(ImGui::MenuItem("UI")) { - UIEditor* editor = new UIEditor(); - editor->modified = true; - setup_editor(editor); - - editors.push_back(editor); - } - ImGui::EndMenu(); } diff --git a/tools/editor/src/uieditor.cpp b/tools/editor/src/uieditor.cpp deleted file mode 100755 index a46eeaa..0000000 --- a/tools/editor/src/uieditor.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "uieditor.hpp" - -#include -#include -#include -#include - -#include "engine.hpp" -#include "imgui_utility.hpp" - -UIEditor::UIEditor() : Editor() { - screen = new ui::Screen(); - screen->extent.width = 1280; - screen->extent.height = 720; -} - -bool UIEditor::has_menubar() const { - return true; -} - -std::string UIEditor::get_title() const { - return path.empty() ? "New UI" : get_filename(path); -} - -Scene* UIEditor::get_scene() const { - return nullptr; -} - -void UIEditor::setup_windows(ImGuiID dockspace) { - ImGuiID dock_main_id = dockspace; - - ImGuiID dock_id_left, dock_id_right; - ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.60f, &dock_id_left, &dock_id_right); - - ImGui::DockBuilderDockWindow(get_window_name("Properties").c_str(), dock_id_right); - - ImGui::DockBuilderSplitNode(dock_id_left, ImGuiDir_Left, 0.30f, &dock_id_left, &dock_id_right); - ImGui::DockBuilderDockWindow(get_window_name("Outliner").c_str(), dock_id_left); - ImGui::DockBuilderDockWindow(get_window_name("Preview").c_str(), dock_id_right); -} - -void UIEditor::edit_metric(const char* label, UIElement::Metrics::Metric* metric) { - if(ImGui::DragInt(label, &metric->value, 1.0f, 0, 0, metric->type == MetricType::Absolute ? "%d" : "%d%%")) - screen->calculate_sizes(); - - ImGui::SameLine(); - - ImGui::PushID(label); - - if(ImGui::ComboEnum("T", &metric->type)) - screen->calculate_sizes(); - - ImGui::PopID(); -} - -std::string UIEditor::save_metric(UIElement::Metrics::Metric metric) { - return std::to_string(metric.value) + (metric.type == MetricType::Absolute ? "px" : "%"); -} - -void UIEditor::save(std::string path) { - nlohmann::json j; - - for (auto& element : screen->elements) { - nlohmann::json e; - e["id"] = element.id; - e["text"] = element.text; - e["visible"] = element.visible; - e["wrapText"] = element.wrap_text; - - nlohmann::json m; - m["x"] = save_metric(element.metrics.x); - m["y"] = save_metric(element.metrics.y); - m["width"] = save_metric(element.metrics.width); - m["height"] = save_metric(element.metrics.height); - - e["metrics"] = m; - - if(element.text_location == UIElement::TextLocation::Center) { - e["textLocation"] = "center"; - } else { - e["textLocation"] = "topLeft"; - } - - j["elements"].push_back(e); - } - - std::ofstream out(path); - out << std::setw(4) << j; -} - -void UIEditor::draw(CommonEditor*) { - if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("File")) { - if(ImGui::MenuItem("Save", "CTRL+S")) { - if (path.empty()) { - platform::save_dialog([this](std::string path) { - this->path = path; - - save(path); - }); - } else { - save(path); - } - } - - if (ImGui::MenuItem("Save as...", "CTRL+S")) { - platform::save_dialog([this](std::string path) { - this->path = path; - - save(path); - }); - } - - ImGui::Separator(); - - if(ImGui::MenuItem("Close")) - wants_to_close = true; - - ImGui::EndMenu(); - } - - ImGui::EndMenuBar(); - } - - if(begin("Outliner")) { - if(ImGui::Button("Add Element")) { - screen->elements.push_back(UIElement()); - current_element = &screen->elements.back(); - } - - for(auto& element : screen->elements) { - if(ImGui::Selectable(element.id.c_str())) - current_element = &element; - } - } - - ImGui::End(); - - if(begin("Properties")) { - if(current_element != nullptr) { - ImGui::InputText("ID", ¤t_element->id); - - edit_metric("X", ¤t_element->metrics.x); - edit_metric("Y", ¤t_element->metrics.y); - edit_metric("Width", ¤t_element->metrics.width); - edit_metric("Height", ¤t_element->metrics.height); - - ImGui::InputText("Text", ¤t_element->text); - - ImGui::ColorEdit4("Background color", current_element->background.color.v); - - ImGui::Checkbox("Visible", ¤t_element->visible); - ImGui::Checkbox("Wrap text", ¤t_element->wrap_text); - - bool setCenter = current_element->text_location == UIElement::TextLocation::Center; - ImGui::Checkbox("Center Text", &setCenter); - - current_element->text_location = setCenter ? UIElement::TextLocation::Center : UIElement::TextLocation::TopLeft; - - if(ImGui::Button("Delete")) { - utility::erase(screen->elements, *current_element); - } - - if(ImGui::Button("Duplicate")) { - UIElement element = *current_element; - element.id += " (duplicate)"; - - screen->elements.push_back(element); - current_element = &screen->elements.back(); - } - } - } - - ImGui::End(); - - if(begin("Preview")) { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - - static int width = 1280, height = 720; - static int scale = 3; - - bool c = ImGui::InputInt("Width", &width); - c |= ImGui::InputInt("Height", &height); - c |= ImGui::InputInt("Scale", &scale); - - if(c) { - screen->extent.width = width; - screen->extent.height = height; - screen->calculate_sizes(); - } - - const ImVec2 p = ImGui::GetCursorScreenPos(); - - draw_list->AddRect(ImVec2(p.x, p.y), ImVec2(p.x + (width / scale), p.y + (height / scale)), IM_COL32_WHITE); - - for(auto& element : screen->elements) { - if(element.absolute_width > 0 && element.absolute_height > 0) { - draw_list->AddRect( - ImVec2(p.x + (element.absolute_x / scale), p.y + (element.absolute_y / scale)), - ImVec2(p.x + ((element.absolute_x + element.absolute_width) / scale), p.y + ((element.absolute_y + element.absolute_height) / scale)), - IM_COL32_WHITE - ); - } - - if(!element.text.empty()) { - if(element.text_location == UIElement::TextLocation::Center) { - auto textSize = ImGui::CalcTextSize(element.text.c_str()); - - draw_list->AddText(ImVec2(p.x + (element.absolute_x + (element.absolute_width / 2)) / scale - (textSize.x / 2), p.y + (element.absolute_y + (element.absolute_height / 2)) / scale - (textSize.y / 2)), IM_COL32_WHITE, element.text.c_str()); - } else { - draw_list->AddText(ImVec2(p.x + (element.absolute_x / scale), p.y + (element.absolute_y / scale)), IM_COL32_WHITE, element.text.c_str()); - } - } - } - } - - ImGui::End(); -} From 529bc27702af30028657538a9d77b167eca76295 Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 13 Sep 2021 23:41:54 -0400 Subject: [PATCH 08/12] Replace old logging and format system with fmt --- engine/asset/src/asset.cpp | 12 ++-- engine/core/src/console.cpp | 6 +- engine/core/src/engine.cpp | 12 ++-- engine/core/src/file.cpp | 2 +- engine/gfx/vulkan/src/gfx_vulkan.cpp | 10 +-- engine/log/CMakeLists.txt | 2 +- engine/log/include/log.hpp | 68 +++----------------- engine/log/src/log.cpp | 25 +------ engine/platform/include/file.hpp | 1 - engine/renderer/src/imguipass.cpp | 2 +- engine/renderer/src/materialcompiler.cpp | 2 +- engine/renderer/src/renderer.cpp | 2 +- engine/shadercompiler/src/shadercompiler.cpp | 8 +-- engine/utility/CMakeLists.txt | 1 - engine/utility/include/file_utils.hpp | 13 ---- engine/utility/include/string_utils.hpp | 17 ----- extern/CMakeLists.txt | 10 ++- tools/common/src/commoneditor.cpp | 14 ++-- tools/shadercompiler/main.cpp | 5 +- 19 files changed, 57 insertions(+), 155 deletions(-) delete mode 100644 engine/utility/include/file_utils.hpp diff --git a/engine/asset/src/asset.cpp b/engine/asset/src/asset.cpp index 8e5b094..17f9665 100644 --- a/engine/asset/src/asset.cpp +++ b/engine/asset/src/asset.cpp @@ -20,7 +20,7 @@ std::unique_ptr load_mesh(const prism::path path) { auto file = prism::open_file(path, true); if(!file.has_value()) { - prism::log::error(System::Renderer, "Failed to load mesh from {}!", path); + prism::log("Failed to load mesh from {}!", path.string()); return nullptr; } @@ -29,7 +29,7 @@ std::unique_ptr load_mesh(const prism::path path) { if(version == 5 || version == 6) { } else { - prism::log::error(System::Renderer, "{} failed the mesh version check! reported version = {}", path, std::to_string(version)); + prism::log("{} failed the mesh version check! reported version = {}", path.string(), version); return nullptr; } @@ -190,7 +190,7 @@ std::unique_ptr load_texture(const prism::path path) { auto file = prism::open_file(path, true); if(!file.has_value()) { - prism::log::error(System::Renderer, "Failed to load texture from {}!", path); + prism::log("Failed to load texture from {}!", path.string()); return nullptr; } @@ -202,7 +202,7 @@ std::unique_ptr load_texture(const prism::path path) { int width, height, channels; unsigned char* data = stbi_load_from_memory(file->cast_data(), file->size(), &width, &height, &channels, 4); if(!data) { - prism::log::error(System::Renderer, "Failed to load texture from {}!", path); + prism::log("Failed to load texture from {}!", path.string()); return nullptr; } @@ -247,7 +247,7 @@ std::unique_ptr load_material(const prism::path path) { auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load material from {}!", path); + prism::log("Failed to load material from {}!", path.string()); return {}; } @@ -258,7 +258,7 @@ std::unique_ptr load_material(const prism::path path) { mat->path = path.string(); if(!j.count("version") || j["version"] != 2) { - prism::log::error(System::Core, "Material {} failed the version check!", path); + prism::log("Material {} failed the version check!", path.string()); return mat; } diff --git a/engine/core/src/console.cpp b/engine/core/src/console.cpp index d93f507..36c666b 100644 --- a/engine/core/src/console.cpp +++ b/engine/core/src/console.cpp @@ -39,7 +39,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co invalid_format = true; if(invalid_format) { - prism::log::info(System::Core, "Invalid command format!"); + prism::log("Invalid command format!"); } else { command_data.function(console::arguments()); } @@ -59,7 +59,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co invalid_format = true; if(invalid_format) { - prism::log::info(System::Core, "Wrong or empty variable type!"); + prism::log("Wrong or empty variable type!"); } else { auto argument = arguments[0]; switch(argument.query_type()) { @@ -73,7 +73,7 @@ void prism::console::invoke_command(const std::string_view name, const prism::co } } - prism::log::info(System::Core, "{} is not the name of a valid command or variable!", name.data()); + prism::log("{} is not the name of a valid command or variable!", name.data()); } void prism::console::parse_and_invoke_command(const std::string_view command) { diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp index 69f4e0d..dd5948e 100755 --- a/engine/core/src/engine.cpp +++ b/engine/core/src/engine.cpp @@ -26,10 +26,10 @@ using prism::engine; engine::engine(const int argc, char* argv[]) { - log::info(System::Core, "Prism Engine loading..."); + log("Prism Engine loading..."); console::register_command("test_cmd", console::argument_format(0), [](const console::arguments&) { - log::info(System::Core, "Test cmd!"); + log("Test cmd!"); }); console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution); @@ -123,7 +123,7 @@ Scene* engine::load_scene(const prism::path& path) { auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load scene from {}!", path); + prism::log("Failed to load scene from {}!", path.string()); return nullptr; } @@ -197,7 +197,7 @@ Animation engine::load_animation(const prism::path& path) { auto file = prism::open_file(path, true); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load animation from {}!", path); + prism::log("Failed to load animation from {}!", path.string()); return {}; } @@ -257,7 +257,7 @@ void engine::load_cutscene(const prism::path& path) { auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load cutscene from {}!", path); + prism::log("Failed to load cutscene from {}!", path.string()); return; } @@ -332,7 +332,7 @@ Object engine::add_prefab(Scene& scene, const prism::path& path, const std::stri auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load prefab from {}!", path); + prism::log("Failed to load prefab from {}!", path.string()); return NullObject; } diff --git a/engine/core/src/file.cpp b/engine/core/src/file.cpp index 1cd3a18..be770de 100755 --- a/engine/core/src/file.cpp +++ b/engine/core/src/file.cpp @@ -21,7 +21,7 @@ std::optional prism::open_file(const prism::path path, const bool b auto str = get_file_path(path).string(); FILE* file = fopen(str.c_str(), binary_mode ? "rb" : "r"); if(file == nullptr) { - prism::log::error(System::File, "Failed to open file handle from {}!", str); + prism::log("Failed to open file handle from {}!", str); return {}; } diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp index bd12ce7..4887331 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan.cpp +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -167,14 +167,14 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) { - prism::log::debug(System::GFX, pCallbackData->pMessage); + prism::log("{}", pCallbackData->pMessage); return VK_FALSE; } VkResult name_object(VkDevice device, VkObjectType type, uint64_t object, std::string_view name) { if(object == 0x0) { - prism::log::error(System::GFX, "Failed to name object {}", name.data()); + prism::log("Failed to name object {}", name); return VK_ERROR_DEVICE_LOST; } @@ -580,7 +580,7 @@ void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) { } void GFXVulkan::copy_texture(GFXTexture* from, GFXTexture* to) { - prism::log::error(System::GFX, "Copy Texture->Texture unimplemented!"); + prism::log("Copy Texture->Texture unimplemented!"); } void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) { @@ -1641,7 +1641,7 @@ void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { } break; default: - prism::log::error(System::GFX, "Unhandled GFX Command Type {}", utility::enum_to_string(command.type)); + prism::log("Unhandled GFX Command Type {}", utility::enum_to_string(command.type)); break; } } @@ -2092,7 +2092,7 @@ void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSe VkResult error = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); if(error != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) { - prism::log::error(System::GFX, "ERROR: COULD NOT CACHE BECAUSE OUT OF DESCRIPTOR SETS."); + prism::log("ERROR: COULD NOT CACHE BECAUSE OUT OF DESCRIPTOR SETS."); return; } diff --git a/engine/log/CMakeLists.txt b/engine/log/CMakeLists.txt index ea0cffc..cd18263 100755 --- a/engine/log/CMakeLists.txt +++ b/engine/log/CMakeLists.txt @@ -4,5 +4,5 @@ set(SRC add_library(Log STATIC ${SRC}) target_include_directories(Log PUBLIC include) -target_link_libraries(Log PRIVATE Utility) +target_link_libraries(Log PUBLIC fmt::fmt) set_engine_properties(Log) diff --git a/engine/log/include/log.hpp b/engine/log/include/log.hpp index 9839e9e..6ceacce 100755 --- a/engine/log/include/log.hpp +++ b/engine/log/include/log.hpp @@ -1,66 +1,14 @@ #pragma once -#include -#include -#include +#include -enum class System { - None, - Core, - Renderer, - Game, - File, - GFX -}; - -enum class Level { - Info, - Warning, - Error, - Debug -}; - -namespace prism::log { - inline void internal_format(std::string &msg, const std::string &arg) { - auto pos = msg.find_first_of("{}"); - msg.replace(pos, 2, arg); +namespace prism { + inline void vlog(fmt::string_view format, fmt::format_args args) { + fmt::vprint(format, args); } - inline void internal_format(std::string &msg, const char *&arg) { - auto pos = msg.find_first_of("{}"); - msg.replace(pos, 2, arg); + template + inline void log(const S& format, Args&&... args) { + vlog(format, fmt::make_args_checked(format, args...)); } - - void process_message(const Level level, const System system, const std::string_view message); - - template - void internal_print(const Level level, const System system, const std::string_view format, Args &&... args) { - auto msg = std::string(format); - - ((internal_format(msg, args)), ...); - - process_message(level, system, msg); - } - - template - void info(const System system, const std::string_view format, Args &&... args) { - internal_print(Level::Info, system, format, args...); - } - - template - void warning(const System system, const std::string_view format, Args &&... args) { - internal_print(Level::Warning, system, format, args...); - } - - template - void error(const System system, const std::string_view format, Args &&... args) { - internal_print(Level::Error, system, format, args...); - } - - template - void debug(const System system, const std::string_view format, Args &&... args) { - internal_print(Level::Debug, system, format, args...); - } - - inline std::vector stored_output; -} +} \ No newline at end of file diff --git a/engine/log/src/log.cpp b/engine/log/src/log.cpp index 490d183..dfcfffa 100755 --- a/engine/log/src/log.cpp +++ b/engine/log/src/log.cpp @@ -1,24 +1 @@ -#include "log.hpp" - -#include -#include -#include -#include "string_utils.hpp" -#include "utility.hpp" - -void prism::log::process_message(const Level level, const System system, const std::string_view message) { - auto now = std::chrono::system_clock::now(); - std::time_t t_c = std::chrono::system_clock::to_time_t(now); - - std::string date; - date.resize(30); - - std::strftime(&date[0], date.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&t_c)); - utility::erase(date, '\0'); // strftime will insert \0 for us, but it's not needed here - - std::string s = utility::format("{} {} {}: {}", date, utility::enum_to_string(system), utility::enum_to_string(level), message); - - std::cout << s << '\n'; - - stored_output.push_back(s); -} +#include "log.hpp" \ No newline at end of file diff --git a/engine/platform/include/file.hpp b/engine/platform/include/file.hpp index 439429c..03596ac 100755 --- a/engine/platform/include/file.hpp +++ b/engine/platform/include/file.hpp @@ -8,7 +8,6 @@ #include #include "log.hpp" -#include "file_utils.hpp" #include "path.hpp" namespace prism { diff --git a/engine/renderer/src/imguipass.cpp b/engine/renderer/src/imguipass.cpp index 8b2aaa6..e9f31d8 100755 --- a/engine/renderer/src/imguipass.cpp +++ b/engine/renderer/src/imguipass.cpp @@ -162,7 +162,7 @@ void ImGuiPass::load_font(const std::string_view filename) { io.Fonts->AddFontFromMemoryTTF(font_file->cast_data(), font_file->size(), 15.0 * platform::get_window_dpi(0)); ImGui::GetIO().FontGlobalScale = 1.0 / platform::get_window_dpi(0); } else { - prism::log::error(System::Renderer, "Failed to load font file for imgui!"); + prism::log("Failed to load font file for imgui!"); return; } } diff --git a/engine/renderer/src/materialcompiler.cpp b/engine/renderer/src/materialcompiler.cpp index ac3aa83..3108f4c 100755 --- a/engine/renderer/src/materialcompiler.cpp +++ b/engine/renderer/src/materialcompiler.cpp @@ -13,7 +13,7 @@ ShaderSource get_shader(std::string filename, bool skinned, bool cubemap) { auto shader_file = prism::open_file(prism::internal_domain / filename); if(!shader_file.has_value()) { - prism::log::error(System::Renderer, "Failed to open shader file {}!", filename); + prism::log("Failed to open shader file {}!", filename); return {}; } diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp index 0f1660c..fa2440f 100755 --- a/engine/renderer/src/renderer.cpp +++ b/engine/renderer/src/renderer.cpp @@ -678,7 +678,7 @@ void renderer::create_post_pipelines() { void renderer::create_font_texture() { auto file = prism::open_file(prism::app_domain / "font.fp", true); if(file == std::nullopt) { - prism::log::error(System::Renderer, "Failed to load font file!"); + prism::log("Failed to load font file!"); return; } diff --git a/engine/shadercompiler/src/shadercompiler.cpp b/engine/shadercompiler/src/shadercompiler.cpp index 501c328..b5c6f4f 100755 --- a/engine/shadercompiler/src/shadercompiler.cpp +++ b/engine/shadercompiler/src/shadercompiler.cpp @@ -53,7 +53,7 @@ std::vector compile_glsl_to_spv(const std::string_view source_string, file_includer.pushExternalLocalDirectory(path); if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault, file_includer)) { - prism::log::error(System::Renderer, "{}", shader.getInfoLog()); + prism::log("{}", shader.getInfoLog()); return {}; } @@ -62,7 +62,7 @@ std::vector compile_glsl_to_spv(const std::string_view source_string, Program.addShader(&shader); if(!Program.link(EShMsgDefault)) { - prism::log::error(System::None, "Failed to link shader: {} {} {}", source_string.data(), shader.getInfoLog(), shader.getInfoDebugLog()); + prism::log("Failed to link shader: {} {} {}", source_string.data(), shader.getInfoLog(), shader.getInfoDebugLog()); return {}; } @@ -77,7 +77,7 @@ std::vector compile_glsl_to_spv(const std::string_view source_string, std::optional ShaderCompiler::compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, const CompileOptions& options) { if(from_language != ShaderLanguage::GLSL) { - prism::log::error(System::Renderer, "Non-supported input language!"); + prism::log("Non-supported input language!"); return std::nullopt; } @@ -96,7 +96,7 @@ std::optional ShaderCompiler::compile(const ShaderLanguage from_la auto spirv = compile_glsl_to_spv(shader_source.as_string(), lang, options); if(spirv.empty()) { - prism::log::error(System::Renderer, "SPIRV generation failed!"); + prism::log("SPIRV generation failed!"); return std::nullopt; } diff --git a/engine/utility/CMakeLists.txt b/engine/utility/CMakeLists.txt index 64efa70..d0bd632 100755 --- a/engine/utility/CMakeLists.txt +++ b/engine/utility/CMakeLists.txt @@ -4,7 +4,6 @@ set(SRC include/string_utils.hpp include/timer.hpp include/common.hpp - include/file_utils.hpp include/assertions.hpp include/path.hpp diff --git a/engine/utility/include/file_utils.hpp b/engine/utility/include/file_utils.hpp deleted file mode 100644 index ce22941..0000000 --- a/engine/utility/include/file_utils.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -#include "path.hpp" - -namespace prism::log { - inline void internal_format(std::string& msg, const prism::path& arg) { - auto pos = msg.find_first_of("{}"); - msg.replace(pos, 2, arg.string()); - } -} \ No newline at end of file diff --git a/engine/utility/include/string_utils.hpp b/engine/utility/include/string_utils.hpp index 0a9bd2c..ae8dd0b 100755 --- a/engine/utility/include/string_utils.hpp +++ b/engine/utility/include/string_utils.hpp @@ -12,20 +12,3 @@ bool string_starts_with(const std::string_view haystack, const std::string_view bool is_numeric(const std::string_view string); std::vector tokenize(const std::string_view string, const std::string_view& delimiters = ","); - -namespace utility { - template - inline void format_internal_format(std::string& msg, const Arg& arg) { - auto pos = msg.find_first_of("{}"); - msg.replace(pos, 2, arg); - } - - template - std::string format(const std::string_view format, Args&&... args) { - auto msg = std::string(format); - - ((format_internal_format(msg, args)), ...); - - return msg; - } -} diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index f222971..4c9a912 100755 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -106,4 +106,12 @@ if(BUILD_TOOLS) ) FetchContent_MakeAvailable(assimp) -endif() \ No newline at end of file +endif() + +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt + GIT_TAG 8.0.1 +) + +FetchContent_MakeAvailable(fmt) \ No newline at end of file diff --git a/tools/common/src/commoneditor.cpp b/tools/common/src/commoneditor.cpp index 07e52bd..0838449 100755 --- a/tools/common/src/commoneditor.cpp +++ b/tools/common/src/commoneditor.cpp @@ -703,7 +703,7 @@ void CommonEditor::set_undo_stack(UndoStack *stack) { bool mesh_readable(const prism::path path) { auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Renderer, "Failed to load mesh from {}!", path); + prism::log("Failed to load mesh from {}!", path.string()); return false; } @@ -716,7 +716,7 @@ bool mesh_readable(const prism::path path) { bool material_readable(const prism::path path) { auto file = prism::open_file(path); if(!file.has_value()) { - prism::log::error(System::Core, "Failed to load material from {}!", path); + prism::log("Failed to load material from {}!", path.string()); return false; } @@ -1014,9 +1014,11 @@ void CommonEditor::drawConsole() { } ImGui::BeginChild("console_output", ImVec2(-1, -1), true); - - for(const auto& message : prism::log::stored_output) - ImGui::TextWrapped("%s", message.c_str()); + + // TODO: implement for new log system + //for(const auto& message : prism::log::stored_output) + // ImGui::TextWrapped("%s", message.c_str()); + ImGui::Text("unimplemented :-("); ImGui::EndChild(); } @@ -1092,7 +1094,7 @@ void CommonEditor::save_thumbnail_cache() { FILE* file = fopen("thumbnail-cache", "wb"); if(file == nullptr) { - prism::log::error(System::Core, "Failed to write thumbnail cache!"); + prism::log("Failed to write thumbnail cache!"); return; } diff --git a/tools/shadercompiler/main.cpp b/tools/shadercompiler/main.cpp index 4ce5bdd..73bc23f 100755 --- a/tools/shadercompiler/main.cpp +++ b/tools/shadercompiler/main.cpp @@ -5,7 +5,6 @@ #include "shadercompiler.hpp" #include "log.hpp" #include "string_utils.hpp" -#include "file_utils.hpp" bool has_extension(const std::filesystem::path path, const std::string_view extension) { return string_contains(path.filename().string(), extension); @@ -13,7 +12,7 @@ bool has_extension(const std::filesystem::path path, const std::string_view exte int main(int argc, char* argv[]) { if(argc < 2) { - prism::log::error(System::Core, "Not enough arguments!"); + prism::log("Not enough arguments!"); return -1; } @@ -46,7 +45,7 @@ int main(int argc, char* argv[]) { const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options); if(!compiled_source.has_value()) { - prism::log::error(System::Core, "Error when compiling {}!", source_path); + prism::log("Error when compiling {}!", source_path.string()); return -1; } From 9c8c257c438e62f75697d49d897eb86e59faebe2 Mon Sep 17 00:00:00 2001 From: redstrate Date: Thu, 7 Oct 2021 17:46:28 -0400 Subject: [PATCH 09/12] Add new console debug window, handle text input under sdl --- engine/core/include/debug.hpp | 1 + engine/core/include/engine.hpp | 8 + engine/core/include/imgui_backend.hpp | 4 + engine/core/include/input.hpp | 8 + engine/core/src/debug.cpp | 13 + engine/core/src/engine.cpp | 15 +- engine/core/src/imgui_backend.cpp | 24 +- engine/core/src/input.cpp | 21 + engine/log/include/log.hpp | 6 +- engine/platform/include/platform.hpp | 4 + extern/magic_enum/include/magic_enum.hpp | 1565 +++++++++++++++------- platforms/sdl/main.cpp.in | 22 +- 12 files changed, 1165 insertions(+), 526 deletions(-) mode change 100755 => 100644 extern/magic_enum/include/magic_enum.hpp diff --git a/engine/core/include/debug.hpp b/engine/core/include/debug.hpp index 6595e9b..5313598 100644 --- a/engine/core/include/debug.hpp +++ b/engine/core/include/debug.hpp @@ -2,6 +2,7 @@ #include +void draw_console(); void draw_debug_ui(); void load_debug_options(); diff --git a/engine/core/include/engine.hpp b/engine/core/include/engine.hpp index 47bd8c1..30fa471 100755 --- a/engine/core/include/engine.hpp +++ b/engine/core/include/engine.hpp @@ -210,6 +210,12 @@ namespace prism { */ void process_mouse_down(int button, prism::Offset offset); + /** + * Called when text has been inputted. This is only emitted when text input is enabled thru input system + * @param string + */ + void process_text_input(const std::string_view string); + /** Adds a timer to the list of timers. @param timer The timer to add. @note The timer instance is passed by reference. Use this to keep track of your timers without having to query it's state back. @@ -282,6 +288,8 @@ namespace prism { bool debug_enabled = false; #endif + bool console_enabled = true; + private: void setup_scene(Scene& scene); diff --git a/engine/core/include/imgui_backend.hpp b/engine/core/include/imgui_backend.hpp index 79966f4..5b302da 100644 --- a/engine/core/include/imgui_backend.hpp +++ b/engine/core/include/imgui_backend.hpp @@ -1,5 +1,7 @@ #pragma once +#include + namespace prism { class imgui_backend { public: @@ -14,6 +16,8 @@ namespace prism { void process_key_down(unsigned int key_code); void process_key_up(unsigned int key_code); + void process_text_input(const std::string_view string); + private: bool mouse_buttons[3] = {}; }; diff --git a/engine/core/include/input.hpp b/engine/core/include/input.hpp index ed1fe54..e564447 100755 --- a/engine/core/include/input.hpp +++ b/engine/core/include/input.hpp @@ -81,8 +81,16 @@ namespace prism { /// Returns all of the bindings registered with this Input system. [[nodiscard]] std::vector get_bindings() const; + void begin_text_input(); + void end_text_input(); + bool is_text_input() const; + + bool get_allowable_text_button(unsigned int keycode) const; + private: std::vector _input_bindings; std::tuple _last_cursor_position; + + bool _in_text_input = false; }; } \ No newline at end of file diff --git a/engine/core/src/debug.cpp b/engine/core/src/debug.cpp index 2470156..7925b27 100644 --- a/engine/core/src/debug.cpp +++ b/engine/core/src/debug.cpp @@ -12,6 +12,7 @@ #include "scene.hpp" #include "renderer.hpp" #include "file.hpp" +#include "console.hpp" struct Options { std::string shader_source_path; @@ -244,3 +245,15 @@ void save_debug_options() { std::string_view get_shader_source_directory() { return options.shader_source_path; } + +void draw_console() { + ImGui::Text("%s", prism::log_output.c_str()); + + static std::string console_input; + ImGui::InputText("##console_input", &console_input); + + if(ImGui::Button("Input")) { + prism::console::parse_and_invoke_command(console_input); + console_input.clear(); + } +} \ No newline at end of file diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp index dd5948e..98ca1f9 100755 --- a/engine/core/src/engine.cpp +++ b/engine/core/src/engine.cpp @@ -424,11 +424,17 @@ void engine::resize(const int identifier, const prism::Extent extent) { void engine::process_key_down(const unsigned int keyCode) { Expects(keyCode >= 0); - + + if(input->is_text_input() && !input->get_allowable_text_button(keyCode)) + return; + imgui->process_key_down(keyCode); if(keyCode == platform::get_keycode(debug_button) && !ImGui::GetIO().WantTextInput) debug_enabled = !debug_enabled; + + if(keyCode == platform::get_keycode(InputButton::C)) + console_enabled = !console_enabled; } void engine::process_key_up(const unsigned int keyCode) { @@ -604,6 +610,9 @@ void engine::begin_frame(const float delta_time) { if(debug_enabled) draw_debug_ui(); + if(console_enabled) + draw_console(); + if(app != nullptr) app->begin_frame(); } @@ -798,3 +807,7 @@ void engine::setup_scene(Scene& scene) { scene.reset_shadows(); scene.reset_environment(); } + +void prism::engine::process_text_input(const std::string_view string) { + imgui->process_text_input(string); +} diff --git a/engine/core/src/imgui_backend.cpp b/engine/core/src/imgui_backend.cpp index ea93270..05ad732 100644 --- a/engine/core/src/imgui_backend.cpp +++ b/engine/core/src/imgui_backend.cpp @@ -6,6 +6,7 @@ #include "engine.hpp" #include "platform.hpp" #include "assertions.hpp" +#include "input.hpp" using prism::imgui_backend; @@ -159,6 +160,17 @@ imgui_backend::imgui_backend() { void imgui_backend::begin_frame(const float delta_time) { ImGuiIO& io = ImGui::GetIO(); + + const bool imgui_wants_text = io.WantTextInput; + const bool input_is_text = ::engine->get_input()->is_text_input(); + + if(imgui_wants_text != input_is_text) { + if(imgui_wants_text) { + ::engine->get_input()->begin_text_input(); + } else { + ::engine->get_input()->end_text_input(); + } + } const auto [width, height] = platform::get_window_size(0); const auto [dw, dh] = platform::get_window_drawable_size(0); @@ -205,10 +217,9 @@ void imgui_backend::render(int index) { void imgui_backend::process_key_down(unsigned int key_code) { Expects(key_code >= 0); - + ImGuiIO& io = ImGui::GetIO(); - io.AddInputCharactersUTF8(platform::translate_keycode(key_code)); - + io.KeysDown[key_code] = true; } @@ -222,4 +233,9 @@ void imgui_backend::process_key_up(unsigned int key_code) { void imgui_backend::process_mouse_down(int button) { mouse_buttons[button] = true; -} \ No newline at end of file +} + +void prism::imgui_backend::process_text_input(const std::string_view string) { + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharactersUTF8(string.data()); +} diff --git a/engine/core/src/input.cpp b/engine/core/src/input.cpp index 7397b03..5ee2844 100755 --- a/engine/core/src/input.cpp +++ b/engine/core/src/input.cpp @@ -155,3 +155,24 @@ bool input_system::is_repeating(const std::string& name) { std::vector input_system::get_bindings() const { return _input_bindings; } + +void input_system::begin_text_input() { + _in_text_input = true; + platform::begin_text_input(); +} + +void input_system::end_text_input() { + _in_text_input = false; + platform::end_text_input(); +} + +bool input_system::is_text_input() const { + return _in_text_input; +} + +bool input_system::get_allowable_text_button(unsigned int keycode) const { + if(platform::get_keycode(InputButton::Backspace) == keycode) + return true; + + return false; +} \ No newline at end of file diff --git a/engine/log/include/log.hpp b/engine/log/include/log.hpp index 6ceacce..51ebb4c 100755 --- a/engine/log/include/log.hpp +++ b/engine/log/include/log.hpp @@ -3,8 +3,12 @@ #include namespace prism { + inline std::string log_output; + inline void vlog(fmt::string_view format, fmt::format_args args) { - fmt::vprint(format, args); + auto str = fmt::vformat(format, args); + fmt::print("{}", str); + log_output += str + "\n"; } template diff --git a/engine/platform/include/platform.hpp b/engine/platform/include/platform.hpp index 9bb0eaa..0c35556 100755 --- a/engine/platform/include/platform.hpp +++ b/engine/platform/include/platform.hpp @@ -159,6 +159,10 @@ namespace platform { /// On platforms that support moue capture, this will lock the mouse cursor to the window and hide it. void capture_mouse(const bool capture); + // TODO: right now the OS intercepting and saying "We dont want text input anymore" ala software keyboards is NOT supported yet + void begin_text_input(); + void end_text_input(); + /**Opens a file dialog to select a file. This will not block. @param existing Whether or not to limit to existing files. @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. diff --git a/extern/magic_enum/include/magic_enum.hpp b/extern/magic_enum/include/magic_enum.hpp old mode 100755 new mode 100644 index ae49308..f2c9dea --- a/extern/magic_enum/include/magic_enum.hpp +++ b/extern/magic_enum/include/magic_enum.hpp @@ -5,11 +5,11 @@ // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum -// |___/ version 0.6.5 +// |___/ version 0.7.3 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT -// Copyright (c) 2019 Daniil Goncharov . +// Copyright (c) 2019 - 2021 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,29 +32,57 @@ #ifndef NEARGYE_MAGIC_ENUM_HPP #define NEARGYE_MAGIC_ENUM_HPP +#define MAGIC_ENUM_VERSION_MAJOR 0 +#define MAGIC_ENUM_VERSION_MINOR 7 +#define MAGIC_ENUM_VERSION_PATCH 3 + #include #include #include #include #include #include -#include -#include #include #include -#if defined(_MSC_VER) +#if defined(MAGIC_ENUM_CONFIG_FILE) +#include MAGIC_ENUM_CONFIG_FILE +#endif + +#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +#include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) +#include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +#include +#endif + +#if defined(__clang__) +# pragma clang diagnostic push +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. +#elif defined(_MSC_VER) # pragma warning(push) -# pragma warning(disable : 26495) // Variable 'magic_enum::detail::static_string::chars' is uninitialized. -# pragma warning(disable : 26451) // Arithmetic overflow: 'indexes[static_cast(value) - min_v]' using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +# pragma warning(disable : 26495) // Variable 'static_string::chars_' is uninitialized. +# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. #endif // Checks magic_enum compiler compatibility. -#if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) -# undef MAGIC_ENUM_SUPPORTED +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 +# undef MAGIC_ENUM_SUPPORTED # define MAGIC_ENUM_SUPPORTED 1 #endif +// Checks magic_enum compiler aliases compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 +# undef MAGIC_ENUM_SUPPORTED_ALIASES +# define MAGIC_ENUM_SUPPORTED_ALIASES 1 +#endif + // Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. // If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. #if !defined(MAGIC_ENUM_RANGE_MIN) @@ -68,544 +96,1043 @@ #endif namespace magic_enum { - - // Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. - // If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. - // If need another range for specific enum type, add specialization enum_range for necessary enum type. - template - struct enum_range { - static_assert(std::is_enum_v, "magic_enum::enum_range requires enum type."); - inline static constexpr int min = MAGIC_ENUM_RANGE_MIN; - inline static constexpr int max = MAGIC_ENUM_RANGE_MAX; - static_assert(max > min, "magic_enum::enum_range requires max > min."); - }; - - static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0."); - static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN."); - - static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0."); - static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX."); - - static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); - - namespace detail { - - template - struct supported -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) - : std::true_type {}; + +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. +#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +MAGIC_ENUM_USING_ALIAS_OPTIONAL #else - : std::false_type {}; +using std::optional; #endif - - template - inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; - - template - struct static_string { - constexpr explicit static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} { - assert(str.size() == N); - } - - constexpr const char* data() const noexcept { return chars.data(); } - - constexpr std::size_t size() const noexcept { return chars.size(); } - - constexpr operator std::string_view() const noexcept { return {data(), size()}; } - - private: - template - constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]...}} {} - - const std::array chars; - }; - - template <> - struct static_string<0> { - constexpr explicit static_string(std::string_view) noexcept {} - - constexpr const char* data() const noexcept { return nullptr; } - - constexpr std::size_t size() const noexcept { return 0; } - - constexpr operator std::string_view() const noexcept { return {}; } - }; - - constexpr std::string_view pretty_name(std::string_view name) noexcept { - for (std::size_t i = name.size(); i > 0; --i) { - if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || - (name[i - 1] >= 'a' && name[i - 1] <= 'z') || - (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || - (name[i - 1] == '_'))) { - name.remove_prefix(i); - break; - } - } - - if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || - (name.front() >= 'A' && name.front() <= 'Z') || - (name.front() == '_'))) { - return name; - } - - return {}; // Invalid name. - } - - template - constexpr bool mixed_sign_less(L lhs, R rhs) noexcept { - static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::mixed_sign_less requires integral type."); - - if constexpr (std::is_signed_v && std::is_unsigned_v) { - // If 'left' is negative, then result is 'true', otherwise cast & compare. - return lhs < 0 || static_cast>(lhs) < rhs; - } else if constexpr (std::is_unsigned_v && std::is_signed_v) { - // If 'right' is negative, then result is 'false', otherwise cast & compare. - return rhs >= 0 && lhs < static_cast>(rhs); - } else { - // If same signedness (both signed or both unsigned). - return lhs < rhs; - } - } - - template - constexpr auto n() noexcept { - static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + +// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +MAGIC_ENUM_USING_ALIAS_STRING_VIEW +#else +using std::string_view; +#endif + +// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING) +MAGIC_ENUM_USING_ALIAS_STRING +#else +using std::string; +#endif + +namespace customize { + +// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. +// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. +// If need another range for specific enum type, add specialization enum_range for necessary enum type. +template +struct enum_range { + static_assert(std::is_enum_v, "magic_enum::customize::enum_range requires enum type."); + inline static constexpr int min = MAGIC_ENUM_RANGE_MIN; + inline static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::customize::enum_range requires max > min."); +}; + +static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0."); +static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN."); + +static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0."); +static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX."); + +static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); + +// If need custom names for enum, add specialization enum_name for necessary enum type. +template +constexpr string_view enum_name(E) noexcept { + static_assert(std::is_enum_v, "magic_enum::customize::enum_name requires enum type."); + + return {}; +} + +} // namespace magic_enum::customize + +namespace detail { + +template +struct supported +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + +struct char_equal_to { + constexpr bool operator()(char lhs, char rhs) const noexcept { + return lhs == rhs; + } +}; + +template +class static_string { + public: + constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_index_sequence{}} { + assert(str.size() == N); + } + + constexpr const char* data() const noexcept { return chars_; } + + constexpr std::size_t size() const noexcept { return N; } + + constexpr operator string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_string(string_view str, std::index_sequence) noexcept : chars_{str[I]..., '\0'} {} + + char chars_[N + 1]; +}; + +template <> +class static_string<0> { + public: + constexpr explicit static_string(string_view) noexcept {} + + constexpr const char* data() const noexcept { return nullptr; } + + constexpr std::size_t size() const noexcept { return 0; } + + constexpr operator string_view() const noexcept { return {}; } +}; + +constexpr string_view pretty_name(string_view name) noexcept { + for (std::size_t i = name.size(); i > 0; --i) { + if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || + (name[i - 1] >= 'a' && name[i - 1] <= 'z') || + (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || + (name[i - 1] == '_'))) { + name.remove_prefix(i); + break; + } + } + + if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || + (name.front() >= 'A' && name.front() <= 'Z') || + (name.front() == '_'))) { + return name; + } + + return {}; // Invalid name. +} + +constexpr std::size_t find(string_view str, char c) noexcept { +#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) +// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc +// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + if constexpr (workaround) { + for (std::size_t i = 0; i < str.size(); ++i) { + if (str[i] == c) { + return i; + } + } + + return string_view::npos; + } else { + return str.find_first_of(c); + } +} + +template +constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) { + return {{a[I]...}}; +} + +template +constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v) { +#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + constexpr bool default_predicate = std::is_same_v, char_equal_to>; + + if constexpr (default_predicate && !workaround) { + static_cast(p); + return lhs == rhs; + } else { + if (lhs.size() != rhs.size()) { + return false; + } + + const auto size = lhs.size(); + for (std::size_t i = 0; i < size; ++i) { + if (!p(lhs[i], rhs[i])) { + return false; + } + } + + return true; + } +} + +template +constexpr bool cmp_less(L lhs, R rhs) noexcept { + static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); + + if constexpr (std::is_signed_v == std::is_signed_v) { + // If same signedness (both signed or both unsigned). + return lhs < rhs; + } else if constexpr (std::is_signed_v) { + // If 'right' is negative, then result is 'false', otherwise cast & compare. + return rhs > 0 && lhs < static_cast>(rhs); + } else { + // If 'left' is negative, then result is 'true', otherwise cast & compare. + return lhs < 0 || static_cast>(lhs) < rhs; + } +} + +template +constexpr I log2(I value) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); + + auto ret = I{0}; + for (; value > I{1}; value >>= I{1}, ++ret) {} + + return ret; +} + +template +constexpr bool is_pow2(I x) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::is_pow2 requires integral type."); + + return x != 0 && (x & (x - 1)) == 0; +} + +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED # if defined(__clang__) - constexpr std::string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; + constexpr string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; # elif defined(__GNUC__) - constexpr std::string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51}; + constexpr string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51}; # elif defined(_MSC_VER) - constexpr std::string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57}; + constexpr string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57}; # endif - return static_string{name}; + return static_string{name}; #else - static_assert(supported::value, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); - return std::string_view{}; // Unsupported compiler. + return string_view{}; // Unsupported compiler. #endif - } - - template - inline constexpr auto type_name_v = n(); - - template - constexpr auto n() noexcept { - static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); +} + +template +inline constexpr auto type_name_v = n(); + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + constexpr auto custom_name = customize::enum_name(V); + + if constexpr (custom_name.empty()) { + static_cast(custom_name); #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED # if defined(__clang__) || defined(__GNUC__) - constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); + constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); # elif defined(_MSC_VER) - constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); + constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); # endif - return static_string{name}; + return static_string{name}; #else - static_assert(supported::value, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); - return std::string_view{}; // Unsupported compiler. + return string_view{}; // Unsupported compiler. #endif - } - - template - inline constexpr auto name_v = n(); - - template - constexpr int reflected_min() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_min requires enum type."); - constexpr auto lhs = enum_range::min; - static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); - constexpr auto rhs = (std::numeric_limits>::min)(); - - return mixed_sign_less(lhs, rhs) ? rhs : lhs; - } - - template - constexpr int reflected_max() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); - constexpr auto lhs = enum_range::max; - static_assert(lhs < (std::numeric_limits::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX."); - constexpr auto rhs = (std::numeric_limits>::max)(); - - return mixed_sign_less(lhs, rhs) ? lhs : rhs; - } - - template - inline constexpr int reflected_min_v = reflected_min(); - - template - inline constexpr int reflected_max_v = reflected_max(); - - template - constexpr std::size_t reflected_size() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_size requires enum type."); - static_assert(reflected_max_v > reflected_min_v, "magic_enum::enum_range requires max > min."); - constexpr auto size = reflected_max_v - reflected_min_v + 1; - static_assert(size > 0, "magic_enum::enum_range requires valid size."); - static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - - return static_cast(size); - } - - template - constexpr auto values(std::integer_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); - constexpr std::array valid{{(n(I + reflected_min_v)>().size() != 0)...}}; - constexpr int count = ((valid[I] ? 1 : 0) + ...); - - std::array values{}; - for (int i = 0, v = 0; v < count; ++i) { - if (valid[i]) { - values[v++] = static_cast(i + reflected_min_v); - } - } - - return values; - } - - template - inline constexpr auto values_v = values(std::make_integer_sequence()>{}); - - template - inline constexpr std::size_t count_v = values_v.size(); - - template - inline constexpr int min_v = values_v.empty() ? 0 : static_cast(values_v.front()); - - template - inline constexpr int max_v = values_v.empty() ? 0 : static_cast(values_v.back()); - - template - constexpr std::size_t range_size() noexcept { - static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); - constexpr auto size = max_v - min_v + 1; - static_assert(size > 0, "magic_enum::enum_range requires valid size."); - static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - - return static_cast(size); - } - - template - inline constexpr std::size_t range_size_v = range_size(); - - template - using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; - - template - inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); - - template - constexpr auto indexes(std::integer_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::indexes requires enum type."); - index_t i = 0; - - return std::array, sizeof...(I)>{{((n(I + min_v)>().size() != 0) ? i++ : invalid_index_v)...}}; - } - - template - constexpr auto names(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); - - return std::array{{name_v[I]>...}}; - } - - template - constexpr auto entries(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); - - return std::array, sizeof...(I)>{{{values_v[I], name_v[I]>}...}}; - } - - template - using enable_if_enum_t = std::enable_if_t>, R>; - - template >>> - using enum_concept = T; - - template > - struct is_scoped_enum : std::false_type {}; - - template - struct is_scoped_enum : std::bool_constant>> {}; - - template > - struct is_unscoped_enum : std::false_type {}; - - template - struct is_unscoped_enum : std::bool_constant>> {}; - - template >> - struct underlying_type {}; - - template - struct underlying_type : std::underlying_type> {}; - - template - struct enum_traits {}; - - template - struct enum_traits>> { - using type = E; - using underlying_type = typename detail::underlying_type::type; - - inline static constexpr std::string_view type_name = detail::type_name_v; - - inline static constexpr bool is_unscoped = detail::is_unscoped_enum::value; - inline static constexpr bool is_scoped = detail::is_scoped_enum::value; - inline static constexpr bool is_dense = detail::range_size_v == detail::count_v; - inline static constexpr bool is_sparse = detail::range_size_v != detail::count_v; - - inline static constexpr std::size_t count = detail::count_v; - inline static constexpr std::array values = detail::values_v; - inline static constexpr std::array names = detail::names(std::make_index_sequence>{}); - inline static constexpr std::array, count> entries = detail::entries(std::make_index_sequence>{}); - - [[nodiscard]] static constexpr bool reflected(E value) noexcept { - return static_cast(value) >= static_cast(reflected_min_v) && static_cast(value) <= static_cast(reflected_max_v); - } - - [[nodiscard]] static constexpr int index(E value) noexcept { - if (static_cast(value) >= static_cast(min_v) && static_cast(value) <= static_cast(max_v)) { - if constexpr (is_sparse) { - if (const auto i = indexes[static_cast(value) - min_v]; i != invalid_index_v) { - return i; - } - } else { - return static_cast(value) - min_v; - } - } - - return -1; // Value out of range. - } - - [[nodiscard]] static constexpr E value(std::size_t index) noexcept { - if constexpr (is_sparse) { - return assert(index < count), values[index]; - } else { - return assert(index < count), static_cast(index + min_v); - } - } - - [[nodiscard]] static constexpr std::string_view name(E value) noexcept { - if (const auto i = index(value); i != -1) { - return names[i]; - } - - return {}; // Value out of range. - } - - private: - static_assert(is_enum_v, "magic_enum::enum_traits requires enum type."); - static_assert(count > 0, "magic_enum::enum_range requires enum implementation or valid max and min."); - using U = underlying_type; - inline static constexpr auto indexes = detail::indexes(std::make_integer_sequence>{}); - }; - - } // namespace magic_enum::detail - - // Checks is magic_enum supported compiler. - inline constexpr bool is_magic_enum_supported = detail::supported::value; - - template - using Enum = detail::enum_concept; - - // Checks whether T is an Unscoped enumeration type. - // Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. - template - struct is_unscoped_enum : detail::is_unscoped_enum {}; - - template - inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; - - // Checks whether T is an Scoped enumeration type. - // Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. - template - struct is_scoped_enum : detail::is_scoped_enum {}; - - template - inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; - - // If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. - // Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. - template - struct underlying_type : detail::underlying_type {}; - - template - using underlying_type_t = typename underlying_type::type; - - // Enum traits defines a compile-time template-based interface to query the properties of enum. - template - using enum_traits = detail::enum_traits>; - - // Obtains enum value from enum string name. - // Returns std::optional with enum value. - template - [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - if constexpr (detail::range_size_v > detail::count_v * 2) { - for (std::size_t i = 0; i < enum_traits::count; ++i) { - if (value == enum_traits::names[i]) { - return enum_traits::values[i]; - } - } - } else { - for (auto i = detail::min_v; i <= detail::max_v; ++i) { - if (value == enum_traits::name(static_cast(i))) { - return static_cast(i); - } - } - } - - return std::nullopt; // Invalid value or out of range. + } else { + return static_string{custom_name}; + } +} + +template +inline constexpr auto enum_name_v = n(); + +template +constexpr bool is_valid() noexcept { + static_assert(is_enum_v, "magic_enum::detail::is_valid requires enum type."); + + return n(V)>().size() != 0; +} + +template > +constexpr E value(std::size_t i) noexcept { + static_assert(is_enum_v, "magic_enum::detail::value requires enum type."); + + if constexpr (IsFlags) { + return static_cast(U{1} << static_cast(static_cast(i) + O)); + } else { + return static_cast(static_cast(i) + O); + } +} + +template > +constexpr int reflected_min() noexcept { + static_assert(is_enum_v, "magic_enum::detail::reflected_min requires enum type."); + + if constexpr (IsFlags) { + return 0; + } else { + constexpr auto lhs = customize::enum_range::min; + static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); + constexpr auto rhs = (std::numeric_limits::min)(); + + if constexpr (cmp_less(lhs, rhs)) { + return rhs; + } else { + static_assert(!is_valid(0)>(), "magic_enum::enum_range detects enum value smaller than min range size."); + return lhs; } - - // Obtains enum value from integer value. - // Returns std::optional with enum value. - template - [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - if (enum_traits::index(static_cast(value)) != -1) { - return static_cast(value); - } - - return std::nullopt; // Invalid value or out of range. + } +} + +template > +constexpr int reflected_max() noexcept { + static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); + + if constexpr (IsFlags) { + return std::numeric_limits::digits - 1; + } else { + constexpr auto lhs = customize::enum_range::max; + static_assert(lhs < (std::numeric_limits::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX."); + constexpr auto rhs = (std::numeric_limits::max)(); + + if constexpr (cmp_less(lhs, rhs)) { + static_assert(!is_valid(0)>(), "magic_enum::enum_range detects enum value larger than max range size."); + return lhs; + } else { + return rhs; } - - // Returns integer value from enum value. - template - [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t> { - return static_cast>(value); + } +} + +template +inline constexpr auto reflected_min_v = reflected_min(); + +template +inline constexpr auto reflected_max_v = reflected_max(); + +template +constexpr std::size_t values_count(const bool (&valid)[N]) noexcept { + auto count = std::size_t{0}; + for (std::size_t i = 0; i < N; ++i) { + if (valid[i]) { + ++count; } - - // Obtains index in enum value sequence from enum value. - // Returns std::optional with index. - template - [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { - if (const auto i = enum_traits::index(value); i != -1) { - return i; - } - - return std::nullopt; // Value out of range. + } + + return count; +} + +template +constexpr auto values(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); + constexpr bool valid[sizeof...(I)] = {is_valid(I)>()...}; + constexpr std::size_t count = values_count(valid); + + if constexpr (count > 0) { + E values[count] = {}; + for (std::size_t i = 0, v = 0; v < count; ++i) { + if (valid[i]) { + values[v++] = value(i); + } } - - // Returns enum value at specified index. - // No bounds checking is performed: the behavior is undefined if index >= number of enum values. - template - [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { - return enum_traits::value(index); + + return to_array(values, std::make_index_sequence{}); + } else { + return std::array{}; + } +} + +template > +constexpr auto values() noexcept { + static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); + constexpr auto min = reflected_min_v; + constexpr auto max = reflected_max_v; + constexpr auto range_size = max - min + 1; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return values>(std::make_index_sequence{}); +} + +template +inline constexpr auto values_v = values(); + +template > +using values_t = decltype((values_v)); + +template +inline constexpr auto count_v = values_v.size(); + +template > +inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; + +template > +inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; + +template > +constexpr std::size_t range_size() noexcept { + static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); + constexpr auto max = IsFlags ? log2(max_v) : max_v; + constexpr auto min = IsFlags ? log2(min_v) : min_v; + constexpr auto range_size = max - min + U{1}; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return static_cast(range_size); +} + +template +inline constexpr auto range_size_v = range_size(); + +template +using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; + +template +inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); + +template +constexpr auto indexes(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::indexes requires enum type."); + constexpr auto min = IsFlags ? log2(min_v) : min_v; + [[maybe_unused]] auto i = index_t{0}; + + return std::array{{(is_valid(I)>() ? i++ : invalid_index_v)...}}; +} + +template +inline constexpr auto indexes_v = indexes(std::make_index_sequence>{}); + +template +constexpr auto names(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); + + return std::array{{enum_name_v[I]>...}}; +} + +template +inline constexpr auto names_v = names(std::make_index_sequence>{}); + +template > +using names_t = decltype((names_v)); + +template +constexpr auto entries(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); + + return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; +} + +template +inline constexpr auto entries_v = entries(std::make_index_sequence>{}); + +template > +using entries_t = decltype((entries_v)); + +template > +constexpr bool is_sparse() noexcept { + static_assert(is_enum_v, "magic_enum::detail::is_sparse requires enum type."); + + return range_size_v != count_v; +} + +template +inline constexpr bool is_sparse_v = is_sparse(); + +template > +constexpr std::size_t undex(U value) noexcept { + static_assert(is_enum_v, "magic_enum::detail::undex requires enum type."); + + if (const auto i = static_cast(value - min_v); value >= min_v && value <= max_v) { + if constexpr (is_sparse_v) { + if (const auto idx = indexes_v[i]; idx != invalid_index_v) { + return idx; + } + } else { + return i; } - - // Obtains value enum sequence. - // Returns std::array with enum values, sorted by enum value. - template - [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t::values)&> { - return enum_traits::values; + } + + return invalid_index_v; // Value out of range. +} + +template > +constexpr std::size_t endex(E value) noexcept { + static_assert(is_enum_v, "magic_enum::detail::endex requires enum type."); + + return undex(static_cast(value)); +} + +template > +constexpr U value_ors() noexcept { + static_assert(is_enum_v, "magic_enum::detail::endex requires enum type."); + + auto value = U{0}; + for (std::size_t i = 0; i < count_v; ++i) { + value |= static_cast(values_v[i]); + } + + return value; +} + +template +struct enable_if_enum {}; + +template +struct enable_if_enum { + using type = R; + using D = std::decay_t; + static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); +}; + +template +using enable_if_enum_t = std::enable_if_t>, R>; + +template >>> +using enum_concept = T; + +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::bool_constant>> {}; + +template > +struct is_unscoped_enum : std::false_type {}; + +template +struct is_unscoped_enum : std::bool_constant>> {}; + +template >> +struct underlying_type {}; + +template +struct underlying_type : std::underlying_type> {}; + +} // namespace magic_enum::detail + +// Checks is magic_enum supported compiler. +inline constexpr bool is_magic_enum_supported = detail::supported::value; + +template +using Enum = detail::enum_concept; + +// Checks whether T is an Unscoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. +template +struct is_unscoped_enum : detail::is_unscoped_enum {}; + +template +inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; + +// Checks whether T is an Scoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. +template +struct is_scoped_enum : detail::is_scoped_enum {}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. +// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. +template +struct underlying_type : detail::underlying_type {}; + +template +using underlying_type_t = typename underlying_type::type; + +// Returns type name of enum. +template +[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + constexpr string_view name = detail::type_name_v; + static_assert(name.size() > 0, "Enum type does not have a name."); + + return name; +} + +// Returns number of enum values. +template +[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return detail::count_v; +} + +// Returns enum value at specified index. +// No bounds checking is performed: the behavior is undefined if index >= number of enum values. +template +[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); + + if constexpr (detail::is_sparse_v) { + return assert((index < detail::count_v)), detail::values_v[index]; + } else { + return assert((index < detail::count_v)), detail::value>(index); + } +} + +// Returns std::array with enum values, sorted by enum value. +template +[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); + + return detail::values_v; +} + +// Returns name from static storage enum variable. +// This version is much lighter on the compile times and is not restricted to the enum_range limitation. +template +[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + constexpr string_view name = detail::enum_name_v; + static_assert(name.size() > 0, "Enum value does not have a name."); + + return name; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template +[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + if (const auto i = detail::endex(value); i != detail::invalid_index_v) { + return detail::names_v[i]; + } + + return {}; // Invalid value or out of range. +} + +// Returns std::array with names, sorted by enum value. +template +[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); + + return detail::names_v; +} + +// Returns std::array with pairs (value, name), sorted by enum value. +template +[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); + + return detail::entries_v; +} + +// Obtains enum value from integer value. +// Returns optional with enum value. +template +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + if (detail::undex(value) != detail::invalid_index_v) { + return static_cast(value); + } + + return {}; // Invalid value or out of range. +} + +// Obtains enum value from name. +// Returns optional with enum value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { + static_assert(std::is_invocable_r_v, "magic_enum::enum_cast requires bool(char, char) invocable predicate."); + using D = std::decay_t; + + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(value, detail::names_v[i], p)) { + return enum_value(i); } - - // Returns number of enum values. - template - [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { - return enum_traits::count; + } + + return {}; // Invalid value or out of range. +} + +// Obtains enum value from name. +// Returns optional with enum value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + return enum_cast(value, detail::char_equal_to{}); +} + +// Returns integer value from enum value. +template +[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t> { + return static_cast>(value); +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + + if (const auto i = detail::endex(value); i != detail::invalid_index_v) { + return i; + } + + return {}; // Invalid value or out of range. +} + +// Checks whether enum contains enumerator with such enum value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return detail::endex(value) != detail::invalid_index_v; +} + +// Checks whether enum contains enumerator with such integer value. +template +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return detail::undex(value) != detail::invalid_index_v; +} + +// Checks whether enum contains enumerator with such name. +template +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { + static_assert(std::is_invocable_r_v, "magic_enum::enum_contains requires bool(char, char) invocable predicate."); + using D = std::decay_t; + + return enum_cast(value, std::move_if_noexcept(p)).has_value(); +} + +// Checks whether enum contains enumerator with such name. +template +[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return enum_cast(value).has_value(); +} + +namespace ostream_operators { + +template , int> = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, E value) { + using D = std::decay_t; + using U = underlying_type_t; +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED + if (const auto name = magic_enum::enum_name(value); !name.empty()) { + for (const auto c : name) { + os.put(c); } - - // Returns string enum name from static storage enum variable. - // This version is much lighter on the compile times and is not restricted to the enum_range limitation. - template - [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t { - constexpr std::string_view name = detail::name_v, V>; - static_assert(name.size() > 0, "Enum value does not have a name."); - - return name; + return os; + } +#endif + return (os << static_cast(value)); +} + +template , int> = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { + return value.has_value() ? (os << value.value()) : os; +} + +} // namespace magic_enum::ostream_operators + +namespace bitwise_operators { + +template , int> = 0> +constexpr E operator~(E rhs) noexcept { + return static_cast(~static_cast>(rhs)); +} + +template , int> = 0> +constexpr E operator|(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) | static_cast>(rhs)); +} + +template , int> = 0> +constexpr E operator&(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) & static_cast>(rhs)); +} + +template , int> = 0> +constexpr E operator^(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); +} + +template , int> = 0> +constexpr E& operator|=(E& lhs, E rhs) noexcept { + return lhs = (lhs | rhs); +} + +template , int> = 0> +constexpr E& operator&=(E& lhs, E rhs) noexcept { + return lhs = (lhs & rhs); +} + +template , int> = 0> +constexpr E& operator^=(E& lhs, E rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +} // namespace magic_enum::bitwise_operators + +namespace flags { + +// Returns type name of enum. +using magic_enum::enum_type_name; + +// Returns number of enum-flags values. +template +[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return detail::count_v; +} + +// Returns enum-flags value at specified index. +// No bounds checking is performed: the behavior is undefined if index >= number of enum-flags values. +template +[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); + + if constexpr (detail::is_sparse_v) { + return assert((index < detail::count_v)), detail::values_v[index]; + } else { + constexpr auto min = detail::log2(detail::min_v); + + return assert((index < detail::count_v)), detail::value(index); + } +} + +// Returns std::array with enum-flags values, sorted by enum-flags value. +template +[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); + + return detail::values_v; +} + +// Returns name from enum-flags value. +// If enum-flags value does not have name or value out of range, returns empty string. +template +[[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_t { + using D = std::decay_t; + using U = underlying_type_t; + + string name; + auto check_value = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { + check_value |= v; + const auto n = detail::names_v[i]; + if (!name.empty()) { + name.append(1, '|'); + } + name.append(n.data(), n.size()); } - - // Returns string enum name from enum value. - // If enum value does not have name or value out of range, returns empty string. - template - [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { - return enum_traits::name(value); + } + + if (check_value != 0 && check_value == static_cast(value)) { + return name; + } + + return {}; // Invalid value or out of range. +} + +// Returns std::array with string names, sorted by enum-flags value. +template +[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); + + return detail::names_v; +} + +// Returns std::array with pairs (value, name), sorted by enum-flags value. +template +[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); + + return detail::entries_v; +} + +// Obtains enum-flags value from integer value. +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + using U = underlying_type_t; + + if constexpr (detail::is_sparse_v) { + auto check_value = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { + check_value |= v; + } } - - // Obtains string enum name sequence. - // Returns std::array with string enum names, sorted by enum value. - template - [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t::names)&> { - return enum_traits::names; + + if (check_value != 0 && check_value == value) { + return static_cast(value); } - - // Obtains pair (value enum, string enum name) sequence. - // Returns std::array with std::pair (value enum, string enum name), sorted by enum value. - template - [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t::entries)&> { - return enum_traits::entries; + } else { + constexpr auto min = detail::min_v; + constexpr auto max = detail::value_ors(); + + if (value >= min && value <= max) { + return static_cast(value); } - - namespace ostream_operators { - - template - auto operator<<(std::basic_ostream& os, E value) -> detail::enable_if_enum_t&> { - if (const auto name = enum_name(value); !name.empty()) { - for (const auto c : name) { - os.put(c); - } - } else { - os << enum_integer(value); - } - - return os; - } - - template - auto operator<<(std::basic_ostream& os, std::optional value) -> detail::enable_if_enum_t&> { - if (value.has_value()) { - os << value.value(); - } - - return os; - } - - } // namespace magic_enum::ostream_operators - - namespace bitwise_operators { - - template - constexpr auto operator~(E rhs) noexcept -> detail::enable_if_enum_t { - return static_cast(~static_cast>(rhs)); - } - - template - constexpr auto operator|(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return static_cast(static_cast>(lhs) | static_cast>(rhs)); - } - - template - constexpr auto operator&(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return static_cast(static_cast>(lhs) & static_cast>(rhs)); - } - - template - constexpr auto operator^(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); - } - - template - constexpr auto operator|=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return lhs = lhs | rhs; - } - - template - constexpr auto operator&=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return lhs = lhs & rhs; - } - - template - constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { - return lhs = lhs ^ rhs; - } - - } // namespace magic_enum::bitwise_operators - + } + + return {}; // Invalid value or out of range. +} + +// Obtains enum-flags value from name. +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { + static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_cast requires bool(char, char) invocable predicate."); + using D = std::decay_t; + using U = underlying_type_t; + + auto result = U{0}; + while (!value.empty()) { + const auto d = detail::find(value, '|'); + const auto s = (d == string_view::npos) ? value : value.substr(0, d); + auto f = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(s, detail::names_v[i], p)) { + f = static_cast(enum_value(i)); + result |= f; + break; + } + } + if (f == U{0}) { + return {}; // Invalid value or out of range. + } + value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); + } + + if (result == U{0}) { + return {}; // Invalid value or out of range. + } else { + return static_cast(result); + } +} + +// Obtains enum-flags value from name. +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + return enum_cast(value, detail::char_equal_to{}); +} + +// Returns integer value from enum value. +using magic_enum::enum_integer; + +// Obtains index in enum-flags values from enum-flags value. +// Returns optional with index. +template +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { + using D = std::decay_t; + using U = underlying_type_t; + + if (detail::is_pow2(static_cast(value))) { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (enum_value(i) == value) { + return i; + } + } + } + + return {}; // Invalid value or out of range. +} + +// Checks whether enum-flags contains enumerator with such enum-flags value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + using U = underlying_type_t; + + return enum_cast(static_cast(value)).has_value(); +} + +// Checks whether enum-flags contains enumerator with such integer value. +template +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return enum_cast(value).has_value(); +} + +// Checks whether enum-flags contains enumerator with such name. +template +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { + static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate."); + using D = std::decay_t; + + return enum_cast(value, std::move_if_noexcept(p)).has_value(); +} + +// Checks whether enum-flags contains enumerator with such name. +template +[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t { + using D = std::decay_t; + + return enum_cast(value).has_value(); +} + +} // namespace magic_enum::flags + +namespace flags::ostream_operators { + +template , int> = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, E value) { + using D = std::decay_t; + using U = underlying_type_t; +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED + if (const auto name = magic_enum::flags::enum_name(value); !name.empty()) { + for (const auto c : name) { + os.put(c); + } + return os; + } +#endif + return (os << static_cast(value)); +} + +template , int> = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { + return value.has_value() ? (os << value.value()) : os; +} + +} // namespace magic_enum::flags::ostream_operators + +namespace flags::bitwise_operators { + +using namespace magic_enum::bitwise_operators; + +} // namespace magic_enum::flags::bitwise_operators + } // namespace magic_enum -#if defined(_MSC_VER) +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) # pragma warning(pop) #endif diff --git a/platforms/sdl/main.cpp.in b/platforms/sdl/main.cpp.in index d570935..cf38c66 100644 --- a/platforms/sdl/main.cpp.in +++ b/platforms/sdl/main.cpp.in @@ -264,7 +264,15 @@ void platform::save_dialog(std::function returnFunction) { } char* platform::translate_keycode(const unsigned int keycode) { - return const_cast(SDL_GetKeyName(keycode)); + return const_cast(SDL_GetKeyName(SDL_GetKeyFromScancode((SDL_Scancode)keycode))); +} + +void platform::begin_text_input() { + SDL_StartTextInput(); +} + +void platform::end_text_input() { + SDL_StopTextInput(); } void platform::mute_output() {} @@ -320,7 +328,13 @@ int main(int argc, char* argv[]) { engine->process_key_down(event.key.keysym.scancode); } break; + case SDL_KEYUP: + { + engine->process_key_up(event.key.keysym.scancode); + } + break; case SDL_WINDOWEVENT: + { if (event.window.event == SDL_WINDOWEVENT_RESIZED) { auto window = get_window_by_sdl_id(event.window.windowID); if(window != nullptr) @@ -328,7 +342,13 @@ int main(int argc, char* argv[]) { } else if(event.window.event == SDL_WINDOWEVENT_CLOSE) { engine->quit(); } + } break; + case SDL_TEXTINPUT: + { + engine->process_text_input(event.text.text); + } + break; } } From 6fde122401e3ccae14828a77197425e417db5c57 Mon Sep 17 00:00:00 2001 From: redstrate Date: Thu, 7 Oct 2021 17:55:14 -0400 Subject: [PATCH 10/12] Improve console interface --- engine/core/src/debug.cpp | 12 ++++++++++-- engine/core/src/input.cpp | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/engine/core/src/debug.cpp b/engine/core/src/debug.cpp index 7925b27..2007b73 100644 --- a/engine/core/src/debug.cpp +++ b/engine/core/src/debug.cpp @@ -250,9 +250,17 @@ void draw_console() { ImGui::Text("%s", prism::log_output.c_str()); static std::string console_input; - ImGui::InputText("##console_input", &console_input); - if(ImGui::Button("Input")) { + ImGui::SetNextItemWidth(-1.0f); + + const bool input_return = ImGui::InputText("##console_input", &console_input, ImGuiInputTextFlags_EnterReturnsTrue); + + if(input_return) + ImGui::SetKeyboardFocusHere(-1); + + const bool button_return = ImGui::Button("Input"); + + if(input_return || button_return) { prism::console::parse_and_invoke_command(console_input); console_input.clear(); } diff --git a/engine/core/src/input.cpp b/engine/core/src/input.cpp index 5ee2844..90362f0 100755 --- a/engine/core/src/input.cpp +++ b/engine/core/src/input.cpp @@ -174,5 +174,8 @@ bool input_system::get_allowable_text_button(unsigned int keycode) const { if(platform::get_keycode(InputButton::Backspace) == keycode) return true; + if(platform::get_keycode(InputButton::Enter) == keycode) + return true; + return false; } \ No newline at end of file From 182fbe195a460278d797a1f9ab49c75f9a6b8ea0 Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 11 Oct 2021 13:39:15 -0400 Subject: [PATCH 11/12] Add imgui open/save dialog --- engine/core/include/engine.hpp | 4 ++ engine/core/include/imgui_backend.hpp | 25 ++++++++++++ engine/core/src/debug.cpp | 3 +- engine/core/src/imgui_backend.cpp | 56 +++++++++++++++++++++++++++ engine/platform/include/platform.hpp | 12 ------ platforms/sdl/main.cpp.in | 6 --- tools/common/include/commoneditor.hpp | 3 +- tools/common/src/commoneditor.cpp | 9 ++--- tools/editor/src/materialeditor.cpp | 4 +- tools/editor/src/prefabeditor.cpp | 4 +- tools/editor/src/prismeditor.cpp | 2 +- tools/editor/src/sceneeditor.cpp | 6 +-- 12 files changed, 101 insertions(+), 33 deletions(-) diff --git a/engine/core/include/engine.hpp b/engine/core/include/engine.hpp index 30fa471..69f513a 100755 --- a/engine/core/include/engine.hpp +++ b/engine/core/include/engine.hpp @@ -248,6 +248,10 @@ namespace prism { */ void update_scene(Scene& scene); + imgui_backend& get_imgui() { + return *imgui; + } + /// The current cutscene. std::unique_ptr cutscene; diff --git a/engine/core/include/imgui_backend.hpp b/engine/core/include/imgui_backend.hpp index 5b302da..6502ac8 100644 --- a/engine/core/include/imgui_backend.hpp +++ b/engine/core/include/imgui_backend.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace prism { class imgui_backend { @@ -18,7 +19,31 @@ namespace prism { void process_text_input(const std::string_view string); + /**Opens a file dialog to select a file. This will not block. + @param existing Whether or not to limit to existing files. + @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. + @param openDirectory Whether or not to allow selecting directories as well. + */ + void open_dialog(const bool existing, std::function returnFunction, bool openDirectory = false); + + /**Opens a file dialog to select a save location for a file. This will not block. + @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. + */ + void save_dialog(std::function returnFunction); + private: bool mouse_buttons[3] = {}; + + bool open_dialog_next_frame = false; + bool save_dialog_next_frame = false; + + struct dialog_data { + std::filesystem::path current_path; + std::filesystem::path selected_path; + std::function return_function; + }; + + dialog_data open_dialog_data; + dialog_data save_dialog_data; }; } \ No newline at end of file diff --git a/engine/core/src/debug.cpp b/engine/core/src/debug.cpp index 2007b73..5d4635f 100644 --- a/engine/core/src/debug.cpp +++ b/engine/core/src/debug.cpp @@ -13,6 +13,7 @@ #include "renderer.hpp" #include "file.hpp" #include "console.hpp" +#include "imgui_backend.hpp" struct Options { std::string shader_source_path; @@ -169,7 +170,7 @@ void draw_shader_editor() { if(options.shader_source_path.empty()) { ImGui::Text("You haven't specified a shader source path yet. Please select one below:"); if(ImGui::Button("Select Path")) { - platform::open_dialog(false, [](std::string path) { + engine->get_imgui().open_dialog(false, [](std::string path) { // open_dialog() can't select folders yet, so use this as a workaround options.shader_source_path = prism::path(path).parent_path().string(); }); diff --git a/engine/core/src/imgui_backend.cpp b/engine/core/src/imgui_backend.cpp index 05ad732..9f61ce7 100644 --- a/engine/core/src/imgui_backend.cpp +++ b/engine/core/src/imgui_backend.cpp @@ -204,6 +204,50 @@ void imgui_backend::begin_frame(const float delta_time) { mouse_buttons[0] = mouse_buttons[1] = mouse_buttons[2] = false; ImGui::NewFrame(); + + if(open_dialog_next_frame) { + ImGui::OpenPopup("Open File"); + open_dialog_next_frame = false; + } + + if(save_dialog_next_frame) { + ImGui::OpenPopup("Save File"); + save_dialog_next_frame = false; + } + + const auto dialog_function = [](dialog_data& data) { + if(ImGui::Selectable("..", false, ImGuiSelectableFlags_DontClosePopups)) + data.current_path = data.current_path.parent_path(); + + for(auto dir_ent : std::filesystem::directory_iterator(data.current_path)) { + if(ImGui::Selectable(dir_ent.path().c_str(), data.selected_path == dir_ent.path(), ImGuiSelectableFlags_DontClosePopups)) { + if(dir_ent.is_directory()) + data.current_path = dir_ent.path(); + else + data.selected_path = dir_ent.path(); + } + } + + ImGui::TextDisabled("Selected: %s", data.selected_path.c_str()); + + if(ImGui::Button("OK")) { + data.return_function(data.selected_path.string()); + ImGui::CloseCurrentPopup(); + } + + if(ImGui::Button("Cancel")) + ImGui::CloseCurrentPopup(); + }; + + if(ImGui::BeginPopup("Open File")) { + dialog_function(open_dialog_data); + ImGui::EndPopup(); + } + + if(ImGui::BeginPopup("Save File")) { + dialog_function(save_dialog_data); + ImGui::EndPopup(); + } } void imgui_backend::render(int index) { @@ -239,3 +283,15 @@ void prism::imgui_backend::process_text_input(const std::string_view string) { ImGuiIO& io = ImGui::GetIO(); io.AddInputCharactersUTF8(string.data()); } + +void prism::imgui_backend::open_dialog(const bool existing, std::function returnFunction, bool openDirectory) { + open_dialog_next_frame = true; + open_dialog_data.current_path = std::filesystem::current_path(); + open_dialog_data.return_function = returnFunction; +} + +void prism::imgui_backend::save_dialog(std::function returnFunction) { + save_dialog_next_frame = true; + save_dialog_data.current_path = std::filesystem::current_path(); + save_dialog_data.return_function = returnFunction; +} \ No newline at end of file diff --git a/engine/platform/include/platform.hpp b/engine/platform/include/platform.hpp index 0c35556..1789a3b 100755 --- a/engine/platform/include/platform.hpp +++ b/engine/platform/include/platform.hpp @@ -163,18 +163,6 @@ namespace platform { void begin_text_input(); void end_text_input(); - /**Opens a file dialog to select a file. This will not block. - @param existing Whether or not to limit to existing files. - @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. - @param openDirectory Whether or not to allow selecting directories as well. - */ - void open_dialog(const bool existing, std::function returnFunction, bool openDirectory = false); - - /**Opens a file dialog to select a save location for a file. This will not block. - @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. - */ - void save_dialog(std::function returnFunction); - /**Translates a virtual keycode to it's character equivalent. @note Example: translateKey(0x01) = 'a'; 0x01 in this example is a platform and language specific keycode for a key named 'a'. @return A char pointer to the string if translated correctly. diff --git a/platforms/sdl/main.cpp.in b/platforms/sdl/main.cpp.in index cf38c66..7741930 100644 --- a/platforms/sdl/main.cpp.in +++ b/platforms/sdl/main.cpp.in @@ -257,12 +257,6 @@ void platform::capture_mouse(const bool capture) { SDL_CaptureMouse((SDL_bool)capture); } -void platform::open_dialog(const bool existing, std::function returnFunction, bool openDirectory) { -} - -void platform::save_dialog(std::function returnFunction) { -} - char* platform::translate_keycode(const unsigned int keycode) { return const_cast(SDL_GetKeyName(SDL_GetKeyFromScancode((SDL_Scancode)keycode))); } diff --git a/tools/common/include/commoneditor.hpp b/tools/common/include/commoneditor.hpp index 7b980b7..dcee9ac 100755 --- a/tools/common/include/commoneditor.hpp +++ b/tools/common/include/commoneditor.hpp @@ -21,6 +21,7 @@ #include "asset.hpp" #include "scene.hpp" #include "renderer.hpp" +#include "imgui_backend.hpp" class TransformCommand : public Command { public: @@ -359,7 +360,7 @@ inline void editPath(const char* label, std::string& path, bool editable = true, ImGui::SameLine(); if(ImGui::Button("...")) { - platform::open_dialog(false, [&path, &on_selected](std::string p) { + engine->get_imgui().open_dialog(false, [&path, &on_selected](std::string p) { path = prism::get_relative_path(prism::domain::app, p).string(); if(on_selected != nullptr) diff --git a/tools/common/src/commoneditor.cpp b/tools/common/src/commoneditor.cpp index 0838449..5cf447a 100755 --- a/tools/common/src/commoneditor.cpp +++ b/tools/common/src/commoneditor.cpp @@ -47,11 +47,7 @@ const std::map imToPl = { }; CommonEditor::CommonEditor(std::string id) : id(id) { -#ifdef PLATFORM_MACOS - prism::set_domain_path(prism::domain::app, "../../../data"); -#else - prism::set_domain_path(prism::domain::app, "data"); -#endif + prism::set_domain_path(prism::domain::app, "{resource_dir}/data"); prism::set_domain_path(prism::domain::internal, "{resource_dir}/shaders"); ImGuiIO& io = ImGui::GetIO(); @@ -730,6 +726,9 @@ void cacheAssetFilesystem() { asset_files.clear(); auto data_directory = "data"; + if(!std::filesystem::exists(data_directory)) + return; + for(auto& p : std::filesystem::recursive_directory_iterator(data_directory)) { if(p.path().extension() == ".model" && mesh_readable(p.path())) { asset_files[std::filesystem::relative(p, data_directory)] = AssetType::Mesh; diff --git a/tools/editor/src/materialeditor.cpp b/tools/editor/src/materialeditor.cpp index c0f633d..1a2d6df 100755 --- a/tools/editor/src/materialeditor.cpp +++ b/tools/editor/src/materialeditor.cpp @@ -131,7 +131,7 @@ void MaterialEditor::draw(CommonEditor* editor) { if (ImGui::BeginMenu("File")) { if(ImGui::MenuItem("Save", "CTRL+S")) { if (path.empty()) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; save_material(*material, path); @@ -142,7 +142,7 @@ void MaterialEditor::draw(CommonEditor* editor) { } if (ImGui::MenuItem("Save as...", "CTRL+S")) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; save_material(*material, path); diff --git a/tools/editor/src/prefabeditor.cpp b/tools/editor/src/prefabeditor.cpp index c614e50..be930b5 100755 --- a/tools/editor/src/prefabeditor.cpp +++ b/tools/editor/src/prefabeditor.cpp @@ -36,7 +36,7 @@ void PrefabEditor::draw(CommonEditor* editor) { if (ImGui::BeginMenu("File")) { if(ImGui::MenuItem("Save", "CTRL+S")) { if (path.empty()) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; engine->save_prefab(root_object, path); @@ -47,7 +47,7 @@ void PrefabEditor::draw(CommonEditor* editor) { } if (ImGui::MenuItem("Save as...", "CTRL+S")) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; engine->save_prefab(root_object, path); diff --git a/tools/editor/src/prismeditor.cpp b/tools/editor/src/prismeditor.cpp index 1af48d9..6eb41ea 100755 --- a/tools/editor/src/prismeditor.cpp +++ b/tools/editor/src/prismeditor.cpp @@ -226,7 +226,7 @@ void PrismEditor::drawUI() { } if(ImGui::MenuItem("Open", "CTRL+O")) { - platform::open_dialog(true, [this](std::string path) { + engine->get_imgui().open_dialog(true, [this](std::string path) { open_requests.emplace_back(path, false); addOpenedFile(path); diff --git a/tools/editor/src/sceneeditor.cpp b/tools/editor/src/sceneeditor.cpp index c5ab0be..e43c714 100755 --- a/tools/editor/src/sceneeditor.cpp +++ b/tools/editor/src/sceneeditor.cpp @@ -44,7 +44,7 @@ void SceneEditor::draw(CommonEditor* editor) { if (ImGui::BeginMenu("File")) { if(ImGui::MenuItem("Save", "CTRL+S")) { if (path.empty()) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; engine->save_scene(path); @@ -55,7 +55,7 @@ void SceneEditor::draw(CommonEditor* editor) { } if(ImGui::MenuItem("Save as...", "CTRL+S")) { - platform::save_dialog([this](std::string path) { + engine->get_imgui().save_dialog([this](std::string path) { this->path = path; engine->save_scene(path); @@ -107,7 +107,7 @@ void SceneEditor::draw(CommonEditor* editor) { } if(ImGui::MenuItem("Prefab")) { - platform::open_dialog(false, [](std::string path) { + engine->get_imgui().open_dialog(false, [](std::string path) { engine->add_prefab(*engine->get_scene(), path); }); } From 91cf44a0de4ac7c2bf3db26a948b5e9b95442045 Mon Sep 17 00:00:00 2001 From: redstrate Date: Mon, 11 Oct 2021 14:33:45 -0400 Subject: [PATCH 12/12] Only enable LTO on release builds --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5c24d5..2024d4d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,9 @@ set(CROSS_LIBS add_subdirectory(extern) # enable lto -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) +if (CMAKE_BUILD_TYPE EQUAL "Release") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) +endif () add_subdirectory(platforms)