cleaned up GUI system ((re)added simple anchoring system, although I need to actually utilize it), fixed SDFs looking like shit
This commit is contained in:
parent
84f2b63a8f
commit
3965d3f719
@ -60,7 +60,7 @@
|
||||
},
|
||||
"graph": {
|
||||
"initial buffer elements": 128,
|
||||
"global storage": true
|
||||
"global storage": false
|
||||
},
|
||||
"ext": {
|
||||
"vulkan": {
|
||||
@ -109,7 +109,7 @@
|
||||
"invariant": {
|
||||
"default stage buffers": true,
|
||||
"default defer buffer destroy": true,
|
||||
"default command buffer immediate": true,
|
||||
"default command buffer immediate": false,
|
||||
"multithreaded recording": true
|
||||
},
|
||||
"pipelines": {
|
||||
@ -117,10 +117,10 @@
|
||||
"gui": true,
|
||||
"vsync": true, // vsync on vulkan side rather than engine-side
|
||||
"hdr": true,
|
||||
"vxgi": false,
|
||||
"vxgi": true,
|
||||
"culling": true,
|
||||
"bloom": false,
|
||||
"dof": false,
|
||||
"bloom": true,
|
||||
"dof": true,
|
||||
"rt": false,
|
||||
"fsr": false,
|
||||
"postProcess": false // "postProcess.chromab" // false
|
||||
@ -363,7 +363,7 @@
|
||||
"render modes": { "gui": true, "deferred": true },
|
||||
"limiters": {
|
||||
"deltaTime": 5,
|
||||
"framerate": "auto" // "auto" // for some reason drops to 60
|
||||
"framerate": 300 // "auto" // for some reason drops to 60
|
||||
},
|
||||
"threads": {
|
||||
"workers" : "auto",
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
"physics": {
|
||||
"gravity": [ 0, -9.81, 0 ],
|
||||
|
||||
"inertia": null,
|
||||
"mass": 10,
|
||||
"type": "bounding box",
|
||||
"recenter": false
|
||||
@ -51,7 +51,7 @@
|
||||
},
|
||||
"tags": {
|
||||
"/^.*/": {
|
||||
"optimize meshlets": { "simplify": 0.125, "print": true }
|
||||
"optimize meshlets": { "simplify": 0.5, "lods": true, "print": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,6 @@
|
||||
},
|
||||
"metadata": {
|
||||
"clickable": false,
|
||||
"hoverable": false,
|
||||
"hoverable": false
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
"type": "Gui",
|
||||
"ignore": false,
|
||||
"assets": [
|
||||
{ "filename": "./textures/mp.png", "hash": "68e7c459f9aecd6815ff7df1e2eefa82db60a23713b0134f0bfc15d82f55453d" }
|
||||
// { "filename": "./textures/mp.png", "hash": "68e7c459f9aecd6815ff7df1e2eefa82db60a23713b0134f0bfc15d82f55453d" }
|
||||
// { "filename": "./textures/ss2.png" }
|
||||
],
|
||||
"transform": {
|
||||
@ -20,16 +20,9 @@
|
||||
"hoverable": false,
|
||||
|
||||
"uv": [ 0, 0, 1, 1 ],
|
||||
// "color": [ 0.8, 0.8, 1, 1 ],
|
||||
// "color": [ 0.416, 0.573, 0.667, 1 ],
|
||||
"color": [ 1, 1, 1, 1 ],
|
||||
"location": "",
|
||||
"scaling": "relative",
|
||||
// "depth": 0.1,
|
||||
// "alpha": 0.5,
|
||||
"alpha": 0.75,
|
||||
"mode": 1,
|
||||
"gui layer": true,
|
||||
"only model": true
|
||||
"mode": 1
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ for i=1, visorLayers do
|
||||
end
|
||||
|
||||
local soundEmitter = ent:loadChild("./sound.json",true)
|
||||
local text = ent:loadChild("./text.json",true)
|
||||
|
||||
local timer = Timer.new()
|
||||
if not timer:running() then timer:start() end
|
||||
@ -51,9 +52,9 @@ local rotate = function( delta )
|
||||
end
|
||||
end
|
||||
|
||||
local windowSize = masterdata["system"]["config"]["window"]["size"];
|
||||
--local windowSize = masterdata["system"]["config"]["window"]["size"];
|
||||
local entTransform = ent:getComponent("Transform")
|
||||
entTransform.scale.x = entTransform.scale.x * windowSize.x / windowSize.y;
|
||||
--entTransform.scale.x = entTransform.scale.x * windowSize.x / windowSize.y;
|
||||
|
||||
for k, obj in pairs(children) do
|
||||
local transform = obj:getComponent("Transform")
|
||||
@ -105,7 +106,17 @@ ent:addHook( "window:Mouse.Moved", function( payload )
|
||||
end )
|
||||
]]
|
||||
|
||||
local fpsCounter = {
|
||||
frames = 0,
|
||||
time = 0,
|
||||
freq = 0.1
|
||||
}
|
||||
text:callHook( "gui:UpdateText.%UID%", {
|
||||
string = ""
|
||||
} )
|
||||
|
||||
ent:bind( "tick", function(self)
|
||||
--[[
|
||||
for k, obj in pairs(children) do
|
||||
local metadata = obj:getComponent("Metadata")
|
||||
local glow = math.sin(time.current()) * 0.5 + 0.5 -- constrained to [0,1]
|
||||
@ -113,16 +124,33 @@ ent:bind( "tick", function(self)
|
||||
metadata["alpha"] = glow
|
||||
obj:setComponent("Metadata", metadata)
|
||||
end
|
||||
]]
|
||||
|
||||
if fpsCounter["time"] > fpsCounter["freq"] then
|
||||
-- update text
|
||||
text:callHook( "gui:UpdateText.%UID%", {
|
||||
string = tostring(math.floor(fpsCounter["frames"] / fpsCounter["time"]))
|
||||
} )
|
||||
|
||||
fpsCounter["time"] = 0
|
||||
fpsCounter["frames"] = 0
|
||||
else
|
||||
fpsCounter["frames"] = fpsCounter["frames"] + 1
|
||||
fpsCounter["time"] = fpsCounter["time"] + time.delta()
|
||||
end
|
||||
|
||||
|
||||
local controllerTransform = controller:getComponent("Transform")
|
||||
local controllerCamera = controller:getComponent("Camera")
|
||||
local controllerCameraTransform = controllerCamera:getTransform()
|
||||
local transform = ent:getComponent("Transform")
|
||||
|
||||
--[[
|
||||
local speed = 2.5
|
||||
if lerper.a == 1 then return end
|
||||
lerper.a = lerper.a + time.delta() * speed
|
||||
if lerper.a > 1 then lerper.a = 1 end
|
||||
]]
|
||||
|
||||
transform.orientation = lerper.from:slerp( lerper.to, lerper.a )
|
||||
local orientation = transform.orientation
|
||||
|
||||
25
bin/data/entities/gui/hud/text.json
Normal file
25
bin/data/entities/gui/hud/text.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "HUD Overlay",
|
||||
"type": "Gui",
|
||||
"ignore": false,
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"transform": {
|
||||
"position": [ -0.9, -0.9, 0 ],
|
||||
"rotation": {
|
||||
"axis": [ 0, 0, 1 ],
|
||||
"angle": 0
|
||||
},
|
||||
"scale": [ 1, 1, 1 ]
|
||||
},
|
||||
"metadata": {
|
||||
"clickable": false,
|
||||
"hoverable": false,
|
||||
|
||||
"uv": [ 0, 0, 1, 1 ],
|
||||
"color": [ 1, 1, 1, 1 ],
|
||||
"scaling": "relative",
|
||||
"string": "1234567890"
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "Gui: Text",
|
||||
"type": "Gui",
|
||||
"ignore": true,
|
||||
"transform": {
|
||||
"position": [ 0, 0, 0 ],
|
||||
"rotation": {
|
||||
"axis": [ 0, 0, 1 ],
|
||||
"angle": 0
|
||||
},
|
||||
"scale": [ 1, 1, 1 ]
|
||||
},
|
||||
"metadata": {
|
||||
"legacy": false,
|
||||
"padding": [ 1, 1 ],
|
||||
"spread": 4,
|
||||
"weight": 0.48,
|
||||
// "size": 36, "scale": 3,
|
||||
// "size": 45, "scale": 2,
|
||||
"size": 60, "scale": 1.5,
|
||||
// "size": 72, "scale": 1.25,
|
||||
// "size": 90, "scale": 1,
|
||||
"sdf": false,
|
||||
"font": "TAZUGANEGOTHICSTDN-BOLD.otf",
|
||||
"kerning": 24,
|
||||
"scaling": "none",
|
||||
// "font": "Coolvetica.ttf",
|
||||
|
||||
"stroke": [ 0, 0, 0, 0 ],
|
||||
"color": [ 1, 1, 1, 1 ],
|
||||
|
||||
"direction": "down",
|
||||
"align": "left",
|
||||
"origin": [ 0, 0 ],
|
||||
|
||||
"string": "",
|
||||
|
||||
"world": false,
|
||||
// "depth": 0,
|
||||
"wrap": true
|
||||
}
|
||||
}
|
||||
@ -17,13 +17,6 @@
|
||||
},
|
||||
"metadata": {
|
||||
"uv": [ 0, 0, 1, 1 ],
|
||||
"location": "",
|
||||
"scaling": "relative",
|
||||
"text settings": {
|
||||
"stroke": [ 1, 0.749, 0.368, 1 ],
|
||||
"color": [ 1, 0.749, 0.368, 1 ],
|
||||
"depth": 0.5,
|
||||
"string": "."
|
||||
}
|
||||
"scaling": "relative"
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@
|
||||
// "./playerModel.json",
|
||||
"./playerLight.json",
|
||||
// "./playerHands.json",
|
||||
"./gui/hud/hud.json",
|
||||
"./scripts/player.lua"
|
||||
],
|
||||
"system": {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"metadata": {
|
||||
"holdable": true,
|
||||
"physics": {
|
||||
"mass": 100,
|
||||
"mass": 100000,
|
||||
"inertia": false,
|
||||
"type": "bounding box"
|
||||
// "type": "mesh"
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
"import": "./base_sourceengine.json",
|
||||
"assets": [
|
||||
// { "filename": "./models/mds_mcdonalds.glb" }
|
||||
{ "filename": "./models/mds_mcdonalds/graph.json" }
|
||||
// ,{ "filename": "/burger.json", "delay": 1 }
|
||||
{ "filename": "./models/mds_mcdonalds/graph.json" },
|
||||
{ "filename": "/burger.json", "delay": 1 }
|
||||
],
|
||||
"metadata": {
|
||||
"graph": {
|
||||
|
||||
@ -11,7 +11,7 @@ layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
#define QUERY_MIPMAPS 1
|
||||
#define DEPTH_BIAS 0.00005
|
||||
#define FRUSTUM_CULLING 1
|
||||
#define OCCLUSION_CULLING 1 // currently whack
|
||||
#define OCCLUSION_CULLING 0 // currently whack
|
||||
#define LODS 1
|
||||
#define MAX_LODS 4
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ void main() {
|
||||
|
||||
const float sampled = texture(samplerTexture, inUv).r;
|
||||
const float smoothing = ( inGlyph.spread > 0 && inGlyph.scale > 0 ) ? 0.25 / (inGlyph.spread * inGlyph.scale) : 0.25 / (4 * 1.5);
|
||||
const float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, sampled);
|
||||
const float outlining = smoothstep(inGlyph.fillWeight - smoothing, inGlyph.fillWeight + smoothing, sampled);
|
||||
const float alpha = smoothstep(inGlyph.weight - smoothing, inGlyph.weight + smoothing, sampled);
|
||||
if ( alpha < 0.001 || alpha > 1 ) discard;
|
||||
C = mix(inGlyph.stroke, inGui.color, outlining);
|
||||
|
||||
@ -15,8 +15,8 @@ struct Glyph {
|
||||
int spread;
|
||||
float weight;
|
||||
|
||||
float fillWeight;
|
||||
float scale;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
uint padding3;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,7 @@ namespace ext {
|
||||
float targetError = 1e-2f / simplify;
|
||||
|
||||
float realError = 0.0f;
|
||||
size_t realIndices = meshopt_simplify(&indicesSimplified[0], &indices[0], indicesCount, &meshlet.vertices[0].position.x, verticesCount, sizeof(T), indicesCount * simplify, targetError);
|
||||
size_t realIndices = meshopt_simplify(&indicesSimplified[0], &indices[0], indicesCount, &meshlet.vertices[0].position.x, verticesCount, sizeof(T), indicesCount * simplify, targetError, 0, &realError);
|
||||
// size_t realIndices = meshopt_simplifySloppy(&indicesSimplified[0], &indices[0], indicesCount, &meshlet.vertices[0].position.x, verticesCount, sizeof(T), targetIndices);
|
||||
|
||||
if ( verbose ) UF_MSG_DEBUG("[Simplified] indices: {} -> {} | error: {} -> {}", indicesCount, realIndices, targetError, realError);
|
||||
|
||||
@ -28,14 +28,6 @@
|
||||
#define EXT_COLOR_FLOATS 1
|
||||
|
||||
namespace {
|
||||
struct {
|
||||
bool initialized = false;
|
||||
|
||||
uf::Mesh mesh;
|
||||
uf::Image image;
|
||||
uf::Serializer settings;
|
||||
} defaults;
|
||||
|
||||
struct Mesh {
|
||||
pod::Vector3f position;
|
||||
pod::Vector2f uv;
|
||||
@ -77,20 +69,33 @@ UF_VERTEX_DESCRIPTOR(Mesh,
|
||||
)
|
||||
|
||||
namespace {
|
||||
uf::Image& generateImage( uf::Image& image ) {
|
||||
image.open(uf::io::root+"/textures/missing.png");
|
||||
return image;
|
||||
// default to center
|
||||
pod::Vector2f parseAnchor( const uf::stl::string& anchor, const pod::Vector2f& def = {0.5f, 0.5f} ) {
|
||||
if ( anchor == "top-center" || anchor == "top" ) return {0.5f, 0.0f};
|
||||
if ( anchor == "top-left" ) return {0.0f, 0.0f};
|
||||
if ( anchor == "top-right" ) return {1.0f, 0.0f};
|
||||
|
||||
if ( anchor == "center" ) return {0.5f, 0.5f};
|
||||
if ( anchor == "center-left" || anchor == "left" ) return {0.0f, 0.5f};
|
||||
if ( anchor == "center-right" || anchor == "right" ) return {1.0f, 0.5f};
|
||||
|
||||
if ( anchor == "bottom-center" || anchor == "bottom" ) return {0.5f, 1.0f};
|
||||
if ( anchor == "bottom-left" ) return {0.0f, 1.0f};
|
||||
if ( anchor == "bottom-right" ) return {1.0f, 1.0f};
|
||||
|
||||
return def;
|
||||
}
|
||||
uf::Mesh& generateMesh( uf::Mesh& mesh, const pod::Vector4f& color = {1, 1, 1, 1} ) {
|
||||
|
||||
uf::Mesh& generateMesh( uf::Mesh& mesh, const pod::Vector4f& color, const pod::Vector2f& center ) {
|
||||
mesh.bind<::Mesh, uint16_t>();
|
||||
mesh.insertVertices<::Mesh>({
|
||||
{ pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color },
|
||||
{ pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, color },
|
||||
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color },
|
||||
{ pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color },
|
||||
{ pod::Vector3f{-1.0f, -1.0f, 0.0f} - center, pod::Vector2f{0.0f, 1.0f}, color },
|
||||
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color },
|
||||
|
||||
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color },
|
||||
{ pod::Vector3f{ 1.0f, 1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, color },
|
||||
{ pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color },
|
||||
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color },
|
||||
{ pod::Vector3f{ 1.0f, 1.0f, 0.0f} - center, pod::Vector2f{1.0f, 0.0f}, color },
|
||||
{ pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color },
|
||||
});
|
||||
mesh.insertIndices<uint16_t>({
|
||||
0, 1, 2, 3, 4, 5
|
||||
@ -98,6 +103,10 @@ namespace {
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
uf::Mesh& generateMesh( uf::Mesh& mesh, const pod::Vector4f& color = {1, 1, 1, 1}, const uf::stl::string& alignment = "center" ) {
|
||||
return ::generateMesh( mesh, color, ::parseAnchor( alignment ) * 2.0f - 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
// YUCK
|
||||
@ -120,54 +129,11 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
|
||||
if ( !::defaults.initialized ) {
|
||||
::defaults.initialized = true;
|
||||
|
||||
::generateImage( ::defaults.image );
|
||||
::generateMesh( ::defaults.mesh );
|
||||
}
|
||||
/*
|
||||
if ( ext::json::isNull( ::defaults.settings["metadata"] ) ) ::defaults.settings.readFromFile(uf::io::root+"/entities/gui.json");
|
||||
// set defaults
|
||||
if ( metadataJson["string"].is<uf::stl::string>() ) {
|
||||
auto copyMetadataJson = metadataJson;
|
||||
ext::json::forEach(::defaults.settings["metadata"], [&]( const uf::stl::string& key, ext::json::Value& value ){
|
||||
if ( ext::json::isNull( copyMetadataJson[key] ) ) {
|
||||
metadataJson[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
UF_BEHAVIOR_METADATA_BIND_SERIALIZER_HOOKS(metadata, metadataJson);
|
||||
|
||||
this->addHook( "gui:Update.%UID%", [&](ext::payloads::GuiInitializationPayload& payload){
|
||||
auto& graphic = this->getComponent<uf::Graphic>();
|
||||
|
||||
/*
|
||||
if ( metadataJson["mode"].as<uf::stl::string>() == "flat" ) {
|
||||
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";
|
||||
} 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";
|
||||
}
|
||||
|
||||
if ( metadataJson["world"].as<bool>() ) {
|
||||
// metadataJson["gui layer"] = false;
|
||||
} else {
|
||||
#if UF_USE_OPENGL
|
||||
if ( ext::json::isNull(metadataJson["cull mode"]) ) metadataJson["cull mode"] = "front";
|
||||
if ( uf::matrix::reverseInfiniteProjection ) metadata.depth = 1 - metadata.depth;
|
||||
// transform.position.z = metadata.depth;
|
||||
#else
|
||||
// if ( metadataJson["flip uv"].as<bool>() ) for ( auto& v : vertices ) v.uv.y = 1 - v.uv.y;
|
||||
#endif
|
||||
// for ( auto& v : vertices ) v.position.z = metadata.depth;
|
||||
}
|
||||
*/
|
||||
if ( ext::json::isNull(metadataJson["cull mode"]) ) metadataJson["cull mode"] = "back";
|
||||
|
||||
//
|
||||
@ -186,11 +152,6 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
auto& texture = graphic.material.textures.emplace_back();
|
||||
texture.loadFromImage( image );
|
||||
|
||||
// update transform
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if ( payload.free ) {
|
||||
delete payload.image;
|
||||
@ -263,6 +224,16 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( metadata.space == "screen" ) {
|
||||
auto anchor = ::parseAnchor( metadata.anchor, metadata.pivot ) * 2.0f - 1.0f;
|
||||
transform.position.x += anchor.x;
|
||||
transform.position.y += anchor.y;
|
||||
/*
|
||||
transform.position.x += anchor.x * ((float) metadata.size.x / uf::renderer::settings::width) * transform.scale.x;
|
||||
transform.position.y += anchor.y * ((float) metadata.size.y / uf::renderer::settings::height) * transform.scale.y;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
metadata.initialized = true;
|
||||
});
|
||||
@ -274,7 +245,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
auto& image = uf::asset::get<uf::Image>( payload );
|
||||
|
||||
// generate default mesh
|
||||
::generateMesh( mesh, metadata.color );
|
||||
::generateMesh( mesh, metadata.color, metadata.alignment );
|
||||
|
||||
{
|
||||
ext::payloads::GuiInitializationPayload payload;
|
||||
@ -291,12 +262,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
if ( !clickTimer.running() ) clickTimer.start();
|
||||
|
||||
this->addHook( "window:Mouse.Click", [&](pod::payloads::windowMouseClick& payload){
|
||||
if ( metadata.world ) return;
|
||||
//if ( !metadata.boxMin && !metadata.boxMax ) return;
|
||||
if ( metadata.space != "screen" ) return;
|
||||
if ((metadata.boxMin.x > metadata.boxMax.x)||(metadata.boxMin.y > metadata.boxMax.y)) return;
|
||||
|
||||
// uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
|
||||
// pod::Vector2ui guiSize = manager ? manager->getComponent<ext::GuiManagerBehavior::Metadata>().size : pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
pod::Vector2ui guiSize = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
|
||||
bool clicked = false;
|
||||
@ -386,12 +354,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
hoverTimer.start( uf::Time<>(-1000000) );
|
||||
|
||||
this->addHook( "window:Mouse.Moved", [&](pod::payloads::windowMouseMoved& payload){
|
||||
if ( metadata.world ) return;
|
||||
//if ( !metadata.boxMin && !metadata.boxMax ) return;
|
||||
if ( metadata.space != "screen" ) return;
|
||||
if ((metadata.boxMin.x > metadata.boxMax.x)||(metadata.boxMin.y > metadata.boxMax.y)) return;
|
||||
|
||||
// uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
|
||||
// pod::Vector2ui guiSize = manager ? manager->getComponent<ext::GuiManagerBehavior::Metadata>().size : pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
pod::Vector2ui guiSize = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
|
||||
bool hovered = false;
|
||||
@ -488,22 +453,18 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
// uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
|
||||
// pod::Vector2ui guiSize = manager ? manager->getComponent<ext::GuiManagerBehavior::Metadata>().size : pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
pod::Vector2ui guiSize = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
if ( metadata.space == "screen" ) {
|
||||
pod::Vector2f guiSize = pod::Vector2f{ uf::renderer::settings::width, uf::renderer::settings::height };
|
||||
pod::Vector2f scale = { 1, 1 };
|
||||
|
||||
if ( metadata.scaleMode == "fixed" || metadata.scaleMode == "fixed-x" ) {
|
||||
flatten.scale.x *= (float) metadata.size.x / (float) guiSize.x;
|
||||
}
|
||||
if ( metadata.scaleMode == "fixed" || metadata.scaleMode == "fixed-y" ) {
|
||||
flatten.scale.y *= (float) metadata.size.x / (float) guiSize.y;
|
||||
}
|
||||
if ( metadata.scaling == "fixed" || metadata.scaling == "fixed-x" ) scale.x = (float) metadata.size.x / guiSize.x;
|
||||
if ( metadata.scaling == "fixed" || metadata.scaling == "fixed-y" ) scale.y = (float) metadata.size.x / guiSize.y;
|
||||
|
||||
if ( metadata.scaleMode == "relative" || metadata.scaleMode == "relative-x" ) {
|
||||
flatten.scale.x *= (float) guiSize.y / (float) guiSize.x;
|
||||
}
|
||||
if ( metadata.scaleMode == "relative" || metadata.scaleMode == "relative-y" ) {
|
||||
flatten.scale.y *= (float) guiSize.x / (float) guiSize.y;
|
||||
if ( metadata.scaling == "relative" || metadata.scaling == "relative-x" ) scale.x = (float) guiSize.y / guiSize.x;
|
||||
if ( metadata.scaling == "relative" || metadata.scaling == "relative-y" ) scale.y = (float) guiSize.x / guiSize.y;
|
||||
|
||||
flatten.scale.x *= scale.x;
|
||||
flatten.scale.y *= scale.y;
|
||||
}
|
||||
|
||||
// bind UBO
|
||||
@ -619,33 +580,48 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
|
||||
void ext::GuiBehavior::render( uf::Object& self ){}
|
||||
void ext::GuiBehavior::destroy( uf::Object& self ){}
|
||||
void ext::GuiBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ){
|
||||
serializer["color"] = uf::vector::encode( /*this->*/color );
|
||||
serializer["uv"] = uf::vector::encode( /*this->*/uv );
|
||||
// serializer["scaling"] = uf::vector::encode( /*this->*/scaling );
|
||||
|
||||
serializer["depth"] = /*this->*/depth;
|
||||
serializer["mode"] = /*this->*/mode;
|
||||
serializer["renderMode"] = /*this->*/renderMode;
|
||||
serializer["scaling"] = /*this->*/scaleMode;
|
||||
|
||||
serializer["clickable"] = /*this->*/clickable;
|
||||
serializer["clicked"] = /*this->*/clicked;
|
||||
|
||||
serializer["hoverable"] = /*this->*/hoverable;
|
||||
serializer["hovered"] = /*this->*/hovered;
|
||||
|
||||
serializer["size"] = uf::vector::encode( /*this->*/size );
|
||||
serializer["uv"] = uf::vector::encode( /*this->*/uv );
|
||||
serializer["color"] = uf::vector::encode( /*this->*/color );
|
||||
|
||||
serializer["renderMode"] = /*this->*/renderMode;
|
||||
serializer["scaling"] = /*this->*/scaling;
|
||||
//
|
||||
serializer["anchor"] = /*this->*/anchor;
|
||||
serializer["alignment"] = /*this->*/alignment;
|
||||
serializer["space"] = /*this->*/space;
|
||||
serializer["pivot"] = uf::vector::encode(/*this->*/pivot);
|
||||
|
||||
}
|
||||
void ext::GuiBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ){
|
||||
/*this->*/color = uf::vector::decode( serializer["color"], /*this->*/color );
|
||||
/*this->*/uv = uf::vector::decode( serializer["uv"], /*this->*/uv );
|
||||
// /*this->*/scaling = uf::vector::decode( serializer["scaling"], /*this->*/scaling );
|
||||
|
||||
/*this->*/depth = serializer["depth"].as( /*this->*/depth );
|
||||
/*this->*/mode = serializer["mode"].as( /*this->*/mode );
|
||||
/*this->*/renderMode = serializer["renderMode"].as( /*this->*/renderMode );
|
||||
/*this->*/scaleMode = serializer["scaling"].as( /*this->*/scaleMode );
|
||||
|
||||
|
||||
/*this->*/clickable = serializer["clickable"].as( /*this->*/clickable );
|
||||
// /*this->*/clicked = serializer["clicked"].as( /*this->*/clicked );
|
||||
/*this->*/hoverable = serializer["hoverable"].as( /*this->*/hoverable );
|
||||
// /*this->*/hovered = serializer["hovered"].as( /*this->*/hovered );
|
||||
|
||||
/*this->*/size = uf::vector::decode( serializer["size"], /*this->*/size );
|
||||
/*this->*/uv = uf::vector::decode( serializer["uv"], /*this->*/uv );
|
||||
/*this->*/color = uf::vector::decode( serializer["color"], /*this->*/color );
|
||||
|
||||
/*this->*/renderMode = serializer["renderMode"].as( /*this->*/renderMode );
|
||||
/*this->*/scaling = serializer["scaling"].as( /*this->*/scaling );
|
||||
|
||||
/*this->*/anchor = serializer["anchor"].as( /*this->*/anchor );
|
||||
/*this->*/alignment = serializer["alignment"].as( /*this->*/alignment );
|
||||
/*this->*/space = serializer["space"].as( /*this->*/space );
|
||||
/*this->*/pivot = uf::vector::decode( serializer["pivot"], /*this->*/pivot );
|
||||
|
||||
}
|
||||
#undef this
|
||||
|
||||
@ -653,7 +629,6 @@ void ext::GuiBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer&
|
||||
#include <uf/ext/lua/component.h>
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(ext::GuiBehavior::Metadata,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::initialized),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::world),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::depth),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::mode),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::clickable),
|
||||
@ -661,11 +636,14 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(ext::GuiBehavior::Metadata,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::hoverable),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::hovered),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::size),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::scale),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::uv),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::color),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::renderMode),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::scaleMode),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::scaling),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::boxMin),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::boxMax)
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::boxMax),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::anchor),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::alignment),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::space),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::GuiBehavior::Metadata::pivot)
|
||||
)
|
||||
@ -20,8 +20,6 @@ namespace ext {
|
||||
UF_BEHAVIOR_DEFINE_METADATA(
|
||||
bool initialized = false;
|
||||
|
||||
bool world = false;
|
||||
|
||||
float depth = 0;
|
||||
size_t mode = 0;
|
||||
|
||||
@ -31,15 +29,19 @@ namespace ext {
|
||||
bool hovered = false;
|
||||
|
||||
pod::Vector2ui size = {};
|
||||
pod::Vector2f scale = { 1, 1 };
|
||||
pod::Vector4f uv = { 0, 0, 1, 1 };
|
||||
pod::Vector4f color = { 1, 1, 1, 1 };
|
||||
|
||||
uf::stl::string renderMode = "Gui";
|
||||
uf::stl::string scaleMode = "fixed";
|
||||
uf::stl::string scaling = "fixed";
|
||||
|
||||
pod::Vector2f boxMin = { 1, 1 };
|
||||
pod::Vector2f boxMax = { 1, 1 };
|
||||
|
||||
uf::stl::string space = "screen";
|
||||
pod::Vector2f pivot = {0.5f, 0.5f}; // if anchor is not a valid string
|
||||
uf::stl::string anchor = ""; // blank as the default changes between normal GUI and glyph
|
||||
uf::stl::string alignment = ""; // ^
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -108,226 +108,268 @@ namespace {
|
||||
return seed;
|
||||
}
|
||||
|
||||
uf::stl::vector<::GlyphBox> generateGlyphs( uf::Object& self, const uf::stl::string& _string ) {
|
||||
uf::stl::vector<::GlyphBox> gs;
|
||||
|
||||
#if UF_USE_FREETYPE
|
||||
auto& glyphs = ::glyphs;
|
||||
auto& metadata = this->getComponent<ext::GuiGlyphBehavior::Metadata>();
|
||||
auto& metadataGui = this->getComponent<ext::GuiBehavior::Metadata>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
// default to left
|
||||
pod::Vector2f parseAnchor( const uf::stl::string& anchor, const pod::Vector2f& def = {0.0f, 0.0f} ) {
|
||||
if ( anchor == "top-center" || anchor == "top" ) return {0.5f, 0.0f};
|
||||
if ( anchor == "top-left" ) return {0.0f, 0.0f};
|
||||
if ( anchor == "top-right" ) return {1.0f, 0.0f};
|
||||
|
||||
if ( anchor == "center" ) return {0.5f, 0.5f};
|
||||
if ( anchor == "center-left" || anchor == "left" ) return {0.0f, 0.5f};
|
||||
if ( anchor == "center-right" || anchor == "right" ) return {1.0f, 0.5f};
|
||||
|
||||
auto string = _string == "" ? metadata.string : _string;
|
||||
auto font = uf::io::root+"/fonts/" + metadata.font;
|
||||
auto color = metadataGui.color;
|
||||
if ( anchor == "bottom-center" || anchor == "bottom" ) return {0.5f, 1.0f};
|
||||
if ( anchor == "bottom-left" ) return {0.0f, 1.0f};
|
||||
if ( anchor == "bottom-right" ) return {1.0f, 1.0f};
|
||||
|
||||
auto origin = uf::stl::string("top");
|
||||
auto align = uf::stl::string("center");
|
||||
auto direction = uf::stl::string("down");
|
||||
return def;
|
||||
}
|
||||
|
||||
if ( glyphs.cache[font].empty() ) ext::freetype::initialize( glyphs.glyph, font );
|
||||
struct TextToken {
|
||||
uf::stl::string text;
|
||||
pod::Vector3f color;
|
||||
};
|
||||
|
||||
struct {
|
||||
struct {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
} origin;
|
||||
|
||||
struct {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
} cursor;
|
||||
float hexToFloat( const uf::stl::string& str ) {
|
||||
int value;
|
||||
uf::stl::stringstream stream;
|
||||
stream << str;
|
||||
stream >> std::hex >> value;
|
||||
return value / 255.0f;
|
||||
}
|
||||
|
||||
struct {
|
||||
float sum = 0;
|
||||
float len = 0;
|
||||
float proc = 0;
|
||||
float tab = 4;
|
||||
} average;
|
||||
|
||||
struct {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
} biggest;
|
||||
// parses a text for special tokens, associating strings with color
|
||||
// should maybe be utf8, but in theory it shouldn't matter since tags are ASCII
|
||||
uf::stl::vector<TextToken> parseTextTokens( const uf::stl::string& text, pod::Vector3f color ) {
|
||||
uf::stl::vector<TextToken> tokens;
|
||||
|
||||
struct {
|
||||
float w = 0;
|
||||
float h = 0;
|
||||
} box;
|
||||
auto tagLength = 10; // hard-coded cringe
|
||||
bool colorChanged = false;
|
||||
size_t currentPos = 0;
|
||||
size_t textLength = text.length();
|
||||
|
||||
struct {
|
||||
uf::stl::vector<pod::Vector3f> container;
|
||||
size_t index = 0;
|
||||
} colors;
|
||||
} stat;
|
||||
TextToken currentToken;
|
||||
currentToken.color = color;
|
||||
|
||||
stat.colors.container.push_back(color);
|
||||
while ( currentPos < textLength ) {
|
||||
size_t tagStart = text.find("${#", currentPos);
|
||||
|
||||
// grab escaped color markers: ${#RRGGBB}
|
||||
{
|
||||
uf::stl::unordered_map<size_t, pod::Vector3f> colors;
|
||||
uf::stl::string text = string;
|
||||
|
||||
std::regex regex("\\$\\{\\#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})\\}");
|
||||
std::smatch match;
|
||||
|
||||
bool matched = false;
|
||||
|
||||
int maxTries = 128;
|
||||
while ( (matched = std::regex_search( text, match, regex )) && --maxTries > 0 ) {
|
||||
struct {
|
||||
uf::stl::string str;
|
||||
int dec;
|
||||
} r, g, b;
|
||||
r.str = match[1].str();
|
||||
g.str = match[2].str();
|
||||
b.str = match[3].str();
|
||||
|
||||
{ uf::stl::stringstream stream; stream << r.str; stream >> std::hex >> r.dec; }
|
||||
{ uf::stl::stringstream stream; stream << g.str; stream >> std::hex >> g.dec; }
|
||||
{ uf::stl::stringstream stream; stream << b.str; stream >> std::hex >> b.dec; }
|
||||
|
||||
pod::Vector3f color = { r.dec / 255.0f, g.dec / 255.0f, b.dec / 255.0f };
|
||||
|
||||
stat.colors.container.push_back(color);
|
||||
text = uf::string::replace( text, "${" + r.str + g.str + b.str + "}", "\x7F" );
|
||||
if ( tagStart == uf::stl::string::npos ) {
|
||||
currentToken.text += text.substr(currentPos);
|
||||
if ( !currentToken.text.empty() || colorChanged ) {
|
||||
tokens.emplace_back(currentToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( tagStart > currentPos ) {
|
||||
currentToken.text += text.substr( currentPos, tagStart - currentPos ); // append everything up to the tag
|
||||
tokens.emplace_back( currentToken ); // commit token
|
||||
currentToken.text = ""; // reset text
|
||||
}
|
||||
|
||||
// validate tag
|
||||
if ( tagStart + tagLength <= textLength && text[tagStart + tagLength - 1] == '}' ) {
|
||||
uf::stl::string rHex = text.substr(tagStart + 3, 2);
|
||||
uf::stl::string gHex = text.substr(tagStart + 5, 2);
|
||||
uf::stl::string bHex = text.substr(tagStart + 7, 2);
|
||||
|
||||
// change color
|
||||
currentToken.color = { hexToFloat(rHex), hexToFloat(gHex), hexToFloat(bHex) };
|
||||
colorChanged = true;
|
||||
|
||||
// advance past the tag
|
||||
currentPos = tagStart + tagLength;
|
||||
} else {
|
||||
currentToken.text += "${#"; // treat it as normal text
|
||||
currentPos = tagStart + 3;
|
||||
}
|
||||
if ( maxTries == 0 ) text += "\n(error formatting)";
|
||||
string = text;
|
||||
}
|
||||
#if 0
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
|
||||
std::wstring str = convert.from_bytes(string);
|
||||
#else
|
||||
std::u8string str(string.begin(), string.end());
|
||||
#endif
|
||||
if ( str.size() == 0 ) return gs;
|
||||
|
||||
// Calculate statistics
|
||||
{
|
||||
// Find tallest glyph for new line
|
||||
for ( auto it = str.begin(); it != str.end(); ++it ) {
|
||||
uint64_t c = *it; if ( c == '\n' ) continue; if ( c == '\t' ) continue; if ( c == 0x01 ) continue;
|
||||
auto key = hashGlyphSettings( c, metadata );
|
||||
auto& glyph = glyphs.cache[font][key];
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// compute the boxes for a given string and settings
|
||||
uf::stl::vector<GlyphBox> calculateGlyphLayout( uf::Object& self, const uf::stl::vector<TextToken>& tokens, const ext::GuiGlyphBehavior::Metadata& metadata, const ext::GuiBehavior::Metadata& metadataGui, const uf::stl::string& font ) {
|
||||
uf::stl::vector<GlyphBox> layout;
|
||||
auto& glyphsCache = ::glyphs.cache[font];
|
||||
|
||||
if ( glyphsCache.empty() ) {
|
||||
ext::freetype::initialize( ::glyphs.glyph, font );
|
||||
}
|
||||
|
||||
pod::Vector2f anchor = ::parseAnchor( metadataGui.alignment );
|
||||
pod::Vector2f cursor = { 0.0f, 0.0f };
|
||||
float maxTextWidth = 0.0f;
|
||||
float maxTextHeight = 0.0f;
|
||||
float tallestGlyphY = 0.0f;
|
||||
float averageTabWidth = 0.0f;
|
||||
float totalWidth = 0.0f;
|
||||
int charCount = 0;
|
||||
|
||||
// generate glyph and line height
|
||||
for ( const auto& token : tokens ) {
|
||||
std::u8string str(token.text.begin(), token.text.end());
|
||||
for ( uint64_t c : str ) {
|
||||
if ( c == '\n' || c == '\t' ) continue; // special characters
|
||||
|
||||
auto key = hashGlyphSettings(c, metadata);
|
||||
auto& glyph = glyphsCache[key];
|
||||
|
||||
// generate glyph
|
||||
if ( !glyph.generated() ) {
|
||||
glyph.setPadding( { metadata.padding[0], metadata.padding[1] } );
|
||||
glyph.setSpread( metadata.spread );
|
||||
glyph.useSdf( metadata.sdf );
|
||||
glyph.generate( glyphs.glyph, c, metadata.size );
|
||||
glyph.setPadding({ metadata.padding[0], metadata.padding[1] });
|
||||
glyph.setSpread(metadata.spread);
|
||||
glyph.useSdf(metadata.sdf);
|
||||
glyph.generate(::glyphs.glyph, c, metadata.size);
|
||||
}
|
||||
|
||||
|
||||
stat.biggest.x = std::max( (float) stat.biggest.x, (float) glyph.getSize().x);
|
||||
stat.biggest.y = std::max( (float) stat.biggest.y, (float) glyph.getSize().y);
|
||||
|
||||
stat.average.sum += glyph.getSize().x;
|
||||
++stat.average.len;
|
||||
tallestGlyphY = std::max(tallestGlyphY, (float) glyph.getSize().y);
|
||||
totalWidth += glyph.getSize().x; // should probably be reset on new-line to find the widest line
|
||||
charCount++;
|
||||
}
|
||||
stat.average.proc = stat.average.sum / stat.average.len;
|
||||
stat.average.tab *= stat.average.proc;
|
||||
}
|
||||
|
||||
// Calculate box: Second pass required because of tab
|
||||
stat.cursor.x = 0;
|
||||
stat.cursor.y = 0;
|
||||
stat.origin.x = 0;
|
||||
stat.origin.y = 0;
|
||||
if ( charCount > 0 ) averageTabWidth = (totalWidth / charCount) * 4.0f;
|
||||
cursor.y = tallestGlyphY;
|
||||
|
||||
for ( auto it = str.begin(); it != str.end(); ++it ) {
|
||||
uint64_t c = *it; if ( c == '\n' ) {
|
||||
stat.cursor.y += stat.biggest.y;
|
||||
stat.cursor.x = 0;
|
||||
// calculate positions
|
||||
for ( const auto& token : tokens ) {
|
||||
std::u8string str( token.text.begin(), token.text.end() );
|
||||
for ( uint64_t c : str ) {
|
||||
// advance cursor on special characters
|
||||
if ( c == '\n' ) {
|
||||
cursor.y += tallestGlyphY;
|
||||
cursor.x = 0;
|
||||
continue;
|
||||
} else if ( c == '\t' ) {
|
||||
// Fixed movement vs Real Tabbing
|
||||
if ( false ) {
|
||||
stat.cursor.x += stat.average.tab;
|
||||
} else {
|
||||
stat.cursor.x = ((stat.cursor.x / stat.average.tab) + 1) * stat.average.tab;
|
||||
}
|
||||
cursor.x = ((int)(cursor.x / averageTabWidth) + 1) * averageTabWidth;
|
||||
continue;
|
||||
} else if ( c == COLOR_CTRL ) {
|
||||
} else if ( c == ' ' ) {
|
||||
cursor.x += averageTabWidth / 4.0f;
|
||||
continue;
|
||||
}
|
||||
auto key = hashGlyphSettings( c, metadata );
|
||||
auto& glyph = glyphs.cache[font][key];
|
||||
::GlyphBox g;
|
||||
|
||||
g.box.w = glyph.getSize().x;
|
||||
g.box.h = glyph.getSize().y;
|
||||
|
||||
g.box.x = stat.cursor.x + glyph.getBearing().x;
|
||||
g.box.y = stat.cursor.y - glyph.getBearing().y; // - (glyph.getSize().y - glyph.getBearing().y);
|
||||
// retrieve glyph
|
||||
auto key = hashGlyphSettings(c, metadata);
|
||||
auto& glyph = glyphsCache[key];
|
||||
auto& g = layout.emplace_back(GlyphBox{
|
||||
.box = {
|
||||
.x = cursor.x + glyph.getBearing().x,
|
||||
.y = cursor.y - glyph.getBearing().y,
|
||||
.w = glyph.getSize().x,
|
||||
.h = glyph.getSize().y,
|
||||
},
|
||||
.color = token.color,
|
||||
.code = c,
|
||||
});
|
||||
|
||||
stat.cursor.x += (glyph.getAdvance().x);
|
||||
|
||||
// advance cursor
|
||||
cursor.x += glyph.getAdvance().x;
|
||||
|
||||
// advance bounding box
|
||||
maxTextWidth = std::max(maxTextWidth, g.box.x + g.box.w);
|
||||
maxTextHeight = std::max(maxTextHeight, g.box.y + g.box.h);
|
||||
}
|
||||
|
||||
stat.origin.x = transform.position.x * ::defaults.size.x; // ( !metadataGui.world && transform.position.x != (int) transform.position.x ) ? transform.position.x * ::defaults.size.x : transform.position.x;
|
||||
stat.origin.y = transform.position.y * ::defaults.size.y; // ( !metadataGui.world && transform.position.y != (int) transform.position.y ) ? transform.position.y * ::defaults.size.y : transform.position.y;
|
||||
|
||||
if ( origin == "top" ) stat.origin.y = ::defaults.size.y - stat.origin.y - stat.biggest.y;// else stat.origin.y = stat.origin.y;
|
||||
if ( align == "right" ) stat.origin.x = ::defaults.size.x - stat.origin.x - stat.box.w;// else stat.origin.x = stat.origin.x;
|
||||
else if ( align == "center" )
|
||||
stat.origin.x -= stat.box.w * 0.5f;
|
||||
}
|
||||
|
||||
// Render Glyphs
|
||||
stat.cursor.x = 0;
|
||||
stat.cursor.y = stat.biggest.y;
|
||||
for ( auto it = str.begin(); it != str.end(); ++it ) {
|
||||
uint64_t c = *it; if ( c == '\n' ) {
|
||||
if ( direction == "down" ) stat.cursor.y += stat.biggest.y; else stat.cursor.y -= stat.biggest.y;
|
||||
stat.cursor.x = 0;
|
||||
continue;
|
||||
} else if ( c == '\t' ) {
|
||||
// Fixed movement vs Real Tabbing
|
||||
if ( false ) {
|
||||
stat.cursor.x += stat.average.tab;
|
||||
} else {
|
||||
stat.cursor.x = ((stat.cursor.x / stat.average.tab) + 1) * stat.average.tab;
|
||||
}
|
||||
continue;
|
||||
} else if ( c == ' ' ) {
|
||||
stat.cursor.x += stat.average.tab / 4.0f;
|
||||
continue;
|
||||
} else if ( c == COLOR_CTRL ) {
|
||||
++stat.colors.index;
|
||||
continue;
|
||||
}
|
||||
auto key = hashGlyphSettings( c, metadata );
|
||||
auto& glyph = glyphs.cache[font][key];
|
||||
// calculate offset based on anchor
|
||||
float offsetX = maxTextWidth * anchor.x;
|
||||
float offsetY = maxTextHeight * anchor.y;
|
||||
|
||||
::GlyphBox g;
|
||||
g.code = c;
|
||||
|
||||
g.box.w = glyph.getSize().x;
|
||||
g.box.h = glyph.getSize().y;
|
||||
|
||||
g.box.x = stat.cursor.x + (glyph.getBearing().x);
|
||||
g.box.y = stat.cursor.y - glyph.getBearing().y; // - (glyph.getSize().y - glyph.getBearing().y);
|
||||
|
||||
stat.cursor.x += (glyph.getAdvance().x);
|
||||
|
||||
if ( stat.colors.index < stat.colors.container.size() ) {
|
||||
g.color = stat.colors.container.at(stat.colors.index);
|
||||
} else {
|
||||
g.color = metadataGui.color;
|
||||
}
|
||||
// adjust all glyphs for our offset
|
||||
for ( auto& g : layout ) {
|
||||
g.box.x -= offsetX;
|
||||
g.box.y -= offsetY;
|
||||
|
||||
// normalize
|
||||
g.box.x /= ::defaults.size.x;
|
||||
g.box.w /= ::defaults.size.x;
|
||||
g.box.y /= ::defaults.size.y;
|
||||
g.box.h /= ::defaults.size.y;
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
gs.push_back(g);
|
||||
// generate the mesh and texture atlas
|
||||
void generateAtlasAndMesh( const uf::stl::vector<GlyphBox>& layout, const ext::GuiGlyphBehavior::Metadata& metadata, const uf::stl::string& font, uf::Atlas& atlas, uf::Mesh& mesh ) {
|
||||
auto& glyphs_cache = ::glyphs.cache[font];
|
||||
uf::stl::unordered_map<size_t, uf::stl::string> glyph_atlas_map;
|
||||
|
||||
#if UF_USE_FREETYPE
|
||||
// generate atlas
|
||||
{
|
||||
atlas.clear();
|
||||
|
||||
// generate atlas
|
||||
for ( const auto& g : layout ) {
|
||||
auto key = hashGlyphSettings(g.code, metadata);
|
||||
auto& glyph = glyphs_cache[key];
|
||||
|
||||
// already in atlas map
|
||||
if ( glyph_atlas_map.find(key) != glyph_atlas_map.end() ) continue;
|
||||
|
||||
const uint8_t* buffer = glyph.getBuffer();
|
||||
uf::Image::container_t pixels;
|
||||
size_t len = glyph.getSize().x * glyph.getSize().y;
|
||||
|
||||
if ( metadata.sdf ) {
|
||||
glyph_atlas_map[key] = atlas.addImage(glyph.getBuffer(), glyph.getSize(), 8, 1, true);
|
||||
} else {
|
||||
pixels.reserve(len * 4);
|
||||
for ( size_t i = 0; i < len; ++i ) {
|
||||
pixels.emplace_back(buffer[i]); // R
|
||||
pixels.emplace_back(buffer[i]); // G
|
||||
pixels.emplace_back(buffer[i]); // B
|
||||
pixels.emplace_back(buffer[i]); // A
|
||||
}
|
||||
glyph_atlas_map[key] = atlas.addImage(&pixels[0], glyph.getSize(), 8, 4, true);
|
||||
}
|
||||
}
|
||||
|
||||
atlas.generate();
|
||||
atlas.clear(false);
|
||||
}
|
||||
#endif
|
||||
// generate mesh
|
||||
{
|
||||
mesh.destroy();
|
||||
mesh.bind<::Mesh, uint16_t>();
|
||||
|
||||
return gs;
|
||||
uf::stl::vector<::Mesh> vertices;
|
||||
uf::stl::vector<uint16_t> indices;
|
||||
vertices.reserve(layout.size() * 4);
|
||||
indices.reserve(layout.size() * 6);
|
||||
|
||||
for ( const auto& g : layout ) {
|
||||
auto key = hashGlyphSettings(g.code, metadata);
|
||||
auto hash = glyph_atlas_map[key];
|
||||
|
||||
#if EXT_COLOR_FLOATS
|
||||
auto& color = g.color;
|
||||
#else
|
||||
pod::ColorRgba color = {
|
||||
(uint8_t)(g.color[0] * 255),
|
||||
(uint8_t)(g.color[1] * 255),
|
||||
(uint8_t)(g.color[2] * 255),
|
||||
(uint8_t)(g.color[3] * 255)
|
||||
};
|
||||
#endif
|
||||
// insert indices
|
||||
uint16_t idx = (uint16_t) vertices.size();
|
||||
indices.insert( indices.end(), { idx, idx + 1, idx + 2, idx, idx + 2, idx + 3 });
|
||||
|
||||
// insert vertices
|
||||
vertices.emplace_back(::Mesh{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color});
|
||||
vertices.emplace_back(::Mesh{pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color});
|
||||
vertices.emplace_back(::Mesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color});
|
||||
vertices.emplace_back(::Mesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color});
|
||||
}
|
||||
|
||||
mesh.insertVertices(vertices);
|
||||
mesh.insertIndices(indices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,29 +378,14 @@ void ext::GuiGlyphBehavior::initialize( uf::Object& self ) {
|
||||
auto& metadataGui = this->getComponent<ext::GuiBehavior::Metadata>();
|
||||
auto& metadataJson = this->getComponent<uf::Serializer>();
|
||||
|
||||
/*
|
||||
if ( ext::json::isNull( ::defaults.settings["metadata"] ) ) ::defaults.settings.readFromFile(uf::io::root+"/entities/gui/text/string.json");
|
||||
// set defaults
|
||||
if ( metadataJson["string"].is<uf::stl::string>() ) {
|
||||
auto copyMetadataJson = metadataJson;
|
||||
ext::json::forEach(::defaults.settings["metadata"], [&]( const uf::stl::string& key, ext::json::Value& value ){
|
||||
if ( ext::json::isNull( copyMetadataJson[key] ) ) {
|
||||
metadataJson[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
// if ( metadataJson["scaling"] == "auto" ) metadataJson["scaling"] = "none";
|
||||
|
||||
this->addHook( "gui:UpdateText.%UID%", [&](ext::json::Value& payload){
|
||||
auto string = payload["string"].as(metadata.string);
|
||||
auto font = uf::io::root+"/fonts/" + payload["font"].as(metadata.font);
|
||||
bool forced = payload["force"].as(false);
|
||||
|
||||
metadata.sdf = false;
|
||||
|
||||
auto glyphs = ::generateGlyphs( self, string );
|
||||
// override
|
||||
// metadata.sdf = false;
|
||||
metadataGui.scaling = "none";
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& mesh = this->getComponent<uf::Mesh>();
|
||||
@ -368,110 +395,12 @@ void ext::GuiGlyphBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
uf::stl::unordered_map<size_t, uf::stl::string> glyph_atlas_map;
|
||||
|
||||
metadataGui.scaleMode = "none";
|
||||
|
||||
// generate texture
|
||||
#if UF_USE_FREETYPE
|
||||
{
|
||||
atlas.clear();
|
||||
|
||||
for ( auto& g : glyphs ) {
|
||||
auto key = ::hashGlyphSettings( g.code, metadata );
|
||||
auto& glyph = glyphs_cache[font][key];
|
||||
|
||||
const uint8_t* buffer = glyph.getBuffer();
|
||||
uf::Image::container_t pixels;
|
||||
size_t len = glyph.getSize().x * glyph.getSize().y;
|
||||
|
||||
if ( metadata.sdf ) {
|
||||
glyph_atlas_map[key] = atlas.addImage( glyph.getBuffer(), glyph.getSize(), 8, 1, true );
|
||||
} else {
|
||||
pixels.reserve( len * 4 );
|
||||
for ( size_t i = 0; i < len; ++i ) {
|
||||
pixels.emplace_back( buffer[i] );
|
||||
pixels.emplace_back( buffer[i] );
|
||||
pixels.emplace_back( buffer[i] );
|
||||
pixels.emplace_back( buffer[i] );
|
||||
// pixels.emplace_back( buffer[i] > 127 ? 255 : 0 );
|
||||
}
|
||||
glyph_atlas_map[key] = atlas.addImage( &pixels[0], glyph.getSize(), 8, 4, true );
|
||||
#if 0
|
||||
pixels.reserve( len * 2 );
|
||||
for ( size_t i = 0; i < len; ++i ) {
|
||||
pixels.emplace_back( buffer[i] );
|
||||
pixels.emplace_back( buffer[i] );
|
||||
// pixels.emplace_back( buffer[i] > 127 ? 255 : 0 );
|
||||
}
|
||||
glyph_atlas_map[key] = atlas.addImage( &pixels[0], glyph.getSize(), 8, 2, true );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
atlas.generate();
|
||||
atlas.clear(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// generate mesh
|
||||
{
|
||||
mesh.destroy();
|
||||
mesh.bind<::Mesh, uint16_t>();
|
||||
|
||||
uf::stl::vector<::Mesh> vertices; vertices.reserve( glyphs.size() * 6 );
|
||||
uf::stl::vector<uint16_t> indices; indices.reserve( glyphs.size() * 6 );
|
||||
|
||||
|
||||
// pod::Vector2f min = { 0, 0 };
|
||||
// pod::Vector2f max = { 0, 0 };
|
||||
|
||||
for ( auto& g : glyphs ) {
|
||||
auto key = ::hashGlyphSettings( g.code, metadata );
|
||||
auto& glyph = glyphs_cache[font][key];
|
||||
auto hash = glyph_atlas_map[key];
|
||||
|
||||
#if EXT_COLOR_FLOATS
|
||||
auto& color = g.color;
|
||||
#else
|
||||
pod::ColorRgba color = { g.color[0] * 255, g.color[1] * 255, g.color[2] * 255, g.color[3] * 255 };
|
||||
#endif
|
||||
// add vertices
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
vertices.emplace_back( ::Mesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() );
|
||||
}
|
||||
|
||||
/*
|
||||
pod::Vector2f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
|
||||
pod::Vector2f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
|
||||
|
||||
for ( auto& vertex : vertices ) {
|
||||
min.x = std::min( min.x, vertex.position.x * ::defaults.size.x * transform.scale.x );
|
||||
min.y = std::min( min.y, vertex.position.y * ::defaults.size.y * transform.scale.y );
|
||||
max.x = std::max( max.x, vertex.position.x * ::defaults.size.x * transform.scale.x );
|
||||
max.y = std::max( max.y, vertex.position.y * ::defaults.size.y * transform.scale.y );
|
||||
|
||||
#if UF_USE_OPENGL
|
||||
vertex.position.y = -vertex.position.y;
|
||||
#endif
|
||||
}
|
||||
|
||||
metadataGui.size = {
|
||||
max.x - min.x,
|
||||
max.y - min.y,
|
||||
};
|
||||
*/
|
||||
|
||||
mesh.insertVertices( vertices );
|
||||
mesh.insertIndices( indices );
|
||||
|
||||
// mesh.resizeVertices( metadata.reserve * 6 );
|
||||
// mesh.resizeIndices( metadata.reserve * 6 );
|
||||
}
|
||||
|
||||
auto tokens = ::parseTextTokens(string, metadataGui.color);
|
||||
auto layout = ::calculateGlyphLayout(self, tokens, metadata, metadataGui, font);
|
||||
::generateAtlasAndMesh( layout, metadata, font, atlas, mesh );
|
||||
|
||||
// set proper shaders
|
||||
if ( metadata.sdf ) {
|
||||
metadataJson["shaders"]["vertex"] = uf::io::root+"/shaders/gui/text/vert.spv";
|
||||
metadataJson["shaders"]["fragment"] = uf::io::root+"/shaders/gui/text/frag.spv";
|
||||
@ -518,22 +447,19 @@ void ext::GuiGlyphBehavior::tick( uf::Object& self ) {
|
||||
/*alignas(4)*/ int32_t spread;
|
||||
/*alignas(4)*/ float weight;
|
||||
|
||||
/*alignas(4)*/ float fillWeight;
|
||||
/*alignas(4)*/ float scale;
|
||||
/*alignas(4)*/ float padding1;
|
||||
/*alignas(4)*/ float padding2;
|
||||
/*alignas(4)*/ float padding3;
|
||||
} ubo = {
|
||||
.stroke = metadata.shader.stroke,
|
||||
.range = metadata.shader.range,
|
||||
|
||||
.spread = metadata.spread,
|
||||
.weight = metadata.shader.weight,
|
||||
.fillWeight = metadata.shader.fillWeight,
|
||||
.scale = metadata.shader.scale,
|
||||
};
|
||||
|
||||
// if ( metadataGlyph.sdf ) uniforms.gui.mode &= 1 << 1;
|
||||
// if ( metadataGlyph.shadowbox ) uniforms.gui.mode &= 1 << 2;
|
||||
|
||||
};
|
||||
|
||||
shader.updateBuffer( (const void*) &ubo, sizeof(ubo), uniformBuffer );
|
||||
}
|
||||
@ -554,6 +480,7 @@ void ext::GuiGlyphBehavior::Metadata::serialize( uf::Object& self, uf::Serialize
|
||||
|
||||
serializer["scale"] = /*this->*/shader.scale;
|
||||
serializer["weight"] = /*this->*/shader.weight;
|
||||
serializer["fillWeight"] = /*this->*/shader.fillWeight;
|
||||
serializer["stroke"] = uf::vector::encode( /*this->*/shader.stroke);
|
||||
serializer["range"] = uf::vector::encode( /*this->*/shader.range);
|
||||
}
|
||||
@ -568,6 +495,7 @@ void ext::GuiGlyphBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
|
||||
|
||||
/*this->*/shader.scale = serializer["scale"].as(/*this->*/shader.scale);
|
||||
/*this->*/shader.weight = serializer["weight"].as(/*this->*/shader.weight);
|
||||
/*this->*/shader.fillWeight = serializer["fillWeight"].as(/*this->*/shader.fillWeight);
|
||||
/*this->*/shader.stroke = uf::vector::decode(serializer["stroke"], /*this->*/shader.stroke);
|
||||
/*this->*/shader.range = uf::vector::decode(serializer["range"], /*this->*/shader.range);
|
||||
|
||||
|
||||
@ -16,15 +16,16 @@ namespace ext {
|
||||
|
||||
bool sdf = true;
|
||||
float size = 96;
|
||||
float spread = 2;
|
||||
float spread = 8;
|
||||
|
||||
pod::Vector2ui padding = { 2, 2 };
|
||||
pod::Vector2ui padding = { 8, 8 };
|
||||
|
||||
size_t reserve = 128;
|
||||
|
||||
struct {
|
||||
float scale = 1.5;
|
||||
float weight = 0.45;
|
||||
float fillWeight = 0.5;
|
||||
pod::Vector4f stroke = { 0, 0, 0, 1 };
|
||||
pod::Vector2i range = { -1, -1 };
|
||||
} shader;
|
||||
|
||||
@ -535,6 +535,7 @@ namespace {
|
||||
}
|
||||
|
||||
void bindInstanceAddresses( uf::renderer::Graphic& graphic, uf::Mesh& mesh, uf::stl::vector<pod::Instance::Addresses>& addresses ) {
|
||||
#if UF_USE_VULKAN
|
||||
if ( !uf::renderer::settings::invariant::deviceAddressing || !mesh.indirect.count ) return;
|
||||
addresses.resize( mesh.indirect.count );
|
||||
|
||||
@ -574,6 +575,7 @@ namespace {
|
||||
instanceAddresses.drawID = drawID;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1576,6 +1578,7 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) {
|
||||
if ( !soft ) {
|
||||
storage.buffers.camera.destroy(true);
|
||||
storage.buffers.drawCommands.destroy(true);
|
||||
storage.buffers.lodMetadata.destroy(true);
|
||||
storage.buffers.instance.destroy(true);
|
||||
storage.buffers.instanceAddresses.destroy(true);
|
||||
storage.buffers.joint.destroy(true);
|
||||
@ -1583,6 +1586,7 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) {
|
||||
storage.buffers.material.destroy(true);
|
||||
storage.buffers.texture.destroy(true);
|
||||
storage.buffers.light.destroy(true);
|
||||
storage.buffers.depthPyramid.destroy(true);
|
||||
}
|
||||
|
||||
uf::renderer::states::rebuild = true;
|
||||
@ -1777,6 +1781,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
drawCommands[drawID].vertexID = 0;
|
||||
} else {
|
||||
drawCommands[drawID] = primitives[drawID].drawCommand;
|
||||
// to-do: LOD pick here for OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,22 +62,8 @@ for ( auto& p : m.primitives ) {
|
||||
|
||||
if ( attribute.name == "POSITION" ) {
|
||||
meshlet.vertices.resize(accessor.count);
|
||||
if ( !graph.metadata["renderer"]["invert"].as<bool>(true) ){
|
||||
meshlet.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
|
||||
meshlet.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
|
||||
} else {
|
||||
meshlet.primitive.instance.bounds.min = pod::Vector3f{ std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
|
||||
meshlet.primitive.instance.bounds.max = pod::Vector3f{ -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
|
||||
}
|
||||
/*
|
||||
meshlet.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
|
||||
meshlet.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
|
||||
|
||||
if ( graph.metadata["renderer"]["invert"].as<bool>(true) ){
|
||||
meshlet.primitive.instance.bounds.min.x = -meshlet.primitive.instance.bounds.min.x;
|
||||
meshlet.primitive.instance.bounds.max.x = -meshlet.primitive.instance.bounds.max.x;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
switch ( accessor.componentType ) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include <uf/ext/meshopt/meshopt.h>
|
||||
#if UF_USE_MESHOPT
|
||||
#include <meshoptimizer.h>
|
||||
#include <cfloat>
|
||||
|
||||
bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o, bool verbose ) {
|
||||
if ( mesh.isInterleaved() ) {
|
||||
@ -53,7 +54,7 @@ bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o, bool verb
|
||||
if ( 0.0f < simplify && simplify < 1.0f ) {
|
||||
uf::stl::vector<uint32_t> indicesSimplified(indicesCount);
|
||||
|
||||
float targetError = 0.1; // 1e-2f / simplify;
|
||||
float targetError = FLT_MAX; // 1e-2f / simplify;
|
||||
float realError = 0.0f;
|
||||
|
||||
size_t realIndices = meshopt_simplify(
|
||||
@ -64,8 +65,8 @@ bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o, bool verb
|
||||
mesh.vertex.count,
|
||||
positionsView.stride(),
|
||||
indicesCount * simplify,
|
||||
targetError
|
||||
//,0, &realError
|
||||
targetError,
|
||||
0, &realError
|
||||
);
|
||||
|
||||
if ( verbose ) {
|
||||
@ -156,24 +157,26 @@ uf::stl::vector<pod::LODMetadata> ext::meshopt::generateLODs( uf::Mesh& mesh, co
|
||||
|
||||
meshopt_optimizeVertexCache(&baseIndices[0], &baseIndices[0], baseIndicesCount, mesh.vertex.count);
|
||||
|
||||
size_t previousIndicesCount = baseIndicesCount;
|
||||
for ( size_t lodIdx = 0; lodIdx < numLODs; ++lodIdx ) {
|
||||
float simplify = lodFactors[lodIdx];
|
||||
uf::stl::vector<uint32_t> lodIndices = baseIndices;
|
||||
size_t currentIndicesCount = baseIndicesCount;
|
||||
|
||||
if ( simplify < 1.0f ) {
|
||||
float targetError = 0.1; // 1e-2f / simplify;
|
||||
float targetError = FLT_MAX; // 1e-2f / simplify;
|
||||
float realError = 0.0f;
|
||||
currentIndicesCount = meshopt_simplify(
|
||||
&lodIndices[0], &baseIndices[0], baseIndicesCount,
|
||||
(const float*)positionsView.data(0), mesh.vertex.count, positionsView.stride(),
|
||||
baseIndicesCount * simplify, targetError
|
||||
//, 0, &realError
|
||||
baseIndicesCount * simplify, targetError,
|
||||
0, &realError
|
||||
);
|
||||
|
||||
if ( baseIndicesCount == currentIndicesCount ) {
|
||||
if ( previousIndicesCount == currentIndicesCount ) {
|
||||
continue;
|
||||
}
|
||||
previousIndicesCount = currentIndicesCount;
|
||||
|
||||
if ( verbose ) {
|
||||
UF_MSG_DEBUG("[View {} Simplified LOD {}] indices: {} -> {} | error: {} -> {}", viewIdx, lodIdx, baseIndicesCount, currentIndicesCount, targetError, realError);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user