LumixEngine/src/renderer/render_scene.cpp

5087 lines
142 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"
#include "engine/blob.h"
#include "engine/crc32.h"
2017-02-24 15:20:58 +01:00
#include "engine/engine.h"
2016-05-10 08:24:31 +02:00
#include "engine/fs/file_system.h"
#include "engine/geometry.h"
2017-09-16 14:04:24 +02:00
#include "engine/job_system.h"
2016-05-10 08:24:31 +02:00
#include "engine/json_serializer.h"
#include "engine/lifo_allocator.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/math_utils.h"
2016-06-12 15:26:41 +02:00
#include "engine/path_utils.h"
2016-10-17 00:19:02 +02:00
#include "engine/plugin_manager.h"
2016-05-10 08:24:31 +02:00
#include "engine/profiler.h"
2017-10-18 23:43:02 +02:00
#include "engine/properties.h"
2016-05-10 08:24:31 +02:00
#include "engine/resource_manager.h"
#include "engine/resource_manager_base.h"
2016-12-11 21:44:47 +01:00
#include "engine/serializer.h"
2016-05-10 08:24:31 +02:00
#include "engine/timer.h"
2017-02-24 15:20:58 +01:00
#include "engine/universe/universe.h"
#include "lua_script/lua_script_system.h"
2015-08-17 23:45:26 +02:00
#include "renderer/culling_system.h"
2016-10-17 10:21:25 +02:00
#include "renderer/frame_buffer.h"
2015-08-17 23:45:26 +02:00
#include "renderer/material.h"
#include "renderer/material_manager.h"
2015-08-17 23:45:26 +02:00
#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/shader.h"
#include "renderer/terrain.h"
#include "renderer/texture.h"
2016-06-12 15:26:41 +02:00
#include "renderer/texture_manager.h"
2016-11-09 10:09:33 +01:00
#include <cfloat>
2017-02-24 15:20:58 +01:00
#include <cmath>
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
{
GRASS_ROTATION_MODE,
2017-02-09 14:22:41 +01:00
GLOBAL_LIGHT_REFACTOR,
2017-02-21 16:37:07 +01:00
EMITTER_MATERIAL,
BONE_ATTACHMENT_TRANSFORM,
2017-04-13 17:05:07 +02:00
MODEL_INSTNACE_FLAGS,
INDIRECT_INTENSITY,
2017-01-24 16:56:42 +01:00
LATEST
};
2017-10-18 23:43:02 +02:00
static const ComponentType MODEL_INSTANCE_TYPE = Properties::getComponentType("renderable");
static const ComponentType DECAL_TYPE = Properties::getComponentType("decal");
static const ComponentType POINT_LIGHT_TYPE = Properties::getComponentType("point_light");
static const ComponentType PARTICLE_EMITTER_TYPE = Properties::getComponentType("particle_emitter");
static const ComponentType PARTICLE_EMITTER_ALPHA_TYPE = Properties::getComponentType("particle_emitter_alpha");
static const ComponentType PARTICLE_EMITTER_FORCE_HASH = Properties::getComponentType("particle_emitter_force");
2016-12-10 15:16:01 +01:00
static const ComponentType PARTICLE_EMITTER_ATTRACTOR_TYPE =
2017-10-18 23:43:02 +02:00
Properties::getComponentType("particle_emitter_attractor");
2016-12-10 15:16:01 +01:00
static const ComponentType PARTICLE_EMITTER_SUBIMAGE_TYPE =
2017-10-18 23:43:02 +02:00
Properties::getComponentType("particle_emitter_subimage");
2016-12-10 15:16:01 +01:00
static const ComponentType PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE =
2017-10-18 23:43:02 +02:00
Properties::getComponentType("particle_emitter_linear_movement");
2016-12-10 15:16:01 +01:00
static const ComponentType PARTICLE_EMITTER_SPAWN_SHAPE_TYPE =
2017-10-18 23:43:02 +02:00
Properties::getComponentType("particle_emitter_spawn_shape");
static const ComponentType PARTICLE_EMITTER_PLANE_TYPE = Properties::getComponentType("particle_emitter_plane");
2016-12-10 15:16:01 +01:00
static const ComponentType PARTICLE_EMITTER_RANDOM_ROTATION_TYPE =
2017-10-18 23:43:02 +02:00
Properties::getComponentType("particle_emitter_random_rotation");
static const ComponentType PARTICLE_EMITTER_SIZE_TYPE = Properties::getComponentType("particle_emitter_size");
static const ComponentType GLOBAL_LIGHT_TYPE = Properties::getComponentType("global_light");
static const ComponentType CAMERA_TYPE = Properties::getComponentType("camera");
static const ComponentType TERRAIN_TYPE = Properties::getComponentType("terrain");
static const ComponentType BONE_ATTACHMENT_TYPE = Properties::getComponentType("bone_attachment");
static const ComponentType ENVIRONMENT_PROBE_TYPE = Properties::getComponentType("environment_probe");
2016-06-22 00:46:48 +02:00
2016-07-24 22:21:43 +02:00
static const ResourceType MATERIAL_TYPE("material");
static const ResourceType TEXTURE_TYPE("texture");
static const ResourceType MODEL_TYPE("model");
2014-06-16 21:18:15 +02:00
2016-07-22 13:57:52 +02:00
struct Decal : public DecalInfo
{
Entity entity;
Vec3 scale;
};
2015-07-21 20:10:50 +02:00
struct PointLight
{
2015-09-02 11:14:42 +02:00
Vec3 m_diffuse_color;
2015-07-21 20:10:50 +02:00
Vec3 m_specular_color;
2016-02-10 12:09:09 +01:00
float m_diffuse_intensity;
float m_specular_intensity;
2015-07-21 20:10:50 +02:00
Entity m_entity;
2016-06-22 15:05:19 +02:00
ComponentHandle m_component;
2015-07-21 20:10:50 +02:00
float m_fov;
2015-09-09 02:18:09 +02:00
float m_attenuation_param;
2015-09-04 14:00:28 +02:00
float m_range;
2015-09-02 11:14:42 +02:00
bool m_cast_shadows;
2015-07-21 20:10:50 +02:00
};
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
struct GlobalLight
{
2016-02-10 12:09:09 +01:00
Vec3 m_diffuse_color;
float m_diffuse_intensity;
float m_indirect_intensity;
2015-07-21 20:10:50 +02:00
Vec3 m_fog_color;
float m_fog_density;
2015-10-17 00:18:47 +02:00
float m_fog_bottom;
float m_fog_height;
2015-07-21 20:10:50 +02:00
Entity m_entity;
Vec4 m_cascades;
2015-07-21 20:10:50 +02:00
};
struct Camera
{
static const int MAX_SLOT_LENGTH = 30;
2016-04-17 21:47:54 +02:00
Entity entity;
float fov;
float aspect;
float near;
float far;
float ortho_size;
float screen_width;
float screen_height;
bool is_ortho;
char slot[MAX_SLOT_LENGTH + 1];
2015-07-21 20:10:50 +02:00
};
2016-06-12 15:26:41 +02:00
struct EnvironmentProbe
{
Texture* texture;
2016-11-29 20:00:36 +01:00
Texture* irradiance;
Texture* radiance;
2017-01-03 17:04:09 +01:00
u64 guid;
2016-06-12 15:26:41 +02:00
};
2016-05-02 21:41:18 +02:00
struct BoneAttachment
{
Entity entity;
Entity parent_entity;
int bone_index;
2017-08-18 13:54:56 +02:00
RigidTransform relative_transform;
2016-05-02 21:41:18 +02:00
};
2016-10-07 12:57:30 +02:00
class RenderSceneImpl LUMIX_FINAL : public RenderScene
2015-07-21 20:10:50 +02:00
{
private:
2016-07-25 02:00:22 +02:00
struct ModelLoadedCallback
2014-06-16 21:18:15 +02:00
{
2015-07-21 20:10:50 +02:00
ModelLoadedCallback(RenderSceneImpl& scene, Model* model)
: m_scene(scene)
, m_ref_count(0)
, m_model(model)
{
2016-07-25 02:00:22 +02:00
m_model->getObserverCb().bind<RenderSceneImpl, &RenderSceneImpl::modelStateChanged>(&scene);
2015-07-21 20:10:50 +02:00
}
~ModelLoadedCallback()
{
2016-07-25 02:00:22 +02:00
m_model->getObserverCb().unbind<RenderSceneImpl, &RenderSceneImpl::modelStateChanged>(&m_scene);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
Model* m_model;
int m_ref_count;
RenderSceneImpl& m_scene;
2014-06-16 21:18:15 +02:00
};
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()
{
2016-05-02 21:41:18 +02:00
m_universe.entityTransformed().unbind<RenderSceneImpl, &RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().unbind<RenderSceneImpl, &RenderSceneImpl::onEntityDestroyed>(this);
2016-07-24 15:44:37 +02:00
CullingSystem::destroy(*m_culling_system);
}
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);
}
else if (old_state == Resource::State::READY && new_state != Resource::State::READY)
{
modelUnloaded(model);
}
}
2016-07-24 15:44:37 +02:00
void clear() override
{
auto& rm = m_engine.getResourceManager();
2016-07-24 22:21:43 +02:00
auto* material_manager = static_cast<MaterialManager*>(rm.get(MATERIAL_TYPE));
2016-07-24 15:44:37 +02:00
m_model_loaded_callbacks.clear();
2014-06-16 21:18:15 +02:00
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
for (auto* emitter : m_particle_emitters)
2015-10-30 21:11:11 +01:00
{
LUMIX_DELETE(m_allocator, emitter);
2015-07-21 20:10:50 +02:00
}
2016-07-24 15:44:37 +02:00
m_particle_emitters.clear();
2015-01-04 15:05:20 +01:00
for (auto& i : m_model_instances)
2015-07-21 20:10:50 +02:00
{
if (i.entity != INVALID_ENTITY && i.model)
2014-06-16 21:18:15 +02:00
{
freeCustomMeshes(i, material_manager);
2016-07-25 01:02:36 +02:00
i.model->getResourceManager().unload(*i.model);
LUMIX_DELETE(m_allocator, i.pose);
2015-07-21 20:10:50 +02:00
}
}
m_model_instances.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
{
2016-07-25 01:02:36 +02:00
if (probe.texture) probe.texture->getResourceManager().unload(*probe.texture);
2017-02-28 21:18:37 +01:00
if (probe.radiance) probe.radiance->getResourceManager().unload(*probe.radiance);
if (probe.irradiance) probe.irradiance->getResourceManager().unload(*probe.irradiance);
2016-06-12 15:26:41 +02:00
}
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
2016-06-22 15:05:19 +02:00
void resetParticleEmitter(ComponentHandle cmp) override
2015-12-17 13:58:40 +01:00
{
m_particle_emitters[{cmp.index}]->reset();
2015-12-17 13:58:40 +01:00
}
2016-02-26 13:49:42 +01:00
2016-06-22 15:05:19 +02:00
ParticleEmitter* getParticleEmitter(ComponentHandle cmp) override
{
return m_particle_emitters[{cmp.index}];
}
2016-06-22 15:05:19 +02:00
void updateEmitter(ComponentHandle cmp, float time_delta) override
{
m_particle_emitters[{cmp.index}]->update(time_delta);
}
Universe& getUniverse() override { return m_universe; }
2014-11-05 19:01:56 +01:00
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle getComponent(Entity entity, ComponentType type) override
{
if (type == MODEL_INSTANCE_TYPE)
{
if (entity.index >= m_model_instances.size()) return INVALID_COMPONENT;
2017-01-11 17:01:53 +01:00
ComponentHandle cmp = {entity.index};
2017-05-23 14:01:09 +02:00
return m_model_instances[entity.index].entity.isValid() ? cmp : INVALID_COMPONENT;
}
2016-07-22 13:57:52 +02:00
if (type == ENVIRONMENT_PROBE_TYPE)
{
int index = m_environment_probes.find(entity);
if (index < 0) return INVALID_COMPONENT;
return {entity.index};
}
if (type == DECAL_TYPE)
{
int index = m_decals.find(entity);
if (index < 0) return INVALID_COMPONENT;
return {entity.index};
}
2016-06-22 00:46:48 +02:00
if (type == POINT_LIGHT_TYPE)
{
for (auto& i : m_point_lights)
{
2016-06-22 15:05:19 +02:00
if (i.m_entity == entity) return i.m_component;
}
return INVALID_COMPONENT;
}
2016-06-22 00:46:48 +02:00
if (type == GLOBAL_LIGHT_TYPE)
{
2017-02-09 14:22:41 +01:00
auto iter = m_global_lights.find(entity);
if (iter.isValid()) return {entity.index};
return INVALID_COMPONENT;
}
2016-06-22 00:46:48 +02:00
if (type == CAMERA_TYPE)
{
auto iter = m_cameras.find(entity);
ComponentHandle cmp = {entity.index};
return iter.isValid() ? cmp : INVALID_COMPONENT;
}
2016-06-22 00:46:48 +02:00
if (type == TERRAIN_TYPE)
{
auto iter = m_terrains.find(entity);
2017-01-11 17:01:53 +01:00
if (!iter.isValid()) return INVALID_COMPONENT;
return {entity.index};
}
2016-06-22 00:46:48 +02:00
if (type == PARTICLE_EMITTER_TYPE)
{
int index = m_particle_emitters.find(entity);
if (index < 0) return INVALID_COMPONENT;
2017-01-11 17:01:53 +01:00
if (m_particle_emitters.at(index)->m_is_valid) return {entity.index};
return INVALID_COMPONENT;
}
if (type == BONE_ATTACHMENT_TYPE)
{
for (auto& attachment : m_bone_attachments)
{
if (attachment.entity == entity)
{
return {entity.index};
}
}
2016-06-22 00:46:48 +02:00
return INVALID_COMPONENT;
}
static const ComponentType EMITTER_MODULES[] = {ParticleEmitter::AttractorModule::s_type,
ParticleEmitter::AlphaModule::s_type,
ParticleEmitter::ForceModule::s_type,
ParticleEmitter::LinearMovementModule::s_type,
ParticleEmitter::PlaneModule::s_type,
ParticleEmitter::RandomRotationModule::s_type,
ParticleEmitter::SizeModule::s_type,
2016-10-02 22:56:47 +02:00
ParticleEmitter::SubimageModule::s_type,
ParticleEmitter::SpawnShapeModule::s_type};
2016-06-22 00:46:48 +02:00
for (auto& module : EMITTER_MODULES)
{
if (module == type)
2016-06-22 00:46:48 +02:00
{
int index = m_particle_emitters.find(entity);
if (index < 0) return INVALID_COMPONENT;
auto* emitter = m_particle_emitters.at(index);
if (emitter->getModule(type)) return {entity.index};
2016-06-22 00:46:48 +02:00
return INVALID_COMPONENT;
}
}
return INVALID_COMPONENT;
}
IPlugin& getPlugin() const override { return m_renderer; }
2015-01-04 15:05:20 +01:00
2016-06-22 15:05:19 +02:00
Int2 getParticleEmitterSpawnCount(ComponentHandle cmp) override
{
Int2 ret;
ret.x = m_particle_emitters[{cmp.index}]->m_spawn_count.from;
ret.y = m_particle_emitters[{cmp.index}]->m_spawn_count.to;
return ret;
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterSpawnCount(ComponentHandle cmp, const Int2& value) override
{
m_particle_emitters[{cmp.index}]->m_spawn_count.from = value.x;
m_particle_emitters[{cmp.index}]->m_spawn_count.to = Math::maximum(value.x, value.y);
}
2016-06-22 15:05:19 +02:00
void getRay(ComponentHandle camera_index,
2017-10-04 10:47:31 +02:00
const Vec2& screen_pos,
Vec3& origin,
Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
Camera& camera = m_cameras[{camera_index.index}];
2016-04-17 21:47:54 +02:00
origin = m_universe.getPosition(camera.entity);
float width = camera.screen_width;
float height = camera.screen_height;
if (width <= 0 || height <= 0)
{
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
2016-04-17 21:47:54 +02:00
Matrix projection_matrix = getCameraProjection(camera_index);
Matrix view_matrix = m_universe.getMatrix(camera.entity);
if (camera.is_ortho)
{
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
origin += view_matrix.getXVector() * nx * camera.ortho_size * ratio
+ view_matrix.getYVector() * ny * camera.ortho_size;
}
2015-07-21 20:10:50 +02:00
view_matrix.inverse();
Matrix inverted = (projection_matrix * view_matrix);
inverted.inverse();
2016-04-17 21:47:54 +02:00
2015-07-21 20:10:50 +02:00
Vec4 p0 = inverted * Vec4(nx, ny, -1, 1);
Vec4 p1 = inverted * Vec4(nx, ny, 1, 1);
2016-04-17 21:47:54 +02:00
p0 *= 1 / p0.w;
p1 *= 1 / p1.w;
dir = p1 - p0;
2015-07-21 20:10:50 +02:00
dir.normalize();
}
2014-08-21 01:22:57 +02:00
2015-07-24 08:42:35 +02:00
2016-06-22 15:05:19 +02:00
Frustum getCameraFrustum(ComponentHandle cmp) const override
2015-07-23 23:17:51 +02:00
{
const Camera& camera = m_cameras[{cmp.index}];
2016-04-17 21:47:54 +02:00
Matrix mtx = m_universe.getMatrix(camera.entity);
2015-08-27 23:18:49 +02:00
Frustum ret;
2016-04-17 21:47:54 +02:00
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
if (camera.is_ortho)
{
ret.computeOrtho(mtx.getTranslation(),
mtx.getZVector(),
mtx.getYVector(),
camera.ortho_size * ratio,
camera.ortho_size,
camera.near,
camera.far);
return ret;
}
2015-08-27 23:18:49 +02:00
ret.computePerspective(mtx.getTranslation(),
2016-07-26 21:03:47 +02:00
-mtx.getZVector(),
2016-04-17 21:47:54 +02:00
mtx.getYVector(),
camera.fov,
2016-04-17 21:47:54 +02:00
ratio,
camera.near,
camera.far);
2015-07-21 20:10:50 +02:00
2015-08-27 23:18:49 +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
2017-10-10 16:53:23 +02:00
Frustum getCameraFrustum(ComponentHandle cmp, const Vec2& viewport_min_px, const Vec2& viewport_max_px) const override
{
const Camera& camera = m_cameras[{cmp.index}];
Matrix mtx = m_universe.getMatrix(camera.entity);
Frustum ret;
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 };
if (camera.is_ortho)
{
ret.computeOrtho(mtx.getTranslation(),
mtx.getZVector(),
mtx.getYVector(),
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;
}
ret.computePerspective(mtx.getTranslation(),
-mtx.getZVector(),
mtx.getYVector(),
camera.fov,
ratio,
camera.near,
2017-10-10 16:53:23 +02:00
camera.far,
viewport_min,
viewport_max);
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;
ComponentHandle model_instance = getModelInstanceComponent(bone_attachment.parent_entity);
if (model_instance == INVALID_COMPONENT) return;
const Pose* parent_pose = lockPose(model_instance);
2016-05-02 21:41:18 +02:00
if (!parent_pose) return;
Transform parent_entity_transform = m_universe.getTransform(bone_attachment.parent_entity);
2016-05-02 21:41:18 +02:00
int idx = bone_attachment.bone_index;
if (idx < 0 || idx > parent_pose->count)
{
unlockPose(model_instance, false);
return;
}
float original_scale = m_universe.getScale(bone_attachment.entity);
2017-08-18 13:54:56 +02:00
Transform bone_transform = {parent_pose->positions[idx], parent_pose->rotations[idx], 1.0f};
Transform relative_transform = { bone_attachment.relative_transform.pos, bone_attachment.relative_transform.rot, 1.0f};
Transform result = parent_entity_transform * bone_transform * relative_transform;
result.scale = original_scale;
m_universe.setTransform(bone_attachment.entity, result);
unlockPose(model_instance, false);
2016-05-02 21:41:18 +02:00
}
2016-06-22 15:05:19 +02:00
Entity getBoneAttachmentParent(ComponentHandle cmp) override
2016-05-02 21:41:18 +02:00
{
return m_bone_attachments[{cmp.index}].parent_entity;
2016-05-02 21:41:18 +02:00
}
void updateRelativeMatrix(BoneAttachment& attachment)
{
if (attachment.parent_entity == INVALID_ENTITY) return;
if (attachment.bone_index < 0) return;
ComponentHandle model_instance = getModelInstanceComponent(attachment.parent_entity);
if (model_instance == INVALID_COMPONENT) return;
const Pose* pose = lockPose(model_instance);
2016-05-02 21:41:18 +02:00
if (!pose) return;
ASSERT(pose->is_absolute);
if (attachment.bone_index >= pose->count)
{
unlockPose(model_instance, false);
return;
}
2017-08-18 13:54:56 +02:00
Transform bone_transform = {pose->positions[attachment.bone_index], pose->rotations[attachment.bone_index], 1.0f};
2016-05-02 21:41:18 +02:00
Transform inv_parent_transform = m_universe.getTransform(attachment.parent_entity) * bone_transform;
inv_parent_transform = inv_parent_transform.inverted();
Transform child_transform = m_universe.getTransform(attachment.entity);
2017-08-18 13:54:56 +02:00
Transform res = inv_parent_transform * child_transform;
attachment.relative_transform = {res.pos, res.rot};
unlockPose(model_instance, false);
2016-05-02 21:41:18 +02:00
}
2016-06-22 15:05:19 +02:00
Vec3 getBoneAttachmentPosition(ComponentHandle cmp) override
{
return m_bone_attachments[{cmp.index}].relative_transform.pos;
}
2016-06-22 15:05:19 +02:00
void setBoneAttachmentPosition(ComponentHandle cmp, const Vec3& pos) override
{
BoneAttachment& attachment = m_bone_attachments[{cmp.index}];
attachment.relative_transform.pos = pos;
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
m_is_updating_attachments = false;
}
2016-08-28 16:56:38 +02:00
Vec3 getBoneAttachmentRotation(ComponentHandle cmp) override
{
return m_bone_attachments[{cmp.index}].relative_transform.rot.toEuler();
2016-08-28 16:56:38 +02:00
}
void setBoneAttachmentRotation(ComponentHandle cmp, const Vec3& rot) override
{
BoneAttachment& attachment = m_bone_attachments[{cmp.index}];
2016-08-28 16:56:38 +02:00
Vec3 euler = rot;
euler.x = Math::clamp(euler.x, -Math::PI * 0.5f, Math::PI * 0.5f);
attachment.relative_transform.rot.fromEuler(euler);
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
m_is_updating_attachments = false;
}
void setBoneAttachmentRotationQuat(ComponentHandle cmp, const Quat& rot) override
{
BoneAttachment& attachment = m_bone_attachments[{cmp.index}];
attachment.relative_transform.rot = rot;
m_is_updating_attachments = true;
updateBoneAttachment(attachment);
m_is_updating_attachments = false;
}
2016-06-22 15:05:19 +02:00
int getBoneAttachmentBone(ComponentHandle cmp) override
2016-05-02 21:41:18 +02:00
{
return m_bone_attachments[{cmp.index}].bone_index;
2016-05-02 21:41:18 +02:00
}
2016-06-22 15:05:19 +02:00
void setBoneAttachmentBone(ComponentHandle cmp, int value) override
2016-05-02 21:41:18 +02:00
{
BoneAttachment& ba = m_bone_attachments[{cmp.index}];
ba.bone_index = value;
updateRelativeMatrix(ba);
2016-05-02 21:41:18 +02:00
}
2016-06-22 15:05:19 +02:00
void setBoneAttachmentParent(ComponentHandle cmp, Entity entity) override
2016-05-02 21:41:18 +02:00
{
BoneAttachment& ba = m_bone_attachments[{cmp.index}];
ba.parent_entity = entity;
if (entity.isValid() && entity.index < m_model_instances.size())
{
ModelInstance& mi = m_model_instances[entity.index];
mi.flags = mi.flags | ModelInstance::IS_BONE_ATTACHMENT_PARENT;
}
updateRelativeMatrix(ba);
2016-05-02 21:41:18 +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;
2016-03-10 19:32:48 +01:00
for (int i = m_debug_triangles.size() - 1; i >= 0; --i)
2015-07-21 20:10:50 +02:00
{
2016-03-10 19:32:48 +01:00
float life = m_debug_triangles[i].life;
2015-07-21 20:10:50 +02:00
if (life < 0)
2016-03-10 19:32:48 +01:00
{
m_debug_triangles.eraseFast(i);
}
else
{
life -= dt;
m_debug_triangles[i].life = life;
}
}
for(int i = m_debug_lines.size() - 1; i >= 0; --i)
{
float life = m_debug_lines[i].life;
if(life < 0)
2014-06-16 21:18:15 +02:00
{
2015-07-21 20:10:50 +02:00
m_debug_lines.eraseFast(i);
2014-06-16 21:18:15 +02:00
}
2015-07-21 20:10:50 +02:00
else
2014-06-16 21:18:15 +02:00
{
2015-07-21 20:10:50 +02:00
life -= dt;
2016-03-10 19:32:48 +01:00
m_debug_lines[i].life = life;
2014-06-16 21:18:15 +02:00
}
2015-07-21 20:10:50 +02:00
}
2016-03-10 19:32:48 +01:00
for (int i = m_debug_points.size() - 1; i >= 0; --i)
{
2016-03-10 19:32:48 +01:00
float life = m_debug_points[i].life;
if (life < 0)
{
2016-03-10 19:32:48 +01:00
m_debug_points.eraseFast(i);
}
else
{
life -= dt;
2016-03-10 19:32:48 +01:00
m_debug_points[i].life = life;
}
}
if (m_is_game_running && !paused)
{
for (auto* emitter : m_particle_emitters)
{
if (emitter->m_is_valid) emitter->update(dt);
}
}
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-05-02 21:41:18 +02:00
2016-12-10 15:16:01 +01:00
void serializeModelInstance(ISerializer& serialize, ComponentHandle cmp)
{
ModelInstance& r = m_model_instances[{cmp.index}];
ASSERT(r.entity != INVALID_ENTITY);
serialize.write("source", r.model ? r.model->getPath().c_str() : "");
2017-08-28 22:58:04 +02:00
serialize.write("flags", u8(r.flags & ModelInstance::PERSISTENT_FLAGS));
2016-12-10 15:16:01 +01:00
bool has_changed_materials = r.model && r.model->isReady() && r.meshes != &r.model->getMesh(0);
serialize.write("custom_materials", has_changed_materials ? r.mesh_count : 0);
if (has_changed_materials)
{
for (int i = 0; i < r.mesh_count; ++i)
{
serialize.write("", r.meshes[i].material->getPath().c_str());
}
}
}
2017-04-13 17:05:07 +02:00
static bool keepSkin(ModelInstance& r)
{
return (r.flags & (u8)ModelInstance::KEEP_SKIN) != 0;
}
static bool hasCustomMeshes(ModelInstance& r)
{
return (r.flags & (u8)ModelInstance::CUSTOM_MESHES) != 0;
}
void deserializeModelInstance(IDeserializer& serializer, Entity entity, int scene_version)
2016-12-10 15:16:01 +01:00
{
while (entity.index >= m_model_instances.size())
{
auto& r = m_model_instances.emplace();
r.entity = INVALID_ENTITY;
r.pose = nullptr;
r.model = nullptr;
r.meshes = nullptr;
r.mesh_count = 0;
}
auto& r = m_model_instances[entity.index];
r.entity = entity;
r.model = nullptr;
r.pose = nullptr;
2017-04-13 17:05:07 +02:00
r.flags = 0;
2016-12-10 15:16:01 +01:00
r.meshes = nullptr;
r.mesh_count = 0;
r.matrix = m_universe.getMatrix(r.entity);
char path[MAX_PATH_LENGTH];
serializer.read(path, lengthOf(path));
2017-04-13 17:05:07 +02:00
if (scene_version > (int)RenderSceneVersion::MODEL_INSTNACE_FLAGS)
{
serializer.read(&r.flags);
2017-08-28 22:58:04 +02:00
r.flags &= ModelInstance::PERSISTENT_FLAGS;
2017-04-13 17:05:07 +02:00
}
2016-12-10 15:16:01 +01:00
ComponentHandle cmp = {r.entity.index};
if (path[0] != 0)
{
auto* model = static_cast<Model*>(m_engine.getResourceManager().get(MODEL_TYPE)->load(Path(path)));
setModel(cmp, model);
}
int material_count;
serializer.read(&material_count);
if (material_count > 0)
{
allocateCustomMeshes(r, material_count);
for (int j = 0; j < material_count; ++j)
{
char path[MAX_PATH_LENGTH];
serializer.read(path, lengthOf(path));
setModelInstanceMaterial(cmp, j, Path(path));
}
}
m_universe.addComponent(r.entity, MODEL_INSTANCE_TYPE, this, cmp);
}
void serializeGlobalLight(ISerializer& serializer, ComponentHandle cmp)
{
2017-02-09 14:22:41 +01:00
GlobalLight& light = m_global_lights[{cmp.index}];
2016-12-10 15:16:01 +01:00
serializer.write("cascades", light.m_cascades);
serializer.write("diffuse_color", light.m_diffuse_color);
serializer.write("diffuse_intensity", light.m_diffuse_intensity);
serializer.write("indirect_intensity", light.m_indirect_intensity);
2016-12-10 15:16:01 +01:00
serializer.write("fog_bottom", light.m_fog_bottom);
serializer.write("fog_color", light.m_fog_color);
serializer.write("fog_density", light.m_fog_density);
serializer.write("fog_height", light.m_fog_height);
}
2017-02-09 14:22:41 +01:00
void deserializeGlobalLight(IDeserializer& serializer, Entity entity, int scene_version)
2016-12-10 15:16:01 +01:00
{
2017-02-09 14:22:41 +01:00
GlobalLight light;
2016-12-10 15:16:01 +01:00
light.m_entity = entity;
serializer.read(&light.m_cascades);
2017-02-21 16:37:07 +01:00
if (scene_version <= (int)RenderSceneVersion::GLOBAL_LIGHT_REFACTOR)
2017-02-09 14:22:41 +01:00
{
ComponentHandle dummy;
serializer.read(&dummy);
}
2016-12-10 15:16:01 +01:00
serializer.read(&light.m_diffuse_color);
serializer.read(&light.m_diffuse_intensity);
if (scene_version > (int)RenderSceneVersion::INDIRECT_INTENSITY)
{
serializer.read(&light.m_indirect_intensity);
}
else
{
light.m_indirect_intensity = 1;
}
2016-12-10 15:16:01 +01:00
serializer.read(&light.m_fog_bottom);
serializer.read(&light.m_fog_color);
serializer.read(&light.m_fog_density);
serializer.read(&light.m_fog_height);
2017-02-09 14:22:41 +01:00
m_global_lights.insert(entity, light);
ComponentHandle cmp = {entity.index};
m_universe.addComponent(light.m_entity, GLOBAL_LIGHT_TYPE, this, cmp);
m_active_global_light_cmp = cmp;
2016-12-10 15:16:01 +01:00
}
void serializePointLight(ISerializer& serializer, ComponentHandle cmp)
{
PointLight& light = m_point_lights[m_point_lights_map[cmp]];
serializer.write("attenuation", light.m_attenuation_param);
serializer.write("cast_shadow", light.m_cast_shadows);
serializer.write("component", light.m_component);
serializer.write("diffuse_color", light.m_diffuse_color);
serializer.write("diffuse_intensity", light.m_diffuse_intensity);
serializer.write("fov", light.m_fov);
serializer.write("range", light.m_range);
serializer.write("specular_color", light.m_specular_color);
serializer.write("specular_intensity", light.m_specular_intensity);
}
2017-01-24 16:56:42 +01:00
void deserializePointLight(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
m_light_influenced_geometry.emplace(m_allocator);
2016-12-10 15:16:01 +01:00
PointLight& light = m_point_lights.emplace();
light.m_entity = entity;
serializer.read(&light.m_attenuation_param);
serializer.read(&light.m_cast_shadows);
serializer.read(&light.m_component);
serializer.read(&light.m_diffuse_color);
serializer.read(&light.m_diffuse_intensity);
serializer.read(&light.m_fov);
serializer.read(&light.m_range);
serializer.read(&light.m_specular_color);
serializer.read(&light.m_specular_intensity);
m_point_lights_map.insert(light.m_component, m_point_lights.size() - 1);
m_universe.addComponent(light.m_entity, POINT_LIGHT_TYPE, this, light.m_component);
}
void serializeDecal(ISerializer& serializer, ComponentHandle cmp)
{
2017-05-18 10:51:28 +02:00
const Decal& decal = m_decals[{cmp.index}];
serializer.write("scale", decal.scale);
serializer.write("material", decal.material ? decal.material->getPath().c_str() : "");
2016-12-10 15:16:01 +01:00
}
2017-01-24 16:56:42 +01:00
void deserializeDecal(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ResourceManagerBase* material_manager = m_engine.getResourceManager().get(MATERIAL_TYPE);
Decal& decal = m_decals.insert(entity);
char tmp[MAX_PATH_LENGTH];
decal.entity = entity;
serializer.read(&decal.scale);
serializer.read(tmp, lengthOf(tmp));
decal.material = tmp[0] == '\0' ? nullptr : static_cast<Material*>(material_manager->load(Path(tmp)));
updateDecalInfo(decal);
m_universe.addComponent(decal.entity, DECAL_TYPE, this, {decal.entity.index});
}
void serializeCamera(ISerializer& serialize, ComponentHandle cmp)
{
Camera& camera = m_cameras[{cmp.index}];
serialize.write("far", camera.far);
serialize.write("fov", camera.fov);
serialize.write("is_ortho", camera.is_ortho);
serialize.write("ortho_size", camera.ortho_size);
serialize.write("near", camera.near);
serialize.write("slot", camera.slot);
}
2017-01-24 16:56:42 +01:00
void deserializeCamera(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
Camera camera;
camera.entity = entity;
serializer.read(&camera.far);
serializer.read(&camera.fov);
serializer.read(&camera.is_ortho);
serializer.read(&camera.ortho_size);
serializer.read(&camera.near);
serializer.read(camera.slot, lengthOf(camera.slot));
m_cameras.insert(camera.entity, camera);
m_universe.addComponent(camera.entity, CAMERA_TYPE, this, {camera.entity.index});
}
void serializeBoneAttachment(ISerializer& serializer, ComponentHandle cmp)
{
BoneAttachment& attachment = m_bone_attachments[{cmp.index}];
2016-12-10 15:16:01 +01:00
serializer.write("bone_index", attachment.bone_index);
serializer.write("parent", attachment.parent_entity);
serializer.write("relative_transform", attachment.relative_transform);
}
2017-01-24 16:56:42 +01:00
void deserializeBoneAttachment(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
BoneAttachment& bone_attachment = m_bone_attachments.emplace(entity);
2016-12-10 15:16:01 +01:00
bone_attachment.entity = entity;
serializer.read(&bone_attachment.bone_index);
serializer.read(&bone_attachment.parent_entity);
serializer.read(&bone_attachment.relative_transform);
ComponentHandle cmp = {bone_attachment.entity.index};
m_universe.addComponent(bone_attachment.entity, BONE_ATTACHMENT_TYPE, this, cmp);
Entity parent_entity = bone_attachment.parent_entity;
if (parent_entity.isValid() && parent_entity.index < m_model_instances.size())
{
ModelInstance& mi = m_model_instances[parent_entity.index];
mi.flags = mi.flags | ModelInstance::IS_BONE_ATTACHMENT_PARENT;
}
2016-12-10 15:16:01 +01:00
}
void serializeTerrain(ISerializer& serializer, ComponentHandle cmp)
{
Terrain* terrain = m_terrains[{cmp.index}];
serializer.write("layer_mask", terrain->m_layer_mask);
serializer.write("scale", terrain->m_scale);
serializer.write("material", terrain->m_material ? terrain->m_material->getPath().c_str() : "");
serializer.write("grass_count", terrain->m_grass_types.size());
for (Terrain::GrassType& type : terrain->m_grass_types)
{
serializer.write("density", type.m_density);
serializer.write("distance", type.m_distance);
2017-01-24 16:56:42 +01:00
serializer.write("rotation_mode", (int)type.m_rotation_mode);
2016-12-10 15:16:01 +01:00
serializer.write("model", type.m_grass_model ? type.m_grass_model->getPath().c_str() : "");
}
}
2017-01-24 16:56:42 +01:00
void deserializeTerrain(IDeserializer& serializer, Entity entity, int version)
2016-12-10 15:16:01 +01:00
{
Terrain* terrain = LUMIX_NEW(m_allocator, Terrain)(m_renderer, entity, *this, m_allocator);
m_terrains.insert(entity, terrain);
terrain->m_entity = entity;
serializer.read(&terrain->m_layer_mask);
serializer.read(&terrain->m_scale);
char tmp[MAX_PATH_LENGTH];
serializer.read(tmp, lengthOf(tmp));
auto* material = tmp[0] ? m_engine.getResourceManager().get(MATERIAL_TYPE)->load(Path(tmp)) : nullptr;
terrain->setMaterial((Material*)material);
int count;
serializer.read(&count);
for(int i = 0; i < count; ++i)
{
Terrain::GrassType type(*terrain);
serializer.read(&type.m_density);
serializer.read(&type.m_distance);
2017-01-24 16:56:42 +01:00
if (version >= (int)RenderSceneVersion::GRASS_ROTATION_MODE)
{
serializer.read((int*)&type.m_rotation_mode);
}
2016-12-12 22:46:07 +01:00
type.m_idx = i;
2016-12-10 15:16:01 +01:00
serializer.read(tmp, lengthOf(tmp));
terrain->m_grass_types.push(type);
terrain->setGrassTypePath(terrain->m_grass_types.size() - 1, Path(tmp));
}
m_universe.addComponent(entity, TERRAIN_TYPE, this, { entity.index });
}
2017-01-03 17:04:09 +01:00
void serializeEnvironmentProbe(ISerializer& serializer, ComponentHandle cmp)
{
serializer.write("guid", m_environment_probes[{cmp.index}].guid);
}
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 deserializeEnvironmentProbe(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
auto* texture_manager = m_engine.getResourceManager().get(TEXTURE_TYPE);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> probe_dir("universes/", m_universe.getName(), "/probes/");
2016-12-10 15:16:01 +01:00
EnvironmentProbe& probe = m_environment_probes.insert(entity);
2017-01-03 17:04:09 +01:00
serializer.read(&probe.guid);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> path_str(probe_dir, probe.guid, ".dds");
2016-12-10 15:16:01 +01:00
probe.texture = static_cast<Texture*>(texture_manager->load(Path(path_str)));
probe.texture->setFlag(BGFX_TEXTURE_SRGB, true);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> irr_path_str(probe_dir, probe.guid, "_irradiance.dds");
2016-12-10 15:16:01 +01:00
probe.irradiance = static_cast<Texture*>(texture_manager->load(Path(irr_path_str)));
probe.irradiance->setFlag(BGFX_TEXTURE_SRGB, true);
probe.irradiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.irradiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> r_path_str(probe_dir, probe.guid, "_radiance.dds");
2016-12-10 15:16:01 +01:00
probe.radiance = static_cast<Texture*>(texture_manager->load(Path(r_path_str)));
probe.radiance->setFlag(BGFX_TEXTURE_SRGB, true);
probe.radiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.radiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
m_universe.addComponent(entity, ENVIRONMENT_PROBE_TYPE, this, {entity.index});
}
void serializeParticleEmitter(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
serializer.write("autoemit", emitter->m_autoemit);
serializer.write("local_space", emitter->m_local_space);
serializer.write("spawn_period_from", emitter->m_spawn_period.from);
serializer.write("spawn_period_to", emitter->m_spawn_period.to);
serializer.write("initial_life_from", emitter->m_initial_life.from);
serializer.write("initial_life_to", emitter->m_initial_life.to);
serializer.write("initial_size_from", emitter->m_initial_size.from);
serializer.write("initial_size_to", emitter->m_initial_size.to);
serializer.write("spawn_count_from", emitter->m_spawn_count.from);
serializer.write("spawn_count_to", emitter->m_spawn_count.to);
2017-02-22 15:12:36 +01:00
const Material* material = emitter->getMaterial();
2017-02-21 16:37:07 +01:00
serializer.write("material", material ? material->getPath().c_str() : "");
2016-12-10 15:16:01 +01:00
}
2017-02-21 16:37:07 +01:00
void deserializeParticleEmitter(IDeserializer& serializer, Entity entity, int scene_version)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = LUMIX_NEW(m_allocator, ParticleEmitter)(entity, m_universe, m_allocator);
emitter->m_entity = entity;
serializer.read(&emitter->m_autoemit);
serializer.read(&emitter->m_local_space);
serializer.read(&emitter->m_spawn_period.from);
serializer.read(&emitter->m_spawn_period.to);
serializer.read(&emitter->m_initial_life.from);
serializer.read(&emitter->m_initial_life.to);
serializer.read(&emitter->m_initial_size.from);
serializer.read(&emitter->m_initial_size.to);
serializer.read(&emitter->m_spawn_count.from);
serializer.read(&emitter->m_spawn_count.to);
2017-02-21 16:37:07 +01:00
if (scene_version > (int)RenderSceneVersion::EMITTER_MATERIAL)
{
char tmp[MAX_PATH_LENGTH];
serializer.read(tmp, lengthOf(tmp));
ResourceManagerBase* material_manager = m_engine.getResourceManager().get(MATERIAL_TYPE);
Material* material = (Material*)material_manager->load(Path(tmp));
emitter->setMaterial(material);
}
2016-12-10 15:16:01 +01:00
m_particle_emitters.insert(entity, emitter);
m_universe.addComponent(entity, PARTICLE_EMITTER_TYPE, this, {entity.index});
}
void serializeParticleEmitterAlpha(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::AlphaModule*)emitter->getModule(PARTICLE_EMITTER_ALPHA_TYPE);
serializer.write("count", module->m_values.size());
for (Vec2 v : module->m_values)
{
serializer.write("", v.x);
serializer.write("", v.y);
}
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterAlpha(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::AlphaModule)(*emitter);
int count;
serializer.read(&count);
module->m_values.clear();
for (int i = 0; i < count; ++i)
{
Vec2& v = module->m_values.emplace();
serializer.read(&v.x);
serializer.read(&v.y);
}
module->sample();
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_ALPHA_TYPE, this, {entity.index});
}
void serializeParticleEmitterAttractor(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::AttractorModule*)emitter->getModule(PARTICLE_EMITTER_ATTRACTOR_TYPE);
serializer.write("force", module->m_force);
serializer.write("count", module->m_count);
for (int i = 0; i < module->m_count; ++i)
{
serializer.write("", module->m_entities[i]);
}
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterAttractor(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::AttractorModule)(*emitter);
serializer.read(&module->m_force);
serializer.read(&module->m_count);
for (int i = 0; i < module->m_count; ++i)
{
serializer.read(&module->m_entities[i]);
}
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_ATTRACTOR_TYPE, this, {entity.index});
}
void serializeParticleEmitterForce(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::ForceModule*)emitter->getModule(PARTICLE_EMITTER_FORCE_HASH);
serializer.write("acceleration", module->m_acceleration);
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterForce(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::ForceModule)(*emitter);
serializer.read(&module->m_acceleration);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_FORCE_HASH, this, {entity.index});
}
void serializeParticleEmitterLinearMovement(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::LinearMovementModule*)emitter->getModule(PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE);
serializer.write("x_from", module->m_x.from);
serializer.write("x_to", module->m_x.to);
serializer.write("y_from", module->m_y.from);
serializer.write("y_to", module->m_y.to);
serializer.write("z_from", module->m_z.from);
serializer.write("z_to", module->m_z.to);
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterLinearMovement(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::LinearMovementModule)(*emitter);
serializer.read(&module->m_x.from);
serializer.read(&module->m_x.to);
serializer.read(&module->m_y.from);
serializer.read(&module->m_y.to);
serializer.read(&module->m_z.from);
serializer.read(&module->m_z.to);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE, this, {entity.index});
}
void serializeParticleEmitterPlane(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::PlaneModule*)emitter->getModule(PARTICLE_EMITTER_PLANE_TYPE);
serializer.write("bounce", module->m_bounce);
serializer.write("entities_count", module->m_count);
for (int i = 0; i < module->m_count; ++i)
{
serializer.write("", module->m_entities[i]);
}
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterPlane(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::PlaneModule)(*emitter);
serializer.read(&module->m_bounce);
serializer.read(&module->m_count);
for (int i = 0; i < module->m_count; ++i)
{
serializer.read(&module->m_entities[i]);
}
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_PLANE_TYPE, this, {entity.index});
}
void serializeParticleEmitterSpawnShape(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::SpawnShapeModule*)emitter->getModule(PARTICLE_EMITTER_SPAWN_SHAPE_TYPE);
serializer.write("shape", (u8)module->m_shape);
serializer.write("radius", module->m_radius);
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterSpawnShape(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::SpawnShapeModule)(*emitter);
serializer.read((u8*)&module->m_shape);
serializer.read(&module->m_radius);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SPAWN_SHAPE_TYPE, this, {entity.index});
}
void serializeParticleEmitterSize(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::SizeModule*)emitter->getModule(PARTICLE_EMITTER_SIZE_TYPE);
serializer.write("count", module->m_values.size());
for (Vec2 v : module->m_values)
{
serializer.write("", v.x);
serializer.write("", v.y);
}
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterSize(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::SizeModule)(*emitter);
int count;
serializer.read(&count);
module->m_values.clear();
for (int i = 0; i < count; ++i)
{
Vec2& v = module->m_values.emplace();
serializer.read(&v.x);
serializer.read(&v.y);
}
module->sample();
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SIZE_TYPE, this, {entity.index});
}
void serializeParticleEmitterRandomRotation(ISerializer& serialize, ComponentHandle cmp) {}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterRandomRotation(IDeserializer& serialize, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::RandomRotationModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_RANDOM_ROTATION_TYPE, this, {entity.index});
}
void serializeParticleEmitterSubimage(ISerializer& serializer, ComponentHandle cmp)
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
auto* module = (ParticleEmitter::SubimageModule*)emitter->getModule(PARTICLE_EMITTER_SUBIMAGE_TYPE);
serializer.write("rows", module->rows);
serializer.write("cols", module->cols);
}
2017-01-24 16:56:42 +01:00
void deserializeParticleEmitterSubimage(IDeserializer& serializer, Entity entity, int /*scene_version*/)
2016-12-10 15:16:01 +01:00
{
ParticleEmitter* emitter = m_particle_emitters[entity];
auto* module = LUMIX_NEW(m_allocator, ParticleEmitter::SubimageModule)(*emitter);
serializer.read(&module->rows);
serializer.read(&module->cols);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SUBIMAGE_TYPE, this, {entity.index});
}
2016-05-02 21:41:18 +02:00
void serializeBoneAttachments(OutputBlob& serializer)
{
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
}
}
2015-07-21 20:10:50 +02:00
void serializeCameras(OutputBlob& serializer)
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_cameras.size());
for (auto& camera : m_cameras)
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
serializer.write(camera.entity);
serializer.write(camera.far);
serializer.write(camera.fov);
serializer.write(camera.is_ortho);
serializer.write(camera.ortho_size);
serializer.write(camera.near);
serializer.writeString(camera.slot);
2015-07-21 20:10:50 +02:00
}
}
2015-02-05 22:57:55 +01:00
2015-07-21 20:10:50 +02:00
void serializeLights(OutputBlob& serializer)
{
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_point_lights.size());
2015-07-21 20:10:50 +02:00
for (int i = 0, c = m_point_lights.size(); i < c; ++i)
{
serializer.write(m_point_lights[i]);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
serializer.write(m_point_light_last_cmp);
2015-07-21 20:10:50 +02:00
2016-11-20 17:27:41 +01:00
serializer.write((i32)m_global_lights.size());
2017-02-09 14:22:41 +01:00
for (const GlobalLight& light : m_global_lights)
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
}
2016-06-22 15:05:19 +02:00
serializer.write(m_active_global_light_cmp);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void serializeModelInstances(OutputBlob& 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.entity);
2017-08-28 22:58:04 +02:00
serializer.write(u8(r.flags & ModelInstance::PERSISTENT_FLAGS));
if(r.entity != INVALID_ENTITY)
2015-12-10 17:09:52 +01:00
{
serializer.write(r.model ? r.model->getPath().getHash() : 0);
2016-02-01 15:13:00 +01:00
bool has_changed_materials = r.model && r.model->isReady() && r.meshes != &r.model->getMesh(0);
serializer.write(has_changed_materials ? r.mesh_count : 0);
if (has_changed_materials)
{
for (int i = 0; i < r.mesh_count; ++i)
{
2016-01-22 18:02:07 +01:00
serializer.writeString(r.meshes[i].material->getPath().c_str());
}
}
2015-12-10 17:09:52 +01:00
}
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
void serializeTerrains(OutputBlob& serializer)
{
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
{
terrain->serialize(serializer);
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
2016-07-22 13:57:52 +02:00
void deserializeDecals(InputBlob& serializer)
{
2016-07-24 22:21:43 +02:00
ResourceManagerBase* material_manager = m_engine.getResourceManager().get(MATERIAL_TYPE);
2016-07-22 13:57:52 +02:00
int count;
serializer.read(count);
m_decals.reserve(count);
for (int i = 0; i < count; ++i)
{
char tmp[MAX_PATH_LENGTH];
Decal decal;
serializer.read(decal.entity);
serializer.read(decal.scale);
serializer.readString(tmp, lengthOf(tmp));
decal.material = tmp[0] == '\0' ? nullptr : static_cast<Material*>(material_manager->load(Path(tmp)));
updateDecalInfo(decal);
m_decals.insert(decal.entity, decal);
m_universe.addComponent(decal.entity, DECAL_TYPE, this, {decal.entity.index});
}
}
void serializeDecals(OutputBlob& serializer)
{
serializer.write(m_decals.size());
for (auto& decal : m_decals)
{
serializer.write(decal.entity);
serializer.write(decal.scale);
serializer.writeString(decal.material ? decal.material->getPath().c_str() : "");
}
}
2016-06-12 15:26:41 +02:00
void serializeEnvironmentProbes(OutputBlob& serializer)
{
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)
{
Entity entity = m_environment_probes.getKey(i);
serializer.write(entity);
2017-01-03 17:04:09 +01:00
serializer.write(m_environment_probes.at(i).guid);
2016-06-12 15:26:41 +02:00
}
}
void deserializeEnvironmentProbes(InputBlob& serializer)
{
2016-11-20 17:27:41 +01:00
i32 count;
2016-06-12 15:26:41 +02:00
serializer.read(count);
m_environment_probes.reserve(count);
2016-07-24 22:21:43 +02:00
auto* texture_manager = m_engine.getResourceManager().get(TEXTURE_TYPE);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> probe_dir("universes/", m_universe.getName(), "/probes/");
2016-06-12 15:26:41 +02:00
for (int i = 0; i < count; ++i)
{
Entity entity;
serializer.read(entity);
2016-07-24 17:29:17 +02:00
EnvironmentProbe& probe = m_environment_probes.insert(entity);
2017-01-03 17:04:09 +01:00
serializer.read(probe.guid);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> path_str(probe_dir, probe.guid, ".dds");
2016-11-29 20:00:36 +01:00
probe.texture = static_cast<Texture*>(texture_manager->load(Path(path_str)));
probe.texture->setFlag(BGFX_TEXTURE_SRGB, true);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> irr_path_str(probe_dir, probe.guid, "_irradiance.dds");
2016-11-29 20:00:36 +01:00
probe.irradiance = static_cast<Texture*>(texture_manager->load(Path(irr_path_str)));
probe.irradiance->setFlag(BGFX_TEXTURE_SRGB, true);
2016-11-30 22:33:33 +01:00
probe.irradiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.irradiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> r_path_str(probe_dir, probe.guid, "_radiance.dds");
2016-11-29 20:00:36 +01:00
probe.radiance = static_cast<Texture*>(texture_manager->load(Path(r_path_str)));
probe.radiance->setFlag(BGFX_TEXTURE_SRGB, true);
2016-11-30 22:33:33 +01:00
probe.radiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.radiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
2016-11-29 20:00:36 +01:00
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = {entity.index};
m_universe.addComponent(entity, ENVIRONMENT_PROBE_TYPE, this, cmp);
2016-06-12 15:26:41 +02:00
}
}
2017-01-03 17:04:09 +01:00
void deserializeBoneAttachments(InputBlob& serializer)
2016-05-02 21:41:18 +02:00
{
2016-11-20 17:27:41 +01:00
i32 count;
2016-05-02 21:41:18 +02:00
serializer.read(count);
m_bone_attachments.clear();
m_bone_attachments.reserve(count);
2016-05-02 21:41:18 +02:00
for (int 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);
serializer.read(bone_attachment.parent_entity);
serializer.read(bone_attachment.relative_transform);
m_bone_attachments.insert(bone_attachment.entity, bone_attachment);
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = {bone_attachment.entity.index};
m_universe.addComponent(bone_attachment.entity, BONE_ATTACHMENT_TYPE, this, cmp);
2016-05-02 21:41:18 +02:00
}
}
2017-01-03 17:04:09 +01:00
void deserializeParticleEmitters(InputBlob& serializer)
{
int count;
serializer.read(count);
m_particle_emitters.reserve(count);
for(int i = 0; i < count; ++i)
{
ParticleEmitter* emitter = LUMIX_NEW(m_allocator, ParticleEmitter)(INVALID_ENTITY, m_universe, m_allocator);
serializer.read(emitter->m_is_valid);
2017-01-03 17:04:09 +01:00
if (emitter->m_is_valid)
{
2017-01-03 17:04:09 +01:00
emitter->deserialize(serializer, m_engine.getResourceManager());
ComponentHandle cmp = {emitter->m_entity.index};
if (emitter->m_is_valid) m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_TYPE, this, cmp);
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::AlphaModule::s_type)
{
2016-06-22 15:05:19 +02:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_ALPHA_TYPE, this, cmp);
}
else if (module->getType() == ParticleEmitter::ForceModule::s_type)
{
2016-06-22 15:05:19 +02:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_FORCE_HASH, this, cmp);
}
2016-10-02 22:56:47 +02:00
else if (module->getType() == ParticleEmitter::SubimageModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_SUBIMAGE_TYPE, this, cmp);
2016-10-02 22:56:47 +02:00
}
else if (module->getType() == ParticleEmitter::SpawnShapeModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_SPAWN_SHAPE_TYPE, this, cmp);
}
else if (module->getType() == ParticleEmitter::AttractorModule::s_type)
2015-12-17 13:58:40 +01:00
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_ATTRACTOR_TYPE, this, cmp);
2015-12-17 13:58:40 +01:00
}
else if (module->getType() == ParticleEmitter::LinearMovementModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE, this, cmp);
}
2015-12-16 21:26:19 +01:00
else if (module->getType() == ParticleEmitter::PlaneModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_PLANE_TYPE, this, cmp);
2015-12-16 21:26:19 +01:00
}
else if (module->getType() == ParticleEmitter::RandomRotationModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_RANDOM_ROTATION_TYPE, this, cmp);
}
2015-11-18 20:18:48 +01:00
else if (module->getType() == ParticleEmitter::SizeModule::s_type)
{
2016-12-10 15:16:01 +01:00
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_SIZE_TYPE, this, cmp);
2015-11-18 20:18:48 +01:00
}
}
}
if (!emitter->m_is_valid && emitter->m_modules.empty())
{
LUMIX_DELETE(m_allocator, emitter);
}
else
{
m_particle_emitters.insert(emitter->m_entity, emitter);
}
}
}
void serializeParticleEmitters(OutputBlob& serializer)
{
serializer.write(m_particle_emitters.size());
for (auto* emitter : m_particle_emitters)
{
serializer.write(emitter->m_is_valid);
emitter->serialize(serializer);
}
}
void serialize(OutputBlob& 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);
2016-07-22 13:57:52 +02:00
serializeDecals(serializer);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2017-01-03 17:04:09 +01:00
void deserializeCameras(InputBlob& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
i32 size;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_cameras.rehash(size);
2015-07-21 20:10:50 +02:00
for (int i = 0; i < size; ++i)
{
Camera camera;
2016-04-17 21:47:54 +02:00
serializer.read(camera.entity);
serializer.read(camera.far);
serializer.read(camera.fov);
serializer.read(camera.is_ortho);
2017-01-03 17:04:09 +01:00
serializer.read(camera.ortho_size);
2016-04-17 21:47:54 +02:00
serializer.read(camera.near);
serializer.readString(camera.slot, lengthOf(camera.slot));
2015-07-21 20:10:50 +02:00
2017-01-03 17:04:09 +01:00
m_cameras.insert(camera.entity, camera);
m_universe.addComponent(camera.entity, CAMERA_TYPE, this, {camera.entity.index});
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
2017-01-03 17:04:09 +01:00
void deserializeModelInstances(InputBlob& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
i32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_model_instances.reserve(size);
2015-07-21 20:10:50 +02:00
for (int i = 0; i < size; ++i)
{
auto& r = m_model_instances.emplace();
serializer.read(r.entity);
2017-04-13 17:05:07 +02:00
serializer.read(r.flags);
2017-08-28 22:58:04 +02:00
r.flags &= ModelInstance::PERSISTENT_FLAGS;
2017-05-23 14:01:09 +02:00
ASSERT(r.entity.index == i || !r.entity.isValid());
r.model = nullptr;
r.pose = nullptr;
r.meshes = nullptr;
r.mesh_count = 0;
2015-07-21 20:10:50 +02:00
if(r.entity != INVALID_ENTITY)
2015-12-10 17:09:52 +01:00
{
r.matrix = m_universe.getMatrix(r.entity);
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
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = { r.entity.index };
if (path != 0)
{
2016-07-24 22:21:43 +02:00
auto* model = static_cast<Model*>(m_engine.getResourceManager().get(MODEL_TYPE)->load(Path(path)));
2016-06-22 15:05:19 +02:00
setModel(cmp, model);
}
2017-01-03 17:04:09 +01:00
int material_count;
serializer.read(material_count);
if (material_count > 0)
2015-12-10 17:09:52 +01:00
{
2017-01-03 17:04:09 +01:00
allocateCustomMeshes(r, material_count);
for (int j = 0; j < material_count; ++j)
{
2017-01-03 17:04:09 +01:00
char path[MAX_PATH_LENGTH];
serializer.readString(path, lengthOf(path));
setModelInstanceMaterial(cmp, j, Path(path));
}
2015-12-10 17:09:52 +01:00
}
m_universe.addComponent(r.entity, MODEL_INSTANCE_TYPE, this, cmp);
2015-12-10 17:09:52 +01:00
}
2015-07-21 20:10:50 +02:00
}
}
2015-02-05 22:57:55 +01:00
2017-01-03 17:04:09 +01:00
void deserializeLights(InputBlob& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
i32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_point_lights.resize(size);
for (int i = 0; i < size; ++i)
{
m_light_influenced_geometry.emplace(m_allocator);
2015-07-21 20:10:50 +02:00
PointLight& light = m_point_lights[i];
2017-01-03 17:04:09 +01:00
serializer.read(light);
2016-06-22 15:05:19 +02:00
m_point_lights_map.insert(light.m_component, i);
2016-06-22 15:05:19 +02:00
m_universe.addComponent(light.m_entity, POINT_LIGHT_TYPE, this, light.m_component);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
serializer.read(m_point_light_last_cmp);
2015-07-21 20:10:50 +02:00
serializer.read(size);
for (int i = 0; i < size; ++i)
{
2017-02-09 14:22:41 +01:00
GlobalLight light;
2017-01-03 17:04:09 +01:00
serializer.read(light);
2017-02-09 14:22:41 +01:00
m_global_lights.insert(light.m_entity, light);
m_universe.addComponent(light.m_entity, GLOBAL_LIGHT_TYPE, this, {light.m_entity.index});
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
serializer.read(m_active_global_light_cmp);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2017-01-03 17:04:09 +01:00
void deserializeTerrains(InputBlob& serializer)
2015-07-21 20:10:50 +02:00
{
2016-11-20 17:27:41 +01:00
i32 size = 0;
serializer.read(size);
2015-07-21 20:10:50 +02:00
for (int i = 0; i < size; ++i)
{
2017-01-03 17:04:09 +01:00
auto* terrain = LUMIX_NEW(m_allocator, Terrain)(m_renderer, INVALID_ENTITY, *this, m_allocator);
terrain->deserialize(serializer, m_universe, *this);
m_terrains.insert(terrain->getEntity(), terrain);
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
2017-01-03 17:04:09 +01:00
void deserialize(InputBlob& serializer) override
{
2017-01-03 17:04:09 +01:00
deserializeCameras(serializer);
deserializeModelInstances(serializer);
deserializeLights(serializer);
deserializeTerrains(serializer);
deserializeParticleEmitters(serializer);
deserializeBoneAttachments(serializer);
deserializeEnvironmentProbes(serializer);
deserializeDecals(serializer);
2016-05-02 21:41:18 +02:00
}
2016-06-22 15:05:19 +02:00
void destroyBoneAttachment(ComponentHandle component)
2016-05-02 21:41:18 +02:00
{
Entity entity = {component.index};
const BoneAttachment& bone_attachment = m_bone_attachments[entity];
Entity parent_entity = bone_attachment.parent_entity;
if (parent_entity.isValid() && parent_entity.index < m_model_instances.size())
{
ModelInstance& mi = m_model_instances[bone_attachment.parent_entity.index];
mi.flags = mi.flags & ~ModelInstance::IS_BONE_ATTACHMENT_PARENT;
}
m_bone_attachments.erase(entity);
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, BONE_ATTACHMENT_TYPE, this, component);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2014-08-17 17:55:34 +02:00
2016-06-22 15:05:19 +02:00
void destroyEnvironmentProbe(ComponentHandle component)
2016-06-12 15:26:41 +02:00
{
2016-06-22 15:05:19 +02:00
Entity entity = {component.index};
2016-06-12 15:26:41 +02:00
auto& probe = m_environment_probes[entity];
2016-07-25 01:02:36 +02:00
if (probe.texture) probe.texture->getResourceManager().unload(*probe.texture);
2016-06-12 15:26:41 +02:00
m_environment_probes.erase(entity);
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, ENVIRONMENT_PROBE_TYPE, this, component);
2016-06-12 15:26:41 +02:00
}
void destroyModelInstance(ComponentHandle component)
2015-07-21 20:10:50 +02:00
{
for (int i = 0; i < m_light_influenced_geometry.size(); ++i)
{
2016-06-22 15:05:19 +02:00
Array<ComponentHandle>& influenced_geometry = m_light_influenced_geometry[i];
2015-07-21 20:10:50 +02:00
for (int j = 0; j < influenced_geometry.size(); ++j)
{
2015-12-10 17:09:52 +01:00
if (influenced_geometry[j] == component)
2015-07-15 20:31:40 +02:00
{
2015-07-21 20:10:50 +02:00
influenced_geometry.erase(j);
break;
}
}
2015-07-21 20:10:50 +02:00
}
2015-12-10 17:09:52 +01:00
setModel(component, nullptr);
auto& model_instance = m_model_instances[component.index];
Entity entity = model_instance.entity;
LUMIX_DELETE(m_allocator, model_instance.pose);
model_instance.pose = nullptr;
model_instance.entity = INVALID_ENTITY;
m_universe.destroyComponent(entity, MODEL_INSTANCE_TYPE, this, component);
2015-07-21 20:10:50 +02:00
}
2014-08-17 17:55:34 +02:00
2016-06-22 15:05:19 +02:00
void destroyGlobalLight(ComponentHandle component)
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
Entity entity = {component.index};
2015-07-23 23:17:51 +02:00
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, GLOBAL_LIGHT_TYPE, this, component);
2015-07-23 23:17:51 +02:00
2016-06-22 15:05:19 +02:00
if (component == m_active_global_light_cmp)
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
m_active_global_light_cmp = INVALID_COMPONENT;
2015-07-21 20:10:50 +02:00
}
2017-02-09 14:22:41 +01:00
m_global_lights.erase(entity);
}
2016-07-22 13:57:52 +02:00
void destroyDecal(ComponentHandle component)
{
Entity entity = {component.index};
m_decals.erase(entity);
m_universe.destroyComponent(entity, DECAL_TYPE, this, component);
}
2016-06-22 15:05:19 +02:00
void destroyPointLight(ComponentHandle component)
{
int index = m_point_lights_map[component];
2016-06-22 15:05:19 +02:00
Entity entity = m_point_lights[index].m_entity;
m_point_lights.eraseFast(index);
2016-01-26 10:27:31 +01:00
m_point_lights_map.erase(component);
m_light_influenced_geometry.eraseFast(index);
2016-06-22 15:05:19 +02:00
if (index < m_point_lights.size())
{
m_point_lights_map[m_point_lights[index].m_component] = index;
}
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, POINT_LIGHT_TYPE, this, component);
}
2016-06-22 15:05:19 +02:00
void destroyCamera(ComponentHandle component)
{
Entity entity = {component.index};
m_cameras.erase(entity);
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, CAMERA_TYPE, this, component);
}
2016-06-22 15:05:19 +02:00
void destroyTerrain(ComponentHandle component)
{
Entity entity = {component.index};
LUMIX_DELETE(m_allocator, m_terrains[entity]);
m_terrains.erase(entity);
2016-06-22 00:46:48 +02:00
m_universe.destroyComponent(entity, TERRAIN_TYPE, this, component);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitter(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
emitter->reset();
emitter->m_is_valid = false;
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_TYPE, this, component);
cleanup(emitter);
}
void cleanup(ParticleEmitter* emitter)
{
if (emitter->m_is_valid) return;
if (!emitter->m_modules.empty()) return;
m_particle_emitters.erase(emitter->m_entity);
2016-06-22 15:05:19 +02:00
LUMIX_DELETE(m_allocator, emitter);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterAlpha(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
auto* module = emitter->getModule(PARTICLE_EMITTER_ALPHA_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_ALPHA_TYPE, this, component);
cleanup(emitter);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterForce(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
auto* module = emitter->getModule(PARTICLE_EMITTER_FORCE_HASH);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_FORCE_HASH, this, component);
cleanup(emitter);
}
2016-10-02 22:56:47 +02:00
void destroyParticleEmitterSubimage(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_SUBIMAGE_TYPE);
2016-10-02 22:56:47 +02:00
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
emitter->m_subimage_module = nullptr;
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_SUBIMAGE_TYPE, this, component);
2016-10-02 22:56:47 +02:00
cleanup(emitter);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterAttractor(ComponentHandle component)
2015-12-17 13:58:40 +01:00
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_ATTRACTOR_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_ATTRACTOR_TYPE, this, component);
cleanup(emitter);
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterSize(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_SIZE_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_SIZE_TYPE, this, component);
cleanup(emitter);
}
2016-06-22 15:05:19 +02:00
float getParticleEmitterPlaneBounce(ComponentHandle cmp) override
{
auto* emitter = m_particle_emitters[{cmp.index}];
2015-12-17 13:58:40 +01:00
for(auto* module : emitter->m_modules)
{
2015-12-17 13:58:40 +01:00
if(module->getType() == ParticleEmitter::PlaneModule::s_type)
{
return static_cast<ParticleEmitter::PlaneModule*>(module)->m_bounce;
}
}
return 0;
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterPlaneBounce(ComponentHandle cmp, float value) override
{
auto* emitter = m_particle_emitters[{cmp.index}];
2016-06-22 15:05:19 +02:00
for (auto* module : emitter->m_modules)
{
2016-06-22 15:05:19 +02:00
if (module->getType() == ParticleEmitter::PlaneModule::s_type)
{
static_cast<ParticleEmitter::PlaneModule*>(module)->m_bounce = value;
break;
}
}
}
2016-06-22 15:05:19 +02:00
float getParticleEmitterAttractorForce(ComponentHandle cmp) override
2015-12-17 13:58:40 +01:00
{
auto* emitter = m_particle_emitters[{cmp.index}];
2016-06-22 15:05:19 +02:00
for (auto* module : emitter->m_modules)
2015-12-17 13:58:40 +01:00
{
2016-06-22 15:05:19 +02:00
if (module->getType() == ParticleEmitter::AttractorModule::s_type)
2015-12-17 13:58:40 +01:00
{
return static_cast<ParticleEmitter::AttractorModule*>(module)->m_force;
}
}
return 0;
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterAttractorForce(ComponentHandle cmp, float value) override
2015-12-17 13:58:40 +01:00
{
auto* emitter = m_particle_emitters[{cmp.index}];
2016-06-22 15:05:19 +02:00
for (auto* module : emitter->m_modules)
2015-12-17 13:58:40 +01:00
{
2016-06-22 15:05:19 +02:00
if (module->getType() == ParticleEmitter::AttractorModule::s_type)
2015-12-17 13:58:40 +01:00
{
static_cast<ParticleEmitter::AttractorModule*>(module)->m_force = value;
break;
}
}
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterPlane(ComponentHandle component)
2015-12-16 21:26:19 +01:00
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_PLANE_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_PLANE_TYPE, this, component);
cleanup(emitter);
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterLinearMovement(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE, this, component);
cleanup(emitter);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterSpawnShape(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_SPAWN_SHAPE_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_SPAWN_SHAPE_TYPE, this, component);
cleanup(emitter);
}
2016-06-22 15:05:19 +02:00
void destroyParticleEmitterRandomRotation(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
2016-12-10 15:16:01 +01:00
auto* module = emitter->getModule(PARTICLE_EMITTER_RANDOM_ROTATION_TYPE);
ASSERT(module);
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
2016-12-10 15:16:01 +01:00
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_RANDOM_ROTATION_TYPE, this, component);
cleanup(emitter);
2015-07-21 20:10:50 +02:00
}
2014-08-17 17:55:34 +02:00
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
void destroyComponent(ComponentHandle component, ComponentType type) override;
2016-06-22 15:05:19 +02:00
void setParticleEmitterAlpha(ComponentHandle cmp, const Vec2* values, int count) override
2015-11-18 20:18:48 +01:00
{
ASSERT(count > 0);
2015-12-07 21:49:27 +01:00
ASSERT(values[1].x < 0.001f);
ASSERT(values[count - 2].x > 0.999f);
2015-12-17 21:38:23 +01:00
auto* alpha_module = getEmitterModule<ParticleEmitter::AlphaModule>(cmp);
if (!alpha_module) return;
2016-02-10 12:09:09 +01:00
2015-12-17 21:38:23 +01:00
alpha_module->m_values.resize(count);
for (int i = 0; i < count; ++i)
2015-11-18 20:18:48 +01:00
{
2015-12-17 21:38:23 +01:00
alpha_module->m_values[i] = values[i];
2015-11-18 20:18:48 +01:00
}
2015-12-17 21:38:23 +01:00
alpha_module->sample();
2015-11-18 20:18:48 +01:00
}
2016-10-02 22:56:47 +02:00
void setParticleEmitterSubimageRows(ComponentHandle cmp, const int& value) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
if (module) module->rows = value;
}
void setParticleEmitterSubimageCols(ComponentHandle cmp, const int& value) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
if (module) module->cols = value;
}
int getParticleEmitterSubimageRows(ComponentHandle cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
return module ? module->rows : 1;
}
int getParticleEmitterSubimageCols(ComponentHandle cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
return module ? module->cols : 1;
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterAcceleration(ComponentHandle cmp, const Vec3& value) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::ForceModule>(cmp);
if (module) module->m_acceleration = value;
}
2016-10-04 17:41:16 +02:00
void setParticleEmitterAutoemit(ComponentHandle cmp, bool autoemit) override
{
m_particle_emitters[{cmp.index}]->m_autoemit = autoemit;
}
bool getParticleEmitterAutoemit(ComponentHandle cmp) override
{
return m_particle_emitters[{cmp.index}]->m_autoemit;
}
2016-10-04 21:12:33 +02:00
void setParticleEmitterLocalSpace(ComponentHandle cmp, bool local_space) override
{
m_particle_emitters[{cmp.index}]->m_local_space = local_space;
}
bool getParticleEmitterLocalSpace(ComponentHandle cmp) override
{
return m_particle_emitters[{cmp.index}]->m_local_space;
}
2016-06-22 15:05:19 +02:00
Vec3 getParticleEmitterAcceleration(ComponentHandle cmp) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::ForceModule>(cmp);
return module ? module->m_acceleration : Vec3();
}
2016-06-22 15:05:19 +02:00
int getParticleEmitterSizeCount(ComponentHandle cmp) override
2015-11-18 20:18:48 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::SizeModule>(cmp);
return module ? module->m_values.size() : 0;
2015-11-18 20:18:48 +01:00
}
2016-06-22 15:05:19 +02:00
const Vec2* getParticleEmitterSize(ComponentHandle cmp) override
2015-12-07 00:55:32 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::SizeModule>(cmp);
return module ? &module->m_values[0] : nullptr;
2015-12-07 00:55:32 +01:00
}
2015-11-18 20:18:48 +01:00
2016-06-22 15:05:19 +02:00
void setParticleEmitterSize(ComponentHandle cmp, const Vec2* values, int count) override
2015-11-18 20:18:48 +01:00
{
2015-12-07 00:55:32 +01:00
ASSERT(count > 0);
ASSERT(values[0].x < 0.001f);
ASSERT(values[count-1].x > 0.999f);
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::SizeModule>(cmp);
if (!module) return;
auto size_module = static_cast<ParticleEmitter::SizeModule*>(module);
size_module->m_values.resize(count);
for (int i = 0; i < count; ++i)
2015-11-18 20:18:48 +01:00
{
2015-12-17 21:38:23 +01:00
size_module->m_values[i] = values[i];
2015-11-18 20:18:48 +01:00
}
2015-12-17 21:38:23 +01:00
size_module->sample();
2015-11-18 20:18:48 +01:00
}
2015-12-17 21:38:23 +01:00
template <typename T>
2016-06-22 15:05:19 +02:00
T* getEmitterModule(ComponentHandle cmp) const
{
auto& modules = m_particle_emitters[{cmp.index}]->m_modules;
2015-12-17 21:38:23 +01:00
for (auto* module : modules)
{
2015-12-17 21:38:23 +01:00
if (module->getType() == T::s_type)
{
2015-12-17 21:38:23 +01:00
return static_cast<T*>(module);
}
}
2015-12-17 21:38:23 +01:00
return nullptr;
}
2016-06-22 15:05:19 +02:00
int getParticleEmitterAlphaCount(ComponentHandle cmp) override
2015-12-17 21:38:23 +01:00
{
auto* module = getEmitterModule<ParticleEmitter::AlphaModule>(cmp);
return module ? module->m_values.size() : 0;
}
2016-06-22 15:05:19 +02:00
const Vec2* getParticleEmitterAlpha(ComponentHandle cmp) override
2015-11-18 20:18:48 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AlphaModule>(cmp);
return module ? &module->m_values[0] : 0;
2015-11-18 20:18:48 +01:00
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterLinearMovementX(ComponentHandle cmp) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
return module ? Vec2(module->m_x.from, module->m_x.to) : Vec2(0, 0);
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterLinearMovementX(ComponentHandle cmp, const Vec2& value) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
2016-01-12 22:59:11 +01:00
if (module)
{
module->m_x = value;
module->m_x.check();
}
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterLinearMovementY(ComponentHandle cmp) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
return module ? Vec2(module->m_y.from, module->m_y.to) : Vec2(0, 0);
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterLinearMovementY(ComponentHandle cmp, const Vec2& value) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
2016-01-12 22:59:11 +01:00
if (module)
{
module->m_y = value;
module->m_y.check();
}
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterLinearMovementZ(ComponentHandle cmp) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
return module ? Vec2(module->m_z.from, module->m_z.to) : Vec2(0, 0);
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterLinearMovementZ(ComponentHandle cmp, const Vec2& value) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::LinearMovementModule>(cmp);
2016-01-12 22:59:11 +01:00
if (module)
{
module->m_z = value;
module->m_z.check();
}
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterInitialLife(ComponentHandle cmp) override
2015-10-30 21:11:11 +01:00
{
return m_particle_emitters[{cmp.index}]->m_initial_life;
2015-10-30 21:11:11 +01:00
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterSpawnPeriod(ComponentHandle cmp) override
2015-10-30 21:11:11 +01:00
{
return m_particle_emitters[{cmp.index}]->m_spawn_period;
2015-10-30 21:11:11 +01:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterInitialLife(ComponentHandle cmp, const Vec2& value) override
2015-10-30 21:11:11 +01:00
{
m_particle_emitters[{cmp.index}]->m_initial_life = value;
m_particle_emitters[{cmp.index}]->m_initial_life.checkZero();
2015-10-30 21:11:11 +01:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterInitialSize(ComponentHandle cmp, const Vec2& value) override
2015-11-01 20:56:29 +01:00
{
m_particle_emitters[{cmp.index}]->m_initial_size = value;
m_particle_emitters[{cmp.index}]->m_initial_size.checkZero();
2015-11-01 20:56:29 +01:00
}
2016-06-22 15:05:19 +02:00
Vec2 getParticleEmitterInitialSize(ComponentHandle cmp) override
2015-11-01 20:56:29 +01:00
{
return m_particle_emitters[{cmp.index}]->m_initial_size;
2015-11-01 20:56:29 +01:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterSpawnPeriod(ComponentHandle cmp, const Vec2& value) override
2015-10-30 21:11:11 +01:00
{
auto* emitter = m_particle_emitters[{cmp.index}];
2016-06-22 15:05:19 +02:00
emitter->m_spawn_period = value;
emitter->m_spawn_period.from = Math::maximum(0.01f, emitter->m_spawn_period.from);
emitter->m_spawn_period.checkZero();
2015-10-30 21:11:11 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle createCamera(Entity 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;
camera.fov = Math::degreesToRadians(60);
2016-04-17 21:47:54 +02:00
camera.screen_width = 800;
camera.screen_height = 600;
camera.aspect = 800.0f / 600.0f;
camera.near = 0.1f;
camera.far = 10000.0f;
camera.slot[0] = '\0';
2017-05-23 14:01:09 +02:00
if (!getCameraInSlot("main").isValid()) copyString(camera.slot, "main");
m_cameras.insert(entity, camera);
m_universe.addComponent(entity, CAMERA_TYPE, this, {entity.index});
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createTerrain(Entity 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);
m_universe.addComponent(entity, TERRAIN_TYPE, this, {entity.index});
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createComponent(ComponentType type, Entity entity) override;
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterRandomRotation(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::RandomRotationModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_RANDOM_ROTATION_TYPE, this, {entity.index});
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterPlane(Entity entity)
2015-12-16 21:26:19 +01:00
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::PlaneModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_PLANE_TYPE, this, {entity.index});
return {entity.index};
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterLinearMovement(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::LinearMovementModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE, this, {entity.index});
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterSpawnShape(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SpawnShapeModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_SPAWN_SHAPE_TYPE, this, {entity.index});
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterAlpha(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::AlphaModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_ALPHA_TYPE, this, {entity.index});
return {entity.index};
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2014-10-31 22:53:37 +01:00
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterForce(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::ForceModule)(*emitter);
emitter->addModule(module);
2016-10-02 22:56:47 +02:00
m_universe.addComponent(entity, PARTICLE_EMITTER_FORCE_HASH, this, {entity.index});
return {entity.index};
}
ComponentHandle createParticleEmitterSubimage(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SubimageModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_SUBIMAGE_TYPE, this, {entity.index});
2016-10-02 22:56:47 +02:00
return {entity.index};
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterAttractor(Entity entity)
2015-12-17 13:58:40 +01:00
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::AttractorModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_ATTRACTOR_TYPE, this, { entity.index });
return{ entity.index };
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitterSize(Entity entity)
2015-11-18 20:18:48 +01:00
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SizeModule)(*emitter);
emitter->addModule(module);
2016-12-10 15:16:01 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_SIZE_TYPE, this, { entity.index });
return{ entity.index };
2015-11-18 20:18:48 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle createParticleEmitter(Entity entity)
2015-10-30 21:11:11 +01:00
{
int index = allocateParticleEmitter(entity);
m_particle_emitters.at(index)->init();
2015-10-30 21:11:11 +01:00
m_universe.addComponent(entity, PARTICLE_EMITTER_TYPE, this, {entity.index});
2015-10-30 21:11:11 +01:00
return {entity.index};
}
2015-10-30 21:11:11 +01:00
int allocateParticleEmitter(Entity entity)
{
int index = m_particle_emitters.find(entity);
if (index >= 0) return index;
return m_particle_emitters.insert(entity, LUMIX_NEW(m_allocator, ParticleEmitter)(entity, m_universe, m_allocator));
2015-10-30 21:11:11 +01:00
}
ModelInstance* getModelInstances() override
{
return &m_model_instances[0];
}
ModelInstance* getModelInstance(ComponentHandle cmp) override
{
return &m_model_instances[cmp.index];
}
ComponentHandle getModelInstanceComponent(Entity entity) override
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = {entity.index};
if (cmp.index >= m_model_instances.size()) return INVALID_COMPONENT;
2017-05-23 14:01:09 +02:00
if (!m_model_instances[cmp.index].entity.isValid()) return INVALID_COMPONENT;
2015-12-10 17:09:52 +01:00
return cmp;
2015-07-21 20:10:50 +02:00
}
2014-10-31 22:53:37 +01:00
Vec3 getPoseBonePosition(ComponentHandle model_instance, int bone_index)
{
Pose* pose = m_model_instances[model_instance.index].pose;
return pose->positions[bone_index];
}
2016-06-22 15:05:19 +02:00
Frustum getPointLightFrustum(ComponentHandle cmp) const
{
const PointLight& light = m_point_lights[m_point_lights_map[cmp]];
Frustum frustum;
frustum.computeOrtho(m_universe.getPosition(light.m_entity),
2016-04-17 21:47:54 +02:00
Vec3(1, 0, 0),
Vec3(0, 1, 0),
light.m_range,
light.m_range,
-light.m_range,
light.m_range);
return frustum;
}
2016-05-02 21:41:18 +02:00
void onEntityDestroyed(Entity entity)
{
for (auto& i : m_bone_attachments)
{
if (i.parent_entity == entity)
{
i.parent_entity = INVALID_ENTITY;
break;
}
}
}
2015-07-24 08:42:35 +02:00
void onEntityMoved(Entity entity)
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
int index = entity.index;
ComponentHandle cmp = {index};
2015-12-10 17:09:52 +01:00
2017-05-23 14:01:09 +02:00
if (index < m_model_instances.size() && m_model_instances[index].entity.isValid() &&
m_model_instances[index].model && m_model_instances[index].model->isReady())
2015-07-21 20:10:50 +02:00
{
ModelInstance& r = m_model_instances[index];
r.matrix = m_universe.getMatrix(entity);
if (r.model && r.model->isReady())
{
float radius = m_universe.getScale(entity) * r.model->getBoundingRadius();
Vec3 position = m_universe.getPosition(entity);
m_culling_system->updateBoundingSphere({position, radius}, cmp);
}
2015-12-10 17:09:52 +01:00
2016-11-02 18:29:44 +01:00
float bounding_radius = r.model ? r.model->getBoundingRadius() : 1;
for (int light_idx = 0, c = m_point_lights.size(); light_idx < c; ++light_idx)
2015-07-21 20:10:50 +02:00
{
2016-11-02 18:29:44 +01:00
for (int j = 0, c2 = m_light_influenced_geometry[light_idx].size(); j < c2; ++j)
2015-07-21 20:10:50 +02:00
{
2016-11-02 18:29:44 +01:00
if(m_light_influenced_geometry[light_idx][j] == cmp)
2015-12-10 17:09:52 +01:00
{
2016-11-02 18:29:44 +01:00
m_light_influenced_geometry[light_idx].eraseFast(j);
break;
2015-12-10 17:09:52 +01:00
}
2016-11-02 18:29:44 +01:00
}
2015-12-10 17:09:52 +01:00
2016-11-02 18:29:44 +01:00
Vec3 pos = m_universe.getPosition(r.entity);
Frustum frustum = getPointLightFrustum({light_idx});
if(frustum.isSphereInside(pos, bounding_radius))
{
m_light_influenced_geometry[light_idx].push(cmp);
2015-07-21 20:10:50 +02:00
}
}
}
2016-07-22 13:57:52 +02:00
int decal_idx = m_decals.find(entity);
if (decal_idx >= 0)
{
updateDecalInfo(m_decals.at(decal_idx));
}
2015-07-21 20:10:50 +02:00
for (int i = 0, c = m_point_lights.size(); i < c; ++i)
{
if (m_point_lights[i].m_entity == entity)
2014-07-20 00:45:57 +02:00
{
2016-06-22 15:05:19 +02:00
detectLightInfluencedGeometry(m_point_lights[i].m_component);
2015-07-21 20:10:50 +02:00
break;
2014-07-20 00:45:57 +02:00
}
2015-07-21 20:10:50 +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;
for (auto& attachment : m_bone_attachments)
{
if (attachment.entity == entity)
{
updateRelativeMatrix(attachment);
break;
}
}
2015-07-21 20:10:50 +02:00
}
2014-07-20 00:45:57 +02:00
Engine& getEngine() const override { return m_engine; }
2016-06-22 15:05:19 +02:00
Entity getTerrainEntity(ComponentHandle cmp) override
2016-03-11 23:26:38 +01:00
{
return {cmp.index};
2016-03-11 23:26:38 +01:00
}
2016-06-22 15:05:19 +02:00
Vec2 getTerrainResolution(ComponentHandle cmp) override
2016-03-11 23:26:38 +01:00
{
auto* terrain = m_terrains[{cmp.index}];
2016-06-22 15:05:19 +02:00
return Vec2((float)terrain->getWidth(), (float)terrain->getHeight());
2016-03-11 23:26:38 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle getFirstTerrain() override
2016-03-11 23:26:38 +01:00
{
if (m_terrains.empty()) return INVALID_COMPONENT;
auto iter = m_terrains.begin();
return {iter.value()->getEntity().index};
2016-03-11 23:26:38 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle getNextTerrain(ComponentHandle cmp) override
2016-03-11 23:26:38 +01:00
{
auto iter = m_terrains.find({cmp.index});
++iter;
if (!iter.isValid()) return INVALID_COMPONENT;
return {iter.value()->getEntity().index};
2016-03-11 23:26:38 +01:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle getTerrainComponent(Entity entity) override
2015-09-12 12:44:04 +02:00
{
auto iter = m_terrains.find(entity);
if (!iter.isValid()) return INVALID_COMPONENT;
return {iter.value()->getEntity().index};
2015-09-12 12:44:04 +02:00
}
2016-06-22 15:05:19 +02:00
Vec3 getTerrainNormalAt(ComponentHandle cmp, float x, float z) override
{
return m_terrains[{cmp.index}]->getNormal(x, z);
}
2016-06-22 15:05:19 +02:00
float getTerrainHeightAt(ComponentHandle cmp, float x, float z) override
2015-07-21 20:10:50 +02:00
{
return m_terrains[{cmp.index}]->getHeight(x, z);
2015-07-21 20:10:50 +02:00
}
2014-09-06 22:21:09 +02:00
2016-06-22 15:05:19 +02:00
AABB getTerrainAABB(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_terrains[{cmp.index}]->getAABB();
2016-03-13 01:27:25 +01:00
}
2016-06-22 15:05:19 +02:00
Vec2 getTerrainSize(ComponentHandle cmp) override
2016-03-13 01:27:25 +01:00
{
return m_terrains[{cmp.index}]->getSize();
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
void setTerrainMaterialPath(ComponentHandle cmp, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2016-02-12 23:49:56 +01:00
if (path.isValid())
{
2016-07-24 22:21:43 +02:00
Material* material = static_cast<Material*>(m_engine.getResourceManager().get(MATERIAL_TYPE)->load(path));
m_terrains[{cmp.index}]->setMaterial(material);
2016-02-12 23:49:56 +01:00
}
else
{
m_terrains[{cmp.index}]->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
Material* getTerrainMaterial(ComponentHandle cmp) override { return m_terrains[{cmp.index}]->getMaterial(); }
2016-07-22 13:57:52 +02:00
void setDecalScale(ComponentHandle cmp, const Vec3& value) override
{
Decal& decal = m_decals[{cmp.index}];
decal.scale = value;
updateDecalInfo(decal);
}
Vec3 getDecalScale(ComponentHandle cmp) override
{
return m_decals[{cmp.index}].scale;
}
void getDecals(const Frustum& frustum, Array<DecalInfo>& decals) override
{
decals.reserve(m_decals.size());
for (const Decal& decal : m_decals)
{
if (!decal.material || !decal.material->isReady()) continue;
if (frustum.isSphereInside(decal.position, decal.radius)) decals.push(decal);
}
}
void setDecalMaterialPath(ComponentHandle cmp, const Path& path) override
{
2016-07-24 22:21:43 +02:00
ResourceManagerBase* material_manager = m_engine.getResourceManager().get(MATERIAL_TYPE);
2016-07-22 13:57:52 +02:00
Decal& decal = m_decals[{cmp.index}];
if (decal.material)
{
material_manager->unload(*decal.material);
}
if (path.isValid())
{
decal.material = static_cast<Material*>(material_manager->load(path));
}
else
{
decal.material = nullptr;
}
}
Path getDecalMaterialPath(ComponentHandle cmp) override
{
Decal& decal = m_decals[{cmp.index}];
return decal.material ? decal.material->getPath() : Path("");
}
2016-06-22 15:05:19 +02:00
Path getTerrainMaterialPath(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
Terrain* terrain = m_terrains[{cmp.index}];
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
}
}
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
void setTerrainXZScale(ComponentHandle cmp, float scale) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->setXZScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
float getTerrainXZScale(ComponentHandle cmp) override { return m_terrains[{cmp.index}]->getXZScale(); }
2014-07-09 21:33:35 +02:00
2016-06-22 15:05:19 +02:00
void setTerrainYScale(ComponentHandle cmp, float scale) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->setYScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-07-09 21:33:35 +02:00
float getTerrainYScale(ComponentHandle cmp) override { return m_terrains[{cmp.index}]->getYScale(); }
2014-06-16 21:18:15 +02:00
Pose* lockPose(ComponentHandle cmp) override { return m_model_instances[cmp.index].pose; }
void unlockPose(ComponentHandle cmp, bool changed) override
{
if (!changed) return;
if (cmp.index < m_model_instances.size()
&& (m_model_instances[cmp.index].flags & ModelInstance::IS_BONE_ATTACHMENT_PARENT) == 0)
{
return;
}
Entity parent = {cmp.index};
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
Entity getModelInstanceEntity(ComponentHandle cmp) override { return m_model_instances[cmp.index].entity; }
2015-07-24 22:38:11 +02:00
Model* getModelInstanceModel(ComponentHandle cmp) override { return m_model_instances[cmp.index].model; }
2014-10-31 21:25:03 +01:00
2016-11-20 17:27:41 +01:00
static u64 getLayerMask(ModelInstance& model_instance)
2016-10-22 18:08:53 +02:00
{
Model* model = model_instance.model;
if (!model->isReady()) return 1;
2016-11-20 17:27:41 +01:00
u64 layer_mask = 0;
2016-10-22 18:08:53 +02:00
for(int i = 0; i < model->getMeshCount(); ++i)
{
layer_mask |= model->getMesh(i).material->getRenderLayerMask();
}
return layer_mask;
}
void showModelInstance(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
auto& model_instance = m_model_instances[cmp.index];
if (!model_instance.model || !model_instance.model->isReady()) return;
Sphere sphere(m_universe.getPosition(model_instance.entity), model_instance.model->getBoundingRadius());
2016-11-20 17:27:41 +01:00
u64 layer_mask = getLayerMask(model_instance);
2016-10-22 18:08:53 +02:00
if(!m_culling_system->isAdded(cmp)) m_culling_system->addStatic(cmp, sphere, layer_mask);
2015-07-21 20:10:50 +02:00
}
2014-10-31 21:25:03 +01:00
void hideModelInstance(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
m_culling_system->removeStatic(cmp);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
Path getModelInstancePath(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_model_instances[cmp.index].model ? m_model_instances[cmp.index].model->getPath() : Path("");
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
int getModelInstanceMaterialsCount(ComponentHandle cmp) override
{
return m_model_instances[cmp.index].model ? m_model_instances[cmp.index].mesh_count : 0;
}
void setModelInstancePath(ComponentHandle cmp, const Path& path) override
2015-07-21 20:10:50 +02:00
{
ModelInstance& r = m_model_instances[cmp.index];
2015-07-21 20:10:50 +02:00
2016-07-24 22:21:43 +02:00
auto* manager = m_engine.getResourceManager().get(MODEL_TYPE);
2016-02-12 23:49:56 +01:00
if (path.isValid())
{
Model* model = static_cast<Model*>(manager->load(path));
setModel(cmp, model);
}
else
{
setModel(cmp, nullptr);
}
r.matrix = m_universe.getMatrix(r.entity);
2015-07-21 20:10:50 +02:00
}
2014-07-08 22:31:01 +02:00
void forceGrassUpdate(ComponentHandle cmp) override { m_terrains[{cmp.index}]->forceGrassUpdate(); }
2017-10-02 13:28:20 +02:00
void getTerrainInfos(const Frustum& frustum, const Vec3& lod_ref_point, Array<TerrainInfo>& infos) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
infos.reserve(m_terrains.size());
for (auto* terrain : m_terrains)
2015-07-21 20:10:50 +02:00
{
2017-09-25 17:33:29 +02:00
terrain->getInfos(infos, frustum, lod_ref_point);
2015-07-21 20:10:50 +02:00
}
}
2014-08-09 14:37:23 +02:00
2017-10-02 13:28:20 +02:00
void getGrassInfos(const Frustum& frustum, ComponentHandle camera, Array<GrassInfo>& infos) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
if (!m_is_grass_enabled) return;
for (auto* terrain : m_terrains)
2015-07-21 20:10:50 +02:00
{
terrain->getGrassInfos(frustum, infos, camera);
2015-07-21 20:10:50 +02:00
}
}
2016-03-13 01:27:25 +01:00
static int LUA_castCameraRay(lua_State* L)
{
auto* scene = LuaWrapper::checkArg<RenderSceneImpl*>(L, 1);
const char* slot = LuaWrapper::checkArg<const char*>(L, 2);
2016-11-11 15:09:52 +01:00
float x, y;
2016-06-22 15:05:19 +02:00
ComponentHandle camera_cmp = scene->getCameraInSlot(slot);
2017-05-23 14:01:09 +02:00
if (!camera_cmp.isValid()) return 0;
2016-11-11 15:09:52 +01:00
if (lua_gettop(L) > 3)
{
x = LuaWrapper::checkArg<float>(L, 3);
y = LuaWrapper::checkArg<float>(L, 4);
}
else
{
x = scene->getCameraScreenWidth(camera_cmp) * 0.5f;
y = scene->getCameraScreenHeight(camera_cmp) * 0.5f;
}
Vec3 origin, dir;
2017-10-04 10:47:31 +02:00
scene->getRay(camera_cmp, {x, y}, origin, dir);
2016-03-13 01:27:25 +01:00
2016-11-11 15:09:52 +01:00
RayCastModelHit hit = scene->castRay(origin, dir, INVALID_COMPONENT);
2016-09-15 22:37:37 +02:00
LuaWrapper::push(L, hit.m_is_hit);
LuaWrapper::push(L, hit.m_is_hit ? hit.m_origin + hit.m_dir * hit.m_t : Vec3(0, 0, 0));
2016-03-13 01:27:25 +01:00
return 2;
}
2016-10-31 16:19:27 +01:00
static bgfx::TextureHandle* LUA_getTextureHandle(RenderScene* scene, int resource_idx)
{
Resource* res = scene->getEngine().getLuaResource(resource_idx);
if (!res) return nullptr;
return &static_cast<Texture*>(res)->handle;
}
2016-09-14 13:19:51 +02:00
2016-11-20 17:27:41 +01:00
static void LUA_setTexturePixel(Texture* texture, int x, int y, u32 value)
2016-09-14 13:19:51 +02:00
{
if (!texture) return;
if (!texture->isReady()) return;
if (texture->data.empty()) return;
if (texture->bytes_per_pixel != 4) return;
x = Math::clamp(x, 0, texture->width - 1);
y = Math::clamp(y, 0, texture->height - 1);
2016-11-20 17:27:41 +01:00
((u32*)&texture->data[0])[x + y * texture->width] = value;
2016-09-14 13:19:51 +02:00
}
static void LUA_updateTextureData(Texture* texture, int x, int y, int w, int h)
{
if (!texture) return;
if (!texture->isReady()) return;
if (texture->data.empty()) return;
texture->onDataUpdated(x, y, w, h);
}
2016-11-29 20:00:36 +01:00
2016-09-14 13:19:51 +02:00
static int LUA_getTextureWidth(Texture* texture)
{
if (!texture) return 0;
if (!texture->isReady()) return 0;
return texture->width;
}
static int LUA_getTextureHeight(Texture* texture)
{
if (!texture) return 0;
if (!texture->isReady()) return 0;
return texture->height;
}
2016-09-14 14:15:27 +02:00
static float LUA_getTerrainHeightAt(RenderSceneImpl* render_scene, ComponentHandle cmp, int x, int z)
{
return render_scene->m_terrains[{cmp.index}]->getHeight(x, z);
}
2016-10-04 17:41:16 +02:00
static void LUA_emitParticle(RenderSceneImpl* render_scene, ComponentHandle emitter)
{
int idx = render_scene->m_particle_emitters.find({ emitter.index });
if (idx < 0) return;
return render_scene->m_particle_emitters.at(idx)->emit();
}
2016-09-14 14:15:27 +02:00
void setTerrainHeightAt(ComponentHandle cmp, int x, int z, float height)
{
m_terrains[{cmp.index}]->setHeight(x, z, height);
}
2016-11-20 17:27:41 +01:00
static u32 LUA_getTexturePixel(Texture* texture, int x, int y)
2016-09-14 13:19:51 +02:00
{
if (!texture) return 0;
if (!texture->isReady()) return 0;
if (texture->data.empty()) return 0;
if (texture->bytes_per_pixel != 4) return 0;
x = Math::clamp(x, 0, texture->width - 1);
y = Math::clamp(y, 0, texture->height - 1);
2016-11-20 17:27:41 +01:00
return ((u32*)&texture->data[0])[x + y * texture->width];
2016-09-14 13:19:51 +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"));
2017-10-03 22:08:41 +02:00
Pipeline* pipeline = Pipeline::create(renderer, Path(path), "", renderer.getEngine().getAllocator());
2016-10-17 00:19:02 +02:00
pipeline->load();
return pipeline;
}
static void LUA_destroyPipeline(Pipeline* pipeline)
{
Pipeline::destroy(pipeline);
}
static void LUA_setPipelineScene(Pipeline* pipeline, RenderScene* scene)
{
pipeline->setScene(scene);
}
2016-10-28 23:16:28 +02:00
static RenderScene* LUA_getPipelineScene(Pipeline* pipeline)
{
return pipeline->getScene();
}
2016-10-17 10:21:25 +02:00
static void LUA_pipelineRender(Pipeline* pipeline, int w, int h)
2016-10-17 00:19:02 +02:00
{
2017-10-06 17:52:00 +02:00
pipeline->resize(w, h);
2016-10-17 00:19:02 +02:00
pipeline->render();
}
2016-10-17 10:21:25 +02:00
static bgfx::TextureHandle* LUA_getRenderBuffer(Pipeline* pipeline,
const char* framebuffer_name,
int renderbuffer_idx)
{
2017-10-06 17:52:00 +02:00
bgfx::TextureHandle& handle = pipeline->getRenderbuffer(framebuffer_name, renderbuffer_idx);
return &handle;
2016-10-17 10:21:25 +02:00
}
2016-03-04 22:49:53 +01:00
static Texture* LUA_getMaterialTexture(Material* material, int texture_index)
{
if (!material) return nullptr;
return material->getTexture(texture_index);
}
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)
{
auto& fs = scene->m_engine.getFileSystem();
2017-05-23 19:57:11 +02:00
auto file1 = fs.open(fs.getDefaultDevice(), Path(path), FS::Mode::OPEN_AND_READ);
auto file2 = fs.open(fs.getDefaultDevice(), Path(path_preimage), FS::Mode::OPEN_AND_READ);
2016-03-31 16:58:42 +02:00
if (!file1)
{
if (file2) fs.close(*file2);
2017-05-23 19:57:11 +02:00
g_log_error.log("render_test") << "Failed to open " << path;
2016-03-31 16:58:42 +02:00
return 0xffffFFFF;
}
else if (!file2)
{
fs.close(*file1);
2017-05-23 19:57:11 +02:00
g_log_error.log("render_test") << "Failed to open " << path_preimage;
2016-03-31 16:58:42 +02:00
return 0xffffFFFF;
}
2017-05-23 19:57:11 +02:00
unsigned int result = Texture::compareTGA(file1, file2, min_diff, scene->m_allocator);
2016-08-17 11:12:10 +02:00
fs.close(*file1);
fs.close(*file2);
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));
}
static void LUA_setModelInstanceMaterial(RenderScene* scene,
2016-06-22 15:05:19 +02:00
ComponentHandle cmp,
2016-03-04 22:49:53 +01:00
int index,
const char* path)
{
scene->setModelInstanceMaterial(cmp, index, Path(path));
2016-03-04 22:49:53 +01:00
}
bool isGrassEnabled() const override
{
return m_is_grass_enabled;
}
2016-02-24 20:46:14 +01:00
2017-01-26 09:28:23 +01:00
int getGrassRotationMode(ComponentHandle cmp, int index) override
{
return (int)m_terrains[{cmp.index}]->getGrassTypeRotationMode(index);
}
void setGrassRotationMode(ComponentHandle cmp, int index, int value) override
{
m_terrains[{cmp.index}]->setGrassTypeRotationMode(index, (Terrain::GrassType::RotationMode)value);
}
2016-06-22 15:05:19 +02:00
float getGrassDistance(ComponentHandle cmp, int index) override
{
return m_terrains[{cmp.index}]->getGrassTypeDistance(index);
}
2016-06-22 15:05:19 +02:00
void setGrassDistance(ComponentHandle cmp, int index, float value) override
{
m_terrains[{cmp.index}]->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; }
2016-08-02 21:02:47 +02:00
void setGrassDensity(ComponentHandle cmp, int index, int density) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->setGrassTypeDensity(index, density);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
int getGrassDensity(ComponentHandle cmp, int index) override
2015-07-21 20:10:50 +02:00
{
return m_terrains[{cmp.index}]->getGrassTypeDensity(index);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
void setGrassPath(ComponentHandle cmp, int index, const Path& path) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->setGrassTypePath(index, path);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
Path getGrassPath(ComponentHandle cmp, int index) override
2015-07-21 20:10:50 +02:00
{
return m_terrains[{cmp.index}]->getGrassTypePath(index);
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
int getGrassCount(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_terrains[{cmp.index}]->getGrassTypeCount();
2015-07-21 20:10:50 +02:00
}
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
void addGrass(ComponentHandle cmp, int index) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->addGrassType(index);
2015-07-21 20:10:50 +02:00
}
2014-10-15 22:16:03 +02:00
2016-06-22 15:05:19 +02:00
void removeGrass(ComponentHandle cmp, int index) override
2015-07-21 20:10:50 +02:00
{
m_terrains[{cmp.index}]->removeGrassType(index);
2015-07-21 20:10:50 +02:00
}
ComponentHandle getFirstModelInstance() override
2015-07-21 20:10:50 +02:00
{
return getNextModelInstance(INVALID_COMPONENT);
2015-07-21 20:10:50 +02:00
}
2014-10-28 23:17:18 +01:00
2014-08-20 22:45:47 +02:00
ComponentHandle getNextModelInstance(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
for(int i = cmp.index + 1; i < m_model_instances.size(); ++i)
2015-07-21 20:10:50 +02:00
{
if (m_model_instances[i].entity != INVALID_ENTITY) return {i};
2015-07-21 20:10:50 +02:00
}
2015-07-24 22:38:11 +02:00
return INVALID_COMPONENT;
2015-07-21 20:10:50 +02:00
}
2014-08-20 22:45:47 +02:00
2017-10-02 16:24:04 +02:00
int getClosestPointLights(const Vec3& reference_pos,
2016-06-22 15:05:19 +02:00
ComponentHandle* lights,
2015-09-02 11:14:42 +02:00
int max_lights) override
{
2015-09-04 14:00:28 +02:00
float dists[16];
ASSERT(max_lights <= lengthOf(dists));
ASSERT(max_lights > 0);
if (m_point_lights.empty()) return 0;
int light_count = 0;
2015-09-02 11:14:42 +02:00
for (auto light : m_point_lights)
{
Vec3 light_pos = m_universe.getPosition(light.m_entity);
float dist_squared = (reference_pos - light_pos).squaredLength();
2015-09-04 14:00:28 +02:00
dists[light_count] = dist_squared;
2016-06-22 15:05:19 +02:00
lights[light_count] = light.m_component;
2015-09-04 14:00:28 +02:00
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;
2016-06-22 15:05:19 +02:00
ComponentHandle tmp2 = lights[i];
2015-09-04 14:00:28 +02:00
lights[i] = lights[i - 1];
lights[i - 1] = tmp2;
}
++light_count;
if (light_count == max_lights)
{
break;
}
2015-09-02 11:14:42 +02:00
}
2015-09-04 14:00:28 +02:00
for (int i = max_lights; i < m_point_lights.size(); ++i)
{
PointLight& light = m_point_lights[i];
Vec3 light_pos = m_universe.getPosition(light.m_entity);
float dist_squared = (reference_pos - light_pos).squaredLength();
if (dist_squared < dists[max_lights - 1])
{
dists[max_lights - 1] = dist_squared;
2016-06-22 15:05:19 +02:00
lights[max_lights - 1] = light.m_component;
2015-09-04 14:00:28 +02:00
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;
2016-06-22 15:05:19 +02:00
ComponentHandle tmp2 = lights[i];
2015-09-04 14:00:28 +02:00
lights[i] = lights[i - 1];
lights[i - 1] = tmp2;
}
}
}
return light_count;
2015-09-02 11:14:42 +02:00
}
2016-06-22 15:05:19 +02:00
void getPointLights(const Frustum& frustum, Array<ComponentHandle>& lights) override
2015-07-21 20:10:50 +02:00
{
for (int i = 0, ci = m_point_lights.size(); i < ci; ++i)
{
PointLight& light = m_point_lights[i];
2016-06-22 15:05:19 +02:00
if (frustum.isSphereInside(m_universe.getPosition(light.m_entity), light.m_range))
2015-02-14 00:13:34 +01:00
{
2016-06-22 15:05:19 +02:00
lights.push(light.m_component);
2015-02-14 00:13:34 +01:00
}
2015-07-21 20:10:50 +02:00
}
}
2015-02-14 00:13:34 +01:00
Entity getCameraEntity(ComponentHandle camera) const override { return {camera.index}; }
2015-07-24 08:42:35 +02:00
2016-06-22 15:05:19 +02:00
void setLightCastShadows(ComponentHandle cmp, bool cast_shadows) override
2015-09-02 11:14:42 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_cast_shadows = cast_shadows;
2015-09-02 11:14:42 +02:00
}
2016-06-22 15:05:19 +02:00
bool getLightCastShadows(ComponentHandle cmp) override
2015-09-02 11:14:42 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_cast_shadows;
2015-09-02 11:14:42 +02:00
}
2016-06-22 15:05:19 +02:00
void getPointLightInfluencedGeometry(ComponentHandle light_cmp,
2015-12-10 17:09:52 +01:00
const Frustum& frustum,
Array<ModelInstanceMesh>& infos) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2015-02-14 00:13:34 +01:00
int light_index = m_point_lights_map[light_cmp];
2015-12-10 17:09:52 +01:00
for (int j = 0, cj = m_light_influenced_geometry[light_index].size(); j < cj; ++j)
{
ComponentHandle model_instance_cmp = m_light_influenced_geometry[light_index][j];
ModelInstance& model_instance = m_model_instances[model_instance_cmp.index];
const Sphere& sphere = m_culling_system->getSphere(model_instance_cmp);
2016-07-22 13:57:52 +02:00
if (frustum.isSphereInside(sphere.position, sphere.radius))
2015-12-10 17:09:52 +01:00
{
for (int k = 0, kc = model_instance.model->getMeshCount(); k < kc; ++k)
2015-02-14 00:13:34 +01:00
{
2016-01-14 16:22:25 +01:00
auto& info = infos.emplace();
info.mesh = &model_instance.model->getMesh(k);
info.model_instance = model_instance_cmp;
2015-02-14 00:13:34 +01:00
}
}
2015-07-21 20:10:50 +02:00
}
}
2015-02-14 00:13:34 +01:00
2014-11-16 19:31:51 +01:00
void getPointLightInfluencedGeometry(ComponentHandle light_cmp, Array<ModelInstanceMesh>& infos) override
2015-09-02 11:14:42 +02:00
{
PROFILE_FUNCTION();
int light_index = m_point_lights_map[light_cmp];
2015-09-02 11:14:42 +02:00
auto& geoms = m_light_influenced_geometry[light_index];
for (int j = 0, cj = geoms.size(); j < cj; ++j)
{
const ModelInstance& model_instance = m_model_instances[geoms[j].index];
for (int k = 0, kc = model_instance.model->getMeshCount(); k < kc; ++k)
2015-09-02 11:14:42 +02:00
{
2016-01-14 16:22:25 +01:00
auto& info = infos.emplace();
info.mesh = &model_instance.model->getMesh(k);
info.model_instance = geoms[j];
2015-09-02 11:14:42 +02:00
}
}
}
void getModelInstanceEntities(const Frustum& frustum, Array<Entity>& entities) override
{
PROFILE_FUNCTION();
2017-10-02 16:24:04 +02:00
auto& results = m_culling_system->cull(frustum, ~0ULL);
2017-10-02 16:24:04 +02:00
for (auto& subresults : results)
{
for (ComponentHandle model_instance_cmp : subresults)
{
entities.push(m_model_instances[model_instance_cmp.index].entity);
}
}
}
2017-10-10 13:21:45 +02:00
float getCameraLODMultiplier(ComponentHandle camera)
{
float lod_multiplier;
if (isCameraOrtho(camera))
{
lod_multiplier = 1;
}
else
{
lod_multiplier = getCameraFOV(camera) / Math::degreesToRadians(60);
lod_multiplier *= lod_multiplier;
}
return lod_multiplier;
}
2016-10-22 18:08:53 +02:00
Array<Array<ModelInstanceMesh>>& getModelInstanceInfos(const Frustum& frustum,
const Vec3& lod_ref_point,
2017-10-10 13:21:45 +02:00
ComponentHandle camera,
2016-11-20 17:27:41 +01:00
u64 layer_mask) override
2015-07-21 20:10:50 +02:00
{
2017-10-02 16:24:04 +02:00
for (auto& i : m_temporary_infos) i.clear();
const CullingSystem::Results& results = m_culling_system->cull(frustum, layer_mask);
while (m_temporary_infos.size() < results.size())
{
m_temporary_infos.emplace(m_allocator);
}
while (m_temporary_infos.size() > results.size())
{
m_temporary_infos.pop();
}
JobSystem::JobDecl jobs[64];
JobSystem::LambdaJob job_storage[64];
ASSERT(results.size() <= lengthOf(jobs));
volatile int counter = 0;
for (int subresult_index = 0; subresult_index < results.size(); ++subresult_index)
{
Array<ModelInstanceMesh>& subinfos = m_temporary_infos[subresult_index];
subinfos.clear();
2017-10-10 13:21:45 +02:00
JobSystem::fromLambda([&subinfos, this, &results, subresult_index, &frustum, lod_ref_point, camera]() {
2017-10-02 16:24:04 +02:00
PROFILE_BLOCK("Temporary Info Job");
PROFILE_INT("ModelInstance count", results[subresult_index].size());
if (results[subresult_index].empty()) return;
2017-10-10 13:21:45 +02:00
float lod_multiplier = getCameraLODMultiplier(camera);
2017-10-02 16:24:04 +02:00
Vec3 ref_point = lod_ref_point;
2017-10-10 13:21:45 +02:00
float final_lod_multiplier = m_lod_multiplier * lod_multiplier;
2017-10-02 16:24:04 +02:00
const ComponentHandle* LUMIX_RESTRICT raw_subresults = &results[subresult_index][0];
ModelInstance* LUMIX_RESTRICT model_instances = &m_model_instances[0];
for (int i = 0, c = results[subresult_index].size(); i < c; ++i)
{
const ModelInstance* LUMIX_RESTRICT model_instance = &model_instances[raw_subresults[i].index];
float squared_distance = (model_instance->matrix.getTranslation() - ref_point).squaredLength();
2017-10-10 13:21:45 +02:00
squared_distance *= final_lod_multiplier;
2014-11-16 19:31:51 +01:00
2017-10-02 16:24:04 +02:00
const Model* LUMIX_RESTRICT model = model_instance->model;
LODMeshIndices lod = model->getLODMeshIndices(squared_distance);
for (int j = lod.from, c = lod.to; j <= c; ++j)
{
auto& info = subinfos.emplace();
info.model_instance = raw_subresults[i];
info.mesh = &model_instance->meshes[j];
}
}
}, &job_storage[subresult_index], &jobs[subresult_index], nullptr);
}
JobSystem::runJobs(jobs, results.size(), &counter);
JobSystem::wait(&counter);
2014-11-16 19:31:51 +01:00
return m_temporary_infos;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2014-11-16 19:31:51 +01:00
2016-06-22 15:05:19 +02:00
void setCameraSlot(ComponentHandle cmp, const char* slot) override
2015-07-21 20:10:50 +02:00
{
auto& camera = m_cameras[{cmp.index}];
2016-06-22 15:05:19 +02:00
copyString(camera.slot, lengthOf(camera.slot), slot);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle getCameraComponent(Entity entity)
{
auto iter = m_cameras.find(entity);
if (!iter.isValid()) return INVALID_COMPONENT;
return {entity.index};
}
const char* getCameraSlot(ComponentHandle camera) override { return m_cameras[{camera.index}].slot; }
float getCameraFOV(ComponentHandle camera) override { return m_cameras[{camera.index}].fov; }
void setCameraFOV(ComponentHandle camera, float fov) override { m_cameras[{camera.index}].fov = fov; }
void setCameraNearPlane(ComponentHandle camera, float near_plane) override { m_cameras[{camera.index}].near = Math::maximum(near_plane, 0.00001f); }
float getCameraNearPlane(ComponentHandle camera) override { return m_cameras[{camera.index}].near; }
void setCameraFarPlane(ComponentHandle camera, float far_plane) override { m_cameras[{camera.index}].far = far_plane; }
float getCameraFarPlane(ComponentHandle camera) override { return m_cameras[{camera.index}].far; }
float getCameraScreenWidth(ComponentHandle camera) override { return m_cameras[{camera.index}].screen_width; }
float getCameraScreenHeight(ComponentHandle camera) override { return m_cameras[{camera.index}].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; }
Matrix getCameraViewProjection(ComponentHandle cmp) override
{
Matrix view = m_universe.getMatrix({cmp.index});
view.fastInverse();
return getCameraProjection(cmp) * view;
}
2016-06-22 15:05:19 +02:00
Matrix getCameraProjection(ComponentHandle cmp) override
2016-04-17 21:47:54 +02:00
{
Camera& camera = m_cameras[{cmp.index}];
2016-04-17 21:47:54 +02:00
Matrix mtx;
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
2017-10-11 17:13:47 +02:00
bool is_homogenous_depth = bgfx::getCaps()->homogeneousDepth;
2016-04-17 21:47:54 +02:00
if (camera.is_ortho)
{
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,
2017-10-11 17:13:47 +02:00
is_homogenous_depth);
2016-04-17 21:47:54 +02:00
}
else
{
2017-10-11 17:13:47 +02:00
mtx.setPerspective(camera.fov, ratio, camera.near, camera.far, is_homogenous_depth);
2016-04-17 21:47:54 +02:00
}
return mtx;
}
2016-06-22 15:05:19 +02:00
void setCameraScreenSize(ComponentHandle 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;
cam.aspect = w / (float)h;
2016-04-17 21:47:54 +02:00
}
2016-06-22 15:05:19 +02:00
Vec2 getCameraScreenSize(ComponentHandle camera) override
{
auto& cam = m_cameras[{camera.index}];
return Vec2(cam.screen_width, cam.screen_height);
}
float getCameraOrthoSize(ComponentHandle camera) override { return m_cameras[{camera.index}].ortho_size; }
void setCameraOrthoSize(ComponentHandle camera, float value) override { m_cameras[{camera.index}].ortho_size = value; }
bool isCameraOrtho(ComponentHandle camera) override { return m_cameras[{camera.index}].is_ortho; }
void setCameraOrtho(ComponentHandle camera, bool is_ortho) override { m_cameras[{camera.index}].is_ortho = is_ortho; }
2016-04-17 21:47:54 +02:00
const Array<DebugTriangle>& getDebugTriangles() const override { return m_debug_triangles; }
const Array<DebugLine>& getDebugLines() const override { return m_debug_lines; }
const Array<DebugPoint>& getDebugPoints() const override { return m_debug_points; }
void addDebugSphere(const Vec3& center,
float radius,
2016-11-20 17:27:41 +01:00
u32 color,
float life) override
2015-07-21 20:10:50 +02:00
{
static const int COLS = 36;
static const int ROWS = COLS >> 1;
static const float STEP = (Math::PI / 180.0f) * 360.0f / COLS;
int p2 = COLS >> 1;
int r2 = ROWS >> 1;
float prev_ci = 1;
float prev_si = 0;
for (int y = -r2; y < r2; ++y)
{
float cy = cos(y * STEP);
float cy1 = cos((y + 1) * STEP);
float sy = sin(y * STEP);
float sy1 = sin((y + 1) * STEP);
for (int i = -p2; i < p2; ++i)
{
float ci = cos(i * STEP);
float si = sin(i * STEP);
addDebugLine(Vec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
Vec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
color,
life);
addDebugLine(Vec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
Vec3(center.x + radius * prev_ci * cy,
center.y + radius * sy,
center.z + radius * prev_si * cy),
color,
life);
addDebugLine(Vec3(center.x + radius * prev_ci * cy1,
center.y + radius * sy1,
center.z + radius * prev_si * cy1),
Vec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
color,
life);
prev_ci = ci;
prev_si = si;
}
}
}
2014-12-14 22:14:21 +01:00
2014-12-14 21:57:08 +01:00
2016-11-20 17:27:41 +01:00
void addDebugHalfSphere(const Matrix& transform, float radius, bool top, u32 color, float life)
2016-06-28 19:48:50 +02:00
{
Vec3 center = transform.getTranslation();
Vec3 x_vec = transform.getXVector();
Vec3 y_vec = transform.getYVector();
if (!top) y_vec *= -1;
Vec3 z_vec = transform.getZVector();
static const int COLS = 36;
static const int ROWS = COLS >> 1;
static const float STEP = Math::degreesToRadians(360.0f) / COLS;
int p2 = COLS >> 1;
for (int y = 0; y < ROWS >> 1; ++y)
{
float cy = cos(y * STEP);
float cy1 = cos((y + 1) * STEP);
float sy = sin(y * STEP);
float sy1 = sin((y + 1) * STEP);
float prev_ci = cos(-STEP);
float prev_si = sin(-STEP);
Vec3 y_offset = y_vec * sy;
Vec3 y_offset1 = y_vec * sy1;
for (int i = 0; i < COLS; ++i)
{
float ci = cos(i * STEP);
float si = sin(i * STEP);
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),
color,
life);
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),
color,
life);
prev_ci = ci;
prev_si = si;
}
}
}
2016-11-20 17:27:41 +01:00
void addDebugHalfSphere(const Vec3& center, float radius, bool top, u32 color, float life)
{
static const int COLS = 36;
static const int ROWS = COLS >> 1;
static const float STEP = (Math::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)
{
float cy = cos(y * STEP);
float cy1 = cos((y + 1) * STEP);
float sy = sin(y * STEP);
float sy1 = sin((y + 1) * STEP);
float prev_ci = cos((-p2 - 1) * STEP);
float prev_si = sin((-p2 - 1) * STEP);
for (int i = -p2; i < p2; ++i)
{
float ci = cos(i * STEP);
float si = sin(i * STEP);
addDebugLine(Vec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
Vec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
color,
life);
addDebugLine(Vec3(center.x + radius * ci * cy,
center.y + radius * sy,
center.z + radius * si * cy),
Vec3(center.x + radius * prev_ci * cy,
center.y + radius * sy,
center.z + radius * prev_si * cy),
color,
life);
addDebugLine(Vec3(center.x + radius * prev_ci * cy1,
center.y + radius * sy1,
center.z + radius * prev_si * cy1),
Vec3(center.x + radius * ci * cy1,
center.y + radius * sy1,
center.z + radius * si * cy1),
color,
life);
prev_ci = ci;
prev_si = si;
}
}
}
2016-03-10 19:32:48 +01:00
void addDebugTriangle(const Vec3& p0,
const Vec3& p1,
const Vec3& p2,
2016-11-20 17:27:41 +01:00
u32 color,
2016-03-10 19:32:48 +01:00
float life) override
{
DebugTriangle& tri = m_debug_triangles.emplace();
tri.p0 = p0;
tri.p1 = p1;
tri.p2 = p2;
tri.color = ARGBToABGR(color);
tri.life = life;
}
void addDebugCapsule(const Vec3& position,
float height,
float radius,
2016-11-20 17:27:41 +01:00
u32 color,
float life) override
{
addDebugHalfSphere(position + Vec3(0, radius, 0), radius, false, color, life);
addDebugHalfSphere(position + Vec3(0, radius + height, 0), radius, true, color, life);
Vec3 z_vec(0, 0, 1.0f);
Vec3 x_vec(1.0f, 0, 0);
z_vec.normalize();
x_vec.normalize();
Vec3 bottom = position + Vec3(0, radius, 0);
Vec3 top = bottom + Vec3(0, height, 0);
for (int i = 1; i <= 32; ++i)
{
float a = i / 32.0f * 2 * Math::PI;
float x = cosf(a) * radius;
float z = sinf(a) * radius;
addDebugLine(bottom + x_vec * x + z_vec * z,
top + x_vec * x + z_vec * z,
color,
life);
}
}
2016-06-28 19:48:50 +02:00
void addDebugCapsule(const Matrix& transform,
float height,
float radius,
2016-11-20 17:27:41 +01:00
u32 color,
2016-06-28 19:48:50 +02:00
float life) override
{
Vec3 x_vec = transform.getXVector();
Vec3 y_vec = transform.getYVector();
Vec3 z_vec = transform.getZVector();
Vec3 position = transform.getTranslation();
Matrix tmp = transform;
tmp.setTranslation(transform.getTranslation() + y_vec * radius);
addDebugHalfSphere(tmp, radius, false, color, life);
tmp.setTranslation(transform.getTranslation() + y_vec * (radius + height));
addDebugHalfSphere(tmp, radius, true, color, life);
Vec3 bottom = position + y_vec * radius;
Vec3 top = bottom + y_vec * height;
for (int i = 1; i <= 32; ++i)
{
float a = i / 32.0f * 2 * Math::PI;
float x = cosf(a) * radius;
float z = sinf(a) * radius;
addDebugLine(bottom + x_vec * x + z_vec * z, top + x_vec * x + z_vec * z, color, life);
}
}
void addDebugCylinder(const Vec3& position,
2015-07-21 20:10:50 +02:00
const Vec3& up,
float radius,
2016-11-20 17:27:41 +01:00
u32 color,
2015-07-21 20:10:50 +02:00
float life) override
{
Vec3 z_vec(-up.y, up.x, 0);
Vec3 x_vec = crossProduct(up, z_vec);
float prevx = radius;
float prevz = 0;
z_vec.normalize();
x_vec.normalize();
Vec3 top = position + up;
for (int i = 1; i <= 32; ++i)
{
float a = i / 32.0f * 2 * Math::PI;
float x = cosf(a) * radius;
float z = sinf(a) * radius;
addDebugLine(position + x_vec * x + z_vec * z,
position + x_vec * prevx + z_vec * prevz,
color,
life);
addDebugLine(top + x_vec * x + z_vec * z,
top + x_vec * prevx + z_vec * prevz,
color,
life);
addDebugLine(position + x_vec * x + z_vec * z,
top + x_vec * x + z_vec * z,
color,
life);
prevx = x;
prevz = z;
}
}
2014-12-14 21:57:08 +01:00
2014-07-05 17:24:12 +02:00
void addDebugCube(const Vec3& pos,
2015-10-24 12:25:06 +02:00
const Vec3& dir,
const Vec3& up,
const Vec3& right,
2016-11-20 17:27:41 +01:00
u32 color,
2015-10-24 12:25:06 +02:00
float life) override
{
addDebugLine(pos + dir + up + right, pos + dir + up - right, color, life);
addDebugLine(pos - dir + up + right, pos - dir + up - right, color, life);
addDebugLine(pos + dir + up + right, pos - dir + up + right, color, life);
addDebugLine(pos + dir + up - right, pos - dir + up - right, color, life);
addDebugLine(pos + dir - up + right, pos + dir - up - right, color, life);
addDebugLine(pos - dir - up + right, pos - dir - up - right, color, life);
addDebugLine(pos + dir - up + right, pos - dir - up + right, color, life);
addDebugLine(pos + dir - up - right, pos - dir - up - right, color, life);
addDebugLine(pos + dir + up + right, pos + dir - up + right, color, life);
addDebugLine(pos + dir + up - right, pos + dir - up - right, color, life);
addDebugLine(pos - dir + up + right, pos - dir - up + right, color, life);
addDebugLine(pos - dir + up - right, pos - dir - up - right, color, life);
}
2016-03-11 17:25:14 +01:00
void addDebugCubeSolid(const Vec3& min,
const Vec3& max,
2016-11-20 17:27:41 +01:00
u32 color,
2016-03-11 17:25:14 +01:00
float life) override
{
Vec3 a = min;
Vec3 b = min;
Vec3 c = max;
b.x = max.x;
c.z = min.z;
addDebugTriangle(a, c, b, color, life);
b.x = min.x;
b.y = max.y;
addDebugTriangle(a, b, c, color, life);
b = max;
c = max;
a.z = max.z;
b.y = min.y;
addDebugTriangle(a, b, c, color, life);
b.x = min.x;
b.y = max.y;
addDebugTriangle(a, c, b, color, life);
a = min;
b = min;
c = max;
b.x = max.x;
c.y = min.y;
addDebugTriangle(a, b, c, color, life);
2016-03-11 17:25:14 +01:00
b.x = min.x;
b.z = max.z;
addDebugTriangle(a, c, b, color, life);
2016-03-11 17:25:14 +01:00
b = max;
c = max;
a.y = max.y;
b.z = min.z;
addDebugTriangle(a, c, b, color, life);
b.x = min.x;
b.z = max.z;
addDebugTriangle(a, b, c, color, life);
a = min;
b = min;
c = max;
b.y = max.y;
c.x = min.x;
addDebugTriangle(a, c, b, color, life);
b.y = min.y;
b.z = max.z;
addDebugTriangle(a, b, c, color, life);
b = max;
c = max;
a.x = max.x;
b.z = min.z;
addDebugTriangle(a, b, c, color, life);
b.y = min.y;
b.z = max.z;
addDebugTriangle(a, c, b, color, life);
}
void addDebugCube(const Vec3& min,
2015-07-21 20:10:50 +02:00
const Vec3& max,
2016-11-20 17:27:41 +01:00
u32 color,
2015-07-21 20:10:50 +02:00
float life) override
{
Vec3 a = min;
Vec3 b = min;
b.x = max.x;
addDebugLine(a, b, color, life);
a.set(b.x, b.y, max.z);
addDebugLine(a, b, color, life);
b.set(min.x, a.y, a.z);
addDebugLine(a, b, color, life);
a.set(b.x, b.y, min.z);
addDebugLine(a, b, color, life);
a = min;
a.y = max.y;
b = a;
b.x = max.x;
addDebugLine(a, b, color, life);
a.set(b.x, b.y, max.z);
addDebugLine(a, b, color, life);
b.set(min.x, a.y, a.z);
addDebugLine(a, b, color, life);
a.set(b.x, b.y, min.z);
addDebugLine(a, b, color, life);
a = min;
b = a;
b.y = max.y;
addDebugLine(a, b, color, life);
a.x = max.x;
b.x = max.x;
addDebugLine(a, b, color, life);
a.z = max.z;
b.z = max.z;
addDebugLine(a, b, color, life);
a.x = min.x;
b.x = min.x;
addDebugLine(a, b, color, life);
}
2014-12-17 21:33:27 +01:00
2016-11-20 17:27:41 +01:00
void addDebugFrustum(const Frustum& frustum, u32 color, float life) override
2015-07-21 20:10:50 +02:00
{
2017-10-10 13:21:45 +02:00
addDebugLine(frustum.points[0], frustum.points[1], color, life);
addDebugLine(frustum.points[1], frustum.points[2], color, life);
addDebugLine(frustum.points[2], frustum.points[3], color, life);
addDebugLine(frustum.points[3], frustum.points[0], color, life);
2015-07-21 20:10:50 +02:00
2017-10-10 13:21:45 +02:00
addDebugLine(frustum.points[4], frustum.points[5], color, life);
addDebugLine(frustum.points[5], frustum.points[6], color, life);
addDebugLine(frustum.points[6], frustum.points[7], color, life);
addDebugLine(frustum.points[7], frustum.points[4], color, life);
2015-07-21 20:10:50 +02:00
2017-10-10 13:21:45 +02:00
addDebugLine(frustum.points[0], frustum.points[4], color, life);
addDebugLine(frustum.points[1], frustum.points[5], color, life);
addDebugLine(frustum.points[2], frustum.points[6], color, life);
addDebugLine(frustum.points[3], frustum.points[7], color, life);
2015-07-21 20:10:50 +02:00
}
2014-12-14 21:42:30 +01:00
2017-10-10 13:21:45 +02:00
2016-11-20 17:27:41 +01:00
void addDebugCircle(const Vec3& center, const Vec3& up, float radius, u32 color, float life) override
2015-07-21 20:10:50 +02:00
{
Vec3 z_vec(-up.y, up.x, 0);
Vec3 x_vec = crossProduct(up, z_vec);
float prevx = radius;
float prevz = 0;
z_vec.normalize();
x_vec.normalize();
for (int i = 1; i <= 64; ++i)
{
float a = i / 64.0f * 2 * Math::PI;
float x = cosf(a) * radius;
float z = sinf(a) * radius;
2016-06-16 19:24:15 +02:00
addDebugLine(center + x_vec * x + z_vec * z, center + x_vec * prevx + z_vec * prevz, color, life);
2015-07-21 20:10:50 +02:00
prevx = x;
prevz = z;
}
}
2017-10-10 13:21:45 +02:00
2016-11-20 17:27:41 +01:00
void addDebugCross(const Vec3& center, float size, u32 color, float life) override
2015-07-21 20:10:50 +02:00
{
2016-06-16 19:24:15 +02:00
addDebugLine(center, Vec3(center.x - size, center.y, center.z), color, life);
addDebugLine(center, Vec3(center.x + size, center.y, center.z), color, life);
addDebugLine(center, Vec3(center.x, center.y - size, center.z), color, life);
addDebugLine(center, Vec3(center.x, center.y + size, center.z), color, life);
addDebugLine(center, Vec3(center.x, center.y, center.z - size), color, life);
addDebugLine(center, Vec3(center.x, center.y, center.z + size), color, life);
2015-07-21 20:10:50 +02:00
}
2014-07-20 18:14:37 +02:00
2016-11-20 17:27:41 +01:00
void addDebugPoint(const Vec3& pos, u32 color, float life) override
{
2016-01-14 16:22:25 +01:00
DebugPoint& point = m_debug_points.emplace();
2016-03-10 19:32:48 +01:00
point.pos = pos;
point.color = ARGBToABGR(color);
point.life = life;
}
2016-06-27 00:57:29 +02:00
void addDebugCone(const Vec3& vertex,
const Vec3& dir,
const Vec3& axis0,
const Vec3& axis1,
2016-11-20 17:27:41 +01:00
u32 color,
2016-06-27 00:57:29 +02:00
float life) override
{
Vec3 base_center = vertex + dir;
Vec3 prev_p = base_center + axis0;
for (int i = 1; i <= 32; ++i)
{
float angle = i / 32.0f * 2 * Math::PI;
Vec3 x = cosf(angle) * axis0;
Vec3 z = sinf(angle) * axis1;
Vec3 p = base_center + x + z;
addDebugLine(p, prev_p, color, life);
2016-06-27 14:35:05 +02:00
addDebugLine(vertex, p, color, life);
2016-06-27 00:57:29 +02:00
prev_p = p;
}
}
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
2016-11-20 17:27:41 +01:00
void addDebugLine(const Vec3& from, const Vec3& to, u32 color, float life) 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);
line.life = life;
2015-07-21 20:10:50 +02:00
}
2015-07-04 11:36:33 +02:00
2015-07-23 23:17:51 +02:00
RayCastModelHit castRayTerrain(ComponentHandle cmp, const Vec3& origin, const Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
RayCastModelHit hit;
hit.m_is_hit = false;
auto iter = m_terrains.find({cmp.index});
if (!iter.isValid()) return hit;
auto* terrain = iter.value();
hit = terrain->castRay(origin, dir);
hit.m_component = cmp;
hit.m_component_type = TERRAIN_TYPE;
hit.m_entity = terrain->getEntity();
2015-07-21 20:10:50 +02:00
return hit;
}
RayCastModelHit castRay(const Vec3& origin, const Vec3& dir, ComponentHandle ignored_model_instance) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2015-07-21 20:10:50 +02:00
RayCastModelHit hit;
hit.m_is_hit = false;
hit.m_origin = origin;
hit.m_dir = dir;
2016-11-09 10:09:33 +01:00
float cur_dist = FLT_MAX;
2015-08-02 10:39:50 +02:00
Universe& universe = getUniverse();
for (int i = 0; i < m_model_instances.size(); ++i)
2015-07-21 20:10:50 +02:00
{
auto& r = m_model_instances[i];
2016-11-09 10:09:33 +01:00
if (ignored_model_instance.index == i || !r.model) continue;
const Vec3& pos = r.matrix.getTranslation();
float scale = universe.getScale(r.entity);
2017-08-18 21:43:16 +02:00
float radius = r.model->getBoundingRadius() * scale;
2016-11-09 10:09:33 +01:00
float 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;
2017-08-18 21:43:16 +02:00
if (Math::getRaySphereIntersection(origin, dir, pos, radius, intersection))
2015-07-21 20:10:50 +02:00
{
2017-04-13 17:05:07 +02:00
RayCastModelHit new_hit = r.model->castRay(origin, dir, r.matrix, r.pose);
2016-11-09 10:09:33 +01:00
if (new_hit.m_is_hit && (!hit.m_is_hit || new_hit.m_t < hit.m_t))
2015-07-21 20:10:50 +02:00
{
2016-11-09 10:09:33 +01:00
new_hit.m_component = {i};
new_hit.m_entity = r.entity;
new_hit.m_component_type = MODEL_INSTANCE_TYPE;
hit = new_hit;
hit.m_is_hit = true;
cur_dist = dir.length() * hit.m_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
for (auto* terrain : m_terrains)
2015-07-21 20:10:50 +02:00
{
RayCastModelHit terrain_hit = terrain->castRay(origin, dir);
if (terrain_hit.m_is_hit && (!hit.m_is_hit || terrain_hit.m_t < hit.m_t))
2015-02-18 00:34:22 +01:00
{
terrain_hit.m_component = {terrain->getEntity().index};
terrain_hit.m_component_type = TERRAIN_TYPE;
terrain_hit.m_entity = terrain->getEntity();
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
2015-07-21 20:10:50 +02:00
return hit;
}
2015-02-18 00:34:22 +01:00
2016-06-22 15:05:19 +02:00
Vec4 getShadowmapCascades(ComponentHandle cmp) override
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_cascades;
}
2016-06-22 15:05:19 +02:00
void setShadowmapCascades(ComponentHandle cmp, const Vec4& value) override
{
Vec4 valid_value = value;
2016-03-06 12:54:29 +01:00
valid_value.x = Math::maximum(valid_value.x, 0.02f);
valid_value.y = Math::maximum(valid_value.x + 0.01f, valid_value.y);
valid_value.z = Math::maximum(valid_value.y + 0.01f, valid_value.z);
valid_value.w = Math::maximum(valid_value.z + 0.01f, valid_value.w);
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_cascades = valid_value;
2015-07-21 20:10:50 +02:00
}
2015-02-18 00:34:22 +01:00
2016-06-22 15:05:19 +02:00
void setFogDensity(ComponentHandle cmp, float density) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_fog_density = density;
2015-07-21 20:10:50 +02:00
}
2014-09-25 22:39:33 +02:00
2016-06-22 15:05:19 +02:00
void setFogColor(ComponentHandle cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_fog_color = color;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-06-22 15:05:19 +02:00
float getFogDensity(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_fog_density;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-06-22 15:05:19 +02:00
float getFogBottom(ComponentHandle cmp) override
2015-10-17 00:18:47 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_fog_bottom;
2015-10-17 00:18:47 +02:00
}
2016-06-22 15:05:19 +02:00
void setFogBottom(ComponentHandle cmp, float bottom) override
2015-10-17 00:18:47 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_fog_bottom = bottom;
2015-10-17 00:18:47 +02:00
}
2016-06-22 15:05:19 +02:00
float getFogHeight(ComponentHandle cmp) override
2015-10-17 00:18:47 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_fog_height;
2015-10-17 00:18:47 +02:00
}
2016-06-22 15:05:19 +02:00
void setFogHeight(ComponentHandle cmp, float height) override
2015-10-17 00:18:47 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_fog_height = height;
2015-10-17 00:18:47 +02:00
}
2016-06-22 15:05:19 +02:00
Vec3 getFogColor(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_fog_color;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-06-22 15:05:19 +02:00
float getLightAttenuation(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_attenuation_param;
2015-07-21 20:10:50 +02:00
}
void setLightAttenuation(ComponentHandle cmp, float attenuation) override
2015-07-21 20:10:50 +02:00
{
int index = m_point_lights_map[cmp];
2015-09-09 02:18:09 +02:00
m_point_lights[index].m_attenuation_param = attenuation;
2015-09-04 14:00:28 +02:00
}
2016-06-22 15:05:19 +02:00
float getLightRange(ComponentHandle cmp) override
2015-09-04 14:00:28 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_range;
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
void setLightRange(ComponentHandle cmp, float value) override
2015-09-09 02:18:09 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_range = value;
2015-09-09 02:18:09 +02:00
}
2016-06-22 15:05:19 +02:00
void setPointLightIntensity(ComponentHandle cmp, float intensity) override
2015-07-21 20:10:50 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_diffuse_intensity = intensity;
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
void setGlobalLightIntensity(ComponentHandle cmp, float intensity) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_diffuse_intensity = intensity;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
void setGlobalLightIndirectIntensity(ComponentHandle cmp, float intensity) override
{
m_global_lights[{cmp.index}].m_indirect_intensity = intensity;
}
2016-06-22 15:05:19 +02:00
void setPointLightColor(ComponentHandle cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_diffuse_color = color;
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
void setGlobalLightColor(ComponentHandle cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
m_global_lights[{cmp.index}].m_diffuse_color = color;
2015-07-21 20:10:50 +02:00
}
2016-12-02 15:46:09 +01:00
2016-06-22 15:05:19 +02:00
float getPointLightIntensity(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_diffuse_intensity;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-06-22 15:05:19 +02:00
float getGlobalLightIntensity(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_diffuse_intensity;
2015-07-21 20:10:50 +02:00
}
float getGlobalLightIndirectIntensity(ComponentHandle cmp) override
{
return m_global_lights[{cmp.index}].m_indirect_intensity;
}
2016-06-22 15:05:19 +02:00
Vec3 getPointLightColor(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_diffuse_color;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
void setPointLightSpecularColor(ComponentHandle cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_specular_color = color;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
Vec3 getPointLightSpecularColor(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_specular_color;
2015-07-21 20:10:50 +02:00
}
2014-06-21 19:26:27 +02:00
2016-06-22 15:05:19 +02:00
void setPointLightSpecularIntensity(ComponentHandle cmp, float intensity) override
2016-02-10 12:09:09 +01:00
{
m_point_lights[m_point_lights_map[cmp]].m_specular_intensity = intensity;
2016-02-10 12:09:09 +01:00
}
2016-06-22 15:05:19 +02:00
float getPointLightSpecularIntensity(ComponentHandle cmp) override
2016-02-10 12:09:09 +01:00
{
return m_point_lights[m_point_lights_map[cmp]].m_specular_intensity;
2016-02-10 12:09:09 +01:00
}
2016-06-22 15:05:19 +02:00
Vec3 getGlobalLightColor(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_diffuse_color;
2015-07-21 20:10:50 +02:00
}
2014-07-05 17:24:12 +02:00
2016-06-22 15:05:19 +02:00
void setActiveGlobalLight(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
m_active_global_light_cmp = cmp;
2015-07-21 20:10:50 +02:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle getActiveGlobalLight() override
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
return m_active_global_light_cmp;
}
2016-06-22 15:05:19 +02:00
Entity getPointLightEntity(ComponentHandle cmp) const override
2015-07-24 08:42:35 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_entity;
2015-07-24 08:42:35 +02:00
}
2016-01-24 17:20:03 +01:00
2016-06-22 15:05:19 +02:00
Entity getGlobalLightEntity(ComponentHandle cmp) const override
2015-07-24 08:42:35 +02:00
{
2017-02-09 14:22:41 +01:00
return m_global_lights[{cmp.index}].m_entity;
2015-07-24 08:42:35 +02:00
}
2016-06-22 15:05:19 +02:00
void reloadEnvironmentProbe(ComponentHandle cmp) override
2016-06-12 15:26:41 +02:00
{
2016-06-22 15:05:19 +02:00
Entity entity = {cmp.index};
auto& probe = m_environment_probes[entity];
2016-07-24 22:21:43 +02:00
auto* texture_manager = m_engine.getResourceManager().get(TEXTURE_TYPE);
2016-06-12 15:26:41 +02:00
if (probe.texture) texture_manager->unload(*probe.texture);
2017-05-23 19:57:11 +02:00
StaticString<MAX_PATH_LENGTH> path("universes/", m_universe.getName(), "/probes/", probe.guid, ".dds");
2016-06-12 15:26:41 +02:00
probe.texture = static_cast<Texture*>(texture_manager->load(Path(path)));
2016-11-29 20:00:36 +01:00
probe.texture->setFlag(BGFX_TEXTURE_SRGB, true);
path = "universes/";
2017-01-05 15:40:59 +01:00
path << m_universe.getName() << "/probes/" << probe.guid << "_irradiance.dds";
2016-11-29 20:00:36 +01:00
probe.irradiance = static_cast<Texture*>(texture_manager->load(Path(path)));
probe.irradiance->setFlag(BGFX_TEXTURE_SRGB, true);
2016-11-30 22:33:33 +01:00
probe.irradiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.irradiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
2016-11-29 20:00:36 +01:00
path = "universes/";
2017-01-05 15:40:59 +01:00
path << m_universe.getName() << "/probes/" << probe.guid << "_radiance.dds";
2016-11-29 20:00:36 +01:00
probe.radiance = static_cast<Texture*>(texture_manager->load(Path(path)));
probe.radiance->setFlag(BGFX_TEXTURE_SRGB, true);
2016-11-30 22:33:33 +01:00
probe.radiance->setFlag(BGFX_TEXTURE_MIN_ANISOTROPIC, true);
probe.radiance->setFlag(BGFX_TEXTURE_MAG_ANISOTROPIC, true);
2016-11-29 20:00:36 +01:00
}
ComponentHandle getNearestEnvironmentProbe(const Vec3& pos) const override
{
float nearest_dist_squared = FLT_MAX;
Entity nearest = INVALID_ENTITY;
for (int i = 0, c = m_environment_probes.size(); i < c; ++i)
{
Entity probe_entity = m_environment_probes.getKey(i);
Vec3 probe_pos = m_universe.getPosition(probe_entity);
float dist_squared = (pos - probe_pos).squaredLength();
if (dist_squared < nearest_dist_squared)
{
nearest = probe_entity;
nearest_dist_squared = dist_squared;
}
}
2017-05-23 14:01:09 +02:00
if (!nearest.isValid()) return INVALID_COMPONENT;
2016-11-29 20:00:36 +01:00
return {nearest.index};
2016-06-12 15:26:41 +02:00
}
2016-11-29 20:00:36 +01:00
Texture* getEnvironmentProbeTexture(ComponentHandle cmp) const override
2016-06-12 15:26:41 +02:00
{
2016-11-29 20:00:36 +01:00
Entity entity = {cmp.index};
2016-06-22 15:05:19 +02:00
return m_environment_probes[entity].texture;
2016-06-12 15:26:41 +02:00
}
2015-07-24 08:42:35 +02:00
2016-11-29 20:00:36 +01:00
Texture* getEnvironmentProbeIrradiance(ComponentHandle cmp) const override
{
Entity entity = {cmp.index};
return m_environment_probes[entity].irradiance;
}
Texture* getEnvironmentProbeRadiance(ComponentHandle cmp) const override
{
Entity entity = {cmp.index};
return m_environment_probes[entity].radiance;
}
2017-01-03 17:04:09 +01:00
u64 getEnvironmentProbeGUID(ComponentHandle cmp) const override
{
Entity entity = { cmp.index };
return m_environment_probes[entity].guid;
}
2016-06-22 15:05:19 +02:00
ComponentHandle getCameraInSlot(const char* slot) override
2015-07-21 20:10:50 +02:00
{
for (const auto& camera : m_cameras)
2015-07-21 20:10:50 +02:00
{
if (equalStrings(camera.slot, slot))
2014-08-20 22:45:47 +02:00
{
return {camera.entity.index};
2014-08-20 22:45:47 +02:00
}
2015-07-21 20:10:50 +02:00
}
2015-07-24 22:38:11 +02:00
return INVALID_COMPONENT;
2015-07-21 20:10:50 +02:00
}
2014-08-20 22:45:47 +02:00
float getTime() const override { return m_time; }
2016-06-22 15:05:19 +02:00
void modelUnloaded(Model*, ComponentHandle component)
2016-01-10 13:41:12 +01:00
{
auto& r = m_model_instances[component.index];
2017-04-13 17:05:07 +02:00
if (!hasCustomMeshes(r))
{
r.meshes = nullptr;
r.mesh_count = 0;
}
2016-02-06 15:20:34 +01:00
LUMIX_DELETE(m_allocator, r.pose);
r.pose = nullptr;
for (int i = 0; i < m_point_lights.size(); ++i)
{
m_light_influenced_geometry[i].eraseItemFast(component);
}
2016-01-10 13:41:12 +01:00
m_culling_system->removeStatic(component);
}
void freeCustomMeshes(ModelInstance& r, MaterialManager* manager)
{
2017-04-13 17:05:07 +02:00
if (!hasCustomMeshes(r)) return;
for (int i = 0; i < r.mesh_count; ++i)
{
2016-01-22 18:02:07 +01:00
manager->unload(*r.meshes[i].material);
r.meshes[i].~Mesh();
}
m_allocator.deallocate(r.meshes);
r.meshes = nullptr;
2017-04-13 17:05:07 +02:00
r.flags = r.flags & ~(u8)ModelInstance::CUSTOM_MESHES;
r.mesh_count = 0;
}
2016-06-22 15:05:19 +02:00
void modelLoaded(Model* model, ComponentHandle component)
2015-07-21 20:10:50 +02:00
{
auto& rm = m_engine.getResourceManager();
2016-07-24 22:21:43 +02:00
auto* material_manager = static_cast<MaterialManager*>(rm.get(MATERIAL_TYPE));
auto& r = m_model_instances[component.index];
2016-10-28 01:49:36 +02:00
2017-02-20 16:06:33 +01:00
if (model->getMesh(0).material->getLayersCount() > 0)
{
if (model->getBoneCount() > 0)
{
r.type = ModelInstance::MULTILAYER_SKINNED;
}
else
{
r.type = ModelInstance::MULTILAYER_RIGID;
}
}
2016-10-28 01:49:36 +02:00
else if (model->getBoneCount() > 0) r.type = ModelInstance::SKINNED;
else r.type = ModelInstance::RIGID;
float bounding_radius = r.model->getBoundingRadius();
float scale = m_universe.getScale(r.entity);
Sphere sphere(r.matrix.getTranslation(), bounding_radius * scale);
2016-10-22 18:08:53 +02:00
m_culling_system->addStatic(component, sphere, getLayerMask(r));
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);
2016-04-26 19:26:39 +02:00
int skinned_define_idx = m_renderer.getShaderDefineIdx("SKINNED");
for (int i = 0; i < model->getMeshCount(); ++i)
{
model->getMesh(i).material->setDefine(skinned_define_idx, true);
}
}
r.matrix = m_universe.getMatrix(r.entity);
2017-04-13 17:05:07 +02:00
ASSERT(!r.meshes || hasCustomMeshes(r));
if (r.meshes)
{
allocateCustomMeshes(r, model->getMeshCount());
for (int i = 0; i < r.mesh_count; ++i)
{
auto& src = model->getMesh(i);
if (!r.meshes[i].material)
{
material_manager->load(*src.material);
r.meshes[i].material = src.material;
}
r.meshes[i].set(
src.attribute_array_offset, src.attribute_array_size, src.indices_offset, src.indices_count);
}
}
else
{
r.meshes = &r.model->getMesh(0);
r.mesh_count = r.model->getMeshCount();
}
2015-07-21 20:10:50 +02:00
if ((r.flags & ModelInstance::IS_BONE_ATTACHMENT_PARENT) != 0)
{
updateBoneAttachment(m_bone_attachments[r.entity]);
}
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_point_lights.size(); ++i)
{
PointLight& light = m_point_lights[i];
Vec3 t = r.matrix.getTranslation();
float radius = r.model->getBoundingRadius();
2015-07-24 08:42:35 +02:00
if ((t - m_universe.getPosition(light.m_entity)).squaredLength() <
2015-12-10 17:09:52 +01:00
(radius + light.m_range) * (radius + light.m_range))
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
m_light_influenced_geometry[i].push(component);
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].entity != INVALID_ENTITY && 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)
{
for (int i = 0, c = m_model_instances.size(); i < c; ++i)
2015-07-21 20:10:50 +02:00
{
if (m_model_instances[i].entity != INVALID_ENTITY && m_model_instances[i].model == model)
{
2016-06-22 15:05:19 +02:00
modelLoaded(model, {i});
}
2015-07-21 20:10:50 +02:00
}
}
2015-02-14 00:13:34 +01:00
2016-07-25 02:00:22 +02:00
ModelLoadedCallback& getModelLoadedCallback(Model* model)
2015-07-21 20:10:50 +02:00
{
2016-07-25 02:00:22 +02:00
int idx = m_model_loaded_callbacks.find(model);
if (idx >= 0) return m_model_loaded_callbacks.at(idx);
return m_model_loaded_callbacks.emplace(model, *this, model);
2015-07-21 20:10:50 +02:00
}
2015-02-14 00:13:34 +01:00
void allocateCustomMeshes(ModelInstance& r, int count)
{
2017-04-13 17:05:07 +02:00
if (hasCustomMeshes(r) && r.mesh_count == count) return;
2016-06-15 15:28:07 +02:00
ASSERT(r.model);
auto& rm = r.model->getResourceManager();
2016-07-25 01:02:36 +02:00
auto* material_manager = static_cast<MaterialManager*>(rm.getOwner().get(MATERIAL_TYPE));
auto* new_meshes = (Mesh*)m_allocator.allocate(count * sizeof(Mesh));
if (r.meshes)
2016-01-22 01:37:13 +01:00
{
for (int i = 0; i < r.mesh_count; ++i)
{
new (NewPlaceholder(), new_meshes + i) Mesh(r.meshes[i]);
2016-01-22 01:37:13 +01:00
}
2017-04-13 17:05:07 +02:00
if (hasCustomMeshes(r))
{
for (int i = count; i < r.mesh_count; ++i)
{
material_manager->unload(*r.meshes[i].material);
}
2016-07-24 15:13:52 +02:00
for (int i = 0; i < r.mesh_count; ++i)
{
r.meshes[i].~Mesh();
}
m_allocator.deallocate(r.meshes);
}
else
{
for (int i = 0; i < r.mesh_count; ++i)
{
material_manager->load(*r.meshes[i].material);
}
}
}
for (int i = r.mesh_count; i < count; ++i)
{
new (NewPlaceholder(), new_meshes + i) Mesh(nullptr, 0, 0, 0, 0, "", m_allocator);
}
r.meshes = new_meshes;
r.mesh_count = count;
2017-04-13 17:05:07 +02:00
r.flags |= (u8)ModelInstance::CUSTOM_MESHES;
}
bool getModelInstanceKeepSkin(ComponentHandle cmp) override
{
auto& r = m_model_instances[cmp.index];
return keepSkin(r);
}
void setModelInstanceKeepSkin(ComponentHandle cmp, bool keep) override
{
auto& r = m_model_instances[cmp.index];
if (keep)
{
r.flags |= (u8)ModelInstance::KEEP_SKIN;
}
else
{
r.flags &= ~(u8)ModelInstance::KEEP_SKIN;
}
}
void setModelInstanceMaterial(ComponentHandle cmp, int index, const Path& path) override
{
auto& r = m_model_instances[cmp.index];
if (r.meshes && r.mesh_count > index && r.meshes[index].material && path == r.meshes[index].material->getPath()) return;
auto& rm = r.model->getResourceManager();
2016-07-25 01:02:36 +02:00
auto* material_manager = static_cast<MaterialManager*>(rm.getOwner().get(MATERIAL_TYPE));
2016-02-10 12:09:09 +01:00
2016-11-20 17:27:41 +01:00
int new_count = Math::maximum(i8(index + 1), r.mesh_count);
allocateCustomMeshes(r, new_count);
2016-06-15 15:28:07 +02:00
ASSERT(r.meshes);
2016-01-22 18:02:07 +01:00
if (r.meshes[index].material) material_manager->unload(*r.meshes[index].material);
auto* new_material = static_cast<Material*>(material_manager->load(path));
2016-01-22 18:02:07 +01:00
r.meshes[index].material = new_material;
}
2016-02-10 12:09:09 +01:00
Path getModelInstanceMaterial(ComponentHandle cmp, int index) override
{
auto& r = m_model_instances[cmp.index];
if (!r.meshes) return Path("");
2016-01-22 18:02:07 +01:00
return r.meshes[index].material->getPath();
}
2016-06-22 15:05:19 +02:00
void setModel(ComponentHandle component, Model* model)
2015-07-21 20:10:50 +02:00
{
auto& model_instance = m_model_instances[component.index];
2017-05-23 14:01:09 +02:00
ASSERT(model_instance.entity.isValid());
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)
{
auto& rm = old_model->getResourceManager();
2016-07-25 01:02:36 +02:00
auto* material_manager = static_cast<MaterialManager*>(rm.getOwner().get(MATERIAL_TYPE));
freeCustomMeshes(model_instance, material_manager);
2016-07-25 02:00:22 +02:00
ModelLoadedCallback& callback = getModelLoadedCallback(old_model);
--callback.m_ref_count;
if (callback.m_ref_count == 0)
2016-05-12 07:48:51 +02:00
{
2016-07-25 02:00:22 +02:00
m_model_loaded_callbacks.erase(old_model);
2016-05-12 07:48:51 +02:00
}
2015-12-10 23:33:21 +01:00
if (old_model->isReady())
{
m_culling_system->removeStatic(component);
}
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)
{
2017-04-13 17:05:07 +02:00
if (keepSkin(model_instance)) model->setKeepSkin();
2016-07-25 02:00:22 +02:00
ModelLoadedCallback& callback = getModelLoadedCallback(model);
++callback.m_ref_count;
2015-07-21 20:10:50 +02:00
if (model->isReady())
{
2015-12-10 17:09:52 +01:00
modelLoaded(model, component);
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
2016-06-22 15:05:19 +02:00
void detectLightInfluencedGeometry(ComponentHandle cmp)
2015-07-21 20:10:50 +02:00
{
2016-06-22 15:05:19 +02:00
Frustum frustum = getPointLightFrustum(cmp);
2017-10-02 16:24:04 +02:00
const CullingSystem::Results& results = m_culling_system->cull(frustum, ~0ULL);
auto& influenced_geometry = m_light_influenced_geometry[m_point_lights_map[cmp]];
influenced_geometry.clear();
for (int i = 0; i < results.size(); ++i)
{
const CullingSystem::Subresults& subresult = results[i];
2016-06-22 15:05:19 +02:00
influenced_geometry.reserve(influenced_geometry.size() + subresult.size());
for (int j = 0, c = subresult.size(); j < c; ++j)
2015-07-21 20:10:50 +02:00
{
influenced_geometry.push(subresult[j]);
2015-07-21 20:10:50 +02:00
}
}
}
2016-06-22 15:05:19 +02:00
int getParticleEmitterAttractorCount(ComponentHandle cmp) override
2015-12-17 13:58:40 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AttractorModule>(cmp);
return module ? module->m_count : 0;
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
void addParticleEmitterAttractor(ComponentHandle cmp, int index) override
2015-12-17 13:58:40 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AttractorModule>(cmp);
if (!module) return;
2015-12-17 13:58:40 +01:00
2015-12-17 21:38:23 +01:00
auto* plane_module = static_cast<ParticleEmitter::AttractorModule*>(module);
if (plane_module->m_count == lengthOf(plane_module->m_entities)) return;
2015-12-17 13:58:40 +01:00
2015-12-17 21:38:23 +01:00
if (index < 0)
{
plane_module->m_entities[plane_module->m_count] = INVALID_ENTITY;
++plane_module->m_count;
return;
}
for (int i = plane_module->m_count - 1; i > index; --i)
{
plane_module->m_entities[i] = plane_module->m_entities[i - 1];
2015-12-17 13:58:40 +01:00
}
2015-12-17 21:38:23 +01:00
plane_module->m_entities[index] = INVALID_ENTITY;
++plane_module->m_count;
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
void removeParticleEmitterAttractor(ComponentHandle cmp, int index) override
2015-12-17 13:58:40 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AttractorModule>(cmp);
if (!module) return;
2015-12-17 13:58:40 +01:00
2015-12-17 21:38:23 +01:00
for (int i = index; i < module->m_count - 1; ++i)
{
module->m_entities[i] = module->m_entities[i + 1];
2015-12-17 13:58:40 +01:00
}
2015-12-17 21:38:23 +01:00
--module->m_count;
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
Entity getParticleEmitterAttractorEntity(ComponentHandle cmp, int index) override
2015-12-17 13:58:40 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AttractorModule>(cmp);
return module ? module->m_entities[index] : INVALID_ENTITY;
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterAttractorEntity(ComponentHandle cmp, int index, Entity entity) override
2015-12-17 13:58:40 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::AttractorModule>(cmp);
if(module) module->m_entities[index] = entity;
2015-12-17 13:58:40 +01:00
}
2016-06-22 15:05:19 +02:00
float getParticleEmitterShapeRadius(ComponentHandle cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SpawnShapeModule>(cmp);
return module ? module->m_radius : 0.0f;
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterShapeRadius(ComponentHandle cmp, float value) override
{
auto* module = getEmitterModule<ParticleEmitter::SpawnShapeModule>(cmp);
if (module) module->m_radius = value;
}
2016-06-22 15:05:19 +02:00
int getParticleEmitterPlaneCount(ComponentHandle cmp) override
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::PlaneModule>(cmp);
return module ? module->m_count : 0;
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
void addParticleEmitterPlane(ComponentHandle cmp, int index) override
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
auto* plane_module = getEmitterModule<ParticleEmitter::PlaneModule>(cmp);
if (!plane_module) return;
if (plane_module->m_count == lengthOf(plane_module->m_entities)) return;
if (index < 0)
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
plane_module->m_entities[plane_module->m_count] = INVALID_ENTITY;
++plane_module->m_count;
return;
}
2015-12-16 21:26:19 +01:00
2015-12-17 21:38:23 +01:00
for (int i = plane_module->m_count - 1; i > index; --i)
{
plane_module->m_entities[i] = plane_module->m_entities[i - 1];
2015-12-16 21:26:19 +01:00
}
2015-12-17 21:38:23 +01:00
plane_module->m_entities[index] = INVALID_ENTITY;
++plane_module->m_count;
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
void removeParticleEmitterPlane(ComponentHandle cmp, int index) override
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
auto* plane_module = getEmitterModule<ParticleEmitter::PlaneModule>(cmp);
if (!plane_module) return;
2015-12-16 21:26:19 +01:00
2015-12-17 21:38:23 +01:00
for (int i = index; i < plane_module->m_count - 1; ++i)
{
plane_module->m_entities[i] = plane_module->m_entities[i + 1];
2015-12-16 21:26:19 +01:00
}
2015-12-17 21:38:23 +01:00
--plane_module->m_count;
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
Entity getParticleEmitterPlaneEntity(ComponentHandle cmp, int index) override
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::PlaneModule>(cmp);
return module ? module->m_entities[index] : INVALID_ENTITY;
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterPlaneEntity(ComponentHandle cmp, int index, Entity entity) override
2015-12-16 21:26:19 +01:00
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::PlaneModule>(cmp);
if (module) module->m_entities[index] = entity;
2015-12-16 21:26:19 +01:00
}
2016-06-22 15:05:19 +02:00
float getLightFOV(ComponentHandle cmp) override
2015-07-21 20:10:50 +02:00
{
return m_point_lights[m_point_lights_map[cmp]].m_fov;
2015-07-21 20:10:50 +02:00
}
2015-02-14 00:13:34 +01:00
2016-06-22 15:05:19 +02:00
void setLightFOV(ComponentHandle cmp, float fov) override
2015-07-21 20:10:50 +02:00
{
m_point_lights[m_point_lights_map[cmp]].m_fov = fov;
2015-07-21 20:10:50 +02:00
}
2015-02-14 00:13:34 +01:00
2014-06-16 21:18:15 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle createGlobalLight(Entity entity)
2015-07-21 20:10:50 +02:00
{
2017-02-09 14:22:41 +01:00
GlobalLight light;
2015-07-21 20:10:50 +02:00
light.m_entity = entity;
2016-02-10 12:09:09 +01:00
light.m_diffuse_color.set(1, 1, 1);
light.m_diffuse_intensity = 0;
light.m_indirect_intensity = 1;
2015-07-21 20:10:50 +02:00
light.m_fog_color.set(1, 1, 1);
light.m_fog_density = 0;
light.m_cascades.set(3, 8, 100, 300);
2015-10-17 00:18:47 +02:00
light.m_fog_bottom = 0.0f;
light.m_fog_height = 10.0f;
2015-07-21 20:10:50 +02:00
2017-02-09 14:22:41 +01:00
ComponentHandle cmp = {entity.index};
if (m_global_lights.empty()) m_active_global_light_cmp = cmp;
2015-07-21 20:10:50 +02:00
2017-02-09 14:22:41 +01:00
m_global_lights.insert(entity, light);
m_universe.addComponent(entity, GLOBAL_LIGHT_TYPE, this, cmp);
return cmp;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle createPointLight(Entity entity)
2014-06-16 21:18:15 +02:00
{
2016-01-14 16:22:25 +01:00
PointLight& light = m_point_lights.emplace();
2016-06-22 15:05:19 +02:00
m_light_influenced_geometry.emplace(m_allocator);
2015-07-21 20:10:50 +02:00
light.m_entity = entity;
2015-09-02 11:14:42 +02:00
light.m_diffuse_color.set(1, 1, 1);
2016-02-10 12:09:09 +01:00
light.m_diffuse_intensity = 1;
2016-06-22 15:05:19 +02:00
++m_point_light_last_cmp.index;
2016-06-22 22:16:20 +02:00
light.m_component = m_point_light_last_cmp;
light.m_fov = Math::degreesToRadians(360);
2015-07-21 20:10:50 +02:00
light.m_specular_color.set(1, 1, 1);
2016-02-10 12:09:09 +01:00
light.m_specular_intensity = 1;
2015-09-02 11:14:42 +02:00
light.m_cast_shadows = false;
2015-09-09 02:18:09 +02:00
light.m_attenuation_param = 2;
light.m_range = 10;
2016-06-22 15:05:19 +02:00
m_point_lights_map.insert(light.m_component, m_point_lights.size() - 1);
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
m_universe.addComponent(entity, POINT_LIGHT_TYPE, this, light.m_component);
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
detectLightInfluencedGeometry(light.m_component);
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
return light.m_component;
2014-06-16 21:18:15 +02:00
}
2016-07-22 13:57:52 +02:00
void updateDecalInfo(Decal& decal) const
{
decal.position = m_universe.getPosition(decal.entity);
decal.radius = decal.scale.length();
decal.mtx = m_universe.getMatrix(decal.entity);
decal.mtx.setXVector(decal.mtx.getXVector() * decal.scale.x);
decal.mtx.setYVector(decal.mtx.getYVector() * decal.scale.y);
decal.mtx.setZVector(decal.mtx.getZVector() * decal.scale.z);
decal.inv_mtx = decal.mtx;
decal.inv_mtx.inverse();
}
ComponentHandle createDecal(Entity entity)
{
2016-07-24 17:29:17 +02:00
Decal& decal = m_decals.insert(entity);
2016-07-22 13:57:52 +02:00
decal.material = nullptr;
decal.entity = entity;
decal.scale.set(1, 1, 1);
updateDecalInfo(decal);
ComponentHandle cmp = {entity.index};
m_universe.addComponent(entity, DECAL_TYPE, this, cmp);
return cmp;
}
2016-06-22 15:05:19 +02:00
ComponentHandle createEnvironmentProbe(Entity entity)
2016-06-12 15:26:41 +02:00
{
2016-07-24 17:29:17 +02:00
EnvironmentProbe& probe = m_environment_probes.insert(entity);
2016-07-24 22:21:43 +02:00
auto* texture_manager = m_engine.getResourceManager().get(TEXTURE_TYPE);
2016-11-29 20:00:36 +01:00
probe.texture = static_cast<Texture*>(texture_manager->load(Path("pipelines/pbr/default_probe.dds")));
probe.texture->setFlag(BGFX_TEXTURE_SRGB, true);
probe.irradiance = static_cast<Texture*>(texture_manager->load(Path("pipelines/pbr/default_probe.dds")));
probe.irradiance->setFlag(BGFX_TEXTURE_SRGB, true);
probe.radiance = static_cast<Texture*>(texture_manager->load(Path("pipelines/pbr/default_probe.dds")));
probe.radiance->setFlag(BGFX_TEXTURE_SRGB, true);
2017-01-03 17:04:09 +01:00
probe.guid = Math::randGUID();
2016-06-12 15:26:41 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = {entity.index};
m_universe.addComponent(entity, ENVIRONMENT_PROBE_TYPE, this, cmp);
return cmp;
2016-06-12 15:26:41 +02:00
}
2016-06-22 15:05:19 +02:00
ComponentHandle createBoneAttachment(Entity 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;
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = { entity.index };
m_universe.addComponent(entity, BONE_ATTACHMENT_TYPE, this, cmp);
return cmp;
2016-05-02 21:41:18 +02:00
}
ComponentHandle createModelInstance(Entity 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.entity = INVALID_ENTITY;
r.model = nullptr;
r.pose = nullptr;
2015-12-10 17:09:52 +01:00
}
auto& r = m_model_instances[entity.index];
r.entity = entity;
r.model = nullptr;
r.meshes = nullptr;
r.pose = nullptr;
2017-04-13 17:05:07 +02:00
r.flags = 0;
r.mesh_count = 0;
r.matrix = m_universe.getMatrix(entity);
2016-06-22 15:05:19 +02:00
ComponentHandle cmp = {entity.index};
m_universe.addComponent(entity, MODEL_INSTANCE_TYPE, this, cmp);
2016-06-22 15:05:19 +02:00
return cmp;
2014-06-16 21:18:15 +02:00
}
2016-06-22 15:05:19 +02:00
void setParticleEmitterMaterialPath(ComponentHandle cmp, const Path& path) override
{
if (!m_particle_emitters[{cmp.index}]) return;
2016-07-24 22:21:43 +02:00
auto* manager = m_engine.getResourceManager().get(MATERIAL_TYPE);
2016-01-06 14:18:59 +01:00
Material* material = static_cast<Material*>(manager->load(path));
m_particle_emitters[{cmp.index}]->setMaterial(material);
}
2016-06-22 15:05:19 +02:00
Path getParticleEmitterMaterialPath(ComponentHandle cmp) override
{
ParticleEmitter* emitter = m_particle_emitters[{cmp.index}];
2016-01-06 14:18:59 +01:00
if (!emitter) return Path("");
if (!emitter->getMaterial()) return Path("");
2016-01-06 14:18:59 +01:00
return emitter->getMaterial()->getPath();
}
const AssociativeArray<Entity, ParticleEmitter*>& getParticleEmitters() const override
{
return m_particle_emitters;
}
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;
2015-07-21 20:10:50 +02:00
2016-06-22 15:05:19 +02:00
ComponentHandle m_point_light_last_cmp;
Array<Array<ComponentHandle>> m_light_influenced_geometry;
ComponentHandle m_active_global_light_cmp;
HashMap<ComponentHandle, int> m_point_lights_map;
2016-07-22 13:57:52 +02:00
AssociativeArray<Entity, Decal> m_decals;
Array<ModelInstance> m_model_instances;
2017-02-09 14:22:41 +01:00
HashMap<Entity, GlobalLight> m_global_lights;
Array<PointLight> m_point_lights;
HashMap<Entity, Camera> m_cameras;
AssociativeArray<Entity, BoneAttachment> m_bone_attachments;
2016-06-12 15:26:41 +02:00
AssociativeArray<Entity, EnvironmentProbe> m_environment_probes;
HashMap<Entity, Terrain*> m_terrains;
AssociativeArray<Entity, 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;
Array<DebugPoint> m_debug_points;
Array<Array<ModelInstanceMesh>> m_temporary_infos;
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;
2016-07-25 02:00:22 +02:00
AssociativeArray<Model*, ModelLoadedCallback> m_model_loaded_callbacks;
2015-07-21 20:10:50 +02:00
};
2016-12-10 15:16:01 +01:00
#define COMPONENT_TYPE(type, name) \
{ \
type \
, static_cast<Universe::Serialize>(&RenderSceneImpl::serialize##name) \
, static_cast<Universe::Deserialize>(&RenderSceneImpl::deserialize##name) \
, &RenderSceneImpl::create##name \
, &RenderSceneImpl::destroy##name \
}
static struct
{
2016-06-22 00:46:48 +02:00
ComponentType type;
2016-12-10 15:16:01 +01:00
Universe::Serialize serialize;
Universe::Deserialize deserialize;
2016-06-22 15:05:19 +02:00
ComponentHandle(RenderSceneImpl::*creator)(Entity);
void (RenderSceneImpl::*destroyer)(ComponentHandle);
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(GLOBAL_LIGHT_TYPE, GlobalLight),
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),
COMPONENT_TYPE(PARTICLE_EMITTER_TYPE, ParticleEmitter),
COMPONENT_TYPE(PARTICLE_EMITTER_ALPHA_TYPE, ParticleEmitterAlpha),
COMPONENT_TYPE(PARTICLE_EMITTER_ATTRACTOR_TYPE, ParticleEmitterAttractor),
COMPONENT_TYPE(PARTICLE_EMITTER_FORCE_HASH, ParticleEmitterForce),
COMPONENT_TYPE(PARTICLE_EMITTER_LINEAR_MOVEMENT_TYPE, ParticleEmitterLinearMovement),
COMPONENT_TYPE(PARTICLE_EMITTER_PLANE_TYPE, ParticleEmitterPlane),
COMPONENT_TYPE(PARTICLE_EMITTER_RANDOM_ROTATION_TYPE, ParticleEmitterRandomRotation),
COMPONENT_TYPE(PARTICLE_EMITTER_SIZE_TYPE, ParticleEmitterSize),
COMPONENT_TYPE(PARTICLE_EMITTER_SPAWN_SHAPE_TYPE, ParticleEmitterSpawnShape),
COMPONENT_TYPE(PARTICLE_EMITTER_SUBIMAGE_TYPE, ParticleEmitterSubimage)
};
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)
, m_model_loaded_callbacks(m_allocator)
, m_model_instances(m_allocator)
2016-07-21 14:23:46 +02:00
, m_cameras(m_allocator)
, m_terrains(m_allocator)
, m_point_lights(m_allocator)
, m_light_influenced_geometry(m_allocator)
, m_global_lights(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)
, m_debug_points(m_allocator)
, m_temporary_infos(m_allocator)
, m_active_global_light_cmp(INVALID_COMPONENT)
, m_point_light_last_cmp(INVALID_COMPONENT)
, m_is_grass_enabled(true)
, m_is_game_running(false)
, m_particle_emitters(m_allocator)
, m_point_lights_map(m_allocator)
, 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)
2016-06-22 00:46:48 +02:00
{
2016-07-21 14:23:46 +02:00
m_universe.entityTransformed().bind<RenderSceneImpl, &RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().bind<RenderSceneImpl, &RenderSceneImpl::onEntityDestroyed>(this);
2017-09-16 14:04:24 +02:00
m_culling_system = CullingSystem::create(m_allocator);
m_model_instances.reserve(5000);
2016-07-21 14:23:46 +02:00
2016-06-22 00:46:48 +02:00
for (auto& i : COMPONENT_INFOS)
{
2016-12-10 15:16:01 +01:00
universe.registerComponentType(i.type, this, i.serialize, i.deserialize);
2016-06-22 00:46:48 +02:00
}
}
2016-06-22 15:05:19 +02:00
ComponentHandle RenderSceneImpl::createComponent(ComponentType type, Entity entity)
{
for (auto& i : COMPONENT_INFOS)
{
if (i.type == type)
{
return (this->*i.creator)(entity);
}
}
return INVALID_COMPONENT;
}
2016-06-22 15:05:19 +02:00
void RenderSceneImpl::destroyComponent(ComponentHandle component, ComponentType type)
{
for (auto& i : COMPONENT_INFOS)
{
if (i.type == type)
{
(this->*i.destroyer)(component);
return;
}
}
ASSERT(false);
}
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)
{
Pipeline::registerLuaAPI(L);
2016-05-07 11:49:39 +02:00
Model::registerLuaAPI(L);
#define REGISTER_FUNCTION(F)\
do { \
auto f = &LuaWrapper::wrapMethod<RenderSceneImpl, decltype(&RenderSceneImpl::F), &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(getCameraViewProjection);
REGISTER_FUNCTION(getGlobalLightEntity);
REGISTER_FUNCTION(getActiveGlobalLight);
2016-08-30 12:19:05 +02:00
REGISTER_FUNCTION(getCameraInSlot);
REGISTER_FUNCTION(getCameraEntity);
REGISTER_FUNCTION(getCameraSlot);
REGISTER_FUNCTION(getCameraComponent);
REGISTER_FUNCTION(getModelInstanceComponent);
REGISTER_FUNCTION(getModelInstanceModel);
REGISTER_FUNCTION(addDebugCross);
2016-05-07 11:49:39 +02:00
REGISTER_FUNCTION(addDebugLine);
2016-10-13 19:48:38 +02:00
REGISTER_FUNCTION(addDebugCircle);
REGISTER_FUNCTION(addDebugSphere);
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);
2016-11-02 19:47:44 +01:00
REGISTER_FUNCTION(hideModelInstance);
REGISTER_FUNCTION(showModelInstance);
REGISTER_FUNCTION(getPoseBonePosition);
2017-01-09 16:34:26 +01:00
#undef REGISTER_FUNCTION
#define REGISTER_FUNCTION(F)\
do { \
auto f = &LuaWrapper::wrap<decltype(&RenderSceneImpl::LUA_##F), &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);
2016-10-17 00:19:02 +02:00
REGISTER_FUNCTION(pipelineRender);
2016-10-17 10:21:25 +02:00
REGISTER_FUNCTION(getRenderBuffer);
REGISTER_FUNCTION(getMaterialTexture);
2016-09-14 13:19:51 +02:00
REGISTER_FUNCTION(getTextureWidth);
REGISTER_FUNCTION(getTextureHeight);
REGISTER_FUNCTION(getTexturePixel);
REGISTER_FUNCTION(setTexturePixel);
2016-10-31 16:19:27 +01:00
REGISTER_FUNCTION(getTextureHandle);
2016-09-14 13:19:51 +02:00
REGISTER_FUNCTION(updateTextureData);
REGISTER_FUNCTION(setModelInstanceMaterial);
REGISTER_FUNCTION(setModelInstancePath);
REGISTER_FUNCTION(getModelBoneIndex);
REGISTER_FUNCTION(makeScreenshot);
REGISTER_FUNCTION(compareTGA);
2016-09-14 14:15:27 +02:00
REGISTER_FUNCTION(getTerrainHeightAt);
2016-10-04 17:41:16 +02:00
REGISTER_FUNCTION(emitParticle);
LuaWrapper::createSystemFunction(L, "Renderer", "castCameraRay", &RenderSceneImpl::LUA_castCameraRay);
#undef REGISTER_FUNCTION
}
} // namespace Lumix