LumixEngine/src/renderer/pipeline.cpp

1983 lines
54 KiB
C++
Raw Normal View History

2015-07-04 15:22:28 +02:00
#include "pipeline.h"
2015-08-17 23:45:26 +02:00
#include "renderer/pipeline.h"
2014-05-20 23:35:09 +02:00
#include "core/array.h"
2014-11-20 23:26:09 +01:00
#include "core/associative_array.h"
2014-05-20 23:35:09 +02:00
#include "core/crc32.h"
2014-10-15 22:16:03 +02:00
#include "core/frustum.h"
2015-05-16 02:24:15 +02:00
#include "core/fs/ifile.h"
2014-05-20 23:35:09 +02:00
#include "core/fs/file_system.h"
#include "core/json_serializer.h"
#include "core/lifo_allocator.h"
2014-06-03 21:46:34 +02:00
#include "core/log.h"
2015-08-11 23:55:58 +02:00
#include "core/lua_wrapper.h"
2014-08-10 23:40:22 +02:00
#include "core/profiler.h"
2014-05-20 23:35:09 +02:00
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
2015-08-12 21:54:47 +02:00
#include "core/static_array.h"
2014-05-20 23:35:09 +02:00
#include "core/string.h"
2015-08-11 23:55:58 +02:00
#include "engine.h"
#include "plugin_manager.h"
2015-08-17 23:45:26 +02:00
#include "renderer/frame_buffer.h"
#include "renderer/material.h"
#include "renderer/model.h"
2015-10-06 17:00:52 +02:00
#include "renderer/pose.h"
2015-08-17 23:45:26 +02:00
#include "renderer/renderer.h"
#include "renderer/shader.h"
#include "renderer/terrain.h"
#include "renderer/texture.h"
#include "renderer/transient_geometry.h"
#include "universe/universe.h"
#include <bgfx/bgfx.h>
2014-05-20 23:35:09 +02:00
2015-07-04 15:22:28 +02:00
namespace Lumix
{
static const float SHADOW_CAM_NEAR = 50.0f;
static const float SHADOW_CAM_FAR = 5000.0f;
2015-07-23 23:17:51 +02:00
2015-10-24 15:27:48 +02:00
2015-07-23 23:17:51 +02:00
class InstanceData
{
public:
2015-09-28 00:51:28 +02:00
static const int MAX_INSTANCE_COUNT = 64;
2015-07-05 15:58:53 +02:00
2015-07-23 23:17:51 +02:00
public:
const bgfx::InstanceDataBuffer* m_buffer;
int m_instance_count;
RenderableMesh m_mesh;
};
2015-07-05 15:58:53 +02:00
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
struct PipelineImpl : public Pipeline
{
PipelineImpl(const Path& path,
ResourceManager& resource_manager,
IAllocator& allocator)
: Pipeline(path, resource_manager, allocator)
, m_allocator(allocator)
, m_framebuffers(allocator)
, m_lua_state(nullptr)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
}
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
Renderer& getRenderer()
{
2015-10-24 15:27:48 +02:00
auto* manager = m_resource_manager.get(ResourceManager::PIPELINE);
return static_cast<PipelineManager*>(manager)->getRenderer();
2015-07-23 23:17:51 +02:00
}
virtual ~PipelineImpl() override
{
if (m_lua_state)
2015-05-16 13:17:20 +02:00
{
2015-07-23 23:17:51 +02:00
lua_close(m_lua_state);
2015-05-16 13:17:20 +02:00
}
2015-07-23 23:17:51 +02:00
ASSERT(isEmpty());
}
2014-05-20 23:35:09 +02:00
2015-10-03 01:14:38 +02:00
virtual void unload(void) override
2015-07-23 23:17:51 +02:00
{
2015-10-03 01:14:38 +02:00
if (!m_lua_state) return;
lua_close(m_lua_state);
m_lua_state = nullptr;
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
void parseRenderbuffers(lua_State* L, FrameBuffer::Declaration& decl)
{
decl.m_renderbuffers_count = 0;
int len = (int)lua_rawlen(L, -1);
for (int i = 0; i < len; ++i)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
if (lua_rawgeti(L, -1, 1 + i) == LUA_TTABLE)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
FrameBuffer::RenderBuffer& buf =
decl.m_renderbuffers[decl.m_renderbuffers_count];
buf.parse(L);
++decl.m_renderbuffers_count;
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
lua_pop(L, 1);
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-05-16 13:17:20 +02:00
2015-07-23 23:17:51 +02:00
void parseFramebuffers(lua_State* L)
{
if (lua_getglobal(L, "framebuffers") == LUA_TTABLE)
2014-05-20 23:35:09 +02:00
{
2015-05-16 13:17:20 +02:00
int len = (int)lua_rawlen(L, -1);
2015-07-23 23:17:51 +02:00
m_framebuffers.resize(len);
2015-05-16 13:17:20 +02:00
for (int i = 0; i < len; ++i)
2014-05-20 23:35:09 +02:00
{
2015-05-16 13:17:20 +02:00
if (lua_rawgeti(L, -1, 1 + i) == LUA_TTABLE)
{
2015-07-23 23:17:51 +02:00
FrameBuffer::Declaration& decl = m_framebuffers[i];
if (lua_getfield(L, -1, "name") == LUA_TSTRING)
{
copyString(decl.m_name,
sizeof(decl.m_name),
lua_tostring(L, -1));
}
lua_pop(L, 1);
if (lua_getfield(L, -1, "width") == LUA_TNUMBER)
2015-05-16 13:17:20 +02:00
{
2015-07-23 23:17:51 +02:00
decl.m_width = (int)lua_tointeger(L, -1);
}
lua_pop(L, 1);
if (lua_getfield(L, -1, "height") == LUA_TNUMBER)
{
decl.m_height = (int)lua_tointeger(L, -1);
}
lua_pop(L, 1);
if (lua_getfield(L, -1, "renderbuffers") == LUA_TTABLE)
{
parseRenderbuffers(L, decl);
2015-05-16 13:17:20 +02:00
}
lua_pop(L, 1);
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
lua_pop(L, 1);
2014-05-20 23:35:09 +02:00
}
}
2015-07-23 23:17:51 +02:00
lua_pop(L, 1);
}
2015-05-16 13:17:20 +02:00
2015-07-23 23:17:51 +02:00
void registerCFunction(const char* name, lua_CFunction function)
{
lua_pushcfunction(m_lua_state, function);
lua_setglobal(m_lua_state, name);
}
2015-05-16 13:17:20 +02:00
2015-07-23 23:17:51 +02:00
void registerCFunctions();
2015-05-16 13:17:20 +02:00
2015-10-03 01:14:38 +02:00
virtual bool load(FS::IFile& file) override
2015-07-23 23:17:51 +02:00
{
if (m_lua_state)
{
lua_close(m_lua_state);
m_lua_state = nullptr;
}
2015-10-03 01:14:38 +02:00
m_lua_state = luaL_newstate();
luaL_openlibs(m_lua_state);
bool errors =
luaL_loadbuffer(
m_lua_state, (const char*)file.getBuffer(), file.size(), getPath().c_str()) !=
LUA_OK;
2015-10-03 01:14:38 +02:00
errors = errors || lua_pcall(m_lua_state, 0, LUA_MULTRET, 0) != LUA_OK;
if (errors)
2015-07-23 23:17:51 +02:00
{
2015-10-03 01:14:38 +02:00
g_log_error.log("lua") << getPath().c_str() << ": " << lua_tostring(m_lua_state, -1);
lua_pop(m_lua_state, 1);
return false;
2014-05-20 23:35:09 +02:00
}
2015-10-03 01:14:38 +02:00
parseFramebuffers(m_lua_state);
registerCFunctions();
return true;
2015-07-23 23:17:51 +02:00
}
lua_State* m_lua_state;
IAllocator& m_allocator;
Array<FrameBuffer::Declaration> m_framebuffers;
};
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
struct PipelineInstanceImpl : public PipelineInstance
{
PipelineInstanceImpl(Pipeline& pipeline, IAllocator& allocator)
: m_source(static_cast<PipelineImpl&>(pipeline))
, m_custom_commands_handlers(allocator)
, m_allocator(allocator)
, m_tmp_terrains(allocator)
, m_tmp_grasses(allocator)
, m_tmp_meshes(allocator)
, m_framebuffers(allocator)
, m_uniforms(allocator)
, m_renderer(static_cast<PipelineImpl&>(pipeline).getRenderer())
, m_default_framebuffer(nullptr)
, m_debug_line_material(nullptr)
, m_debug_flags(BGFX_DEBUG_TEXT)
2015-09-02 11:14:42 +02:00
, m_point_light_shadowmaps(allocator)
, m_materials(allocator)
, m_is_rendering_in_shadowmap(false)
2015-07-23 23:17:51 +02:00
{
2015-10-24 15:27:48 +02:00
m_base_vertex_decl.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.end();
2015-09-21 22:55:15 +02:00
m_is_wireframe = false;
2015-09-20 17:30:37 +02:00
m_view_x = m_view_y = 0;
2015-09-05 13:08:47 +02:00
m_has_shadowmap_define_idx = m_renderer.getShaderDefineIdx("HAS_SHADOWMAP");
2015-10-24 15:27:48 +02:00
createUniforms();
ResourceManagerBase* material_manager =
pipeline.getResourceManager().get(ResourceManager::MATERIAL);
m_debug_line_material = static_cast<Material*>(
material_manager->load(Lumix::Path("models/editor/debug_line.mat")));
m_scene = nullptr;
m_width = m_height = -1;
pipeline.onLoaded<PipelineInstanceImpl, &PipelineInstanceImpl::sourceLoaded>(this);
}
void createUniforms()
{
m_cam_view_uniform = bgfx::createUniform("u_camView", bgfx::UniformType::Mat4);
m_cam_inv_proj_uniform = bgfx::createUniform("u_camInvProj", bgfx::UniformType::Mat4);
m_tex_shadowmap_uniform = bgfx::createUniform("u_texShadowmap", bgfx::UniformType::Int1);
2015-09-04 14:00:28 +02:00
m_attenuation_params_uniform =
bgfx::createUniform("u_attenuationParams", bgfx::UniformType::Vec4);
m_terrain_scale_uniform = bgfx::createUniform("u_terrainScale", bgfx::UniformType::Vec4);
m_rel_camera_pos_uniform = bgfx::createUniform("u_relCamPos", bgfx::UniformType::Vec4);
m_terrain_params_uniform = bgfx::createUniform("u_terrainParams", bgfx::UniformType::Vec4);
2015-10-17 00:18:47 +02:00
m_fog_params_uniform = bgfx::createUniform("u_fogParams", bgfx::UniformType::Vec4);
2015-07-23 23:17:51 +02:00
m_fog_color_density_uniform =
bgfx::createUniform("u_fogColorDensity", bgfx::UniformType::Vec4);
m_light_pos_radius_uniform =
bgfx::createUniform("u_lightPosRadius", bgfx::UniformType::Vec4);
m_light_color_uniform = bgfx::createUniform("u_lightRgbInnerR", bgfx::UniformType::Vec4);
m_light_dir_fov_uniform = bgfx::createUniform("u_lightDirFov", bgfx::UniformType::Vec4);
2015-07-23 23:17:51 +02:00
m_light_specular_uniform =
bgfx::createUniform("u_lightSpecular", bgfx::UniformType::Mat4, 64);
m_ambient_color_uniform = bgfx::createUniform("u_ambientColor", bgfx::UniformType::Vec4);
m_shadowmap_matrices_uniform =
bgfx::createUniform("u_shadowmapMatrices", bgfx::UniformType::Mat4, 4);
2015-07-23 23:17:51 +02:00
m_bone_matrices_uniform =
bgfx::createUniform("u_boneMatrices", bgfx::UniformType::Mat4, 64);
m_specular_shininess_uniform =
bgfx::createUniform("u_materialSpecularShininess", bgfx::UniformType::Vec4);
m_terrain_matrix_uniform = bgfx::createUniform("u_terrainMatrix", bgfx::UniformType::Mat4);
2015-07-23 23:17:51 +02:00
}
2015-10-24 15:27:48 +02:00
void destroyUniforms()
2015-07-23 23:17:51 +02:00
{
2015-09-05 13:08:47 +02:00
bgfx::destroyUniform(m_tex_shadowmap_uniform);
2015-09-04 14:00:28 +02:00
bgfx::destroyUniform(m_attenuation_params_uniform);
2015-07-23 23:17:51 +02:00
bgfx::destroyUniform(m_terrain_matrix_uniform);
bgfx::destroyUniform(m_specular_shininess_uniform);
bgfx::destroyUniform(m_bone_matrices_uniform);
bgfx::destroyUniform(m_terrain_scale_uniform);
bgfx::destroyUniform(m_rel_camera_pos_uniform);
bgfx::destroyUniform(m_terrain_params_uniform);
2015-10-17 00:18:47 +02:00
bgfx::destroyUniform(m_fog_params_uniform);
2015-07-23 23:17:51 +02:00
bgfx::destroyUniform(m_fog_color_density_uniform);
bgfx::destroyUniform(m_light_pos_radius_uniform);
bgfx::destroyUniform(m_light_color_uniform);
bgfx::destroyUniform(m_light_dir_fov_uniform);
bgfx::destroyUniform(m_ambient_color_uniform);
bgfx::destroyUniform(m_shadowmap_matrices_uniform);
bgfx::destroyUniform(m_light_specular_uniform);
bgfx::destroyUniform(m_cam_inv_proj_uniform);
bgfx::destroyUniform(m_cam_view_uniform);
2015-10-24 15:27:48 +02:00
}
~PipelineInstanceImpl()
{
ResourceManagerBase* material_manager =
m_source.getResourceManager().get(ResourceManager::MATERIAL);
for (auto* material : m_materials)
{
material_manager->unload(*material);
}
material_manager->unload(*m_debug_line_material);
destroyUniforms();
2015-07-23 23:17:51 +02:00
for (int i = 0; i < m_uniforms.size(); ++i)
{
bgfx::destroyUniform(m_uniforms[i]);
}
2015-10-03 01:53:04 +02:00
m_source.getObserverCb().unbind<PipelineInstanceImpl, &PipelineInstanceImpl::sourceLoaded>(
this);
m_source.getResourceManager().get(ResourceManager::PIPELINE)->unload(m_source);
2015-07-23 23:17:51 +02:00
for (int i = 0; i < m_framebuffers.size(); ++i)
{
m_allocator.deleteObject(m_framebuffers[i]);
if (m_framebuffers[i] == m_default_framebuffer) m_default_framebuffer = nullptr;
2015-07-23 23:17:51 +02:00
}
m_allocator.deleteObject(m_default_framebuffer);
}
2015-01-03 12:13:13 +01:00
2015-08-14 22:12:51 +02:00
void bindFramebufferTexture(const char* framebuffer_name,
int renderbuffer_idx,
int uniform_idx)
{
FrameBuffer* fb = getFramebuffer(framebuffer_name);
if (!fb) return;
bgfx::setTexture(0, m_uniforms[uniform_idx], fb->getRenderbufferHandle(renderbuffer_idx));
}
2015-08-14 22:12:51 +02:00
virtual void setViewProjection(const Matrix& mtx, int width, int height) override
{
bgfx::setViewRect(m_view_idx, 0, 0, width, height);
bgfx::setViewTransform(m_view_idx, nullptr, &mtx.m11);
}
2015-07-23 23:17:51 +02:00
void finishInstances(int idx)
2014-05-20 23:35:09 +02:00
{
2015-08-27 23:18:49 +02:00
InstanceData& data = m_instances_data[idx];
if (!data.m_buffer) return;
2015-07-23 23:17:51 +02:00
2015-08-27 23:18:49 +02:00
const RenderableMesh& info = data.m_mesh;
const Mesh& mesh = *info.m_mesh;
const Model& model = *info.m_model;
2015-09-04 14:00:28 +02:00
Material* material = mesh.getMaterial();
2015-08-27 23:18:49 +02:00
const uint16_t stride = mesh.getVertexDefinition().getStride();
setMaterial(material);
2015-10-06 17:00:52 +02:00
bgfx::setVertexBuffer(model.getVerticesHandle(),
2015-08-27 23:18:49 +02:00
mesh.getAttributeArrayOffset() / stride,
mesh.getAttributeArraySize() / stride);
2015-10-06 17:00:52 +02:00
bgfx::setIndexBuffer(model.getIndicesHandle(),
2015-08-27 23:18:49 +02:00
mesh.getIndicesOffset(),
mesh.getIndexCount());
bgfx::setState(m_render_state | material->getRenderStates());
bgfx::setInstanceDataBuffer(data.m_buffer, data.m_instance_count);
2015-09-04 14:00:28 +02:00
ShaderInstance& shader_instance =
info.m_mesh->getMaterial()->getShaderInstance();
2015-08-27 23:18:49 +02:00
bgfx::submit(m_view_idx, shader_instance.m_program_handles[m_pass_idx]);
2015-10-06 17:00:52 +02:00
2015-08-27 23:18:49 +02:00
data.m_buffer = nullptr;
data.m_instance_count = 0;
data.m_mesh.m_mesh->setInstanceIdx(-1);
}
void applyCamera(const char* slot)
{
ComponentIndex cmp = getScene()->getCameraInSlot(slot);
if (cmp < 0) return;
getScene()->setCameraSize(cmp, m_width, m_height);
m_applied_camera = cmp;
m_camera_frustum = getScene()->getCameraFrustum(cmp);
Matrix projection_matrix;
float fov = getScene()->getCameraFOV(cmp);
float near_plane = getScene()->getCameraNearPlane(cmp);
float far_plane = getScene()->getCameraFarPlane(cmp);
2015-09-02 11:14:42 +02:00
float ratio = float(m_width) / m_height;
projection_matrix.setPerspective(
Math::degreesToRadians(fov), ratio, near_plane, far_plane);
2015-08-27 23:18:49 +02:00
Universe& universe = getScene()->getUniverse();
Matrix mtx = universe.getMatrix(getScene()->getCameraEntity(cmp));
mtx.fastInverse();
bgfx::setViewTransform(m_view_idx, &mtx.m11, &projection_matrix.m11);
bgfx::setViewRect(
2015-09-20 17:30:37 +02:00
m_view_idx, m_view_x, m_view_y, (uint16_t)m_width, (uint16_t)m_height);
2015-07-23 23:17:51 +02:00
}
void finishInstances()
{
for (int i = 0; i < lengthOf(m_instances_data); ++i)
{
finishInstances(i);
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
m_instance_data_idx = 0;
}
2014-05-20 23:35:09 +02:00
2015-01-03 12:13:13 +01:00
2015-07-23 23:17:51 +02:00
void setPass(const char* name)
{
m_pass_idx = m_renderer.getPassIdx(name);
2015-08-12 21:54:47 +02:00
for (int i = 0; i < m_view2pass_map.size(); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
if (m_view2pass_map[i] == m_pass_idx)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
m_view_idx = i;
2015-10-24 15:27:48 +02:00
return;
2015-07-04 15:22:28 +02:00
}
}
2015-10-24 15:27:48 +02:00
beginNewView(m_current_framebuffer);
2015-07-23 23:17:51 +02:00
}
2015-07-05 15:58:53 +02:00
2015-07-23 23:17:51 +02:00
CustomCommandHandler& addCustomCommandHandler(const char* name) override
{
return m_custom_commands_handlers[crc32(name)];
}
2015-07-05 15:58:53 +02:00
2015-07-23 23:17:51 +02:00
2015-09-20 17:30:37 +02:00
virtual FrameBuffer* getFramebuffer(const char* framebuffer_name) override
2015-07-23 23:17:51 +02:00
{
for (int i = 0, c = m_framebuffers.size(); i < c; ++i)
2015-07-05 15:58:53 +02:00
{
2015-07-23 23:17:51 +02:00
if (strcmp(m_framebuffers[i]->getName(), framebuffer_name) == 0)
2015-07-05 15:58:53 +02:00
{
2015-07-23 23:17:51 +02:00
return m_framebuffers[i];
2015-07-05 15:58:53 +02:00
}
}
2015-07-23 23:17:51 +02:00
return nullptr;
}
2015-07-05 15:58:53 +02:00
2015-01-03 12:13:13 +01:00
2015-07-23 23:17:51 +02:00
void setCurrentFramebuffer(const char* framebuffer_name)
{
if (strcmp(framebuffer_name, "default") == 0)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
m_current_framebuffer = m_default_framebuffer;
if (m_current_framebuffer)
{
2015-07-23 23:17:51 +02:00
bgfx::setViewFrameBuffer(m_view_idx,
m_current_framebuffer->getHandle());
}
else
{
bgfx::setViewFrameBuffer(m_view_idx, BGFX_INVALID_HANDLE);
}
2015-07-23 23:17:51 +02:00
return;
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
m_current_framebuffer = getFramebuffer(framebuffer_name);
if (m_current_framebuffer)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
bgfx::setViewFrameBuffer(m_view_idx,
m_current_framebuffer->getHandle());
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
else
{
g_log_warning.log("renderer") << "Framebuffer " << framebuffer_name
<< " not found";
}
}
2014-05-20 23:35:09 +02:00
2014-07-13 16:54:09 +02:00
2015-07-23 23:17:51 +02:00
virtual int getWidth() override { return m_width; }
2014-07-13 16:54:09 +02:00
2015-01-03 12:13:13 +01:00
2015-07-23 23:17:51 +02:00
virtual int getHeight() override { return m_height; }
void sourceLoaded(Resource::State old_state, Resource::State new_state)
{
if (old_state != Resource::State::READY &&
new_state == Resource::State::READY)
2015-07-04 15:22:28 +02:00
{
m_width = m_height = -1;
2015-07-23 23:17:51 +02:00
for (int i = 0; i < m_framebuffers.size(); ++i)
{
2015-07-23 23:17:51 +02:00
m_allocator.deleteObject(m_framebuffers[i]);
}
2015-07-23 23:17:51 +02:00
m_framebuffers.clear();
m_framebuffers.reserve(m_source.m_framebuffers.size());
for (int i = 0; i < m_source.m_framebuffers.size(); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
FrameBuffer::Declaration& decl = m_source.m_framebuffers[i];
2015-09-20 17:30:37 +02:00
auto* fb = m_allocator.newObject<FrameBuffer>(decl);
m_framebuffers.push(fb);
if (strcmp(decl.m_name, "default") == 0) m_default_framebuffer = fb;
2015-07-04 15:22:28 +02:00
}
2015-01-03 12:13:13 +01:00
2015-07-23 23:17:51 +02:00
if (lua_getglobal(m_source.m_lua_state, "init") == LUA_TFUNCTION)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
lua_pushlightuserdata(m_source.m_lua_state, this);
if (lua_pcall(m_source.m_lua_state, 1, 0, 0) != LUA_OK)
{
g_log_error.log("lua")
<< lua_tostring(m_source.m_lua_state, -1);
2015-08-12 21:54:47 +02:00
lua_pop(m_source.m_lua_state, 1);
2015-07-23 23:17:51 +02:00
}
2015-07-04 15:22:28 +02:00
}
2015-08-27 23:18:49 +02:00
else
{
lua_pop(m_source.m_lua_state, 1);
}
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
}
2015-01-03 12:13:13 +01:00
2015-02-28 11:41:31 +01:00
2015-07-23 23:17:51 +02:00
void executeCustomCommand(uint32_t name)
{
CustomCommandHandler handler;
if (m_custom_commands_handlers.find(name, handler))
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
handler.invoke();
2015-07-04 15:22:28 +02:00
}
finishInstances();
2015-07-23 23:17:51 +02:00
}
2015-02-28 11:41:31 +01:00
2015-09-02 11:14:42 +02:00
void renderPointLightShadowmaps(ComponentIndex camera, ComponentIndex light)
{
Frustum light_frustum;
int64_t mask = 0;
mask = ~mask;
renderPointLightInfluencedGeometry(light_frustum, mask);
}
2015-09-04 14:00:28 +02:00
void beginNewView(FrameBuffer* framebuffer)
2015-09-02 11:14:42 +02:00
{
m_renderer.viewCounterAdd();
m_view_idx = m_renderer.getViewCounter();
m_view2pass_map[m_view_idx] = m_pass_idx;
2015-09-04 14:00:28 +02:00
m_current_framebuffer = framebuffer;
if (framebuffer)
{
bgfx::setViewFrameBuffer(m_view_idx,
m_current_framebuffer->getHandle());
}
else
{
bgfx::setViewFrameBuffer(m_view_idx, BGFX_INVALID_HANDLE);
}
bgfx::setViewClear(m_view_idx, 0);
2015-09-02 11:14:42 +02:00
}
2015-10-24 15:27:48 +02:00
2015-09-02 11:14:42 +02:00
void renderSpotLightShadowmap(FrameBuffer* fb,
ComponentIndex light,
int64_t layer_mask)
{
ASSERT(fb);
2015-09-04 14:00:28 +02:00
beginNewView(fb);
2015-09-02 11:14:42 +02:00
Entity light_entity = m_scene->getPointLightEntity(light);
Matrix mtx = m_scene->getUniverse().getMatrix(light_entity);
float fov = m_scene->getLightFOV(light);
float range = m_scene->getLightRange(light);
uint16_t shadowmap_height = (uint16_t)m_current_framebuffer->getHeight();
uint16_t shadowmap_width = (uint16_t)m_current_framebuffer->getWidth();
Vec3 pos = mtx.getTranslation();
bgfx::setViewClear(m_view_idx, BGFX_CLEAR_DEPTH, 0, 1.0f, 0);
bgfx::touch(m_view_idx);
bgfx::setViewRect(m_view_idx, 0, 0, shadowmap_width, shadowmap_height);
Matrix projection_matrix;
projection_matrix.setPerspective(
Math::degreesToRadians(fov), 1, 0.01f, range);
Matrix view_matrix;
view_matrix.lookAt(pos, pos + mtx.getZVector(), mtx.getYVector());
bgfx::setViewTransform(
m_view_idx, &view_matrix.m11, &projection_matrix.m11);
PointLightShadowmap& s = m_point_light_shadowmaps.pushEmpty();
s.m_framebuffer = m_current_framebuffer;
s.m_light = light;
static const Matrix biasMatrix(
0.5, 0.0, 0.0, 0.0,
0.0, -0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
2015-09-04 14:00:28 +02:00
s.m_matrices[0] = biasMatrix * (projection_matrix * view_matrix);
2015-09-02 11:14:42 +02:00
renderPointLightInfluencedGeometry(light, layer_mask);
}
2015-09-04 14:00:28 +02:00
void renderOmniLightShadowmap(FrameBuffer* fb,
ComponentIndex light,
int64_t layer_mask)
{
Entity light_entity = m_scene->getPointLightEntity(light);
Vec3 light_pos = m_scene->getUniverse().getPosition(light_entity);
float range = m_scene->getLightRange(light);
uint16_t shadowmap_height = (uint16_t)fb->getHeight();
uint16_t shadowmap_width = (uint16_t)fb->getWidth();
float viewports[] = {0, 0, 0.5, 0, 0, 0.5, 0.5, 0.5};
static const float YPR[4][3] = {
{Math::degreesToRadians(0.0f),
Math::degreesToRadians(27.36780516f),
Math::degreesToRadians(0.0f)},
{Math::degreesToRadians(180.0f),
Math::degreesToRadians(27.36780516f),
Math::degreesToRadians(0.0f)},
{Math::degreesToRadians(-90.0f),
Math::degreesToRadians(-27.36780516f),
Math::degreesToRadians(0.0f)},
{Math::degreesToRadians(90.0f),
Math::degreesToRadians(-27.36780516f),
Math::degreesToRadians(0.0f)},
};
PointLightShadowmap& shadowmap_info =
m_point_light_shadowmaps.pushEmpty();
shadowmap_info.m_framebuffer = fb;
shadowmap_info.m_light = light;
for (int i = 0; i < 4; ++i)
{
ASSERT(fb);
beginNewView(fb);
bgfx::setViewClear(m_view_idx, BGFX_CLEAR_DEPTH, 0, 1.0f, 0);
bgfx::touch(m_view_idx);
uint16_t view_x = uint16_t(shadowmap_width * viewports[i * 2]);
uint16_t view_y = uint16_t(shadowmap_height * viewports[i * 2 + 1]);
bgfx::setViewRect(m_view_idx,
view_x,
view_y,
shadowmap_width >> 1,
shadowmap_height >> 1);
float fovx = Math::degreesToRadians(143.98570868f + 3.51f);
float fovy = Math::degreesToRadians(125.26438968f + 9.85f);
float aspect = tanf(fovx * 0.5f) / tanf(fovy * 0.5f);
Matrix projection_matrix;
projection_matrix.setPerspective(fovx, aspect, 0.01f, range);
2015-09-04 14:00:28 +02:00
Matrix view_matrix;
view_matrix.fromEuler(YPR[i][0], YPR[i][1], YPR[i][2]);
view_matrix.setTranslation(light_pos);
Frustum frustum;
frustum.computePerspective(light_pos,
view_matrix.getZVector(),
view_matrix.getYVector(),
fovx,
aspect,
0.01f,
range);
2015-09-04 14:00:28 +02:00
view_matrix.fastInverse();
bgfx::setViewTransform(
m_view_idx, &view_matrix.m11, &projection_matrix.m11);
static const Matrix biasMatrix(
0.5, 0.0, 0.0, 0.0,
0.0, -0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
shadowmap_info.m_matrices[i] = biasMatrix * (projection_matrix * view_matrix);
renderModels(light, frustum, layer_mask);
}
}
void renderModels(ComponentIndex light,
const Frustum& frustum,
int64_t layer_mask)
2015-09-04 14:00:28 +02:00
{
PROFILE_FUNCTION();
m_tmp_meshes.clear();
m_current_light = light;
m_is_current_light_global = false;
m_scene->getPointLightInfluencedGeometry(
light, frustum, m_tmp_meshes, layer_mask);
2015-09-04 14:00:28 +02:00
renderMeshes(m_tmp_meshes);
m_current_light = -1;
}
2015-09-02 11:14:42 +02:00
void renderLocalLightShadowmaps(ComponentIndex camera,
FrameBuffer** fbs,
int framebuffers_count,
int64_t layer_mask)
{
Universe& universe = m_scene->getUniverse();
Entity camera_entity = m_scene->getCameraEntity(camera);
Vec3 camera_pos = universe.getPosition(camera_entity);
ComponentIndex lights[16];
int light_count = m_scene->getClosestPointLights(
camera_pos, lights, lengthOf(lights));
int fb_index = 0;
for (int i = 0; i < light_count; ++i)
{
if (!m_scene->getLightCastShadows(lights[i])) continue;
if (fb_index == framebuffers_count) break;
float fov = m_scene->getLightFOV(lights[i]);
if (fov < 180)
{
renderSpotLightShadowmap(fbs[fb_index], lights[i], layer_mask);
++fb_index;
continue;
}
2015-09-04 14:00:28 +02:00
else
{
renderOmniLightShadowmap(fbs[fb_index], lights[i], layer_mask);
++fb_index;
continue;
}
2015-09-02 11:14:42 +02:00
}
}
static Vec3 shadowmapTexelAlign(const Vec3& shadow_cam_pos,
float shadowmap_width,
float frustum_radius,
const Matrix& light_mtx)
{
Matrix inv = light_mtx;
inv.fastInverse();
Vec3 out = inv.multiplyPosition(shadow_cam_pos);
float align = 2 * frustum_radius / (shadowmap_width * 0.5f - 2);
out.x -= fmodf(out.x, align);
out.y -= fmodf(out.y, align);
out = light_mtx.multiplyPosition(out);
return out;
}
2015-07-24 08:42:35 +02:00
void renderShadowmap(ComponentIndex camera, int64_t layer_mask)
2015-07-23 23:17:51 +02:00
{
Universe& universe = m_scene->getUniverse();
2015-07-24 08:42:35 +02:00
ComponentIndex light_cmp = m_scene->getActiveGlobalLight();
if (light_cmp < 0 || camera < 0) return;
2015-02-28 11:41:31 +01:00
Matrix light_mtx = universe.getMatrix(m_scene->getGlobalLightEntity(light_cmp));
m_global_light_shadowmap = m_current_framebuffer;
2015-07-23 23:17:51 +02:00
float shadowmap_height = (float)m_current_framebuffer->getHeight();
float shadowmap_width = (float)m_current_framebuffer->getWidth();
float viewports[] = {0, 0, 0.5f, 0, 0, 0.5f, 0.5f, 0.5f};
float camera_fov = Math::degreesToRadians(m_scene->getCameraFOV(camera));
float camera_ratio = m_scene->getCameraWidth(camera) / m_scene->getCameraHeight(camera);
Vec4 cascades = m_scene->getShadowmapCascades(light_cmp);
float split_distances[] = {0.01f, cascades.x, cascades.y, cascades.z, cascades.w};
m_is_rendering_in_shadowmap = true;
2015-07-23 23:17:51 +02:00
for (int split_index = 0; split_index < 4; ++split_index)
2014-05-20 23:35:09 +02:00
{
if (split_index > 0) beginNewView(m_current_framebuffer);
2015-07-23 23:17:51 +02:00
bgfx::setViewClear(
m_view_idx, BGFX_CLEAR_DEPTH | BGFX_CLEAR_COLOR, 0xffffffff, 1.0f, 0);
2015-08-04 22:34:27 +02:00
bgfx::touch(m_view_idx);
2015-07-23 23:17:51 +02:00
float* viewport = viewports + split_index * 2;
bgfx::setViewRect(m_view_idx,
(uint16_t)(1 + shadowmap_width * viewport[0]),
(uint16_t)(1 + shadowmap_height * viewport[1]),
(uint16_t)(0.5f * shadowmap_width - 2),
(uint16_t)(0.5f * shadowmap_height - 2));
2015-07-23 23:17:51 +02:00
Frustum frustum;
Matrix camera_matrix = universe.getMatrix(m_scene->getCameraEntity(camera));
2015-07-23 23:17:51 +02:00
frustum.computePerspective(camera_matrix.getTranslation(),
camera_matrix.getZVector(),
camera_matrix.getYVector(),
camera_fov,
camera_ratio,
split_distances[split_index],
split_distances[split_index + 1]);
2015-07-23 23:17:51 +02:00
2015-09-07 13:32:19 +02:00
Vec3 shadow_cam_pos = camera_matrix.getTranslation();
2015-07-23 23:17:51 +02:00
float bb_size = frustum.getRadius();
shadow_cam_pos =
shadowmapTexelAlign(shadow_cam_pos, 0.5f * shadowmap_width - 2, bb_size, light_mtx);
2015-07-23 23:17:51 +02:00
Matrix projection_matrix;
projection_matrix.setOrtho(
bb_size, -bb_size, -bb_size, bb_size, SHADOW_CAM_NEAR, SHADOW_CAM_FAR);
2015-07-23 23:17:51 +02:00
Vec3 light_forward = light_mtx.getZVector();
shadow_cam_pos -= light_forward * SHADOW_CAM_FAR * 0.5f;
Matrix view_matrix;
view_matrix.lookAt(
shadow_cam_pos, shadow_cam_pos + light_forward, light_mtx.getYVector());
bgfx::setViewTransform(m_view_idx, &view_matrix.m11, &projection_matrix.m11);
static const Matrix biasMatrix(
0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0);
m_shadow_viewprojection[split_index] = biasMatrix * (projection_matrix * view_matrix);
2015-07-23 23:17:51 +02:00
Frustum shadow_camera_frustum;
shadow_camera_frustum.computeOrtho(shadow_cam_pos,
-light_forward,
light_mtx.getYVector(),
bb_size * 2,
bb_size * 2,
SHADOW_CAM_NEAR,
SHADOW_CAM_FAR);
renderAll(shadow_camera_frustum, layer_mask, false);
2014-05-20 23:35:09 +02:00
}
m_is_rendering_in_shadowmap = false;
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
void renderDebugPoints()
{
const Array<DebugPoint>& points = m_scene->getDebugPoints();
if (points.empty() || !m_debug_line_material->isReady())
{
return;
}
bgfx::TransientVertexBuffer tvb;
bgfx::TransientIndexBuffer tib;
2015-10-24 15:27:48 +02:00
if (bgfx::allocTransientBuffers(
&tvb, m_base_vertex_decl, points.size(), &tib, points.size()))
{
BaseVertex* vertex = (BaseVertex*)tvb.data;
uint16_t* indices = (uint16_t*)tib.data;
for (int i = 0; i < points.size(); ++i)
{
const DebugPoint& point = points[i];
vertex[0].m_rgba = point.m_color;
vertex[0].m_x = point.m_pos.x;
vertex[0].m_y = point.m_pos.y;
vertex[0].m_z = point.m_pos.z;
vertex[0].m_u = vertex[0].m_v = 0;
indices[0] = i;
++vertex;
++indices;
}
bgfx::setVertexBuffer(&tvb);
bgfx::setIndexBuffer(&tib);
2015-10-24 15:27:48 +02:00
bgfx::setState(
m_render_state | m_debug_line_material->getRenderStates() | BGFX_STATE_PT_POINTS);
bgfx::submit(m_view_idx,
2015-10-24 15:27:48 +02:00
m_debug_line_material->getShaderInstance().m_program_handles[m_pass_idx]);
}
}
2015-07-23 23:17:51 +02:00
void renderDebugLines()
{
const Array<DebugLine>& lines = m_scene->getDebugLines();
2015-10-24 12:25:06 +02:00
if (lines.empty() || !m_debug_line_material->isReady()) return;
2015-07-23 23:17:51 +02:00
bgfx::TransientVertexBuffer tvb;
bgfx::TransientIndexBuffer tib;
2015-10-24 15:27:48 +02:00
if (bgfx::allocTransientBuffers(
&tvb, m_base_vertex_decl, lines.size() * 2, &tib, lines.size() * 2))
2015-07-23 23:17:51 +02:00
{
BaseVertex* vertex = (BaseVertex*)tvb.data;
uint16_t* indices = (uint16_t*)tib.data;
for (int i = 0; i < lines.size(); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
const DebugLine& line = lines[i];
vertex[0].m_rgba = line.m_color;
vertex[0].m_x = line.m_from.x;
vertex[0].m_y = line.m_from.y;
vertex[0].m_z = line.m_from.z;
vertex[0].m_u = vertex[0].m_v = 0;
vertex[1].m_rgba = line.m_color;
vertex[1].m_x = line.m_to.x;
vertex[1].m_y = line.m_to.y;
vertex[1].m_z = line.m_to.z;
vertex[1].m_u = vertex[0].m_v = 0;
indices[0] = i * 2;
indices[1] = i * 2 + 1;
vertex += 2;
indices += 2;
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
bgfx::setVertexBuffer(&tvb);
bgfx::setIndexBuffer(&tib);
2015-10-24 12:25:06 +02:00
bgfx::setState(
m_render_state | m_debug_line_material->getRenderStates() | BGFX_STATE_PT_LINES);
2015-08-04 22:34:27 +02:00
bgfx::submit(m_view_idx,
2015-10-24 12:25:06 +02:00
m_debug_line_material->getShaderInstance().m_program_handles[m_pass_idx]);
2014-06-03 16:43:35 +02:00
}
2015-07-23 23:17:51 +02:00
}
2014-06-03 16:43:35 +02:00
2014-09-26 23:50:05 +02:00
2015-10-15 20:53:13 +02:00
virtual int getPassIdx() const override
{
return m_pass_idx;
}
2015-09-04 14:00:28 +02:00
void setPointLightUniforms(Material* material, ComponentIndex light_cmp)
2015-07-23 23:17:51 +02:00
{
if (light_cmp < 0) return;
2015-07-24 08:42:35 +02:00
2015-07-23 23:17:51 +02:00
Universe& universe = m_scene->getUniverse();
2015-09-05 13:08:47 +02:00
Entity light_entity = m_scene->getPointLightEntity(light_cmp);
Vec3 light_pos = universe.getPosition(light_entity);
Vec3 light_dir = universe.getRotation(light_entity) * Vec3(0, 0, 1);
float fov = Math::degreesToRadians(m_scene->getLightFOV(light_cmp));
Vec3 color = m_scene->getPointLightColor(light_cmp) *
m_scene->getPointLightIntensity(light_cmp);
2015-10-06 17:00:52 +02:00
float range = m_scene->getLightRange(light_cmp);
float attenuation = m_scene->getLightAttenuation(light_cmp);
Vec4 attenuation_params(range, attenuation, 0, 1);
Vec4 light_pos_radius(light_pos, range);
2015-09-05 13:08:47 +02:00
Vec4 light_color(color, 0);
Vec4 light_dir_fov(light_dir, fov);
Vec4 light_specular(m_scene->getPointLightSpecularColor(light_cmp), 1);
2015-09-04 14:00:28 +02:00
2015-09-05 13:08:47 +02:00
bgfx::setUniform(m_attenuation_params_uniform, &attenuation_params);
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_light_pos_radius_uniform, &light_pos_radius);
bgfx::setUniform(m_light_color_uniform, &light_color);
bgfx::setUniform(m_light_dir_fov_uniform, &light_dir_fov);
bgfx::setUniform(m_light_specular_uniform, &light_specular);
2015-07-24 08:42:35 +02:00
2015-09-02 11:14:42 +02:00
if (m_scene->getLightCastShadows(light_cmp))
{
2015-09-05 13:08:47 +02:00
setPointLightShadowmapUniforms(material, light_cmp);
2015-09-04 14:00:28 +02:00
}
else
{
2015-09-05 13:08:47 +02:00
material->unsetUserDefine(m_has_shadowmap_define_idx);
2015-09-02 11:14:42 +02:00
}
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-10-24 15:27:48 +02:00
void setPointLightShadowmapUniforms(Material* material, ComponentIndex light)
2015-09-02 11:14:42 +02:00
{
for (auto& info : m_point_light_shadowmaps)
{
if (info.m_light == light)
{
2015-09-05 13:08:47 +02:00
material->setUserDefine(m_has_shadowmap_define_idx);
2015-09-04 14:00:28 +02:00
bgfx::setUniform(m_shadowmap_matrices_uniform,
2015-10-24 15:27:48 +02:00
&info.m_matrices[0].m11,
m_scene->getLightFOV(light) > 180 ? 4 : 1);
2015-09-04 14:00:28 +02:00
int texture_offset = material->getTextureCount();
bgfx::setTexture(texture_offset,
m_tex_shadowmap_uniform,
info.m_framebuffer->getRenderbufferHandle(0));
2015-09-04 14:00:28 +02:00
return;
2015-09-02 11:14:42 +02:00
}
}
2015-09-05 13:08:47 +02:00
material->unsetUserDefine(m_has_shadowmap_define_idx);
2015-09-02 11:14:42 +02:00
}
2015-07-24 08:42:35 +02:00
void setDirectionalLightUniforms(ComponentIndex light_cmp) const
2015-07-23 23:17:51 +02:00
{
2015-10-17 00:18:47 +02:00
if (light_cmp < 0) return;
2015-07-24 08:42:35 +02:00
2015-07-23 23:17:51 +02:00
Universe& universe = m_scene->getUniverse();
2015-09-05 13:08:47 +02:00
Entity light_entity = m_scene->getGlobalLightEntity(light_cmp);
Vec3 light_dir = universe.getRotation(light_entity) * Vec3(0, 0, 1);
Vec3 diffuse_color = m_scene->getGlobalLightColor(light_cmp) *
m_scene->getGlobalLightIntensity(light_cmp);
Vec3 ambient_color = m_scene->getLightAmbientColor(light_cmp) *
m_scene->getLightAmbientIntensity(light_cmp);
Vec4 diffuse_light_color(diffuse_color, 1);
Vec3 fog_color = m_scene->getFogColor(light_cmp);
float fog_density = m_scene->getFogDensity(light_cmp);
Vec4 ambient_light_color(ambient_color, 1);
Vec4 light_dir_fov(light_dir, 0);
fog_density *= fog_density * fog_density;
Vec4 fog_color_density(fog_color, fog_density);
2015-10-17 00:18:47 +02:00
Vec4 fog_params(m_scene->getFogBottom(light_cmp), m_scene->getFogHeight(light_cmp), 0, 0);
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_light_color_uniform, &diffuse_light_color);
bgfx::setUniform(m_ambient_color_uniform, &ambient_light_color);
bgfx::setUniform(m_light_dir_fov_uniform, &light_dir_fov);
bgfx::setUniform(m_fog_color_density_uniform, &fog_color_density);
2015-10-17 00:18:47 +02:00
bgfx::setUniform(m_fog_params_uniform, &fog_params);
bgfx::setUniform(m_shadowmap_matrices_uniform, &m_shadow_viewprojection, 4);
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
void enableBlending() { m_render_state |= BGFX_STATE_BLEND_ADD; }
2015-09-04 14:00:28 +02:00
void disableBlending() { m_render_state &= ~BGFX_STATE_BLEND_MASK; }
2015-07-04 15:22:28 +02:00
2015-09-04 14:00:28 +02:00
void enableDepthWrite() { m_render_state |= BGFX_STATE_DEPTH_WRITE; }
void disableDepthWrite() { m_render_state &= ~BGFX_STATE_DEPTH_WRITE; }
2015-07-04 15:22:28 +02:00
2015-09-04 14:00:28 +02:00
void enableAlphaWrite() { m_render_state |= BGFX_STATE_ALPHA_WRITE; }
void disableAlphaWrite() { m_render_state &= ~BGFX_STATE_ALPHA_WRITE; }
2015-09-04 14:00:28 +02:00
void enableRGBWrite() { m_render_state |= BGFX_STATE_RGB_WRITE; }
void disableRGBWrite() { m_render_state &= ~BGFX_STATE_RGB_WRITE; }
2014-11-30 15:10:13 +01:00
2015-10-24 15:27:48 +02:00
void renderPointLightInfluencedGeometry(ComponentIndex light, int64_t layer_mask)
2015-09-02 11:14:42 +02:00
{
PROFILE_FUNCTION();
m_tmp_meshes.clear();
2015-10-24 15:27:48 +02:00
m_scene->getPointLightInfluencedGeometry(light, m_tmp_meshes, layer_mask);
2015-09-02 11:14:42 +02:00
renderMeshes(m_tmp_meshes);
}
2015-07-23 23:17:51 +02:00
void renderPointLightInfluencedGeometry(const Frustum& frustum,
int64_t layer_mask)
{
PROFILE_FUNCTION();
2014-11-30 15:10:13 +01:00
2015-07-24 08:42:35 +02:00
Array<ComponentIndex> lights(m_allocator);
2015-07-23 23:17:51 +02:00
m_scene->getPointLights(frustum, lights);
for (int i = 0; i < lights.size(); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
m_tmp_grasses.clear();
m_tmp_meshes.clear();
m_tmp_terrains.clear();
2015-07-04 15:22:28 +02:00
2015-07-24 08:42:35 +02:00
ComponentIndex light = lights[i];
2015-09-02 11:14:42 +02:00
m_current_light = light;
m_is_current_light_global = false;
2015-10-24 15:27:48 +02:00
m_scene->getPointLightInfluencedGeometry(light, frustum, m_tmp_meshes, layer_mask);
2015-10-24 15:27:48 +02:00
m_scene->getTerrainInfos(m_tmp_terrains,
2015-07-23 23:17:51 +02:00
layer_mask,
2015-10-24 15:27:48 +02:00
m_scene->getUniverse().getPosition(m_scene->getCameraEntity(m_applied_camera)),
2015-09-26 19:59:14 +02:00
m_renderer.getFrameAllocator());
2014-09-29 01:53:17 +02:00
2015-10-24 15:27:48 +02:00
m_scene->getGrassInfos(frustum, m_tmp_grasses, layer_mask, m_applied_camera);
2015-07-23 23:17:51 +02:00
renderMeshes(m_tmp_meshes);
renderTerrains(m_tmp_terrains);
renderGrasses(m_tmp_grasses);
2015-07-04 15:22:28 +02:00
}
2015-09-03 14:25:12 +02:00
m_current_light = -1;
2015-07-23 23:17:51 +02:00
}
2015-07-04 15:22:28 +02:00
2014-09-29 01:53:17 +02:00
void drawQuad(float x, float y, float w, float h, int material_index)
2015-07-23 23:17:51 +02:00
{
Material* material = m_materials[material_index];
2015-10-24 15:27:48 +02:00
if (!material->isReady() || !bgfx::checkAvailTransientVertexBuffer(3, m_base_vertex_decl))
{
bgfx::touch(m_view_idx);
2015-08-27 23:18:49 +02:00
return;
2015-10-24 15:27:48 +02:00
}
2015-08-11 22:55:17 +02:00
2015-08-27 23:18:49 +02:00
Matrix projection_mtx;
projection_mtx.setOrtho(-1, 1, 1, -1, 0, 30);
2015-07-04 15:22:28 +02:00
2015-10-24 15:27:48 +02:00
bgfx::setViewTransform(m_view_idx, &Matrix::IDENTITY.m11, &projection_mtx.m11);
if (m_current_framebuffer)
{
bgfx::setViewRect(m_view_idx,
m_view_x,
m_view_y,
(uint16_t)m_current_framebuffer->getWidth(),
(uint16_t)m_current_framebuffer->getHeight());
}
else
{
bgfx::setViewRect(m_view_idx, m_view_x, m_view_y, (uint16_t)m_width, (uint16_t)m_height);
}
2015-08-27 23:18:49 +02:00
bgfx::TransientVertexBuffer vb;
2015-10-24 15:27:48 +02:00
bgfx::allocTransientVertexBuffer(&vb, 6, m_base_vertex_decl);
2015-08-27 23:18:49 +02:00
BaseVertex* vertex = (BaseVertex*)vb.data;
float x2 = x + w;
float y2 = y + h;
vertex[0].m_x = x;
vertex[0].m_y = y;
vertex[0].m_z = 0;
vertex[0].m_rgba = 0xffffffff;
vertex[0].m_u = 0;
vertex[0].m_v = 0;
vertex[1].m_x = x2;
vertex[1].m_y = y;
vertex[1].m_z = 0;
vertex[1].m_rgba = 0xffffffff;
vertex[1].m_u = 1;
vertex[1].m_v = 0;
vertex[2].m_x = x2;
vertex[2].m_y = y2;
vertex[2].m_z = 0;
vertex[2].m_rgba = 0xffffffff;
vertex[2].m_u = 1;
vertex[2].m_v = 1;
vertex[3].m_x = x;
vertex[3].m_y = y;
vertex[3].m_z = 0;
vertex[3].m_rgba = 0xffffffff;
vertex[3].m_u = 0;
vertex[3].m_v = 0;
vertex[4].m_x = x2;
vertex[4].m_y = y2;
vertex[4].m_z = 0;
vertex[4].m_rgba = 0xffffffff;
vertex[4].m_u = 1;
vertex[4].m_v = 1;
vertex[5].m_x = x;
vertex[5].m_y = y2;
vertex[5].m_z = 0;
vertex[5].m_rgba = 0xffffffff;
vertex[5].m_u = 0;
vertex[5].m_v = 1;
for (int i = 0; i < material->getUniformCount(); ++i)
{
const Material::Uniform& uniform = material->getUniform(i);
switch (uniform.m_type)
{
2015-10-24 15:27:48 +02:00
case Material::Uniform::FLOAT:
{
Vec4 v(uniform.m_float, 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
}
break;
case Material::Uniform::TIME:
{
Vec4 v(m_scene->getTime(), 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
}
break;
2015-10-24 15:27:48 +02:00
default: ASSERT(false); break;
}
}
Shader* shader = material->getShader();
for (int i = 0; i < material->getTextureCount(); ++i)
{
Texture* texture = material->getTexture(i);
if (texture)
{
bgfx::setTexture(
2015-10-24 15:27:48 +02:00
i, shader->getTextureSlot(i).m_uniform_handle, texture->getTextureHandle());
}
}
2015-08-27 23:18:49 +02:00
if (m_applied_camera >= 0)
{
Matrix projection_matrix;
float fov = getScene()->getCameraFOV(m_applied_camera);
float near_plane = getScene()->getCameraNearPlane(m_applied_camera);
float far_plane = getScene()->getCameraFarPlane(m_applied_camera);
float ratio = float(m_width) / m_height;
projection_matrix.setPerspective(
Math::degreesToRadians(fov), ratio, near_plane, far_plane);
projection_matrix.inverse();
bgfx::setUniform(m_cam_inv_proj_uniform, &projection_matrix.m11);
Universe& universe = getScene()->getUniverse();
Matrix mtx = universe.getMatrix(getScene()->getCameraEntity(m_applied_camera));
bgfx::setUniform(m_cam_view_uniform, &mtx.m11);
}
bgfx::setState(m_render_state | material->getRenderStates());
2015-08-27 23:18:49 +02:00
bgfx::setVertexBuffer(&vb);
2015-10-24 15:27:48 +02:00
bgfx::submit(m_view_idx, material->getShaderInstance().m_program_handles[m_pass_idx]);
2015-07-23 23:17:51 +02:00
}
2014-09-07 01:10:24 +02:00
2014-11-16 19:31:51 +01:00
void renderAll(const Frustum& frustum, int64_t layer_mask, bool render_grass)
2015-07-23 23:17:51 +02:00
{
PROFILE_FUNCTION();
2015-08-27 23:18:49 +02:00
if (m_applied_camera < 0) return;
m_tmp_grasses.clear();
m_tmp_meshes.clear();
m_tmp_terrains.clear();
m_scene->getRenderableInfos(frustum, m_tmp_meshes, layer_mask);
Entity camera_entity = m_scene->getCameraEntity(m_applied_camera);
Vec3 camera_pos = m_scene->getUniverse().getPosition(camera_entity);
LIFOAllocator& frame_allocator = m_renderer.getFrameAllocator();
m_scene->getTerrainInfos(m_tmp_terrains, layer_mask, camera_pos, frame_allocator);
2015-10-24 15:27:48 +02:00
2015-09-02 11:14:42 +02:00
m_is_current_light_global = true;
m_current_light = m_scene->getActiveGlobalLight();
2015-10-24 15:27:48 +02:00
2015-08-27 23:18:49 +02:00
renderMeshes(m_tmp_meshes);
renderTerrains(m_tmp_terrains);
if (render_grass)
2015-07-23 23:17:51 +02:00
{
m_scene->getGrassInfos(frustum, m_tmp_grasses, layer_mask, m_applied_camera);
2015-08-27 23:18:49 +02:00
renderGrasses(m_tmp_grasses);
2015-02-14 00:13:34 +01:00
}
2015-09-03 14:25:12 +02:00
m_current_light = -1;
2015-07-23 23:17:51 +02:00
}
2015-02-14 00:13:34 +01:00
2015-07-23 23:17:51 +02:00
virtual void toggleStats() override
{
m_debug_flags ^= BGFX_DEBUG_STATS;
bgfx::setDebug(m_debug_flags);
}
2015-02-18 00:52:03 +01:00
2015-07-23 23:17:51 +02:00
virtual void setWindowHandle(void* data) override
{
m_default_framebuffer =
m_allocator.newObject<FrameBuffer>("default", m_width, m_height, data);
2015-07-23 23:17:51 +02:00
}
2015-02-28 10:06:50 +01:00
2015-07-23 23:17:51 +02:00
virtual void renderModel(Model& model, const Matrix& mtx) override
{
RenderableMesh mesh;
mesh.m_matrix = &mtx;
mesh.m_model = &model;
mesh.m_pose = nullptr;
for (int i = 0; i < model.getMeshCount(); ++i)
2014-11-16 19:31:51 +01:00
{
2015-07-23 23:17:51 +02:00
mesh.m_mesh = &model.getMesh(i);
renderRigidMesh(mesh);
2014-11-16 19:31:51 +01:00
}
2015-07-23 23:17:51 +02:00
}
2015-02-14 14:23:12 +01:00
2015-07-23 23:17:51 +02:00
void setPoseUniform(const RenderableMesh& renderable_mesh) const
{
Matrix bone_mtx[64];
2015-07-13 09:17:09 +02:00
2015-07-23 23:17:51 +02:00
const Pose& pose = *renderable_mesh.m_pose;
const Model& model = *renderable_mesh.m_model;
Vec3* poss = pose.getPositions();
Quat* rots = pose.getRotations();
2015-07-13 09:17:09 +02:00
2015-07-23 23:17:51 +02:00
ASSERT(pose.getCount() <= lengthOf(bone_mtx));
2015-10-24 14:05:24 +02:00
for (int bone_index = 0, bone_count = pose.getCount(); bone_index < bone_count;
2015-07-23 23:17:51 +02:00
++bone_index)
2014-11-16 19:31:51 +01:00
{
2015-07-23 23:17:51 +02:00
rots[bone_index].toMatrix(bone_mtx[bone_index]);
bone_mtx[bone_index].translate(poss[bone_index]);
2015-10-24 14:05:24 +02:00
bone_mtx[bone_index] = bone_mtx[bone_index] * model.getBone(bone_index).inv_bind_matrix;
2014-11-16 19:31:51 +01:00
}
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_bone_matrices_uniform, bone_mtx, pose.getCount());
}
2015-02-14 14:23:12 +01:00
2014-11-16 19:31:51 +01:00
2015-07-23 23:17:51 +02:00
void renderSkinnedMesh(const RenderableMesh& info)
{
2015-10-06 17:00:52 +02:00
if (!info.m_model->isReady()) return;
2015-07-23 23:17:51 +02:00
const Mesh& mesh = *info.m_mesh;
2015-09-04 14:00:28 +02:00
Material* material = mesh.getMaterial();
2015-07-23 23:17:51 +02:00
setPoseUniform(info);
setMaterial(material);
bgfx::setTransform(info.m_matrix);
2015-10-06 17:00:52 +02:00
bgfx::setVertexBuffer(info.m_model->getVerticesHandle(),
2015-10-24 14:05:24 +02:00
mesh.getAttributeArrayOffset() / mesh.getVertexDefinition().getStride(),
mesh.getAttributeArraySize() / mesh.getVertexDefinition().getStride());
bgfx::setIndexBuffer(
info.m_model->getIndicesHandle(), mesh.getIndicesOffset(), mesh.getIndexCount());
2015-07-23 23:17:51 +02:00
bgfx::setState(m_render_state | material->getRenderStates());
2015-08-04 22:34:27 +02:00
bgfx::submit(m_view_idx,
2015-10-24 14:05:24 +02:00
info.m_mesh->getMaterial()->getShaderInstance().m_program_handles[m_pass_idx]);
2015-07-23 23:17:51 +02:00
}
2014-11-16 19:31:51 +01:00
2015-08-15 09:56:37 +02:00
virtual void setScissor(int x, int y, int width, int height) override
{
bgfx::setScissor(x, y, width, height);
}
2015-10-24 14:05:24 +02:00
virtual void setTexture(int slot,
bgfx::TextureHandle texture,
bgfx::UniformHandle uniform) override
2015-08-14 22:12:51 +02:00
{
2015-10-24 14:05:24 +02:00
bgfx::setTexture(0, uniform, texture);
2015-08-14 22:12:51 +02:00
}
2015-10-15 20:53:13 +02:00
virtual void render(TransientGeometry& geom,
const Matrix& mtx,
2015-10-24 14:05:24 +02:00
int first_index,
int num_indices,
2015-10-15 20:53:13 +02:00
uint64_t render_states,
bgfx::ProgramHandle program_handle) override
{
bgfx::setState(m_render_state | render_states);
bgfx::setTransform(&mtx.m11);
bgfx::setVertexBuffer(&geom.getVertexBuffer());
2015-10-24 14:05:24 +02:00
bgfx::setIndexBuffer(&geom.getIndexBuffer(), first_index, num_indices);
2015-10-15 20:53:13 +02:00
bgfx::submit(m_view_idx, program_handle);
}
2015-07-23 23:17:51 +02:00
void renderRigidMesh(const RenderableMesh& info)
{
2015-10-06 17:00:52 +02:00
if (!info.m_model->isReady()) return;
2015-07-23 23:17:51 +02:00
int instance_idx = info.m_mesh->getInstanceIdx();
if (instance_idx == -1)
2015-07-12 17:14:43 +02:00
{
2015-07-23 23:17:51 +02:00
instance_idx = m_instance_data_idx;
2015-10-24 15:27:48 +02:00
m_instance_data_idx = (m_instance_data_idx + 1) % lengthOf(m_instances_data);
2015-07-23 23:17:51 +02:00
if (m_instances_data[instance_idx].m_buffer)
2015-07-12 17:14:43 +02:00
{
2015-07-23 23:17:51 +02:00
finishInstances(instance_idx);
2015-07-12 17:14:43 +02:00
}
2015-07-23 23:17:51 +02:00
info.m_mesh->setInstanceIdx(instance_idx);
}
InstanceData& data = m_instances_data[instance_idx];
if (!data.m_buffer)
{
2015-10-24 15:27:48 +02:00
data.m_buffer =
bgfx::allocInstanceDataBuffer(InstanceData::MAX_INSTANCE_COUNT, sizeof(Matrix));
2015-07-23 23:17:51 +02:00
data.m_instance_count = 0;
data.m_mesh = info;
}
Matrix* mtcs = (Matrix*)data.m_buffer->data;
mtcs[data.m_instance_count] = *info.m_matrix;
++data.m_instance_count;
2015-09-28 00:51:28 +02:00
2015-07-23 23:17:51 +02:00
if (data.m_instance_count == InstanceData::MAX_INSTANCE_COUNT)
{
2015-10-24 15:27:48 +02:00
finishInstances(instance_idx);
2015-07-12 17:14:43 +02:00
}
2015-07-23 23:17:51 +02:00
}
2015-07-12 17:14:43 +02:00
2015-09-04 14:00:28 +02:00
void setMaterial(Material* material)
2015-07-23 23:17:51 +02:00
{
2015-09-02 11:14:42 +02:00
if (m_is_current_light_global)
2015-09-04 14:00:28 +02:00
{
2015-09-02 11:14:42 +02:00
setDirectionalLightUniforms(m_current_light);
2015-09-04 14:00:28 +02:00
}
2015-09-02 11:14:42 +02:00
else
2015-09-04 14:00:28 +02:00
{
setPointLightUniforms(material, m_current_light);
}
2015-09-02 11:14:42 +02:00
2015-07-23 23:17:51 +02:00
for (int i = 0; i < material->getUniformCount(); ++i)
2014-10-17 01:21:59 +02:00
{
2015-07-23 23:17:51 +02:00
const Material::Uniform& uniform = material->getUniform(i);
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
switch (uniform.m_type)
2015-02-18 00:52:03 +01:00
{
2015-07-23 23:17:51 +02:00
case Material::Uniform::FLOAT:
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
Vec4 v(uniform.m_float, 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
break;
case Material::Uniform::TIME:
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
Vec4 v(m_scene->getTime(), 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
break;
2015-10-24 15:27:48 +02:00
default: ASSERT(false); break;
2015-07-04 15:22:28 +02:00
}
}
2015-02-14 14:23:12 +01:00
2015-08-11 22:55:17 +02:00
Shader* shader = material->getShader();
2015-07-23 23:17:51 +02:00
for (int i = 0; i < material->getTextureCount(); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
Texture* texture = material->getTexture(i);
if (!texture) continue;
bgfx::setTexture(
i, shader->getTextureSlot(i).m_uniform_handle, texture->getTextureHandle());
}
2015-07-04 15:22:28 +02:00
2015-10-06 17:00:52 +02:00
Vec4 specular_shininess(material->getSpecular(), material->getShininess());
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_specular_shininess_uniform, &specular_shininess);
2015-07-04 15:22:28 +02:00
2015-10-07 17:59:49 +02:00
if (m_is_current_light_global && !m_is_rendering_in_shadowmap && m_global_light_shadowmap)
{
auto handle = m_global_light_shadowmap->getRenderbufferHandle(0);
2015-10-06 17:00:52 +02:00
bgfx::setTexture(shader->getTextureSlotCount(), m_tex_shadowmap_uniform, handle);
}
2015-07-23 23:17:51 +02:00
}
2015-02-14 14:23:12 +01:00
2015-07-23 23:17:51 +02:00
void renderTerrain(const TerrainInfo& info)
{
2015-10-24 15:27:48 +02:00
if (!info.m_terrain->getMaterial()->isReady()) return;
2015-07-23 23:17:51 +02:00
auto& inst = m_terrain_instances[info.m_index];
2015-10-24 15:27:48 +02:00
if ((inst.m_count > 0 && inst.m_infos[0]->m_terrain != info.m_terrain) ||
2015-07-23 23:17:51 +02:00
inst.m_count == lengthOf(inst.m_infos))
{
finishTerrainInstances(info.m_index);
}
inst.m_infos[inst.m_count] = &info;
++inst.m_count;
}
2015-07-23 23:17:51 +02:00
void finishTerrainInstances(int index)
{
2015-10-06 17:00:52 +02:00
if (m_terrain_instances[index].m_count == 0) return;
2015-07-23 23:17:51 +02:00
const TerrainInfo& info = *m_terrain_instances[index].m_infos[0];
Material* material = info.m_terrain->getMaterial();
2015-10-06 17:00:52 +02:00
if (!material->isReady()) return;
2015-08-27 23:18:49 +02:00
Texture* detail_texture = info.m_terrain->getDetailTexture();
2015-10-06 17:00:52 +02:00
if (!detail_texture) return;
2015-10-07 17:48:34 +02:00
Texture* splat_texture = info.m_terrain->getSplatmap();
if (!splat_texture) return;
2015-08-27 23:18:49 +02:00
2015-07-23 23:17:51 +02:00
Matrix inv_world_matrix;
inv_world_matrix = info.m_world_matrix;
inv_world_matrix.fastInverse();
2015-10-24 15:27:48 +02:00
Vec3 camera_pos =
m_scene->getUniverse().getPosition(m_scene->getCameraEntity(m_applied_camera));
2015-07-24 08:42:35 +02:00
2015-10-24 15:27:48 +02:00
Vec3 rel_cam_pos =
inv_world_matrix.multiplyPosition(camera_pos) / info.m_terrain->getXZScale();
2015-07-23 23:17:51 +02:00
const Mesh& mesh = *info.m_terrain->getMesh();
Vec4 terrain_params(info.m_terrain->getRootSize(),
2015-10-24 15:27:48 +02:00
(float)detail_texture->getWidth(),
(float)detail_texture->getAtlasSize(),
(float)splat_texture->getWidth());
bgfx::setUniform(m_terrain_params_uniform, &terrain_params);
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_rel_camera_pos_uniform, &Vec4(rel_cam_pos, 0));
2015-10-06 17:00:52 +02:00
bgfx::setUniform(m_terrain_scale_uniform, &Vec4(info.m_terrain->getScale(), 0));
2015-07-23 23:17:51 +02:00
bgfx::setUniform(m_terrain_matrix_uniform, &info.m_world_matrix.m11);
setMaterial(material);
2015-08-27 23:18:49 +02:00
struct TerrainInstanceData
{
Vec4 m_quad_min_and_size;
Vec4 m_morph_const;
};
const bgfx::InstanceDataBuffer* instance_buffer = bgfx::allocInstanceDataBuffer(
m_terrain_instances[index].m_count, sizeof(TerrainInstanceData));
2015-10-06 17:00:52 +02:00
TerrainInstanceData* instance_data = (TerrainInstanceData*)instance_buffer->data;
2015-07-23 23:17:51 +02:00
for (int i = 0; i < m_terrain_instances[index].m_count; ++i)
{
const TerrainInfo& info = *m_terrain_instances[index].m_infos[i];
instance_data[i].m_quad_min_and_size.set(
info.m_min.x, info.m_min.y, info.m_min.z, info.m_size);
instance_data[i].m_morph_const.set(
info.m_morph_const.x, info.m_morph_const.y, info.m_morph_const.z, 0);
2015-07-23 23:17:51 +02:00
}
2015-10-24 15:27:48 +02:00
bgfx::setVertexBuffer(info.m_terrain->getVerticesHandle());
2015-07-23 23:17:51 +02:00
int mesh_part_indices_count = mesh.getIndexCount() / 4;
2015-10-06 17:00:52 +02:00
bgfx::setIndexBuffer(info.m_terrain->getIndicesHandle(),
info.m_index * mesh_part_indices_count,
mesh_part_indices_count);
2015-07-23 23:17:51 +02:00
bgfx::setState(m_render_state | mesh.getMaterial()->getRenderStates());
bgfx::setInstanceDataBuffer(instance_buffer, m_terrain_instances[index].m_count);
2015-10-06 17:00:52 +02:00
auto shader_instance = material->getShaderInstance().m_program_handles[m_pass_idx];
bgfx::submit(m_view_idx, shader_instance);
2015-10-24 15:27:48 +02:00
2015-07-23 23:17:51 +02:00
m_terrain_instances[index].m_count = 0;
}
2015-02-14 00:13:34 +01:00
2015-07-23 23:17:51 +02:00
void renderGrass(const GrassInfo& grass)
{
const bgfx::InstanceDataBuffer* idb =
bgfx::allocInstanceDataBuffer(grass.m_matrix_count, sizeof(Matrix));
2015-10-24 15:27:48 +02:00
memcpy(idb->data, &grass.m_matrices[0], grass.m_matrix_count * sizeof(Matrix));
2015-07-23 23:17:51 +02:00
const Mesh& mesh = grass.m_model->getMesh(0);
2015-09-04 14:00:28 +02:00
Material* material = mesh.getMaterial();
2015-07-23 23:17:51 +02:00
setMaterial(material);
2015-10-06 17:00:52 +02:00
bgfx::setVertexBuffer(grass.m_model->getVerticesHandle(),
2015-10-24 15:27:48 +02:00
mesh.getAttributeArrayOffset() / mesh.getVertexDefinition().getStride(),
mesh.getAttributeArraySize() / mesh.getVertexDefinition().getStride());
bgfx::setIndexBuffer(
grass.m_model->getIndicesHandle(), mesh.getIndicesOffset(), mesh.getIndexCount());
2015-07-23 23:17:51 +02:00
bgfx::setState(m_render_state | material->getRenderStates());
bgfx::setInstanceDataBuffer(idb, grass.m_matrix_count);
2015-08-04 22:34:27 +02:00
bgfx::submit(m_view_idx, material->getShaderInstance().m_program_handles[m_pass_idx]);
2015-07-23 23:17:51 +02:00
}
2015-02-14 00:13:34 +01:00
2015-07-23 23:17:51 +02:00
void renderGrasses(const Array<GrassInfo>& grasses)
{
PROFILE_FUNCTION();
for (const auto& grass : grasses)
2015-02-14 14:23:12 +01:00
{
2015-07-23 23:17:51 +02:00
renderGrass(grass);
2015-02-14 14:23:12 +01:00
}
2015-07-23 23:17:51 +02:00
}
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
void renderTerrains(const Array<const TerrainInfo*>& terrains)
{
PROFILE_FUNCTION();
for (auto* info : terrains)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
renderTerrain(*info);
2014-05-20 23:35:09 +02:00
}
2015-07-23 23:17:51 +02:00
for (int i = 0; i < lengthOf(m_terrain_instances); ++i)
{
finishTerrainInstances(i);
}
}
2015-02-14 00:13:34 +01:00
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
void renderMeshes(const Array<const RenderableMesh*>& meshes)
{
PROFILE_FUNCTION();
for (auto* mesh : meshes)
2015-05-16 13:17:20 +02:00
{
2015-07-23 23:17:51 +02:00
if (mesh->m_pose && mesh->m_pose->getCount() > 0)
2015-07-13 09:17:09 +02:00
{
2015-07-23 23:17:51 +02:00
renderSkinnedMesh(*mesh);
2015-07-13 09:17:09 +02:00
}
else
{
2015-07-23 23:17:51 +02:00
renderRigidMesh(*mesh);
2015-07-13 09:17:09 +02:00
}
2015-05-16 13:17:20 +02:00
}
2015-07-23 23:17:51 +02:00
finishInstances();
}
2015-07-04 15:22:28 +02:00
2015-09-20 17:30:37 +02:00
virtual void setViewport(int x, int y, int w, int h) override
2015-07-23 23:17:51 +02:00
{
2015-09-20 17:30:37 +02:00
m_view_x = x;
m_view_y = y;
if (m_width == w && m_height == h) return;
2015-07-23 23:17:51 +02:00
if (m_default_framebuffer)
2014-05-20 23:35:09 +02:00
{
2015-07-23 23:17:51 +02:00
m_default_framebuffer->resize(w, h);
}
m_width = w;
m_height = h;
}
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
virtual void render() override
{
PROFILE_FUNCTION();
2015-07-04 15:22:28 +02:00
2015-10-24 15:27:48 +02:00
if (!m_source.isReady()) return;
2015-05-16 13:17:20 +02:00
2015-10-24 15:27:48 +02:00
m_render_state = BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_WRITE |
BGFX_STATE_MSAA;
2015-10-07 17:59:49 +02:00
m_global_light_shadowmap = nullptr;
2015-09-21 22:55:15 +02:00
m_render_state |= m_is_wireframe ? BGFX_STATE_PT_LINESTRIP : 0;
m_view_idx = m_renderer.getViewCounter();
2015-07-23 23:17:51 +02:00
m_pass_idx = -1;
m_current_framebuffer = m_default_framebuffer;
2015-09-22 23:58:11 +02:00
m_current_light = -1;
2015-08-12 21:54:47 +02:00
m_view2pass_map.assign(0xFF);
2015-07-23 23:17:51 +02:00
m_instance_data_idx = 0;
2015-09-02 11:14:42 +02:00
m_point_light_shadowmaps.clear();
2015-07-23 23:17:51 +02:00
for (int i = 0; i < lengthOf(m_terrain_instances); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
m_terrain_instances[i].m_count = 0;
2015-07-04 15:22:28 +02:00
}
2015-07-23 23:17:51 +02:00
for (int i = 0; i < lengthOf(m_instances_data); ++i)
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
m_instances_data[i].m_buffer = nullptr;
m_instances_data[i].m_instance_count = 0;
2015-07-04 15:22:28 +02:00
}
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
if (lua_getglobal(m_source.m_lua_state, "render") == LUA_TFUNCTION)
2015-05-15 22:38:34 +02:00
{
2015-07-23 23:17:51 +02:00
lua_pushlightuserdata(m_source.m_lua_state, this);
if (lua_pcall(m_source.m_lua_state, 1, 0, 0) != LUA_OK)
2015-07-04 15:22:28 +02:00
{
g_log_error.log("lua") << lua_tostring(m_source.m_lua_state, -1);
2015-08-12 21:54:47 +02:00
lua_pop(m_source.m_lua_state, 1);
2015-07-04 15:22:28 +02:00
}
2015-05-15 22:38:34 +02:00
}
2015-08-27 23:18:49 +02:00
else
{
lua_pop(m_source.m_lua_state, 1);
}
2015-07-23 23:17:51 +02:00
finishInstances();
2015-05-15 22:38:34 +02:00
2015-09-26 19:59:14 +02:00
m_renderer.getFrameAllocator().clear();
2015-07-23 23:17:51 +02:00
}
2015-05-15 22:38:34 +02:00
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
virtual void setScene(RenderScene* scene) override { m_scene = scene; }
virtual RenderScene* getScene() override { return m_scene; }
2015-10-24 15:27:48 +02:00
virtual void setWireframe(bool wireframe) override { m_is_wireframe = wireframe; }
2014-05-20 23:35:09 +02:00
2015-08-27 23:18:49 +02:00
struct TerrainInstance
2015-07-04 15:22:28 +02:00
{
2015-07-23 23:17:51 +02:00
int m_count;
const TerrainInfo* m_infos[64];
};
2014-05-20 23:35:09 +02:00
2015-10-24 15:27:48 +02:00
2015-09-02 11:14:42 +02:00
struct PointLightShadowmap
{
ComponentIndex m_light;
FrameBuffer* m_framebuffer;
2015-09-04 14:00:28 +02:00
Matrix m_matrices[4];
2015-09-02 11:14:42 +02:00
};
2015-10-24 15:27:48 +02:00
struct BaseVertex
{
float m_x, m_y, m_z;
uint32_t m_rgba;
float m_u;
float m_v;
};
bgfx::VertexDecl m_base_vertex_decl;
2015-07-23 23:17:51 +02:00
TerrainInstance m_terrain_instances[4];
uint32_t m_debug_flags;
uint8_t m_view_idx;
int m_pass_idx;
2015-09-02 11:14:42 +02:00
StaticArray<uint8_t, 256> m_view2pass_map;
2015-07-23 23:17:51 +02:00
uint64_t m_render_state;
IAllocator& m_allocator;
Renderer& m_renderer;
PipelineImpl& m_source;
RenderScene* m_scene;
FrameBuffer* m_current_framebuffer;
FrameBuffer* m_default_framebuffer;
Array<FrameBuffer*> m_framebuffers;
Array<bgfx::UniformHandle> m_uniforms;
Array<Material*> m_materials;
2015-09-02 11:14:42 +02:00
Array<PointLightShadowmap> m_point_light_shadowmaps;
FrameBuffer* m_global_light_shadowmap;
2015-07-23 23:17:51 +02:00
InstanceData m_instances_data[128];
int m_instance_data_idx;
2015-08-27 23:18:49 +02:00
ComponentIndex m_applied_camera;
2015-09-02 11:14:42 +02:00
ComponentIndex m_current_light;
bool m_is_current_light_global;
2015-09-21 22:55:15 +02:00
bool m_is_wireframe;
bool m_is_rendering_in_shadowmap;
2015-08-27 23:18:49 +02:00
Frustum m_camera_frustum;
2015-07-23 23:17:51 +02:00
2015-09-05 13:08:47 +02:00
Matrix m_shadow_viewprojection[4];
2015-09-20 17:30:37 +02:00
int m_view_x;
int m_view_y;
2015-07-23 23:17:51 +02:00
int m_width;
int m_height;
AssociativeArray<uint32_t, CustomCommandHandler> m_custom_commands_handlers;
Array<const RenderableMesh*> m_tmp_meshes;
Array<const TerrainInfo*> m_tmp_terrains;
Array<GrassInfo> m_tmp_grasses;
2015-10-24 15:27:48 +02:00
2015-07-23 23:17:51 +02:00
bgfx::UniformHandle m_specular_shininess_uniform;
bgfx::UniformHandle m_bone_matrices_uniform;
bgfx::UniformHandle m_terrain_scale_uniform;
bgfx::UniformHandle m_rel_camera_pos_uniform;
bgfx::UniformHandle m_terrain_params_uniform;
2015-07-23 23:17:51 +02:00
bgfx::UniformHandle m_fog_color_density_uniform;
2015-10-17 00:18:47 +02:00
bgfx::UniformHandle m_fog_params_uniform;
2015-07-23 23:17:51 +02:00
bgfx::UniformHandle m_light_pos_radius_uniform;
bgfx::UniformHandle m_light_color_uniform;
bgfx::UniformHandle m_ambient_color_uniform;
bgfx::UniformHandle m_light_dir_fov_uniform;
bgfx::UniformHandle m_shadowmap_matrices_uniform;
bgfx::UniformHandle m_light_specular_uniform;
bgfx::UniformHandle m_terrain_matrix_uniform;
2015-09-04 14:00:28 +02:00
bgfx::UniformHandle m_attenuation_params_uniform;
2015-09-05 13:08:47 +02:00
bgfx::UniformHandle m_tex_shadowmap_uniform;
bgfx::UniformHandle m_cam_view_uniform;
bgfx::UniformHandle m_cam_inv_proj_uniform;
2015-10-24 15:27:48 +02:00
2015-07-23 23:17:51 +02:00
Material* m_debug_line_material;
2015-09-05 13:08:47 +02:00
int m_has_shadowmap_define_idx;
2015-07-23 23:17:51 +02:00
private:
void operator=(const PipelineInstanceImpl&);
PipelineInstanceImpl(const PipelineInstanceImpl&);
};
2015-10-24 15:27:48 +02:00
Pipeline::Pipeline(const Path& path, ResourceManager& resource_manager, IAllocator& allocator)
2015-07-23 23:17:51 +02:00
: Resource(path, resource_manager, allocator)
{
}
2015-05-14 23:22:49 +02:00
2015-10-24 15:27:48 +02:00
PipelineInstance* PipelineInstance::create(Pipeline& pipeline, IAllocator& allocator)
2015-07-23 23:17:51 +02:00
{
return allocator.newObject<PipelineInstanceImpl>(pipeline, allocator);
}
2015-05-14 23:22:49 +02:00
2015-07-23 23:17:51 +02:00
void PipelineInstance::destroy(PipelineInstance* pipeline)
{
2015-10-24 15:27:48 +02:00
static_cast<PipelineInstanceImpl*>(pipeline)->m_allocator.deleteObject(pipeline);
2015-07-23 23:17:51 +02:00
}
2015-05-23 14:55:57 +02:00
2015-07-23 23:17:51 +02:00
Resource* PipelineManager::createResource(const Path& path)
{
return m_allocator.newObject<PipelineImpl>(path, getOwner(), m_allocator);
}
2015-07-23 23:17:51 +02:00
void PipelineManager::destroyResource(Resource& resource)
{
m_allocator.deleteObject(static_cast<PipelineImpl*>(&resource));
}
2015-07-04 15:22:28 +02:00
2015-07-23 23:17:51 +02:00
namespace LuaAPI
{
2014-10-07 22:49:01 +02:00
2015-07-23 23:17:51 +02:00
void setPass(PipelineInstanceImpl* pipeline, const char* pass)
{
pipeline->setPass(pass);
}
2014-10-07 22:49:01 +02:00
2015-10-24 15:27:48 +02:00
void setFramebuffer(PipelineInstanceImpl* pipeline, const char* framebuffer_name)
2015-07-23 23:17:51 +02:00
{
pipeline->setCurrentFramebuffer(framebuffer_name);
}
2014-05-20 23:35:09 +02:00
2015-09-04 14:00:28 +02:00
void enableAlphaWrite(PipelineInstanceImpl* pipeline)
{
pipeline->enableAlphaWrite();
}
void disableAlphaWrite(PipelineInstanceImpl* pipeline)
{
pipeline->disableAlphaWrite();
}
void enableDepthWrite(PipelineInstanceImpl* pipeline)
{
pipeline->enableDepthWrite();
}
void disableDepthWrite(PipelineInstanceImpl* pipeline)
{
pipeline->disableDepthWrite();
}
void enableRGBWrite(PipelineInstanceImpl* pipeline)
{
pipeline->enableRGBWrite();
}
void disableRGBWrite(PipelineInstanceImpl* pipeline)
{
pipeline->disableRGBWrite();
}
2015-07-23 23:17:51 +02:00
void enableBlending(PipelineInstanceImpl* pipeline)
{
pipeline->enableBlending();
}
2015-05-16 13:17:20 +02:00
2015-02-14 14:23:12 +01:00
2015-07-23 23:17:51 +02:00
void disableBlending(PipelineInstanceImpl* pipeline)
{
pipeline->disableBlending();
}
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
void applyCamera(PipelineInstanceImpl* pipeline, const char* slot)
{
2015-08-27 23:18:49 +02:00
pipeline->applyCamera(slot);
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
void clear(PipelineInstanceImpl* pipeline, const char* buffers, int color)
2015-07-23 23:17:51 +02:00
{
uint16_t flags = 0;
if (strcmp(buffers, "all") == 0)
{
flags = BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH;
}
else if (strcmp(buffers, "depth") == 0)
{
flags = BGFX_CLEAR_DEPTH;
}
bgfx::setViewClear(pipeline->m_view_idx, flags, color, 1.0f, 0);
2015-08-04 22:34:27 +02:00
bgfx::touch(pipeline->m_view_idx);
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
void renderModels(PipelineInstanceImpl* pipeline,
int64_t layer_mask,
bool is_point_light_render)
2015-07-23 23:17:51 +02:00
{
if (is_point_light_render)
{
2015-10-24 15:27:48 +02:00
pipeline->renderPointLightInfluencedGeometry(pipeline->m_camera_frustum, layer_mask);
2015-07-23 23:17:51 +02:00
}
else
{
pipeline->renderAll(pipeline->m_camera_frustum, layer_mask, true);
2015-07-23 23:17:51 +02:00
}
}
2014-11-30 15:10:13 +01:00
2015-07-23 23:17:51 +02:00
void executeCustomCommand(PipelineInstanceImpl* pipeline, const char* command)
{
pipeline->executeCustomCommand(crc32(command));
}
2014-11-30 15:10:13 +01:00
2014-10-05 15:23:52 +02:00
2015-09-12 14:51:13 +02:00
bool hasScene(PipelineInstanceImpl* pipeline)
{
2015-09-14 18:03:45 +02:00
return pipeline->getScene() != nullptr;
2015-09-12 14:51:13 +02:00
}
bool cameraExists(PipelineInstanceImpl* pipeline, const char* slot_name)
{
return pipeline->getScene()->getCameraInSlot(slot_name) != INVALID_ENTITY;
}
2015-07-23 23:17:51 +02:00
float getFPS(PipelineInstanceImpl* pipeline)
{
return pipeline->m_renderer.getEngine().getFPS();
}
2014-05-20 23:35:09 +02:00
void renderDebugShapes(PipelineInstanceImpl* pipeline)
2015-07-23 23:17:51 +02:00
{
pipeline->renderDebugLines();
pipeline->renderDebugPoints();
2015-07-23 23:17:51 +02:00
}
2014-05-20 23:35:09 +02:00
2015-09-02 11:14:42 +02:00
int renderLocalLightsShadowmaps(lua_State* L)
{
if (!LuaWrapper::isType<PipelineInstanceImpl*>(L, 1)
|| !LuaWrapper::isType<int>(L, 2)
|| !LuaWrapper::isType<const char*>(L, 4))
{
return 0;
}
FrameBuffer* fbs[16];
auto* pipeline = (PipelineInstanceImpl*)lua_touserdata(L, 1);
int len = Math::minValue((int)lua_rawlen(L, 3), lengthOf(fbs));
for (int i = 0; i < len; ++i)
{
if (lua_rawgeti(L, 3, 1 + i) == LUA_TSTRING)
{
const char* fb_name = lua_tostring(L, -1);
fbs[i] = pipeline->getFramebuffer(fb_name);
}
lua_pop(L, 1);
}
RenderScene* scene = pipeline->m_scene;
int64_t layer_mask = (int64_t)lua_tonumber(L, 2);
ComponentIndex camera = scene->getCameraInSlot(lua_tostring(L, 4));
pipeline->renderLocalLightShadowmaps(camera, fbs, len, layer_mask);
return 0;
}
2015-10-24 15:27:48 +02:00
void renderShadowmap(PipelineInstanceImpl* pipeline, int64_t layer_mask, const char* slot)
2015-07-23 23:17:51 +02:00
{
2015-10-24 15:27:48 +02:00
pipeline->renderShadowmap(pipeline->getScene()->getCameraInSlot(slot), layer_mask);
2015-07-23 23:17:51 +02:00
}
2015-05-23 14:55:57 +02:00
2014-05-20 23:35:09 +02:00
2015-07-23 23:17:51 +02:00
int createUniform(PipelineInstanceImpl* pipeline, const char* name)
{
2015-10-24 15:27:48 +02:00
bgfx::UniformHandle handle = bgfx::createUniform(name, bgfx::UniformType::Int1);
2015-07-23 23:17:51 +02:00
pipeline->m_uniforms.push(handle);
return pipeline->m_uniforms.size() - 1;
}
2014-05-20 23:35:09 +02:00
2015-05-23 14:55:57 +02:00
int loadMaterial(PipelineInstanceImpl* pipeline, const char* path)
{
ResourceManagerBase* material_manager =
pipeline->m_source.getResourceManager().get(ResourceManager::MATERIAL);
2015-10-24 15:27:48 +02:00
auto* material = static_cast<Material*>(material_manager->load(Lumix::Path(path)));
pipeline->m_materials.push(material);
return pipeline->m_materials.size() - 1;
}
void bindFramebufferTexture(PipelineInstanceImpl* pipeline,
const char* framebuffer_name,
int renderbuffer_index,
int uniform_idx)
{
pipeline->bindFramebufferTexture(framebuffer_name, renderbuffer_index, uniform_idx);
}
2015-10-24 15:27:48 +02:00
void drawQuad(PipelineInstanceImpl* pipeline,
float x,
float y,
float w,
float h,
int material_index)
2015-07-23 23:17:51 +02:00
{
pipeline->drawQuad(x, y, w, h, material_index);
2015-07-23 23:17:51 +02:00
}
2015-05-23 14:55:57 +02:00
2015-07-23 23:17:51 +02:00
void print(int x, int y, const char* text)
{
bgfx::dbgTextPrintf(x, y, 0x4f, text);
}
} // namespace LuaAPI
void PipelineImpl::registerCFunctions()
{
#define REGISTER_FUNCTION(name) \
registerCFunction(#name, LuaWrapper::wrap<decltype(&LuaAPI::name), LuaAPI::name>)
REGISTER_FUNCTION(drawQuad);
REGISTER_FUNCTION(print);
REGISTER_FUNCTION(loadMaterial);
REGISTER_FUNCTION(createUniform);
REGISTER_FUNCTION(setFramebuffer);
REGISTER_FUNCTION(enableBlending);
REGISTER_FUNCTION(disableBlending);
REGISTER_FUNCTION(enableAlphaWrite);
REGISTER_FUNCTION(disableAlphaWrite);
REGISTER_FUNCTION(enableRGBWrite);
REGISTER_FUNCTION(disableRGBWrite);
REGISTER_FUNCTION(enableDepthWrite);
REGISTER_FUNCTION(disableDepthWrite);
REGISTER_FUNCTION(setPass);
REGISTER_FUNCTION(applyCamera);
REGISTER_FUNCTION(clear);
REGISTER_FUNCTION(renderModels);
REGISTER_FUNCTION(renderShadowmap);
REGISTER_FUNCTION(renderLocalLightsShadowmaps);
REGISTER_FUNCTION(executeCustomCommand);
REGISTER_FUNCTION(renderDebugShapes);
REGISTER_FUNCTION(getFPS);
REGISTER_FUNCTION(cameraExists);
REGISTER_FUNCTION(hasScene);
REGISTER_FUNCTION(bindFramebufferTexture);
#undef REGISTER_FUNCTION
2015-07-23 23:17:51 +02:00
}
2015-05-23 14:55:57 +02:00
2014-06-16 21:18:15 +02:00
} // ~namespace Lumix