Add rubber band rendering for legacy video drivers

This commit is contained in:
Benau 2022-11-13 16:08:54 +08:00
parent 013d604846
commit 58223928d8
2 changed files with 136 additions and 47 deletions

View File

@ -35,6 +35,10 @@
#include "mini_glm.hpp"
#include "utils/string_utils.hpp"
#include <array>
#include <SMesh.h>
#include <SMeshBuffer.h>
/** RubberBand constructor. It creates a simple quad and attaches it to the
* root(!) of the graph. It's easier this way to get the right coordinates
* than attaching it to the plunger or kart, and trying to find the other
@ -44,33 +48,60 @@
* \param kart Reference to the kart.
*/
RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart)
: m_plunger(plunger), m_owner(kart)
: m_plunger(plunger), m_owner(kart), m_node(NULL)
{
m_hit_kart = NULL;
m_attached_state = RB_TO_PLUNGER;
#ifndef SERVER_ONLY
if (GUIEngine::isNoGraphics() || !CVS->isGLSL())
{
if (GUIEngine::isNoGraphics())
return;
}
video::SColor color(255, 179, 0, 0);
if (CVS->isDeferredEnabled())
if (CVS->isGLSL())
{
color.setRed(SP::srgb255ToLinear(color.getRed()));
color.setGreen(SP::srgb255ToLinear(color.getGreen()));
color.setBlue(SP::srgb255ToLinear(color.getBlue()));
if (CVS->isDeferredEnabled())
{
color.setRed(SP::srgb255ToLinear(color.getRed()));
color.setGreen(SP::srgb255ToLinear(color.getGreen()));
color.setBlue(SP::srgb255ToLinear(color.getBlue()));
}
m_dy_dc = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP, SP::SPShaderManager::get()->getSPShader
("unlit"), material_manager->getDefaultSPMaterial("unlit"));
m_dy_dc->getVerticesVector().resize(4);
// Set the vertex colors properly, as the new pipeline doesn't use the
// old light values
for (unsigned i = 0; i < 4; i++)
{
m_dy_dc->getSPMVertex()[i].m_color = color;
}
SP::addDynamicDrawCall(m_dy_dc);
}
m_dy_dc = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP, SP::SPShaderManager::get()->getSPShader
("unlit"), material_manager->getDefaultSPMaterial("unlit"));
m_dy_dc->getVerticesVector().resize(4);
// Set the vertex colors properly, as the new pipeline doesn't use the old
// light values
for (unsigned i = 0; i < 4; i++)
else
{
m_dy_dc->getSPMVertex()[i].m_color = color;
video::S3DVertex v;
v.Normal = core::vector3df(0, 1, 0);
v.Color = color;
std::array<video::S3DVertex, 4> vertices = {{ v, v, v, v }};
std::array<uint16_t, 6> indices = {{ 0, 1, 2, 0, 2, 3 }};
scene::SMeshBuffer* buffer = new scene::SMeshBuffer();
buffer->append(vertices.data(), vertices.size(), indices.data(),
indices.size());
buffer->getMaterial().AmbientColor = color;
buffer->getMaterial().DiffuseColor = color;
buffer->getMaterial().EmissiveColor = color;
buffer->setHardwareMappingHint(scene::EHM_STREAM);
buffer->recalculateBoundingBox();
scene::SMesh* mesh = new scene::SMesh();
mesh->addMeshBuffer(buffer);
mesh->setBoundingBox(buffer->getBoundingBox());
buffer->drop();
std::string debug_name = m_owner->getIdent() + " (rubber-band)";
m_node = static_cast<scene::IMeshSceneNode*>(
irr_driver->addMesh(mesh, debug_name));
mesh->drop();
}
SP::addDynamicDrawCall(m_dy_dc);
#endif
} // RubberBand
@ -112,40 +143,83 @@ void RubberBand::updatePosition()
void RubberBand::updateGraphics(float dt)
{
#ifndef SERVER_ONLY
if (!m_dy_dc)
if (m_node)
{
return;
scene::IMesh* mesh = m_node->getMesh();
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(0);
// Update the rubber band positions
// --------------------------------
// Todo: make height dependent on length (i.e. rubber band gets
// thinner). And call explosion if the band is too long.
const Vec3& k = m_owner->getXYZ();
const float hh = .1f; // half height of the band
const Vec3& p = m_end_position; // for shorter typing
core::vector3df& v0 = buffer->getPosition(0);
core::vector3df& v1 = buffer->getPosition(1);
core::vector3df& v2 = buffer->getPosition(2);
core::vector3df& v3 = buffer->getPosition(3);
v0.X = p.getX() - hh; v0.Y = p.getY(); v0.Z = p.getZ() - hh;
v1.X = p.getX() + hh; v1.Y = p.getY(); v1.Z = p.getZ() + hh;
v2.X = k.getX() + hh; v2.Y = k.getY(); v2.Z = k.getZ() + hh;
v3.X = k.getX() - hh; v3.Y = k.getY(); v3.Z = k.getZ() - hh;
core::vector3df normal = (v1 - v0).crossProduct(v2 - v0);
core::vector3df kart_pos = Vec3(m_owner->getTrans()(
Vec3(0, 5.0f, -2.0f))).toIrrVector();
float dot_product = (v0 - kart_pos).dotProduct(normal);
// For avoiding cull face
if (dot_product >= 0.0f)
{
buffer->getIndices()[0] = 2;
buffer->getIndices()[1] = 1;
buffer->getIndices()[2] = 0;
buffer->getIndices()[3] = 3;
buffer->getIndices()[4] = 2;
buffer->getIndices()[5] = 0;
}
else
{
buffer->getIndices()[0] = 0;
buffer->getIndices()[1] = 1;
buffer->getIndices()[2] = 2;
buffer->getIndices()[3] = 0;
buffer->getIndices()[4] = 2;
buffer->getIndices()[5] = 3;
}
buffer->recalculateBoundingBox();
mesh->setBoundingBox(buffer->getBoundingBox());
}
// Update the rubber band positions
// --------------------------------
// Todo: make height dependent on length (i.e. rubber band gets
// thinner). And call explosion if the band is too long.
const Vec3 &k = m_owner->getXYZ();
const float hh=.1f; // half height of the band
const Vec3 &p=m_end_position; // for shorter typing
auto& v = m_dy_dc->getVerticesVector();
v[0].m_position.X = p.getX()-hh; v[0].m_position.Y=p.getY(); v[0].m_position.Z = p.getZ()-hh;
v[1].m_position.X = p.getX()+hh; v[1].m_position.Y=p.getY(); v[1].m_position.Z = p.getZ()+hh;
v[2].m_position.X = k.getX()-hh; v[2].m_position.Y=k.getY(); v[2].m_position.Z = k.getZ()-hh;
v[3].m_position.X = k.getX()+hh; v[3].m_position.Y=k.getY(); v[3].m_position.Z = k.getZ()+hh;
v[0].m_normal = 0x1FF << 10;
v[1].m_normal = 0x1FF << 10;
v[2].m_normal = 0x1FF << 10;
v[3].m_normal = 0x1FF << 10;
core::vector3df normal = (v[1].m_position - v[0].m_position)
.crossProduct(v[2].m_position - v[0].m_position);
core::vector3df kart_pos = Vec3(m_owner->getTrans()(Vec3(0, 5.0f, -2.0f))).toIrrVector();
float dot_product = (v[0].m_position - kart_pos).dotProduct(normal);
// For avoiding cull face
if (dot_product >= 0.0f)
else if (m_dy_dc)
{
video::S3DVertexSkinnedMesh tmp = v[1];
v[1] = v[2];
v[2] = tmp;
// Update the rubber band positions
// --------------------------------
// Todo: make height dependent on length (i.e. rubber band gets
// thinner). And call explosion if the band is too long.
const Vec3 &k = m_owner->getXYZ();
const float hh=.1f; // half height of the band
const Vec3 &p=m_end_position; // for shorter typing
auto& v = m_dy_dc->getVerticesVector();
v[0].m_position.X = p.getX()-hh; v[0].m_position.Y=p.getY(); v[0].m_position.Z = p.getZ()-hh;
v[1].m_position.X = p.getX()+hh; v[1].m_position.Y=p.getY(); v[1].m_position.Z = p.getZ()+hh;
v[2].m_position.X = k.getX()-hh; v[2].m_position.Y=k.getY(); v[2].m_position.Z = k.getZ()-hh;
v[3].m_position.X = k.getX()+hh; v[3].m_position.Y=k.getY(); v[3].m_position.Z = k.getZ()+hh;
v[0].m_normal = 0x1FF << 10;
v[1].m_normal = 0x1FF << 10;
v[2].m_normal = 0x1FF << 10;
v[3].m_normal = 0x1FF << 10;
core::vector3df normal = (v[1].m_position - v[0].m_position)
.crossProduct(v[2].m_position - v[0].m_position);
core::vector3df kart_pos = Vec3(m_owner->getTrans()(Vec3(0, 5.0f, -2.0f))).toIrrVector();
float dot_product = (v[0].m_position - kart_pos).dotProduct(normal);
// For avoiding cull face
if (dot_product >= 0.0f)
{
video::S3DVertexSkinnedMesh tmp = v[1];
v[1] = v[2];
v[2] = tmp;
}
m_dy_dc->setUpdateOffset(0);
m_dy_dc->recalculateBoundingBox();
}
m_dy_dc->setUpdateOffset(0);
m_dy_dc->recalculateBoundingBox();
#endif
} // updateGraphics
@ -297,6 +371,11 @@ void RubberBand::remove()
m_dy_dc->removeFromSP();
m_dy_dc = nullptr;
}
else if (m_node)
{
irr_driver->removeNode(m_node);
m_node = NULL;
}
#endif
} // remove

View File

@ -30,6 +30,14 @@ namespace SP
class SPDynamicDrawCall;
}
namespace irr
{
namespace scene
{
class IMeshSceneNode;
}
}
class AbstractKart;
class Plunger;
@ -59,6 +67,8 @@ private:
/** The dynamic draw call of the rubber band. */
std::shared_ptr<SP::SPDynamicDrawCall> m_dy_dc;
irr::scene::IMeshSceneNode* m_node;
/** The kart a plunger might have hit. */
AbstractKart *m_hit_kart;
/** Stores the end of the rubber band (i.e. the side attached to the