Commit for 2020.09.07.7z

This commit is contained in:
mrq 2020-09-07 00:00:00 -05:00
parent 1313677a56
commit 1acffac153
69 changed files with 40518 additions and 1651 deletions

View File

@ -15,7 +15,7 @@ UF_LIBS =
# EXT_LIBS = -lpng16 -lz -lassimp -lsfml-main -lsfml-system -lsfml-window -lsfml-graphics -llua52
# EXT_LIBS = -lpng16 -lz -lassimp -ljsoncpp -lopenal32 -lalut -lvorbis -lvorbisfile -logg -lfreetype
EXT_LIBS =
#FLAGS = -std=c++0x -Wall -g -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENGL -DUF_USE_GLEW
#FLAGS = -Og -DUF_DISABLE_ALIGNAS -std=c++20 -Wno-c++11-narrowing -Wno-narrowing -g -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN -DGLM_ENABLE_EXPERIMENTAL -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENAL -DUF_USE_VORBIS -DUF_USE_FREETYPE -DUSE_OPENVR_MINGW
FLAGS = -std=c++20 -Wno-c++11-narrowing -Wno-narrowing -g -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN -DGLM_ENABLE_EXPERIMENTAL -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENAL -DUF_USE_VORBIS -DUF_USE_FREETYPE -DUSE_OPENVR_MINGW
#-march=native
LIB_NAME = uf

View File

@ -3,19 +3,20 @@
layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUv;
layout (location = 1) in vec3 inPosition;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec4 inColor;
layout (location = 3) in vec3 inPosition;
layout (location = 0) out vec4 outAlbedoSpecular;
layout (location = 1) out vec4 outPosition;
layout (location = 2) out vec4 outNormal;
layout (location = 1) out vec4 outNormal;
layout (location = 2) out vec4 outPosition;
void main() {
outAlbedoSpecular = texture(samplerColor, inUv);
if ( outAlbedoSpecular.a < 0.001 ) discard;
outAlbedoSpecular.rgb *= inColor.rgb;
outAlbedoSpecular.a = 1;
// outPosition = vec4(inPosition, 1.0);
// outNormal = vec4(normalize(inNormal), 1.0);
outNormal = vec4(inNormal,1);
outPosition = vec4(inPosition,1);
}

View File

@ -20,9 +20,9 @@ layout (binding = 0) uniform UBO {
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec3 outPosition;
layout (location = 1) out vec4 outColor;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec4 outColor;
layout (location = 3) out vec3 outPosition;
out gl_PerVertex {
vec4 gl_Position;
@ -35,9 +35,7 @@ void main() {
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);
gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0);
}

View File

@ -1,39 +0,0 @@
#version 450
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec3 inNormal;
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
struct Matrices {
mat4 model;
mat4 view[2];
mat4 projection[2];
};
layout (binding = 0) uniform UBO {
Matrices matrices;
vec4 color;
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec3 outPositionEye;
layout (location = 2) out vec3 outNormalEye;
layout (location = 3) out vec4 outColor;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outPositionEye = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormalEye = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outColor = ubo.color;
gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0);
}

View File

@ -1,10 +0,0 @@
#version 450
layout (input_attachment_index = 0, binding = 1) uniform subpassInput samplerOutput;
layout (location = 0) in vec2 inUv;
layout (location = 0) out vec4 outFragColor;
void main() {
outFragColor = subpassLoad(samplerOutput);
}

View File

@ -3,8 +3,7 @@
layout (binding = 1) uniform sampler samp;
layout (binding = 2) uniform texture2D albedoTexture;
layout (binding = 3) uniform texture2D positionTexture;
layout (binding = 4) uniform texture2D normalTexture;
layout (binding = 3) uniform texture2D normalTexture;
struct Cursor {
vec2 position;
@ -17,8 +16,7 @@ layout (location = 1) in float inAlpha;
layout (location = 2) in Cursor inCursor;
layout (location = 0) out vec4 outAlbedoSpecular;
layout (location = 1) out vec4 outPosition;
layout (location = 2) out vec4 outNormal;
layout (location = 1) out vec4 outNormal;
void main() {
outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), inUv);
@ -26,7 +24,6 @@ void main() {
vec2 uv = gl_FragCoord.xy / textureSize(albedoTexture, 0);
// uv.x = 1-uv.x;
outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), uv);
outPosition = texture(sampler2D(positionTexture, samp), uv);
outNormal = texture(sampler2D(normalTexture, samp), uv);
if ( outAlbedoSpecular.a < 0.01f ) outAlbedoSpecular = vec4(0,0,0,1);
return;

View File

@ -27,7 +27,7 @@ struct Matrices {
layout (binding = 0) uniform UBO {
Matrices matrices;
Cursor cursor;
float alpha;
vec2 alpha;
} ubo;
void main() {

View File

@ -1,22 +1,29 @@
#version 450
#define BASE_LIGHTS_SIZE 16
layout (constant_id = 0) const uint LIGHTS = BASE_LIGHTS_SIZE;
layout (input_attachment_index = 0, binding = 1) uniform subpassInput samplerAlbedo;
layout (input_attachment_index = 0, binding = 2) uniform subpassInput samplerPosition;
layout (input_attachment_index = 0, binding = 3) uniform subpassInput samplerNormal;
layout (input_attachment_index = 0, binding = 4) uniform subpassInput samplerDepth;
layout (input_attachment_index = 0, binding = 2) uniform subpassInput samplerNormal;
layout (input_attachment_index = 0, binding = 3) uniform subpassInput samplerPosition;
// layout (input_attachment_index = 0, binding = 4) uniform subpassInput samplerDepth;
layout (binding = 5) uniform sampler2D samplerShadows[BASE_LIGHTS_SIZE];
layout (location = 0) in vec2 inUv;
layout (location = 1) in flat uint inPushConstantPass;
layout (location = 0) out vec4 outFragColor;
layout (constant_id = 0) const uint LIGHTS = 32;
struct Light {
vec3 position;
float power;
vec3 color;
float radius;
int type;
int shadowed;
mat4 view;
mat4 projection;
};
struct Matrices {
@ -78,31 +85,117 @@ void phong( Light light, vec4 albedoSpecular, inout vec3 i ) {
i += Id * light.power;
}
bool debugShadow( Light light, uint i ) {
return false;
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
positionClip.xyz /= positionClip.w;
float lightDepth = texture(samplerShadows[i], positionClip.xy * 0.5 + 0.5).r;
float eyeDepth = positionClip.z;
eyeDepth = lightDepth;
float bias = 0.0005;
if ( positionClip.x < -1 || positionClip.x >= 1 ) eyeDepth = 1;
else if ( positionClip.y < -1 || positionClip.y >= 1 ) eyeDepth = 1;
else if ( positionClip.z < 0 || positionClip.z >= 1 ) eyeDepth = 1;
// else eyeDepth /= 0.00526;
outFragColor.rgb = vec3( 1 - eyeDepth );
outFragColor.a = 1;
return true;
}
float shadowFactor( Light light, uint i ) {
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
positionClip.xyz /= positionClip.w;
float lightDepth = texture(samplerShadows[i], positionClip.xy * 0.5 + 0.5).r;
float eyeDepth = positionClip.z;
float bias = 0.0005;
// bias = max(0.05 * (1.0 - dot(normal.eye, light.position.xyz - position.eye)), bias);
// eyeDepth /= 0.00526;
// lightDepth /= 0.00526;
eyeDepth = 1 - eyeDepth;
lightDepth = 1 - lightDepth;
if ( positionClip.x < -1 || positionClip.x >= 1 ) return 0.0;
if ( positionClip.y < -1 || positionClip.y >= 1 ) return 0.0;
if ( positionClip.z < 0 || positionClip.z >= 1 ) return 0.0;
return eyeDepth - bias < lightDepth ? 1.0 : 0.0;
}
void main() {
vec4 albedoSpecular = subpassLoad(samplerAlbedo);
position.eye = subpassLoad(samplerPosition).rgb;
normal.eye = subpassLoad(samplerNormal).rgb;
position.eye = subpassLoad(samplerPosition).rgb;
{
float depth = subpassLoad(samplerDepth).r;
mat4 iView = inverse( ubo.matrices.view[inPushConstantPass] );
vec4 positionWorld = iView * vec4(position.eye, 1);
position.world = positionWorld.xyz;
}
/*
{
mat4 iProj = inverse( ubo.matrices.projection[inPushConstantPass] );
mat4 iView = inverse( ubo.matrices.view[inPushConstantPass] );
float depth = subpassLoad(samplerDepth).r;
if ( false ) {
depth /= 0.00526;
outFragColor.rgb = vec3( 1 - depth );
outFragColor.a = 1;
return;
}
vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0);
positionClip.y *= -1;
vec4 positionEye = iProj * positionClip;
positionEye /= positionEye.w;
position.eye = positionEye.xyz;
vec4 positionWorld = iView * positionEye;
position.world = positionWorld.xyz;
}
*/
vec3 fragColor = albedoSpecular.rgb * ubo.ambient.rgb;
bool lit = false;
for ( uint i = 0; i < LIGHTS; ++i ) {
Light light = ubo.lights[i];
if ( light.power <= 0.001 ) continue;
lit = true;
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
if ( light.shadowed > 0 ) {
float shadowFactor = shadowFactor( light, i );
if ( shadowFactor <= 0.0001 ) continue;
}
phong( light, albedoSpecular, fragColor );
}
if ( !lit ) fragColor = albedoSpecular.rgb;
fog(fragColor);
outFragColor = vec4(fragColor,1);
/*
if ( !false ) {
float depth = texture(samplerShadows[0], inUv).r;
depth /= 0.00526;
outFragColor = vec4( vec3(1 - depth), 1 );
return;
} else if ( !false ) {
outFragColor = vec4( texture(samplerShadows[0], inUv).rgb, 1 );
return;
} else {
outFragColor = vec4( inUv.x, 0, inUv.y, 1 );
return;
}
*/
}

View File

@ -3,19 +3,17 @@
layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUv;
layout (location = 1) in vec3 inPosition;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec4 inColor;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec4 inColor;
layout (location = 0) out vec4 outAlbedoSpecular;
layout (location = 1) out vec4 outPosition;
layout (location = 2) out vec4 outNormal;
layout (location = 1) out vec4 outNormal;
void main() {
outAlbedoSpecular = texture(samplerColor, inUv);
outAlbedoSpecular = vec4(1,1,1,1);
outAlbedoSpecular.rgb *= inColor.rgb;
outAlbedoSpecular.a = 1;
outPosition = vec4(inPosition, 1.0);
// outPosition = vec4(inPosition, 1.0);
outNormal = vec4(normalize(inNormal), 1.0);
}

View File

@ -21,9 +21,8 @@ layout (binding = 0) uniform UBO {
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec3 outPosition;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec4 outColor;
layout (location = 1) out vec3 outNormal;
layout (location = 2) out vec4 outColor;
out gl_PerVertex {
vec4 gl_Position;
@ -34,7 +33,7 @@ void main() {
outUv = inUv;
// outColor = ubo.color;
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.matrices.model * vec4(inPos.xyz, 1.0));

View File

@ -1,7 +1,6 @@
#version 450
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inColor;
layout (location = 0) in vec3 inColor;
layout (location = 0) out vec4 outAlbedoSpecular;

View File

@ -17,8 +17,7 @@ layout (binding = 0) uniform UBO {
vec4 color;
} ubo;
layout (location = 0) out vec3 outPosition;
layout (location = 1) out vec4 outColor;
layout (location = 0) out vec4 outColor;
out gl_PerVertex {
vec4 gl_Position;
@ -28,7 +27,7 @@ out gl_PerVertex {
void main() {
outColor = ubo.color;
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0);
}

View File

@ -3,18 +3,18 @@
layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUv;
layout (location = 1) in vec3 inPosition;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec4 inColor;
layout (location = 3) in vec3 inPosition;
layout (location = 0) out vec4 outAlbedoSpecular;
layout (location = 1) out vec4 outPosition;
layout (location = 2) out vec4 outNormal;
layout (location = 1) out vec4 outNormal;
layout (location = 2) out vec4 outPosition;
void main() {
outAlbedoSpecular = texture(samplerColor, inUv);
outAlbedoSpecular.rgb *= inColor.rgb;
// outAlbedoSpecular.rgb *= inColor.rgb;
outAlbedoSpecular.a = 1;
outPosition = vec4(inPosition, 1.0);
outNormal = vec4(normalize(inNormal), 1.0);
outNormal = vec4(inNormal,1);
outPosition = vec4(inPosition,1);
}

View File

@ -21,9 +21,9 @@ layout (binding = 0) uniform UBO {
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec3 outPosition;
layout (location = 1) out vec4 outColor;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec4 outColor;
layout (location = 3) out vec3 outPosition;
out gl_PerVertex {
vec4 gl_Position;
@ -36,9 +36,7 @@ void main() {
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);
outColor.a = (inColor >> 24u) & 0xFF;
outColor.b = (inColor >> 16u) & 0xFF;

View File

@ -1,47 +0,0 @@
#version 450
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in uint inColor;
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
struct Matrices {
mat4 model;
mat4 view[2];
mat4 projection[2];
};
layout (binding = 0) uniform UBO {
Matrices matrices;
vec4 color;
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec3 outPositionEye;
layout (location = 2) out vec3 outNormalEye;
layout (location = 3) out vec4 outColor;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outPositionEye = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormalEye = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outColor = ubo.color;
outColor.a = (inColor >> 24u) & 0xFF;
outColor.b = (inColor >> 16u) & 0xFF;
outColor.g = (inColor >> 8u) & 0xFF;
outColor.r = (inColor ) & 0xFF;
outColor.rgb /= 256.0;
outColor.a = 0.5;
gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0);
}

20406
engine/inc/gltf/json.hpp Normal file

File diff suppressed because it is too large Load Diff

7530
engine/inc/gltf/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

7639
engine/inc/gltf/tiny_gltf.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
#pragma once
#include <uf/engine/object/object.h>
namespace ext {
namespace gltf {
enum LoadMode {
GENERATE_NORMALS = 0x1 << 0,
APPLY_TRANSFORMS = 0x1 << 1,
SEPARATE_MESHES = 0x1 << 2,
RENDER = 0x1 << 3,
COLLISION = 0x1 << 4,
AABB = 0x1 << 5,
};
bool UF_API load( uf::Object&, const std::string&, uint8_t = LoadMode::GENERATE_NORMALS | LoadMode::RENDER );
}
}

View File

@ -35,6 +35,7 @@ namespace ext {
extern UF_API float width, height;
extern UF_API bool enabled;
extern UF_API bool swapEyes;
extern UF_API uint8_t dominantEye;
bool UF_API initialize( int stage = 0 );
void UF_API tick();

View File

@ -16,6 +16,7 @@ namespace ext {
VkImageView view;
VmaAllocation allocation;
VmaAllocationInfo allocationInfo;
VkPipelineColorBlendAttachmentState blendState;
} Attachment;
std::vector<Attachment> attachments;
@ -38,7 +39,7 @@ namespace ext {
void initialize( Device& device );
void destroy();
void addPass( VkPipelineStageFlags, VkAccessFlags, const std::vector<size_t>&, const std::vector<size_t>&, size_t );
size_t attach( VkFormat format, VkImageUsageFlags usage, VkImageLayout layout, Attachment* attachment = NULL );
size_t attach( VkFormat format, VkImageUsageFlags usage, VkImageLayout layout, bool blend = false, Attachment* attachment = NULL );
};
}
}

View File

@ -11,10 +11,29 @@ namespace ext {
Device* device = NULL;
VkSampler sampler;
VkDescriptorImageInfo descriptor;
VkFilter filter = VK_FILTER_LINEAR;
struct {
struct {
VkFilter min = VK_FILTER_LINEAR;
VkFilter mag = VK_FILTER_LINEAR;
} filter;
struct {
VkSamplerAddressMode u = VK_SAMPLER_ADDRESS_MODE_REPEAT, v = VK_SAMPLER_ADDRESS_MODE_REPEAT, w = VK_SAMPLER_ADDRESS_MODE_REPEAT;
} addressMode;
struct {
VkSamplerMipmapMode mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
float lodBias = 0.0f;
} mip;
VkCompareOp compareOp = VK_COMPARE_OP_NEVER;
struct {
float min = 0.0f;
float max = 0.0f;
} lod;
float maxAnisotropy;
void initialize( Device& device, VkFilter filter = VK_FILTER_LINEAR );
VkDescriptorImageInfo info;
} descriptor;
void initialize( Device& device );
void destroy();
};
struct UF_API Texture {
@ -59,6 +78,7 @@ namespace ext {
);
};
struct UF_API Texture2D : public Texture {
static Texture2D empty;
void loadFromFile(
std::string filename,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
@ -99,7 +119,6 @@ namespace ext {
uint32_t texHeight,
Device& device,
VkQueue copyQueue,
VkFilter filter = VK_FILTER_LINEAR,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);

View File

@ -43,6 +43,8 @@ namespace ext {
extern UF_API uint32_t height;
extern UF_API bool validation;
extern UF_API std::vector<std::string> validationFilters;
extern UF_API std::vector<std::string> requestedDeviceFeatures;
extern UF_API Device device;
typedef VmaAllocator Allocator;
extern UF_API Allocator allocator;

View File

@ -22,6 +22,7 @@ namespace uf {
} perspective;
int mode;
pod::Vector3 offset;
bool stereoscopic = false;
} m_settings;
struct {
struct {
@ -38,6 +39,7 @@ namespace uf {
Camera( const Camera& copy );
*/
bool modified() const;
void setStereoscopic( bool );
pod::Transform<>& getTransform();
const pod::Transform<>& getTransform() const;

View File

@ -35,7 +35,7 @@ namespace uf {
~Image();
void clear(); // empties pixel container
// Getters
void loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels );
void loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false );
void loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false );
std::string getFilename() const;
Image::container_t& getPixels();

View File

@ -2,157 +2,29 @@
#include <uf/config.h>
#include <uf/utils/math/vector.h>
#include <functional>
#include "./collision/gjk.h"
#include "./collision/boundingbox.h"
#include "./collision/sphere.h"
#include "./collision/mesh.h"
#include <vector>
// #include <uf/gl/mesh/mesh.h>
namespace pod {
struct UF_API Simplex {
public:
struct UF_API SupportPoint {
pod::Vector3 a, b, v;
bool operator==( const pod::Simplex::SupportPoint& r ) const {
return v == r.v;
}
pod::Vector3 operator-( const pod::Simplex::SupportPoint& r ) const {
return v - r.v;
}
pod::Vector3 operator*( float r ) const {
return v * r;
}
pod::Vector3 operator-( const pod::Vector3& r ) const {
return v - r;
}
float dot( const pod::Vector3& r ) const {
return uf::vector::dot(v, r);
}
pod::Vector3 cross( const pod::Simplex::SupportPoint& r ) const {
return uf::vector::cross(v, r.v);
}
pod::Vector3 cross( const pod::Vector3& r ) const {
return uf::vector::cross(v, r);
}
};
int size = 0;
pod::Simplex::SupportPoint b, c, d;
/* pod::Vector3 b, c, d;
Simplex( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() );
void add( const pod::Vector3& );
void set( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() );
*/
};
}
namespace uf {
class UF_API Collider {
public:
typedef std::vector<pod::Collider*> container_t;
protected:
uf::Collider::container_t m_container;
public:
struct UF_API Manifold {
const uf::Collider* a;
const uf::Collider* b;
pod::Vector3 normal;
float depth;
bool colliding;
Manifold() {
this->normal = pod::Vector3{0.0f, 0.0f, 0.0f};
this->depth = -0.1f;
this->colliding = false;
}
Manifold( const uf::Collider& a, const uf::Collider& b ) {
this->a = &a;
this->b = &b;
this->normal = pod::Vector3{0.0f, 0.0f, 0.0f};
this->depth = -0.1f;
this->colliding = false;
}
Manifold( const uf::Collider& a, const uf::Collider& b, const pod::Vector3& normal, float depth, bool colliding ) {
this->a = &a;
this->b = &b;
this->normal = normal;
this->depth = depth;
this->colliding = colliding;
}
};
virtual ~Collider();
virtual std::string type() const;
virtual pod::Vector3* expand() const = 0;
virtual pod::Vector3 support( const pod::Vector3& ) const = 0;
virtual uf::Collider::Manifold intersects( const uf::Collider& ) const;
};
class UF_API AABBox : public uf::Collider {
protected:
pod::Vector3 m_origin;
pod::Vector3 m_corner;
public:
AABBox( const pod::Vector3&, const pod::Vector3& );
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
virtual uf::Collider::Manifold intersects( const uf::AABBox& ) const;
};
class UF_API SphereCollider : public uf::Collider {
protected:
float m_radius;
pod::Vector3 m_origin;
public:
SphereCollider( float = 1.0f, const pod::Vector3& = pod::Vector3{} );
float getRadius() const;
const pod::Vector3& getOrigin() const;
void setRadius( float = 1.0f );
void setOrigin( const pod::Vector3& );
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
virtual uf::Collider::Manifold intersects( const uf::SphereCollider& ) const;
};
class UF_API ModularCollider : public uf::Collider {
public:
typedef std::function<pod::Vector3*()> function_expand_t;
typedef std::function<pod::Vector3(const pod::Vector3&)> function_support_t;
protected:
uint m_len;
pod::Vector3* m_container;
bool m_should_free;
uf::ModularCollider::function_expand_t m_function_expand;
uf::ModularCollider::function_support_t m_function_support;
public:
ModularCollider( uint len = 0, pod::Vector3* = NULL, bool = false, const uf::ModularCollider::function_expand_t& = NULL, const uf::ModularCollider::function_support_t& = NULL );
~ModularCollider();
void setExpand( const uf::ModularCollider::function_expand_t& = NULL );
void setSupport( const uf::ModularCollider::function_support_t& = NULL );
pod::Vector3* getContainer();
uint getSize() const;
void setContainer( pod::Vector3*, uint );
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
};
class UF_API CollisionBody {
public:
typedef std::vector<uf::Collider*> container_t;
protected:
uf::CollisionBody::container_t m_container;
public:
~CollisionBody();
~Collider();
void clear();
void add( uf::Collider* );
uf::CollisionBody::container_t& getContainer();
const uf::CollisionBody::container_t& getContainer() const;
void add( pod::Collider* );
uf::Collider::container_t& getContainer();
const uf::Collider::container_t& getContainer() const;
std::size_t getSize() const;
std::vector<uf::Collider::Manifold> intersects( const uf::CollisionBody& ) const;
std::vector<uf::Collider::Manifold> intersects( const uf::Collider& ) const;
std::vector<pod::Collider::Manifold> intersects( const uf::Collider&, bool = false ) const;
std::vector<pod::Collider::Manifold> intersects( const pod::Collider&, bool = false ) const;
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "gjk.h"
namespace uf {
class UF_API BoundingBox : public pod::Collider {
protected:
pod::Vector3 m_origin;
pod::Vector3 m_corner;
public:
BoundingBox( const pod::Vector3& = {}, const pod::Vector3& = {} );
const pod::Vector3& getOrigin() const;
const pod::Vector3& getCorner() const;
void setOrigin( const pod::Vector3& );
void setCorner( const pod::Vector3& );
pod::Vector3 min() const;
pod::Vector3 max() const;
pod::Vector3 closest( const pod::Vector3f& ) const;
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
virtual pod::Collider::Manifold intersects( const uf::BoundingBox& ) const;
};
}

View File

@ -0,0 +1,88 @@
#pragma once
#include <uf/config.h>
#include <uf/utils/math/vector.h>
#include <uf/utils/math/transform.h>
namespace pod {
struct UF_API Simplex {
public:
struct UF_API SupportPoint {
pod::Vector3 a, b, v;
bool operator==( const pod::Simplex::SupportPoint& r ) const {
return v == r.v;
}
pod::Vector3 operator-( const pod::Simplex::SupportPoint& r ) const {
return v - r.v;
}
pod::Vector3 operator*( float r ) const {
return v * r;
}
pod::Vector3 operator-( const pod::Vector3& r ) const {
return v - r;
}
float dot( const pod::Vector3& r ) const {
return uf::vector::dot(v, r);
}
pod::Vector3 cross( const pod::Simplex::SupportPoint& r ) const {
return uf::vector::cross(v, r.v);
}
pod::Vector3 cross( const pod::Vector3& r ) const {
return uf::vector::cross(v, r);
}
};
int size = 0;
pod::Simplex::SupportPoint b, c, d;
/*
pod::Vector3 b, c, d;
Simplex( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() );
void add( const pod::Vector3& );
void set( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() );
*/
};
}
namespace pod {
class UF_API Collider {
protected:
pod::Transform<> m_transform;
public:
struct UF_API Manifold {
const pod::Collider* a;
const pod::Collider* b;
pod::Vector3 normal;
float depth;
bool colliding;
Manifold() {
this->normal = pod::Vector3{0.0f, 0.0f, 0.0f};
this->depth = -0.1f;
this->colliding = false;
}
Manifold( const pod::Collider& a, const pod::Collider& b ) {
this->a = &a;
this->b = &b;
this->normal = pod::Vector3{0.0f, 0.0f, 0.0f};
this->depth = -0.1f;
this->colliding = false;
}
Manifold( const pod::Collider& a, const pod::Collider& b, const pod::Vector3& normal, float depth, bool colliding ) {
this->a = &a;
this->b = &b;
this->normal = normal;
this->depth = depth;
this->colliding = colliding;
}
};
virtual ~Collider();
virtual std::string type() const;
virtual pod::Vector3* expand() const = 0;
virtual pod::Vector3 support( const pod::Vector3& ) const = 0;
virtual pod::Collider::Manifold intersects( const pod::Collider& ) const;
pod::Vector3f getPosition() const;
pod::Transform<>& getTransform();
const pod::Transform<>& getTransform() const;
void setTransform( const pod::Transform<>& );
};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "gjk.h"
#include <uf/utils/graphic/mesh.h>
namespace uf {
class UF_API MeshCollider : public pod::Collider {
protected:
std::vector<pod::Vector3> m_positions;
public:
MeshCollider( const pod::Transform<>& = {}, const std::vector<pod::Vector3>& = {} );
std::vector<pod::Vector3>& getPositions();
const std::vector<pod::Vector3>& getPositions() const;
void setPositions( const std::vector<pod::Vector3>& );
template<typename T, typename U>
void setPositions( const uf::BaseMesh<T, U>& mesh ) {
this->m_positions.clear();
this->m_positions.reserve( std::max( mesh.vertices.size(), mesh.indices.size() ) );
if ( !mesh.indices.empty() ) {
for ( auto& index : mesh.indices ) this->m_positions.push_back( mesh.vertices[index].position );
} else {
for ( auto& vertex : mesh.vertices ) this->m_positions.push_back( vertex.position );
}
}
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "gjk.h"
#include <functional>
namespace uf {
class UF_API ModularCollider : public pod::Collider {
public:
typedef std::function<pod::Vector3*()> function_expand_t;
typedef std::function<pod::Vector3(const pod::Vector3&)> function_support_t;
protected:
uint m_len;
pod::Vector3* m_container;
bool m_should_free;
uf::ModularCollider::function_expand_t m_function_expand;
uf::ModularCollider::function_support_t m_function_support;
public:
ModularCollider( uint len = 0, pod::Vector3* = NULL, bool = false, const uf::ModularCollider::function_expand_t& = NULL, const uf::ModularCollider::function_support_t& = NULL );
~ModularCollider();
void setExpand( const uf::ModularCollider::function_expand_t& = NULL );
void setSupport( const uf::ModularCollider::function_support_t& = NULL );
pod::Vector3* getContainer();
uint getSize() const;
void setContainer( pod::Vector3*, uint );
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
};
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "gjk.h"
namespace uf {
class UF_API SphereCollider : public pod::Collider {
protected:
float m_radius;
pod::Vector3 m_origin;
public:
SphereCollider( float = 1.0f, const pod::Vector3& = pod::Vector3{} );
float getRadius() const;
const pod::Vector3& getOrigin() const;
void setRadius( float = 1.0f );
void setOrigin( const pod::Vector3& );
virtual std::string type() const;
virtual pod::Vector3* expand() const;
virtual pod::Vector3 support( const pod::Vector3& ) const;
virtual pod::Collider::Manifold intersects( const uf::SphereCollider& ) const;
};
}

View File

@ -21,8 +21,11 @@ namespace pod {
namespace uf {
namespace physics {
namespace time {
UF_API uf::Timer<> timer;
UF_API double current, previous, delta, clamp;
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;
}
void UF_API tick();
template<typename T> pod::Transform<T>& update( pod::Transform<T>& transform, pod::Physics& physics );

View File

@ -214,8 +214,7 @@ std::string uf::Asset::load( const std::string& uri ) {
uf::Serializer& json = container.emplace_back();
json.readFromFile(filename);
} else {
uf::iostream << "Failed to load `" + filename + "`: Unimplemented extension: " + extension << "\n";
return "";
uf::iostream << "Failed to parse `" + filename + "`: Unimplemented extension: " + extension << "\n";
}
return filename;
}

View File

@ -3,6 +3,11 @@
#include <uf/engine/scene/scene.h>
#include <uf/utils/time/time.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/graphic/mesh.h>
#include <uf/ext/gltf/gltf.h>
namespace {
uf::Timer<long long> timer(false);
@ -14,6 +19,7 @@ namespace {
if ( filename.substr(0,9) == "/smtsamo/" ) root = "./data/";
else if ( extension == "json" ) root = "./data/entities/";
else if ( extension == "png" ) root = "./data/textures/";
else if ( extension == "glb" ) root = "./data/models/";
else if ( extension == "ogg" ) root = "./data/audio/";
}
return uf::string::sanitize(filename, root);
@ -23,6 +29,33 @@ namespace {
UF_OBJECT_REGISTER_CPP(Object)
void uf::Object::initialize() {
uf::Entity::initialize();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( metadata["system"]["type"].isNull() || metadata["system"]["defaults"]["asset load"].asBool() ) {
// Default load: GLTF model
this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string filename = json["filename"].asString();
if ( uf::string::extension(filename) != "glb" ) return "false";
int8_t LOAD_FLAGS = 0;
if ( metadata["model"]["flags"]["GENERATE_NORMALS"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::GENERATE_NORMALS; // 0x1 << 0;
if ( metadata["model"]["flags"]["APPLY_TRANSFORMS"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::APPLY_TRANSFORMS; // 0x1 << 1;
if ( metadata["model"]["flags"]["SEPARATE_MESHES"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::SEPARATE_MESHES; // 0x1 << 2;
if ( metadata["model"]["flags"]["RENDER"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::RENDER; // 0x1 << 3;
if ( metadata["model"]["flags"]["COLLISION"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::COLLISION; // 0x1 << 4;
if ( metadata["model"]["flags"]["AABB"].asBool() )
LOAD_FLAGS |= ext::gltf::LoadMode::AABB; // 0x1 << 5;
ext::gltf::load( *this, filename, LOAD_FLAGS );
return "true";
});
}
}
void uf::Object::destroy() {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
@ -41,10 +74,14 @@ void uf::Object::tick() {
// listen for metadata file changes
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( metadata["system"]["hot reload"]["enabled"].asBool() ) {
/*
std::string filename = "./entities/"+metadata["system"]["source"].asString();
std::string root = "./data/" + uf::string::directory(filename);
size_t mtime = uf::string::mtime( root + uf::string::filename(filename) );
*/
size_t mtime = uf::string::mtime( metadata["system"]["source"].asString() );
if ( metadata["system"]["hot reload"]["mtime"].asUInt64() < mtime ) {
std::cout << metadata["system"]["hot reload"]["mtime"] << ": " << mtime << std::endl;
metadata["system"]["hot reload"]["mtime"] = mtime;
this->reload();
//this->queueHook("metadata:Reload.%UID%");
@ -71,6 +108,32 @@ void uf::Object::tick() {
}
void uf::Object::render() {
uf::Entity::render();
auto& metadata = this->getComponent<uf::Serializer>();
if ( metadata["system"]["type"].isNull() || metadata["system"]["defaults"]["render"].asBool() ) {
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = uf::scene::getCurrentScene();
auto& graphic = this->getComponent<uf::Graphic>();
auto& transform = this->getComponent<pod::Transform<>>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
uniforms.matrices.model = uf::transform::model( transform );
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms.matrices.view[i] = camera.getView( i );
uniforms.matrices.projection[i] = camera.getProjection( i );
}
uniforms.color[0] = 1;
uniforms.color[1] = 1;
uniforms.color[2] = 1;
uniforms.color[3] = 1;
graphic.material.shaders.front().updateBuffer( uniforms, 0, false );
};
}
}
void uf::Object::queueHook( const std::string& name, const std::string& payload, double timeout ) {
@ -105,11 +168,11 @@ bool uf::Object::load( const std::string& f, bool inheritRoot ) {
}
std::string filename = grabURI( f, root );
if ( !json.readFromFile( filename ) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
return false;
}
json["root"] = uf::string::directory(filename);
json["source"] = uf::string::filename(filename);
json["source"] = filename; // uf::string::filename(filename);
json["hot reload"]["mtime"] = uf::string::mtime(filename);
return this->load(json);
}
@ -118,9 +181,10 @@ bool uf::Object::reload( bool hard ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( !metadata["system"]["source"].isString() ) return false;
uf::Serializer json;
std::string filename = grabURI( metadata["system"]["source"].asString(), metadata["system"]["root"].asString() ); // uf::string::sanitize(metadata["system"]["source"].asString(), metadata["system"]["root"].asString());
std::string filename = metadata["system"]["source"].asString(); //grabURI( metadata["system"]["source"].asString(), metadata["system"]["root"].asString() ); // uf::string::sanitize(metadata["system"]["source"].asString(), metadata["system"]["root"].asString());
if ( !json.readFromFile( filename ) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
uf::iostream << this << ": " << this->getName() << ": " << this->getUid() << ": " << metadata << "\n";
return false;
}
if ( hard ) return this->load(filename);
@ -136,11 +200,11 @@ std::size_t uf::Object::loadChild( const std::string& f, bool initialize ) {
uf::Serializer json;
std::string filename = grabURI( f, metadata["system"]["root"].asString() );
if ( !json.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
return -1;
}
json["root"] = uf::string::directory(filename);
json["source"] = uf::string::filename(filename);
json["source"] = metadata["system"]["source"].asString(); //uf::string::filename(filename);
json["hot reload"]["mtime"] = uf::string::mtime( filename );
return this->loadChild(json, initialize);
}
@ -150,7 +214,9 @@ bool uf::Object::load( const uf::Serializer& json ) {
{
// Set name
this->m_name = json["name"].isString() ? json["name"].asString() : json["type"].asString();
// Set transform
}
// Set transform
{
bool load = json["transform"].isObject();
if ( this->hasComponent<pod::Transform<>>() ) load = false;
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
@ -182,6 +248,25 @@ bool uf::Object::load( const uf::Serializer& json ) {
transform = uf::transform::reorient( transform );
}
}
// Set movement
{
if ( json["physics"].isObject() && !this->hasComponent<pod::Physics>() ) {
auto& physics = this->getComponent<pod::Physics>();
if ( json["physics"]["linear"]["velocity"].isArray() )
for ( uint j = 0; j < 3; ++j )
physics.linear.velocity[j] = json["physics"]["linear"]["velocity"][j].asFloat();
if ( json["physics"]["linear"]["acceleration"].isArray() )
for ( uint j = 0; j < 3; ++j )
physics.linear.acceleration[j] = json["physics"]["linear"]["acceleration"][j].asFloat();
if ( json["physics"]["rotational"]["velocity"].isArray() )
for ( uint j = 0; j < 4; ++j )
physics.rotational.velocity[j] = json["physics"]["rotational"]["velocity"][j].asFloat();
if ( json["physics"]["rotational"]["acceleration"].isArray() )
for ( uint j = 0; j < 4; ++j )
physics.rotational.acceleration[j] = json["physics"]["rotational"]["acceleration"][j].asFloat();
}
}
uf::Scene& scene = this->getRootParent<uf::Scene>();
uf::Asset& assetLoader = scene.getComponent<uf::Asset>();
@ -204,12 +289,6 @@ bool uf::Object::load( const uf::Serializer& json ) {
std::string filename = grabURI( target[i].asString(), json["root"].asString() );
if ( uf::string::extension(filename) != "ogg" ) continue;
if ( (canonical = assetLoader.load( filename )) != "" ) {
/*
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
*/
uf::Serializer payload;
payload["filename"] = canonical;
this->queueHook( "asset:Load.%UID%", payload );
@ -234,12 +313,6 @@ bool uf::Object::load( const uf::Serializer& json ) {
std::string filename = grabURI( target[i].asString(), json["root"].asString() );
if ( uf::string::extension(filename) != "png" ) continue;
if ( (canonical = assetLoader.load( filename )) != "" ) {
/*
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
*/
uf::Serializer payload;
payload["filename"] = canonical;
this->queueHook( "asset:Load.%UID%", payload );
@ -247,7 +320,31 @@ bool uf::Object::load( const uf::Serializer& json ) {
}
}
uf::Serializer queue = metadata["system"]["hooks"]["queue"];
// gltf (singular)
{
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["models"].isNull() ) {
target = json["assets"]["models"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string canonical = "";
std::string f = target[i].asString();
std::string filename = grabURI( target[i].asString(), json["root"].asString() );
if ( uf::string::extension(filename) != "glb" ) continue;
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer payload;
payload["filename"] = canonical;
this->queueHook( "asset:Load.%UID%", payload );
}
}
}
uf::Serializer hooks = metadata["system"]["hooks"];
// Metadata
if ( json["metadata"] != Json::nullValue ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
@ -255,7 +352,7 @@ bool uf::Object::load( const uf::Serializer& json ) {
std::string f = json["metadata"].asString();
std::string filename = grabURI( json["metadata"].asString(), json["root"].asString() );
if ( !metadata.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
return false;
}
} else {
@ -264,7 +361,11 @@ bool uf::Object::load( const uf::Serializer& json ) {
}
metadata["system"] = json;
metadata["system"].removeMember("metadata");
metadata["system"]["hooks"]["queue"] = queue;
metadata["system"]["hooks"] = hooks;
for ( auto it = json["system"].begin(); it != json["system"].end(); ++it ) {
if ( metadata["system"][it.key().asString()].isNull() )
metadata["system"][it.key().asString()] = json["system"][it.key().asString()];
}
// check for children
{
@ -284,15 +385,39 @@ bool uf::Object::load( const uf::Serializer& json ) {
if ( uf::string::extension(filename) != "json" ) continue;
if ( (filename = assetLoader.load(filename) ) == "" ) continue;
if ( !json.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
continue;
}
json["root"] = uf::string::directory(filename);
json["source"] = uf::string::filename(filename);
json["source"] = filename; // uf::string::filename(filename)
json["hot reload"]["mtime"] = uf::string::mtime( filename );
if ( this->loadChild(json) == -1 ) continue;
}
}
// Add lights
if ( metadata["system"]["lights"].isArray() ) {
uf::Serializer target = metadata["system"]["lights"];
for ( uint i = 0; i < target.size(); ++i ) {
uf::Serializer json = target[i];
auto* light = this->findByUid(this->loadChild("/light.json", false));
if ( !light ) continue;
auto& metadata = light->getComponent<uf::Serializer>();
auto& transform = light->getComponent<pod::Transform<>>();
if ( json["position"].isArray() )
for ( uint j = 0; j < 3; ++j ) transform.position[j] = json["position"][j].asFloat();
if ( json["orientation"].isArray() )
for ( uint j = 0; j < 4; ++j ) transform.orientation[j] = json["orientation"][j].asFloat();
if ( !json["color"].isNull() ) metadata["light"]["color"] = json["color"];
if ( !json["radius"].isNull() ) metadata["light"]["radius"] = json["radius"];
if ( !json["power"].isNull() ) metadata["light"]["power"] = json["power"];
if ( !json["shadows"].isNull() ) metadata["light"]["shadows"] = json["shadows"];
light->initialize();
// std::cout << json << "\t" << metadata["light"] << std::endl;
}
}
return true;
}
@ -303,7 +428,7 @@ std::size_t uf::Object::loadChild( const uf::Serializer& json, bool initialize )
entity = uf::instantiator::instantiate(type);
if ( !((uf::Object*) entity)->load(json) ) {
uf::iostream << "Error loading `" << json << "!" << "\n";
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << " loading `" << json << "!" << "\n";
delete entity;
return -1;
}

View File

@ -1,22 +1,174 @@
#include <uf/engine/scene/scene.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/utils/string/ext.h>
#include <uf/utils/camera/camera.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/rendermodes/stereoscopic_deferred.h>
UF_OBJECT_REGISTER_CPP(Scene)
void uf::Scene::initialize() {
// this->m_graphics = new std::vector<ext::vulkan::Graphic*>();
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
ext::vulkan::scenes.push_back(this);
ext::vulkan::rebuild = true;
uf::Object::initialize();
}
void uf::Scene::tick() {
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
uf::Object::tick();
if ( uf::scene::getCurrentScene().getUid() == this->getUid() ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
/* Update lights */ if ( metadata["light"]["should"].asBool() ) {
// if ( !ext::vulkan::currentRenderMode || ext::vulkan::currentRenderMode->name != "" ) return;
auto& scene = uf::scene::getCurrentScene();
std::vector<ext::vulkan::Graphic*> blitters;
auto& renderMode = ext::vulkan::getRenderMode("", true);
if ( renderMode.getType() == "Deferred (Stereoscopic)" ) {
auto* renderModePointer = (ext::vulkan::StereoscopicDeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitters.left);
blitters.push_back(&renderModePointer->blitters.right);
} else if ( renderMode.getType() == "Deferred" ) {
auto* renderModePointer = (ext::vulkan::DeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitter);
}
auto& controller = *scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
// auto& uniforms = blitter.uniforms;
struct UniformDescriptor {
struct Matrices {
alignas(16) pod::Matrix4f view[2];
alignas(16) pod::Matrix4f projection[2];
} matrices;
alignas(16) pod::Vector4f ambient;
struct Light {
alignas(16) pod::Vector4f position;
alignas(16) pod::Vector4f color;
alignas(8) pod::Vector2i type;
alignas(16) pod::Matrix4f view;
alignas(16) pod::Matrix4f projection;
} lights;
};
struct SpecializationConstant {
int32_t maxLights = 16;
} specializationConstants;
for ( size_t _ = 0; _ < blitters.size(); ++_ ) {
auto& blitter = *blitters[_];
uint8_t* buffer;
size_t len;
auto* shader = &blitter.material.shaders.front();
for ( auto& _ : blitter.material.shaders ) {
if ( _.uniforms.empty() ) continue;
auto& userdata = _.uniforms.front();
buffer = (uint8_t*) (void*) userdata;
len = userdata.data().len;
shader = &_;
specializationConstants = _.specializationConstants.get<SpecializationConstant>();
}
if ( !buffer ) continue;
UniformDescriptor* uniforms = (UniformDescriptor*) buffer;
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms->matrices.view[i] = camera.getView( i );
uniforms->matrices.projection[i] = camera.getProjection( i );
}
{
uniforms->ambient.x = metadata["light"]["ambient"][0].asFloat();
uniforms->ambient.y = metadata["light"]["ambient"][1].asFloat();
uniforms->ambient.z = metadata["light"]["ambient"][2].asFloat();
uniforms->ambient.w = metadata["light"]["kexp"].asFloat();
}
{
std::vector<uf::Entity*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity || entity->getName() != "Light" ) return;
entities.push_back(entity);
};
for ( uf::Scene* scene : ext::vulkan::scenes ) { if ( !scene ) continue;
scene->process(filter);
}
{
const pod::Vector3& position = controller.getComponent<pod::Transform<>>().position;
std::sort( entities.begin(), entities.end(), [&]( const uf::Entity* l, const uf::Entity* r ){
if ( !l ) return false; if ( !r ) return true;
if ( !l->hasComponent<pod::Transform<>>() ) return false; if ( !r->hasComponent<pod::Transform<>>() ) return true;
return uf::vector::magnitude( uf::vector::subtract( l->getComponent<pod::Transform<>>().position, position ) ) < uf::vector::magnitude( uf::vector::subtract( r->getComponent<pod::Transform<>>().position, position ) );
} );
}
{
uf::Serializer& metadata = controller.getComponent<uf::Serializer>();
if ( metadata["light"]["should"].asBool() ) entities.push_back(&controller);
}
UniformDescriptor::Light* lights = (UniformDescriptor::Light*) &buffer[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Light)];
for ( size_t i = 0; i < specializationConstants.maxLights; ++i ) {
UniformDescriptor::Light& light = lights[i];
light.position = { 0, 0, 0, 0 };
light.color = { 0, 0, 0, 0 };
light.type = { 0, 0 };
}
blitter.material.textures.clear();
for ( size_t i = 0; i < specializationConstants.maxLights && i < entities.size(); ++i ) {
UniformDescriptor::Light& light = lights[i];
uf::Entity* entity = entities[i];
pod::Transform<>& transform = entity->getComponent<pod::Transform<>>();
uf::Serializer& metadata = entity->getComponent<uf::Serializer>();
uf::Camera& camera = entity->getComponent<uf::Camera>();
light.position.x = transform.position.x;
light.position.y = transform.position.y;
light.position.z = transform.position.z;
light.view = camera.getView();
light.projection = camera.getProjection();
if ( entity == &controller ) light.position.y += 2;
light.position.w = metadata["light"]["power"].asFloat();
light.color.x = metadata["light"]["color"][0].asFloat();
light.color.y = metadata["light"]["color"][1].asFloat();
light.color.z = metadata["light"]["color"][2].asFloat();
light.color.w = metadata["light"]["radius"].asFloat();
light.type.x = metadata["light"]["type"].asUInt64();
light.type.y = metadata["light"]["shadows"]["enabled"].asBool();
if ( entity->hasComponent<ext::vulkan::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<ext::vulkan::RenderTargetRenderMode>();
auto& renderTarget = renderMode.renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
auto& texture = blitter.material.textures.emplace_back();
texture.aliasAttachment(attachment);
light.type.y = true;
break;
}
} else {
light.type.y = false;
}
}
}
blitter.getPipeline().update( blitter );
shader->updateBuffer( (void*) buffer, len, 0, false );
}
}
}
}
void uf::Scene::render() {
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
uf::Object::render();
}
void uf::Scene::destroy() {
uf::Object::destroy();
@ -27,29 +179,45 @@ void uf::Scene::destroy() {
ext::vulkan::scenes.erase(it);
}
}
/*
ext::vulkan::scenes.erase(
std::remove(ext::vulkan::scenes.begin(), ext::vulkan::scenes.end(), this),
ext::vulkan::scenes.end()
);
*/
ext::vulkan::rebuild = true;
/*
std::vector<ext::vulkan::Graphic*>* graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
for ( auto* graphic : *graphics ) {
graphic->destroy();
}
delete graphics;
ext::vulkan::graphics = NULL;
*/
}
/*
uf::Entity* uf::Scene::getController() {
return this->findByName("Player");
}
const uf::Entity* uf::Scene::getController() const {
return this->findByName("Player");
}
*/
uf::Entity* uf::Scene::getController() {
if ( ext::vulkan::currentRenderMode ) {
auto& renderMode = *ext::vulkan::currentRenderMode;
std::string name = renderMode.name;
auto split = uf::string::split( name, ": " );
if ( split.front() == "Render Target" ) {
uint64_t uid = std::stoi( split.back() );
uf::Entity* ent = this->findByUid( uid );
if ( ent ) return ent;
}
}
return this->findByName("Player");
}
const uf::Entity* uf::Scene::getController() const {
if ( ext::vulkan::currentRenderMode ) {
auto& renderMode = *ext::vulkan::currentRenderMode;
std::string name = renderMode.name;
auto split = uf::string::split( name, ": " );
if ( split.front() == "Render Target" ) {
uint64_t uid = std::stoi( split.back() );
const uf::Entity* ent = this->findByUid( uid );
if ( ent ) return ent;
}
}
return this->findByName("Player");
}
std::vector<uf::Scene*> uf::scene::scenes;
uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& filename ) {

View File

@ -0,0 +1,334 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <gltf/tiny_gltf.h>
#include <uf/ext/gltf/gltf.h>
#include <uf/utils/string/ext.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/graphic/mesh.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/math/collision.h>
namespace {
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode) {
switch (wrapMode) {
case 10497: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case 33071: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case 33648: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
default: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
}
}
VkFilter getVkFilterMode(int32_t filterMode) {
switch (filterMode) {
case 9728: return VK_FILTER_NEAREST;
case 9729: return VK_FILTER_LINEAR;
case 9984: return VK_FILTER_NEAREST;
case 9985: return VK_FILTER_NEAREST;
case 9986: return VK_FILTER_LINEAR;
case 9987: return VK_FILTER_LINEAR;
default: return VK_FILTER_LINEAR;
}
}
void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf::Node& node, uint8_t mode ) {
auto& transform = entity.getComponent<pod::Transform<>>();
if ( node.translation.size() == 3 ) {
transform.position.x = node.translation[0];
transform.position.y = node.translation[1];
transform.position.z = node.translation[2];
}
if ( node.rotation.size() == 4 ) {
transform.orientation.x = node.rotation[0];
transform.orientation.y = node.rotation[1];
transform.orientation.z = node.rotation[2];
transform.orientation.w = node.rotation[3];
}
if ( node.scale.size() == 3 ) {
transform.scale.x = node.scale[0];
transform.scale.y = node.scale[1];
transform.scale.z = node.scale[2];
}
// if ( node.matrix.size() == 16 ) {}
auto fillMesh = [&]( uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t>& mesh, const tinygltf::Primitive& primitive, uf::Collider& collider ) {
size_t verticesStart = mesh.vertices.size();
size_t indicesStart = mesh.indices.size();
size_t vertices = 0;
struct Attribute {
std::string name = "";
size_t components = 1;
std::vector<float> buffer;
};
std::unordered_map<std::string, Attribute> attributes = {
{"POSITION", {}},
{"TEXCOORD_0", {}},
{"NORMAL", {}},
};
for ( auto& kv : attributes ) {
auto& attribute = kv.second;
attribute.name = kv.first;
auto it = primitive.attributes.find(attribute.name);
if ( it == primitive.attributes.end() ) continue;
auto& accessor = model.accessors[it->second];
auto& view = model.bufferViews[accessor.bufferView];
auto* buffer = reinterpret_cast<const float*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
if ( attribute.name == "POSITION" ) {
vertices = accessor.count;
pod::Vector3f minCorner = { accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
pod::Vector3f maxCorner = { accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
pod::Vector3f origin = (maxCorner + minCorner) * 0.5f;
pod::Vector3f size = (maxCorner - minCorner) * 0.5f;
if ( (mode & ext::gltf::LoadMode::COLLISION) && (mode & ext::gltf::LoadMode::AABB) ) {
auto* box = new uf::BoundingBox( origin, size );
collider.add(box);
}
}
attribute.components = accessor.ByteStride(view) / sizeof(float);
attribute.buffer.reserve( accessor.count * attribute.components );
attribute.buffer.insert( attribute.buffer.end(), &buffer[0], &buffer[accessor.count * attribute.components] );
}
mesh.vertices.reserve( vertices + verticesStart );
for ( size_t i = 0; i < vertices; ++i ) {
auto& vertex = mesh.vertices.emplace_back();
#define ITERATE_ATTRIBUTE( name, member )\
if ( !attributes[name].buffer.empty() ) { \
for ( size_t j = 0; j < attributes[name].components; ++j )\
vertex.member[j] = attributes[name].buffer[i * attributes[name].components + j];\
}
ITERATE_ATTRIBUTE("POSITION", position);
ITERATE_ATTRIBUTE("TEXCOORD_0", uv);
ITERATE_ATTRIBUTE("NORMAL", normal);
#undef ITERATE_ATTRIBUTE
}
if ( primitive.indices > -1 ) {
auto& accessor = model.accessors[primitive.indices];
auto& view = model.bufferViews[accessor.bufferView];
auto& buffer = model.buffers[view.buffer];
mesh.indices.reserve( accessor.count + indicesStart );
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 );
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
auto* buf = static_cast<const uint16_t*>( pointer );
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
break;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
auto* buf = static_cast<const uint8_t*>( pointer );
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
break;
}
}
if ( mode & ext::gltf::LoadMode::GENERATE_NORMALS ) {
for ( size_t i = 0; i < mesh.indices.size(); i+=3 ) {
auto& A = mesh.vertices[mesh.indices[i+0]];
auto& B = mesh.vertices[mesh.indices[i+1]];
auto& C = mesh.vertices[mesh.indices[i+2]];
auto& a = A.position;
auto& b = B.position;
auto& c = C.position;
pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) );
A.normal = normal;
B.normal = normal;
C.normal = normal;
}
}
} else {
// recalc normals
if ( mode & ext::gltf::LoadMode::GENERATE_NORMALS ) {
// bool invert = false;
for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) {
// auto& b = mesh.vertices[i+(invert ? 2 : 1)].position;
// auto& c = mesh.vertices[i+(invert ? 1 : 2)].position;
auto& a = mesh.vertices[i+0].position;
auto& b = mesh.vertices[i+1].position;
auto& c = mesh.vertices[i+2].position;
pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) );
mesh.vertices[i+0].normal = normal;
mesh.vertices[i+1].normal = normal;
mesh.vertices[i+2].normal = normal;
}
}
}
if ( mode & ext::gltf::LoadMode::APPLY_TRANSFORMS ) {
pod::Matrix4f model = uf::transform::model( transform );
for ( auto& vertex : mesh.vertices ) {
vertex.position = uf::matrix::multiply<float>( model, vertex.position );
}
}
};
if ( node.mesh > -1 ) {
auto& m = model.meshes[node.mesh];
std::vector<ext::vulkan::Sampler> samplers;
std::vector<uf::Image> images;
/*
std::vector<uf::Object> lights;
for ( auto& l : model.lights ) {
auto& light = lights.emplace_back();
auto& metadata = light.getComponent<uf::Serializer>();
metadata["light"]["color"][0] = l.color[0];
metadata["light"]["color"][1] = l.color[1];
metadata["light"]["color"][2] = l.color[2];
metadata["light"]["radius"] = l.range;
metadata["light"]["power"] = l.intensity;
std::cout << metadata << std::endl;
}
*/
for ( auto& s : model.samplers ) {
auto& sampler = samplers.emplace_back();
sampler.descriptor.filter.min = getVkFilterMode( s.minFilter );
sampler.descriptor.filter.mag = getVkFilterMode( s.magFilter );
sampler.descriptor.addressMode.u = getVkWrapMode( s.wrapS );
sampler.descriptor.addressMode.v = getVkWrapMode( s.wrapT );
sampler.descriptor.addressMode.w = sampler.descriptor.addressMode.v;
}
for ( auto& t : model.textures ) {
auto& im = model.images[t.source];
uf::Image& image = images.emplace_back();
// std::cout << "Loading image: " << im.width << ", " << im.height << std::endl;
image.loadFromBuffer( &im.image[0], {im.width, im.height}, 8, im.component, true );
}
// if ( model.textures.size() > 1 && m.primitives.size() == model.textures.size() ) {
if ( mode & ext::gltf::LoadMode::SEPARATE_MESHES ) {
auto sampler = samplers.begin();
auto image = images.begin();
for ( auto& primitive : m.primitives ) {
uf::Object* child = new uf::Object;
uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t> mesh;
auto& cTransform = child->getComponent<pod::Transform<>>();
cTransform = transform;
auto& collider = child->getComponent<uf::Collider>();
fillMesh( mesh, primitive, collider );
if ( (mode & ext::gltf::LoadMode::COLLISION) && !(mode & ext::gltf::LoadMode::AABB) ) {
auto* box = new uf::MeshCollider( cTransform );
box->setPositions( mesh );
collider.add(box);
}
if ( mode & ext::gltf::LoadMode::RENDER ) {
auto& graphic = child->getComponent<uf::Graphic>();
// graphic.descriptor.cullMode = VK_CULL_MODE_NONE;
graphic.initialize();
graphic.initializeGeometry( mesh );
graphic.material.attachShader("./data/shaders/base.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
graphic.material.attachShader("./data/shaders/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
if ( image != images.end() ) graphic.material.textures.emplace_back().loadFromImage( *(image++) );
if ( sampler != samplers.end() ) graphic.material.samplers.push_back( *(sampler++) );
}
for ( auto* collider : collider.getContainer() ) collider->getTransform().reference = &cTransform;
entity.addChild( *child );
child->initialize();
if ( mode & ext::gltf::LoadMode::APPLY_TRANSFORMS ) cTransform = {};
}
} else {
uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t> mesh;
auto& collider = entity.getComponent<uf::Collider>();
for ( auto& primitive : m.primitives ) fillMesh( mesh, primitive, collider );
if ( (mode & ext::gltf::LoadMode::COLLISION) && !(mode & ext::gltf::LoadMode::AABB) ) {
auto* c = new uf::MeshCollider( transform );
c->setPositions( mesh );
collider.add(c);
}
for ( auto* collider : collider.getContainer() ) collider->getTransform().reference = &transform;
if ( mode & ext::gltf::LoadMode::RENDER ) {
auto& graphic = entity.getComponent<uf::Graphic>();
graphic.initialize();
graphic.initializeGeometry( mesh );
graphic.material.attachShader("./data/shaders/base.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
graphic.material.attachShader("./data/shaders/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
for ( auto& image : images ) graphic.material.textures.emplace_back().loadFromImage( image );
for ( auto& sampler : samplers ) graphic.material.samplers.push_back(sampler);
}
if ( mode & ext::gltf::LoadMode::APPLY_TRANSFORMS ) transform = {};
}
}
for ( auto i : node.children ) {
uf::Object* child = new uf::Object;
entity.addChild( *child );
loadNode( *child, model, model.nodes[i], mode );
child->initialize();
}
}
}
bool ext::gltf::load( uf::Object& entity, const std::string& filename, uint8_t mode ) {
tinygltf::Model model;
tinygltf::TinyGLTF loader;
std::string warn, err;
std::string extension = uf::string::extension( filename );
bool ret;
if ( extension == "glb" )
ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename); // for binary glTF(.glb)
else
ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
if ( !warn.empty() ) std::cout << "glTF warning: " << warn << std::endl;
if ( !err.empty() ) std::cout << "glTF error: " << err << std::endl;
if ( !ret ) { std::cout << "glTF error: failed to parse file: " << filename << std::endl;
return false;
}
const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
for ( auto i : scene.nodes ) {
loadNode( entity, model, model.nodes[i], mode );
}
// parent transform
auto& transform = entity.getComponent<pod::Transform<>>();
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* child ) {
if ( child == &entity ) return;
if ( !child->hasComponent<pod::Transform<>>() ) return;
child->getComponent<pod::Transform<>>().reference = &transform;
};
entity.process(filter);
return true;
}

View File

@ -14,6 +14,7 @@ float ext::openvr::width = 0;
float ext::openvr::height = 0;
bool ext::openvr::enabled = false;
bool ext::openvr::swapEyes = false;
uint8_t ext::openvr::dominantEye = 0;
#define VR_CHECK_INPUT_RESULT(f)\
if ( f != vr::VRInputError_None ) {\
@ -556,7 +557,7 @@ pod::Matrix4t<> ext::openvr::hmdProjectionMatrix( vr::Hmd_Eye eye, float zNear,
frustum.bottom = abs( frustum.bottom );
} else {
}
std::cout << frustum.left << "\t" << frustum.right << "\t" << frustum.top << "\t" << frustum.bottom << std::endl;
// std::cout << frustum.left << "\t" << frustum.right << "\t" << frustum.top << "\t" << frustum.bottom << std::endl;
/*
float fov = this->m_settings.perspective.fov * (3.14159265358f / 180.0f);

View File

@ -8,6 +8,8 @@
#include <set>
#include <map>
#include <uf/utils/serialize/serializer.h>
namespace {
void VRExtensions( std::vector<std::string>& requested ) {
if ( !vr::VRCompositor() ) return;
@ -18,34 +20,142 @@ namespace {
vr::VRCompositor()->GetVulkanInstanceExtensionsRequired( pExtensionStr, nBufferSize );
std::vector<std::string> extensions = uf::string::split( pExtensionStr, " " );
requested.insert( requested.end(), extensions.begin(), extensions.end() );
/*
// Allocate enough ExtensionProperties to support all extensions being enabled
uint32_t extensionsCount = 0;
uint32_t enabledExtensionsCount = 0;
VK_CHECK_RESULT(vkEnumerateInstanceExtensionProperties( NULL, &extensionsCount, NULL ));
std::vector<VkExtensionProperties> extensionProperties(extensionsCount);
VK_CHECK_RESULT( vkEnumerateInstanceExtensionProperties( NULL, &extensionsCount, &extensionProperties[0] ) );
for ( size_t i = 0; i < extensions.size(); ++i ) {
bool found = false;
uint32_t index = 0;
for ( index = 0; index < extensionsCount; index++ ) {
if ( strcmp( extensions[i].c_str(), extensionProperties[index].extensionName ) == 0 ) {
for ( auto alreadyAdded : supportedExtensions ) {
if ( strcmp( extensions[i].c_str(), alreadyAdded ) == 0 ) {
found = true;
break;
}
}
if ( found ) break;
found = true;
supportedExtensions.push_back(extensionProperties[index].extensionName);
break;
}
}
if ( !found ) std::cout << "Vulkan missing requested extension " << extensions[index] << std::endl;
}
void enableRequestedDeviceFeatures( ext::vulkan::Device& device ) {
uf::Serializer json;
#define CHECK_FEATURE( NAME )\
if ( feature == #NAME ) {\
if ( device.features.NAME == VK_TRUE ) {\
device.enabledFeatures.NAME = true;\
if ( ext::vulkan::validation ) std::cout << "Enabled feature: " << feature << std::endl;\
} else if ( ext::vulkan::validation ) std::cout << "Failed to enable feature: " << feature << std::endl;\
}
*/
for ( auto& feature : ext::vulkan::requestedDeviceFeatures ) {
CHECK_FEATURE(robustBufferAccess);
CHECK_FEATURE(fullDrawIndexUint32);
CHECK_FEATURE(imageCubeArray);
CHECK_FEATURE(independentBlend);
CHECK_FEATURE(geometryShader);
CHECK_FEATURE(tessellationShader);
CHECK_FEATURE(sampleRateShading);
CHECK_FEATURE(dualSrcBlend);
CHECK_FEATURE(logicOp);
CHECK_FEATURE(multiDrawIndirect);
CHECK_FEATURE(drawIndirectFirstInstance);
CHECK_FEATURE(depthClamp);
CHECK_FEATURE(depthBiasClamp);
CHECK_FEATURE(fillModeNonSolid);
CHECK_FEATURE(depthBounds);
CHECK_FEATURE(wideLines);
CHECK_FEATURE(largePoints);
CHECK_FEATURE(alphaToOne);
CHECK_FEATURE(multiViewport);
CHECK_FEATURE(samplerAnisotropy);
CHECK_FEATURE(textureCompressionETC2);
CHECK_FEATURE(textureCompressionASTC_LDR);
CHECK_FEATURE(textureCompressionBC);
CHECK_FEATURE(occlusionQueryPrecise);
CHECK_FEATURE(pipelineStatisticsQuery);
CHECK_FEATURE(vertexPipelineStoresAndAtomics);
CHECK_FEATURE(fragmentStoresAndAtomics);
CHECK_FEATURE(shaderTessellationAndGeometryPointSize);
CHECK_FEATURE(shaderImageGatherExtended);
CHECK_FEATURE(shaderStorageImageExtendedFormats);
CHECK_FEATURE(shaderStorageImageMultisample);
CHECK_FEATURE(shaderStorageImageReadWithoutFormat);
CHECK_FEATURE(shaderStorageImageWriteWithoutFormat);
CHECK_FEATURE(shaderUniformBufferArrayDynamicIndexing);
CHECK_FEATURE(shaderSampledImageArrayDynamicIndexing);
CHECK_FEATURE(shaderStorageBufferArrayDynamicIndexing);
CHECK_FEATURE(shaderStorageImageArrayDynamicIndexing);
CHECK_FEATURE(shaderClipDistance);
CHECK_FEATURE(shaderCullDistance);
CHECK_FEATURE(shaderFloat64);
CHECK_FEATURE(shaderInt64);
CHECK_FEATURE(shaderInt16);
CHECK_FEATURE(shaderResourceResidency);
CHECK_FEATURE(shaderResourceMinLod);
CHECK_FEATURE(sparseBinding);
CHECK_FEATURE(sparseResidencyBuffer);
CHECK_FEATURE(sparseResidencyImage2D);
CHECK_FEATURE(sparseResidencyImage3D);
CHECK_FEATURE(sparseResidency2Samples);
CHECK_FEATURE(sparseResidency4Samples);
CHECK_FEATURE(sparseResidency8Samples);
CHECK_FEATURE(sparseResidency16Samples);
CHECK_FEATURE(sparseResidencyAliased);
CHECK_FEATURE(variableMultisampleRate);
CHECK_FEATURE(inheritedQueries);
}
#undef CHECK_FEATURE
}
uf::Serializer retrieveDeviceFeatures( ext::vulkan::Device& device ) {
uf::Serializer json;
#define CHECK_FEATURE( NAME )\
json[#NAME]["supported"] = device.features.NAME;\
json[#NAME]["enabled"] = device.enabledFeatures.NAME;
CHECK_FEATURE(robustBufferAccess);
CHECK_FEATURE(fullDrawIndexUint32);
CHECK_FEATURE(imageCubeArray);
CHECK_FEATURE(independentBlend);
CHECK_FEATURE(geometryShader);
CHECK_FEATURE(tessellationShader);
CHECK_FEATURE(sampleRateShading);
CHECK_FEATURE(dualSrcBlend);
CHECK_FEATURE(logicOp);
CHECK_FEATURE(multiDrawIndirect);
CHECK_FEATURE(drawIndirectFirstInstance);
CHECK_FEATURE(depthClamp);
CHECK_FEATURE(depthBiasClamp);
CHECK_FEATURE(fillModeNonSolid);
CHECK_FEATURE(depthBounds);
CHECK_FEATURE(wideLines);
CHECK_FEATURE(largePoints);
CHECK_FEATURE(alphaToOne);
CHECK_FEATURE(multiViewport);
CHECK_FEATURE(samplerAnisotropy);
CHECK_FEATURE(textureCompressionETC2);
CHECK_FEATURE(textureCompressionASTC_LDR);
CHECK_FEATURE(textureCompressionBC);
CHECK_FEATURE(occlusionQueryPrecise);
CHECK_FEATURE(pipelineStatisticsQuery);
CHECK_FEATURE(vertexPipelineStoresAndAtomics);
CHECK_FEATURE(fragmentStoresAndAtomics);
CHECK_FEATURE(shaderTessellationAndGeometryPointSize);
CHECK_FEATURE(shaderImageGatherExtended);
CHECK_FEATURE(shaderStorageImageExtendedFormats);
CHECK_FEATURE(shaderStorageImageMultisample);
CHECK_FEATURE(shaderStorageImageReadWithoutFormat);
CHECK_FEATURE(shaderStorageImageWriteWithoutFormat);
CHECK_FEATURE(shaderUniformBufferArrayDynamicIndexing);
CHECK_FEATURE(shaderSampledImageArrayDynamicIndexing);
CHECK_FEATURE(shaderStorageBufferArrayDynamicIndexing);
CHECK_FEATURE(shaderStorageImageArrayDynamicIndexing);
CHECK_FEATURE(shaderClipDistance);
CHECK_FEATURE(shaderCullDistance);
CHECK_FEATURE(shaderFloat64);
CHECK_FEATURE(shaderInt64);
CHECK_FEATURE(shaderInt16);
CHECK_FEATURE(shaderResourceResidency);
CHECK_FEATURE(shaderResourceMinLod);
CHECK_FEATURE(sparseBinding);
CHECK_FEATURE(sparseResidencyBuffer);
CHECK_FEATURE(sparseResidencyImage2D);
CHECK_FEATURE(sparseResidencyImage3D);
CHECK_FEATURE(sparseResidency2Samples);
CHECK_FEATURE(sparseResidency4Samples);
CHECK_FEATURE(sparseResidency8Samples);
CHECK_FEATURE(sparseResidency16Samples);
CHECK_FEATURE(sparseResidencyAliased);
CHECK_FEATURE(variableMultisampleRate);
CHECK_FEATURE(inheritedQueries);
#undef CHECK_FEATURE
return json;
}
}
@ -512,6 +622,8 @@ void ext::vulkan::Device::initialize() {
deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
enableRequestedDeviceFeatures( *this );
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
@ -525,6 +637,9 @@ void ext::vulkan::Device::initialize() {
if ( vkCreateDevice( this->physicalDevice, &deviceCreateInfo, nullptr, &this->logicalDevice) != VK_SUCCESS )
throw std::runtime_error("failed to create logical device!");
if ( ext::vulkan::validation )
std::cout << retrieveDeviceFeatures( *this ) << std::endl;
}
// Create command pool
{

View File

@ -58,24 +58,23 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st
spirv_cross::Compiler comp( (uint32_t*) &spirv[0], spirv.size() / 4 );
spirv_cross::ShaderResources res = comp.get_shader_resources();
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType type ) {
// comp.get_decoration(resource.id, spv::DecorationDescriptorSet);
switch ( type ) {
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
} break;
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType ) {
switch ( descriptorType ) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
const auto& type = comp.get_type(resource.base_type_id);
size_t size = comp.get_declared_struct_size(type);
const auto& base_type = comp.get_type(resource.base_type_id);
auto& uniform = uniforms.emplace_back();
uniform.create( size );
uniform.create( comp.get_declared_struct_size(base_type) );
} break;
}
descriptorSetLayoutBindings.push_back(ext::vulkan::initializers::descriptorSetLayoutBinding( type, stage, comp.get_decoration(resource.id, spv::DecorationBinding) ) );
const auto& type = comp.get_type(resource.type_id);
size_t size = 1;
if ( !type.array.empty() ) size = type.array[0];
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), size ) );
};
// std::cout << "Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding) << std::endl;\
// std::cout << "Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding) << std::endl;
#define LOOP_RESOURCES( key, type ) for ( const auto& resource : res.key ) {\
parseResource( resource, type );\
}
@ -86,8 +85,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER );
LOOP_RESOURCES( subpass_inputs, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT );
LOOP_RESOURCES( storage_buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER );
#undef LOOP_RESOURCES
#undef LOOP_RESOURCES
for ( const auto& resource : res.push_constant_buffers ) {
auto& pushConstant = pushConstants.emplace_back();
@ -196,6 +194,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
this->device = graphic.device;
Device& device = *graphic.device;
// std::cout << &graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size() << std::endl;
assert( graphic.material.shaders.size() > 0 );
RenderMode& renderMode = ext::vulkan::getRenderMode(graphic.descriptor.renderMode, true);
@ -274,6 +273,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
std::vector<VkPipelineColorBlendAttachmentState> blendAttachmentStates;
auto& subpass = renderTarget.passes[graphic.descriptor.subpass];
/*
for ( auto& color : subpass.colors ) {
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
@ -285,16 +285,19 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
/*
if ( !blendAttachmentStates.empty() ) {
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
}
*/
blendAttachmentStates.push_back(blendAttachmentState);
}
*/
for ( auto& color : subpass.colors ) {
blendAttachmentStates.push_back(renderTarget.attachments[color.attachment].blendState);
}
// require blending if independentBlend is not an enabled feature
if ( !device.enabledFeatures.independentBlend ) {
for ( size_t i = 1; i < blendAttachmentStates.size(); ++i ) {
blendAttachmentStates[i] = blendAttachmentStates[0];
}
}
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
blendAttachmentStates.size(),
blendAttachmentStates.data()
@ -398,9 +401,13 @@ void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuf
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
}
void ext::vulkan::Pipeline::update( Graphic& graphic ) {
// generate fallback empty texture
auto& emptyTexture = Texture2D::empty;
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
std::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
std::vector<VkDescriptorImageInfo> inputDescriptors;
std::vector<VkDescriptorImageInfo> imageInfos;
for ( auto& shader : graphic.material.shaders ) {
descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() );
@ -414,6 +421,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
inputDescriptors.push_back(ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[input.attachment].view,
input.layout
// input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout
));
}
{
@ -424,42 +432,88 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
auto attachments = inputDescriptors.begin();
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
VkDescriptorBufferInfo* bufferInfo = NULL;
if ( layout.descriptorCount > 1 ) {
switch ( layout.descriptorType ) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
size_t imageInfosStart = imageInfos.size();
// assume we have a texture, and fill it in the slots as defaults
for ( size_t i = 0; i < layout.descriptorCount; ++i ) {
VkDescriptorImageInfo d = emptyTexture.descriptor;
if ( textures != graphic.material.textures.end() ) {
d = (textures++)->descriptor;
if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !d.sampler )
d.sampler = emptyTexture.sampler.sampler;
// if ( d.imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL )
// d.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
imageInfos.push_back( d );
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&imageInfos[imageInfosStart],
imageInfos.size() - imageInfosStart
));
} break;
}
continue;
}
VkDescriptorImageInfo* imageInfo = NULL;
switch ( layout.descriptorType ) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
if ( textures == graphic.material.textures.end() ) {
imageInfo = &emptyTexture.descriptor;
break;
}
imageInfo = &((textures++)->descriptor);
} break;
case VK_DESCRIPTOR_TYPE_SAMPLER: {
imageInfo = &((samplers++)->descriptor);
if ( samplers == graphic.material.samplers.end() ) {
std::cout << "samplers == graphic.material.samplers.end()" << std::endl;
break;
}
imageInfo = &((samplers++)->descriptor.info);
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
bufferInfo = &((buffers++)->descriptor);
if ( buffers == shader.buffers.end() ) {
std::cout << "buffers == shader.buffers.end()" << std::endl;
break;
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&((buffers++)->descriptor)
));
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
if ( attachments == inputDescriptors.end() ) {
std::cout << "attachments == inputDescriptors.end()" << std::endl;
break;
}
imageInfo = &(*(attachments++));
} break;
}
if ( !bufferInfo && !imageInfo ) continue;
if ( bufferInfo )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
bufferInfo
));
else if ( imageInfo )
if ( imageInfo ) {
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
imageInfo
));
}
}
}
}
vkUpdateDescriptorSets(
*device,
writeDescriptorSets.size(),

View File

@ -91,6 +91,10 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
// this->width = 0; //ext::vulkan::width;
// this->height = 0; //ext::vulkan::height;
{
if ( this->width > 0 ) renderTarget.width = this->width;
if ( this->height > 0 ) renderTarget.height = this->height;
}
// Create command buffers
{

View File

@ -21,13 +21,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
renderTarget.device = &device;
// attach targets
struct {
size_t albedo, position, normals, depth, output;
size_t albedo, normals, position, depth, output, ping, pong;
} attachments;
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // position
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // normals
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ); // depth
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // normals
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // position
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true ); // depth
// attachments.ping = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
// attachments.pong = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
// Attach swapchain's image as output
{
attachments.output = renderTarget.attachments.size();
@ -36,6 +38,23 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
swapchainAttachment.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchainAttachment.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
swapchainAttachment.aliased = true;
{
VkBool32 blendEnabled = VK_TRUE;
VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
writeMask,
blendEnabled
);
if ( blendEnabled == VK_TRUE ) {
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
}
swapchainAttachment.blendState = blendAttachmentState;
}
renderTarget.attachments.push_back(swapchainAttachment);
}
@ -43,7 +62,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.position, attachments.normals },
{ attachments.albedo, attachments.normals, attachments.position },
{},
attachments.depth
);
@ -53,7 +72,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
renderTarget.addPass(
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
{ attachments.output },
{ attachments.albedo, attachments.position, attachments.normals, attachments.depth },
{ attachments.albedo, attachments.normals, attachments.position/*, attachments.depth*/ },
attachments.depth
);
}
@ -63,10 +82,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
uf::BaseMesh<pod::Vertex_2F2F, uint16_t> mesh;
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 1.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {1.0f, 1.0f}, {1.0f, 0.0f}, }
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
};
mesh.indices = {
0, 1, 2, 0, 2, 3
@ -169,6 +188,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
@ -218,11 +238,12 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = attachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}

View File

@ -17,16 +17,16 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
{
renderTarget.device = &device;
struct {
size_t albedo, position, normals, depth, output;
size_t albedo, normals, position, depth, output;
} attachments;
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // position
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // normals
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ); // depth
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // normals
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // position
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true ); // depth
// Attach swapchain's image as output
if ( !false ) {
attachments.output = renderTarget.attach( device.formats.color, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ); // depth
attachments.output = renderTarget.attach( device.formats.color, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, true ); // output
} else {
attachments.output = renderTarget.attachments.size();
RenderTarget::Attachment swapchainAttachment;
@ -34,13 +34,31 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
swapchainAttachment.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchainAttachment.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
swapchainAttachment.aliased = true;
{
VkBool32 blendEnabled = VK_TRUE;
VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
writeMask,
blendEnabled
);
if ( blendEnabled == VK_TRUE ) {
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
}
swapchainAttachment.blendState = blendAttachmentState;
}
renderTarget.attachments.push_back(swapchainAttachment);
}
// First pass: write to target
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.position, attachments.normals },
{ attachments.albedo, attachments.normals, attachments.position },
{},
attachments.depth
);
@ -50,7 +68,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
renderTarget.addPass(
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
{ attachments.output },
{ attachments.albedo, attachments.position, attachments.normals },
{ attachments.albedo, attachments.normals, attachments.position/*, attachments.depth*/ },
attachments.depth
);
}

View File

@ -11,11 +11,6 @@
#include <uf/utils/math/transform.h>
#include <uf/ext/openvr/openvr.h>
namespace {
// 0 left 1 right
uint8_t DOMINANT_EYE = 0;
}
// ext::vulkan::StereoscopicDeferredRenderMode::StereoscopicDeferredRenderMode() : renderTargets({ renderTarget }), blitters({ blitter }) {
ext::vulkan::StereoscopicDeferredRenderMode::StereoscopicDeferredRenderMode() : renderTargets({ renderTarget }) {
}
@ -58,16 +53,18 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
renderTarget.height = this->height;
// attach targets
struct {
size_t albedo, position, normals, depth, output;
size_t albedo, normals, position, depth, output;
} attachments;
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // position
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // normals
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ); // depth
attachments.output = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
// Attach swapchain's image as output
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // normals
attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // position
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false ); // depth
attachments.output = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo
// attachments.ping = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
// attachments.pong = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo
/*
// Attach swapchain's image as output
if ( !true ) {
attachments.swapchain = renderTarget.attachments.size();
RenderTarget::Attachment swapchainAttachment;
@ -81,8 +78,8 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
// First pass: fill the G-Buffer
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.position, attachments.normals },
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.normals, attachments.position },
{},
attachments.depth
);
@ -90,9 +87,9 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
// Second pass: write to output
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
{ attachments.output },
{ attachments.albedo, attachments.position, attachments.normals },
{ attachments.albedo, attachments.normals, attachments.position/*, attachments.depth*/ },
attachments.depth
);
}
@ -100,10 +97,10 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
{
uf::BaseMesh<pod::Vertex_2F2F, uint16_t> mesh;
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 1.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {1.0f, 1.0f}, {1.0f, 0.0f}, }
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
};
mesh.indices = {
0, 1, 2, 0, 2, 3
@ -230,13 +227,17 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
for ( auto layer : layers ) {
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
imageMemoryBarrier.image = renderTarget.attachments[0].image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = renderTarget.attachments[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
renderTarget.attachments[0].layout = imageMemoryBarrier.newLayout;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = attachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
@ -258,7 +259,9 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
}
}
vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE);
blitter.record(commands[i]);
{
blitter.record(commands[i]);
}
// render gui layer
{
for ( auto _ : layers ) {
@ -269,149 +272,117 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
blitter.record(commands[i]);
}
}
/*
vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE);
if ( ext::openvr::renderPass == DOMINANT_EYE ) {
viewport.width = (float) ::ext::vulkan::width;
viewport.height = (float) ::ext::vulkan::height;
scissor.extent.width = ::ext::vulkan::width;
scissor.extent.height = ::ext::vulkan::height;
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
this->blitter.createCommandBuffer(commands[i]);
// render gui layer
{
for ( auto layer : layers ) {
if ( layer->getName() == "Gui" ) {
RenderTargetRenderMode* guiLayer = (RenderTargetRenderMode*) layer;
if ( guiLayer->blitter.subpass == 2 ) guiLayer->blitter.createCommandBuffer(commands[i]);
}
}
}
}
*/
vkCmdEndRenderPass(commands[i]);
for ( auto layer : layers ) {
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
imageMemoryBarrier.image = renderTarget.attachments[0].image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = renderTarget.attachments[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
renderTarget.attachments[0].layout = imageMemoryBarrier.newLayout;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = attachment.layout;
imageMemoryBarrier.newLayout = attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
}
}
}
// Blit eye to swapchain
{
// if ( false ) {
auto& swapchainRender = ext::vulkan::getRenderMode("Swapchain");
{
auto& renderTarget = swapchainRender.renderTarget;
float width = renderTarget.width;
float height = renderTarget.height;
std::vector<VkClearValue> clearValues; clearValues.resize(2);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(commands[i]);
}
{
auto& renderTarget = DOMINANT_EYE == 0 ? renderTargets.left : renderTargets.right;
VkImageBlit imageBlitRegion{};
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.srcSubresource.layerCount = 1;
imageBlitRegion.srcOffsets[1] = { width, height, 1 };
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.dstSubresource.layerCount = 1;
imageBlitRegion.dstOffsets[1] = {
swapchainRender.width > 0 ? swapchainRender.width : ext::vulkan::width,
swapchainRender.height > 0 ? swapchainRender.height : ext::vulkan::height,
1
};
auto& outputAttachment = renderTarget.attachments[renderTarget.attachments.size()-1];
// Transition to KHR
// Blit eye to swapchain
if ( ext::openvr::dominantEye == ext::openvr::renderPass ) {
// if ( false ) {
// transition swapchain to proper layout
auto& swapchainRender = ext::vulkan::getRenderMode("Swapchain");
{
imageMemoryBarrier.image = outputAttachment.image;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.oldLayout = outputAttachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
outputAttachment.layout = imageMemoryBarrier.newLayout;
}
{
imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.oldLayout = swapchainRender.renderTarget.attachments[i].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
swapchainRender.renderTarget.attachments[i].layout = imageMemoryBarrier.newLayout;
auto& renderTarget = swapchainRender.renderTarget;
float width = renderTarget.width;
float height = renderTarget.height;
std::vector<VkClearValue> clearValues; clearValues.resize(2);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(commands[i]);
}
vkCmdBlitImage(
commands[i],
outputAttachment.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
swapchainRender.renderTarget.attachments[i].image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageBlitRegion,
VK_FILTER_LINEAR
);
{
VkImageBlit imageBlitRegion{};
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.srcSubresource.layerCount = 1;
imageBlitRegion.srcOffsets[1] = { width, height, 1 };
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.dstSubresource.layerCount = 1;
imageBlitRegion.dstOffsets[1] = {
swapchainRender.width > 0 ? swapchainRender.width : ext::vulkan::width,
swapchainRender.height > 0 ? swapchainRender.height : ext::vulkan::height,
1
};
{
imageMemoryBarrier.image = outputAttachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = outputAttachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
outputAttachment.layout = imageMemoryBarrier.newLayout;
}
{
imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = swapchainRender.renderTarget.attachments[i].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
swapchainRender.renderTarget.attachments[i].layout = imageMemoryBarrier.newLayout;
auto& outputAttachment = renderTarget.attachments[renderTarget.attachments.size()-1];
// Transition to KHR
{
imageMemoryBarrier.image = outputAttachment.image;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.oldLayout = outputAttachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
outputAttachment.layout = imageMemoryBarrier.newLayout;
}
{
imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.oldLayout = swapchainRender.renderTarget.attachments[i].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
swapchainRender.renderTarget.attachments[i].layout = imageMemoryBarrier.newLayout;
}
vkCmdBlitImage(
commands[i],
outputAttachment.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
swapchainRender.renderTarget.attachments[i].image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageBlitRegion,
VK_FILTER_LINEAR
);
{
imageMemoryBarrier.image = outputAttachment.image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = outputAttachment.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
outputAttachment.layout = imageMemoryBarrier.newLayout;
}
{
imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = swapchainRender.renderTarget.attachments[i].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
swapchainRender.renderTarget.attachments[i].layout = imageMemoryBarrier.newLayout;
}
}
}
}

View File

@ -13,10 +13,11 @@ void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFla
pass.access = access;
for ( auto& i : colors ) pass.colors.push_back( { (uint32_t) i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } );
for ( auto& i : inputs ) pass.inputs.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } );
// for ( auto& i : inputs ) pass.inputs.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } );
if ( depth < attachments.size() ) pass.depth = { (uint32_t) depth, attachments[depth].layout };
passes.push_back(pass);
}
size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usage, VkImageLayout layout, Attachment* attachment ) {
size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usage, VkImageLayout layout, bool blend, Attachment* attachment ) {
uint32_t width = this->width > 0 ? this->width : ext::vulkan::width;
uint32_t height = this->height > 0 ? this->height : ext::vulkan::height;
@ -98,6 +99,30 @@ size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usa
VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->view));
{
VkBool32 blendEnabled = VK_FALSE;
VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;
if ( blend ) {
blendEnabled = VK_TRUE;
writeMask |= VK_COLOR_COMPONENT_A_BIT;
}
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
writeMask,
blendEnabled
);
if ( blendEnabled == VK_TRUE ) {
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
}
attachment->blendState = blendAttachmentState;
}
return attachments.size()-1;
}
void ext::vulkan::RenderTarget::initialize( Device& device ) {
@ -112,7 +137,8 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
if ( initialized ) {
for ( auto& attachment: this->attachments ) {
if ( attachment.aliased ) continue;
attach( attachment.format, attachment.usage, attachment.layout, &attachment );
bool blend = attachment.blendState.blendEnable == VK_TRUE;
attach( attachment.format, attachment.usage, attachment.layout, blend, &attachment );
}
}
// ensure attachments are already created
@ -131,7 +157,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
description.finalLayout = attachment.layout;
description.finalLayout = attachment.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : attachment.layout;
description.flags = 0;
attachments.push_back(description);
@ -191,6 +217,39 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies.push_back(dependency);
}
// depth dependency
{
VkSubpassDependency dependency;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependency.dstSubpass = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies.push_back(dependency);
}
{
VkSubpassDependency dependency;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependency.srcSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dstSubpass = i == 1 ? VK_SUBPASS_EXTERNAL : 1;
dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependency.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies.push_back(dependency);
}
/*
for ( auto& dependency : dependencies ) {
std::cout << "Pass: " << dependency.srcSubpass << " -> " << dependency.dstSubpass << std::endl;

View File

@ -3,29 +3,30 @@
#include <uf/utils/image/image.h>
#include <uf/ext/vulkan/vulkan.h>
void ext::vulkan::Sampler::initialize( Device& device, VkFilter filter ) {
ext::vulkan::Texture2D ext::vulkan::Texture2D::empty;
void ext::vulkan::Sampler::initialize( Device& device ) {
this->device = &device;
this->filter = filter;
{
VkSamplerCreateInfo samplerCreateInfo = {};
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCreateInfo.magFilter = filter;
samplerCreateInfo.minFilter = filter;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.mipLodBias = 0.0f;
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = 0.0f;
samplerCreateInfo.maxAnisotropy = 1.0f;
samplerCreateInfo.minFilter = descriptor.filter.min;
samplerCreateInfo.magFilter = descriptor.filter.mag;
samplerCreateInfo.addressModeU = descriptor.addressMode.u;
samplerCreateInfo.addressModeV = descriptor.addressMode.v;
samplerCreateInfo.addressModeW = descriptor.addressMode.w;
samplerCreateInfo.mipmapMode = descriptor.mip.mode;
samplerCreateInfo.mipLodBias = descriptor.mip.lodBias;
samplerCreateInfo.compareOp = descriptor.compareOp;
samplerCreateInfo.minLod = descriptor.lod.min;
samplerCreateInfo.maxLod = descriptor.lod.max;
samplerCreateInfo.maxAnisotropy = descriptor.maxAnisotropy;
VK_CHECK_RESULT(vkCreateSampler(device.logicalDevice, &samplerCreateInfo, nullptr, &sampler));
}
{
descriptor.sampler = sampler;
descriptor.info.sampler = sampler;
}
}
void ext::vulkan::Sampler::destroy() {
@ -274,7 +275,6 @@ void ext::vulkan::Texture2D::loadFromFile(
image.getDimensions()[1],
device,
copyQueue,
sampler.filter,
imageUsageFlags,
imageLayout
);
@ -347,7 +347,6 @@ void ext::vulkan::Texture2D::loadFromImage(
image.getDimensions()[1],
device,
copyQueue,
sampler.filter,
imageUsageFlags,
imageLayout
);
@ -360,7 +359,6 @@ void ext::vulkan::Texture2D::fromBuffers(
uint32_t texHeight,
Device& device,
VkQueue copyQueue,
VkFilter filter,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout
) {
@ -466,7 +464,7 @@ void ext::vulkan::Texture2D::fromBuffers(
staging.destroy();
// Create sampler
sampler.initialize( device, sampler.filter );
sampler.initialize( device );
// Create image view
VkImageViewCreateInfo viewCreateInfo = {};
@ -535,7 +533,7 @@ void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uin
device.flushCommandBuffer(layoutCmd, copyQueue, true);
// Create sampler
sampler.initialize( device, sampler.filter );
sampler.initialize( device );
// Create image view
VkImageViewCreateInfo viewCreateInfo = ext::vulkan::initializers::imageViewCreateInfo();
@ -556,7 +554,7 @@ void ext::vulkan::Texture2D::aliasAttachment( const RenderTarget::Attachment& at
deviceMemory = attachment.mem;
// Create sampler
if ( createSampler ) sampler.initialize( ext::vulkan::device, sampler.filter );
if ( createSampler ) sampler.initialize( ext::vulkan::device );
this->updateDescriptors();
}

View File

@ -12,6 +12,8 @@ uint32_t ext::vulkan::width = 1280;
uint32_t ext::vulkan::height = 720;
bool ext::vulkan::validation = true;
std::vector<std::string> ext::vulkan::validationFilters;
std::vector<std::string> ext::vulkan::requestedDeviceFeatures;
ext::vulkan::Device ext::vulkan::device;
ext::vulkan::Allocator ext::vulkan::allocator;
ext::vulkan::Swapchain ext::vulkan::swapchain;
@ -46,7 +48,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL ext::vulkan::debugCallback(
void* pUserData
) {
if ( messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) return VK_FALSE;
uf::iostream << "[Validation Layer] " << pCallbackData->pMessage << "\n";
std::string message = pCallbackData->pMessage;
for ( auto& filter : ext::vulkan::validationFilters ) {
if ( message.find(filter) != std::string::npos ) return VK_FALSE;
}
uf::iostream << "[Validation Layer] " << message << "\n";
return VK_FALSE;
}
@ -220,6 +226,15 @@ void ext::vulkan::initialize( uint8_t stage ) {
allocatorInfo.device = device.logicalDevice;
vmaCreateAllocator(&allocatorInfo, &allocator);
}
{
std::vector<uint8_t> pixels = {
255, 0, 255, 255, 0, 0, 0, 255,
0, 0, 0, 255, 255, 0, 255, 255,
};
Texture2D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
Texture2D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), VK_FORMAT_R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, ext::vulkan::device.graphicsQueue, VK_IMAGE_USAGE_SAMPLED_BIT );
}
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->initialize(device);
@ -234,14 +249,7 @@ void ext::vulkan::initialize( uint8_t stage ) {
if ( !entity->hasComponent<uf::Graphic>() ) return;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
if ( graphic.initialized ) return;
/*
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !mesh.generated ) return;
if ( !graphic.process ) return;
if ( graphic.initialized ) return;
*/
graphic.initializePipeline();
ext::vulkan::rebuild = true;
};
@ -269,12 +277,7 @@ void ext::vulkan::tick() {
if ( !entity->hasComponent<uf::Graphic>() ) return;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
if ( graphic.initialized ) return;
/*
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !mesh.generated ) return;
*/
if ( !graphic.process ) return;
if ( graphic.initialized ) return;
graphic.initializePipeline();
@ -320,6 +323,8 @@ void ext::vulkan::destroy() {
ext::vulkan::mutex.lock();
vkDeviceWaitIdle( device );
Texture2D::empty.destroy();
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() ) return;
uf::Graphic& graphic = entity->getComponent<uf::Graphic>();

View File

@ -18,6 +18,7 @@ uf::Camera::Camera() :
this->m_settings.offset = {0, 0, 0};
this->m_settings.mode = 1;
this->setModel(uf::matrix::identity());
this->setView(uf::matrix::identity());
this->setProjection(uf::matrix::identity());
@ -61,6 +62,7 @@ const pod::Transform<>& uf::Camera::getTransform() const {
}
pod::Matrix4& uf::Camera::getView( size_t eye ) {
// if ( !this->m_settings.stereoscopic ) eye = 0;
switch ( eye ) {
case 0:
return this->m_matrices.left.view;
@ -80,6 +82,7 @@ pod::Matrix4& uf::Camera::getView( size_t eye ) {
*/
}
pod::Matrix4& uf::Camera::getProjection( size_t eye ) {
// if ( !this->m_settings.stereoscopic ) eye = 0;
switch ( eye ) {
case 0:
return this->m_matrices.left.projection;
@ -103,6 +106,7 @@ pod::Matrix4& uf::Camera::getModel() {
}
const pod::Matrix4& uf::Camera::getView( size_t eye ) const {
// if ( !this->m_settings.stereoscopic ) eye = 0;
switch ( eye ) {
case 0:
return this->m_matrices.left.view;
@ -122,6 +126,7 @@ const pod::Matrix4& uf::Camera::getView( size_t eye ) const {
*/
}
const pod::Matrix4& uf::Camera::getProjection( size_t eye ) const {
// if ( !this->m_settings.stereoscopic ) eye = 0;
switch ( eye ) {
case 0:
return this->m_matrices.left.projection;
@ -177,6 +182,7 @@ void uf::Camera::setTransform( const pod::Transform<>& transform ) {
this->update(true);
}
void uf::Camera::setView( const pod::Matrix4& mat, size_t i ) {
// if ( !this->m_settings.stereoscopic ) i = 2;
switch ( i ) {
case 0:
this->m_matrices.left.view = mat;
@ -191,6 +197,7 @@ void uf::Camera::setView( const pod::Matrix4& mat, size_t i ) {
}
}
void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) {
// if ( !this->m_settings.stereoscopic ) i = 2;
switch ( i ) {
case 0:
this->m_matrices.left.projection = mat;
@ -235,7 +242,9 @@ void uf::Camera::ortho( const pod::Vector2& lr, const pod::Vector2& bt, const po
this->update(true);
}
void uf::Camera::setStereoscopic(bool settings) {
this->m_settings.stereoscopic = settings;
}
void uf::Camera::update(bool override) {
if ( !override && !this->modified() ) return;
this->updateView();
@ -243,7 +252,7 @@ void uf::Camera::update(bool override) {
this->m_modified = true;
}
void uf::Camera::updateView() {
if ( ext::openvr::context ) {
if ( this->m_settings.stereoscopic && ext::openvr::context ) {
pod::Transform<>& transform = this->getTransform();
pod::Vector3t<> position = transform.position;
if ( transform.reference ) position += transform.reference->position;
@ -251,9 +260,10 @@ void uf::Camera::updateView() {
pod::Transform<> flatten = uf::transform::flatten( transform );
pod::Matrix4t<> translation = uf::matrix::translate( uf::matrix::identity(), position );
pod::Matrix4t<> rotation = uf::quaternion::matrix( flatten.orientation );
pod::Matrix4t<> rotation = uf::quaternion::matrix( flatten.orientation * pod::Vector4f{1,1,1,-1} );
pod::Matrix4t<> view = uf::matrix::inverse( translation * rotation );
transform.orientation = ext::openvr::hmdQuaternion();
this->setView( ext::openvr::hmdViewMatrix(vr::Eye_Left, view ), 0 );
this->setView( ext::openvr::hmdViewMatrix(vr::Eye_Right, view ), 1 );
@ -301,8 +311,11 @@ void uf::Camera::updateView() {
pod::Matrix4t<> translation = uf::matrix::translate( uf::matrix::identity(), position * -1 );
pod::Transform<> flatten = uf::transform::flatten(transform, true);
pod::Matrix4t<> rotation = uf::quaternion::matrix( flatten.orientation );
pod::Matrix4t<> scale = uf::matrix::inverse( uf::matrix::scale( uf::matrix::identity(), transform.scale ) );
this->setView(rotation * translation);
// std::cout << transform.scale.x << ", " << transform.scale.y << ", " << transform.scale.z << std::endl;
this->setView(rotation * translation * scale);
/*
pod::Transform<> transform = this->getTransform();
if ( transform.reference ) transform.position += transform.reference->position;
@ -316,7 +329,7 @@ void uf::Camera::updateView() {
}
}
void uf::Camera::updateProjection() {
if ( ext::openvr::context ) {
if ( this->m_settings.stereoscopic && ext::openvr::context ) {
// ::projection.left = ext::openvr::hmdProjectionMatrix( vr::Eye_Left, this->m_settings.perspective.bounds.x, this->m_settings.perspective.bounds.y );
// ::projection.right = ext::openvr::hmdProjectionMatrix( vr::Eye_Right, this->m_settings.perspective.bounds.x, this->m_settings.perspective.bounds.y );
this->setProjection( ext::openvr::hmdProjectionMatrix( vr::Eye_Left, this->m_settings.perspective.bounds.x, this->m_settings.perspective.bounds.y ), 0 );

View File

@ -4,6 +4,10 @@
#include <fstream> // std::fstream
#include <iostream> // std::fstream
#include <png/png.h> // libpng
#define STB_IMAGE_IMPLEMENTATION
#include <gltf/stb_image.h>
// C-tor
// Default
uf::Image::Image() :
@ -58,9 +62,6 @@ uf::Image::Image( const Image::container_t& copy, const Image::vec2_t& size ) :
}
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
std::string uf::Image::getFilename() const {
return this->m_filename;
}
@ -189,7 +190,7 @@ bool uf::Image::open( const std::string& filename ) {
}
return true;
}
void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels ) {
void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) {
this->m_dimensions = size;
this->m_bpp = bit_depth * channels;
this->m_channels = channels;
@ -199,6 +200,20 @@ void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod
this->m_pixels.resize( len );
//for ( size_t i = 0; i < len; ++i ) this->m_pixels[i] = pointer[i];
memcpy( &this->m_pixels[0], pointer, len );
if ( flip ) {
auto w = this->m_dimensions.x;
auto h = this->m_dimensions.y;
uint8_t* pixels = &this->m_pixels[0];
for (uint j = 0; j * 2 < h; ++j) {
uint x = j * w * this->m_bpp/8;
uint y = (h - 1 - j) * w * this->m_bpp/8;
for (uint i = w * this->m_bpp/8; i > 0; --i) {
std::swap( pixels[x], pixels[y] );
++x, ++y;
}
}
}
}
void uf::Image::loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) {
this->m_dimensions = size;
@ -206,10 +221,10 @@ void uf::Image::loadFromBuffer( const Image::container_t& container, const pod::
this->m_channels = channels;
this->m_pixels = container;
uint8_t* pixels = &this->m_pixels[0];
if ( flip ) {
auto w = this->m_dimensions.x;
auto h = this->m_dimensions.y;
uint8_t* pixels = &this->m_pixels[0];
for (uint j = 0; j * 2 < h; ++j) {
uint x = j * w * this->m_bpp/8;
uint y = (h - 1 - j) * w * this->m_bpp/8;

View File

@ -1,446 +1,62 @@
#include <uf/utils/math/collision.h>
#include <uf/utils/math/collision/gjk.h>
#include <uf/utils/math/collision/boundingbox.h>
#include <uf/utils/math/collision/sphere.h>
#include <uf/utils/math/collision/mesh.h>
#include <uf/utils/math/collision/modular.h>
#include <iostream>
/*
pod::Simplex::Simplex( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) {
this->set(b, c, d);
}
void pod::Simplex::add( const pod::Vector3& a ) {
this->d = this->c;
this->c = this->b;
this->b = a;
}
void pod::Simplex::set( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) {
this->b = b;
this->c = c;
this->d = d;
if ( b != pod::Vector3{} ) this->size++;
if ( c != pod::Vector3{} ) this->size++;
if ( d != pod::Vector3{} ) this->size++;
}
*/
uf::Collider::~Collider(){}
std::string UF_API uf::Collider::type() const { return ""; }
uf::Collider::Manifold UF_API uf::Collider::intersects( const uf::Collider& y ) const {
const uf::Collider& x = *this;
pod::Simplex simplex;
pod::Vector3 direction = pod::Vector3{ 1.0f, 0.0f, 0.0f };
uf::Collider::Manifold manifold(x, y);
double dot = -0.1;
uint iterations = 0;
uint iterations_cap = 25;
while ( iterations++ < iterations_cap ) {
direction = uf::vector::normalize(direction);
pod::Simplex::SupportPoint a;
a.a = x.support(direction);
a.b = y.support(-direction);
a.v = a.a - a.b;
if ( (dot = a.dot(direction)) < 0 ) {
return manifold;
}
if( simplex.size == 0 ) {
simplex.b = a;
direction = direction * -1;
simplex.size = 1;
continue;
}
if ( simplex.size == 1 ) {
direction = uf::vector::cross(a.cross(simplex.b), a.v);
simplex.c = simplex.b;
simplex.b = a;
simplex.size = 2;
continue;
}
if ( simplex.size == 2 ) {
pod::Vector3 ao = a * -1;
pod::Vector3 ab = simplex.b - a;
pod::Vector3 ac = simplex.c - a;
pod::Vector3 abc = uf::vector::cross(ab, ac);
pod::Vector3 abP = uf::vector::cross(ab, abc);
if ( uf::vector::dot(abP, ao) > 0 ) {
simplex.c = simplex.b;
simplex.b = a;
direction = uf::vector::cross(ab, ao);
continue;
}
pod::Vector3 acP = uf::vector::cross(abc, ac);
if ( uf::vector::dot(acP, ao) > 0 ) {
simplex.b = a;
direction = uf::vector::cross(ac, ao);
continue;
}
if ( uf::vector::dot(abc, ao) > 0 ) {
simplex.d = simplex.c;
simplex.c = simplex.b;
simplex.b = a;
direction = abc;
continue;
}
simplex.d = simplex.b;
simplex.b = a;
direction = abc * -1;
simplex.size = 3;
continue;
}
if ( simplex.size == 3 ) {
pod::Vector3 ao = a * -1;
pod::Vector3 ab = simplex.b - a;
pod::Vector3 ac = simplex.c - a;
pod::Vector3 abc = uf::vector::cross(ab, ac);
pod::Vector3 ad, acd, adb;
if ( uf::vector::dot(abc, ao) > 0 ) {
goto check_face;
}
ad = simplex.d - a;
acd = uf::vector::cross(ac, ad);
if ( uf::vector::dot(acd, ao) > 0 ) {
simplex.b = simplex.c;
simplex.c = simplex.d;
ab = ac;
ac = ad;
abc = acd;
goto check_face;
}
goto EPA;
check_face:
pod::Vector3 abP = uf::vector::cross(ab, abc);
if ( uf::vector::dot(abP, ao) > 0 ) {
simplex.c = simplex.b;
simplex.b = a;
direction = uf::vector::cross(uf::vector::cross(ab, ao), ab);
simplex.size = 2;
continue;
}
pod::Vector3 acP = uf::vector::cross(abc, ac);
if ( uf::vector::dot(acP, ao) > 0 ) {
simplex.b = a;
direction = uf::vector::cross(uf::vector::cross(ac, ao), ac);
simplex.size = 2;
continue;
}
simplex.d = simplex.c;
simplex.c = simplex.b;
simplex.b = a;
direction = abc;
simplex.size = 3;
continue;
}
}
goto EPA;
EPA:
manifold.colliding = true;
manifold.normal = direction;
manifold.depth = dot;
return manifold;
}
/*
*/
UF_API uf::AABBox::AABBox( const pod::Vector3& origin, const pod::Vector3& corner ) {
this->m_origin = origin;
this->m_corner = corner;
}
std::string UF_API uf::AABBox::type() const { return "AABBox"; }
pod::Vector3* UF_API uf::AABBox::expand() const {
pod::Vector3* raw = new pod::Vector3[8];
raw[0] = pod::Vector3{ this->m_corner.x, this->m_corner.y, this->m_corner.z};
raw[1] = pod::Vector3{ this->m_corner.x, this->m_corner.y, -this->m_corner.z};
raw[2] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, -this->m_corner.z};
raw[3] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, this->m_corner.z};
raw[4] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z};
raw[5] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, this->m_corner.z};
raw[6] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, -this->m_corner.z};
raw[7] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z};
for ( uint i = 0; i < 8; i++ ) raw[0] += this->m_origin;
return raw;
}
pod::Vector3 UF_API uf::AABBox::support( const pod::Vector3& direction ) const {
pod::Vector3 res;
res[0] = this->m_origin.x + this->m_corner.x * (direction.x >= 0 ? 1 : -1);
res[1] = this->m_origin.y + this->m_corner.y * (direction.y >= 0 ? 1 : -1);
res[2] = this->m_origin.z + this->m_corner.z * (direction.z >= 0 ? 1 : -1);
return res;
}
uf::Collider::Manifold UF_API uf::AABBox::intersects( const uf::AABBox& b ) const {
const uf::AABBox& a = *this;
uf::Collider::Manifold manifold(a, b);
float a_left = a.m_origin.x - a.m_corner.x;
float a_right = a.m_origin.x + a.m_corner.x;
float a_bottom = a.m_origin.y - a.m_corner.y;
float a_top = a.m_origin.y + a.m_corner.y;
float a_back = a.m_origin.z - a.m_corner.z;
float a_front = a.m_origin.z + a.m_corner.z;
float b_left = b.m_origin.x - b.m_corner.x;
float b_right = b.m_origin.x + b.m_corner.x;
float b_bottom = b.m_origin.y - b.m_corner.y;
float b_top = b.m_origin.y + b.m_corner.y;
float b_back = b.m_origin.z - b.m_corner.z;
float b_front = b.m_origin.z + b.m_corner.z;
manifold.depth = 9E9;
auto test = [&]( const pod::Vector3& axis, float minA, float maxA, float minB, float maxB )->bool{
float axisLSqr = uf::vector::dot(axis, axis);
if ( axisLSqr < 1E-8f ) return true;
float d0 = maxB - minA;
float d1 = maxA - minB;
if ( d0 < 0 || d1 < 0 ) return false;
float overlap = d0 < d1 ? d0 : -d1;
pod::Vector3 sep = axis * ( overlap / axisLSqr );
float sepLSqr = uf::vector::dot( sep, sep );
if ( sepLSqr < manifold.depth ) {
manifold.normal = sep;
manifold.depth = sepLSqr;
}
return true;
};
if ( !test( {1, 0, 0}, a_left, a_right, b_left, b_right ) ) return manifold;
if ( !test( {0, 1, 0}, a_bottom, a_top, b_bottom, b_top ) ) return manifold;
if ( !test( {0, 0, 1}, a_back, a_front, b_back, b_front ) ) return manifold;
manifold.normal = uf::vector::normalize( manifold.normal );
manifold.depth = sqrt( manifold.depth ); // * 1.001;
manifold.colliding = true;
return manifold;
/*
if ( a_right < b_left ) return manifold;
if ( a_left > b_right ) return manifold;
if ( a_top < b_bottom ) return manifold;
if ( a_bottom > b_top ) return manifold;
if ( a_front < b_back ) return manifold;
if ( a_back > b_front ) return manifold;
pod::Vector3* a_points = a.expand();
pod::Vector3* b_points = b.expand();
float smallest = 9E9;
for ( uint b = 0; b < 8; b++ ) {
for ( uint a = 0; a < 8; a++ ) {
float distance = uf::vector::distanceSquared(b_points[b], a_points[a]);
smallest = fmin( smallest, distance );
}
}
delete[] a_points;
delete[] b_points;
manifold.depth = sqrt(smallest);
manifold.normal = b.m_origin - a.m_origin;
manifold.colliding = true;
return manifold;
*/
}
/*
*/
UF_API uf::SphereCollider::SphereCollider( float r, const pod::Vector3& origin ) {
this->m_radius = r;
this->m_origin = origin;
}
std::string UF_API uf::SphereCollider::type() const { return "Sphere"; }
float UF_API uf::SphereCollider::getRadius() const {
return this->m_radius;
}
const pod::Vector3& UF_API uf::SphereCollider::getOrigin() const {
return this->m_origin;
}
void UF_API uf::SphereCollider::setRadius( float r ) {
this->m_radius = r;
}
void UF_API uf::SphereCollider::setOrigin( const pod::Vector3& origin ) {
this->m_origin = origin;
}
pod::Vector3* UF_API uf::SphereCollider::expand() const {
return NULL;
}
pod::Vector3 UF_API uf::SphereCollider::support( const pod::Vector3& direction ) const {
return this->m_origin + direction * (this->m_radius/uf::vector::magnitude(direction));
}
uf::Collider::Manifold uf::SphereCollider::intersects( const uf::SphereCollider& b ) const {
const uf::SphereCollider& a = *this;
uf::Collider::Manifold manifold(a, b);
float distance = uf::vector::distance(a.m_origin, b.m_origin);
float sum = a.m_radius + b.m_radius;
if ( distance >= sum ) return manifold;
manifold.depth = fabs(b.m_radius - a.m_radius);
manifold.normal = b.m_origin - a.m_origin;
manifold.colliding = true;
return manifold;
}
/*
*/
/*
uf::MeshCollider::MeshCollider( uf::Mesh& mesh ) : mesh(mesh) {
const uf::Mesh::vertices_t verts = this->m_mesh.getVertices();
this->m_raw = verts.get();
}
std::string UF_API uf::Collider::type() const { return "Mesh"; }
uf::Mesh& uf::MeshCollider::getMesh() {
return this->m_mesh;
}
const uf::Mesh& uf::MeshCollider::getMesh() const {
return this->m_mesh;
}
void uf::MeshCollider::setMesh( const uf::Mesh& mesh ) {
this->m_mesh = mesh;
const uf::Mesh::vertices_t verts = this->m_mesh.getVertices();
this->m_raw = verts.get();
}
pod::Vector3* uf::MeshCollider::expand() const {
return (pod::Vector3*) &this->m_raw[0];
}
pod::Vector3 uf::MeshCollider::support( const pod::Vector3& direction ) const {
uint len = this->m_raw.size();
pod::Vector3* points = this->m_expand();
uint best = 0;
float best_dot = points[0].dot(direction);
for ( uint i = 1; i < len; i++ ) {
float dot = points[i].dot(direction);
if ( dot > best_dot ) {
best = i;
best_dot = dot;
}
}
return points[best];
}
*/
/*
*/
UF_API uf::ModularCollider::ModularCollider( uint len, pod::Vector3* container, bool should_free, const uf::ModularCollider::function_expand_t& expand, const uf::ModularCollider::function_support_t& support ) {
this->m_len = len;
this->m_container = container;
this->m_should_free = should_free;
this->m_function_expand = expand;
this->m_function_support = support;
}
UF_API uf::ModularCollider::~ModularCollider() {
if ( this->m_container != NULL && this->m_should_free ) delete[] this->m_container;
}
std::string UF_API uf::ModularCollider::type() const { return "Modular"; }
void UF_API uf::ModularCollider::setExpand( const uf::ModularCollider::function_expand_t& expand ) {
this->m_function_expand = expand;
}
void UF_API uf::ModularCollider::setSupport( const uf::ModularCollider::function_support_t& support ) {
this->m_function_support = support;
}
pod::Vector3* UF_API uf::ModularCollider::getContainer() {
return this->m_container;
}
uint UF_API uf::ModularCollider::getSize() const {
return this->m_len;
}
void UF_API uf::ModularCollider::setContainer( pod::Vector3* container, uint len ) {
this->m_container = container;
this->m_len = len;
}
pod::Vector3* UF_API uf::ModularCollider::expand() const {
return this->m_function_expand ? this->m_function_expand() : this->m_container;
}
pod::Vector3 UF_API uf::ModularCollider::support( const pod::Vector3& direction ) const {
if ( this->m_function_support ) return this->m_function_support(direction);
uint len = this->m_len;
pod::Vector3* points = this->expand();
uint best = 0;
float best_dot = uf::vector::dot(points[0], direction);
for ( uint i = 1; i < len; i++ ) {
float dot = uf::vector::dot(points[i], direction);
if ( dot > best_dot ) {
best = i;
best_dot = dot;
}
}
return points[best];
}
uf::CollisionBody::~CollisionBody() {
uf::Collider::~Collider() {
this->clear();
}
void UF_API uf::CollisionBody::clear() {
for ( uf::Collider* pointer : this->m_container ) delete pointer;
void UF_API uf::Collider::clear() {
for ( pod::Collider* pointer : this->m_container ) delete pointer;
this->m_container.clear();
}
void UF_API uf::CollisionBody::add( uf::Collider* pointer ) {
void UF_API uf::Collider::add( pod::Collider* pointer ) {
this->m_container.push_back(pointer);
}
uf::CollisionBody::container_t& UF_API uf::CollisionBody::getContainer() {
uf::Collider::container_t& UF_API uf::Collider::getContainer() {
return this->m_container;
}
const uf::CollisionBody::container_t& UF_API uf::CollisionBody::getContainer() const {
const uf::Collider::container_t& UF_API uf::Collider::getContainer() const {
return this->m_container;
}
std::size_t UF_API uf::CollisionBody::getSize() const {
std::size_t UF_API uf::Collider::getSize() const {
return this->m_container.size();
}
std::vector<uf::Collider::Manifold> UF_API uf::CollisionBody::intersects( const uf::CollisionBody& body ) const {
std::vector<uf::Collider::Manifold> manifolds;
for ( const uf::Collider* pointer : body.m_container ) {
std::vector<uf::Collider::Manifold> result = this->intersects( *pointer );
std::vector<pod::Collider::Manifold> UF_API uf::Collider::intersects( const uf::Collider& body, bool smart ) const {
std::vector<pod::Collider::Manifold> manifolds;
manifolds.reserve( this->m_container.size() * body.m_container.size() );
for ( const pod::Collider* pointer : body.m_container ) {
std::vector<pod::Collider::Manifold> result = this->intersects( *pointer, smart );
manifolds.insert( manifolds.end(), result.begin(), result.end() );
}
return manifolds;
}
std::vector<uf::Collider::Manifold> UF_API uf::CollisionBody::intersects( const uf::Collider& body ) const {
std::vector<uf::Collider::Manifold> manifolds;
for ( const uf::Collider* pointer : this->m_container ) {
uf::Collider::Manifold manifold;
std::vector<pod::Collider::Manifold> UF_API uf::Collider::intersects( const pod::Collider& body, bool smart ) const {
// smart = false;
std::vector<pod::Collider::Manifold> manifolds;
for ( const pod::Collider* pointer : this->m_container ) {
pod::Collider::Manifold& manifold = manifolds.emplace_back();
if ( !pointer ) continue;
if ( pointer->type() == body.type() ) {
if ( pointer->type() == "AABBox" ) {
const uf::AABBox& a = *((const uf::AABBox*) pointer);
const uf::AABBox& b = *((const uf::AABBox*) &body);
if ( smart && pointer->type() == body.type() ) {
if ( pointer->type() == "BoundingBox" ) {
const uf::BoundingBox& a = *((const uf::BoundingBox*) pointer);
const uf::BoundingBox& b = *((const uf::BoundingBox*) &body);
manifold = a.intersects(b);
} else if ( pointer->type() == "Sphere" ) {
const uf::SphereCollider& a = *((const uf::SphereCollider*) pointer);
const uf::SphereCollider& b = *((const uf::SphereCollider*) &body);
manifold = a.intersects(b);
}
else manifold = pointer->intersects( body );
else
manifold = pointer->intersects( body );
} else manifold = pointer->intersects( body );
manifolds.push_back( manifold );
}
return manifolds;
}

View File

@ -0,0 +1,157 @@
#include <uf/utils/math/collision/boundingbox.h>
UF_API uf::BoundingBox::BoundingBox( const pod::Vector3& origin, const pod::Vector3& corner ) {
this->m_origin = origin;
this->m_corner = corner;
}
const pod::Vector3& uf::BoundingBox::getOrigin() const {
return this->m_origin;
}
const pod::Vector3& uf::BoundingBox::getCorner() const {
return this->m_corner;
}
void uf::BoundingBox::setOrigin( const pod::Vector3& origin ) {
this->m_origin = origin;
}
void uf::BoundingBox::setCorner( const pod::Vector3& corner ) {
this->m_corner = corner;
}
pod::Vector3 uf::BoundingBox::min() const {
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
return position - this->m_corner;
}
pod::Vector3 uf::BoundingBox::max() const {
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
return position + this->m_corner;
}
pod::Vector3 uf::BoundingBox::closest( const pod::Vector3f& point ) const {
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
float distance = 9E9;
pod::Vector3f vector = point;
pod::Vector3f min = position - this->m_corner;
pod::Vector3f max = position + this->m_corner;
float test = 0;
if ( (test = fabs(min.x - point.x)) < distance ) {
distance = test;
vector.x = min.x;
}
if ( (test = fabs(max.x - point.x)) < distance ) {
distance = test;
vector.x = max.x;
}
if ( (test = fabs(min.y - point.y)) < distance ) {
distance = test;
vector.y = min.y;
}
if ( (test = fabs(max.y - point.y)) < distance ) {
distance = test;
vector.y = max.y;
}
if ( (test = fabs(min.z - point.z)) < distance ) {
distance = test;
vector.z = min.z;
}
if ( (test = fabs(max.z - point.z)) < distance ) {
distance = test;
vector.z = max.z;
}
return vector;
}
std::string UF_API uf::BoundingBox::type() const { return "BoundingBox"; }
pod::Vector3* UF_API uf::BoundingBox::expand() const {
pod::Vector3* raw = new pod::Vector3[8];
raw[0] = pod::Vector3{ this->m_corner.x, this->m_corner.y, this->m_corner.z};
raw[1] = pod::Vector3{ this->m_corner.x, this->m_corner.y, -this->m_corner.z};
raw[2] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, -this->m_corner.z};
raw[3] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, this->m_corner.z};
raw[4] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z};
raw[5] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, this->m_corner.z};
raw[6] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, -this->m_corner.z};
raw[7] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z};
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
for ( uint i = 0; i < 8; i++ ) raw[0] += position;
return raw;
}
pod::Vector3 UF_API uf::BoundingBox::support( const pod::Vector3& direction ) const {
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
pod::Vector3 res = {
position.x + fabs(this->m_corner.x) * (direction.x > 0 ? 1 : -1),
position.y + fabs(this->m_corner.y) * (direction.y > 0 ? 1 : -1),
position.z + fabs(this->m_corner.z) * (direction.z > 0 ? 1 : -1),
};
return res;
}
pod::Collider::Manifold UF_API uf::BoundingBox::intersects( const uf::BoundingBox& b ) const {
const uf::BoundingBox& a = *this;
pod::Collider::Manifold manifold(a, b);
BoundingBox difference(a.min() - b.max() + a.m_corner + b.m_corner, (a.m_corner + b.m_corner) * 2.0f);
pod::Vector3f min = difference.m_origin - this->m_corner;
pod::Vector3f max = difference.m_origin + this->m_corner;
manifold.colliding = min.x <= 0 && max.x >= 0 && min.y <= 0 && max.y >= 0;
if ( !manifold.colliding ) return manifold;
pod::Vector3f penetration = difference.closest( {0, 0, 0} );
manifold.depth = uf::vector::norm( penetration );
manifold.normal = penetration / manifold.depth;
/*
float a_left = position_a.x - a.m_corner.x;
float a_right = position_a.x + a.m_corner.x;
float a_bottom = position_a.y - a.m_corner.y;
float a_top = position_a.y + a.m_corner.y;
float a_back = position_a.z - a.m_corner.z;
float a_front = position_a.z + a.m_corner.z;
float b_left = position_b.x - b.m_corner.x;
float b_right = position_b.x + b.m_corner.x;
float b_bottom = position_b.y - b.m_corner.y;
float b_top = position_b.y + b.m_corner.y;
float b_back = position_b.z - b.m_corner.z;
float b_front = position_b.z + b.m_corner.z;
manifold.depth = 9E9;
auto test = [&]( const pod::Vector3& axis, float minA, float maxA, float minB, float maxB )->bool{
float axisLSqr = uf::vector::dot(axis, axis);
if ( axisLSqr < 1E-8f ) return true;
float d0 = maxB - minA;
float d1 = maxA - minB;
if ( d0 < 0 || d1 < 0 ) return false;
float overlap = d0 < d1 ? d0 : -d1;
pod::Vector3 sep = axis * ( overlap / axisLSqr );
float sepLSqr = uf::vector::dot( sep, sep );
if ( sepLSqr < manifold.depth ) {
manifold.normal = sep;
manifold.depth = sepLSqr;
}
return true;
};
if ( !test( {1, 0, 0}, a_left, a_right, b_left, b_right ) ) return manifold;
if ( !test( {0, 1, 0}, a_bottom, a_top, b_bottom, b_top ) ) return manifold;
if ( !test( {0, 0, 1}, a_back, a_front, b_back, b_front ) ) return manifold;
manifold.normal = uf::vector::normalize( manifold.normal );
manifold.depth = sqrt( manifold.depth );
// manifold.depth = manifold.depth;
manifold.colliding = true;
*/
return manifold;
}

View File

@ -0,0 +1,247 @@
#include <uf/utils/math/collision/gjk.h>
/*
pod::Simplex::Simplex( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) {
this->set(b, c, d);
}
void pod::Simplex::add( const pod::Vector3& a ) {
this->d = this->c;
this->c = this->b;
this->b = a;
}
void pod::Simplex::set( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) {
this->b = b;
this->c = c;
this->d = d;
if ( b != pod::Vector3{} ) this->size++;
if ( c != pod::Vector3{} ) this->size++;
if ( d != pod::Vector3{} ) this->size++;
}
*/
pod::Collider::~Collider(){}
std::string UF_API pod::Collider::type() const { return ""; }
pod::Collider::Manifold UF_API pod::Collider::intersects( const pod::Collider& y ) const {
const pod::Collider& x = *this;
pod::Simplex::SupportPoint a;
pod::Simplex simplex;
pod::Vector3 direction = pod::Vector3{ 1.0f, 0.0f, 0.0f };
pod::Collider::Manifold manifold(x, y);
float dot = -0.1;
uint16_t iterations = 0;
uint16_t iterations_cap = 25;
while ( iterations++ < iterations_cap ) {
direction = uf::vector::normalize(direction);
a = pod::Simplex::SupportPoint{};
a.a = x.support(direction);
a.b = y.support(-direction);
a.v = a.a - a.b;
if ( (dot = a.dot(direction)) < 0 ) {
return manifold;
}
if( simplex.size == 0 ) {
simplex.b = a;
direction = direction * -1;
simplex.size = 1;
continue;
}
if ( simplex.size == 1 ) {
direction = uf::vector::cross(a.cross(simplex.b), a.v);
simplex.c = simplex.b;
simplex.b = a;
simplex.size = 2;
continue;
}
if ( simplex.size == 2 ) {
pod::Vector3 ao = a * -1;
pod::Vector3 ab = simplex.b - a;
pod::Vector3 ac = simplex.c - a;
pod::Vector3 abc = uf::vector::cross(ab, ac);
pod::Vector3 abP = uf::vector::cross(ab, abc);
if ( uf::vector::dot(abP, ao) > 0 ) {
simplex.c = simplex.b;
simplex.b = a;
direction = uf::vector::cross(ab, ao);
continue;
}
pod::Vector3 acP = uf::vector::cross(abc, ac);
if ( uf::vector::dot(acP, ao) > 0 ) {
simplex.b = a;
direction = uf::vector::cross(ac, ao);
continue;
}
if ( uf::vector::dot(abc, ao) > 0 ) {
simplex.d = simplex.c;
simplex.c = simplex.b;
simplex.b = a;
direction = abc;
continue;
}
simplex.d = simplex.b;
simplex.b = a;
direction = abc * -1;
simplex.size = 3;
continue;
}
if ( simplex.size == 3 ) {
pod::Vector3 ao = a * -1;
pod::Vector3 ab = simplex.b - a;
pod::Vector3 ac = simplex.c - a;
pod::Vector3 abc = uf::vector::cross(ab, ac);
pod::Vector3 ad, acd, adb;
if ( uf::vector::dot(abc, ao) > 0 ) {
goto check_face;
}
ad = simplex.d - a;
acd = uf::vector::cross(ac, ad);
if ( uf::vector::dot(acd, ao) > 0 ) {
simplex.b = simplex.c;
simplex.c = simplex.d;
ab = ac;
ac = ad;
abc = acd;
goto check_face;
}
goto EPA;
check_face:
pod::Vector3 abP = uf::vector::cross(ab, abc);
if ( uf::vector::dot(abP, ao) > 0 ) {
simplex.c = simplex.b;
simplex.b = a;
direction = uf::vector::cross(uf::vector::cross(ab, ao), ab);
simplex.size = 2;
continue;
}
pod::Vector3 acP = uf::vector::cross(abc, ac);
if ( uf::vector::dot(acP, ao) > 0 ) {
simplex.b = a;
direction = uf::vector::cross(uf::vector::cross(ac, ao), ac);
simplex.size = 2;
continue;
}
simplex.d = simplex.c;
simplex.c = simplex.b;
simplex.b = a;
direction = abc;
simplex.size = 3;
continue;
}
}
return manifold;
EPA:
struct Triangle {
pod::Simplex::SupportPoint points[3];
pod::Vector3f normal;
Triangle( const pod::Simplex::SupportPoint& a, const pod::Simplex::SupportPoint& b, const pod::Simplex::SupportPoint& c ) {
points[0] = a;
points[1] = b;
points[2] = c;
normal = uf::vector::normalize( uf::vector::cross( b.v - a.v, c.v - a.v ) );
}
};
struct Edge {
pod::Simplex::SupportPoint points[2];
Edge( const pod::Simplex::SupportPoint& a, const pod::Simplex::SupportPoint& b ) {
points[0] = a;
points[1] = b;
}
};
iterations = 0;
manifold.colliding = true;
manifold.depth = 0.0f;
manifold.normal = { 0, 0, 0 };
std::vector<Triangle> triangles;
std::vector<Edge> edges;
triangles.emplace_back( a, simplex.b, simplex.c );
triangles.emplace_back( a, simplex.b, simplex.d );
triangles.emplace_back( a, simplex.c, simplex.d );
triangles.emplace_back( simplex.b, simplex.c, simplex.d );
auto addEdge = [&]( const pod::Simplex::SupportPoint& a, const pod::Simplex::SupportPoint& b ) {
for ( auto it = edges.begin(); it != edges.end(); ++it ) {
if( it->points[0]== b && it->points[1]== a ) {
edges.erase(it);
return;
}
}
edges.emplace_back( a, b );
};
while ( iterations++ < iterations_cap ) {
// find closest triangle to origin
struct {
std::vector<Triangle>::iterator it;
float distance = 9E9;
pod::Simplex::SupportPoint support;
} closest = { triangles.begin() };
for(auto it = triangles.begin(); it != triangles.end(); it++) {
float distance = fabs( uf::vector::dot(it->normal, it->points[0].v) );
if( distance < closest.distance ) {
closest.distance = distance;
closest.it = it;
}
}
{
closest.support.a = x.support(closest.it->normal);
closest.support.b = y.support(-closest.it->normal);
closest.support.v = closest.support.a - closest.support.b;
}
manifold.normal = -closest.it->normal;
manifold.depth = uf::vector::dot( closest.it->normal, closest.support.v );
if( manifold.depth - closest.distance < 0.00001f ) {
manifold.depth = uf::vector::dot( closest.it->normal, closest.it->points[0].v );
return manifold;
}
for(auto it = triangles.begin(); it != triangles.end();) {
// can this face be 'seen' by closest.support?
if( uf::vector::dot( it->normal, (closest.support.v - it->points[0].v) ) > 0) {
addEdge( it->points[0], it->points[1] );
addEdge( it->points[1], it->points[2] );
addEdge( it->points[2], it->points[0] );
it = triangles.erase(it);
continue;
}
it++;
}
// create new triangles from the edges in the edge list
for(auto it = edges.begin(); it != edges.end(); it++)
triangles.emplace_back( closest.support, it->points[0], it->points[1] );
edges.clear();
}
return manifold;
}
pod::Vector3f pod::Collider::getPosition() const {
return this->m_transform.reference ? this->m_transform.reference->position : this->m_transform.position;
// return uf::transform::flatten( this->m_transform.reference ? *this->m_transform.reference : this->m_transform ).position;
}
pod::Transform<>& pod::Collider::getTransform() {
return this->m_transform;
}
const pod::Transform<>& pod::Collider::getTransform() const {
return this->m_transform;
}
void pod::Collider::setTransform( const pod::Transform<>& transform ) {
this->m_transform = transform;
}

View File

@ -0,0 +1,42 @@
#include <uf/utils/math/collision/mesh.h>
uf::MeshCollider::MeshCollider( const pod::Transform<>& transform, const std::vector<pod::Vector3>& positions ) : m_positions(positions) {
this->setTransform(transform);
}
std::string UF_API uf::MeshCollider::type() const { return "Mesh"; }
std::vector<pod::Vector3>& uf::MeshCollider::getPositions() {
return this->m_positions;
}
const std::vector<pod::Vector3>& uf::MeshCollider::getPositions() const {
return this->m_positions;
}
void uf::MeshCollider::setPositions( const std::vector<pod::Vector3>& positions ) {
this->m_positions = positions;
}
pod::Vector3* uf::MeshCollider::expand() const {
return (pod::Vector3*) &this->m_positions[0];
}
pod::Vector3 uf::MeshCollider::support( const pod::Vector3& direction ) const {
size_t len = this->m_positions.size();
pod::Vector3* points = this->expand();
pod::Matrix4f model = uf::transform::model( this->m_transform );
struct {
size_t i = 0;
float dot = 0;
} best;
for ( size_t i = 0; i < len; ++i ) {
float dot = uf::vector::dot( uf::matrix::multiply<float>( model, points[i] ), direction);
// float dot = uf::vector::dot( points[i], direction);
if ( i == 0 || dot > best.dot ) {
best.i = i;
best.dot = dot;
}
}
return points[best.i];
}

View File

@ -0,0 +1,55 @@
#include <uf/utils/math/collision/modular.h>
UF_API uf::ModularCollider::ModularCollider( uint len, pod::Vector3* container, bool should_free, const uf::ModularCollider::function_expand_t& expand, const uf::ModularCollider::function_support_t& support ) {
this->m_len = len;
this->m_container = container;
this->m_should_free = should_free;
this->m_function_expand = expand;
this->m_function_support = support;
}
UF_API uf::ModularCollider::~ModularCollider() {
if ( this->m_container != NULL && this->m_should_free ) delete[] this->m_container;
}
std::string UF_API uf::ModularCollider::type() const { return "Modular"; }
void UF_API uf::ModularCollider::setExpand( const uf::ModularCollider::function_expand_t& expand ) {
this->m_function_expand = expand;
}
void UF_API uf::ModularCollider::setSupport( const uf::ModularCollider::function_support_t& support ) {
this->m_function_support = support;
}
pod::Vector3* UF_API uf::ModularCollider::getContainer() {
return this->m_container;
}
uint UF_API uf::ModularCollider::getSize() const {
return this->m_len;
}
void UF_API uf::ModularCollider::setContainer( pod::Vector3* container, uint len ) {
this->m_container = container;
this->m_len = len;
}
pod::Vector3* UF_API uf::ModularCollider::expand() const {
return this->m_function_expand ? this->m_function_expand() : this->m_container;
}
pod::Vector3 UF_API uf::ModularCollider::support( const pod::Vector3& direction ) const {
if ( this->m_function_support ) return this->m_function_support(direction);
pod::Vector3* points = this->expand();
uint len = this->m_len;
struct {
size_t i = 0;
float dot = 0;
} best;
for ( size_t i = 0; i < len; ++i ) {
// float dot = uf::vector::dot( uf::matrix::multiply<float>( model, points[i] ), direction);
float dot = uf::vector::dot( points[i], direction);
if ( i == 0 || dot > best.dot ) {
best.i = i;
best.dot = dot;
}
}
return points[best.i];
}

View File

@ -0,0 +1,49 @@
#include <uf/utils/math/collision/sphere.h>
UF_API uf::SphereCollider::SphereCollider( float r, const pod::Vector3& origin ) {
this->m_radius = r;
this->m_origin = origin;
}
std::string UF_API uf::SphereCollider::type() const { return "Sphere"; }
float UF_API uf::SphereCollider::getRadius() const {
return this->m_radius;
}
const pod::Vector3& UF_API uf::SphereCollider::getOrigin() const {
return this->m_origin;
}
void UF_API uf::SphereCollider::setRadius( float r ) {
this->m_radius = r;
}
void UF_API uf::SphereCollider::setOrigin( const pod::Vector3& origin ) {
this->m_origin = origin;
}
pod::Vector3* UF_API uf::SphereCollider::expand() const {
return NULL;
}
pod::Vector3 UF_API uf::SphereCollider::support( const pod::Vector3& direction ) const {
pod::Vector3f position = this->getPosition() + this->m_origin;
// const pod::Vector3f& position = this->m_origin;
return position + direction * (this->m_radius/uf::vector::magnitude(direction));
}
pod::Collider::Manifold uf::SphereCollider::intersects( const uf::SphereCollider& b ) const {
const uf::SphereCollider& a = *this;
pod::Collider::Manifold manifold(a, b);
pod::Vector3f position_a = a.getPosition() + a.m_origin;
pod::Vector3f position_b = b.getPosition() + b.m_origin;
// const pod::Vector3f& position_a = a.m_origin;
// const pod::Vector3f& position_b = b.m_origin;
float distanceSquared = uf::vector::distanceSquared(position_a, position_b);
float sum = a.m_radius + b.m_radius;
float sumSquared = sum * sum;
if ( distanceSquared >= sumSquared ) return manifold;
manifold.depth = fabs(b.m_radius - a.m_radius);
manifold.normal = position_b - position_a;
manifold.colliding = true;
return manifold;
}

View File

@ -1,5 +1,11 @@
#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;
void UF_API uf::physics::tick() {
uf::physics::time::previous = uf::physics::time::current;
uf::physics::time::current = uf::physics::time::timer.elapsed().asDouble();

View File

@ -745,7 +745,7 @@ void ext::Gui::initialize() {
float delay = 0.0f;
float scale = metadata["text settings"]["scale"].asFloat();
std::vector<::GlyphBox> glyphs = generateGlyphs(*this);
std::cout << "Loading string: " << metadata["text settings"]["string"] << std::endl;
// std::cout << "Loading string: " << metadata["text settings"]["string"] << std::endl;
for ( auto& glyph : glyphs ) {
ext::Gui* glyphElement = (ext::Gui*) this->findByUid( this->loadChild("/gui/text/letter.json", false) );
/*
@ -860,7 +860,7 @@ void ext::Gui::render() {
metadata["text settings"]["stroke"][2].asFloat(),
metadata["text settings"]["stroke"][3].asFloat()
};
/*
if ( uf::Window::isKeyPressed("V") ) {
metadata["text settings"]["weight"] = metadata["text settings"]["weight"].asFloat() + uf::physics::time::delta;
std::cout << metadata["text settings"]["weight"].asFloat() << std::endl;
@ -877,7 +877,7 @@ void ext::Gui::render() {
metadata["text settings"]["spread"] = metadata["text settings"]["spread"].asFloat() - uf::physics::time::delta;
std::cout << metadata["text settings"]["spread"].asFloat() << std::endl;
}
*/
uniforms.gui.offset = offset;
uniforms.gui.color = color;
uniforms.gui.stroke = stroke;
@ -1036,7 +1036,7 @@ void ext::Gui::render() {
alignas(8) pod::Vector2f radius = { 0.1f, 0.1f };
alignas(16) pod::Vector4f color = { 1, 1, 1, 1 };
} cursor;
alignas(4) float alpha;
alignas(8) pod::Vector2f alpha;
};
auto& shader = blitter.material.shaders.front();
auto& uniforms = shader.uniforms.front().get<UniformDescriptor>();
@ -1077,7 +1077,8 @@ void ext::Gui::render() {
pod::Matrix4t<> model = uf::matrix::translate( uf::matrix::identity(), { 0, 0, 1 } );
uniforms.matrices.models[i] = model;
}
uniforms.alpha = metadata["overlay"]["alpha"].asFloat();
uniforms.alpha.x = metadata["overlay"]["alpha"].asFloat();
uniforms.alpha.y = 0;
uniforms.cursor.position.x = (metadata["overlay"]["cursor"]["position"][0].asFloat() + 1.0f) * 0.5f; //(::mouse.position.x + 1.0f) * 0.5f;
uniforms.cursor.position.y = (metadata["overlay"]["cursor"]["position"][1].asFloat() + 1.0f) * 0.5f; //(::mouse.position.y + 1.0f) * 0.5f;

View File

@ -102,12 +102,22 @@ void EXT_API ext::initialize() {
// Set worker threads
uf::thread::workers = ::config["engine"]["worker threads"].asUInt64();
// Enable valiation layer
ext::vulkan::validation = ::config["engine"]["ext"]["vulkan"]["validation"].asBool();
ext::vulkan::validation = ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].asBool();
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["validation"]["filters"].size(); ++i ) {
ext::vulkan::validationFilters.push_back( ::config["engine"]["ext"]["vulkan"]["validation"]["filters"][i].asString() );
}
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["features"].size(); ++i ) {
ext::vulkan::requestedDeviceFeatures.push_back( ::config["engine"]["ext"]["vulkan"]["features"][i].asString() );
}
//
// ext::vulkan::DeferredRenderingGraphic::maxLights = ::config["engine"]["scenes"]["max lights"].asUInt();
//
ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].asBool();
ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].asBool();
// ext::openvr::dominantEye = ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ? 0 : 1;
if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ) ext::openvr::dominantEye = 0;
if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "right" ) ext::openvr::dominantEye = 1;
ext::openvr::driver.manifest = ::config["engine"]["ext"]["vr"]["manifest"].asString();
if ( ext::openvr::enabled ) {
::config["engine"]["render modes"]["stereo deferred"] = true;
@ -222,13 +232,42 @@ void EXT_API ext::tick() {
uf::iostream << ext::vulkan::allocatorStats() << "\n";
}
}
/* Print Entity Information */ {
/* Attempt to reset VR position */ {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( uf::Window::isKeyPressed("Home") && timer.elapsed().asDouble() >= 1 ) { timer.reset();
if ( uf::Window::isKeyPressed("Z") && timer.elapsed().asDouble() >= 1 ) { timer.reset();
uf::hooks.call("VR:Seat.Reset");
}
}
/* Print controller position */ if ( false ) {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( uf::Window::isKeyPressed("Z") && timer.elapsed().asDouble() >= 1 ) { timer.reset();
auto& scene = uf::scene::getCurrentScene();
auto* controller = scene.getController();
auto& camera = controller->getComponent<uf::Camera>();
auto& t = camera.getTransform(); //controller->getComponent<pod::Transform<>>();
uf::iostream << "Viewport position: (" << t.position.x << ", " << t.position.y << ", " << t.position.z << ") (" << t.orientation.x << ", " << t.orientation.y << ", " << t.orientation.z << ", " << t.orientation.w << ")";
uf::iostream << "\n";
if ( false ) {
uf::Entity* light = scene.findByUid(scene.loadChild("/light.json", true));
if ( light ) {
auto& lTransform = light->getComponent<pod::Transform<>>();
auto& lMetadata = light->getComponent<uf::Serializer>();
lTransform.position = t.position;
lTransform.orientation = t.orientation;
if ( !lMetadata["light"].isArray() ) {
lMetadata["light"]["color"][0] = (rand() % 100) / 100.0;
lMetadata["light"]["color"][1] = (rand() % 100) / 100.0;
lMetadata["light"]["color"][2] = (rand() % 100) / 100.0;
}
}
auto& sMetadata = scene.getComponent<uf::Serializer>();
sMetadata["light"]["should"] = true;
}
}
}
/* Update physics timer */ {
uf::physics::tick();

View File

@ -7,11 +7,18 @@
#include <uf/utils/audio/audio.h>
#include <uf/utils/thread/thread.h>
#include <uf/utils/camera/camera.h>
#include <uf/engine/asset/asset.h>
#include <uf/engine/asset/masterdata.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/rendermodes/stereoscopic_deferred.h>
#include <uf/ext/gltf/gltf.h>
#include <uf/utils/math/collision.h>
#include "../../ext.h"
#include "../../gui/gui.h"
@ -27,34 +34,6 @@ void ext::TestScene::initialize() {
ext::ready = false;
return "true";
});
this->addHook( "asset:Load." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string filename = json["filename"].asString();
if ( uf::string::extension(filename) != "ogg" ) return "false";
const uf::Audio* audioPointer = NULL;
try { audioPointer = &assetLoader.get<uf::Audio>(filename); } catch ( ... ) {}
if ( !audioPointer ) return "false";
uf::Audio& audio = this->getComponent<uf::Audio>();
if ( audio.playing() ) {
/*
if ( filename.find("_intro") == std::string::npos ) {
metadata["previous bgm"]["filename"] = audio.getFilename();
metadata["previous bgm"]["timestamp"] = audio.getTime();
}
*/
audio.stop();
}
// std::cout << metadata["previous bgm"] << std::endl;
audio.load(filename);
audio.setVolume(metadata["volumes"]["bgm"].asFloat());
audio.play();
return "true";
});
{
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
@ -115,6 +94,9 @@ void ext::TestScene::initialize() {
}
}
void ext::TestScene::render() {
uf::Scene::render();
}
void ext::TestScene::tick() {
uf::Scene::tick();
@ -138,4 +120,57 @@ void ext::TestScene::tick() {
ext::oal.listener( "VELOCITY", { 0, 0, 0 } );
ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } );
}
/* Collision */ {
bool local = false;
bool sort = false;
bool useStrongest = false;
// pod::Thread& thread = uf::thread::fetchWorker();
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return;
if ( entity->hasComponent<uf::Collider>() )
entities.push_back((uf::Object*) entity);
};
this->process(filter);
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
uf::Serializer payload;
payload["normal"][0] = manifold.normal.x;
payload["normal"][1] = manifold.normal.y;
payload["normal"][2] = manifold.normal.z;
payload["entity"] = b->getUid();
payload["depth"] = -manifold.depth;
a->callHook("world:Collision.%UID%", payload);
payload["entity"] = a->getUid();
payload["depth"] = manifold.depth;
b->callHook("world:Collision.%UID%", payload);
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
// collide with others
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
testColliders( entityA.getComponent<uf::Collider>(), entityB.getComponent<uf::Collider>(), &entityA, &entityB, useStrongest );
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
}

View File

@ -10,5 +10,6 @@ namespace ext {
public:
virtual void initialize();
virtual void tick();
virtual void render();
};
}

View File

@ -44,19 +44,24 @@ void ext::Craeture::initialize() {
}
*/
/* Gravity */ {
if ( metadata["collision"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["collision"]["gravity"][0].asFloat();
physics.linear.acceleration.y = metadata["collision"]["gravity"][1].asFloat();
physics.linear.acceleration.z = metadata["collision"]["gravity"][2].asFloat();
if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat();
physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat();
physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat();
}
if ( !metadata["collision"]["should"].asBool() ) {
if ( !metadata["system"]["physics"]["collision"].asBool() ) {
physics.linear.acceleration.x = 0;
physics.linear.acceleration.y = 0;
physics.linear.acceleration.z = 0;
}
}
/* Collider */ {
uf::CollisionBody& collider = this->getComponent<uf::CollisionBody>();
uf::Collider& collider = this->getComponent<uf::Collider>();
collider.clear();
auto* box = new uf::BoundingBox( {0, 1.5, 0}, {0.7, 1.6, 0.7} );
box->getTransform().reference = &transform;
collider.add(box);
}
/* RPG */ {
ext::HousamoBattle& battle = this->getComponent<ext::HousamoBattle>();
@ -70,6 +75,28 @@ void ext::Craeture::initialize() {
} timers;
*/
static uf::Timer<long long> timer(true);
this->addHook( "world:Collision.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
size_t uid = json["uid"].asUInt64();
// do not collide with children
// if ( this->findByUid(uid) ) return "false";
pod::Vector3 normal;
float depth = json["depth"].asFloat() * 1.001f;
normal.x = json["normal"][0].asFloat();
normal.y = json["normal"][1].asFloat();
normal.z = json["normal"][2].asFloat();
pod::Vector3 correction = normal * depth;
transform.position -= correction;
if ( normal.x == 1 || normal.x == -1 ) physics.linear.velocity.x = 0;
if ( normal.y == 1 || normal.y == -1 ) physics.linear.velocity.y = 0;
if ( normal.z == 1 || normal.z == -1 ) physics.linear.velocity.z = 0;
return "true";
});
this->addHook( "asset:Cache.Sound.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
@ -148,157 +175,157 @@ void ext::Craeture::tick() {
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
pod::Physics& physics = this->getComponent<pod::Physics>();
/* Gravity */ {
if ( metadata["collision"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["collision"]["gravity"][0].asFloat();
physics.linear.acceleration.y = metadata["collision"]["gravity"][1].asFloat();
physics.linear.acceleration.z = metadata["collision"]["gravity"][2].asFloat();
if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat();
physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat();
physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat();
}
if ( !metadata["collision"]["should"].asBool() ) {
if ( !metadata["system"]["physics"]["collision"].asBool() ) {
physics.linear.acceleration.x = 0;
physics.linear.acceleration.y = 0;
physics.linear.acceleration.z = 0;
}
}
transform = uf::physics::update( transform, physics );
#if 0
if ( !false ) {
bool sort = false;
bool local = false;
bool useStrongest = true;
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
pod::Transform<>& transform = b->getComponent<pod::Transform<>>();
pod::Physics& physics = b->getComponent<pod::Physics>();
bool local = false;
bool sort = false;
// pod::Thread& thread = uf::thread::fetchWorker();
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
uf::Serializer payload;
pod::Vector3 correction = manifold.normal * manifold.depth;
transform.position -= correction;
/* Collision against world */ {
auto function = [&]() -> int {
if ( this->hasParent() && metadata["collision"]["should"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
uf::Entity& parent = this->getParent();
ext::TerrainGenerator& generator = parent.getComponent<ext::TerrainGenerator>();
uf::Serializer& rMetadata = parent.getComponent<uf::Serializer>();
pod::Transform<>& rTransform = parent.getComponent<pod::Transform<>>();
pod::Vector3ui size; {
size.x = rMetadata["region"]["size"][0].asUInt();
size.y = rMetadata["region"]["size"][1].asUInt();
size.z = rMetadata["region"]["size"][2].asUInt();
}
pod::Vector3f voxelPosition = transform.position - rTransform.position;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
uf::CollisionBody pCollider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
if ( this->m_name == "HousamoSprite" ) {
// bottom
uint16_t uid = generator.getVoxel( voxelPosition.x, voxelPosition.y, voxelPosition.z );
auto light = generator.getLight( voxelPosition.x, voxelPosition.y, voxelPosition.z );
metadata["color"][0] = ((light >> 12) & 0xF) / (float) (0xF);
metadata["color"][1] = ((light >> 8) & 0xF) / (float) (0xF);
metadata["color"][2] = ((light >> 4) & 0xF) / (float) (0xF);
metadata["color"][3] = ((light ) & 0xF) / (float) (0xF);
/*
if ( uid == ext::TerrainVoxelLava().uid() ) {
this->callHook("world:Craeture.Hurt.%UID%");
}
*/
}
if ( false ) {
// top
if ( ext::TerrainVoxel::atlas( generator.getVoxel( voxelPosition.x, voxelPosition.y + 1, voxelPosition.z ) ).solid() && physics.linear.velocity.y != 0 ) {
transform.position.y += physics.linear.velocity.y * uf::physics::time::delta;
physics.linear.velocity.y = 0;
}
// bottom
if ( ext::TerrainVoxel::atlas( generator.getVoxel( voxelPosition.x, voxelPosition.y - 1, voxelPosition.z ) ).solid() && physics.linear.velocity.y != 0 ) {
transform.position.y -= physics.linear.velocity.y * uf::physics::time::delta;
physics.linear.velocity.y = 0;
}
} else {
positions.push_back( { voxelPosition.x, voxelPosition.y - 1, voxelPosition.z } );
positions.push_back( { voxelPosition.x, voxelPosition.y + 1, voxelPosition.z } );
}
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = rTransform.position;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
uf::Collider* box = new uf::AABBox( offset, {0.5, 0.5, 0.5} );
pCollider.add(box);
}
uf::CollisionBody& collider = this->getComponent<uf::CollisionBody>();
pod::Transform<>& transform = this->getComponent<pod::Transform<>>(); {
collider.clear();
uf::Collider* box = new uf::AABBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} );
collider.add(box);
}
pod::Physics& physics = this->getComponent<pod::Physics>();
auto result = pCollider.intersects(collider);
uf::Collider::Manifold strongest;
strongest.depth = 0.001;
bool useStrongest = true;
for ( auto manifold : result ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( strongest.depth < manifold.depth ) strongest = manifold;
if ( !useStrongest ) {
pod::Vector3 correction = uf::vector::normalize(manifold.normal) * -(manifold.depth * manifold.depth * 1.001);
transform.position += correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
if ( useStrongest && strongest.colliding ) {
pod::Vector3 correction = uf::vector::normalize(strongest.normal) * -(strongest.depth * strongest.depth * 1.001);
transform.position += correction;
// std::cout << "Collision! " << ( strongest.colliding ? "yes" : "no" ) << " " << strongest.normal.x << ", " << strongest.normal.y << ", " << strongest.normal.z << " / " << strongest.depth << std::endl;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
return 0;
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
/* Collision against world */ {
auto function = [&]() -> int {
if ( this->hasParent() && metadata["system"]["physics"]["collision"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
/* Collision against world */ if ( false ) {
auto function = [&]() -> int {
if ( this->hasParent() && metadata["collision"]["should"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getName() == "Player" ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
if ( !this->getParent().hasParent() ) { return 0; }
if ( this->getParent().getParent().getName() != "Terrain" ) { return 0; }
uf::Entity& parent = this->getParent();
ext::TerrainGenerator& generator = parent.getComponent<ext::TerrainGenerator>();
uf::Serializer& rMetadata = parent.getComponent<uf::Serializer>();
pod::Transform<>& rTransform = parent.getComponent<pod::Transform<>>();
uf::Entity& parentRegion = this->getParent();
uf::Entity& parentTerrain = parentRegion.getParent();
pod::Vector3ui size; {
size.x = rMetadata["region"]["size"][0].asUInt();
size.y = rMetadata["region"]["size"][1].asUInt();
size.z = rMetadata["region"]["size"][2].asUInt();
}
pod::Vector3f voxelPosition = transform.position - rTransform.position;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
int regions = 0;
std::vector<uf::Entity*> entities;
entities.push_back(&parentRegion);
if ( false ) {
/* Retrieve close entities */ for ( uf::Entity* kv : parentTerrain.getChildren() ) { if ( !kv ) continue; if ( kv->getName() != "Region" ) continue;
if ( kv->getUid() == parentRegion.getUid() ) continue;
uf::Serializer& rMetadata = kv->getComponent<uf::Serializer>();
if ( !rMetadata["region"]["initialized"].asBool() ) continue;
if ( ++regions <= 2 ) entities.push_back(kv);
uf::Collider pCollider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y - 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y + 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
if ( this->m_name == "HousamoSprite" ) {
// bottom
uint16_t uid = generator.getVoxel( voxelPosition.x, voxelPosition.y, voxelPosition.z );
auto light = generator.getLight( voxelPosition.x, voxelPosition.y, voxelPosition.z );
metadata["color"][0] = ((light >> 12) & 0xF) / (float) (0xF);
metadata["color"][1] = ((light >> 8) & 0xF) / (float) (0xF);
metadata["color"][2] = ((light >> 4) & 0xF) / (float) (0xF);
metadata["color"][3] = ((light ) & 0xF) / (float) (0xF);
// if ( uid == ext::TerrainVoxelLava().uid() ) this->callHook("world:Craeture.Hurt.%UID%");
}
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = rTransform.position;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
pCollider.add( new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ) );
}
uf::Collider& collider = this->getComponent<uf::Collider>();
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
{
collider.clear();
collider.add(new uf::BoundingBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} ));
}
pod::Physics& physics = this->getComponent<pod::Physics>();
auto result = pCollider.intersects(collider);
pod::Collider::Manifold strongest;
for ( auto manifold : result ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( strongest.depth < manifold.depth ) strongest = manifold;
if ( !useStrongest ) {
pod::Vector3 correction = manifold.normal * manifold.depth;
transform.position -= correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
if ( useStrongest && strongest.colliding ) {
pod::Vector3 correction = strongest.normal * strongest.depth;
transform.position -= correction;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
/* Collision against other craetures */ {
auto function = [&]() -> int {
/* Collision */ if ( this->hasParent() && metadata["system"]["physics"]["collision"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
uf::Entity& parent = this->getParent();
int regions = 0;
std::vector<uf::Entity*> entities;
/* Retrieve close entities */ for ( uf::Entity* kv : parent.getChildren() ) {
if ( !kv ) continue;
if ( kv->getUid() == this->getUid() ) continue;
if ( !kv->hasComponent<uf::Collider>() ) continue;
entities.push_back(kv);
}
/* Sort by closest to farthest */ if ( sort ) {
const pod::Vector3& position = this->getComponent<pod::Transform<>>().position;
@ -309,146 +336,284 @@ void ext::Craeture::tick() {
return uf::vector::magnitude( uf::vector::subtract( l->getComponent<pod::Transform<>>().position, position ) ) < uf::vector::magnitude( uf::vector::subtract( r->getComponent<pod::Transform<>>().position, position ) );
} );
}
}
for ( uf::Entity* e : entities ) {
uf::CollisionBody& collider = this->getComponent<uf::CollisionBody>();
uf::CollisionBody& pCollider = e->getComponent<uf::CollisionBody>();
for ( uf::Entity* e : entities ) {
if ( e->getUid() == 0 ) continue;
pod::Transform<>& transform = this->getComponent<pod::Transform<>>(); {
collider.clear();
uf::Collider* box = new uf::AABBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} );
collider.add(box);
}
uf::Collider& collider = this->getComponent<uf::Collider>();
uf::Collider& pCollider = e->getComponent<uf::Collider>();
if ( !e ) continue;
if ( e->getUid() == 0 ) continue;
if ( this->getUid() == 0 ) return 0;
if ( !this->hasComponent<pod::Physics>() ) return 0;
pod::Physics& physics = this->getComponent<pod::Physics>();
auto result = pCollider.intersects(collider);
uf::Collider::Manifold strongest;
strongest.depth = 0.001;
bool useStrongest = true;
for ( auto manifold : result ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( strongest.depth < manifold.depth ) strongest = manifold;
if ( !useStrongest ) {
pod::Vector3 correction = uf::vector::normalize(manifold.normal) * -(manifold.depth * manifold.depth * 1.001);
transform.position += correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
if ( useStrongest && strongest.colliding ) {
pod::Vector3 correction = uf::vector::normalize(strongest.normal) * -(strongest.depth * strongest.depth * 1.001);
transform.position += correction;
// std::cout << "Collision! " << ( strongest.colliding ? "yes" : "no" ) << " " << strongest.normal.x << ", " << strongest.normal.y << ", " << strongest.normal.z << " / " << strongest.depth << std::endl;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
/* Collision against other craetures */ {
auto function = [&]() -> int {
/* Collision */ if ( this->hasParent() && metadata["collision"]["should"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
uf::Entity& parent = this->getParent();
int regions = 0;
std::vector<uf::Entity*> entities;
/* Retrieve close entities */ for ( uf::Entity* kv : parent.getChildren() ) {
if ( !kv ) continue;
if ( kv->getUid() == this->getUid() ) continue;
if ( !kv->hasComponent<uf::CollisionBody>() ) continue;
entities.push_back(kv);
}
/* Sort by closest to farthest */ if ( sort ) {
const pod::Vector3& position = this->getComponent<pod::Transform<>>().position;
std::sort( entities.begin(), entities.end(), [&]( const uf::Entity* l, const uf::Entity* r ){
if ( !l ) return false; if ( !r ) return true;
if ( l->getUid() == 0 ) return false; if ( r->getUid() == 0 ) return true;
if ( !l->hasComponent<pod::Transform<>>() ) return false; if ( !r->hasComponent<pod::Transform<>>() ) return true;
return uf::vector::magnitude( uf::vector::subtract( l->getComponent<pod::Transform<>>().position, position ) ) < uf::vector::magnitude( uf::vector::subtract( r->getComponent<pod::Transform<>>().position, position ) );
} );
}
for ( uf::Entity* e : entities ) {
if ( e->getUid() == 0 ) continue;
uf::CollisionBody& collider = this->getComponent<uf::CollisionBody>();
uf::CollisionBody& pCollider = e->getComponent<uf::CollisionBody>();
pod::Transform<>& transform = this->getComponent<pod::Transform<>>(); {
collider.clear();
uf::Collider* box = new uf::AABBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} );
collider.add(box);
}
pod::Physics& physics = this->getComponent<pod::Physics>();
auto result = pCollider.intersects(collider);
uf::Collider::Manifold strongest;
strongest.depth = 0.001;
bool useStrongest = true;
for ( auto manifold : result ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( strongest.depth < manifold.depth ) strongest = manifold;
if ( !useStrongest ) {
pod::Vector3 correction = uf::vector::normalize(manifold.normal) * -(manifold.depth * manifold.depth * 1.001);
transform.position += correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Serializer& pSerializer = e->getComponent<uf::Serializer>();
if ( useStrongest && strongest.colliding ) {
// signal collision, if available
pod::Vector3 correction = uf::vector::normalize(strongest.normal) * -(strongest.depth * strongest.depth * 1.001);
pod::Physics& physics = this->getComponent<pod::Physics>();
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
{
uf::Serializer payload;
payload["entity"] = e->getUid();
payload["correction"]["x"] = correction.x;
payload["correction"]["y"] = correction.y;
payload["correction"]["z"] = correction.z;
payload["depth"] = strongest.depth;
payload["normal"]["x"] = strongest.normal.x;
payload["normal"]["y"] = strongest.normal.y;
payload["normal"]["z"] = strongest.normal.z;
uf::hooks.call("world:Collision." + std::to_string(this->getUid()), payload);
collider.clear();
collider.add(new uf::BoundingBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} ));
}
auto result = pCollider.intersects(collider);
pod::Collider::Manifold strongest;
for ( auto manifold : result ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( strongest.depth < manifold.depth ) strongest = manifold;
if ( !useStrongest ) {
pod::Vector3 correction = manifold.normal * manifold.depth;
transform.position += correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
transform.position += correction;
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Serializer& pSerializer = e->getComponent<uf::Serializer>();
// std::cout << "Collision! " << ( strongest.colliding ? "yes" : "no" ) << " " << strongest.normal.x << ", " << strongest.normal.y << ", " << strongest.normal.z << " / " << strongest.depth << std::endl;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
if ( useStrongest && strongest.colliding ) {
// signal collision, if available
pod::Vector3 correction = strongest.normal * strongest.depth;
{
uf::Serializer payload;
payload["entity"] = e->getUid();
payload["correction"]["x"] = correction.x;
payload["correction"]["y"] = correction.y;
payload["correction"]["z"] = correction.z;
payload["depth"] = strongest.depth;
payload["normal"]["x"] = strongest.normal.x;
payload["normal"]["y"] = strongest.normal.y;
payload["normal"]["z"] = strongest.normal.z;
uf::hooks.call("world:Collision." + std::to_string(this->getUid()), payload);
}
transform.position -= correction;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
}
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
} else if ( false ) {
bool sort = false;
bool local = false;
bool useStrongest = true;
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
pod::Transform<>& transform = b->getComponent<pod::Transform<>>();
pod::Physics& physics = b->getComponent<pod::Physics>();
uf::Serializer payload;
pod::Vector3 correction = manifold.normal * manifold.depth;
transform.position -= correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
/* Collision against world */ {
auto function = [&]() -> int {
if ( this->hasParent() && metadata["system"]["physics"]["collision"].asBool() ) {
if ( !this->hasParent() ) { return 0; }
if ( this->getParent().getName() != "Region" ) { return 0; }
uf::Entity& parent = this->getParent();
ext::TerrainGenerator& generator = parent.getComponent<ext::TerrainGenerator>();
uf::Serializer& rMetadata = parent.getComponent<uf::Serializer>();
pod::Transform<>& rTransform = parent.getComponent<pod::Transform<>>();
pod::Vector3ui size; {
size.x = rMetadata["region"]["size"][0].asUInt();
size.y = rMetadata["region"]["size"][1].asUInt();
size.z = rMetadata["region"]["size"][2].asUInt();
}
pod::Vector3f voxelPosition = transform.position - rTransform.position;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
uf::Collider pCollider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y - 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y + 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
if ( this->m_name == "HousamoSprite" ) {
uint16_t uid = generator.getVoxel( voxelPosition.x, voxelPosition.y, voxelPosition.z );
auto light = generator.getLight( voxelPosition.x, voxelPosition.y, voxelPosition.z );
metadata["color"][0] = ((light >> 12) & 0xF) / (float) (0xF);
metadata["color"][1] = ((light >> 8) & 0xF) / (float) (0xF);
metadata["color"][2] = ((light >> 4) & 0xF) / (float) (0xF);
metadata["color"][3] = ((light ) & 0xF) / (float) (0xF);
// if ( uid == ext::TerrainVoxelLava().uid() ) this->callHook("world:Craeture.Hurt.%UID%");
}
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = rTransform.position;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
pCollider.add( new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ) );
}
uf::Collider& collider = this->getComponent<uf::Collider>();
testColliders( pCollider, collider, (uf::Object*) &parent, this, useStrongest );
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
} else if ( false ) {
bool local = false;
bool sort = false;
bool useStrongest = false;
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return;
if ( entity->hasComponent<uf::Collider>() )
entities.push_back((uf::Object*) entity);
};
uf::Entity* regionPointer = &this->getParent();
if ( regionPointer->getName() != "Region" ) return 0;
ext::Region& region = *(ext::Region*) regionPointer;
region.process(filter);
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
uf::Serializer payload;
payload["normal"][0] = manifold.normal.x;
payload["normal"][1] = manifold.normal.y;
payload["normal"][2] = manifold.normal.z;
payload["entity"] = b->getUid();
payload["depth"] = -manifold.depth;
a->callHook("world:Collision.%UID%", payload);
payload["entity"] = a->getUid();
payload["depth"] = manifold.depth;
b->callHook("world:Collision.%UID%", payload);
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
// collide with world
auto& metadata = region.getComponent<uf::Serializer>();
auto& generator = region.getComponent<ext::TerrainGenerator>();
auto& regionPosition = region.getComponent<pod::Transform<>>().position;
pod::Vector3f size; {
size.x = metadata["region"]["size"][0].asUInt();
size.y = metadata["region"]["size"][1].asUInt();
size.z = metadata["region"]["size"][2].asUInt();
}
for ( auto* _ : entities ) {
uf::Object& entity = *_;
auto& transform = entity.getComponent<pod::Transform<>>();
pod::Vector3f voxelPosition = transform.position - regionPosition;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
uf::Collider collider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y - 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y + 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = regionPosition;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
collider.add( new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ) );
/*
uf::BaseMesh<pod::Vertex_3F> mesh;
const ext::TerrainVoxel::Model& model = voxel.model();
#define TERRAIN_SHOULD_RENDER_FACE(SIDE)\
for ( uint i = 0; i < model.position.SIDE.size() / 3; ++i ) {\
auto& vertex = mesh.vertices.emplace_back();\
{\
pod::Vector3f& p = vertex.position;\
p.x = model.position.SIDE[i*3+0]; p.y = model.position.SIDE[i*3+1]; p.z = model.position.SIDE[i*3+2];\
p.x += offset.x; p.y += offset.y; p.z += offset.z;\
}\
}
TERRAIN_SHOULD_RENDER_FACE(left)
TERRAIN_SHOULD_RENDER_FACE(right)
TERRAIN_SHOULD_RENDER_FACE(top)
TERRAIN_SHOULD_RENDER_FACE(bottom)
TERRAIN_SHOULD_RENDER_FACE(back)
TERRAIN_SHOULD_RENDER_FACE(front)
uf::MeshCollider* mCollider = new uf::MeshCollider();
mCollider->setPositions( mesh );
pCollider.add(mCollider);
*/
}
testColliders( collider, entity.getComponent<uf::Collider>(), this, &entity, useStrongest );
}
// collide with others
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
{
uf::Collider& collider = entityB.getComponent<uf::Collider>();
pod::Transform<>& transform = entityB.getComponent<pod::Transform<>>();
collider.clear();
collider.add(uf::BoundingBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.7, 1.6, 0.7} ));
}
testColliders( entityA.getComponent<uf::Collider>(), entityB.getComponent<uf::Collider>(), &entityA, &entityB, useStrongest );
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
#endif
}
void ext::Craeture::render() {
uf::Object::render();

View File

@ -136,8 +136,21 @@ void ext::HousamoSprite::render() {
if ( !metadata["system"]["loaded"].asBool() ) return;
ext::Craeture::render();
/* Update uniforms */ if ( this->hasComponent<uf::Mesh>() ) {
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& mesh = this->getComponent<uf::Mesh>();
auto& scene = this->getRootParent<uf::Scene>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& transform = this->getComponent<pod::Transform<>>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
uniforms.matrices.model = uf::transform::model( transform );
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms.matrices.view[i] = camera.getView( i );
uniforms.matrices.projection[i] = camera.getProjection( i );
}
/*
auto& graphic = this->getComponent<uf::Graphic>();
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
@ -152,6 +165,7 @@ void ext::HousamoSprite::render() {
uniforms.matrices.view[i] = camera.getView( i );
uniforms.matrices.projection[i] = camera.getProjection( i );
}
*/
uniforms.color[0] = metadata["color"][0].asFloat();
uniforms.color[1] = metadata["color"][1].asFloat();
uniforms.color[2] = metadata["color"][2].asFloat();

View File

@ -3,6 +3,7 @@
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/camera/camera.h>
EXT_OBJECT_REGISTER_CPP(Light)
@ -11,86 +12,64 @@ void ext::Light::initialize() {
auto& metadata = this->getComponent<uf::Serializer>();
auto& transform = this->getComponent<pod::Transform<>>();
auto& camera = this->getComponent<uf::Camera>();
{
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
camera = controller.getComponent<uf::Camera>();
camera.setFov( metadata["light"]["fov"].asFloat() );
}
{
if ( metadata["light"]["shadows"]["enabled"].asBool() ) {
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
renderMode.width = 512;
renderMode.height = 512;
std::string name = "Render Target: " + std::to_string((int) this->getUid());
ext::vulkan::addRenderMode( &renderMode, name );
if ( metadata["light"]["shadows"]["resolution"].isArray() ) {
renderMode.width = metadata["light"]["shadows"]["resolution"][0].asUInt64();
renderMode.height = metadata["light"]["shadows"]["resolution"][1].asUInt64();
} else {
renderMode.width = metadata["light"]["shadows"]["resolution"].asUInt64();
renderMode.height = metadata["light"]["shadows"]["resolution"].asUInt64();
}
{
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
camera = controller.getComponent<uf::Camera>();
camera.getTransform() = {};
camera.setStereoscopic(false);
if ( metadata["light"]["shadows"]["fov"].isNumeric() ) {
camera.setFov( metadata["light"]["shadows"]["fov"].asFloat() );
camera.updateProjection();
}
}
}
if ( !metadata["light"].isArray() ) {
metadata["light"]["color"][0] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1;
metadata["light"]["color"][1] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1;
metadata["light"]["color"][2] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1;
}
}
void ext::Light::tick() {
uf::Object::tick();
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
renderMode.target = "";
if ( this->hasComponent<ext::vulkan::RenderTargetRenderMode>() ) {
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
renderMode.target = "";
}
auto& camera = this->getComponent<uf::Camera>();
auto& transform = this->getComponent<pod::Transform<>>();
for ( std::size_t i = 0; i < 2; ++i ) {
camera.setView( uf::matrix::inverse( uf::transform::model( transform ) ), i );
if ( this->hasComponent<pod::Physics>() ) {
pod::Physics& physics = this->getComponent<pod::Physics>();
transform = uf::physics::update( transform, physics );
}
auto& camera = this->getComponent<uf::Camera>();
auto& metadata = this->getComponent<uf::Serializer>();
if ( metadata["light"]["external update"].isNull() || (!metadata["light"]["external update"].isNull() && !metadata["light"]["external update"].asBool()) ) {
for ( std::size_t i = 0; i < 2; ++i ) {
camera.setView( uf::matrix::inverse( uf::transform::model( transform ) ), i );
}
}
}
void ext::Light::render() {
uf::Object::render();
/*
{
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
auto& blitter = renderMode.blitter;
auto& transform = this->getComponent<pod::Transform<>>();
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
auto& camera = this->getComponent<uf::Camera>();
auto& controllerCamera = controller.getComponent<uf::Camera>();
if ( !blitter.initialized ) return;
struct UniformDescriptor {
struct {
alignas(16) pod::Matrix4f models[2];
} matrices;
struct {
alignas(8) pod::Vector2f position = { 0.5f, 0.5f };
alignas(8) pod::Vector2f radius = { 0.1f, 0.1f };
alignas(16) pod::Vector4f color = { 1, 1, 1, 1 };
} cursor;
alignas(4) float alpha;
};
auto& shader = blitter.material.shaders.front();
auto& uniforms = shader.uniforms.front().get<UniformDescriptor>();
for ( std::size_t i = 0; i < 2; ++i ) {
pod::Matrix4f model = uf::transform::model( transform );
uniforms.matrices.models[i] = controllerCamera.getProjection(i) * controllerCamera.getView(i) * model;
uniforms.alpha = 1.0f;
uniforms.cursor.position.x = -1.0f;
uniforms.cursor.position.y = -1.0f;
uniforms.cursor.radius.x = 0.0f;
uniforms.cursor.radius.y = 0.0f;
uniforms.cursor.color.x = 0.0f;
uniforms.cursor.color.y = 0.0f;
uniforms.cursor.color.z = 0.0f;
uniforms.cursor.color.w = 0.0f;
}
shader.updateBuffer( (void*) &uniforms, sizeof(uniforms), 0 );
}
*/
}
void ext::Light::destroy() {
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
ext::vulkan::removeRenderMode( &renderMode, false );
if ( this->hasComponent<ext::vulkan::RenderTargetRenderMode>() ) {
auto& renderMode = this->getComponent<ext::vulkan::RenderTargetRenderMode>();
ext::vulkan::removeRenderMode( &renderMode, false );
}
uf::Object::destroy();
}

View File

@ -17,12 +17,11 @@
namespace {
struct {
uf::Object left, right;
} hands;
} hands, lines;
struct {
uf::Object left, right;
} lines;
uf::Object* left;
uf::Object* right;
} lights;
}
EXT_OBJECT_REGISTER_CPP(Hands)
@ -35,8 +34,8 @@ void ext::Hands::initialize() {
this->addChild(::hands.left);
this->addChild(::hands.right);
this->addChild(::lines.left);
this->addChild(::lines.right);
::hands.left.addChild(::lines.left);
::hands.right.addChild(::lines.right);
}
{
bool loaded = true;
@ -49,48 +48,51 @@ void ext::Hands::initialize() {
uf::Serializer json = event;
std::string name = json["name"].asString();
uf::Object* pointer = NULL;
if ( name == metadata["hands"]["left"]["controller"]["model"].asString() ) pointer = &hands.left;
else if ( name == metadata["hands"]["right"]["controller"]["model"].asString() ) pointer = &hands.right;
else return "false";
std::string side = "";
if ( name == metadata["hands"]["left"]["controller"]["model"].asString() ) {
side = "left";
} else if ( name == metadata["hands"]["right"]["controller"]["model"].asString() ) {
side = "right";
};
if ( side == "" ) return "false";
uf::Object& hand = side == "left" ? hands.left : hands.right;
uf::Object& line = side == "left" ? lines.left : lines.right;
{
uf::Object& hand = *pointer;
uf::Graphic& graphic = (hand.getComponent<uf::Graphic>() = ext::openvr::getRenderModel( name ));
graphic.process = true;
graphic.descriptor.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
graphic.material.attachShader("./data/shaders/base.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
graphic.material.attachShader("./data/shaders/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
hand.initialize();
}
{
std::string hand = pointer == &hands.left ? "left" : "right";
auto& line = pointer == &hands.left ? lines.left : lines.right;
if ( metadata["hands"][side]["pointer"]["length"].asFloat() > 0 ) {
line.addAlias<uf::LineMesh, uf::Mesh>();
pod::Transform<>& transform = line.getComponent<pod::Transform<>>();
transform.orientation = uf::quaternion::axisAngle(
{
metadata["hands"][hand]["pointer"]["orientation"]["axis"][0].asFloat(),
metadata["hands"][hand]["pointer"]["orientation"]["axis"][1].asFloat(),
metadata["hands"][hand]["pointer"]["orientation"]["axis"][2].asFloat()
metadata["hands"][side]["pointer"]["orientation"]["axis"][0].asFloat(),
metadata["hands"][side]["pointer"]["orientation"]["axis"][1].asFloat(),
metadata["hands"][side]["pointer"]["orientation"]["axis"][2].asFloat()
},
metadata["hands"][hand]["pointer"]["orientation"]["angle"].asFloat() * 3.14159f / 180.0f
metadata["hands"][side]["pointer"]["orientation"]["angle"].asFloat() * 3.14159f / 180.0f
);
transform.position = {
metadata["hands"][hand]["pointer"]["offset"][0].asFloat(),
metadata["hands"][hand]["pointer"]["offset"][1].asFloat(),
metadata["hands"][hand]["pointer"]["offset"][2].asFloat()
metadata["hands"][side]["pointer"]["offset"][0].asFloat(),
metadata["hands"][side]["pointer"]["offset"][1].asFloat(),
metadata["hands"][side]["pointer"]["offset"][2].asFloat()
};
auto& mesh = line.getComponent<uf::LineMesh>();
auto& graphic = line.getComponent<uf::Graphic>();
mesh.vertices = {
{ {0.0f, 0.0f, 0.0f} },
{ {0.0f, 0.0f, metadata["hands"][hand]["pointer"]["length"].asFloat()} },
{ {0.0f, 0.0f, 0.0f} },
{ {0.0f, 0.0f, metadata["hands"][side]["pointer"]["length"].asFloat()} },
};
graphic.initialize();
graphic.initializeGeometry(mesh);
@ -99,27 +101,31 @@ void ext::Hands::initialize() {
graphic.material.attachShader("./data/shaders/line.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
graphic.descriptor.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
graphic.descriptor.fill = VK_POLYGON_MODE_LINE;
graphic.descriptor.lineWidth = metadata["hands"][hand]["pointer"]["width"].asFloat();
/*
graphic.initializeShaders({
{"./data/shaders/line.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/line.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
mesh.generate();
graphic.bindUniform<uf::StereoMeshDescriptor>();
graphic.description.rasterMode.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
graphic.description.rasterMode.fill = VK_POLYGON_MODE_LINE;
graphic.description.rasterMode.lineWidth = metadata["hands"][hand]["pointer"]["width"].asFloat();
graphic.initialize();
graphic.autoAssign();
*/
graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].asFloat();
line.initialize();
}
if ( metadata["hands"][side]["light"]["should"].asBool() ){
auto* child = (uf::Object*) hand.findByUid(hand.loadChild("/light.json", false));
if ( child ) {
if (side == "left" ) lights.left = child; else lights.right = child;
auto& json = metadata["hands"][side]["light"];
auto& light = side == "left" ? *lights.left : *lights.right;
auto& metadata = light.getComponent<uf::Serializer>();
if ( !json["color"].isNull() ) metadata["light"]["color"] = json["color"];
if ( !json["radius"].isNull() ) metadata["light"]["radius"] = json["radius"];
if ( !json["power"].isNull() ) metadata["light"]["power"] = json["power"];
if ( !json["shadows"].isNull() ) metadata["light"]["shadows"] = json["shadows"];
metadata["lights"]["external update"] = true;
light.initialize();
}
}
return "true";
});
}
std::vector<uf::Object*> vHands = { &::hands.left, &::hands.right };
for ( auto pointer : vHands ) {
auto& hand = *pointer;
@ -142,12 +148,34 @@ void ext::Hands::initialize() {
payload["mouse"]["button"] = side == "left" ? "Right" : "Left";
payload["mouse"]["state"] = json["state"].asBool() ? "Down": "Up";
uf::hooks.call( payload["type"].asString(), payload );
}
return "true";
});
hand.addHook("world:Collision.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string side = &hand == &hands.left ? "left" : "right";
float mag = json["depth"].asFloat();
uf::Serializer payload;
payload["delay"] = 0.0f;
payload["duration"] = uf::physics::time::delta;
payload["frequency"] = 1.0f;
payload["amplitude"] = fmin(1.0f, 1000.0f * mag);
payload["side"] = side;
uf::hooks.call( "VR:Haptics." + side, payload );
return "true";
});
auto& transform = hand.getComponent<pod::Transform<>>();
auto& collider = hand.getComponent<uf::Collider>();
// auto* box = new uf::BoundingBox( transform.position, {0.25, 0.25, 0.25} );
// box->getTransform().reference = &transform;
// collider.add(box);
}
}
}
@ -155,26 +183,58 @@ void ext::Hands::tick() {
uf::Object::tick();
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& controllerCamera = controller.getComponent<uf::Camera>();
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
auto& controllerCameraTransform = controllerCamera.getTransform();
{
pod::Transform<>& transform = hands.left.getComponent<pod::Transform<>>();
transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Left );
transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Left );
transform.scale = { 1, 1, 1 };
// transform.reference = &camera.getTransform();
transform.reference = &controllerTransform;
auto& collider = hands.left.getComponent<uf::Collider>();
for ( auto* box : collider.getContainer() ) {
box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position;
}
}
{
pod::Transform<>& transform = hands.right.getComponent<pod::Transform<>>();
transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Right );
transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right );
transform.scale = { 1, 1, 1 };
// transform.reference = &camera.getTransform();
transform.reference = &controllerTransform;
auto& collider = hands.right.getComponent<uf::Collider>();
for ( auto* box : collider.getContainer() ) {
box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position;
}
}
{
pod::Transform<>& transform = lines.left.getComponent<pod::Transform<>>();
transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Left, true );
transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Left, true );
transform.scale = { 1, 1, 1 };
transform.reference = &controllerTransform;
if ( lights.left ) {
auto& light = *lights.left;
auto& lightTransform = light.getComponent<pod::Transform<>>();
lightTransform.position = controllerCameraTransform.position + controller.getComponent<pod::Transform<>>().position + transform.position;
// lightTransform.orientation = controllerTransform.orientation * transform.orientation;
auto& lightCamera = light.getComponent<uf::Camera>();
pod::Matrix4f playerModel = uf::matrix::identity();
pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), controllerCameraTransform.position + controllerTransform.position );
pod::Matrix4f rotation = uf::quaternion::matrix( controllerTransform.orientation * pod::Vector4f{1,1,1,-1} );
playerModel = translation * rotation;
pod::Matrix4f model = uf::matrix::inverse( playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true ) );
for ( size_t i = 0; i < 2; ++i ) lightCamera.setView( model, i );
// lightTransform.position = transform.position;
// lightTransform.orientation = transform.orientation;
// lightTransform.reference = &controllerTransform;
}
// transform.reference = hands.left.getComponentPointer<pod::Transform<>>();
}
{
@ -182,6 +242,26 @@ void ext::Hands::tick() {
transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Right, true );
transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right, true );
transform.scale = { 1, 1, 1 };
transform.reference = &controllerTransform;
if ( lights.right ) {
auto& light = *lights.right;
auto& lightTransform = light.getComponent<pod::Transform<>>();
lightTransform.position = controllerCameraTransform.position + controllerTransform.position + transform.position;
// lightTransform.orientation = controllerTransform.orientation * transform.orientation;
auto& lightCamera = light.getComponent<uf::Camera>();
pod::Matrix4f playerModel = uf::matrix::identity();
pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), controllerCameraTransform.position + controllerTransform.position );
pod::Matrix4f rotation = uf::quaternion::matrix( controllerTransform.orientation * pod::Vector4f{1,1,1,-1} );
playerModel = translation * rotation;
pod::Matrix4f model = uf::matrix::inverse( playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true ) );
for ( size_t i = 0; i < 2; ++i ) lightCamera.setView( model, i );
// lightTransform.position = transform.position;
// lightTransform.orientation = transform.orientation;
// lightTransform.reference = &controllerTransform;
}
// transform.reference = hands.right.getComponentPointer<pod::Transform<>>();
}
@ -256,9 +336,7 @@ void ext::Hands::tick() {
}
}
}
#define DEBUG_MARKER() std::cout << side << ": " << __LINE__ << std::endl;
#if 0
/* Collision against world */ {
bool local = true;
bool sort = false;
@ -271,7 +349,7 @@ void ext::Hands::tick() {
pod::Transform<> transform = hand.getComponent<pod::Transform<>>();
transform.position = uf::quaternion::rotate( controller.getComponent<pod::Transform<>>().orientation, transform.position );
transform.position += controller.getComponent<pod::Transform<>>().position;
transform.position += camera.getTransform().position;
transform.position += controllerCamera.getTransform().position;
uf::Entity& parent = controller.getParent();
ext::TerrainGenerator& generator = parent.getComponent<ext::TerrainGenerator>();
@ -319,13 +397,13 @@ void ext::Hands::tick() {
if ( !voxel.solid() ) continue;
uf::Collider* box = new uf::AABBox( offset, {0.5, 0.5, 0.5} );
uf::Collider* box = new uf::BoundingBox( offset, {0.5, 0.5, 0.5} );
pCollider.add(box);
}
uf::CollisionBody& collider = hand.getComponent<uf::CollisionBody>(); {
collider.clear();
uf::Collider* box = new uf::AABBox( transform.position, {0.25, 0.25, 0.25} );
uf::Collider* box = new uf::BoundingBox( transform.position, {0.25, 0.25, 0.25} );
collider.add(box);
}
@ -351,17 +429,12 @@ void ext::Hands::tick() {
payload["side"] = side;
uf::hooks.call( "VR:Haptics." + side, payload );
}
/*
transform.position += correction;
if ( strongest.normal.x == 1 || strongest.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( strongest.normal.y == 1 || strongest.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( strongest.normal.z == 1 || strongest.normal.z == -1 ) physics.linear.velocity.z = 0;
*/
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
#endif
}
}
}
@ -373,13 +446,19 @@ void ext::Hands::render() {
auto& controller = *scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
pod::Matrix4f cameraModel = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent<pod::Transform<>>().position ) * uf::quaternion::matrix( controller.getComponent<pod::Transform<>>().orientation * pod::Vector4f{1,1,1,-1} );
if ( hands.left.hasComponent<uf::Mesh>() ) {
auto& mesh = hands.left.getComponent<uf::Mesh>();
pod::Matrix4f playerModel = uf::matrix::identity(); {
auto& controller = this->getParent();
auto& camera = controller.getComponent<uf::Camera>();
pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent<pod::Transform<>>().position );
pod::Matrix4f rotation = uf::quaternion::matrix( controller.getComponent<pod::Transform<>>().orientation * pod::Vector4f{1,1,1,-1} );
playerModel = translation * rotation;
}
// pod::Matrix4f cameraModel = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent<pod::Transform<>>().position ) * uf::quaternion::matrix( controller.getComponent<pod::Transform<>>().orientation * pod::Vector4f{1,1,1,-1} );
if ( hands.left.hasComponent<uf::Graphic>() ) {
auto& graphic = hands.left.getComponent<uf::Graphic>();
auto& transform = hands.left.getComponent<pod::Transform<>>();
graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left );
pod::Matrix4f model = cameraModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, false );
pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, false );
if ( graphic.initialized ) {
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
@ -396,12 +475,11 @@ void ext::Hands::render() {
graphic.material.shaders.front().updateBuffer( uniforms, 0, false );
}
}
if ( hands.right.hasComponent<uf::Mesh>() ) {
auto& mesh = hands.right.getComponent<uf::Mesh>();
if ( hands.right.hasComponent<uf::Graphic>() ) {
auto& graphic = hands.right.getComponent<uf::Graphic>();
auto& transform = hands.right.getComponent<pod::Transform<>>();
graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right );
pod::Matrix4f model = cameraModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, false );
pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, false );
if ( graphic.initialized ) {
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
@ -418,12 +496,11 @@ void ext::Hands::render() {
graphic.material.shaders.front().updateBuffer( uniforms, 0, false );
}
}
if ( lines.left.hasComponent<uf::Mesh>() ) {
auto& mesh = lines.left.getComponent<uf::Mesh>();
if ( lines.left.hasComponent<uf::Graphic>() ) {
auto& graphic = lines.left.getComponent<uf::Graphic>();
auto& transform = lines.left.getComponent<pod::Transform<>>();
graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left );
pod::Matrix4f model = cameraModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true );
pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true );
if ( graphic.initialized ) {
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
@ -440,12 +517,11 @@ void ext::Hands::render() {
graphic.material.shaders.front().updateBuffer( uniforms, 0, false );
}
}
if ( lines.right.hasComponent<uf::Mesh>() ) {
auto& mesh = lines.right.getComponent<uf::Mesh>();
if ( lines.right.hasComponent<uf::Graphic>() ) {
auto& graphic = lines.right.getComponent<uf::Graphic>();
auto& transform = lines.right.getComponent<pod::Transform<>>();
graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right );
pod::Matrix4f model = cameraModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true );
pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true );
if ( graphic.initialized ) {
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();

View File

@ -63,6 +63,7 @@ void ext::Player::initialize() {
pod::Vector2 bounds = {0.5, 128.0};
} perspective;
pod::Vector3 offset = {0, 0, 0};
bool stereoscopic = true;
} settings;
uf::Camera& camera = this->getComponent<uf::Camera>();
@ -86,8 +87,8 @@ void ext::Player::initialize() {
camera.setFov(settings.perspective.fov);
camera.setBounds(settings.perspective.bounds);
}
camera.setStereoscopic(true);
settings.offset.x = metadata["camera"]["offset"][0].asDouble();
settings.offset.y = metadata["camera"]["offset"][1].asDouble();
@ -98,6 +99,10 @@ void ext::Player::initialize() {
transform.position.x = metadata["camera"]["position"][0].asDouble();
transform.position.y = metadata["camera"]["position"][1].asDouble();
transform.position.z = metadata["camera"]["position"][2].asDouble();
transform.scale.x = metadata["camera"]["scale"][0].asDouble();
transform.scale.y = metadata["camera"]["scale"][1].asDouble();
transform.scale.z = metadata["camera"]["scale"][2].asDouble();
}
camera.setOffset(settings.offset);
@ -318,14 +323,17 @@ void ext::Player::tick() {
if ( ext::openvr::context ) {
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadUp" )["state"].asBool() ) keys.forward = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadDown" )["state"].asBool() ) keys.backwards = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadLeft" )["state"].asBool() ) keys.lookLeft = true; //keys.left = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadRight" )["state"].asBool() ) keys.lookRight = true; //keys.right = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadLeft" )["state"].asBool() ) keys.left = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadRight" )["state"].asBool() ) keys.right = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "thumbclick" )["state"].asBool() ) keys.running = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "a" )["state"].asBool() ) keys.jump = true;
// if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadUp" )["state"].asBool() ) keys.forward = true;
// if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadDown" )["state"].asBool() ) keys.backwards = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadUp" )["state"].asBool() ) keys.forward = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadDown" )["state"].asBool() ) keys.backwards = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadLeft" )["state"].asBool() ) keys.lookLeft = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadRight" )["state"].asBool() ) keys.lookRight = true;
// std::cout << ext::openvr::controllerState( vr::Controller_Hand::Hand_Right ) << std::endl;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "thumbclick" )["state"].asBool() ) keys.crouch = true, keys.walk = true;
if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "a" )["state"].asBool() ) keys.paused = true;
}
struct {
@ -339,22 +347,32 @@ void ext::Player::tick() {
stats.menu = metadata["system"]["menu"].asString();
struct {
float move = 4; //uf::physics::time::delta * 4;
float rotate = uf::physics::time::delta * 1.25f;
float move = 4;
float walk = 1;
float run = 8;
float rotate = uf::physics::time::delta;
float limitSquared = 4*4;
} speed;
} speed; {
speed.rotate *= metadata["system"]["physics"]["rotate"].asFloat();
speed.move = metadata["system"]["physics"]["move"].asFloat();
speed.run = metadata["system"]["physics"]["run"].asFloat() / metadata["system"]["physics"]["move"].asFloat();
speed.walk = metadata["system"]["physics"]["walk"].asFloat() / metadata["system"]["physics"]["move"].asFloat();
}
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( keys.vee ) {
if ( timer.elapsed().asDouble() >= 0.25 ) {
timer.reset();
metadata["collision"]["should"] = !metadata["collision"]["should"].asBool();
metadata["system"]["physics"]["collision"] = !metadata["system"]["physics"]["collision"].asBool();
physics.linear.velocity = {0,0,0};
}
}
if ( keys.running ) speed.move *= 2;
else if ( keys.walk ) speed.move /= 4;
if ( keys.running ) speed.move *= speed.run;
else if ( keys.walk ) speed.move *= speed.walk;
speed.limitSquared = speed.move * speed.move;
uf::Object* menu = (uf::Object*) this->getRootParent().findByName("Gui: Menu");
@ -382,7 +400,7 @@ void ext::Player::tick() {
// translator.orientation = uf::quaternion::multiply( transform.orientation * pod::Vector4f{1,1,1,-1}, ext::openvr::hmdQuaternion() * pod::Vector4f{1,1,1,-1} );
// translator.orientation = uf::quaternion::multiply( ext::openvr::hmdQuaternion(), transform.orientation );
//translator.orientation = ext::openvr::hmdQuaternion();
bool useController = true;
bool useController = false;
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 = uf::transform::reorient( translator );
{
@ -437,15 +455,15 @@ void ext::Player::tick() {
physics.linear.velocity.z = correction.z;
stats.updateCamera = (stats.walking = true);
}
if ( keys.jump && metadata["collision"]["jump"] != Json::nullValue ) {
if ( !metadata["collision"]["should"].asBool() ) {
if ( metadata["collision"]["jump"][0].asFloat() != 0 ) transform.position.x += metadata["collision"]["jump"][0].asFloat() * uf::physics::time::delta;
if ( metadata["collision"]["jump"][1].asFloat() != 0 ) transform.position.y += metadata["collision"]["jump"][1].asFloat() * uf::physics::time::delta;
if ( metadata["collision"]["jump"][2].asFloat() != 0 ) transform.position.z += metadata["collision"]["jump"][2].asFloat() * uf::physics::time::delta;
if ( keys.jump ) {
if ( !metadata["system"]["physics"]["collision"].asBool() ) {
if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) transform.position.x += metadata["system"]["physics"]["jump"][0].asFloat() * uf::physics::time::delta;
if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) transform.position.y += metadata["system"]["physics"]["jump"][1].asFloat() * uf::physics::time::delta;
if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) transform.position.z += metadata["system"]["physics"]["jump"][2].asFloat() * uf::physics::time::delta;
} else {
if ( metadata["collision"]["jump"][0].asFloat() != 0 ) physics.linear.velocity.x = metadata["collision"]["jump"][0].asFloat();
if ( metadata["collision"]["jump"][1].asFloat() != 0 ) physics.linear.velocity.y = metadata["collision"]["jump"][1].asFloat();
if ( metadata["collision"]["jump"][2].asFloat() != 0 ) physics.linear.velocity.z = metadata["collision"]["jump"][2].asFloat();
if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) physics.linear.velocity.x = metadata["system"]["physics"]["jump"][0].asFloat();
if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) physics.linear.velocity.y = metadata["system"]["physics"]["jump"][1].asFloat();
if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) physics.linear.velocity.z = metadata["system"]["physics"]["jump"][2].asFloat();
}
}
}
@ -458,10 +476,10 @@ void ext::Player::tick() {
}
if ( keys.crouch ) {
if ( !metadata["collision"]["should"].asBool() ) {
if ( metadata["collision"]["jump"][0].asFloat() != 0 ) transform.position.x -= metadata["collision"]["jump"][0].asFloat() * uf::physics::time::delta;
if ( metadata["collision"]["jump"][1].asFloat() != 0 ) transform.position.y -= metadata["collision"]["jump"][1].asFloat() * uf::physics::time::delta;
if ( metadata["collision"]["jump"][2].asFloat() != 0 ) transform.position.z -= metadata["collision"]["jump"][2].asFloat() * uf::physics::time::delta;
if ( !metadata["system"]["physics"]["collision"].asBool() ) {
if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) transform.position.x -= metadata["system"]["physics"]["jump"][0].asFloat() * uf::physics::time::delta;
if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) transform.position.y -= metadata["system"]["physics"]["jump"][1].asFloat() * uf::physics::time::delta;
if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) transform.position.z -= metadata["system"]["physics"]["jump"][2].asFloat() * uf::physics::time::delta;
} else {
if ( !metadata["system"]["crouching"].asBool() ) stats.deltaCrouch = true;
metadata["system"]["crouching"] = true;
@ -472,7 +490,7 @@ void ext::Player::tick() {
}
}
if ( stats.deltaCrouch ) {
float delta = 1.0f;
float delta = metadata["system"]["physics"]["crouch"].asFloat();
if ( metadata["system"]["crouching"].asBool() ) camera.getTransform().position.y -= delta;
else camera.getTransform().position.y += delta;
stats.updateCamera = true;
@ -495,7 +513,7 @@ void ext::Player::tick() {
footstep.setVolume(0.1f);
footstep.setPosition( transform.position );
}
} else {
} else if ( !keys.jump ) {
physics.linear.velocity.x = 0;
physics.linear.velocity.y = 0;
physics.linear.velocity.z = 0;

View File

@ -6,6 +6,7 @@
#include "..//sprite.h"
#include <uf/engine/asset/asset.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/thread/thread.h>
#include <uf/utils/math/collision.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/graphic/mesh.h>
@ -54,7 +55,8 @@ void ext::Region::initialize() {
graphic.process = false;
auto& texture = graphic.material.textures.emplace_back();
texture.sampler.filter = VK_FILTER_NEAREST;
texture.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
texture.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
texture.loadFromFile( textureFilename );
std::string suffix = ""; {
@ -83,9 +85,9 @@ void ext::Region::initialize() {
generator.generate(*this);
generator.updateLight();
/* Collider */ {
/* Collider */ if ( false ) {
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
uf::CollisionBody& collider = this->getComponent<uf::CollisionBody>();
uf::Collider& collider = this->getComponent<uf::Collider>();
std::size_t i = 0;
const auto& voxels = generator.getVoxels();
@ -108,8 +110,7 @@ void ext::Region::initialize() {
if ( !voxel.solid() ) continue;
uf::Collider* box = new uf::AABBox( offset, {0.5, 0.5, 0.5} );
collider.add(box);
collider.add(new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ));
}
}
}
@ -200,12 +201,16 @@ void ext::Region::initialize() {
}
if ( should ) {
uf::Entity* light = this->findByUid(this->loadChild("./light.json", true));
uf::Serializer& metadata = light->getComponent<uf::Serializer>();
pod::Transform<>& lTransform = light->getComponent<pod::Transform<>>();
lTransform.position = transform.position;
metadata["light"]["color"][0] = r;
metadata["light"]["color"][1] = r;
metadata["light"]["color"][2] = r;
if ( light ) {
uf::Serializer& metadata = light->getComponent<uf::Serializer>();
pod::Transform<>& lTransform = light->getComponent<pod::Transform<>>();
lTransform.position += transform.position;
if ( !metadata["light"].isArray() ) {
metadata["light"]["color"][0] = (rand() % 100) / 100.0;
metadata["light"]["color"][1] = (rand() % 100) / 100.0;
metadata["light"]["color"][2] = (rand() % 100) / 100.0;
}
}
}
}
// add mobs
@ -273,6 +278,139 @@ void ext::Region::initialize() {
}
void ext::Region::tick() {
uf::Object::tick();
// do collision on children
#if 1
{
bool local = false;
bool sort = false;
bool useStrongest = true;
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return;
if ( entity->hasComponent<uf::Collider>() )
entities.push_back((uf::Object*) entity);
};
this->process(filter);
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
uf::Serializer payload;
payload["normal"][0] = manifold.normal.x;
payload["normal"][1] = manifold.normal.y;
payload["normal"][2] = manifold.normal.z;
payload["entity"] = b->getUid();
payload["depth"] = -manifold.depth;
a->callHook("world:Collision.%UID%", payload);
payload["entity"] = a->getUid();
payload["depth"] = manifold.depth;
b->callHook("world:Collision.%UID%", payload);
/*
pod::Transform<>& transform = b->getComponent<pod::Transform<>>();
pod::Physics& physics = b->getComponent<pod::Physics>();
uf::Serializer payload;
pod::Vector3 correction = uf::vector::normalize(manifold.normal) * manifold.depth;
transform.position -= correction;
if ( manifold.normal.x == 1 || manifold.normal.x == -1 ) physics.linear.velocity.x = 0;
if ( manifold.normal.y == 1 || manifold.normal.y == -1 ) physics.linear.velocity.y = 0;
if ( manifold.normal.z == 1 || manifold.normal.z == -1 ) physics.linear.velocity.z = 0;
*/
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
// collide with world
auto& metadata = this->getComponent<uf::Serializer>();
auto& generator = this->getComponent<ext::TerrainGenerator>();
auto& regionPosition = this->getComponent<pod::Transform<>>().position;
pod::Vector3f size; {
size.x = metadata["region"]["size"][0].asUInt();
size.y = metadata["region"]["size"][1].asUInt();
size.z = metadata["region"]["size"][2].asUInt();
}
for ( auto* _ : entities ) {
uf::Object& entity = *_;
auto& transform = entity.getComponent<pod::Transform<>>();
pod::Vector3f voxelPosition = transform.position - regionPosition;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
uf::Collider collider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y - 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y + 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = regionPosition;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
collider.add( new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ) );
/*
uf::BaseMesh<pod::Vertex_3F> mesh;
const ext::TerrainVoxel::Model& model = voxel.model();
#define TERRAIN_SHOULD_RENDER_FACE(SIDE)\
for ( uint i = 0; i < model.position.SIDE.size() / 3; ++i ) {\
auto& vertex = mesh.vertices.emplace_back();\
{\
pod::Vector3f& p = vertex.position;\
p.x = model.position.SIDE[i*3+0]; p.y = model.position.SIDE[i*3+1]; p.z = model.position.SIDE[i*3+2];\
p.x += offset.x; p.y += offset.y; p.z += offset.z;\
}\
}
TERRAIN_SHOULD_RENDER_FACE(left)
TERRAIN_SHOULD_RENDER_FACE(right)
TERRAIN_SHOULD_RENDER_FACE(top)
TERRAIN_SHOULD_RENDER_FACE(bottom)
TERRAIN_SHOULD_RENDER_FACE(back)
TERRAIN_SHOULD_RENDER_FACE(front)
uf::MeshCollider* mCollider = new uf::MeshCollider();
mCollider->setPositions( mesh );
pCollider.add(mCollider);
*/
}
testColliders( collider, entity.getComponent<uf::Collider>(), this, &entity, useStrongest );
}
// collide with others
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
testColliders( entityA.getComponent<uf::Collider>(), entityB.getComponent<uf::Collider>(), &entityA, &entityB, useStrongest );
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
#endif
}
void ext::Region::destroy() {
auto& graphic = this->getComponent<uf::Graphic>();
@ -289,11 +427,11 @@ void ext::Region::render( ) {
uf::Object::render();
if ( !metadata["region"]["rasterized"].asBool() ) return;
/* Update uniforms */ if ( this->hasComponent<ext::TerrainGenerator::mesh_t>() ) {
auto& world = this->getRootParent<uf::Scene>();
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = this->getRootParent<uf::Scene>();
auto& mesh = this->getComponent<ext::TerrainGenerator::mesh_t>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& camera = world.getController()->getComponent<uf::Camera>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
// auto& uniforms = graphic.uniforms<uf::StereoMeshDescriptor>();
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();

View File

@ -1,4 +1,5 @@
#include "terrain.h"
#include "generator.h"
#include "../../../ext.h"
#include <uf/engine/asset/asset.h>
@ -10,6 +11,7 @@
#include <uf/utils/graphic/mesh.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/math/collision.h>
#include <uf/utils/thread/thread.h>
#include <uf/ext/vulkan/graphic.h>
#include <uf/ext/vulkan/vulkan.h>
@ -145,7 +147,150 @@ void ext::Terrain::tick() {
// multipurpose timer
static uf::Timer<long long> timer(false);
// do collision on children
#if 0
{
bool local = false;
bool sort = false;
bool useStrongest = false;
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return;
if ( entity->hasComponent<uf::Collider>() )
entities.push_back((uf::Object*) entity);
};
this->process(filter);
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
uf::Serializer payload;
payload["normal"][0] = manifold.normal.x;
payload["normal"][1] = manifold.normal.y;
payload["normal"][2] = manifold.normal.z;
payload["entity"] = b->getUid();
payload["depth"] = -manifold.depth;
a->callHook("world:Collision.%UID%", payload);
payload["entity"] = a->getUid();
payload["depth"] = manifold.depth;
b->callHook("world:Collision.%UID%", payload);
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
// collide with world
for ( auto* _ : entities ) {
uf::Object& entity = *_;
auto& transform = entity.getComponent<pod::Transform<>>();
pod::Vector3f size; {
size.x = metadata["region"]["size"][0].asUInt();
size.y = metadata["region"]["size"][1].asUInt();
size.z = metadata["region"]["size"][2].asUInt();
}
uf::Entity* regionPointer = _;
while ( regionPointer->getName() != "Region" ) {
regionPointer = &regionPointer->getParent();
if ( regionPointer->getUid() == 0 ) break;
if ( regionPointer->getUid() == this->getUid() ) break;
}
if ( regionPointer == this ) continue;
if ( regionPointer->getUid() == 0 ) continue;
if ( regionPointer->getName() != "Region" ) continue;
if ( !regionPointer ) continue;
ext::Region& region = *(ext::Region*) regionPointer;
/*
pod::Vector3f pointf = transform.position / size;
pod::Vector3i point = {
(int) (pointf.x + (pointf.x > 0 ? 0.5 : -0.5)),
(int) (pointf.y + (pointf.y > 0 ? 0.5 : -0.5)),
(int) (pointf.z + (pointf.z > 0 ? 0.5 : -0.5)),
};
// std::cout << entity.getName() << ": " << entity.getUid() << ": " << point.x << ", " << point.y << ", " << point.z << std::endl;
if ( !this->exists(point) ) continue;
ext::Region* regionPointer = this->at(point);
if ( !regionPointer ) continue;
ext::Region& region = *regionPointer;
*/
auto& generator = region.getComponent<ext::TerrainGenerator>();
auto& regionPosition = region.getComponent<pod::Transform<>>().position;
pod::Vector3f voxelPosition = transform.position - regionPosition;
voxelPosition.x += size.x / 2.0f;
voxelPosition.y += size.y / 2.0f + 1;
voxelPosition.z += size.z / 2.0f;
uf::Collider collider;
std::vector<pod::Vector3ui> positions = {
{ voxelPosition.x, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x - 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x + 1, voxelPosition.y, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y - 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y + 1, voxelPosition.z },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z - 1 },
{ voxelPosition.x, voxelPosition.y, voxelPosition.z + 1},
};
for ( auto& position : positions ) {
ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( generator.getVoxel( position.x, position.y, position.z ) );
pod::Vector3 offset = regionPosition;
offset.x += position.x - (size.x / 2.0f);
offset.y += position.y - (size.y / 2.0f);
offset.z += position.z - (size.z / 2.0f);
if ( !voxel.solid() ) continue;
collider.add( new uf::BoundingBox( offset, {0.5, 0.5, 0.5} ) );
/*
uf::BaseMesh<pod::Vertex_3F> mesh;
const ext::TerrainVoxel::Model& model = voxel.model();
#define TERRAIN_SHOULD_RENDER_FACE(SIDE)\
for ( uint i = 0; i < model.position.SIDE.size() / 3; ++i ) {\
auto& vertex = mesh.vertices.emplace_back();\
{\
pod::Vector3f& p = vertex.position;\
p.x = model.position.SIDE[i*3+0]; p.y = model.position.SIDE[i*3+1]; p.z = model.position.SIDE[i*3+2];\
p.x += offset.x; p.y += offset.y; p.z += offset.z;\
}\
}
TERRAIN_SHOULD_RENDER_FACE(left)
TERRAIN_SHOULD_RENDER_FACE(right)
TERRAIN_SHOULD_RENDER_FACE(top)
TERRAIN_SHOULD_RENDER_FACE(bottom)
TERRAIN_SHOULD_RENDER_FACE(back)
TERRAIN_SHOULD_RENDER_FACE(front)
uf::MeshCollider* mCollider = new uf::MeshCollider();
mCollider->setPositions( mesh );
pCollider.add(mCollider);
*/
}
testColliders( collider, entity.getComponent<uf::Collider>(), &region, &entity, useStrongest );
}
// collide with others
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
testColliders( entityA.getComponent<uf::Collider>(), entityB.getComponent<uf::Collider>(), &entityA, &entityB, useStrongest );
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
#endif
// open gamestate, look for work
if ( metadata["system"]["state"] == "open" ) { transitionResolvingState(*this);
// cleanup orphans

View File

@ -293,12 +293,8 @@ void ext::World::tick() {
ext::oal.listener( "VELOCITY", { 0, 0, 0 } );
ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } );
}
}
void ext::World::render() {
uf::Scene::render();
/* Update lights */ {
/**/ if ( false ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
auto& scene = *this;
std::vector<ext::vulkan::Graphic*> blitters;
@ -311,128 +307,14 @@ void ext::World::render() {
auto* renderModePointer = (ext::vulkan::DeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitter);
}
auto& controller = *scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
// auto& uniforms = blitter.uniforms;
struct UniformDescriptor {
struct Matrices {
alignas(16) pod::Matrix4f view[2];
alignas(16) pod::Matrix4f projection[2];
} matrices;
alignas(16) pod::Vector4f ambient;
struct Light {
alignas(16) pod::Vector4f position;
alignas(16) pod::Vector4f color;
} lights;
};
struct SpecializationConstant {
int32_t maxLights = 32;
} specializationConstants;
for ( size_t _ = 0; _ < blitters.size(); ++_ ) {
auto& blitter = *blitters[_];
uint8_t* buffer;
size_t len;
auto* shader = &blitter.material.shaders.front();
for ( auto& _ : blitter.material.shaders ) {
if ( _.uniforms.empty() ) continue;
auto& userdata = _.uniforms.front();
buffer = (uint8_t*) (void*) userdata;
len = userdata.data().len;
shader = &_;
specializationConstants = _.specializationConstants.get<SpecializationConstant>();
}
if ( !buffer ) continue;
UniformDescriptor* uniforms = (UniformDescriptor*) buffer;
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms->matrices.view[i] = camera.getView( i );
uniforms->matrices.projection[i] = camera.getProjection( i );
}
{
uniforms->ambient.x = metadata["light"]["ambient"][0].asFloat();
uniforms->ambient.y = metadata["light"]["ambient"][1].asFloat();
uniforms->ambient.z = metadata["light"]["ambient"][2].asFloat();
uniforms->ambient.w = metadata["light"]["kexp"].asFloat();
}
{
std::vector<uf::Entity*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity || entity->getName() != "Light" ) return;
entities.push_back(entity);
};
for ( uf::Scene* scene : ext::vulkan::scenes ) { if ( !scene ) continue;
scene->process(filter);
}
{
const pod::Vector3& position = controller.getComponent<pod::Transform<>>().position;
std::sort( entities.begin(), entities.end(), [&]( const uf::Entity* l, const uf::Entity* r ){
if ( !l ) return false; if ( !r ) return true;
if ( !l->hasComponent<pod::Transform<>>() ) return false; if ( !r->hasComponent<pod::Transform<>>() ) return true;
return uf::vector::magnitude( uf::vector::subtract( l->getComponent<pod::Transform<>>().position, position ) ) < uf::vector::magnitude( uf::vector::subtract( r->getComponent<pod::Transform<>>().position, position ) );
} );
}
{
uf::Serializer& metadata = controller.getComponent<uf::Serializer>();
if ( metadata["light"]["should"].asBool() ) {
entities.push_back(&controller);
}
}
UniformDescriptor::Light* lights = (UniformDescriptor::Light*) &buffer[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Light)];
for ( size_t i = 0; i < specializationConstants.maxLights; ++i ) {
UniformDescriptor::Light& light = lights[i];
light.position = { 0, 0, 0, 0 };
light.color = { 0, 0, 0, 0 };
}
for ( size_t i = 0; i < specializationConstants.maxLights && i < entities.size(); ++i ) {
UniformDescriptor::Light& light = lights[i];
uf::Entity* entity = entities[i];
pod::Transform<>& transform = entity->getComponent<pod::Transform<>>();
uf::Serializer& metadata = entity->getComponent<uf::Serializer>();
light.position.x = transform.position.x;
light.position.y = transform.position.y;
light.position.z = transform.position.z;
if ( entity == &controller ) {
light.position.y += 2;
}
light.position.w = metadata["light"]["power"].asFloat();
light.color.x = metadata["light"]["color"][0].asFloat();
light.color.y = metadata["light"]["color"][1].asFloat();
light.color.z = metadata["light"]["color"][2].asFloat();
light.color.w = metadata["light"]["radius"].asFloat();
}
}
// blitter.updateBuffer( (void*) buffer, blitter.uniforms.data().len, 0, false );
shader->updateBuffer( (void*) buffer, len, 0, false );
blitter.getPipeline().update( blitter );
}
}
}
uf::Entity* ext::World::getController() {
if ( ext::vulkan::currentRenderMode ) {
auto& renderMode = *ext::vulkan::currentRenderMode;
std::string name = renderMode.name;
auto split = uf::string::split( name, ": " );
if ( split.front() == "Render Target" ) {
uint64_t uid = std::stoi( split.back() );
uf::Entity* ent = this->findByUid( uid );
if ( ent ) return ent;
}
}
return uf::Scene::getController();
}
const uf::Entity* ext::World::getController() const {
return uf::Scene::getController();
void ext::World::render() {
uf::Scene::render();
}

View File

@ -12,8 +12,5 @@ namespace ext {
virtual void initialize();
virtual void tick();
virtual void render();
virtual uf::Entity* getController();
virtual const uf::Entity* getController() const;
};
}