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