more fixes

This commit is contained in:
ecker 2026-06-30 21:21:43 -05:00
parent a2636e834c
commit 65a08839f9
22 changed files with 280 additions and 192 deletions

View File

@ -274,7 +274,7 @@
"rebuild on tick begin": false
},
"pipelines": {
"culling": false
"culling": true
},
"experimental": {
"rebuild on tick begin": false,

View File

@ -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" }
]
}

View File

@ -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" }
]
}

View File

@ -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"
}

View File

@ -97,6 +97,10 @@ struct Bounds {
float padding1;
vec3 max;
float padding2;
vec3 center;
float padding3;
vec3 extent;
float padding4;
};
struct LOD {

View File

@ -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;
}

View File

@ -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;
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;

View File

@ -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;
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;

View File

@ -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 );

View File

@ -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;

View File

@ -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<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
alignas(4) float padding1 = 0;
alignas(4) float padding1;
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::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

View File

@ -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];

View File

@ -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<size_t>(1);
uf::stl::string formatHint = "";
size_t offset = 0;
size_t length = 0;
size_t format = 0;
size_t layers = json["layers"].as<size_t>(1);
uf::stl::string extension = "";
if ( json["format"].is<uf::stl::string>() ) {
format = deduceFormat( json["format"].as<uf::stl::string>() );
} else {
format = json["format"].as<size_t>();
}
#if UF_ENV_DREAMCAST
if (json["dtex"].isObject()) {
if ( json["dtex"].isObject() ) {
filename = json["dtex"]["filename"].as<uf::stl::string>();
extension = "dtex";
offset = json["dtex"]["offset"].as<size_t>();
length = json["dtex"]["length"].as<size_t>();
formatHint = "dtex";
if ( json["dtex"]["format"].is<uf::stl::string>() ) {
format = deduceFormat( json["dtex"]["format"].as<uf::stl::string>() );
} else {
format = json["dtex"]["format"].as<size_t>();
}
} else
#endif
if ( json["filename"].is<uf::stl::string>() ) {
filename = json["filename"].as<uf::stl::string>();
extension = uf::io::extension(filename);
offset = json["offset"].as<size_t>(0);
length = json["length"].as<size_t>(0);
formatHint = uf::io::extension(filename);
} else {
auto size = uf::vector::decode( json["size"], pod::Vector2ui{} );
size_t bpp = json["bpp"].as<size_t>();
@ -52,6 +72,7 @@ namespace {
auto pixels = uf::base64::decode( json["data"].as<uf::stl::string>() );
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<uint8_t> 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<bool>() )
{

View File

@ -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<uint8_t> 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 );

View File

@ -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<bool>() ) {
if ( graphMetadataJson["lights"]["lightmap"].as<bool>() ) {
#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<bool>();
@ -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<float>( model, bounds.min, 1.0f );
auto max = bounds.max; // uf::matrix::multiply<float>( 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

View File

@ -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();

View File

@ -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<uint8_t*>(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<uint16_t> 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));
}

View File

@ -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));

View File

@ -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 ) {

View File

@ -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;
}
}
}
}

View File

@ -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(),

View File

@ -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 );