Add dynamic draw call for skidmarks

This commit is contained in:
Benau 2017-12-28 16:14:09 +08:00
parent 52b19dd83a
commit 590850eacf
16 changed files with 771 additions and 314 deletions

View File

@ -8,6 +8,7 @@
#include "vector3d.h" #include "vector3d.h"
#include "vector2d.h" #include "vector2d.h"
#include "SColor.h" #include "SColor.h"
#include <cstring>
namespace irr namespace irr
{ {
@ -253,6 +254,7 @@ struct S3DVertexTangents : public S3DVertex
} }
}; };
//! SPM usage. */
struct S3DVertexSkinnedMesh struct S3DVertexSkinnedMesh
{ {
core::vector3df m_position; core::vector3df m_position;
@ -263,13 +265,22 @@ struct S3DVertexSkinnedMesh
s16 m_joint_idx[4]; s16 m_joint_idx[4];
s16 m_weight[4]; s16 m_weight[4];
S3DVertexSkinnedMesh()
{
m_normal = 0;
m_color.color = -1;
memset(m_all_uvs, 0, 8);
m_tangent = 0;
memset(m_joint_idx, 0, 8);
memset(m_weight, 0, 8);
}
E_VERTEX_TYPE getType() const E_VERTEX_TYPE getType() const
{ {
return EVT_SKINNED_MESH; return EVT_SKINNED_MESH;
} }
}; };
inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType) inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
{ {
switch (vertexType) switch (vertexType)

View File

@ -204,6 +204,7 @@ void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
parseSceneManager( parseSceneManager(
irr_driver->getSceneManager()->getRootSceneNode()->getChildren(), irr_driver->getSceneManager()->getRootSceneNode()->getChildren(),
camnode); camnode);
SP::handleDynamicDrawCall();
SP::updateModelMatrix(); SP::updateModelMatrix();
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
@ -221,7 +222,7 @@ void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
do do
{ {
reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000); reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000);
} }
while (reason == GL_TIMEOUT_EXPIRED); while (reason == GL_TIMEOUT_EXPIRED);
} }
glDeleteSync(m_sync); glDeleteSync(m_sync);

View File

@ -86,7 +86,8 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
Material* MaterialManager::getMaterialSPM(std::string lay_one_tex_lc, Material* MaterialManager::getMaterialSPM(std::string lay_one_tex_lc,
std::string lay_two_tex_lc) std::string lay_two_tex_lc,
const std::string& def_shader_name)
{ {
std::string orignal_layer_one = lay_one_tex_lc; std::string orignal_layer_one = lay_one_tex_lc;
core::stringc lc(lay_one_tex_lc.c_str()); core::stringc lc(lay_one_tex_lc.c_str());
@ -140,7 +141,8 @@ Material* MaterialManager::getMaterialSPM(std::string lay_one_tex_lc,
} }
} // for i } // for i
} }
return getSPMaterial("solid", StringUtils::getBasename(orignal_layer_one)); return getSPMaterial(def_shader_name,
StringUtils::getBasename(orignal_layer_one));
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -64,7 +64,8 @@ public:
video::E_MATERIAL_TYPE material_type); video::E_MATERIAL_TYPE material_type);
Material* getMaterialFor(video::ITexture* t); Material* getMaterialFor(video::ITexture* t);
Material* getMaterialSPM(std::string lay_one_tex_lc, Material* getMaterialSPM(std::string lay_one_tex_lc,
std::string lay_two_tex_lc); std::string lay_two_tex_lc,
const std::string& def_shader_name = "solid");
void setAllMaterialFlags(video::ITexture* t, void setAllMaterialFlags(video::ITexture* t,
scene::IMeshBuffer *mb); scene::IMeshBuffer *mb);
void adjustForFog(video::ITexture* t, void adjustForFog(video::ITexture* t,

View File

@ -20,42 +20,34 @@
#include "graphics/skid_marks.hpp" #include "graphics/skid_marks.hpp"
#include "config/stk_config.hpp" #include "config/stk_config.hpp"
#include "graphics/irr_driver.hpp" #include "graphics/central_settings.hpp"
#include "graphics/stk_mesh_scene_node.hpp" #include "graphics/material_manager.hpp"
#include "karts/controller/controller.hpp"
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "karts/skidding.hpp" #include "karts/skidding.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_dynamic_draw_call.hpp"
#include "graphics/sp/sp_per_object_uniform.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
#include "physics/btKart.hpp" #include "physics/btKart.hpp"
#include "utils/mini_glm.hpp"
#include <IMeshSceneNode.h> #ifndef SERVER_ONLY
#include <SMesh.h>
float SkidMarks::m_avoid_z_fighting = 0.005f; float SkidMarks::m_avoid_z_fighting = 0.005f;
const int SkidMarks::m_start_alpha = 128; const int SkidMarks::m_start_alpha = 200;
const int SkidMarks::m_start_grey = 32; const int SkidMarks::m_start_grey = 32;
/** Initialises empty skid marks. */ /** Initialises empty skid marks. */
SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart) SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart)
{ {
m_width = width; m_width = width;
m_material = new video::SMaterial(); m_material = material_manager->getMaterialSPM("skidmarks.png", "",
m_material->MaterialType = video::EMT_ONETEXTURE_BLEND; "alphablend");
m_material->MaterialTypeParam = m_shader = SP::getSPShader("alphablend");
pack_textureBlendFunc(video::EBF_SRC_ALPHA, assert(m_shader != NULL);
video::EBF_ONE_MINUS_SRC_ALPHA, m_skid_marking = false;
video::EMFN_MODULATE_1X,
video::EAS_TEXTURE | video::EAS_VERTEX_COLOR);
m_material->AmbientColor = video::SColor(128, 0, 0, 0);
m_material->DiffuseColor = video::SColor(128, 16, 16, 16);
//m_material->AmbientColor = video::SColor(255, 255, 255, 255);
//m_material->DiffuseColor = video::SColor(255, 255, 255, 255);
m_material->setFlag(video::EMF_ANISOTROPIC_FILTER, true);
m_material->setFlag(video::EMF_ZWRITE_ENABLE, false);
m_material->Shininess = 0;
m_material->TextureLayer[0].Texture = irr_driver->getTexture("skidmarks.png");
m_skid_marking = false;
m_current = -1;
} // SkidMark } // SkidMark
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -63,7 +55,6 @@ SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart)
SkidMarks::~SkidMarks() SkidMarks::~SkidMarks()
{ {
reset(); // remove all skid marks reset(); // remove all skid marks
delete m_material;
} // ~SkidMarks } // ~SkidMarks
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -71,17 +62,9 @@ SkidMarks::~SkidMarks()
*/ */
void SkidMarks::reset() void SkidMarks::reset()
{ {
for(unsigned int i=0; i<m_nodes.size(); i++)
{
irr_driver->removeNode(m_nodes[i]);
m_left[i]->drop();
m_right[i]->drop();
}
m_left.clear(); m_left.clear();
m_right.clear(); m_right.clear();
m_nodes.clear();
m_skid_marking = false; m_skid_marking = false;
m_current = -1;
} // reset } // reset
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -96,11 +79,26 @@ void SkidMarks::update(float dt, bool force_skid_marks,
if(m_kart.isWheeless()) if(m_kart.isWheeless())
return; return;
float f = dt/stk_config->m_skid_fadeout_time*m_start_alpha; float f = dt / stk_config->m_skid_fadeout_time;
for(unsigned int i=0; i<m_left.size(); i++) auto it = m_left.begin();
while (it != m_left.end())
{ {
m_left[i]->fade(f); if ((*it)->fade(f))
m_right[i]->fade(f); {
it = m_left.erase(it);
continue;
}
it++;
}
it = m_right.begin();
while (it != m_right.end())
{
if ((*it)->fade(f))
{
it = m_right.erase(it);
continue;
}
it++;
} }
// Get raycast information // Get raycast information
@ -129,17 +127,11 @@ void SkidMarks::update(float dt, bool force_skid_marks,
if(m_skid_marking) if(m_skid_marking)
{ {
assert(!m_left.empty());
assert(!m_right.empty());
if (!is_skidding) // end skid marking if (!is_skidding) // end skid marking
{ {
m_skid_marking = false; m_skid_marking = false;
#ifndef SERVER_ONLY
// The vertices and indices will not change anymore
// (till these skid mark quads are deleted)
m_left[m_current]->setHardwareMappingHint(scene::EHM_STATIC);
m_right[m_current]->setHardwareMappingHint(scene::EHM_STATIC);
if (STKMeshSceneNode* stkm = dynamic_cast<STKMeshSceneNode*>(m_nodes[m_current]))
stkm->setReloadEachFrame(false);
#endif
return; return;
} }
@ -149,23 +141,16 @@ void SkidMarks::update(float dt, bool force_skid_marks,
delta.normalize(); delta.normalize();
delta *= m_width*0.5f; delta *= m_width*0.5f;
Vec3 start = m_left[m_current]->getCenterStart(); Vec3 start = m_left.back()->getCenterStart();
Vec3 newPoint = (raycast_left + raycast_right)/2; Vec3 newPoint = (raycast_left + raycast_right)/2;
// this linear distance does not account for the kart turning, it's true, // this linear distance does not account for the kart turning, it's true,
// but it produces good enough results // but it produces good enough results
float distance = (newPoint - start).length(); float distance = (newPoint - start).length();
m_left [m_current]->add(raycast_left-delta, raycast_left+delta, m_left.back()->add(raycast_left-delta, raycast_left+delta,
m_kart.getNormal(), distance); m_kart.getNormal(), distance);
m_right[m_current]->add(raycast_right-delta, raycast_right+delta, m_right.back()->add(raycast_right-delta, raycast_right+delta,
m_kart.getNormal(), distance); m_kart.getNormal(), distance);
// Adjust the boundary box of the mesh to include the
// adjusted aabb of its buffers.
//core::aabbox3df aabb=m_nodes[m_current]->getMesh()
// ->getBoundingBox();
//aabb.addInternalBox(m_left[m_current]->getAABB());
//aabb.addInternalBox(m_right[m_current]->getAABB());
//m_nodes[m_current]->getMesh()->setBoundingBox(aabb);
return; return;
} }
@ -182,89 +167,75 @@ void SkidMarks::update(float dt, bool force_skid_marks,
delta.normalize(); delta.normalize();
delta *= m_width*0.5f; delta *= m_width*0.5f;
SkidMarkQuads *smq_left = const int cleaning_threshold =
new SkidMarkQuads(raycast_left-delta, raycast_left+delta,
m_kart.getNormal(), m_material, m_avoid_z_fighting,
custom_color);
scene::SMesh *new_mesh = new scene::SMesh();
new_mesh->addMeshBuffer(smq_left);
SkidMarkQuads *smq_right =
new SkidMarkQuads(raycast_right-delta, raycast_right+delta,
m_kart.getNormal(), m_material, m_avoid_z_fighting,
custom_color);
new_mesh->addMeshBuffer(smq_right);
scene::ISceneNode *new_node = irr_driver->addMesh(new_mesh, "skidmark");
#ifndef SERVER_ONLY
if (STKMeshSceneNode* stkm = dynamic_cast<STKMeshSceneNode*>(new_node))
stkm->setReloadEachFrame(true);
#ifdef DEBUG
std::string debug_name = m_kart.getIdent()+" (skid-mark)";
new_node->setName(debug_name.c_str());
#endif
#endif
// We don't keep a reference to the mesh here, so we have to decrement
// the reference count (which is set to 1 when doing "new SMesh())".
// The scene node will keep the mesh alive.
new_mesh->drop();
m_current++;
int cleaning_threshold =
core::clamp(int(World::getWorld()->getNumKarts()), 5, 15); core::clamp(int(World::getWorld()->getNumKarts()), 5, 15);
if(m_current>=int(stk_config->m_max_skidmarks/cleaning_threshold)) while ((int)m_left.size() >=
m_current = 0; stk_config->m_max_skidmarks / cleaning_threshold)
if(m_current>=(int)m_left.size())
{ {
m_left. push_back (smq_left ); m_left.erase(m_left.begin());
m_right.push_back (smq_right);
m_nodes.push_back (new_node);
} }
else while ((int)m_right.size() >=
stk_config->m_max_skidmarks / cleaning_threshold)
{ {
irr_driver->removeNode(m_nodes[m_current]); m_right.erase(m_right.begin());
// Not necessary to delete m_nodes: removeNode }
// deletes the node since its refcount reaches zero.
m_left[m_current]->drop();
m_right[m_current]->drop();
m_left [m_current] = smq_left; m_left.emplace_back(
m_right [m_current] = smq_right; new SkidMarkQuads(raycast_left-delta, raycast_left+delta,
m_nodes [m_current] = new_node; m_kart.getNormal(), m_material, m_shader,
} m_avoid_z_fighting, custom_color));
m_right.emplace_back(
new SkidMarkQuads(raycast_right-delta, raycast_right+delta,
m_kart.getNormal(), m_material, m_shader,
m_avoid_z_fighting, custom_color));
m_skid_marking = true; m_skid_marking = true;
// More triangles are added each frame, so for now leave it
// to stream.
m_left[m_current]->setHardwareMappingHint(scene::EHM_STREAM);
m_right[m_current]->setHardwareMappingHint(scene::EHM_STREAM);
} // update } // update
//============================================================================= //=============================================================================
SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left, SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left,
const Vec3 &right, const Vec3 &right,
const Vec3 &normal, const Vec3 &normal,
video::SMaterial *material, Material* material,
SP::SPShader* shader,
float z_offset, float z_offset,
video::SColor* custom_color) video::SColor* custom_color)
: scene::SMeshBuffer()
{ {
m_center_start = (left + right)/2; m_center_start = (left + right)/2;
m_z_offset = z_offset; m_z_offset = z_offset;
m_fade_out = 0.0f; m_fade_out = 0.0f;
m_dy_dc = new SP::SPDynamicDrawCall(scene::EPT_TRIANGLE_STRIP,
shader, material);
static_cast<SP::SPPerObjectUniform*>(m_dy_dc)->addAssignerFunction
("custom_alpha", [this](SP::SPUniformAssigner* ua)->void
{
// SP custom_alpha is assigned 1 - x, so this is correct
ua->setValue(m_fade_out);
});
SP::addDynamicDrawCall(m_dy_dc);
m_start_color = (custom_color != NULL ? *custom_color : m_start_color = (custom_color != NULL ? *custom_color :
video::SColor(255, video::SColor(255, SkidMarks::m_start_grey, SkidMarks::m_start_grey,
SkidMarks::m_start_grey, SkidMarks::m_start_grey));
SkidMarks::m_start_grey,
SkidMarks::m_start_grey)); if (CVS->isDefferedEnabled())
{
video::SColorf tmp(m_start_color);
m_start_color.setRed(SP::srgbToLinear(tmp.r));
m_start_color.setGreen(SP::srgbToLinear(tmp.g));
m_start_color.setBlue(SP::srgbToLinear(tmp.b));
}
Material = *material;
m_aabb = core::aabbox3df(left.toIrrVector());
add(left, right, normal, 0.0f); add(left, right, normal, 0.0f);
} // SkidMarkQuads } // SkidMarkQuads
//-----------------------------------------------------------------------------
SkidMarks::SkidMarkQuads::~SkidMarkQuads()
{
SP::removeDynamicDrawCall(m_dy_dc);
delete m_dy_dc;
} // ~SkidMarkQuads
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Adds the two points to this SkidMarkQuads. /** Adds the two points to this SkidMarkQuads.
* \param left,right Left and right coordinates. * \param left,right Left and right coordinates.
@ -276,78 +247,50 @@ void SkidMarks::SkidMarkQuads::add(const Vec3 &left,
{ {
// The skid marks must be raised slightly higher, otherwise it blends // The skid marks must be raised slightly higher, otherwise it blends
// too much with the track. // too much with the track.
int n = Vertices.size(); int n = m_dy_dc->getVertexCount();
video::S3DVertex v; video::S3DVertexSkinnedMesh v;
v.Color = m_start_color; v.m_color = m_start_color;
v.Color.setAlpha(0); // initially create all vertices at alpha=0... v.m_color.setAlpha(0); // initially create all vertices at alpha=0...
// then when adding a new set of vertices, make the previous 2 opaque. // then when adding a new set of vertices, make the previous 2 opaque.
// this ensures that the last two vertices are always at alpha=0, // this ensures that the last two vertices are always at alpha=0,
// producing a fade-out effect // producing a fade-out effect
if (n > 4) if (n > 2)
{ {
Vertices[n - 1].Color.setAlpha(m_start_alpha); m_dy_dc->getSPMVertex()[n - 1].m_color.setAlpha(m_start_alpha);
Vertices[n - 2].Color.setAlpha(m_start_alpha); m_dy_dc->getSPMVertex()[n - 2].m_color.setAlpha(m_start_alpha);
} }
v.Pos = Vec3(left + normal * m_z_offset).toIrrVector(); v.m_position = Vec3(right + normal * m_z_offset).toIrrVector();
v.Normal = normal.toIrrVector(); v.m_normal = MiniGLM::compressVector3(normal.toIrrVector());
v.TCoords = core::vector2df(0.0f, distance*0.5f); short half_float_1 = 15360;
Vertices.push_back(v); v.m_all_uvs[0] = half_float_1;
v.Pos = Vec3(right + normal * m_z_offset).toIrrVector(); v.m_all_uvs[1] = MiniGLM::toFloat16(distance * 0.5f);
v.TCoords = core::vector2df(1.0f, distance*0.5f); m_dy_dc->addSPMVertex(v);
Vertices.push_back(v);
// Out of the box Irrlicht only supports triangle meshes and not v.m_position = Vec3(left + normal * m_z_offset).toIrrVector();
// triangle strips. Since this is a strip it would be more efficient v.m_all_uvs[0] = 0;
// to use a special triangle strip scene node. v.m_all_uvs[1] = MiniGLM::toFloat16(distance * 0.5f);
if(n>=2) m_dy_dc->addSPMVertex(v);
{ m_dy_dc->setUpdateOffset(n > 2 ? n - 2 : n);
Indices.push_back(n-2); m_dy_dc->recalculateBoundingBox();
Indices.push_back(n );
Indices.push_back(n-1);
Indices.push_back(n-1);
Indices.push_back(n );
Indices.push_back(n+1);
}
// Adjust the axis-aligned boundary boxes.
m_aabb.addInternalPoint(left.toIrrVector() );
m_aabb.addInternalPoint(right.toIrrVector());
setBoundingBox(m_aabb);
setDirty();
} // add } // add
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Fades the current skid marks. /** Fades the current skid marks.
* \param f fade factor. * \param f fade factor.
* \return true if this skid mark can be deleted (alpha == zero)
*/ */
void SkidMarks::SkidMarkQuads::fade(float f) bool SkidMarks::SkidMarkQuads::fade(float f)
{ {
m_fade_out += f; m_fade_out += f;
// Changing the alpha value is quite expensive, so it's only done if (m_fade_out >= 1.0f)
// about 10 times till 0 is reached.
if(m_fade_out*10>SkidMarks::m_start_alpha)
{ {
video::SColor &c = Material.DiffuseColor; return true;
int a = c.getAlpha();
a -= (a < m_fade_out ? a : (int)m_fade_out);
c.setAlpha(a);
// the first 2 and last 2 already have alpha=0 for fade-in and fade-out
for(unsigned int i=2; i<Vertices.size() - 2; i++)
{
Vertices[i].Color.setAlpha(a);
}
m_fade_out = 0.0f;
} }
return false;
} // fade } // fade
// ---------------------------------------------------------------------------- #endif
/** Sets the fog handling for the skid marks.
* \param enabled True if fog should be enabled.
*/
void SkidMarks::adjustFog(bool enabled)
{
m_material->FogEnable = enabled;
}

View File

@ -20,17 +20,21 @@
#ifndef HEADER_SKID_MARK_HPP #ifndef HEADER_SKID_MARK_HPP
#define HEADER_SKID_MARK_HPP #define HEADER_SKID_MARK_HPP
#include <aabbox3d.h>
#include <memory>
#include <SColor.h>
#include <vector> #include <vector>
#include <aabbox3d.h>
#include <SMeshBuffer.h>
namespace irr
{
namespace video { class SMaterial; }
namespace scene { class ISceneNode; }
}
using namespace irr; using namespace irr;
class Material;
namespace SP
{
class SPDynamicDrawCall;
class SPShader;
}
#include "utils/no_copy.hpp" #include "utils/no_copy.hpp"
#include "utils/vec3.hpp" #include "utils/vec3.hpp"
@ -51,9 +55,6 @@ private:
/** Reduce effect of Z-fighting. */ /** Reduce effect of Z-fighting. */
float m_width; float m_width;
/** Index of current (last added) skid mark quad. */
int m_current;
/** Initial alpha value. */ /** Initial alpha value. */
static const int m_start_alpha; static const int m_start_alpha;
@ -61,10 +62,13 @@ private:
static const int m_start_grey; static const int m_start_grey;
/** Material to use for the skid marks. */ /** Material to use for the skid marks. */
video::SMaterial *m_material; Material* m_material;
/** Shader(alphablend) to use for the skid marks. */
SP::SPShader* m_shader;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
class SkidMarkQuads : public scene::SMeshBuffer, public NoCopy class SkidMarkQuads : public NoCopy
{ {
/** Used to move skid marks at the same location slightly on /** Used to move skid marks at the same location slightly on
* top of each other to avoid a 'wobbling' effect when sometines * top of each other to avoid a 'wobbling' effect when sometines
@ -74,35 +78,30 @@ private:
/** Fade out = alpha value. */ /** Fade out = alpha value. */
float m_fade_out; float m_fade_out;
/** For culling, we need the overall radius of the skid marks. We
* approximate this by maintaining an axis-aligned boundary box. */
core::aabbox3df m_aabb;
video::SColor m_start_color; video::SColor m_start_color;
/** Vector marking the start of the skidmarks (located between left and right wheel) */ /** Vector marking the start of the skidmarks (located between left and right wheel) */
Vec3 m_center_start; Vec3 m_center_start;
SP::SPDynamicDrawCall* m_dy_dc;
public: public:
SkidMarkQuads (const Vec3 &left, const Vec3 &right, SkidMarkQuads (const Vec3 &left, const Vec3 &right,
const Vec3 &normal, video::SMaterial *material, const Vec3 &normal, Material* material,
SP::SPShader* shader,
float z_offset, video::SColor* custom_color = NULL); float z_offset, video::SColor* custom_color = NULL);
~SkidMarkQuads();
void add (const Vec3 &left, void add (const Vec3 &left,
const Vec3 &right, const Vec3 &right,
const Vec3 &normal, const Vec3 &normal,
float distance); float distance);
void fade (float f); bool fade (float f);
/** Returns the aabb of this skid mark quads. */
const core::aabbox3df &getAABB() { return m_aabb; }
const Vec3& getCenterStart() const { return m_center_start; } const Vec3& getCenterStart() const { return m_center_start; }
}; // SkidMarkQuads }; // SkidMarkQuads
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Two skidmark objects for the left and right wheel. */ /** Two skidmark objects for the left and right wheel. */
std::vector<SkidMarkQuads *> m_left, m_right; std::vector<std::unique_ptr<SkidMarkQuads> > m_left, m_right;
/** The nodes where each left/right pair is attached to. */
std::vector<scene::ISceneNode *> m_nodes;
/** Shared static so that consecutive skidmarks are at a slightly /** Shared static so that consecutive skidmarks are at a slightly
* different height. */ * different height. */
@ -115,8 +114,6 @@ public:
video::SColor* custom_color = NULL); video::SColor* custom_color = NULL);
void reset(); void reset();
void adjustFog(bool enabled);
}; // SkidMarks }; // SkidMarks
#endif #endif

View File

@ -30,6 +30,7 @@
#include "graphics/rtts.hpp" #include "graphics/rtts.hpp"
#include "graphics/shaders.hpp" #include "graphics/shaders.hpp"
#include "graphics/stk_tex_manager.hpp" #include "graphics/stk_tex_manager.hpp"
#include "graphics/sp/sp_dynamic_draw_call.hpp"
#include "graphics/sp/sp_instanced_data.hpp" #include "graphics/sp/sp_instanced_data.hpp"
#include "graphics/sp/sp_per_object_uniform.hpp" #include "graphics/sp/sp_per_object_uniform.hpp"
#include "graphics/sp/sp_mesh.hpp" #include "graphics/sp/sp_mesh.hpp"
@ -75,7 +76,7 @@ SPShader* g_glow_shader = NULL;
typedef std::unordered_map<SPShader*, std::unordered_map<std::string, typedef std::unordered_map<SPShader*, std::unordered_map<std::string,
std::unordered_set<SPMeshBuffer*> > > DrawCall; std::unordered_set<SPMeshBuffer*> > > DrawCall;
DrawCall g_draw_calls[DCT_COUNT]; DrawCall g_draw_calls[DCT_FOR_VAO];
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
std::vector<std::pair<SPShader*, std::vector<std::pair<std::array<GLuint, 6>, std::vector<std::pair<SPShader*, std::vector<std::pair<std::array<GLuint, 6>,
std::vector<std::pair<SPMeshBuffer*, int/*material_id*/> > > > > > std::vector<std::pair<SPMeshBuffer*, int/*material_id*/> > > > > >
@ -94,7 +95,7 @@ std::vector<float> g_bounding_boxes;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
core::vector3df g_wind_dir; core::vector3df g_wind_dir;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
//std::unordered_set<SPDynamicDrawCall*> g_dy_dc; std::unordered_set<SPDynamicDrawCall*> g_dy_dc;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float g_frustums[5][24] = { { } }; float g_frustums[5][24] = { { } };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -149,6 +150,12 @@ void fogUniformAssigner(SPUniformAssigner* ua)
ua->setValue(fog_enable); ua->setValue(fog_enable);
} // fogUniformAssigner } // fogUniformAssigner
// ----------------------------------------------------------------------------
void zeroAlphaUniformAssigner(SPUniformAssigner* ua)
{
ua->setValue(0.0f);
} // zeroAlphaUniformAssigner
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void ghostAlphaAssigner(SPUniformAssigner* ua) void ghostAlphaAssigner(SPUniformAssigner* ua)
{ {
@ -417,7 +424,7 @@ void loadShaders()
addShader(shader); addShader(shader);
// ======================================================================== // ========================================================================
shader = new SPShader("alphatest", 4, false, 0, true); shader = new SPShader("alphatest", 3, false, 0, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST); shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST);
@ -438,7 +445,7 @@ void loadShaders()
addShader(shader); addShader(shader);
shader = new SPShader("alphatest_skinned", 4, false, 0, true); shader = new SPShader("alphatest_skinned", 3, false, 0, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST); shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST);
@ -460,7 +467,7 @@ void loadShaders()
addShader(shader); addShader(shader);
// ======================================================================== // ========================================================================
shader = new SPShader("unlit", 4, false, 0, true); shader = new SPShader("unlit", 3, false, 0, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST); shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST);
@ -481,7 +488,7 @@ void loadShaders()
addShader(shader); addShader(shader);
shader = new SPShader("unlit_skinned", 4, false, 0, true); shader = new SPShader("unlit_skinned", 3, false, 0, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST); shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST);
@ -524,7 +531,7 @@ void loadShaders()
addShader(shader); addShader(shader);
shader = new SPShader("normalmap_skinned", 4, false); shader = new SPShader("normalmap_skinned", 3, false);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_map.frag", GL_FRAGMENT_SHADER, RP_1ST); shader->addShaderFile("sp_normal_map.frag", GL_FRAGMENT_SHADER, RP_1ST);
@ -546,7 +553,7 @@ void loadShaders()
addShader(shader); addShader(shader);
// ======================================================================== // ========================================================================
shader = new SPShader("grass", 4, false, 0, true); shader = new SPShader("grass", 3, false, 0, true);
shader->addShaderFile("sp_grass_pass.vert", GL_VERTEX_SHADER, RP_1ST); shader->addShaderFile("sp_grass_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_grass.frag", GL_FRAGMENT_SHADER, shader->addShaderFile("sp_grass.frag", GL_FRAGMENT_SHADER,
RP_1ST); RP_1ST);
@ -590,10 +597,7 @@ void loadShaders()
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner); ->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", [](SPUniformAssigner* ua) ->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
{
ua->setValue(0.0f);
});
addShader(shader); addShader(shader);
shader = new SPShader("alphablend", 1, true); shader = new SPShader("alphablend", 1, true);
@ -609,10 +613,7 @@ void loadShaders()
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner); ->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", [](SPUniformAssigner* ua) ->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
{
ua->setValue(0.0f);
});
addShader(shader); addShader(shader);
shader = new SPShader("additive_skinned", 1, true); shader = new SPShader("additive_skinned", 1, true);
@ -628,10 +629,7 @@ void loadShaders()
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner); ->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", [](SPUniformAssigner* ua) ->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
{
ua->setValue(0.0f);
});
addShader(shader); addShader(shader);
shader = new SPShader("additive", 1, true); shader = new SPShader("additive", 1, true);
@ -647,10 +645,7 @@ void loadShaders()
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner); ->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader) static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", [](SPUniformAssigner* ua) ->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
{
ua->setValue(0.0f);
});
addShader(shader); addShader(shader);
shader = new SPShader("ghost_skinned", 1, true/*transparent_shader*/, shader = new SPShader("ghost_skinned", 1, true/*transparent_shader*/,
@ -1344,6 +1339,120 @@ void addObject(SPMeshNode* node)
#endif #endif
} }
// ----------------------------------------------------------------------------
void handleDynamicDrawCall()
{
for (SPDynamicDrawCall* dydc : g_dy_dc)
{
if (!dydc->isVisible())
{
continue;
}
dydc->resetCullingResult();
SPShader* shader = dydc->getShader();
core::aabbox3df bb = dydc->getBoundingBox();
dydc->getAbsoluteTransformation().transformBoxEx(bb);
std::vector<bool> discard;
discard.resize((g_handle_shadow ? 5 : 1), false);
for (int dc_type = 0; dc_type < (g_handle_shadow ? 5 : 1); dc_type++)
{
for (int i = 0; i < 24; i += 4)
{
bool outside = true;
for (int j = 0; j < 8; j++)
{
const float dist =
getCorner(bb, j).X * g_frustums[dc_type][i] +
getCorner(bb, j).Y * g_frustums[dc_type][i + 1] +
getCorner(bb, j).Z * g_frustums[dc_type][i + 2] +
g_frustums[dc_type][i + 3];
outside = outside && dist < 0.0f;
if (!outside)
{
break;
}
}
if (outside)
{
discard[dc_type] = true;
break;
}
}
}
if (g_handle_shadow ?
(discard[0] && discard[1] && discard[2] && discard[3] &&
discard[4]) : discard[0])
{
continue;
}
for (int dc_type = 0; dc_type < (g_handle_shadow ? 5 : 1); dc_type++)
{
if (discard[dc_type])
{
continue;
}
if (dc_type == 0)
{
sp_solid_poly_count += dydc->getVertexCount();
}
else
{
sp_shadow_poly_count += dydc->getVertexCount();
}
if (shader->isTransparent())
{
// Transparent shader should always uses mesh samplers
// All transparent draw calls go DCT_TRANSPARENT
if (dc_type == 0)
{
auto& ret = g_draw_calls[DCT_TRANSPARENT][shader];
if (CVS->isARBBindlessTextureUsable() ||
CVS->useArrayTextures())
{
ret[""].insert(dydc);
}
else
{
for (auto& p : dydc->getTextureCompare())
{
ret[p.first].insert(dydc);
}
}
dydc->setCullingResult(DCT_TRANSPARENT, false);
}
else
{
continue;
}
}
else
{
dydc->setCullingResult((DrawCallType)dc_type, false);
// Check if shader for render pass uses mesh samplers
const RenderPass check_pass =
dc_type == DCT_NORMAL ? RP_1ST : RP_SHADOW;
const bool sampler_less = shader->samplerLess(check_pass) ||
CVS->isARBBindlessTextureUsable() ||
CVS->useArrayTextures();
auto& ret = g_draw_calls[dc_type][shader];
if (sampler_less)
{
ret[""].insert(dydc);
}
else
{
for (auto& p : dydc->getTextureCompare())
{
ret[p.first].insert(dydc);
}
}
}
g_instances.insert(dydc);
}
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void updateModelMatrix() void updateModelMatrix()
{ {
@ -1557,8 +1666,8 @@ void draw(RenderPass rp, DrawCallType dct)
std::stringstream profiler_name; std::stringstream profiler_name;
profiler_name << "SP::Draw " << dct << " with " << rp; profiler_name << "SP::Draw " << dct << " with " << rp;
PROFILER_PUSH_CPU_MARKER(profiler_name.str().c_str(), PROFILER_PUSH_CPU_MARKER(profiler_name.str().c_str(),
(uint8_t)(float(dct + rp + 2) / float(DCT_COUNT + RP_COUNT) * 255.0f), (uint8_t)(float(dct + rp + 2) / float(DCT_FOR_VAO + RP_COUNT) * 255.0f),
(uint8_t)(float(dct + 1) / (float)DCT_COUNT * 255.0f) , (uint8_t)(float(dct + 1) / (float)DCT_FOR_VAO * 255.0f) ,
(uint8_t)(float(rp + 1) / (float)RP_COUNT * 255.0f)); (uint8_t)(float(rp + 1) / (float)RP_COUNT * 255.0f));
assert(dct < DCT_FOR_VAO); assert(dct < DCT_FOR_VAO);
@ -1570,7 +1679,7 @@ void draw(RenderPass rp, DrawCallType dct)
continue; continue;
} }
p.first->use(rp); p.first->use(rp);
std::vector<SPUniformAssigner*> shader_uniforms; static std::vector<SPUniformAssigner*> shader_uniforms;
p.first->setUniformsPerObject(static_cast<SPPerObjectUniform*> p.first->setUniformsPerObject(static_cast<SPPerObjectUniform*>
(p.first), &shader_uniforms, rp); (p.first), &shader_uniforms, rp);
p.first->bindPrefilledTextures(rp); p.first->bindPrefilledTextures(rp);
@ -1583,50 +1692,31 @@ void draw(RenderPass rp, DrawCallType dct)
} }
for (unsigned k = 0; k < p.second[j].second.size(); k++) for (unsigned k = 0; k < p.second[j].second.size(); k++)
{ {
/*std::vector<SPUniformAssigner*> draw_call_uniforms; static std::vector<SPUniformAssigner*> draw_call_uniforms;
p.first->setUniformsPerObject(static_cast<SPPerObjectUniform*> p.first->setUniformsPerObject(dynamic_cast<SPPerObjectUniform*>
(draw_call), &draw_call_uniforms, rp); (p.second[j].second[k].first), &draw_call_uniforms, rp);
sp_draw_call_count++;*/
p.second[j].second[k].first->draw(dct, p.second[j].second[k].first->draw(dct,
p.second[j].second[k].second/*material_id*/, p.second[j].second[k].second/*material_id*/,
CVS->isARBBindlessTextureUsable() || CVS->isARBBindlessTextureUsable() ||
CVS->useArrayTextures()); CVS->useArrayTextures());
/*for (SPUniformAssigner* ua : draw_call_uniforms) for (SPUniformAssigner* ua : draw_call_uniforms)
{ {
ua->reset(); ua->reset();
}*/ }
draw_call_uniforms.clear();
} }
} }
for (SPUniformAssigner* ua : shader_uniforms) for (SPUniformAssigner* ua : shader_uniforms)
{ {
ua->reset(); ua->reset();
} }
shader_uniforms.clear();
p.first->unuse(rp); p.first->unuse(rp);
} }
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
#endif #endif
} // draw } // draw
//-----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void d()
{
/*
*/
}
/*
// ----------------------------------------------------------------------------
void unsynchronisedUpdate()
{
for (SPDynamicDrawCall* dy_dc : g_dy_dc)
{
dy_dc->update(true);
}
} // unsynchronisedUpdate
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void addDynamicDrawCall(SPDynamicDrawCall* dy_dc) void addDynamicDrawCall(SPDynamicDrawCall* dy_dc)
{ {
@ -1638,6 +1728,5 @@ void removeDynamicDrawCall(SPDynamicDrawCall* dy_dc)
{ {
g_dy_dc.erase(dy_dc); g_dy_dc.erase(dy_dc);
} // removeDynamicDrawCall } // removeDynamicDrawCall
*/
} }

View File

@ -52,8 +52,7 @@ enum DrawCallType: unsigned int
DCT_SHADOW3, DCT_SHADOW3,
DCT_SHADOW4, DCT_SHADOW4,
DCT_TRANSPARENT, DCT_TRANSPARENT,
DCT_FOR_VAO, DCT_FOR_VAO
DCT_COUNT = DCT_FOR_VAO
}; };
inline std::ostream& operator<<(std::ostream& os, const DrawCallType& dct) inline std::ostream& operator<<(std::ostream& os, const DrawCallType& dct)
@ -118,21 +117,13 @@ void drawGlow();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void drawNormal(); void drawNormal();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void drawBoundingBoxes();
// ----------------------------------------------------------------------------
void addObject(SPMeshNode*); void addObject(SPMeshNode*);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void removeObject(SPMeshNode*);
// ----------------------------------------------------------------------------
void cleanAllMeshBuffer();
// ----------------------------------------------------------------------------
void updateTransformation();
// ----------------------------------------------------------------------------
void initSTKRenderer(ShaderBasedRenderer*); void initSTKRenderer(ShaderBasedRenderer*);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void prepareScene(); void prepareScene();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void unsynchronisedUpdate(); void handleDynamicDrawCall();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void addDynamicDrawCall(SPDynamicDrawCall*); void addDynamicDrawCall(SPDynamicDrawCall*);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -0,0 +1,228 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2017 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.
#include "graphics/sp/sp_dynamic_draw_call.hpp"
#include "graphics/sp/sp_texture.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/material.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "race/race_manager.hpp"
#include "utils/mini_glm.hpp"
#include "utils/string_utils.hpp"
namespace SP
{
// ----------------------------------------------------------------------------
SPDynamicDrawCall::SPDynamicDrawCall(scene::E_PRIMITIVE_TYPE pt,
SPShader* shader, Material* m)
: SPMeshBuffer()
{
#ifndef SERVER_ONLY
m_primitive_type = pt;
m_shader = shader;
m_stk_material[0] = std::make_tuple(0u, 0u, m);
m_textures.resize(m_stk_material.size());
for (unsigned j = 0; j < 6; j++)
{
m_textures[0][j] = SPTextureManager::get()->getTexture
(std::get<2>(m_stk_material[0])->getSamplerPath(j),
j == 0 ? std::get<2>(m_stk_material[0]) : NULL,
j < 2 && CVS->isDefferedEnabled());
}
m_tex_cmp[m_textures[0][0]->getPath() + m_textures[0][1]->getPath()] = 0;
m_pitch = 48;
resetCullingResult();
// Rerserve 4 vertices, and use m_ibo buffer for instance array
glGenBuffers(1, &m_vbo);
m_vertices.reserve(4);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, 4 * 48, NULL, GL_DYNAMIC_DRAW);
glGenBuffers(1, &m_ibo);
glBindBuffer(GL_ARRAY_BUFFER, m_ibo);
glBufferData(GL_ARRAY_BUFFER, 32 + 48/*Max textures handles*/, NULL,
GL_DYNAMIC_DRAW);
SPInstancedData id = SPInstancedData(m_trans, 0.0f, 0.0f, 0.0f, 0);
glBufferSubData(GL_ARRAY_BUFFER, 0, 32, &id);
SPTextureManager::get()->increaseGLCommandFunctionCount(1);
SPTextureManager::get()->addGLCommandFunction
(std::bind(&SPDynamicDrawCall::initTextureDyDc, this));
glBindBuffer(GL_ARRAY_BUFFER, 0);
recreateDynamicVAO();
#endif
} // SPDynamicDrawCall
// ----------------------------------------------------------------------------
bool SPDynamicDrawCall::initTextureDyDc()
{
#ifndef SERVER_ONLY
for (unsigned i = 0; i < m_stk_material.size(); i++)
{
for (unsigned j = 0; j < 6; j++)
{
if (!m_textures[i][j]->initialized())
{
return false;
}
}
}
if (!(CVS->useArrayTextures() || CVS->isARBBindlessTextureUsable()))
{
return true;
}
glBindBuffer(GL_ARRAY_BUFFER, m_ibo);
if (CVS->useArrayTextures())
{
for (unsigned i = 0; i < 6; i++)
{
uint16_t array_index = (uint16_t)
m_textures[0][i]->getTextureArrayIndex();
glBufferSubData(GL_ARRAY_BUFFER, 32 + (i * 2), 2, &array_index);
}
}
else
{
for (unsigned i = 0; i < 6; i++)
{
glBufferSubData(GL_ARRAY_BUFFER, 32 + (i * 8), 8,
m_textures[0][i]->getTextureHandlePointer());
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
#endif
return true;
} // initTextureDyDc
// ----------------------------------------------------------------------------
void SPDynamicDrawCall::recreateDynamicVAO()
{
#ifndef SERVER_ONLY
if (m_vao[0] != 0)
{
glDeleteVertexArrays(1, &m_vao[0]);
}
glGenVertexArrays(1, &m_vao[0]);
glBindVertexArray(m_vao[0]);
size_t offset = 0;
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
// Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 48, (void*)offset);
offset += 12;
// Normal, if 10bit vector normalization is wrongly done by drivers, use
// original value and normalize ourselves in shader
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_INT_2_10_10_10_REV,
GraphicsRestrictions::isDisabled
(GraphicsRestrictions::GR_10BIT_VECTOR) ? GL_FALSE : GL_TRUE, 48,
(void*)offset);
offset += 4;
// Vertex color
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 48,
(void*)offset);
offset += 4;
// 1st texture coordinates
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_HALF_FLOAT, GL_FALSE, 48, (void*)offset);
offset += 4;
// 2nd texture coordinates
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_HALF_FLOAT, GL_FALSE, 48,
(void*)offset);
offset += 4;
// Tangent and bi-tanget sign
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_INT_2_10_10_10_REV,
GraphicsRestrictions::isDisabled
(GraphicsRestrictions::GR_10BIT_VECTOR) ? GL_FALSE : GL_TRUE,
48, (void*)offset);
offset += 4;
// 4 Joint indices
glEnableVertexAttribArray(6);
glVertexAttribIPointer(6, 4, GL_SHORT, 48, (void*)offset);
offset += 8;
// 4 Joint weights
glEnableVertexAttribArray(7);
glVertexAttribPointer(7, 4, GL_HALF_FLOAT, GL_FALSE, 48,
(void*)offset);
offset += 8;
glBindBuffer(GL_ARRAY_BUFFER, m_ibo);
// Origin
glEnableVertexAttribArray(8);
glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 32 + 48, (void*)0);
glVertexAttribDivisorARB(8, 1);
// Rotation (quaternion .xyz)
glEnableVertexAttribArray(9);
glVertexAttribPointer(9, 4, GL_INT_2_10_10_10_REV,
GraphicsRestrictions::isDisabled
(GraphicsRestrictions::GR_10BIT_VECTOR) ? GL_FALSE : GL_TRUE, 32 + 48,
(void*)12);
glVertexAttribDivisorARB(9, 1);
// Scale (3 half floats and .w for quaternion .w)
glEnableVertexAttribArray(10);
glVertexAttribPointer(10, 4, GL_HALF_FLOAT, GL_FALSE, 32 + 48, (void*)16);
glVertexAttribDivisorARB(10, 1);
// Texture translation
glEnableVertexAttribArray(11);
glVertexAttribPointer(11, 2, GL_HALF_FLOAT, GL_FALSE, 32 + 48, (void*)24);
glVertexAttribDivisorARB(11, 1);
// Misc data (skinning offset and hue change)
glEnableVertexAttribArray(12);
glVertexAttribIPointer(12, 2, GL_SHORT, 32 + 48, (void*)28);
glVertexAttribDivisorARB(12, 1);
if (CVS->useArrayTextures())
{
// uvec4 + uvec2 for 6 texture array indices
glEnableVertexAttribArray(13);
glVertexAttribIPointer(13, 4, GL_UNSIGNED_SHORT, 32 + 48, (void*)32);
glVertexAttribDivisorARB(13, 1);
glEnableVertexAttribArray(14);
glVertexAttribIPointer(14, 2, GL_UNSIGNED_SHORT, 32 + 48, (void*)40);
glVertexAttribDivisorARB(14, 1);
glDisableVertexAttribArray(15);
}
else if (CVS->isARBBindlessTextureUsable())
{
// 3 * 2 uvec2 for bindless samplers
glEnableVertexAttribArray(13);
glVertexAttribIPointer(13, 4, GL_UNSIGNED_INT, 32 + 48, (void*)32);
glVertexAttribDivisorARB(13, 1);
glEnableVertexAttribArray(14);
glVertexAttribIPointer(14, 4, GL_UNSIGNED_INT, 32 + 48, (void*)48);
glVertexAttribDivisorARB(14, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, 32 + 48, (void*)64);
glVertexAttribDivisorARB(15, 1);
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
#endif
} // recreateVAO
}

View File

@ -0,0 +1,191 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2017 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_SP_DYNAMIC_DRAW_CALL_HPP
#define HEADER_SP_DYNAMIC_DRAW_CALL_HPP
#include "graphics/sp/sp_mesh_buffer.hpp"
#include "graphics/sp/sp_per_object_uniform.hpp"
#include <IMeshBuffer.h>
#include <array>
#include <cassert>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
using namespace irr;
using namespace scene;
class Material;
namespace SP
{
class SPShader;
class SPDynamicDrawCall : public SPMeshBuffer, public SPPerObjectUniform
{
private:
core::matrix4 m_trans;
SPShader* m_shader;
core::vector2df m_texture_trans;
scene::E_PRIMITIVE_TYPE m_primitive_type;
unsigned m_gl_vbo_size = 4;
int m_update_offset = -1;
std::vector<bool> m_culling_result;
bool m_visible = true;
bool m_update_trans = false;
// ------------------------------------------------------------------------
bool initTextureDyDc();
// ------------------------------------------------------------------------
void recreateDynamicVAO();
public:
SPDynamicDrawCall(scene::E_PRIMITIVE_TYPE pt, SPShader* shader,
Material* m);
// ------------------------------------------------------------------------
~SPDynamicDrawCall() {}
// ------------------------------------------------------------------------
virtual void draw(DrawCallType dct, int material_id = -1,
bool bindless_texture = false) const
{
#ifndef SERVER_ONLY
if (m_culling_result[dct])
{
return;
}
glBindVertexArray(m_vao[0]);
glDrawArraysInstanced(
m_primitive_type == EPT_TRIANGLES ? GL_TRIANGLES :
m_primitive_type == EPT_TRIANGLE_STRIP ? GL_TRIANGLE_STRIP :
GL_TRIANGLE_FAN, 0, getVertexCount(), 1);
#endif
}
// ------------------------------------------------------------------------
virtual void uploadInstanceData()
{
#ifndef SERVER_ONLY
if (m_texture_trans.X != 0.0f || m_texture_trans.Y != 0.0f ||
m_update_trans)
{
m_update_trans = false;
SPInstancedData id = SPInstancedData(m_trans,
m_texture_trans.X, m_texture_trans.Y, 0.0f, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_ibo);
glBufferSubData(GL_ARRAY_BUFFER, 0, 32, &id);
}
if (m_update_offset >= 0 && !m_vertices.empty())
{
if ((unsigned)m_vertices.capacity() > m_gl_vbo_size)
{
m_update_offset = 0;
glDeleteBuffers(1, &m_vbo);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
m_gl_vbo_size = (unsigned)m_vertices.capacity();
glBufferData(GL_ARRAY_BUFFER, m_gl_vbo_size * 48, NULL,
GL_DYNAMIC_DRAW);
recreateDynamicVAO();
}
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
const int length = ((int)m_vertices.size() - m_update_offset) * 48;
assert(length > 0);
glBufferSubData(GL_ARRAY_BUFFER, m_update_offset * 48, length,
m_vertices.data() + m_update_offset);
m_update_offset = -1;
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
#endif
}
// ------------------------------------------------------------------------
virtual void uploadGLMesh() {}
// ------------------------------------------------------------------------
virtual void enableTextureMatrix(unsigned mat_id) {}
// ------------------------------------------------------------------------
SPShader* getShader() const { return m_shader; }
// ------------------------------------------------------------------------
std::vector<video::S3DVertexSkinnedMesh>& getVerticesVector()
{ return m_vertices; }
// ------------------------------------------------------------------------
core::vector2df& getTextureTrans() { return m_texture_trans; }
// ------------------------------------------------------------------------
void setUpdateOffset(int offset) { m_update_offset = offset; }
// ------------------------------------------------------------------------
void resetCullingResult()
{
m_culling_result.clear();
m_culling_result.resize(DCT_FOR_VAO, true);
}
// ------------------------------------------------------------------------
void setCullingResult(DrawCallType dct, bool ret)
{ m_culling_result[dct] = ret; }
// ------------------------------------------------------------------------
bool isVisible() const { return m_visible; }
// ------------------------------------------------------------------------
void setVisible(bool val) { m_visible = val; }
// ------------------------------------------------------------------------
const core::matrix4& getAbsoluteTransformation() const { return m_trans; }
// ------------------------------------------------------------------------
void setAbsoluteTransformation(core::matrix4& mat)
{
m_trans = mat;
m_update_trans = true;
}
// ------------------------------------------------------------------------
void setPosition(const core::vector3df pos)
{
m_trans.setTranslation(pos);
m_update_trans = true;
}
// ------------------------------------------------------------------------
void setRotationRadians(const core::vector3df rot)
{
m_trans.setRotationRadians(rot);
m_update_trans = true;
}
// ------------------------------------------------------------------------
void setRotationDegrees(const core::vector3df rot)
{
m_trans.setRotationDegrees(rot);
m_update_trans = true;
}
// ------------------------------------------------------------------------
void setScale(const core::vector3df scale)
{
m_trans.setScale(scale);
m_update_trans = true;
}
};
}
#endif
#include <S3DVertex.h>

View File

@ -34,6 +34,11 @@ private:
char m_data[32]; char m_data[32];
public: public:
// ------------------------------------------------------------------------
SPInstancedData()
{
memset(m_data, 0, 32);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
SPInstancedData(const core::matrix4& model_mat, SPInstancedData(const core::matrix4& model_mat,
float texture_trans_x, float texture_trans_y, float hue, float texture_trans_x, float texture_trans_y, float hue,

View File

@ -20,7 +20,6 @@
#include "graphics/central_settings.hpp" #include "graphics/central_settings.hpp"
#include "graphics/graphics_restrictions.hpp" #include "graphics/graphics_restrictions.hpp"
#include "graphics/material.hpp" #include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/sp/sp_texture_manager.hpp" #include "graphics/sp/sp_texture_manager.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "utils/mini_glm.hpp" #include "utils/mini_glm.hpp"
@ -372,7 +371,7 @@ void SPMeshBuffer::recreateVAO(unsigned i)
glEnableVertexAttribArray(7); glEnableVertexAttribArray(7);
glVertexAttribPointer(7, 4, GL_HALF_FLOAT, GL_FALSE, pitch, glVertexAttribPointer(7, 4, GL_HALF_FLOAT, GL_FALSE, pitch,
(void*)offset); (void*)offset);
offset += 8; offset += 8;
} }
else else
{ {

View File

@ -44,7 +44,7 @@ class SPTexture;
class SPMeshBuffer : public IMeshBuffer class SPMeshBuffer : public IMeshBuffer
{ {
private: protected:
std::vector<std::tuple<size_t/*first_index_id*/, std::vector<std::tuple<size_t/*first_index_id*/,
unsigned/*indices_count*/, Material*> > m_stk_material; unsigned/*indices_count*/, Material*> > m_stk_material;
@ -54,6 +54,13 @@ private:
std::vector<video::S3DVertexSkinnedMesh> m_vertices; std::vector<video::S3DVertexSkinnedMesh> m_vertices;
GLuint m_ibo, m_vbo;
GLuint m_vao[DCT_FOR_VAO];
unsigned m_pitch;
private:
std::vector<uint16_t> m_indices; std::vector<uint16_t> m_indices;
core::aabbox3d<f32> m_bounding_box; core::aabbox3d<f32> m_bounding_box;
@ -62,16 +69,10 @@ private:
void* m_ins_dat_mapped_ptr[DCT_FOR_VAO]; void* m_ins_dat_mapped_ptr[DCT_FOR_VAO];
GLuint m_ibo, m_vbo;
unsigned m_gl_instance_size[DCT_FOR_VAO]; unsigned m_gl_instance_size[DCT_FOR_VAO];
GLuint m_vao[DCT_FOR_VAO];
GLuint m_ins_array[DCT_FOR_VAO]; GLuint m_ins_array[DCT_FOR_VAO];
unsigned m_pitch;
bool m_uploaded_gl; bool m_uploaded_gl;
bool m_uploaded_instance; bool m_uploaded_instance;
@ -107,31 +108,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
~SPMeshBuffer(); ~SPMeshBuffer();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool combineMeshBuffer(SPMeshBuffer* spmb) virtual void draw(DrawCallType dct, int material_id = -1,
{ bool bindless_texture = false) const
// We only use 16bit vertices
if (spmb->m_vertices.size() + m_vertices.size() > 65536)
{
return false;
}
const uint16_t old_vtx_count = (uint16_t)m_vertices.size();
m_vertices.insert(m_vertices.end(), spmb->m_vertices.begin(),
spmb->m_vertices.end());
for (uint16_t& idx : spmb->m_indices)
{
idx += old_vtx_count;
}
m_stk_material.emplace_back(getIndexCount(), spmb->getIndexCount(),
std::get<2>(spmb->m_stk_material[0]));
m_indices.insert(m_indices.end(), spmb->m_indices.begin(),
spmb->m_indices.end());
return true;
}
// ------------------------------------------------------------------------
void bindVAO(DrawCallType dct) const { glBindVertexArray(m_vao[dct]); }
// ------------------------------------------------------------------------
void draw(DrawCallType dct, int material_id = -1,
bool bindless_texture = false) const
{ {
glBindVertexArray(m_vao[dct]); glBindVertexArray(m_vao[dct]);
if (material_id == -1 || bindless_texture) if (material_id == -1 || bindless_texture)
@ -165,12 +143,35 @@ public:
} }
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void uploadGLMesh();
// ------------------------------------------------------------------------
virtual void uploadInstanceData();
// ------------------------------------------------------------------------
bool combineMeshBuffer(SPMeshBuffer* spmb)
{
// We only use 16bit vertices
if (spmb->m_vertices.size() + m_vertices.size() > 65536)
{
return false;
}
const uint16_t old_vtx_count = (uint16_t)m_vertices.size();
m_vertices.insert(m_vertices.end(), spmb->m_vertices.begin(),
spmb->m_vertices.end());
for (uint16_t& idx : spmb->m_indices)
{
idx += old_vtx_count;
}
m_stk_material.emplace_back(getIndexCount(), spmb->getIndexCount(),
std::get<2>(spmb->m_stk_material[0]));
m_indices.insert(m_indices.end(), spmb->m_indices.begin(),
spmb->m_indices.end());
return true;
}
// ------------------------------------------------------------------------
void initDrawMaterial(); void initDrawMaterial();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void enableSkinningData() { m_skinned = true; } void enableSkinningData() { m_skinned = true; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void uploadGLMesh();
// ------------------------------------------------------------------------
Material* getSTKMaterial(unsigned first_index = 0) const Material* getSTKMaterial(unsigned first_index = 0) const
{ {
for (unsigned i = 0; i < m_stk_material.size(); i++) for (unsigned i = 0; i < m_stk_material.size(); i++)
@ -248,8 +249,6 @@ public:
m_ins_dat[dct].push_back(id); m_ins_dat[dct].push_back(id);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void uploadInstanceData();
// ------------------------------------------------------------------------
void recreateVAO(unsigned i); void recreateVAO(unsigned i);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
video::S3DVertexSkinnedMesh* getSPMVertex() video::S3DVertexSkinnedMesh* getSPMVertex()

View File

@ -218,6 +218,10 @@ void SPShader::setUniformsPerObject(SPPerObjectUniform* sppou,
RenderPass rp) RenderPass rp)
{ {
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
if (sppou == NULL)
{
return;
}
for (auto& p : m_uniforms[rp]) for (auto& p : m_uniforms[rp])
{ {
if (sppou->assignUniform(p.first, p.second)) if (sppou->assignUniform(p.first, p.second))

View File

@ -55,7 +55,6 @@ enum RenderPass: unsigned int
RP_1ST = 0, RP_1ST = 0,
RP_2ND, RP_2ND,
RP_SHADOW, RP_SHADOW,
RP_RSM,
RP_COUNT RP_COUNT
}; };
@ -67,6 +66,8 @@ inline std::ostream& operator<<(std::ostream& os, const RenderPass& rp)
return os << "first pass"; return os << "first pass";
case RP_2ND: case RP_2ND:
return os << "second pass"; return os << "second pass";
case RP_SHADOW:
return os << "shadow pass";
default: default:
return os; return os;
} }
@ -102,14 +103,14 @@ private:
public: public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
SPShader(const std::string& name, unsigned pass_count = 4, SPShader(const std::string& name, unsigned pass_count = 3,
bool transparent_shader = false, int drawing_priority = 0, bool transparent_shader = false, int drawing_priority = 0,
bool use_alpha_channel = false) bool use_alpha_channel = false)
: m_name(name), m_drawing_priority(drawing_priority), : m_name(name), m_drawing_priority(drawing_priority),
m_transparent_shader(transparent_shader), m_transparent_shader(transparent_shader),
m_use_alpha_channel(use_alpha_channel || transparent_shader) m_use_alpha_channel(use_alpha_channel || transparent_shader)
{ {
memset(m_program, 0, sizeof(GLuint) * 4); memset(m_program, 0, 12);
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
for (unsigned rp = RP_1ST; rp < pass_count; rp++) for (unsigned rp = RP_1ST; rp < pass_count; rp++)
{ {

View File

@ -413,9 +413,6 @@ void Kart::reset()
if (m_skidmarks) if (m_skidmarks)
{ {
m_skidmarks->reset(); m_skidmarks->reset();
const Track *track =
track_manager->getTrack( race_manager->getTrackName() );
m_skidmarks->adjustFog(track->isFogEnabled() );
} }
Vec3 front(0, 0, getKartLength()*0.5f); Vec3 front(0, 0, getKartLength()*0.5f);
@ -1529,7 +1526,7 @@ void Kart::update(float dt)
static video::SColor green(255, 61, 87, 23); static video::SColor green(255, 61, 87, 23);
// draw skidmarks if relevant (we force pink skidmarks on when hitting a bubblegum) // draw skidmarks if relevant (we force pink skidmarks on when hitting a bubblegum)
if(m_kart_properties->getSkidEnabled()) if(m_kart_properties->getSkidEnabled() && m_skidmarks)
{ {
m_skidmarks->update(dt, m_skidmarks->update(dt,
m_bubblegum_time > 0, m_bubblegum_time > 0,
@ -2644,14 +2641,12 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model)
m_slipstream = new SlipStream(this); m_slipstream = new SlipStream(this);
if (m_kart_properties->getSkidEnabled()) #ifndef SERVER_ONLY
if (m_kart_properties->getSkidEnabled() && CVS->isGLSL())
{ {
m_skidmarks = new SkidMarks(*this); m_skidmarks = new SkidMarks(*this);
m_skidmarks->adjustFog(
track_manager->getTrack(race_manager->getTrackName())
->isFogEnabled() );
} }
#ifndef SERVER_ONLY
bool create_shadow = m_kart_properties->getShadowTexture() != NULL && bool create_shadow = m_kart_properties->getShadowTexture() != NULL &&
!CVS->supportsShadows(); !CVS->supportsShadows();