diff --git a/bin/data/config.json b/bin/data/config.json index 03fadef6..9d623896 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -274,7 +274,7 @@ "rebuild on tick begin": false }, "pipelines": { - "culling": false + "culling": true }, "experimental": { "rebuild on tick begin": false, diff --git a/bin/data/scenes/sourceengine/cs_office.json b/bin/data/scenes/sourceengine/cs_office.json index 398df6e8..af8b3c8d 100644 --- a/bin/data/scenes/sourceengine/cs_office.json +++ b/bin/data/scenes/sourceengine/cs_office.json @@ -1,7 +1,7 @@ { "import": "./base_sourceengine.json", "assets": [ - // { "filename": "./maps/cs_office.bsp" } - { "filename": "./maps/cs_office/graph.json" } + { "filename": "./maps/cs_office.bsp" } + // { "filename": "./maps/cs_office/graph.json" } ] } \ No newline at end of file diff --git a/bin/data/scenes/sourceengine/de_dust2.json b/bin/data/scenes/sourceengine/de_dust2.json index ac26e0d2..9b341be7 100644 --- a/bin/data/scenes/sourceengine/de_dust2.json +++ b/bin/data/scenes/sourceengine/de_dust2.json @@ -1,7 +1,7 @@ { "import": "./base_sourceengine.json", "assets": [ - { "filename": "./maps/de_dust2.bsp" } - // { "filename": "./maps/de_dust2/graph.json" } + // { "filename": "./maps/de_dust2.bsp" } + { "filename": "./maps/de_dust2/graph.json" } ] } \ No newline at end of file diff --git a/bin/data/scenes/sourceengine/sourceengine.json b/bin/data/scenes/sourceengine/sourceengine.json index f7a5e99b..89c57145 100644 --- a/bin/data/scenes/sourceengine/sourceengine.json +++ b/bin/data/scenes/sourceengine/sourceengine.json @@ -1,8 +1,8 @@ { // "import": "./rp_downtown_v2.json" // "import": "./ss2_medsci1.json" - "import": "./mds_mcdonalds.json" -// "import": "./cs_office.json" +// "import": "./mds_mcdonalds.json" + "import": "./cs_office.json" // "import": "./de_dust2.json" // "import": "./gm_construct.json" } \ No newline at end of file diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index f25afe1c..fbfa0fe8 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -97,6 +97,10 @@ struct Bounds { float padding1; vec3 max; float padding2; + vec3 center; + float padding3; + vec3 extent; + float padding4; }; struct LOD { diff --git a/bin/data/shaders/graph/cull/comp.glsl b/bin/data/shaders/graph/cull/comp.glsl index 797424c8..446caf14 100644 --- a/bin/data/shaders/graph/cull/comp.glsl +++ b/bin/data/shaders/graph/cull/comp.glsl @@ -27,8 +27,8 @@ float mipLevels( ivec2 size ) { vec4 aabbToSphere( Bounds bounds ) { vec4 sphere; - sphere.xyz = (bounds.max + bounds.min) * 0.5; - sphere.w = length((bounds.max - bounds.min) * 0.5); + sphere.xyz = bounds.center; + sphere.w = length( bounds.extent ); return sphere; } diff --git a/engine/inc/uf/ext/opengl/enums/format.inl b/engine/inc/uf/ext/opengl/enums/format.inl index 9e6d09b9..0602164b 100644 --- a/engine/inc/uf/ext/opengl/enums/format.inl +++ b/engine/inc/uf/ext/opengl/enums/format.inl @@ -182,4 +182,8 @@ static const type_t ASTC_10x10_SRGB_BLOCK = 180; static const type_t ASTC_12x10_UNORM_BLOCK = 181; static const type_t ASTC_12x10_SRGB_BLOCK = 182; static const type_t ASTC_12x12_UNORM_BLOCK = 183; -static const type_t ASTC_12x12_SRGB_BLOCK = 184; \ No newline at end of file +static const type_t ASTC_12x12_SRGB_BLOCK = 184; + +static const type_t R8G8B8A8_RGBE = 255; +static const type_t R8G8B8_UNORM_E8_SINT = R8G8B8A8_RGBE; +static const type_t R8G8B8E8_UFLOAT = R8G8B8A8_RGBE; \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/enums/format.inl b/engine/inc/uf/ext/vulkan/enums/format.inl index e837e2c0..6c2f7afd 100644 --- a/engine/inc/uf/ext/vulkan/enums/format.inl +++ b/engine/inc/uf/ext/vulkan/enums/format.inl @@ -182,4 +182,8 @@ static const type_t ASTC_10x10_SRGB_BLOCK = VK_FORMAT_ASTC_10x10_SRGB_BLOCK; static const type_t ASTC_12x10_UNORM_BLOCK = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; static const type_t ASTC_12x10_SRGB_BLOCK = VK_FORMAT_ASTC_12x10_SRGB_BLOCK; static const type_t ASTC_12x12_UNORM_BLOCK = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; -static const type_t ASTC_12x12_SRGB_BLOCK = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; \ No newline at end of file +static const type_t ASTC_12x12_SRGB_BLOCK = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; + +static const type_t R8G8B8A8_RGBE = (VkFormat)(255); +static const type_t R8G8B8_UNORM_E8_SINT = R8G8B8A8_RGBE; +static const type_t R8G8B8E8_UFLOAT = R8G8B8A8_RGBE; \ No newline at end of file diff --git a/engine/inc/uf/utils/image/image.h b/engine/inc/uf/utils/image/image.h index de4d0a61..ad1ed2de 100644 --- a/engine/inc/uf/utils/image/image.h +++ b/engine/inc/uf/utils/image/image.h @@ -93,7 +93,9 @@ namespace uf { size_t getChannels() const; uf::stl::string getHash() const; - size_t getFormat() const; + + size_t getFormat( bool srgb = false ) const; + void setFormat( size_t ); void setLayers( size_t ); diff --git a/engine/inc/uf/utils/mesh/grid.h b/engine/inc/uf/utils/mesh/grid.h index 0628e7d1..70702a55 100644 --- a/engine/inc/uf/utils/mesh/grid.h +++ b/engine/inc/uf/utils/mesh/grid.h @@ -126,6 +126,8 @@ namespace uf { slice.primitive.instance.auxID = atlasID; slice.primitive.instance.bounds.min = node.effectiveExtents.min; slice.primitive.instance.bounds.max = node.effectiveExtents.max; + slice.primitive.instance.bounds.center = (node.effectiveExtents.max + node.effectiveExtents.min) * 0.5f; + slice.primitive.instance.bounds.extent = (node.effectiveExtents.max - node.effectiveExtents.min) * 0.5f; slice.primitive.drawCommand.indices = slice.indices.size(); slice.primitive.drawCommand.instances = 1; diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index abc1e207..bd97dcd0 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -103,9 +103,13 @@ namespace pod { // should be for the specific draw call itself, rather than the mesh(let) entirely struct Bounds { pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; - alignas(4) float padding1 = 0; + alignas(4) float padding1; pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; - alignas(4) float padding2 = 0; + alignas(4) float padding2; + pod::Vector3f center = { 0, 0, 0 }; + alignas(4) float padding3; + pod::Vector3f extent = { 0, 0, 0 }; + alignas(4) float padding4; } bounds; // stores "pointers" on the GPU side for buffer locations, used for RT / recalculating barycentrics diff --git a/engine/src/engine/graph/convert.cpp b/engine/src/engine/graph/convert.cpp index 29064b7a..4e1b2f49 100644 --- a/engine/src/engine/graph/convert.cpp +++ b/engine/src/engine/graph/convert.cpp @@ -113,6 +113,8 @@ namespace { instance.jointID = -1; instance.bounds.min = boundsMin; instance.bounds.max = boundsMax; + instance.bounds.center = (boundsMax + boundsMin) * 0.5f; + instance.bounds.extent = (boundsMax - boundsMin) * 0.5f; if ( sourceDrawCommands ) { drawCommand = sourceDrawCommands[drawCommandID]; diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index d1c5aed0..9a9ab816 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -25,26 +25,46 @@ #endif namespace { + size_t deduceFormat( const uf::stl::string& format ) { + if ( format == "ARGB4444" ) return uf::renderer::enums::Format::R4G4B4A4_UNORM_PACK16; + if ( format == "RGB565" ) return uf::renderer::enums::Format::R5G6B5_UNORM_PACK16; + return 0; + } uf::Image decodeImage( ext::json::Value& json, pod::Graph& graph, const uf::stl::string& imageName ) { uf::Image image; uf::stl::string filename = ""; - size_t offset = 0, length = 0, layers = json["layers"].as(1); - uf::stl::string formatHint = ""; + size_t offset = 0; + size_t length = 0; + size_t format = 0; + size_t layers = json["layers"].as(1); + uf::stl::string extension = ""; + if ( json["format"].is() ) { + format = deduceFormat( json["format"].as() ); + } else { + format = json["format"].as(); + } #if UF_ENV_DREAMCAST - if (json["dtex"].isObject()) { + if ( json["dtex"].isObject() ) { filename = json["dtex"]["filename"].as(); + extension = "dtex"; + offset = json["dtex"]["offset"].as(); length = json["dtex"]["length"].as(); - formatHint = "dtex"; + if ( json["dtex"]["format"].is() ) { + format = deduceFormat( json["dtex"]["format"].as() ); + } else { + format = json["dtex"]["format"].as(); + } } else #endif if ( json["filename"].is() ) { filename = json["filename"].as(); + extension = uf::io::extension(filename); + offset = json["offset"].as(0); length = json["length"].as(0); - formatHint = uf::io::extension(filename); } else { auto size = uf::vector::decode( json["size"], pod::Vector2ui{} ); size_t bpp = json["bpp"].as(); @@ -52,6 +72,7 @@ namespace { auto pixels = uf::base64::decode( json["data"].as() ); image.loadFromBuffer( &pixels[0], size, bpp, channels, true ); image.setLayers( layers ); + image.setFormat( format ); return image; } @@ -60,19 +81,20 @@ namespace { if ( graph.settings.stream.textures ) { auto& storage = uf::graph::getStorage(graph); graph.streams.images[imageName] = { fullPath, offset, length }; - image.setFilename(fullPath); } else { uf::stl::vector buffer; - if (length > 0) { - uf::io::readAsBuffer(buffer, fullPath, offset, length); + if ( length > 0 ) { + uf::io::readAsBuffer( buffer, fullPath, offset, length ); } else { - uf::io::readAsBuffer(buffer, fullPath); + uf::io::readAsBuffer( buffer, fullPath ); } - uf::image::open( image, buffer, formatHint, false ); + uf::image::open( image, buffer, extension, false ); uf::image::layers( image, layers ); - image.setFilename(fullPath); } + + image.setFilename( fullPath ); + image.setFormat( format ); return image; } @@ -252,7 +274,7 @@ namespace { uf::io::readAsBuffer(mesh.buffers[attr.buffer], region.filename, region.offset, region.length); } - #if UF_ENV_DREAMCAST + #if 1 || UF_ENV_DREAMCAST // remove extraneous buffers // if ( graph.metadata["renderer"]["separate"].as() ) { diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index 96dc0caf..0d5f9e69 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -389,6 +389,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& auto& image = storage.images.map.at(name).data; uf::Serializer json; json["name"] = name; + json["format"] = image.getFormat(); if ( !settings.combined ) { uf::stl::string f = ::fmt::format("image.{}.png", i ); @@ -409,9 +410,44 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& json["layers"] = image.layers; #if UF_USE_DC_TEXCONV - auto converted = image.scale( {32, 32}, "nearest" ); + auto img = uf::Image(image); + pod::Vector2ui size = { 32, 32 }; + uf::stl::string filter = "nearest"; + uf::stl::string dtexFormat = "ARGB4444"; + if ( name == "lightmap_atlas" || img.getFormat() == uf::renderer::enums::Format::R8G8B8A8_RGBE ) { + size = { 128, 128 }; + filter = "linear"; + dtexFormat = "RGB565"; + auto* pixels = (pod::Vector4ub*) img.getPixels().data(); + auto& size = img.getDimensions(); + for ( auto p = 0; p < size.x * size.y; ++p ) { + auto& pixel = pixels[p]; + if ( pixel.w == 0 ) { + pixel = {0,0,0,255}; + continue; + } + + // decode + float exp = (float) pixel.w - 128.0f; + float mult = std::exp2(exp); + + const float gamma = 1.0f / 2.2f; + auto linear = pod::Vector3f{ pixel.x, pixel.y, pixel.z } * mult / 255.0f; + // tone-map + FOR_EACH( 3, { + linear[i] = linear[i] / ( 1 + linear[i] ); + }); + // gamma correct + linear = uf::vector::pow( uf::vector::clamp( linear, 0.0f, 1.0f ), gamma ); + // 0-1 => 0-255 + linear *= 255.0f; + pixel = { (uint8_t)(linear.x), (uint8_t)(linear.y), (uint8_t)(linear.z), 255 }; + } + } + + img = img.scale( size, filter ); uf::stl::vector dtexBytes; - auto dtex = ext::texconv::convert( converted ); + auto dtex = ext::texconv::convert( img, dtexFormat ); ext::texconv::save( dtex, dtexBytes ); size_t dtexOffset = dtexBuffer.size(); @@ -421,6 +457,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& json["dtex"]["filename"] = dtexBinName; json["dtex"]["offset"] = dtexOffset; json["dtex"]["length"] = dtexLength; + json["dtex"]["format"] = dtexFormat; #endif serializer["images"].emplace_back( json ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index c3e52bb1..d6ea0515 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -837,7 +837,37 @@ void uf::graph::process( pod::Graph& graph ) { graphMetadataJson["baking"]["enabled"] = false; textureDescriptors["lightmap_atlas"].srgb = false; - if ( !graphMetadataJson["lights"]["lightmap"].as() ) { + if ( graphMetadataJson["lights"]["lightmap"].as() ) { + #if UF_USE_OPENGL && !UF_ENV_DREAMCAST + auto& image = storage.images["lightmap_atlas"].data; + auto* pixels = (pod::Vector4ub*) image.getPixels().data(); + auto& size = image.getDimensions(); + for ( auto p = 0; p < size.x * size.y; ++p ) { + auto& pixel = pixels[p]; + if ( pixel.w == 0 ) { + pixel = {0,0,0,255}; + continue; + } + + // decode + float exp = (float) pixel.w - 128.0f; + float mult = std::exp2(exp); + + const float gamma = 1.0f / 2.2f; + auto linear = pod::Vector3f{ pixel.x, pixel.y, pixel.z } * mult / 255.0f; + // tone-map + FOR_EACH( 3, { + linear[i] = linear[i] / ( 1 + linear[i] ); + }); + // gamma correct + linear = uf::vector::pow( uf::vector::clamp( linear, 0.0f, 1.0f ), gamma ); + // 0-1 => 0-255 + linear *= 255.0f; + pixel = { (uint8_t)(linear.x), (uint8_t)(linear.y), (uint8_t)(linear.z), 255 }; + } + // to-do: update format + #endif + } else { for ( auto& name : graph.primitives ) { auto& primitives = storage.primitives[name]; for ( auto& primitive : primitives ) { @@ -1555,6 +1585,9 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) grouped.emplace_back(newInstance); } + bounds.center = (bounds.max + bounds.min) * 0.5f; + bounds.extent = uf::vector::abs(bounds.max - bounds.min) * 0.5f; + #if !UF_GRAPH_EXTENDED bool isFirstInstance = ( grouped.size() == primitives.size() ); bool isSkinned = graphMetadataJson["renderer"]["skinned"].as(); @@ -1575,16 +1608,10 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) bool isMesh = type == "mesh" || type == "hull"; if ( !isMesh ) { - auto min = bounds.min; // uf::matrix::multiply( model, bounds.min, 1.0f ); - auto max = bounds.max; // uf::matrix::multiply( model, bounds.max, 1.0f ); - - pod::Vector3f center = (max + min) * 0.5f; - pod::Vector3f extent = uf::vector::abs(max - min) * 0.5f; - - if ( ext::json::isNull( metadataJson["physics"]["center"] ) ) metadataJson["physics"]["center"] = uf::vector::encode( center ); - if ( ext::json::isNull( metadataJson["physics"]["extent"] ) ) metadataJson["physics"]["extent"] = uf::vector::encode( extent ); - if ( ext::json::isNull( metadataJson["physics"]["min"] ) ) metadataJson["physics"]["min"] = uf::vector::encode( min ); - if ( ext::json::isNull( metadataJson["physics"]["max"] ) ) metadataJson["physics"]["max"] = uf::vector::encode( max ); + if ( ext::json::isNull( metadataJson["physics"]["center"] ) ) metadataJson["physics"]["center"] = uf::vector::encode( bounds.center ); + if ( ext::json::isNull( metadataJson["physics"]["extent"] ) ) metadataJson["physics"]["extent"] = uf::vector::encode( bounds.extent ); + if ( ext::json::isNull( metadataJson["physics"]["min"] ) ) metadataJson["physics"]["min"] = uf::vector::encode( bounds.min ); + if ( ext::json::isNull( metadataJson["physics"]["max"] ) ) metadataJson["physics"]["max"] = uf::vector::encode( bounds.max ); } #if !UF_GRAPH_EXTENDED if ( isMesh ) { @@ -2108,7 +2135,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { auto& instance = primitive.instance; auto& drawCommand = primitive.drawCommand; - pod::Vector3f center = uf::matrix::multiply( model, (instance.bounds.max + instance.bounds.min) * 0.5f, 1.0f ); // transform the center of the draw call + pod::Vector3f center = uf::matrix::multiply( model, instance.bounds.center, 1.0f ); // transform the center of the draw call float distanceSquared = uf::vector::distanceSquared( center, controllerPosition ); // saves a sqrt() // store closest draw call diff --git a/engine/src/ext/gltf/processPrimitives.inl b/engine/src/ext/gltf/processPrimitives.inl index 213e43eb..f3f3f5d9 100644 --- a/engine/src/ext/gltf/processPrimitives.inl +++ b/engine/src/ext/gltf/processPrimitives.inl @@ -186,6 +186,9 @@ for ( auto& p : m.primitives ) { meshlet.primitive.drawCommand.instanceID = 0; meshlet.primitive.drawCommand.vertices = meshlet.vertices.size(); + meshlet.primitive.instance.bounds.center = (meshlet.primitive.instance.bounds.max + meshlet.primitive.instance.bounds.min) * 0.5f; + meshlet.primitive.instance.bounds.extent = (meshlet.primitive.instance.bounds.max - meshlet.primitive.instance.bounds.min) * 0.5f; + /* detect winding order */ if ( sanitizer.windingOrder.should ) { sanitizer.windingOrder.corrected += uf::mesh::windingOrder( meshlet.vertices, meshlet.indices ); sanitizer.windingOrder.total += meshlet.indices.empty() ? meshlet.vertices.size() : meshlet.indices.size(); diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index 2a8cb118..c0c6c049 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -197,71 +197,29 @@ pod::Matrix4f ext::opengl::CommandBuffer::bindUniform( const ext::opengl::Buffer namespace { bool inside( const pod::Instance& instance, const pod::Matrix4f& mat ) { - bool visible = false; - #if 0 - pod::Vector4f corners[8] = { - pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f }, + #pragma unroll + for ( auto p = 0; p < 4; ++p ) { + int i = p / 2; + int j = p % 2; - pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f }, - }; - #pragma unroll - for ( uint p = 0; p < 8; ++p ) { - pod::Vector4f t = uf::matrix::multiply( mat, corners[p] ); - float w = t.w * 1.25f; - if ( -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && -w <= t.z && t.z <= w ) return true; - } - #else - pod::Vector4f planes[6]; { - #pragma unroll - for ( auto i = 0; i < 3; ++i ) - #pragma unroll - for ( auto j = 0; j < 2; ++j) { - float x = mat[4*0+3] + (j == 0 ? mat[4*0+i] : -mat[4*0+i]); - float y = mat[4*1+3] + (j == 0 ? mat[4*1+i] : -mat[4*1+i]); - float z = mat[4*2+3] + (j == 0 ? mat[4*2+i] : -mat[4*2+i]); - float w = mat[4*3+3] + (j == 0 ? mat[4*3+i] : -mat[4*3+i]); - float length = 1.0f / sqrt( x * x + y * y + z * z ); - - planes[i*2+j] = pod::Vector4f{ x * length, y * length, z * length, w * length }; - } - } - #if 1 - #pragma unroll - for ( auto p = 0; p < 6; ++p ) { - float d = std::max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x) - + std::max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y) - + std::max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z); - if ( d > -planes[p].w ) return true; - } - #else - pod::Vector4f corners[8] = { - pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f }, - pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f }, + float x = mat(0,3) + (j == 0 ? mat(0,i) : -mat(0,i)); + float y = mat(1,3) + (j == 0 ? mat(1,i) : -mat(1,i)); + float z = mat(2,3) + (j == 0 ? mat(2,i) : -mat(2,i)); + float w = mat(3,3) + (j == 0 ? mat(3,i) : -mat(3,i)); - pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f }, - pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f }, - }; - #pragma unroll - for ( uint p = 0; p < 8; ++p ) corners[p] = uf::matrix::multiply( mat, corners[p] ); - #pragma unroll - for ( uint p = 0; p < 6; ++p ) { - #pragma unroll - for ( uint q = 0; q < 8; ++q ) if ( uf::vector::dot( corners[q], planes[p] ) > 0 ) return true; - return false; - } - #endif - #endif - return visible; + float length = 1.0f / std::sqrt( x * x + y * y + z * z ); + + pod::Vector3f normal = { x * length, y * length, z * length }; + float planeDist = w * length; + + pod::Vector3f absNormal = uf::vector::abs(normal); + float r = uf::vector::dot(instance.bounds.extent, absNormal); + float d = uf::vector::dot(instance.bounds.center, normal) + planeDist; + + if ( d < -r ) return false; + } + + return true; } } @@ -275,8 +233,8 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: if ( drawInfo.matrices.projection ) projection = *drawInfo.matrices.projection; if ( drawInfo.attributes.indirect.pointer && drawInfo.attributes.indirect.length == sizeof(pod::DrawCommand) ) { - pod::DrawCommand& drawCommand = *(pod::DrawCommand*) drawInfo.attributes.indirect.pointer; if ( ext::opengl::settings::pipelines::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) { + pod::DrawCommand& drawCommand = *(pod::DrawCommand*) drawInfo.attributes.indirect.pointer; pod::Instance& instance = *(pod::Instance*) drawInfo.attributes.instance.pointer; pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (*drawInfo.matrices.model); @@ -447,11 +405,15 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glNormalPointer(normalType, drawInfo.attributes.normal.stride, normalPtr)); } - // prioritize uniform color for now - if ( drawInfo.color.enabled ) { - const auto& color = drawInfo.color.pointer ? *drawInfo.color.pointer : drawInfo.color.value; + { + pod::Vector4f color = {1,1,1,1}; + if ( drawInfo.color.enabled ) { + color = drawInfo.color.pointer ? *drawInfo.color.pointer : drawInfo.color.value; + } GL_ERROR_CHECK(glColor4f( color[0], color[1], color[2], color[3] )); - } else if ( drawInfo.attributes.color.pointer ) { + } + + if ( drawInfo.attributes.color.pointer ) { GLenum colorType = GL_UNSIGNED_BYTE; switch ( drawInfo.attributes.color.descriptor.size / drawInfo.attributes.color.descriptor.components ) { case sizeof(uint8_t): colorType = GL_UNSIGNED_BYTE; break; @@ -459,8 +421,6 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: } GL_ERROR_CHECK(glEnableClientState(GL_COLOR_ARRAY)); GL_ERROR_CHECK(glColorPointer(drawInfo.attributes.color.descriptor.components, colorType, drawInfo.attributes.color.stride, colorPtr)); - } else { - GL_ERROR_CHECK(glColor4f( 1, 1, 1, 1 )); } if ( drawInfo.textures.primary.image && drawInfo.attributes.uv.pointer ) { @@ -471,7 +431,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image)); GL_ERROR_CHECK(glTexCoordPointer(2, uvType, drawInfo.attributes.uv.stride, uvPtr)); - if ( drawInfo.attributes.color.pointer || drawInfo.color.enabled ) { + if ( drawInfo.attributes.color.pointer ) { GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); } else { GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); @@ -503,15 +463,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: if ( drawInfo.descriptor.inputs.index.count ) { GL_ERROR_CHECK(glDrawElements(mode, drawInfo.descriptor.inputs.index.count, indicesType, (static_cast(drawInfo.attributes.index.pointer) + drawInfo.attributes.index.stride * drawInfo.descriptor.inputs.index.first))); } else { - #if 0 && UF_ENV_DREAMCAST - // GLdc has a "regression" where glDrawArrays does not work - // everything should be using indices anyways so this path shouldn't really ever be taken - uf::stl::vector indices(drawInfo.descriptor.inputs.vertex.count); - for ( auto i = 0; i < drawInfo.descriptor.inputs.vertex.count; ++i ) indices[i] = i; - GL_ERROR_CHECK(glDrawElements(mode, indices.size(), GL_UNSIGNED_SHORT, indices.data())); - #else GL_ERROR_CHECK(glDrawArrays(mode, drawInfo.descriptor.inputs.vertex.first, drawInfo.descriptor.inputs.vertex.count)); - #endif } if ( drawInfo.textures.secondary.image ) { @@ -528,7 +480,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: } if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glDisableClientState(GL_NORMAL_ARRAY)); - if ( drawInfo.attributes.color.pointer || drawInfo.color.enabled ) GL_ERROR_CHECK(glDisableClientState(GL_COLOR_ARRAY)); + if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glDisableClientState(GL_COLOR_ARRAY)); if ( drawInfo.attributes.uv.pointer ) GL_ERROR_CHECK(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); GL_ERROR_CHECK(glDisableClientState(GL_VERTEX_ARRAY)); } diff --git a/engine/src/ext/opengl/texture.cpp b/engine/src/ext/opengl/texture.cpp index e5b20281..75d5a8c5 100644 --- a/engine/src/ext/opengl/texture.cpp +++ b/engine/src/ext/opengl/texture.cpp @@ -107,73 +107,8 @@ void ext::opengl::Texture::loadFromImage( Device& device, enums::Format::type_t format ) { - switch ( format ) { - case enums::Format::R8_SRGB: - case enums::Format::R8G8_SRGB: - case enums::Format::R8G8B8_SRGB: - case enums::Format::R8G8B8A8_SRGB: - srgb = true; - break; - } - - if ( image.getFormat() != 0 ) { - internalFormat = image.getFormat(); - } else { - switch ( image.getChannels() ) { - // R - case 1: - switch ( image.getBpp() ) { - case 8: - format = srgb ? enums::Format::R8_SRGB : enums::Format::R8_UNORM; - break; - default: - UF_EXCEPTION("OpenGL error: unsupported BPP of {}", image.getBpp() ); - break; - } - break; - // RB - case 2: - switch ( image.getBpp() ) { - case 16: - format = srgb ? enums::Format::R8G8_SRGB : enums::Format::R8G8_UNORM; - break; - default: - UF_EXCEPTION("OpenGL error: unsupported BPP of {}", image.getBpp() ); - break; - } - break; - // RGB - case 3: - switch ( image.getBpp() ) { - case 24: - format = srgb ? enums::Format::R8G8B8_SRGB : enums::Format::R8G8B8_UNORM; - break; - default: - UF_EXCEPTION("OpenGL error: unsupported BPP of {}", image.getBpp() ); - break; - } - break; - // RGBA - case 4: - switch ( image.getBpp() ) { - case 16: - format = enums::Format::R4G4B4A4_UNORM_PACK16; - break; - case 32: - format = srgb ? enums::Format::R8G8B8A8_SRGB : enums::Format::R8G8B8A8_UNORM; - break; - default: - UF_EXCEPTION("OpenGL error: unsupported BPP of {}", image.getBpp() ); - break; - } - break; - default: - UF_EXCEPTION("OpenGL error: unsupported channels of {}", image.getChannels() ); - break; - } - } - // convert to power of two - //image.padToPowerOfTwo(); + format = image.getFormat( srgb ); + internalFormat = image.format > 0 ? format : 0; this->fromBuffers( (void*) image.getPixelsPtr(), @@ -334,6 +269,12 @@ void ext::opengl::Texture::update( void* data, size_t bufferSize, uint32_t layer format = GL_RGBA; internalFormat = GL_RGBA8; break; + + // to-do: convert + case enums::Format::R8G8B8A8_RGBE: + format = GL_RGBA; + internalFormat = GL_RGBA; + break; } GL_MUTEX_LOCK(); GL_ERROR_CHECK(glBindTexture(viewType, image)); diff --git a/engine/src/ext/valve/bsp.cpp b/engine/src/ext/valve/bsp.cpp index 4602d3ae..2667ba57 100644 --- a/engine/src/ext/valve/bsp.cpp +++ b/engine/src/ext/valve/bsp.cpp @@ -1096,7 +1096,12 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co auto& mesh = storage.meshes[meshName]; auto& primitives = storage.primitives[meshName]; - // for ( auto& pair : meshlets ) uf::mesh::tangents( pair.second.vertices, pair.second.indices ); + // recompute bounds from min/max to center-extent + for ( auto& [ _, meshlet ] : meshlets ) { + auto& bounds = meshlet.primitive.instance.bounds; + bounds.center = ( bounds.min + bounds.max ) * 0.5f; + bounds.extent = ( bounds.min - bounds.max ) * 0.5f; + } // slice worldspawn if ( false && m == 0 ) { diff --git a/engine/src/ext/valve/mdl.cpp b/engine/src/ext/valve/mdl.cpp index 55be29c6..e3c74e2c 100644 --- a/engine/src/ext/valve/mdl.cpp +++ b/engine/src/ext/valve/mdl.cpp @@ -396,6 +396,13 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { } meshlet.primitive.instance.materialID = materialID; + + // recompute bounds + { + auto& bounds = meshlet.primitive.instance.bounds; + bounds.center = ( bounds.max + bounds.min ) * 0.5f; + bounds.extent = ( bounds.max - bounds.min ) * 0.5f; + } } } } diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 468baad8..1c0d0422 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -405,13 +405,24 @@ void ext::vulkan::Texture::loadFromImage( VkImageLayout layout, VkImageCreateFlags flags ) { + // for some reason this causes everything to get washed out +#if 0 + format = (VkFormat) image.getFormat( srgb ); + + // convert non-vulkan formats + switch ( format ) { + case enums::Format::R8G8B8A8_RGBE: + format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; + break; + } +#else switch ( image.getChannels() ) { // R case 1: switch ( image.getBpp() ) { case 8: format = srgb ? VK_FORMAT_R8_SRGB : VK_FORMAT_R8_UNORM; break; - case 16: format = VK_FORMAT_R16_SFLOAT; break; // Half-float - case 32: format = VK_FORMAT_R32_SFLOAT; break; // Full-float + case 16: format = VK_FORMAT_R16_SFLOAT; break; + case 32: format = VK_FORMAT_R32_SFLOAT; break; default: UF_EXCEPTION("Vulkan error: unsupported BPP of {}", image.getBpp() ); break; } break; @@ -446,6 +457,7 @@ void ext::vulkan::Texture::loadFromImage( UF_EXCEPTION("Vulkan error: unsupported channels of {}", image.getChannels() ); break; } +#endif this->fromBuffers( (void*) image.getPixelsPtr(), diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 94a427cd..d6952071 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -570,8 +570,68 @@ size_t& uf::Image::getChannels() { size_t uf::Image::getChannels() const { return this->channels; } -size_t uf::Image::getFormat() const { - return this->format; +size_t uf::Image::getFormat( bool srgb ) const { + auto format = this->format; + + // for some reason i'm auto-deducing it here +#if UF_USE_OPENGL + switch ( format ) { + case uf::renderer::enums::Format::R8_SRGB: + case uf::renderer::enums::Format::R8G8_SRGB: + case uf::renderer::enums::Format::R8G8B8_SRGB: + case uf::renderer::enums::Format::R8G8B8A8_SRGB: + srgb = true; + break; + } +#endif + + if ( this->format > 0 ) format = this->format; + else switch ( this->channels ) { + // R + case 1: + switch ( this->bpp ) { + case 8: format = srgb ? uf::renderer::enums::Format::R8_SRGB : uf::renderer::enums::Format::R8_UNORM; break; + case 16: format = uf::renderer::enums::Format::R16_SFLOAT; break; + case 32: format = uf::renderer::enums::Format::R32_SFLOAT; break; + default: UF_EXCEPTION("unsupported BPP of {}", this->bpp ); break; + } + break; + // RG + case 2: + switch ( this->bpp ) { + case 16: format = srgb ? uf::renderer::enums::Format::R8G8_SRGB : uf::renderer::enums::Format::R8G8_UNORM; break; + case 32: format = uf::renderer::enums::Format::R16G16_SFLOAT; break; + case 64: format = uf::renderer::enums::Format::R32G32_SFLOAT; break; + default: UF_EXCEPTION("unsupported BPP of {}", this->bpp ); break; + } + break; + // RGB + case 3: + switch ( this->bpp ) { + case 24: format = srgb ? uf::renderer::enums::Format::R8G8B8_SRGB : uf::renderer::enums::Format::R8G8B8_UNORM; break; + case 48: format = uf::renderer::enums::Format::R16G16B16_SFLOAT; break; + case 96: format = uf::renderer::enums::Format::R32G32B32_SFLOAT; break; + default: UF_EXCEPTION("unsupported BPP of {}", this->bpp ); break; + } + break; + // RGBA + case 4: + switch ( this->bpp ) { + case 32: format = srgb ? uf::renderer::enums::Format::R8G8B8A8_SRGB : uf::renderer::enums::Format::R8G8B8A8_UNORM; break; + case 64: format = uf::renderer::enums::Format::R16G16B16A16_SFLOAT; break; // 16-bit HDR + case 128: format = uf::renderer::enums::Format::R32G32B32A32_SFLOAT; break; // 32-bit HDR + default: UF_EXCEPTION("unsupported BPP of {}", this->bpp ); break; + } + break; + default: + UF_EXCEPTION("unsupported channels of {}", this->channels ); + break; + } + + return format; +} +void uf::Image::setFormat( size_t format ) { + this->format = format; } uf::stl::string uf::Image::getHash() const { return uf::image::hash( *this );