675 lines
28 KiB
C++
675 lines
28 KiB
C++
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2015 SuperTuxKart-Team
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 3
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#ifndef HEADER_COMMAND_BUFFER_HPP
|
|
#define HEADER_COMMAND_BUFFER_HPP
|
|
|
|
#include "graphics/draw_tools.hpp"
|
|
#include "graphics/gl_headers.hpp"
|
|
#include "graphics/material.hpp"
|
|
#include "graphics/materials.hpp"
|
|
#include "graphics/render_info.hpp"
|
|
#include "graphics/stk_mesh_scene_node.hpp"
|
|
#include "graphics/vao_manager.hpp"
|
|
#include <irrlicht.h>
|
|
#include <array>
|
|
#include <unordered_map>
|
|
|
|
struct InstanceList
|
|
{
|
|
GLMesh *m_mesh;
|
|
std::vector<irr::scene::ISceneNode*> m_scene_nodes;
|
|
};
|
|
|
|
typedef std::unordered_map <std::pair<scene::IMeshBuffer*, RenderInfo*>, InstanceList,
|
|
MeshRenderInfoHash, MeshRenderInfoEquals> SolidPassMeshMap;
|
|
|
|
typedef std::unordered_map <irr::scene::IMeshBuffer *, InstanceList > OtherMeshMap;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Fill origin, orientation and scale attributes
|
|
* \param node The scene node of the mesh
|
|
* \param[out] instance The instance to fill
|
|
*/
|
|
template<typename InstanceData>
|
|
void fillOriginOrientationScale(scene::ISceneNode *node, InstanceData &instance)
|
|
{
|
|
const core::matrix4 &mat = node->getAbsoluteTransformation();
|
|
const core::vector3df &Origin = mat.getTranslation();
|
|
const core::vector3df &Orientation = mat.getRotationDegrees();
|
|
const core::vector3df &Scale = mat.getScale();
|
|
instance.Origin.X = Origin.X;
|
|
instance.Origin.Y = Origin.Y;
|
|
instance.Origin.Z = Origin.Z;
|
|
instance.Orientation.X = Orientation.X;
|
|
instance.Orientation.Y = Orientation.Y;
|
|
instance.Orientation.Z = Orientation.Z;
|
|
instance.Scale.X = Scale.X;
|
|
instance.Scale.Y = Scale.Y;
|
|
instance.Scale.Z = Scale.Z;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
template<typename InstanceData>
|
|
struct InstanceFiller
|
|
{
|
|
static void add(GLMesh *, scene::ISceneNode *, InstanceData &);
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Fill a command buffer (in video RAM) with meshes data
|
|
* \param instance_list A vector of scene nodes associated with the same mesh
|
|
* \param[in,out] instance_buffer Mesh data (position, orientation, textures, etc)
|
|
* \param[in,out] command_buffer A pointer to meshes data in VRAM.
|
|
* \param[in,out] instance_buffer_offset Current offset for instance_buffer.
|
|
* Will be updated to next offset.
|
|
* \param[in,out] command_buffer_offset Current offset for command_buffer.
|
|
* Will be updated to next offset.
|
|
* \param[in,out] poly_count Number of triangles. Will be updated.
|
|
*/
|
|
template<typename T>
|
|
void FillInstances_impl(InstanceList instance_list,
|
|
T * instance_buffer,
|
|
DrawElementsIndirectCommand *command_buffer,
|
|
size_t &instance_buffer_offset,
|
|
size_t &command_buffer_offset,
|
|
size_t &poly_count)
|
|
{
|
|
// Should never be empty
|
|
GLMesh *mesh = instance_list.m_mesh;
|
|
size_t initial_offset = instance_buffer_offset;
|
|
|
|
for (unsigned i = 0; i < instance_list.m_scene_nodes.size(); i++)
|
|
{
|
|
scene::ISceneNode *node = instance_list.m_scene_nodes[i];
|
|
InstanceFiller<T>::add(mesh, node, instance_buffer[instance_buffer_offset++]);
|
|
assert(instance_buffer_offset * sizeof(T) < 10000 * sizeof(InstanceDataThreeTex));
|
|
}
|
|
|
|
DrawElementsIndirectCommand &CurrentCommand = command_buffer[command_buffer_offset++];
|
|
CurrentCommand.baseVertex = mesh->vaoBaseVertex;
|
|
CurrentCommand.count = mesh->IndexCount;
|
|
CurrentCommand.firstIndex = mesh->vaoOffset / 2;
|
|
CurrentCommand.baseInstance = initial_offset;
|
|
CurrentCommand.instanceCount = instance_buffer_offset - initial_offset;
|
|
|
|
poly_count += (instance_buffer_offset - initial_offset) * mesh->IndexCount / 3;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Bind textures for second rendering pass.
|
|
* \param mesh The mesh which owns the textures
|
|
* \param prefilled_tex Textures which have been drawn during previous rendering passes.
|
|
*/
|
|
template<typename T>
|
|
void expandTexSecondPass(const GLMesh &mesh,
|
|
const std::vector<GLuint> &prefilled_tex)
|
|
{
|
|
TexExpander<typename T::InstancedSecondPassShader>::template
|
|
expandTex(mesh, T::SecondPassTextures, prefilled_tex[0],
|
|
prefilled_tex[1], prefilled_tex[2]);
|
|
}
|
|
|
|
template<>
|
|
void expandTexSecondPass<GrassMat>(const GLMesh &mesh,
|
|
const std::vector<GLuint> &prefilled_tex);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Give acces textures for second rendering pass in shaders
|
|
* without first binding them in order to reduce driver overhead.
|
|
* (require GL_ARB_bindless_texture extension)
|
|
* \param handles The handles to textures which have been drawn
|
|
* during previous rendering passes.
|
|
*/
|
|
template<typename T>
|
|
void expandHandlesSecondPass(const std::vector<uint64_t> &handles)
|
|
{
|
|
uint64_t nulltex[10] = {};
|
|
HandleExpander<typename T::InstancedSecondPassShader>::template
|
|
expand(nulltex, T::SecondPassTextures,
|
|
handles[0], handles[1], handles[2]);
|
|
}
|
|
|
|
template<>
|
|
void expandHandlesSecondPass<GrassMat>(const std::vector<uint64_t> &handles);
|
|
|
|
|
|
#if !defined(USE_GLES2)
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class CommandBuffer
|
|
* \brief Template class to draw meshes with as few draw calls as possible
|
|
*
|
|
*/
|
|
template<int N>
|
|
class CommandBuffer
|
|
{
|
|
|
|
protected:
|
|
GLuint m_draw_indirect_cmd_id;
|
|
DrawElementsIndirectCommand *m_draw_indirect_cmd;
|
|
|
|
std::array<std::vector<GLMesh *>, N> m_meshes;
|
|
std::array<size_t,N> m_offset;
|
|
std::array<size_t,N> m_size;
|
|
|
|
size_t m_poly_count;
|
|
size_t m_instance_buffer_offset;
|
|
size_t m_command_buffer_offset;
|
|
|
|
void clearMeshes();
|
|
void mapIndirectBuffer();
|
|
|
|
// ------------------------------------------------------------------------
|
|
/** Send in VRAM all meshes associated with same material
|
|
* \param material_id The id of the material shared by the meshes
|
|
* \param mesh_map List of meshes
|
|
* \param[in,out] instance_buffer Meshes data (position, orientation, textures, etc)
|
|
*/
|
|
template<typename T, typename MeshMap>
|
|
void fillMaterial(int material_id,
|
|
MeshMap *mesh_map,
|
|
T *instance_buffer)
|
|
{
|
|
m_offset[material_id] = m_command_buffer_offset;
|
|
for(auto& instance_list : mesh_map[material_id])
|
|
{
|
|
FillInstances_impl<T>(instance_list.second,
|
|
instance_buffer,
|
|
m_draw_indirect_cmd,
|
|
m_instance_buffer_offset,
|
|
m_command_buffer_offset,
|
|
m_poly_count);
|
|
if (!CVS->isAZDOEnabled())
|
|
m_meshes[material_id].push_back(instance_list.second.m_mesh);
|
|
}
|
|
|
|
m_size[material_id] = m_command_buffer_offset - m_offset[material_id];
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
/** Send into VRAM all meshes associated with same type of material
|
|
* \param mesh_map List of meshes to send into VRAM
|
|
* \param material_list Ids of materials: meshes associated to these materials
|
|
* will be sent into VRAM
|
|
* \param instance_type The type of material
|
|
*
|
|
*/
|
|
template<typename InstanceData, typename MeshMap>
|
|
void fillInstanceData(MeshMap *mesh_map,
|
|
const std::vector<int> &material_list,
|
|
InstanceType instance_type)
|
|
{
|
|
InstanceData *instance_buffer;
|
|
|
|
if (CVS->supportsAsyncInstanceUpload())
|
|
{
|
|
instance_buffer = (InstanceData*)VAOManager::getInstance()->
|
|
getInstanceBufferPtr(instance_type);
|
|
}
|
|
else
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER,
|
|
VAOManager::getInstance()->getInstanceBuffer(instance_type));
|
|
instance_buffer = (InstanceData*)
|
|
glMapBufferRange(GL_ARRAY_BUFFER, 0,
|
|
10000 * sizeof(InstanceDataThreeTex),
|
|
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
|
}
|
|
|
|
for(int material_id: material_list)
|
|
{
|
|
fillMaterial( material_id,
|
|
mesh_map,
|
|
instance_buffer);
|
|
}
|
|
|
|
if (!CVS->supportsAsyncInstanceUpload())
|
|
{
|
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
|
CommandBuffer();
|
|
virtual ~CommandBuffer() { glDeleteBuffers(1, &m_draw_indirect_cmd_id); }
|
|
|
|
inline size_t getPolyCount() const {return m_poly_count;}
|
|
|
|
inline void bind() const
|
|
{
|
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_indirect_cmd_id);
|
|
}
|
|
}; //CommandBuffer
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class SolidCommandBuffer
|
|
* This class is used for rendering meshes during solid first pass
|
|
* and solid second pass.
|
|
*/
|
|
class SolidCommandBuffer: public CommandBuffer<static_cast<int>(Material::SHADERTYPE_COUNT)>
|
|
{
|
|
public:
|
|
SolidCommandBuffer();
|
|
void fill(SolidPassMeshMap *mesh_map);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** First rendering pass; draw all meshes associated with the same material
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shader associated with T material
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void drawIndirectFirstPass(Uniforms...uniforms) const
|
|
{
|
|
T::InstancedFirstPassShader::getInstance()->use();
|
|
T::InstancedFirstPassShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
for (unsigned i = 0; i < m_meshes[T::MaterialType].size(); i++)
|
|
{
|
|
GLMesh *mesh = m_meshes[T::MaterialType][i];
|
|
#ifdef DEBUG
|
|
if (mesh->VAOType != T::VertexType)
|
|
{
|
|
Log::error("CommandBuffer", "Wrong instanced vertex format (hint : %s)",
|
|
mesh->textures[0]->getName().getPath().c_str());
|
|
continue;
|
|
}
|
|
#endif
|
|
TexExpander<typename T::InstancedFirstPassShader>::template
|
|
expandTex(*mesh, T::FirstPassTextures);
|
|
if (!mesh->mb->getMaterial().BackfaceCulling)
|
|
glDisable(GL_CULL_FACE);
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand)));
|
|
if (!mesh->mb->getMaterial().BackfaceCulling)
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
} //drawIndirectFirstPass
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** First rendering pass; draw all meshes associated with the same material
|
|
* Faster than drawIndirectFirstPass.
|
|
* Require OpenGL AZDO extensions
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shader associated with T material
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void multidrawFirstPass(Uniforms...uniforms) const
|
|
{
|
|
if (m_size[T::MaterialType])
|
|
{
|
|
T::InstancedFirstPassShader::getInstance()->use();
|
|
T::InstancedFirstPassShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[T::MaterialType] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[T::MaterialType],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidrawFirstPass
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Second rendering pass; draw all meshes associated with the same material
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*
|
|
* \tparam T The material
|
|
* \param prefilled_tex Textures filled during previous rendering passes (diffuse, depth, etc)
|
|
* \param uniforms Uniforms needed by the shader associated with T material
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void drawIndirectSecondPass(const std::vector<GLuint> &prefilled_tex,
|
|
Uniforms...uniforms ) const
|
|
{
|
|
T::InstancedSecondPassShader::getInstance()->use();
|
|
T::InstancedSecondPassShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
for (unsigned i = 0; i < m_meshes[T::MaterialType].size(); i++)
|
|
{
|
|
GLMesh *mesh = m_meshes[T::MaterialType][i];
|
|
expandTexSecondPass<T>(*mesh, prefilled_tex);
|
|
|
|
//TODO: next 10 lines are duplicated in draw_tools.hpp (see CustomUnrollArgs::drawMesh)
|
|
//TODO: find a way to remove duplicated code
|
|
const bool support_change_hue = (mesh->m_render_info != NULL &&
|
|
mesh->m_material != NULL);
|
|
const bool need_change_hue =
|
|
(support_change_hue && mesh->m_render_info->getHue() > 0.0f);
|
|
if (need_change_hue)
|
|
{
|
|
T::InstancedSecondPassShader::getInstance()->changeableColor
|
|
(mesh->m_render_info->getHue(),
|
|
mesh->m_material->getColorizationFactor());
|
|
}
|
|
if (!mesh->mb->getMaterial().BackfaceCulling)
|
|
glDisable(GL_CULL_FACE);
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand)));
|
|
if (!mesh->mb->getMaterial().BackfaceCulling)
|
|
glEnable(GL_CULL_FACE);
|
|
if (need_change_hue)
|
|
{
|
|
// Reset after changing
|
|
T::InstancedSecondPassShader::getInstance()->changeableColor();
|
|
}
|
|
}
|
|
} //drawIndirectSecondPass
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Second rendering pass; draw all meshes associated with the same material
|
|
* Faster than drawIndirectSecondPass.
|
|
* Require OpenGL AZDO extensions
|
|
*
|
|
* \tparam T The material
|
|
* \param handles Handles to textures filled during previous rendering passes
|
|
* (diffuse, depth, etc)
|
|
* \param uniforms Uniforms needed by the shader associated with T material
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void multidraw2ndPass(const std::vector<uint64_t> &handles,
|
|
Uniforms... uniforms) const
|
|
{
|
|
if (m_size[T::MaterialType])
|
|
{
|
|
T::InstancedSecondPassShader::getInstance()->use();
|
|
T::InstancedSecondPassShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
expandHandlesSecondPass<T>(handles);
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[T::MaterialType] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[T::MaterialType],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidraw2ndPass
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw normals (debug): draw all meshes associated with the same material
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*
|
|
* \tparam T The material
|
|
*/
|
|
template<typename T>
|
|
void drawIndirectNormals() const
|
|
{
|
|
NormalVisualizer::getInstance()->use();
|
|
NormalVisualizer::getInstance()->setUniforms(video::SColor(255, 0, 255, 0));
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
for (unsigned i = 0; i < m_meshes[T::MaterialType].size(); i++)
|
|
{
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand))); }
|
|
} // drawIndirectNormals
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw normals (debug): draw all meshes associated with the same material
|
|
* Faster than drawIndirectNormals.
|
|
* Require OpenGL AZDO extensions
|
|
*
|
|
* \tparam T The material
|
|
*/
|
|
template<typename T>
|
|
void multidrawNormals() const
|
|
{
|
|
|
|
if (m_size[T::MaterialType])
|
|
{
|
|
NormalVisualizer::getInstance()->use();
|
|
NormalVisualizer::getInstance()->setUniforms(video::SColor(255, 0, 255, 0));
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
T::Instance));
|
|
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[T::MaterialType] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[T::MaterialType],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidrawNormals
|
|
}; //SolidCommandBuffer
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class ShadowCommandBuffer
|
|
* This class is used for rendering shadows.
|
|
*/
|
|
class ShadowCommandBuffer: public CommandBuffer<4*static_cast<int>(Material::SHADERTYPE_COUNT)>
|
|
{
|
|
public:
|
|
ShadowCommandBuffer();
|
|
void fill(OtherMeshMap *mesh_map);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw shadowmaps for meshes with the same material
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shadow shader associated with T material
|
|
* \param cascade The cascade id (see cascading shadow maps)
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void drawIndirect(unsigned cascade, Uniforms ...uniforms) const
|
|
{
|
|
T::InstancedShadowPassShader::getInstance()->use();
|
|
T::InstancedShadowPassShader::getInstance()->setUniforms(cascade, uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
InstanceTypeShadow));
|
|
|
|
int material_id = T::MaterialType + cascade * Material::SHADERTYPE_COUNT;
|
|
|
|
for (unsigned i = 0; i < m_meshes[material_id].size(); i++)
|
|
{
|
|
GLMesh *mesh = m_meshes[material_id][i];
|
|
|
|
TexExpander<typename T::InstancedShadowPassShader>::template
|
|
expandTex(*mesh, T::ShadowTextures);
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[material_id] + i)
|
|
* sizeof(DrawElementsIndirectCommand)));
|
|
} // for i
|
|
} // drawIndirect
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw shadowmaps for meshes with the same material
|
|
* Faster than drawIndirect.
|
|
* Require OpenGL AZDO extensions
|
|
*
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shadow shader associated with T material
|
|
* \param cascade The cascade id (see cascading shadow maps)
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void multidrawShadow(unsigned cascade, Uniforms ...uniforms) const
|
|
{
|
|
int material_id = T::MaterialType + cascade * Material::SHADERTYPE_COUNT;
|
|
|
|
if (m_size[material_id])
|
|
{
|
|
T::InstancedShadowPassShader::getInstance()->use();
|
|
T::InstancedShadowPassShader::getInstance()->setUniforms(cascade, uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
InstanceTypeShadow));
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[material_id] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[material_id],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidrawShadow
|
|
}; //ShadowCommandBuffer
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class ReflectiveShadowMapCommandBuffer
|
|
* This class is used for rendering the reflective shadow map once per track.
|
|
*/
|
|
class ReflectiveShadowMapCommandBuffer: public CommandBuffer<static_cast<int>(Material::SHADERTYPE_COUNT)>
|
|
{
|
|
public:
|
|
ReflectiveShadowMapCommandBuffer();
|
|
void fill(OtherMeshMap *mesh_map);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw reflective shadow map for meshes with the same material
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shadow shader associated with T material
|
|
*/
|
|
template<typename T, typename...Uniforms>
|
|
void drawIndirect(Uniforms ...uniforms) const
|
|
{
|
|
T::InstancedRSMShader::getInstance()->use();
|
|
T::InstancedRSMShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
InstanceTypeRSM));
|
|
|
|
for (unsigned i = 0; i < m_meshes[T::MaterialType].size(); i++)
|
|
{
|
|
GLMesh *mesh = m_meshes[T::MaterialType][i];
|
|
|
|
TexExpander<typename T::InstancedRSMShader>::template expandTex(*mesh, T::RSMTextures);
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand)));
|
|
}
|
|
} //drawIndirect
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw reflective shadow map for meshes with the same material
|
|
* Faster than drawIndirect.
|
|
* Require OpenGL AZDO extensions
|
|
*
|
|
* \tparam T The material
|
|
* \param uniforms Uniforms needed by the shadow shader associated with T material
|
|
*/
|
|
template<typename T, typename... Uniforms>
|
|
void multidraw(Uniforms...uniforms) const
|
|
{
|
|
if (m_size[T::MaterialType])
|
|
{
|
|
T::InstancedRSMShader::getInstance()->use();
|
|
T::InstancedRSMShader::getInstance()->setUniforms(uniforms...);
|
|
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
|
InstanceTypeRSM));
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[T::MaterialType] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[T::MaterialType],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidraw
|
|
}; //ReflectiveShadowMapCommandBuffer
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class InstancedColorizeShader
|
|
* Draw meshes with glow color.
|
|
*/
|
|
class InstancedColorizeShader : public Shader<InstancedColorizeShader>
|
|
{
|
|
public:
|
|
InstancedColorizeShader()
|
|
{
|
|
loadProgram(OBJECT, GL_VERTEX_SHADER, "glow_object.vert",
|
|
GL_FRAGMENT_SHADER, "glow_object.frag");
|
|
assignUniforms();
|
|
} // InstancedColorizeShader
|
|
}; // InstancedColorizeShader
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/**
|
|
* \class GlowCommandBuffer
|
|
* This class is used for rendering glowing meshes.
|
|
*/
|
|
class GlowCommandBuffer: public CommandBuffer<1>
|
|
{
|
|
public:
|
|
GlowCommandBuffer();
|
|
void fill(OtherMeshMap *mesh_map);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw glowing meshes.
|
|
* Require OpenGL 4.0 (or higher)
|
|
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
|
|
*/
|
|
void drawIndirect() const
|
|
{
|
|
InstancedColorizeShader::getInstance()->use();
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(irr::video::EVT_STANDARD,
|
|
InstanceTypeGlow));
|
|
for (unsigned i = 0; i < m_meshes[0].size(); i++)
|
|
{
|
|
glDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)((m_offset[0] + i) * sizeof(DrawElementsIndirectCommand)));
|
|
}
|
|
} //drawIndirect
|
|
|
|
// ----------------------------------------------------------------------------
|
|
/** Draw glowing meshes.
|
|
* Faster than drawIndirect.
|
|
* Require OpenGL AZDO extensions
|
|
*/
|
|
void multidraw() const
|
|
{
|
|
InstancedColorizeShader::getInstance()->use();
|
|
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(irr::video::EVT_STANDARD,
|
|
InstanceTypeGlow));
|
|
if (m_size[0])
|
|
{
|
|
glMultiDrawElementsIndirect(GL_TRIANGLES,
|
|
GL_UNSIGNED_SHORT,
|
|
(const void*)(m_offset[0] * sizeof(DrawElementsIndirectCommand)),
|
|
(int) m_size[0],
|
|
sizeof(DrawElementsIndirectCommand));
|
|
}
|
|
} // multidraw
|
|
};
|
|
#endif // !defined(USE_GLES2)
|
|
#endif //HEADER_COMMAND_BUFFER_HPP
|