LumixEngine/src/renderer/render_scene.cpp

4057 lines
102 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"
#include "engine/fs/file_system.h"
#include "engine/geometry.h"
#include "engine/json_serializer.h"
#include "engine/lifo_allocator.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/math_utils.h"
#include "engine/mtjd/generic_job.h"
#include "engine/mtjd/job.h"
#include "engine/mtjd/manager.h"
#include "engine/profiler.h"
#include "engine/resource_manager.h"
#include "engine/resource_manager_base.h"
#include "engine/timer.h"
2014-08-20 22:45:47 +02:00
#include "engine/engine.h"
2014-08-20 22:45:47 +02:00
#include "lua_script/lua_script_system.h"
2015-08-17 23:45:26 +02:00
#include "renderer/culling_system.h"
#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"
2014-08-20 22:45:47 +02:00
#include "engine/universe/universe.h"
2015-12-02 01:37:53 +01:00
#include <cmath>
2014-06-16 21:18:15 +02:00
namespace Lumix
{
2015-07-24 22:38:11 +02:00
static const uint32 RENDERABLE_HASH = crc32("renderable");
static const uint32 POINT_LIGHT_HASH = crc32("point_light");
static const uint32 PARTICLE_EMITTER_HASH = crc32("particle_emitter");
static const uint32 PARTICLE_EMITTER_FADE_HASH = crc32("particle_emitter_fade");
static const uint32 PARTICLE_EMITTER_FORCE_HASH = crc32("particle_emitter_force");
2015-12-17 13:58:40 +01:00
static const uint32 PARTICLE_EMITTER_ATTRACTOR_HASH = crc32("particle_emitter_attractor");
static const uint32 PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH =
crc32("particle_emitter_linear_movement");
2016-02-24 20:46:14 +01:00
static const uint32 PARTICLE_EMITTER_SPAWN_SHAPE_HASH = crc32("particle_emitter_spawn_shape");
static const uint32 PARTICLE_EMITTER_PLANE_HASH = crc32("particle_emitter_plane");
static const uint32 PARTICLE_EMITTER_RANDOM_ROTATION_HASH =
crc32("particle_emitter_random_rotation");
2015-11-18 20:18:48 +01:00
static const uint32 PARTICLE_EMITTER_SIZE_HASH = crc32("particle_emitter_size");
static const uint32 GLOBAL_LIGHT_HASH = crc32("global_light");
static const uint32 CAMERA_HASH = crc32("camera");
static const uint32 TERRAIN_HASH = crc32("terrain");
2016-05-02 21:41:18 +02:00
static const uint32 BONE_ATTACHMENT_HASH = crc32("bone_attachment");
2014-06-16 21:18:15 +02:00
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;
int m_uid;
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
{
2015-12-07 21:49:27 +01:00
ComponentIndex m_uid;
2016-02-10 12:09:09 +01:00
Vec3 m_diffuse_color;
float m_specular_intensity;
2016-01-28 21:44:35 +01:00
Vec3 m_specular;
2016-02-10 12:09:09 +01:00
float m_diffuse_intensity;
2015-07-21 20:10:50 +02:00
Vec3 m_ambient_color;
float m_ambient_intensity;
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_free;
bool is_ortho;
char slot[MAX_SLOT_LENGTH + 1];
2015-07-21 20:10:50 +02:00
};
2016-05-02 21:41:18 +02:00
struct BoneAttachment
{
Entity entity;
Entity parent_entity;
int bone_index;
Matrix relative_matrix;
};
2015-07-21 20:10:50 +02:00
class RenderSceneImpl : public RenderScene
{
private:
class ModelLoadedCallback
2014-06-16 21:18:15 +02:00
{
2015-07-21 20:10:50 +02:00
public:
ModelLoadedCallback(RenderSceneImpl& scene, Model* model)
: m_scene(scene)
, m_ref_count(0)
, m_model(model)
{
2015-12-10 23:33:21 +01:00
m_model->getObserverCb().bind<ModelLoadedCallback, &ModelLoadedCallback::callback>(
this);
2015-07-21 20:10:50 +02:00
}
~ModelLoadedCallback()
{
2015-10-03 01:53:04 +02:00
m_model->getObserverCb().unbind<ModelLoadedCallback, &ModelLoadedCallback::callback>(
this);
2015-07-21 20:10:50 +02:00
}
2016-01-10 13:41:12 +01:00
void callback(Resource::State old_state, Resource::State new_state)
2015-07-21 20:10:50 +02:00
{
if (new_state == Resource::State::READY)
{
m_scene.modelLoaded(m_model);
}
2016-02-06 15:20:34 +01:00
else if (old_state == Resource::State::READY && new_state != Resource::State::READY)
2016-01-10 13:41:12 +01:00
{
m_scene.modelUnloaded(m_model);
2016-01-10 13:41:12 +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
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,
bool is_forward_rendered,
IAllocator& allocator)
2015-07-21 20:10:50 +02:00
: m_engine(engine)
, m_universe(universe)
, m_renderer(renderer)
, m_allocator(allocator)
, m_model_loaded_callbacks(m_allocator)
, m_renderables(m_allocator)
, 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-03-10 19:32:48 +01:00
, m_debug_triangles(m_allocator)
2015-07-21 20:10:50 +02:00
, m_debug_lines(m_allocator)
, m_debug_points(m_allocator)
2015-07-21 20:10:50 +02:00
, m_temporary_infos(m_allocator)
, m_sync_point(true, m_allocator)
, m_jobs(m_allocator)
, m_active_global_light_uid(-1)
, m_global_light_last_uid(-1)
, m_point_light_last_uid(-1)
, m_is_forward_rendered(is_forward_rendered)
2015-07-24 22:38:11 +02:00
, m_renderable_created(m_allocator)
, m_renderable_destroyed(m_allocator)
, m_is_grass_enabled(true)
, m_is_game_running(false)
2015-10-30 21:11:11 +01:00
, m_particle_emitters(m_allocator)
2016-01-26 10:27:31 +01:00
, m_point_lights_map(m_allocator)
2016-05-02 21:41:18 +02:00
, m_bone_attachments(m_allocator)
2014-06-16 21:18:15 +02:00
{
2016-05-02 21:41:18 +02:00
m_is_updating_attachments = false;
m_universe.entityTransformed().bind<RenderSceneImpl, &RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().bind<RenderSceneImpl, &RenderSceneImpl::onEntityDestroyed>(this);
m_culling_system = CullingSystem::create(m_engine.getMTJDManager(), m_allocator);
2015-07-21 20:10:50 +02:00
m_time = 0;
2015-12-10 17:09:52 +01:00
m_renderables.reserve(5000);
2015-07-21 20:10:50 +02:00
}
2015-07-21 20:10:50 +02:00
~RenderSceneImpl()
{
auto& rm = m_engine.getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
2016-05-02 21:41:18 +02:00
m_universe.entityTransformed().unbind<RenderSceneImpl, &RenderSceneImpl::onEntityMoved>(this);
m_universe.entityDestroyed().unbind<RenderSceneImpl, &RenderSceneImpl::onEntityDestroyed>(this);
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_model_loaded_callbacks.size(); ++i)
{
2015-10-30 21:11:11 +01:00
LUMIX_DELETE(m_allocator, m_model_loaded_callbacks[i]);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_terrains.size(); ++i)
{
2015-10-30 21:11:11 +01:00
LUMIX_DELETE(m_allocator, m_terrains[i]);
}
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
LUMIX_DELETE(m_allocator, m_particle_emitters[i]);
2015-07-21 20:10:50 +02:00
}
2015-01-04 15:05:20 +01:00
2015-12-10 17:09:52 +01:00
for (auto& i : m_renderables)
2015-07-21 20:10:50 +02:00
{
if (i.entity != INVALID_ENTITY && i.model)
2014-06-16 21:18:15 +02:00
{
auto& manager = i.model->getResourceManager();
freeCustomMeshes(i, material_manager);
manager.get(ResourceManager::MODEL)->unload(*i.model);
LUMIX_DELETE(m_allocator, i.pose);
2015-07-21 20:10:50 +02:00
}
}
2014-10-15 20:46:01 +02:00
2015-07-21 20:10:50 +02:00
CullingSystem::destroy(*m_culling_system);
}
2014-10-15 20:46:01 +02:00
2014-08-20 22:45:47 +02:00
2015-12-17 13:58:40 +01:00
void resetParticleEmitter(ComponentIndex cmp) override
{
m_particle_emitters[cmp]->reset();
}
2016-02-26 13:49:42 +01:00
2016-05-03 12:50:58 +02:00
ParticleEmitter* getParticleEmitter(ComponentIndex cmp) override
{
return m_particle_emitters[cmp];
}
void updateEmitter(ComponentIndex cmp, float time_delta) override
{
m_particle_emitters[cmp]->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
bool ownComponentType(uint32 type) const override
2015-07-21 20:10:50 +02:00
{
return type == RENDERABLE_HASH || type == POINT_LIGHT_HASH ||
type == GLOBAL_LIGHT_HASH || type == CAMERA_HASH ||
type == TERRAIN_HASH;
2015-07-21 20:10:50 +02:00
}
2015-07-19 18:37:31 +02:00
ComponentIndex getComponent(Entity entity, uint32 type) override
{
if (type == RENDERABLE_HASH)
{
if (entity >= m_renderables.size()) return INVALID_COMPONENT;
return m_renderables[entity].entity != INVALID_ENTITY ? entity : INVALID_COMPONENT;
}
if (type == POINT_LIGHT_HASH)
{
for (auto& i : m_point_lights)
{
if (i.m_entity == entity) return i.m_uid;
}
return INVALID_COMPONENT;
}
if (type == GLOBAL_LIGHT_HASH)
{
for (auto& i : m_global_lights)
{
if (i.m_entity == entity) return i.m_uid;
}
return INVALID_COMPONENT;
}
if (type == CAMERA_HASH)
{
for (int i = 0; i < m_cameras.size(); ++i)
{
2016-04-17 21:47:54 +02:00
if (!m_cameras[i].is_free && m_cameras[i].entity == entity) return i;
}
return INVALID_COMPONENT;
}
if (type == TERRAIN_HASH)
{
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i] && m_terrains[i]->getEntity() == entity) return i;
}
return INVALID_COMPONENT;
}
return INVALID_COMPONENT;
}
IPlugin& getPlugin() const override { return m_renderer; }
2015-01-04 15:05:20 +01:00
Int2 getParticleEmitterSpawnCount(ComponentIndex cmp) override
{
Int2 ret;
ret.x = m_particle_emitters[cmp]->m_spawn_count.from;
ret.y = m_particle_emitters[cmp]->m_spawn_count.to;
return ret;
}
void setParticleEmitterSpawnCount(ComponentIndex cmp, const Int2& value) override
{
m_particle_emitters[cmp]->m_spawn_count.from = value.x;
2016-03-06 12:54:29 +01:00
m_particle_emitters[cmp]->m_spawn_count.to = Math::maximum(value.x, value.y);
}
2016-04-17 21:47:54 +02:00
void getRay(ComponentIndex camera_index,
float x,
float y,
Vec3& origin,
Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
Camera& camera = m_cameras[camera_index];
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) * Vec3(0, 0, 1);
return;
}
2015-07-21 20:10:50 +02:00
float nx = 2 * (x / width) - 1;
float ny = 2 * ((height - y) / height) - 1;
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-04-17 21:47:54 +02:00
Frustum getCameraFrustum(ComponentIndex cmp) const override
2015-07-23 23:17:51 +02:00
{
2016-04-17 21:47:54 +02:00
const Camera& camera = m_cameras[cmp];
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-04-17 21:47:54 +02:00
mtx.getZVector(),
mtx.getYVector(),
Math::degreesToRadians(camera.fov),
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
2016-05-02 21:41:18 +02:00
int getBoneAttachmentIdx(ComponentIndex cmp) const
{
for (int i = 0; i < m_bone_attachments.size(); ++i)
{
if (m_bone_attachments[i].entity == cmp) return i;
}
return -1;
}
void updateBoneAttachment(const BoneAttachment& bone_attachment)
{
if (bone_attachment.parent_entity == INVALID_ENTITY) return;
ComponentIndex renderable = getRenderableComponent(bone_attachment.parent_entity);
if (renderable == INVALID_COMPONENT) return;
auto* parent_pose = getPose(renderable);
if (!parent_pose) return;
Matrix parent_entity_mtx = m_universe.getMatrix(bone_attachment.parent_entity);
int idx = bone_attachment.bone_index;
if (idx < 0 || idx > parent_pose->count) return;
Matrix bone_mtx;
parent_pose->rotations[idx].toMatrix(bone_mtx);
bone_mtx.setTranslation(parent_pose->positions[idx]);
m_universe.setMatrix(bone_attachment.entity, parent_entity_mtx * bone_mtx * bone_attachment.relative_matrix);
}
Entity getBoneAttachmentParent(ComponentIndex cmp) override
{
int idx = getBoneAttachmentIdx(cmp);
return m_bone_attachments[idx].parent_entity;
}
void updateRelativeMatrix(BoneAttachment& attachment)
{
if (attachment.parent_entity == INVALID_ENTITY) return;
if (attachment.bone_index < 0) return;
ComponentIndex renderable = getRenderableComponent(attachment.parent_entity);
if (renderable == INVALID_COMPONENT) return;
Pose* pose = getPose(renderable);
if (!pose) return;
ASSERT(pose->is_absolute);
if (attachment.bone_index >= pose->count) return;
Matrix bone_matrix;
pose->rotations[attachment.bone_index].toMatrix(bone_matrix);
bone_matrix.setTranslation(pose->positions[attachment.bone_index]);
Matrix inv_parent_matrix = m_universe.getMatrix(attachment.parent_entity) * bone_matrix;
inv_parent_matrix.inverse();
Matrix child_matrix = m_universe.getMatrix(attachment.entity);
attachment.relative_matrix = inv_parent_matrix * child_matrix;
}
Vec3 getBoneAttachmentPosition(ComponentIndex cmp) override
{
int idx = getBoneAttachmentIdx(cmp);
if (idx < 0) return {0, 0, 0};
return m_bone_attachments[idx].relative_matrix.getTranslation();
}
void setBoneAttachmentPosition(ComponentIndex cmp, const Vec3& pos) override
{
int idx = getBoneAttachmentIdx(cmp);
if (idx < 0) return;
return m_bone_attachments[idx].relative_matrix.setTranslation(pos);
}
2016-05-02 21:41:18 +02:00
int getBoneAttachmentBone(ComponentIndex cmp) override
{
int idx = getBoneAttachmentIdx(cmp);
if (idx < 0) return -1;
return m_bone_attachments[idx].bone_index;
}
void setBoneAttachmentBone(ComponentIndex cmp, int value) override
{
int idx = getBoneAttachmentIdx(cmp);
if (idx < 0) return;
m_bone_attachments[idx].bone_index = value;
updateRelativeMatrix(m_bone_attachments[idx]);
}
void setBoneAttachmentParent(ComponentIndex cmp, Entity entity) override
{
int idx = getBoneAttachmentIdx(cmp);
m_bone_attachments[idx].parent_entity = entity;
updateRelativeMatrix(m_bone_attachments[idx]);
}
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
if (m_is_game_running)
{
m_is_updating_attachments = true;
for (auto& bone_attachment : m_bone_attachments)
{
updateBoneAttachment(bone_attachment);
}
m_is_updating_attachments = false;
}
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) continue;
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
void serializeBoneAttachments(OutputBlob& serializer)
{
serializer.write((int32)m_bone_attachments.size());
for (auto& attachment : m_bone_attachments)
{
serializer.write(attachment.bone_index);
serializer.write(attachment.entity);
serializer.write(attachment.parent_entity);
}
}
2015-07-21 20:10:50 +02:00
void serializeCameras(OutputBlob& serializer)
{
serializer.write((int32)m_cameras.size());
2015-07-21 20:10:50 +02:00
for (int i = 0, c = m_cameras.size(); i < c; ++i)
{
Camera& camera = m_cameras[i];
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.is_free);
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)
{
serializer.write((int32)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
}
serializer.write(m_point_light_last_uid);
serializer.write((int32)m_global_lights.size());
2015-07-21 20:10:50 +02:00
for (int i = 0, c = m_global_lights.size(); i < c; ++i)
{
serializer.write(m_global_lights[i]);
2015-07-21 20:10:50 +02:00
}
serializer.write((int32)m_global_light_last_uid);
serializer.write((int32)m_active_global_light_uid);
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 serializeRenderables(OutputBlob& serializer)
{
serializer.write((int32)m_renderables.size());
for (auto& r : m_renderables)
2015-07-21 20:10:50 +02:00
{
serializer.write(r.entity);
if(r.entity != INVALID_ENTITY)
2015-12-10 17:09:52 +01:00
{
serializer.write(r.layer_mask);
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)
{
serializer.write((int32)m_terrains.size());
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i])
2014-06-16 21:18:15 +02:00
{
2015-07-21 20:10:50 +02:00
serializer.write(true);
m_terrains[i]->serialize(serializer);
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
serializer.write(false);
2014-06-16 21:18:15 +02:00
}
2015-07-21 20:10:50 +02:00
}
}
2014-06-16 21:18:15 +02:00
2016-05-02 21:41:18 +02:00
void deserializeBoneAttachments(InputBlob& serializer, int version)
{
if (version <= (int)RenderSceneVersion::BONE_ATTACHMENTS) return;
int32 count;
serializer.read(count);
m_bone_attachments.resize(count);
for (int i = 0; i < count; ++i)
{
serializer.read(m_bone_attachments[i].bone_index);
serializer.read(m_bone_attachments[i].entity);
serializer.read(m_bone_attachments[i].parent_entity);
updateRelativeMatrix(m_bone_attachments[i]);
m_universe.addComponent(
m_bone_attachments[i].entity, BONE_ATTACHMENT_HASH, this, m_bone_attachments[i].entity);
}
}
void deserializeParticleEmitters(InputBlob& serializer, int version)
{
int count;
serializer.read(count);
m_particle_emitters.resize(count);
for(int i = 0; i < count; ++i)
{
bool is_emitter;
serializer.read(is_emitter);
ParticleEmitter* emitter = nullptr;
if (is_emitter)
{
emitter = LUMIX_NEW(m_allocator, ParticleEmitter)(
INVALID_ENTITY, m_universe, m_allocator);
emitter->deserialize(serializer,
m_engine.getResourceManager(),
version > (int)RenderSceneVersion::PARTICLE_EMITTERS_SPAWN_COUNT);
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_HASH, this, i);
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::AlphaModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_FADE_HASH, this, i);
}
else if (module->getType() == ParticleEmitter::ForceModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_FORCE_HASH, this, i);
}
else if (module->getType() == ParticleEmitter::SpawnShapeModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_SPAWN_SHAPE_HASH, this, i);
}
else if (module->getType() == ParticleEmitter::AttractorModule::s_type)
2015-12-17 13:58:40 +01:00
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_ATTRACTOR_HASH, this, i);
}
else if (module->getType() == ParticleEmitter::LinearMovementModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH, this, i);
}
2015-12-16 21:26:19 +01:00
else if (module->getType() == ParticleEmitter::PlaneModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_PLANE_HASH, this, i);
}
else if (module->getType() == ParticleEmitter::RandomRotationModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_RANDOM_ROTATION_HASH, this, i);
}
2015-11-18 20:18:48 +01:00
else if (module->getType() == ParticleEmitter::SizeModule::s_type)
{
m_universe.addComponent(
emitter->m_entity, PARTICLE_EMITTER_SIZE_HASH, this, i);
}
}
}
m_particle_emitters[i] = emitter;
}
}
void serializeParticleEmitters(OutputBlob& serializer)
{
serializer.write(m_particle_emitters.size());
for (auto* emitter : m_particle_emitters)
{
if (emitter)
{
serializer.write(true);
emitter->serialize(serializer);
}
else
{
serializer.write(false);
}
}
}
void serialize(OutputBlob& serializer) override
2015-07-21 20:10:50 +02:00
{
serializeCameras(serializer);
serializeRenderables(serializer);
serializeLights(serializer);
serializeTerrains(serializer);
serializeParticleEmitters(serializer);
2016-05-02 21:41:18 +02:00
serializeBoneAttachments(serializer);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-02-15 15:50:24 +01:00
void deserializeRenderParams(InputBlob& serializer)
{
2016-02-26 13:49:42 +01:00
int dummy;
serializer.read(dummy);
2016-02-15 15:50:24 +01:00
int count;
serializer.read(count);
2016-02-26 13:49:42 +01:00
char tmp[32];
bool any = false;
2016-02-15 15:50:24 +01:00
for(int i = 0; i < count; ++i)
{
2016-02-26 13:49:42 +01:00
any = true;
serializer.readString(tmp, lengthOf(tmp));
float value;
serializer.read(value);
2016-02-15 15:50:24 +01:00
}
serializer.read(count);
for(int i = 0; i < count; ++i)
{
2016-02-26 13:49:42 +01:00
any = true;
serializer.readString(tmp, lengthOf(tmp));
Vec4 value;
serializer.read(value);
}
if(any)
{
g_log_warning.log("Renderer") << "Render params are deprecated";
2016-02-15 15:50:24 +01:00
}
}
2016-02-26 13:49:42 +01:00
2016-04-17 21:47:54 +02:00
void deserializeCameras(InputBlob& serializer, RenderSceneVersion version)
2015-07-21 20:10:50 +02:00
{
int32 size;
2015-07-21 20:10:50 +02:00
serializer.read(size);
m_cameras.resize(size);
for (int i = 0; i < size; ++i)
{
Camera& camera = m_cameras[i];
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);
if (version <= RenderSceneVersion::ORTHO_CAMERA)
{
camera.is_ortho = false;
camera.ortho_size = 10;
}
else
{
serializer.read(camera.ortho_size);
}
serializer.read(camera.is_free);
serializer.read(camera.near);
serializer.readString(camera.slot, sizeof(camera.slot));
2015-07-21 20:10:50 +02:00
2016-04-17 21:47:54 +02:00
if (!camera.is_free)
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
m_universe.addComponent(m_cameras[i].entity, CAMERA_HASH, this, i);
2015-07-21 20:10:50 +02:00
}
}
}
2014-06-16 21:18:15 +02:00
void deserializeRenderables(InputBlob& serializer, RenderSceneVersion version)
2015-07-21 20:10:50 +02:00
{
int32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
2015-09-26 15:12:28 +02:00
for (int i = 0; i < m_renderables.size(); ++i)
2015-07-21 20:10:50 +02:00
{
if (m_renderables[i].entity != INVALID_ENTITY)
{
setModel(i, nullptr);
}
2015-07-21 20:10:50 +02:00
}
m_culling_system->clear();
m_renderables.clear();
m_renderables.reserve(size);
for (int i = 0; i < size; ++i)
{
2016-01-14 16:22:25 +01:00
auto& r = m_renderables.emplace();
serializer.read(r.entity);
ASSERT(r.entity == i || r.entity == INVALID_ENTITY);
r.model = nullptr;
r.pose = nullptr;
r.custom_meshes = false;
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
{
serializer.read(r.layer_mask);
r.matrix = m_universe.getMatrix(r.entity);
2015-07-23 23:17:51 +02:00
2015-12-10 17:09:52 +01:00
uint32 path;
serializer.read(path);
2015-07-23 23:17:51 +02:00
if (path != 0)
{
auto* model = static_cast<Model*>(m_engine.getResourceManager()
.get(ResourceManager::MODEL)
->load(Path(path)));
setModel(r.entity, model);
}
if (version > RenderSceneVersion::RENDERABLE_MATERIALS)
2015-12-10 17:09:52 +01:00
{
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.readString(path, lengthOf(path));
Material* material = static_cast<Material*>(
m_engine.getResourceManager().get(ResourceManager::MATERIAL)->load(Path(path)));
r.meshes[j].material = material;
}
}
2015-12-10 17:09:52 +01:00
}
m_universe.addComponent(r.entity, RENDERABLE_HASH, this, r.entity);
2015-12-10 17:09:52 +01:00
}
2015-07-21 20:10:50 +02:00
}
}
2015-02-05 22:57:55 +01:00
void deserializeLights(InputBlob& serializer, RenderSceneVersion version)
2015-07-21 20:10:50 +02:00
{
int32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
2016-01-26 10:27:31 +01:00
m_point_lights_map.clear();
2015-07-21 20:10:50 +02:00
m_point_lights.resize(size);
m_light_influenced_geometry.clear();
for (int i = 0; i < size; ++i)
{
m_light_influenced_geometry.push(Array<int>(m_allocator));
PointLight& light = m_point_lights[i];
2016-02-10 12:09:09 +01:00
if (version > RenderSceneVersion::SPECULAR_INTENSITY)
{
serializer.read(light);
}
else
{
serializer.read(light.m_diffuse_color);
2016-02-10 12:09:09 +01:00
serializer.read(light.m_specular_color);
serializer.read(light.m_diffuse_intensity);
serializer.read(light.m_entity);
2016-02-10 12:09:09 +01:00
serializer.read(light.m_uid);
serializer.read(light.m_fov);
2016-02-10 12:09:09 +01:00
serializer.read(light.m_attenuation_param);
serializer.read(light.m_range);
serializer.read(light.m_cast_shadows);
2016-02-10 12:09:09 +01:00
uint8 padding;
for(int j = 0; j < 3; ++j) serializer.read(padding);
light.m_specular_intensity = 1;
}
2016-01-26 16:49:47 +01:00
m_point_lights_map.insert(light.m_uid, i);
m_universe.addComponent(light.m_entity, POINT_LIGHT_HASH, this, light.m_uid);
2015-07-21 20:10:50 +02:00
}
serializer.read(m_point_light_last_uid);
serializer.read(size);
m_global_lights.resize(size);
for (int i = 0; i < size; ++i)
{
GlobalLight& light = m_global_lights[i];
2016-01-28 21:44:35 +01:00
light.m_specular.set(0, 0, 0);
2016-02-10 12:09:09 +01:00
if (version > RenderSceneVersion::SPECULAR_INTENSITY)
{
serializer.read(light);
}
2016-01-28 21:44:35 +01:00
else
{
serializer.read(light.m_uid);
2016-02-10 12:09:09 +01:00
serializer.read(light.m_diffuse_color);
serializer.read(light.m_specular);
serializer.read(light.m_diffuse_intensity);
2016-01-28 21:44:35 +01:00
serializer.read(light.m_ambient_color);
serializer.read(light.m_ambient_intensity);
serializer.read(light.m_fog_color);
serializer.read(light.m_fog_density);
serializer.read(light.m_fog_bottom);
serializer.read(light.m_fog_height);
serializer.read(light.m_entity);
serializer.read(light.m_cascades);
2016-02-10 12:09:09 +01:00
light.m_specular_intensity = 1;
2016-01-28 21:44:35 +01:00
}
m_universe.addComponent(light.m_entity, GLOBAL_LIGHT_HASH, this, light.m_uid);
2015-07-21 20:10:50 +02:00
}
serializer.read(m_global_light_last_uid);
serializer.read(m_active_global_light_uid);
}
2014-06-16 21:18:15 +02:00
2016-03-25 19:53:41 +01:00
void deserializeTerrains(InputBlob& serializer, RenderSceneVersion version)
2015-07-21 20:10:50 +02:00
{
int32 size = 0;
2015-07-21 20:10:50 +02:00
serializer.read(size);
2015-09-26 13:51:55 +02:00
int old_size = m_terrains.size();
2015-07-21 20:10:50 +02:00
for (int i = size; i < m_terrains.size(); ++i)
{
LUMIX_DELETE(m_allocator, m_terrains[i]);
2015-07-25 19:33:19 +02:00
m_terrains[i] = nullptr;
2015-07-21 20:10:50 +02:00
}
m_terrains.resize(size);
2015-09-26 13:51:55 +02:00
for (int i = old_size; i < size; ++i)
{
m_terrains[i] = nullptr;
}
2015-07-21 20:10:50 +02:00
for (int i = 0; i < size; ++i)
{
bool exists;
serializer.read(exists);
if (exists)
{
2015-09-26 13:51:55 +02:00
if (!m_terrains[i])
{
m_terrains[i] = LUMIX_NEW(m_allocator, Terrain)(
2015-09-26 13:51:55 +02:00
m_renderer, INVALID_ENTITY, *this, m_allocator);
}
2015-07-21 20:10:50 +02:00
Terrain* terrain = m_terrains[i];
2016-03-25 19:53:41 +01:00
terrain->deserialize(serializer, m_universe, *this, i, (int)version);
2015-07-21 20:10:50 +02:00
}
else
{
2015-07-25 19:33:19 +02:00
m_terrains[i] = nullptr;
2015-07-21 20:10:50 +02:00
}
}
}
2014-06-16 21:18:15 +02:00
int getVersion() const override
{
return (int)RenderSceneVersion::LATEST;
}
void deserialize(InputBlob& serializer, int version) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
deserializeCameras(serializer, (RenderSceneVersion)version);
deserializeRenderables(serializer, (RenderSceneVersion)version);
deserializeLights(serializer, (RenderSceneVersion)version);
2016-03-25 19:53:41 +01:00
deserializeTerrains(serializer, (RenderSceneVersion)version);
if (version >= 0) deserializeParticleEmitters(serializer, version);
2016-02-26 13:49:42 +01:00
if (version >= (int)RenderSceneVersion::RENDER_PARAMS &&
version < (int)RenderSceneVersion::RENDER_PARAMS_REMOVED)
{
deserializeRenderParams(serializer);
}
2016-05-02 21:41:18 +02:00
deserializeBoneAttachments(serializer, version);
}
void destroyBoneAttachment(ComponentIndex component)
{
int idx = getBoneAttachmentIdx(component);
Entity entity = m_bone_attachments[idx].entity;
m_bone_attachments.eraseFast(idx);
m_universe.destroyComponent(entity, BONE_ATTACHMENT_HASH, 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
2015-07-24 08:42:35 +02:00
void destroyRenderable(ComponentIndex component)
2015-07-21 20:10:50 +02:00
{
2015-07-24 22:38:11 +02:00
m_renderable_destroyed.invoke(component);
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_light_influenced_geometry.size(); ++i)
{
Array<int>& influenced_geometry = m_light_influenced_geometry[i];
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);
Entity entity = m_renderables[component].entity;
LUMIX_DELETE(m_allocator, m_renderables[component].pose);
m_renderables[component].pose = nullptr;
m_renderables[component].entity = INVALID_ENTITY;
2015-07-24 22:38:11 +02:00
m_universe.destroyComponent(entity, RENDERABLE_HASH, this, component);
2015-07-21 20:10:50 +02:00
}
2014-08-17 17:55:34 +02:00
void destroyGlobalLight(ComponentIndex component)
2015-07-21 20:10:50 +02:00
{
Entity entity = m_global_lights[getGlobalLightIndex(component)].m_entity;
2015-07-23 23:17:51 +02:00
m_universe.destroyComponent(entity, GLOBAL_LIGHT_HASH, this, component);
2015-07-23 23:17:51 +02:00
if (component == m_active_global_light_uid)
2015-07-21 20:10:50 +02:00
{
m_active_global_light_uid = -1;
2015-07-21 20:10:50 +02:00
}
m_global_lights.eraseFast(getGlobalLightIndex(component));
}
void destroyPointLight(ComponentIndex component)
{
int index = getPointLightIndex(component);
Entity entity = m_point_lights[getPointLightIndex(component)].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);
m_universe.destroyComponent(entity, POINT_LIGHT_HASH, this, component);
}
void destroyCamera(ComponentIndex component)
{
2016-04-17 21:47:54 +02:00
Entity entity = m_cameras[component].entity;
m_cameras[component].is_free = true;
m_universe.destroyComponent(entity, CAMERA_HASH, this, component);
}
void destroyTerrain(ComponentIndex component)
{
Entity entity = m_terrains[component]->getEntity();
LUMIX_DELETE(m_allocator, m_terrains[component]);
m_terrains[component] = nullptr;
m_universe.destroyComponent(entity, TERRAIN_HASH, this, component);
}
void destroyParticleEmitter(ComponentIndex component)
{
Entity entity = m_particle_emitters[component]->m_entity;
LUMIX_DELETE(m_allocator, m_particle_emitters[component]);
m_particle_emitters[component] = nullptr;
m_universe.destroyComponent(entity, PARTICLE_EMITTER_HASH, this, component);
}
void destroyParticleEmitterFade(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::AlphaModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_FADE_HASH, this, component);
break;
}
}
}
void destroyParticleEmitterForce(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
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::ForceModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_FORCE_HASH, this, component);
break;
}
}
}
2015-12-17 13:58:40 +01:00
void destroyParticleEmitterAttractor(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for(auto* module : emitter->m_modules)
{
if(module->getType() == ParticleEmitter::AttractorModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_ATTRACTOR_HASH, this, component);
break;
}
}
}
void destroyParticleEmitterSize(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
2015-11-18 20:18:48 +01:00
{
if (module->getType() == ParticleEmitter::SizeModule::s_type)
2015-11-18 20:18:48 +01:00
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_SIZE_HASH, this, component);
break;
2015-11-18 20:18:48 +01:00
}
}
}
float getParticleEmitterPlaneBounce(ComponentIndex cmp) override
{
auto* emitter = m_particle_emitters[cmp];
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;
}
void setParticleEmitterPlaneBounce(ComponentIndex cmp, float value) override
{
auto* emitter = m_particle_emitters[cmp];
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)
{
static_cast<ParticleEmitter::PlaneModule*>(module)->m_bounce = value;
break;
}
}
}
2015-12-17 13:58:40 +01:00
float getParticleEmitterAttractorForce(ComponentIndex cmp) override
{
auto* emitter = m_particle_emitters[cmp];
for(auto* module : emitter->m_modules)
{
if(module->getType() == ParticleEmitter::AttractorModule::s_type)
{
return static_cast<ParticleEmitter::AttractorModule*>(module)->m_force;
}
}
return 0;
}
void setParticleEmitterAttractorForce(ComponentIndex cmp, float value) override
{
auto* emitter = m_particle_emitters[cmp];
for(auto* module : emitter->m_modules)
{
if(module->getType() == ParticleEmitter::AttractorModule::s_type)
{
static_cast<ParticleEmitter::AttractorModule*>(module)->m_force = value;
break;
}
}
}
2015-12-16 21:26:19 +01:00
void destroyParticleEmitterPlane(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::PlaneModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(
emitter->m_entity, PARTICLE_EMITTER_PLANE_HASH, this, component);
break;
}
}
}
void destroyParticleEmitterLinearMovement(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::LinearMovementModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(
emitter->m_entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH, this, component);
break;
}
}
}
void destroyParticleEmitterSpawnShape(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::SpawnShapeModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(
emitter->m_entity, PARTICLE_EMITTER_SPAWN_SHAPE_HASH, this, component);
break;
}
}
}
void destroyParticleEmitterRandomRotation(ComponentIndex component)
{
auto* emitter = m_particle_emitters[component];
for (auto* module : emitter->m_modules)
{
if (module->getType() == ParticleEmitter::RandomRotationModule::s_type)
{
LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
m_universe.destroyComponent(
emitter->m_entity, PARTICLE_EMITTER_RANDOM_ROTATION_HASH, this, component);
break;
}
}
2015-07-21 20:10:50 +02:00
}
2014-08-17 17:55:34 +02:00
2015-07-21 20:10:50 +02:00
void destroyComponent(ComponentIndex component, uint32 type) override;
void setParticleEmitterAlpha(ComponentIndex 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
}
void setParticleEmitterAcceleration(ComponentIndex 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;
}
Vec3 getParticleEmitterAcceleration(ComponentIndex cmp) override
{
2015-12-17 21:38:23 +01:00
auto* module = getEmitterModule<ParticleEmitter::ForceModule>(cmp);
return module ? module->m_acceleration : Vec3();
}
2015-12-07 00:55:32 +01:00
int getParticleEmitterSizeCount(ComponentIndex 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
}
2015-12-07 00:55:32 +01:00
const Vec2* getParticleEmitterSize(ComponentIndex cmp) override
{
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
2015-12-07 00:55:32 +01:00
void setParticleEmitterSize(ComponentIndex 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>
T* getEmitterModule(ComponentIndex cmp) const
{
auto& modules = m_particle_emitters[cmp]->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;
}
int getParticleEmitterAlphaCount(ComponentIndex cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::AlphaModule>(cmp);
return module ? module->m_values.size() : 0;
}
const Vec2* getParticleEmitterAlpha(ComponentIndex 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
}
Vec2 getParticleEmitterLinearMovementX(ComponentIndex 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);
}
void setParticleEmitterLinearMovementX(ComponentIndex 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();
}
}
Vec2 getParticleEmitterLinearMovementY(ComponentIndex 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);
}
void setParticleEmitterLinearMovementY(ComponentIndex 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();
}
}
Vec2 getParticleEmitterLinearMovementZ(ComponentIndex 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);
}
void setParticleEmitterLinearMovementZ(ComponentIndex 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();
}
}
Vec2 getParticleEmitterInitialLife(ComponentIndex cmp) override
2015-10-30 21:11:11 +01:00
{
return m_particle_emitters[cmp]->m_initial_life;
}
Vec2 getParticleEmitterSpawnPeriod(ComponentIndex cmp) override
2015-10-30 21:11:11 +01:00
{
return m_particle_emitters[cmp]->m_spawn_period;
}
void setParticleEmitterInitialLife(ComponentIndex cmp, const Vec2& value) override
2015-10-30 21:11:11 +01:00
{
m_particle_emitters[cmp]->m_initial_life = value;
2016-01-12 22:59:11 +01:00
m_particle_emitters[cmp]->m_initial_life.checkZero();
2015-10-30 21:11:11 +01:00
}
void setParticleEmitterInitialSize(ComponentIndex cmp, const Vec2& value) override
2015-11-01 20:56:29 +01:00
{
m_particle_emitters[cmp]->m_initial_size = value;
2016-01-12 22:59:11 +01:00
m_particle_emitters[cmp]->m_initial_size.checkZero();
2015-11-01 20:56:29 +01:00
}
Vec2 getParticleEmitterInitialSize(ComponentIndex cmp) override
2015-11-01 20:56:29 +01:00
{
return m_particle_emitters[cmp]->m_initial_size;
}
void setParticleEmitterSpawnPeriod(ComponentIndex cmp, const Vec2& value) override
2015-10-30 21:11:11 +01:00
{
m_particle_emitters[cmp]->m_spawn_period = value;
m_particle_emitters[cmp]->m_spawn_period.from =
2016-03-06 12:54:29 +01:00
Math::maximum(0.01f, m_particle_emitters[cmp]->m_spawn_period.from);
2016-01-12 22:59:11 +01:00
m_particle_emitters[cmp]->m_spawn_period.checkZero();
2015-10-30 21:11:11 +01:00
}
ComponentIndex createCamera(Entity entity)
2015-07-21 20:10:50 +02:00
{
2016-01-14 16:22:25 +01:00
Camera& camera = m_cameras.emplace();
2016-04-17 21:47:54 +02:00
camera.is_free = false;
camera.is_ortho = false;
camera.ortho_size = 10;
camera.entity = entity;
camera.fov = 60;
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';
m_universe.addComponent(entity, CAMERA_HASH, this, m_cameras.size() - 1);
return m_cameras.size() - 1;
}
ComponentIndex createTerrain(Entity entity)
{
Terrain* terrain = LUMIX_NEW(m_allocator, Terrain)(
m_renderer, entity, *this, m_allocator);
m_terrains.push(terrain);
m_universe.addComponent(entity, TERRAIN_HASH, this, m_terrains.size() - 1);
return m_terrains.size() - 1;
}
ComponentIndex createComponent(uint32 type, Entity entity) override;
ComponentIndex createParticleEmitterRandomRotation(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::RandomRotationModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_RANDOM_ROTATION_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
2015-12-16 21:26:19 +01:00
ComponentIndex createParticleEmitterPlane(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::PlaneModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_PLANE_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
ComponentIndex createParticleEmitterLinearMovement(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::LinearMovementModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
ComponentIndex createParticleEmitterSpawnShape(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SpawnShapeModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SPAWN_SHAPE_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
ComponentIndex createParticleEmitterFade(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::AlphaModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_FADE_HASH, this, i);
return i;
}
}
2015-07-24 22:38:11 +02:00
return INVALID_COMPONENT;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2014-10-31 22:53:37 +01:00
ComponentIndex createParticleEmitterForce(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::ForceModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_FORCE_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
2015-12-17 13:58:40 +01:00
ComponentIndex createParticleEmitterAttractor(Entity entity)
{
for(int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if(emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::AttractorModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_ATTRACTOR_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
2015-11-18 20:18:48 +01:00
ComponentIndex createParticleEmitterSize(Entity entity)
{
for (int i = 0; i < m_particle_emitters.size(); ++i)
{
auto* emitter = m_particle_emitters[i];
if (emitter->m_entity == entity)
{
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SizeModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SIZE_HASH, this, i);
return i;
}
}
return INVALID_COMPONENT;
}
2015-10-30 21:11:11 +01:00
ComponentIndex createParticleEmitter(Entity entity)
{
int index = -1;
for (int i = 0, c = m_particle_emitters.size(); i < c; ++i)
{
if (!m_particle_emitters[i])
{
index = i;
break;
}
}
if (index == -1)
{
index = m_particle_emitters.size();
m_particle_emitters.push(nullptr);
}
m_particle_emitters[index] =
LUMIX_NEW(m_allocator, ParticleEmitter)(entity, m_universe, m_allocator);
m_universe.addComponent(entity, PARTICLE_EMITTER_HASH, this, index);
return index;
}
Renderable* getRenderables() override
{
return &m_renderables[0];
}
Renderable* getRenderable(ComponentIndex cmp) override
{
return &m_renderables[cmp];
}
ComponentIndex getRenderableComponent(Entity entity) override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
ComponentIndex cmp = (ComponentIndex)entity;
2016-01-15 23:21:37 +01:00
if (cmp >= m_renderables.size()) return INVALID_COMPONENT;
if (m_renderables[cmp].entity == INVALID_ENTITY) 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
Frustum getPointLightFrustum(ComponentIndex index) const
{
const PointLight& light = m_point_lights[index];
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
{
2015-12-10 17:09:52 +01:00
ComponentIndex cmp = (ComponentIndex)entity;
if (cmp < m_renderables.size() && m_renderables[cmp].entity != INVALID_ENTITY &&
m_renderables[cmp].model && m_renderables[cmp].model->isReady())
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
Renderable& r = m_renderables[cmp];
r.matrix = m_universe.getMatrix(entity);
2015-12-10 17:09:52 +01:00
m_culling_system->updateBoundingPosition(m_universe.getPosition(entity), cmp);
if (r.model && r.model->isReady())
{
float radius = m_universe.getScale(entity) * r.model->getBoundingRadius();
m_culling_system->updateBoundingRadius(radius, cmp);
}
2015-12-10 17:09:52 +01:00
if(m_is_forward_rendered)
2015-07-21 20:10:50 +02:00
{
2015-12-10 23:33:21 +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
{
2015-12-10 17:09:52 +01:00
for (int j = 0, c2 = m_light_influenced_geometry[light_idx].size(); j < c2; ++j)
{
if(m_light_influenced_geometry[light_idx][j] == cmp)
{
m_light_influenced_geometry[light_idx].eraseFast(j);
break;
}
}
Vec3 pos = m_universe.getPosition(r.entity);
2015-12-10 17:09:52 +01:00
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
}
}
}
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
{
2015-07-21 20:10:50 +02:00
detectLightInfluencedGeometry(i);
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-03-11 23:26:38 +01:00
Entity getTerrainEntity(ComponentIndex cmp) override
{
return m_terrains[cmp]->getEntity();
}
Vec2 getTerrainResolution(ComponentIndex cmp) override
{
return Vec2((float)m_terrains[cmp]->getWidth(), (float)m_terrains[cmp]->getHeight());
}
ComponentIndex getFirstTerrain() override
{
if (m_terrains.empty()) return INVALID_COMPONENT;
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i]) return i;
}
return INVALID_COMPONENT;
}
ComponentIndex getNextTerrain(ComponentIndex cmp) override
{
for (int i = cmp + 1; i < m_terrains.size(); ++i)
{
if (m_terrains[i]) return i;
}
return INVALID_COMPONENT;
}
ComponentIndex getTerrainComponent(Entity entity) override
2015-09-12 12:44:04 +02:00
{
for (int i = 0; i < m_terrains.size(); ++i)
{
auto* terrain = m_terrains[i];
if (terrain && terrain->getEntity() == entity)
{
return i;
}
}
return -1;
}
2016-05-03 12:50:58 +02:00
Vec3 getTerrainNormalAt(ComponentIndex cmp, float x, float z) override
{
return m_terrains[cmp]->getNormal(x, z);
}
float getTerrainHeightAt(ComponentIndex cmp, float x, float z) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_terrains[cmp]->getHeight(x, z);
2015-07-21 20:10:50 +02:00
}
2014-09-06 22:21:09 +02:00
2016-03-13 01:27:25 +01:00
AABB getTerrainAABB(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2016-03-13 01:27:25 +01:00
return m_terrains[cmp]->getAABB();
}
Vec2 getTerrainSize(ComponentIndex cmp) override
{
return m_terrains[cmp]->getSize();
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-01-06 14:18:59 +01:00
void setTerrainMaterialPath(ComponentIndex cmp, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2016-02-12 23:49:56 +01:00
if (path.isValid())
{
Material* material = static_cast<Material*>(
m_engine.getResourceManager().get(ResourceManager::MATERIAL)->load(path));
m_terrains[cmp]->setMaterial(material);
}
else
{
m_terrains[cmp]->setMaterial(nullptr);
}
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
Material* getTerrainMaterial(ComponentIndex cmp) override
{
return m_terrains[cmp]->getMaterial();
}
2016-01-06 14:18:59 +01:00
Path getTerrainMaterialPath(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
if (m_terrains[cmp]->getMaterial())
2015-07-21 20:10:50 +02:00
{
2016-01-06 14:18:59 +01:00
return m_terrains[cmp]->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
void setTerrainXZScale(ComponentIndex cmp, float scale) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->setXZScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-12-10 17:09:52 +01:00
float getTerrainXZScale(ComponentIndex cmp) override { return m_terrains[cmp]->getXZScale(); }
2014-07-09 21:33:35 +02:00
void setTerrainYScale(ComponentIndex cmp, float scale) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->setYScale(scale);
2015-07-21 20:10:50 +02:00
}
2014-07-09 21:33:35 +02:00
2016-05-03 12:50:58 +02:00
float getTerrainYScale(ComponentIndex cmp) override { return m_terrains[cmp]->getYScale(); }
2014-06-16 21:18:15 +02:00
Pose* getPose(ComponentIndex cmp) override { return m_renderables[cmp].pose; }
2014-06-20 22:54:32 +02:00
Entity getRenderableEntity(ComponentIndex cmp) override { return m_renderables[cmp].entity; }
2015-07-24 22:38:11 +02:00
Model* getRenderableModel(ComponentIndex cmp) override { return m_renderables[cmp].model; }
2014-10-31 21:25:03 +01:00
void showRenderable(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
if (!m_renderables[cmp].model || !m_renderables[cmp].model->isReady()) return;
Sphere sphere(m_universe.getPosition(m_renderables[cmp].entity),
m_renderables[cmp].model->getBoundingRadius());
2015-12-10 17:09:52 +01:00
m_culling_system->addStatic(cmp, sphere);
2015-07-21 20:10:50 +02:00
}
2014-10-31 21:25:03 +01:00
void hideRenderable(ComponentIndex 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
2016-01-06 14:18:59 +01:00
Path getRenderablePath(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2016-01-06 14:18:59 +01:00
return m_renderables[cmp].model ? m_renderables[cmp].model->getPath() : Path("");
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-12-10 17:09:52 +01:00
void setRenderableLayer(ComponentIndex cmp, const int32& layer) override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
m_culling_system->setLayerMask(cmp, (int64)1 << (int64)layer);
2015-07-21 20:10:50 +02:00
}
2015-07-24 08:42:35 +02:00
int getRenderableMaterialsCount(ComponentIndex cmp) override
{
return m_renderables[cmp].model ? m_renderables[cmp].mesh_count : 0;
}
2016-01-06 14:18:59 +01:00
void setRenderablePath(ComponentIndex cmp, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
Renderable& r = m_renderables[cmp];
2015-07-21 20:10:50 +02:00
2016-01-06 14:18:59 +01:00
auto* manager = m_engine.getResourceManager().get(ResourceManager::MODEL);
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
2015-12-10 17:09:52 +01:00
void forceGrassUpdate(ComponentIndex cmp) override { m_terrains[cmp]->forceGrassUpdate(); }
void getTerrainInfos(Array<const TerrainInfo*>& infos,
const Vec3& camera_pos,
LIFOAllocator& frame_allocator) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
infos.reserve(m_terrains.size());
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i])
2014-08-09 14:37:23 +02:00
{
2015-07-21 20:10:50 +02:00
m_terrains[i]->getInfos(infos, camera_pos, frame_allocator);
2014-08-09 14:37:23 +02:00
}
2015-07-21 20:10:50 +02:00
}
}
2014-08-09 14:37:23 +02:00
void getGrassInfos(const Frustum& frustum,
Array<GrassInfo>& infos,
ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
if (!m_is_grass_enabled) return;
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i])
{
2015-10-22 23:07:56 +02:00
m_terrains[i]->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);
ComponentIndex camera_cmp = scene->getCameraInSlot(slot);
2016-04-17 21:47:54 +02:00
Vec3 origin = scene->m_universe.getPosition(scene->m_cameras[camera_cmp].entity);
Quat rot = scene->m_universe.getRotation(scene->m_cameras[camera_cmp].entity);
2016-03-13 01:27:25 +01:00
RayCastModelHit hit = scene->castRay(origin, rot * Vec3(0, 0, -1), INVALID_COMPONENT);
LuaWrapper::pushLua(L, hit.m_is_hit);
LuaWrapper::pushLua(L, hit.m_is_hit ? hit.m_origin + hit.m_dir * hit.m_t : Vec3(0, 0, 0));
return 2;
}
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_setRenderablePath(IScene* scene, int component, const char* path)
{
RenderScene* render_scene = (RenderScene*)scene;
render_scene->setRenderablePath(component, Path(path));
}
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();
auto file1 = fs.open(fs.getDefaultDevice(), Lumix::Path(path), Lumix::FS::Mode::OPEN_AND_READ);
auto file2 = fs.open(fs.getDefaultDevice(), Lumix::Path(path_preimage), Lumix::FS::Mode::OPEN_AND_READ);
if (!file1)
{
if (file2) fs.close(*file2);
Lumix::g_log_error.log("render_test") << "Failed to open " << path;
return 0xffffFFFF;
}
else if (!file2)
{
fs.close(*file1);
Lumix::g_log_error.log("render_test") << "Failed to open " << path_preimage;
return 0xffffFFFF;
}
return Lumix::Texture::compareTGA(scene->m_allocator, file1, file2, min_diff);
}
static void LUA_makeScreenshot(RenderSceneImpl* scene, const char* path)
{
scene->m_renderer.makeScreenshot(Path(path));
}
2016-03-04 22:49:53 +01:00
static void LUA_setRenderableMaterial(RenderScene* scene,
ComponentIndex cmp,
int index,
const char* path)
{
scene->setRenderableMaterial(cmp, index, Path(path));
}
bool isGrassEnabled() const override
{
return m_is_grass_enabled;
}
2016-02-24 20:46:14 +01:00
2016-03-25 19:53:41 +01:00
float getGrassDistance(ComponentIndex cmp, int index) override
{
2016-03-25 19:53:41 +01:00
return m_terrains[cmp]->getGrassTypeDistance(index);
}
2016-03-25 19:53:41 +01:00
void setGrassDistance(ComponentIndex cmp, int index, float value) override
{
2016-03-25 19:53:41 +01:00
m_terrains[cmp]->setGrassTypeDistance(index, value);
}
2016-02-24 20:46:14 +01:00
void enableGrass(bool enabled) override
{
m_is_grass_enabled = enabled;
}
void
2015-07-24 08:42:35 +02:00
setGrassDensity(ComponentIndex cmp, int index, int density) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->setGrassTypeDensity(index, density);
2015-07-21 20:10:50 +02:00
}
int getGrassDensity(ComponentIndex cmp, int index) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_terrains[cmp]->getGrassTypeDensity(index);
2015-07-21 20:10:50 +02:00
}
void
2015-07-24 08:42:35 +02:00
setGrassGround(ComponentIndex cmp, int index, int ground) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->setGrassTypeGround(index, ground);
2015-07-21 20:10:50 +02:00
}
int getGrassGround(ComponentIndex cmp, int index) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_terrains[cmp]->getGrassTypeGround(index);
2015-07-21 20:10:50 +02:00
}
2016-01-06 14:18:59 +01:00
void setGrassPath(ComponentIndex cmp, int index, const Path& path) override
2015-07-21 20:10:50 +02:00
{
2016-01-06 14:18:59 +01:00
m_terrains[cmp]->setGrassTypePath(index, path);
2015-07-21 20:10:50 +02:00
}
2016-01-06 14:18:59 +01:00
Path getGrassPath(ComponentIndex cmp, int index) override
2015-07-21 20:10:50 +02:00
{
2016-01-06 14:18:59 +01:00
return m_terrains[cmp]->getGrassTypePath(index);
2015-07-21 20:10:50 +02:00
}
int getGrassCount(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_terrains[cmp]->getGrassTypeCount();
2015-07-21 20:10:50 +02:00
}
2015-07-21 20:10:50 +02:00
void addGrass(ComponentIndex cmp, int index) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->addGrassType(index);
2015-07-21 20:10:50 +02:00
}
2014-10-15 22:16:03 +02:00
void removeGrass(ComponentIndex cmp, int index) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_terrains[cmp]->removeGrassType(index);
2015-07-21 20:10:50 +02:00
}
ComponentIndex getFirstRenderable() override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
return getNextRenderable(-1);
2015-07-21 20:10:50 +02:00
}
2014-10-28 23:17:18 +01:00
2014-08-20 22:45:47 +02:00
ComponentIndex getNextRenderable(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-12-10 17:09:52 +01:00
for(int i = cmp + 1; i < m_renderables.size(); ++i)
2015-07-21 20:10:50 +02:00
{
if(m_renderables[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
2016-02-16 10:32:31 +01:00
const CullingSystem::Results* cull(const Frustum& frustum)
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2015-12-10 17:09:52 +01:00
if (m_renderables.empty()) return nullptr;
2014-11-16 19:31:51 +01:00
2016-02-16 10:32:31 +01:00
m_culling_system->cullToFrustumAsync(frustum, ~0UL);
2015-07-21 20:10:50 +02:00
return &m_culling_system->getResult();
}
2014-11-16 19:31:51 +01:00
2015-07-21 20:10:50 +02:00
void runJobs(Array<MTJD::Job*>& jobs, MTJD::Group& sync_point)
{
PROFILE_FUNCTION();
for (int i = 0; i < jobs.size(); ++i)
{
m_engine.getMTJDManager().schedule(jobs[i]);
}
if (!jobs.empty())
{
sync_point.sync();
}
}
2016-03-04 00:39:17 +01:00
void fillTemporaryInfos(const CullingSystem::Results& results,
const Frustum& frustum,
const Vec3& lod_ref_point)
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
m_jobs.clear();
while (m_temporary_infos.size() < results.size())
{
m_temporary_infos.emplace(m_allocator);
}
while (m_temporary_infos.size() > results.size())
{
m_temporary_infos.pop();
}
for (int subresult_index = 0; subresult_index < results.size(); ++subresult_index)
2015-07-21 20:10:50 +02:00
{
Array<RenderableMesh>& subinfos = m_temporary_infos[subresult_index];
2015-07-21 20:10:50 +02:00
subinfos.clear();
if (results[subresult_index].empty()) continue;
MTJD::Job* job = MTJD::makeJob(m_engine.getMTJDManager(),
2016-03-04 00:39:17 +01:00
[&subinfos, this, &results, subresult_index, &frustum, lod_ref_point]()
2015-07-21 20:10:50 +02:00
{
PROFILE_BLOCK("Temporary Info Job");
2015-12-14 01:39:37 +01:00
PROFILE_INT("Renderable count", results[subresult_index].size());
2016-03-04 00:39:17 +01:00
Vec3 ref_point = lod_ref_point;
const int* LUMIX_RESTRICT raw_subresults = &results[subresult_index][0];
Renderable* LUMIX_RESTRICT renderables = &m_renderables[0];
for (int i = 0, c = results[subresult_index].size(); i < c; ++i)
2015-07-21 20:10:50 +02:00
{
Renderable* LUMIX_RESTRICT renderable = &renderables[raw_subresults[i]];
Model* LUMIX_RESTRICT model = renderable->model;
2015-07-21 20:10:50 +02:00
float squared_distance =
2016-03-04 00:39:17 +01:00
(renderable->matrix.getTranslation() - ref_point).squaredLength();
LODMeshIndices lod = model->getLODMeshIndices(squared_distance);
2016-01-29 01:18:41 +01:00
for (int j = lod.from, c = lod.to; j <= c; ++j)
2014-06-16 21:18:15 +02:00
{
2016-01-14 16:22:25 +01:00
auto& info = subinfos.emplace();
info.renderable = raw_subresults[i];
info.mesh = &renderable->meshes[j];
}
2015-07-21 20:10:50 +02:00
}
},
m_allocator);
job->addDependency(&m_sync_point);
m_jobs.push(job);
}
runJobs(m_jobs, m_sync_point);
}
2014-11-16 19:31:51 +01:00
2015-02-14 00:13:34 +01:00
int getClosestPointLights(const Vec3& reference_pos,
2015-09-02 11:14:42 +02:00
ComponentIndex* lights,
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;
lights[light_count] = light.m_uid;
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;
ComponentIndex tmp2 = lights[i];
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;
lights[max_lights - 1] = light.m_uid;
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;
ComponentIndex tmp2 = lights[i];
lights[i] = lights[i - 1];
lights[i - 1] = tmp2;
}
}
}
return light_count;
2015-09-02 11:14:42 +02:00
}
void getPointLights(const Frustum& frustum,
2015-07-24 08:42:35 +02:00
Array<ComponentIndex>& 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];
2015-07-24 08:42:35 +02:00
if (frustum.isSphereInside(m_universe.getPosition(light.m_entity),
light.m_range))
2015-02-14 00:13:34 +01:00
{
2015-07-24 08:42:35 +02:00
lights.push(light.m_uid);
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(ComponentIndex camera) const override
2015-07-24 08:42:35 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].entity;
2015-07-24 08:42:35 +02:00
}
void setLightCastShadows(ComponentIndex cmp,
2015-09-02 11:14:42 +02:00
bool cast_shadows) override
{
m_point_lights[getPointLightIndex(cmp)].m_cast_shadows = cast_shadows;
}
2015-12-10 17:09:52 +01:00
bool getLightCastShadows(ComponentIndex cmp) override
2015-09-02 11:14:42 +02:00
{
return m_point_lights[getPointLightIndex(cmp)].m_cast_shadows;
}
2015-12-10 17:09:52 +01:00
void getPointLightInfluencedGeometry(ComponentIndex light_cmp,
const Frustum& frustum,
2016-02-16 10:32:31 +01:00
Array<RenderableMesh>& infos) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2015-02-14 00:13:34 +01:00
2015-07-24 08:42:35 +02:00
int light_index = getPointLightIndex(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)
{
ComponentIndex renderable_cmp = m_light_influenced_geometry[light_index][j];
Renderable& renderable = m_renderables[renderable_cmp];
const Sphere& sphere = m_culling_system->getSphere(renderable_cmp);
2016-02-16 10:32:31 +01:00
if (frustum.isSphereInside(sphere.m_position, sphere.m_radius))
2015-12-10 17:09:52 +01:00
{
for (int k = 0, kc = renderable.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 = &renderable.model->getMesh(k);
info.renderable = renderable_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(ComponentIndex light_cmp,
2016-02-16 10:32:31 +01:00
Array<RenderableMesh>& infos) override
2015-09-02 11:14:42 +02:00
{
PROFILE_FUNCTION();
int light_index = getPointLightIndex(light_cmp);
auto& geoms = m_light_influenced_geometry[light_index];
for (int j = 0, cj = geoms.size(); j < cj; ++j)
{
2015-12-10 17:09:52 +01:00
const Renderable& renderable = m_renderables[geoms[j]];
for (int k = 0, kc = renderable.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 = &renderable.model->getMesh(k);
info.renderable = geoms[j];
2015-09-02 11:14:42 +02:00
}
}
}
2016-02-16 10:32:31 +01:00
void getRenderableEntities(const Frustum& frustum, Array<Entity>& entities) override
{
PROFILE_FUNCTION();
2016-02-16 10:32:31 +01:00
const CullingSystem::Results* results = cull(frustum);
if (!results) return;
for (auto& subresults : *results)
{
2015-12-10 17:09:52 +01:00
for (ComponentIndex renderable_cmp : subresults)
{
entities.push(m_renderables[renderable_cmp].entity);
}
}
}
2016-03-04 00:39:17 +01:00
Array<Array<RenderableMesh>>& getRenderableInfos(const Frustum& frustum,
const Vec3& lod_ref_point) override
2015-07-21 20:10:50 +02:00
{
PROFILE_FUNCTION();
2014-11-16 19:31:51 +01:00
2016-02-16 11:55:55 +01:00
for(auto& i : m_temporary_infos) i.clear();
const CullingSystem::Results* results = cull(frustum);
if (!results) return m_temporary_infos;
2014-11-16 19:31:51 +01:00
2016-03-04 00:39:17 +01:00
fillTemporaryInfos(*results, frustum, lod_ref_point);
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
void setCameraSlot(ComponentIndex camera, const char* slot) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
copyString(m_cameras[camera].slot, lengthOf(m_cameras[camera].slot), slot);
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
ComponentIndex getCameraComponent(Entity entity)
{
for (int i = 0; i < m_cameras.size(); ++i)
{
2016-04-17 21:47:54 +02:00
if (m_cameras[i].entity == entity) return i;
}
return INVALID_COMPONENT;
}
const char* getCameraSlot(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].slot;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
float getCameraFOV(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].fov;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void setCameraFOV(ComponentIndex camera, float fov) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
m_cameras[camera].fov = fov;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void setCameraNearPlane(ComponentIndex camera,
2015-07-23 23:17:51 +02:00
float near_plane) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
m_cameras[camera].near = near_plane;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
float getCameraNearPlane(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].near;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
void setCameraFarPlane(ComponentIndex camera,
2015-07-23 23:17:51 +02:00
float far_plane) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
m_cameras[camera].far = far_plane;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
float getCameraFarPlane(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].far;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-04-17 21:47:54 +02:00
float getCameraScreenWidth(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].screen_width;
2015-07-21 20:10:50 +02:00
}
2014-11-30 15:10:13 +01:00
2014-06-16 21:18:15 +02:00
2016-04-17 21:47:54 +02:00
float getCameraScreenHeight(ComponentIndex camera) override
{
return m_cameras[camera].screen_height;
}
Matrix getCameraProjection(ComponentIndex cmp) override
{
Camera& camera = m_cameras[cmp];
Matrix mtx;
float ratio = camera.screen_height > 0 ? camera.screen_width / camera.screen_height : 1;
if (camera.is_ortho)
{
mtx.setOrtho(-camera.ortho_size * ratio,
camera.ortho_size * ratio,
camera.ortho_size,
-camera.ortho_size,
camera.near,
camera.far);
}
else
{
mtx.setPerspective(Math::degreesToRadians(camera.fov), ratio, camera.near, camera.far);
}
return mtx;
}
void setCameraScreenSize(ComponentIndex camera, int w, int h) override
{
m_cameras[camera].screen_width = (float)w;
m_cameras[camera].screen_height = (float)h;
m_cameras[camera].aspect = w / (float)h;
}
float getCameraOrthoSize(ComponentIndex camera) override { return m_cameras[camera].ortho_size; }
void setCameraOrthoSize(ComponentIndex camera, float value) override { m_cameras[camera].ortho_size = value; }
bool isCameraOrtho(ComponentIndex camera) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
return m_cameras[camera].is_ortho;
2015-07-21 20:10:50 +02:00
}
2014-11-30 15:10:13 +01:00
2014-06-16 21:18:15 +02:00
2016-04-17 21:47:54 +02:00
void setCameraOrtho(ComponentIndex camera, bool is_ortho) override
2015-07-21 20:10:50 +02:00
{
2016-04-17 21:47:54 +02:00
m_cameras[camera].is_ortho = is_ortho;
2015-07-21 20:10:50 +02:00
}
2014-11-30 15:10:13 +01:00
2014-06-16 21:18:15 +02:00
2016-03-10 19:32:48 +01:00
const Array<DebugTriangle>& getDebugTriangles() const override
{
return m_debug_triangles;
}
const Array<DebugLine>& getDebugLines() const override
2015-07-21 20:10:50 +02:00
{
return m_debug_lines;
}
2014-11-30 15:10:13 +01:00
2014-12-14 22:14:21 +01:00
const Array<DebugPoint>& getDebugPoints() const override
{
return m_debug_points;
}
void addDebugSphere(const Vec3& center,
float radius,
uint32 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
void addDebugHalfSphere(const Vec3& center, float radius, bool top, uint32 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,
uint32 color,
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,
uint32 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);
}
}
void addDebugCylinder(const Vec3& position,
2015-07-21 20:10:50 +02:00
const Vec3& up,
float radius,
uint32 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,
uint32 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,
uint32 color,
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, c, b, color, life);
b.x = min.x;
b.z = max.z;
addDebugTriangle(a, b, c, color, life);
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,
uint32 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
void addDebugFrustum(const Frustum& frustum, uint32 color, float life) override
2015-07-21 20:10:50 +02:00
{
2016-03-11 17:25:14 +01:00
addDebugFrustum(frustum.position,
frustum.direction,
frustum.up,
frustum.fov,
frustum.ratio,
frustum.near_distance,
frustum.far_distance,
2015-07-21 20:10:50 +02:00
color,
life);
}
2014-12-17 21:33:27 +01:00
2014-12-14 21:42:30 +01:00
void addDebugFrustum(const Vec3& position,
2015-07-21 20:10:50 +02:00
const Vec3& direction,
const Vec3& up,
float fov,
float ratio,
float near_distance,
float far_distance,
uint32 color,
2015-07-21 20:10:50 +02:00
float life) override
{
Vec3 points[8];
Vec3 near_center = position + direction * near_distance;
Vec3 far_center = position + direction * far_distance;
Vec3 right = crossProduct(direction, up);
float scale = (float)tan(Math::degreesToRadians(fov * 0.5f));
Vec3 up_near = up * near_distance * scale;
Vec3 right_near = right * (near_distance * scale * ratio);
2015-07-21 20:10:50 +02:00
points[0] = near_center + up_near + right_near;
points[1] = near_center + up_near - right_near;
points[2] = near_center - up_near - right_near;
points[3] = near_center - up_near + right_near;
Vec3 up_far = up * far_distance * scale;
Vec3 right_far = right * (far_distance * scale * ratio);
2015-07-21 20:10:50 +02:00
points[4] = far_center + up_far + right_far;
points[5] = far_center + up_far - right_far;
points[6] = far_center - up_far - right_far;
points[7] = far_center - up_far + right_far;
addDebugLine(points[0], points[1], color, life);
addDebugLine(points[1], points[2], color, life);
addDebugLine(points[2], points[3], color, life);
addDebugLine(points[3], points[0], color, life);
addDebugLine(points[4], points[5], color, life);
addDebugLine(points[5], points[6], color, life);
addDebugLine(points[6], points[7], color, life);
addDebugLine(points[7], points[4], color, life);
addDebugLine(points[0], points[4], color, life);
addDebugLine(points[1], points[5], color, life);
addDebugLine(points[2], points[6], color, life);
addDebugLine(points[3], points[7], color, life);
}
2014-12-14 21:42:30 +01:00
void addDebugCircle(const Vec3& center,
2015-10-24 12:25:06 +02:00
const Vec3& up,
float radius,
uint32 color,
2015-10-24 12:25:06 +02:00
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;
addDebugLine(center + x_vec * x + z_vec * z,
2015-10-24 12:25:06 +02:00
center + x_vec * prevx + z_vec * prevz,
color,
life);
2015-07-21 20:10:50 +02:00
prevx = x;
prevz = z;
}
}
void addDebugCross(const Vec3& center,
2015-07-21 20:10:50 +02:00
float size,
uint32 color,
2015-07-21 20:10:50 +02:00
float life) override
{
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);
}
2014-07-20 18:14:37 +02:00
void addDebugPoint(const Vec3& pos, uint32 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;
}
static uint32 ARGBToABGR(uint32 color)
2015-07-21 20:10:50 +02:00
{
2015-10-24 12:25:06 +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
void addDebugLine(const Vec3& from, const Vec3& to, uint32 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(ComponentIndex terrain,
2015-10-24 12:25:06 +02:00
const Vec3& origin,
const Vec3& dir) override
2015-07-21 20:10:50 +02:00
{
RayCastModelHit hit;
hit.m_is_hit = false;
2015-07-23 23:17:51 +02:00
if (m_terrains[terrain])
2015-07-21 20:10:50 +02:00
{
2015-07-23 23:17:51 +02:00
hit = m_terrains[terrain]->castRay(origin, dir);
2015-07-25 00:09:11 +02:00
hit.m_component = terrain;
hit.m_component_type = TERRAIN_HASH;
hit.m_entity = m_terrains[terrain]->getEntity();
2015-07-21 20:10:50 +02:00
}
return hit;
}
RayCastModelHit castRay(const Vec3& origin,
2015-12-10 17:09:52 +01:00
const Vec3& dir,
ComponentIndex ignored_renderable) 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;
2015-08-02 10:39:50 +02:00
Universe& universe = getUniverse();
2015-07-21 20:10:50 +02:00
for (int i = 0; i < m_renderables.size(); ++i)
{
2015-12-10 17:09:52 +01:00
auto& r = m_renderables[i];
if (ignored_renderable != i && r.model)
2015-07-21 20:10:50 +02:00
{
const Vec3& pos = r.matrix.getTranslation();
float radius = r.model->getBoundingRadius();
float scale = universe.getScale(r.entity);
2015-07-21 20:10:50 +02:00
Vec3 intersection;
if (dotProduct(pos - origin, pos - origin) < radius * radius ||
2015-12-10 17:09:52 +01:00
Math::getRaySphereIntersection(origin, dir, pos, radius * scale, intersection))
2015-07-21 20:10:50 +02:00
{
RayCastModelHit new_hit = r.model->castRay(origin, dir, r.matrix);
2015-12-10 17:09:52 +01:00
if (new_hit.m_is_hit && (!hit.m_is_hit || new_hit.m_t < hit.m_t))
2014-07-20 18:14:37 +02:00
{
2015-07-25 00:09:11 +02:00
new_hit.m_component = i;
new_hit.m_entity = r.entity;
2015-07-25 00:09:11 +02:00
new_hit.m_component_type = RENDERABLE_HASH;
2015-07-21 20:10:50 +02:00
hit = new_hit;
hit.m_is_hit = true;
2014-07-20 18:14:37 +02:00
}
}
2014-06-16 21:18:15 +02:00
}
2015-07-21 20:10:50 +02:00
}
for (int i = 0; i < m_terrains.size(); ++i)
{
if (m_terrains[i])
2015-02-18 00:34:22 +01:00
{
2015-12-10 17:09:52 +01:00
RayCastModelHit terrain_hit = m_terrains[i]->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
{
2015-07-25 00:09:11 +02:00
terrain_hit.m_component = i;
terrain_hit.m_component_type = TERRAIN_HASH;
terrain_hit.m_entity = m_terrains[i]->getEntity();
2015-07-21 20:10:50 +02:00
hit = terrain_hit;
2015-02-18 00:34:22 +01:00
}
}
2015-07-21 20:10:50 +02:00
}
return hit;
}
2015-02-18 00:34:22 +01:00
2015-07-25 00:09:11 +02:00
int getPointLightIndex(ComponentIndex cmp) const
2015-07-21 20:10:50 +02:00
{
2016-01-26 10:27:31 +01:00
return m_point_lights_map[cmp];
2015-07-21 20:10:50 +02:00
}
2015-02-18 00:34:22 +01:00
Vec4 getShadowmapCascades(ComponentIndex cmp) override
{
return m_global_lights[getGlobalLightIndex(cmp)].m_cascades;
}
void setShadowmapCascades(ComponentIndex 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);
m_global_lights[getGlobalLightIndex(cmp)].m_cascades = valid_value;
}
2015-07-21 20:10:50 +02:00
int getGlobalLightIndex(int uid) const
{
for (int i = 0; i < m_global_lights.size(); ++i)
{
if (m_global_lights[i].m_uid == uid)
2015-02-18 00:34:22 +01:00
{
2015-07-21 20:10:50 +02:00
return i;
2015-02-18 00:34:22 +01:00
}
2015-07-21 20:10:50 +02:00
}
return -1;
}
2015-02-18 00:34:22 +01:00
void setFogDensity(ComponentIndex cmp, float density) override
2015-07-21 20:10:50 +02:00
{
m_global_lights[getGlobalLightIndex(cmp)].m_fog_density = density;
}
2014-09-25 22:39:33 +02:00
void setFogColor(ComponentIndex cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
m_global_lights[getGlobalLightIndex(cmp)].m_fog_color = color;
}
2015-02-05 22:57:55 +01:00
float getFogDensity(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_fog_density;
}
2015-02-05 22:57:55 +01:00
float getFogBottom(ComponentIndex cmp) override
2015-10-17 00:18:47 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_fog_bottom;
}
void setFogBottom(ComponentIndex cmp, float bottom) override
2015-10-17 00:18:47 +02:00
{
m_global_lights[getGlobalLightIndex(cmp)].m_fog_bottom = bottom;
}
float getFogHeight(ComponentIndex cmp) override
2015-10-17 00:18:47 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_fog_height;
}
void setFogHeight(ComponentIndex cmp, float height) override
2015-10-17 00:18:47 +02:00
{
m_global_lights[getGlobalLightIndex(cmp)].m_fog_height = height;
}
Vec3 getFogColor(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_fog_color;
}
2015-02-05 22:57:55 +01:00
float getLightAttenuation(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-09-09 02:18:09 +02:00
return m_point_lights[getPointLightIndex(cmp)].m_attenuation_param;
2015-07-21 20:10:50 +02:00
}
void setLightAttenuation(ComponentIndex cmp,
2015-09-09 02:18:09 +02:00
float attenuation) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
int index = getPointLightIndex(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
}
float getLightRange(ComponentIndex cmp) override
2015-09-04 14:00:28 +02:00
{
return m_point_lights[getPointLightIndex(cmp)].m_range;
2015-07-21 20:10:50 +02:00
}
void setLightRange(ComponentIndex cmp, float value) override
2015-09-09 02:18:09 +02:00
{
m_point_lights[getPointLightIndex(cmp)].m_range = value;
}
2016-01-28 21:44:35 +01:00
void setPointLightIntensity(ComponentIndex cmp, float intensity) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
m_point_lights[getPointLightIndex(cmp)].m_diffuse_intensity = intensity;
2015-07-21 20:10:50 +02:00
}
2016-01-28 21:44:35 +01:00
void setGlobalLightIntensity(ComponentIndex cmp, float intensity) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
m_global_lights[getGlobalLightIndex(cmp)].m_diffuse_intensity = intensity;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-01-28 21:44:35 +01:00
void setPointLightColor(ComponentIndex cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
2015-09-02 11:14:42 +02:00
m_point_lights[getPointLightIndex(cmp)].m_diffuse_color = color;
2015-07-21 20:10:50 +02:00
}
2016-01-28 21:44:35 +01:00
void setGlobalLightColor(ComponentIndex cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
m_global_lights[getGlobalLightIndex(cmp)].m_diffuse_color = color;
2015-07-21 20:10:50 +02:00
}
2016-01-28 21:44:35 +01:00
void setGlobalLightSpecular(ComponentIndex cmp, const Vec3& color) override
{
m_global_lights[getGlobalLightIndex(cmp)].m_specular = color;
}
2016-02-10 12:09:09 +01:00
void setGlobalLightSpecularIntensity(ComponentIndex cmp, float intensity) override
{
m_global_lights[getGlobalLightIndex(cmp)].m_specular_intensity = intensity;
}
2016-01-28 21:44:35 +01:00
void setLightAmbientIntensity(ComponentIndex cmp, float intensity) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
m_global_lights[getGlobalLightIndex(cmp)].m_ambient_intensity = intensity;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
2016-02-10 12:09:09 +01:00
void setLightAmbientColor(ComponentIndex cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
m_global_lights[getGlobalLightIndex(cmp)].m_ambient_color = color;
}
float getPointLightIntensity(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
return m_point_lights[getPointLightIndex(cmp)].m_diffuse_intensity;
2015-07-21 20:10:50 +02:00
}
2015-02-05 22:57:55 +01:00
float getGlobalLightIntensity(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
return m_global_lights[getGlobalLightIndex(cmp)].m_diffuse_intensity;
2015-07-21 20:10:50 +02:00
}
Vec3 getPointLightColor(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-09-02 11:14:42 +02:00
return m_point_lights[getPointLightIndex(cmp)].m_diffuse_color;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2016-02-10 12:09:09 +01:00
void setPointLightSpecularColor(ComponentIndex cmp, const Vec3& color) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_point_lights[getPointLightIndex(cmp)].m_specular_color = color;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
Vec3 getPointLightSpecularColor(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_point_lights[getPointLightIndex(cmp)].m_specular_color;
2015-07-21 20:10:50 +02:00
}
2014-06-21 19:26:27 +02:00
2016-02-10 12:09:09 +01:00
void setPointLightSpecularIntensity(ComponentIndex cmp, float intensity) override
{
m_point_lights[getPointLightIndex(cmp)].m_specular_intensity = intensity;
}
float getPointLightSpecularIntensity(ComponentIndex cmp) override
{
return m_point_lights[getPointLightIndex(cmp)].m_specular_intensity;
}
Vec3 getGlobalLightColor(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2016-02-10 12:09:09 +01:00
return m_global_lights[getGlobalLightIndex(cmp)].m_diffuse_color;
2015-07-21 20:10:50 +02:00
}
2014-07-05 17:24:12 +02:00
2016-01-28 21:44:35 +01:00
Vec3 getGlobalLightSpecular(ComponentIndex cmp) override
{
return m_global_lights[getGlobalLightIndex(cmp)].m_specular;
}
2016-02-10 12:09:09 +01:00
float getGlobalLightSpecularIntensity(ComponentIndex cmp) override
{
return m_global_lights[getGlobalLightIndex(cmp)].m_specular_intensity;
}
float getLightAmbientIntensity(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_ambient_intensity;
}
Vec3 getLightAmbientColor(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_ambient_color;
}
void setActiveGlobalLight(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-07-23 23:17:51 +02:00
m_active_global_light_uid = cmp;
2015-07-21 20:10:50 +02:00
}
ComponentIndex getActiveGlobalLight() override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_active_global_light_uid;
2015-07-21 20:10:50 +02:00
};
Entity getPointLightEntity(ComponentIndex cmp) const override
2015-07-24 08:42:35 +02:00
{
return m_point_lights[getPointLightIndex(cmp)].m_entity;
}
2016-01-24 17:20:03 +01:00
Entity getGlobalLightEntity(ComponentIndex cmp) const override
2015-07-24 08:42:35 +02:00
{
return m_global_lights[getGlobalLightIndex(cmp)].m_entity;
}
ComponentIndex getCameraInSlot(const char* slot) override
2015-07-21 20:10:50 +02:00
{
for (int i = 0, c = m_cameras.size(); i < c; ++i)
{
2016-04-17 21:47:54 +02:00
if (!m_cameras[i].is_free && compareString(m_cameras[i].slot, slot) == 0)
2014-08-20 22:45:47 +02:00
{
2015-07-24 08:42:35 +02:00
return i;
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-01-10 13:41:12 +01:00
void modelUnloaded(Model*, ComponentIndex component)
{
auto& r = m_renderables[component];
if (!r.custom_meshes)
{
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(Renderable& r, MaterialManager* manager)
{
if (!r.custom_meshes) 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;
r.custom_meshes = false;
r.mesh_count = 0;
}
2015-12-10 17:09:52 +01:00
void modelLoaded(Model* model, ComponentIndex component)
2015-07-21 20:10:50 +02:00
{
auto& rm = m_engine.getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
2015-12-10 17:09:52 +01:00
auto& r = m_renderables[component];
float bounding_radius = r.model->getBoundingRadius();
float scale = m_universe.getScale(r.entity);
Sphere sphere(r.matrix.getTranslation(), bounding_radius * scale);
m_culling_system->addStatic(component, sphere);
m_culling_system->setLayerMask(component, r.layer_mask);
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);
2016-04-19 10:25:24 +02:00
ASSERT(!r.meshes || r.custom_meshes);
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
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_renderables.size(); i < c; ++i)
{
if (m_renderables[i].entity != INVALID_ENTITY && m_renderables[i].model == model)
{
modelUnloaded(model, i);
}
}
}
2015-07-21 20:10:50 +02:00
void modelLoaded(Model* model)
{
2015-12-10 17:09:52 +01:00
for (int i = 0, c = m_renderables.size(); i < c; ++i)
2015-07-21 20:10:50 +02:00
{
if (m_renderables[i].entity != INVALID_ENTITY && m_renderables[i].model == model)
{
2015-07-21 20:10:50 +02:00
modelLoaded(model, i);
}
2015-07-21 20:10:50 +02:00
}
2016-05-02 21:41:18 +02:00
for (auto& attachment : m_bone_attachments)
{
if (m_renderables[attachment.parent_entity].entity != INVALID_ENTITY &&
m_renderables[attachment.parent_entity].model == model)
{
updateRelativeMatrix(attachment);
}
}
2015-07-21 20:10:50 +02:00
}
2015-02-14 00:13:34 +01:00
2015-07-21 20:10:50 +02:00
ModelLoadedCallback* getModelLoadedCallback(Model* model)
{
for (int i = 0; i < m_model_loaded_callbacks.size(); ++i)
{
if (m_model_loaded_callbacks[i]->m_model == model)
2015-02-14 00:13:34 +01:00
{
2015-07-21 20:10:50 +02:00
return m_model_loaded_callbacks[i];
2015-02-14 00:13:34 +01:00
}
2015-07-21 20:10:50 +02:00
}
ModelLoadedCallback* new_callback =
LUMIX_NEW(m_allocator, ModelLoadedCallback)(*this, model);
2015-07-21 20:10:50 +02:00
m_model_loaded_callbacks.push(new_callback);
return new_callback;
}
2015-02-14 00:13:34 +01:00
void allocateCustomMeshes(Renderable& r, int count)
{
if (r.custom_meshes && r.mesh_count == count) return;
auto& rm = r.model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
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
}
if (r.custom_meshes)
{
for (int i = count; i < r.mesh_count; ++i)
{
material_manager->unload(*r.meshes[i].material);
}
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;
r.custom_meshes = true;
}
void setRenderableMaterial(ComponentIndex cmp, int index, const Path& path) override
{
auto& r = m_renderables[cmp];
if (r.meshes && r.mesh_count > index && path == r.meshes[index].material->getPath()) return;
auto& rm = r.model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
2016-02-10 12:09:09 +01:00
2016-03-06 12:54:29 +01:00
int new_count = Math::maximum(int8(index + 1), r.mesh_count);
allocateCustomMeshes(r, new_count);
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 getRenderableMaterial(ComponentIndex cmp, int index) override
{
auto& r = m_renderables[cmp];
if (!r.meshes) return Path("");
2016-01-22 18:02:07 +01:00
return r.meshes[index].material->getPath();
}
2015-12-10 17:09:52 +01:00
void setModel(ComponentIndex component, Model* model)
2015-07-21 20:10:50 +02:00
{
ASSERT(m_renderables[component].entity != INVALID_ENTITY);
2015-12-10 17:09:52 +01:00
Model* old_model = m_renderables[component].model;
bool no_change = model == old_model && old_model;
if (no_change)
2015-07-21 20:10:50 +02:00
{
2015-09-26 15:12:28 +02:00
old_model->getResourceManager().get(ResourceManager::MODEL)->unload(*old_model);
2015-07-21 20:10:50 +02:00
return;
}
if (old_model)
{
auto& rm = old_model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
freeCustomMeshes(m_renderables[component], material_manager);
2015-07-21 20:10:50 +02:00
ModelLoadedCallback* callback = getModelLoadedCallback(old_model);
--callback->m_ref_count;
2015-12-10 23:33:21 +01:00
if (old_model->isReady())
{
m_culling_system->removeStatic(component);
}
2015-09-26 15:12:28 +02:00
old_model->getResourceManager().get(ResourceManager::MODEL)->unload(*old_model);
2015-07-21 20:10:50 +02:00
}
m_renderables[component].model = model;
m_renderables[component].meshes = nullptr;
m_renderables[component].mesh_count = 0;
LUMIX_DELETE(m_allocator, m_renderables[component].pose);
m_renderables[component].pose = nullptr;
2015-07-21 20:10:50 +02:00
if (model)
{
ModelLoadedCallback* callback = getModelLoadedCallback(model);
++callback->m_ref_count;
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
2015-07-21 20:10:50 +02:00
void detectLightInfluencedGeometry(int light_index)
{
if (!m_is_forward_rendered) return;
2016-01-26 15:21:38 +01:00
Frustum frustum = getPointLightFrustum(light_index);
m_culling_system->cullToFrustum(frustum, 0xffffFFFF);
const CullingSystem::Results& results =
m_culling_system->getResult();
Array<int>& influenced_geometry =
m_light_influenced_geometry[light_index];
influenced_geometry.clear();
for (int i = 0; i < results.size(); ++i)
{
const CullingSystem::Subresults& subresult = results[i];
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
}
}
}
2015-12-17 13:58:40 +01:00
int getParticleEmitterAttractorCount(ComponentIndex cmp) override
{
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
}
void addParticleEmitterAttractor(ComponentIndex cmp, int index) override
{
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
}
void removeParticleEmitterAttractor(ComponentIndex cmp, int index) override
{
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
}
Entity getParticleEmitterAttractorEntity(ComponentIndex cmp, int index) override
{
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
}
void setParticleEmitterAttractorEntity(ComponentIndex cmp, int index, Entity entity) override
{
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
}
float getParticleEmitterShapeRadius(ComponentIndex cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SpawnShapeModule>(cmp);
return module ? module->m_radius : 0.0f;
}
void setParticleEmitterShapeRadius(ComponentIndex cmp, float value) override
{
auto* module = getEmitterModule<ParticleEmitter::SpawnShapeModule>(cmp);
if (module) module->m_radius = value;
}
2015-12-16 21:26:19 +01:00
int getParticleEmitterPlaneCount(ComponentIndex cmp) override
{
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
}
void addParticleEmitterPlane(ComponentIndex cmp, int index) override
{
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
}
void removeParticleEmitterPlane(ComponentIndex cmp, int index) override
{
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
}
Entity getParticleEmitterPlaneEntity(ComponentIndex cmp, int index) override
{
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
}
void setParticleEmitterPlaneEntity(ComponentIndex cmp, int index, Entity entity) override
{
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
}
DelegateList<void(ComponentIndex)>& renderableCreated() override
2015-07-24 22:38:11 +02:00
{
return m_renderable_created;
}
DelegateList<void(ComponentIndex)>& renderableDestroyed() override
2015-07-24 22:38:11 +02:00
{
return m_renderable_destroyed;
}
float getLightFOV(ComponentIndex cmp) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
return m_point_lights[getPointLightIndex(cmp)].m_fov;
2015-07-21 20:10:50 +02:00
}
2015-02-14 00:13:34 +01:00
void setLightFOV(ComponentIndex cmp, float fov) override
2015-07-21 20:10:50 +02:00
{
2015-07-24 08:42:35 +02:00
m_point_lights[getPointLightIndex(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
2015-07-25 00:09:11 +02:00
ComponentIndex createGlobalLight(Entity entity)
2015-07-21 20:10:50 +02:00
{
2016-01-14 16:22:25 +01:00
GlobalLight& light = m_global_lights.emplace();
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;
2015-07-21 20:10:50 +02:00
light.m_ambient_color.set(1, 1, 1);
light.m_ambient_intensity = 1;
light.m_fog_color.set(1, 1, 1);
light.m_fog_density = 0;
light.m_uid = ++m_global_light_last_uid;
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;
2016-01-28 21:44:35 +01:00
light.m_specular.set(0, 0, 0);
2016-02-10 12:09:09 +01:00
light.m_specular_intensity = 1;
2015-07-21 20:10:50 +02:00
if (m_global_lights.size() == 1)
{
m_active_global_light_uid = light.m_uid;
}
2015-07-25 00:09:11 +02:00
m_universe.addComponent(entity, GLOBAL_LIGHT_HASH, this, light.m_uid);
return light.m_uid;
2015-07-21 20:10:50 +02:00
}
2014-06-16 21:18:15 +02:00
2015-07-21 20:10:50 +02:00
2015-07-25 00:09:11 +02:00
ComponentIndex 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();
m_light_influenced_geometry.push(Array<int>(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;
2015-07-21 20:10:50 +02:00
light.m_uid = ++m_point_light_last_uid;
light.m_fov = 999;
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-01-26 10:27:31 +01:00
m_point_lights_map.insert(light.m_uid, m_point_lights.size() - 1);
2015-07-21 20:10:50 +02:00
2015-07-25 00:09:11 +02:00
m_universe.addComponent(entity, POINT_LIGHT_HASH, this, light.m_uid);
2015-07-21 20:10:50 +02:00
detectLightInfluencedGeometry(m_point_lights.size() - 1);
2015-07-25 00:09:11 +02:00
return light.m_uid;
2014-06-16 21:18:15 +02:00
}
2016-05-02 21:41:18 +02:00
ComponentIndex createBoneAttachment(Entity entity)
{
BoneAttachment& attachment = m_bone_attachments.emplace();
attachment.entity = entity;
attachment.parent_entity = INVALID_ENTITY;
attachment.bone_index = -1;
m_universe.addComponent(entity, BONE_ATTACHMENT_HASH, this, entity);
return entity;
}
2015-07-25 00:09:11 +02:00
ComponentIndex createRenderable(Entity entity)
2014-06-16 21:18:15 +02:00
{
2015-12-10 17:09:52 +01:00
while(entity >= m_renderables.size())
{
auto& r = m_renderables.emplace();
r.entity = INVALID_ENTITY;
r.model = nullptr;
r.pose = nullptr;
2015-12-10 17:09:52 +01:00
}
auto& r = m_renderables[entity];
r.entity = entity;
r.model = nullptr;
r.layer_mask = 1;
r.meshes = nullptr;
r.pose = nullptr;
r.custom_meshes = false;
r.mesh_count = 0;
r.matrix = m_universe.getMatrix(entity);
m_universe.addComponent(entity, RENDERABLE_HASH, this, entity);
2015-12-10 17:09:52 +01:00
m_renderable_created.invoke(m_renderables.size() - 1);
return entity;
2014-06-16 21:18:15 +02:00
}
2016-01-06 14:18:59 +01:00
void setParticleEmitterMaterialPath(ComponentIndex cmp, const Path& path) override
{
if (!m_particle_emitters[cmp]) return;
auto* manager = m_engine.getResourceManager().get(ResourceManager::MATERIAL);
2016-01-06 14:18:59 +01:00
Material* material = static_cast<Material*>(manager->load(path));
m_particle_emitters[cmp]->setMaterial(material);
}
2016-01-06 14:18:59 +01:00
Path getParticleEmitterMaterialPath(ComponentIndex cmp) override
{
ParticleEmitter* emitter = m_particle_emitters[cmp];
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 Array<ParticleEmitter*>& getParticleEmitters() const override
{
return m_particle_emitters;
}
2015-07-21 20:10:50 +02:00
private:
IAllocator& m_allocator;
Array<ModelLoadedCallback*> m_model_loaded_callbacks;
2015-12-10 17:09:52 +01:00
Array<Renderable> m_renderables;
2015-07-21 20:10:50 +02:00
int m_point_light_last_uid;
Array<PointLight> m_point_lights;
2016-03-06 12:54:29 +01:00
HashMap<ComponentIndex, int> m_point_lights_map;
2015-12-10 17:09:52 +01:00
Array<Array<ComponentIndex>> m_light_influenced_geometry;
2015-07-21 20:10:50 +02:00
int m_active_global_light_uid;
int m_global_light_last_uid;
Array<GlobalLight> m_global_lights;
Array<Camera> m_cameras;
2016-05-02 21:41:18 +02:00
Array<BoneAttachment> m_bone_attachments;
2015-07-21 20:10:50 +02:00
Array<Terrain*> m_terrains;
Universe& m_universe;
Renderer& m_renderer;
Engine& m_engine;
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;
2015-07-21 20:10:50 +02:00
CullingSystem* m_culling_system;
2015-10-30 21:11:11 +01:00
Array<ParticleEmitter*> m_particle_emitters;
Array<Array<RenderableMesh>> m_temporary_infos;
2015-07-21 20:10:50 +02:00
MTJD::Group m_sync_point;
Array<MTJD::Job*> m_jobs;
float m_time;
2016-05-02 21:41:18 +02:00
bool m_is_updating_attachments;
2015-07-21 20:10:50 +02:00
bool m_is_forward_rendered;
bool m_is_grass_enabled;
bool m_is_game_running;
2015-07-24 22:38:11 +02:00
DelegateList<void(ComponentIndex)> m_renderable_created;
DelegateList<void(ComponentIndex)> m_renderable_destroyed;
2015-07-21 20:10:50 +02:00
};
static struct
{
uint32 type;
ComponentIndex(RenderSceneImpl::*creator)(Entity);
void (RenderSceneImpl::*destroyer)(ComponentIndex);
2016-05-02 21:41:18 +02:00
} COMPONENT_INFOS[] = {{RENDERABLE_HASH, &RenderSceneImpl::createRenderable, &RenderSceneImpl::destroyRenderable},
{GLOBAL_LIGHT_HASH, &RenderSceneImpl::createGlobalLight, &RenderSceneImpl::destroyGlobalLight},
{POINT_LIGHT_HASH, &RenderSceneImpl::createPointLight, &RenderSceneImpl::destroyPointLight},
{CAMERA_HASH, &RenderSceneImpl::createCamera, &RenderSceneImpl::destroyCamera},
{TERRAIN_HASH, &RenderSceneImpl::createTerrain, &RenderSceneImpl::destroyTerrain},
2016-05-02 21:41:18 +02:00
{PARTICLE_EMITTER_HASH, &RenderSceneImpl::createParticleEmitter, &RenderSceneImpl::destroyParticleEmitter},
{PARTICLE_EMITTER_FADE_HASH,
&RenderSceneImpl::createParticleEmitterFade,
&RenderSceneImpl::destroyParticleEmitterFade},
2016-05-02 21:41:18 +02:00
{PARTICLE_EMITTER_FORCE_HASH,
&RenderSceneImpl::createParticleEmitterForce,
&RenderSceneImpl::destroyParticleEmitterForce},
2015-12-17 13:58:40 +01:00
{PARTICLE_EMITTER_ATTRACTOR_HASH,
&RenderSceneImpl::createParticleEmitterAttractor,
&RenderSceneImpl::destroyParticleEmitterAttractor},
{PARTICLE_EMITTER_SIZE_HASH,
&RenderSceneImpl::createParticleEmitterSize,
&RenderSceneImpl::destroyParticleEmitterSize},
{PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH,
&RenderSceneImpl::createParticleEmitterLinearMovement,
&RenderSceneImpl::destroyParticleEmitterLinearMovement},
{PARTICLE_EMITTER_SPAWN_SHAPE_HASH,
&RenderSceneImpl::createParticleEmitterSpawnShape,
2016-05-02 21:41:18 +02:00
&RenderSceneImpl::destroyParticleEmitterSpawnShape},
{PARTICLE_EMITTER_RANDOM_ROTATION_HASH,
&RenderSceneImpl::createParticleEmitterRandomRotation,
2015-12-16 21:26:19 +01:00
&RenderSceneImpl::destroyParticleEmitterRandomRotation},
{PARTICLE_EMITTER_PLANE_HASH,
&RenderSceneImpl::createParticleEmitterPlane,
&RenderSceneImpl::destroyParticleEmitterPlane},
2016-05-02 21:41:18 +02:00
{BONE_ATTACHMENT_HASH, &RenderSceneImpl::createBoneAttachment, &RenderSceneImpl::destroyBoneAttachment}
};
2016-05-02 21:41:18 +02:00
ComponentIndex RenderSceneImpl::createComponent(uint32 type, Entity entity)
{
for (auto& i : COMPONENT_INFOS)
{
if (i.type == type)
{
return (this->*i.creator)(entity);
}
}
return INVALID_COMPONENT;
}
void RenderSceneImpl::destroyComponent(ComponentIndex component, uint32 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,
bool is_forward_rendered,
IAllocator& allocator)
{
return LUMIX_NEW(allocator, RenderSceneImpl)(
2015-07-21 20:10:50 +02:00
renderer, engine, universe, is_forward_rendered, allocator);
}
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) \
REGISTER_FUNCTION(getCameraSlot);
REGISTER_FUNCTION(getCameraComponent);
REGISTER_FUNCTION(getRenderableComponent);
2016-05-07 11:49:39 +02:00
REGISTER_FUNCTION(getRenderableModel);
REGISTER_FUNCTION(addDebugCross);
2016-05-07 11:49:39 +02:00
REGISTER_FUNCTION(addDebugLine);
REGISTER_FUNCTION(getTerrainMaterial);
#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) \
REGISTER_FUNCTION(getMaterialTexture);
REGISTER_FUNCTION(setRenderableMaterial);
REGISTER_FUNCTION(setRenderablePath);
REGISTER_FUNCTION(makeScreenshot);
REGISTER_FUNCTION(compareTGA);
LuaWrapper::createSystemFunction(L, "Renderer", "castCameraRay", &RenderSceneImpl::LUA_castCameraRay);
#undef REGISTER_FUNCTION
}
} // namespace Lumix