LumixEngine/src/renderer/render_scene.cpp

3026 lines
81 KiB
C++
Raw Normal View History

2014-06-16 21:18:15 +02:00
#include "render_scene.h"
2014-08-20 22:45:47 +02:00
2016-05-10 08:24:31 +02:00
#include "engine/array.h"
2019-06-21 17:14:06 +02:00
#include "engine/associative_array.h"
#include "engine/crc32.h"
#include "engine/crt.h"
2017-02-24 15:20:58 +01:00
#include "engine/engine.h"
2019-06-11 22:39:39 +02:00
#include "engine/file_system.h"
2016-05-10 08:24:31 +02:00
#include "engine/geometry.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
2019-06-13 17:26:52 +02:00
#include "engine/math.h"
2019-06-11 22:39:39 +02:00
#include "engine/os.h"
2019-07-04 18:21:35 +02:00
#include "engine/page_allocator.h"
2016-05-10 08:24:31 +02:00
#include "engine/profiler.h"
2017-11-19 14:04:10 +01:00
#include "engine/reflection.h"
2016-05-10 08:24:31 +02:00
#include "engine/resource_manager.h"
2019-06-11 22:39:39 +02:00
#include "engine/stream.h"
2020-02-21 22:09:11 +01:00
#include "engine/universe.h"
2015-08-17 23:45:26 +02:00
#include "renderer/culling_system.h"
2019-06-26 18:52:52 +02:00
#include "renderer/font.h"
2015-08-17 23:45:26 +02:00
#include "renderer/material.h"
#include "renderer/model.h"
2015-10-30 21:11:11 +01:00
#include "renderer/particle_system.h"
#include "renderer/pipeline.h"
2015-10-06 17:00:52 +02:00
#include "renderer/pose.h"
2015-08-17 23:45:26 +02:00
#include "renderer/renderer.h"
#include "renderer/terrain.h"
#include "renderer/texture.h"
2014-06-16 21:18:15 +02:00
namespace Lumix
{
2015-07-24 22:38:11 +02:00
2017-01-24 16:56:42 +01:00
enum class RenderSceneVersion : int
{
LATEST
};
2018-07-29 10:53:13 +02:00
static const ComponentType MODEL_INSTANCE_TYPE = Reflection::getComponentType("model_instance");
2017-11-19 14:04:10 +01:00
static const ComponentType DECAL_TYPE = Reflection::getComponentType("decal");
static const ComponentType POINT_LIGHT_TYPE = Reflection::getComponentType("point_light");
static const ComponentType PARTICLE_EMITTER_TYPE = Reflection::getComponentType("particle_emitter");
static const ComponentType ENVIRONMENT_TYPE = Reflection::getComponentType("environment");
2017-11-19 14:04:10 +01:00
static const ComponentType CAMERA_TYPE = Reflection::getComponentType("camera");
static const ComponentType TERRAIN_TYPE = Reflection::getComponentType("terrain");
static const ComponentType BONE_ATTACHMENT_TYPE = Reflection::getComponentType("bone_attachment");
static const ComponentType ENVIRONMENT_PROBE_TYPE = Reflection::getComponentType("environment_probe");
2019-11-11 21:30:12 +01:00
static const ComponentType LIGHT_PROBE_GRID_TYPE = Reflection::getComponentType("light_probe_grid");
2018-01-30 21:39:21 +01:00
static const ComponentType TEXT_MESH_TYPE = Reflection::getComponentType("text_mesh");
2016-06-22 00:46:48 +02:00
2014-06-16 21:18:15 +02:00
struct Decal
2016-07-22 13:57:52 +02:00
{
Material* material = nullptr;
Transform transform;
float radius;
2018-08-19 17:35:37 +02:00
EntityRef entity;
2018-10-13 15:08:58 +02:00
EntityPtr prev_decal = INVALID_ENTITY;
EntityPtr next_decal = INVALID_ENTITY;
2018-10-10 23:41:26 +02:00
Vec3 half_extents;
2016-07-22 13:57:52 +02:00
};
2016-05-02 21:41:18 +02:00
struct BoneAttachment
{
2018-08-19 17:35:37 +02:00
EntityRef entity;
EntityPtr parent_entity;
2016-05-02 21:41:18 +02:00
int bone_index;
2018-09-20 23:17:45 +02:00
LocalRigidTransform relative_transform;
2016-05-02 21:41:18 +02:00
};
2018-01-30 21:39:21 +01:00
struct TextMesh
{
enum Flags : u32
{
CAMERA_ORIENTED = 1 << 0
};
2018-01-30 21:39:21 +01:00
TextMesh(IAllocator& allocator) : text("", allocator) {}
2018-02-19 14:10:11 +01:00
~TextMesh() { setFontResource(nullptr); }
void setFontResource(FontResource* res)
{
if (m_font_resource)
{
if (m_font)
{
m_font_resource->removeRef(*m_font);
m_font = nullptr;
}
2020-01-07 19:17:48 +01:00
m_font_resource->getObserverCb().unbind<&TextMesh::onFontLoaded>(this);
2018-02-19 14:10:11 +01:00
m_font_resource->getResourceManager().unload(*m_font_resource);
}
m_font_resource = res;
2020-01-07 19:17:48 +01:00
if (res) res->onLoaded<&TextMesh::onFontLoaded>(this);
2018-02-19 14:10:11 +01:00
}
void onFontLoaded(Resource::State, Resource::State new_state, Resource&)
{
if (new_state != Resource::State::READY)
{
m_font = nullptr;
}
else
{
m_font = m_font_resource->addRef(m_font_size);
}
}
void setFontSize(int value)
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
m_font_size = value;
if (m_font_resource && m_font_resource->isReady())
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
if(m_font) m_font_resource->removeRef(*m_font);
m_font = m_font_resource->addRef(m_font_size);
2018-01-30 21:39:21 +01:00
}
}
2018-02-19 14:10:11 +01:00
FontResource* getFontResource() const { return m_font_resource; }
Font* getFont() const { return m_font; }
int getFontSize() const { return m_font_size; }
2019-06-21 17:14:06 +02:00
String text;
2018-01-30 21:39:21 +01:00
u32 color = 0xff000000;
FlagSet<Flags, u32> m_flags;
2018-02-19 14:10:11 +01:00
private:
int m_font_size = 13;
Font* m_font = nullptr;
FontResource* m_font_resource = nullptr;
2018-01-30 21:39:21 +01:00
};
2018-09-29 15:14:46 +02:00
static RenderableTypes getRenderableType(const Model& model)
{
ASSERT(model.isReady());
if (model.isSkinned()) return RenderableTypes::SKINNED;
if (model.getMeshCount() > 1) return RenderableTypes::MESH_GROUP;
return RenderableTypes::MESH;
}
2020-02-21 22:09:11 +01:00
struct RenderSceneImpl final : RenderScene
2015-07-21 20:10:50 +02:00
{
public:
RenderSceneImpl(Renderer& renderer,
Engine& engine,
Universe& universe,
2016-07-21 14:23:46 +02:00
IAllocator& allocator);
2015-07-21 20:10:50 +02:00
~RenderSceneImpl()
{
2020-01-07 19:17:48 +01:00
m_universe.entityTransformed().unbind<&RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().unbind<&RenderSceneImpl::onEntityDestroyed>(this);
2016-07-24 15:44:37 +02:00
CullingSystem::destroy(*m_culling_system);
}
2018-10-13 15:08:58 +02:00
void decalMaterialStateChanged(Resource::State old_state, Resource::State new_state, Resource& resource)
{
Material& material = static_cast<Material&>(resource);
if (new_state == Resource::State::READY) {
auto map_iter = m_material_decal_map.find(&material);
EntityPtr e = map_iter.value();
while(e.isValid()) {
const float radius = m_decals[(EntityRef)e].half_extents.length();
const DVec3 pos = m_universe.getPosition((EntityRef)e);
m_culling_system->add((EntityRef)e, (u8)RenderableTypes::DECAL, pos, radius);
e = m_decals[(EntityRef)e].next_decal;
}
return;
}
2018-12-24 16:15:22 +01:00
if (old_state == Resource::State::READY) {
2018-10-13 15:08:58 +02:00
auto map_iter = m_material_decal_map.find(&material);
EntityPtr e = map_iter.value();
while(e.isValid()) {
m_culling_system->remove((EntityRef)e);
e = m_decals[(EntityRef)e].next_decal;
}
}
}
2016-07-25 02:00:22 +02:00
void modelStateChanged(Resource::State old_state, Resource::State new_state, Resource& resource)
{
Model* model = static_cast<Model*>(&resource);
if (new_state == Resource::State::READY)
{
modelLoaded(model);
}
2018-12-24 16:15:22 +01:00
else if (old_state == Resource::State::READY)
2016-07-25 02:00:22 +02:00
{
modelUnloaded(model);
}
}
2016-07-24 15:44:37 +02:00
void clear() override
{
auto& rm = m_engine.getResourceManager();
2019-06-12 18:23:23 +02:00
auto* material_manager = rm.get(Material::TYPE);
2018-02-19 14:10:11 +01:00
for (TextMesh* text_mesh : m_text_meshes)
{
LUMIX_DELETE(m_allocator, text_mesh);
}
2018-01-30 21:39:21 +01:00
m_text_meshes.clear();
2016-07-22 13:57:52 +02:00
for (Decal& decal : m_decals)
{
2016-07-24 15:44:37 +02:00
if (decal.material) material_manager->unload(*decal.material);
2016-07-22 13:57:52 +02:00
}
2016-07-24 15:44:37 +02:00
m_decals.clear();
2016-07-22 13:57:52 +02:00
2016-08-02 21:34:22 +02:00
m_cameras.clear();
for (auto* terrain : m_terrains)
2015-07-21 20:10:50 +02:00
{
LUMIX_DELETE(m_allocator, terrain);
2015-10-30 21:11:11 +01:00
}
2016-07-24 15:44:37 +02:00
m_terrains.clear();
2015-10-30 21:11:11 +01:00
2018-08-22 19:52:08 +02:00
for (auto* emitter : m_particle_emitters)
2017-10-24 17:18:53 +02:00
{
LUMIX_DELETE(m_allocator, emitter);
}
2018-08-22 19:52:08 +02:00
m_particle_emitters.clear();
2015-01-04 15:05:20 +01:00
for (ModelInstance& i : m_model_instances)
2015-07-21 20:10:50 +02:00
{
if (i.flags.isSet(ModelInstance::VALID) && i.model)
2014-06-16 21:18:15 +02:00
{
2016-07-25 01:02:36 +02:00
i.model->getResourceManager().unload(*i.model);
LUMIX_DELETE(m_allocator, i.pose);
i.pose = nullptr;
2015-07-21 20:10:50 +02:00
}
}
m_model_instances.clear();
2018-09-09 14:31:00 +02:00
for(auto iter = m_model_entity_map.begin(), end = m_model_entity_map.end(); iter != end; ++iter) {
Model* model = iter.key();
2020-01-07 19:17:48 +01:00
model->getObserverCb().unbind<&RenderSceneImpl::modelStateChanged>(this);
2018-09-09 14:31:00 +02:00
}
m_model_entity_map.clear();
2018-10-13 15:08:58 +02:00
for(auto iter = m_material_decal_map.begin(), end = m_material_decal_map.end(); iter != end; ++iter) {
Material* mat = iter.key();
2020-01-07 19:17:48 +01:00
mat->getObserverCb().unbind<&RenderSceneImpl::decalMaterialStateChanged>(this);
2018-10-13 15:08:58 +02:00
}
m_material_decal_map.clear();
2016-07-24 15:44:37 +02:00
m_culling_system->clear();
2014-10-15 20:46:01 +02:00
for (auto& probe : m_environment_probes)
2016-06-12 15:26:41 +02:00
{
2019-11-14 22:26:43 +01:00
if (probe.reflection) probe.reflection->getResourceManager().unload(*probe.reflection);
2017-02-28 21:18:37 +01:00
if (probe.radiance) probe.radiance->getResourceManager().unload(*probe.radiance);
2016-06-12 15:26:41 +02:00
}
2019-11-24 00:30:34 +01:00
for (auto& lpg : m_light_probe_grids)
{
for (Texture* t : lpg.data) {
if (t) t->getResourceManager().unload(*t);
}
}
2016-07-24 15:44:37 +02:00
m_environment_probes.clear();
2015-07-21 20:10:50 +02:00
}
2014-10-15 20:46:01 +02:00
2014-08-20 22:45:47 +02:00
Universe& getUniverse() override { return m_universe; }
2014-11-05 19:01:56 +01:00
2014-06-16 21:18:15 +02:00
IPlugin& getPlugin() const override { return m_renderer; }
2015-01-04 15:05:20 +01:00
2018-08-19 17:35:37 +02:00
void getRay(EntityRef camera_entity,
2017-10-04 10:47:31 +02:00
const Vec2& screen_pos,
2018-09-16 18:35:57 +02:00
DVec3& origin,
Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
2018-09-20 23:17:45 +02:00
Camera& camera = m_cameras[camera_entity];
2018-01-12 17:01:26 +01:00
origin = m_universe.getPosition(camera_entity);
2016-04-17 21:47:54 +02:00
float width = camera.screen_width;
float height = camera.screen_height;
if (width <= 0 || height <= 0)
{
2018-01-12 17:01:26 +01:00
dir = m_universe.getRotation(camera_entity).rotate(Vec3(0, 0, 1));
2016-04-17 21:47:54 +02:00
return;
}
2017-10-04 10:47:31 +02:00
float nx = 2 * (screen_pos.x / width) - 1;
float ny = 2 * ((height - screen_pos.y) / height) - 1;
2015-07-21 20:10:50 +02:00
2018-09-16 18:35:57 +02:00
const Matrix projection_matrix = getCameraProjection(camera_entity);
2018-09-20 23:17:45 +02:00
const Transform view = m_universe.getTransform(camera_entity);
2016-04-17 21:47:54 +02:00
2018-09-20 23:17:45 +02:00
if (camera.is_ortho) {
const float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
origin += view.rot * Vec3(1, 0, 0) * nx * camera.ortho_size * ratio
+ view.rot * Vec3(0, 1, 0) * ny * camera.ortho_size;
2016-04-17 21:47:54 +02:00
}
2015-07-21 20:10:50 +02:00
2018-09-20 23:17:45 +02:00
Matrix inv_projection = projection_matrix;
inv_projection.inverse();
2016-04-17 21:47:54 +02:00
2018-09-20 23:17:45 +02:00
Vec4 p0 = inv_projection * Vec4(nx, ny, -1, 1);
Vec4 p1 = inv_projection * Vec4(nx, ny, 1, 1);
2016-04-17 21:47:54 +02:00
p0 *= 1 / p0.w;
p1 *= 1 / p1.w;
2018-03-11 18:19:01 +01:00
dir = (p1 - p0).xyz();
2018-09-20 23:17:45 +02:00
dir.normalize();
dir = view.rot * dir;
2015-07-21 20:10:50 +02:00
}
2014-08-21 01:22:57 +02:00
2018-08-22 19:52:08 +02:00
EntityPtr getActiveCamera() const override
{
return m_active_camera;
}
Viewport getCameraViewport(EntityRef entity) const override
{
Viewport vp;
const Camera& cam = m_cameras[entity];
vp.far = cam.far;
vp.near = cam.near;
vp.is_ortho = cam.is_ortho;
vp.h = (int)cam.screen_height;
vp.w = (int)cam.screen_width;
if(vp.is_ortho) {
vp.ortho_size = cam.ortho_size;
}
else {
vp.fov = cam.fov;
}
vp.pos = m_universe.getPosition(entity);
vp.rot = m_universe.getRotation(entity);
return vp;
}
2015-07-24 08:42:35 +02:00
2018-07-08 00:44:45 +02:00
float getCameraLODMultiplier(float fov, bool is_ortho) const override
2018-07-06 21:31:44 +02:00
{
2018-07-08 00:44:45 +02:00
if (is_ortho) return 1;
2018-07-06 21:31:44 +02:00
2019-06-13 17:26:52 +02:00
const float lod_multiplier = fov / degreesToRadians(60);
2018-07-06 21:31:44 +02:00
return lod_multiplier * lod_multiplier;
}
2018-08-19 17:35:37 +02:00
float getCameraLODMultiplier(EntityRef entity) const override
2018-07-08 00:44:45 +02:00
{
const Camera& camera = m_cameras[entity];
return getCameraLODMultiplier(camera.fov, camera.is_ortho);
}
2018-09-20 23:17:45 +02:00
ShiftedFrustum getCameraFrustum(EntityRef entity) const override
2015-07-23 23:17:51 +02:00
{
2018-09-20 23:17:45 +02:00
ShiftedFrustum ret;
const Camera& camera = m_cameras[entity];
const Transform tr = m_universe.getTransform(entity);
2016-04-17 21:47:54 +02:00
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
2018-09-20 23:17:45 +02:00
if (camera.is_ortho) {
ret.computeOrtho(tr.pos,
tr.rot * Vec3(0, 0, 1),
tr.rot * Vec3(0, 1, 0),
2016-04-17 21:47:54 +02:00
camera.ortho_size * ratio,
camera.ortho_size,
camera.near,
camera.far);
return ret;
}
2018-09-20 23:17:45 +02:00
ret.computePerspective(tr.pos,
tr.rot * Vec3(0, 0, -1),
tr.rot * Vec3(0, 1, 0),
camera.fov,
2016-04-17 21:47:54 +02:00
ratio,
camera.near,
camera.far);
2018-09-20 23:17:45 +02:00
return ret;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-08-27 23:18:49 +02:00
2018-09-20 23:17:45 +02:00
ShiftedFrustum getCameraFrustum(EntityRef entity, const Vec2& viewport_min_px, const Vec2& viewport_max_px) const override
{
2018-09-20 23:17:45 +02:00
ShiftedFrustum ret;
2018-01-12 17:01:26 +01:00
const Camera& camera = m_cameras[entity];
2018-09-20 23:17:45 +02:00
const Transform tr = m_universe.getTransform(entity);
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
2017-10-10 16:53:23 +02:00
Vec2 viewport_min = { viewport_min_px.x / camera.screen_width * 2 - 1, (1 - viewport_max_px.y / camera.screen_height) * 2 - 1 };
Vec2 viewport_max = { viewport_max_px.x / camera.screen_width * 2 - 1, (1 - viewport_min_px.y / camera.screen_height) * 2 - 1 };
2018-09-20 23:17:45 +02:00
if (camera.is_ortho) {
ret.computeOrtho(tr.pos,
tr.rot * Vec3(0, 0, 1),
tr.rot * Vec3(0, 1, 0),
camera.ortho_size * ratio,
camera.ortho_size,
camera.near,
2017-10-10 17:29:40 +02:00
camera.far,
viewport_min,
viewport_max);
return ret;
}
2018-09-20 23:17:45 +02:00
ret.computePerspective(tr.pos,
tr.rot * Vec3(0, 0, -1),
tr.rot * Vec3(0, 1, 0),
camera.fov,
ratio,
camera.near,
2017-10-10 16:53:23 +02:00
camera.far,
viewport_min,
viewport_max);
2018-09-20 23:17:45 +02:00
return ret;
}
2016-05-02 21:41:18 +02:00
void updateBoneAttachment(const BoneAttachment& bone_attachment)
{
2017-05-23 14:01:09 +02:00
if (!bone_attachment.parent_entity.isValid()) return;
2018-08-19 17:35:37 +02:00
const EntityPtr model_instance_ptr = bone_attachment.parent_entity;
if (!model_instance_ptr.isValid()) return;
const EntityRef model_instance = (EntityRef)model_instance_ptr;
2018-01-12 17:01:26 +01:00
if (!m_universe.hasComponent(model_instance, MODEL_INSTANCE_TYPE)) return;
const Pose* parent_pose = lockPose(model_instance);
2016-05-02 21:41:18 +02:00
if (!parent_pose) return;
2018-08-19 17:35:37 +02:00
Transform parent_entity_transform = m_universe.getTransform((EntityRef)bone_attachment.parent_entity);
2016-05-02 21:41:18 +02:00
int idx = bone_attachment.bone_index;
2019-09-10 18:12:05 +02:00
if (idx < 0 || idx >= (int)parent_pose->count) {
unlockPose(model_instance, false);
return;
}
float original_scale = m_universe.getScale(bone_attachment.entity);
2018-09-20 23:17:45 +02:00
const LocalRigidTransform bone_transform = {parent_pose->positions[idx], parent_pose->rotations[idx] };
const LocalRigidTransform relative_transform = { bone_attachment.relative_transform.pos, bone_attachment.relative_transform.rot };
Transform result = parent_entity_transform * bone_transform * relative_transform;
result.scale = original_scale;
m_universe.setTransform(bone_attachment.entity, result);
2018-09-20 23:17:45 +02:00
unlockPose(model_instance, false);
2016-05-02 21:41:18 +02:00
}
2018-08-19 17:35:37 +02:00
EntityPtr getBoneAttachmentParent(EntityRef entity) override
2016-05-02 21:41:18 +02:00
{
2018-01-12 17:01:26 +01:00
return m_bone_attachments[entity].parent_entity;
2016-05-02 21:41:18 +02:00
}
void updateRelativeMatrix(BoneAttachment& attachment)
{
2018-08-19 17:35:37 +02:00
if (!attachment.parent_entity.isValid()) return;
2016-05-02 21:41:18 +02:00
if (attachment.bone_index < 0) return;
2018-08-19 17:35:37 +02:00
const EntityPtr model_instance_ptr = attachment.parent_entity;
if (!model_instance_ptr.isValid()) return;
const EntityRef model_instance = (EntityRef)model_instance_ptr;
2018-01-12 17:01:26 +01:00
if (!m_universe.hasComponent(model_instance, MODEL_INSTANCE_TYPE)) return;
const Pose* pose = lockPose(model_instance);
2016-05-02 21:41:18 +02:00
if (!pose) return;
2018-08-19 17:35:37 +02:00
2016-05-02 21:41:18 +02:00
ASSERT(pose->is_absolute);
2019-09-10 18:12:05 +02:00
if (attachment.bone_index >= (int)pose->count) {
unlockPose(model_instance, false);
return;
}
2018-09-20 23:17:45 +02:00
const LocalRigidTransform bone_transform = {pose->positions[attachment.bone_index], pose->rotations[attachment.bone_index]};
2016-05-02 21:41:18 +02:00
2018-08-19 17:35:37 +02:00
const EntityRef parent = (EntityRef)attachment.parent_entity;
Transform inv_parent_transform = m_universe.getTransform(parent) * bone_transform;
inv_parent_transform = inv_parent_transform.inverted();
2018-09-20 23:17:45 +02:00
const Transform child_transform = m_universe.getTransform(attachment.entity);
const Transform res = inv_parent_transform * child_transform;
attachment.relative_transform = {res.pos.toFloat(), res.rot};
unlockPose(model_instance, false);
2016-05-02 21:41:18 +02:00
}
2018-08-19 17:35:37 +02:00
Vec3 getBoneAttachmentPosition(EntityRef entity) override
{
2018-09-20 23:17:45 +02:00
return m_bone_attachments[entity].relative_transform.pos;
2018-09-16 18:35:57 +02:00
}
2018-08-19 17:35:37 +02:00
void setBoneAttachmentPosition(EntityRef entity, const Vec3& pos) override
{
2018-01-12 17:01:26 +01:00
BoneAttachment& attachment = m_bone_attachments[entity];
attachment.relative_transform.pos = pos;
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
2018-09-20 23:17:45 +02:00
m_is_updating_attachments = false;
}
2018-08-19 17:35:37 +02:00
Vec3 getBoneAttachmentRotation(EntityRef entity) override
2016-08-28 16:56:38 +02:00
{
2018-01-12 17:01:26 +01:00
return m_bone_attachments[entity].relative_transform.rot.toEuler();
2016-08-28 16:56:38 +02:00
}
2018-08-19 17:35:37 +02:00
void setBoneAttachmentRotation(EntityRef entity, const Vec3& rot) override
2016-08-28 16:56:38 +02:00
{
2018-01-12 17:01:26 +01:00
BoneAttachment& attachment = m_bone_attachments[entity];
2016-08-28 16:56:38 +02:00
Vec3 euler = rot;
2019-06-13 17:26:52 +02:00
euler.x = clamp(euler.x, -PI * 0.5f, PI * 0.5f);
2016-08-28 16:56:38 +02:00
attachment.relative_transform.rot.fromEuler(euler);
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
m_is_updating_attachments = false;
}
2018-08-19 17:35:37 +02:00
void setBoneAttachmentRotationQuat(EntityRef entity, const Quat& rot) override
{
2018-01-12 17:01:26 +01:00
BoneAttachment& attachment = m_bone_attachments[entity];
attachment.relative_transform.rot = rot;
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
m_is_updating_attachments = false;
}
2018-08-19 17:35:37 +02:00
int getBoneAttachmentBone(EntityRef entity) override
2016-05-02 21:41:18 +02:00
{
2018-01-12 17:01:26 +01:00
return m_bone_attachments[entity].bone_index;
2016-05-02 21:41:18 +02:00
}
2018-08-19 17:35:37 +02:00
void setBoneAttachmentBone(EntityRef entity, int value) override
2016-05-02 21:41:18 +02:00
{
2018-01-12 17:01:26 +01:00
BoneAttachment& ba = m_bone_attachments[entity];
ba.bone_index = value;
updateRelativeMatrix(ba);
2016-05-02 21:41:18 +02:00
}
2018-08-19 17:35:37 +02:00
void setBoneAttachmentParent(EntityRef entity, EntityPtr parent) override
2016-05-02 21:41:18 +02:00
{
2018-01-12 17:01:26 +01:00
BoneAttachment& ba = m_bone_attachments[entity];
ba.parent_entity = parent;
if (parent.isValid() && parent.index < m_model_instances.size())
{
2018-03-15 11:41:31 +01:00
ModelInstance& mi = m_model_instances[parent.index];
mi.flags.set(ModelInstance::IS_BONE_ATTACHMENT_PARENT);
}
updateRelativeMatrix(ba);
2016-05-02 21:41:18 +02:00
}
2018-09-26 20:21:04 +02:00
void startGame() override
{
m_is_game_running = true;
}
void stopGame() override
{
m_is_game_running = false;
}
void update(float dt, bool paused) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2016-05-02 21:41:18 +02:00
2015-07-21 20:10:50 +02:00
m_time += dt;
if (m_is_game_running && !paused)
{
2018-08-22 19:52:08 +02:00
for (auto* emitter : m_particle_emitters)
2017-10-24 17:18:53 +02:00
{
emitter->update(dt);
}
}
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2019-11-11 21:30:12 +01:00
void loadLightProbeGridData(LightProbeGrid& lp) const {
StaticString<MAX_PATH_LENGTH> dir("universes/", m_universe.getName(), "/probes/");
ResourceManagerHub& manager = m_engine.getResourceManager();
for (u32 i = 0; i < lengthOf(lp.data); ++i) {
const StaticString<MAX_PATH_LENGTH> path_str(dir, lp.guid, "_grid", i, ".raw");
lp.data[i] = manager.load<Texture>(Path(path_str));
2019-11-17 19:45:54 +01:00
lp.data[i]->setFlag(Texture::Flags::CLAMP_U, true);
lp.data[i]->setFlag(Texture::Flags::CLAMP_V, true);
lp.data[i]->setFlag(Texture::Flags::CLAMP_W, true);
}
2019-11-11 21:30:12 +01:00
}
2018-08-19 17:35:37 +02:00
void setTextMeshText(EntityRef entity, const char* text) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
m_text_meshes.get(entity)->text = text;
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
const char* getTextMeshText(EntityRef entity) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
return m_text_meshes.get(entity)->text.c_str();
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
bool isTextMeshCameraOriented(EntityRef entity) override
{
TextMesh& text = *m_text_meshes.get(entity);
return text.m_flags.isSet(TextMesh::CAMERA_ORIENTED);
}
2018-08-19 17:35:37 +02:00
void setTextMeshCameraOriented(EntityRef entity, bool is_oriented) override
{
TextMesh& text = *m_text_meshes.get(entity);
text.m_flags.set(TextMesh::CAMERA_ORIENTED, is_oriented);
}
2018-08-19 17:35:37 +02:00
void setTextMeshFontSize(EntityRef entity, int value) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
TextMesh& text = *m_text_meshes.get(entity);
text.setFontSize(value);
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
int getTextMeshFontSize(EntityRef entity) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
return m_text_meshes.get(entity)->getFontSize();
2018-01-30 21:39:21 +01:00
}
static Vec4 ABGRu32ToRGBAVec4(u32 value)
{
float inv = 1 / 255.0f;
return {
((value >> 0) & 0xFF) * inv,
((value >> 8) & 0xFF) * inv,
((value >> 16) & 0xFF) * inv,
((value >> 24) & 0xFF) * inv,
};
}
static u32 RGBAVec4ToABGRu32(const Vec4& value)
{
u8 r = u8(value.x * 255 + 0.5f);
u8 g = u8(value.y * 255 + 0.5f);
u8 b = u8(value.z * 255 + 0.5f);
u8 a = u8(value.w * 255 + 0.5f);
return (a << 24) + (b << 16) + (g << 8) + r;
}
2018-08-19 17:35:37 +02:00
Vec4 getTextMeshColorRGBA(EntityRef entity) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
return ABGRu32ToRGBAVec4(m_text_meshes.get(entity)->color);
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
void setTextMeshColorRGBA(EntityRef entity, const Vec4& color) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
m_text_meshes.get(entity)->color = RGBAVec4ToABGRu32(color);
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
Path getTextMeshFontPath(EntityRef entity) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
TextMesh& text = *m_text_meshes.get(entity);
return text.getFontResource() == nullptr ? Path() : text.getFontResource()->getPath();
2018-01-30 21:39:21 +01:00
}
2019-07-04 15:20:50 +02:00
u32 getTextMeshesVerticesCount() const override {
u32 count = 0;
for (int j = 0, nj = m_text_meshes.size(); j < nj; ++j) {
const TextMesh& text = *m_text_meshes.at(j);
count += 6 * text.text.length();
}
return count;
}
2018-01-30 21:39:21 +01:00
2019-07-04 15:20:50 +02:00
void getTextMeshesVertices(TextMeshVertex* vertices, const DVec3& cam_pos, const Quat& cam_rot) override
2018-10-20 01:55:30 +02:00
{
const Vec3 cam_right = cam_rot * Vec3(1, 0, 0);
const Vec3 cam_up = cam_rot * Vec3(0, -1, 0);
2019-07-04 15:20:50 +02:00
u32 idx = 0;
2018-10-20 01:55:30 +02:00
for (int j = 0, nj = m_text_meshes.size(); j < nj; ++j) {
const TextMesh& text = *m_text_meshes.at(j);
const Font* font = text.getFont();
if (!font) continue;
2018-10-20 01:55:30 +02:00
const EntityRef entity = m_text_meshes.getKey(j);
2018-01-30 21:39:21 +01:00
const char* str = text.text.c_str();
2018-10-20 01:55:30 +02:00
Vec3 base = (m_universe.getPosition(entity) - cam_pos).toFloat();
const Quat rot = m_universe.getRotation(entity);
const float scale = m_universe.getScale(entity);
Vec3 right = rot.rotate(Vec3(1, 0, 0)) * scale;
Vec3 up = rot.rotate(Vec3(0, -1, 0)) * scale;
if (text.m_flags.isSet(TextMesh::CAMERA_ORIENTED)) {
2018-04-21 18:51:14 +02:00
right = cam_right * scale;
up = cam_up * scale;
}
2018-01-30 21:39:21 +01:00
u32 color = text.color;
const Vec2 text_size = measureTextA(*font, str, nullptr);
2018-01-30 21:39:21 +01:00
base += right * text_size.x * -0.5f;
base += up * text_size.y * -0.5f;
2018-10-20 01:55:30 +02:00
for (int i = 0, n = text.text.length(); i < n; ++i) {
const Glyph* glyph = findGlyph(*font, str[i]);
2018-01-30 21:39:21 +01:00
if (!glyph) continue;
const Vec3 x0y0 = base + right * float(glyph->x0) + up * float(glyph->y0);
const Vec3 x1y0 = base + right * float(glyph->x1) + up * float(glyph->y0);
const Vec3 x1y1 = base + right * float(glyph->x1) + up * float(glyph->y1);
const Vec3 x0y1 = base + right * float(glyph->x0) + up * float(glyph->y1);
2018-01-30 21:39:21 +01:00
vertices[idx + 0] = { x0y0, color, { glyph->u0, glyph->v0 } };
vertices[idx + 1] = { x1y0, color, { glyph->u1, glyph->v0 } };
vertices[idx + 2] = { x1y1, color, { glyph->u1, glyph->v1 } };
2019-07-04 15:20:50 +02:00
vertices[idx + 3] = { x0y0, color, { glyph->u0, glyph->v0 } };
vertices[idx + 4] = { x1y1, color, { glyph->u1, glyph->v1 } };
vertices[idx + 5] = { x0y1, color, { glyph->u0, glyph->v1 } };
2019-07-04 15:20:50 +02:00
idx += 6;
2018-01-30 21:39:21 +01:00
base += right * float(glyph->advance_x);
2018-01-30 21:39:21 +01:00
}
2018-10-20 01:55:30 +02:00
}
2018-01-30 21:39:21 +01:00
}
2018-08-19 17:35:37 +02:00
void setTextMeshFontPath(EntityRef entity, const Path& path) override
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
TextMesh& text = *m_text_meshes.get(entity);
ResourceManagerHub& manager = m_renderer.getEngine().getResourceManager();
FontResource* res = path.isValid() ? manager.load<FontResource>(path) : nullptr;
2018-02-19 14:10:11 +01:00
text.setFontResource(res);
2018-01-30 21:39:21 +01:00
}
2016-12-10 15:16:01 +01:00
2017-02-09 19:46:18 +01:00
int getVersion() const override { return (int)RenderSceneVersion::LATEST; }
2017-01-24 16:56:42 +01:00
void serializeBoneAttachments(OutputMemoryStream& serializer)
2016-05-02 21:41:18 +02:00
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_bone_attachments.size());
2016-05-02 21:41:18 +02:00
for (auto& attachment : m_bone_attachments)
{
serializer.write(attachment.bone_index);
serializer.write(attachment.entity);
serializer.write(attachment.parent_entity);
serializer.write(attachment.relative_transform);
2016-05-02 21:41:18 +02:00
}
}
void serializeCameras(OutputMemoryStream& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_cameras.size());
2019-11-21 18:53:27 +01:00
for (Camera& camera : m_cameras)
2015-07-21 20:10:50 +02:00
{
2019-11-21 18:53:27 +01:00
serializer.write(camera);
2015-07-21 20:10:50 +02:00
}
}
2015-02-05 22:57:55 +01:00
void serializeLights(OutputMemoryStream& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_point_lights.size());
2018-10-20 21:35:03 +02:00
for (const PointLight& pl : m_point_lights) {
serializer.write(pl);
2015-07-21 20:10:50 +02:00
}
serializer.write((i32)m_environments.size());
for (const Environment& light : m_environments)
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
serializer.write(light);
2015-07-21 20:10:50 +02:00
}
2018-01-12 17:01:26 +01:00
serializer.write(m_active_global_light_entity);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void serializeModelInstances(OutputMemoryStream& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_model_instances.size());
for (auto& r : m_model_instances)
2015-07-21 20:10:50 +02:00
{
serializer.write(r.flags.base);
if(r.flags.isSet(ModelInstance::VALID))
2015-12-10 17:09:52 +01:00
{
serializer.write(r.model ? r.model->getPath().getHash() : 0);
2015-12-10 17:09:52 +01:00
}
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
void serializeTerrains(OutputMemoryStream& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_terrains.size());
for (auto* terrain : m_terrains)
2015-07-21 20:10:50 +02:00
{
2018-11-01 22:15:05 +01:00
serializer.write(terrain->getEntity());
terrain->serialize(serializer);
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
void serializeTextMeshes(OutputMemoryStream& serializer)
2018-01-30 21:39:21 +01:00
{
serializer.write(m_text_meshes.size());
for (int i = 0, n = m_text_meshes.size(); i < n; ++i)
{
2018-02-19 14:10:11 +01:00
TextMesh& text = *m_text_meshes.at(i);
2018-08-19 17:35:37 +02:00
EntityRef e = m_text_meshes.getKey(i);
2018-01-30 21:39:21 +01:00
serializer.write(e);
2018-02-19 14:10:11 +01:00
serializer.writeString(text.getFontResource() ? text.getFontResource()->getPath().c_str() : "");
2018-01-30 21:39:21 +01:00
serializer.write(text.color);
2018-02-19 14:10:11 +01:00
serializer.write(text.getFontSize());
2018-01-30 21:39:21 +01:00
serializer.write(text.text);
}
}
void deserializeTextMeshes(InputMemoryStream& serializer, const EntityMap& entity_map)
2018-01-30 21:39:21 +01:00
{
u32 count;
2018-01-30 21:39:21 +01:00
serializer.read(count);
ResourceManagerHub& manager = m_renderer.getEngine().getResourceManager();
for (u32 i = 0; i < count; ++i) {
2018-08-19 17:35:37 +02:00
EntityRef e;
2018-01-30 21:39:21 +01:00
serializer.read(e);
e = entity_map.get(e);
2018-02-19 14:10:11 +01:00
TextMesh& text = *LUMIX_NEW(m_allocator, TextMesh)(m_allocator);
m_text_meshes.insert(e, &text);
const char* tmp = serializer.readString();
2018-01-30 21:39:21 +01:00
serializer.read(text.color);
2018-02-19 14:10:11 +01:00
int font_size;
serializer.read(font_size);
text.setFontSize(font_size);
2018-01-30 21:39:21 +01:00
serializer.read(text.text);
FontResource* res = tmp[0] ? manager.load<FontResource>(Path(tmp)) : nullptr;
2018-02-19 14:10:11 +01:00
text.setFontResource(res);
2018-01-30 21:39:21 +01:00
m_universe.onComponentCreated(e, TEXT_MESH_TYPE, this);
}
}
void deserializeDecals(InputMemoryStream& serializer, const EntityMap& entity_map)
2016-07-22 13:57:52 +02:00
{
u32 count;
2016-07-22 13:57:52 +02:00
serializer.read(count);
m_decals.reserve(count + m_decals.size());
for (u32 i = 0; i < count; ++i) {
2016-07-22 13:57:52 +02:00
Decal decal;
serializer.read(decal.entity);
decal.entity = entity_map.get(decal.entity);
2018-10-10 23:41:26 +02:00
serializer.read(decal.half_extents);
const char* tmp = serializer.readString();
2016-07-22 13:57:52 +02:00
updateDecalInfo(decal);
m_decals.insert(decal.entity, decal);
2018-10-13 15:08:58 +02:00
setDecalMaterialPath(decal.entity, Path(tmp));
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(decal.entity, DECAL_TYPE, this);
2016-07-22 13:57:52 +02:00
}
}
void serializeDecals(OutputMemoryStream& serializer)
2016-07-22 13:57:52 +02:00
{
serializer.write(m_decals.size());
for (auto& decal : m_decals)
{
serializer.write(decal.entity);
2018-10-10 23:41:26 +02:00
serializer.write(decal.half_extents);
2016-07-22 13:57:52 +02:00
serializer.writeString(decal.material ? decal.material->getPath().c_str() : "");
}
}
void serializeLightProbeGrids(OutputMemoryStream& serializer) {
2019-11-11 21:30:12 +01:00
const i32 count = m_light_probe_grids.size();
serializer.write(count);
for (auto iter : m_light_probe_grids) {
serializer.write(iter.entity);
serializer.write(iter.guid);
serializer.write(iter.resolution);
2019-11-17 19:45:54 +01:00
serializer.write(iter.half_extents);
2019-11-11 21:30:12 +01:00
}
}
2016-07-22 13:57:52 +02:00
void serializeEnvironmentProbes(OutputMemoryStream& serializer)
2016-06-12 15:26:41 +02:00
{
2016-11-20 17:27:41 +01:00
i32 count = m_environment_probes.size();
2016-06-12 15:26:41 +02:00
serializer.write(count);
for (int i = 0; i < count; ++i)
{
2018-08-19 17:35:37 +02:00
EntityRef entity = m_environment_probes.getKey(i);
2016-06-12 15:26:41 +02:00
serializer.write(entity);
const EnvironmentProbe& probe = m_environment_probes.at(i);
serializer.write(probe.guid);
serializer.write(probe.flags.base);
2019-11-14 22:26:43 +01:00
serializer.write(probe.half_extents);
serializer.write(probe.radiance_size);
serializer.write(probe.reflection_size);
2019-11-14 22:26:43 +01:00
serializer.write(probe.sh_coefs);
2016-06-12 15:26:41 +02:00
}
}
void deserializeLightProbeGrids(InputMemoryStream& serializer, const EntityMap& entity_map) {
u32 count;
2019-11-11 21:30:12 +01:00
serializer.read(count);
m_light_probe_grids.reserve(count + m_light_probe_grids.size());
for (u32 i = 0; i < count; ++i) {
2019-11-11 21:30:12 +01:00
LightProbeGrid lp;
serializer.read(lp.entity);
lp.entity = entity_map.get(lp.entity);
2019-11-11 21:30:12 +01:00
serializer.read(lp.guid);
serializer.read(lp.resolution);
2019-11-17 19:45:54 +01:00
serializer.read(lp.half_extents);
2019-11-11 21:30:12 +01:00
loadLightProbeGridData(lp);
m_light_probe_grids.insert(lp.entity, lp);
m_universe.onComponentCreated(lp.entity, LIGHT_PROBE_GRID_TYPE, this);
}
}
2016-06-12 15:26:41 +02:00
void deserializeEnvironmentProbes(InputMemoryStream& serializer, const EntityMap& entity_map)
2016-06-12 15:26:41 +02:00
{
u32 count;
2016-06-12 15:26:41 +02:00
serializer.read(count);
m_environment_probes.reserve(count + m_environment_probes.size());
ResourceManagerHub& manager = m_engine.getResourceManager();
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> probe_dir("universes/", m_universe.getName(), "/probes/");
for (u32 i = 0; i < count; ++i) {
2018-08-19 17:35:37 +02:00
EntityRef entity;
2016-06-12 15:26:41 +02:00
serializer.read(entity);
entity = entity_map.get(entity);
2016-07-24 17:29:17 +02:00
EnvironmentProbe& probe = m_environment_probes.insert(entity);
// TODO probes are stored in per-universe directory, that won't work with additive loading
2017-01-03 17:04:09 +01:00
serializer.read(probe.guid);
serializer.read(probe.flags.base);
2019-11-14 22:26:43 +01:00
serializer.read(probe.half_extents);
serializer.read(probe.radiance_size);
serializer.read(probe.reflection_size);
2019-11-14 22:26:43 +01:00
serializer.read(probe.sh_coefs);
ASSERT(probe.reflection == nullptr);
if (probe.flags.isSet(EnvironmentProbe::REFLECTION)) {
StaticString<MAX_PATH_LENGTH> path_str(probe_dir, probe.guid, ".dds");
2019-11-14 22:26:43 +01:00
probe.reflection = manager.load<Texture>(Path(path_str));
}
ASSERT(probe.radiance == nullptr);
if (probe.flags.isSet(EnvironmentProbe::SPECULAR)) {
StaticString<MAX_PATH_LENGTH> r_path_str(probe_dir, probe.guid, "_radiance.dds");
probe.radiance = manager.load<Texture>(Path(r_path_str));
}
2016-11-29 20:00:36 +01:00
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, ENVIRONMENT_PROBE_TYPE, this);
2018-07-06 21:31:44 +02:00
}
2016-06-12 15:26:41 +02:00
}
void deserializeBoneAttachments(InputMemoryStream& serializer, const EntityMap& entity_map)
2016-05-02 21:41:18 +02:00
{
u32 count;
2016-05-02 21:41:18 +02:00
serializer.read(count);
m_bone_attachments.reserve(count + m_bone_attachments.size());
for (u32 i = 0; i < count; ++i) {
BoneAttachment bone_attachment;
2016-06-22 15:05:19 +02:00
serializer.read(bone_attachment.bone_index);
serializer.read(bone_attachment.entity);
bone_attachment.entity = entity_map.get(bone_attachment.entity);
2016-06-22 15:05:19 +02:00
serializer.read(bone_attachment.parent_entity);
serializer.read(bone_attachment.relative_transform);
m_bone_attachments.insert(bone_attachment.entity, bone_attachment);
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(bone_attachment.entity, BONE_ATTACHMENT_TYPE, this);
2016-05-02 21:41:18 +02:00
}
}
void deserializeParticleEmitters(InputMemoryStream& serializer, const EntityMap& entity_map)
{
const u32 count = serializer.read<u32>();
m_particle_emitters.reserve(count + m_particle_emitters.size());
for (u32 i = 0; i < count; ++i) {
2018-08-22 19:52:08 +02:00
ParticleEmitter* emitter = LUMIX_NEW(m_allocator, ParticleEmitter)(INVALID_ENTITY, m_allocator);
2017-10-24 17:18:53 +02:00
emitter->deserialize(serializer, m_engine.getResourceManager());
emitter->m_entity = entity_map.get(emitter->m_entity);
2018-08-19 17:35:37 +02:00
if(emitter->m_entity.isValid()) {
2018-08-22 19:52:08 +02:00
m_particle_emitters.insert((EntityRef)emitter->m_entity, emitter);
m_universe.onComponentCreated((EntityRef)emitter->m_entity, PARTICLE_EMITTER_TYPE, this);
2018-08-19 17:35:37 +02:00
}
else {
LUMIX_DELETE(m_allocator, emitter);
}
2017-10-24 17:18:53 +02:00
}
}
void serializeParticleEmitters(OutputMemoryStream& serializer)
{
2018-08-22 19:52:08 +02:00
serializer.write(m_particle_emitters.size());
for (auto* emitter : m_particle_emitters)
2017-10-24 17:18:53 +02:00
{
emitter->serialize(serializer);
}
}
2019-06-11 22:39:39 +02:00
void serialize(OutputMemoryStream& serializer) override
2015-07-21 20:10:50 +02:00
{
serializeCameras(serializer);
serializeModelInstances(serializer);
2015-07-21 20:10:50 +02:00
serializeLights(serializer);
serializeTerrains(serializer);
serializeParticleEmitters(serializer);
2016-05-02 21:41:18 +02:00
serializeBoneAttachments(serializer);
2016-06-12 15:26:41 +02:00
serializeEnvironmentProbes(serializer);
2019-11-11 21:30:12 +01:00
serializeLightProbeGrids(serializer);
2016-07-22 13:57:52 +02:00
serializeDecals(serializer);
2018-01-30 21:39:21 +01:00
serializeTextMeshes(serializer);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void deserializeCameras(InputMemoryStream& serializer, const EntityMap& entity_map)
2015-07-21 20:10:50 +02:00
{
u32 size;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_cameras.reserve(size + m_cameras.size());
for (u32 i = 0; i < size; ++i)
2015-07-21 20:10:50 +02:00
{
Camera camera;
2019-11-21 18:53:27 +01:00
serializer.read(camera);
camera.entity = entity_map.get(camera.entity);
2015-07-21 20:10:50 +02:00
2017-01-03 17:04:09 +01:00
m_cameras.insert(camera.entity, camera);
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(camera.entity, CAMERA_TYPE, this);
if (!m_active_camera.isValid()) m_active_camera = camera.entity;
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
void deserializeModelInstances(IInputStream& serializer, const EntityMap& entity_map)
2015-07-21 20:10:50 +02:00
{
u32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_model_instances.reserve(size + m_model_instances.size());
m_mesh_sort_data.reserve(size + m_mesh_sort_data.size());
for (u32 i = 0; i < size; ++i) {
FlagSet<ModelInstance::Flags, u8> flags;
serializer.read(flags);
if(flags.isSet(ModelInstance::VALID)) {
const EntityRef e = entity_map.get(EntityRef{(i32)i});
while (e.index >= m_model_instances.size()) {
auto& r = m_model_instances.emplace();
r.flags.clear();
r.flags.set(ModelInstance::VALID, false);
r.model = nullptr;
r.pose = nullptr;
}
2015-07-21 20:10:50 +02:00
ModelInstance& r = m_model_instances[e.index];
r.flags = flags;
r.model = nullptr;
r.pose = nullptr;
r.meshes = nullptr;
r.mesh_count = 0;
2015-07-23 23:17:51 +02:00
2016-11-20 17:27:41 +01:00
u32 path;
2015-12-10 17:09:52 +01:00
serializer.read(path);
2015-07-23 23:17:51 +02:00
if (path != 0) {
Model* model = m_engine.getResourceManager().load<Model>(Path(path));
2018-08-19 17:35:37 +02:00
setModel(e, model);
}
2018-08-19 17:35:37 +02:00
m_universe.onComponentCreated(e, MODEL_INSTANCE_TYPE, this);
2015-12-10 17:09:52 +01:00
}
2018-09-22 12:56:45 +02:00
}
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
void deserializeLights(IInputStream& serializer, const EntityMap& entity_map)
2015-11-18 20:18:48 +01:00
{
u32 size = 0;
2018-08-19 17:35:37 +02:00
serializer.read(size);
m_point_lights.reserve(size + m_point_lights.size());
for (u32 i = 0; i < size; ++i) {
2018-10-20 21:35:03 +02:00
PointLight light;
2018-08-19 17:35:37 +02:00
serializer.read(light);
light.entity = entity_map.get(light.entity);
2019-05-18 23:24:07 +02:00
m_point_lights.insert(light.entity, light);
const DVec3 pos = m_universe.getPosition(light.entity);
m_culling_system->add(light.entity, (u8)RenderableTypes::LOCAL_LIGHT, pos, light.range);
m_universe.onComponentCreated(light.entity, POINT_LIGHT_TYPE, this);
2018-08-19 17:35:37 +02:00
}
2015-12-17 21:38:23 +01:00
2018-08-19 17:35:37 +02:00
serializer.read(size);
for (u32 i = 0; i < size; ++i) {
Environment light;
2018-08-19 17:35:37 +02:00
serializer.read(light);
light.entity = entity_map.get(light.entity);
2019-11-26 16:50:08 +01:00
m_environments.insert(light.entity, light);
m_universe.onComponentCreated(light.entity, ENVIRONMENT_TYPE, this);
2015-11-18 20:18:48 +01:00
}
EntityPtr tmp;
serializer.read(tmp);
if (!m_active_global_light_entity.isValid()) {
m_active_global_light_entity = tmp;
}
2015-11-18 20:18:48 +01:00
}
void deserializeTerrains(InputMemoryStream& serializer, const EntityMap& entity_map)
{
2018-08-19 17:35:37 +02:00
i32 size = 0;
serializer.read(size);
for (int i = 0; i < size; ++i)
{
2018-11-01 22:15:05 +01:00
EntityRef entity;
serializer.read(entity);
entity = entity_map.get(entity);
2018-11-01 22:15:05 +01:00
auto* terrain = LUMIX_NEW(m_allocator, Terrain)(m_renderer, entity, *this, m_allocator);
terrain->deserialize(entity, serializer, m_universe, *this);
m_terrains.insert(entity, terrain);
}
2015-11-18 20:18:48 +01:00
}
void deserialize(InputMemoryStream& serializer, const EntityMap& entity_map) override
{
deserializeCameras(serializer, entity_map);
deserializeModelInstances(serializer, entity_map);
deserializeLights(serializer, entity_map);
deserializeTerrains(serializer, entity_map);
deserializeParticleEmitters(serializer, entity_map);
deserializeBoneAttachments(serializer, entity_map);
deserializeEnvironmentProbes(serializer, entity_map);
deserializeLightProbeGrids(serializer, entity_map);
deserializeDecals(serializer, entity_map);
deserializeTextMeshes(serializer, entity_map);
}
2018-08-19 17:35:37 +02:00
void destroyBoneAttachment(EntityRef entity)
{
2018-08-19 17:35:37 +02:00
const BoneAttachment& bone_attachment = m_bone_attachments[entity];
const EntityPtr parent_entity = bone_attachment.parent_entity;
if (parent_entity.isValid() && parent_entity.index < m_model_instances.size())
2016-01-12 22:59:11 +01:00
{
2018-08-19 17:35:37 +02:00
ModelInstance& mi = m_model_instances[bone_attachment.parent_entity.index];
mi.flags.unset(ModelInstance::IS_BONE_ATTACHMENT_PARENT);
2016-01-12 22:59:11 +01:00
}
2018-08-19 17:35:37 +02:00
m_bone_attachments.erase(entity);
m_universe.onComponentDestroyed(entity, BONE_ATTACHMENT_TYPE, this);
}
2018-08-19 17:35:37 +02:00
void destroyEnvironmentProbe(EntityRef entity)
{
2018-08-19 17:35:37 +02:00
auto& probe = m_environment_probes[entity];
2019-11-14 22:26:43 +01:00
if (probe.reflection) probe.reflection->getResourceManager().unload(*probe.reflection);
2018-08-19 17:35:37 +02:00
if (probe.radiance) probe.radiance->getResourceManager().unload(*probe.radiance);
m_environment_probes.erase(entity);
m_universe.onComponentDestroyed(entity, ENVIRONMENT_PROBE_TYPE, this);
}
2018-08-19 17:35:37 +02:00
void destroyModelInstance(EntityRef entity)
{
2018-08-19 17:35:37 +02:00
setModel(entity, nullptr);
auto& model_instance = m_model_instances[entity.index];
LUMIX_DELETE(m_allocator, model_instance.pose);
model_instance.pose = nullptr;
model_instance.flags.clear();
model_instance.flags.set(ModelInstance::VALID, false);
2018-08-19 17:35:37 +02:00
m_universe.onComponentDestroyed(entity, MODEL_INSTANCE_TYPE, this);
}
2019-11-11 21:30:12 +01:00
void destroyLightProbeGrid(EntityRef entity) {
const LightProbeGrid& lp = m_light_probe_grids[entity];
m_universe.onComponentDestroyed(entity, LIGHT_PROBE_GRID_TYPE, this);
for (Texture* t : lp.data) {
if (t) t->getResourceManager().unload(*t);
}
m_light_probe_grids.erase(entity);
}
void destroyEnvironment(EntityRef entity)
{
m_universe.onComponentDestroyed(entity, ENVIRONMENT_TYPE, this);
2018-08-19 17:35:37 +02:00
if ((EntityPtr)entity == m_active_global_light_entity)
2016-01-12 22:59:11 +01:00
{
2018-08-19 17:35:37 +02:00
m_active_global_light_entity = INVALID_ENTITY;
2016-01-12 22:59:11 +01:00
}
m_environments.erase(entity);
}
2018-08-19 17:35:37 +02:00
void destroyDecal(EntityRef entity)
2015-10-30 21:11:11 +01:00
{
2018-10-10 23:41:26 +02:00
m_culling_system->remove(entity);
2018-08-19 17:35:37 +02:00
m_decals.erase(entity);
m_universe.onComponentDestroyed(entity, DECAL_TYPE, this);
2015-10-30 21:11:11 +01:00
}
2018-08-19 17:35:37 +02:00
void destroyPointLight(EntityRef entity)
2015-10-30 21:11:11 +01:00
{
2018-10-20 21:35:03 +02:00
m_point_lights.erase(entity);
m_culling_system->remove(entity);
2018-08-19 17:35:37 +02:00
m_universe.onComponentDestroyed(entity, POINT_LIGHT_TYPE, this);
2015-10-30 21:11:11 +01:00
}
2018-08-19 17:35:37 +02:00
void destroyTextMesh(EntityRef entity)
2015-10-30 21:11:11 +01:00
{
2018-08-19 17:35:37 +02:00
TextMesh* text = m_text_meshes[entity];
LUMIX_DELETE(m_allocator, text);
m_text_meshes.erase(entity);
m_universe.onComponentDestroyed(entity, TEXT_MESH_TYPE, this);
2015-10-30 21:11:11 +01:00
}
2018-08-19 17:35:37 +02:00
void destroyCamera(EntityRef entity)
2015-11-01 20:56:29 +01:00
{
2018-08-19 17:35:37 +02:00
m_cameras.erase(entity);
m_universe.onComponentDestroyed(entity, CAMERA_TYPE, this);
2018-08-22 19:52:08 +02:00
if (m_active_camera == entity) m_active_camera = INVALID_ENTITY;
2015-11-01 20:56:29 +01:00
}
2018-08-19 17:35:37 +02:00
void destroyTerrain(EntityRef entity)
2015-11-01 20:56:29 +01:00
{
2018-08-19 17:35:37 +02:00
LUMIX_DELETE(m_allocator, m_terrains[entity]);
m_terrains.erase(entity);
m_universe.onComponentDestroyed(entity, TERRAIN_TYPE, this);
2015-11-01 20:56:29 +01:00
}
2018-08-22 19:52:08 +02:00
void destroyParticleEmitter(EntityRef entity)
2015-10-30 21:11:11 +01:00
{
2018-08-22 19:52:08 +02:00
auto* emitter = m_particle_emitters[entity];
m_universe.onComponentDestroyed((EntityRef)emitter->m_entity, PARTICLE_EMITTER_TYPE, this);
m_particle_emitters.erase((EntityRef)emitter->m_entity);
2018-08-19 17:35:37 +02:00
LUMIX_DELETE(m_allocator, emitter);
2015-10-30 21:11:11 +01:00
}
2018-08-19 17:35:37 +02:00
void createTextMesh(EntityRef entity)
2018-01-30 21:39:21 +01:00
{
2018-02-19 14:10:11 +01:00
TextMesh* text = LUMIX_NEW(m_allocator, TextMesh)(m_allocator);
m_text_meshes.insert(entity, text);
2018-01-30 21:39:21 +01:00
m_universe.onComponentCreated(entity, TEXT_MESH_TYPE, this);
}
2018-08-19 17:35:37 +02:00
void createCamera(EntityRef entity)
2015-07-21 20:10:50 +02:00
{
Camera camera;
2016-04-17 21:47:54 +02:00
camera.is_ortho = false;
camera.ortho_size = 10;
camera.entity = entity;
2019-06-13 17:26:52 +02:00
camera.fov = degreesToRadians(60);
2016-04-17 21:47:54 +02:00
camera.screen_width = 800;
camera.screen_height = 600;
camera.near = 0.1f;
camera.far = 10000.0f;
m_cameras.insert(entity, camera);
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, CAMERA_TYPE, this);
2018-08-22 19:52:08 +02:00
if (!m_active_camera.isValid()) m_active_camera = entity;
}
2018-08-19 17:35:37 +02:00
void createTerrain(EntityRef entity)
{
2016-06-22 15:05:19 +02:00
Terrain* terrain = LUMIX_NEW(m_allocator, Terrain)(m_renderer, entity, *this, m_allocator);
m_terrains.insert(entity, terrain);
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, TERRAIN_TYPE, this);
}
2018-08-22 19:52:08 +02:00
void createParticleEmitter(EntityRef entity)
2017-10-24 17:18:53 +02:00
{
2018-08-22 19:52:08 +02:00
m_particle_emitters.insert(entity, LUMIX_NEW(m_allocator, ParticleEmitter)(entity, m_allocator));
m_universe.onComponentCreated(entity, PARTICLE_EMITTER_TYPE, this);
2015-11-18 20:18:48 +01:00
}
2019-09-10 18:12:05 +02:00
int getClosestShadowcastingPointLights(const DVec3& reference_pos, u32 max_lights, PointLight* lights) override
2019-05-19 15:19:01 +02:00
{
float dists[16];
ASSERT(max_lights <= lengthOf(dists));
ASSERT(max_lights > 0);
if (m_point_lights.empty()) return 0;
2019-09-10 18:12:05 +02:00
u32 light_count = 0;
2019-05-19 15:19:01 +02:00
auto iter = m_point_lights.begin();
auto end = m_point_lights.end();
while (iter != end && light_count < max_lights) {
const PointLight& light = iter.value();
++iter;
if (!light.cast_shadows) continue;
const DVec3 light_pos = m_universe.getPosition(light.entity);
float dist_squared = float((reference_pos - light_pos).squaredLength());
dists[light_count] = dist_squared;
lights[light_count] = light;
for (int i = light_count; i > 0 && dists[i - 1] > dists[i]; --i) {
float tmp = dists[i];
dists[i] = dists[i - 1];
dists[i - 1] = tmp;
const PointLight tmp2 = lights[i];
lights[i] = lights[i - 1];
lights[i - 1] = tmp2;
}
++light_count;
}
while(iter != end) {
const PointLight& light = iter.value();
++iter;
if (!light.cast_shadows) continue;
const DVec3 light_pos = m_universe.getPosition(light.entity);
float dist_squared = float((reference_pos - light_pos).squaredLength());
if (dist_squared < dists[max_lights - 1]) {
dists[max_lights - 1] = dist_squared;
lights[max_lights - 1] = light;
for (int i = max_lights - 1; i > 0 && dists[i - 1] > dists[i];
--i)
{
float tmp = dists[i];
dists[i] = dists[i - 1];
dists[i - 1] = tmp;
const PointLight tmp2 = lights[i];
lights[i] = lights[i - 1];
lights[i - 1] = tmp2;
}
}
}
return light_count;
}
2019-07-13 21:13:21 +02:00
bool getEnvironmentCastShadows(EntityRef entity) override {
return m_environments[entity].flags.isSet(Environment::CAST_SHADOWS);
}
void setEnvironmentCastShadows(EntityRef entity, bool enable) override {
m_environments[entity].flags.set(Environment::CAST_SHADOWS, enable);
}
2019-05-19 15:19:01 +02:00
Environment& getEnvironment(EntityRef entity) override
2019-06-13 17:26:52 +02:00
{
return m_environments[entity];
2019-06-13 17:26:52 +02:00
}
PointLight& getPointLight(EntityRef entity) override
2018-11-18 17:02:41 +01:00
{
return m_point_lights[entity];
}
2019-06-05 01:45:55 +02:00
const MeshSortData* getMeshSortData() const override
{
return m_mesh_sort_data.empty() ? nullptr : m_mesh_sort_data.begin();
}
2018-11-18 17:02:41 +01:00
2018-09-23 18:18:18 +02:00
const ModelInstance* getModelInstances() const override
{
2018-04-24 00:55:10 +02:00
return m_model_instances.empty() ? nullptr : &m_model_instances[0];
}
2018-08-19 17:35:37 +02:00
ModelInstance* getModelInstance(EntityRef entity) override
{
2018-01-12 17:01:26 +01:00
return &m_model_instances[entity.index];
}
2018-08-19 17:35:37 +02:00
Vec3 getPoseBonePosition(EntityRef model_instance, int bone_index)
{
Pose* pose = m_model_instances[model_instance.index].pose;
return pose->positions[bone_index];
}
2018-08-19 17:35:37 +02:00
void onEntityDestroyed(EntityRef entity)
2016-05-02 21:41:18 +02:00
{
for (auto& i : m_bone_attachments)
{
if (i.parent_entity == entity)
{
i.parent_entity = INVALID_ENTITY;
break;
}
}
}
2018-08-19 17:35:37 +02:00
void onEntityMoved(EntityRef entity)
2015-07-21 20:10:50 +02:00
{
const u64 cmp_mask = m_universe.getComponentsMask(entity);
if ((cmp_mask & m_render_cmps_mask) == 0) {
return;
}
if (m_culling_system->isAdded(entity)) {
if (m_universe.hasComponent(entity, MODEL_INSTANCE_TYPE)) {
2018-09-26 20:21:04 +02:00
const DVec3 position = m_universe.getPosition(entity);
2018-09-16 18:35:57 +02:00
m_culling_system->setPosition(entity, position);
2015-07-21 20:10:50 +02:00
}
else if (m_universe.hasComponent(entity, DECAL_TYPE)) {
auto iter = m_decals.find(entity);
updateDecalInfo(iter.value());
const DVec3 position = m_universe.getPosition(entity);
2018-10-28 13:40:09 +01:00
m_culling_system->setPosition(entity, position);
}
else if (m_universe.hasComponent(entity, POINT_LIGHT_TYPE)) {
const DVec3 pos = m_universe.getPosition(entity);
m_culling_system->setPosition(entity, pos);
}
2016-07-22 13:57:52 +02:00
}
2016-05-02 21:41:18 +02:00
bool was_updating = m_is_updating_attachments;
m_is_updating_attachments = true;
for (auto& attachment : m_bone_attachments)
{
if (attachment.parent_entity == entity)
{
updateBoneAttachment(attachment);
}
}
m_is_updating_attachments = was_updating;
if (m_is_updating_attachments || m_is_game_running) return;
2018-09-26 20:21:04 +02:00
if(m_universe.hasComponent(entity, BONE_ATTACHMENT_TYPE)) {
for (auto& attachment : m_bone_attachments)
2016-05-02 21:41:18 +02:00
{
2018-09-26 20:21:04 +02:00
if (attachment.entity == entity)
{
updateRelativeMatrix(attachment);
break;
}
2016-05-02 21:41:18 +02:00
}
}
2015-07-21 20:10:50 +02:00
}
2014-07-20 00:45:57 +02:00
Engine& getEngine() const override { return m_engine; }
2018-10-21 18:05:43 +02:00
Terrain* getTerrain(EntityRef entity) override
{
return m_terrains[entity];
}
2019-07-05 11:32:37 +02:00
IVec2 getTerrainResolution(EntityRef entity) override
2016-03-11 23:26:38 +01:00
{
2018-01-12 17:01:26 +01:00
auto* terrain = m_terrains[entity];
2019-07-05 11:32:37 +02:00
return IVec2(terrain->getWidth(), terrain->getHeight());
2016-03-11 23:26:38 +01:00
}
2018-08-19 17:35:37 +02:00
EntityPtr getFirstTerrain() override
2016-03-11 23:26:38 +01:00
{
2018-01-12 17:01:26 +01:00
if (m_terrains.empty()) return INVALID_ENTITY;
auto iter = m_terrains.begin();
2018-01-12 17:01:26 +01:00
return iter.value()->getEntity();
2016-03-11 23:26:38 +01:00
}
2018-08-19 17:35:37 +02:00
EntityPtr getNextTerrain(EntityRef entity) override
2015-09-12 12:44:04 +02:00
{
auto iter = m_terrains.find(entity);
2018-01-12 17:01:26 +01:00
++iter;
if (!iter.isValid()) return INVALID_ENTITY;
return iter.value()->getEntity();
2015-09-12 12:44:04 +02:00
}
2018-08-19 17:35:37 +02:00
Vec3 getTerrainNormalAt(EntityRef entity, float x, float z) override
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getNormal(x, z);
}
2018-08-19 17:35:37 +02:00
float getTerrainHeightAt(EntityRef entity, float x, float z) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getHeight(x, z);
2015-07-21 20:10:50 +02:00
}
2014-09-06 22:21:09 +02:00
2018-08-19 17:35:37 +02:00
AABB getTerrainAABB(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getAABB();
2016-03-13 01:27:25 +01:00
}
2018-08-19 17:35:37 +02:00
Vec2 getTerrainSize(EntityRef entity) override
2016-03-13 01:27:25 +01:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getSize();
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2018-08-19 17:35:37 +02:00
void setTerrainMaterialPath(EntityRef entity, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2016-02-12 23:49:56 +01:00
if (path.isValid())
{
Material* material = m_engine.getResourceManager().load<Material>(path);
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setMaterial(material);
2016-02-12 23:49:56 +01:00
}
else
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setMaterial(nullptr);
2016-02-12 23:49:56 +01:00
}
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2018-08-19 17:35:37 +02:00
Material* getTerrainMaterial(EntityRef entity) override { return m_terrains[entity]->getMaterial(); }
2018-10-10 23:41:26 +02:00
void setDecalHalfExtents(EntityRef entity, const Vec3& value) override
2016-07-22 13:57:52 +02:00
{
2018-01-12 17:01:26 +01:00
Decal& decal = m_decals[entity];
2018-10-10 23:41:26 +02:00
decal.half_extents = value;
2018-10-13 23:24:44 +02:00
if (decal.material && decal.material->isReady()) {
m_culling_system->setRadius(entity, value.length());
}
2016-07-22 13:57:52 +02:00
updateDecalInfo(decal);
}
2018-10-10 23:41:26 +02:00
Vec3 getDecalHalfExtents(EntityRef entity) override
2016-07-22 13:57:52 +02:00
{
2018-10-10 23:41:26 +02:00
return m_decals[entity].half_extents;
2016-07-22 13:57:52 +02:00
}
2018-08-19 17:35:37 +02:00
void setDecalMaterialPath(EntityRef entity, const Path& path) override
2016-07-22 13:57:52 +02:00
{
2018-01-12 17:01:26 +01:00
Decal& decal = m_decals[entity];
if (decal.material) {
2018-10-13 15:08:58 +02:00
removeFromMaterialDecalMap(decal.material, entity);
decal.material->getResourceManager().unload(*decal.material);
2016-07-22 13:57:52 +02:00
}
if (path.isValid()) {
decal.material = m_engine.getResourceManager().load<Material>(path);
2018-10-13 15:08:58 +02:00
addToMaterialDecalMap(decal.material, entity);
2018-10-13 23:24:44 +02:00
if (decal.material->isReady()) {
const float radius = m_decals[entity].half_extents.length();
const DVec3 pos = m_universe.getPosition(entity);
m_culling_system->add(entity, (u8)RenderableTypes::DECAL, pos, radius);
}
2016-07-22 13:57:52 +02:00
}
else {
2016-07-22 13:57:52 +02:00
decal.material = nullptr;
}
}
2018-10-13 15:08:58 +02:00
Material* getDecalMaterial(EntityRef entity) const override
{
auto iter = m_decals.find(entity);
return iter.value().material;
}
2016-07-22 13:57:52 +02:00
2018-08-19 17:35:37 +02:00
Path getDecalMaterialPath(EntityRef entity) override
2016-07-22 13:57:52 +02:00
{
2018-01-12 17:01:26 +01:00
Decal& decal = m_decals[entity];
2016-07-22 13:57:52 +02:00
return decal.material ? decal.material->getPath() : Path("");
}
2018-08-19 17:35:37 +02:00
Path getTerrainMaterialPath(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
Terrain* terrain = m_terrains[entity];
if (terrain->getMaterial())
2015-07-21 20:10:50 +02:00
{
return terrain->getMaterial()->getPath();
2015-07-21 20:10:50 +02:00
}
else
{
2016-01-06 14:18:59 +01:00
return Path("");
2015-07-21 20:10:50 +02:00
}
}
2018-10-21 18:05:43 +02:00
2018-08-19 17:35:37 +02:00
void setTerrainXZScale(EntityRef entity, float scale) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setXZScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2018-10-28 17:38:15 +01:00
2018-08-19 17:35:37 +02:00
float getTerrainXZScale(EntityRef entity) override { return m_terrains[entity]->getXZScale(); }
2014-07-09 21:33:35 +02:00
2018-08-19 17:35:37 +02:00
void setTerrainYScale(EntityRef entity, float scale) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setYScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-07-09 21:33:35 +02:00
2018-10-28 17:38:15 +01:00
2018-08-19 17:35:37 +02:00
float getTerrainYScale(EntityRef entity) override { return m_terrains[entity]->getYScale(); }
2014-06-16 21:18:15 +02:00
2018-08-19 17:35:37 +02:00
Pose* lockPose(EntityRef entity) override { return m_model_instances[entity.index].pose; }
void unlockPose(EntityRef entity, bool changed) override
{
if (!changed) return;
2018-01-12 17:01:26 +01:00
if (entity.index < m_model_instances.size()
&& (m_model_instances[entity.index].flags.isSet(ModelInstance::IS_BONE_ATTACHMENT_PARENT)) == 0)
{
return;
}
2018-08-19 17:35:37 +02:00
EntityRef parent = entity;
for (BoneAttachment& ba : m_bone_attachments)
{
if (ba.parent_entity != parent) continue;
m_is_updating_attachments = true;
updateBoneAttachment(ba);
m_is_updating_attachments = false;
}
}
2014-06-20 22:54:32 +02:00
2018-08-19 17:35:37 +02:00
Model* getModelInstanceModel(EntityRef entity) override { return m_model_instances[entity.index].model; }
2014-10-31 21:25:03 +01:00
2018-08-19 17:35:37 +02:00
bool isModelInstanceEnabled(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
ModelInstance& model_instance = m_model_instances[entity.index];
2017-12-09 00:15:41 +01:00
return model_instance.flags.isSet(ModelInstance::ENABLED);
2015-07-21 20:10:50 +02:00
}
2014-10-31 21:25:03 +01:00
2018-08-19 17:35:37 +02:00
void enableModelInstance(EntityRef entity, bool enable) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
ModelInstance& model_instance = m_model_instances[entity.index];
2017-12-09 00:15:41 +01:00
model_instance.flags.set(ModelInstance::ENABLED, enable);
if (enable)
{
if (!model_instance.model || !model_instance.model->isReady()) return;
const DVec3 pos = m_universe.getPosition(entity);
2018-09-15 15:06:37 +02:00
const float radius = model_instance.model->getBoundingRadius();
2018-09-23 18:18:18 +02:00
if (!m_culling_system->isAdded(entity)) {
2018-09-29 15:14:46 +02:00
const RenderableTypes type = getRenderableType(*model_instance.model);
2018-09-23 18:18:18 +02:00
m_culling_system->add(entity, (u8)type, pos, radius);
}
}
else
{
2018-09-15 15:06:37 +02:00
m_culling_system->remove(entity);
}
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2018-08-19 17:35:37 +02:00
Path getModelInstancePath(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_model_instances[entity.index].model ? m_model_instances[entity.index].model->getPath() : Path("");
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2018-08-19 17:35:37 +02:00
void setModelInstancePath(EntityRef entity, const Path& path) override
2015-07-21 20:10:50 +02:00
{
if (path.isValid()) {
Model* model = m_engine.getResourceManager().load<Model>(path);
2018-01-12 17:01:26 +01:00
setModel(entity, model);
2016-02-12 23:49:56 +01:00
}
else {
2018-01-12 17:01:26 +01:00
setModel(entity, nullptr);
2016-02-12 23:49:56 +01:00
}
2015-07-21 20:10:50 +02:00
}
2014-07-08 22:31:01 +02:00
2018-08-19 17:35:37 +02:00
void forceGrassUpdate(EntityRef entity) override { m_terrains[entity]->forceGrassUpdate(); }
void getTerrainInfos(Array<TerrainInfo>& infos) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
infos.reserve(m_terrains.size());
for (auto* terrain : m_terrains) {
const TerrainInfo info = terrain->getInfo();
if (info.terrain) infos.push(info);
2015-07-21 20:10:50 +02:00
}
}
2014-08-09 14:37:23 +02:00
2016-03-13 01:27:25 +01:00
static int LUA_castCameraRay(lua_State* L)
{
auto* scene = LuaWrapper::checkArg<RenderSceneImpl*>(L, 1);
2018-08-19 17:35:37 +02:00
EntityRef camera_entity = LuaWrapper::checkArg<EntityRef>(L, 2);
2018-07-08 00:44:45 +02:00
float x, y;
if (lua_gettop(L) > 3) {
2016-11-11 15:09:52 +01:00
x = LuaWrapper::checkArg<float>(L, 3);
y = LuaWrapper::checkArg<float>(L, 4);
}
2018-07-08 00:44:45 +02:00
else {
2018-01-12 17:01:26 +01:00
x = scene->getCameraScreenWidth(camera_entity) * 0.5f;
y = scene->getCameraScreenHeight(camera_entity) * 0.5f;
2016-11-11 15:09:52 +01:00
}
2018-09-16 18:35:57 +02:00
DVec3 origin;
Vec3 dir;
2018-01-12 17:01:26 +01:00
scene->getRay(camera_entity, {x, y}, origin, dir);
2016-03-13 01:27:25 +01:00
2018-01-12 17:01:26 +01:00
RayCastModelHit hit = scene->castRay(origin, dir, INVALID_ENTITY);
2018-09-20 23:17:45 +02:00
LuaWrapper::push(L, hit.is_hit);
LuaWrapper::push(L, hit.is_hit ? hit.origin + hit.dir * hit.t : DVec3(0));
2016-03-13 01:27:25 +01:00
return 2;
}
2016-10-31 16:19:27 +01:00
2018-08-19 17:35:37 +02:00
static float LUA_getTerrainHeightAt(RenderSceneImpl* render_scene, EntityRef entity, int x, int z)
2016-09-14 14:15:27 +02:00
{
2018-01-12 17:01:26 +01:00
return render_scene->m_terrains[entity]->getHeight(x, z);
2016-09-14 14:15:27 +02:00
}
2018-08-19 17:35:37 +02:00
void setTerrainHeightAt(EntityRef entity, int x, int z, float height)
2016-09-14 14:15:27 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setHeight(x, z, height);
2016-09-14 14:15:27 +02:00
}
2016-03-13 01:27:25 +01:00
2016-10-17 00:19:02 +02:00
static Pipeline* LUA_createPipeline(Engine* engine, const char* path)
{
Renderer& renderer = *static_cast<Renderer*>(engine->getPluginManager().getPlugin("renderer"));
2018-09-09 17:58:25 +02:00
PipelineResource* pres = engine->getResourceManager().load<PipelineResource>(Path(path));
return Pipeline::create(renderer, pres, "", renderer.getEngine().getAllocator());
2016-10-17 00:19:02 +02:00
}
static void LUA_destroyPipeline(Pipeline* pipeline)
{
Pipeline::destroy(pipeline);
}
static void LUA_setPipelineScene(Pipeline* pipeline, RenderScene* scene)
{
2020-02-05 18:08:37 +01:00
pipeline->setUniverse(&scene->getUniverse());
2016-10-17 00:19:02 +02:00
}
2016-10-28 23:16:28 +02:00
static RenderScene* LUA_getPipelineScene(Pipeline* pipeline)
{
return pipeline->getScene();
}
static void LUA_setModelInstancePath(IScene* scene, int component, const char* path)
2016-03-04 22:49:53 +01:00
{
RenderScene* render_scene = (RenderScene*)scene;
render_scene->setModelInstancePath({component}, Path(path));
2016-03-04 22:49:53 +01:00
}
static int LUA_getModelBoneIndex(Model* model, const char* bone)
{
if (!model) return 0;
return model->getBoneIndex(crc32(bone)).value();
}
2016-03-31 16:58:42 +02:00
static unsigned int LUA_compareTGA(RenderSceneImpl* scene, const char* path, const char* path_preimage, int min_diff)
{
2019-06-11 22:39:39 +02:00
OS::InputFile file1, file2;
if (!file1.open(path))
2016-03-31 16:58:42 +02:00
{
2019-06-21 17:14:06 +02:00
logError("render_test") << "Failed to open " << path;
2016-03-31 16:58:42 +02:00
return 0xffffFFFF;
}
2019-06-11 22:39:39 +02:00
else if (!file2.open(path_preimage))
2016-03-31 16:58:42 +02:00
{
file1.close();
2019-06-21 17:14:06 +02:00
logError("render_test") << "Failed to open " << path_preimage;
2016-03-31 16:58:42 +02:00
return 0xffffFFFF;
}
unsigned int result = Texture::compareTGA(&file1, &file2, min_diff, scene->m_allocator);
file1.close();
file2.close();
2016-08-17 11:12:10 +02:00
return result;
2016-03-31 16:58:42 +02:00
}
static void LUA_makeScreenshot(RenderSceneImpl* scene, const char* path)
{
scene->m_renderer.makeScreenshot(Path(path));
}
bool isGrassEnabled() const override
{
return m_is_grass_enabled;
}
2016-02-24 20:46:14 +01:00
2018-08-19 17:35:37 +02:00
int getGrassRotationMode(EntityRef entity, int index) override
2017-01-26 09:28:23 +01:00
{
2018-01-12 17:01:26 +01:00
return (int)m_terrains[entity]->getGrassTypeRotationMode(index);
2017-01-26 09:28:23 +01:00
}
2018-08-19 17:35:37 +02:00
void setGrassRotationMode(EntityRef entity, int index, int value) override
2017-01-26 09:28:23 +01:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setGrassTypeRotationMode(index, (Terrain::GrassType::RotationMode)value);
2017-01-26 09:28:23 +01:00
}
2018-08-19 17:35:37 +02:00
float getGrassDistance(EntityRef entity, int index) override
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getGrassTypeDistance(index);
}
2018-08-19 17:35:37 +02:00
void setGrassDistance(EntityRef entity, int index, float value) override
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setGrassTypeDistance(index, value);
}
2016-02-24 20:46:14 +01:00
2016-08-02 21:02:47 +02:00
void enableGrass(bool enabled) override { m_is_grass_enabled = enabled; }
2018-08-19 17:35:37 +02:00
void setGrassDensity(EntityRef entity, int index, int density) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setGrassTypeDensity(index, density);
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
int getGrassDensity(EntityRef entity, int index) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getGrassTypeDensity(index);
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
void setGrassPath(EntityRef entity, int index, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->setGrassTypePath(index, path);
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
Path getGrassPath(EntityRef entity, int index) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getGrassTypePath(index);
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
int getGrassCount(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_terrains[entity]->getGrassTypeCount();
2015-07-21 20:10:50 +02:00
}
2015-07-21 20:10:50 +02:00
2018-08-19 17:35:37 +02:00
void addGrass(EntityRef entity, int index) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->addGrassType(index);
2015-07-21 20:10:50 +02:00
}
2014-10-15 22:16:03 +02:00
2018-08-19 17:35:37 +02:00
void removeGrass(EntityRef entity, int index) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_terrains[entity]->removeGrassType(index);
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
EntityPtr getFirstModelInstance() override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return getNextModelInstance(INVALID_ENTITY);
2015-07-21 20:10:50 +02:00
}
2014-10-28 23:17:18 +01:00
2014-08-20 22:45:47 +02:00
2018-08-19 17:35:37 +02:00
EntityPtr getNextModelInstance(EntityPtr entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
for(int i = entity.index + 1; i < m_model_instances.size(); ++i)
2015-07-21 20:10:50 +02:00
{
if (m_model_instances[i].flags.isSet(ModelInstance::VALID)) return {i};
2015-07-21 20:10:50 +02:00
}
2018-01-12 17:01:26 +01:00
return INVALID_ENTITY;
2015-07-21 20:10:50 +02:00
}
2014-08-20 22:45:47 +02:00
2015-09-02 11:14:42 +02:00
2018-08-19 17:35:37 +02:00
float getCameraLODMultiplier(EntityRef camera)
2017-10-10 13:21:45 +02:00
{
float lod_multiplier;
2019-06-13 17:26:52 +02:00
if (getCamera(camera).is_ortho)
2017-10-10 13:21:45 +02:00
{
lod_multiplier = 1;
}
else
{
2019-06-13 17:26:52 +02:00
lod_multiplier = getCamera(camera).fov / degreesToRadians(60);
2017-10-10 13:21:45 +02:00
lod_multiplier *= lod_multiplier;
}
return lod_multiplier;
}
2019-06-03 22:25:58 +02:00
CullResult* getRenderables(const ShiftedFrustum& frustum, RenderableTypes type) const override
2019-06-01 01:43:28 +02:00
{
2019-07-04 18:21:35 +02:00
if(type == RenderableTypes::GRASS) {
2019-06-03 22:31:20 +02:00
if (m_is_grass_enabled && !m_terrains.empty()) {
2019-07-04 18:21:35 +02:00
PageAllocator& page_allocator = m_engine.getPageAllocator();
CullResult* result = (CullResult*)page_allocator.allocate(true);
CullResult* iter = result;
result->header.count = 0;
result->header.next = nullptr;
2019-06-03 22:31:20 +02:00
for (auto* terrain : m_terrains) {
2019-07-04 18:21:35 +02:00
terrain->updateGrass(0, frustum.origin);
if(iter->header.count == lengthOf(iter->entities)) {
iter->header.next = (CullResult*)page_allocator.allocate(true);
iter->header.next->header.next = nullptr;
iter->header.next->header.count = 0;
iter = iter->header.next;
}
iter->entities[iter->header.count] = terrain->m_entity;
++iter->header.count;
2019-06-03 22:31:20 +02:00
}
2019-07-04 18:21:35 +02:00
return result;
2019-06-03 22:31:20 +02:00
}
2019-07-04 18:21:35 +02:00
}
return m_culling_system->cull(frustum, static_cast<u8>(type));
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2014-11-16 19:31:51 +01:00
2018-08-19 17:35:37 +02:00
float getCameraScreenWidth(EntityRef camera) override { return m_cameras[camera].screen_width; }
float getCameraScreenHeight(EntityRef camera) override { return m_cameras[camera].screen_height; }
2016-04-17 21:47:54 +02:00
2016-09-17 01:00:38 +02:00
void setGlobalLODMultiplier(float multiplier) { m_lod_multiplier = multiplier; }
float getGlobalLODMultiplier() const { return m_lod_multiplier; }
2019-06-13 17:26:52 +02:00
Camera& getCamera(EntityRef entity) override { return m_cameras[entity]; }
2018-08-19 17:35:37 +02:00
Matrix getCameraProjection(EntityRef entity) override
2016-04-17 21:47:54 +02:00
{
2018-06-30 15:18:27 +02:00
const Camera& camera = m_cameras[entity];
2016-04-17 21:47:54 +02:00
Matrix mtx;
2018-06-30 15:18:27 +02:00
const float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
2019-10-24 21:53:19 +02:00
const bool is_homogenous_depth = gpu::isHomogenousDepth();
2018-06-30 15:18:27 +02:00
if (camera.is_ortho) {
2016-04-17 21:47:54 +02:00
mtx.setOrtho(-camera.ortho_size * ratio,
camera.ortho_size * ratio,
-camera.ortho_size,
camera.ortho_size,
2016-04-17 21:47:54 +02:00
camera.near,
camera.far,
2018-04-17 02:41:01 +02:00
is_homogenous_depth,
true);
2016-04-17 21:47:54 +02:00
}
2018-06-30 15:18:27 +02:00
else {
2018-04-17 02:41:01 +02:00
mtx.setPerspective(camera.fov, ratio, camera.near, camera.far, is_homogenous_depth, true);
2016-04-17 21:47:54 +02:00
}
return mtx;
}
2018-08-19 17:35:37 +02:00
void setCameraScreenSize(EntityRef camera, int w, int h) override
2016-04-17 21:47:54 +02:00
{
auto& cam = m_cameras[{camera.index}];
cam.screen_width = (float)w;
cam.screen_height = (float)h;
2016-04-17 21:47:54 +02:00
}
2018-08-19 17:35:37 +02:00
Vec2 getCameraScreenSize(EntityRef camera) override
{
auto& cam = m_cameras[{camera.index}];
return Vec2(cam.screen_width, cam.screen_height);
}
2019-07-04 15:10:53 +02:00
void clearDebugLines() override { m_debug_lines.clear(); }
void clearDebugTriangles() override { m_debug_triangles.clear(); }
const Array<DebugTriangle>& getDebugTriangles() const override { return m_debug_triangles; }
const Array<DebugLine>& getDebugLines() const override { return m_debug_lines; }
2019-06-14 18:54:41 +02:00
void addDebugHalfSphere(const RigidTransform& transform, float radius, bool top, u32 color)
2016-06-28 19:48:50 +02:00
{
2018-09-16 18:35:57 +02:00
const DVec3 center = transform.pos;
const Vec3 x_vec = transform.rot * Vec3(1, 0, 0);
const Vec3 y_vec = transform.rot * Vec3(0, top ? 1.f : -1.f, 0);
const Vec3 z_vec = transform.rot * Vec3(0, 0, 1);
2016-06-28 19:48:50 +02:00
static const int COLS = 36;
static const int ROWS = COLS >> 1;
2019-06-13 17:26:52 +02:00
static const float STEP = degreesToRadians(360.0f) / COLS;
2016-06-28 19:48:50 +02:00
for (int y = 0; y < ROWS >> 1; ++y)
{
2019-07-29 18:03:08 +02:00
float cy = cosf(y * STEP);
float cy1 = cosf((y + 1) * STEP);
float sy = sinf(y * STEP);
float sy1 = sinf((y + 1) * STEP);
float prev_ci = cosf(-STEP);
float prev_si = sinf(-STEP);
2016-06-28 19:48:50 +02:00
Vec3 y_offset = y_vec * sy;
Vec3 y_offset1 = y_vec * sy1;
for (int i = 0; i < COLS; ++i)
{
2019-07-29 18:03:08 +02:00
float ci = cosf(i * STEP);
float si = sinf(i * STEP);
2016-06-28 19:48:50 +02:00
addDebugLine(
center + radius * (x_vec * ci * cy + z_vec * si * cy + y_offset),
center + radius * (x_vec * prev_ci * cy + z_vec * prev_si * cy + y_offset),
2019-06-14 18:54:41 +02:00
color);
2016-06-28 19:48:50 +02:00
addDebugLine(
center + radius * (x_vec * ci * cy + z_vec * si * cy + y_offset),
center + radius * (x_vec * ci * cy1 + z_vec * si * cy1 + y_offset1),
2019-06-14 18:54:41 +02:00
color);
2016-06-28 19:48:50 +02:00
prev_ci = ci;
prev_si = si;
}
}
}
2019-06-14 18:54:41 +02:00
void addDebugHalfSphere(const DVec3& center, float radius, bool top, u32 color)
{
static const int COLS = 36;
static const int ROWS = COLS >> 1;
2019-06-13 17:26:52 +02:00
static const float STEP = (PI / 180.0f) * 360.0f / COLS;
int p2 = COLS >> 1;
int yfrom = top ? 0 : -(ROWS >> 1);
int yto = top ? ROWS >> 1 : 0;
for (int y = yfrom; y < yto; ++y)
{
2019-07-29 18:03:08 +02:00
float cy = cosf(y * STEP);
float cy1 = cosf((y + 1) * STEP);
float sy = sinf(y * STEP);
float sy1 = sinf((y + 1) * STEP);
float prev_ci = cosf((-p2 - 1) * STEP);
float prev_si = sinf((-p2 - 1) * STEP);
for (int i = -p2; i < p2; ++i)
{
2019-07-29 18:03:08 +02:00
float ci = cosf(i * STEP);
float si = sinf(i * STEP);
2018-09-16 18:35:57 +02:00
addDebugLine(DVec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
2018-09-16 18:35:57 +02:00
DVec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
2019-06-14 18:54:41 +02:00
color);
2018-09-16 18:35:57 +02:00
addDebugLine(DVec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
2018-09-16 18:35:57 +02:00
DVec3(center.x + radius * prev_ci * cy,
center.y + radius * sy,
center.z + radius * prev_si * cy),
2019-06-14 18:54:41 +02:00
color);
2018-09-16 18:35:57 +02:00
addDebugLine(DVec3(center.x + radius * prev_ci * cy1,
center.y + radius * sy1,
center.z + radius * prev_si * cy1),
2018-09-16 18:35:57 +02:00
DVec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
2019-06-14 18:54:41 +02:00
color);
prev_ci = ci;
prev_si = si;
}
}
}
2018-09-16 18:35:57 +02:00
void addDebugTriangle(const DVec3& p0,
const DVec3& p1,
const DVec3& p2,
2019-06-14 18:54:41 +02:00
u32 color) override
2016-03-10 19:32:48 +01:00
{
DebugTriangle& tri = m_debug_triangles.emplace();
tri.p0 = p0;
tri.p1 = p1;
tri.p2 = p2;
tri.color = ARGBToABGR(color);
}
2018-09-16 18:35:57 +02:00
void addDebugCube(const DVec3& pos,
2015-10-24 12:25:06 +02:00
const Vec3& dir,
const Vec3& up,
const Vec3& right,
2019-06-14 18:54:41 +02:00
u32 color) override
{
2019-06-14 18:54:41 +02:00
addDebugLine(pos + dir + up + right, pos + dir + up - right, color);
addDebugLine(pos - dir + up + right, pos - dir + up - right, color);
addDebugLine(pos + dir + up + right, pos - dir + up + right, color);
addDebugLine(pos + dir + up - right, pos - dir + up - right, color);
2019-06-14 18:54:41 +02:00
addDebugLine(pos + dir - up + right, pos + dir - up - right, color);
addDebugLine(pos - dir - up + right, pos - dir - up - right, color);
addDebugLine(pos + dir - up + right, pos - dir - up + right, color);
addDebugLine(pos + dir - up - right, pos - dir - up - right, color);
2019-06-14 18:54:41 +02:00
addDebugLine(pos + dir + up + right, pos + dir - up + right, color);
addDebugLine(pos + dir + up - right, pos + dir - up - right, color);
addDebugLine(pos - dir + up + right, pos - dir - up + right, color);
addDebugLine(pos - dir + up - right, pos - dir - up - right, color);
}
2018-09-16 18:35:57 +02:00
void addDebugCubeSolid(const DVec3& min,
const DVec3& max,
2019-06-14 18:54:41 +02:00
u32 color) override
2016-03-11 17:25:14 +01:00
{
2018-09-16 18:35:57 +02:00
DVec3 a = min;
DVec3 b = min;
DVec3 c = max;
2016-03-11 17:25:14 +01:00
b.x = max.x;
c.z = min.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
b.x = min.x;
b.y = max.y;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
b = max;
c = max;
a.z = max.z;
b.y = min.y;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
b.x = min.x;
b.y = max.y;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
a = min;
b = min;
c = max;
b.x = max.x;
c.y = min.y;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
b.x = min.x;
b.z = max.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
b = max;
c = max;
a.y = max.y;
b.z = min.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
b.x = min.x;
b.z = max.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
a = min;
b = min;
c = max;
b.y = max.y;
c.x = min.x;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
b.y = min.y;
b.z = max.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
b = max;
c = max;
a.x = max.x;
b.z = min.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, b, c, color);
2016-03-11 17:25:14 +01:00
b.y = min.y;
b.z = max.z;
2019-06-14 18:54:41 +02:00
addDebugTriangle(a, c, b, color);
2016-03-11 17:25:14 +01:00
}
2018-09-16 18:35:57 +02:00
void addDebugCube(const DVec3& min,
const DVec3& max,
2019-06-14 18:54:41 +02:00
u32 color) override
2015-07-21 20:10:50 +02:00
{
2018-09-16 18:35:57 +02:00
DVec3 a = min;
DVec3 b = min;
2015-07-21 20:10:50 +02:00
b.x = max.x;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
a = DVec3(b.x, b.y, max.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
b = DVec3(min.x, a.y, a.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
a = DVec3(b.x, b.y, min.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
a = min;
a.y = max.y;
b = a;
b.x = max.x;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
a = DVec3(b.x, b.y, max.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
b = DVec3(min.x, a.y, a.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2018-09-16 18:35:57 +02:00
a = DVec3(b.x, b.y, min.z);
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
a = min;
b = a;
b.y = max.y;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
a.x = max.x;
b.x = max.x;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
a.z = max.z;
b.z = max.z;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
a.x = min.x;
b.x = min.x;
2019-06-14 18:54:41 +02:00
addDebugLine(a, b, color);
2015-07-21 20:10:50 +02:00
}
2014-12-17 21:33:27 +01:00
2019-06-14 18:54:41 +02:00
void addDebugCross(const DVec3& center, float size, u32 color) override
2015-07-21 20:10:50 +02:00
{
2019-06-14 18:54:41 +02:00
addDebugLine(center, DVec3(center.x - size, center.y, center.z), color);
addDebugLine(center, DVec3(center.x + size, center.y, center.z), color);
addDebugLine(center, DVec3(center.x, center.y - size, center.z), color);
addDebugLine(center, DVec3(center.x, center.y + size, center.z), color);
addDebugLine(center, DVec3(center.x, center.y, center.z - size), color);
addDebugLine(center, DVec3(center.x, center.y, center.z + size), color);
}
2016-11-20 17:27:41 +01:00
static u32 ARGBToABGR(u32 color)
2015-07-21 20:10:50 +02:00
{
2016-06-16 19:24:15 +02:00
return ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16) | (color & 0xff000000);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2019-06-14 18:54:41 +02:00
void addDebugLine(const DVec3& from, const DVec3& to, u32 color) override
2015-07-21 20:10:50 +02:00
{
2016-01-14 16:22:25 +01:00
DebugLine& line = m_debug_lines.emplace();
2016-03-10 19:32:48 +01:00
line.from = from;
line.to = to;
line.color = ARGBToABGR(color);
2019-06-14 18:54:41 +02:00
}
2019-11-11 21:30:12 +01:00
2019-11-17 19:45:54 +01:00
Span<LightProbeGrid> getLightProbeGrids() override {
return Span(m_light_probe_grids.begin(), m_light_probe_grids.size());
}
2019-11-11 21:30:12 +01:00
LightProbeGrid& getLightProbeGrid(EntityRef entity) override {
return m_light_probe_grids[entity];
}
2019-06-14 18:54:41 +02:00
2019-12-20 19:25:33 +01:00
DebugTriangle* addDebugTriangles(int count) override
2019-06-14 18:54:41 +02:00
{
2019-09-10 18:12:05 +02:00
const u32 new_size = m_debug_triangles.size() + count;
2019-06-14 18:54:41 +02:00
if (new_size < m_debug_triangles.capacity()) {
m_debug_triangles.reserve(maximum(new_size, m_debug_triangles.capacity() * 3 / 2));
}
m_debug_triangles.resize(new_size);
return &m_debug_triangles[new_size - count];
}
DebugLine* addDebugLines(int count) override
{
2019-09-10 18:12:05 +02:00
const u32 new_size = m_debug_lines.size() + count;
2019-06-14 18:54:41 +02:00
if (new_size < m_debug_lines.capacity()) {
m_debug_lines.reserve(maximum(new_size, m_debug_lines.capacity() * 3 / 2));
}
m_debug_lines.resize(new_size);
return &m_debug_lines[new_size - count];
2015-07-21 20:10:50 +02:00
}
2015-07-04 11:36:33 +02:00
2015-07-23 23:17:51 +02:00
2018-09-16 18:35:57 +02:00
RayCastModelHit castRayTerrain(EntityRef entity, const DVec3& origin, const Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
RayCastModelHit hit;
2018-09-20 23:17:45 +02:00
hit.is_hit = false;
2018-01-12 17:01:26 +01:00
auto iter = m_terrains.find(entity);
if (!iter.isValid()) return hit;
2018-09-20 23:17:45 +02:00
Terrain* terrain = iter.value();
hit = terrain->castRay(origin, dir);
2018-09-20 23:17:45 +02:00
hit.component_type = TERRAIN_TYPE;
hit.entity = terrain->getEntity();
2015-07-21 20:10:50 +02:00
return hit;
}
2018-09-16 18:35:57 +02:00
RayCastModelHit castRay(const DVec3& origin, const Vec3& dir, EntityPtr ignored_model_instance) override
2015-07-21 20:10:50 +02:00
{
2018-09-20 23:17:45 +02:00
PROFILE_FUNCTION();
2015-07-21 20:10:50 +02:00
RayCastModelHit hit;
2018-09-20 23:17:45 +02:00
hit.is_hit = false;
double cur_dist = DBL_MAX;
const Universe& universe = getUniverse();
for (int i = 0; i < m_model_instances.size(); ++i) {
auto& r = m_model_instances[i];
2016-11-09 10:09:33 +01:00
if (ignored_model_instance.index == i || !r.model) continue;
2017-12-09 00:15:41 +01:00
if (!r.flags.isSet(ModelInstance::ENABLED)) continue;
2016-11-09 10:09:33 +01:00
const EntityRef entity{i};
2018-09-20 23:17:45 +02:00
const DVec3& pos = universe.getPosition(entity);
2018-08-19 17:35:37 +02:00
float scale = universe.getScale(entity);
2017-08-18 21:43:16 +02:00
float radius = r.model->getBoundingRadius() * scale;
2018-09-20 23:17:45 +02:00
const double dist = (pos - origin).length();
2017-08-18 21:43:16 +02:00
if (dist - radius > cur_dist) continue;
2016-11-09 10:09:33 +01:00
Vec3 intersection;
2018-09-20 23:17:45 +02:00
const Vec3 rel_pos = (origin - pos).toFloat();
2019-06-13 17:26:52 +02:00
if (getRaySphereIntersection(rel_pos, dir, Vec3::ZERO, radius, intersection)) {
2018-12-16 11:23:24 +01:00
RayCastModelHit new_hit = r.model->castRay(rel_pos / scale, dir, r.pose);
if (new_hit.is_hit && (!hit.is_hit || new_hit.t * scale < hit.t)) {
2018-09-20 23:17:45 +02:00
new_hit.entity = entity;
new_hit.component_type = MODEL_INSTANCE_TYPE;
2016-11-09 10:09:33 +01:00
hit = new_hit;
2018-12-16 11:23:24 +01:00
hit.t *= scale;
2018-09-20 23:17:45 +02:00
hit.is_hit = true;
cur_dist = dir.length() * hit.t;
2014-07-20 18:14:37 +02:00
}
2014-06-16 21:18:15 +02:00
}
2015-07-21 20:10:50 +02:00
}
2016-11-09 10:09:33 +01:00
2018-09-20 23:17:45 +02:00
for (auto* terrain : m_terrains) {
RayCastModelHit terrain_hit = terrain->castRay(origin, dir);
2018-09-20 23:17:45 +02:00
if (terrain_hit.is_hit && (!hit.is_hit || terrain_hit.t < hit.t)) {
terrain_hit.component_type = TERRAIN_TYPE;
terrain_hit.entity = terrain->getEntity();
terrain_hit.mesh = nullptr;
hit = terrain_hit;
2015-02-18 00:34:22 +01:00
}
2015-07-21 20:10:50 +02:00
}
2016-11-09 10:09:33 +01:00
2019-11-17 19:45:54 +01:00
hit.origin = origin;
hit.dir = dir;
2018-09-20 23:17:45 +02:00
return hit;
2015-07-21 20:10:50 +02:00
}
2015-02-18 00:34:22 +01:00
2018-08-19 17:35:37 +02:00
Vec4 getShadowmapCascades(EntityRef entity) override
{
2019-11-26 16:50:08 +01:00
return m_environments[entity].cascades;
}
2018-08-19 17:35:37 +02:00
void setShadowmapCascades(EntityRef entity, const Vec4& value) override
{
Vec4 valid_value = value;
2019-06-13 17:26:52 +02:00
valid_value.x = maximum(valid_value.x, 0.02f);
valid_value.y = maximum(valid_value.x + 0.01f, valid_value.y);
valid_value.z = maximum(valid_value.y + 0.01f, valid_value.z);
valid_value.w = maximum(valid_value.z + 0.01f, valid_value.w);
2019-11-26 16:50:08 +01:00
m_environments[entity].cascades = valid_value;
2015-07-21 20:10:50 +02:00
}
2015-02-18 00:34:22 +01:00
2018-08-19 17:35:37 +02:00
float getLightRange(EntityRef entity) override
2015-09-04 14:00:28 +02:00
{
2019-05-18 23:24:07 +02:00
return m_point_lights[entity].range;
2015-07-21 20:10:50 +02:00
}
2018-08-19 17:35:37 +02:00
void setLightRange(EntityRef entity, float value) override
2015-09-09 02:18:09 +02:00
{
2019-05-18 23:24:07 +02:00
m_point_lights[entity].range = value;
2018-10-20 21:35:03 +02:00
m_culling_system->setRadius(entity, value);
2015-09-09 02:18:09 +02:00
}
void setActiveEnvironment(EntityRef entity) override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
m_active_global_light_entity = entity;
2015-07-21 20:10:50 +02:00
}
EntityPtr getActiveEnvironment() override
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
return m_active_global_light_entity;
}
2018-09-05 20:45:06 +02:00
void getEnvironmentProbes(Array<EnvProbeInfo>& probes) override
{
// TODO probes in culling system
2018-09-05 20:45:06 +02:00
PROFILE_FUNCTION();
2018-09-15 09:55:46 +02:00
probes.reserve(m_environment_probes.size());
2018-09-05 20:45:06 +02:00
for (int i = 0; i < m_environment_probes.size(); ++i) {
const EnvironmentProbe& probe = m_environment_probes.at(i);
const EntityRef entity = m_environment_probes.getKey(i);
2018-09-15 09:55:46 +02:00
if(!probe.flags.isSet(EnvironmentProbe::ENABLED)) continue;
EnvProbeInfo& out = probes.emplace();
2019-11-14 22:26:43 +01:00
out.half_extents = probe.half_extents;
2018-09-05 20:45:06 +02:00
out.position = m_universe.getPosition(entity);
2019-11-10 17:16:46 +01:00
out.radiance = probe.flags.isSet(EnvironmentProbe::SPECULAR) && probe.radiance && probe.radiance->isReady() ? probe.radiance->handle : gpu::INVALID_TEXTURE;
2019-11-14 22:26:43 +01:00
out.reflection = probe.flags.isSet(EnvironmentProbe::REFLECTION) && probe.reflection && probe.reflection->isReady() ? probe.reflection->handle : gpu::INVALID_TEXTURE;
out.use_irradiance = probe.flags.isSet(EnvironmentProbe::DIFFUSE);
memcpy(out.sh_coefs, probe.sh_coefs, sizeof(out.sh_coefs));
2018-09-05 20:45:06 +02:00
}
}
2018-09-15 09:55:46 +02:00
2019-09-23 23:33:43 +02:00
Span<EntityRef> getAllEnvironmentProbes() override {
return m_environment_probes.keys();
}
2018-09-15 09:55:46 +02:00
2019-06-13 17:26:52 +02:00
EnvironmentProbe& getEnvironmentProbe(EntityRef entity) override
2018-09-15 09:55:46 +02:00
{
2019-06-13 17:26:52 +02:00
return m_environment_probes[entity];
2018-09-15 09:55:46 +02:00
}
2019-06-13 17:26:52 +02:00
void enableEnvironmentProbe(EntityRef entity, bool enable) override
{
2019-06-13 17:26:52 +02:00
return m_environment_probes[entity].flags.set(EnvironmentProbe::ENABLED, enable);
}
2019-06-13 17:26:52 +02:00
bool isEnvironmentProbeEnabled(EntityRef entity) override
{
2019-06-13 17:26:52 +02:00
return m_environment_probes[entity].flags.isSet(EnvironmentProbe::ENABLED);
}
2018-08-19 17:35:37 +02:00
bool isEnvironmentProbeCustomSize(EntityRef entity) override
{
return m_environment_probes[entity].flags.isSet(EnvironmentProbe::OVERRIDE_GLOBAL_SIZE);
}
2018-08-19 17:35:37 +02:00
void enableEnvironmentProbeCustomSize(EntityRef entity, bool enable) override
{
m_environment_probes[entity].flags.set(EnvironmentProbe::OVERRIDE_GLOBAL_SIZE, enable);
}
2018-08-19 17:35:37 +02:00
bool isEnvironmentProbeReflectionEnabled(EntityRef entity) override
{
return m_environment_probes[entity].flags.isSet(EnvironmentProbe::REFLECTION);
}
2018-08-19 17:35:37 +02:00
void enableEnvironmentProbeReflection(EntityRef entity, bool enable) override
{
2019-11-14 22:26:43 +01:00
EnvironmentProbe& p = m_environment_probes[entity];
p.flags.set(EnvironmentProbe::REFLECTION, enable);
if (enable) {
ResourceManagerHub& rm = m_engine.getResourceManager();
StaticString<MAX_PATH_LENGTH> path("universes/", m_universe.getName(), "/probes/", p.guid, ".dds");
p.reflection = rm.load<Texture>(Path(path));
}
else {
2019-11-17 23:12:50 +01:00
if (p.reflection) {
p.reflection->getResourceManager().unload(*p.reflection);
p.reflection = nullptr;
}
2019-11-14 22:26:43 +01:00
}
}
bool isEnvironmentProbeSpecular(EntityRef entity) override
{
return m_environment_probes[entity].flags.isSet(EnvironmentProbe::SPECULAR);
}
void enableEnvironmentProbeSpecular(EntityRef entity, bool enable) override
{
2019-11-14 22:26:43 +01:00
EnvironmentProbe& p = m_environment_probes[entity];
p.flags.set(EnvironmentProbe::SPECULAR, enable);
if (enable) {
ResourceManagerHub& rm = m_engine.getResourceManager();
StaticString<MAX_PATH_LENGTH> path("universes/", m_universe.getName(), "/probes/", p.guid, "_radiance.dds");
p.radiance = rm.load<Texture>(Path(path));
}
else {
2019-11-17 23:12:50 +01:00
if (p.radiance) {
p.radiance->getResourceManager().unload(*p.radiance);
p.radiance = nullptr;
}
2019-11-14 22:26:43 +01:00
}
}
bool isEnvironmentProbeDiffuse(EntityRef entity) override
{
return m_environment_probes[entity].flags.isSet(EnvironmentProbe::DIFFUSE);
}
void enableEnvironmentProbeDiffuse(EntityRef entity, bool enable) override
{
m_environment_probes[entity].flags.set(EnvironmentProbe::DIFFUSE, enable);
}
float getTime() const override { return m_time; }
2018-08-19 17:35:37 +02:00
void modelUnloaded(Model*, EntityRef entity)
2016-01-10 13:41:12 +01:00
{
2018-01-12 17:01:26 +01:00
auto& r = m_model_instances[entity.index];
2018-09-26 20:35:30 +02:00
r.meshes = nullptr;
r.mesh_count = 0;
2016-02-06 15:20:34 +01:00
LUMIX_DELETE(m_allocator, r.pose);
r.pose = nullptr;
2018-09-15 15:06:37 +02:00
m_culling_system->remove(entity);
2016-01-10 13:41:12 +01:00
}
2018-08-19 17:35:37 +02:00
void modelLoaded(Model* model, EntityRef entity)
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
auto& r = m_model_instances[entity.index];
2017-11-07 16:49:18 +01:00
float bounding_radius = r.model->getBoundingRadius();
2018-08-19 17:35:37 +02:00
float scale = m_universe.getScale(entity);
2018-09-16 18:35:57 +02:00
const DVec3 pos = m_universe.getPosition(entity);
2018-09-15 15:06:37 +02:00
const float radius = bounding_radius * scale;
2018-09-23 18:18:18 +02:00
if(r.flags.isSet(ModelInstance::ENABLED)) {
2018-09-29 15:14:46 +02:00
const RenderableTypes type = getRenderableType(*model);
2018-09-23 18:18:18 +02:00
m_culling_system->add(entity, (u8)type, pos, radius);
}
2016-02-06 11:20:21 +01:00
ASSERT(!r.pose);
if (model->getBoneCount() > 0)
{
r.pose = LUMIX_NEW(m_allocator, Pose)(m_allocator);
r.pose->resize(model->getBoneCount());
model->getPose(*r.pose);
}
r.meshes = &r.model->getMesh(0);
r.mesh_count = r.model->getMeshCount();
2015-07-21 20:10:50 +02:00
if (r.flags.isSet(ModelInstance::IS_BONE_ATTACHMENT_PARENT))
{
2018-08-19 17:35:37 +02:00
updateBoneAttachment(m_bone_attachments[entity]);
}
2019-06-05 01:45:55 +02:00
while (m_mesh_sort_data.size() < m_model_instances.size()) {
m_mesh_sort_data.emplace();
}
2019-06-13 00:01:11 +02:00
m_mesh_sort_data[entity.index].layer = r.meshes[0].layer;
m_mesh_sort_data[entity.index].sort_key = r.meshes[0].sort_key;
2015-07-21 20:10:50 +02:00
}
2016-01-10 13:41:12 +01:00
void modelUnloaded(Model* model)
2016-01-10 13:41:12 +01:00
{
for (int i = 0, c = m_model_instances.size(); i < c; ++i)
2016-01-10 13:41:12 +01:00
{
if (m_model_instances[i].flags.isSet(ModelInstance::VALID) && m_model_instances[i].model == model)
2016-01-10 13:41:12 +01:00
{
2016-06-22 15:05:19 +02:00
modelUnloaded(model, {i});
2016-01-10 13:41:12 +01:00
}
}
}
2015-07-21 20:10:50 +02:00
void modelLoaded(Model* model)
{
2018-09-08 22:00:02 +02:00
auto map_iter = m_model_entity_map.find(model);
2018-09-08 20:47:11 +02:00
EntityPtr e = map_iter.value();
while(e.isValid()) {
modelLoaded(model, (EntityRef)e);
e = m_model_instances[e.index].next_model;
2015-07-21 20:10:50 +02:00
}
}
2018-09-08 20:47:11 +02:00
2018-10-13 15:08:58 +02:00
void addToMaterialDecalMap(Material* material, EntityRef entity)
{
Decal& d = m_decals[entity];
d.prev_decal = INVALID_ENTITY;
auto map_iter = m_material_decal_map.find(material);
if(map_iter.isValid()) {
d.next_decal = map_iter.value();
m_material_decal_map[material] = entity;
}
else {
d.next_decal = INVALID_ENTITY;
m_material_decal_map.insert(material, entity);
2020-01-07 19:17:48 +01:00
material->getObserverCb().bind<&RenderSceneImpl::decalMaterialStateChanged>(this);
2018-10-13 15:08:58 +02:00
}
}
2018-09-08 22:00:02 +02:00
void addToModelEntityMap(Model* model, EntityRef entity)
2018-09-08 20:47:11 +02:00
{
ModelInstance& r = m_model_instances[entity.index];
r.prev_model = INVALID_ENTITY;
2018-09-08 22:00:02 +02:00
auto map_iter = m_model_entity_map.find(model);
2018-09-08 20:47:11 +02:00
if(map_iter.isValid()) {
r.next_model = map_iter.value();
2018-09-08 22:00:02 +02:00
m_model_entity_map[model] = entity;
2018-09-08 20:47:11 +02:00
}
else {
r.next_model = INVALID_ENTITY;
2018-09-08 22:00:02 +02:00
m_model_entity_map.insert(model, entity);
2020-01-07 19:17:48 +01:00
model->getObserverCb().bind<&RenderSceneImpl::modelStateChanged>(this);
2018-09-08 20:47:11 +02:00
}
}
2018-09-08 22:00:02 +02:00
void removeFromModelEntityMap(Model* model, EntityRef entity)
2018-09-08 20:47:11 +02:00
{
ModelInstance& r = m_model_instances[entity.index];
if(r.prev_model.isValid()) {
m_model_instances[r.prev_model.index].next_model = r.next_model;
}
if(r.next_model.isValid()) {
m_model_instances[r.next_model.index].prev_model = r.prev_model;
}
2018-09-08 22:00:02 +02:00
auto map_iter = m_model_entity_map.find(model);
2018-09-08 20:47:11 +02:00
if(map_iter.value() == entity) {
if(r.next_model.isValid()) {
2018-09-08 22:00:02 +02:00
m_model_entity_map[model] = (EntityRef)r.next_model;
2018-09-08 20:47:11 +02:00
}
else {
2018-09-08 22:00:02 +02:00
m_model_entity_map.erase(model);
2020-01-07 19:17:48 +01:00
model->getObserverCb().unbind<&RenderSceneImpl::modelStateChanged>(this);
2018-09-08 20:47:11 +02:00
}
}
}
2018-10-13 15:08:58 +02:00
2018-09-08 20:47:11 +02:00
2018-10-13 15:08:58 +02:00
void removeFromMaterialDecalMap(Material* material, EntityRef entity)
{
Decal& d = m_decals[entity];
if(d.prev_decal.isValid()) {
m_decals[(EntityRef)d.prev_decal].next_decal = d.next_decal;
}
if(d.next_decal.isValid()) {
m_decals[(EntityRef)d.next_decal].prev_decal = d.prev_decal;
}
auto map_iter = m_material_decal_map.find(material);
if(map_iter.value() == entity) {
if(d.next_decal.isValid()) {
m_material_decal_map[material] = (EntityRef)d.next_decal;
}
else {
m_material_decal_map.erase(material);
2020-01-07 19:17:48 +01:00
material->getObserverCb().unbind<&RenderSceneImpl::decalMaterialStateChanged>(this);
2018-10-13 15:08:58 +02:00
}
}
}
2018-08-19 17:35:37 +02:00
void setModel(EntityRef entity, Model* model)
2015-07-21 20:10:50 +02:00
{
2018-01-12 17:01:26 +01:00
auto& model_instance = m_model_instances[entity.index];
ASSERT(model_instance.flags.isSet(ModelInstance::VALID));
Model* old_model = model_instance.model;
bool no_change = model == old_model && old_model;
if (no_change)
2015-07-21 20:10:50 +02:00
{
2016-07-25 01:02:36 +02:00
old_model->getResourceManager().unload(*old_model);
2015-07-21 20:10:50 +02:00
return;
}
if (old_model)
{
2018-09-08 22:00:02 +02:00
removeFromModelEntityMap(old_model, entity);
2016-05-12 07:48:51 +02:00
2015-12-10 23:33:21 +01:00
if (old_model->isReady())
{
2018-09-15 15:06:37 +02:00
m_culling_system->remove(entity);
2015-12-10 23:33:21 +01:00
}
2016-07-25 01:02:36 +02:00
old_model->getResourceManager().unload(*old_model);
2015-07-21 20:10:50 +02:00
}
model_instance.model = model;
model_instance.meshes = nullptr;
model_instance.mesh_count = 0;
LUMIX_DELETE(m_allocator, model_instance.pose);
model_instance.pose = nullptr;
2015-07-21 20:10:50 +02:00
if (model)
{
2018-09-08 22:00:02 +02:00
addToModelEntityMap(model, entity);
2015-07-21 20:10:50 +02:00
if (model->isReady())
{
2018-01-12 17:01:26 +01:00
modelLoaded(model, entity);
2015-07-21 20:10:50 +02:00
}
}
}
2015-04-08 00:32:36 +02:00
IAllocator& getAllocator() override { return m_allocator; }
2015-04-08 00:32:36 +02:00
2019-11-11 21:30:12 +01:00
void createLightProbeGrid(EntityRef entity) {
LightProbeGrid lp = {};
lp.entity = entity;
lp.guid = randGUID();
lp.resolution = IVec3(32, 8, 32);
2019-11-17 19:45:54 +01:00
lp.half_extents = Vec3(16.f, 4.f, 16.f);
2019-11-11 21:30:12 +01:00
loadLightProbeGridData(lp);
m_light_probe_grids.insert(entity, lp);
m_universe.onComponentCreated(entity, LIGHT_PROBE_GRID_TYPE, this);
}
2015-04-08 00:32:36 +02:00
void createEnvironment(EntityRef entity)
2015-07-21 20:10:50 +02:00
{
Environment light;
2019-07-13 21:13:21 +02:00
light.flags.set(Environment::CAST_SHADOWS);
2019-11-26 16:50:08 +01:00
light.entity = entity;
light.diffuse_color.set(1, 1, 1);
light.diffuse_intensity = 0;
light.indirect_intensity = 1;
light.fog_color.set(1, 1, 1);
light.fog_density = 0;
light.cascades.set(3, 8, 100, 300);
light.fog_bottom = 0.0f;
light.fog_height = 10.0f;
2015-07-21 20:10:50 +02:00
if (m_environments.empty()) m_active_global_light_entity = entity;
2015-07-21 20:10:50 +02:00
m_environments.insert(entity, light);
m_universe.onComponentCreated(entity, ENVIRONMENT_TYPE, this);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
2018-08-19 17:35:37 +02:00
void createPointLight(EntityRef entity)
2014-06-16 21:18:15 +02:00
{
2018-10-20 21:35:03 +02:00
PointLight light;
2019-05-18 23:24:07 +02:00
light.entity = entity;
light.color.set(1, 1, 1);
light.intensity = 1;
2019-06-13 17:26:52 +02:00
light.fov = degreesToRadians(360);
2019-05-18 23:24:07 +02:00
light.cast_shadows = false;
light.attenuation_param = 2;
light.range = 10;
2018-10-20 21:35:03 +02:00
const DVec3 pos = m_universe.getPosition(entity);
m_point_lights.insert(entity, light);
2019-05-18 23:24:07 +02:00
m_culling_system->add(entity, (u8)RenderableTypes::LOCAL_LIGHT, pos, light.range);
2015-07-21 20:10:50 +02:00
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, POINT_LIGHT_TYPE, this);
2014-06-16 21:18:15 +02:00
}
2016-07-22 13:57:52 +02:00
void updateDecalInfo(Decal& decal) const
{
2018-10-10 23:41:26 +02:00
decal.radius = decal.half_extents.length();
decal.transform = m_universe.getTransform(decal.entity);
2016-07-22 13:57:52 +02:00
}
2018-08-19 17:35:37 +02:00
void createDecal(EntityRef entity)
2016-07-22 13:57:52 +02:00
{
2018-10-13 15:08:58 +02:00
m_decals.insert(entity, Decal());
Decal& decal = m_decals[entity];
2016-07-22 13:57:52 +02:00
decal.material = nullptr;
decal.entity = entity;
2018-10-10 23:41:26 +02:00
decal.half_extents.set(1, 1, 1);
2016-07-22 13:57:52 +02:00
updateDecalInfo(decal);
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, DECAL_TYPE, this);
2016-07-22 13:57:52 +02:00
}
2018-08-19 17:35:37 +02:00
void createEnvironmentProbe(EntityRef entity)
2016-06-12 15:26:41 +02:00
{
2016-07-24 17:29:17 +02:00
EnvironmentProbe& probe = m_environment_probes.insert(entity);
probe.guid = randGUID();
2019-09-23 23:33:43 +02:00
StaticString<MAX_PATH_LENGTH> path;
2019-11-14 22:26:43 +01:00
probe.reflection = nullptr;
probe.radiance = nullptr;
2019-09-23 23:33:43 +02:00
2019-11-14 22:26:43 +01:00
probe.half_extents = Vec3(9001.f);
2018-09-15 09:55:46 +02:00
probe.flags.set(EnvironmentProbe::ENABLED);
probe.flags.set(EnvironmentProbe::DIFFUSE);
2019-11-14 22:26:43 +01:00
memset(probe.sh_coefs, 0, sizeof(probe.sh_coefs));
2016-06-12 15:26:41 +02:00
2018-07-05 15:54:14 +02:00
m_universe.onComponentCreated(entity, ENVIRONMENT_PROBE_TYPE, this);
2016-06-12 15:26:41 +02:00
}
2018-08-19 17:35:37 +02:00
void createBoneAttachment(EntityRef entity)
2016-05-02 21:41:18 +02:00
{
BoneAttachment& attachment = m_bone_attachments.emplace(entity);
2016-05-02 21:41:18 +02:00
attachment.entity = entity;
attachment.parent_entity = INVALID_ENTITY;
attachment.bone_index = -1;
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, BONE_ATTACHMENT_TYPE, this);
2016-05-02 21:41:18 +02:00
}
2018-08-19 17:35:37 +02:00
void createModelInstance(EntityRef entity)
2014-06-16 21:18:15 +02:00
{
while(entity.index >= m_model_instances.size())
2015-12-10 17:09:52 +01:00
{
auto& r = m_model_instances.emplace();
r.flags.clear();
r.flags.set(ModelInstance::VALID, false);
r.model = nullptr;
r.pose = nullptr;
2015-12-10 17:09:52 +01:00
}
auto& r = m_model_instances[entity.index];
r.model = nullptr;
r.meshes = nullptr;
r.pose = nullptr;
r.flags.clear();
r.flags.set(ModelInstance::VALID);
2017-12-13 23:55:09 +01:00
r.flags.set(ModelInstance::ENABLED);
r.mesh_count = 0;
2018-01-12 17:01:26 +01:00
m_universe.onComponentCreated(entity, MODEL_INSTANCE_TYPE, this);
2014-06-16 21:18:15 +02:00
}
2018-08-22 19:52:08 +02:00
void setParticleEmitterPath(EntityRef entity, const Path& path) override
2017-10-24 17:18:53 +02:00
{
2018-08-22 19:52:08 +02:00
if (!m_particle_emitters[entity]) return;
2017-10-24 17:18:53 +02:00
ParticleEmitterResource* res = m_engine.getResourceManager().load<ParticleEmitterResource>(path);
2018-08-22 19:52:08 +02:00
m_particle_emitters[entity]->setResource(res);
2017-10-24 17:18:53 +02:00
}
2018-08-22 19:52:08 +02:00
Path getParticleEmitterPath(EntityRef entity) override
2017-10-24 17:18:53 +02:00
{
2018-08-22 19:52:08 +02:00
ParticleEmitter* emitter = m_particle_emitters[entity];
2017-10-24 17:18:53 +02:00
if (!emitter) return Path("");
2018-08-22 19:52:08 +02:00
if (!emitter->getResource()) return Path("");
2017-10-24 17:18:53 +02:00
2018-08-22 19:52:08 +02:00
return emitter->getResource()->getPath();
2017-10-24 17:18:53 +02:00
}
2018-08-22 19:52:08 +02:00
const AssociativeArray<EntityRef, ParticleEmitter*>& getParticleEmitters() const override
2017-10-24 17:18:53 +02:00
{
2018-08-22 19:52:08 +02:00
return m_particle_emitters;
2017-10-24 17:18:53 +02:00
}
2015-07-21 20:10:50 +02:00
private:
IAllocator& m_allocator;
Universe& m_universe;
Renderer& m_renderer;
Engine& m_engine;
CullingSystem* m_culling_system;
u64 m_render_cmps_mask;
2015-07-21 20:10:50 +02:00
2018-08-19 17:35:37 +02:00
EntityPtr m_active_global_light_entity;
2018-10-20 21:35:03 +02:00
HashMap<EntityRef, PointLight> m_point_lights;
2018-10-13 15:08:58 +02:00
HashMap<EntityRef, Decal> m_decals;
Array<ModelInstance> m_model_instances;
Array<MeshSortData> m_mesh_sort_data;
HashMap<EntityRef, Environment> m_environments;
2019-11-17 19:45:54 +01:00
AssociativeArray<EntityRef, LightProbeGrid> m_light_probe_grids;
2018-08-19 17:35:37 +02:00
HashMap<EntityRef, Camera> m_cameras;
EntityPtr m_active_camera = INVALID_ENTITY;
2018-08-19 17:35:37 +02:00
AssociativeArray<EntityRef, TextMesh*> m_text_meshes;
AssociativeArray<EntityRef, BoneAttachment> m_bone_attachments;
AssociativeArray<EntityRef, EnvironmentProbe> m_environment_probes;
HashMap<EntityRef, Terrain*> m_terrains;
2018-08-22 19:52:08 +02:00
AssociativeArray<EntityRef, ParticleEmitter*> m_particle_emitters;
2016-03-10 19:32:48 +01:00
Array<DebugTriangle> m_debug_triangles;
2015-07-21 20:10:50 +02:00
Array<DebugLine> m_debug_lines;
2015-07-21 20:10:50 +02:00
float m_time;
2016-09-17 01:00:38 +02:00
float m_lod_multiplier;
2016-05-02 21:41:18 +02:00
bool m_is_updating_attachments;
bool m_is_grass_enabled;
bool m_is_game_running;
2018-09-08 22:00:02 +02:00
HashMap<Model*, EntityRef> m_model_entity_map;
2018-10-13 15:08:58 +02:00
HashMap<Material*, EntityRef> m_material_decal_map;
2015-07-21 20:10:50 +02:00
};
2016-12-10 15:16:01 +01:00
#define COMPONENT_TYPE(type, name) \
{ \
type \
, &RenderSceneImpl::create##name \
, &RenderSceneImpl::destroy##name \
}
static struct
{
2016-06-22 00:46:48 +02:00
ComponentType type;
2018-08-19 17:35:37 +02:00
void (RenderSceneImpl::*creator)(EntityRef);
void (RenderSceneImpl::*destroyer)(EntityRef);
2016-10-02 22:56:47 +02:00
} COMPONENT_INFOS[] = {
2016-12-10 15:16:01 +01:00
COMPONENT_TYPE(MODEL_INSTANCE_TYPE, ModelInstance),
COMPONENT_TYPE(ENVIRONMENT_TYPE, Environment),
2019-11-11 21:30:12 +01:00
COMPONENT_TYPE(LIGHT_PROBE_GRID_TYPE, LightProbeGrid),
2016-12-10 15:16:01 +01:00
COMPONENT_TYPE(POINT_LIGHT_TYPE, PointLight),
COMPONENT_TYPE(DECAL_TYPE, Decal),
COMPONENT_TYPE(CAMERA_TYPE, Camera),
COMPONENT_TYPE(TERRAIN_TYPE, Terrain),
COMPONENT_TYPE(BONE_ATTACHMENT_TYPE, BoneAttachment),
COMPONENT_TYPE(ENVIRONMENT_PROBE_TYPE, EnvironmentProbe),
2018-08-22 19:52:08 +02:00
COMPONENT_TYPE(PARTICLE_EMITTER_TYPE, ParticleEmitter),
2018-01-30 21:39:21 +01:00
COMPONENT_TYPE(TEXT_MESH_TYPE, TextMesh)
2016-12-10 15:16:01 +01:00
};
2016-12-10 15:16:01 +01:00
#undef COMPONENT_TYPE
2016-07-21 14:23:46 +02:00
RenderSceneImpl::RenderSceneImpl(Renderer& renderer,
Engine& engine,
Universe& universe,
IAllocator& allocator)
: m_engine(engine)
, m_universe(universe)
, m_renderer(renderer)
, m_allocator(allocator)
2018-09-08 22:00:02 +02:00
, m_model_entity_map(m_allocator)
, m_model_instances(m_allocator)
2016-07-21 14:23:46 +02:00
, m_cameras(m_allocator)
2018-01-30 21:39:21 +01:00
, m_text_meshes(m_allocator)
2016-07-21 14:23:46 +02:00
, m_terrains(m_allocator)
, m_point_lights(m_allocator)
, m_environments(m_allocator)
2016-07-22 13:57:52 +02:00
, m_decals(m_allocator)
2016-07-21 14:23:46 +02:00
, m_debug_triangles(m_allocator)
, m_debug_lines(m_allocator)
2018-01-12 17:01:26 +01:00
, m_active_global_light_entity(INVALID_ENTITY)
2018-08-22 19:52:08 +02:00
, m_active_camera(INVALID_ENTITY)
2016-07-21 14:23:46 +02:00
, m_is_grass_enabled(true)
, m_is_game_running(false)
2018-08-22 19:52:08 +02:00
, m_particle_emitters(m_allocator)
2016-07-21 14:23:46 +02:00
, m_bone_attachments(m_allocator)
, m_environment_probes(m_allocator)
2016-09-17 01:00:38 +02:00
, m_lod_multiplier(1.0f)
, m_time(0)
, m_is_updating_attachments(false)
2018-10-13 15:08:58 +02:00
, m_material_decal_map(m_allocator)
, m_mesh_sort_data(m_allocator)
2019-11-11 21:30:12 +01:00
, m_light_probe_grids(m_allocator)
2016-06-22 00:46:48 +02:00
{
2020-01-07 19:17:48 +01:00
m_universe.entityTransformed().bind<&RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().bind<&RenderSceneImpl::onEntityDestroyed>(this);
2019-06-03 22:25:58 +02:00
m_culling_system = CullingSystem::create(m_allocator, engine.getPageAllocator());
m_model_instances.reserve(5000);
2019-06-05 01:45:55 +02:00
m_mesh_sort_data.reserve(5000);
2016-07-21 14:23:46 +02:00
m_render_cmps_mask = 0;
2016-06-22 00:46:48 +02:00
for (auto& i : COMPONENT_INFOS)
{
m_render_cmps_mask |= (u64)1 << i.type.index;
universe.registerComponentType(i.type, this, i.creator, i.destroyer);
}
}
2015-07-21 20:10:50 +02:00
RenderScene* RenderScene::createInstance(Renderer& renderer,
Engine& engine,
Universe& universe,
IAllocator& allocator)
2015-07-21 20:10:50 +02:00
{
2016-11-02 18:29:44 +01:00
return LUMIX_NEW(allocator, RenderSceneImpl)(renderer, engine, universe, allocator);
2015-07-21 20:10:50 +02:00
}
void RenderScene::destroyInstance(RenderScene* scene)
{
LUMIX_DELETE(scene->getAllocator(), static_cast<RenderSceneImpl*>(scene));
2015-07-21 20:10:50 +02:00
}
void RenderScene::registerLuaAPI(lua_State* L)
{
2016-05-07 11:49:39 +02:00
Model::registerLuaAPI(L);
#define REGISTER_FUNCTION(F)\
do { \
2019-10-29 22:47:42 +01:00
auto f = &LuaWrapper::wrapMethod<&RenderSceneImpl::F>; \
LuaWrapper::createSystemFunction(L, "Renderer", #F, f); \
} while(false) \
2016-09-17 01:00:38 +02:00
REGISTER_FUNCTION(setGlobalLODMultiplier);
REGISTER_FUNCTION(getGlobalLODMultiplier);
REGISTER_FUNCTION(getActiveEnvironment);
REGISTER_FUNCTION(getModelInstanceModel);
REGISTER_FUNCTION(addDebugCross);
2016-05-07 11:49:39 +02:00
REGISTER_FUNCTION(addDebugLine);
REGISTER_FUNCTION(getTerrainMaterial);
2016-09-14 13:19:51 +02:00
REGISTER_FUNCTION(getTerrainNormalAt);
2016-09-14 14:15:27 +02:00
REGISTER_FUNCTION(setTerrainHeightAt);
//REGISTER_FUNCTION(enableModelInstance);
REGISTER_FUNCTION(getPoseBonePosition);
2017-01-09 16:34:26 +01:00
#undef REGISTER_FUNCTION
#define REGISTER_FUNCTION(F)\
do { \
2019-10-29 22:47:42 +01:00
auto f = &LuaWrapper::wrap<&RenderSceneImpl::LUA_##F>; \
LuaWrapper::createSystemFunction(L, "Renderer", #F, f); \
} while(false) \
2016-10-17 00:19:02 +02:00
REGISTER_FUNCTION(createPipeline);
REGISTER_FUNCTION(destroyPipeline);
REGISTER_FUNCTION(setPipelineScene);
2016-10-28 23:16:28 +02:00
REGISTER_FUNCTION(getPipelineScene);
//REGISTER_FUNCTION(setModelInstancePath);
REGISTER_FUNCTION(getModelBoneIndex);
REGISTER_FUNCTION(makeScreenshot);
REGISTER_FUNCTION(compareTGA);
2016-09-14 14:15:27 +02:00
REGISTER_FUNCTION(getTerrainHeightAt);
LuaWrapper::createSystemFunction(L, "Renderer", "castCameraRay", &RenderSceneImpl::LUA_castCameraRay);
#undef REGISTER_FUNCTION
}
} // namespace Lumix