Commit for 2022.06.05 22-42-59.7z

This commit is contained in:
mrq 2022-06-05 22:42:00 -05:00
parent 82390c927b
commit a9f5a56366
22 changed files with 481 additions and 364 deletions

View File

@ -186,7 +186,7 @@ ifneq (,$(findstring simd,$(REQ_DEPS)))
endif
endif
ifneq (,$(findstring meshoptimizer,$(REQ_DEPS)))
FLAGS += -DUF_USE_MESHOPTIMIZER
FLAGS += -DUF_USE_MESHOPT
DEPS += -lmeshoptimizer
endif
ifneq (,$(findstring draco,$(REQ_DEPS)))
@ -315,7 +315,9 @@ clean:
@-rm ./bin/dreamcast/build/*
@-rm ./bin/dreamcast/romdisk.*
@-rm ./bin/dreamcast/$(TARGET_NAME).*
# @-find ./bin/data/ -name "*.gz" -type f -delete
clean-zips:
@-find ./bin/data/ -name "*.gz" -type f -delete
run:
$(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi
@ -328,6 +330,8 @@ clean:
@-rm -f $(OBJS_DLL)
@-rm -f $(OBJS_EXT_DLL)
@-rm -f $(OBJS)
clean-zips:
@-find ./bin/data/ -name "*.gz" -type f -delete
run:

View File

@ -6,7 +6,7 @@
"matrix": { "reverseInfinite": true },
"lights": { "enabled": true,
"useLightmaps": false,
"max": 16
"max": 32
},
"shadows": {
"enabled": true,
@ -24,17 +24,17 @@
},
"vxgi": {
"limiter": 1,
"size": 86,
"size": 128,
"dispatch": 8,
"cascades": 4,
"cascadePower": 4,
"cascadePower": 3,
"granularity": 8,
"voxelizeScale": 1,
"occlusionFalloff": 2,
"shadows": 0,
"extents": {
"min": [ -4, -4, -4 ],
"max": [ 4, 4, 4 ]
"min": [ -8, -1, -8 ],
"max": [ 8, 4, 8 ]
}
},
"bloom": {

View File

@ -24,14 +24,15 @@
"precision": 4,
"combined": false,
"encode buffers": true,
"unwrap": true,
"unwrap": false,
"optimize": "tagged",
"quit": true,
"mesh": {
// "print": true
}
},
"baking": {
"enabled": false,
"enabled": true,
"resolution": 8192,
"shadows": 1024,
"layers": 1,

View File

@ -22,7 +22,8 @@
"tags": {
"/^worldspawn/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [4,1,4], "epsilon": 1.0, "cleanup": true, "print": true }
"grid": { "size": [4,1,4], "epsilon": 1.0, "cleanup": true, "print": true },
"optimize mesh": { "simplify": 0 }
},
"info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true },

View File

@ -2,15 +2,16 @@
"import": "/model.json",
"assets": [
// { "filename": "./craeture.json", "delay": 1 },
{ "filename": "./test.json", "delay": 1 },
// { "filename": "./models/tiny_msci.glb" }
// { "filename": "./models/tiny_msci/graph.json" }
{ "filename": "./models/tiny_msci/graph.json" }
// { "filename": "./models/micro_sci.glb" }
// { "filename": "./models/micro_sci/graph.json" }
// { "filename": "./models/msci.glb" }
{ "filename": "./models/msci/graph.json" }
// { "filename": "./models/msci/graph.json" }
// { "filename": "./models/medsci.glb" }
// { "filename": "./models/medsci/graph.json" }
@ -25,7 +26,8 @@
"tags": {
"/^worldspawn/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [5,1,5], "epsilon": 1.0, "cleanup": true, "print": true }
"grid": { "size": [5,1,5], "epsilon": 1.0, "cleanup": true, "print": true },
"optimize mesh": { "simplify": 0 }
},
"info_player_spawn": {
"action": "attach",

View File

@ -0,0 +1,25 @@
{
"name": "Gui: Text Test",
"type": "Gui",
"ignore": false,
"transform": {
"position": [18.3785, 2.41477, 0.859857],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 3.141
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"world": true,
"cull mode": "none",
"text settings": {
"scale": 8,
"font": "Coolvetica.ttf",
"string": "Grimgram"
}
}
}

View File

@ -1,7 +1,7 @@
{
"engine": {
"scenes": {
"start": "SS2",
"start": "McDonalds",
"meshes": { "interleaved": false },
"matrix": { "reverseInfinite": false },
"lights": { "enabled": false,

View File

@ -7,6 +7,7 @@ namespace uf {
pod::ColorRgba color{ (uint8_t) ~0, (uint8_t) ~0, (uint8_t) ~0, (uint8_t) ~0 };
pod::Vector2f st{};
pod::Vector3f normal{};
pod::Vector<uint16_t, 2> id{};
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
@ -19,6 +20,7 @@ namespace uf {
pod::Vector3f tangent{};
pod::Vector<uint16_t, 4> joints{};
pod::Vector4f weights{};
pod::Vector<uint16_t, 2> id{};
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};

View File

@ -6,6 +6,6 @@
namespace ext {
namespace meshopt {
void UF_API optimize( uf::Mesh&, size_t = SIZE_MAX );
bool UF_API optimize( uf::Mesh&, float simplify = 1.0f, size_t = SIZE_MAX );
}
}

View File

@ -87,16 +87,22 @@ namespace uf {
if ( mlet.indices.empty() ) continue;
auto& meshlet = meshlets[mlet.primitive.instance.primitiveID];
size_t primitiveID = partitioned.size();
auto& slice = partitioned.emplace_back();
slice.vertices.reserve( mlet.indices.size() );
slice.indices.reserve( mlet.indices.size() );
for ( auto idx : mlet.indices ) {
slice.vertices.emplace_back( meshlet.vertices[idx] );
slice.indices.emplace_back( slice.indices.size() );
auto& vertex = slice.vertices.emplace_back( meshlet.vertices[idx] );
auto& index = slice.indices.emplace_back( slice.indices.size() );
vertex.id.x = primitiveID;
vertex.id.y = meshlet.primitive.instance.meshID;
}
slice.primitive.instance = meshlet.primitive.instance;
slice.primitive.instance.materialID = meshlet.primitive.instance.materialID;
slice.primitive.instance.primitiveID = partitioned.size() - 1;
slice.primitive.instance.primitiveID = primitiveID;
slice.primitive.instance.meshID = meshlet.primitive.instance.meshID;
slice.primitive.instance.objectID = 0;
slice.primitive.instance.auxID = atlasID;
slice.primitive.instance.bounds.min = node.effectiveExtents.min;

View File

@ -359,8 +359,10 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) {
#endif
asset = uf::graph::load( filename, metadata[payload.filename] );
uf::graph::process( asset );
#if !UF_ENV_DREAMCAST
if ( asset.metadata["debug"]["print stats"].as<bool>() ) UF_MSG_INFO(uf::graph::stats( asset ).dump(1,'\t'));
if ( asset.metadata["debug"]["print tree"].as<bool>() ) UF_MSG_INFO(uf::graph::print( asset ));
#endif
if ( !asset.metadata["debug"]["no cleanup"].as<bool>() ) uf::graph::cleanup( asset );
} break;
default: {

View File

@ -121,47 +121,111 @@ pod::Graph& UF_API uf::graph::convert( uf::Object& object, bool process ) {
for ( auto index : graph.root.children ) uf::graph::process( graph, index, *graph.root.entity );
}
// remap textures->images IDs
for ( auto& name : graph.textures ) {
auto& texture = uf::graph::storage.textures[name];
auto& keys = uf::graph::storage.images.keys;
auto& indices = uf::graph::storage.images.indices;
if ( !(0 <= texture.index && texture.index < graph.images.size()) ) continue;
auto& needle = graph.images[texture.index];
#if 1
texture.index = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
texture.index = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
texture.index = it - keys.begin();
#endif
}
// remap materials->texture IDs
for ( auto& name : graph.materials ) {
auto& material = uf::graph::storage.materials[name];
auto& keys = uf::graph::storage.textures.keys;
auto& indices = uf::graph::storage.textures.indices;
int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness };
for ( auto* pointer : IDs ) {
auto& ID = *pointer;
if ( !(0 <= ID && ID < graph.materials.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), graph.textures[ID] );
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
auto& needle = graph.textures[ID];
#if 1
ID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
ID = i;
break;
}
#else
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
ID = it - keys.begin();
#endif
}
}
// remap textures->images IDs
/*
for ( auto& name : graph.textures ) {
auto& texture = uf::graph::storage.textures[name];
auto& keys = uf::graph::storage.images.keys;
if ( !(0 <= texture.index && texture.index < graph.textures.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), graph.images[texture.index] );
UF_ASSERT( it != keys.end() );
texture.index = it - keys.begin();
}
*/
// remap instance variables
for ( auto& name : graph.instances ) {
auto& instance = uf::graph::storage.instances[name];
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.materials.keys;
auto it = std::find( keys.begin(), keys.end(), graph.materials[instance.materialID] );
auto& indices = /*graph.storage*/uf::graph::storage.materials.indices;
if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue;
auto& needle = graph.materials[instance.materialID];
#if 1
instance.materialID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
instance.materialID = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
instance.materialID = it - keys.begin();
#endif
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.textures.keys;
auto& indices = /*graph.storage*/uf::graph::storage.textures.indices;
if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue;
auto& needle = graph.textures[instance.lightmapID];
#if 1
instance.lightmapID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
instance.lightmapID = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
instance.lightmapID = it - keys.begin();
#endif
}
#if 0
// i genuinely dont remember what this is used for
if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.images.keys;
auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] );
UF_ASSERT( it != keys.end() );
instance.imageID = it - keys.begin();
}
#endif
// remap a skinID as an actual jointID
if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) {
auto& name = graph.skins[instance.jointID];
@ -172,12 +236,6 @@ pod::Graph& UF_API uf::graph::convert( uf::Object& object, bool process ) {
instance.jointID += joints.size();
}
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.textures.keys;
auto it = std::find( keys.begin(), keys.end(), graph.textures[instance.lightmapID] );
UF_ASSERT( it != keys.end() );
instance.lightmapID = it - keys.begin();
}
}
uf::graph::reload();

View File

@ -225,16 +225,36 @@ namespace {
});
// remove extraneous buffers
#if UF_USE_OPENGL
/*
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) continue;
if ( attribute.descriptor.name == "color" ) continue;
if ( attribute.descriptor.name == "uv" ) continue;
if ( attribute.descriptor.name == "st" ) continue;
if ( !mesh.isInterleaved() ) {
uf::stl::vector<size_t> remove; remove.reserve(mesh.vertex.attributes.size());
for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) {
auto& attribute = mesh.vertex.attributes[i];
if ( attribute.descriptor.name == "position" ) continue;
if ( attribute.descriptor.name == "color" ) continue;
if ( attribute.descriptor.name == "uv" ) continue;
if ( attribute.descriptor.name == "st" ) continue;
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
if ( attribute.descriptor.name == "tangent" ) continue;
if ( attribute.descriptor.name == "joints" ) continue;
if ( attribute.descriptor.name == "weights" ) continue;
}
#if !UF_USE_OPENGL
if ( attribute.descriptor.name == "normal" ) continue;
#endif
remove.insert(remove.begin(), i);
}
for ( auto& i : remove ) {
// UF_MSG_DEBUG("Removing " << mesh.vertex.attributes[i].descriptor.name);
mesh.buffers[mesh.vertex.attributes[i].buffer].clear();
mesh.buffers[mesh.vertex.attributes[i].buffer].shrink_to_fit();
mesh.vertex.attributes.erase(mesh.vertex.attributes.begin() + i);
}
} else {
UF_MSG_DEBUG("Attribute removal requested yet mesh is not interleaved, ignoring...");
}
*/
#endif
mesh.updateDescriptor();

View File

@ -9,12 +9,7 @@
#include <uf/utils/math/physics.h>
#include <uf/ext/xatlas/xatlas.h>
#if UF_ENV_DREAMCAST
#define UF_GRAPH_LOAD_MULTITHREAD 0
#else
#define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM
#endif
#if !UF_ENV_DREAMCAST
namespace {
struct EncodingSettings : public ext::json::EncodingSettings {
bool combined = false;
@ -23,7 +18,7 @@ namespace {
uf::stl::string filename = "";
};
uf::Serializer encode( const uf::Image& image, const EncodingSettings& settings ) {
uf::Serializer encode( const uf::Image& image, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["size"] = uf::vector::encode( image.getDimensions() );
json["bpp"] = image.getBpp() / image.getChannels();
@ -31,7 +26,7 @@ namespace {
json["data"] = uf::base64::encode( image.getPixels() );
return json;
}
uf::Serializer encode( const pod::Texture& texture, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Texture& texture, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["index"] = texture.index;
json["sampler"] = texture.sampler;
@ -40,7 +35,7 @@ namespace {
json["lerp"] = uf::vector::encode( texture.lerp, settings );
return json;
}
uf::Serializer encode( const uf::renderer::Sampler& sampler, const EncodingSettings& settings ) {
uf::Serializer encode( const uf::renderer::Sampler& sampler, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["min"] = sampler.descriptor.filter.min;
json["mag"] = sampler.descriptor.filter.mag;
@ -48,7 +43,7 @@ namespace {
json["v"] = sampler.descriptor.addressMode.v;
return json;
}
uf::Serializer encode( const pod::Material& material, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Material& material, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["base"] = uf::vector::encode( material.colorBase, settings );
json["emissive"] = uf::vector::encode( material.colorEmissive, settings );
@ -64,14 +59,14 @@ namespace {
json["modeAlpha"] = material.modeAlpha;
return json;
}
uf::Serializer encode( const pod::Light& light, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Light& light, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["color"] = uf::vector::encode( light.color, settings );
json["intensity"] = light.intensity;
json["range"] = light.range;
return json;
}
uf::Serializer encode( const pod::Animation& animation, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Animation& animation, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["name"] = animation.name;
json["start"] = animation.start;
@ -99,7 +94,7 @@ namespace {
}
return json;
}
uf::Serializer encode( const pod::Skin& skin, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Skin& skin, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["name"] = skin.name;
@ -111,7 +106,7 @@ namespace {
json["inverseBindMatrices"].emplace_back( uf::matrix::encode(inverseBindMatrix, settings) );
return json;
}
uf::Serializer encode( const pod::Instance& instance, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Instance& instance, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["model"] = uf::matrix::encode( instance.model, settings );
json["color"] = uf::vector::encode( instance.color, settings );
@ -126,7 +121,7 @@ namespace {
return json;
}
uf::Serializer encode( const pod::DrawCommand& drawCommand, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::DrawCommand& drawCommand, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["indices"] = drawCommand.indices;
json["instances"] = drawCommand.instances;
@ -138,34 +133,48 @@ namespace {
json["vertices"] = drawCommand.vertices;
return json;
}
uf::Serializer encode( const pod::Primitive& primitive, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Primitive& primitive, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["drawCommand"] = encode( primitive.drawCommand, settings );
json["instance"] = encode( primitive.instance, settings );
json["drawCommand"] = encode( primitive.drawCommand, settings, graph );
json["instance"] = encode( primitive.instance, settings, graph );
return json;
}
uf::Serializer encode( const uf::Mesh& mesh, const EncodingSettings& settings ) {
uf::Serializer encode( const uf::Mesh& mesh, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
#if 0
uf::Mesh mesh = mesh;
// remove extraneous buffers
if ( !mesh.isInterleaved() ) {
uf::stl::vector<size_t> remove; remove.reserve(mesh.vertex.attributes.size());
/*
struct Attribute {
ext::RENDERER::AttributeDescriptor descriptor;
int32_t buffer = -1;
size_t offset = 0;
for ( size_t i = 0; i < mesh.vertex.attributes.size(); ++i ) {
auto& attribute = mesh.vertex.attributes[i];
if ( attribute.descriptor.name == "position" ) continue;
if ( attribute.descriptor.name == "color" ) continue;
if ( attribute.descriptor.name == "uv" ) continue;
if ( attribute.descriptor.name == "st" ) continue;
size_t stride = 0;
size_t length = 0;
void* pointer = NULL;
};
struct Input {
uf::stl::vector<Attribute> attributes;
size_t count = 0; // how many elements is the input using
size_t first = 0; // base index to start from
size_t size = 0; // size of one element in the input's buffer
size_t offset = 0; // bytes to offset from within the associated buffer
int32_t interleaved = -1; // index to interleaved buffer if in bounds
} vertex, index, instance, indirect;
*/
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
if ( attribute.descriptor.name == "tangent" ) continue;
if ( attribute.descriptor.name == "joints" ) continue;
if ( attribute.descriptor.name == "weights" ) continue;
}
#if !UF_USE_OPENGL
if ( attribute.descriptor.name == "normal" ) continue;
#endif
remove.insert(remove.begin(), i);
}
for ( auto& i : remove ) {
// UF_MSG_DEBUG("Removing " << mesh.vertex.attributes[i].descriptor.name);
mesh.buffers[mesh.vertex.attributes[i].buffer].clear();
mesh.buffers[mesh.vertex.attributes[i].buffer].shrink_to_fit();
mesh.vertex.attributes.erase(mesh.vertex.attributes.begin() + i);
}
} else {
// UF_MSG_DEBUG("Attribute removal requested yet mesh is not interleaved, ignoring...");
}
#endif
#define SERIALIZE_MESH(N) {\
auto& input = json["inputs"][#N];\
@ -203,7 +212,7 @@ namespace {
}
return json;
}
uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings ) {
uf::Serializer encode( const pod::Node& node, const EncodingSettings& settings, const pod::Graph& graph ) {
uf::Serializer json;
json["name"] = node.name;
json["index"] = node.index;
@ -239,7 +248,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
};
if ( settings.encoding == "auto" ) settings.encoding = ext::json::PREFERRED_ENCODING;
if ( settings.compression == "auto" ) settings.compression = ext::json::PREFERRED_COMPRESSION;
if ( settings.compression == "auto" ) settings.compression = ext::json::PREFERRED_COMPRESSION;
if ( !settings.combined ) uf::io::mkdir(directory);
#if UF_USE_XATLAS
@ -258,7 +267,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
for ( size_t i = 0; i < graph.instances.size(); ++i ) {
auto& name = graph.instances[i];
auto& instance = /*graph.storage*/uf::graph::storage.instances.map.at(name);
uf::Serializer json = encode( instance, settings );
uf::Serializer json = encode( instance, settings, graph );
json["name"] = name;
serializer["instances"].emplace_back( json );
}
@ -272,7 +281,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
json["name"] = name;
// ext::json::reserve( json["primitives"], primitives.size() );
for ( auto& primitive : primitives ) {
json["primitives"].emplace_back( encode( primitive, settings ) );
json["primitives"].emplace_back( encode( primitive, settings, graph ) );
}
}
});
@ -285,7 +294,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
json["name"] = name;
// ext::json::reserve( json["drawCommands"], drawCommands.size() );
for ( auto& drawCommand : drawCommands ) {
json["drawCommands"].emplace_back( encode( drawCommand, settings ) );
json["drawCommands"].emplace_back( encode( drawCommand, settings, graph ) );
}
}
});
@ -299,14 +308,14 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
auto& mesh = /*graph.storage*/uf::graph::storage.meshes.map.at(name);
if ( !s.encodeBuffers ) {
s.filename = directory+"/mesh."+std::to_string(i)+".json";
encode(mesh, s).writeToFile(s.filename);
encode(mesh, s, graph).writeToFile(s.filename);
uf::Serializer json;
json["name"] = name;
json["filename"] = uf::io::filename(s.filename);
serializer["meshes"].emplace_back( json );
} else {
s.filename = directory+"/mesh."+std::to_string(i);
auto json = encode(mesh, s);
auto json = encode(mesh, s, graph);
json["name"] = name;
serializer["meshes"].emplace_back(json);
}
@ -314,7 +323,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
} else {
for ( auto& name : graph.meshes ) {
auto& mesh = /*graph.storage*/uf::graph::storage.meshes.map.at(name);
auto json = encode(mesh, settings);
auto json = encode(mesh, settings, graph);
json["name"] = name;
serializer["meshes"].emplace_back(json);
}
@ -330,7 +339,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
image.save(directory + "/atlas.png");
serializer["atlas"] = "atlas.png";
} else {
serializer["atlas"] = encode(image, settings);
serializer["atlas"] = encode(image, settings, graph);
}
}
});
@ -352,7 +361,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
} else {
for ( auto& name : graph.images ) {
auto& image = /*graph.storage*/uf::graph::storage.images.map.at(name);
auto json = encode(image, settings);
auto json = encode(image, settings, graph);
json["name"] = name;
serializer["images"].emplace_back( json );
}
@ -363,7 +372,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
ext::json::reserve( serializer["textures"], graph.textures.size() );
for ( auto& name : graph.textures ) {
auto& texture = /*graph.storage*/uf::graph::storage.textures.map.at(name);
auto json = encode(texture, settings);
auto json = encode(texture, settings, graph);
json["name"] = name;
serializer["textures"].emplace_back(json);
}
@ -373,7 +382,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
ext::json::reserve( serializer["samplers"], graph.samplers.size() );
for ( auto& name : graph.samplers ) {
auto& sampler = /*graph.storage*/uf::graph::storage.samplers.map.at(name);
auto json = encode(sampler, settings);
auto json = encode(sampler, settings, graph);
json["name"] = name;
serializer["samplers"].emplace_back(json);
}
@ -383,7 +392,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
ext::json::reserve( serializer["materials"], graph.materials.size() );
for ( auto& name : graph.materials ) {
auto& material = /*graph.storage*/uf::graph::storage.materials.map.at(name);
auto json = encode(material, settings);
auto json = encode(material, settings, graph);
json["name"] = name;
serializer["materials"].emplace_back(json);
}
@ -394,7 +403,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
for ( auto pair : graph.lights ) {
auto& name = pair.first;
auto& light = pair.second;
auto json = encode(light, settings);
auto json = encode(light, settings, graph);
json["name"] = name;
serializer["lights"].emplace_back(json);
}
@ -407,13 +416,13 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
auto& name = graph.animations[i];
uf::stl::string f = "animation."+std::to_string(i)+".json";
auto& animation = /*graph.storage*/uf::graph::storage.animations.map.at(name);
encode(animation, settings).writeToFile(directory+"/"+f);
encode(animation, settings, graph).writeToFile(directory+"/"+f);
serializer["animations"].emplace_back(f);
}
} else {
for ( auto& name : graph.animations ) {
auto& animation = /*graph.storage*/uf::graph::storage.animations.map.at(name);
serializer["animations"][name] = encode(animation, settings);
serializer["animations"][name] = encode(animation, settings, graph);
}
}
});
@ -422,14 +431,14 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
ext::json::reserve( serializer["skins"], graph.skins.size() );
for ( auto& name : graph.skins ) {
auto& skin = /*graph.storage*/uf::graph::storage.skins.map.at(name);
serializer["skins"].emplace_back( encode(skin, settings) );
serializer["skins"].emplace_back( encode(skin, settings, graph) );
}
});
jobs.emplace_back([&]{
// store node information
ext::json::reserve( serializer["nodes"], graph.nodes.size() );
for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings) );
serializer["root"] = encode(graph.root, settings);
for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings, graph) );
serializer["root"] = encode(graph.root, settings, graph);
});
#if UF_GRAPH_LOAD_MULTITHREAD
if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs );
@ -551,4 +560,5 @@ uf::Serializer uf::graph::stats( const pod::Graph& graph ) {
*/
#endif
return json;
}
}
#endif

View File

@ -22,6 +22,7 @@ UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R8G8B8A8_UNORM, color)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, st)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, normal)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R16G16_UINT, id)
);
UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, position)
@ -32,6 +33,7 @@ UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, tangent)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16B16A16_UINT, joints)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32A32_SFLOAT, weights)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R16G16_UINT, id)
);
pod::Matrix4f uf::graph::local( pod::Graph& graph, int32_t index ) {

View File

@ -19,6 +19,10 @@
#include <gltf/tiny_gltf.h>
#include <uf/ext/gltf/gltf.h>
#if UF_USE_MESHOPT
#include <uf/ext/meshopt/meshopt.h>
#endif
#if UF_USE_XATLAS
#include <uf/ext/xatlas/xatlas.h>
#endif
@ -282,7 +286,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print);
meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup);
}
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
#define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t
@ -298,75 +301,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
#undef UF_GRAPH_PROCESS_PRIMITIVES_FULL
#undef UF_GRAPH_MESH_FORMAT
}
#if 0
if ( m.name == "worldspawn_20" ) {
uf::stl::vector<::Primitive<>> objs;
#include "processPrimitives2.inl"
graph.primitives.emplace_back(keyName);
graph.drawCommands.emplace_back(keyName);
auto& drawCommands = /*graph.storage*/uf::graph::storage.drawCommands[keyName];
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName];
mesh.bindIndirect<pod::DrawCommand>();
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
size_t indexID = 0;
size_t vertexID = 0;
for ( auto& obj : objs ) {
drawCommands.emplace_back(pod::DrawCommand{
.indices = obj.indices.size(),
.instances = 1,
.indexID = indexID,
.vertexID = vertexID,
.instanceID = 0,
.vertices = obj.vertices.size(),
});
primitives.emplace_back( obj.primitive );
indexID += obj.indices.size();
vertexID += obj.vertices.size();
mesh.insertVertices(obj.vertices);
mesh.insertIndices(obj.indices);
}
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();
} else {
graph.primitives.emplace_back(keyName);
graph.drawCommands.emplace_back(keyName);
auto& drawCommands = /*graph.storage*/uf::graph::storage.drawCommands[keyName];
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName];
mesh.bindIndirect<pod::DrawCommand>();
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
uf::stl::vector<uf::graph::mesh::Skinned> vertices;
uf::stl::vector<uint32_t> indices;
#define UF_GRAPH_PROCESS_PRIMITIVES_FULL 1
#include "processPrimitives.inl"
#undef UF_GRAPH_PROCESS_PRIMITIVES_FULL
} else {
mesh.bind<uf::graph::mesh::Base, uint32_t>();
uf::stl::vector<uf::graph::mesh::Base> vertices;
uf::stl::vector<uint32_t> indices;
#include "processPrimitives.inl"
}
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();
}
#endif
}
}
// load skins
@ -530,14 +464,50 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
texture.index = atlasImageIndex;
}
}
// generate STs
#if UF_USE_XATLAS
if ( graph.metadata["exporter"]["unwrap"].as<bool>() ) {
// generate STs
if ( graph.metadata["exporter"]["unwrap"].as<bool>(true) ) {
UF_MSG_DEBUG( "Generating ST's..." );
size_t atlases = ext::xatlas::unwrap( graph );
UF_MSG_DEBUG( "Generated ST's for " << atlases << " lightmaps" );
}
#endif
#if UF_USE_MESHOPT
// cleanup if blender's exporter is poopy
if ( graph.metadata["exporter"]["optimize"].as<bool>(true) || graph.metadata["exporter"]["optimize"].as<uf::stl::string>("") == "tagged" ) {
UF_MSG_DEBUG( "Optimizing meshes..." );
for ( auto& keyName : graph.meshes ) {
size_t level = SIZE_MAX;
float simplify = 1.0f;
if ( graph.metadata["exporter"]["optimize"].as<uf::stl::string>("") == "tagged" ) {
bool should = false;
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( ext::json::isNull( value["optimize mesh"] ) ) return;
if ( uf::string::isRegex( key ) ) {
if ( !uf::string::matched( keyName, key ) ) return;
} else if ( keyName != key ) return;
should = true;
if ( ext::json::isObject( value["optimize mesh"] ) ) {
level = value["optimize mesh"]["level"].as(level);
simplify = value["optimize mesh"]["simplify"].as(simplify);
}
});
if ( !should ) continue;
}
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName];
UF_MSG_DEBUG("Optimizing mesh at level " << level << ": " << keyName);
if ( !ext::meshopt::optimize( mesh, simplify, level ) ) {
UF_MSG_ERROR("Mesh optimization failed: " << keyName );
}
}
UF_MSG_DEBUG( "Optimized mesh" );
}
#endif
if ( graph.metadata["exporter"]["enabled"].as<bool>() ) {
graph.name = uf::graph::save( graph, filename );

View File

@ -1,6 +1,7 @@
uf::stl::vector<uf::Meshlet_T<UF_GRAPH_MESH_FORMAT>> meshlets;
for ( auto& p : m.primitives ) {
size_t primitiveID = meshlets.size();
auto& meshlet = meshlets.emplace_back();
struct Attribute {
@ -123,6 +124,9 @@ for ( auto& p : m.primitives ) {
vertex.tangent.x = -vertex.tangent.x;
#endif
}
vertex.id.x = primitiveID;
vertex.id.y = meshID;
}
if ( p.indices > -1 ) {
@ -155,10 +159,8 @@ for ( auto& p : m.primitives ) {
#undef COPY_INDICES
}
meshlet.primitive.instance.materialID = p.material;
meshlet.primitive.instance.primitiveID = meshlets.size() - 1;
meshlet.primitive.instance.primitiveID = primitiveID;
meshlet.primitive.instance.meshID = meshID;
meshlet.primitive.instance.objectID = 0;

View File

@ -1,126 +1,164 @@
#include <uf/ext/meshopt/meshopt.h>
#if UF_USE_MESHOPTIMIZER
#include <meshoptimizer.h>
#endif
#if UF_USE_MESHOPT
#include <meshoptimizer.h>
void ext::meshopt::optimize( uf::Mesh& mesh, size_t o ) {
#if 0
bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o ) {
if ( mesh.isInterleaved() ) {
UF_MSG_ERROR("optimization of interleaved meshes is currently not supported");
return false;
}
mesh.updateDescriptor();
void* vertices = NULL;
void* indices = NULL;
size_t verticesCount = mesh.attributes.vertex.length;
size_t indicesCount = mesh.attributes.index.length;
struct Remap {
uf::Mesh::Attribute attribute;
uf::stl::vector<uint8_t> buffer;
};
if ( !indicesCount ) mesh.generateIndices();
if ( o == 0 ) {
if ( !indicesCount ) {
mesh.resizeIndices(verticesCount);
switch ( mesh.attributes.index.size ) {
case sizeof(uint32_t):
for ( size_t i = 0; i < verticesCount; ++i ) ((uint32_t*) mesh.attributes.index.pointer)[i] = i;
break;
case sizeof(uint16_t):
for ( size_t i = 0; i < verticesCount; ++i ) ((uint16_t*) mesh.attributes.index.pointer)[i] = i;
break;
case sizeof(uint8_t):
for ( size_t i = 0; i < verticesCount; ++i ) ((uint8_t*) mesh.attributes.index.pointer)[i] = i;
break;
uf::stl::vector<Remap> attributes;
uf::stl::vector<meshopt_Stream> streams;
for ( auto& attribute : mesh.vertex.attributes ) {
auto& p = attributes.emplace_back();
p.attribute = attribute;
auto& stream = streams.emplace_back();
stream.data = p.attribute.pointer;
stream.size = p.attribute.descriptor.size;
stream.stride = p.attribute.stride;
}
size_t indicesCount = mesh.vertex.count;
uf::stl::vector<uint32_t> remap(indicesCount);
size_t verticesCount = meshopt_generateVertexRemapMulti( &remap[0], NULL, indicesCount, indicesCount, &streams[0], streams.size() );
// generate new indices, as they're going to be specific to a region of vertices due to drawcommand shittery
uf::stl::vector<uint32_t> indices(indicesCount);
meshopt_remapIndexBuffer(&indices[0], NULL, indicesCount, &remap[0]);
//
for ( auto& p : attributes ) {
auto& buffer = p.buffer;
buffer.resize(verticesCount * p.attribute.descriptor.size);
meshopt_remapVertexBuffer(&buffer[0], p.attribute.pointer, indicesCount, p.attribute.descriptor.size, &remap[0]);
}
//
meshopt_optimizeVertexCache(&indices[0], &indices[0], indicesCount, verticesCount);
//
meshopt_optimizeVertexFetchRemap(&remap[0], &indices[0], indicesCount, verticesCount);
//
for ( auto& p : attributes ) {
auto& buffer = p.buffer;
p.attribute.pointer = &buffer[0];
meshopt_remapVertexBuffer(p.attribute.pointer, p.attribute.pointer, verticesCount, p.attribute.descriptor.size, &remap[0]);
}
// almost always causes ID discontinuities
if ( 0.0f < simplify && simplify < 1.0f ) {
uf::stl::vector<uint32_t> indicesSimplified(indicesCount);
uf::Mesh::Attribute positionAttribute;
for ( auto& p : attributes ) if ( p.attribute.descriptor.name == "position" ) positionAttribute = p.attribute;
size_t targetIndices = indicesCount * simplify;
float targetError = 1e-2f / simplify;
float realError = 0.0f;
// size_t realIndices = meshopt_simplify(&indicesSimplified[0], &indices[0], indicesCount, (float*) positionAttribute.pointer, verticesCount, positionAttribute.stride, targetError, realError);
size_t realIndices = meshopt_simplifySloppy(&indicesSimplified[0], &indices[0], indicesCount, (float*) positionAttribute.pointer, verticesCount, positionAttribute.stride, targetIndices);
UF_MSG_DEBUG("[Simplified] indices: " << indicesCount << " -> " << realIndices << " | error: " << targetError << " -> " << realError);
indicesCount = realIndices;
indices.swap( indicesSimplified );
}
// done
if ( mesh.indirect.count ) {
bool discontinuityDetected = false;
size_t lastID = 0;
struct Remap {
pod::DrawCommand* drawCommand;
struct {
size_t start = SIZE_MAX;
size_t end = 0;
} index, vertex;
};
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data();
uf::stl::vector<Remap> remappedDrawCommands( mesh.indirect.count );
uf::Mesh::Attribute idAttribute;
for ( auto& p : attributes ) if ( p.attribute.descriptor.name == "id" ) idAttribute = p.attribute;
for ( size_t index = 0; index < indicesCount; ++index ) {
size_t vertex = indices[index];
pod::Vector<uint16_t,2>& id = *(pod::Vector<uint16_t,2>*) ( static_cast<uint8_t*>(idAttribute.pointer) + idAttribute.stride * vertex );
auto& d = remappedDrawCommands[id.x];
d.drawCommand = &drawCommands[id.x];
d.vertex.start = std::min( d.vertex.start, vertex );
d.vertex.end = std::max( d.vertex.end, vertex );
d.index.start = std::min( d.index.start, index );
d.index.end = std::max( d.index.end, index );
if ( lastID == id.x ) {
} else if ( lastID + 1 == id.x ) {
lastID = id.x;
} else {
UF_MSG_DEBUG("Discontinuity detected: " << index << " | " << vertex << " | " << lastID << " | " << id.x);
discontinuityDetected = true;
lastID = id.x;
}
}
return;
if ( discontinuityDetected ) {
UF_MSG_ERROR("Discontinuity detected, bailing...");
return false;
}
for ( auto& d : remappedDrawCommands ) {
d.drawCommand->indices = d.index.end - d.index.start + 1;
d.drawCommand->indexID = d.index.start;
d.drawCommand->vertexID = d.vertex.start;
d.drawCommand->vertices = d.vertex.end - d.vertex.start + 1;
}
for ( size_t index = 0; index < indicesCount; ++index ) {
auto& vertex = indices[index];
pod::Vector<uint16_t,2>& id = *(pod::Vector<uint16_t,2>*) ( static_cast<uint8_t*>(idAttribute.pointer) + idAttribute.stride * vertex );
auto& d = remappedDrawCommands[id.x];
vertex -= d.vertex.start;
}
}
mesh.index.count = indicesCount;
mesh.vertex.count = verticesCount;
// vertices
for ( size_t i = 0; i < attributes.size(); ++i ) {
auto& attribute = mesh.vertex.attributes[i];
auto& remapped = attributes[i];
mesh.buffers[attribute.buffer].swap( remapped.buffer );
attribute.pointer = mesh.buffers[attribute.buffer].data();
}
// indices
{
vertices = malloc(verticesCount * mesh.attributes.vertex.size);
memcpy( vertices, mesh.attributes.vertex.pointer, verticesCount );
}
if ( indicesCount > 0 ) {
indices = malloc(indicesCount);
memcpy( indices, mesh.attributes.index.pointer, indicesCount );
mesh.resizeIndices( mesh.index.count );
uint8_t* pointer = (uint8_t*) mesh.getBuffer(mesh.index).data();
for ( auto index = 0; index < indicesCount; ++index ) {
switch ( mesh.index.size ) {
case 1: (( uint8_t*) pointer)[index] = indices[index]; break;
case 2: ((uint16_t*) pointer)[index] = indices[index]; break;
case 4: ((uint32_t*) pointer)[index] = indices[index]; break;
}
}
}
uf::stl::vector<uint32_t> remap(verticesCount);
verticesCount = meshopt_generateVertexRemap(&remap[0], (uint32_t*) indices, indicesCount ? indicesCount : verticesCount, (float*) vertices, verticesCount, mesh.attributes.vertex.size);
mesh.resizeIndices(indicesCount);
mesh.resizeVertices(verticesCount);
meshopt_remapIndexBuffer((uint32_t*) mesh.attributes.index.pointer, (uint32_t*) indices, indicesCount, &remap[0]);
meshopt_remapVertexBuffer(mesh.attributes.vertex.pointer, (float*) vertices, verticesCount, mesh.attributes.vertex.size, &remap[0]);
if ( vertices ) free(vertices);
if ( indices ) free(indices);
#endif
#if 0
auto vertices = std::move( this->vertices );
size_t valueCount = vertices.size();
uf::stl::vector<uint32_t> remap(valueCount);
size_t verticesCount = meshopt_generateVertexRemap(&remap[0], NULL, valueCount, &vertices[0], valueCount, sizeof(T));
this->indices.resize(valueCount);
meshopt_remapIndexBuffer(&this->indices[0], NULL, valueCount, &remap[0]);
//meshopt_remapIndexBuffer(&this->indices[0], (const U*) NULL, indices, &remap[0]);
this->vertices.resize(verticesCount);
meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], valueCount, sizeof(T), &remap[0]);
size_t verticesCount = this->vertices.size();
size_t indicesCount = this->indices.size();
if ( indicesCount == 0 ) indicesCount = verticesCount;
auto vertices = std::move( this->vertices );
auto indices = std::move( this->indices );
uf::stl::vector<uint32_t> remap(indicesCount);
verticesCount = meshopt_generateVertexRemap(&remap[0], &indices[0], indicesCount, &vertices[0], verticesCount, sizeof(T));
this->indices.resize(indicesCount);
this->vertices.resize(verticesCount);
meshopt_remapIndexBuffer(&this->indices[0], &indices[0], indicesCount, &remap[0]);
meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], verticesCount, sizeof(T), &remap[0]);
#endif
#if 0
// optimize for cache
if ( o >= 2 ) {
meshopt_optimizeVertexCache(mesh.attributes.index.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, mesh.attributes.vertex.length);
}
// optimize for overdraw
if ( o >= 3 ) {
const float kOverdrawThreshold = 3.f;
meshopt_optimizeOverdraw(mesh.attributes.index.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, (float*) mesh.attributes.vertex.pointer.position, mesh.attributes.vertex.length, sizeof(T), kOverdrawThreshold);
}
// optimize for fetch
if ( o >= 4 ) {
meshopt_optimizeVertexFetch(mesh.attributes.vertex.pointer, mesh.attributes.index.pointer, mesh.attributes.index.length, mesh.attributes.vertex.pointer, mesh.attributes.vertex.length, mesh.attributes.vertex.size);
}
#endif
mesh.updateDescriptor();
return true;
}
/*
auto vertices = std::move( this->vertices );
U indices = vertices.size();
uf::stl::vector<uint32_t> remap(indices);
size_t verticesCount = meshopt_generateVertexRemap(&remap[0], NULL, indices, &vertices[0], indices, sizeof(T));
this->indices.resize(indices);
//meshopt_remapIndexBuffer(&this->indices[0], NULL, indices, &remap[0]);
meshopt_remapIndexBuffer(&this->indices[0], (const U*) NULL, indices, &remap[0]);
this->vertices.resize(verticesCount);
meshopt_remapVertexBuffer(&this->vertices[0], &vertices[0], indices, sizeof(T), &remap[0]);
// optimize for cache
if ( o >= 1 ) {
meshopt_optimizeVertexCache(&this->indices[0], &this->indices[0], this->indices.size(), this->vertices.size());
}
// optimize for overdraw
if ( o >= 2 ) {
const float kOverdrawThreshold = 3.f;
meshopt_optimizeOverdraw(&this->indices[0], &this->indices[0], this->indices.size(), (float*) &this->vertices[0].position, this->vertices.size(), sizeof(T), kOverdrawThreshold);
}
// optimize for fetch
if ( o >= 3 ) {
meshopt_optimizeVertexFetch(&this->vertices[0], &this->indices[0], this->indices.size(), &this->vertices[0], this->vertices.size(), sizeof(T));
}
*/
#endif

View File

@ -232,11 +232,21 @@ namespace {
void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::InfoDraw& drawInfo ) {
pod::Matrix4f modelView = uf::matrix::identity(), projection = uf::matrix::identity();
if ( drawInfo.matrices.model && drawInfo.matrices.view ) modelView = uf::matrix::multiply( *drawInfo.matrices.view, *drawInfo.matrices.model );
else if ( drawInfo.matrices.model ) modelView = *drawInfo.matrices.model;
else if ( drawInfo.matrices.view ) modelView = *drawInfo.matrices.view;
if ( drawInfo.matrices.projection ) projection = *drawInfo.matrices.projection;
#if 0
{
if ( drawInfo.matrices.model ) UF_MSG_DEBUG( "model: " << drawInfo.matrices.model << " " << uf::matrix::toString( *drawInfo.matrices.model ) );
if ( drawInfo.matrices.view ) UF_MSG_DEBUG( "view: " << drawInfo.matrices.view << " " << uf::matrix::toString( *drawInfo.matrices.view ) );
if ( drawInfo.matrices.projection ) UF_MSG_DEBUG( "projection: " << drawInfo.matrices.projection << " " << uf::matrix::toString( *drawInfo.matrices.projection ) );
}
#endif
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::experimental::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) {

View File

@ -357,8 +357,10 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
}
auto uniformBufferIt = uniformBuffers.begin();
auto uniformBuffer = (*uniformBufferIt++).buffer;
auto uniformBuffer = (*uniformBufferIt).buffer;
auto uniformBufferSize = (*uniformBufferIt).range;
pod::Camera::Viewports* viewports = (pod::Camera::Viewports*) device->getBuffer( uniformBuffer );
pod::Uniform* viewports2 = (pod::Uniform*) device->getBuffer( uniformBuffer );
CommandBuffer::InfoDraw drawCommandInfoBase = {};
drawCommandInfoBase.type = ext::opengl::enums::Command::DRAW;
@ -373,10 +375,14 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
}
drawCommandInfoBase.attributes.index = descriptor.inputs.index.attributes.front();
drawCommandInfoBase.matrices.view = &viewports->matrices[0].view;
drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection;
if ( uniformBufferSize == sizeof(pod::Camera::Viewports) ) {
drawCommandInfoBase.matrices.view = &viewports->matrices[0].view;
drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection;
} else if ( uniformBufferSize == sizeof(pod::Uniform) ) {
drawCommandInfoBase.matrices.model = &viewports2->modelView;
drawCommandInfoBase.matrices.projection = &viewports2->projection;
}
#if 1
if ( descriptor.inputs.indirect.count ) {
auto& indirectAttribute = descriptor.inputs.indirect.attributes.front();
@ -406,22 +412,6 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
auto& infos = pool[textureID];
CommandBuffer::InfoDraw& drawCommandInfo = infos.emplace_back( drawCommandInfoBase );
/*
drawCommandInfo.type = ext::opengl::enums::Command::DRAW;
drawCommandInfo.descriptor = descriptor;
drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front();
for ( uf::Mesh::Attribute attribute : descriptor.inputs.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) drawCommandInfo.attributes.position = attribute;
else if ( attribute.descriptor.name == "uv" ) drawCommandInfo.attributes.uv = attribute;
else if ( attribute.descriptor.name == "st" ) drawCommandInfo.attributes.st = attribute;
else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute;
else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute;
}
drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front();
drawCommandInfo.matrices.view = &viewports->matrices[0].view;
drawCommandInfo.matrices.projection = &viewports->matrices[0].projection;
*/
drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID;
drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices;
@ -447,41 +437,18 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
auto texture2DID = textures[instance.lightmapID].index;
drawCommandInfo.textures.secondary = this->material.textures.at(texture2DID).descriptor;
}
// if ( !optimize )
commandBuffer.record(drawCommandInfo);
}
// if ( optimize ) for ( auto pair : pool ) for ( auto& info : pair.second ) commandBuffer.record(info);
} else {
} else {
/*
auto uniformBufferIt = uniformBuffers.begin();
auto uniformBuffer = (*uniformBufferIt++).buffer;
auto uniformOffset = (size_t) 0;
CommandBuffer::InfoDraw drawCommandInfo = {};
drawCommandInfo.type = ext::opengl::enums::Command::DRAW;
drawCommandInfo.descriptor = descriptor;
drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front();
for ( auto& attribute : descriptor.inputs.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) drawCommandInfo.attributes.position = attribute;
else if ( attribute.descriptor.name == "uv" ) drawCommandInfo.attributes.uv = attribute;
else if ( attribute.descriptor.name == "st" ) drawCommandInfo.attributes.st = attribute;
else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute;
else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute;
}
drawCommandInfo.textures.primary = this->material.textures.front().descriptor;
if ( !uniformBuffers.empty() ) {
pod::Uniform* uniforms = (pod::Uniform*) device->getBuffer( uniformBuffer );
drawCommandInfo.matrices.model = NULL;
drawCommandInfo.matrices.view = &uniforms->modelView;
drawCommandInfo.matrices.projection = &uniforms->projection;
}
UF_MSG_DEBUG( viewports << " " << uniformBuffers.size() );
if ( drawCommandInfoBase.matrices.model ) UF_MSG_DEBUG( "model: " << drawCommandInfoBase.matrices.model << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.model ) );
if ( drawCommandInfoBase.matrices.view ) UF_MSG_DEBUG( "view: " << drawCommandInfoBase.matrices.view << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.view ) );
if ( drawCommandInfoBase.matrices.projection ) UF_MSG_DEBUG( "projection: " << drawCommandInfoBase.matrices.projection << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.projection ) );
*/
commandBuffer.record(drawCommandInfoBase);
}
#endif
}
void ext::opengl::Graphic::destroy() {
for ( auto& pair : pipelines ) pair.second.destroy();

View File

@ -322,7 +322,8 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
}
// indices
if ( mesh.index.count ) {
uint8_t* pointer = (uint8_t*) mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer].data();
// uint8_t* pointer = (uint8_t*) mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer].data();
uint8_t* pointer = (uint8_t*) mesh.getBuffer(mesh.index).data();
for ( auto index = 0; index < xmesh.indexCount; ++index ) {
switch ( mesh.index.size ) {
case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break;

View File

@ -40,6 +40,7 @@ namespace {
uf::stl::unordered_map<uf::stl::string, uf::stl::unordered_map<uf::stl::string, uf::Glyph>> cache;
} glyphs;
#endif
uf::stl::string defaultRenderMode = "Gui";
uf::Serializer defaultSettings;
@ -342,18 +343,16 @@ void ext::Gui::load( const uf::Image& image ) {
if ( ext::json::isNull(metadataJson["projection"]) ) metadataJson["projection"] = false;
if ( ext::json::isNull(metadataJson["flip uv"]) ) metadataJson["flip uv"] = true;
if ( ext::json::isNull(metadataJson["front face"]) ) metadataJson["front face"] = "ccw";
#if UF_USE_OPENGL
metadataJson["cull mode"] = "back";
// metadataJson["depth test"]["test"] = false;
// metadataJson["depth test"]["write"] = true;
// if ( metadataJson["flip uv"].is<bool>() ) metadataJson["flip uv"] = !metadataJson["flip uv"].as<bool>();
#endif
} else {
if ( ext::json::isNull(metadataJson["projection"]) ) metadataJson["projection"] = true;
if ( ext::json::isNull(metadataJson["flip uv"]) ) metadataJson["flip uv"] = false;
if ( ext::json::isNull(metadataJson["front face"]) ) metadataJson["front face"] = "cw";
}
metadataJson["cull mode"] = "none";
if ( metadataJson["world"].as<bool>() ) {
}
graphic.descriptor.parse( metadataJson );
if ( uf::matrix::reverseInfiniteProjection ) {
} else {
@ -752,9 +751,10 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
bool isGlyph = this->hasComponent<ext::GuiBehavior::GlyphMetadata>();
#if UF_USE_OPENGL
auto model = uf::matrix::identity();
auto model = transform.model;
auto& shader = graphic.material.getShader("vertex");
pod::Uniform uniform;
if ( metadata.mode == 1 ) {
uniform.modelView = transform.model;
uniform.projection = uf::matrix::identity();
@ -764,7 +764,6 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
auto& camera = controller.getComponent<uf::Camera>();
uniform.modelView = camera.getView() * uf::transform::model( transform );
uniform.projection = camera.getProjection();
model = uniform.modelView;
} else if ( metadata.mode == 3 ) {
pod::Transform<> flatten = uf::transform::flatten( transform );
uniform.modelView =
@ -773,19 +772,8 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
uf::quaternion::matrix( flatten.orientation ) *
flatten.model;
uniform.projection = camera.getProjection();
model = uniform.modelView;
} else {
pod::Transform<> flatten = uf::transform::flatten( transform );
model =
uf::matrix::translate( uf::matrix::identity(), flatten.position ) *
uf::matrix::scale( uf::matrix::identity(), flatten.scale ) *
uf::quaternion::matrix( flatten.orientation ) *
flatten.model;
flatten.position.y = -flatten.position.y;
if ( isGlyph ) flatten.scale.y = -flatten.scale.y;
flatten.position.z = 1;
uniform.modelView =
uf::matrix::translate( uf::matrix::identity(), flatten.position ) *
uf::matrix::scale( uf::matrix::identity(), flatten.scale ) *
@ -793,7 +781,15 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
flatten.model;
uniform.projection = uf::matrix::identity();
}
shader.updateUniform( "UBO", (const void*) &uniform, sizeof(uniform) );
pod::Uniform* uniformBuffer = (pod::Uniform*) shader.device->getBuffer(shader.getUniformBuffer("UBO").descriptor.buffer);
#if 0
UF_MSG_DEBUG( "buffer: " << uniformBuffer );
UF_MSG_DEBUG( "modelView: " << &uniformBuffer->modelView << " " << uf::matrix::toString( uniformBuffer->modelView ) );
UF_MSG_DEBUG( "projection: " << &uniformBuffer->projection << " " << uf::matrix::toString( uniformBuffer->projection ) );
#endif
/*
auto model = uf::matrix::identity();
auto uniformBuffer = graphic.getUniform();