Commit for 2021.07.27 22-27-21.7z

This commit is contained in:
mrq 2021-07-27 22:27:00 -05:00
parent ff15e641eb
commit 60cb5bd236
66 changed files with 1192 additions and 1365 deletions

View File

@ -3,6 +3,7 @@ CC = $(shell cat "./bin/exe/default.config")
TARGET_NAME = program
TARGET_EXTENSION = exe
TARGET_LIB_EXTENSION = dll
RENDERER = vulkan
include makefiles/$(ARCH).$(CC).make
@ -44,11 +45,11 @@ LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS)
DEPS +=
ifneq (,$(findstring win64,$(ARCH)))
REQ_DEPS += vulkan json:nlohmann png zlib openal ogg freetype ncurses curl luajit bullet meshoptimizer xatlas simd ctti # openvr draco discord
REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype ncurses curl luajit bullet meshoptimizer xatlas simd ctti # openvr draco discord
FLAGS +=
DEPS += -lgdi32
else ifneq (,$(findstring dreamcast,$(ARCH)))
REQ_DEPS += opengl gldc json:nlohmann bullet lua freetype png zlib ctti # ogg openal meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord
REQ_DEPS += opengl gldc json:nlohmann bullet lua freetype png zlib ctti ogg openal aldc # ogg openal meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord
endif
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
FLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN
@ -82,12 +83,16 @@ ifneq (,$(findstring png,$(REQ_DEPS)))
DEPS += -lpng -lz
endif
ifneq (,$(findstring openal,$(REQ_DEPS)))
FLAGS += -DUF_USE_OPENAL
FLAGS += -DUF_USE_OPENAL -DUF_USE_ALUT
ifneq (,$(findstring dreamcast,$(ARCH)))
DEPS += -lAL
ifneq (,$(findstring aldc,$(REQ_DEPS)))
DEPS += -lALdc
FLAGS += -DUF_USE_OPENGL_ALDC
else
DEPS += -lAL
endif
else
FLAGS += -DUF_USE_ALUT
DEPS += -lopenal -lalut
DEPS += -lopenal -lalut
endif
endif
ifneq (,$(findstring ogg,$(REQ_DEPS)))

View File

@ -1,7 +1,7 @@
{
"engine": {
"scenes": {
"start": "SH2_McDonalds",
"start": "SS2",
"meshes": {
"interleave": false
},
@ -28,10 +28,10 @@
},
"vxgi": {
"limiter": 0.125,
"size": 64,
"size": 128,
"dispatch": 8,
"cascades": 6,
"cascadePower": 2,
"cascades": 3,
"cascadePower": 3,
"shadows": 0,
"granularity": 4,
"extents": {
@ -80,7 +80,7 @@
"vsync": true,
"hdr": false,
"vxgi": true,
"deferred sampling": true,
"deferred sampling": false,
"culling": true,
"bloom": true
},
@ -152,6 +152,7 @@
}
},
"lua": {
"enabled": true,
"main": "/main.lua",
"modules": {
"json": "/json.lua"
@ -193,6 +194,11 @@
"size": 32768,
"count": 4
},
"volumes": {
"sfx": 0.25,
"bgm": 0.15,
"voice": 1.0
},
"streams by default": true
},
"memory pool": {
@ -252,10 +258,10 @@
},
"mode" : "windowed", // fullscreen, borderless, windowed
"icon" : "./data/textures/icon.png",
// "size" : [ 1920, 1080 ],
"size" : [ 1920, 1080 ],
// "size" : [ 1280, 720 ],
// "size" : [ 960, 540 ],
"size" : [ 640, 480 ],
// "size" : [ 640, 480 ],
"title" : "Grimgram",
"visible" : true
}

View File

@ -24,11 +24,11 @@
"gravity": [ 0, -9.81, 0 ],
"inertia": [ 10, 10, 10 ],
"walk": 1,
"move": 4,
"run": 8,
"rotate": 1.25,
"move": 8,
"run": 12,
"rotate": 2,
"crouch": 1,
"jump": [ 0, 4, 0 ],
"jump": [ 0, 6, 0 ],
"type": "Capsule",
"radius": 1,
@ -62,8 +62,8 @@
"footstep": {
"volume": 0.5,
"list": [
"./data/audio/footstep/1.ogg",
"./data/audio/footstep/2.ogg"
"/footstep/1.ogg",
"/footstep/2.ogg"
]
}
},

View File

@ -12,6 +12,7 @@
],
"transform": {
"position": [ 0, -2.0, 0 ],
// "position": [ 12.5715, 3.53811, 7.6238 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0

View File

@ -25,11 +25,6 @@
"menus": {
"pause": "/gui/pause/menu.json"
},
"volumes": {
"sfx": 0.25,
"bgm": 0.15,
"voice": 1.0
},
"light": {
"exposure": 1.0,
"gamma": 1.0,

View File

@ -5,9 +5,9 @@
"assets": [
// { "filename": "./static.json", "delay": 8 },
{ "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"behaviors": [
"LoadingBehavior"
@ -54,10 +54,9 @@
"SEPARATE": false,
"NORMALS": false
},
"lightmap": "",
// "lightmap": "./lightmap.png",
"lightmap": "./lightmap.png",
// "cull mode": "none",
// "filter": "NEAREST",
"filter": "NEAREST",
"lights": {
"shadows": true
},

View File

@ -24,11 +24,6 @@
"menus": {
"pause": "/gui/pause/menu.json"
},
"volumes": {
"sfx": 0.25,
"bgm": 0.75,
"voice": 1.0
},
"bloom": {
"scale": 1.0,
"strength": 0.5,

View File

@ -24,11 +24,6 @@
"menus": {
"pause": "/gui/pause/menu.json"
},
"volumes": {
"sfx": 0.25,
"bgm": 0.75,
"voice": 1.0
},
"bloom": {
"scale": 1.0,
"strength": 0.5,

View File

@ -5,9 +5,9 @@
"assets": [
// { "filename": "./models/micro_sci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/micro_sci/graph.json", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/msci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/msci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/msci/graph.json", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
@ -58,7 +58,7 @@
},
*/
// "lightmap": "./lightmap.min.png",
"lightmap": "./lightmap.png",
// "lightmap": "./lightmap.png",
"filter": "NEAREST",
"flags": {
"ATLAS": false,

View File

@ -2,7 +2,6 @@
"import": "/scene.json",
"assets": [
{ "filename": "./audio/music/medsci1.ogg", "category": "audio-stream", "override": true, "streamed": true },
// "./audio/music/medsci1.ogg",
"./loading.json"
],
"system": {
@ -21,17 +20,9 @@
}
},
"metadata": {
"debug": {
"target": 0
},
"menus": {
"pause": "/gui/pause/menu.json"
},
"volumes": {
"sfx": 0.25,
"bgm": 0.15,
"voice": 1.0
},
"bloom": {
"scale": 1.0,
"strength": 0.125,

View File

@ -0,0 +1,27 @@
float shadowFactor( const Light light, float def );
void lambert() {
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( -surface.position.world );
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
for ( uint i = 0; i < lights.length(); ++i ) {
const Light light = lights[i];
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lp = light.position;
// const vec3 Liu = light.position - surface.position.world;
const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye;
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
const float Ls = shadowFactor( light, 0.0 );
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Li = normalize(Liu);
const vec3 Lr = light.color.rgb * light.power * La * Ls;
// const float cosLi = abs(dot(surface.normal.world, Li));
const float cosLi = max(0.0, dot(surface.normal.eye, Li));
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
}
}

View File

@ -13,7 +13,10 @@ float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
}
vec3 fresnelSchlick(vec3 F0, float cosTheta) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); }
#if !BAKING
void pbr() {
if ( validTextureIndex( surface.material.lightmapID ) ) return;
const float Rs = 4.0; // specular lighting looks gross without this
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( -surface.position.eye );
@ -31,10 +34,6 @@ void pbr() {
const float cosLi = max(0.0, dot(surface.normal.eye, Li));
const vec3 Lr = light.color.rgb * light.power * La * Ls;
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
const float cosLh = max(0.0, dot(surface.normal.eye, Lh));
@ -43,7 +42,6 @@ void pbr() {
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
// lightmapped, compute only specular
if ( light.type >= 0 && validTextureIndex( surface.material.lightmapID ) ) surface.fragment.rgb += (specular) * Lr * cosLi;
// point light, compute only diffuse
@ -51,4 +49,5 @@ void pbr() {
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
}
}
}
#endif

View File

@ -11,12 +11,16 @@ layout (binding = 5) uniform samplerCube samplerCubemaps[CUBEMAPS];
#define SHADOW_SAMPLES 16
#define PBR 0
#define LAMBERT 1
#define BAKING 1
#define PBR 1
#define LAMBERT 0
#include "../../common/macros.h"
#include "../../common/structs.h"
#include "../../common/functions.h"
#include "../../common/shadows.h"
#if PBR
#include "../../common/pbr.h"
#endif
layout (std140, binding = 6) readonly buffer Instances {
Instance instances[];
@ -60,13 +64,16 @@ void main() {
surface.fragment = material.colorEmissive;
surface.material.albedo = vec4(1);
{
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( -surface.position.world );
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
for ( uint i = 0; i < lights.length(); ++i ) {
const Light light = lights[i];
const mat4 mat = light.view; // inverse(light.view);
const vec3 position = surface.position.world;
// const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) );
const vec3 normal = surface.normal.world;
// const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) );
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lp = light.position;
const vec3 Liu = light.position - surface.position.world;
@ -74,18 +81,23 @@ void main() {
const float Ls = shadowFactor( light, 0.0 );
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lo = normalize( -position );
const float cosLo = max(0.0, dot(normal, Lo));
const vec3 Li = normalize(Liu);
const vec3 Lr = light.color.rgb * light.power * La * Ls;
const float cosLi = abs(dot(surface.normal.world, Li));// max(0.0, dot(N, Li));
// const float cosLi = max(0.0, dot(normal, Li));
const float cosLi = abs(dot(normal, Li));
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
const float cosLh = max(0.0, dot(N, Lh));
// const float cosLh = max(0.0, dot(normal, Lh));
const float cosLh = abs(dot(normal, Lh));
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
const float D = ndfGGX( cosLh, surface.material.roughness );
const float D = 1; // ndfGGX( cosLh, surface.material.roughness );
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
@ -98,8 +110,8 @@ void main() {
#define EXPOSURE 1
#define GAMMA 1
surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * EXPOSURE);
surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / GAMMA));
// surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * EXPOSURE);
// surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / GAMMA));
outAlbedo = vec4(surface.fragment.rgb, 1);
}

View File

@ -4,82 +4,5 @@
#define INSTANCED 1
#define SKINNED 0
#define BAKING 1
#if 1
#include "../base.vert.h"
#else
#extension GL_ARB_shader_draw_parameters : enable
#include "../../common/structs.h"
layout (constant_id = 0) const uint PASSES = 6;
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec2 inSt;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in vec4 inTangent;
#if SKINNED
layout (location = 5) in uvec4 inJoints;
layout (location = 6) in vec4 inWeights;
#endif
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
/*
layout (std140, binding = 0) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
*/
layout (std140, binding = 1) readonly buffer Instances {
Instance instances[];
};
#if SKINNED
layout (std140, binding = 2) readonly buffer Joints {
mat4 joints[];
};
#endif
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec2 outSt;
layout (location = 2) out vec4 outColor;
layout (location = 3) out vec3 outNormal;
layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) flat out uvec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outSt = inSt;
#if SKINNED
const mat4 skinned = joints.length() <= 0 ? mat4(1.0) : inWeights.x * joints[int(inJoints.x)] + inWeights.y * joints[int(inJoints.y)] + inWeights.z * joints[int(inJoints.z)] + inWeights.w * joints[int(inJoints.w)];
#else
const mat4 skinned = mat4(1.0);
#endif
const uint drawID = gl_DrawIDARB;
// const DrawCommand drawCommand = drawCommands[drawID];
const uint instanceID = gl_InstanceIndex;
const Instance instance = instances[instanceID];
const uint materialID = instance.materialID;
const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned);
outId = ivec4(drawID, instanceID, materialID, PushConstant.pass);
outColor = instance.color;
outPosition = vec3(model * vec4(inPos.xyz, 1.0));
outNormal = vec3(model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);
vec3 T = vec3(model * vec4(inTangent.xyz, 0.0));
vec3 N = outNormal;
vec3 B = cross(N, T) * inTangent.w;
outTBN = mat3( T, B, N );
gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0);
}
#endif

View File

@ -83,7 +83,7 @@ void main() {
const Texture t = textures[instance.lightmapID];
const float gamma = LIGHTMAP_GAMMA;
const vec4 L = pow(textureLod( samplerTextures[nonuniformEXT(t.index)], inSt, mip ), vec4(1.0 / gamma));
A *= L;
A.rgb *= L.rgb;
#endif
}
#endif

View File

@ -3,13 +3,14 @@ layout (constant_id = 0) const uint PASSES = 6;
#include "../common/structs.h"
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec2 inSt;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in vec4 inTangent;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec2 inUv;
layout (location = 3) in vec2 inSt;
layout (location = 4) in vec3 inNormal;
layout (location = 5) in vec4 inTangent;
#if SKINNED
layout (location = 5) in uvec4 inJoints;
layout (location = 6) in vec4 inWeights;
layout (location = 6) in uvec4 inJoints;
layout (location = 7) in vec4 inWeights;
#endif
layout( push_constant ) uniform PushBlock {

View File

@ -32,20 +32,6 @@ struct Frustum {
vec4 planes[6];
};
float inside( vec3 v, vec3 min, vec3 max ) {
vec3 s = step(min, v) - step(max, v);
return s.x * s.y * s.z;
}
/*
T f = 1 / tan( fov / 2 );
return pod::Matrix4t<T>({
f / raidou, 0, 0, 0,
0, -f, 0, 0,
0, 0, 0, 1,
0, 0, znear, 0
});
*/
vec4 normalizePlane( vec4 p ) {
return p / length(p.xyz);
}
@ -59,8 +45,8 @@ bool frustumCull( uint id ) {
bool visible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
// return if our camera position is inside the AABB
vec3 camPos = vec3( inverse(camera.viewport[pass].view)[3] );
if ( instance.bounds.min.x <= camPos.x && camPos.x <= instance.bounds.max.x && instance.bounds.min.y <= camPos.y && camPos.y <= instance.bounds.max.y && instance.bounds.min.z <= camPos.z && camPos.z <= instance.bounds.max.z ) return true;
// vec3 camPos = vec3( inverse(camera.viewport[pass].view)[3] );
// if ( instance.bounds.min.x <= camPos.x && camPos.x <= instance.bounds.max.x && instance.bounds.min.y <= camPos.y && camPos.y <= instance.bounds.max.y && instance.bounds.min.z <= camPos.z && camPos.z <= instance.bounds.max.z ) return true;
// sphere based one, source of this block uses reverse infinite Z, but would be nice if it used AABB
// doesn't work
#if 0

View File

@ -95,7 +95,7 @@ void main() {
Texture t = textures[instance.lightmapID];
const float gamma = LIGHTMAP_GAMMA;
const vec4 L = pow(textureLod( samplerTextures[nonuniformEXT(t.index)], inSt, mip ), vec4(1.0 / gamma));
A *= L;
A.rgb *= L.rgb;
#endif
}
#endif

View File

@ -21,11 +21,11 @@
},
"textures": {
"max": {
"2D": 256,
"cube": 16,
"2D": 192,
"cube": 8,
"3D": 1
}
},
}
},
"ext": {
"opengl": {
@ -45,11 +45,12 @@
"deferred mode": "",
"deferred reconstruct position": true,
"deferred alias output to swapchain": true,
"hdr": false
"hdr": false,
"culling": true
},
"formats": {
"depth": "D32_SFLOAT",
"color": "R8G8B8A8_UNORM", // "R32G32B32A32_SFLOAT",
"color": "R8G8B8A8_UNORM",
"normal": "R16G16B16A16_SFLOAT",
"position": "R16G16B16A16_SFLOAT"
},
@ -60,6 +61,7 @@
}
},
"lua": {
"enabled": false,
"main": "/main.lua",
"modules": {
"json": "/json.lua"
@ -83,17 +85,22 @@
"audio": {
"mute": false,
"buffers": {
"size": 32768,
"count": 4
"size": 16384,
"count": 2
},
"volumes": {
"sfx": 1.0,
"bgm": 1.0,
"voice": 1.0
},
"streams by default": true
},
"memory pool": {
"enabled": false,
"enabled": true,
"subPools": true,
"alignment": 32,
"override": true,
"size": "6 MiB",
"size": "8 MiB",
"pools": {
"entity": "96 KiB",
"userdata": "96 KiB",
@ -107,7 +114,7 @@
"multiview stereo deferred": false
},
"limiters": {
"deltaTime": 20,
"deltaTime": 5,
"framerate": "auto"
},
"threads": {
@ -143,7 +150,7 @@
"visible" : true,
"center" : false
},
"mode" : "windowed", // fullscreen, borderless, windowed
"mode" : "windowed",
"icon" : "./data/textures/icon.png",
"size" : [ 640, 480 ],
"title" : "Grimgram",

View File

@ -64,19 +64,6 @@ void client::initialize() {
client::window.setTitle(title);
#endif
}
#if UF_USE_OPENAL
/* Initialize OpenAL */ {
ext::al::initialize();
/*
if ( !ext::al::initialize() ) {
std::cerr << "[ERROR] AL failed to initialize!" << std::endl;
std::exit(EXIT_SUCCESS);
return;
}
*/
}
#endif
/* Initialize hooks */ {
uf::hooks.addHook( "window:Mouse.CursorVisibility", [&]( ext::json::Value& json ){
@ -179,15 +166,4 @@ void client::terminate() {
}
client::window.terminate();
#if UF_USE_OPENAL
ext::al::destroy();
/*
if ( !ext::al::destroy() ) {
std::cerr << "[ERROR] AL failed to terminate!" << std::endl;
std::exit(EXIT_SUCCESS);
return;
}
*/
#endif
}

View File

@ -85,8 +85,12 @@ int main(int argc, char** argv){
uf::hooks.call(hook, json);
}
#if UF_ENV_DREAMCAST
// UF_TIMER_MULTITRACE_START("Starting");
ext::render();
// UF_TIMER_MULTITRACE("render");
ext::tick();
// UF_TIMER_MULTITRACE("tick");
// UF_TIMER_MULTITRACE_END("Finished");
#else
client::tick();
client::render();
@ -96,14 +100,18 @@ int main(int argc, char** argv){
#if HANDLE_EXCEPTIONS
} catch ( std::runtime_error& e ) {
UF_MSG_ERROR("RUNTIME ERROR: " << e.what());
break;
abort();
} catch ( std::exception& e ) {
UF_MSG_ERROR("EXCEPTION ERROR: " << e.what());
throw e;
abort();
} catch ( bool handled ) {
if (!handled) UF_MSG_ERROR("UNHANDLED ERROR: " << "???");
if (!handled) {
UF_MSG_ERROR("UNHANDLED ERROR: " << "???");
abort();
}
} catch ( ... ) {
UF_MSG_ERROR("UNKNOWN ERROR: " << "???");
abort();
}
#endif
}

View File

@ -1,40 +1,27 @@
namespace uf {
namespace graph {
namespace mesh {
typedef uint16_t id_t;
struct Base {
pod::Vector3f position;
pod::Vector2f uv;
pod::Vector2f st;
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
struct ID {
pod::Vector3f position;
pod::ColorRgba color;
pod::Vector2f uv;
pod::Vector2f st;
pod::Vector3f normal;
pod::Vector3f tangent;
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
struct Skinned {
pod::Vector3f position;
pod::ColorRgba color;
pod::Vector2f uv;
pod::Vector2f st;
pod::Vector3f normal;
pod::Vector3f tangent;
pod::Vector<id_t, 4> joints;
pod::Vector<uint16_t, 4> joints;
pod::Vector4f weights;
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
}
/*
typedef uf::Mesh<uf::graph::mesh::Base> base_mesh_t;
typedef uf::Mesh<uf::graph::mesh::ID> id_mesh_t;
typedef uf::Mesh<uf::graph::mesh::Skinned> skinned_mesh_t;
*/
}
}

View File

@ -79,13 +79,17 @@ namespace ext {
// directly move a transform
void UF_API applyMovement( pod::Bullet&, const pod::Vector3f& );
// directly apply a velocity
void UF_API setVelocity( pod::Bullet&, const pod::Vector3f& );
void UF_API applyVelocity( pod::Bullet&, const pod::Vector3f& );
// directly rotate a transform
void UF_API applyRotation( pod::Bullet&, const pod::Quaternion<>& );
void UF_API applyRotation( pod::Bullet&, const pod::Vector3f&, float );
// picks an appropriate movement option
void UF_API move( pod::Bullet&, const pod::Vector3f&, bool = false );
// void UF_API move( pod::Bullet&, const pod::Vector3f&, bool = false );
// ray casting
float UF_API rayCast( const pod::Vector3f&, const pod::Vector3f& );
// allows noclip
void UF_API activateCollision( pod::Bullet&, bool = true );

View File

@ -29,6 +29,7 @@ namespace pod {
namespace ext {
namespace lua {
extern UF_API bool enabled;
extern UF_API sol::state state;
extern UF_API uf::stl::string main;
extern UF_API uf::stl::unordered_map<uf::stl::string, uf::stl::string> modules;

View File

@ -2,6 +2,7 @@
#include <uf/config.h>
#include <uf/utils/mesh/mesh.h>
#include <uf/ext/meshopt/meshopt.h>
namespace ext {
namespace meshopt {

View File

@ -3,10 +3,15 @@
#include <uf/config.h>
#if UF_USE_OPENAL
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alut.h>
#if UF_ENV_DREAMCAST && UF_USE_OPENAL_ALDC
#include <ALdc/al.h>
#include <ALdc/alc.h>
#include <ALdc/alut.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alut.h>
#endif
#include <uf/utils/memory/string.h>
#include <uf/utils/memory/vector.h>

View File

@ -52,6 +52,8 @@ namespace ext {
uf::Mesh::Attribute st = {};
uf::Mesh::Attribute normal = {};
uf::Mesh::Attribute color = {};
uf::Mesh::Attribute instance = {};
uf::Mesh::Attribute indirect = {};
} attributes;
struct {

View File

@ -3,20 +3,37 @@
#define UF_NS_GET_LAST(name) uf::string::replace( uf::string::split( #name, "::" ).back(), "<>", "" )
#define TIMER(x, ...) auto TOKEN_PASTE(TIMER, __LINE__) = []( double every = 1 ) {\
/*
#define TIMER(x, ...) auto TOKEN_PASTE(TIMER, __LINE__) = []( uf::physics::num_t every = 1 ) {\
static uf::Timer<long long> timer(false);\
if ( !timer.running() ) {\
timer.start(uf::Time<long long>(-x * 1000, uf::Time<long long>::milliseconds));\
}\
double time = 0;\
if ( (time = timer.elapsed().asDouble()) >= every ) {\
uf::physics::num_t time = 0;\
if ( (time = timer.elapsed()) >= every ) {\
timer.reset();\
}\
static bool first = true; if ( first ) { first = false; return every; }\
return time;\
};\
double time = 0;\
uf::physics::num_t time = 0;\
if ( __VA_ARGS__ (time = TOKEN_PASTE(TIMER, __LINE__)(x)) >= x )
*/
#define TIMER_LAMBDA(x) []() {\
static uf::Timer<long long> timer(false);\
if ( !timer.running() ) timer.start(uf::Time<long long>(-x * 1000, uf::Time<long long>::milliseconds));\
uf::physics::num_t time = timer.elapsed();\
if ( time >= every ) timer.reset();\
static bool first = true; if ( first ) { first = false; return every; }\
return time;\
};
#define TIMER(x, ...)\
static uf::Timer<long long> timer(false);\
if ( !timer.running() ) timer.start(uf::Time<long long>(-x * 1000, uf::Time<long long>::milliseconds));\
uf::physics::num_t time = timer.elapsed();\
if ( time >= x ) timer.reset();\
if ( __VA_ARGS__ time >= x )
#define UF_DEBUG 1
#if UF_DEBUG
@ -97,7 +114,7 @@
#define TYPE_NAME(T) TYPE(T).name()
#endif
#define MIN(X, Y) X < Y ? X : Y
#define MAX(X, Y) X > Y ? X : Y
#define MIN(X, Y) (X) < (Y) ? (X) : (Y)
#define MAX(X, Y) (X) > (Y) ? (X) : (Y)
#define LENGTH_OF(X) *(&X + 1) - X
#define FOR_ARRAY(X) for ( auto i = 0; i < LENGTH_OF(X); ++i )

View File

@ -29,6 +29,15 @@ namespace uf {
extern UF_API bool streamsByDefault;
extern UF_API uint8_t buffers;
extern UF_API size_t bufferSize;
#if UF_AUDIO_MAPPED_VOLUMES
extern UF_API uf::stl::unordered_map<uf::stl::string, float> volumes;
#else
namespace volumes {
extern UF_API float bgm;
extern UF_API float sfx;
extern UF_API float voice;
};
#endif
}
class UF_API Audio {
public:

View File

@ -72,17 +72,17 @@ namespace uf {
template<typename T=pod::Matrix4> T /*UF_API*/ multiplyAll( const T& matrix, typename T::type_t scalar );
template<typename T=pod::Matrix4> T /*UF_API*/ add( const T& lhs, const T& rhs );
// Writes to first value
// template<typename T=pod::Matrix4> pod::Matrix<typename T::type_t, C, C>& /*UF_API*/ multiply( T& left, const T& right ); // Multiplies two matrices of same type and size together
template<typename T, typename U> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply( T& left, const U& right ); // Multiplies two matrices of same type and size together
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply( T& left, const T& right );
template<typename T=pod::Matrix4> T& /*UF_API*/ invert( T& matrix ); // Flip sign of all components
// template<typename T=pod::Matrix4> pod::Matrix<typename T::type_t, C, C>& /*UF_API*/ multiply_( T& left, const T& right ); // Multiplies two matrices of same type and size together
template<typename T, typename U> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const U& right ); // Multiplies two matrices of same type and size together
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const T& right );
template<typename T=pod::Matrix4> T& /*UF_API*/ translate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ rotate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ scale_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
// Complex arithmetic
template<typename T=pod::Matrix4> T /*UF_API*/ translate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T /*UF_API*/ rotate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T /*UF_API*/ scale( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ translate( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ rotate( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ scale( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> pod::Vector3t<typename T::type_t> /*UF_API*/ eulerAngles( const T& matrix );
template<typename T=pod::Math::num_t> pod::Matrix4t<T> /*UF_API*/ orthographic( T, T, T, T, T, T );

View File

@ -424,11 +424,6 @@ template<typename T> T uf::matrix::inverse( const T& matrix ) {
return inverted;
}
// Writes to first value
// Multiplies two matrices of same type and size together
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> uf::matrix::multiply( T& left, const T& right ) {
return left = uf::matrix::multiply((const T&) left, right);
}
template<typename T> pod::Vector3t<T> uf::matrix::multiply( const pod::Matrix4t<T>& mat, const pod::Vector3t<T>& vector, T w, bool div ) {
return uf::matrix::multiply( mat, pod::Vector4t<T>{ vector[0], vector[1], vector[2], w }, div );
}
@ -450,10 +445,51 @@ template<typename T> pod::Vector4t<T> uf::matrix::multiply( const pod::Matrix4t<
return res;
#endif
}
// Writes to first value
// Multiplies two matrices of same type and size together
// Flip sign of all components
template<typename T> T& uf::matrix::invert( T& matrix ) {
return matrix = uf::matrix::inverse((const T&) matrix);
}
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> uf::matrix::multiply_( T& left, const T& right ) {
return left = uf::matrix::multiply((const T&) left, right);
}
template<typename T> T& uf::matrix::translate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[12] = vector.x;
matrix[13] = vector.y;
matrix[14] = vector.z;
return matrix;
}
template<typename T> T& uf::matrix::rotate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
if ( vector.x != 0 ) {
matrix[5] = cos( vector.x );
matrix[6] = sin( vector.x );
matrix[9] = -1 * sin( vector.x );
matrix[10] = cos( vector.x );
}
if ( vector.y != 0 ) {
matrix[0] = cos( vector.y );
matrix[2] = -1 * sin( vector.y );
matrix[8] = sin( vector.y );
matrix[10] = cos( vector.y );
}
if ( vector.z != 0 ) {
matrix[0] = cos( vector.z );
matrix[1] = sin( vector.z );
matrix[4] = -1 * sin( vector.z );
matrix[5] = cos( vector.z );
}
return matrix;
}
template<typename T> T& uf::matrix::scale_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[0] = vector.x;
matrix[5] = vector.y;
matrix[10] = vector.z;
return matrix;
}
// Complex arithmetic
template<typename T> T uf::matrix::translate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
alignas(16) T res = matrix;
@ -493,41 +529,6 @@ template<typename T> T uf::matrix::scale( const T& matrix, const pod::Vector3t<t
res[10] = vector.z;
return res;
}
template<typename T> T& uf::matrix::translate( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[12] = vector.x;
matrix[13] = vector.y;
matrix[14] = vector.z;
return matrix;
}
template<typename T> T& uf::matrix::rotate( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
if ( vector.x != 0 ) {
matrix[5] = cos( vector.x );
matrix[6] = sin( vector.x );
matrix[9] = -1 * sin( vector.x );
matrix[10] = cos( vector.x );
}
if ( vector.y != 0 ) {
matrix[0] = cos( vector.y );
matrix[2] = -1 * sin( vector.y );
matrix[8] = sin( vector.y );
matrix[10] = cos( vector.y );
}
if ( vector.z != 0 ) {
matrix[0] = cos( vector.z );
matrix[1] = sin( vector.z );
matrix[4] = -1 * sin( vector.z );
matrix[5] = cos( vector.z );
}
return matrix;
}
template<typename T> T& uf::matrix::scale( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[0] = vector.x;
matrix[5] = vector.y;
matrix[10] = vector.z;
return matrix;
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t, T f, T n ) {
alignas(16) pod::Matrix4t<T> m = uf::matrix::identity();

View File

@ -20,12 +20,14 @@ namespace pod {
namespace uf {
namespace physics {
typedef pod::Math::num_t num_t;
namespace time {
extern UF_API uf::Timer<> timer;
extern UF_API double current;
extern UF_API double previous;
extern UF_API double delta;
extern UF_API double clamp;
extern UF_API uf::physics::num_t current;
extern UF_API uf::physics::num_t previous;
extern UF_API uf::physics::num_t delta;
extern UF_API uf::physics::num_t clamp;
}
void UF_API tick();
template<typename T> pod::Transform<T>& update( pod::Transform<T>& transform, pod::Physics& physics );

View File

@ -15,18 +15,18 @@
namespace pod {
// Simple vectors (designed [to store in arrays] with minimal headaches)
template<typename T = pod::Math::num_t, std::size_t N = 3>
template<typename T = pod::Math::num_t, size_t N = 3>
struct /*UF_API*/ Vector {
// n-dimensional/unspecialized vector access
T components[N];
// POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = N;
static const size_t size = N;
// Overload access
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
Vector<T,N> operator()() const; // Negation
Vector<T,N> operator-() const; // Negation
@ -110,27 +110,28 @@ namespace uf {
template<typename T> bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two vectors (equals)
// Basic arithmetic
template<typename T> T /*UF_API*/ add( const T& left, const T& right ); // Adds two vectors of same type and size together
template<typename T> T /*UF_API*/ add( const T& left, const typename T::type_t& scalar ); // Adds two vectors of same type and size together
template<typename T> T /*UF_API*/ add( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together
template<typename T> T /*UF_API*/ subtract( const T& left, const T& right ); // Subtracts two vectors of same type and size together
template<typename T> T /*UF_API*/ subtract( const T& left, const typename T::type_t& scalar ); // Subtracts two vectors of same type and size together
template<typename T> T /*UF_API*/ subtract( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Subtracts two vectors of same type and size together
template<typename T> T /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two vectors of same type and size together
template<typename T> T /*UF_API*/ multiply( const T& vector, const typename T::type_t& scalar ); // Multiplies this vector by a scalar
template<typename T> T /*UF_API*/ multiply( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ); // Multiplies this vector by a scalar
template<typename T> T /*UF_API*/ divide( const T& left, const T& right ); // Divides two vectors of same type and size together
template<typename T> T /*UF_API*/ divide( const T& left, const typename T::type_t& scalar ); // Divides this vector by a scalar
template<typename T> T /*UF_API*/ divide( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Divides this vector by a scalar
template<typename T> typename T::type_t /*UF_API*/ sum( const T& vector ); // Compute the sum of all components
template<typename T> typename T::type_t /*UF_API*/ product( const T& vector ); // Compute the product of all components
template<typename T> T /*UF_API*/ negate( const T& vector ); // Flip sign of all components
// Writes to first value
template<typename T> T& /*UF_API*/ add( T& left, const T& right ); // Adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ add( T& left, const typename T::type_t& scalar ); // Adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ subtract( T& left, const T& right ); // Subtracts two vectors of same type and size together
template<typename T> T& /*UF_API*/ subtract( T& left, const typename T::type_t& scalar ); // Subtracts two vectors of same type and size together
template<typename T> T& /*UF_API*/ multiply( T& left, const T& right ); // Multiplies two vectors of same type and size together
template<typename T> T& /*UF_API*/ multiply( T& vector, const typename T::type_t& scalar ); // Multiplies this vector by a scalar
template<typename T> T& /*UF_API*/ divide( T& left, const T& right ); // Divides two vectors of same type and size together
template<typename T> T& /*UF_API*/ divide( T& left, const typename T::type_t& scalar ); // Divides this vector by a scalar
template<typename T> T& /*UF_API*/ negate( T& vector ); // Flip sign of all components
template<typename T> T& /*UF_API*/ normalize( T& vector ); // Normalizes a vector
template<typename T> T& /*UF_API*/ add_( T& left, const T& right ); // Adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ add_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ subtract_( T& left, const T& right ); // Subtracts two vectors of same type and size together
template<typename T> T& /*UF_API*/ subtract_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Subtracts two vectors of same type and size together
template<typename T> T& /*UF_API*/ multiply_( T& left, const T& right ); // Multiplies two vectors of same type and size together
template<typename T> T& /*UF_API*/ multiply_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ); // Multiplies this vector by a scalar
template<typename T> T& /*UF_API*/ divide_( T& left, const T& right ); // Divides two vectors of same type and size together
template<typename T> T& /*UF_API*/ divide_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Divides this vector by a scalar
template<typename T> T& /*UF_API*/ negate_( T& vector ); // Flip sign of all components
template<typename T> T& /*UF_API*/ normalize_( T& vector ); // Normalizes a vector
template<typename T> T /*UF_API*/ min( const T& left, const T& right ); //
template<typename T> T /*UF_API*/ max( const T& left, const T& right ); //
template<typename T> T /*UF_API*/ ceil( const T& vector ); //
@ -149,8 +150,8 @@ namespace uf {
template<typename T> typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); // Compute the distance between two vectors (doesn't sqrt)
template<typename T> typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // Compute the distance between two vectors
template<typename T> typename T::type_t /*UF_API*/ magnitude( const T& vector ); // Gets the magnitude of the vector
template<typename T> typename T::type_t /*UF_API*/ norm( const T& vector ); // Compute the norm of the vector
template<typename T> typename T::type_t /*UF_API*/ magnitude( const T& vector ); // Gets the magnitude of the vector
template<typename T> T /*UF_API*/ normalize( const T& vector ); // Normalizes a vector
template<typename T> void /*UF_API*/ orthonormalize( T& x, T& y ); // Normalizes a vector
template<typename T> T /*UF_API*/ orthonormalize( const T& x, const T& y ); // Normalizes a vector
@ -166,7 +167,7 @@ namespace uf {
namespace uf {
// Provides operations for POD vector
template<typename T = pod::Math::num_t, std::size_t N = 3>
template<typename T = pod::Math::num_t, size_t N = 3>
class /*UF_API*/ Vector {
public:
// Easily access POD's type
@ -174,7 +175,7 @@ namespace uf {
// Replicate POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = N;
static const size_t size = N;
protected:
// POD storage
Vector<T,N>::pod_t m_pod;
@ -194,11 +195,11 @@ namespace uf {
// Alternative POD access
T* get(); // Returns a pointer to the entire array
const T* get() const; // Returns a const-pointer to the entire array
T& getComponent( std::size_t i ); // Returns a reference to a single element
const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element
T& getComponent( size_t i ); // Returns a reference to a single element
const T& getComponent( size_t i ) const; // Returns a const-reference to a single element
// POD manipulation
T* set(const T components[N]); // Sets the entire array
T& setComponent( std::size_t i, const T& value ); // Sets a single element
T& setComponent( size_t i, const T& value ); // Sets a single element
// Validation
bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.)
// Basic arithmetic
@ -230,8 +231,8 @@ namespace uf {
inline uf::stl::string toString() const;
// Overloaded ops
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
inline Vector<T,N> operator-() const; // Negation
inline Vector<T,N> operator+( const Vector<T,N>& vector ) const; // Addition between two vectors
@ -325,11 +326,11 @@ namespace pod {
// POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = 1;
static const size_t size = 1;
// Overload access
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
inline Vector<T,1> operator()() const; // Creation
inline Vector<T,1> operator-() const; // Negation
@ -375,11 +376,11 @@ namespace pod {
// POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = 2;
static const size_t size = 2;
// Overload access
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
inline Vector<T,2> operator()() const; // Creation
inline Vector<T,2> operator-() const; // Negation
@ -426,11 +427,11 @@ namespace pod {
// POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = 3;
static const size_t size = 3;
// Overload access
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
inline Vector<T,3> operator()() const; // Creation
inline Vector<T,3> operator-() const; // Negation
@ -483,11 +484,11 @@ namespace pod {
// POD information
typedef T type_t;
typedef T* container_t;
static const std::size_t size = 4;
static const size_t size = 4;
// Overload access
// Accessing via subscripts
T& operator[](std::size_t i);
const T& operator[](std::size_t i) const;
T& operator[](size_t i);
const T& operator[](size_t i) const;
// Arithmetic
inline Vector<T,4> operator()() const; // Creation
inline Vector<T,4> operator-() const; // Negation

View File

@ -22,7 +22,7 @@ template<typename T, size_t N, typename U>
pod::Vector<T, N> /*UF_API*/ uf::vector::cast( const U& from ) {
alignas(16) pod::Vector<T, N> to;
#pragma unroll // GCC unroll N
for ( uint_fast8_t i = 0; i < N && i < U::size; ++i )
for ( auto i = 0; i < N && i < U::size; ++i )
to[i] = from[i];
return to;
}
@ -35,7 +35,7 @@ template<typename T> // Equality check between two vectors (equal
bool /*UF_API*/ uf::vector::equals( const T& left, const T& right ) {
// return uf::vector::compareTo(left, right) == 0;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
if ( left[i] != right[i] ) return false;
return true;
}
@ -47,18 +47,18 @@ T /*UF_API*/ uf::vector::add( const T& left, const T& right ) {
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = left[i] + right[i];
return res;
}
template<typename T> // Multiplies this vector by a scalar
T /*UF_API*/ uf::vector::add( const T& vector, const typename T::type_t& scalar ) {
T /*UF_API*/ uf::vector::add( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return uf::simd::add( vector, scalar );
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = vector[i] + scalar;
return res;
}
@ -69,18 +69,18 @@ T /*UF_API*/ uf::vector::subtract( const T& left, const T& right ) {
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = left[i] - right[i];
return res;
}
template<typename T> // Multiplies this vector by a scalar
T /*UF_API*/ uf::vector::subtract( const T& vector, const typename T::type_t& scalar ) {
T /*UF_API*/ uf::vector::subtract( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return uf::simd::sub( vector, scalar );
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = vector[i] - scalar;
return res;
}
@ -91,18 +91,18 @@ T /*UF_API*/ uf::vector::multiply( const T& left, const T& right ) {
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = left[i] * right[i];
return res;
}
template<typename T> // Multiplies this vector by a scalar
T /*UF_API*/ uf::vector::multiply( const T& vector, const typename T::type_t& scalar ) {
T /*UF_API*/ uf::vector::multiply( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return uf::simd::mul( vector, scalar );
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = vector[i] * scalar;
return res;
}
@ -113,32 +113,34 @@ T /*UF_API*/ uf::vector::divide( const T& left, const T& right ) {
#elif UF_ENV_DREAMCAST
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = MATH_Fast_Divide(left[i], right[i]);
return res;
#else
alignas(16) T res;
scalar = 1.0 / scalar;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
res[i] = left[i] / right[i];
for ( auto i = 0; i < T::size; ++i )
res[i] = left[i] * right[i];
return res;
#endif
}
template<typename T> // Divides this vector by a scalar
T /*UF_API*/ uf::vector::divide( const T& vector, const typename T::type_t& scalar ) {
T /*UF_API*/ uf::vector::divide( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return uf::simd::div( vector, scalar );
#elif UF_ENV_DREAMCAST
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = MATH_Fast_Divide(vector[i], scalar);
return res;
#else
alignas(16) T res;
scalar = 1.0 / scalar;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
res[i] = vector[i] / scalar;
for ( auto i = 0; i < T::size; ++i )
res[i] = vector[i] * scalar;
return res;
#endif
}
@ -146,7 +148,7 @@ template<typename T> // Compute the sum of all components
typename T::type_t /*UF_API*/ uf::vector::sum( const T& vector ) {
typename T::type_t res = 0;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res += vector[i];
return res;
}
@ -154,7 +156,7 @@ template<typename T> // Compute the product of all components
typename T::type_t /*UF_API*/ uf::vector::product( const T& vector ) {
typename T::type_t res = 0;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res *= vector[i];
return res;
}
@ -165,135 +167,135 @@ T /*UF_API*/ uf::vector::negate( const T& vector ) {
#endif
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = -vector[i];
return res;
}
// Writes to first value
template<typename T> // Adds two vectors of same type and size together
T& /*UF_API*/ uf::vector::add( T& left, const T& right ) {
T& /*UF_API*/ uf::vector::add_( T& left, const T& right ) {
#if UF_USE_SIMD
return left = uf::vector::add( (const T&) left, right );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
left[i] += right[i];
return left;
}
template<typename T> // Multiplies this vector by a scalar
T& /*UF_API*/ uf::vector::add( T& vector, const typename T::type_t& scalar ) {
T& /*UF_API*/ uf::vector::add_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return vector = uf::vector::add( (const T&) vector, scalar );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
vector[i] += scalar;
return vector;
}
template<typename T> // Subtracts two vectors of same type and size together
T& /*UF_API*/ uf::vector::subtract( T& left, const T& right ) {
T& /*UF_API*/ uf::vector::subtract_( T& left, const T& right ) {
#if UF_USE_SIMD
return left = uf::vector::subtract( (const T&) left, right );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
left[i] -= right[i];
return left;
}
template<typename T> // Multiplies this vector by a scalar
T& /*UF_API*/ uf::vector::subtract( T& vector, const typename T::type_t& scalar ) {
T& /*UF_API*/ uf::vector::subtract_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return vector = uf::vector::subtract( (const T&) vector, scalar );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
vector[i] -= scalar;
return vector;
}
template<typename T> // Multiplies two vectors of same type and size together
T& /*UF_API*/ uf::vector::multiply( T& left, const T& right ) {
T& /*UF_API*/ uf::vector::multiply_( T& left, const T& right ) {
#if UF_USE_SIMD
return left = uf::vector::multiply( (const T&) left, right );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
left[i] *= right[i];
return left;
}
template<typename T> // Multiplies this vector by a scalar
T& /*UF_API*/ uf::vector::multiply( T& vector, const typename T::type_t& scalar ) {
T& /*UF_API*/ uf::vector::multiply_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return vector = uf::vector::multiply( (const T&) vector, scalar );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
vector[i] *= scalar;
return vector;
}
template<typename T> // Divides two vectors of same type and size together
T& /*UF_API*/ uf::vector::divide( T& left, const T& right ) {
T& /*UF_API*/ uf::vector::divide_( T& left, const T& right ) {
#if UF_USE_SIMD
return left = uf::vector::divide( (const T&) left, right );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
left[i] /= right[i];
return left;
}
template<typename T> // Divides this vector by a scalar
T& /*UF_API*/ uf::vector::divide( T& vector, const typename T::type_t& scalar ) {
T& /*UF_API*/ uf::vector::divide_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) {
#if UF_USE_SIMD
return vector = uf::vector::divide( (const T&) vector, scalar );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
vector[i] /= scalar;
return vector;
}
template<typename T> // Flip sign of all components
T& /*UF_API*/ uf::vector::negate( T& vector ) {
T& /*UF_API*/ uf::vector::negate_( T& vector ) {
#if UF_USE_SIMD
return vector = uf::vector::negate( (const T&) vector );
#endif
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
vector[i] = -vector[i];
return vector;
}
template<typename T> // Normalizes a vector
T& /*UF_API*/ uf::vector::normalize( T& vector ) {
T& /*UF_API*/ uf::vector::normalize_( T& vector ) {
typename T::type_t norm = uf::vector::norm(vector);
if ( norm == 0 ) return vector;
return uf::vector::divide(vector, norm);
return vector = uf::vector::divide((const T&) vector, norm);
}
template<typename T> //
T /*UF_API*/ uf::vector::min( const T& left, const T& right ) {
T res = left;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::min( left[i], right[i] );
for ( auto i = 0; i < T::size; ++i ) res[i] = std::min( left[i], right[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::max( const T& left, const T& right ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::max( left[i], right[i] );
for ( auto i = 0; i < T::size; ++i ) res[i] = std::max( left[i], right[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::ceil( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::ceil( vector[i] );
for ( auto i = 0; i < T::size; ++i ) res[i] = std::ceil( vector[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::floor( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::floor( vector[i] );
for ( auto i = 0; i < T::size; ++i ) res[i] = std::floor( vector[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::round( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = ::round( vector[i] );
for ( auto i = 0; i < T::size; ++i ) res[i] = ::round( vector[i] );
return res;
}
// Complex arithmetic
@ -317,7 +319,7 @@ T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, double delta, bool cl
#if UF_ENV_DREAMCAST
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = MATH_Lerp( from[i], to[i], delta );
return res;
#elif UF_USE_SIMD
@ -332,7 +334,7 @@ T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, const T& delta, bool
#if UF_ENV_DREAMCAST
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < T::size; ++i )
for ( auto i = 0; i < T::size; ++i )
res[i] = MATH_Lerp( from[i], to[i], delta[i] );
return res;
#elif UF_USE_SIMD
@ -370,11 +372,16 @@ typename T::type_t /*UF_API*/ uf::vector::distanceSquared( const T& a, const T&
return MATH_Sum_of_Squares( UF_EZ_VEC4( delta, T::size ) );
#elif UF_USE_SIMD
uf::simd::value<typename T::type_t> delta = uf::simd::sub( b, a );
return uf::vector::sum( uf::simd::vector( uf::simd::mul( delta, delta ) ) );
// return uf::vector::sum( uf::simd::vector( uf::simd::mul( delta, delta ) ) );
return uf::simd::dot( delta, delta );
#else
alignas(16) T delta = uf::vector::subtract(b, a);
return uf::vector::dot( delta, delta );
/*
alignas(16) T delta = uf::vector::subtract(b, a);
uf::vector::multiply( delta, delta );
return uf::vector::sum(delta);
*/
#endif
}
template<typename T> // Compute the distance between two vectors
@ -455,7 +462,7 @@ uf::stl::string /*UF_API*/ uf::vector::toString( const T& v ) {
uf::stl::stringstream ss;
ss << "Vector(";
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < size; ++i ) {
for ( auto i = 0; i < size; ++i ) {
ss << v[i];
if ( i + 1 < size ) ss << ", ";
}
@ -468,11 +475,11 @@ ext::json::Value /*UF_API*/ uf::vector::encode( const pod::Vector<T,N>& v, const
ext::json::Value json;
if ( settings.quantize )
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < N; ++i )
for ( auto i = 0; i < N; ++i )
json[i] = uf::math::quantizeShort( v[i] );
else
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < N; ++i )
for ( auto i = 0; i < N; ++i )
json[i] = v[i];
return json;
}
@ -480,10 +487,10 @@ template<typename T, size_t N>
pod::Vector<T,N>& /*UF_API*/ uf::vector::decode( const ext::json::Value& json, pod::Vector<T,N>& v ) {
if ( ext::json::isArray(json) )
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < N; ++i )
for ( auto i = 0; i < N; ++i )
v[i] = json[i].as<T>(v[i]);
else if ( ext::json::isObject(json) ) {
uint_fast8_t i = 0;
auto i = 0;
ext::json::forEach(json, [&](const ext::json::Value& c){
if ( i >= N ) return;
v[i] = uf::math::unquantize( c.as<T>(v[i]) );
@ -497,10 +504,10 @@ pod::Vector<T,N> /*UF_API*/ uf::vector::decode( const ext::json::Value& json, co
pod::Vector<T,N> v = _v;
if ( ext::json::isArray(json) )
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < N; ++i )
for ( auto i = 0; i < N; ++i )
v[i] = json[i].as<T>(_v[i]);
else if ( ext::json::isObject(json) ) {
uint_fast8_t i = 0;
auto i = 0;
ext::json::forEach(json, [&](const ext::json::Value& c){
if ( i >= N ) return;
v[i] = c.as<T>(_v[i]);

View File

@ -47,35 +47,35 @@ inline pod::Vector<T,N> pod::Vector<T,N>::operator/( T scalar ) const {
}
template<typename T, std::size_t N> // Addition set between two vectors
inline pod::Vector<T,N>& pod::Vector<T,N>::operator +=( const pod::Vector<T,N>& vector ) {
return uf::vector::add( *this, vector );
return uf::vector::add_( *this, vector );
}
template<typename T, std::size_t N> // Subtraction set between two vectors
inline pod::Vector<T,N>& pod::Vector<T,N>::operator -=( const pod::Vector<T,N>& vector ) {
return uf::vector::subtract( *this, vector );
return uf::vector::subtract_( *this, vector );
}
template<typename T, std::size_t N> // Multiplication set between two vectors
inline pod::Vector<T,N>& pod::Vector<T,N>::operator *=( const pod::Vector<T,N>& vector ) {
return uf::vector::multiply( *this, vector );
return uf::vector::multiply_( *this, vector );
}
template<typename T, std::size_t N> // Division set between two vectors
inline pod::Vector<T,N>& pod::Vector<T,N>::operator /=( const pod::Vector<T,N>& vector ) {
return uf::vector::divide( *this, vector );
return uf::vector::divide_( *this, vector );
}
template<typename T, std::size_t N> // Multiplication set with scalar
inline pod::Vector<T,N>& pod::Vector<T,N>::operator +=( T scalar ) {
return uf::vector::add( *this, scalar );
return uf::vector::add_( *this, scalar );
}
template<typename T, std::size_t N> // Multiplication set with scalar
inline pod::Vector<T,N>& pod::Vector<T,N>::operator -=( T scalar ) {
return uf::vector::subtract( *this, scalar );
return uf::vector::subtract_( *this, scalar );
}
template<typename T, std::size_t N> // Multiplication set with scalar
inline pod::Vector<T,N>& pod::Vector<T,N>::operator *=( T scalar ) {
return uf::vector::multiply( *this, scalar );
return uf::vector::multiply_( *this, scalar );
}
template<typename T, std::size_t N> // Division set with scalar
inline pod::Vector<T,N>& pod::Vector<T,N>::operator /=( T scalar ) {
return uf::vector::divide( *this, scalar );
return uf::vector::divide_( *this, scalar );
}
template<typename T, std::size_t N> // Equality check between two vectors (equals)
inline bool pod::Vector<T,N>::operator==( const pod::Vector<T,N>& vector ) const {
@ -170,35 +170,35 @@ inline pod::Vector<T,1> pod::Vector<T,1>::operator/( T scalar ) const {
}
template<typename T> // Addition set between two vectors
inline pod::Vector<T,1>& pod::Vector<T,1>::operator +=( const pod::Vector<T,1>& vector ) {
return uf::vector::add( *this, vector );
return uf::vector::add_( *this, vector );
}
template<typename T> // Subtraction set between two vectors
inline pod::Vector<T,1>& pod::Vector<T,1>::operator -=( const pod::Vector<T,1>& vector ) {
return uf::vector::subtract( *this, vector );
return uf::vector::subtract_( *this, vector );
}
template<typename T> // Multiplication set between two vectors
inline pod::Vector<T,1>& pod::Vector<T,1>::operator *=( const pod::Vector<T,1>& vector ) {
return uf::vector::multiply( *this, vector );
return uf::vector::multiply_( *this, vector );
}
template<typename T> // Division set between two vectors
inline pod::Vector<T,1>& pod::Vector<T,1>::operator /=( const pod::Vector<T,1>& vector ) {
return uf::vector::divide( *this, vector );
return uf::vector::divide_( *this, vector );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,1>& pod::Vector<T,1>::operator +=( T scalar ) {
return uf::vector::add( *this, scalar );
return uf::vector::add_( *this, scalar );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,1>& pod::Vector<T,1>::operator -=( T scalar ) {
return uf::vector::subtract( *this, scalar );
return uf::vector::subtract_( *this, scalar );
}
template<typename T> // Multiplication set with scalar
inline pod::Vector<T,1>& pod::Vector<T,1>::operator *=( T scalar ) {
return uf::vector::multiply( *this, scalar );
return uf::vector::multiply_( *this, scalar );
}
template<typename T> // Division set with scalar
inline pod::Vector<T,1>& pod::Vector<T,1>::operator /=( T scalar ) {
return uf::vector::divide( *this, scalar );
return uf::vector::divide_( *this, scalar );
}
template<typename T> // Equality check between two vectors (equals)
inline bool pod::Vector<T,1>::operator==( const pod::Vector<T,1>& vector ) const {
@ -292,35 +292,35 @@ inline pod::Vector<T,2> pod::Vector<T,2>::operator/( T scalar ) const {
}
template<typename T> // Addition set between two vectors
inline pod::Vector<T,2>& pod::Vector<T,2>::operator +=( const pod::Vector<T,2>& vector ) {
return uf::vector::add( *this, vector );
return uf::vector::add_( *this, vector );
}
template<typename T> // Subtraction set between two vectors
inline pod::Vector<T,2>& pod::Vector<T,2>::operator -=( const pod::Vector<T,2>& vector ) {
return uf::vector::subtract( *this, vector );
return uf::vector::subtract_( *this, vector );
}
template<typename T> // Multiplication set between two vectors
inline pod::Vector<T,2>& pod::Vector<T,2>::operator *=( const pod::Vector<T,2>& vector ) {
return uf::vector::multiply( *this, vector );
return uf::vector::multiply_( *this, vector );
}
template<typename T> // Division set between two vectors
inline pod::Vector<T,2>& pod::Vector<T,2>::operator /=( const pod::Vector<T,2>& vector ) {
return uf::vector::divide( *this, vector );
return uf::vector::divide_( *this, vector );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,2>& pod::Vector<T,2>::operator+=( T scalar ) {
return uf::vector::add( *this, scalar );
return uf::vector::add_( *this, scalar );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,2>& pod::Vector<T,2>::operator-=( T scalar ) {
return uf::vector::subtract( *this, scalar );
return uf::vector::subtract_( *this, scalar );
}
template<typename T> // Multiplication set with scalar
inline pod::Vector<T,2>& pod::Vector<T,2>::operator *=( T scalar ) {
return uf::vector::multiply( *this, scalar );
return uf::vector::multiply_( *this, scalar );
}
template<typename T> // Division set with scalar
inline pod::Vector<T,2>& pod::Vector<T,2>::operator /=( T scalar ) {
return uf::vector::divide( *this, scalar );
return uf::vector::divide_( *this, scalar );
}
template<typename T> // Equality check between two vectors (equals)
inline bool pod::Vector<T,2>::operator==( const pod::Vector<T,2>& vector ) const {
@ -414,35 +414,35 @@ inline pod::Vector<T,3> pod::Vector<T,3>::operator/( T scalar ) const {
}
template<typename T> // Addition set between two vectors
inline pod::Vector<T,3>& pod::Vector<T,3>::operator +=( const pod::Vector<T,3>& vector ) {
return uf::vector::add( *this, vector );
return uf::vector::add_( *this, vector );
}
template<typename T> // Subtraction set between two vectors
inline pod::Vector<T,3>& pod::Vector<T,3>::operator -=( const pod::Vector<T,3>& vector ) {
return uf::vector::subtract( *this, vector );
return uf::vector::subtract_( *this, vector );
}
template<typename T> // Multiplication set between two vectors
inline pod::Vector<T,3>& pod::Vector<T,3>::operator *=( const pod::Vector<T,3>& vector ) {
return uf::vector::multiply( *this, vector );
return uf::vector::multiply_( *this, vector );
}
template<typename T> // Division set between two vectors
inline pod::Vector<T,3>& pod::Vector<T,3>::operator /=( const pod::Vector<T,3>& vector ) {
return uf::vector::divide( *this, vector );
return uf::vector::divide_( *this, vector );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,3>& pod::Vector<T,3>::operator +=( T scalar ) {
return uf::vector::add( *this, scalar );
return uf::vector::add_( *this, scalar );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,3>& pod::Vector<T,3>::operator -=( T scalar ) {
return uf::vector::subtract( *this, scalar );
return uf::vector::subtract_( *this, scalar );
}
template<typename T> // Multiplication set with scalar
inline pod::Vector<T,3>& pod::Vector<T,3>::operator *=( T scalar ) {
return uf::vector::multiply( *this, scalar );
return uf::vector::multiply_( *this, scalar );
}
template<typename T> // Division set with scalar
inline pod::Vector<T,3>& pod::Vector<T,3>::operator /=( T scalar ) {
return uf::vector::divide( *this, scalar );
return uf::vector::divide_( *this, scalar );
}
template<typename T> // Equality check between two vectors (equals)
inline bool pod::Vector<T,3>::operator==( const pod::Vector<T,3>& vector ) const {
@ -549,35 +549,35 @@ inline pod::Vector<T,4> pod::Vector<T,4>::operator/( T scalar ) const {
}
template<typename T> // Addition set between two vectors
inline pod::Vector<T,4>& pod::Vector<T,4>::operator +=( const pod::Vector<T,4>& vector ) {
return uf::vector::add( *this, vector );
return uf::vector::add_( *this, vector );
}
template<typename T> // Subtraction set between two vectors
inline pod::Vector<T,4>& pod::Vector<T,4>::operator -=( const pod::Vector<T,4>& vector ) {
return uf::vector::subtract( *this, vector );
return uf::vector::subtract_( *this, vector );
}
template<typename T> // Multiplication set between two vectors
inline pod::Vector<T,4>& pod::Vector<T,4>::operator *=( const pod::Vector<T,4>& vector ) {
return uf::vector::multiply( *this, vector );
return uf::vector::multiply_( *this, vector );
}
template<typename T> // Division set between two vectors
inline pod::Vector<T,4>& pod::Vector<T,4>::operator /=( const pod::Vector<T,4>& vector ) {
return uf::vector::divide( *this, vector );
return uf::vector::divide_( *this, vector );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,4>& pod::Vector<T,4>::operator+=( T scalar ) {
return uf::vector::add( *this, scalar );
return uf::vector::add_( *this, scalar );
}
template<typename T> // Multiplication with scalar
inline pod::Vector<T,4>& pod::Vector<T,4>::operator-=( T scalar ) {
return uf::vector::subtract( *this, scalar );
return uf::vector::subtract_( *this, scalar );
}
template<typename T> // Multiplication set with scalar
inline pod::Vector<T,4>& pod::Vector<T,4>::operator *=( T scalar ) {
return uf::vector::multiply( *this, scalar );
return uf::vector::multiply_( *this, scalar );
}
template<typename T> // Division set with scalar
inline pod::Vector<T,4>& pod::Vector<T,4>::operator /=( T scalar ) {
return uf::vector::divide( *this, scalar );
return uf::vector::divide_( *this, scalar );
}
template<typename T> // Equality check between two vectors (equals)
inline bool pod::Vector<T,4>::operator==( const pod::Vector<T,4>& vector ) const {

View File

@ -31,13 +31,15 @@ namespace ext {
ext::RENDERER::enums::Type::type_t type = 0;
size_t components = 0;
bool operator==( const AttributeDescriptor& right ) const { return
bool operator==( const AttributeDescriptor& right ) const { return name == right.name;
/*
offset == right.offset &&
size == right.size &&
format == right.format &&
name == right.name &&
type == right.type &&
components == right.components;
*/
}
bool operator!=( const AttributeDescriptor& right ) const { return !(*this == right); };
};
@ -323,8 +325,4 @@ namespace pod {
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
}
#include <uf/ext/meshopt/meshopt.h>
#include "mesh.inl"
}

View File

@ -1,163 +0,0 @@
#if 0
template<typename T, typename U>
void uf::Mesh<T, U>::initialize( size_t o ) {
this->optimize(o);
if ( this->indices.empty() ) this->generateIndices();
this->updateDescriptor();
}
template<typename T, typename U>
void uf::Mesh<T, U>::expand( bool check ) {
if ( this->indices.empty() ) return;
uf::stl::vector<vertex_t> _vertices = std::move( this->vertices );
this->vertices.clear();
this->vertices.reserve( this->indices.size() );
if ( !check ) {
for ( auto& index : this->indices ) this->vertices.emplace_back( _vertices[index] );
} else {
uf::stl::vector<vertex_t> cache;
bool valid = true;
cache.reserve(3);
for ( auto& index : this->indices ) {
// flush cache
if ( cache.size() == 3 ) {
if ( valid ) {
this->vertices.emplace_back(cache[0]);
this->vertices.emplace_back(cache[1]);
this->vertices.emplace_back(cache[2]);
}
cache.clear();
valid = true;
}
// invalid index, mark cache as invalid
if ( index >= _vertices.size() ) {
UF_MSG_DEBUG("Invalid index: Max: " << _vertices.size() << "\tGot: " << index);
valid = false;
cache.emplace_back( cache.empty() ? vertex_t{} : cache.back() );
continue;
}
// fill cache
cache.emplace_back( _vertices[index] );
}
}
this->generateIndices();
this->updateDescriptor();
}
template<typename T, typename U>
void uf::Mesh<T, U>::updateDescriptor() {
attributes.vertex.size = sizeof(vertex_t);
attributes.vertex.length = this->vertices.size();
attributes.vertex.pointer = &this->vertices[0];
attributes.vertex.descriptor = vertex_t::descriptor;
attributes.index.size = sizeof(indices_t);
attributes.index.length = this->indices.size();
attributes.index.pointer = &this->indices[0];
}
template<typename T, typename U>
void uf::Mesh<T, U>::destroy() {
this->indices.clear();
this->vertices.clear();
}
template<typename T, typename U>
uf::Mesh<T,U> uf::Mesh<T,U>::simplify( float threshold ) {
size_t target = size_t(this->indices.size() * threshold);
float error = 1e-2f;
uf::Mesh<T,U> lod;
lod.indices.resize(this->indices.size());
lod.indices.resize(meshopt_simplify(&lod.indices[0], &this->indices[0], this->indices.size(), (float*) &this->vertices[0].position, this->vertices.size(), sizeof(T), target, error));
lod.vertices.resize(lod.indices.size() < this->vertices.size() ? lod.indices.size() : this->vertices.size()); // note: this is just to reduce the cost of resize()
lod.vertices.resize(meshopt_optimizeVertexFetch(&lod.vertices[0], &lod.indices[0], lod.indices.size(), &this->vertices[0], this->vertices.size(), sizeof(T)));
return lod;
}
template<typename T, typename U>
void uf::Mesh<T,U>::optimize( size_t o ) {
#if UF_USE_MESHOPTIMIZER
ext::meshopt::optimize( *this, o );
#endif
this->updateDescriptor();
}
template<typename T, typename U>
void uf::Mesh<T,U>::insert( const uf::Mesh<T,U>& mesh ) {
size_t startVertices = this->vertices.size();
size_t startIndices = this->indices.size();
this->vertices.reserve( startVertices + mesh.vertices.size() );
this->indices.reserve( startIndices + mesh.indices.size() );
for ( auto& v : mesh.vertices ) this->vertices.emplace_back( v );
for ( auto& i : mesh.indices ) this->indices.emplace_back( i + startVertices );
this->updateDescriptor();
}
template<typename T, typename U>
void uf::Mesh<T,U>::resizeVertices( size_t n ) {
this->vertices.resize(n);
this->updateDescriptor();
}
template<typename T, typename U>
void uf::Mesh<T,U>::resizeIndices( size_t n ) {
this->indices.resize(n);
this->updateDescriptor();
}
//
template<typename T, typename U>
bool pod::VaryingMesh::is() const {
#if 0
return uf::pointeredUserdata::is<uf::Mesh<T,U>>();
#else
if ( attributes.vertex.descriptor.size() != T::descriptor.size() ||
// vertex types are the same size
attributes.vertex.size != sizeof(T) ||
// index types are the same size
attributes.index.size != sizeof(U) ) return false;
for ( size_t i = 0; i < attributes.vertex.descriptor.size(); ++i ) {
if ( attributes.vertex.descriptor[i].offset != attributes.vertex.descriptor[i].offset || attributes.vertex.descriptor[i].size != attributes.vertex.descriptor[i].size || attributes.vertex.descriptor[i].components != attributes.vertex.descriptor[i].components ) return false;
}
return true;
#if 0
return
// descriptors are the same size
attributes.vertex.descriptor.size() == T::descriptor.size() &&
// vertex types are the same size
attributes.vertex.size == sizeof(T) &&
// index types are the same size
attributes.index.size == sizeof(U) &&
// attributes are the same
std::equal( attributes.vertex.descriptor.begin(), attributes.vertex.descriptor.end(), T::descriptor.begin() );
#endif
#endif
}
template<typename T, typename U>
uf::Mesh<T,U>& pod::VaryingMesh::get() {
if ( !userdata.data ) set<T,U>();
return uf::pointeredUserdata::get<uf::Mesh<T,U>>( userdata );
}
template<typename T, typename U>
const uf::Mesh<T,U>& pod::VaryingMesh::get() const {
UF_ASSERT( userdata.data );
return uf::pointeredUserdata::get<uf::Mesh<T,U>>( userdata );
}
template<typename T, typename U>
void pod::VaryingMesh::set( const uf::Mesh<T, U>& mesh ) {
if ( userdata.data ) uf::pointeredUserdata::destroy( userdata );
userdata = uf::pointeredUserdata::create( mesh );
attributes = mesh.attributes;
}
template<typename T, typename U>
void pod::VaryingMesh::insert( const pod::VaryingMesh& mesh ) {
get<T,U>().insert( mesh.get<T,U>() );
updateDescriptor();
}
template<typename T, typename U>
void pod::VaryingMesh::insert( const uf::Mesh<T, U>& mesh ) {
get<T,U>().insert( mesh );
updateDescriptor();
}
#endif

View File

@ -6,7 +6,7 @@
namespace uf {
template<typename T = spec::Time::time_t>
class UF_API Time {
class /*UF_API*/ Time {
public:
typedef T time_t;
typedef spec::Time::exp_t exp_t;
@ -19,39 +19,41 @@ namespace uf {
static const uf::Time<T>::exp_t microseconds = -6;
static const uf::Time<T>::exp_t nanoseconds = -9;
UF_API_CALL Time(uf::Time<T>::time_t t = 0, uf::Time<T>::exp_t b = spec::Time::unit );
Time(uf::Time<T>::time_t t = 0, uf::Time<T>::exp_t b = spec::Time::unit );
void UF_API_CALL set(uf::Time<T>::time_t t);
void UF_API_CALL set(uf::Time<T>::time_t t, uf::Time<T>::exp_t b);
inline void UF_API_CALL fromSeconds(uf::Time<T>::time_t t);
inline void UF_API_CALL fromMilliseconds(uf::Time<T>::time_t t);
inline void UF_API_CALL fromMicroseconds(uf::Time<T>::time_t t);
inline void UF_API_CALL fromNanoseconds(uf::Time<T>::time_t t);
void set(uf::Time<T>::time_t t);
void set(uf::Time<T>::time_t t, uf::Time<T>::exp_t b);
inline void fromSeconds(uf::Time<T>::time_t t);
inline void fromMilliseconds(uf::Time<T>::time_t t);
inline void fromMicroseconds(uf::Time<T>::time_t t);
inline void fromNanoseconds(uf::Time<T>::time_t t);
uf::Time<T>::time_t UF_API_CALL get() const;
uf::Time<T>::exp_t UF_API_CALL getBase() const;
uf::Time<T>::time_t get() const;
uf::Time<T>::exp_t getBase() const;
uf::Time<T>::time_t UF_API_CALL asBase(uf::Time<T>::exp_t base = spec::Time::unit );
inline uf::Time<T>::time_t UF_API_CALL asSeconds();
inline uf::Time<T>::time_t UF_API_CALL asMilliseconds();
inline uf::Time<T>::time_t UF_API_CALL asMicroseconds();
inline uf::Time<T>::time_t UF_API_CALL asNanoseconds();
double UF_API_CALL asDouble();
uf::Time<T>::time_t asBase(uf::Time<T>::exp_t base = spec::Time::unit );
inline uf::Time<T>::time_t asSeconds();
inline uf::Time<T>::time_t asMilliseconds();
inline uf::Time<T>::time_t asMicroseconds();
inline uf::Time<T>::time_t asNanoseconds();
float asFloat();
double asDouble();
uf::Time<T>& UF_API_CALL operator=( const uf::Time<T>::time_t& t );
UF_API_CALL operator double();
bool UF_API_CALL operator>( const uf::Time<T>::time_t& t );
bool UF_API_CALL operator>=( const uf::Time<T>::time_t& t );
bool UF_API_CALL operator<( const uf::Time<T>::time_t& t );
bool UF_API_CALL operator<=( const uf::Time<T>::time_t& t );
bool UF_API_CALL operator==( const uf::Time<T>::time_t& t );
bool UF_API_CALL operator>( const uf::Time<T>& t );
bool UF_API_CALL operator>=( const uf::Time<T>& t );
bool UF_API_CALL operator<( const uf::Time<T>& t );
bool UF_API_CALL operator<=( const uf::Time<T>& t );
bool UF_API_CALL operator==( const uf::Time<T>& t );
uf::Time<T> UF_API_CALL operator-( const uf::Time<T>& t );
uf::Time<T> UF_API_CALL operator+( const uf::Time<T>& t );
uf::Time<T>& operator=( const uf::Time<T>::time_t& t );
operator float();
operator double();
bool operator>( const uf::Time<T>::time_t& t );
bool operator>=( const uf::Time<T>::time_t& t );
bool operator<( const uf::Time<T>::time_t& t );
bool operator<=( const uf::Time<T>::time_t& t );
bool operator==( const uf::Time<T>::time_t& t );
bool operator>( const uf::Time<T>& t );
bool operator>=( const uf::Time<T>& t );
bool operator<( const uf::Time<T>& t );
bool operator<=( const uf::Time<T>& t );
bool operator==( const uf::Time<T>& t );
uf::Time<T> operator-( const uf::Time<T>& t );
uf::Time<T> operator+( const uf::Time<T>& t );
};
template<typename T = spec::Time::time_t>
class /*UF_API*/ Timer {

View File

@ -61,6 +61,10 @@ inline typename uf::Time<T>::time_t uf::Time<T>::asNanoseconds() {
return this->asBase( uf::Time<T>::nanoseconds );
}
template<typename T>
float uf::Time<T>::asFloat() {
return this->m_time * pow(10.0f, this->m_exp);
}
template<typename T>
double uf::Time<T>::asDouble() {
return this->m_time * pow(10.0, this->m_exp);
}
@ -75,6 +79,10 @@ uf::Time<T>::operator double() {
return this->asDouble();
}
template<typename T>
uf::Time<T>::operator float() {
return this->asFloat();
}
template<typename T>
bool uf::Time<T>::operator>( const uf::Time<T>::time_t& t ) {
return this->m_time > t;
}

View File

@ -65,7 +65,7 @@ void uf::Behaviors::generateGraph() {
}
}
#define UF_BEHAVIOR_POLYFILL UF_BEHAVIOR_POLYFILL_FAST
#define UF_BEHAVIOR_POLYFILL UF_BEHAVIOR_POLYFILL_GRAPH
#define UF_BEHAVIOR_POLYFILL_SAFE(f)\
const bool forwardIteration = true;\
if ( forwardIteration ) for ( auto& behavior : m_behaviors ) behavior.f(self);\
@ -82,12 +82,30 @@ void uf::Behaviors::initialize() {
void uf::Behaviors::tick() {
uf::Object& self = *((uf::Object*) this);
if ( !self.isValid() ) return;
if ( m_graph.tick.empty() ) return;
// if ( !m_graph.tickMT.empty() ) uf::thread::batchWorkers(m_graph.tickMT, false);
/*
UF_TIMER_MULTITRACE_START("Starting " << self.getName() << ": " << self.getUid());
for ( auto& fun : m_graph.tick ) {
fun(self);
UF_TIMER_MULTITRACE("");
}
UF_TIMER_MULTITRACE_END("Finished " << self.getName() << ": " << self.getUid())
*/
UF_BEHAVIOR_POLYFILL(tick)
}
void uf::Behaviors::render() {
uf::Object& self = *((uf::Object*) this);
if ( !self.isValid() ) return;
if ( m_graph.render.empty() ) return;
/*
UF_TIMER_MULTITRACE_START("Starting " << self.getName() << ": " << self.getUid());
for ( auto& fun : m_graph.render ) {
fun(self);
UF_TIMER_MULTITRACE("");
}
UF_TIMER_MULTITRACE_END("Finished " << self.getName() << ": " << self.getUid())
*/
UF_BEHAVIOR_POLYFILL(render)
}
void uf::Behaviors::destroy() {

View File

@ -23,18 +23,14 @@ pod::Graph::Storage uf::graph::storage;
UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Base,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R8G8B8A8_UNORM, color)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, uv)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32_SFLOAT, st)
);
UF_VERTEX_DESCRIPTOR(uf::graph::mesh::ID,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, uv)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32_SFLOAT, st)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, normal)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::ID, R32G32B32_SFLOAT, tangent)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Base, R32G32B32_SFLOAT, normal)
);
UF_VERTEX_DESCRIPTOR(uf::graph::mesh::Skinned,
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R8G8B8A8_UNORM, color)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, uv)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32_SFLOAT, st)
UF_VERTEX_DESCRIPTION(uf::graph::mesh::Skinned, R32G32B32_SFLOAT, normal)
@ -355,14 +351,14 @@ void uf::graph::process( pod::Graph& graph ) {
auto& image = uf::graph::storage.images[keyName];
auto& texture = uf::graph::storage.texture2Ds[keyName];
if ( !texture.generated() ) {
texture.loadFromImage( image );
#if UF_ENV_DREAMCAST
image.clear();
#endif
if ( graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" ) {
texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST;
texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST;
}
texture.loadFromImage( image );
#if UF_ENV_DREAMCAST
image.clear();
#endif
}
}
@ -468,7 +464,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
if ( uf::string::split( node.name, "_" ).back() == "Orientation" ) return;
// for dreamcast, ignore lights if we're baked
#if UF_USE_OPENGL
if ( graph.metadata["lightmapped"].as<bool>() ) if ( graph.lights.count(node.name) > 0 ) return;
// if ( graph.metadata["lightmapped"].as<bool>() )
if ( graph.lights.count(node.name) > 0 ) return;
#endif
//UF_MSG_DEBUG( "Loading " << node.name );
// create child if requested
@ -814,8 +811,10 @@ void uf::graph::initialize( pod::Graph& graph ) {
});
}
void uf::graph::animate( pod::Graph& graph, const uf::stl::string& name, float speed, bool immediate ) {
void uf::graph::animate( pod::Graph& graph, const uf::stl::string& _name, float speed, bool immediate ) {
if ( !(graph.metadata["flags"]["SKINNED"].as<bool>()) ) return;
const uf::stl::string name = graph.name + "/" + _name;
// UF_MSG_DEBUG( graph.name << " " << name );
// if ( graph.animations.count( name ) > 0 ) {
if ( uf::graph::storage.animations.map.count( name ) > 0 ) {
// if already playing, ignore it
@ -844,12 +843,13 @@ void uf::graph::update( pod::Graph& graph, float delta ) {
// no skins
if ( !(graph.metadata["flags"]["SKINNED"].as<bool>()) ) return;
if ( graph.sequence.empty() ) goto UPDATE;
if ( graph.settings.animations.override.a >= 0 ) goto OVERRIDE;
{
uf::stl::string name = graph.sequence.front();
pod::Animation* animation = &uf::graph::storage.animations.map[name]; // &graph.animations[name];
// std::cout << "ANIMATION: " << name << "\t" << animation->cur << std::endl;
// UF_MSG_DEBUG("ANIMATION: " << name << "\t" << animation->cur);
animation->cur += delta * graph.settings.animations.speed; // * graph.settings.animations.override.speed;
if ( animation->end < animation->cur ) {
animation->cur = graph.settings.animations.loop ? animation->cur - animation->end : 0;
@ -884,7 +884,7 @@ void uf::graph::update( pod::Graph& graph, float delta ) {
goto UPDATE;
}
OVERRIDE:
// std::cout << "OVERRIDED: " << graph.settings.animations.override.a << "\t" << -std::numeric_limits<float>::max() << std::endl;
// UF_MSG_DEBUG("OVERRIDED: " << graph.settings.animations.override.a << "\t" << -std::numeric_limits<float>::max());
for ( auto pair : graph.settings.animations.override.map ) {
graph.nodes[pair.first].transform.position = uf::vector::mix( pair.second.first.position, pair.second.second.position, graph.settings.animations.override.a );
graph.nodes[pair.first].transform.orientation = uf::quaternion::normalize( uf::quaternion::slerp(pair.second.first.orientation, pair.second.second.orientation, graph.settings.animations.override.a) );

View File

@ -17,6 +17,8 @@ UF_BEHAVIOR_TRAITS_CPP(uf::LuaBehavior, ticks = false, renders = false, multithr
#define this (&self)
void uf::LuaBehavior::initialize( uf::Object& self ) {
#if UF_USE_LUA
if ( !ext::lua::enabled ) return;
this->addHook( "asset:Load.%UID%", [&](ext::json::Value& json){
uf::stl::string filename = json["filename"].as<uf::stl::string>();
uf::stl::string category = json["category"].as<uf::stl::string>();

View File

@ -490,7 +490,7 @@ pod::Bullet& ext::bullet::create( uf::Object& object, float radius, float height
return collider;
}
void UF_API ext::bullet::move( pod::Bullet& collider, const pod::Vector3f& v, bool override ) {
void UF_API ext::bullet::setVelocity( pod::Bullet& collider, const pod::Vector3f& v ) {
if ( !collider.body ) return;
collider.body->setLinearVelocity( btVector3( v.x, v.y, v.z ) );
}
@ -537,6 +537,21 @@ void UF_API ext::bullet::activateCollision( pod::Bullet& collider, bool enabled
collider.body->activate(enabled);
}
float UF_API ext::bullet::rayCast( const pod::Vector3f& from, const pod::Vector3f& to ) {
btVector3 _from(from.x, from.y, from.z);
btVector3 _to(to.x, to.y, to.z);
btCollisionWorld::ClosestRayResultCallback res(_from, _to);
ext::bullet::dynamicsWorld->rayTest(_from, _to, res);
if ( !res.hasHit() ) return -1.0;
/*
float length = uf::vector::distanceSquared( from, to );
float depth = uf::vector::distanceSquared( from, pod::Vector3f{ res.m_hitPointWorld.getX(), res.m_hitPointWorld.getY(), res.m_hitPointWorld.getZ() } );
return depth / length;
*/
return uf::vector::distance( from, pod::Vector3f{ res.m_hitPointWorld.getX(), res.m_hitPointWorld.getY(), res.m_hitPointWorld.getZ() } );
}
void UF_API ext::bullet::debugDraw( uf::Object& object ) {
auto& mesh = ext::bullet::debugDrawer.getMesh();
if ( !mesh.vertex.count ) return;

View File

@ -232,149 +232,288 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
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 primitiveID = 0;
*/
uf::stl::vector<uf::graph::mesh::Skinned> vertices;
uf::stl::vector<uint32_t> indices;
for ( auto& p : m.primitives ) {
vertices.clear();
indices.clear();
auto& primitive = primitives.emplace_back();
#if UF_USE_VULKAN
bool full = true;
#else
bool full = graph.metadata["flags"]["SKINNED"].as<bool>();
#endif
if ( full ) {
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
uf::stl::vector<uf::graph::mesh::Skinned> vertices;
uf::stl::vector<uint32_t> indices;
for ( auto& p : m.primitives ) {
vertices.clear();
indices.clear();
auto& primitive = primitives.emplace_back();
struct Attribute {
uf::stl::string name = "";
size_t components = 1;
uf::stl::vector<float> floats;
uf::stl::vector<uint16_t> ints;
};
struct Attribute {
uf::stl::string name = "";
size_t components = 1;
uf::stl::vector<float> floats;
uf::stl::vector<uint16_t> ints;
};
uf::stl::unordered_map<uf::stl::string, Attribute> attributes = {
{"POSITION", {}},
{"TEXCOORD_0", {}},
{"NORMAL", {}},
{"TANGENT", {}},
{"JOINTS_0", {}},
{"WEIGHTS_0", {}},
};
uf::stl::unordered_map<uf::stl::string, Attribute> attributes = {
{"POSITION", {}},
{"TEXCOORD_0", {}},
{"NORMAL", {}},
{"TANGENT", {}},
{"JOINTS_0", {}},
{"WEIGHTS_0", {}},
};
for ( auto& kv : attributes ) {
auto& attribute = kv.second;
attribute.name = kv.first;
auto it = p.attributes.find(attribute.name);
if ( it == p.attributes.end() ) continue;
for ( auto& kv : attributes ) {
auto& attribute = kv.second;
attribute.name = kv.first;
auto it = p.attributes.find(attribute.name);
if ( it == p.attributes.end() ) continue;
auto& accessor = model.accessors[it->second];
auto& view = model.bufferViews[accessor.bufferView];
if ( attribute.name == "POSITION" ) {
vertices.resize(accessor.count);
primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
auto& accessor = model.accessors[it->second];
auto& view = model.bufferViews[accessor.bufferView];
if ( attribute.name == "POSITION" ) {
vertices.resize(accessor.count);
primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
primitive.instance.bounds.min.x = -primitive.instance.bounds.min.x;
primitive.instance.bounds.max.x = -primitive.instance.bounds.max.x;
}
}
if ( attribute.name == "JOINTS_0" ) {
auto* buffer = reinterpret_cast<const uint16_t*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(uint16_t);
size_t len = accessor.count * attribute.components;
attribute.ints.assign( &buffer[0], &buffer[len] );
} else {
auto* buffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(float);
size_t len = accessor.count * attribute.components;
attribute.floats.assign( &buffer[0], &buffer[len] );
}
}
for ( size_t i = 0; i < vertices.size(); ++i ) {
#define ITERATE_ATTRIBUTE( name, member )\
if ( !attributes[name].ints.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].ints[i * attributes[name].components + j];\
} else if ( !attributes[name].floats.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].floats[i * attributes[name].components + j];\
}
auto& vertex = vertices[i];
ITERATE_ATTRIBUTE("POSITION", position);
ITERATE_ATTRIBUTE("TEXCOORD_0", uv);
ITERATE_ATTRIBUTE("NORMAL", normal);
ITERATE_ATTRIBUTE("TANGENT", tangent);
ITERATE_ATTRIBUTE("JOINTS_0", joints);
ITERATE_ATTRIBUTE("WEIGHTS_0", weights);
#undef ITERATE_ATTRIBUTE
// required due to reverse-Z projection matrix flipping the X axis as well
// default is to proceed with this
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
primitive.instance.bounds.min.x = -primitive.instance.bounds.min.x;
primitive.instance.bounds.max.x = -primitive.instance.bounds.max.x;
vertex.position.x = -vertex.position.x;
vertex.normal.x = -vertex.normal.x;
vertex.tangent.x = -vertex.tangent.x;
}
}
if ( attribute.name == "JOINTS_0" ) {
auto* buffer = reinterpret_cast<const uint16_t*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(uint16_t);
size_t len = accessor.count * attribute.components;
attribute.ints.assign( &buffer[0], &buffer[len] );
} else {
auto* buffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(float);
size_t len = accessor.count * attribute.components;
attribute.floats.assign( &buffer[0], &buffer[len] );
if ( p.indices > -1 ) {
auto& accessor = model.accessors[p.indices];
auto& view = model.bufferViews[accessor.bufferView];
auto& buffer = model.buffers[view.buffer];
indices.reserve( static_cast<uint32_t>(accessor.count) );
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) indices.emplace_back(buf[index]);
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
switch (accessor.componentType) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
auto* buf = static_cast<const uint32_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
auto* buf = static_cast<const uint16_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
auto* buf = static_cast<const uint8_t*>( pointer );
COPY_INDICES()
break;
}
}
#undef COPY_INDICES
}
primitive.instance.materialID = p.material;
primitive.instance.primitiveID = primitives.size() - 1;
primitive.instance.meshID = meshID;
primitive.instance.objectID = 0;
primitive.drawCommand.indices = indices.size();
primitive.drawCommand.instances = 1;
primitive.drawCommand.indexID = 0;
primitive.drawCommand.vertexID = 0;
primitive.drawCommand.instanceID = 0;
primitive.drawCommand.vertices = vertices.size();
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
.indices = indices.size(),
.instances = 1,
.indexID = mesh.index.count,
.vertexID = mesh.vertex.count,
.instanceID = 0,
.vertices = vertices.size(),
});
mesh.insertVertices(vertices);
mesh.insertIndices(indices);
}
} else {
mesh.bind<uf::graph::mesh::Base, uint32_t>();
uf::stl::vector<uf::graph::mesh::Base> vertices;
uf::stl::vector<uint32_t> indices;
for ( auto& p : m.primitives ) {
vertices.clear();
indices.clear();
auto& primitive = primitives.emplace_back();
for ( size_t i = 0; i < vertices.size(); ++i ) {
#define ITERATE_ATTRIBUTE( name, member )\
if ( !attributes[name].ints.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].ints[i * attributes[name].components + j];\
} else if ( !attributes[name].floats.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].floats[i * attributes[name].components + j];\
struct Attribute {
uf::stl::string name = "";
size_t components = 1;
uf::stl::vector<float> floats;
uf::stl::vector<uint16_t> ints;
};
uf::stl::unordered_map<uf::stl::string, Attribute> attributes = {
{"POSITION", {}},
{"TEXCOORD_0", {}},
{"NORMAL", {}},
};
for ( auto& kv : attributes ) {
auto& attribute = kv.second;
attribute.name = kv.first;
auto it = p.attributes.find(attribute.name);
if ( it == p.attributes.end() ) continue;
auto& accessor = model.accessors[it->second];
auto& view = model.bufferViews[accessor.bufferView];
if ( attribute.name == "POSITION" ) {
vertices.resize(accessor.count);
primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
primitive.instance.bounds.min.x = -primitive.instance.bounds.min.x;
primitive.instance.bounds.max.x = -primitive.instance.bounds.max.x;
}
}
auto& vertex = vertices[i];
ITERATE_ATTRIBUTE("POSITION", position);
ITERATE_ATTRIBUTE("TEXCOORD_0", uv);
ITERATE_ATTRIBUTE("NORMAL", normal);
ITERATE_ATTRIBUTE("TANGENT", tangent);
ITERATE_ATTRIBUTE("JOINTS_0", joints);
ITERATE_ATTRIBUTE("WEIGHTS_0", weights);
#undef ITERATE_ATTRIBUTE
// required due to reverse-Z projection matrix flipping the X axis as well
// default is to proceed with this
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
vertex.position.x = -vertex.position.x;
vertex.normal.x = -vertex.normal.x;
vertex.tangent.x = -vertex.tangent.x;
}
}
if ( p.indices > -1 ) {
auto& accessor = model.accessors[p.indices];
auto& view = model.bufferViews[accessor.bufferView];
auto& buffer = model.buffers[view.buffer];
indices.reserve( static_cast<uint32_t>(accessor.count) );
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) indices.emplace_back(buf[index]);
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
switch (accessor.componentType) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
auto* buf = static_cast<const uint32_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
auto* buf = static_cast<const uint16_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
auto* buf = static_cast<const uint8_t*>( pointer );
COPY_INDICES()
break;
if ( attribute.name == "JOINTS_0" ) {
auto* buffer = reinterpret_cast<const uint16_t*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(uint16_t);
size_t len = accessor.count * attribute.components;
attribute.ints.assign( &buffer[0], &buffer[len] );
} else {
auto* buffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
attribute.components = accessor.ByteStride(view) / sizeof(float);
size_t len = accessor.count * attribute.components;
attribute.floats.assign( &buffer[0], &buffer[len] );
}
}
#undef COPY_INDICES
for ( size_t i = 0; i < vertices.size(); ++i ) {
#define ITERATE_ATTRIBUTE( name, member )\
if ( !attributes[name].ints.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].ints[i * attributes[name].components + j];\
} else if ( !attributes[name].floats.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].floats[i * attributes[name].components + j];\
}
auto& vertex = vertices[i];
ITERATE_ATTRIBUTE("POSITION", position);
ITERATE_ATTRIBUTE("TEXCOORD_0", uv);
ITERATE_ATTRIBUTE("NORMAL", normal);
#undef ITERATE_ATTRIBUTE
// required due to reverse-Z projection matrix flipping the X axis as well
// default is to proceed with this
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
vertex.position.x = -vertex.position.x;
vertex.normal.x = -vertex.normal.x;
}
}
if ( p.indices > -1 ) {
auto& accessor = model.accessors[p.indices];
auto& view = model.bufferViews[accessor.bufferView];
auto& buffer = model.buffers[view.buffer];
indices.reserve( static_cast<uint32_t>(accessor.count) );
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) indices.emplace_back(buf[index]);
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
switch (accessor.componentType) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
auto* buf = static_cast<const uint32_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
auto* buf = static_cast<const uint16_t*>( pointer );
COPY_INDICES()
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
auto* buf = static_cast<const uint8_t*>( pointer );
COPY_INDICES()
break;
}
}
#undef COPY_INDICES
}
primitive.instance.materialID = p.material;
primitive.instance.primitiveID = primitives.size() - 1;
primitive.instance.meshID = meshID;
primitive.instance.objectID = 0;
primitive.drawCommand.indices = indices.size();
primitive.drawCommand.instances = 1;
primitive.drawCommand.indexID = 0;
primitive.drawCommand.vertexID = 0;
primitive.drawCommand.instanceID = 0;
primitive.drawCommand.vertices = vertices.size();
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
.indices = indices.size(),
.instances = 1,
.indexID = mesh.index.count,
.vertexID = mesh.vertex.count,
.instanceID = 0,
.vertices = vertices.size(),
});
mesh.insertVertices(vertices);
mesh.insertIndices(indices);
}
primitive.instance.materialID = p.material;
primitive.instance.primitiveID = primitives.size() - 1;
primitive.instance.meshID = meshID;
primitive.instance.objectID = 0;
primitive.drawCommand.indices = indices.size();
primitive.drawCommand.instances = 1;
primitive.drawCommand.indexID = 0;
primitive.drawCommand.vertexID = 0;
primitive.drawCommand.instanceID = 0;
primitive.drawCommand.vertices = vertices.size();
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
.indices = indices.size(),
.instances = 1,
.indexID = mesh.index.count,
.vertexID = mesh.vertex.count,
.instanceID = 0,
.vertices = vertices.size(),
});
mesh.insertVertices(vertices);
mesh.insertIndices(indices);
}
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();

View File

@ -1,5 +1,6 @@
#include <uf/ext/lua/lua.h>
#if UF_USE_LUA
bool ext::lua::enabled = true;
sol::state ext::lua::state;
uf::stl::string ext::lua::main = uf::io::root + "/scripts/main.lua";
uf::stl::unordered_map<uf::stl::string, uf::stl::string> ext::lua::modules;
@ -162,6 +163,8 @@ namespace binds {
}
void ext::lua::initialize() {
if ( !ext::lua::enabled ) return;
state.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table, sol::lib::math, sol::lib::string, sol::lib::ffi, sol::lib::jit);
// load modules
@ -269,6 +272,8 @@ bool ext::lua::run( const uf::stl::string& s, bool safe ) {
pod::LuaScript ext::lua::script( const uf::stl::string& filename ) {
pod::LuaScript script;
if ( !ext::lua::enabled ) return script;
script.file = filename;
script.env = sol::environment( ext::lua::state, sol::create, ext::lua::state.globals() );
return script;

View File

@ -1,4 +1,4 @@
#include <uf/utils/mesh/mesh.h>
#include <uf/ext/meshopt/meshopt.h>
#if UF_USE_MESHOPTIMIZER
#include <meshoptimizer.h>
#endif

View File

@ -5,6 +5,7 @@
#include <uf/utils/memory/pool.h>
#include <uf/utils/string/io.h>
#include <uf/ext/vorbis/vorbis.h>
#include <uf/utils/audio/audio.h>
#include <iostream>
namespace {
@ -13,37 +14,51 @@ namespace {
}
void ext::al::initialize() {
/*
this->m_device = alcOpenDevice(NULL);
if ( !this->m_device ) { this->checkError(__LINE__);
return false;
#if UF_USE_ALUT
::device = alcOpenDevice(alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
assert(::device);
::context = alcCreateContext(::device, NULL);
assert(::context);
alcMakeContextCurrent(::context);
if ( alutInit(NULL, NULL) != AL_TRUE ) {
uf::audio::muted = true;
UF_EXCEPTION("AL error: " << alutGetErrorString( alutGetError() ) );
}
#else
::device = alcOpenDevice(NULL);
if ( !::device ) {
UF_EXCEPTION(ext::al::getError());
}
ALboolean enumeration = alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT");
if (enumeration == AL_FALSE) { this->checkError(__LINE__);
if (enumeration == AL_FALSE) {
// do something
std::cout << "Device enumeration not available" << std::endl;
UF_EXCEPTION("Device enumeration not available");
}
this->m_context = alcCreateContext(this->m_device, NULL);
if ( !alcMakeContextCurrent(this->m_context) ) {
this->checkError(__LINE__);
return false;
}
return this->m_initialized = true;
*/
if ( alutInit(NULL, NULL) != AL_TRUE ) {
UF_EXCEPTION("AL error: " << alutGetErrorString( alutGetError() ) );
::context = alcCreateContext(::device, NULL);
if ( !alcMakeContextCurrent(::context) ) {
UF_EXCEPTION(ext::al::getError());
}
#endif
}
void ext::al::destroy() {
/*
this->m_device = alcGetContextsDevice(this->m_context);
#if UF_USE_ALUT
::context = alcGetCurrentContext();
alcMakeContextCurrent(NULL);
alcDestroyContext(this->m_context);
alcCloseDevice(this->m_device);
*/
alcDestroyContext(::context);
alcCloseDevice(::device);
alutExit();
#else
::device = alcGetContextsDevice(::context);
alcMakeContextCurrent(NULL);
alcDestroyContext(::context);
alcCloseDevice(::device);
#endif
}
#if 0
void ext::al::listener( ALenum name, ALfloat x ) { AL_CHECK_RESULT(alListenerf( name, x )); }
@ -89,7 +104,7 @@ uf::audio::Metadata* ext::al::create( const uf::stl::string& filename, bool stre
uf::audio::Metadata* pointer = (memoryPool) ? &memoryPool->alloc<uf::audio::Metadata>() : new uf::audio::Metadata;
#endif
uf::audio::Metadata& metadata = *pointer;
metadata.filename = filename;
metadata.filename = uf::io::resolveURI(filename);
metadata.settings.streamed = streamed;
metadata.settings.buffers = buffers;
metadata.extension = uf::io::extension( metadata.filename );

View File

@ -13,8 +13,10 @@
#define VERBOSE false
#define VERBOSE_SUBMIT false
namespace {
size_t culled = 0;
}
size_t ext::opengl::CommandBuffer::preallocate = 8;
void ext::opengl::CommandBuffer::initialize( Device& device ) {
this->device = &device;
if ( !this->mutex ) this->mutex = new std::mutex;
@ -93,16 +95,8 @@ void ext::opengl::CommandBuffer::record( const CommandBuffer& commandBuffer ) {
}
void ext::opengl::CommandBuffer::submit() {
if ( infos.empty() ) return;
mutex->lock();
#if UF_ENV_DREAMCAST
static GLint maxTextures = 80;
#else
static GLint maxTextures = 0;
if ( maxTextures <= 0 ) {
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextures);
}
#endif
//UF_TIMER_MULTITRACE_START("Starting command buffer submission: " << this);
for ( auto& info : infos ) {
CommandBuffer::Info* header = (CommandBuffer::Info*) (void*) info;
switch ( header->type ) {
@ -112,23 +106,32 @@ void ext::opengl::CommandBuffer::submit() {
GL_ERROR_CHECK(glClearDepth(info->depth));
GL_ERROR_CHECK(glClear(info->bits));
// GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0]));
//UF_TIMER_MULTITRACE("Command::CLEAR");
} break;
case ext::opengl::enums::Command::VIEWPORT: {
InfoViewport* info = (InfoViewport*) header;
GL_ERROR_CHECK(glViewport(info->corner[0], info->corner[1], info->size[0], info->size[1]));
//UF_TIMER_MULTITRACE("Command::VIEWPORT");
} break;
case ext::opengl::enums::Command::VARIANT: {
InfoVariant* info = (InfoVariant*) header;
if ( info->lambda ) info->lambda();
//UF_TIMER_MULTITRACE("Command::VARIANT");
} break;
case ext::opengl::enums::Command::DRAW: {
InfoDraw* info = (InfoDraw*) header;
drawIndexed( *info );
//UF_TIMER_MULTITRACE("Command::DRAW");
} break;
default: {
} break;
}
}
if ( ::culled ) {
// UF_MSG_DEBUG("Culled " << ::culled << " meshes.");
::culled = 0;
}
//UF_TIMER_MULTITRACE_END("Finished command buffer submission: " << this);
state = 3;
mutex->unlock();
}
@ -156,28 +159,106 @@ pod::Matrix4f ext::opengl::CommandBuffer::bindUniform( const ext::opengl::Buffer
return uniform->projection * uniform->modelView;
#endif
}
void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::InfoDraw& drawInfo ) {
if ( drawInfo.matrices.model && drawInfo.matrices.view && drawInfo.matrices.projection ) {
pod::Matrix4f modelView = uf::matrix::multiply( *drawInfo.matrices.view, *drawInfo.matrices.model );
GL_ERROR_CHECK(glMatrixMode(GL_MODELVIEW));
GL_ERROR_CHECK(glLoadMatrixf( &modelView[0] ));
namespace {
bool inside( const pod::Instance& instance, const pod::Matrix4f& mat ) {
bool visible = false;
#if 1
pod::Vector4f corners[8] = {
pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f },
GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION));
GL_ERROR_CHECK(glLoadMatrixf( (float*) drawInfo.matrices.projection ));
} else if ( drawInfo.matrices.model && drawInfo.matrices.projection ) {
GL_ERROR_CHECK(glMatrixMode(GL_MODELVIEW));
GL_ERROR_CHECK(glLoadMatrixf( (float*) drawInfo.matrices.model ));
pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f },
};
//#pragma unroll
for ( uint p = 0; p < 8; ++p ) {
pod::Vector4f t = uf::matrix::multiply( mat, corners[p] );
float w = t.w * 1.25f;
if ( -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && -w <= t.z && t.z <= w ) return true;
}
#else
pod::Vector4f planes[6]; {
//#pragma unroll
for ( auto i = 0; i < 3; ++i )
//#pragma unroll
for ( auto j = 0; j < 2; ++j) {
float x = mat[4*0+3] + (j == 0 ? mat[4*0+i] : -mat[4*0+i]);
float y = mat[4*1+3] + (j == 0 ? mat[4*1+i] : -mat[4*1+i]);
float z = mat[4*2+3] + (j == 0 ? mat[4*2+i] : -mat[4*2+i]);
float w = mat[4*3+3] + (j == 0 ? mat[4*3+i] : -mat[4*3+i]);
float length = 1.0f / sqrt( x * x + y * y + z * z );
planes[i*2+j] = pod::Vector4f{ x * length, y * length, z * length, w * length };
}
}
#if 0
//#pragma unroll
for ( auto p = 0; p < 6; ++p ) {
float d = std::max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x)
+ std::max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y);
+ std::max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z);
if ( d > -planes[p].w ) return true;
}
#else
pod::Vector4f corners[8] = {
pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f },
pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0f },
GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION));
GL_ERROR_CHECK(glLoadMatrixf( (float*) drawInfo.matrices.projection ));
} else if ( drawInfo.matrices.view && drawInfo.matrices.projection ) {
GL_ERROR_CHECK(glMatrixMode(GL_MODELVIEW));
GL_ERROR_CHECK(glLoadMatrixf( (float*) drawInfo.matrices.view ));
GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION));
GL_ERROR_CHECK(glLoadMatrixf( (float*) drawInfo.matrices.projection ));
pod::Vector4f{ instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f },
pod::Vector4f{ instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0f },
};
//#pragma unroll
for ( uint p = 0; p < 8; ++p ) corners[p] = uf::matrix::multiply( mat, corners[p] );
//#pragma unroll
for ( uint p = 0; p < 6; ++p ) {
//#pragma unroll
for ( uint q = 0; q < 8; ++q ) {
if ( uf::vector::dot( corners[q], planes[p] ) > 0 ) return true;
}
return false;
}
#endif
#endif
return visible;
}
}
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 ( 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) ) {
pod::Instance& instance = *(pod::Instance*) drawInfo.attributes.instance.pointer;
pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (*drawInfo.matrices.model);
// pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (instance.model);
// pod::Matrix4f mat = uf::matrix::multiply( projection, modelView );
bool visible = inside( instance, mat );
drawCommand.instances = visible ? 1 : 0;
if ( !visible ) ++::culled;
}
if ( drawCommand.instances == 0 ) return;
}
GL_ERROR_CHECK(glMatrixMode(GL_MODELVIEW));
GL_ERROR_CHECK(glLoadMatrixf( &modelView[0] ));
GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION));
GL_ERROR_CHECK(glLoadMatrixf( &projection[0] ));
if ( drawInfo.descriptor.cullMode == GL_NONE ) {
GL_ERROR_CHECK(glDisable(GL_CULL_FACE));
@ -207,37 +288,35 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::
}
if ( drawInfo.textures.primary.image && drawInfo.attributes.uv.pointer ) {
static GLuint previous = 0;
if ( previous != drawInfo.textures.primary.image ) {
previous = drawInfo.textures.primary.image;
GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE0));
GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE0));
GL_ERROR_CHECK(glEnable(drawInfo.textures.primary.viewType));
GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image));
GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
}
// static GLuint previous = 0;
// if ( previous != drawInfo.textures.primary.image ) previous = drawInfo.textures.primary.image;
GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE0));
GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE0));
GL_ERROR_CHECK(glEnable(drawInfo.textures.primary.viewType));
GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image));
GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.uv.stride, drawInfo.attributes.uv.pointer));
}
if ( drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer ) {
static GLuint previous = 0;
if ( previous != drawInfo.textures.secondary.image ) {
previous = drawInfo.textures.secondary.image;
GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE1));
GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE1));
GL_ERROR_CHECK(glEnable(drawInfo.textures.secondary.viewType));
GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glBindTexture(drawInfo.textures.secondary.viewType, drawInfo.textures.secondary.image));
GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE));
GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, drawInfo.attributes.st.pointer));
}
// static GLuint previous = 0;
// if ( previous != drawInfo.textures.secondary.image ) previous = drawInfo.textures.secondary.image;
GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE1));
GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE1));
GL_ERROR_CHECK(glEnable(drawInfo.textures.secondary.viewType));
GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glBindTexture(drawInfo.textures.secondary.viewType, drawInfo.textures.secondary.image));
GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE));
GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, drawInfo.attributes.st.pointer));
#if UF_ENV_DREAMCAST
GL_ERROR_CHECK(glDisable(GL_BLEND));
#endif
}
if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glNormalPointer(GL_FLOAT, drawInfo.attributes.normal.stride, drawInfo.attributes.normal.pointer));
if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glColorPointer(3, GL_FLOAT, drawInfo.attributes.color.stride, drawInfo.attributes.color.pointer));
if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glColorPointer(4, GL_UNSIGNED_BYTE, drawInfo.attributes.color.stride, drawInfo.attributes.color.pointer));
GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, drawInfo.attributes.position.stride, drawInfo.attributes.position.pointer));
GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, drawInfo.attributes.index.length, indicesType, drawInfo.attributes.index.pointer));

View File

@ -404,10 +404,16 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
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;
// else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute;
// else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute;
}
drawCommandInfo.attributes.instance.pointer = &instance;
drawCommandInfo.attributes.instance.length = sizeof(instance);
drawCommandInfo.attributes.indirect.pointer = &drawCommand;
drawCommandInfo.attributes.indirect.length = sizeof(drawCommand);
drawCommandInfo.matrices.model = &instance.model;
drawCommandInfo.matrices.view = &viewports->matrices[0].view;
drawCommandInfo.matrices.projection = &viewports->matrices[0].projection;
@ -528,275 +534,4 @@ ext::opengl::GraphicDescriptor::hash_t ext::opengl::GraphicDescriptor::hash() co
return hash;
}
ext::json::Value ext::opengl::definitionToJson(/*const*/ ext::json::Value& definition ) {
ext::json::Value member;
// is object
if ( !ext::json::isNull(definition["members"]) ) {
ext::json::forEach(definition["members"], [&](/*const*/ ext::json::Value& value){
uf::stl::string key = uf::string::split(value["name"].as<uf::stl::string>(), " ").back();
member[key] = ext::opengl::definitionToJson(value);
});
// is primitive
} else if ( !ext::json::isNull(definition["value"]) ) {
// is array of structs
if ( definition["struct"].as<bool>() ) {
ext::json::forEach(definition["value"], [&](/*const*/ ext::json::Value& value){
ext::json::Value parsed;
parsed["name"] = definition["name"];
parsed["size"] = definition["size"];
parsed["struct"] = definition["struct"];
parsed["members"] = value;
parsed = ext::opengl::definitionToJson(parsed);
member.emplace_back(parsed);
});
} else {
member = definition["value"];
}
}
return member;
}
ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& payload, const ext::json::Value& definition ) {
size_t bufferLen = definition["size"].as<size_t>();
ext::opengl::userdata_t userdata;
userdata.create(bufferLen);
uint8_t* byteBuffer = (uint8_t*) (void*) userdata;
uint8_t* byteBufferStart = byteBuffer;
uint8_t* byteBufferEnd = byteBuffer + bufferLen;
#if UF_JSON_NLOHMANN_ORDERED
// JSON is ordered, we can just push directly
#define UF_SHADER_TRACK_NAMES 0
#if UF_SHADER_TRACK_NAMES
uf::stl::vector<uf::stl::string> variableName;
#endif
std::function<void(const ext::json::Value&)> parse = [&]( const ext::json::Value& value ){
// is array or object
#if UF_SHADER_TRACK_NAMES
if ( ext::json::isObject(value) ) {
ext::json::forEach(value, [&]( const uf::stl::string& name, const ext::json::Value& member ){
#if UF_SHADER_TRACK_NAMES
variableName.emplace_back(name);
#endif
parse(member);
});
#if UF_SHADER_TRACK_NAMES
if ( !variableName.empty() ) variableName.pop_back();
#endif
return;
}
if ( ext::json::isArray(value) ) {
ext::json::forEach(value, [&]( size_t i, const ext::json::Value& element ){
variableName.emplace_back("["+std::to_string(i)+"]");
parse(element);
});
#if UF_SHADER_TRACK_NAMES
if ( !variableName.empty() ) variableName.pop_back();
#endif
return;
}
#else
if ( ext::json::isArray(value) || ext::json::isObject(value) ) {
ext::json::forEach(value, parse);
return;
}
#endif
#if UF_SHADER_TRACK_NAMES
uf::stl::string path = uf::string::join(variableName, ".");
path = uf::string::replace( path, ".[", "[" );
GL_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump());
#endif
// is strictly an int
if ( value.is<int>(true) ) {
size_t size = sizeof(int32_t);
auto get = value.as<int32_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
// is strictly an unsigned int
} else if ( value.is<size_t>(true) ) {
size_t size = sizeof(uint32_t);
auto get = value.as<uint32_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
// is strictly a float
} else if ( value.is<float>(true) ) {
size_t size = sizeof(float);
auto get = value.as<float>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
}
#if UF_SHADER_TRACK_NAMES
if ( !variableName.empty() ) variableName.pop_back();
#endif
};
#if UF_SHADER_TRACK_NAMES
GL_VALIDATION_MESSAGE("Updating " << name << " in " << filename);
GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif
parse(payload);
#if UF_SHADER_TRACK_NAMES
GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif
#else
auto pushValue = [&]( const uf::stl::string& primitive, const ext::json::Value& input ){
if ( primitive == "bool" ) {
size_t size = sizeof(bool); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<bool>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "int8_t" ) {
size_t size = sizeof(int8_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
// auto get = input.as<int8_t>();
// memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "uint8_t" ) {
size_t size = sizeof(uint8_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
// auto get = input.as<uint8_t>();
// memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "int16_t" ) {
size_t size = sizeof(int16_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
// auto get = input.as<int16_t>();
// memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "uint16_t" ) {
size_t size = sizeof(uint16_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
// auto get = input.as<uint16_t>();
// memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "int32_t" ) {
size_t size = sizeof(int32_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<int32_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "uint32_t" ) {
size_t size = sizeof(uint32_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<int32_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "int64_t" ) {
size_t size = sizeof(int64_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<uint64_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "uint64_t" ) {
size_t size = sizeof(uint64_t); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<uint64_t>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "half" ) {
size_t size = sizeof(float); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
// auto get = input.as<float>();
// memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "float" ) {
size_t size = sizeof(float); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
auto get = input.as<float>();
memcpy( byteBuffer, &get, size );
byteBuffer += size;
} else if ( primitive == "double" ) {
auto get = input.as<double>();
size_t size = sizeof(double); // v["size"].as<size_t>();
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
memcpy( byteBuffer, &get, size );
byteBuffer += size;
}
return true;
};
#define UF_SHADER_TRACK_NAMES 0
#if UF_SHADER_TRACK_NAMES
bool SKIP_ADD = false;
uf::stl::vector<uf::stl::string> variableName;
#endif
std::function<void(const ext::json::Value&, const ext::json::Value&)> parseDefinition = [&](const ext::json::Value& input, const ext::json::Value& definition ){
#if UF_SHADER_TRACK_NAMES
if ( SKIP_ADD ) {
SKIP_ADD = false;
} else {
auto split = uf::string::split(definition["name"].as<uf::stl::string>(), " ");
uf::stl::string type = split.front();
uf::stl::string name = split.back();
variableName.emplace_back(name);
}
#endif
// is object
if ( !ext::json::isNull(definition["members"]) ) {
ext::json::forEach(definition["members"], [&](const ext::json::Value& member){
uf::stl::string key = uf::string::split(member["name"].as<uf::stl::string>(), " ").back();
parseDefinition(input[key], member);
});
// is array or primitive
} else if ( !ext::json::isNull(definition["value"]) ) {
// is object
auto split = uf::string::split(definition["name"].as<uf::stl::string>(), " ");
uf::stl::string type = split.front();
uf::stl::string name = split.back();
std::regex regex("^(?:(.+?)\\<)?(.+?)(?:\\>)?(?:\\[(\\d+)\\])?$");
std::smatch match;
if ( !std::regex_search( type, match, regex ) ) {
std::cout << "Ill formatted typename: " << definition["name"].as<uf::stl::string>() << std::endl;
return;
}
uf::stl::string vectorMatrix = match[1].str();
uf::stl::string primitive = match[2].str();
uf::stl::string arraySize = match[3].str();
if ( ext::json::isObject(input) ) {
ext::json::Value cloned;
cloned["name"] = definition["name"];
cloned["size"] = definition["size"].as<size_t>() / definition["value"].size();
cloned["members"] = definition["value"][0];
parseDefinition( input, cloned );
}
// is array
else if ( ext::json::isArray(input) ) {
ext::json::forEach( input, [&]( size_t i, const ext::json::Value& value){
#if UF_SHADER_TRACK_NAMES
variableName.emplace_back("["+std::to_string(i)+"]");
SKIP_ADD = true;
#endif
parseDefinition(input[i], definition);
});
}
// is primitive
else {
#if UF_SHADER_TRACK_NAMES
uf::stl::string path = uf::string::join(variableName, ".");
path = uf::string::replace( path, ".[", "[" );
GL_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump());
#endif
pushValue( primitive, input );
}
}
#if UF_SHADER_TRACK_NAMES
if ( !variableName.empty() ) variableName.pop_back();
#endif
};
//auto& definitions = metadata["definitions"]["uniforms"][name];
#if UF_SHADER_TRACK_NAMES
GL_VALIDATION_MESSAGE("Updating " << name << " in " << filename);
GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif
parseDefinition(payload, definition);
#if UF_SHADER_TRACK_NAMES
GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif
#endif
return userdata;
}
#endif

View File

@ -169,6 +169,15 @@ void UF_API ext::opengl::initialize() {
}
if ( !jobs.empty() ) uf::thread::batchWorkers( jobs );
// bind shaders
/*
{
ext::opengl::Shader::bind( uf::io::root + "shaders/graph/cull.comp.spv", []( const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic ) {
uf::Mesh::Attribute position = {};
uf::Mesh::Attribute index = {};
uf::Mesh::Attribute indirect = {};
});
}
*/
#if 0
{
ext::opengl::Shader::bind( uf::io::root + "shaders/graph/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) {

View File

@ -193,6 +193,7 @@ const ext::opengl::Buffer& ext::opengl::Shader::getStorageBuffer( const uf::stl:
UF_EXCEPTION("buffer not found: " << name);
}
// JSON shit
#if 0
ext::opengl::userdata_t ext::opengl::Shader::getUniformUserdata( const uf::stl::string& name, const ext::json::Value& payload ) {
if ( !hasUniform(name) ) return false;
return jsonToUserdata(payload, metadata.json["definitions"]["uniforms"][name]);
@ -215,4 +216,5 @@ ext::opengl::userdata_t ext::opengl::Shader::getStorageUserdata( const uf::stl::
if ( !hasStorage(name) ) return false;
return jsonToUserdata(payload, metadata.json["definitions"]["storage"][name]);
}
#endif
#endif

View File

@ -252,7 +252,8 @@ void ext::vorbis::update( uf::Audio::Metadata& metadata ) {
if ( metadata.settings.loopMode == 1 ) metadata.al.source.set( AL_LOOPING, AL_FALSE );
ALint state;
metadata.al.source.get( AL_SOURCE_STATE, &state );
// metadata.al.source.get( AL_SOURCE_STATE, &state );
metadata.al.source.get( AL_SOURCE_STATE, state );
if ( state != AL_PLAYING ) {
if ( !metadata.settings.loop && metadata.stream.consumed >= metadata.info.size ) {
// UF_MSG_INFO("Vorbis stream finished: " << metadata.filename);
@ -264,7 +265,8 @@ void ext::vorbis::update( uf::Audio::Metadata& metadata ) {
}
ALint processed = 0;
metadata.al.source.get(AL_BUFFERS_PROCESSED, &processed);
// metadata.al.source.get(AL_BUFFERS_PROCESSED, &processed);
metadata.al.source.get(AL_BUFFERS_PROCESSED, processed);
// no work need to be done
if ( processed <= 0 ) return;

View File

@ -15,6 +15,8 @@
#define VK_DEBUG_VALIDATION_MESSAGE(x)\
// VK_VALIDATION_MESSAGE(x);
#define UF_SHADER_PARSE_AS_JSON 0
#if UF_SHADER_PARSE_AS_JSON
ext::json::Value ext::vulkan::definitionToJson(/*const*/ ext::json::Value& definition ) {
ext::json::Value member;
// is object
@ -284,7 +286,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
#endif
return userdata;
}
#endif
void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl::string& filename, VkShaderStageFlagBits stage ) {
this->device = &device;
ext::vulkan::Buffers::initialize( device );
@ -327,7 +329,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
{
spirv_cross::Compiler comp( (uint32_t*) &spirv[0], spirv.size() / 4 );
spirv_cross::ShaderResources res = comp.get_shader_resources();
#if UF_SHADER_PARSE_AS_JSON
std::function<ext::json::Value(spirv_cross::TypeID)> parseMembers = [&]( spirv_cross::TypeID type_id ) {
auto parseMember = [&]( auto type_id ){
uf::Serializer payload;
@ -434,7 +436,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
}
return payload;
};
#endif
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType, size_t index ) {
const auto& type = comp.get_type(resource.type_id);
const auto& base_type = comp.get_type(resource.base_type_id);
@ -461,11 +463,13 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
case spv::Dim::DimSubpassData: tname = "SubpassData"; break;
}
uf::stl::string key = std::to_string(binding);
#if UF_SHADER_PARSE_AS_JSON
metadata.json["definitions"]["textures"][key]["name"] = name;
metadata.json["definitions"]["textures"][key]["index"] = index;
metadata.json["definitions"]["textures"][key]["binding"] = binding;
metadata.json["definitions"]["textures"][key]["size"] = arraySize;
metadata.json["definitions"]["textures"][key]["type"] = tname;
#endif
metadata.definitions.textures[binding] = Shader::Metadata::Definition::Texture{
name,
@ -493,6 +497,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
// uniform.create( bufferSize );
}
// generate definition to JSON
#if UF_SHADER_PARSE_AS_JSON
{
metadata.json["definitions"]["uniforms"][name]["name"] = name;
metadata.json["definitions"]["uniforms"][name]["index"] = index;
@ -500,6 +505,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
metadata.json["definitions"]["uniforms"][name]["size"] = bufferSize;
metadata.json["definitions"]["uniforms"][name]["members"] = parseMembers(resource.type_id);
}
#endif
// generate definition to unordered_map
metadata.definitions.uniforms[name] = Shader::Metadata::Definition::Uniform{
name,
@ -510,12 +516,14 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
// generate definition to JSON
#if UF_SHADER_PARSE_AS_JSON
{
metadata.json["definitions"]["storage"][name]["name"] = name;
metadata.json["definitions"]["storage"][name]["index"] = index;
metadata.json["definitions"]["storage"][name]["binding"] = binding;
metadata.json["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id);
}
#endif
metadata.definitions.storage[name] = Shader::Metadata::Definition::Storage{
name,
index,
@ -524,10 +532,10 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
} break;
}
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, binding, arraySize ) );
};
};
//for ( const auto& resource : res.key ) {
#define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\
const auto& resource = res.key[i];\
VK_DEBUG_VALIDATION_MESSAGE("["<<filename<<"] Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding));\
@ -570,6 +578,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
const uf::stl::string name = resource.name;
size_t size = 0; // comp.get_declared_struct_size(type);
// generate definition to JSON
#if UF_SHADER_PARSE_AS_JSON
{
metadata.json["definitions"]["inputs"][name]["name"] = name;
metadata.json["definitions"]["inputs"][name]["index"] = i;
@ -577,6 +586,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
metadata.json["definitions"]["inputs"][name]["size"] = size;
metadata.json["definitions"]["inputs"][name]["members"] = parseMembers(resource.type_id);
}
#endif
// generate definition to unordered_map
{
metadata.definitions.inputs[name] = Shader::Metadata::Definition::InOut{
@ -595,6 +605,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
const uf::stl::string name = resource.name;
size_t size = 0; // comp.get_declared_struct_size(type);
// generate definition to JSON
#if UF_SHADER_PARSE_AS_JSON
{
metadata.json["definitions"]["outputs"][name]["name"] = name;
metadata.json["definitions"]["outputs"][name]["index"] = i;
@ -602,6 +613,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
metadata.json["definitions"]["outputs"][name]["size"] = size;
metadata.json["definitions"]["outputs"][name]["members"] = parseMembers(resource.type_id);
}
#endif
// generate definition to unordered_map
{
metadata.definitions.outputs[name] = Shader::Metadata::Definition::InOut{
@ -636,6 +648,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
pushConstant.create( size );
}
// generate definition to JSON
#if UF_SHADER_PARSE_AS_JSON
{
metadata.json["definitions"]["pushConstants"][name]["name"] = name;
metadata.json["definitions"]["pushConstants"][name]["index"] = pushConstants.size() - 1;
@ -643,6 +656,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
metadata.json["definitions"]["pushConstants"][name]["size"] = size;
metadata.json["definitions"]["pushConstants"][name]["members"] = parseMembers(resource.type_id);
}
#endif
// generate definition to unordered_map
{
metadata.definitions.pushConstants[name] = Shader::Metadata::Definition::PushConstant{
@ -680,26 +694,31 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
uint8_t* s = (uint8_t*) (void*) specializationConstants;
size_t offset = 0;
#if UF_SHADER_PARSE_AS_JSON
metadata.json["specializationConstants"] = ext::json::array();
#endif
for ( const auto& constant : comp.get_specialization_constants() ) {
const auto& value = comp.get_constant(constant.id);
const auto& type = comp.get_type(value.constant_type);
uf::stl::string name = comp.get_name (constant.id);
ext::json::Value member;
size_t size = 4;
uint8_t buffer[size];
auto& definition = metadata.definitions.specializationConstants[name];
definition.name = name;
definition.index = offset / size;
#if UF_SHADER_PARSE_AS_JSON
ext::json::Value member;
#endif
switch ( type.basetype ) {
case spirv_cross::SPIRType::UInt: {
auto v = value.scalar();
#if UF_SHADER_PARSE_AS_JSON
member["type"] = "uint32_t";
member["value"] = v;
member["validate"] = true;
#endif
memcpy( &buffer[0], &v, sizeof(v) );
definition.type = "uint32_t";
@ -708,8 +727,10 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
} break;
case spirv_cross::SPIRType::Int: {
auto v = value.scalar_i32();
#if UF_SHADER_PARSE_AS_JSON
member["type"] = "int32_t";
member["value"] = v;
#endif
memcpy( &buffer[0], &v, sizeof(v) );
definition.type = "int32_t";
@ -718,8 +739,10 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
} break;
case spirv_cross::SPIRType::Float: {
auto v = value.scalar_f32();
#if UF_SHADER_PARSE_AS_JSON
member["type"] = "float";
member["value"] = v;
#endif
memcpy( &buffer[0], &v, sizeof(v) );
definition.type = "float";
@ -728,8 +751,10 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
} break;
case spirv_cross::SPIRType::Boolean: {
auto v = value.scalar()!=0;
#if UF_SHADER_PARSE_AS_JSON
member["type"] = "bool";
member["value"] = v;
#endif
memcpy( &buffer[0], &v, sizeof(v) );
definition.type = "bool";
@ -740,11 +765,13 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
VK_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset " << offset << " for shader " << filename );
} break;
}
#if UF_SHADER_PARSE_AS_JSON
member["name"] = name;
member["size"] = size;
member["default"] = member["value"];
VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as<uf::stl::string>() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename );
metadata.json["specializationConstants"].emplace_back(member);
VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as<uf::stl::string>() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename );
#endif
memcpy( &s[offset], &buffer, size );
offset += size;
@ -869,7 +896,7 @@ bool ext::vulkan::Shader::updateStorage( const uf::stl::string& name, const void
return true;
}
// JSON shit
/*
#if 0 && UF_SHADER_PARSE_AS_JSON
uf::Serializer ext::vulkan::Shader::getUniformJson( const uf::stl::string& name, bool cache ) {
if ( !hasUniform(name) ) return ext::json::null();
if ( cache && !ext::json::isNull(metadata.json["uniforms"][name]) ) return metadata.json["uniforms"][name];
@ -897,5 +924,5 @@ ext::vulkan::userdata_t ext::vulkan::Shader::getStorageUserdata( const uf::stl::
if ( !hasStorage(name) ) return false;
return jsonToUserdata(payload, metadata.json["definitions"]["storage"][name]);
}
*/
#endif
#endif

View File

@ -2,6 +2,7 @@
#if UF_USE_XATLAS
#include <xatlas/xatlas.h>
#endif
#if 0
pod::Vector2ui UF_API ext::xatlas::unwrap( uf::stl::vector<uf::graph::mesh::Skinned>& vertices, uf::stl::vector<uint32_t>& indices ) {
#if UF_USE_XATLAS
uf::stl::vector<uf::graph::mesh::Skinned> source = std::move(vertices);
@ -41,6 +42,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( uf::stl::vector<uf::graph::mesh::Skin
return size;
#endif
}
#endif
pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
#if UF_USE_XATLAS
struct Pair {
@ -135,11 +137,11 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
// chartOptions.useInputMeshUvs = true;
::xatlas::PackOptions packOptions{};
// packOptions.bruteForce = true;
packOptions.bruteForce = true;
// packOptions.resolution = resolution;
// packOptions.texelsPerUnit = 64.0f;
// packOptions.blockAlign = true;
// packOptions.bilinear = true;
packOptions.blockAlign = true;
packOptions.bilinear = true;
::xatlas::Generate(atlas, chartOptions, packOptions);

View File

@ -16,6 +16,14 @@ uint8_t uf::audio::buffers = 4;
size_t uf::audio::bufferSize = 1024 * 16;
uf::Audio uf::audio::null;
#if UF_AUDIO_MAPPED_VOLUMES
uf::stl::unordered_map<uf::stl::string, float> uf::audio::volumes;
#else
float uf::audio::volumes::bgm = 1.0f;
float uf::audio::volumes::sfx = 1.0f;
float uf::audio::volumes::voice = 1.0f;
#endif
bool uf::Audio::initialized() const {
#if UF_USE_OPENAL
return this->m_metadata && this->m_metadata->al.source.getIndex();
@ -116,7 +124,7 @@ void uf::Audio::setTime( float v ) {
void uf::Audio::setPosition( const pod::Vector3f& v ) {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return;
this->m_metadata->al.source.set( AL_POSITION, &v[0] );
this->m_metadata->al.source.set( AL_POSITION, v[0], v[1], v[2] );
#endif
}
void uf::Audio::setOrientation( const pod::Quaternion<>& v ) {

View File

@ -1,16 +1,16 @@
#include <uf/utils/math/physics.h>
uf::Timer<> uf::physics::time::timer;
double uf::physics::time::current;
double uf::physics::time::previous;
double uf::physics::time::delta;
double uf::physics::time::clamp;
uf::physics::num_t uf::physics::time::current;
uf::physics::num_t uf::physics::time::previous;
uf::physics::num_t uf::physics::time::delta;
uf::physics::num_t uf::physics::time::clamp;
#include <iostream>
void UF_API uf::physics::tick() {
uf::physics::time::previous = uf::physics::time::current;
uf::physics::time::current = uf::physics::time::timer.elapsed().asDouble();
uf::physics::time::current = uf::physics::time::timer.elapsed();
uf::physics::time::delta = uf::physics::time::current - uf::physics::time::previous;
if ( uf::physics::time::delta > uf::physics::time::clamp ) {
uf::physics::time::delta = uf::physics::time::clamp;

View File

@ -293,22 +293,36 @@ uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, con
return res;
}
void uf::Mesh::_insertVs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
if ( !_hasV( input, srcInput ) ) return;
_reserveVs( input, input.count += srcInput.count );
// both meshes are interleaved, just copy directly
if ( isInterleaved(input.interleaved) && isInterleaved(srcInput.interleaved) ) {
if ( !_hasV( input, srcInput ) ) return;
auto& src = mesh.buffers[srcInput.interleaved];
auto& dst = buffers[input.interleaved];
dst.insert( dst.end(), src.begin(), src.end() );
// both meshes are de-interleaved, just copy directly
} else if ( !isInterleaved(input.interleaved) && !isInterleaved(srcInput.interleaved) ) {
for ( auto i = 0; i < input.attributes.size(); ++i ) {
auto& srcAttribute = srcInput.attributes[i];
auto& dstAttribute = input.attributes[i];
auto& src = mesh.buffers[srcAttribute.buffer];
auto& dst = buffers[dstAttribute.buffer];
dst.insert( dst.end(), src.begin(), src.end() );
if ( _hasV( input, srcInput ) ) {
for ( auto i = 0; i < input.attributes.size(); ++i ) {
auto& srcAttribute = srcInput.attributes[i];
auto& dstAttribute = input.attributes[i];
auto& src = mesh.buffers[srcAttribute.buffer];
auto& dst = buffers[dstAttribute.buffer];
dst.insert( dst.end(), src.begin(), src.end() );
}
} else {
for ( auto& dstAttribute : input.attributes ) {
for ( auto& srcAttribute : srcInput.attributes ) {
if ( srcAttribute.descriptor != dstAttribute.descriptor ) continue;
auto& src = mesh.buffers[srcAttribute.buffer];
auto& dst = buffers[dstAttribute.buffer];
dst.insert( dst.end(), src.begin(), src.end() );
break;
}
}
}
// not easy to convert, will implement later
} else {

View File

@ -35,15 +35,16 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
if ( metadataJson["baking"]["resolution"].is<size_t>() )
metadata.size = { metadataJson["baking"]["resolution"].as<size_t>(), metadataJson["baking"]["resolution"].as<size_t>() };
metadata.max.lights = metadataJson["baking"]["lights"].as<size_t>(metadata.max.lights);
metadata.max.shadows = metadataJson["baking"]["shadows"].as<size_t>(metadata.max.shadows);
metadata.cull = metadataJson["baking"]["cull"].as<bool>();
metadata.previous.max = sceneMetadata.shadow.max;
metadata.previous.lights = sceneMetadata.light.max;
metadata.previous.shadows = sceneMetadata.shadow.max;
metadata.previous.update = sceneMetadata.shadow.update;
sceneMetadata.shadow.max = 1024;
sceneMetadata.shadow.update = 1024;
sceneMetadata.light.max = metadata.max.shadows;
sceneMetadata.shadow.max = metadata.max.shadows;
sceneMetadata.shadow.update = metadata.max.shadows;
UF_MSG_DEBUG("Temporarily altering shadow limits...");
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
@ -172,7 +173,8 @@ SAVE: {
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadata = scene.getComponent<ext::ExtSceneBehavior::Metadata>();
sceneMetadata.shadow.max = metadata.previous.max;
sceneMetadata.light.max = metadata.previous.lights;
sceneMetadata.shadow.max = metadata.previous.shadows;
sceneMetadata.shadow.update = metadata.previous.update;
UF_MSG_DEBUG("Reverted shadow limits");

View File

@ -31,7 +31,8 @@ namespace ext {
size_t shadows = 1024;
} max;
struct {
size_t max = 0;
size_t lights = 0;
size_t shadows = 0;
size_t update = 0;
} previous;
struct {

View File

@ -75,18 +75,14 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) {
pod::Vector2 relta = { (float) sensitivity * payload.mouse.delta.x / payload.window.size.x, (float) sensitivity * payload.mouse.delta.y / payload.window.size.y };
if ( (payload.mouse.delta.x == 0 && payload.mouse.delta.y == 0) || !metadata.system.control ) return;
bool updateCamera = false;
if ( payload.mouse.delta.x != 0 ) {
if ( metadata.camera.invert.x ) relta.x *= -1;
metadata.camera.limit.current.x += relta.x;
if ( metadata.camera.limit.current.x != metadata.camera.limit.current.x || ( metadata.camera.limit.current.x < metadata.camera.limit.max.x && metadata.camera.limit.current.x > metadata.camera.limit.min.x ) ) {
if ( collider.body && !collider.shared ) {
#if UF_USE_BULLET
ext::bullet::applyRotation( collider, transform.up, relta.x );
#endif
} else {
uf::transform::rotate( transform, transform.up, relta.x ), updateCamera = true;
}
#if UF_USE_BULLET
if ( collider.body && !collider.shared ) ext::bullet::applyRotation( collider, transform.up, relta.x ); else
#endif
uf::transform::rotate( transform, transform.up, relta.x );
} else metadata.camera.limit.current.x -= relta.x;
}
if ( payload.mouse.delta.y != 0 ) {
@ -98,10 +94,9 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) {
// } else {
uf::transform::rotate( cameraTransform, cameraTransform.right, relta.y );
// }
updateCamera = true;
} else metadata.camera.limit.current.y -= relta.y;
}
if ( updateCamera ) camera.update(true);
camera.update(true);
});
#if UF_USE_DISCORD
@ -190,7 +185,6 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
}
struct {
bool updateCamera = true;
bool deltaCrouch = false;
bool walking = false;
bool floored = true;
@ -208,30 +202,37 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
stats.menu = metadata.system.menu;
stats.impulse = metadata.system.physics.impulse;
stats.noclipped = metadata.system.noclipped;
stats.floored = fabs(physics.linear.velocity.y) < 0.01f || stats.noclipped;
stats.floored = stats.noclipped;
#if UF_USE_BULLET
auto& collider = this->getComponent<pod::Bullet>();
if ( !stats.floored && collider.body && ext::bullet::rayCast( transform.position, transform.position - pod::Vector3f{0,1,0} ) >= 0.0f ) stats.floored = true; else
#endif
stats.floored |= fabs(physics.linear.velocity.y) < 0.01f;
struct {
float move = 4;
float walk = 1;
float run = 8;
float rotate = uf::physics::time::delta;
float limitSquared = 4*4;
float rotate = 1;
float friction = 0.8f;
} speed; {
speed.rotate *= metadata.system.physics.rotate;
speed.rotate = metadata.system.physics.rotate * uf::physics::time::delta;
speed.move = metadata.system.physics.move;
speed.run = metadata.system.physics.run / speed.move;
speed.walk = metadata.system.physics.walk / speed.move;
speed.run = metadata.system.physics.run;
speed.walk = metadata.system.physics.walk;
if ( stats.noclipped ) {
speed.move *= 4.0;
speed.run *= 2.0;
}
if ( !stats.floored || stats.noclipped ) speed.friction = 1;
if ( stats.noclipped ) physics.linear.velocity = {};
}
if ( !metadata.system.physics.collision ) {
stats.impulse = true;
}
if ( keys.running ) speed.move *= speed.run;
else if ( keys.walk ) speed.move *= speed.walk;
speed.limitSquared = speed.move * speed.move;
if ( keys.running ) speed.move = speed.run;
else if ( keys.walk ) speed.move = speed.walk;
uf::Object* menu = (uf::Object*) scene.globalFindByName("Gui: Menu");
if ( !menu ) stats.menu = "";
@ -250,44 +251,45 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
metadata.system.control = false;
}
metadata.system.menu = stats.menu;
auto& collider = this->getComponent<pod::Bullet>();
if ( metadata.system.control ) {
{
TIMER(0.25, keys.vee && ) {
bool state = !stats.noclipped;
metadata.system.noclipped = state;
UF_MSG_DEBUG( (state ? "En" : "Dis") << "abled noclip: " << uf::vector::toString(transform.position));
if ( state ) {
#if UF_USE_BULLET
if ( collider.body ) {
collider.body->setGravity(btVector3(0,0.0,0));
collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
collider.body->setActivationState(DISABLE_SIMULATION);
}
#endif
} else {
#if UF_USE_BULLET
if ( collider.body ) {
collider.body->setGravity(btVector3(0,-9.81,0));
collider.body->setCollisionFlags(collider.body->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
collider.body->setActivationState(DISABLE_DEACTIVATION);
}
#endif
}
stats.noclipped = state;
}
}
if ( stats.floored ) {
if ( metadata.system.control ) {
// noclip handler
TIMER(0.25, keys.vee && ) {
bool state = !stats.noclipped;
metadata.system.noclipped = state;
UF_MSG_DEBUG( (state ? "En" : "Dis") << "abled noclip: " << uf::vector::toString(transform.position));
if ( state ) {
#if UF_USE_BULLET
if ( collider.body ) {
collider.body->setGravity(btVector3(0,0.0,0));
collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
collider.body->setActivationState(DISABLE_SIMULATION);
}
#endif
} else {
#if UF_USE_BULLET
if ( collider.body ) {
collider.body->setGravity(btVector3(0,-9.81,0));
collider.body->setCollisionFlags(collider.body->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
collider.body->setActivationState(DISABLE_DEACTIVATION);
}
#endif
}
stats.noclipped = state;
}
// movement handler
{
pod::Transform<> translator = transform;
#if UF_USE_OPENVR
// use the orientation of our controller to determine our target
if ( ext::openvr::context ) {
bool useController = true;
translator.orientation = uf::quaternion::multiply( transform.orientation * pod::Vector4f{1,1,1,1}, useController ? (ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right ) * pod::Vector4f{1,1,1,1}) : ext::openvr::hmdQuaternion() );
translator.orientation = uf::quaternion::multiply( transform.orientation, useController ? ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right ) : ext::openvr::hmdQuaternion() );
translator = uf::transform::reorient( translator );
// flatten if not noclipped
if ( !stats.noclipped ) {
translator.forward *= { 1, 0, 1 };
translator.right *= { 1, 0, 1 };
@ -297,155 +299,66 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
translator.right = uf::vector::normalize( translator.right );
} else
#endif
// un-flatted if noclipped
if ( stats.noclipped ){
auto& cameraTransform = camera.getTransform();
// translator = uf::transform::flatten( cameraTransform );
translator.forward.y += cameraTransform.forward.y;
translator.forward = uf::vector::normalize( translator.forward );
}
pod::Vector3f queued = {};
if ( keys.forward || keys.backwards ) {
float polarity = keys.forward ? 1 : -1;
float mag = uf::vector::magnitude(physics.linear.velocity); // * pod::Vector3{1, 0, 1});
if ( mag < speed.limitSquared ) {
mag = uf::vector::magnitude(physics.linear.velocity + translator.forward * speed.move * polarity);
} else mag = speed.limitSquared;
pod::Vector3 correction = translator.forward * ::sqrt(mag) * polarity;
if ( collider.body && !collider.shared ) {
queued += correction;
} else {
if ( stats.impulse && stats.noclipped ) {
physics.linear.velocity.x = correction.x;
physics.linear.velocity.z = correction.z;
if ( stats.noclipped ) physics.linear.velocity.y = correction.y;
} else {
correction *= uf::physics::time::delta;
transform.position.x += correction.x;
transform.position.z += correction.z;
if ( stats.noclipped ) transform.position.y += correction.y;
}
}
stats.updateCamera = (stats.walking = true);
}
if ( keys.left || keys.right ) {
float polarity = keys.right ? 1 : -1;
float mag = uf::vector::magnitude(physics.linear.velocity); // * pod::Vector3{1, 0, 1});
if ( mag < speed.limitSquared ) {
mag = uf::vector::magnitude(physics.linear.velocity + translator.right * speed.move * polarity);
} else mag = speed.limitSquared;
pod::Vector3 correction = translator.right * ::sqrt(mag) * polarity;
if ( collider.body && !collider.shared ) {
queued += correction;
} else {
if ( stats.impulse && stats.noclipped ) {
physics.linear.velocity.x = correction.x;
physics.linear.velocity.z = correction.z;
} else {
correction *= uf::physics::time::delta;
transform.position.x += correction.x;
transform.position.z += correction.z;
}
}
stats.updateCamera = (stats.walking = true);
}
if ( keys.left || keys.right || keys.forward || keys.backwards ) {
if ( collider.body && !collider.shared ) {
physics.linear.velocity.x = queued.x;
physics.linear.velocity.z = queued.z;
if ( stats.noclipped ) physics.linear.velocity.y = queued.y;
#if UF_USE_BULLET
ext::bullet::move( collider, physics.linear.velocity );
#endif
}
}
if ( !keys.forward && !keys.backwards && !keys.left && !keys.right ) {
if ( collider.body && !collider.shared ) {
physics.linear.velocity.x = 0;
physics.linear.velocity.z = 0;
if ( stats.noclipped ) physics.linear.velocity.y = 0;
#if UF_USE_BULLET
ext::bullet::move( collider, physics.linear.velocity );
#endif
}
}
if ( keys.jump ) {
pod::Vector3f yump = metadata.system.physics.jump;
if ( collider.body && !collider.shared ) {
if ( fabs(yump.x) > 0.001f ) physics.linear.velocity.x = yump.x;
if ( fabs(yump.y) > 0.001f ) physics.linear.velocity.y = yump.y;
if ( fabs(yump.z) > 0.001f ) physics.linear.velocity.z = yump.z;
#if UF_USE_BULLET
ext::bullet::move( collider, physics.linear.velocity );
#endif
} else {
transform.position += uf::vector::multiply(yump, uf::physics::time::delta);
}
}
}
if ( keys.lookLeft ) {
if ( collider.body && !collider.shared ) {
#if UF_USE_BULLET
ext::bullet::applyRotation( collider, transform.up, -speed.rotate );
#endif
} else {
uf::transform::rotate( transform, transform.up, -speed.rotate );
}
stats.updateCamera = true;
}
if ( keys.lookRight ) {
if ( collider.body && !collider.shared ) {
#if UF_USE_BULLET
ext::bullet::applyRotation( collider, transform.up, speed.rotate );
#endif
} else {
uf::transform::rotate( transform, transform.up, speed.rotate );
}
stats.updateCamera = true;
}
if ( keys.crouch ) {
pod::Vector3f yump = metadata.system.physics.jump;
if ( stats.noclipped ) {
if ( collider.body && !collider.shared ) {
if ( fabs(yump.x) > 0.001f ) physics.linear.velocity.x = -yump.x;
if ( fabs(yump.y) > 0.001f ) physics.linear.velocity.y = -yump.y;
if ( fabs(yump.z) > 0.001f ) physics.linear.velocity.z = -yump.z;
#if UF_USE_BULLET
ext::bullet::move( collider, physics.linear.velocity );
#endif
}
} else {
if ( !metadata.system.physics.collision ) {
transform.position -= uf::vector::multiply(yump, uf::physics::time::delta);
// setup desired direction
pod::Vector3f target = {};
if ( keys.forward ^ keys.backwards ) target += translator.forward * (keys.forward ? 1 : -1);
if ( keys.left ^ keys.right ) target += translator.right * (keys.right ? 1 : -1);
target = uf::vector::normalize( target );
physics.linear.velocity *= { speed.friction, 1, speed.friction };
stats.walking = (keys.forward ^ keys.backwards) || (keys.left ^ keys.right);
if ( stats.walking ) {
if ( !true && stats.noclipped ) {
physics.linear.velocity = target * speed.move;
} else {
if ( !metadata.system.crouching ) stats.deltaCrouch = true;
metadata.system.crouching = true;
physics.linear.velocity += target * std::clamp( speed.move * (stats.floored ? 1.0f : 0.5f) - uf::vector::dot( physics.linear.velocity, target ), 0.0f, speed.move * 10 * uf::physics::time::delta );
}
}
} else {
if ( metadata.system.crouching ) stats.deltaCrouch = true;
metadata.system.crouching = false;
if ( !stats.floored ) stats.walking = false;
}
}
if ( stats.noclipped && !keys.forward && !keys.backwards && !keys.left && !keys.right && !keys.jump && !keys.crouch ) {
if ( collider.body && !collider.shared ) {
physics.linear.velocity = {};
#if UF_USE_BULLET
ext::bullet::move( collider, physics.linear.velocity );
#endif
}
if ( stats.floored && keys.jump ) {
physics.linear.velocity += metadata.system.physics.jump;
}
if ( keys.crouch ) {
if ( stats.noclipped ) physics.linear.velocity -= metadata.system.physics.jump;
else {
if ( !metadata.system.crouching ) stats.deltaCrouch = true;
metadata.system.crouching = true;
}
} else {
if ( metadata.system.crouching ) stats.deltaCrouch = true;
metadata.system.crouching = false;
}
if ( keys.lookRight ^ keys.lookLeft ) {
#if UF_USE_BULLET
if ( collider.body && !collider.shared ) ext::bullet::applyRotation( collider, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); else
#endif
uf::transform::rotate( transform, transform.up, speed.rotate );
}
{
#if UF_USE_BULLET
if ( collider.body && !collider.shared ) ext::bullet::setVelocity( collider, physics.linear.velocity ); else
#endif
transform.position += physics.linear.velocity * uf::physics::time::delta;
}
if ( stats.deltaCrouch ) {
float delta = metadata.system.physics.crouch;
if ( metadata.system.crouching ) camera.getTransform().position.y -= delta;
else camera.getTransform().position.y += delta;
stats.updateCamera = true;
}
#if UF_USE_OPENAL
if ( stats.floored ) {
if ( stats.walking ) {
@ -525,7 +438,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
}
}
#endif
if ( stats.updateCamera ) camera.update(true);
camera.update(true);
#if UF_ENTITY_METADATA_USE_JSON
metadata.serialize(self, metadataJson);

View File

@ -22,6 +22,8 @@ namespace ext {
float run = 1.0f;
float walk = 1.0f;
pod::Vector3f jump = {0,8,0};
pod::Vector3f velocity = {0,0,0};
} physics;
bool control = true;

View File

@ -44,7 +44,7 @@ void ext::PlayerModelBehavior::tick( uf::Object& self ) {
if ( !entity->hasComponent<uf::Graphic>() ) return;
auto& graphic = entity->getComponent<uf::Graphic>();
auto& pipeline = graphic.getPipeline();
pipeline.metadata.process = false;
pipeline.metadata.process = !metadata.hide;
metadata.set = true;
});
metadata.set = true;
@ -53,16 +53,17 @@ void ext::PlayerModelBehavior::tick( uf::Object& self ) {
void ext::PlayerModelBehavior::render( uf::Object& self ){}
void ext::PlayerModelBehavior::destroy( uf::Object& self ){}
void ext::PlayerModelBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ){
serializer["track"] = /*this->*/track;
serializer["hide"] = /*this->*/hide;
}
void ext::PlayerModelBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ){
auto& transform = this->getComponent<pod::Transform<>>();
/*this->*/track = serializer["track"].as<bool>();
/*this->*/hide = serializer["hide"].as<bool>();
/*this->*/scale = transform.scale;
/*this->*/set = false;
transform.reference = /*this->*/track ? /*this->*/reference : NULL;
}
void ext::PlayerModelBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ){
serializer["track"] = /*this->*/track;
serializer["hide"] = /*this->*/hide;
}
#undef this

View File

@ -57,7 +57,11 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
audio = std::move(asset);
assetLoader.remove<uf::Audio>(filename);
audio.setVolume(metadataJson["volumes"]["bgm"].as<float>());
#if UF_AUDIO_MAPPED_VOLUMES
audio.setVolume(uf::audio::volumes.count("bgm") > 0 ? uf::audio::volumes.at("bgm") : 1.0);
#else
audio.setVolume(uf::audio::volumes::bgm);
#endif
audio.loop( true );
audio.play();
});
@ -175,11 +179,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
image.open(filename);
image.flip();
if ( size.x == 0 && size.y == 0 ) {
size = image.getDimensions();
} else if ( size != image.getDimensions() ) {
UF_MSG_ERROR("ERROR: MISMATCH CUBEMAP FACE SIZE");
}
if ( size.x == 0 && size.y == 0 ) size = image.getDimensions();
else if ( size != image.getDimensions() ) UF_EXCEPTION("ERROR: MISMATCH CUBEMAP FACE SIZE");
auto& p = image.getPixels();
pixels.reserve( pixels.size() + p.size() );
@ -340,9 +341,9 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
uf::stl::vector<LightInfo> entities; entities.reserve(graph.size() / 2);
uf::graph::storage.lights.clear(); uf::graph::storage.lights.reserve(metadata.max.lights);
uf::graph::storage.shadow2Ds.clear(); uf::graph::storage.shadow2Ds.reserve(metadata.max.lights);
uf::graph::storage.shadowCubes.clear(); uf::graph::storage.shadowCubes.reserve(metadata.max.lights);
uf::graph::storage.lights.clear(); uf::graph::storage.lights.reserve(metadata.light.max);
uf::graph::storage.shadow2Ds.clear(); uf::graph::storage.shadow2Ds.reserve(metadata.light.max);
uf::graph::storage.shadowCubes.clear(); uf::graph::storage.shadowCubes.reserve(metadata.light.max);
// traverse scene graph
for ( auto entity : graph ) {
@ -382,7 +383,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false;
// bind lighting and requested shadow maps
for ( uint32_t i = 0; i < entities.size() && uf::graph::storage.lights.size() < metadata.max.lights; ++i ) {
for ( uint32_t i = 0; i < entities.size() && uf::graph::storage.lights.size() < metadata.light.max; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
@ -522,7 +523,7 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
/*this->*/max.textures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as<uint32_t>(/*this->*/max.textures2D);
/*this->*/max.texturesCube = ext::config["engine"]["scenes"]["textures"]["max"]["cube"].as<uint32_t>(/*this->*/max.texturesCube);
/*this->*/max.textures3D = ext::config["engine"]["scenes"]["textures"]["max"]["3D"].as<uint32_t>(/*this->*/max.textures3D);
/*this->*/max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as<uint32_t>(/*this->*/max.lights);
/*this->*/light.max = ext::config["engine"]["scenes"]["lights"]["max"].as<uint32_t>(/*this->*/light.max);
/*this->*/shadow.enabled = ext::config["engine"]["scenes"]["shadows"]["enabled"].as<bool>(true) && serializer["light"]["shadows"].as<bool>(true);
/*this->*/shadow.samples = ext::config["engine"]["scenes"]["shadows"]["samples"].as<uint32_t>();
@ -537,8 +538,6 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
/*this->*/light.gamma = serializer["light"]["gamma"].as<float>(2.2f);
/*this->*/light.brightnessThreshold = serializer["light"]["brightnessThreshold"].as<float>(ext::config["engine"]["scenes"]["bloom"]["brightnessThreshold"].as<float>(1.0f));
UF_MSG_DEBUG( serializer["bloom"] );
/*this->*/bloom.scale = serializer["bloom"]["scale"].as(ext::config["engine"]["scenes"]["bloom"]["scale"].as(bloom.scale));
/*this->*/bloom.strength = serializer["bloom"]["strength"].as(ext::config["engine"]["scenes"]["bloom"]["strength"].as(bloom.strength));
/*this->*/bloom.sigma = serializer["bloom"]["sigma"].as(ext::config["engine"]["scenes"]["bloom"]["sigma"].as(bloom.sigma));
@ -642,12 +641,12 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
static GLint glMaxLights = 0;
if ( !glMaxLights ) glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights);
metadata.max.lights = std::min( (uint32_t) glMaxLights, metadata.max.lights );
metadata.light.max = std::min( (uint32_t) glMaxLights, metadata.light.max );
// add lighting
{
uint32_t i = 0;
for ( ; i < entities.size() && i < metadata.max.lights; ++i ) {
for ( ; i < entities.size() && i < metadata.light.max; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
GLenum target = GL_LIGHT0+i;
@ -660,7 +659,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
GL_ERROR_CHECK(glLightf(target, GL_LINEAR_ATTENUATION, 0));
GL_ERROR_CHECK(glLightf(target, GL_QUADRATIC_ATTENUATION, 1.0f / info.power));
}
for ( ; i < metadata.max.lights; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i));
for ( ; i < metadata.light.max; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i));
}
#elif UF_USE_VULKAN
struct UniformDescriptor {
@ -805,7 +804,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
};
uniforms.lengths = UniformDescriptor::Lengths{
.lights = MIN( uf::graph::storage.lights.size(), metadata.max.lights ),
.lights = MIN( uf::graph::storage.lights.size(), metadata.light.max ),
.materials = MIN( uf::graph::storage.materials.keys.size(), metadata.max.textures2D ),
.textures = MIN( uf::graph::storage.textures.keys.size(), metadata.max.textures2D ),
.drawCommands = MIN( 0, metadata.max.textures2D ),

View File

@ -16,10 +16,10 @@ namespace ext {
uint32_t textures2D = 512;
uint32_t texturesCube = 128;
uint32_t textures3D = 128;
uint32_t lights = 256;
} max;
struct {
bool enabled = true;
uint32_t max = 256;
pod::Vector4f ambient = {0,0,0,1};
pod::Vector4f specular = {1,1,1,1};
float exposure = 1.0f;

View File

@ -17,7 +17,6 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
auto& sounds = emitter.get();
auto& scene = uf::scene::getCurrentScene();
auto& sMetadata = scene.getComponent<uf::Serializer>();
auto& assetLoader = scene.getComponent<uf::Asset>();
if ( !metadata["audio"]["epsilon"].is<float>() )
@ -68,7 +67,13 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
if ( json["volume"].is<double>() ) volume = json["volume"].as<float>();
else if ( json["volume"].is<uf::stl::string>() ) {
uf::stl::string key = json["volume"].as<uf::stl::string>();
if ( sMetadata["volumes"][key].is<double>() ) volume = sMetadata["volumes"][key].as<float>();
#if UF_AUDIO_MAPPED_VOLUMES
if ( uf::audio::volumes.count(key) > 0 ) volume = uf::audio::volumes.at(key);
#else
if ( key == "bgm" ) volume = uf::audio::volumes::bgm;
else if ( key == "sfx" ) volume = uf::audio::volumes::sfx;
else if ( key == "voice" ) volume = uf::audio::volumes::voice;
#endif
}
audio.setVolume(volume);

View File

@ -244,7 +244,11 @@ void EXT_API ext::initialize() {
}
{
uf::Mesh::defaultInterleaved = ::config["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
#if 0 && UF_USE_OPENGL
uf::matrix::reverseInfiniteProjection = false;
#else
uf::matrix::reverseInfiniteProjection = ::config["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
#endif
}
/* Create initial scene (kludge) */ {
@ -278,11 +282,6 @@ void EXT_API ext::initialize() {
double limit = ::config["engine"]["limiters"]["deltaTime"].as<double>();
uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0;
}
// Mute audio
uf::audio::muted = ::config["engine"]["audio"]["mute"].as( uf::audio::muted );
uf::audio::streamsByDefault = ::config["engine"]["audio"]["streams by default"].as( uf::audio::streamsByDefault );
uf::audio::bufferSize = ::config["engine"]["audio"]["buffers"]["size"].as( uf::audio::bufferSize );
uf::audio::buffers = ::config["engine"]["audio"]["buffers"]["count"].as( uf::audio::buffers );
// Set worker threads
if ( ::config["engine"]["threads"]["workers"].as<uf::stl::string>() == "auto" ) {
@ -290,6 +289,26 @@ void EXT_API ext::initialize() {
::config["engine"]["threads"]["workers"] = threads;
UF_MSG_DEBUG("Using " << threads << " worker threads");
}
// Mute audio
uf::audio::muted = ::config["engine"]["audio"]["mute"].as( uf::audio::muted );
uf::audio::streamsByDefault = ::config["engine"]["audio"]["streams by default"].as( uf::audio::streamsByDefault );
uf::audio::bufferSize = ::config["engine"]["audio"]["buffers"]["size"].as( uf::audio::bufferSize );
uf::audio::buffers = ::config["engine"]["audio"]["buffers"]["count"].as( uf::audio::buffers );
#if UF_AUDIO_MAPPED_VOLUMES
ext::json::forEach( ::config["engine"]["audio"]["volumes"], []( const uf::stl::string& key, ext::json::Value& value ){
float volume; volume = value.as(volume);
uf::audio::volumes[key] = volume;
});
#else
uf::audio::volumes::bgm = ::config["engine"]["audio"]["volumes"]["bgm"].as(uf::audio::volumes::bgm);
uf::audio::volumes::sfx = ::config["engine"]["audio"]["volumes"]["sfx"].as(uf::audio::volumes::sfx);
uf::audio::volumes::voice = ::config["engine"]["audio"]["volumes"]["voice"].as(uf::audio::volumes::voice);
#endif
#if UF_USE_OPENAL
/* Initialize OpenAL */ {
ext::al::initialize();
}
#endif
#if UF_USE_BULLET
// set bullet parameters
@ -375,11 +394,11 @@ void EXT_API ext::initialize() {
#if UF_USE_LUA
/* Lua */ {
ext::lua::main = ::config["engine"]["ext"]["lua"]["main"].as<uf::stl::string>();
for ( auto it = ::config["engine"]["ext"]["lua"]["modules"].begin(); it != ::config["engine"]["ext"]["lua"]["modules"].end(); ++it ) {
uf::stl::string key = it.key();
ext::lua::modules[key] = ::config["engine"]["ext"]["lua"]["modules"][key].as<uf::stl::string>();
}
ext::lua::enabled = ::config["engine"]["ext"]["lua"]["enabled"].as(ext::lua::enabled);
ext::lua::main = ::config["engine"]["ext"]["lua"]["main"].as(ext::lua::main);
ext::json::forEach( ::config["engine"]["ext"]["lua"]["modules"], []( const uf::stl::string& key, ext::json::Value& value ){
ext::lua::modules[key] = value.as<uf::stl::string>();
});
ext::lua::initialize();
}
#endif
@ -544,18 +563,17 @@ void EXT_API ext::initialize() {
payload["scene"] = ::config["engine"]["scenes"]["start"];
payload["immediate"] = true;
uf::hooks.call("game:Scene.Load", payload);
}
ext::ready = true;
UF_MSG_INFO("EXT took " << times.sys.elapsed().asDouble() << " seconds to initialize!");
{
uf::thread::add( uf::thread::fetchWorker(), [&]() -> int {
auto& scene = uf::scene::getCurrentScene();
auto& assetLoader = scene.getComponent<uf::Asset>();
assetLoader.processQueue();
return 0;}, false );
}
ext::ready = true;
UF_MSG_INFO("EXT took " << times.sys.elapsed().asDouble() << " seconds to initialize!");
}
void EXT_API ext::tick() {
@ -774,6 +792,12 @@ void EXT_API ext::terminate() {
uf::renderer::destroy();
}
#if UF_USE_OPENAL
/* Initialize OpenAL */ {
ext::al::destroy();
}
#endif
/* Print system stats */ {
::times.total.time = times.sys.elapsed().asDouble();
UF_MSG_DEBUG("System: Total Time: " << ::times.total.time << " | Total Frames: " << ::times.total.frames << " | Average FPS: " << ::times.total.frames / ::times.total.time);