Merge remote-tracking branch 'origin/master' into fix_2112

This commit is contained in:
Benau 2016-11-13 10:42:47 +08:00
commit 5879933a23
113 changed files with 8065 additions and 5706 deletions

3
.gitignore vendored
View File

@ -1,8 +1,7 @@
bld*/
build*/
cmake_build/
cmake_build*/
dependencies/
dependencies*/
CMakeFiles/
stk-editor/

View File

@ -38,7 +38,12 @@ addons:
- zlib1g-dev
before_script:
- export THREADS=$((`nproc` + 1))
# Unfortunately using all threads crashes g++: "g++: internal compiler error: Killed (program cc1plus)"
- 'if [ ${CC} = "gcc" ]; then
export THREADS=4;
else
export THREADS=$((`nproc` + 1));
fi'
- echo "THREADS = $THREADS"
- free -mt

View File

@ -7,7 +7,7 @@
<card contains="Intel" os="osx" disable="GI"/>
<card contains="Intel" os="linux" version="<11.2" disable="ComputeShader"/>
<card contains="Intel" os="linux" version="<11.2" disable="GeometryShader"/>
<card contains="Intel" os="linux" version="<16.0" disable="FramebufferSRGBCapable"/>
<card contains="Intel" os="linux" disable="FramebufferSRGBCapable"/>
<card contains="Intel" os="linux" version="<11.2" disable="TextureCompressionS3TC"/>
<card contains="Intel" os="windows" disable="TextureCompressionS3TC"/>
<card contains="Intel" os="osx" disable="TextureCompressionS3TC"/>

View File

@ -4,5 +4,5 @@ out vec4 FragColor;
void main()
{
FragColor = vec4(glowColor.rgb, 1.0);
FragColor = vec4(glowColor.bgr, 1.0);
}

View File

@ -34,8 +34,8 @@ namespace irr
IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */
EET_KEY_INPUT_EVENT,
//! A multi touch event.
EET_MULTI_TOUCH_EVENT,
//! A touch input event.
EET_TOUCH_INPUT_EVENT,
//! A accelerometer event.
EET_ACCELEROMETER_EVENT,
@ -177,22 +177,19 @@ namespace irr
#endif
//! Enumeration for all touch input events
enum EMULTI_TOUCH_INPUT_EVENT
enum ETOUCH_INPUT_EVENT
{
//! Max multi touch count
NUMBER_OF_MULTI_TOUCHES = 10,
//! Touch was pressed down.
EMTIE_PRESSED_DOWN = 0,
ETIE_PRESSED_DOWN = 0,
//! Touch was left up.
EMTIE_LEFT_UP,
ETIE_LEFT_UP,
//! The touch changed its position.
EMTIE_MOVED,
ETIE_MOVED,
//! No real event. Just for convenience to get number of events
EMTIE_COUNT
ETIE_COUNT
};
namespace gui
@ -384,55 +381,23 @@ struct SEvent
bool Control:1;
};
//! Any kind of multi touch event.
struct SMultiTouchInput
//! Any kind of touch event.
struct STouchInput
{
//! A helper function to check if a button is pressed.
u32 touchedCount() const
{
u32 count = 0;
for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i)
{
if (Touched[i])
count++;
}
return count;
}
//! Reset variables.
void clear()
{
for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i)
{
Touched[i] = 0;
X[i] = 0;
Y[i] = 0;
PrevX[i] = 0;
PrevY[i] = 0;
}
}
// Status of simple touch.
u8 Touched[NUMBER_OF_MULTI_TOUCHES];
// Touch ID.
size_t ID;
// X position of simple touch.
s32 X[NUMBER_OF_MULTI_TOUCHES];
s32 X;
// Y position of simple touch.
s32 Y[NUMBER_OF_MULTI_TOUCHES];
s32 Y;
// Previous X position of simple touch.
s32 PrevX[NUMBER_OF_MULTI_TOUCHES];
// Previous Y position of simple touch.
s32 PrevY[NUMBER_OF_MULTI_TOUCHES];
//! Type of multi touch event
EMULTI_TOUCH_INPUT_EVENT Event;
//! Type of touch event.
ETOUCH_INPUT_EVENT Event;
};
//! Any kind of accelerometer event.
struct SAccelerometerEvent
{
@ -575,7 +540,7 @@ struct SEvent
struct SGUIEvent GUIEvent;
struct SMouseInput MouseInput;
struct SKeyInput KeyInput;
struct SMultiTouchInput MultiTouchInput;
struct STouchInput TouchInput;
struct SAccelerometerEvent AccelerometerEvent;
struct SGyroscopeEvent GyroscopeEvent;
struct SDeviceMotionEvent DeviceMotionEvent;

View File

@ -443,6 +443,8 @@ bool CGUIListBox::OnEvent(const SEvent& event)
case EET_JOYSTICK_INPUT_EVENT:
case EGUIET_FORCE_32_BIT:
break;
default:
break;
}
}

View File

@ -75,9 +75,6 @@ void NewsManager::init(bool force_refresh)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// Should be the default, but just in case:
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_t thread_id;
int error = pthread_create(&thread_id, &attr,
&NewsManager::downloadNews, this);

View File

@ -91,9 +91,6 @@ SFXManager::SFXManager()
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Should be the default, but just in case:
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
m_thread_id.setAtomic(new pthread_t());
// The thread is created even if there atm sfx are disabled
// (since the user might enable it later).
@ -299,8 +296,6 @@ void* SFXManager::mainLoop(void *obj)
VS::setThreadName("SFXManager");
SFXManager *me = (SFXManager*)obj;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
me->m_sfx_commands.lock();
// Wait till we have an empty sfx in the queue

View File

@ -389,6 +389,28 @@ namespace UserConfigParams
&m_wiimote_group,
"A weight applied to the sin component of mapping wiimote angle to steering angle"));
// ---- Multitouch device
PARAM_PREFIX GroupUserConfigParam m_multitouch_group
PARAM_DEFAULT( GroupUserConfigParam("Multitouch",
"Settings for the multitouch device") );
PARAM_PREFIX BoolUserConfigParam m_multitouch_enabled
PARAM_DEFAULT( BoolUserConfigParam(false, "multitouch_enabled",
&m_multitouch_group,
"Enable multitouch support.") );
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_center
PARAM_DEFAULT( FloatUserConfigParam(0.15f, "multitouch_deadzone_center",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as centered in steering button."));
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_edge
PARAM_DEFAULT( FloatUserConfigParam(0.15f, "multitouch_deadzone_edge",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as max value in steering button."));
// ---- GP start order
PARAM_PREFIX GroupUserConfigParam m_gp_start_order
PARAM_DEFAULT( GroupUserConfigParam("GpStartOrder",

View File

@ -15,14 +15,16 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "2dutils.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shader.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/texture_shader.hpp"
#include "glwrap.hpp"
#include "utils/cpp2011.hpp"
#if defined(USE_GLES2)

View File

@ -0,0 +1,204 @@
// 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.
#include "graphics/abstract_renderer.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
using namespace irr;
#ifdef DEBUG
void AbstractRenderer::drawDebugMeshes() const
{
std::vector<irr::scene::IAnimatedMeshSceneNode*> debug_meshes = irr_driver->getDebugMeshes();
for (unsigned int n=0; n<debug_meshes.size(); n++)
{
scene::IMesh* mesh = debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
const core::array< scene::ISkinnedMesh::SJoint * >& joints =
smesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
drawJoint( false, true, joints[j], smesh, j);
}
}
video::SColor color(255,255,255,255);
video::SMaterial material;
material.Thickness = 2;
material.AmbientColor = color;
material.DiffuseColor = color;
material.EmissiveColor= color;
material.BackfaceCulling = false;
material.setFlag(video::EMF_LIGHTING, false);
irr_driver->getVideoDriver()->setMaterial(material);
irr_driver->getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix);
for (unsigned int n=0; n<debug_meshes.size(); n++)
{
scene::IMesh* mesh = debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
const core::array< scene::ISkinnedMesh::SJoint * >& joints =
smesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
scene::IMesh* mesh = debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
drawJoint(true, false, joints[j], smesh, j);
}
}
} // drawDebugMeshes
// ----------------------------------------------------------------------------
/** Draws a joint for debugging skeletons.
* \param drawline If true draw a line to the parent.
* \param drawname If true draw the name of the joint.
* \param joint The joint to draw.
* \param mesh The mesh whose skeleton is drawn (only used to get
* all joints to find the parent).
* \param id Index, which (%4) determines the color to use.
*/
void AbstractRenderer::drawJoint(bool drawline, bool drawname,
scene::ISkinnedMesh::SJoint* joint,
scene::ISkinnedMesh* mesh, int id) const
{
scene::ISkinnedMesh::SJoint* parent = NULL;
const core::array< scene::ISkinnedMesh::SJoint * >& joints
= mesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
if (joints[j]->Children.linear_search(joint) != -1)
{
parent = joints[j];
break;
}
}
core::vector3df jointpos = joint->GlobalMatrix.getTranslation();
video::SColor color(255, 255,255,255);
if (parent == NULL) color = video::SColor(255,0,255,0);
switch (id % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
if (parent)
{
core::vector3df parentpos = parent->GlobalMatrix.getTranslation();
jointpos = joint->GlobalMatrix.getTranslation();
if (drawline)
{
irr_driver->getVideoDriver()->draw3DLine(jointpos,
parentpos,
color);
}
}
if (joint->Children.size() == 0)
{
switch ((id + 1) % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
// This code doesn't quite work. 0.25 is used so that the bone is not
// way too long (not sure why I need to manually size it down)
// and the rotation of the bone is often rather off
core::vector3df v(0.0f, 0.25f, 0.0f);
//joint->GlobalMatrix.rotateVect(v);
joint->LocalMatrix.rotateVect(v);
v *= joint->LocalMatrix.getScale();
irr_driver->getVideoDriver()->draw3DLine(jointpos,
jointpos + v,
color);
}
switch ((id + 1) % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
if (drawname)
{
irr_driver->getVideoDriver()->setTransform(video::ETS_WORLD,
core::IdentityMatrix);
core::vector2di textpos =
irr_driver->getSceneManager()->getSceneCollisionManager()
->getScreenCoordinatesFrom3DPosition(jointpos);
GUIEngine::getSmallFont()->draw( core::stringw(joint->Name.c_str()),
core::rect<s32>(textpos,
core::dimension2d<s32>(500,50)),
color, false, false );
}
} //drawJoint
#endif //DEBUG
AbstractRenderer::AbstractRenderer()
{
resetObjectCount();
resetPolyCount();
}

View File

@ -0,0 +1,127 @@
// 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_ABSTRACT_RENDERER_HPP
#define HEADER_ABSTRACT_RENDERER_HPP
#include "graphics/gl_headers.hpp"
#include <irrlicht.h>
#include <memory>
#include <string>
#include <vector>
class RenderTarget;
enum STKRenderingPass
{
SOLID_NORMAL_AND_DEPTH_PASS,
SOLID_LIT_PASS,
TRANSPARENT_PASS,
GLOW_PASS,
SHADOW_PASS,
PASS_COUNT,
};
enum TypeRTT : unsigned int;
struct GlowData {
irr::scene::ISceneNode * node;
float r, g, b;
};
struct SHCoefficients;
/**
* \class AbstractRenderer
* \brief Virtual base class for the renderer
*
* \ingroup graphics
*/
class AbstractRenderer
{
protected:
irr::core::vector2df m_current_screen_size;
/** Performance stats */
unsigned m_object_count[PASS_COUNT];
unsigned m_poly_count [PASS_COUNT];
#ifdef DEBUG
void drawDebugMeshes() const;
void drawJoint(bool drawline, bool drawname,
irr::scene::ISkinnedMesh::SJoint* joint,
irr::scene::ISkinnedMesh* mesh, int id) const;
#endif
void renderSkybox(const irr::scene::ICameraSceneNode *camera) const;
public:
AbstractRenderer();
virtual ~AbstractRenderer(){}
virtual void onLoadWorld() = 0;
virtual void onUnloadWorld() = 0;
virtual void resetPostProcessing() {}
virtual void giveBoost(unsigned int cam_index) {}
virtual void addSkyBox(const std::vector<irr::video::ITexture*> &texture,
const std::vector<irr::video::ITexture*> &spherical_harmonics_textures) {}
virtual void removeSkyBox() {}
//FIXME: these three methods should not appear in the public Renderer interface
virtual const SHCoefficients* getSHCoefficients() const { return NULL; }
virtual GLuint getRenderTargetTexture(TypeRTT which) const { return 0;}
virtual GLuint getDepthStencilTexture( ) const { return 0;}
virtual void setAmbientLight(const irr::video::SColorf &light,
bool force_SH_computation = true) {}
virtual void addSunLight(const irr::core::vector3df &pos){}
virtual void addGlowingNode(irr::scene::ISceneNode *n,
float r = 1.0f, float g = 1.0f, float b = 1.0f) {}
virtual void clearGlowingNodes() {}
virtual void render(float dt) = 0;
// ------------------------------------------------------------------------
const irr::core::vector2df &getCurrentScreenSize() const
{
return m_current_screen_size;
}
// ----------------------------------------------------------------------------
/** Create a RenderTarget (for rendering to a texture)
* \param dimension The dimension of the texture
* \param name A unique name for the render target
*/
virtual std::unique_ptr<RenderTarget> createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name) = 0;
void resetObjectCount() { memset(m_object_count, 0, sizeof(m_object_count));}
void resetPolyCount() { memset(m_poly_count, 0, sizeof(m_poly_count)); }
void incObjectCount(STKRenderingPass phase) { m_object_count[phase]++; }
unsigned getObjectCount(STKRenderingPass pass) const { return m_object_count[pass]; }
unsigned getPolyCount(STKRenderingPass pass) const { return m_poly_count [pass]; }
};
#endif //HEADER_ABSTRACT_RENDERER_HPP

View File

@ -34,7 +34,7 @@ void CentralVideoSettings::init()
// Parse extensions
hasVSLayer = false;
hasBaseInstance = false;
hasBuffserStorage = false;
hasBufferStorage = false;
hasDrawIndirect = false;
hasComputeShaders = false;
hasArraysOfArrays = false;
@ -98,7 +98,7 @@ void CentralVideoSettings::init()
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_BUFFER_STORAGE) &&
hasGLExtension("GL_ARB_buffer_storage") )
{
hasBuffserStorage = true;
hasBufferStorage = true;
Log::info("GLDriver", "ARB Buffer Storage Present");
}
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_BASE_INSTANCE) &&
@ -315,7 +315,7 @@ bool CentralVideoSettings::isAMDVertexShaderLayerUsable() const
bool CentralVideoSettings::isARBBufferStorageUsable() const
{
return hasBuffserStorage;
return hasBufferStorage;
}
bool CentralVideoSettings::isARBComputeShaderUsable() const
@ -355,7 +355,7 @@ bool CentralVideoSettings::isARBShaderStorageBufferObjectUsable() const
bool CentralVideoSettings::isARBImageLoadStoreUsable() const
{
return hasComputeShaders;
return hasImageLoadStore;
}
bool CentralVideoSettings::isARBMultiDrawIndirectUsable() const

View File

@ -28,7 +28,7 @@ private:
bool hasVSLayer;
bool hasBaseInstance;
bool hasDrawIndirect;
bool hasBuffserStorage;
bool hasBufferStorage;
bool hasComputeShaders;
bool hasArraysOfArrays;
bool hasTextureStorage;

View File

@ -0,0 +1,255 @@
// 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.
#include "graphics/command_buffer.hpp"
#include "graphics/central_settings.hpp"
#include "utils/cpp2011.hpp"
// ----------------------------------------------------------------------------
template<>
void InstanceFiller<InstanceDataSingleTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataSingleTex &instance)
{
fillOriginOrientationScale<InstanceDataSingleTex>(node, instance);
instance.Texture = mesh->TextureHandles[0];
}
// ----------------------------------------------------------------------------
template<>
void InstanceFiller<InstanceDataDualTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataDualTex &instance)
{
fillOriginOrientationScale<InstanceDataDualTex>(node, instance);
instance.Texture = mesh->TextureHandles[0];
instance.SecondTexture = mesh->TextureHandles[1];
}
// ----------------------------------------------------------------------------
template<>
void InstanceFiller<InstanceDataThreeTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataThreeTex &instance)
{
fillOriginOrientationScale<InstanceDataThreeTex>(node, instance);
instance.Texture = mesh->TextureHandles[0];
instance.SecondTexture = mesh->TextureHandles[1];
instance.ThirdTexture = mesh->TextureHandles[2];
}
// ----------------------------------------------------------------------------
template<>
void InstanceFiller<GlowInstanceData>::add(GLMesh *mesh, scene::ISceneNode *node, GlowInstanceData &instance)
{
fillOriginOrientationScale<GlowInstanceData>(node, instance);
STKMeshSceneNode *nd = dynamic_cast<STKMeshSceneNode*>(node);
instance.Color = nd->getGlowColor().color;
}
// ----------------------------------------------------------------------------
template<>
void expandTexSecondPass<GrassMat>(const GLMesh &mesh,
const std::vector<GLuint> &prefilled_tex)
{
TexExpander<typename GrassMat::InstancedSecondPassShader>::
expandTex(mesh, GrassMat::SecondPassTextures, prefilled_tex[0],
prefilled_tex[1], prefilled_tex[2], prefilled_tex[3]);
}
// ----------------------------------------------------------------------------
template<>
void expandHandlesSecondPass<GrassMat>(const std::vector<uint64_t> &handles)
{
uint64_t nulltex[10] = {};
HandleExpander<GrassMat::InstancedSecondPassShader>::
expand(nulltex, GrassMat::SecondPassTextures,
handles[0], handles[1], handles[2], handles[3]);
}
#if !defined(USE_GLES2)
// ----------------------------------------------------------------------------
template<int N>
void CommandBuffer<N>::clearMeshes()
{
m_instance_buffer_offset = 0;
m_command_buffer_offset = 0;
m_poly_count = 0;
for(int i=0;i<N;i++)
{
m_meshes[i].clear();
}
}
// ----------------------------------------------------------------------------
template<int N>
void CommandBuffer<N>::mapIndirectBuffer()
{
glBindBuffer(GL_DRAW_INDIRECT_BUFFER,
m_draw_indirect_cmd_id);
m_draw_indirect_cmd = (DrawElementsIndirectCommand*)
glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0,
10000 * sizeof(DrawElementsIndirectCommand),
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
// ----------------------------------------------------------------------------
template<int N>
CommandBuffer<N>::CommandBuffer():
m_poly_count(0)
{
glGenBuffers(1, &m_draw_indirect_cmd_id);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_indirect_cmd_id);
if (CVS->supportsAsyncInstanceUpload())
{
glBufferStorage(GL_DRAW_INDIRECT_BUFFER,
10000 * sizeof(DrawElementsIndirectCommand),
0, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
m_draw_indirect_cmd = (DrawElementsIndirectCommand *)
glMapBufferRange(GL_DRAW_INDIRECT_BUFFER,
0, 10000 * sizeof(DrawElementsIndirectCommand),
GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
}
else
{
glBufferData(GL_DRAW_INDIRECT_BUFFER,
10000 * sizeof(DrawElementsIndirectCommand),
0, GL_STREAM_DRAW);
}
}
// ----------------------------------------------------------------------------
SolidCommandBuffer::SolidCommandBuffer(): CommandBuffer()
{
}
// ----------------------------------------------------------------------------
void SolidCommandBuffer::fill(SolidPassMeshMap *mesh_map)
{
clearMeshes();
if(!CVS->supportsAsyncInstanceUpload())
mapIndirectBuffer();
std::vector<int> dual_tex_material_list =
createVector<int>(Material::SHADERTYPE_SOLID,
Material::SHADERTYPE_ALPHA_TEST,
Material::SHADERTYPE_SOLID_UNLIT,
Material::SHADERTYPE_SPHERE_MAP,
Material::SHADERTYPE_VEGETATION);
fillInstanceData<InstanceDataDualTex, SolidPassMeshMap>
(mesh_map, dual_tex_material_list, InstanceTypeDualTex);
std::vector<int> three_tex_material_list =
createVector<int>(Material::SHADERTYPE_DETAIL_MAP,
Material::SHADERTYPE_NORMAL_MAP);
fillInstanceData<InstanceDataThreeTex, SolidPassMeshMap>
(mesh_map, three_tex_material_list, InstanceTypeThreeTex);
if (!CVS->supportsAsyncInstanceUpload())
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
} //SolidCommandBuffer::fill
// ----------------------------------------------------------------------------
ShadowCommandBuffer::ShadowCommandBuffer(): CommandBuffer()
{
}
// ----------------------------------------------------------------------------
void ShadowCommandBuffer::fill(OtherMeshMap *mesh_map)
{
clearMeshes();
if(!CVS->supportsAsyncInstanceUpload())
mapIndirectBuffer();
std::vector<int> shadow_tex_material_list;
for(int cascade=0; cascade<4; cascade++)
{
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SOLID);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_ALPHA_TEST);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SOLID_UNLIT);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_NORMAL_MAP);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SPHERE_MAP);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_DETAIL_MAP);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_VEGETATION);
shadow_tex_material_list.push_back(cascade * Material::SHADERTYPE_COUNT
+ Material::SHADERTYPE_SPLATTING);
}
fillInstanceData<InstanceDataSingleTex, OtherMeshMap>
(mesh_map, shadow_tex_material_list, InstanceTypeShadow);
if (!CVS->supportsAsyncInstanceUpload())
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
} //ShadowCommandBuffer::fill
// ----------------------------------------------------------------------------
ReflectiveShadowMapCommandBuffer::ReflectiveShadowMapCommandBuffer()
{
}
// ----------------------------------------------------------------------------
void ReflectiveShadowMapCommandBuffer::fill(OtherMeshMap *mesh_map)
{
clearMeshes();
if(!CVS->supportsAsyncInstanceUpload())
mapIndirectBuffer();
std::vector<int> rsm_material_list =
createVector<int>(Material::SHADERTYPE_SOLID,
Material::SHADERTYPE_ALPHA_TEST,
Material::SHADERTYPE_SOLID_UNLIT,
Material::SHADERTYPE_DETAIL_MAP,
Material::SHADERTYPE_NORMAL_MAP);
fillInstanceData<InstanceDataSingleTex, OtherMeshMap>
(mesh_map, rsm_material_list, InstanceTypeRSM);
if (!CVS->supportsAsyncInstanceUpload())
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
} //ReflectiveShadowMapCommandBuffer::fill
// ----------------------------------------------------------------------------
GlowCommandBuffer::GlowCommandBuffer()
{
}
// ----------------------------------------------------------------------------
void GlowCommandBuffer::fill(OtherMeshMap *mesh_map)
{
clearMeshes();
if(!CVS->supportsAsyncInstanceUpload())
mapIndirectBuffer();
fillInstanceData<GlowInstanceData, OtherMeshMap>
(mesh_map, createVector<int>(0), InstanceTypeGlow);
if (!CVS->supportsAsyncInstanceUpload())
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
} //GlowCommandBuffer::fill
#endif // !defined(USE_GLES2)

View File

@ -0,0 +1,669 @@
// 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(InstanceDataDualTex));
}
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(InstanceDataDualTex),
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);
glDrawElementsIndirect(GL_TRIANGLES,
GL_UNSIGNED_SHORT,
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand)));
}
} //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());
}
glDrawElementsIndirect(GL_TRIANGLES,
GL_UNSIGNED_SHORT,
(const void*)((m_offset[T::MaterialType] + i) * sizeof(DrawElementsIndirectCommand)));
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

847
src/graphics/draw_calls.cpp Normal file
View File

@ -0,0 +1,847 @@
// 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.
#include "graphics/draw_calls.hpp"
#include "config/user_config.hpp"
#include "graphics/draw_tools.hpp"
#include "graphics/gpu_particles.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/materials.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/stk_scene_manager.hpp"
#include "graphics/vao_manager.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
using namespace irr;
namespace
{
void FixBoundingBoxes(scene::ISceneNode* node)
{
for (scene::ISceneNode *child : node->getChildren())
{
FixBoundingBoxes(child);
const_cast<core::aabbox3df&>(node->getBoundingBox()).addInternalBox(child->getBoundingBox());
}
}
} //namespace
// ----------------------------------------------------------------------------
void DrawCalls::clearLists()
{
ListBlendTransparent::getInstance()->clear();
ListAdditiveTransparent::getInstance()->clear();
ListGhostKart::getInstance()->clear();
ListGhostKartTangents::getInstance()->clear();
ListBlendTransparentFog::getInstance()->clear();
ListAdditiveTransparentFog::getInstance()->clear();
ListDisplacement::getInstance()->clear();
ListMatDefault::getInstance()->clear();
ListMatAlphaRef::getInstance()->clear();
ListMatSphereMap::getInstance()->clear();
ListMatDetails::getInstance()->clear();
ListMatUnlit::getInstance()->clear();
ListMatNormalMap::getInstance()->clear();
ListMatGrass::getInstance()->clear();
ListMatSplatting::getInstance()->clear();
m_immediate_draw_list.clear();
m_billboard_list.clear();
m_particles_list.clear();
}
// ----------------------------------------------------------------------------
void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode *cam,
scene::ICameraSceneNode *shadowcam[4],
const scene::ICameraSceneNode *rsmcam,
bool &culledforcam,
bool culledforshadowcam[4],
bool &culledforrsm,
bool drawRSM)
{
STKMeshCommon *node = dynamic_cast<STKMeshCommon*>(Node);
if (!node)
return;
node->updateNoGL();
m_deferred_update.push_back(node);
const core::matrix4 &trans = Node->getAbsoluteTransformation();
core::vector3df edges[8];
Node->getBoundingBox().getEdges(edges);
for (unsigned i = 0; i < 8; i++)
trans.transformVect(edges[i]);
/* From irrlicht
/3--------/7
/ | / |
/ | / |
1---------5 |
| /2- - -|- -6
| / | /
|/ | /
0---------4/
*/
if (irr_driver->getBoundingBoxesViz())
{
addEdge(edges[0], edges[1]);
addEdge(edges[1], edges[5]);
addEdge(edges[5], edges[4]);
addEdge(edges[4], edges[0]);
addEdge(edges[2], edges[3]);
addEdge(edges[3], edges[7]);
addEdge(edges[7], edges[6]);
addEdge(edges[6], edges[2]);
addEdge(edges[0], edges[2]);
addEdge(edges[1], edges[3]);
addEdge(edges[5], edges[7]);
addEdge(edges[4], edges[6]);
}
if (node->isImmediateDraw())
{
ImmediateDraw->push_back(Node);
return;
}
culledforcam = culledforcam || isCulledPrecise(cam, Node);
culledforrsm = culledforrsm || isCulledPrecise(rsmcam, Node);
for (unsigned i = 0; i < 4; i++)
culledforshadowcam[i] = culledforshadowcam[i] || isCulledPrecise(shadowcam[i], Node);
// Transparent
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
const Track * const track = World::getWorld()->getTrack();
// Todo : put everything in a ubo
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
video::SColorf col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
for (GLMesh *mesh : node->TransparentMesh[TM_DEFAULT])
pushVector(ListBlendTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix,
fogmax, startH, endH, start, end, col);
for (GLMesh *mesh : node->TransparentMesh[TM_ADDITIVE])
pushVector(ListAdditiveTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix,
fogmax, startH, endH, start, end, col);
}
else
{
for (GLMesh *mesh : node->TransparentMesh[TM_DEFAULT])
pushVector(ListBlendTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, 1.0f);
for (GLMesh *mesh : node->TransparentMesh[TM_ADDITIVE])
pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, 1.0f);
}
// Use sun color to determine custom alpha for ghost karts
float custom_alpha = 1.0f;
if (World::getWorld())
{
const video::SColor& c = World::getWorld()->getTrack()->getSunColor();
float y = 0.2126f * c.getRed() + 0.7152f * c.getGreen() + 0.0722f * c.getBlue();
custom_alpha = y > 128.0f ? 0.5f : 0.35f;
}
for (GLMesh *mesh : node->TransparentMesh[TM_GHOST_KART])
pushVector(ListGhostKart::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, custom_alpha);
for (GLMesh *mesh : node->TransparentMesh[TM_GHOST_KART_TANGENTS])
pushVector(ListGhostKartTangents::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, custom_alpha);
for (GLMesh *mesh : node->TransparentMesh[TM_DISPLACEMENT])
pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation());
if (!culledforcam)
{
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
if (node->glow())
{
m_glow_pass_mesh[mesh->mb].m_mesh = mesh;
m_glow_pass_mesh[mesh->mb].m_scene_nodes.emplace_back(Node);
}
if (Mat != Material::SHADERTYPE_SPLATTING && mesh->TextureMatrix.isIdentity())
{
std::pair<scene::IMeshBuffer*, RenderInfo*> meshRenderInfo(mesh->mb, mesh->m_render_info);
m_solid_pass_mesh[Mat][meshRenderInfo].m_mesh = mesh;
m_solid_pass_mesh[Mat][meshRenderInfo].m_scene_nodes.emplace_back(Node);
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_ALPHA_BLEND:
break;
case Material::SHADERTYPE_ADDITIVE:
break;
case Material::SHADERTYPE_VEGETATION:
break;
case Material::SHADERTYPE_WATER:
break;
case Material::SHADERTYPE_SPHERE_MAP:
break;
case Material::SHADERTYPE_NORMAL_MAP:
break;
case Material::SHADERTYPE_DETAIL_MAP:
break;
default:
Log::warn("DrawCalls", "Unknown material type: %d", Mat);
}
}
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, m_wind_dir);
break;
case Material::SHADERTYPE_ALPHA_BLEND:
break;
case Material::SHADERTYPE_ADDITIVE:
break;
case Material::SHADERTYPE_WATER:
break;
default:
Log::warn("DrawCalls", "Unknown material type: %d", Mat);
}
}
}
}
}
if (!CVS->isShadowEnabled())
return;
for (unsigned cascade = 0; cascade < 4; ++cascade)
{
if (culledforshadowcam[cascade])
continue;
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_mesh = mesh;
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_scene_nodes.emplace_back(Node);
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, m_wind_dir);
case Material::SHADERTYPE_ALPHA_BLEND:
break;
case Material::SHADERTYPE_ADDITIVE:
break;
case Material::SHADERTYPE_WATER:
break;
default:
Log::warn("DrawCalls", "Unknown material type: %d", Mat);
}
}
}
}
}
if (!UserConfigParams::m_gi || !drawRSM)
return;
if (!culledforrsm)
{
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
if (Mat == Material::SHADERTYPE_SPLATTING)
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
}
else
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_mesh = mesh;
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_scene_nodes.emplace_back(Node);
}
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, m_wind_dir);
break;
case Material::SHADERTYPE_ALPHA_BLEND:
break;
case Material::SHADERTYPE_ADDITIVE:
break;
case Material::SHADERTYPE_WATER:
break;
default:
Log::warn("DrawCalls", "Unknown material type: %d", Mat);
}
}
}
}
}
}
void DrawCalls::parseSceneManager(core::list<scene::ISceneNode*> &List,
std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode* cam,
scene::ICameraSceneNode *shadow_cam[4],
const scene::ICameraSceneNode *rsmcam,
bool culledforcam,
bool culledforshadowcam[4],
bool culledforrsm,
bool drawRSM)
{
core::list<scene::ISceneNode*>::Iterator I = List.begin(), E = List.end();
for (; I != E; ++I)
{
if (LODNode *node = dynamic_cast<LODNode *>(*I))
node->updateVisibility();
(*I)->updateAbsolutePosition();
if (!(*I)->isVisible())
continue;
if (ParticleSystemProxy *node = dynamic_cast<ParticleSystemProxy *>(*I))
{
if (!isCulledPrecise(cam, *I))
m_particles_list.push_back(node);
continue;
}
if (STKBillboard *node = dynamic_cast<STKBillboard *>(*I))
{
if (!isCulledPrecise(cam, *I))
m_billboard_list.push_back(node);
continue;
}
bool newculledforcam = culledforcam;
bool newculledforrsm = culledforrsm;
bool newculledforshadowcam[4] = { culledforshadowcam[0], culledforshadowcam[1], culledforshadowcam[2], culledforshadowcam[3] };
handleSTKCommon(*I, ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm, drawRSM);
parseSceneManager(const_cast<core::list<scene::ISceneNode*>& >((*I)->getChildren()), ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm, drawRSM);
}
}
// ----------------------------------------------------------------------------
DrawCalls::DrawCalls()
{
m_sync = 0;
#if !defined(USE_GLES2)
m_solid_cmd_buffer = NULL;
m_shadow_cmd_buffer = NULL;
m_reflective_shadow_map_cmd_buffer = NULL;
m_glow_cmd_buffer = NULL;
if(CVS->supportsIndirectInstancingRendering())
{
m_solid_cmd_buffer = new SolidCommandBuffer();
m_shadow_cmd_buffer = new ShadowCommandBuffer();
m_reflective_shadow_map_cmd_buffer = new ReflectiveShadowMapCommandBuffer();
m_glow_cmd_buffer = new GlowCommandBuffer();
}
#endif // !defined(USE_GLES2)
} //DrawCalls
DrawCalls::~DrawCalls()
{
#if !defined(USE_GLES2)
delete m_solid_cmd_buffer;
delete m_shadow_cmd_buffer;
delete m_reflective_shadow_map_cmd_buffer;
delete m_glow_cmd_buffer;
#endif // !defined(USE_GLES2)
} //~DrawCalls
// ----------------------------------------------------------------------------
/** Prepare draw calls before scene rendering
* \param[out] solid_poly_count Total number of polygons in objects
* that will be rendered in this frame
* \param[out] shadow_poly_count Total number of polygons for shadow
* (rendered this frame)
*/
void DrawCalls::prepareDrawCalls( ShadowMatrices& shadow_matrices,
scene::ICameraSceneNode *camnode,
unsigned &solid_poly_count,
unsigned &shadow_poly_count)
{
m_wind_dir = getWindDir();
clearLists();
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
m_solid_pass_mesh[Mat].clear();
m_reflective_shadow_map_mesh[Mat].clear();
for (unsigned i = 0; i < 4; i++)
m_shadow_pass_mesh[i * Material::SHADERTYPE_COUNT + Mat].clear();
}
m_glow_pass_mesh.clear();
m_deferred_update.clear();
core::list<scene::ISceneNode*> List = irr_driver->getSceneManager()->getRootSceneNode()->getChildren();
PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
for (scene::ISceneNode *child : List)
FixBoundingBoxes(child);
bool cam = false, rsmcam = false;
bool shadowcam[4] = { false, false, false, false };
parseSceneManager(List,
&m_immediate_draw_list,
camnode,
shadow_matrices.getShadowCamNodes(),
shadow_matrices.getSunCam(),
cam, shadowcam, rsmcam,
!shadow_matrices.isRSMMapAvail());
PROFILER_POP_CPU_MARKER();
// Add a 1 s timeout
if (!m_sync)
m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
PROFILER_PUSH_CPU_MARKER("- Sync Stall", 0xFF, 0x0, 0x0);
GLenum reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
if (reason != GL_ALREADY_SIGNALED)
{
do
{
reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000);
}
while (reason == GL_TIMEOUT_EXPIRED);
}
glDeleteSync(m_sync);
PROFILER_POP_CPU_MARKER();
/* switch (reason)
{
case GL_ALREADY_SIGNALED:
printf("Already Signaled\n");
break;
case GL_TIMEOUT_EXPIRED:
printf("Timeout Expired\n");
break;
case GL_CONDITION_SATISFIED:
printf("Condition Satisfied\n");
break;
case GL_WAIT_FAILED:
printf("Wait Failed\n");
break;
}*/
PROFILER_PUSH_CPU_MARKER("- Animations/Buffer upload", 0x0, 0x0, 0x0);
for (unsigned i = 0; i < m_deferred_update.size(); i++)
m_deferred_update[i]->updateGL();
PROFILER_POP_CPU_MARKER();
if (!CVS->supportsIndirectInstancingRendering())
return;
#if !defined(USE_GLES2)
int enableOpenMP = 0;
if (CVS->supportsAsyncInstanceUpload())
enableOpenMP = 1;
PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF);
#pragma omp parallel sections if(enableOpenMP)
{
#pragma omp section
{
m_solid_cmd_buffer->fill(m_solid_pass_mesh);
}
#pragma omp section
{
m_glow_cmd_buffer->fill(&m_glow_pass_mesh);
}
#pragma omp section
{
irr_driver->setPhase(SHADOW_PASS);
m_shadow_cmd_buffer->fill(m_shadow_pass_mesh);
}
#pragma omp section
if (!shadow_matrices.isRSMMapAvail())
{
m_reflective_shadow_map_cmd_buffer->fill(m_reflective_shadow_map_mesh);
}
}
PROFILER_POP_CPU_MARKER();
solid_poly_count = m_solid_cmd_buffer->getPolyCount();
shadow_poly_count = m_shadow_cmd_buffer->getPolyCount();
if (CVS->supportsAsyncInstanceUpload())
glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
#endif // !defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void DrawCalls::renderImmediateDrawList() const
{
glActiveTexture(GL_TEXTURE0);
for(auto node: m_immediate_draw_list)
node->render();
}
// ----------------------------------------------------------------------------
void DrawCalls::renderBillboardList() const
{
glActiveTexture(GL_TEXTURE0);
for(auto billboard: m_billboard_list)
billboard->render();
}
// ----------------------------------------------------------------------------
void DrawCalls::renderParticlesList() const
{
glActiveTexture(GL_TEXTURE0);
for(auto particles: m_particles_list)
particles->render();
}
#if !defined(USE_GLES2)
// ----------------------------------------------------------------------------
/** Render the solid first pass (depth and normals)
* Require at least OpenGL 4.0
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
*/
void DrawCalls::drawIndirectSolidFirstPass() const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->drawIndirectFirstPass<DefaultMaterial>();
m_solid_cmd_buffer->drawIndirectFirstPass<AlphaRef>();
m_solid_cmd_buffer->drawIndirectFirstPass<UnlitMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<SphereMap>();
m_solid_cmd_buffer->drawIndirectFirstPass<GrassMat>(m_wind_dir);
m_solid_cmd_buffer->drawIndirectFirstPass<DetailMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<NormalMat>();
}
// ----------------------------------------------------------------------------
/** Render the solid first pass (depth and normals)
* Require OpenGL AZDO extensions. Faster than drawIndirectSolidFirstPass.
*/
void DrawCalls::multidrawSolidFirstPass() const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->multidrawFirstPass<DefaultMaterial>();
m_solid_cmd_buffer->multidrawFirstPass<AlphaRef>();
m_solid_cmd_buffer->multidrawFirstPass<SphereMap>();
m_solid_cmd_buffer->multidrawFirstPass<UnlitMat>();
m_solid_cmd_buffer->multidrawFirstPass<GrassMat>(m_wind_dir);
m_solid_cmd_buffer->multidrawFirstPass<NormalMat>();
m_solid_cmd_buffer->multidrawFirstPass<DetailMat>();
}
// ----------------------------------------------------------------------------
/** Render the solid second pass (apply lighting on materials)
* Require at least OpenGL 4.0
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
* \param prefilled_tex The textures which have been drawn
* during previous rendering passes.
*/
void DrawCalls::drawIndirectSolidSecondPass(const std::vector<GLuint> &prefilled_tex) const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->drawIndirectSecondPass<DefaultMaterial>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<AlphaRef>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<UnlitMat>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SphereMap>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<GrassMat>(prefilled_tex, m_wind_dir);
m_solid_cmd_buffer->drawIndirectSecondPass<DetailMat>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<NormalMat>(prefilled_tex);
}
// ----------------------------------------------------------------------------
/** Render the solid second pass (apply lighting on materials)
* Require OpenGL AZDO extensions. Faster than drawIndirectSolidSecondPass.
* \param handles The handles to textures which have been drawn
* during previous rendering passes.
*/
void DrawCalls::multidrawSolidSecondPass(const std::vector<uint64_t> &handles) const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->multidraw2ndPass<DefaultMaterial>(handles);
m_solid_cmd_buffer->multidraw2ndPass<AlphaRef>(handles);
m_solid_cmd_buffer->multidraw2ndPass<SphereMap>(handles);
m_solid_cmd_buffer->multidraw2ndPass<UnlitMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<NormalMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<DetailMat>(handles);
m_solid_cmd_buffer->multidraw2ndPass<GrassMat>(handles, m_wind_dir);
}
// ----------------------------------------------------------------------------
/** Render normals (for debug)
* Require at least OpenGL 4.0
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
*/
void DrawCalls::drawIndirectNormals() const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->drawIndirectNormals<DefaultMaterial>();
m_solid_cmd_buffer->drawIndirectNormals<AlphaRef>();
m_solid_cmd_buffer->drawIndirectNormals<UnlitMat>();
m_solid_cmd_buffer->drawIndirectNormals<SphereMap>();
m_solid_cmd_buffer->drawIndirectNormals<DetailMat>();
m_solid_cmd_buffer->drawIndirectNormals<NormalMat>();
}
// ----------------------------------------------------------------------------
/** Render normals (for debug)
* Require OpenGL AZDO extensions. Faster than drawIndirectNormals.
*/
void DrawCalls::multidrawNormals() const
{
m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->multidrawNormals<DefaultMaterial>();
m_solid_cmd_buffer->multidrawNormals<AlphaRef>();
m_solid_cmd_buffer->multidrawNormals<UnlitMat>();
m_solid_cmd_buffer->multidrawNormals<SphereMap>();
m_solid_cmd_buffer->multidrawNormals<DetailMat>();
m_solid_cmd_buffer->multidrawNormals<NormalMat>();
}
// ----------------------------------------------------------------------------
/** Render shadow map
* Require at least OpenGL 4.0
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
* \param cascade The id of the cascading shadow map.
*/
void DrawCalls::drawIndirectShadows(unsigned cascade) const
{
m_shadow_cmd_buffer->bind();
m_shadow_cmd_buffer->drawIndirect<DefaultMaterial>(cascade);
m_shadow_cmd_buffer->drawIndirect<DetailMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<AlphaRef>(cascade);
m_shadow_cmd_buffer->drawIndirect<UnlitMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<GrassMat,irr::core::vector3df>(cascade, m_wind_dir);
m_shadow_cmd_buffer->drawIndirect<NormalMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<SplattingMat>(cascade);
m_shadow_cmd_buffer->drawIndirect<SphereMap>(cascade);
}
// ----------------------------------------------------------------------------
/** Render shadow map
* Require OpenGL AZDO extensions. Faster than drawIndirectShadows.
* \param cascade The id of the cascading shadow map.
*/
void DrawCalls::multidrawShadows(unsigned cascade) const
{
m_shadow_cmd_buffer->bind();
m_shadow_cmd_buffer->multidrawShadow<DefaultMaterial>(cascade);
m_shadow_cmd_buffer->multidrawShadow<DetailMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<NormalMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<AlphaRef>(cascade);
m_shadow_cmd_buffer->multidrawShadow<UnlitMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<GrassMat,irr::core::vector3df>(cascade, m_wind_dir);
m_shadow_cmd_buffer->multidrawShadow<SplattingMat>(cascade);
m_shadow_cmd_buffer->multidrawShadow<SphereMap>(cascade);
}
// ----------------------------------------------------------------------------
/** Render reflective shadow map (need to be called only once per track)
* Require at least OpenGL 4.0
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)
* \param rsm_matrix The reflective shadow map matrix
*/
void DrawCalls::drawIndirectReflectiveShadowMaps(const core::matrix4 &rsm_matrix) const
{
m_reflective_shadow_map_cmd_buffer->bind();
m_reflective_shadow_map_cmd_buffer->drawIndirect<DefaultMaterial>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->drawIndirect<AlphaRef>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->drawIndirect<UnlitMat>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->drawIndirect<NormalMat>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->drawIndirect<DetailMat>(rsm_matrix);
}
// ----------------------------------------------------------------------------
/** Render reflective shadow map (need to be called only once per track)
* Require OpenGL AZDO extensions. Faster than drawIndirectReflectiveShadowMaps.
* \param rsm_matrix The reflective shadow map matrix
*/
void DrawCalls::multidrawReflectiveShadowMaps(const core::matrix4 &rsm_matrix) const
{
m_reflective_shadow_map_cmd_buffer->bind();
m_reflective_shadow_map_cmd_buffer->multidraw<DefaultMaterial>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->multidraw<NormalMat>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->multidraw<AlphaRef>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->multidraw<UnlitMat>(rsm_matrix);
m_reflective_shadow_map_cmd_buffer->multidraw<DetailMat>(rsm_matrix);
}
// ----------------------------------------------------------------------------
/** Render glowing objects.
* Require at least OpenGL 4.0
* or GL_ARB_base_instance, GL_ARB_draw_indirect
* and GL_ARB_explicit_attrib_location extensions
*/
void DrawCalls::drawIndirectGlow() const
{
m_glow_cmd_buffer->bind();
m_glow_cmd_buffer->drawIndirect();
}
// ----------------------------------------------------------------------------
/** Render glowing objects.
* Require OpenGL AZDO extensions. Faster than drawIndirectGlow.
*/
void DrawCalls::multidrawGlow() const
{
m_glow_cmd_buffer->bind();
m_glow_cmd_buffer->multidraw();
}
#endif // !defined(USE_GLES2)

109
src/graphics/draw_calls.hpp Normal file
View File

@ -0,0 +1,109 @@
// 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_DRAW_CALLS_HPP
#define HEADER_DRAW_CALLS_HPP
#include "graphics/command_buffer.hpp"
#include <irrlicht.h>
#include <unordered_map>
class ParticleSystemProxy;
class ShadowMatrices;
class STKBillboard;
class DrawCalls
{
private:
std::vector<STKMeshCommon *> m_deferred_update;
irr::core::vector3df m_wind_dir;
GLsync m_sync;
std::vector<irr::scene::ISceneNode *> m_immediate_draw_list;
std::vector<STKBillboard *> m_billboard_list;
std::vector<ParticleSystemProxy *> m_particles_list;
/** meshes to draw */
SolidPassMeshMap m_solid_pass_mesh [ Material::SHADERTYPE_COUNT];
OtherMeshMap m_shadow_pass_mesh [4 * Material::SHADERTYPE_COUNT];
OtherMeshMap m_reflective_shadow_map_mesh [ Material::SHADERTYPE_COUNT];
OtherMeshMap m_glow_pass_mesh;
#if !defined(USE_GLES2)
/** meshes data in VRAM */
SolidCommandBuffer *m_solid_cmd_buffer;
ShadowCommandBuffer *m_shadow_cmd_buffer;
ReflectiveShadowMapCommandBuffer *m_reflective_shadow_map_cmd_buffer;
GlowCommandBuffer *m_glow_cmd_buffer;
#endif // !defined(USE_GLES2)
void clearLists();
void handleSTKCommon(scene::ISceneNode *Node,
std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode *cam,
scene::ICameraSceneNode *shadowcam[4],
const scene::ICameraSceneNode *rsmcam,
bool &culledforcam,
bool culledforshadowcam[4],
bool &culledforrsm,
bool drawRSM);
void parseSceneManager(core::list<scene::ISceneNode*> &List,
std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode* cam,
scene::ICameraSceneNode *shadow_cam[4],
const scene::ICameraSceneNode *rsmcam,
bool culledforcam,
bool culledforshadowcam[4],
bool culledforrsm,
bool drawRSM);
public:
DrawCalls();
~DrawCalls();
void prepareDrawCalls(ShadowMatrices& shadow_matrices,
irr::scene::ICameraSceneNode *camnode,
unsigned &solid_poly_count,
unsigned &shadow_poly_count);
void setFenceSync() { m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); }
void renderImmediateDrawList() const;
void renderBillboardList() const;
void renderParticlesList() const;
void drawIndirectSolidFirstPass() const;
void multidrawSolidFirstPass() const;
void drawIndirectSolidSecondPass(const std::vector<GLuint> &prefilled_tex) const;
void multidrawSolidSecondPass(const std::vector<uint64_t> &handles) const;
void drawIndirectNormals() const;
void multidrawNormals() const;
void drawIndirectShadows(unsigned cascade) const;
void multidrawShadows(unsigned cascade) const;
void drawIndirectReflectiveShadowMaps(const core::matrix4 &rsm_matrix) const;
void multidrawReflectiveShadowMaps(const core::matrix4 &rsm_matrix) const;
void drawIndirectGlow() const;
void multidrawGlow() const;
};
#endif //HEADER_DRAW_CALLS_HPP

View File

@ -0,0 +1,338 @@
// 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.
#include "graphics/draw_policies.hpp"
#include "graphics/draw_tools.hpp"
#include "graphics/materials.hpp"
// ----------------------------------------------------------------------------
template<typename T, int ...List>
void renderMeshes1stPass()
{
auto &meshes = T::List::getInstance()->SolidPass;
T::FirstPassShader::getInstance()->use();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(T::VertexType));
for (unsigned i = 0; i < meshes.size(); i++)
{
GLMesh &mesh = *(STK::tuple_get<0>(meshes.at(i)));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh.vao);
if (mesh.VAOType != T::VertexType)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to pass 1 (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str());
#endif
continue;
}
if (CVS->isAZDOEnabled())
HandleExpander<typename T::FirstPassShader>::template expand(mesh.TextureHandles, T::FirstPassTextures);
else
TexExpander<typename T::FirstPassShader>::template expandTex(mesh, T::FirstPassTextures);
CustomUnrollArgs<List...>::template drawMesh<typename T::FirstPassShader>(meshes.at(i));
}
} // renderMeshes1stPass
// ----------------------------------------------------------------------------
template<typename T, int...List>
void renderMeshes2ndPass( const std::vector<uint64_t> &Prefilled_Handle,
const std::vector<GLuint> &Prefilled_Tex)
{
auto &meshes = T::List::getInstance()->SolidPass;
T::SecondPassShader::getInstance()->use();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(T::VertexType));
for (unsigned i = 0; i < meshes.size(); i++)
{
GLMesh &mesh = *(STK::tuple_get<0>(meshes.at(i)));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh.vao);
if (mesh.VAOType != T::VertexType)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to pass 2 "
"(hint texture : %s)",
mesh.textures[0]->getName().getPath().c_str());
#endif
continue;
}
if (CVS->isAZDOEnabled())
HandleExpander<typename T::SecondPassShader>::template
expand(mesh.TextureHandles, T::SecondPassTextures,
Prefilled_Handle[0], Prefilled_Handle[1],
Prefilled_Handle[2]);
else
TexExpander<typename T::SecondPassShader>::template
expandTex(mesh, T::SecondPassTextures, Prefilled_Tex[0],
Prefilled_Tex[1], Prefilled_Tex[2]);
CustomUnrollArgs<List...>::template drawMesh<typename T::SecondPassShader>(meshes.at(i));
}
} // renderMeshes2ndPass
// ----------------------------------------------------------------------------
template<typename T, int...List>
void renderShadow(unsigned cascade)
{
auto &t = T::List::getInstance()->Shadows[cascade];
T::ShadowPassShader::getInstance()->use();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(T::VertexType));
for (unsigned i = 0; i < t.size(); i++)
{
GLMesh *mesh = STK::tuple_get<0>(t.at(i));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh->vao);
if (CVS->isAZDOEnabled())
HandleExpander<typename T::ShadowPassShader>::template expand(mesh->TextureHandles, T::ShadowTextures);
else
TexExpander<typename T::ShadowPassShader>::template expandTex(*mesh, T::ShadowTextures);
CustomUnrollArgs<List...>::template drawMesh<typename T::ShadowPassShader>(t.at(i), cascade);
} // for i
} // renderShadow
// ----------------------------------------------------------------------------
template<typename T, int... Selector>
void drawRSM(const core::matrix4 & rsm_matrix)
{
T::RSMShader::getInstance()->use();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(T::VertexType));
auto t = T::List::getInstance()->RSM;
for (unsigned i = 0; i < t.size(); i++)
{
std::vector<GLuint> Textures;
GLMesh *mesh = STK::tuple_get<0>(t.at(i));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh->vao);
if (CVS->isAZDOEnabled())
HandleExpander<typename T::RSMShader>::template expand(mesh->TextureHandles, T::RSMTextures);
else
TexExpander<typename T::RSMShader>::template expandTex(*mesh, T::RSMTextures);
CustomUnrollArgs<Selector...>::template drawMesh<typename T::RSMShader>(t.at(i), rsm_matrix);
}
} // drawRSM
// ----------------------------------------------------------------------------
void GL3DrawPolicy::drawSolidFirstPass(const DrawCalls& draw_calls) const
{
renderMeshes1stPass<DefaultMaterial, 2, 1>();
renderMeshes1stPass<SplattingMat, 2, 1>();
renderMeshes1stPass<UnlitMat, 3, 2, 1>();
renderMeshes1stPass<AlphaRef, 3, 2, 1>();
renderMeshes1stPass<GrassMat, 3, 2, 1>();
renderMeshes1stPass<NormalMat, 2, 1>();
renderMeshes1stPass<SphereMap, 2, 1>();
renderMeshes1stPass<DetailMat, 2, 1>();
}
// ----------------------------------------------------------------------------
void GL3DrawPolicy::drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const
{
renderMeshes2ndPass<DefaultMaterial, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<AlphaRef, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<UnlitMat, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<SplattingMat, 1 > (handles, prefilled_tex);
renderMeshes2ndPass<SphereMap, 2, 1> (handles, prefilled_tex);
renderMeshes2ndPass<DetailMat, 1 > (handles, prefilled_tex);
renderMeshes2ndPass<GrassMat, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<NormalMat, 3, 1> (handles, prefilled_tex);
}
// ----------------------------------------------------------------------------
void GL3DrawPolicy::drawGlow(const DrawCalls& draw_calls,
const std::vector<GlowData>& glows) const
{
for (u32 i = 0; i < glows.size(); i++)
glows[i].node->render();
}
// ----------------------------------------------------------------------------
void GL3DrawPolicy::drawShadows(const DrawCalls& draw_calls, unsigned cascade) const
{
renderShadow<DefaultMaterial, 1>(cascade);
renderShadow<SphereMap, 1>(cascade);
renderShadow<DetailMat, 1>(cascade);
renderShadow<SplattingMat, 1>(cascade);
renderShadow<NormalMat, 1>(cascade);
renderShadow<AlphaRef, 1>(cascade);
renderShadow<UnlitMat, 1>(cascade);
renderShadow<GrassMat, 3, 1>(cascade);
}
// ----------------------------------------------------------------------------
void GL3DrawPolicy::drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix) const
{
drawRSM<DefaultMaterial, 3, 1>(rsm_matrix);
drawRSM<AlphaRef, 3, 1>(rsm_matrix);
drawRSM<NormalMat, 3, 1>(rsm_matrix);
drawRSM<UnlitMat, 3, 1>(rsm_matrix);
drawRSM<DetailMat, 3, 1>(rsm_matrix);
drawRSM<SplattingMat, 1>(rsm_matrix);
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawSolidFirstPass(const DrawCalls& draw_calls) const
{
#if !defined(USE_GLES2)
//TODO: find a way to add TextureMarix in instanced shaders,
//and remove these four lines
renderMeshes1stPass<DefaultMaterial, 2, 1>();
renderMeshes1stPass<SplattingMat, 2, 1>();
renderMeshes1stPass<UnlitMat, 3, 2, 1>();
renderMeshes1stPass<AlphaRef, 3, 2, 1>();
draw_calls.drawIndirectSolidFirstPass();
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const
{
#if !defined(USE_GLES2)
//TODO: find a way to add TextureMatrix in instanced shaders,
//and remove these four lines
renderMeshes2ndPass<DefaultMaterial, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<AlphaRef, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<UnlitMat, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<SplattingMat, 1 > (handles, prefilled_tex);
draw_calls.drawIndirectSolidSecondPass(prefilled_tex);
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawNormals(const DrawCalls& draw_calls) const
{
#if !defined(USE_GLES2)
draw_calls.drawIndirectNormals();
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawGlow(const DrawCalls& draw_calls,
const std::vector<GlowData>& glows) const
{
#if !defined(USE_GLES2)
//to draw Glow with indirect commands, we also need GL_ARB_explicit_attrib_location extension
//TODO: add a way to render glow without explicit attrib
if(CVS->isARBExplicitAttribLocationUsable())
{
draw_calls.drawIndirectGlow();
}
#endif // !defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawShadows(const DrawCalls& draw_calls, unsigned cascade) const
{
#if !defined(USE_GLES2)
draw_calls.drawIndirectShadows(cascade);
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void IndirectDrawPolicy::drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix) const
{
#if !defined(USE_GLES2)
drawRSM<SplattingMat, 1>(rsm_matrix); //TODO: write instanced splatting RSM shader and remove this line
draw_calls.drawIndirectReflectiveShadowMaps(rsm_matrix);
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawSolidFirstPass(const DrawCalls& draw_calls) const
{
#if !defined(USE_GLES2)
//TODO: find a way to add TextureMarix in instanced shaders,
//and remove these four lines
renderMeshes1stPass<DefaultMaterial, 2, 1>();
renderMeshes1stPass<SplattingMat, 2, 1>();
renderMeshes1stPass<UnlitMat, 3, 2, 1>();
renderMeshes1stPass<AlphaRef, 3, 2, 1>();
draw_calls.multidrawSolidFirstPass();
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const
{
#if !defined(USE_GLES2)
//TODO: find a way to add TextureMarix in instanced shaders,
//and remove these four lines
renderMeshes2ndPass<DefaultMaterial, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<AlphaRef, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<UnlitMat, 3, 1> (handles, prefilled_tex);
renderMeshes2ndPass<SplattingMat, 1 > (handles, prefilled_tex);
draw_calls.multidrawSolidSecondPass(handles);
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawGlow(const DrawCalls& draw_calls,
const std::vector<GlowData>& glows) const
{
#if !defined(USE_GLES2)
draw_calls.multidrawGlow();
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawNormals(const DrawCalls& draw_calls) const
{
#if !defined(USE_GLES2)
draw_calls.multidrawNormals();
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawShadows(const DrawCalls& draw_calls, unsigned cascade) const
{
#if !defined(USE_GLES2)
draw_calls.multidrawShadows(cascade);
#endif //!defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
void MultidrawPolicy::drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix) const
{
#if !defined(USE_GLES2)
drawRSM<SplattingMat, 1>(rsm_matrix); //TODO: add instanced splatting RSM shader
draw_calls.multidrawReflectiveShadowMaps(rsm_matrix);
#endif //!defined(USE_GLES2)
}

View File

@ -0,0 +1,95 @@
// 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_DRAW_POLICIES_HPP
#define HEADER_DRAW_POLICIES_HPP
#include "graphics/draw_calls.hpp"
/** Rendering methods in this class only require
* OpenGL3.2 functions */
class GL3DrawPolicy
{
public:
void drawSolidFirstPass (const DrawCalls& draw_calls ) const;
void drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const;
void drawNormals (const DrawCalls& draw_calls ) const {}
void drawGlow (const DrawCalls& draw_calls,
const std::vector<GlowData>& glows ) const;
void drawShadows (const DrawCalls& draw_calls,
unsigned cascade ) const;
void drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix ) const;
};
/** Faster than GL3GeometryPasses.
* Require OpenGL 4.0 (or higher)
* or GL_ARB_base_instance and GL_ARB_draw_indirect extensions)*/
class IndirectDrawPolicy
{
public:
void drawSolidFirstPass (const DrawCalls& draw_calls ) const;
void drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const;
void drawNormals (const DrawCalls& draw_calls ) const;
void drawGlow (const DrawCalls& draw_calls,
const std::vector<GlowData>& glows ) const;
void drawShadows (const DrawCalls& draw_calls,
unsigned cascade ) const;
void drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix ) const;
};
/** Faster than IndirectGeometryPasses.
* Require OpenGL AZDO extensions */
class MultidrawPolicy
{
public:
void drawSolidFirstPass (const DrawCalls& draw_calls ) const;
void drawSolidSecondPass (const DrawCalls& draw_calls,
const std::vector<uint64_t>& handles,
const std::vector<GLuint>& prefilled_tex) const;
void drawNormals (const DrawCalls& draw_calls ) const;
void drawGlow (const DrawCalls& draw_calls,
const std::vector<GlowData>& glows ) const;
void drawShadows (const DrawCalls& draw_calls,
unsigned cascade ) const;
void drawReflectiveShadowMap(const DrawCalls& draw_calls,
const core::matrix4 &rsm_matrix ) const;
};
#endif //HEADER_DRAW_POLICIES_HPP

210
src/graphics/draw_tools.hpp Normal file
View File

@ -0,0 +1,210 @@
// 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_DRAW_TOOLS_HPP
#define HEADER_DRAW_TOOLS_HPP
#include "graphics/shader.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/render_info.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/texture_manager.hpp"
// ----------------------------------------------------------------------------
/** Variadic template to draw a mesh (using OpenGL 3.2 function)
* using specified shader with per mesh custom uniforms.*/
template<int...list>
struct CustomUnrollArgs;
// ----------------------------------------------------------------------------
template<int n, int...list>
struct CustomUnrollArgs<n, list...>
{
/** Draw a mesh using specified shader (require OpenGL 3.2)
* \tparam S The shader to use.
* \param t First tuple element is the mesh to draw, next elements are per mesh uniforms values
* \param args Shader other uniforms values
*/
template<typename S,
typename ...TupleTypes,
typename ...Args>
static void drawMesh(const STK::Tuple<TupleTypes...> &t,
Args... args)
{
CustomUnrollArgs<list...>::template drawMesh<S>(t, STK::tuple_get<n>(t), args...);
} // drawMesh
}; // CustomUnrollArgs
// ----------------------------------------------------------------------------
/** Partial specialisation of CustomUnrollArgs to end the recursion */
template<>
struct CustomUnrollArgs<>
{
template<typename S,
typename ...TupleTypes,
typename ...Args>
static void drawMesh(const STK::Tuple<TupleTypes...> &t,
Args... args)
{
irr_driver->IncreaseObjectCount(); //TODO: move somewhere else
GLMesh *mesh = STK::tuple_get<0>(t);
//shadow_custom_unroll_args, rsm_custom_unroll_args and custom_unroll_args
// have been merged in order to avoid duplicated code.
// don't need to call change color things for shadows and rsm
//TODO: don't call next 10 lines for shadow/rsm shaders?
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)
{
S::getInstance()->changeableColor(mesh->m_render_info->getHue(),
mesh->m_material->getColorizationFactor());
}
S::getInstance()->setUniforms(args...);
glDrawElementsBaseVertex(mesh->PrimitiveType,
(int)mesh->IndexCount,
mesh->IndexType,
(GLvoid *)mesh->vaoOffset,
(int)mesh->vaoBaseVertex);
if (need_change_hue)
{
// Reset after changing
S::getInstance()->changeableColor();
}
} // drawMesh
}; // CustomUnrollArgs
// ----------------------------------------------------------------------------
/** Variadic template to implement TexExpander*/
template<typename T, int N>
struct TexExpanderImpl
{
template<typename...TupleArgs,
typename... Args>
static void expandTex(const GLMesh &mesh,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
size_t idx = STK::tuple_get<sizeof...(TupleArgs) - N>(tex_swizzle);
TexExpanderImpl<T, N - 1>::template expandTex( mesh,
tex_swizzle,
args...,
getTextureGLuint(mesh.textures[idx]));
} // ExpandTex
}; // TexExpanderImpl
// ----------------------------------------------------------------------------
/** Partial specialisation of TexExpanderImpl to end the recursion */
template<typename T>
struct TexExpanderImpl<T, 0>
{
template<typename...TupleArgs, typename... Args>
static void expandTex(const GLMesh &mesh,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
T::getInstance()->setTextureUnits(args...);
} // ExpandTex
}; // TexExpanderImpl
// ----------------------------------------------------------------------------
template<typename T>
struct TexExpander
{
/** Bind textures.
* \param mesh The mesh which owns the textures
* \param tex_swizzle Indices of texture id in mesh texture array
* \param args Other textures ids (each of them will be bound)
*/
template<typename...TupleArgs,
typename... Args>
static void expandTex(const GLMesh &mesh,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
TexExpanderImpl<T, sizeof...(TupleArgs)>::expandTex(mesh,
tex_swizzle,
args...);
} // ExpandTex
}; // TexExpander
// ----------------------------------------------------------------------------
/** Variadic template to implement HandleExpander*/
template<typename T, int N>
struct HandleExpanderImpl
{
template<typename...TupleArgs, typename... Args>
static void expand(uint64_t *texture_handles,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
size_t idx = STK::tuple_get<sizeof...(TupleArgs)-N>(tex_swizzle);
HandleExpanderImpl<T, N - 1>::template expand(texture_handles,
tex_swizzle,
args...,
texture_handles[idx]);
} // Expand
}; // HandleExpanderImpl
// ----------------------------------------------------------------------------
/** Partial specialisation of TexExpanderImpl to end the recursion */
template<typename T>
struct HandleExpanderImpl<T, 0>
{
template<typename...TupleArgs, typename... Args>
static void expand(uint64_t *texture_handles,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
T::getInstance()->setTextureHandles(args...);
} // Expand
}; // HandleExpanderImpl
// ----------------------------------------------------------------------------
template<typename T>
struct HandleExpander
{
/** Give acces to textures in shaders without first binding them
* (require GL_ARB_bindless_texture extension) in order to reduce
* driver overhead.
* \param texture_handles Array of handles
* \param tex_swizzle Indices of handles in textures_handles array
* \param args Other textures handles
* (each of them will be accessible in shader)
*/
template<typename...TupleArgs,
typename... Args>
static void expand(uint64_t *texture_handles,
const STK::Tuple<TupleArgs...> &tex_swizzle,
Args... args)
{
HandleExpanderImpl<T, sizeof...(TupleArgs)>::expand(texture_handles,
tex_swizzle,
args...);
} // Expand
}; // HandleExpander
#endif //HEADER_DRAW_TOOLS_HPP

View File

@ -0,0 +1,114 @@
// 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.
#include "graphics/fixed_pipeline_renderer.hpp"
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/render_target.hpp"
#include "modes/world.hpp"
#include "physics/physics.hpp"
#include "utils/profiler.hpp"
void FixedPipelineRenderer::onLoadWorld()
{
}
void FixedPipelineRenderer::onUnloadWorld()
{
}
void FixedPipelineRenderer::render(float dt)
{
World *world = World::getWorld(); // Never NULL.
irr_driver->getVideoDriver()->beginScene(/*backBuffer clear*/ true,
/*zBuffer*/ true,
world->getClearColor());
irr_driver->getVideoDriver()->enableMaterial2D();
RaceGUIBase *rg = world->getRaceGUI();
if (rg) rg->update(dt);
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "drawAll() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (i+1)*60,
0x00, 0x00);
camera->activate();
rg->preRenderCallback(camera); // adjusts start referee
irr_driver->getSceneManager()->drawAll();
PROFILER_POP_CPU_MARKER();
// Note that drawAll must be called before rendering
// the bullet debug view, since otherwise the camera
// is not set up properly. This is only used for
// the bullet debug view.
if (UserConfigParams::m_artist_debug_mode)
World::getWorld()->getPhysics()->draw();
} // for i<world->getNumKarts()
// Set the viewport back to the full screen for race gui
irr_driver->getVideoDriver()->setViewPort(core::recti(0, 0,
UserConfigParams::m_width,
UserConfigParams::m_height));
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "renderPlayerView() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), 0x00, 0x00, (i+1)*60);
rg->renderPlayerView(camera, dt);
PROFILER_POP_CPU_MARKER();
} // for i<getNumKarts
// Either render the gui, or the global elements of the race gui.
GUIEngine::render(dt);
// Render the profiler
if(UserConfigParams::m_profiler_enabled)
{
PROFILER_DRAW();
}
#ifdef DEBUG
drawDebugMeshes();
#endif
irr_driver->getVideoDriver()->endScene();
}
std::unique_ptr<RenderTarget> FixedPipelineRenderer::createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name)
{
return std::unique_ptr<RenderTarget>(new GL1RenderTarget(dimension, name));
}

View File

@ -0,0 +1,40 @@
// 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_FIXED_PIPELINE_RENDERER_HPP
#define HEADER_FIXED_PIPELINE_RENDERER_HPP
#include "graphics/abstract_renderer.hpp"
#include <map>
class RenderTarget;
class GL1RenderTarget;
class FixedPipelineRenderer: public AbstractRenderer
{
public:
void onLoadWorld() ;
void onUnloadWorld();
void render(float dt);
std::unique_ptr<RenderTarget> createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name);
};
#endif //HEADER_FIXED_PIPELINE_RENDERER_HPP

View File

@ -0,0 +1,389 @@
// 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.
#include "graphics/geometry_passes.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/draw_tools.hpp"
#include "graphics/materials.hpp"
#include "graphics/post_processing.hpp"
#include "graphics/rtts.hpp"
#include "graphics/shaders.hpp"
#include "graphics/stk_scene_manager.hpp"
#include "modes/world.hpp"
#include "utils/tuple.hpp"
#include <SColor.h>
#include <S3DVertex.h>
/**
\page geometry_passes Geometry Rendering Overview
\section adding_material Adding a solid material
You need to consider twice before adding a new material : in the worst case a material requires 8 shaders :
one for each solid pass, one for shadow pass, one for RSM pass, and you need to double that for instanced version.
You need to declare a new enum in MeshMaterial and to write the corresponding dispatch code in getMeshMaterialFromType
and to create a new List* structure for non instanced.
Then you need to write the code in draw_calls.cpp that will add any mesh with the new material to their corresponding
lists : in handleSTKCommon for the standard version and in the body of prepareDrawCalls for instanced version.
\section vertex_layout Available Vertex Layout
There are 3 different layout that comes from Irrlicht loading routines :
EVT_STANDARD, EVT_2TCOORDS, EVT_TANGENT.
Below are the attributes for each vertex layout and their predefined location.
\subsection EVT_STANDARD
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec2 Texcoord;
\subsection EVT_2TCOORDS
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec2 Texcoord;
layout(location = 4) in vec2 SecondTexcoord;
\subsection EVT_TANGENT
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec2 Texcoord;
layout(location = 5) in vec3 Tangent;
layout(location = 6) in vec3 Bitangent;
*/
// ============================================================================
namespace RenderGeometry
{
struct TexUnit
{
GLuint m_id;
bool m_premul_alpha;
TexUnit(GLuint id, bool premul_alpha)
{
m_id = id;
m_premul_alpha = premul_alpha;
}
}; // struct TexUnit
// ------------------------------------------------------------------------
template <typename T>
std::vector<TexUnit> TexUnits(T curr) // required on older clang versions
{
std::vector<TexUnit> v;
v.push_back(curr);
return v;
} // TexUnits
// ------------------------------------------------------------------------
// required on older clang versions
template <typename T, typename... R>
std::vector<TexUnit> TexUnits(T curr, R... rest)
{
std::vector<TexUnit> v;
v.push_back(curr);
VTexUnits(v, rest...);
return v;
} // TexUnits
// ------------------------------------------------------------------------
// required on older clang versions
template <typename T, typename... R>
void VTexUnits(std::vector<TexUnit>& v, T curr, R... rest)
{
v.push_back(curr);
VTexUnits(v, rest...);
} // VTexUnits
// ------------------------------------------------------------------------
template <typename T>
void VTexUnits(std::vector<TexUnit>& v, T curr)
{
v.push_back(curr);
} // VTexUnits
} // namespace RenderGeometry
using namespace RenderGeometry;
#if !defined(USE_GLES2)
// ----------------------------------------------------------------------------
void AbstractGeometryPasses::prepareShadowRendering(const FrameBuffer& shadow_framebuffer) const
{
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
shadow_framebuffer.bind();
if (!CVS->isESMEnabled())
{
glDrawBuffer(GL_NONE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.5, 50.);
}
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glClearColor(1., 1., 1., 1.);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(0., 0., 0., 0.);
}
// ----------------------------------------------------------------------------
void AbstractGeometryPasses::shadowPostProcessing(const ShadowMatrices& shadow_matrices,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& scalar_framebuffer,
const PostProcessing* post_processing) const
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SHADOW_POSTPROCESS));
if (CVS->isARBTextureViewUsable())
{
const std::pair<float, float>* shadow_scales
= shadow_matrices.getShadowScales();
for (unsigned i = 0; i < 2; i++)
{
post_processing->renderGaussian6BlurLayer(
shadow_framebuffer, scalar_framebuffer, i,
2.f * shadow_scales[0].first / shadow_scales[i].first,
2.f * shadow_scales[0].second / shadow_scales[i].second);
}
}
glBindTexture(GL_TEXTURE_2D_ARRAY, shadow_framebuffer.getRTT()[0]);
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
}
#endif // !defined(USE_GLES2)
AbstractGeometryPasses::AbstractGeometryPasses()
{
m_displace_tex = irr_driver->getTexture(FileManager::TEXTURE, "displace.png");
}
// ----------------------------------------------------------------------------
void AbstractGeometryPasses::setFirstPassRenderTargets(const std::vector<GLuint>& prefilled_textures)
{
m_prefilled_textures = prefilled_textures;
#if !defined(USE_GLES2)
if (CVS->isAZDOEnabled())
{
m_textures_handles.clear();
for(size_t i=0;i<m_prefilled_textures.size();i++)
{
uint64_t handle = 0;
handle = glGetTextureSamplerHandleARB(m_prefilled_textures[i],
Shaders::ObjectPass2Shader::getInstance()->m_sampler_ids[i]);
if (!glIsTextureHandleResidentARB(handle))
glMakeTextureHandleResidentARB(handle);
m_textures_handles.push_back(handle);
}
}
#endif // !defined(USE_GLES2)
}
// ----------------------------------------------------------------------------
template<typename Shader, enum video::E_VERTEX_TYPE VertexType, int...List,
typename... TupleType>
void renderTransparenPass(const std::vector<RenderGeometry::TexUnit> &TexUnits,
std::vector<STK::Tuple<TupleType...> > *meshes)
{
Shader::getInstance()->use();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType));
for (unsigned i = 0; i < meshes->size(); i++)
{
GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i)));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh.vao);
if (mesh.VAOType != VertexType)
{
#ifdef DEBUG
Log::error("Materials", "Wrong vertex Type associed to pass 2 "
"(hint texture : %s)",
mesh.textures[0]->getName().getPath().c_str());
#endif
continue;
}
if (CVS->isAZDOEnabled())
Shader::getInstance()->setTextureHandles(mesh.TextureHandles[0]);
else
Shader::getInstance()->setTextureUnits(getTextureGLuint(mesh.textures[0]));
CustomUnrollArgs<List...>::template drawMesh<Shader>(meshes->at(i));
}
} // renderTransparenPass
// ----------------------------------------------------------------------------
void AbstractGeometryPasses::renderTransparent(const DrawCalls& draw_calls,
const FrameBuffer& tmp_framebuffer,
const FrameBuffer& displace_framebuffer,
const FrameBuffer& colors_framebuffer,
const PostProcessing* post_processing)
{
irr_driver->setPhase(TRANSPARENT_PASS);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
renderTransparenPass<Shaders::TransparentShader, video::EVT_STANDARD, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListGhostKart::getInstance());
renderTransparenPass<Shaders::TransparentShader, video::EVT_TANGENTS, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListGhostKartTangents::getInstance());
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
draw_calls.renderImmediateDrawList();
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(video::EVT_STANDARD));
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
renderTransparenPass<Shaders::TransparentFogShader, video::EVT_STANDARD,
8, 7, 6, 5, 4, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListBlendTransparentFog::getInstance());
glBlendFunc(GL_ONE, GL_ONE);
renderTransparenPass<Shaders::TransparentFogShader,
video::EVT_STANDARD, 8, 7, 6, 5, 4, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListAdditiveTransparentFog::getInstance());
}
else
{
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
renderTransparenPass<Shaders::TransparentShader,
video::EVT_STANDARD, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListBlendTransparent::getInstance());
glBlendFunc(GL_ONE, GL_ONE);
renderTransparenPass<Shaders::TransparentShader, video::EVT_STANDARD, 3, 2, 1>(
TexUnits(RenderGeometry::TexUnit(0, true)),
ListAdditiveTransparent::getInstance());
}
draw_calls.renderBillboardList();
if (!CVS->isDefferedEnabled())
return;
// Render displacement nodes
DisplaceProvider * const cb =
(DisplaceProvider *)Shaders::getCallback(ES_DISPLACE);
cb->update();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(video::EVT_2TCOORDS));
// Generate displace mask
// Use RTT_TMP4 as displace mask
if (ListDisplacement::getInstance()->size() > 0)
{
tmp_framebuffer.bind();
glClear(GL_COLOR_BUFFER_BIT);
}
for (unsigned i = 0; i < ListDisplacement::getInstance()->size(); i++)
{
const GLMesh &mesh =
*(STK::tuple_get<0>(ListDisplacement::getInstance()->at(i)));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh.vao);
const core::matrix4 &AbsoluteTransformation
= STK::tuple_get<1>(ListDisplacement::getInstance()->at(i));
if (mesh.VAOType != video::EVT_2TCOORDS)
{
#ifdef DEBUG
Log::error("Materials", "Displacement has wrong vertex type");
#endif
continue;
}
GLenum ptype = mesh.PrimitiveType;
GLenum itype = mesh.IndexType;
size_t count = mesh.IndexCount;
DisplaceMaskShader::getInstance()->use();
DisplaceMaskShader::getInstance()->setUniforms(AbsoluteTransformation);
glDrawElementsBaseVertex(ptype, (int)count, itype,
(GLvoid *)mesh.vaoOffset, (int)mesh.vaoBaseVertex);
}
if (ListDisplacement::getInstance()->size() > 0)
{
displace_framebuffer.bind();
glClear(GL_COLOR_BUFFER_BIT);
}
for (unsigned i = 0; i < ListDisplacement::getInstance()->size(); i++)
{
const GLMesh &mesh =
*(STK::tuple_get<0>(ListDisplacement::getInstance()->at(i)));
if (!CVS->isARBBaseInstanceUsable())
glBindVertexArray(mesh.vao);
const core::matrix4 &AbsoluteTransformation =
STK::tuple_get<1>(ListDisplacement::getInstance()->at(i));
if (mesh.VAOType != video::EVT_2TCOORDS)
continue;
GLenum ptype = mesh.PrimitiveType;
GLenum itype = mesh.IndexType;
size_t count = mesh.IndexCount;
// Render the effect
DisplaceShader::getInstance()->setTextureUnits(
getTextureGLuint(m_displace_tex),
colors_framebuffer.getRTT()[0],
tmp_framebuffer.getRTT()[0],
getTextureGLuint(mesh.textures[0]));
DisplaceShader::getInstance()->use();
DisplaceShader::getInstance()->setUniforms(AbsoluteTransformation,
core::vector2df(cb->getDirX(), cb->getDirY()),
core::vector2df(cb->getDir2X(), cb->getDir2Y()));
glDrawElementsBaseVertex(ptype, (int)count, itype, (GLvoid *)mesh.vaoOffset,
(int)mesh.vaoBaseVertex);
}
colors_framebuffer.bind();
glStencilFunc(GL_EQUAL, 1, 0xFF);
post_processing->renderPassThrough(displace_framebuffer.getRTT()[0],
colors_framebuffer.getWidth(),
colors_framebuffer.getHeight());
glDisable(GL_STENCIL_TEST);
} // renderTransparent

View File

@ -0,0 +1,173 @@
// 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_GEOMETRY_PASSES_HPP
#define HEADER_GEOMETRY_PASSES_HPP
#include "graphics/draw_calls.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/shadow_matrices.hpp"
#include "utils/profiler.hpp"
#include <ITexture.h>
class AbstractGeometryPasses
{
protected:
irr::video::ITexture *m_displace_tex;
std::vector<GLuint> m_prefilled_textures;
std::vector<uint64_t> m_textures_handles;
#if !defined(USE_GLES2)
void prepareShadowRendering(const FrameBuffer& shadow_framebuffer) const;
void shadowPostProcessing(const ShadowMatrices& shadow_matrices,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& scalar_framebuffer,
const PostProcessing* post_processing) const;
#endif // !defined(USE_GLES2)
public:
AbstractGeometryPasses();
virtual ~AbstractGeometryPasses(){}
void setFirstPassRenderTargets(const std::vector<GLuint>& prefilled_textures);
virtual void renderSolidFirstPass(const DrawCalls& draw_calls) const = 0;
virtual void renderSolidSecondPass( const DrawCalls& draw_calls) const = 0;
virtual void renderNormalsVisualisation(const DrawCalls& draw_calls) const = 0;
virtual void renderGlowingObjects(const DrawCalls& draw_calls,
const std::vector<GlowData>& glows,
const FrameBuffer& glow_framebuffer) const = 0;
void renderTransparent(const DrawCalls& draw_calls,
const FrameBuffer& tmp_framebuffer,
const FrameBuffer& displace_framebuffer,
const FrameBuffer& colors_framebuffer,
const PostProcessing* post_processing);
#if !defined(USE_GLES2)
virtual void renderShadows (const DrawCalls& draw_calls,
const ShadowMatrices& shadow_matrices,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& scalar_framebuffer,
const PostProcessing* post_processing ) const = 0;
virtual void renderReflectiveShadowMap(const DrawCalls& draw_calls,
const ShadowMatrices& shadow_matrices,
const FrameBuffer& reflective_shadow_map_framebuffer) const = 0 ;
#endif // !defined(USE_GLES2)
};
template<typename DrawPolicy>
class GeometryPasses: public AbstractGeometryPasses, public DrawPolicy
{
public:
// ----------------------------------------------------------------------------
/** Render the solid first pass (depth and normals)*/
void renderSolidFirstPass(const DrawCalls& draw_calls) const
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SOLID_PASS1));
irr_driver->setPhase(SOLID_NORMAL_AND_DEPTH_PASS);
draw_calls.renderImmediateDrawList();
DrawPolicy::drawSolidFirstPass(draw_calls);
} // renderSolidFirstPass
// ----------------------------------------------------------------------------
/** Render the solid second pass (apply lighting on materials) */
void renderSolidSecondPass( const DrawCalls& draw_calls) const
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SOLID_PASS2));
irr_driver->setPhase(SOLID_LIT_PASS);
draw_calls.renderImmediateDrawList();
DrawPolicy::drawSolidSecondPass(draw_calls,
m_textures_handles,
m_prefilled_textures);
}
void renderNormalsVisualisation(const DrawCalls& draw_calls) const
{
DrawPolicy::drawNormals(draw_calls);
}
void renderGlowingObjects(const DrawCalls& draw_calls,
const std::vector<GlowData>& glows,
const FrameBuffer& glow_framebuffer) const
{
irr_driver->getSceneManager()->setCurrentRendertime(scene::ESNRP_SOLID);
glow_framebuffer.bind();
glClearStencil(0);
glClearColor(0, 0, 0, 0);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, ~0);
glEnable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
DrawPolicy::drawGlow(draw_calls, glows);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glDisable(GL_STENCIL_TEST);
}
#if !defined(USE_GLES2)
void renderShadows(const DrawCalls& draw_calls,
const ShadowMatrices& shadow_matrices,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& scalar_framebuffer,
const PostProcessing* post_processing) const
{
prepareShadowRendering(shadow_framebuffer);
for (unsigned cascade = 0; cascade < 4; cascade++)
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SHADOWS_CASCADE0 + cascade));
DrawPolicy::drawShadows(draw_calls, cascade);
}
glDisable(GL_POLYGON_OFFSET_FILL);
if (CVS->isESMEnabled())
shadowPostProcessing(shadow_matrices, shadow_framebuffer,
scalar_framebuffer, post_processing);
}
void renderReflectiveShadowMap(const DrawCalls& draw_calls,
const ShadowMatrices& shadow_matrices,
const FrameBuffer& reflective_shadow_map_framebuffer) const
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_RSM));
reflective_shadow_map_framebuffer.bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawPolicy::drawReflectiveShadowMap(draw_calls, shadow_matrices.getRSMMatrix());
}
#endif // !defined(USE_GLES2)
};
#endif //HEADER_GEOMETRY_PASSES_HPP

View File

@ -17,10 +17,10 @@
#include "graphics/glwrap.hpp"
#include "config/hardware_stats.hpp"
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shaders.hpp"
#include "graphics/stk_mesh.hpp"
#include "utils/profiler.hpp"
@ -289,17 +289,18 @@ void FrameBuffer::bind() const
glDrawBuffers((int)RenderTargets.size(), bufs);
}
void FrameBuffer::bindLayer(unsigned i)
void FrameBuffer::bindLayer(unsigned i) const
{
glBindFramebuffer(GL_FRAMEBUFFER, fbolayer);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, RenderTargets[0], 0, i);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, DepthTexture, 0, i);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE_EXT);
glViewport(0, 0, (int)width, (int)height);
GLenum bufs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers((int)RenderTargets.size(), bufs);
}
void FrameBuffer::Blit(const FrameBuffer &Src, FrameBuffer &Dst, GLbitfield mask, GLenum filter)
void FrameBuffer::Blit(const FrameBuffer &Src, const FrameBuffer &Dst, GLbitfield mask, GLenum filter)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, Src.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, Dst.fbo);

View File

@ -20,13 +20,12 @@
#include "graphics/gl_headers.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/vao_manager.hpp"
#include "utils/log.hpp"
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
#include <irrlicht.h>
#include <vector>
namespace HardwareStats
@ -35,7 +34,6 @@ namespace HardwareStats
}
void initGL();
video::ITexture* getUnicolorTexture(const video::SColor &c);
class GPUTimer;
@ -73,12 +71,12 @@ public:
FrameBuffer(const std::vector <GLuint> &RTTs, GLuint DS, size_t w, size_t h, bool layered = false);
~FrameBuffer();
void bind() const;
void bindLayer(unsigned);
void bindLayer(unsigned) const;
const std::vector<GLuint> &getRTT() const { return RenderTargets; }
GLuint &getDepthTexture() { assert(DepthTexture); return DepthTexture; }
GLuint getDepthTexture() const { assert(DepthTexture); return DepthTexture; }
size_t getWidth() const { return width; }
size_t getHeight() const { return height; }
static void Blit(const FrameBuffer &Src, FrameBuffer &Dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_NEAREST);
static void Blit(const FrameBuffer &Src, const FrameBuffer &Dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_NEAREST);
void BlitToDefault(size_t, size_t, size_t, size_t);
LEAK_CHECK();

View File

@ -18,11 +18,11 @@
#include "graphics/gpu_particles.hpp"
#include "config/user_config.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/particle_emitter.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/texture_shader.hpp"
#include "guiengine/engine.hpp"
#include "io/file_manager.hpp"
@ -496,6 +496,7 @@ void ParticleSystemProxy::simulate()
glDrawArrays(GL_POINTS, 0, m_count);
glEndTransformFeedback();
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_RASTERIZER_DISCARD);
#ifdef DEBUG_PARTICLES

View File

@ -22,27 +22,24 @@
#include "graphics/callbacks.hpp"
#include "graphics/camera.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/fixed_pipeline_renderer.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/light.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/particle_kind_manager.hpp"
#include "graphics/per_camera_node.hpp"
#include "graphics/post_processing.hpp"
#include "graphics/referee.hpp"
#include "graphics/render_info.hpp"
#include "graphics/render_target.hpp"
#include "graphics/shader_based_renderer.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/stk_scene_manager.hpp"
#include "graphics/sun.hpp"
#include "graphics/rtts.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/water.hpp"
#include "graphics/wind.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/message_queue.hpp"
#include "guiengine/modaldialog.hpp"
@ -69,7 +66,6 @@
#include "utils/vs.hpp"
#include <irrlicht.h>
#include "../lib/irrlicht/source/Irrlicht/CSkinnedMesh.h"
/* Build-time check that the Irrlicht we're building against works for us.
* Should help prevent distros building against an incompatible library.
@ -115,7 +111,6 @@ const bool ALLOW_1280_X_720 = true;
*/
IrrDriver::IrrDriver()
{
m_shadow_matrices = NULL;
m_resolution_changing = RES_CHANGE_NONE;
m_phase = SOLID_NORMAL_AND_DEPTH_PASS;
m_device = createDevice(video::EDT_NULL,
@ -126,18 +121,13 @@ IrrDriver::IrrDriver()
/*event receiver*/ NULL,
file_manager->getFileSystem());
m_request_screenshot = false;
m_rtts = NULL;
m_post_processing = NULL;
m_renderer = NULL;
m_wind = new Wind();
m_skybox = NULL;
m_spherical_harmonics = NULL;
m_mipviz = m_wireframe = m_normals = m_ssaoviz = false;
m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = false;
m_boundingboxesviz = false;
m_last_light_bucket_distance = 0;
memset(m_object_count, 0, sizeof(m_object_count));
memset(m_poly_count, 0, sizeof(m_poly_count));
} // IrrDriver
// ----------------------------------------------------------------------------
@ -145,19 +135,6 @@ IrrDriver::IrrDriver()
*/
IrrDriver::~IrrDriver()
{
// Note that we can not simply delete m_post_processing here:
// m_post_processing uses a material that has a reference to
// m_post_processing (for a callback). So when the material is
// removed it will try to drop the ref count of its callback object,
// which is m_post_processing, and which was already deleted. So
// instead we just decrease the ref count here. When the material
// is deleted, it will trigger the actual deletion of
// PostProcessing when decreasing the refcount of its callback object.
if(m_post_processing)
{
// check if we createad the OpenGL device by calling initDevice()
m_post_processing->drop();
}
assert(m_device != NULL);
cleanUnicolorTextures();
@ -165,14 +142,12 @@ IrrDriver::~IrrDriver()
m_device = NULL;
m_modes.clear();
delete m_shadow_matrices;
m_shadow_matrices = NULL;
if (CVS->isGLSL())
{
Shaders::destroy();
}
delete m_wind;
delete m_spherical_harmonics;
delete m_renderer;
} // ~IrrDriver
// ----------------------------------------------------------------------------
@ -180,7 +155,7 @@ IrrDriver::~IrrDriver()
*/
void IrrDriver::reset()
{
if (CVS->isGLSL()) m_post_processing->reset();
m_renderer->resetPostProcessing();
} // reset
void IrrDriver::setPhase(STKRenderingPass p)
@ -195,12 +170,7 @@ STKRenderingPass IrrDriver::getPhase() const
void IrrDriver::IncreaseObjectCount()
{
m_object_count[m_phase]++;
}
void IrrDriver::IncreasePolyCount(unsigned Polys)
{
m_poly_count[m_phase] += Polys;
m_renderer->incObjectCount(m_phase);
}
core::array<video::IRenderTarget> &IrrDriver::getMainSetup()
@ -213,15 +183,13 @@ GPUTimer &IrrDriver::getGPUTimer(unsigned i)
return m_perf_query[i];
}
// ----------------------------------------------------------------------------
void IrrDriver::computeMatrixesAndCameras(scene::ICameraSceneNode *const camnode,
size_t width, size_t height)
std::unique_ptr<RenderTarget> IrrDriver::createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name)
{
float w = width * UserConfigParams::m_scale_rtts_factor;
float h = height * UserConfigParams::m_scale_rtts_factor;
m_current_screen_size = core::vector2df(w, h);
m_shadow_matrices->computeMatrixesAndCameras(camnode, int(w), int(h));
} // computeMatrixesAndCameras
return m_renderer->createRenderTarget(dimension, name);
}
// ----------------------------------------------------------------------------
@ -580,11 +548,13 @@ void IrrDriver::initDevice()
m_scene_manager = m_device->getSceneManager();
m_gui_env = m_device->getGUIEnvironment();
m_video_driver = m_device->getVideoDriver();
m_sync = 0;
m_actual_screen_size = m_video_driver->getCurrentRenderTargetSize();
m_spherical_harmonics = new SphericalHarmonics(m_scene_manager->getAmbientLight().toSColor());
if(CVS->isGLSL())
m_renderer = new ShaderBasedRenderer();
else
m_renderer = new FixedPipelineRenderer();
if (UserConfigParams::m_shadows_resolution != 0 &&
(UserConfigParams::m_shadows_resolution < 512 ||
@ -683,14 +653,10 @@ void IrrDriver::initDevice()
material2D.AntiAliasing=video::EAAM_FULL_BASIC;
//m_video_driver->enableMaterial2D();
// Initialize post-processing if supported
m_post_processing = new PostProcessing(m_video_driver);
// set cursor visible by default (what's the default is not too clearly documented,
// so let's decide ourselves...)
m_device->getCursorControl()->setVisible(true);
m_pointer_shown = true;
m_shadow_matrices = new ShadowMatrices();
} // initDevice
// ----------------------------------------------------------------------------
@ -896,28 +862,14 @@ void IrrDriver::applyResolutionSettings()
// (we're sure to update main.cpp at some point and forget this one...)
ShaderBase::updateShaders();
VAOManager::getInstance()->kill();
SolidPassCmd::getInstance()->kill();
ShadowPassCmd::getInstance()->kill();
RSMPassCmd::getInstance()->kill();
GlowPassCmd::getInstance()->kill();
resetTextureTable();
if (m_post_processing)
{
// check if we createad the OpenGL device by calling initDevice()
m_post_processing->drop();
}
cleanUnicolorTextures();
delete m_shadow_matrices;
// initDevice will drop the current device.
if (CVS->isGLSL())
{
Shaders::destroy();
}
delete m_spherical_harmonics;
// initDevice will drop the current device.
delete m_renderer;
initDevice();
font_manager = new FontManager();
@ -1475,15 +1427,7 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector<video::ITexture*> &tex
{
assert(texture.size() == 6);
if (CVS->isGLSL())
{
m_skybox = new Skybox(texture);
}
if(spherical_harmonics_textures.size() == 6)
{
m_spherical_harmonics->setTextures(spherical_harmonics_textures);
}
m_renderer->addSkyBox(texture, spherical_harmonics_textures);
return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1],
texture[2], texture[3],
@ -1492,8 +1436,7 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector<video::ITexture*> &tex
void IrrDriver::suppressSkyBox()
{
delete m_skybox;
m_skybox = NULL;
m_renderer->removeSkyBox();;
}
// ----------------------------------------------------------------------------
@ -1841,39 +1784,27 @@ video::ITexture* IrrDriver::applyMask(video::ITexture* texture,
mask->drop();
return t;
} // applyMask
// ----------------------------------------------------------------------------
void IrrDriver::setRTT(RTT* rtt)
{
m_shadow_matrices->resetShadowCamNodes();
m_rtts = rtt;
}
// ----------------------------------------------------------------------------
void IrrDriver::onLoadWorld()
{
if (CVS->isGLSL())
{
const core::recti &viewport = Camera::getCamera(0)->getViewport();
size_t width = viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X;
size_t height = viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y;
m_rtts = new RTT(width, height);
}
m_renderer->onLoadWorld();
}
// ----------------------------------------------------------------------------
void IrrDriver::onUnloadWorld()
{
delete m_rtts;
m_rtts = NULL;
suppressSkyBox();
m_renderer->onUnloadWorld();
}
// ----------------------------------------------------------------------------
/** Sets the ambient light.
* \param light The colour of the light to set.
* \param force_SH_computation If false, do not recompute spherical harmonics
* coefficient when spherical harmonics textures have been defined
*/
void IrrDriver::setAmbientLight(const video::SColorf &light)
void IrrDriver::setAmbientLight(const video::SColorf &light, bool force_SH_computation)
{
m_scene_manager->setAmbientLight(light);
m_spherical_harmonics->setAmbientLight(light.toSColor());
m_renderer->setAmbientLight(light, force_SH_computation);
} // setAmbientLight
video::SColorf IrrDriver::getAmbientLight() const
@ -1941,211 +1872,23 @@ void IrrDriver::displayFPS()
if (low > kilotris) low = kilotris;
if (high < kilotris) high = kilotris;
core::stringw fpsString;
core::stringw fps_string;
if (UserConfigParams::m_artist_debug_mode)
if ((UserConfigParams::m_artist_debug_mode)&&(CVS->isGLSL()))
{
fpsString = _("FPS: %d/%d/%d - PolyCount: %d Solid, "
fps_string = _("FPS: %d/%d/%d - PolyCount: %d Solid, "
"%d Shadows - LightDist : %d",
min, fps, max, m_poly_count[SOLID_NORMAL_AND_DEPTH_PASS],
m_poly_count[SHADOW_PASS], m_last_light_bucket_distance);
m_poly_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0;
m_poly_count[SHADOW_PASS] = 0;
m_object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0;
m_object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0;
m_object_count[TRANSPARENT_PASS] = 0;
min, fps, max, m_renderer->getPolyCount(SOLID_NORMAL_AND_DEPTH_PASS),
m_renderer->getPolyCount(SHADOW_PASS), m_last_light_bucket_distance);
}
else
fpsString = _("FPS: %d/%d/%d - %d KTris", min, fps, max, (int)roundf(kilotris));
fps_string = _("FPS: %d/%d/%d - %d KTris", min, fps, max, (int)roundf(kilotris));
static video::SColor fpsColor = video::SColor(255, 0, 0, 0);
font->draw( fpsString.c_str(), position, fpsColor, false );
font->draw( fps_string.c_str(), position, fpsColor, false );
} // updateFPS
// ----------------------------------------------------------------------------
#ifdef DEBUG
void IrrDriver::drawDebugMeshes()
{
for (unsigned int n=0; n<m_debug_meshes.size(); n++)
{
scene::IMesh* mesh = m_debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
const core::array< scene::ISkinnedMesh::SJoint * >& joints =
smesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
drawJoint( false, true, joints[j], smesh, j);
}
}
video::SColor color(255,255,255,255);
video::SMaterial material;
material.Thickness = 2;
material.AmbientColor = color;
material.DiffuseColor = color;
material.EmissiveColor= color;
material.BackfaceCulling = false;
material.setFlag(video::EMF_LIGHTING, false);
getVideoDriver()->setMaterial(material);
getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix);
for (unsigned int n=0; n<m_debug_meshes.size(); n++)
{
scene::IMesh* mesh = m_debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
const core::array< scene::ISkinnedMesh::SJoint * >& joints =
smesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
scene::IMesh* mesh = m_debug_meshes[n]->getMesh();
scene::ISkinnedMesh* smesh = static_cast<scene::ISkinnedMesh*>(mesh);
drawJoint(true, false, joints[j], smesh, j);
}
}
} // drawDebugMeshes
// ----------------------------------------------------------------------------
/** Draws a joing for debugging skeletons.
* \param drawline If true draw a line to the parent.
* \param drawname If true draw the name of the joint.
* \param joint The joint to draw.
* \param mesh The mesh whose skeleton is drawn (only used to get
* all joints to find the parent).
* \param id Index, which (%4) determines the color to use.
*/
void IrrDriver::drawJoint(bool drawline, bool drawname,
scene::ISkinnedMesh::SJoint* joint,
scene::ISkinnedMesh* mesh, int id)
{
scene::ISkinnedMesh::SJoint* parent = NULL;
const core::array< scene::ISkinnedMesh::SJoint * >& joints
= mesh->getAllJoints();
for (unsigned int j=0; j<joints.size(); j++)
{
if (joints[j]->Children.linear_search(joint) != -1)
{
parent = joints[j];
break;
}
}
core::vector3df jointpos = joint->GlobalMatrix.getTranslation();
video::SColor color(255, 255,255,255);
if (parent == NULL) color = video::SColor(255,0,255,0);
switch (id % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
if (parent)
{
core::vector3df parentpos = parent->GlobalMatrix.getTranslation();
jointpos = joint->GlobalMatrix.getTranslation();
if (drawline)
{
irr_driver->getVideoDriver()->draw3DLine(jointpos,
parentpos,
color);
}
}
else
{
/*
if (drawline)
{
irr_driver->getVideoDriver()->draw3DLine(jointpos,
core::vector3df(0,0,0),
color);
}
*/
}
if (joint->Children.size() == 0)
{
switch ((id + 1) % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
// This code doesn't quite work. 0.25 is used so that the bone is not
// way too long (not sure why I need to manually size it down)
// and the rotation of the bone is often rather off
core::vector3df v(0.0f, 0.25f, 0.0f);
//joint->GlobalMatrix.rotateVect(v);
joint->LocalMatrix.rotateVect(v);
v *= joint->LocalMatrix.getScale();
irr_driver->getVideoDriver()->draw3DLine(jointpos,
jointpos + v,
color);
}
switch ((id + 1) % 4)
{
case 0:
color = video::SColor(255,255,0,255);
break;
case 1:
color = video::SColor(255,255,0,0);
break;
case 2:
color = video::SColor(255,0,0,255);
break;
case 3:
color = video::SColor(255,0,255,255);
break;
}
if (drawname)
{
irr_driver->getVideoDriver()->setTransform(video::ETS_WORLD,
core::IdentityMatrix);
core::vector2di textpos =
irr_driver->getSceneManager()->getSceneCollisionManager()
->getScreenCoordinatesFrom3DPosition(jointpos);
GUIEngine::getSmallFont()->draw( stringw(joint->Name.c_str()),
core::rect<s32>(textpos,
core::dimension2d<s32>(500,50)),
color, false, false );
}
}
#endif
// ----------------------------------------------------------------------------
/** Requess a screenshot from irrlicht, and save it in a file.
*/
@ -2242,10 +1985,7 @@ void IrrDriver::update(float dt)
if (world)
{
if (CVS->isGLSL())
renderGLSL(dt);
else
renderFixed(dt);
m_renderer->render(dt);
GUIEngine::Screen* current_screen = GUIEngine::getCurrentScreen();
if (current_screen != NULL && current_screen->needs3D())
@ -2328,227 +2068,12 @@ bool IrrDriver::OnEvent(const irr::SEvent &event)
} // OnEvent
// ----------------------------------------------------------------------------
bool IrrDriver::supportsSplatting()
{
return CVS->isGLSL();
}
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
#pragma mark RTT
#endif
// ----------------------------------------------------------------------------
/**
* THIS IS THE OLD OPENGL 1 RTT PROVIDER, USE THE SHADER-BASED
* RTT FOR NEW DEVELOPMENT
* Begins a rendering to a texture.
* \param dimension The size of the texture.
* \param name Name of the texture.
* \param persistent_texture Whether the created RTT texture should persist in
* memory after the RTTProvider is deleted
*/
IrrDriver::RTTProvider::RTTProvider(const core::dimension2du &dimension,
const std::string &name, bool persistent_texture)
{
m_persistent_texture = persistent_texture;
m_video_driver = irr_driver->getVideoDriver();
m_render_target_texture =
m_video_driver->addRenderTargetTexture(dimension,
name.c_str(),
video::ECF_A8R8G8B8);
if (m_render_target_texture != NULL)
{
m_video_driver->setRenderTarget(m_render_target_texture);
}
m_rtt_main_node = NULL;
m_camera = NULL;
m_light = NULL;
} // RTTProvider
// ----------------------------------------------------------------------------
IrrDriver::RTTProvider::~RTTProvider()
{
tearDownRTTScene();
if (!m_persistent_texture)
irr_driver->removeTexture(m_render_target_texture);
} // ~RTTProvider
// ----------------------------------------------------------------------------
/** Sets up a given vector of meshes for render-to-texture. Ideal to embed a 3D
* object inside the GUI. If there are multiple meshes, the first mesh is
* considered to be the root, and all following meshes will have their
* locations relative to the location of the first mesh.
*/
void IrrDriver::RTTProvider::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
AlignedArray<Vec3>& mesh_location,
AlignedArray<Vec3>& mesh_scale,
const std::vector<int>& model_frames)
{
if (model_frames[0] == -1)
{
scene::ISceneNode* node =
irr_driver->getSceneManager()->addMeshSceneNode(mesh.get(0), NULL);
node->setPosition( mesh_location[0].toIrrVector() );
node->setScale( mesh_scale[0].toIrrVector() );
node->setMaterialFlag(video::EMF_FOG_ENABLE, false);
m_rtt_main_node = node;
}
else
{
scene::IAnimatedMeshSceneNode* node =
irr_driver->getSceneManager()->addAnimatedMeshSceneNode(
(scene::IAnimatedMesh*)mesh.get(0), NULL );
node->setPosition( mesh_location[0].toIrrVector() );
node->setFrameLoop(model_frames[0], model_frames[0]);
node->setAnimationSpeed(0);
node->setScale( mesh_scale[0].toIrrVector() );
node->setMaterialFlag(video::EMF_FOG_ENABLE, false);
m_rtt_main_node = node;
}
assert(m_rtt_main_node != NULL);
assert(mesh.size() == mesh_location.size());
assert(mesh.size() == model_frames.size());
const int mesh_amount = mesh.size();
for (int n=1; n<mesh_amount; n++)
{
if (model_frames[n] == -1)
{
scene::ISceneNode* node =
irr_driver->getSceneManager()->addMeshSceneNode(mesh.get(n),
m_rtt_main_node);
node->setPosition( mesh_location[n].toIrrVector() );
node->updateAbsolutePosition();
node->setScale( mesh_scale[n].toIrrVector() );
}
else
{
scene::IAnimatedMeshSceneNode* node =
irr_driver->getSceneManager()
->addAnimatedMeshSceneNode((scene::IAnimatedMesh*)mesh.get(n),
m_rtt_main_node );
node->setPosition( mesh_location[n].toIrrVector() );
node->setFrameLoop(model_frames[n], model_frames[n]);
node->setAnimationSpeed(0);
node->updateAbsolutePosition();
node->setScale( mesh_scale[n].toIrrVector() );
//Log::info("RTTProvider::setupRTTScene", "Set frame %d", model_frames[n]);
}
}
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 35, 35, 35) );
const core::vector3df &spot_pos = core::vector3df(0, 30, 40);
m_light = irr_driver->getSceneManager()
->addLightSceneNode(NULL, spot_pos, video::SColorf(1.0f,1.0f,1.0f),
1600 /* radius */);
m_light->setLightType(video::ELT_SPOT);
m_light->setRotation((core::vector3df(0, 10, 0) - spot_pos).getHorizontalAngle());
m_light->updateAbsolutePosition();
m_rtt_main_node->setMaterialFlag(video::EMF_GOURAUD_SHADING , true);
m_rtt_main_node->setMaterialFlag(video::EMF_LIGHTING, true);
const int materials = m_rtt_main_node->getMaterialCount();
for (int n=0; n<materials; n++)
{
m_rtt_main_node->getMaterial(n).setFlag(video::EMF_LIGHTING, true);
// set size of specular highlights
m_rtt_main_node->getMaterial(n).Shininess = 100.0f;
m_rtt_main_node->getMaterial(n).SpecularColor.set(255,50,50,50);
m_rtt_main_node->getMaterial(n).DiffuseColor.set(255,150,150,150);
m_rtt_main_node->getMaterial(n).setFlag(video::EMF_GOURAUD_SHADING ,
true);
}
m_camera = irr_driver->getSceneManager()->addCameraSceneNode();
m_camera->setPosition( core::vector3df(0.0, 20.0f, 70.0f) );
if (CVS->isGLSL())
m_camera->setUpVector( core::vector3df(0.0, 1.0, 0.0) );
else
m_camera->setUpVector( core::vector3df(0.0, 1.0, 0.0) );
m_camera->setTarget( core::vector3df(0, 10, 0.0f) );
m_camera->setFOV( DEGREE_TO_RAD*50.0f );
m_camera->updateAbsolutePosition();
// Detach the note from the scene so we can render it independently
m_rtt_main_node->setVisible(false);
m_light->setVisible(false);
} // setupRTTScene
// ----------------------------------------------------------------------------
void IrrDriver::RTTProvider::tearDownRTTScene()
{
//if (m_rtt_main_node != NULL) m_rtt_main_node->drop();
if (m_rtt_main_node != NULL) m_rtt_main_node->remove();
if (m_light != NULL) m_light->remove();
if (m_camera != NULL) m_camera->remove();
m_rtt_main_node = NULL;
m_camera = NULL;
m_light = NULL;
} // tearDownRTTScene
// ----------------------------------------------------------------------------
/**
* Performs the actual render-to-texture
* \param target The texture to render the meshes to.
* \param angle (Optional) heading for all meshes.
* \return the texture that was rendered to, or NULL if RTT does not work on
* this computer
*/
video::ITexture* IrrDriver::RTTProvider::renderToTexture(float angle,
bool is_2d_render)
{
// m_render_target_texture will be NULL if RTT doesn't work on this computer
if (m_render_target_texture == NULL) return NULL;
// Rendering a 2d only model (using direct opengl rendering)
// does not work if setRenderTarget is called here again.
// And rendering 3d only works if it is called here :(
if(!is_2d_render)
m_video_driver->setRenderTarget(m_render_target_texture);
if (angle != -1 && m_rtt_main_node != NULL)
m_rtt_main_node->setRotation( core::vector3df(0, angle, 0) );
video::SOverrideMaterial &overridemat = m_video_driver->getOverrideMaterial();
overridemat.EnablePasses = scene::ESNRP_SOLID;
overridemat.EnableFlags = video::EMF_MATERIAL_TYPE;
overridemat.Material.MaterialType = video::EMT_SOLID;
if (m_rtt_main_node == NULL)
{
irr_driver->getSceneManager()->drawAll();
}
else
{
m_rtt_main_node->setVisible(true);
m_light->setVisible(true);
irr_driver->getSceneManager()->drawAll();
m_rtt_main_node->setVisible(false);
m_light->setVisible(false);
}
overridemat.EnablePasses = 0;
m_video_driver->setRenderTarget(0, false, false);
return m_render_target_texture;
}
// ----------------------------------------------------------------------------
void IrrDriver::applyObjectPassShader(scene::ISceneNode * const node, bool rimlit)
{
if (!CVS->isGLSL())
@ -2653,7 +2178,7 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos,
{
//m_sun_interposer->setPosition(pos);
//m_sun_interposer->updateAbsolutePosition();
m_shadow_matrices->addLight(pos);
m_renderer->addSunLight(pos);
((WaterShaderProvider *) Shaders::getCallback(ES_WATER) )
->setSunPosition(pos);
@ -2682,23 +2207,15 @@ void IrrDriver::clearLights()
} // clearLights
// ----------------------------------------------------------------------------
GLuint IrrDriver::getRenderTargetTexture(TypeRTT which)
{
return m_rtts->getRenderTarget(which);
return m_renderer->getRenderTargetTexture(which);
} // getRenderTargetTexture
// ----------------------------------------------------------------------------
FrameBuffer& IrrDriver::getFBO(TypeFBO which)
{
return m_rtts->getFBO(which);
} // getFBO
// ----------------------------------------------------------------------------
GLuint IrrDriver::getDepthStencilTexture()
{
return m_rtts->getDepthStencilTexture();
return m_renderer->getDepthStencilTexture();
} // getDepthStencilTexture

View File

@ -27,24 +27,24 @@
* management, etc...)
*/
#include <string>
#include <vector>
#include <IVideoDriver.h>
#include <vector2d.h>
#include <dimension2d.h>
#include <SColor.h>
#include "IrrlichtDevice.h"
#include "ISkinnedMesh.h"
#include "graphics/abstract_renderer.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/skybox.hpp"
#include "graphics/sphericalHarmonics.hpp"
#include "graphics/wind.hpp"
#include "io/file_manager.hpp"
#include "utils/aligned_array.hpp"
#include "utils/no_copy.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/vec3.hpp"
#include <memory>
#include <string>
#include <vector>
namespace irr
{
@ -55,132 +55,17 @@ namespace irr
}
using namespace irr;
class RTT;
class RenderInfo;
class FrameBuffer;
class ShadowImportanceProvider;
enum TypeRTT : unsigned int;
class AbstractKart;
class AbstractRenderer;
class Camera;
class PerCameraNode;
class PostProcessing;
class FrameBuffer;
class LightNode;
class ShadowImportance;
class ShadowMatrices;
class PerCameraNode;
class RenderInfo;
class RenderTarget;
enum STKRenderingPass
{
SOLID_NORMAL_AND_DEPTH_PASS,
SOLID_LIT_PASS,
TRANSPARENT_PASS,
GLOW_PASS,
SHADOW_PASS,
PASS_COUNT,
};
enum TypeFBO
{
FBO_SSAO,
FBO_NORMAL_AND_DEPTHS,
FBO_COMBINED_DIFFUSE_SPECULAR,
FBO_COLORS,
FBO_DIFFUSE,
FBO_SPECULAR,
FBO_MLAA_COLORS,
FBO_MLAA_BLEND,
FBO_MLAA_TMP,
FBO_TMP1_WITH_DS,
FBO_TMP2_WITH_DS,
FBO_TMP4,
FBO_LINEAR_DEPTH,
FBO_HALF1,
FBO_HALF1_R,
FBO_HALF2,
FBO_HALF2_R,
FBO_QUARTER1,
FBO_QUARTER2,
FBO_EIGHTH1,
FBO_EIGHTH2,
FBO_DISPLACE,
FBO_BLOOM_1024,
#if !defined(USE_GLES2)
FBO_SCALAR_1024,
#endif
FBO_BLOOM_512,
FBO_TMP_512,
FBO_LENS_512,
FBO_BLOOM_256,
FBO_TMP_256,
FBO_LENS_256,
FBO_BLOOM_128,
FBO_TMP_128,
FBO_LENS_128,
FBO_COUNT
};
enum TypeRTT
{
RTT_TMP1 = 0,
RTT_TMP2,
RTT_TMP3,
RTT_TMP4,
RTT_LINEAR_DEPTH,
RTT_NORMAL_AND_DEPTH,
RTT_COLOR,
RTT_DIFFUSE,
RTT_SPECULAR,
RTT_HALF1,
RTT_HALF2,
RTT_HALF1_R,
RTT_HALF2_R,
RTT_QUARTER1,
RTT_QUARTER2,
// RTT_QUARTER3,
// RTT_QUARTER4,
RTT_EIGHTH1,
RTT_EIGHTH2,
// RTT_SIXTEENTH1,
// RTT_SIXTEENTH2,
RTT_SSAO,
// RTT_COLLAPSE,
// RTT_COLLAPSEH,
// RTT_COLLAPSEV,
// RTT_COLLAPSEH2,
// RTT_COLLAPSEV2,
// RTT_WARPH,
// RTT_WARPV,
// RTT_HALF_SOFT,
RTT_DISPLACE,
RTT_MLAA_COLORS,
RTT_MLAA_BLEND,
RTT_MLAA_TMP,
RTT_BLOOM_1024,
#if !defined(USE_GLES2)
RTT_SCALAR_1024,
#endif
RTT_BLOOM_512,
RTT_TMP_512,
RTT_LENS_512,
RTT_BLOOM_256,
RTT_TMP_256,
RTT_LENS_256,
RTT_BLOOM_128,
RTT_TMP_128,
RTT_LENS_128,
RTT_COUNT
};
struct SHCoefficients;
/**
* \brief class that creates the irrLicht device and offers higher-level
@ -190,7 +75,6 @@ enum TypeRTT
class IrrDriver : public IEventReceiver, public NoCopy
{
private:
GLsync m_sync;
/** The irrlicht device. */
IrrlichtDevice *m_device;
/** Irrlicht scene manager. */
@ -201,14 +85,12 @@ private:
video::IVideoDriver *m_video_driver;
/** Irrlicht race font. */
gui::IGUIFont *m_race_font;
/** Post-processing. */
PostProcessing *m_post_processing;
/** Renderer. */
AbstractRenderer *m_renderer;
/** Wind. */
Wind *m_wind;
/** RTTs. */
RTT *m_rtts;
core::vector2df m_current_screen_size;
core::dimension2du m_actual_screen_size;
/** Additional details to be shown in case that a texture is not found.
@ -221,8 +103,6 @@ private:
/** Matrixes used in several places stored here to avoid recomputation. */
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix;
Skybox *m_skybox;
SphericalHarmonics *m_spherical_harmonics;
private:
@ -237,7 +117,6 @@ private:
enum {RES_CHANGE_NONE, RES_CHANGE_YES,
RES_CHANGE_CANCEL} m_resolution_changing;
ShadowMatrices *m_shadow_matrices;
public:
/** A simple class to store video resolutions. */
@ -259,10 +138,7 @@ public:
video::SColorf getAmbientLight() const;
struct GlowData {
scene::ISceneNode * node;
float r, g, b;
};
private:
std::vector<VideoMode> m_modes;
@ -289,16 +165,13 @@ private:
bool m_lightviz;
bool m_distortviz;
bool m_boundingboxesviz;
/** Performance stats */
unsigned m_last_light_bucket_distance;
unsigned m_object_count[PASS_COUNT];
unsigned m_poly_count[PASS_COUNT];
u32 m_renderpass;
class STKMeshSceneNode *m_sun_interposer;
core::vector3df m_sun_direction;
video::SColorf m_suncolor;
std::vector<GlowData> m_glowing;
std::vector<LightNode *> m_lights;
@ -315,30 +188,10 @@ private:
#ifdef DEBUG
/** Used to visualise skeletons. */
std::vector<irr::scene::IAnimatedMeshSceneNode*> m_debug_meshes;
void drawDebugMeshes();
void drawJoint(bool drawline, bool drawname,
irr::scene::ISkinnedMesh::SJoint* joint,
irr::scene::ISkinnedMesh* mesh, int id);
#endif
void renderFixed(float dt);
void renderGLSL(float dt);
void renderSolidFirstPass();
void renderSolidSecondPass();
void renderNormalsVisualisation();
void renderTransparent();
void renderParticles();
void renderShadows();
void renderRSM();
void renderGlow(std::vector<GlowData>& glows);
void renderSSAO();
void renderLights(unsigned pointlightCount, bool hasShadow);
void renderAmbientScatter();
void renderLightsScatter(unsigned pointlightCount);
void renderShadowsDebug();
public:
void doScreenShot();
void PrepareDrawCalls(scene::ICameraSceneNode *camnode);
public:
IrrDriver();
~IrrDriver();
@ -348,11 +201,9 @@ public:
void getOpenGLData(std::string *vendor, std::string *renderer,
std::string *version);
void renderSkybox(const scene::ICameraSceneNode *camera);
void setPhase(STKRenderingPass);
STKRenderingPass getPhase() const;
void IncreaseObjectCount();
void IncreasePolyCount(unsigned);
core::array<video::IRenderTarget> &getMainSetup();
void updateConfigIfRelevant();
void setAllMaterialFlags(scene::IMesh *mesh) const;
@ -362,7 +213,8 @@ public:
const std::string& mask_path);
void displayFPS();
bool OnEvent(const irr::SEvent &event);
void setAmbientLight(const video::SColorf &light);
void setAmbientLight(const video::SColorf &light,
bool force_SH_computation = true);
std::string generateSmallerTextures(const std::string& dir);
std::string getSmallerTexture(const std::string& texture);
video::ITexture *getTexture(FileManager::AssetType type,
@ -445,14 +297,8 @@ public:
void unsetTextureErrorMessage();
class GPUTimer &getGPUTimer(unsigned);
void draw2dTriangle(const core::vector2df &a, const core::vector2df &b,
const core::vector2df &c,
const video::ITexture *texture = NULL,
const video::SColor *ca=NULL,
const video::SColor *cb=NULL,
const video::SColor *cc=NULL);
std::unique_ptr<RenderTarget> createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name);
// ------------------------------------------------------------------------
/** Convenience function that loads a texture with default parameters
@ -502,10 +348,7 @@ public:
{
return m_texture_error_message;
} // getTextureErrorMessage
// ------------------------------------------------------------------------
void setRTT(RTT* rtt);
// ------------------------------------------------------------------------
RTT* getRTT() { return m_rtts; }
// ------------------------------------------------------------------------
/** Returns a list of all video modes supports by the graphics card. */
const std::vector<VideoMode>& getVideoModes() const { return m_modes; }
@ -530,16 +373,14 @@ public:
* application. Value in msec. */
unsigned int getRealTime() {return m_device->getTimer()->getRealTime(); }
// ------------------------------------------------------------------------
/** Returns a pointer to the post processing object. */
inline PostProcessing* getPostProcessing() {return m_post_processing;}
/** Use motion blur for a short time */
void giveBoost(unsigned int cam_index) { m_renderer->giveBoost(cam_index);}
// ------------------------------------------------------------------------
inline core::vector3df getWind() {return m_wind->getWind();}
// -----------------------------------------------------------------------
/** Returns a pointer to the skybox. */
inline Skybox *getSkybox() {return m_skybox;}
// -----------------------------------------------------------------------
/** Returns a pointer to spherical harmonics. */
inline SphericalHarmonics *getSphericalHarmonics() {return m_spherical_harmonics;}
/** Returns a pointer to the spherical harmonics coefficients. */
inline const SHCoefficients* getSHCoefficients() {return m_renderer->getSHCoefficients();}
// -----------------------------------------------------------------------
const core::vector3df& getSunDirection() const { return m_sun_direction; };
// -----------------------------------------------------------------------
@ -556,7 +397,6 @@ public:
}
// ------------------------------------------------------------------------
GLuint getRenderTargetTexture(TypeRTT which);
FrameBuffer& getFBO(TypeFBO which);
GLuint getDepthStencilTexture();
// ------------------------------------------------------------------------
void resetDebugModes()
@ -576,8 +416,12 @@ public:
// ------------------------------------------------------------------------
void toggleWireframe() { m_wireframe = !m_wireframe; }
// ------------------------------------------------------------------------
bool getWireframe() { return m_wireframe; }
// ------------------------------------------------------------------------
void toggleMipVisualization() { m_mipviz = !m_mipviz; }
// ------------------------------------------------------------------------
bool getMipViz() { return m_mipviz; }
// ------------------------------------------------------------------------
void toggleNormals() { m_normals = !m_normals; }
// ------------------------------------------------------------------------
bool getNormals() { return m_normals; }
@ -621,16 +465,10 @@ public:
void addGlowingNode(scene::ISceneNode *n, float r = 1.0f, float g = 1.0f,
float b = 1.0f)
{
GlowData dat;
dat.node = n;
dat.r = r;
dat.g = g;
dat.b = b;
m_glowing.push_back(dat);
m_renderer->addGlowingNode(n, r, g, b);
}
// ------------------------------------------------------------------------
void clearGlowingNodes() { m_glowing.clear(); }
void clearGlowingNodes() { m_renderer->clearGlowingNodes(); }
// ------------------------------------------------------------------------
void addForcedBloomNode(scene::ISceneNode *n, float power = 1)
{
@ -668,8 +506,6 @@ public:
// ------------------------------------------------------------------------
class STKMeshSceneNode *getSunInterposer() { return m_sun_interposer; }
// ------------------------------------------------------------------------
ShadowMatrices *getShadowMatrices() { return m_shadow_matrices; }
// ------------------------------------------------------------------------
void cleanSunInterposer();
void createSunInterposer();
@ -708,7 +544,7 @@ public:
// ------------------------------------------------------------------------
const core::vector2df &getCurrentScreenSize() const
{
return m_current_screen_size;
return m_renderer->getCurrentScreenSize();
}
// ------------------------------------------------------------------------
const core::dimension2du getActualScreenSize() const
@ -751,6 +587,10 @@ public:
m_ssao_sigma = v;
}
#ifdef DEBUG
std::vector<scene::IAnimatedMeshSceneNode*> getDebugMeshes()
{
return m_debug_meshes;
}
/** Removes debug meshes. */
void clearDebugMesh() { m_debug_meshes.clear(); }
// ------------------------------------------------------------------------
@ -761,92 +601,14 @@ public:
} // addDebugMesh
#endif
void onLoadWorld();
void onUnloadWorld();
void renderScene(scene::ICameraSceneNode * const camnode,
unsigned pointlightcount, std::vector<GlowData>& glows,
float dt, bool hasShadows, bool forceRTT);
unsigned updateLightsInfo(scene::ICameraSceneNode * const camnode,
float dt);
void updateSplitAndLightcoordRangeFromComputeShaders(size_t width,
size_t height);
void computeMatrixesAndCameras(scene::ICameraSceneNode * const camnode,
size_t width, size_t height);
void uploadLightingData();
// --------------------- OLD RTT --------------------
/**
* THIS IS THE OLD OPENGL 1 RTT PROVIDER, USE THE SHADER-BASED
* RTT FOR NEW DEVELOPMENT
*
* Class that provides RTT (currently, only when no other 3D rendering
* in the main scene is required)
* Provides an optional 'setupRTTScene' method to make it quick and easy
* to prepare rendering of 3D objects but you can also manually set the
* scene/camera. If you use the factory 'setupRTTScene', cleanup can be
* done through 'tearDownRTTScene' (destructor will also do this). If
* you set it up manually, you need to clean it up manually.
*/
class RTTProvider
{
/** A pointer to texture on which a scene is rendered. Only used
* in between beginRenderToTexture() and endRenderToTexture calls. */
video::ITexture *m_render_target_texture;
bool m_persistent_texture;
/** Main node of the RTT scene */
scene::ISceneNode *m_rtt_main_node;
scene::ICameraSceneNode *m_camera;
scene::ILightSceneNode *m_light;
/** Irrlicht video driver. */
video::IVideoDriver *m_video_driver;
public:
RTTProvider(const core::dimension2du &dimension,
const std::string &name, bool persistent_texture);
~RTTProvider();
/**
* \brief Quick utility method to setup a scene from a plain list
* of models
*
* Sets up a given vector of meshes for render-to-texture. Ideal to
* embed a 3D object inside the GUI. If there are multiple meshes,
* the first mesh is considered to be the root, and all following
* meshes will have their locations relative to the location of the
* first mesh.
*
* \param mesh The list of meshes to add to the scene
* \param mesh_location Location of each fo these meshes
* \param model_frames For animated meshes, which frame to use
* (value can be -1 to set none)
* When frame is not -1, the corresponding
* IMesh must be an IAnimatedMesh.
* \pre The 3 vectors have the same size.
*/
void setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
AlignedArray<Vec3>& mesh_location,
AlignedArray<Vec3>& mesh_scale,
const std::vector<int>& model_frames);
/** Optional 'angle' parameter will rotate the object added
* *through setupRTTScene* */
video::ITexture* renderToTexture(float angle=-1,
bool is_2d_render=false);
void tearDownRTTScene();
};
}; // IrrDriver
extern IrrDriver *irr_driver;

View File

@ -18,21 +18,9 @@
#include "graphics/light.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/rtts.hpp"
#include "graphics/screen_quad.hpp"
#include "graphics/shaders.hpp"
using namespace video;
using namespace scene;
using namespace core;
aabbox3df LightNode::box;
#include <ISceneManager.h>
core::aabbox3df LightNode::box;
LightNode::LightNode(scene::ISceneManager* mgr, scene::ISceneNode* parent, float e, float d, float r, float g, float b):
ISceneNode(parent == NULL ? mgr->getRootSceneNode() : parent, mgr, -1)

View File

@ -1,5 +1,5 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014-2015 SuperTuxKart-Team
// 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
@ -15,9 +15,8 @@
// 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/lighting_passes.hpp"
#include "config/user_config.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
@ -26,14 +25,10 @@
#include "graphics/rtts.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
class LightBaseClass
{
public:
@ -54,9 +49,32 @@ public:
static struct PointLightInfo m_point_lights_info[MAXLIGHT];
}; // LightBaseClass
const unsigned int LightBaseClass::MAXLIGHT;
// ============================================================================
LightBaseClass::PointLightInfo m_point_lights_info[LightBaseClass::MAXLIGHT];
// ============================================================================
class FogShader : public TextureShader<FogShader, 1, float, core::vector3df>
{
public:
FogShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "fog.frag");
assignUniforms("density", "col");
assignSamplerNames(0, "tex", ST_NEAREST_FILTERED);
} // FogShader
// ------------------------------------------------------------------------
void render(float start, const core::vector3df &color, GLuint depth_stencil_texture)
{
setTextureUnits(depth_stencil_texture);
drawFullScreenEffect(1.f / (40.f * start), color);
} // render
}; // FogShader
// ============================================================================
class PointLightShader : public TextureShader < PointLightShader, 2 >
{
@ -109,6 +127,8 @@ public:
}; // PointLightShader
// ============================================================================
class PointLightScatterShader : public TextureShader<PointLightScatterShader,
1, float, core::vector3df>
@ -157,69 +177,6 @@ public:
} // PointLightScatterShader
};
// ============================================================================
class ShadowedSunLightShaderPCF : public TextureShader<ShadowedSunLightShaderPCF,
3, float, float, float,
float, float>
{
public:
ShadowedSunLightShaderPCF()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlightshadow.frag");
// Use 8 to circumvent a catalyst bug when binding sampler
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
8, "shadowtex", ST_SHADOW_SAMPLER);
assignUniforms("split0", "split1", "split2", "splitmax", "shadow_res");
} // ShadowedSunLightShaderPCF
// ------------------------------------------------------------------------
void render(RTT *rtts)
{
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture(),
rtts->getShadowFBO().getDepthTexture() );
drawFullScreenEffect(ShadowMatrices::m_shadow_split[1],
ShadowMatrices::m_shadow_split[2],
ShadowMatrices::m_shadow_split[3],
ShadowMatrices::m_shadow_split[4],
float(UserConfigParams::m_shadows_resolution) );
} // render
}; // ShadowedSunLightShaderPCF
// ============================================================================
class ShadowedSunLightShaderESM : public TextureShader<ShadowedSunLightShaderESM,
3, float, float, float,
float>
{
public:
ShadowedSunLightShaderESM()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlightshadowesm.frag");
// Use 8 to circumvent a catalyst bug when binding sampler
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
8, "shadowtex", ST_TRILINEAR_CLAMPED_ARRAY2D);
assignUniforms("split0", "split1", "split2", "splitmax");
} // ShadowedSunLightShaderESM
// ------------------------------------------------------------------------
void render(RTT *rtt)
{
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture(),
rtt->getShadowFBO().getRTT()[0]);
drawFullScreenEffect(ShadowMatrices::m_shadow_split[1],
ShadowMatrices::m_shadow_split[2],
ShadowMatrices::m_shadow_split[3],
ShadowMatrices::m_shadow_split[4]);
} // render
}; // ShadowedSunLightShaderESM
#if !defined(USE_GLES2)
// ============================================================================
class RadianceHintsConstructionShader
@ -269,30 +226,172 @@ public:
2, "dtex", ST_BILINEAR_FILTERED);
} // NVWorkaroundRadianceHintsConstructionShader
}; // NVWorkaroundRadianceHintsConstructionShader
#endif
#endif // !defined(USE_GLES2)
// ============================================================================
class FogShader : public TextureShader<FogShader, 1, float, core::vector3df>
class GlobalIlluminationReconstructionShader
: public TextureShader<GlobalIlluminationReconstructionShader, 5,
core::matrix4, core::matrix4, core::vector3df >
{
public:
FogShader()
GlobalIlluminationReconstructionShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "fog.frag");
assignUniforms("density", "col");
assignSamplerNames(0, "tex", ST_NEAREST_FILTERED);
} // FogShader
// ------------------------------------------------------------------------
void render(float start, const core::vector3df &color)
{
setTextureUnits(irr_driver->getDepthStencilTexture());
drawFullScreenEffect(1.f / (40.f * start), color);
GL_FRAGMENT_SHADER, "gi.frag");
assignUniforms("rh_matrix", "inv_rh_matrix", "extents");
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
2, "SHR", ST_VOLUME_LINEAR_FILTERED,
3, "SHG", ST_VOLUME_LINEAR_FILTERED,
4, "SHB", ST_VOLUME_LINEAR_FILTERED);
} // GlobalIlluminationReconstructionShader
// ------------------------------------------------------------------------
void render(const core::matrix4 &rh_matrix,
const core::vector3df &rh_extend, const FrameBuffer &fb,
GLuint normal_depth_texture,
GLuint depth_stencil_texture)
{
core::matrix4 inv_rh_matrix;
rh_matrix.getInverse(inv_rh_matrix);
glDisable(GL_DEPTH_TEST);
setTextureUnits(normal_depth_texture,
depth_stencil_texture,
fb.getRTT()[0], fb.getRTT()[1], fb.getRTT()[2]);
drawFullScreenEffect(rh_matrix, inv_rh_matrix, rh_extend);
} // render
}; // FogShader
}; // GlobalIlluminationReconstructionShader
// ============================================================================
static void renderPointLights(unsigned count)
class IBLShader : public TextureShader<IBLShader, 3>
{
public:
IBLShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "IBL.frag");
assignUniforms();
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
2, "probe", ST_TRILINEAR_CUBEMAP);
} // IBLShader
}; // IBLShader
// ============================================================================
class DegradedIBLShader : public TextureShader<DegradedIBLShader, 1>
{
public:
DegradedIBLShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "degraded_ibl.frag");
assignUniforms();
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED);
} // DegradedIBLShader
}; // DegradedIBLShader
// ============================================================================
class ShadowedSunLightShaderPCF : public TextureShader<ShadowedSunLightShaderPCF,
3, float, float, float,
float, float>
{
public:
ShadowedSunLightShaderPCF()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlightshadow.frag");
// Use 8 to circumvent a catalyst bug when binding sampler
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
8, "shadowtex", ST_SHADOW_SAMPLER);
assignUniforms("split0", "split1", "split2", "splitmax", "shadow_res");
} // ShadowedSunLightShaderPCF
// ------------------------------------------------------------------------
void render(GLuint normal_depth_texture,
GLuint depth_stencil_texture,
const FrameBuffer& shadow_framebuffer)
{
setTextureUnits(normal_depth_texture,
depth_stencil_texture,
shadow_framebuffer.getDepthTexture() );
drawFullScreenEffect(ShadowMatrices::m_shadow_split[1],
ShadowMatrices::m_shadow_split[2],
ShadowMatrices::m_shadow_split[3],
ShadowMatrices::m_shadow_split[4],
float(UserConfigParams::m_shadows_resolution) );
} // render
}; // ShadowedSunLightShaderPCF
// ============================================================================
class ShadowedSunLightShaderESM : public TextureShader<ShadowedSunLightShaderESM,
3, float, float, float,
float>
{
public:
ShadowedSunLightShaderESM()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlightshadowesm.frag");
// Use 8 to circumvent a catalyst bug when binding sampler
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
8, "shadowtex", ST_TRILINEAR_CLAMPED_ARRAY2D);
assignUniforms("split0", "split1", "split2", "splitmax");
} // ShadowedSunLightShaderESM
// ------------------------------------------------------------------------
void render(GLuint normal_depth_texture,
GLuint depth_stencil_texture,
const FrameBuffer& shadow_framebuffer)
{
setTextureUnits(normal_depth_texture,
depth_stencil_texture,
shadow_framebuffer.getRTT()[0]);
drawFullScreenEffect(ShadowMatrices::m_shadow_split[1],
ShadowMatrices::m_shadow_split[2],
ShadowMatrices::m_shadow_split[3],
ShadowMatrices::m_shadow_split[4]);
} // render
}; // ShadowedSunLightShaderESM
// ============================================================================
class SunLightShader : public TextureShader<SunLightShader, 2,
core::vector3df, video::SColorf>
{
public:
SunLightShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlight.frag");
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED);
assignUniforms("direction", "col");
} // SunLightShader
// ------------------------------------------------------------------------
void render(const core::vector3df &direction, const video::SColorf &col,
GLuint normal_depth_texture,
GLuint depth_stencil_texture)
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
setTextureUnits(normal_depth_texture, depth_stencil_texture);
drawFullScreenEffect(direction, col);
} // render
}; // SunLightShader
// ============================================================================
static void renderPointLights(unsigned count,
GLuint normal_depth_rander_target,
GLuint depth_stencil_texture)
{
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
@ -308,47 +407,99 @@ static void renderPointLights(unsigned count)
m_point_lights_info);
PointLightShader::getInstance()->setTextureUnits(
irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture());
normal_depth_rander_target,
depth_stencil_texture);
PointLightShader::getInstance()->setUniforms();
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count);
} // renderPointLights
// ----------------------------------------------------------------------------
unsigned IrrDriver::updateLightsInfo(scene::ICameraSceneNode * const camnode,
void LightingPasses::renderEnvMap(GLuint normal_depth_texture,
GLuint depth_stencil_texture,
GLuint specular_probe)
{
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
if (UserConfigParams::m_degraded_IBL)
{
DegradedIBLShader::getInstance()->use();
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
DegradedIBLShader::getInstance()
->setTextureUnits(normal_depth_texture);
DegradedIBLShader::getInstance()->setUniforms();
}
else
{
IBLShader::getInstance()->use();
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
IBLShader::getInstance()->setTextureUnits(
normal_depth_texture,
depth_stencil_texture,
specular_probe);
IBLShader::getInstance()->setUniforms();
}
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
} // renderEnvMap
// ----------------------------------------------------------------------------
void LightingPasses::renderSunlight(const core::vector3df &direction,
const video::SColorf &col,
GLuint normal_depth_texture,
GLuint depth_stencil_texture)
{
SunLightShader::getInstance()->render(direction, col,
normal_depth_texture,
depth_stencil_texture);
} // renderSunlight
// ----------------------------------------------------------------------------
void LightingPasses::updateLightsInfo(scene::ICameraSceneNode * const camnode,
float dt)
{
const u32 lightcount = (u32)m_lights.size();
std::vector<LightNode *> lights = irr_driver->getLights();
const u32 lightcount = (u32)lights.size();
const core::vector3df &campos = camnode->getAbsolutePosition();
std::vector<LightNode *> BucketedLN[15];
for (unsigned int i = 0; i < lightcount; i++)
{
if (!m_lights[i]->isVisible())
if (!lights[i]->isVisible())
continue;
if (!m_lights[i]->isPointLight())
if (!lights[i]->isPointLight())
{
m_lights[i]->render();
lights[i]->render();
continue;
}
const core::vector3df &lightpos =
(m_lights[i]->getAbsolutePosition() - campos);
(lights[i]->getAbsolutePosition() - campos);
unsigned idx = (unsigned)(lightpos.getLength() / 10);
if (idx > 14)
idx = 14;
BucketedLN[idx].push_back(m_lights[i]);
BucketedLN[idx].push_back(lights[i]);
}
unsigned lightnum = 0;
m_point_light_count = 0;
bool multiplayer = (race_manager->getNumLocalPlayers() > 1);
for (unsigned i = 0; i < 15; i++)
{
for (unsigned j = 0; j < BucketedLN[i].size(); j++)
{
if (++lightnum >= LightBaseClass::MAXLIGHT)
if (++m_point_light_count >= LightBaseClass::MAXLIGHT)
{
LightNode* light_node = BucketedLN[i].at(j);
light_node->setEnergyMultiplier(0.0f);
@ -369,82 +520,60 @@ unsigned IrrDriver::updateLightsInfo(scene::ICameraSceneNode * const camnode,
}
const core::vector3df &pos = light_node->getAbsolutePosition();
m_point_lights_info[lightnum].posX = pos.X;
m_point_lights_info[lightnum].posY = pos.Y;
m_point_lights_info[lightnum].posZ = pos.Z;
m_point_lights_info[m_point_light_count].posX = pos.X;
m_point_lights_info[m_point_light_count].posY = pos.Y;
m_point_lights_info[m_point_light_count].posZ = pos.Z;
m_point_lights_info[lightnum].energy =
m_point_lights_info[m_point_light_count].energy =
light_node->getEffectiveEnergy();
const core::vector3df &col = light_node->getColor();
m_point_lights_info[lightnum].red = col.X;
m_point_lights_info[lightnum].green = col.Y;
m_point_lights_info[lightnum].blue = col.Z;
m_point_lights_info[m_point_light_count].red = col.X;
m_point_lights_info[m_point_light_count].green = col.Y;
m_point_lights_info[m_point_light_count].blue = col.Z;
// Light radius
m_point_lights_info[lightnum].radius = light_node->getRadius();
m_point_lights_info[m_point_light_count].radius = light_node->getRadius();
}
}
if (lightnum > LightBaseClass::MAXLIGHT)
if (m_point_light_count > LightBaseClass::MAXLIGHT)
{
irr_driver->setLastLightBucketDistance(i * 10);
break;
}
}
lightnum++;
return lightnum;
m_point_light_count++;
} // updateLightsInfo
// ----------------------------------------------------------------------------
/** Upload lighting info to the dedicated uniform buffer
*/
void IrrDriver::uploadLightingData()
void LightingPasses::renderGlobalIllumination( const ShadowMatrices& shadow_matrices,
const FrameBuffer& radiance_hint_framebuffer,
const FrameBuffer& reflective_shadow_map_framebuffer,
const FrameBuffer& diffuse_framebuffer,
GLuint normal_depth_texture,
GLuint depth_stencil_texture)
{
float Lighting[36];
Lighting[0] = m_sun_direction.X;
Lighting[1] = m_sun_direction.Y;
Lighting[2] = m_sun_direction.Z;
Lighting[4] = m_suncolor.getRed();
Lighting[5] = m_suncolor.getGreen();
Lighting[6] = m_suncolor.getBlue();
Lighting[7] = 0.54f;
if(m_spherical_harmonics) {
memcpy(&Lighting[8], m_spherical_harmonics->getBlueSHCoeff(), 9 * sizeof(float));
memcpy(&Lighting[17], m_spherical_harmonics->getGreenSHCoeff(), 9 * sizeof(float));
memcpy(&Lighting[26], m_spherical_harmonics->getRedSHCoeff(), 9 * sizeof(float));
}
glBindBuffer(GL_UNIFORM_BUFFER, SharedGPUObjects::getLightingDataUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, 36 * sizeof(float), Lighting);
} // uploadLightingData
// ----------------------------------------------------------------------------
void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
{
//RH
//Radiance hints
#if !defined(USE_GLES2)
if (CVS->isGlobalIlluminationEnabled() && hasShadow)
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_RH));
glDisable(GL_BLEND);
m_rtts->getRH().bind();
radiance_hint_framebuffer.bind();
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
if (CVS->needRHWorkaround())
{
NVWorkaroundRadianceHintsConstructionShader::getInstance()->use();
NVWorkaroundRadianceHintsConstructionShader::getInstance()
->setTextureUnits(
m_rtts->getRSM().getRTT()[0],
m_rtts->getRSM().getRTT()[1],
m_rtts->getRSM().getDepthTexture());
reflective_shadow_map_framebuffer.getRTT()[0],
reflective_shadow_map_framebuffer.getRTT()[1],
reflective_shadow_map_framebuffer.getDepthTexture());
for (unsigned i = 0; i < 32; i++)
{
NVWorkaroundRadianceHintsConstructionShader::getInstance()
->setUniforms(getShadowMatrices()->getRSMMatrix(),
getShadowMatrices()->getRHMatrix(),
getShadowMatrices()->getRHExtend(), i,
->setUniforms(shadow_matrices.getRSMMatrix(),
shadow_matrices.getRHMatrix(),
shadow_matrices.getRHExtend(), i,
irr_driver->getSunColor());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
@ -454,99 +583,93 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
RadianceHintsConstructionShader::getInstance()->use();
RadianceHintsConstructionShader::getInstance()
->setTextureUnits(
m_rtts->getRSM().getRTT()[0],
m_rtts->getRSM().getRTT()[1],
m_rtts->getRSM().getDepthTexture()
reflective_shadow_map_framebuffer.getRTT()[0],
reflective_shadow_map_framebuffer.getRTT()[1],
reflective_shadow_map_framebuffer.getDepthTexture()
);
RadianceHintsConstructionShader::getInstance()
->setUniforms(getShadowMatrices()->getRSMMatrix(),
getShadowMatrices()->getRHMatrix(),
getShadowMatrices()->getRHExtend(),
->setUniforms(shadow_matrices.getRSMMatrix(),
shadow_matrices.getRHMatrix(),
shadow_matrices.getRHExtend(),
irr_driver->getSunColor());
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32);
}
}
#endif
getShadowMatrices()->updateSunOrthoMatrices();
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).bind();
glClear(GL_COLOR_BUFFER_BIT);
#endif //!defined(USE_GLES2)
m_rtts->getFBO(FBO_DIFFUSE).bind();
if (CVS->isGlobalIlluminationEnabled() && hasShadow)
//Global illumination
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_GI));
m_post_processing->renderGI(getShadowMatrices()->getRHMatrix(),
getShadowMatrices()->getRHExtend(),
m_rtts->getRH());
diffuse_framebuffer.bind();
GlobalIlluminationReconstructionShader::getInstance()
->render(shadow_matrices.getRHMatrix(),
shadow_matrices.getRHExtend(),
radiance_hint_framebuffer,
normal_depth_texture,
depth_stencil_texture);
}
}
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).bind();
// ----------------------------------------------------------------------------
void LightingPasses::renderLights( bool has_shadow,
GLuint normal_depth_texture,
GLuint depth_stencil_texture,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& diffuse_specular_framebuffer,
GLuint specular_probe)
{
diffuse_specular_framebuffer.bind();
glClear(GL_COLOR_BUFFER_BIT);
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_ENVMAP));
if(m_skybox)
{
m_post_processing->renderEnvMap(m_skybox->getSpecularProbe());
}
else
{
m_post_processing->renderEnvMap(0);
}
renderEnvMap(normal_depth_texture,
depth_stencil_texture,
specular_probe);
}
// Render sunlight if and only if track supports shadow
if (!World::getWorld() || World::getWorld()->getTrack()->hasShadows())
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_SUN));
if (World::getWorld() && CVS->isShadowEnabled() && hasShadow)
if (World::getWorld() && CVS->isShadowEnabled() && has_shadow)
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
if (CVS->isESMEnabled())
{
ShadowedSunLightShaderESM::getInstance()->render(m_rtts);
ShadowedSunLightShaderESM::getInstance()->render(normal_depth_texture,
depth_stencil_texture,
shadow_framebuffer);
}
else
{
ShadowedSunLightShaderPCF::getInstance()->render(m_rtts);
ShadowedSunLightShaderPCF::getInstance()->render(normal_depth_texture,
depth_stencil_texture,
shadow_framebuffer);
}
}
else
m_post_processing->renderSunlight(irr_driver->getSunDirection(),
irr_driver->getSunColor());
renderSunlight(irr_driver->getSunDirection(),
irr_driver->getSunColor(),
normal_depth_texture,
depth_stencil_texture);
}
//points lights
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_POINTLIGHTS));
renderPointLights(MIN2(pointlightcount, LightBaseClass::MAXLIGHT));
renderPointLights(std::min(m_point_light_count, LightBaseClass::MAXLIGHT),
normal_depth_texture,
depth_stencil_texture);
}
} // renderLights
// ----------------------------------------------------------------------------
void IrrDriver::renderSSAO()
{
#if defined(USE_GLES2)
if (!CVS->isEXTColorBufferFloatUsable())
return;
#endif
m_rtts->getFBO(FBO_SSAO).bind();
glClearColor(1., 1., 1., 1.);
glClear(GL_COLOR_BUFFER_BIT);
m_post_processing->renderSSAO();
// Blur it to reduce noise.
FrameBuffer::Blit(m_rtts->getFBO(FBO_SSAO),
m_rtts->getFBO(FBO_HALF1_R),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
m_post_processing->renderGaussian17TapBlur(irr_driver->getFBO(FBO_HALF1_R),
irr_driver->getFBO(FBO_HALF2_R));
} // renderSSAO
// ----------------------------------------------------------------------------
void IrrDriver::renderAmbientScatter()
void LightingPasses::renderAmbientScatter(GLuint depth_stencil_texture)
{
const Track * const track = World::getWorld()->getTrack();
@ -564,13 +687,17 @@ void IrrDriver::renderAmbientScatter()
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
FogShader::getInstance()->render(start, col);
FogShader::getInstance()->render(start, col, depth_stencil_texture);
} // renderAmbientScatter
// ----------------------------------------------------------------------------
void IrrDriver::renderLightsScatter(unsigned pointlightcount)
void LightingPasses::renderLightsScatter(GLuint depth_stencil_texture,
const FrameBuffer& half1_framebuffer,
const FrameBuffer& half2_framebuffer,
const FrameBuffer& colors_framebuffer,
const PostProcessing* post_processing)
{
getFBO(FBO_HALF1).bind();
half1_framebuffer.bind();
glClearColor(0., 0., 0., 0.);
glClear(GL_COLOR_BUFFER_BIT);
@ -596,22 +723,24 @@ void IrrDriver::renderLightsScatter(unsigned pointlightcount)
glBindVertexArray(PointLightScatterShader::getInstance()->vao);
PointLightScatterShader::getInstance()
->setTextureUnits(irr_driver->getDepthStencilTexture());
->setTextureUnits(depth_stencil_texture);
PointLightScatterShader::getInstance()
->setUniforms(1.f / (40.f * start), col2);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4,
MIN2(pointlightcount, LightBaseClass::MAXLIGHT));
std::min(m_point_light_count,
LightBaseClass::MAXLIGHT));
glDisable(GL_BLEND);
m_post_processing->renderGaussian6Blur(getFBO(FBO_HALF1),
getFBO(FBO_HALF2), 5., 5.);
post_processing->renderGaussian6Blur(half1_framebuffer,
half2_framebuffer, 5., 5.);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
getFBO(FBO_COLORS).bind();
m_post_processing->renderPassThrough(getRenderTargetTexture(RTT_HALF1),
getFBO(FBO_COLORS).getWidth(),
getFBO(FBO_COLORS).getHeight());
colors_framebuffer.bind();
post_processing->renderPassThrough(half1_framebuffer.getRTT()[0],
colors_framebuffer.getWidth(),
colors_framebuffer.getHeight());
} // renderLightsScatter

View File

@ -0,0 +1,74 @@
// 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_LIGHTING_PASSES_HPP
#define HEADER_LIGHTING_PASSES_HPP
#include "graphics/gl_headers.hpp"
#include <irrlicht.h>
class FrameBuffer;
class PostProcessing;
class ShadowMatrices;
using namespace irr;
class LightingPasses
{
private:
unsigned m_point_light_count;
void renderEnvMap(GLuint normal_depth_texture,
GLuint depth_stencil_texture,
GLuint specular_probe);
/** Generate diffuse and specular map */
void renderSunlight(const core::vector3df &direction,
const video::SColorf &col,
GLuint normal_depth_texture,
GLuint depth_stencil_texture);
public:
LightingPasses(): m_point_light_count(0){}
void updateLightsInfo(irr::scene::ICameraSceneNode * const camnode,
float dt);
void renderGlobalIllumination( const ShadowMatrices& shadow_matrices,
const FrameBuffer& radiance_hint_framebuffer,
const FrameBuffer& reflective_shadow_map_framebuffer,
const FrameBuffer& diffuse_framebuffer,
GLuint normal_depth_texture,
GLuint depth_stencil_texture);
void renderLights( bool has_shadow,
GLuint normal_depth_texture,
GLuint depth_stencil_texture,
const FrameBuffer& shadow_framebuffer,
const FrameBuffer& diffuse_specular_framebuffer,
GLuint specular_probe);
void renderAmbientScatter(GLuint depth_stencil_texture);
void renderLightsScatter(GLuint depth_stencil_texture,
const FrameBuffer& half1_framebuffer,
const FrameBuffer& half2_framebuffer,
const FrameBuffer& colors_framebuffer,
const PostProcessing* post_processing);
};
#endif //HEADER_LIGHTING_PASSES_HPP

View File

@ -30,10 +30,10 @@
#include "guiengine/engine.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/particle_kind_manager.hpp"
#include "graphics/shaders.hpp"
#include "graphics/texture_manager.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "utils/string_utils.hpp"

View File

@ -47,7 +47,7 @@ class Material : public NoCopy
public:
enum ShaderType
{
SHADERTYPE_SOLID,
SHADERTYPE_SOLID = 0,
SHADERTYPE_ALPHA_TEST,
SHADERTYPE_ALPHA_BLEND,
SHADERTYPE_ADDITIVE,

View File

@ -0,0 +1,78 @@
// 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.
#include "graphics/materials.hpp"
const STK::Tuple<size_t> DefaultMaterial::FirstPassTextures
= STK::Tuple<size_t>(1);
const STK::Tuple<size_t, size_t, size_t> DefaultMaterial::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 7);
const STK::Tuple<> DefaultMaterial::ShadowTextures;
const STK::Tuple<size_t> DefaultMaterial::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> AlphaRef::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t, size_t> AlphaRef::SecondPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t> AlphaRef::ShadowTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> AlphaRef::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t> SphereMap::FirstPassTextures = STK::Tuple<size_t>(1);
const STK::Tuple<size_t> SphereMap::SecondPassTextures = STK::Tuple<size_t>(0);
const STK::Tuple<> SphereMap::ShadowTextures;
const STK::Tuple<size_t> SphereMap::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> UnlitMat::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t> UnlitMat::SecondPassTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> UnlitMat::ShadowTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> UnlitMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> GrassMat::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t, size_t> GrassMat::SecondPassTextures
= STK::Tuple<size_t, size_t>(0, 1);
const STK::Tuple<size_t> GrassMat::ShadowTextures = STK::Tuple<size_t>(0);
const STK::Tuple<size_t> GrassMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> NormalMat::FirstPassTextures
= STK::Tuple<size_t, size_t>(2, 1);
const STK::Tuple<size_t, size_t, size_t> NormalMat::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 7);
const STK::Tuple<> NormalMat::ShadowTextures;
const STK::Tuple<size_t> NormalMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t> DetailMat::FirstPassTextures = STK::Tuple<size_t>(1);
const STK::Tuple<size_t, size_t, size_t> DetailMat::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 2, 1);
const STK::Tuple<> DetailMat::ShadowTextures;
const STK::Tuple<size_t> DetailMat::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t> SplattingMat::FirstPassTextures = STK::Tuple<size_t>(6);
const STK::Tuple<size_t, size_t, size_t, size_t, size_t>
SplattingMat::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t, size_t, size_t>(1, 2, 3, 4, 5);
const STK::Tuple<> SplattingMat::ShadowTextures;
const STK::Tuple<size_t, size_t, size_t, size_t, size_t> SplattingMat::RSMTextures
= STK::Tuple<size_t, size_t, size_t, size_t, size_t>(1, 2, 3, 4, 5);

799
src/graphics/materials.hpp Normal file
View File

@ -0,0 +1,799 @@
// 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_MATERIAL_TYPE_HPP
#define HEADER_MATERIAL_TYPE_HPP
#include "graphics/shader.hpp"
#include "graphics/shaders.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/vao_manager.hpp"
// ============================================================================
class InstancedObjectPass1Shader : public TextureShader<InstancedObjectPass1Shader, 1>
{
public:
InstancedObjectPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass1.frag");
assignUniforms();
assignSamplerNames(0, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedObjectPass1Shader
}; // class InstancedObjectPass1Shader
// ============================================================================
class InstancedObjectRefPass1Shader : public TextureShader<InstancedObjectRefPass1Shader, 2>
{
public:
InstancedObjectRefPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_objectref_pass1.frag");
assignUniforms();
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
}
}; // InstancedObjectRefPass1Shader
// ============================================================================
class ObjectRefPass2Shader : public TextureShader<ObjectRefPass2Shader, 5,
core::matrix4, core::matrix4>
{
public:
ObjectRefPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "objectref_pass2.frag");
assignUniforms("ModelMatrix", "TextureMatrix");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // ObjectRefPass2Shader
}; // ObjectRefPass2Shader
// ============================================================================
class InstancedObjectPass2Shader : public TextureShader<InstancedObjectPass2Shader, 6>
{
private:
GLint m_color_change_location;
public:
InstancedObjectPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass2.frag");
m_color_change_location = glGetUniformLocation(m_program, "color_change");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedObjectPass2Shader
virtual bool changeableColor(float hue = 0.0f, float min_sat = 0.0f) const OVERRIDE
{
glUniform2f(m_color_change_location, hue, min_sat);
return true;
} // changeableColor
}; // InstancedObjectPass2Shader
// ============================================================================
class InstancedObjectRefPass2Shader : public TextureShader<InstancedObjectRefPass2Shader, 5>
{
public:
InstancedObjectRefPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_objectref_pass2.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedObjectRefPass2Shader
}; // InstancedObjectRefPass2Shader
// ============================================================================
class ShadowShader : public TextureShader<ShadowShader, 0, core::matrix4, int>
{
public:
ShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow.vert",
GL_FRAGMENT_SHADER, "shadow.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow.vert",
GL_GEOMETRY_SHADER, "shadow.geom",
GL_FRAGMENT_SHADER, "shadow.frag");
}
assignUniforms("ModelMatrix", "layer");
#endif
} // ShadowShader
}; // ShadowShader
// ============================================================================
class InstancedShadowShader : public TextureShader<InstancedShadowShader, 0, int>
{
public:
InstancedShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedshadow.vert",
GL_FRAGMENT_SHADER, "shadow.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedshadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "shadow.frag");
}
assignUniforms("layer");
#endif
} // InstancedShadowShader
}; // InstancedShadowShader
// ============================================================================
class CRSMShader : public TextureShader<CRSMShader, 1, core::matrix4, core::matrix4,
core::matrix4>
{
public:
CRSMShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "rsm.vert",
GL_FRAGMENT_SHADER, "rsm.frag");
assignUniforms("RSMMatrix", "ModelMatrix", "TextureMatrix");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // CRSMShader
}; // CRSMShader
// ============================================================================
class SplattingRSMShader : public TextureShader<SplattingRSMShader, 5, core::matrix4,
core::matrix4>
{
public:
SplattingRSMShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "rsm.vert",
GL_FRAGMENT_SHADER, "splatting_rsm.frag");
assignUniforms("RSMMatrix", "ModelMatrix");
assignSamplerNames(0, "tex_layout", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "tex_detail0", ST_TRILINEAR_ANISOTROPIC_FILTERED,
2, "tex_detail1", ST_TRILINEAR_ANISOTROPIC_FILTERED,
3, "tex_detail2", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "tex_detail3", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SplattingRSMShader
}; // SplattingRSMShader
// ============================================================================
class CInstancedRSMShader : public TextureShader<CInstancedRSMShader, 1, core::matrix4>
{
public:
CInstancedRSMShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_rsm.vert",
GL_FRAGMENT_SHADER, "instanced_rsm.frag");
assignUniforms("RSMMatrix");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // CInstancedRSMShader
}; // CInstancedRSMShader
// ============================================================================
class SphereMapShader : public TextureShader<SphereMapShader, 4, core::matrix4,
core::matrix4>
{
public:
SphereMapShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "objectpass_spheremap.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SphereMapShader
}; // SphereMapShader
// ============================================================================
class InstancedSphereMapShader : public TextureShader<InstancedSphereMapShader, 4>
{
public:
InstancedSphereMapShader()
{
loadProgram(OBJECT,
GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_objectpass_spheremap.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSphereMapShader
}; // InstancedSphereMapShader
// ============================================================================
class SplattingShader : public TextureShader<SplattingShader, 8, core::matrix4>
{
public:
SplattingShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "splatting.frag");
assignUniforms("ModelMatrix");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex_layout", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "tex_detail0", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "tex_detail1", ST_TRILINEAR_ANISOTROPIC_FILTERED,
6, "tex_detail2", ST_TRILINEAR_ANISOTROPIC_FILTERED,
7, "tex_detail3", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // SplattingShader
}; // SplattingShader
// ============================================================================
class ObjectRefPass1Shader : public TextureShader<ObjectRefPass1Shader, 2, core::matrix4,
core::matrix4, core::matrix4>
{
public:
ObjectRefPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "objectref_pass1.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix", "TextureMatrix");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // ObjectRefPass1Shader
}; // ObjectRefPass1Shader
// ============================================================================
class NormalMapShader : public TextureShader<NormalMapShader, 2, core::matrix4,
core::matrix4>
{
public:
NormalMapShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "normalmap.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix");
assignSamplerNames(1, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
0, "DiffuseForAlpha", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // NormalMapShader
}; // NormalMapShader
// ============================================================================
class InstancedNormalMapShader : public TextureShader<InstancedNormalMapShader, 2>
{
public:
InstancedNormalMapShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_normalmap.frag");
assignUniforms();
assignSamplerNames(0, "normalMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glossMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedNormalMapShader
}; // InstancedNormalMapShader
// ============================================================================
class ObjectUnlitShader : public TextureShader<ObjectUnlitShader, 4, core::matrix4,
core::matrix4>
{
public:
ObjectUnlitShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "object_unlit.frag");
assignUniforms("ModelMatrix", "TextureMatrix");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // ObjectUnlitShader
}; // ObjectUnlitShader
// ============================================================================
class InstancedObjectUnlitShader : public TextureShader<InstancedObjectUnlitShader, 4>
{
public:
InstancedObjectUnlitShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_object_unlit.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedObjectUnlitShader
}; // InstancedObjectUnlitShader
// ============================================================================
class RefShadowShader : public TextureShader<RefShadowShader, 1,
core::matrix4, int>
{
public:
RefShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow.vert",
GL_FRAGMENT_SHADER, "shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow.vert",
GL_GEOMETRY_SHADER, "shadow.geom",
GL_FRAGMENT_SHADER, "shadowref.frag");
}
assignUniforms("ModelMatrix", "layer");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
#endif
} // RefShadowShader
}; // RefShadowShader
// ============================================================================
class InstancedRefShadowShader : public TextureShader<InstancedRefShadowShader,
1, int>
{
public:
InstancedRefShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanciedshadow.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT,GL_VERTEX_SHADER, "instanciedshadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
assignUniforms("layer");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
#endif
} // InstancedRefShadowShader
}; // InstancedRefShadowShader
// ============================================================================
class DisplaceMaskShader : public Shader<DisplaceMaskShader, core::matrix4>
{
public:
DisplaceMaskShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "displace.vert",
GL_FRAGMENT_SHADER, "white.frag");
assignUniforms("ModelMatrix");
} // DisplaceMaskShader
}; // DisplaceMaskShader
// ============================================================================
class DisplaceShader : public TextureShader<DisplaceShader, 4, core::matrix4,
core::vector2df, core::vector2df>
{
public:
DisplaceShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "displace.vert",
GL_FRAGMENT_SHADER, "displace.frag");
assignUniforms("ModelMatrix", "dir", "dir2");
assignSamplerNames(0, "displacement_tex", ST_BILINEAR_FILTERED,
1, "color_tex", ST_BILINEAR_FILTERED,
2, "mask_tex", ST_BILINEAR_FILTERED,
3, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // DisplaceShader
}; // DisplaceShader
// ============================================================================
class NormalVisualizer : public Shader<NormalVisualizer, video::SColor>
{
public:
NormalVisualizer()
{
#if !defined(USE_GLES2)
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_GEOMETRY_SHADER, "normal_visualizer.geom",
GL_FRAGMENT_SHADER, "coloredquad.frag");
assignUniforms("color");
#endif
} // NormalVisualizer
}; // NormalVisualizer
// ============================================================================
class GrassPass1Shader : public TextureShader<GrassPass1Shader, 2, core::matrix4,
core::matrix4, core::vector3df>
{
public:
GrassPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "grass_pass.vert",
GL_FRAGMENT_SHADER, "objectref_pass1.frag");
assignUniforms("ModelMatrix", "InverseModelMatrix", "windDir");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // GrassPass1Shader
}; // class GrassPass1Shader
// ============================================================================
class InstancedGrassPass1Shader : public TextureShader<InstancedGrassPass1Shader, 2,
core::vector3df>
{
public:
InstancedGrassPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_grass.vert",
GL_FRAGMENT_SHADER, "instanced_objectref_pass1.frag");
assignUniforms("windDir");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED,
1, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedGrassPass1Shader
}; // InstancedGrassPass1Shader
// ============================================================================
class GrassShadowShader : public TextureShader<GrassShadowShader, 1, core::matrix4,
core::vector3df, int>
{
public:
GrassShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow_grass.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "shadow_grass.vert",
GL_GEOMETRY_SHADER, "shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
assignUniforms("ModelMatrix", "windDir", "layer");
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
#endif
} // GrassShadowShader
}; // GrassShadowShader
// ============================================================================
class InstancedGrassShadowShader : public TextureShader<InstancedGrassShadowShader, 1,
int, core::vector3df>
{
public:
InstancedGrassShadowShader()
{
#if !defined(USE_GLES2)
// Geometry shader needed
if (CVS->getGLSLVersion() < 150)
return;
if (CVS->isAMDVertexShaderLayerUsable())
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedgrassshadow.vert",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
else
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanciedgrassshadow.vert",
GL_GEOMETRY_SHADER, "instanced_shadow.geom",
GL_FRAGMENT_SHADER, "instanced_shadowref.frag");
}
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
assignUniforms("layer", "windDir");
#endif
} // InstancedGrassShadowShader
}; // InstancedGrassShadowShader
// ============================================================================
class GrassPass2Shader : public TextureShader<GrassPass2Shader, 5, core::matrix4,
core::vector3df>
{
public:
GrassPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "grass_pass.vert",
GL_FRAGMENT_SHADER, "grass_pass2.frag");
assignUniforms("ModelMatrix", "windDir");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // GrassPass2Shader
}; // GrassPass2Shader
// ============================================================================
class InstancedGrassPass2Shader : public TextureShader<InstancedGrassPass2Shader, 6,
core::vector3df>
{
public:
InstancedGrassPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_grass.vert",
GL_FRAGMENT_SHADER, "instanced_grass_pass2.frag");
assignUniforms("windDir");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "dtex", ST_NEAREST_FILTERED,
4, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedGrassPass2Shader
}; // InstancedGrassPass2Shader
// ============================================================================
class DetailedObjectPass2Shader : public TextureShader<DetailedObjectPass2Shader, 6,
core::matrix4>
{
public:
DetailedObjectPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
GL_FRAGMENT_SHADER, "detailed_object_pass2.frag");
assignUniforms("ModelMatrix");
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "Detail", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // DetailedObjectPass2Shader
}; // DetailedObjectPass2Shader
// ============================================================================
class InstancedDetailedObjectPass2Shader : public TextureShader<InstancedDetailedObjectPass2Shader, 6>
{
public:
InstancedDetailedObjectPass2Shader()
{
loadProgram(OBJECT,
GL_VERTEX_SHADER, "instanced_object_pass.vert",
GL_FRAGMENT_SHADER, "instanced_detailed_object_pass2.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "Detail", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedDetailedObjectPass2Shader
}; // InstancedDetailedObjectPass2Shader
// ============================================================================
struct DefaultMaterial
{
typedef InstancedObjectPass1Shader InstancedFirstPassShader;
typedef InstancedObjectPass2Shader InstancedSecondPassShader;
typedef InstancedShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef Shaders::ObjectPass1Shader FirstPassShader;
typedef Shaders::ObjectPass2Shader SecondPassShader;
typedef ShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatDefault List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_STANDARD;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_SOLID;
static const enum InstanceType Instance = InstanceTypeDualTex;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct DefaultMaterial
// ----------------------------------------------------------------------------
struct AlphaRef
{
typedef InstancedObjectRefPass1Shader InstancedFirstPassShader;
typedef InstancedObjectRefPass2Shader InstancedSecondPassShader;
typedef InstancedRefShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef ObjectRefPass1Shader FirstPassShader;
typedef ObjectRefPass2Shader SecondPassShader;
typedef RefShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatAlphaRef List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_STANDARD;
static const enum Material::ShaderType MaterialType = Material::SHADERTYPE_ALPHA_TEST;
static const enum InstanceType Instance = InstanceTypeDualTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t> SecondPassTextures;
static const STK::Tuple<size_t> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct AlphaRef
// ----------------------------------------------------------------------------
struct SphereMap
{
typedef InstancedObjectPass1Shader InstancedFirstPassShader;
typedef InstancedSphereMapShader InstancedSecondPassShader;
typedef InstancedShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef Shaders::ObjectPass1Shader FirstPassShader;
typedef SphereMapShader SecondPassShader;
typedef ShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatSphereMap List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_STANDARD;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_SPHERE_MAP;
static const enum InstanceType Instance = InstanceTypeDualTex;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct SphereMap
// ----------------------------------------------------------------------------
struct UnlitMat
{
typedef InstancedObjectRefPass1Shader InstancedFirstPassShader;
typedef InstancedObjectUnlitShader InstancedSecondPassShader;
typedef InstancedRefShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef ObjectRefPass1Shader FirstPassShader;
typedef ObjectUnlitShader SecondPassShader;
typedef RefShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatUnlit List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_STANDARD;
static const enum Material::ShaderType MaterialType =
Material::SHADERTYPE_SOLID_UNLIT;
static const enum InstanceType Instance = InstanceTypeDualTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t> SecondPassTextures;
static const STK::Tuple<size_t> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct UnlitMat
// ----------------------------------------------------------------------------
struct GrassMat
{
typedef InstancedGrassPass1Shader InstancedFirstPassShader;
typedef InstancedGrassPass2Shader InstancedSecondPassShader;
typedef InstancedGrassShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef GrassPass1Shader FirstPassShader;
typedef GrassPass2Shader SecondPassShader;
typedef GrassShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatGrass List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_STANDARD;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_VEGETATION;
static const enum InstanceType Instance = InstanceTypeDualTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t> SecondPassTextures;
static const STK::Tuple<size_t> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // GrassMat
// ----------------------------------------------------------------------------
struct NormalMat
{
typedef InstancedNormalMapShader InstancedFirstPassShader;
typedef InstancedObjectPass2Shader InstancedSecondPassShader;
typedef InstancedShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef NormalMapShader FirstPassShader;
typedef Shaders::ObjectPass2Shader SecondPassShader;
typedef ShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatNormalMap List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_TANGENTS;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_NORMAL_MAP;
static const enum InstanceType Instance = InstanceTypeThreeTex;
static const STK::Tuple<size_t, size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // NormalMat
// ----------------------------------------------------------------------------
struct DetailMat
{
typedef InstancedObjectPass1Shader InstancedFirstPassShader;
typedef InstancedDetailedObjectPass2Shader InstancedSecondPassShader;
typedef InstancedShadowShader InstancedShadowPassShader;
typedef CInstancedRSMShader InstancedRSMShader;
typedef Shaders::ObjectPass1Shader FirstPassShader;
typedef DetailedObjectPass2Shader SecondPassShader;
typedef ShadowShader ShadowPassShader;
typedef CRSMShader RSMShader;
typedef ListMatDetails List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_2TCOORDS;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_DETAIL_MAP;
static const enum InstanceType Instance = InstanceTypeThreeTex;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // DetailMat
// ----------------------------------------------------------------------------
struct SplattingMat
{
typedef InstancedObjectPass1Shader InstancedFirstPassShader;
//TODO: InstancedSecondPassShader
typedef InstancedShadowShader InstancedShadowPassShader;
//TODO InstancedRSMShader
typedef Shaders::ObjectPass1Shader FirstPassShader;
typedef SplattingShader SecondPassShader;
typedef ShadowShader ShadowPassShader;
typedef SplattingRSMShader RSMShader;
typedef ListMatSplatting List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_2TCOORDS;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_SPLATTING;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t, size_t, size_t, size_t, size_t> RSMTextures;
}; // SplattingMat
#endif //HEADER_MATERIAL_TYPE_HPP

View File

@ -15,19 +15,21 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#include "post_processing.hpp"
#include "graphics/post_processing.hpp"
#include "config/user_config.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/camera.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/mlaa_areamap.hpp"
#include "graphics/rtts.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/weather.hpp"
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
@ -221,10 +223,11 @@ public:
1, "depth", ST_BILINEAR_CLAMPED_FILTERED);
} // Gaussian17TapHShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &fb, int width, int height)
void render(const FrameBuffer &fb, const FrameBuffer &linear_depth,
int width, int height)
{
setTextureUnits(fb.getRTT()[0],
irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0] );
linear_depth.getRTT()[0] );
drawFullScreenEffect(core::vector2df(1.0f/width, 1.0f/height));
} // render
@ -249,13 +252,14 @@ public:
} // ComputeGaussian17TapHShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &fb, const FrameBuffer &auxiliary,
const FrameBuffer &linear_depth,
int width, int height)
{
#if !defined(USE_GLES2)
use();
glBindSampler(m_dest_tu, 0);
setTextureUnits(fb.getRTT()[0],
irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0]);
linear_depth.getRTT()[0]);
glBindImageTexture(m_dest_tu, auxiliary.getRTT()[0], 0, false,
0, GL_WRITE_ONLY, GL_R16F);
setUniforms(core::vector2df(1.0f/width, 1.0f/height));
@ -280,10 +284,11 @@ public:
1, "depth", ST_BILINEAR_CLAMPED_FILTERED);
} // Gaussian17TapVShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &auxiliary, int width, int height)
void render(const FrameBuffer &auxiliary, const FrameBuffer &linear_depth,
int width, int height)
{
setTextureUnits(auxiliary.getRTT()[0],
irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0]);
linear_depth.getRTT()[0]);
drawFullScreenEffect(core::vector2df(1.0f/width, 1.0f/height));
} // render
@ -309,6 +314,7 @@ public:
} // ComputeGaussian17TapVShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &auxiliary, const FrameBuffer &fb,
const FrameBuffer &linear_depth,
int width, int height)
{
#if !defined(USE_GLES2)
@ -316,7 +322,7 @@ public:
use();
glBindSampler(m_dest_tu, 0);
setTextureUnits(auxiliary.getRTT()[0],
irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0]);
linear_depth.getRTT()[0]);
glBindImageTexture(m_dest_tu, fb.getRTT()[0], 0, false, 0,
GL_WRITE_ONLY, GL_R16F);
setUniforms(core::vector2df(1.0f/width, 1.0f/height));
@ -365,11 +371,13 @@ public:
3, "tex_dust", ST_BILINEAR_FILTERED);
} // BloomBlendShader
// ------------------------------------------------------------------------
void render()
void render(GLuint render_target_bloom_128,
GLuint render_target_bloom_256,
GLuint render_target_bloom_512)
{
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_BLOOM_128),
irr_driver->getRenderTargetTexture(RTT_BLOOM_256),
irr_driver->getRenderTargetTexture(RTT_BLOOM_512),
setTextureUnits(render_target_bloom_128,
render_target_bloom_256,
render_target_bloom_512,
getTextureGLuint(lensDustTex));
drawFullScreenEffect();
} // render
@ -390,11 +398,13 @@ public:
2, "tex_512", ST_BILINEAR_FILTERED);
} // LensBlendShader
// ------------------------------------------------------------------------
void render()
void render(GLuint render_target_lens_128,
GLuint render_target_lens_256,
GLuint render_target_lens_512)
{
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_LENS_128),
irr_driver->getRenderTargetTexture(RTT_LENS_256),
irr_driver->getRenderTargetTexture(RTT_LENS_512));
setTextureUnits(render_target_lens_128,
render_target_lens_256,
render_target_lens_512);
drawFullScreenEffect();
} // render
@ -435,43 +445,15 @@ public:
1, "dtex", ST_NEAREST_FILTERED);
} // DepthOfFieldShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &fb, GLuint rtt)
void render(const FrameBuffer &framebuffer, GLuint color_texture, GLuint depth_stencil_texture)
{
fb.bind();
setTextureUnits(rtt, irr_driver->getDepthStencilTexture());
framebuffer.bind();
setTextureUnits(color_texture, depth_stencil_texture);
drawFullScreenEffect();
} // render
}; // DepthOfFieldShader
// ============================================================================
class IBLShader : public TextureShader<IBLShader, 3>
{
public:
IBLShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "IBL.frag");
assignUniforms();
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
2, "probe", ST_TRILINEAR_CUBEMAP);
} // IBLShader
}; // IBLShader
// ============================================================================
class DegradedIBLShader : public TextureShader<DegradedIBLShader, 1>
{
public:
DegradedIBLShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "degraded_ibl.frag");
assignUniforms();
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED);
} // DegradedIBLShader
}; // DegradedIBLShader
// ============================================================================
class RHDebug : public Shader<RHDebug, core::matrix4, core::vector3df>
{
@ -491,39 +473,6 @@ public:
} // RHDebug
}; // RHDebug
// ============================================================================
class GlobalIlluminationReconstructionShader
: public TextureShader<GlobalIlluminationReconstructionShader, 5,
core::matrix4, core::matrix4, core::vector3df >
{
public:
GlobalIlluminationReconstructionShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "gi.frag");
assignUniforms("rh_matrix", "inv_rh_matrix", "extents");
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED,
2, "SHR", ST_VOLUME_LINEAR_FILTERED,
3, "SHG", ST_VOLUME_LINEAR_FILTERED,
4, "SHB", ST_VOLUME_LINEAR_FILTERED);
} // GlobalIlluminationReconstructionShader
// ------------------------------------------------------------------------
void render(const core::matrix4 &rh_matrix,
const core::vector3df &rh_extend, const FrameBuffer &fb)
{
core::matrix4 inv_rh_matrix;
rh_matrix.getInverse(inv_rh_matrix);
glDisable(GL_DEPTH_TEST);
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture(),
fb.getRTT()[0], fb.getRTT()[1], fb.getRTT()[2]);
drawFullScreenEffect(rh_matrix, inv_rh_matrix, rh_extend);
} // render
}; // GlobalIlluminationReconstructionShader
// ============================================================================
class PassThroughShader : public TextureShader<PassThroughShader, 1, int, int>
{
@ -586,9 +535,9 @@ public:
assignSamplerNames(0, "texture", ST_BILINEAR_FILTERED);
} // LinearizeDepthShader
// ------------------------------------------------------------------------
void render()
void render(GLuint depth_stencil_texture)
{
setTextureUnits(irr_driver->getDepthStencilTexture());
setTextureUnits(depth_stencil_texture);
scene::ICameraSceneNode *c = irr_driver->getSceneManager()->getActiveCamera();
drawFullScreenEffect(c->getNearValue(), c->getFarValue() );
@ -634,9 +583,9 @@ public:
assignSamplerNames(0, "dtex", ST_SEMI_TRILINEAR);
} // SSAOShader
// ------------------------------------------------------------------------
void render()
void render(GLuint render_target_linear_depth)
{
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_LINEAR_DEPTH));
setTextureUnits(render_target_linear_depth);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenEffect(irr_driver->getSSAORadius(),
@ -662,9 +611,9 @@ public:
1, "dtex", ST_NEAREST_FILTERED);
} // MotionBlurShader
// ------------------------------------------------------------------------
void render(const FrameBuffer &fb, float boost_time)
void render(const FrameBuffer &fb, float boost_time, GLuint depth_stencil_texture)
{
setTextureUnits(fb.getRTT()[0], irr_driver->getDepthStencilTexture());
setTextureUnits(fb.getRTT()[0], depth_stencil_texture);
Camera *cam = Camera::getActiveCamera();
// Todo : use a previousPVMatrix per cam, not global
drawFullScreenEffect(cam->getPreviousPVMatrix(),
@ -726,10 +675,10 @@ public:
assignSamplerNames(0, "colorMapG", ST_NEAREST_FILTERED);
} // MLAAColorEdgeDetectionSHader
// ------------------------------------------------------------------------
void render(const core::vector2df &pixel_size)
void render(const core::vector2df &pixel_size, GLuint rtt_mlaa_colors)
{
use();
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_MLAA_COLORS));
setTextureUnits(rtt_mlaa_colors);
drawFullScreenEffect(pixel_size);
} // render
}; // MLAAColorEdgeDetectionSHader
@ -749,10 +698,12 @@ public:
1, "areaMap", ST_NEAREST_FILTERED);
} // MLAABlendWeightSHader
// ------------------------------------------------------------------------
void render(video::ITexture *area_map, const core::vector2df &pixel_size)
void render(video::ITexture *area_map,
const core::vector2df &pixel_size,
GLuint rtt_mlaa_tmp)
{
use();
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_MLAA_TMP),
setTextureUnits(rtt_mlaa_tmp,
getTextureGLuint(area_map));
drawFullScreenEffect(pixel_size);
@ -773,44 +724,18 @@ public:
1, "colorMap", ST_NEAREST_FILTERED);
} // MLAAGatherSHader
// ------------------------------------------------------------------------
void render(const core::vector2df &pixel_size)
void render(const core::vector2df &pixel_size,
GLuint rtt_mlaa_blend,
GLuint rtt_mlaa_tmp)
{
use();
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_MLAA_BLEND),
irr_driver->getRenderTargetTexture(RTT_MLAA_TMP));
setTextureUnits(rtt_mlaa_blend,
rtt_mlaa_tmp);
drawFullScreenEffect(pixel_size);
} // render
}; // MLAAGatherSHader
// ============================================================================
class SunLightShader : public TextureShader<SunLightShader, 2,
core::vector3df, video::SColorf>
{
public:
SunLightShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
GL_FRAGMENT_SHADER, "sunlight.frag");
assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED,
1, "dtex", ST_NEAREST_FILTERED);
assignUniforms("direction", "col");
} // SunLightShader
// ------------------------------------------------------------------------
void render(const core::vector3df &direction, const video::SColorf &col)
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture());
drawFullScreenEffect(direction, col);
} // render
}; // SunLightShader
// ============================================================================
class LightningShader : public TextureShader<LightningShader, 1,
core::vector3df>
@ -999,48 +924,11 @@ void PostProcessing::update(float dt)
} // update
// ----------------------------------------------------------------------------
static void renderBloom(GLuint in)
void PostProcessing::renderBloom(GLuint in)
{
BloomShader::getInstance()->render(in);
} // renderBloom
// ----------------------------------------------------------------------------
void PostProcessing::renderEnvMap(GLuint skybox)
{
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
if (UserConfigParams::m_degraded_IBL)
{
DegradedIBLShader::getInstance()->use();
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
DegradedIBLShader::getInstance()
->setTextureUnits(irr_driver
->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH));
DegradedIBLShader::getInstance()->setUniforms();
}
else
{
IBLShader::getInstance()->use();
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
IBLShader::getInstance()->setTextureUnits(
irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH),
irr_driver->getDepthStencilTexture(), skybox);
IBLShader::getInstance()->setUniforms();
}
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
} // renderEnvMap
// ----------------------------------------------------------------------------
void PostProcessing::renderRHDebug(unsigned SHR, unsigned SHG, unsigned SHB,
const core::matrix4 &rh_matrix,
@ -1061,23 +949,6 @@ void PostProcessing::renderRHDebug(unsigned SHR, unsigned SHG, unsigned SHB,
#endif
} // renderRHDebug
// ----------------------------------------------------------------------------
void PostProcessing::renderGI(const core::matrix4 &rh_matrix,
const core::vector3df &rh_extend,
const FrameBuffer &fb)
{
GlobalIlluminationReconstructionShader::getInstance()->render(rh_matrix,
rh_extend,
fb);
} // renderGI
// ----------------------------------------------------------------------------
void PostProcessing::renderSunlight(const core::vector3df &direction,
const video::SColorf &col)
{
SunLightShader::getInstance()->render(direction, col);
} // renderSunlight
// ----------------------------------------------------------------------------
static std::vector<float> getGaussianWeight(float sigma, size_t count)
{
@ -1102,7 +973,7 @@ static std::vector<float> getGaussianWeight(float sigma, size_t count)
// ----------------------------------------------------------------------------
void PostProcessing::renderGaussian3Blur(const FrameBuffer &in_fbo,
const FrameBuffer &auxiliary)
const FrameBuffer &auxiliary) const
{
assert(in_fbo.getWidth() == auxiliary.getWidth() &&
in_fbo.getHeight() == auxiliary.getHeight());
@ -1121,9 +992,10 @@ void PostProcessing::renderGaussian3Blur(const FrameBuffer &in_fbo,
} // renderGaussian3Blur
// ----------------------------------------------------------------------------
void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo,
void PostProcessing::renderGaussian6BlurLayer(const FrameBuffer &in_fbo,
const FrameBuffer &scalar_fbo,
size_t layer, float sigma_h,
float sigma_v)
float sigma_v) const
{
#if !defined(USE_GLES2)
GLuint layer_tex;
@ -1133,14 +1005,14 @@ void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo,
if (!CVS->supportsComputeShadersFiltering())
{
// Used as temp
irr_driver->getFBO(FBO_SCALAR_1024).bind();
scalar_fbo.bind();
Gaussian6VBlurShader::getInstance()
->render(layer_tex, UserConfigParams::m_shadows_resolution,
UserConfigParams::m_shadows_resolution, sigma_v);
in_fbo.bindLayer(layer);
Gaussian6HBlurShader::getInstance()
->render(irr_driver->getFBO(FBO_SCALAR_1024),
->render(scalar_fbo,
UserConfigParams::m_shadows_resolution,
UserConfigParams::m_shadows_resolution, sigma_h);
}
@ -1152,7 +1024,7 @@ void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo,
ComputeShadowBlurVShader::getInstance()->setTextureUnits(layer_tex);
glBindSampler(ComputeShadowBlurVShader::getInstance()->m_dest_tu, 0);
glBindImageTexture(ComputeShadowBlurVShader::getInstance()->m_dest_tu,
irr_driver->getFBO(FBO_SCALAR_1024).getRTT()[0], 0,
scalar_fbo.getRTT()[0], 0,
false, 0, GL_WRITE_ONLY, GL_R32F);
ComputeShadowBlurVShader::getInstance()->setUniforms
(core::vector2df(1.f / UserConfigParams::m_shadows_resolution,
@ -1166,7 +1038,7 @@ void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo,
| GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
ComputeShadowBlurHShader::getInstance()->use();
ComputeShadowBlurHShader::getInstance()
->setTextureUnits(irr_driver->getFBO(FBO_SCALAR_1024).getRTT()[0]);
->setTextureUnits(scalar_fbo.getRTT()[0]);
glBindSampler(ComputeShadowBlurHShader::getInstance()->m_dest_tu, 0);
glBindImageTexture(ComputeShadowBlurHShader::getInstance()->m_dest_tu,
layer_tex, 0, false, 0, GL_WRITE_ONLY, GL_R32F);
@ -1185,7 +1057,7 @@ void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo,
// ----------------------------------------------------------------------------
void PostProcessing::renderGaussian6Blur(const FrameBuffer &in_fbo,
const FrameBuffer &auxiliary, float sigma_v,
float sigma_h)
float sigma_h) const
{
assert(in_fbo.getWidth() == auxiliary.getWidth() &&
in_fbo.getHeight() == auxiliary.getHeight());
@ -1243,7 +1115,7 @@ void PostProcessing::renderGaussian6Blur(const FrameBuffer &in_fbo,
// ----------------------------------------------------------------------------
void PostProcessing::renderHorizontalBlur(const FrameBuffer &in_fbo,
const FrameBuffer &auxiliary)
const FrameBuffer &auxiliary) const
{
assert(in_fbo.getWidth() == auxiliary.getWidth() &&
in_fbo.getHeight() == auxiliary.getHeight());
@ -1259,7 +1131,8 @@ void PostProcessing::renderHorizontalBlur(const FrameBuffer &in_fbo,
// ----------------------------------------------------------------------------
void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
const FrameBuffer &auxiliary)
const FrameBuffer &auxiliary,
const FrameBuffer &linear_depth) const
{
assert(in_fbo.getWidth() == auxiliary.getWidth() &&
in_fbo.getHeight() == auxiliary.getHeight());
@ -1274,6 +1147,7 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
{
auxiliary.bind();
Gaussian17TapHShader::getInstance()->render(in_fbo,
linear_depth,
in_fbo.getWidth(),
in_fbo.getHeight());
}
@ -1281,6 +1155,7 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
{
ComputeGaussian17TapHShader::getInstance()->render(in_fbo,
auxiliary,
linear_depth,
in_fbo.getWidth(),
in_fbo.getHeight());
}
@ -1296,6 +1171,7 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
{
in_fbo.bind();
Gaussian17TapVShader::getInstance()->render(auxiliary,
linear_depth,
in_fbo.getWidth(),
in_fbo.getHeight());
}
@ -1303,6 +1179,7 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
{
ComputeGaussian17TapVShader::getInstance()->render(auxiliary,
in_fbo,
linear_depth,
in_fbo.getWidth(),
in_fbo.getHeight());
}
@ -1316,13 +1193,13 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
// ----------------------------------------------------------------------------
void PostProcessing::renderPassThrough(GLuint tex, unsigned width,
unsigned height)
unsigned height) const
{
PassThroughShader::getInstance()->render(tex, width, height);
} // renderPassThrough
// ----------------------------------------------------------------------------
void PostProcessing::renderTextureLayer(unsigned tex, unsigned layer)
void PostProcessing::renderTextureLayer(unsigned tex, unsigned layer) const
{
LayerPassThroughShader::getInstance()->use();
LayerPassThroughShader::getInstance()->bindVertexArray();
@ -1336,27 +1213,47 @@ void PostProcessing::renderTextureLayer(unsigned tex, unsigned layer)
} // renderTextureLayer
// ----------------------------------------------------------------------------
void PostProcessing::renderGlow(unsigned tex)
void PostProcessing::renderGlow(const FrameBuffer& glow_framebuffer,
const FrameBuffer& half_framebuffer,
const FrameBuffer& quarter_framebuffer,
const FrameBuffer& color_framebuffer ) const
{
GlowShader::getInstance()->render(tex);
// To half
FrameBuffer::Blit(glow_framebuffer, half_framebuffer, GL_COLOR_BUFFER_BIT, GL_LINEAR);
// To quarter
FrameBuffer::Blit(half_framebuffer, quarter_framebuffer, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glStencilFunc(GL_EQUAL, 0, ~0);
glEnable(GL_STENCIL_TEST);
color_framebuffer.bind();
GlowShader::getInstance()->render(quarter_framebuffer.getRTT()[0]);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
} // renderGlow
// ----------------------------------------------------------------------------
void PostProcessing::renderSSAO()
void PostProcessing::renderSSAO(const FrameBuffer& linear_depth_framebuffer,
const FrameBuffer& ssao_framebuffer,
GLuint depth_stencil_texture)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
// Generate linear depth buffer
irr_driver->getFBO(FBO_LINEAR_DEPTH).bind();
LinearizeDepthShader::getInstance()->render();
irr_driver->getFBO(FBO_SSAO).bind();
SSAOShader::getInstance()->render();
linear_depth_framebuffer.bind();
LinearizeDepthShader::getInstance()->render(depth_stencil_texture);
ssao_framebuffer.bind();
SSAOShader::getInstance()->render(linear_depth_framebuffer.getRTT()[0]);
} // renderSSAO
// ----------------------------------------------------------------------------
void PostProcessing::renderMotionBlur(unsigned , const FrameBuffer &in_fbo,
FrameBuffer &out_fbo)
FrameBuffer &out_fbo,
GLuint depth_stencil_texture)
{
MotionBlurProvider * const cb =
(MotionBlurProvider *)Shaders::getCallback(ES_MOTIONBLUR);
@ -1384,24 +1281,98 @@ void PostProcessing::renderMotionBlur(unsigned , const FrameBuffer &in_fbo,
glClear(GL_COLOR_BUFFER_BIT);
float boost_time = cb->getBoostTime(cam->getIndex()) * 10;
MotionBlurShader::getInstance()->render(in_fbo, boost_time);
MotionBlurShader::getInstance()->render(in_fbo, boost_time, depth_stencil_texture);
} // renderMotionBlur
// ----------------------------------------------------------------------------
static void renderDoF(const FrameBuffer &fbo, GLuint rtt)
void PostProcessing::renderDoF(const FrameBuffer &framebuffer, GLuint color_texture, GLuint depth_stencil_texture)
{
DepthOfFieldShader::getInstance()->render(fbo, rtt);
DepthOfFieldShader::getInstance()->render(framebuffer, color_texture, depth_stencil_texture);
} // renderDoF
// ----------------------------------------------------------------------------
void PostProcessing::applyMLAA()
void PostProcessing::renderGodRays(scene::ICameraSceneNode * const camnode,
const FrameBuffer &fbo,
const FrameBuffer &quarter1_fbo,
const FrameBuffer &quarter2_fbo)
{
Track* track = World::getWorld()->getTrack();
glEnable(GL_DEPTH_TEST);
// Grab the sky
fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
// irr_driver->renderSkybox(camnode);
// Set the sun's color
const SColor col = track->getGodRaysColor();
// The sun interposer
STKMeshSceneNode *sun = irr_driver->getSunInterposer();
sun->setGlowColors(col);
sun->setPosition(track->getGodRaysPosition());
sun->updateAbsolutePosition();
irr_driver->setPhase(GLOW_PASS);
sun->render();
glDisable(GL_DEPTH_TEST);
// Fade to quarter
quarter1_fbo.bind();
glViewport(0, 0, irr_driver->getActualScreenSize().Width / 4,
irr_driver->getActualScreenSize().Height / 4);
GodFadeShader::getInstance()->render(fbo.getRTT()[0], col);
// Blur
renderGaussian3Blur(quarter1_fbo, quarter2_fbo);
// Calculate the sun's position in texcoords
const core::vector3df pos = track->getGodRaysPosition();
float ndc[4];
core::matrix4 trans = camnode->getProjectionMatrix();
trans *= camnode->getViewMatrix();
trans.transformVect(ndc, pos);
const float texh =
m_vertices[0].v1.TCoords.Y - m_vertices[0].v0.TCoords.Y;
const float texw =
m_vertices[0].v3.TCoords.X - m_vertices[0].v0.TCoords.X;
const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw;
const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh;
// Rays please
quarter2_fbo.bind();
GodRayShader::getInstance()
->render(quarter1_fbo.getRTT()[0], core::vector2df(sunx, suny));
// Blur
renderGaussian3Blur(quarter2_fbo, quarter1_fbo);
// Blend
glEnable(GL_BLEND);
glBlendColor(0., 0., 0., track->getGodRaysOpacity());
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
fbo.bind();
renderPassThrough(quarter2_fbo.getRTT()[0], fbo.getWidth(), fbo.getHeight());
glDisable(GL_BLEND);
}
// ----------------------------------------------------------------------------
void PostProcessing::applyMLAA(const FrameBuffer& mlaa_tmp_framebuffer,
const FrameBuffer& mlaa_blend_framebuffer,
const FrameBuffer& mlaa_colors_framebuffer)
{
const core::vector2df &PIXEL_SIZE =
core::vector2df(1.0f / UserConfigParams::m_width,
1.0f / UserConfigParams::m_height);
irr_driver->getFBO(FBO_MLAA_TMP).bind();
mlaa_tmp_framebuffer.bind();
glEnable(GL_STENCIL_TEST);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@ -1409,24 +1380,25 @@ void PostProcessing::applyMLAA()
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// Pass 1: color edge detection
MLAAColorEdgeDetectionSHader::getInstance()->render(PIXEL_SIZE);
MLAAColorEdgeDetectionSHader::getInstance()->render(PIXEL_SIZE, mlaa_colors_framebuffer.getRTT()[0]);
glStencilFunc(GL_EQUAL, 1, ~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// Pass 2: blend weights
irr_driver->getFBO(FBO_MLAA_BLEND).bind();
mlaa_blend_framebuffer.bind();
glClear(GL_COLOR_BUFFER_BIT);
MLAABlendWeightSHader::getInstance()->render(m_areamap, PIXEL_SIZE);
MLAABlendWeightSHader::getInstance()->render(m_areamap, PIXEL_SIZE, mlaa_tmp_framebuffer.getRTT()[0]);
// Blit in to tmp1
FrameBuffer::Blit(irr_driver->getFBO(FBO_MLAA_COLORS),
irr_driver->getFBO(FBO_MLAA_TMP));
FrameBuffer::Blit(mlaa_colors_framebuffer,
mlaa_tmp_framebuffer);
// Pass 3: gather
irr_driver->getFBO(FBO_MLAA_COLORS).bind();
MLAAGatherSHader::getInstance()->render(PIXEL_SIZE);
mlaa_colors_framebuffer.bind();
MLAAGatherSHader::getInstance()
->render(PIXEL_SIZE, mlaa_blend_framebuffer.getRTT()[0], mlaa_tmp_framebuffer.getRTT()[0]);
// Done.
glDisable(GL_STENCIL_TEST);
@ -1447,10 +1419,11 @@ void PostProcessing::renderLightning(core::vector3df intensity)
// ----------------------------------------------------------------------------
/** Render the post-processed scene */
FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
bool isRace)
bool isRace,
RTT *rtts)
{
FrameBuffer *in_fbo = &irr_driver->getFBO(FBO_COLORS);
FrameBuffer *out_fbo = &irr_driver->getFBO(FBO_TMP1_WITH_DS);
FrameBuffer *in_fbo = &rtts->getFBO(FBO_COLORS);
FrameBuffer *out_fbo = &rtts->getFBO(FBO_TMP1_WITH_DS);
// Each effect uses these as named, and sets them up for the next effect.
// This allows chaining effects where some may be disabled.
@ -1462,97 +1435,28 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
World *world = World::getWorld();
Physics *physics = world ? world->getPhysics() : NULL;
if (isRace && UserConfigParams::m_dof && (physics == NULL || !physics->isDebug()))
{
PROFILER_PUSH_CPU_MARKER("- DoF", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_DOF));
renderDoF(*out_fbo, in_fbo->getRTT()[0]);
renderDoF(*out_fbo, in_fbo->getRTT()[0], rtts->getDepthStencilTexture());
std::swap(in_fbo, out_fbo);
PROFILER_POP_CPU_MARKER();
}
{
PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GODRAYS));
bool hasgodrays = false;
if (World::getWorld() != NULL)
hasgodrays = World::getWorld()->getTrack()->hasGodRays();
if (isRace && UserConfigParams::m_light_shaft && hasgodrays)
{
Track* track = World::getWorld()->getTrack();
glEnable(GL_DEPTH_TEST);
// Grab the sky
out_fbo->bind();
glClear(GL_COLOR_BUFFER_BIT);
// irr_driver->renderSkybox(camnode);
// Set the sun's color
const SColor col = track->getGodRaysColor();
// The sun interposer
STKMeshSceneNode *sun = irr_driver->getSunInterposer();
sun->setGlowColors(col);
sun->setPosition(track->getGodRaysPosition());
sun->updateAbsolutePosition();
irr_driver->setPhase(GLOW_PASS);
sun->render();
glDisable(GL_DEPTH_TEST);
// Fade to quarter
irr_driver->getFBO(FBO_QUARTER1).bind();
glViewport(0, 0, irr_driver->getActualScreenSize().Width / 4,
irr_driver->getActualScreenSize().Height / 4);
GodFadeShader::getInstance()->render(out_fbo->getRTT()[0], col);
// Blur
renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER1),
irr_driver->getFBO(FBO_QUARTER2));
// Calculate the sun's position in texcoords
const core::vector3df pos = track->getGodRaysPosition();
float ndc[4];
core::matrix4 trans = camnode->getProjectionMatrix();
trans *= camnode->getViewMatrix();
trans.transformVect(ndc, pos);
const float texh =
m_vertices[0].v1.TCoords.Y - m_vertices[0].v0.TCoords.Y;
const float texw =
m_vertices[0].v3.TCoords.X - m_vertices[0].v0.TCoords.X;
const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw;
const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh;
// Rays please
irr_driver->getFBO(FBO_QUARTER2).bind();
GodRayShader::getInstance()
->render(irr_driver->getRenderTargetTexture(RTT_QUARTER1),
core::vector2df(sunx, suny) );
// Blur
renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER2),
irr_driver->getFBO(FBO_QUARTER1));
// Blend
glEnable(GL_BLEND);
glBlendColor(0., 0., 0., track->getGodRaysOpacity());
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
in_fbo->bind();
renderPassThrough(irr_driver->getRenderTargetTexture(RTT_QUARTER2),
in_fbo->getWidth(), in_fbo->getHeight());
glDisable(GL_BLEND);
}
PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GODRAYS));
renderGodRays(camnode, *out_fbo, rtts->getFBO(FBO_QUARTER1), rtts->getFBO(FBO_QUARTER2));
PROFILER_POP_CPU_MARKER();
}
// Simulate camera defects from there
{
PROFILER_PUSH_CPU_MARKER("- Bloom", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_BLOOM));
@ -1562,47 +1466,48 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
glClear(GL_STENCIL_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
FrameBuffer::Blit(*in_fbo, irr_driver->getFBO(FBO_BLOOM_1024),
FrameBuffer::Blit(*in_fbo, rtts->getFBO(FBO_BLOOM_1024),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
irr_driver->getFBO(FBO_BLOOM_512).bind();
renderBloom(irr_driver->getRenderTargetTexture(RTT_BLOOM_1024));
rtts->getFBO(FBO_BLOOM_512).bind();
renderBloom(rtts->getRenderTarget(RTT_BLOOM_1024));
// Downsample
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512),
irr_driver->getFBO(FBO_BLOOM_256),
FrameBuffer::Blit(rtts->getFBO(FBO_BLOOM_512),
rtts->getFBO(FBO_BLOOM_256),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256),
irr_driver->getFBO(FBO_BLOOM_128),
FrameBuffer::Blit(rtts->getFBO(FBO_BLOOM_256),
rtts->getFBO(FBO_BLOOM_128),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
// Copy for lens flare
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512),
irr_driver->getFBO(FBO_LENS_512),
FrameBuffer::Blit(rtts->getFBO(FBO_BLOOM_512),
rtts->getFBO(FBO_LENS_512),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256),
irr_driver->getFBO(FBO_LENS_256),
FrameBuffer::Blit(rtts->getFBO(FBO_BLOOM_256),
rtts->getFBO(FBO_LENS_256),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_128),
irr_driver->getFBO(FBO_LENS_128),
FrameBuffer::Blit(rtts->getFBO(FBO_BLOOM_128),
rtts->getFBO(FBO_LENS_128),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
// Blur
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_512),
irr_driver->getFBO(FBO_TMP_512), 1., 1.);
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_256),
irr_driver->getFBO(FBO_TMP_256), 1., 1.);
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_128),
irr_driver->getFBO(FBO_TMP_128), 1., 1.);
renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_512),
irr_driver->getFBO(FBO_TMP_512));
renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_256),
irr_driver->getFBO(FBO_TMP_256));
renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_128),
irr_driver->getFBO(FBO_TMP_128));
renderGaussian6Blur(rtts->getFBO(FBO_BLOOM_512),
rtts->getFBO(FBO_TMP_512), 1., 1.);
renderGaussian6Blur(rtts->getFBO(FBO_BLOOM_256),
rtts->getFBO(FBO_TMP_256), 1., 1.);
renderGaussian6Blur(rtts->getFBO(FBO_BLOOM_128),
rtts->getFBO(FBO_TMP_128), 1., 1.);
renderHorizontalBlur(rtts->getFBO(FBO_LENS_512),
rtts->getFBO(FBO_TMP_512));
renderHorizontalBlur(rtts->getFBO(FBO_LENS_256),
rtts->getFBO(FBO_TMP_256));
renderHorizontalBlur(rtts->getFBO(FBO_LENS_128),
rtts->getFBO(FBO_TMP_128));
// Additively blend on top of tmp1
in_fbo->bind();
@ -1610,8 +1515,14 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
BloomBlendShader::getInstance()->render();
LensBlendShader::getInstance()->render();
BloomBlendShader::getInstance()
->render(rtts->getRenderTarget(RTT_BLOOM_128),
rtts->getRenderTarget(RTT_BLOOM_256),
rtts->getRenderTarget(RTT_BLOOM_512));
LensBlendShader::getInstance()
->render(rtts->getRenderTarget(RTT_LENS_128),
rtts->getRenderTarget(RTT_LENS_256),
rtts->getRenderTarget(RTT_LENS_512));
glDisable(GL_BLEND);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@ -1639,7 +1550,7 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
if (isRace && UserConfigParams::m_motionblur && World::getWorld() &&
cb->getBoostTime(Camera::getActiveCamera()->getIndex()) > 0.) // motion blur
{
renderMotionBlur(0, *in_fbo, *out_fbo);
renderMotionBlur(0, *in_fbo, *out_fbo, irr_driver->getDepthStencilTexture());
std::swap(in_fbo, out_fbo);
}
PROFILER_POP_CPU_MARKER();
@ -1662,21 +1573,23 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
}
// Workaround a bug with srgb fbo on sandy bridge windows
if (!CVS->isARBUniformBufferObjectUsable())
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
return in_fbo;
glEnable(GL_FRAMEBUFFER_SRGB);
irr_driver->getFBO(FBO_MLAA_COLORS).bind();
out_fbo = &rtts->getFBO(FBO_MLAA_COLORS);
out_fbo->bind();
renderPassThrough(in_fbo->getRTT()[0],
irr_driver->getFBO(FBO_MLAA_COLORS).getWidth(),
irr_driver->getFBO(FBO_MLAA_COLORS).getHeight());
out_fbo = &irr_driver->getFBO(FBO_MLAA_COLORS);
out_fbo->getWidth(),
out_fbo->getHeight());
if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter.
{
PROFILER_PUSH_CPU_MARKER("- MLAA", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MLAA));
applyMLAA();
applyMLAA(rtts->getFBO(FBO_MLAA_TMP),
rtts->getFBO(FBO_MLAA_BLEND),
*out_fbo);
PROFILER_POP_CPU_MARKER();
}
glDisable(GL_FRAMEBUFFER_SRGB);

View File

@ -18,19 +18,22 @@
#ifndef HEADER_POST_PROCESSING_HPP
#define HEADER_POST_PROCESSING_HPP
#include "IShaderConstantSetCallBack.h"
#include "S3DVertex.h"
#include "SMaterial.h"
#include "graphics/camera.hpp"
#include "graphics/gl_headers.hpp"
#include <IReferenceCounted.h>
#include <S3DVertex.h>
#include <SMaterial.h>
#include <vector>
class FrameBuffer;
#include <vector>
class RTT;
namespace irr
{
namespace video { class IVideoDriver; class ITexture; }
namespace scene { class ICameraSceneNode; }
}
using namespace irr;
/** \brief Handles post processing, eg motion blur
@ -74,44 +77,55 @@ public:
void begin();
void update(float dt);
/** Generate diffuse and specular map */
void renderSunlight(const core::vector3df &direction,
const video::SColorf &col);
void renderSSAO();
void renderEnvMap(unsigned skycubemap);
void renderBloom(GLuint in);
void renderSSAO(const FrameBuffer& linear_depth_framebuffer,
const FrameBuffer& ssao_framebuffer,
GLuint depth_stencil_texture);
void renderRHDebug(unsigned SHR, unsigned SHG, unsigned SHB,
const core::matrix4 &rh_matrix,
const core::vector3df &rh_extend);
void renderGI(const core::matrix4 &rh_matrix,
const core::vector3df &rh_extend,
const FrameBuffer &fb);
/** Blur the in texture */
void renderGaussian3Blur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary);
void renderGaussian3Blur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary) const;
void renderGaussian6Blur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary,
float sigmaV, float sigmaH);
void renderHorizontalBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary);
float sigmaV, float sigmaH) const;
void renderHorizontalBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary) const;
void renderGaussian6BlurLayer(FrameBuffer &in_fbo, size_t layer,
float sigmaH, float sigmaV);
void renderGaussian17TapBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary);
void renderGaussian6BlurLayer(const FrameBuffer &in_fbo, const FrameBuffer &scalar_fbo,
size_t layer, float sigmaH, float sigmaV) const;
void renderGaussian17TapBlur(const FrameBuffer &in_fbo,
const FrameBuffer &auxiliary,
const FrameBuffer &linear_depth) const;
/** Render tex. Used for blit/texture resize */
void renderPassThrough(unsigned tex, unsigned width, unsigned height);
void renderTextureLayer(unsigned tex, unsigned layer);
void applyMLAA();
void renderPassThrough(unsigned tex, unsigned width, unsigned height) const;
void renderTextureLayer(unsigned tex, unsigned layer) const;
void renderDoF(const FrameBuffer &framebuffer, GLuint color_texture, GLuint depth_stencil_texture);
void renderGodRays(scene::ICameraSceneNode * const camnode,
const FrameBuffer &in_fbo,
const FrameBuffer &quarter1_fbo,
const FrameBuffer &quarter2_fbo);
void applyMLAA(const FrameBuffer& mlaa_tmp_framebuffer,
const FrameBuffer& mlaa_blend_framebuffer,
const FrameBuffer& mlaa_colors_framebuffer);
void renderMotionBlur(unsigned cam, const FrameBuffer &in_fbo,
FrameBuffer &out_fbo);
void renderGlow(unsigned tex);
FrameBuffer &out_fbo,
GLuint depth_stencil_texture);
void renderGlow(const FrameBuffer& glow_framebuffer,
const FrameBuffer& half_framebuffer,
const FrameBuffer& quarter_framebuffer,
const FrameBuffer& color_framebuffer) const;
void renderLightning(core::vector3df intensity);
/** Render the post-processed scene */
FrameBuffer *render(scene::ICameraSceneNode * const camnode, bool isRace);
/** Use motion blur for a short time */
void giveBoost(unsigned int cam_index);
/** Render the post-processed scene */
FrameBuffer *render(scene::ICameraSceneNode * const camnode, bool isRace,
RTT *rtts);
}; // class PostProcessing
#endif // HEADER_POST_PROCESSING_HPP

View File

@ -1,732 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// 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/irr_driver.hpp"
#include "config/user_config.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/post_processing.hpp"
#include "graphics/referee.hpp"
#include "graphics/rtts.hpp"
#include "graphics/screen_quad.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/stk_scene_manager.hpp"
#include "items/item_manager.hpp"
#include "items/powerup_manager.hpp"
#include "modes/world.hpp"
#include "physics/physics.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
// ============================================================================
class InstancedColorizeShader : public Shader<InstancedColorizeShader>
{
public:
InstancedColorizeShader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "glow_object.vert",
GL_FRAGMENT_SHADER, "glow_object.frag");
assignUniforms();
} // InstancedColorizeShader
}; // InstancedColorizeShader
// ============================================================================
extern std::vector<float> BoundingBoxes;
void IrrDriver::renderGLSL(float dt)
{
BoundingBoxes.clear();
World *world = World::getWorld(); // Never NULL.
Track *track = world->getTrack();
for (unsigned i = 0; i < PowerupManager::POWERUP_MAX; i++)
{
scene::IMesh *mesh = powerup_manager->m_all_meshes[i];
if (!mesh)
continue;
for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++)
{
scene::IMeshBuffer *mb = mesh->getMeshBuffer(j);
if (!mb)
continue;
for (unsigned k = 0; k < 4; k++)
{
video::ITexture *tex = mb->getMaterial().getTexture(k);
if (!tex)
continue;
compressTexture(tex, true);
}
}
}
// Overrides
video::SOverrideMaterial &overridemat = m_video_driver->getOverrideMaterial();
overridemat.EnablePasses = scene::ESNRP_SOLID | scene::ESNRP_TRANSPARENT;
overridemat.EnableFlags = 0;
if (m_wireframe)
{
overridemat.Material.Wireframe = 1;
overridemat.EnableFlags |= video::EMF_WIREFRAME;
}
if (m_mipviz)
{
overridemat.Material.MaterialType = Shaders::getShader(ES_MIPVIZ);
overridemat.EnableFlags |= video::EMF_MATERIAL_TYPE;
overridemat.EnablePasses = scene::ESNRP_SOLID;
}
// Get a list of all glowing things. The driver's list contains the static ones,
// here we add items, as they may disappear each frame.
std::vector<GlowData> glows = m_glowing;
ItemManager * const items = ItemManager::get();
const u32 itemcount = items->getNumberOfItems();
u32 i;
for (i = 0; i < itemcount; i++)
{
Item * const item = items->getItem(i);
if (!item) continue;
const Item::ItemType type = item->getType();
if (type != Item::ITEM_NITRO_BIG && type != Item::ITEM_NITRO_SMALL &&
type != Item::ITEM_BONUS_BOX && type != Item::ITEM_BANANA && type != Item::ITEM_BUBBLEGUM)
continue;
LODNode * const lod = (LODNode *) item->getSceneNode();
if (!lod->isVisible()) continue;
const int level = lod->getLevel();
if (level < 0) continue;
scene::ISceneNode * const node = lod->getAllNodes()[level];
node->updateAbsolutePosition();
GlowData dat;
dat.node = node;
dat.r = 1.0f;
dat.g = 1.0f;
dat.b = 1.0f;
const video::SColorf &c = ItemManager::getGlowColor(type);
dat.r = c.getRed();
dat.g = c.getGreen();
dat.b = c.getBlue();
glows.push_back(dat);
}
// Start the RTT for post-processing.
// We do this before beginScene() because we want to capture the glClear()
// because of tracks that do not have skyboxes (generally add-on tracks)
m_post_processing->begin();
RaceGUIBase *rg = world->getRaceGUI();
if (rg) rg->update(dt);
if (!CVS->isDefferedEnabled())
{
SColor clearColor(0, 150, 150, 150);
if (World::getWorld() != NULL)
clearColor = World::getWorld()->getClearColor();
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(clearColor.getRed() / 255.f, clearColor.getGreen() / 255.f,
clearColor.getBlue() / 255.f, clearColor.getAlpha() / 255.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
for(unsigned int cam = 0; cam < Camera::getNumCameras(); cam++)
{
Camera * const camera = Camera::getCamera(cam);
scene::ICameraSceneNode * const camnode = camera->getCameraSceneNode();
std::ostringstream oss;
oss << "drawAll() for kart " << cam;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (cam+1)*60,
0x00, 0x00);
camera->activate(!CVS->isDefferedEnabled());
rg->preRenderCallback(camera); // adjusts start referee
m_scene_manager->setActiveCamera(camnode);
const core::recti &viewport = camera->getViewport();
if (World::getWorld() && World::getWorld()->getTrack()->hasShadows() && m_spherical_harmonics->has6Textures())
irr_driver->getSceneManager()->setAmbientLight(SColor(0, 0, 0, 0));
if (!CVS->isDefferedEnabled())
glEnable(GL_FRAMEBUFFER_SRGB);
PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0);
unsigned plc = updateLightsInfo(camnode, dt);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("UBO upload", 0x0, 0xFF, 0x0);
computeMatrixesAndCameras(camnode, viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
uploadLightingData();
PROFILER_POP_CPU_MARKER();
renderScene(camnode, plc, glows, dt, track->hasShadows(), false);
// Render bounding boxes
if (irr_driver->getBoundingBoxesViz())
{
Shaders::ColoredLine *line = Shaders::ColoredLine::getInstance();
line->use();
line->bindVertexArray();
line->bindBuffer();
line->setUniforms(SColor(255, 255, 0, 0));
const float *tmp = BoundingBoxes.data();
for (unsigned int i = 0; i < BoundingBoxes.size(); i += 1024 * 6)
{
unsigned count = MIN2((int)BoundingBoxes.size() - i, 1024 * 6);
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(float), &tmp[i]);
glDrawArrays(GL_LINES, 0, count / 3);
}
}
// Debug physic
// Note that drawAll must be called before rendering
// the bullet debug view, since otherwise the camera
// is not set up properly. This is only used for
// the bullet debug view.
if (UserConfigParams::m_artist_debug_mode)
World::getWorld()->getPhysics()->draw();
if (world != NULL && world->getPhysics() != NULL)
{
IrrDebugDrawer* debug_drawer = world->getPhysics()->getDebugDrawer();
if (debug_drawer != NULL && debug_drawer->debugEnabled())
{
const std::map<video::SColor, std::vector<float> >& lines = debug_drawer->getLines();
std::map<video::SColor, std::vector<float> >::const_iterator it;
Shaders::ColoredLine *line = Shaders::ColoredLine::getInstance();
line->use();
line->bindVertexArray();
line->bindBuffer();
for (it = lines.begin(); it != lines.end(); it++)
{
line->setUniforms(it->first);
const std::vector<float> &vertex = it->second;
const float *tmp = vertex.data();
for (unsigned int i = 0; i < vertex.size(); i += 1024 * 6)
{
unsigned count = MIN2((int)vertex.size() - i, 1024 * 6);
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(float), &tmp[i]);
glDrawArrays(GL_LINES, 0, count / 3);
}
}
glUseProgram(0);
glBindVertexArray(0);
}
}
// Render the post-processed scene
if (CVS->isDefferedEnabled())
{
bool isRace = StateManager::get()->getGameState() == GUIEngine::GAME;
FrameBuffer *fbo = m_post_processing->render(camnode, isRace);
// The viewport has been changed using glViewport function directly
// during scene rendering, but irrlicht thinks that nothing changed
// when single camera is used. In this case we set the viewport
// to whole screen manually.
glViewport(0, 0, irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height);
if (irr_driver->getNormals())
{
irr_driver->getFBO(FBO_NORMAL_AND_DEPTHS).BlitToDefault(
viewport.UpperLeftCorner.X,
irr_driver->getActualScreenSize().Height - viewport.LowerRightCorner.Y,
viewport.LowerRightCorner.X,
irr_driver->getActualScreenSize().Height - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getSSAOViz())
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(m_rtts->getFBO(FBO_HALF1_R).getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getRSM())
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(m_rtts->getRSM().getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getShadowViz())
{
getShadowMatrices()->renderShadowsDebug();
}
else
{
glEnable(GL_FRAMEBUFFER_SRGB);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(fbo->getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
glDisable(GL_FRAMEBUFFER_SRGB);
}
}
// Save projection-view matrix for the next frame
camera->setPreviousPVMatrix(m_ProjViewMatrix);
PROFILER_POP_CPU_MARKER();
} // for i<world->getNumKarts()
// Use full screen size
float tmp[2];
tmp[0] = float(m_actual_screen_size.Width);
tmp[1] = float(m_actual_screen_size.Height);
glBindBuffer(GL_UNIFORM_BUFFER,
SharedGPUObjects::getViewProjectionMatricesUBO());
glBufferSubData(GL_UNIFORM_BUFFER, (16 * 9) * sizeof(float),
2 * sizeof(float), tmp);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
// Set the viewport back to the full screen for race gui
m_video_driver->setViewPort(core::recti(0, 0,
irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height));
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "renderPlayerView() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), 0x00, 0x00, (i+1)*60);
rg->renderPlayerView(camera, dt);
PROFILER_POP_CPU_MARKER();
} // for i<getNumKarts
{
ScopedGPUTimer Timer(getGPUTimer(Q_GUI));
PROFILER_PUSH_CPU_MARKER("GUIEngine", 0x75, 0x75, 0x75);
// Either render the gui, or the global elements of the race gui.
GUIEngine::render(dt);
PROFILER_POP_CPU_MARKER();
}
// Render the profiler
if(UserConfigParams::m_profiler_enabled)
{
PROFILER_DRAW();
}
#ifdef DEBUG
drawDebugMeshes();
#endif
PROFILER_PUSH_CPU_MARKER("EndSccene", 0x45, 0x75, 0x45);
m_video_driver->endScene();
PROFILER_POP_CPU_MARKER();
getPostProcessing()->update(dt);
}
void IrrDriver::renderScene(scene::ICameraSceneNode * const camnode, unsigned pointlightcount, std::vector<GlowData>& glows, float dt, bool hasShadow, bool forceRTT)
{
glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO());
glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO());
m_scene_manager->setActiveCamera(camnode);
PROFILER_PUSH_CPU_MARKER("- Draw Call Generation", 0xFF, 0xFF, 0xFF);
PrepareDrawCalls(camnode);
PROFILER_POP_CPU_MARKER();
// Shadows
{
// To avoid wrong culling, use the largest view possible
m_scene_manager->setActiveCamera(getShadowMatrices()->getSunCam());
if (CVS->isDefferedEnabled() &&
CVS->isShadowEnabled() && hasShadow)
{
PROFILER_PUSH_CPU_MARKER("- Shadow", 0x30, 0x6F, 0x90);
renderShadows();
PROFILER_POP_CPU_MARKER();
if (CVS->isGlobalIlluminationEnabled())
{
PROFILER_PUSH_CPU_MARKER("- RSM", 0xFF, 0x0, 0xFF);
renderRSM();
PROFILER_POP_CPU_MARKER();
}
}
m_scene_manager->setActiveCamera(camnode);
}
PROFILER_PUSH_CPU_MARKER("- Solid Pass 1", 0xFF, 0x00, 0x00);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
if (CVS->isDefferedEnabled() || forceRTT)
{
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
glClearColor(0., 0., 0., 0.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
renderSolidFirstPass();
}
else
{
// We need a cleared depth buffer for some effect (eg particles depth blending)
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
glDisable(GL_FRAMEBUFFER_SRGB);
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
// Bind() modifies the viewport. In order not to affect anything else,
// the viewport is just reset here and not removed in Bind().
const core::recti &vp = Camera::getActiveCamera()->getViewport();
glViewport(vp.UpperLeftCorner.X,
irr_driver->getActualScreenSize().Height - vp.LowerRightCorner.Y,
vp.LowerRightCorner.X - vp.UpperLeftCorner.X,
vp.LowerRightCorner.Y - vp.UpperLeftCorner.Y);
glClear(GL_DEPTH_BUFFER_BIT);
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
glEnable(GL_FRAMEBUFFER_SRGB);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
PROFILER_POP_CPU_MARKER();
// Lights
{
PROFILER_PUSH_CPU_MARKER("- Light", 0x00, 0xFF, 0x00);
if (CVS->isDefferedEnabled())
renderLights(pointlightcount, hasShadow);
PROFILER_POP_CPU_MARKER();
}
// Handle SSAO
{
PROFILER_PUSH_CPU_MARKER("- SSAO", 0xFF, 0xFF, 0x00);
ScopedGPUTimer Timer(getGPUTimer(Q_SSAO));
if (UserConfigParams::m_ssao)
renderSSAO();
PROFILER_POP_CPU_MARKER();
}
PROFILER_PUSH_CPU_MARKER("- Solid Pass 2", 0x00, 0x00, 0xFF);
if (CVS->isDefferedEnabled() || forceRTT)
{
m_rtts->getFBO(FBO_COLORS).bind();
SColor clearColor(0, 150, 150, 150);
if (World::getWorld() != NULL)
clearColor = World::getWorld()->getClearColor();
glClearColor(clearColor.getRed() / 255.f, clearColor.getGreen() / 255.f,
clearColor.getBlue() / 255.f, clearColor.getAlpha() / 255.f);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(GL_FALSE);
}
renderSolidSecondPass();
PROFILER_POP_CPU_MARKER();
if (getNormals())
{
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
renderNormalsVisualisation();
m_rtts->getFBO(FBO_COLORS).bind();
}
// Render ambient scattering
if (CVS->isDefferedEnabled() && World::getWorld() != NULL &&
World::getWorld()->isFogEnabled())
{
PROFILER_PUSH_CPU_MARKER("- Ambient scatter", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(getGPUTimer(Q_FOG));
renderAmbientScatter();
PROFILER_POP_CPU_MARKER();
}
{
PROFILER_PUSH_CPU_MARKER("- Skybox", 0xFF, 0x00, 0xFF);
ScopedGPUTimer Timer(getGPUTimer(Q_SKYBOX));
renderSkybox(camnode);
PROFILER_POP_CPU_MARKER();
}
// Render discrete lights scattering
if (CVS->isDefferedEnabled() && World::getWorld() != NULL &&
World::getWorld()->isFogEnabled())
{
PROFILER_PUSH_CPU_MARKER("- PointLight Scatter", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(getGPUTimer(Q_FOG));
renderLightsScatter(pointlightcount);
PROFILER_POP_CPU_MARKER();
}
if (getRH())
{
glDisable(GL_BLEND);
m_rtts->getFBO(FBO_COLORS).bind();
m_post_processing->renderRHDebug(m_rtts->getRH().getRTT()[0],
m_rtts->getRH().getRTT()[1],
m_rtts->getRH().getRTT()[2],
getShadowMatrices()->getRHMatrix(),
getShadowMatrices()->getRHExtend());
}
if (getGI())
{
glDisable(GL_BLEND);
m_rtts->getFBO(FBO_COLORS).bind();
m_post_processing->renderGI(getShadowMatrices()->getRHMatrix(),
getShadowMatrices()->getRHExtend(),
m_rtts->getRH());
}
PROFILER_PUSH_CPU_MARKER("- Glow", 0xFF, 0xFF, 0x00);
// Render anything glowing.
if (!m_mipviz && !m_wireframe && UserConfigParams::m_glow)
{
ScopedGPUTimer Timer(getGPUTimer(Q_GLOW));
irr_driver->setPhase(GLOW_PASS);
renderGlow(glows);
} // end glow
PROFILER_POP_CPU_MARKER();
// Render transparent
{
PROFILER_PUSH_CPU_MARKER("- Transparent Pass", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(getGPUTimer(Q_TRANSPARENT));
renderTransparent();
PROFILER_POP_CPU_MARKER();
}
m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// Render particles
{
PROFILER_PUSH_CPU_MARKER("- Particles", 0xFF, 0xFF, 0x00);
ScopedGPUTimer Timer(getGPUTimer(Q_PARTICLES));
renderParticles();
PROFILER_POP_CPU_MARKER();
}
if (!CVS->isDefferedEnabled() && !forceRTT)
{
glDisable(GL_FRAMEBUFFER_SRGB);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
return;
}
// Ensure that no object will be drawn after that by using invalid pass
irr_driver->setPhase(PASS_COUNT);
}
// --------------------------------------------
void IrrDriver::renderFixed(float dt)
{
World *world = World::getWorld(); // Never NULL.
m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true,
world->getClearColor());
irr_driver->getVideoDriver()->enableMaterial2D();
RaceGUIBase *rg = world->getRaceGUI();
if (rg) rg->update(dt);
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "drawAll() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (i+1)*60,
0x00, 0x00);
camera->activate();
rg->preRenderCallback(camera); // adjusts start referee
m_renderpass = ~0;
m_scene_manager->drawAll();
PROFILER_POP_CPU_MARKER();
// Note that drawAll must be called before rendering
// the bullet debug view, since otherwise the camera
// is not set up properly. This is only used for
// the bullet debug view.
if (UserConfigParams::m_artist_debug_mode)
World::getWorld()->getPhysics()->draw();
} // for i<world->getNumKarts()
// Set the viewport back to the full screen for race gui
m_video_driver->setViewPort(core::recti(0, 0,
UserConfigParams::m_width,
UserConfigParams::m_height));
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "renderPlayerView() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), 0x00, 0x00, (i+1)*60);
rg->renderPlayerView(camera, dt);
PROFILER_POP_CPU_MARKER();
} // for i<getNumKarts
// Either render the gui, or the global elements of the race gui.
GUIEngine::render(dt);
// Render the profiler
if(UserConfigParams::m_profiler_enabled)
{
PROFILER_DRAW();
}
#ifdef DEBUG
drawDebugMeshes();
#endif
m_video_driver->endScene();
}
// ----------------------------------------------------------------------------
void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera)
{
if(m_skybox)
{
m_skybox->render(camera);
}
} // renderSkybox
// ----------------------------------------------------------------------------
void IrrDriver::renderParticles()
{
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
for (unsigned i = 0; i < ParticlesList::getInstance()->size(); ++i)
ParticlesList::getInstance()->at(i)->render();
// m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT_EFFECT);
}
// ----------------------------------------------------------------------------
void IrrDriver::renderGlow(std::vector<GlowData>& glows)
{
m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID);
m_rtts->getFBO(FBO_TMP1_WITH_DS).bind();
glClearStencil(0);
glClearColor(0, 0, 0, 0);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
const u32 glowcount = (int)glows.size();
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, ~0);
glEnable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
if (CVS->isARBBaseInstanceUsable())
glBindVertexArray(VAOManager::getInstance()->getVAO(EVT_STANDARD));
for (u32 i = 0; i < glowcount; i++)
{
const GlowData &dat = glows[i];
scene::ISceneNode * cur = dat.node;
STKMeshSceneNode *node = static_cast<STKMeshSceneNode *>(cur);
node->setGlowColors(SColor(0, (unsigned) (dat.b * 255.f), (unsigned)(dat.g * 255.f), (unsigned)(dat.r * 255.f)));
if (!CVS->supportsIndirectInstancingRendering())
node->render();
}
if (CVS->supportsIndirectInstancingRendering() && CVS->isARBExplicitAttribLocationUsable())
{
#if !defined(USE_GLES2)
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, GlowPassCmd::getInstance()->drawindirectcmd);
InstancedColorizeShader::getInstance()->use();
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeGlow));
if (CVS->isAZDOEnabled())
{
if (GlowPassCmd::getInstance()->Size)
{
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT,
(const void*)(GlowPassCmd::getInstance()->Offset * sizeof(DrawElementsIndirectCommand)),
(int)GlowPassCmd::getInstance()->Size,
sizeof(DrawElementsIndirectCommand));
}
}
else
{
for (unsigned i = 0; i < ListInstancedGlow::getInstance()->size(); i++)
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((GlowPassCmd::getInstance()->Offset + i) * sizeof(DrawElementsIndirectCommand)));
}
#endif
}
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
// To half
FrameBuffer::Blit(irr_driver->getFBO(FBO_TMP1_WITH_DS), irr_driver->getFBO(FBO_HALF1), GL_COLOR_BUFFER_BIT, GL_LINEAR);
// To quarter
FrameBuffer::Blit(irr_driver->getFBO(FBO_HALF1), irr_driver->getFBO(FBO_QUARTER1), GL_COLOR_BUFFER_BIT, GL_LINEAR);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glStencilFunc(GL_EQUAL, 0, ~0);
glEnable(GL_STENCIL_TEST);
m_rtts->getFBO(FBO_COLORS).bind();
m_post_processing->renderGlow(m_rtts->getRenderTarget(RTT_QUARTER1));
glDisable(GL_STENCIL_TEST);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,153 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014-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.
#include "graphics/render_target.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/rtts.hpp"
#include "graphics/shader_based_renderer.hpp"
//-----------------------------------------------------------------------------
GL1RenderTarget::GL1RenderTarget(const irr::core::dimension2du &dimension,
const std::string &name)
{
m_render_target_texture =
irr_driver->getVideoDriver()->addRenderTargetTexture(dimension,
name.c_str(),
video::ECF_A8R8G8B8);
if (m_render_target_texture != NULL)
{
irr_driver->getVideoDriver()->setRenderTarget(m_render_target_texture);
}
m_rtt_main_node = NULL;
}
GL1RenderTarget::~GL1RenderTarget()
{
/*assert(m_old_rtt_mini_map->getReferenceCount() == 1);
irr_driver->removeTexture(m_old_rtt_mini_map);
m_old_rtt_mini_map = NULL;*/
}
//-----------------------------------------------------------------------------
irr::core::dimension2du GL1RenderTarget::getTextureSize() const
{
if (m_render_target_texture == NULL) return irr::core::dimension2du(0, 0);
return m_render_target_texture->getSize();
}
//-----------------------------------------------------------------------------
void GL1RenderTarget::renderToTexture(irr::scene::ICameraSceneNode* camera, float dt)
{
// m_render_target_texture will be NULL if RTT doesn't work on this computer
if (m_render_target_texture == NULL)
{
Log::error("GL1RenderTarget", "Cannot render to texture.");
return;
}
irr_driver->getVideoDriver()->setRenderTarget(m_render_target_texture);
irr::video::SOverrideMaterial &overridemat = irr_driver->getVideoDriver()->getOverrideMaterial();
overridemat.EnablePasses = scene::ESNRP_SOLID;
overridemat.EnableFlags = video::EMF_MATERIAL_TYPE;
overridemat.Material.MaterialType = video::EMT_SOLID;
if (m_rtt_main_node == NULL)
{
irr_driver->getSceneManager()->drawAll();
}
else
{
m_rtt_main_node->setVisible(true);
irr_driver->getSceneManager()->drawAll();
m_rtt_main_node->setVisible(false);
}
overridemat.EnablePasses = 0;
irr_driver->getVideoDriver()->setRenderTarget(0, false, false);
}
//-----------------------------------------------------------------------------
void GL1RenderTarget::draw2DImage(const irr::core::rect<s32>& dest_rect,
const irr::core::rect<s32>* clip_rect,
const irr::video::SColor &colors,
bool use_alpha_channel_of_texture) const
{
if (m_render_target_texture == NULL) return;
irr::core::rect<s32> source_rect(irr::core::position2di(0, 0),
m_render_target_texture->getSize());
::draw2DImage(m_render_target_texture, dest_rect, source_rect,
clip_rect, colors, use_alpha_channel_of_texture);
}
//-----------------------------------------------------------------------------
GL3RenderTarget::GL3RenderTarget(const irr::core::dimension2du &dimension,
const std::string &name,
ShaderBasedRenderer *renderer)
: m_renderer(renderer), m_name(name)
{
m_rtts = new RTT(dimension.Width, dimension.Height);
m_frame_buffer = NULL;
} // GL3RenderTarget
//-----------------------------------------------------------------------------
GL3RenderTarget::~GL3RenderTarget()
{
delete m_rtts;
m_renderer->setRTT(NULL);
} // ~GL3RenderTarget
//-----------------------------------------------------------------------------
void GL3RenderTarget::renderToTexture(irr::scene::ICameraSceneNode* camera,
float dt)
{
m_frame_buffer = NULL;
m_renderer->setRTT(m_rtts);
m_renderer->renderToTexture(this, camera, dt);
} // renderToTexture
//-----------------------------------------------------------------------------
irr::core::dimension2du GL3RenderTarget::getTextureSize() const
{
return irr::core::dimension2du(m_frame_buffer->getWidth(),
m_frame_buffer->getHeight());
} // getTextureSize
//-----------------------------------------------------------------------------
void GL3RenderTarget::draw2DImage(const irr::core::rect<s32>& dest_rect,
const irr::core::rect<s32>* clip_rect,
const irr::video::SColor &colors,
bool use_alpha_channel_of_texture) const
{
assert(m_frame_buffer != NULL);
irr::core::rect<s32> source_rect(0, 0, m_frame_buffer->getWidth(),
m_frame_buffer->getHeight());
glEnable(GL_FRAMEBUFFER_SRGB);
draw2DImageFromRTT(m_frame_buffer->getRTT()[0],
m_frame_buffer->getWidth(), m_frame_buffer->getHeight(),
dest_rect, source_rect,
clip_rect, colors, use_alpha_channel_of_texture);
glDisable(GL_FRAMEBUFFER_SRGB);
} // draw2DImage

View File

@ -0,0 +1,90 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014-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_RENDER_TARGET_HPP
#define HEADER_RENDER_TARGET_HPP
#include <irrlicht.h>
#include <string>
class FrameBuffer;
class RTT;
class ShaderBasedRenderer;
class RenderTarget
{
public:
virtual ~RenderTarget() {}
virtual irr::core::dimension2du getTextureSize() const = 0;
virtual void renderToTexture(irr::scene::ICameraSceneNode* camera, float dt) = 0;
virtual void draw2DImage(const irr::core::rect<irr::s32>& dest_rect,
const irr::core::rect<irr::s32>* clip_rect,
const irr::video::SColor &colors,
bool use_alpha_channel_of_texture) const = 0;
};
class GL1RenderTarget: public RenderTarget
{
private:
/** A pointer to texture on which a scene is rendered. Only used
* in between beginRenderToTexture() and endRenderToTexture calls. */
irr::video::ITexture *m_render_target_texture;
/** Main node of the RTT scene */
irr::scene::ISceneNode *m_rtt_main_node;
public:
GL1RenderTarget(const irr::core::dimension2du &dimension,
const std::string &name);
~GL1RenderTarget();
irr::core::dimension2du getTextureSize() const;
void renderToTexture(irr::scene::ICameraSceneNode* camera, float dt);
void draw2DImage(const irr::core::rect<irr::s32>& dest_rect,
const irr::core::rect<irr::s32>* clip_rect,
const irr::video::SColor &colors,
bool use_alpha_channel_of_texture) const;
};
class GL3RenderTarget: public RenderTarget
{
private:
ShaderBasedRenderer* m_renderer;
std::string m_name;
RTT* m_rtts;
FrameBuffer* m_frame_buffer;
public:
GL3RenderTarget(const irr::core::dimension2du &dimension,
const std::string &name,
ShaderBasedRenderer *renderer);
~GL3RenderTarget();
void draw2DImage(const irr::core::rect<irr::s32>& dest_rect,
const irr::core::rect<irr::s32>* clip_rect,
const irr::video::SColor &colors,
bool use_alpha_channel_of_texture) const;
irr::core::dimension2du getTextureSize() const;
void renderToTexture(irr::scene::ICameraSceneNode* camera, float dt);
void setFrameBuffer(FrameBuffer* fb) { m_frame_buffer = fb; }
};
#endif

View File

@ -16,13 +16,11 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/rtts.hpp"
#include "central_settings.hpp"
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/post_processing.hpp"
#include "utils/log.hpp"
#include <ISceneManager.h>
static GLuint generateRTT3D(GLenum target, size_t w, size_t h, size_t d, GLint internalFormat, GLint format, GLint type, unsigned mipmaplevel = 1)
{
@ -297,6 +295,7 @@ RTT::RTT(size_t width, size_t height)
RTT::~RTT()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteTextures(RTT_COUNT, RenderTargetTextures);
glDeleteTextures(1, &DepthStencilTexture);
if (CVS->isShadowEnabled())
@ -318,33 +317,3 @@ RTT::~RTT()
}
}
void RTT::prepareRender(scene::ICameraSceneNode* camera)
{
irr_driver->setRTT(this);
irr_driver->getSceneManager()->setActiveCamera(camera);
}
FrameBuffer* RTT::render(scene::ICameraSceneNode* camera, float dt)
{
irr_driver->setRTT(this);
irr_driver->getSceneManager()->setActiveCamera(camera);
std::vector<IrrDriver::GlowData> glows;
irr_driver->computeMatrixesAndCameras(camera, m_width, m_height);
unsigned plc = irr_driver->updateLightsInfo(camera, dt);
irr_driver->uploadLightingData();
irr_driver->renderScene(camera, plc, glows, dt, false, true);
FrameBuffer* frame_buffer = irr_driver->getPostProcessing()->render(camera, false);
// reset
glViewport(0, 0,
irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height);
irr_driver->setRTT(NULL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
irr_driver->getSceneManager()->setActiveCamera(NULL);
return frame_buffer;
}

View File

@ -18,9 +18,9 @@
#ifndef HEADER_RTTS_HPP
#define HEADER_RTTS_HPP
#include "graphics/irr_driver.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/leak_check.hpp"
#include <stddef.h>
class FrameBuffer;
@ -35,6 +35,110 @@ namespace irr {
using irr::video::ITexture;
enum TypeFBO
{
FBO_SSAO,
FBO_NORMAL_AND_DEPTHS,
FBO_COMBINED_DIFFUSE_SPECULAR,
FBO_COLORS,
FBO_DIFFUSE,
FBO_SPECULAR,
FBO_MLAA_COLORS,
FBO_MLAA_BLEND,
FBO_MLAA_TMP,
FBO_TMP1_WITH_DS,
FBO_TMP2_WITH_DS,
FBO_TMP4,
FBO_LINEAR_DEPTH,
FBO_HALF1,
FBO_HALF1_R,
FBO_HALF2,
FBO_HALF2_R,
FBO_QUARTER1,
FBO_QUARTER2,
FBO_EIGHTH1,
FBO_EIGHTH2,
FBO_DISPLACE,
FBO_BLOOM_1024,
#if !defined(USE_GLES2)
FBO_SCALAR_1024,
#endif
FBO_BLOOM_512,
FBO_TMP_512,
FBO_LENS_512,
FBO_BLOOM_256,
FBO_TMP_256,
FBO_LENS_256,
FBO_BLOOM_128,
FBO_TMP_128,
FBO_LENS_128,
FBO_COUNT
};
enum TypeRTT : unsigned int
{
RTT_TMP1 = 0,
RTT_TMP2,
RTT_TMP3,
RTT_TMP4,
RTT_LINEAR_DEPTH,
RTT_NORMAL_AND_DEPTH,
RTT_COLOR,
RTT_DIFFUSE,
RTT_SPECULAR,
RTT_HALF1,
RTT_HALF2,
RTT_HALF1_R,
RTT_HALF2_R,
RTT_QUARTER1,
RTT_QUARTER2,
// RTT_QUARTER3,
// RTT_QUARTER4,
RTT_EIGHTH1,
RTT_EIGHTH2,
// RTT_SIXTEENTH1,
// RTT_SIXTEENTH2,
RTT_SSAO,
// RTT_COLLAPSE,
// RTT_COLLAPSEH,
// RTT_COLLAPSEV,
// RTT_COLLAPSEH2,
// RTT_COLLAPSEV2,
// RTT_WARPH,
// RTT_WARPV,
// RTT_HALF_SOFT,
RTT_DISPLACE,
RTT_MLAA_COLORS,
RTT_MLAA_BLEND,
RTT_MLAA_TMP,
RTT_BLOOM_1024,
#if !defined(USE_GLES2)
RTT_SCALAR_1024,
#endif
RTT_BLOOM_512,
RTT_TMP_512,
RTT_LENS_512,
RTT_BLOOM_256,
RTT_TMP_256,
RTT_LENS_256,
RTT_BLOOM_128,
RTT_TMP_128,
RTT_LENS_128,
RTT_COUNT
};
class RTT
{
@ -42,25 +146,24 @@ public:
RTT(size_t width, size_t height);
~RTT();
FrameBuffer &getShadowFBO() { return *m_shadow_FBO; }
FrameBuffer &getRH() { return *m_RH_FBO; }
FrameBuffer &getRSM() { return *m_RSM; }
size_t getWidth () const { return m_width ; }
size_t getHeight() const { return m_height; }
FrameBuffer &getShadowFrameBuffer() { return *m_shadow_FBO; }
FrameBuffer &getRadianceHintFrameBuffer() { return *m_RH_FBO; }
FrameBuffer &getReflectiveShadowMapFrameBuffer() { return *m_RSM; }
unsigned getDepthStencilTexture() const { return DepthStencilTexture; }
unsigned getRenderTarget(enum TypeRTT target) const { return RenderTargetTextures[target]; }
FrameBuffer& getFBO(enum TypeFBO fbo) { return FrameBuffers[fbo]; }
FrameBuffer* render(irr::scene::ICameraSceneNode* camera, float dt);
void prepareRender(scene::ICameraSceneNode* camera);
private:
unsigned RenderTargetTextures[RTT_COUNT];
PtrVector<FrameBuffer> FrameBuffers;
unsigned DepthStencilTexture;
int m_width;
int m_height;
size_t m_width;
size_t m_height;
unsigned shadowColorTex, shadowDepthTex;
unsigned RSM_Color, RSM_Normal, RSM_Depth;

View File

@ -22,6 +22,7 @@
#include "graphics/gl_headers.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/spherical_harmonics.hpp"
#include "io/file_manager.hpp"
#include "utils/log.hpp"
@ -263,17 +264,16 @@ void ShaderBase::bypassUBO() const
glUniform2f(Screen, irr_driver->getCurrentScreenSize().X,
irr_driver->getCurrentScreenSize().Y);
const SHCoefficients* sh_coeff = irr_driver->getSHCoefficients();
GLint bLmn = glGetUniformLocation(m_program, "blueLmn[0]");
const float* blue_SH_coeff = irr_driver->getSphericalHarmonics()->getBlueSHCoeff();
glUniform1fv(bLmn, 9, blue_SH_coeff);
glUniform1fv(bLmn, 9, sh_coeff->blue_SH_coeff);
GLint gLmn = glGetUniformLocation(m_program, "greenLmn[0]");
const float* green_SH_coeff = irr_driver->getSphericalHarmonics()->getGreenSHCoeff();
glUniform1fv(gLmn, 9, green_SH_coeff);
glUniform1fv(gLmn, 9, sh_coeff->green_SH_coeff);
GLint rLmn = glGetUniformLocation(m_program, "redLmn[0]");
const float* red_SH_coeff = irr_driver->getSphericalHarmonics()->getRedSHCoeff();
glUniform1fv(rLmn, 9, red_SH_coeff);
glUniform1fv(rLmn, 9, sh_coeff->red_SH_coeff);
GLint sun_dir = glGetUniformLocation(m_program, "sun_direction");
const core::vector3df &sd = irr_driver->getSunDirection();

View File

@ -0,0 +1,975 @@
// 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.
#include "graphics/shader_based_renderer.hpp"
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/draw_policies.hpp"
#include "graphics/geometry_passes.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/post_processing.hpp"
#include "graphics/render_target.hpp"
#include "graphics/rtts.hpp"
#include "graphics/shaders.hpp"
#include "graphics/skybox.hpp"
#include "graphics/spherical_harmonics.hpp"
#include "graphics/stk_scene_manager.hpp"
#include "graphics/texture_manager.hpp"
#include "items/item_manager.hpp"
#include "items/powerup_manager.hpp"
#include "modes/world.hpp"
#include "physics/physics.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#include <algorithm>
extern std::vector<float> BoundingBoxes; //TODO: replace global variable by something cleaner
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::setRTT(RTT* rtts)
{
if (m_rtts != rtts && rtts != NULL)
{
// Update prefilled textures if new RTT is used
std::vector<GLuint> prefilled_textures =
createVector<GLuint>(rtts->getRenderTarget(RTT_DIFFUSE),
rtts->getRenderTarget(RTT_SPECULAR),
rtts->getRenderTarget(RTT_HALF1_R),
rtts->getDepthStencilTexture());
m_geometry_passes->setFirstPassRenderTargets(prefilled_textures);
m_rtts = rtts;
}
else if (rtts == NULL)
{
m_rtts = NULL;
}
} //setRTT
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::compressPowerUpTextures()
{
for (unsigned i = 0; i < PowerupManager::POWERUP_MAX; i++)
{
scene::IMesh *mesh = powerup_manager->m_all_meshes[i];
if (!mesh)
continue;
for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++)
{
scene::IMeshBuffer *mb = mesh->getMeshBuffer(j);
if (!mb)
continue;
for (unsigned k = 0; k < 4; k++)
{
video::ITexture *tex = mb->getMaterial().getTexture(k);
if (!tex)
continue;
compressTexture(tex, true);
}
}
}
} //compressPowerUpTextures
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::setOverrideMaterial()
{
video::SOverrideMaterial &overridemat = irr_driver->getVideoDriver()->getOverrideMaterial();
overridemat.EnablePasses = scene::ESNRP_SOLID | scene::ESNRP_TRANSPARENT;
overridemat.EnableFlags = 0;
if (irr_driver->getWireframe())
{
overridemat.Material.Wireframe = 1;
overridemat.EnableFlags |= video::EMF_WIREFRAME;
}
if (irr_driver->getMipViz())
{
overridemat.Material.MaterialType = Shaders::getShader(ES_MIPVIZ);
overridemat.EnableFlags |= video::EMF_MATERIAL_TYPE;
overridemat.EnablePasses = scene::ESNRP_SOLID;
}
} //setOverrideMaterial
// ----------------------------------------------------------------------------
/** Add glowing items, they may appear or disappear each frame. */
void ShaderBasedRenderer::addItemsInGlowingList()
{
ItemManager * const items = ItemManager::get();
const u32 itemcount = items->getNumberOfItems();
u32 i;
for (i = 0; i < itemcount; i++)
{
Item * const item = items->getItem(i);
if (!item) continue;
const Item::ItemType type = item->getType();
if (type != Item::ITEM_NITRO_BIG && type != Item::ITEM_NITRO_SMALL &&
type != Item::ITEM_BONUS_BOX && type != Item::ITEM_BANANA && type != Item::ITEM_BUBBLEGUM)
continue;
LODNode * const lod = (LODNode *) item->getSceneNode();
if (!lod->isVisible()) continue;
const int level = lod->getLevel();
if (level < 0) continue;
scene::ISceneNode * const node = lod->getAllNodes()[level];
node->updateAbsolutePosition();
GlowData dat;
dat.node = node;
dat.r = 1.0f;
dat.g = 1.0f;
dat.b = 1.0f;
const video::SColorf &c = ItemManager::getGlowColor(type);
dat.r = c.getRed();
dat.g = c.getGreen();
dat.b = c.getBlue();
STKMeshSceneNode *stk_node = static_cast<STKMeshSceneNode *>(node);
stk_node->setGlowColors(irr::video::SColor(0, (unsigned) (dat.r * 255.f), (unsigned)(dat.g * 255.f), (unsigned)(dat.b * 255.f)));
m_glowing.push_back(dat);
}
} //addItemsInGlowingList
// ----------------------------------------------------------------------------
/** Remove all non static glowing things */
void ShaderBasedRenderer::removeItemsInGlowingList()
{
while(m_glowing.size() > m_nb_static_glowing)
m_glowing.pop_back();
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::prepareForwardRenderer()
{
irr::video::SColor clearColor(0, 150, 150, 150);
if (World::getWorld() != NULL)
clearColor = World::getWorld()->getClearColor();
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(clearColor.getRed() / 255.f, clearColor.getGreen() / 255.f,
clearColor.getBlue() / 255.f, clearColor.getAlpha() / 255.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::updateLightsInfo(scene::ICameraSceneNode * const camnode,
float dt)
{
m_lighting_passes.updateLightsInfo(camnode, dt);
}
// ----------------------------------------------------------------------------
/** Upload lighting info to the dedicated uniform buffer
*/
void ShaderBasedRenderer::uploadLightingData() const
{
assert(CVS->isARBUniformBufferObjectUsable());
float Lighting[36];
core::vector3df sun_direction = irr_driver->getSunDirection();
video::SColorf sun_color = irr_driver->getSunColor();
Lighting[0] = sun_direction.X;
Lighting[1] = sun_direction.Y;
Lighting[2] = sun_direction.Z;
Lighting[4] = sun_color.getRed();
Lighting[5] = sun_color.getGreen();
Lighting[6] = sun_color.getBlue();
Lighting[7] = 0.54f;
const SHCoefficients* sh_coeff = m_spherical_harmonics->getCoefficients();
if(sh_coeff) {
memcpy(&Lighting[8], sh_coeff->blue_SH_coeff, 9 * sizeof(float));
memcpy(&Lighting[17], sh_coeff->green_SH_coeff, 9 * sizeof(float));
memcpy(&Lighting[26], sh_coeff->red_SH_coeff, 9 * sizeof(float));
}
glBindBuffer(GL_UNIFORM_BUFFER, SharedGPUObjects::getLightingDataUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, 36 * sizeof(float), Lighting);
} // uploadLightingData
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::computeMatrixesAndCameras(scene::ICameraSceneNode *const camnode,
size_t width, size_t height)
{
float w = width * UserConfigParams::m_scale_rtts_factor;
float h = height * UserConfigParams::m_scale_rtts_factor;
m_current_screen_size = core::vector2df(w, h);
m_shadow_matrices.computeMatrixesAndCameras(camnode, int(w), int(h),
m_rtts->getDepthStencilTexture());
} // computeMatrixesAndCameras
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderSkybox(const scene::ICameraSceneNode *camera) const
{
if(m_skybox)
{
m_skybox->render(camera);
}
} // renderSkybox
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderSSAO() const
{
#if defined(USE_GLES2)
if (!CVS->isEXTColorBufferFloatUsable())
return;
#endif
m_rtts->getFBO(FBO_SSAO).bind();
glClearColor(1., 1., 1., 1.);
glClear(GL_COLOR_BUFFER_BIT);
m_post_processing->renderSSAO(m_rtts->getFBO(FBO_LINEAR_DEPTH),
m_rtts->getFBO(FBO_SSAO),
m_rtts->getDepthStencilTexture());
// Blur it to reduce noise.
FrameBuffer::Blit(m_rtts->getFBO(FBO_SSAO),
m_rtts->getFBO(FBO_HALF1_R),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
m_post_processing->renderGaussian17TapBlur(m_rtts->getFBO(FBO_HALF1_R),
m_rtts->getFBO(FBO_HALF2_R),
m_rtts->getFBO(FBO_LINEAR_DEPTH));
} // renderSSAO
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
float dt,
bool hasShadow,
bool forceRTT)
{
if(CVS->isARBUniformBufferObjectUsable())
{
glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO());
glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO());
}
irr_driver->getSceneManager()->setActiveCamera(camnode);
PROFILER_PUSH_CPU_MARKER("- Draw Call Generation", 0xFF, 0xFF, 0xFF);
unsigned solid_poly_count = 0;
unsigned shadow_poly_count = 0;
m_draw_calls.prepareDrawCalls(m_shadow_matrices, camnode, solid_poly_count, shadow_poly_count);
m_poly_count[SOLID_NORMAL_AND_DEPTH_PASS] += solid_poly_count;
m_poly_count[SHADOW_PASS] += shadow_poly_count;
PROFILER_POP_CPU_MARKER();
#if !defined(USE_GLES2)
// Shadows
{
// To avoid wrong culling, use the largest view possible
irr_driver->getSceneManager()->setActiveCamera(m_shadow_matrices.getSunCam());
if (CVS->isDefferedEnabled() &&
CVS->isShadowEnabled() && hasShadow)
{
PROFILER_PUSH_CPU_MARKER("- Shadow", 0x30, 0x6F, 0x90);
m_geometry_passes->renderShadows(m_draw_calls,
m_shadow_matrices,
m_rtts->getShadowFrameBuffer(),
m_rtts->getFBO(FBO_SCALAR_1024),
m_post_processing);
PROFILER_POP_CPU_MARKER();
if (CVS->isGlobalIlluminationEnabled())
{
if (!m_shadow_matrices.isRSMMapAvail())
{
PROFILER_PUSH_CPU_MARKER("- RSM", 0xFF, 0x0, 0xFF);
m_geometry_passes->renderReflectiveShadowMap(m_draw_calls,
m_shadow_matrices,
m_rtts->getReflectiveShadowMapFrameBuffer()); //TODO: move somewhere else as RSM are computed only once per track
m_shadow_matrices.setRSMMapAvail(true);
PROFILER_POP_CPU_MARKER();
}
}
}
irr_driver->getSceneManager()->setActiveCamera(camnode);
}
#endif // !defined(USE_GLES2)
PROFILER_PUSH_CPU_MARKER("- Solid Pass 1", 0xFF, 0x00, 0x00);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
if (CVS->isDefferedEnabled() || forceRTT)
{
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
glClearColor(0., 0., 0., 0.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_geometry_passes->renderSolidFirstPass(m_draw_calls);
}
else
{
// We need a cleared depth buffer for some effect (eg particles depth blending)
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
glDisable(GL_FRAMEBUFFER_SRGB);
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
// Bind() modifies the viewport. In order not to affect anything else,
// the viewport is just reset here and not removed in Bind().
const core::recti &vp = Camera::getActiveCamera()->getViewport();
glViewport(vp.UpperLeftCorner.X,
irr_driver->getActualScreenSize().Height - vp.LowerRightCorner.Y,
vp.LowerRightCorner.X - vp.UpperLeftCorner.X,
vp.LowerRightCorner.Y - vp.UpperLeftCorner.Y);
glClear(GL_DEPTH_BUFFER_BIT);
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_WORKING))
glEnable(GL_FRAMEBUFFER_SRGB);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
PROFILER_POP_CPU_MARKER();
// Lights
{
PROFILER_PUSH_CPU_MARKER("- Light", 0x00, 0xFF, 0x00);
if (CVS->isDefferedEnabled())
{
if (CVS->isGlobalIlluminationEnabled() && hasShadow)
{
m_lighting_passes.renderGlobalIllumination( m_shadow_matrices,
m_rtts->getRadianceHintFrameBuffer(),
m_rtts->getReflectiveShadowMapFrameBuffer(),
m_rtts->getFBO(FBO_DIFFUSE),
m_rtts->getRenderTarget(RTT_NORMAL_AND_DEPTH),
m_rtts->getDepthStencilTexture());
}
GLuint specular_probe;
if(m_skybox)
{
specular_probe = m_skybox->getSpecularProbe();
}
else
{
specular_probe = 0;
}
m_lighting_passes.renderLights( hasShadow,
m_rtts->getRenderTarget(RTT_NORMAL_AND_DEPTH),
m_rtts->getDepthStencilTexture(),
m_rtts->getShadowFrameBuffer(),
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR),
specular_probe);
}
PROFILER_POP_CPU_MARKER();
}
// Handle SSAO
{
PROFILER_PUSH_CPU_MARKER("- SSAO", 0xFF, 0xFF, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SSAO));
if (UserConfigParams::m_ssao)
renderSSAO();
PROFILER_POP_CPU_MARKER();
}
PROFILER_PUSH_CPU_MARKER("- Solid Pass 2", 0x00, 0x00, 0xFF);
if (CVS->isDefferedEnabled() || forceRTT)
{
m_rtts->getFBO(FBO_COLORS).bind();
video::SColor clearColor(0, 150, 150, 150);
if (World::getWorld() != NULL)
clearColor = World::getWorld()->getClearColor();
glClearColor(clearColor.getRed() / 255.f, clearColor.getGreen() / 255.f,
clearColor.getBlue() / 255.f, clearColor.getAlpha() / 255.f);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(GL_FALSE);
}
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
m_geometry_passes->renderSolidSecondPass(m_draw_calls);
PROFILER_POP_CPU_MARKER();
if (irr_driver->getNormals())
{
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).bind();
m_geometry_passes->renderNormalsVisualisation(m_draw_calls);
m_rtts->getFBO(FBO_COLORS).bind();
}
// Render ambient scattering
if (CVS->isDefferedEnabled() && World::getWorld() != NULL &&
World::getWorld()->isFogEnabled())
{
PROFILER_PUSH_CPU_MARKER("- Ambient scatter", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_FOG));
m_lighting_passes.renderAmbientScatter(m_rtts->getDepthStencilTexture());
PROFILER_POP_CPU_MARKER();
}
{
PROFILER_PUSH_CPU_MARKER("- Skybox", 0xFF, 0x00, 0xFF);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SKYBOX));
renderSkybox(camnode);
PROFILER_POP_CPU_MARKER();
}
// Render discrete lights scattering
if (CVS->isDefferedEnabled() && World::getWorld() != NULL &&
World::getWorld()->isFogEnabled())
{
PROFILER_PUSH_CPU_MARKER("- PointLight Scatter", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_FOG));
m_lighting_passes.renderLightsScatter(m_rtts->getDepthStencilTexture(),
m_rtts->getFBO(FBO_HALF1),
m_rtts->getFBO(FBO_HALF2),
m_rtts->getFBO(FBO_COLORS),
m_post_processing);
PROFILER_POP_CPU_MARKER();
}
if (irr_driver->getRH())
{
glDisable(GL_BLEND);
m_rtts->getFBO(FBO_COLORS).bind();
m_post_processing->renderRHDebug(m_rtts->getRadianceHintFrameBuffer().getRTT()[0],
m_rtts->getRadianceHintFrameBuffer().getRTT()[1],
m_rtts->getRadianceHintFrameBuffer().getRTT()[2],
m_shadow_matrices.getRHMatrix(),
m_shadow_matrices.getRHExtend());
}
if (irr_driver->getGI())
{
glDisable(GL_BLEND);
m_rtts->getFBO(FBO_COLORS).bind();
m_lighting_passes.renderGlobalIllumination(m_shadow_matrices,
m_rtts->getRadianceHintFrameBuffer(),
m_rtts->getReflectiveShadowMapFrameBuffer(),
m_rtts->getFBO(FBO_DIFFUSE),
m_rtts->getRenderTarget(RTT_NORMAL_AND_DEPTH),
m_rtts->getDepthStencilTexture());
}
PROFILER_PUSH_CPU_MARKER("- Glow", 0xFF, 0xFF, 0x00);
// Render anything glowing.
if (!irr_driver->getWireframe() && !irr_driver->getMipViz() && UserConfigParams::m_glow)
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GLOW));
irr_driver->setPhase(GLOW_PASS);
m_geometry_passes->renderGlowingObjects(m_draw_calls, m_glowing,
m_rtts->getFBO(FBO_TMP1_WITH_DS));
m_post_processing->renderGlow(m_rtts->getFBO(FBO_TMP1_WITH_DS),
m_rtts->getFBO(FBO_HALF1),
m_rtts->getFBO(FBO_QUARTER1),
m_rtts->getFBO(FBO_COLORS));
} // end glow
PROFILER_POP_CPU_MARKER();
// Render transparent
{
PROFILER_PUSH_CPU_MARKER("- Transparent Pass", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_TRANSPARENT));
m_geometry_passes->renderTransparent(m_draw_calls,
m_rtts->getFBO(FBO_TMP1_WITH_DS),
m_rtts->getFBO(FBO_DISPLACE),
m_rtts->getFBO(FBO_COLORS),
m_post_processing);
PROFILER_POP_CPU_MARKER();
}
m_draw_calls.setFenceSync();
// Render particles
{
PROFILER_PUSH_CPU_MARKER("- Particles", 0xFF, 0xFF, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_PARTICLES));
renderParticles();
PROFILER_POP_CPU_MARKER();
}
if (!CVS->isDefferedEnabled() && !forceRTT)
{
glDisable(GL_FRAMEBUFFER_SRGB);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
return;
}
// Ensure that no object will be drawn after that by using invalid pass
irr_driver->setPhase(PASS_COUNT);
} //renderScene
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderParticles()
{
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
m_draw_calls.renderParticlesList();
// m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT_EFFECT);
} //renderParticles
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderBoundingBoxes()
{
Shaders::ColoredLine *line = Shaders::ColoredLine::getInstance();
line->use();
line->bindVertexArray();
line->bindBuffer();
line->setUniforms(irr::video::SColor(255, 255, 0, 0));
const float *tmp = BoundingBoxes.data();
for (unsigned int i = 0; i < BoundingBoxes.size(); i += 1024 * 6)
{
unsigned count = std::min((unsigned)BoundingBoxes.size() - i, (unsigned)1024 * 6);
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(float), &tmp[i]);
glDrawArrays(GL_LINES, 0, count / 3);
}
} //renderBoundingBoxes
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::debugPhysics()
{
// Note that drawAll must be called before rendering
// the bullet debug view, since otherwise the camera
// is not set up properly. This is only used for
// the bullet debug view.
World *world = World::getWorld();
if (UserConfigParams::m_artist_debug_mode)
world->getPhysics()->draw();
if (world != NULL && world->getPhysics() != NULL)
{
IrrDebugDrawer* debug_drawer = world->getPhysics()->getDebugDrawer();
if (debug_drawer != NULL && debug_drawer->debugEnabled())
{
const std::map<video::SColor, std::vector<float> >& lines = debug_drawer->getLines();
std::map<video::SColor, std::vector<float> >::const_iterator it;
Shaders::ColoredLine *line = Shaders::ColoredLine::getInstance();
line->use();
line->bindVertexArray();
line->bindBuffer();
for (it = lines.begin(); it != lines.end(); it++)
{
line->setUniforms(it->first);
const std::vector<float> &vertex = it->second;
const float *tmp = vertex.data();
for (unsigned int i = 0; i < vertex.size(); i += 1024 * 6)
{
unsigned count = std::min((unsigned)vertex.size() - i, (unsigned)1024 * 6);
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(float), &tmp[i]);
glDrawArrays(GL_LINES, 0, count / 3);
}
}
glUseProgram(0);
glBindVertexArray(0);
}
}
} //debugPhysics
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderPostProcessing(Camera * const camera)
{
scene::ICameraSceneNode * const camnode = camera->getCameraSceneNode();
const core::recti &viewport = camera->getViewport();
bool isRace = StateManager::get()->getGameState() == GUIEngine::GAME;
FrameBuffer *fbo = m_post_processing->render(camnode, isRace, m_rtts);
// The viewport has been changed using glViewport function directly
// during scene rendering, but irrlicht thinks that nothing changed
// when single camera is used. In this case we set the viewport
// to whole screen manually.
glViewport(0, 0, irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height);
if (irr_driver->getNormals())
{
m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).BlitToDefault(
viewport.UpperLeftCorner.X,
irr_driver->getActualScreenSize().Height - viewport.LowerRightCorner.Y,
viewport.LowerRightCorner.X,
irr_driver->getActualScreenSize().Height - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getSSAOViz())
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(m_rtts->getFBO(FBO_HALF1_R).getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getRSM())
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(m_rtts->getReflectiveShadowMapFrameBuffer().getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
}
else if (irr_driver->getShadowViz())
{
m_shadow_matrices.renderShadowsDebug(m_rtts->getShadowFrameBuffer(), m_post_processing);
}
else
{
glEnable(GL_FRAMEBUFFER_SRGB);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
camera->activate();
m_post_processing->renderPassThrough(fbo->getRTT()[0], viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
glDisable(GL_FRAMEBUFFER_SRGB);
}
} //renderPostProcessing
// ----------------------------------------------------------------------------
ShaderBasedRenderer::ShaderBasedRenderer()
{
m_rtts = NULL;
m_skybox = NULL;
m_spherical_harmonics = new SphericalHarmonics(irr_driver->getAmbientLight().toSColor());
m_nb_static_glowing = 0;
if (CVS->isAZDOEnabled())
{
m_geometry_passes = new GeometryPasses<MultidrawPolicy>();
Log::info("ShaderBasedRenderer", "Geometry will be rendered with multidraw policy.");
}
else if (CVS->supportsIndirectInstancingRendering())
{
m_geometry_passes = new GeometryPasses<IndirectDrawPolicy>();
Log::info("ShaderBasedRenderer", "Geometry will be rendered with indirect draw policy.");
}
else
{
m_geometry_passes = new GeometryPasses<GL3DrawPolicy>();
Log::info("ShaderBasedRenderer", "Geometry will be rendered with GL3 policy.");
}
m_post_processing = new PostProcessing(irr_driver->getVideoDriver());
}
// ----------------------------------------------------------------------------
ShaderBasedRenderer::~ShaderBasedRenderer()
{
// Note that we can not simply delete m_post_processing here:
// m_post_processing uses a material that has a reference to
// m_post_processing (for a callback). So when the material is
// removed it will try to drop the ref count of its callback object,
// which is m_post_processing, and which was already deleted. So
// instead we just decrease the ref count here. When the material
// is deleted, it will trigger the actual deletion of
// PostProcessing when decreasing the refcount of its callback object.
if(m_post_processing)
{
// check if we createad the OpenGL device by calling initDevice()
m_post_processing->drop();
}
delete m_geometry_passes;
delete m_spherical_harmonics;
delete m_skybox;
delete m_rtts;
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::onLoadWorld()
{
const core::recti &viewport = Camera::getCamera(0)->getViewport();
size_t width = viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X;
size_t height = viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y;
RTT* rtts = new RTT(width, height);
setRTT(rtts);
compressPowerUpTextures();
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::onUnloadWorld()
{
delete m_rtts;
m_rtts = NULL;
removeSkyBox();
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::resetPostProcessing()
{
m_post_processing->reset();
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::giveBoost(unsigned int cam_index)
{
m_post_processing->giveBoost(cam_index);
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::addSkyBox(const std::vector<video::ITexture*> &texture,
const std::vector<video::ITexture*> &spherical_harmonics_textures)
{
m_skybox = new Skybox(texture);
if(spherical_harmonics_textures.size() == 6)
{
m_spherical_harmonics->setTextures(spherical_harmonics_textures);
}
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::removeSkyBox()
{
delete m_skybox;
m_skybox = NULL;
}
// ----------------------------------------------------------------------------
const SHCoefficients* ShaderBasedRenderer::getSHCoefficients() const
{
return m_spherical_harmonics->getCoefficients();
}
// ----------------------------------------------------------------------------
GLuint ShaderBasedRenderer::getRenderTargetTexture(TypeRTT which) const
{
return m_rtts->getRenderTarget(which);
}
// ----------------------------------------------------------------------------
GLuint ShaderBasedRenderer::getDepthStencilTexture() const
{
return m_rtts->getDepthStencilTexture();
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::setAmbientLight(const video::SColorf &light,
bool force_SH_computation)
{
if(!m_spherical_harmonics->has6Textures() || force_SH_computation)
m_spherical_harmonics->setAmbientLight(light.toSColor());
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::addSunLight(const core::vector3df &pos)
{
m_shadow_matrices.addLight(pos);
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::addGlowingNode(scene::ISceneNode *n, float r, float g, float b)
{
GlowData dat;
dat.node = n;
dat.r = r;
dat.g = g;
dat.b = b;
STKMeshSceneNode *node = static_cast<STKMeshSceneNode *>(n);
node->setGlowColors(irr::video::SColor(0, (unsigned) (dat.r * 255.f), (unsigned)(dat.g * 255.f), (unsigned)(dat.b * 255.f)));
m_glowing.push_back(dat);
m_nb_static_glowing++;
} //addGlowingNode
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::clearGlowingNodes()
{
m_glowing.clear();
m_nb_static_glowing = 0;
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::render(float dt)
{
resetObjectCount();
resetPolyCount();
BoundingBoxes.clear(); //TODO: do not use a global variable
setOverrideMaterial();
addItemsInGlowingList();
// Start the RTT for post-processing.
// We do this before beginScene() because we want to capture the glClear()
// because of tracks that do not have skyboxes (generally add-on tracks)
m_post_processing->begin();
World *world = World::getWorld(); // Never NULL.
Track *track = world->getTrack();
RaceGUIBase *rg = world->getRaceGUI();
if (rg) rg->update(dt);
if (!CVS->isDefferedEnabled())
{
prepareForwardRenderer();
}
for(unsigned int cam = 0; cam < Camera::getNumCameras(); cam++)
{
Camera * const camera = Camera::getCamera(cam);
scene::ICameraSceneNode * const camnode = camera->getCameraSceneNode();
std::ostringstream oss;
oss << "drawAll() for kart " << cam;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (cam+1)*60,
0x00, 0x00);
camera->activate(!CVS->isDefferedEnabled());
rg->preRenderCallback(camera); // adjusts start referee
irr_driver->getSceneManager()->setActiveCamera(camnode);
const core::recti &viewport = camera->getViewport();
if (!CVS->isDefferedEnabled())
glEnable(GL_FRAMEBUFFER_SRGB);
PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0);
m_lighting_passes.updateLightsInfo(camnode, dt);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("UBO upload", 0x0, 0xFF, 0x0);
computeMatrixesAndCameras(camnode, viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y);
m_shadow_matrices.updateSunOrthoMatrices();
if(CVS->isARBUniformBufferObjectUsable())
uploadLightingData();
PROFILER_POP_CPU_MARKER();
renderScene(camnode, dt, track->hasShadows(), false);
if (irr_driver->getBoundingBoxesViz())
{
renderBoundingBoxes();
}
debugPhysics();
if (CVS->isDefferedEnabled())
{
renderPostProcessing(camera);
}
// Save projection-view matrix for the next frame
camera->setPreviousPVMatrix(irr_driver->getProjViewMatrix());
PROFILER_POP_CPU_MARKER();
} // for i<world->getNumKarts()
if(CVS->isARBUniformBufferObjectUsable())
{
// Use full screen size
float tmp[2];
tmp[0] = float(irr_driver->getActualScreenSize().Width);
tmp[1] = float(irr_driver->getActualScreenSize().Height);
glBindBuffer(GL_UNIFORM_BUFFER,
SharedGPUObjects::getViewProjectionMatricesUBO());
glBufferSubData(GL_UNIFORM_BUFFER, (16 * 9) * sizeof(float),
2 * sizeof(float), tmp);
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
// Set the viewport back to the full screen for race gui
irr_driver->getVideoDriver()->setViewPort(core::recti(0, 0,
irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height));
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
std::ostringstream oss;
oss << "renderPlayerView() for kart " << i;
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), 0x00, 0x00, (i+1)*60);
rg->renderPlayerView(camera, dt);
PROFILER_POP_CPU_MARKER();
} // for i<getNumKarts
{
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GUI));
PROFILER_PUSH_CPU_MARKER("GUIEngine", 0x75, 0x75, 0x75);
// Either render the gui, or the global elements of the race gui.
GUIEngine::render(dt);
PROFILER_POP_CPU_MARKER();
}
// Render the profiler
if(UserConfigParams::m_profiler_enabled)
{
PROFILER_DRAW();
}
#ifdef DEBUG
drawDebugMeshes();
#endif
PROFILER_PUSH_CPU_MARKER("EndSccene", 0x45, 0x75, 0x45);
irr_driver->getVideoDriver()->endScene();
PROFILER_POP_CPU_MARKER();
m_post_processing->update(dt);
removeItemsInGlowingList();
} //render
// ----------------------------------------------------------------------------
std::unique_ptr<RenderTarget> ShaderBasedRenderer::createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name)
{
return std::unique_ptr<RenderTarget>(new GL3RenderTarget(dimension, name, this));
//return std::make_unique<GL3RenderTarget>(dimension, name, this); //require C++14
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::renderToTexture(GL3RenderTarget *render_target,
irr::scene::ICameraSceneNode* camera,
float dt)
{
resetObjectCount();
resetPolyCount();
assert(m_rtts != NULL);
irr_driver->getSceneManager()->setActiveCamera(camera);
computeMatrixesAndCameras(camera, m_rtts->getWidth(), m_rtts->getHeight());
updateLightsInfo(camera, dt);
if (CVS->isARBUniformBufferObjectUsable())
uploadLightingData();
renderScene(camera, dt, false, true);
render_target->setFrameBuffer(m_post_processing
->render(camera, false, m_rtts));
// reset
glViewport(0, 0,
irr_driver->getActualScreenSize().Width,
irr_driver->getActualScreenSize().Height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
irr_driver->getSceneManager()->setActiveCamera(NULL);
} //renderToTexture

View File

@ -0,0 +1,129 @@
// 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_SHADER_BASED_RENDERER_HPP
#define HEADER_SHADER_BASED_RENDERER_HPP
#include "graphics/abstract_renderer.hpp"
#include "graphics/draw_calls.hpp"
#include "graphics/lighting_passes.hpp"
#include "graphics/shadow_matrices.hpp"
#include "utils/cpp2011.hpp"
#include <map>
#include <string>
class AbstractGeometryPasses;
class GL3RenderTarget;
class RenderTarget;
class RTT;
class Skybox;
class SphericalHarmonics;
class PostProcessing;
class ShaderBasedRenderer: public AbstractRenderer
{
private:
RTT *m_rtts;
Skybox *m_skybox;
SphericalHarmonics *m_spherical_harmonics;
DrawCalls m_draw_calls;
AbstractGeometryPasses *m_geometry_passes;
LightingPasses m_lighting_passes;
ShadowMatrices m_shadow_matrices;
PostProcessing *m_post_processing;
/** Static glowing things are loaded once per track.
* Glowing items can appear ordisappear each frame */
std::vector<GlowData> m_glowing;
size_t m_nb_static_glowing;
void compressPowerUpTextures();
void setOverrideMaterial();
void addItemsInGlowingList();
void removeItemsInGlowingList();
void prepareForwardRenderer();
void updateLightsInfo(irr::scene::ICameraSceneNode * const camnode,
float dt);
void uploadLightingData() const;
void computeMatrixesAndCameras(scene::ICameraSceneNode * const camnode,
size_t width, size_t height);
void resetShadowCamNodes(){m_shadow_matrices.resetShadowCamNodes();}
void renderSkybox(const scene::ICameraSceneNode *camera) const;
void prepareDrawCalls(scene::ICameraSceneNode *camnode);
void renderSSAO() const;
void renderScene(irr::scene::ICameraSceneNode * const camnode,
float dt, bool hasShadows, bool forceRTT);
void renderParticles();
void renderBoundingBoxes();
void debugPhysics();
void renderPostProcessing(Camera * const camera);
public:
ShaderBasedRenderer();
~ShaderBasedRenderer();
void onLoadWorld() OVERRIDE;
void onUnloadWorld() OVERRIDE;
void resetPostProcessing() OVERRIDE;
void giveBoost(unsigned int cam_index) OVERRIDE;
void addSkyBox(const std::vector<irr::video::ITexture*> &texture,
const std::vector<irr::video::ITexture*> &spherical_harmonics_textures) OVERRIDE;
void removeSkyBox() OVERRIDE;
const SHCoefficients* getSHCoefficients() const OVERRIDE;
GLuint getRenderTargetTexture(TypeRTT which) const OVERRIDE;
GLuint getDepthStencilTexture() const OVERRIDE;
void setAmbientLight(const irr::video::SColorf &light,
bool force_SH_computation = true) OVERRIDE;
void addSunLight(const irr::core::vector3df &pos) OVERRIDE;
void addGlowingNode(scene::ISceneNode *n,
float r = 1.0f, float g = 1.0f, float b = 1.0f) OVERRIDE;
void clearGlowingNodes() OVERRIDE;
void render(float dt) OVERRIDE;
std::unique_ptr<RenderTarget> createRenderTarget(const irr::core::dimension2du &dimension,
const std::string &name) OVERRIDE;
void renderToTexture(GL3RenderTarget *render_target,
irr::scene::ICameraSceneNode* camera,
float dt);
void setRTT(RTT* rtts);
};
#endif //HEADER_SHADER_BASED_RENDERER_HPP

View File

@ -240,7 +240,8 @@ core::matrix4 ShadowMatrices::getTighestFitOrthoProj(const core::matrix4 &transf
* I have some motivation
*/
void ShadowMatrices::updateSplitAndLightcoordRangeFromComputeShaders(unsigned int width,
unsigned int height)
unsigned int height,
GLuint depth_stencil_texture)
{
#if !defined(USE_GLES2)
struct CascadeBoundingBox
@ -278,7 +279,7 @@ void ShadowMatrices::updateSplitAndLightcoordRangeFromComputeShaders(unsigned in
LightspaceBoundingBoxShader::getInstance()->use();
LightspaceBoundingBoxShader::getInstance()
->setTextureUnits(irr_driver->getDepthStencilTexture());
->setTextureUnits(depth_stencil_texture);
LightspaceBoundingBoxShader::getInstance()
->setUniforms(m_sun_cam->getViewMatrix(),
ShadowMatrices::m_shadow_split[1],
@ -317,10 +318,11 @@ void ShadowMatrices::updateSplitAndLightcoordRangeFromComputeShaders(unsigned in
* \param height of the rendering viewport
*/
void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const camnode,
unsigned int width, unsigned int height)
unsigned int width, unsigned int height,
GLuint depth_stencil_texture)
{
if (CVS->isSDSMEnabled())
updateSplitAndLightcoordRangeFromComputeShaders(width, height);
updateSplitAndLightcoordRangeFromComputeShaders(width, height, depth_stencil_texture);
static_cast<scene::CSceneManager *>(irr_driver->getSceneManager())
->OnAnimate(os::Timer::getTime());
camnode->render();
@ -470,6 +472,9 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca
16 * sizeof(float));
}
if(!CVS->isARBUniformBufferObjectUsable())
return;
tmp[144] = float(width);
tmp[145] = float(height);
glBindBuffer(GL_UNIFORM_BUFFER,
@ -497,25 +502,24 @@ void ShadowMatrices::renderWireFrameFrustrum(float *tmp, unsigned i)
glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0);
}
// ----------------------------------------------------------------------------
void ShadowMatrices::renderShadowsDebug()
void ShadowMatrices::renderShadowsDebug(const FrameBuffer &shadow_framebuffer,
const PostProcessing *post_processing)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, UserConfigParams::m_height / 2,
UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
PostProcessing *post_processing = irr_driver->getPostProcessing();
RTT *rtt = irr_driver->getRTT();
post_processing->renderTextureLayer(rtt->getShadowFBO().getRTT()[0], 0);
post_processing->renderTextureLayer(shadow_framebuffer.getRTT()[0], 0);
renderWireFrameFrustrum(m_shadows_cam[0], 0);
glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2,
UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
post_processing->renderTextureLayer(rtt->getShadowFBO().getRTT()[0], 1);
post_processing->renderTextureLayer(shadow_framebuffer.getRTT()[0], 1);
renderWireFrameFrustrum(m_shadows_cam[1], 1);
glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
post_processing->renderTextureLayer(rtt->getShadowFBO().getRTT()[0], 2);
post_processing->renderTextureLayer(shadow_framebuffer.getRTT()[0], 2);
renderWireFrameFrustrum(m_shadows_cam[2], 2);
glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2,
UserConfigParams::m_height / 2);
post_processing->renderTextureLayer(rtt->getShadowFBO().getRTT()[0], 3);
post_processing->renderTextureLayer(shadow_framebuffer.getRTT()[0], 3);
renderWireFrameFrustrum(m_shadows_cam[3], 3);
glViewport(0, 0, UserConfigParams::m_width, UserConfigParams::m_height);
}

View File

@ -19,11 +19,12 @@
#ifndef HEADER_SHADOW_MATRICES_HPP
#define HEADER_SHADOW_MATRICES_HPP
#include "matrix4.h"
#include "vector3d.h"
#include "graphics/gl_headers.hpp"
#include <matrix4.h>
#include <tuple>
#include <vector>
#include <vector3d.h>
namespace irr
{
@ -32,7 +33,8 @@ namespace irr
using namespace irr;
class FrameBuffer;
class PostProcessing;
class ShadowMatrices
{
@ -53,7 +55,8 @@ private:
void updateSplitAndLightcoordRangeFromComputeShaders(unsigned int width,
unsigned int height);
unsigned int height,
GLuint depth_stencil_texture);
core::matrix4 getTighestFitOrthoProj(const core::matrix4 &transform,
const std::vector<core::vector3df> &pointsInside,
std::pair<float, float> &size);
@ -64,10 +67,12 @@ public:
~ShadowMatrices();
void computeMatrixesAndCameras(scene::ICameraSceneNode *const camnode,
unsigned int width, unsigned int height);
unsigned int width, unsigned int height,
GLuint depth_stencil_texture);
void addLight(const core::vector3df &pos);
void updateSunOrthoMatrices();
void renderShadowsDebug();
void renderShadowsDebug(const FrameBuffer &shadow_framebuffer,
const PostProcessing *post_processing);
// ------------------------------------------------------------------------
void resetShadowCamNodes();
@ -79,11 +84,11 @@ public:
// ------------------------------------------------------------------------
scene::ICameraSceneNode* getSunCam() { return m_sun_cam; }
// ------------------------------------------------------------------------
core::matrix4& getRHMatrix() { return m_rh_matrix; }
const core::matrix4& getRHMatrix() const { return m_rh_matrix; }
// ------------------------------------------------------------------------
core::vector3df& getRHExtend() { return m_rh_extend; }
const core::vector3df& getRHExtend() const { return m_rh_extend; }
// ------------------------------------------------------------------------
core::matrix4& getRSMMatrix() { return m_rsm_matrix; }
const core::matrix4& getRSMMatrix() const { return m_rsm_matrix; }
// ------------------------------------------------------------------------
std::vector<core::matrix4>& getSunOrthoMatrices()
{
@ -99,7 +104,6 @@ public:
return m_shadow_scales;
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
}; // class ShadowMatrices

View File

@ -16,6 +16,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/central_settings.hpp"
GLuint SharedGPUObjects::m_billboard_vbo;
GLuint SharedGPUObjects::m_sky_tri_vbo;
@ -147,6 +148,7 @@ void SharedGPUObjects::initFrustrumVBO()
// ----------------------------------------------------------------------------
void SharedGPUObjects::initShadowVPMUBO()
{
assert(CVS->isARBUniformBufferObjectUsable());
glGenBuffers(1, &m_View_projection_matrices_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, m_View_projection_matrices_ubo);
glBufferData(GL_UNIFORM_BUFFER, (16 * 9 + 2) * sizeof(float), 0,
@ -157,6 +159,7 @@ void SharedGPUObjects::initShadowVPMUBO()
// ----------------------------------------------------------------------------
void SharedGPUObjects::initLightingDataUBO()
{
assert(CVS->isARBUniformBufferObjectUsable());
glGenBuffers(1, &m_lighting_data_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, m_lighting_data_ubo);
glBufferData(GL_UNIFORM_BUFFER, 36 * sizeof(float), 0, GL_STREAM_DRAW);
@ -190,9 +193,13 @@ void SharedGPUObjects::init()
initBillboardVBO();
initSkyTriVBO();
initFrustrumVBO();
initParticleQuadVBO();
if(CVS->isARBUniformBufferObjectUsable())
{
initShadowVPMUBO();
initLightingDataUBO();
initParticleQuadVBO();
}
m_has_been_initialised = true;
} // SharedGPUObjects

View File

@ -18,8 +18,8 @@
#include "graphics/show_curve.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/texture_manager.hpp"
#include "utils/vec3.hpp"
#include <IMeshSceneNode.h>

View File

@ -342,6 +342,7 @@ Skybox::Skybox(const std::vector<video::ITexture *> &skybox_textures)
if (!skybox_textures.empty())
{
generateCubeMapFromTextures();
if(CVS->isGLSL())
generateSpecularCubemap();
}
}

View File

@ -19,11 +19,11 @@
#include "graphics/slip_stream.hpp"
#include "graphics/central_settings.hpp"
#include "config/user_config.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/texture_manager.hpp"
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"

View File

@ -17,7 +17,7 @@
#include "graphics/irr_driver.hpp"
#include "graphics/sphericalHarmonics.hpp"
#include "graphics/spherical_harmonics.hpp"
#include "utils/log.hpp"
#include <algorithm>
@ -192,7 +192,8 @@ namespace
} //namespace
// ----------------------------------------------------------------------------
/** Compute m_red_SH_coeff, m_green_SH_coeff and m_blue_SH_coeff from Yml values
/** Compute m_SH_coeff->red_SH_coeff, m_SH_coeff->green_SH_coeff
* and m_SH_coeff->blue_SH_coeff from Yml values
* \param cubemap_face The 6 cubemap faces (float textures)
* \param edge_size Size of the cubemap face
* \param Yml The sphericals harmonics functions values on each texel of the cubemap
@ -205,9 +206,9 @@ void SphericalHarmonics::projectSH(Color *cubemap_face[6], size_t edge_size,
{
for (unsigned i = 0; i < 9; i++)
{
m_blue_SH_coeff[i] = 0;
m_green_SH_coeff[i] = 0;
m_red_SH_coeff[i] = 0;
m_SH_coeff->blue_SH_coeff[i] = 0;
m_SH_coeff->green_SH_coeff[i] = 0;
m_SH_coeff->red_SH_coeff[i] = 0;
}
float wh = float(edge_size * edge_size);
@ -272,35 +273,35 @@ void SphericalHarmonics::projectSH(Color *cubemap_face[6], size_t edge_size,
}
}
m_blue_SH_coeff[0] = b0;
m_blue_SH_coeff[1] = b1;
m_blue_SH_coeff[2] = b2;
m_blue_SH_coeff[3] = b3;
m_blue_SH_coeff[4] = b4;
m_blue_SH_coeff[5] = b5;
m_blue_SH_coeff[6] = b6;
m_blue_SH_coeff[7] = b7;
m_blue_SH_coeff[8] = b8;
m_SH_coeff->blue_SH_coeff[0] = b0;
m_SH_coeff->blue_SH_coeff[1] = b1;
m_SH_coeff->blue_SH_coeff[2] = b2;
m_SH_coeff->blue_SH_coeff[3] = b3;
m_SH_coeff->blue_SH_coeff[4] = b4;
m_SH_coeff->blue_SH_coeff[5] = b5;
m_SH_coeff->blue_SH_coeff[6] = b6;
m_SH_coeff->blue_SH_coeff[7] = b7;
m_SH_coeff->blue_SH_coeff[8] = b8;
m_red_SH_coeff[0] = r0;
m_red_SH_coeff[1] = r1;
m_red_SH_coeff[2] = r2;
m_red_SH_coeff[3] = r3;
m_red_SH_coeff[4] = r4;
m_red_SH_coeff[5] = r5;
m_red_SH_coeff[6] = r6;
m_red_SH_coeff[7] = r7;
m_red_SH_coeff[8] = r8;
m_SH_coeff->red_SH_coeff[0] = r0;
m_SH_coeff->red_SH_coeff[1] = r1;
m_SH_coeff->red_SH_coeff[2] = r2;
m_SH_coeff->red_SH_coeff[3] = r3;
m_SH_coeff->red_SH_coeff[4] = r4;
m_SH_coeff->red_SH_coeff[5] = r5;
m_SH_coeff->red_SH_coeff[6] = r6;
m_SH_coeff->red_SH_coeff[7] = r7;
m_SH_coeff->red_SH_coeff[8] = r8;
m_green_SH_coeff[0] = g0;
m_green_SH_coeff[1] = g1;
m_green_SH_coeff[2] = g2;
m_green_SH_coeff[3] = g3;
m_green_SH_coeff[4] = g4;
m_green_SH_coeff[5] = g5;
m_green_SH_coeff[6] = g6;
m_green_SH_coeff[7] = g7;
m_green_SH_coeff[8] = g8;
m_SH_coeff->green_SH_coeff[0] = g0;
m_SH_coeff->green_SH_coeff[1] = g1;
m_SH_coeff->green_SH_coeff[2] = g2;
m_SH_coeff->green_SH_coeff[3] = g3;
m_SH_coeff->green_SH_coeff[4] = g4;
m_SH_coeff->green_SH_coeff[5] = g5;
m_SH_coeff->green_SH_coeff[6] = g6;
m_SH_coeff->green_SH_coeff[7] = g7;
m_SH_coeff->green_SH_coeff[8] = g8;
} // projectSH
// ----------------------------------------------------------------------------
@ -358,6 +359,7 @@ void SphericalHarmonics::generateSphericalHarmonics(Color *cubemap_face[6], size
// ----------------------------------------------------------------------------
SphericalHarmonics::SphericalHarmonics(const std::vector<video::ITexture *> &spherical_harmonics_textures)
{
m_SH_coeff = new SHCoefficients;
setTextures(spherical_harmonics_textures);
}
@ -369,9 +371,16 @@ SphericalHarmonics::SphericalHarmonics(const video::SColor &ambient)
{
//make sure m_ambient and ambient are not equal
m_ambient = (ambient==0) ? 1 : 0;
m_SH_coeff = new SHCoefficients;
setAmbientLight(ambient);
}
SphericalHarmonics::~SphericalHarmonics()
{
delete m_SH_coeff;
}
/** Compute spherical harmonics coefficients from 6 textures */
void SphericalHarmonics::setTextures(const std::vector<video::ITexture *> &spherical_harmonics_textures)
{
@ -459,9 +468,9 @@ void SphericalHarmonics::setAmbientLight(const video::SColor &ambient)
// Diffuse env map is x 0.25, compensate
for (unsigned i = 0; i < 9; i++)
{
m_blue_SH_coeff[i] *= 4;
m_green_SH_coeff[i] *= 4;
m_red_SH_coeff[i] *= 4;
m_SH_coeff->blue_SH_coeff[i] *= 4;
m_SH_coeff->green_SH_coeff[i] *= 4;
m_SH_coeff->red_SH_coeff[i] *= 4;
}
} //setAmbientLight
@ -469,11 +478,11 @@ void SphericalHarmonics::setAmbientLight(const video::SColor &ambient)
/** Print spherical harmonics coefficients (debug) */
void SphericalHarmonics::printCoeff() {
Log::debug("SphericalHarmonics", "Blue_SH:");
displayCoeff(m_blue_SH_coeff);
displayCoeff(m_SH_coeff->blue_SH_coeff);
Log::debug("SphericalHarmonics", "Green_SH:");
displayCoeff(m_green_SH_coeff);
displayCoeff(m_SH_coeff->green_SH_coeff);
Log::debug("SphericalHarmonics", "Red_SH:");
displayCoeff(m_red_SH_coeff);
displayCoeff(m_SH_coeff->red_SH_coeff);
} //printCoeff
// ----------------------------------------------------------------------------
@ -500,17 +509,17 @@ void SphericalHarmonics::unprojectSH(size_t width, size_t height,
fi = 2 * fi - 1, fj = 2 * fj - 1;
output[face][4 * height * i + 4 * j + 2] =
getTexelValue(i, j, width, height, m_red_SH_coeff, Y00[face],
getTexelValue(i, j, width, height, m_SH_coeff->red_SH_coeff, Y00[face],
Y1minus1[face], Y10[face], Y11[face],
Y2minus2[face], Y2minus1[face], Y20[face],
Y21[face], Y22[face]);
output[face][4 * height * i + 4 * j + 1] =
getTexelValue(i, j, width, height, m_green_SH_coeff, Y00[face],
getTexelValue(i, j, width, height, m_SH_coeff->green_SH_coeff, Y00[face],
Y1minus1[face], Y10[face], Y11[face],
Y2minus2[face], Y2minus1[face], Y20[face],
Y21[face], Y22[face]);
output[face][4 * height * i + 4 * j] =
getTexelValue(i, j, width, height, m_blue_SH_coeff, Y00[face],
getTexelValue(i, j, width, height, m_SH_coeff->blue_SH_coeff, Y00[face],
Y1minus1[face], Y10[face], Y11[face],
Y2minus2[face], Y2minus1[face], Y20[face],
Y21[face], Y22[face]);

View File

@ -29,6 +29,13 @@ struct Color
float Blue;
};
struct SHCoefficients
{
float blue_SH_coeff[9];
float green_SH_coeff[9];
float red_SH_coeff[9];
};
class SphericalHarmonics
{
@ -40,10 +47,7 @@ private:
irr::video::SColor m_ambient;
/** The spherical harmonics coefficients */
float m_blue_SH_coeff[9];
float m_green_SH_coeff[9];
float m_red_SH_coeff[9];
SHCoefficients *m_SH_coeff;
void projectSH(Color *cubemap_face[6], size_t edge_size, float *Y00[],
float *Y1minus1[], float *Y10[], float *Y11[],
@ -55,13 +59,12 @@ private:
public:
SphericalHarmonics(const std::vector<irr::video::ITexture *> &spherical_harmonics_textures);
SphericalHarmonics(const irr::video::SColor &ambient);
~SphericalHarmonics();
void setTextures(const std::vector<irr::video::ITexture *> &spherical_harmonics_textures);
void setAmbientLight(const irr::video::SColor &ambient);
inline const float* getBlueSHCoeff () const {return m_blue_SH_coeff; }
inline const float* getGreenSHCoeff() const {return m_green_SH_coeff; }
inline const float* getRedSHCoeff () const {return m_red_SH_coeff; }
inline const SHCoefficients* getCoefficients() const { return m_SH_coeff; }
inline bool has6Textures() const {return m_spherical_harmonics_textures.size()==6;}

View File

@ -15,19 +15,13 @@
// 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/glwrap.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "config/user_config.hpp"
#include "central_settings.hpp"
#include "graphics/camera.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#include "utils/cpp2011.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/vao_manager.hpp"
#include <IMaterialRenderer.h>
#include <ISceneManager.h>

View File

@ -17,12 +17,12 @@
#include "graphics/stk_billboard.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/shaders.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/texture_manager.hpp"
#include <ISceneManager.h>

View File

@ -17,18 +17,12 @@
#include "graphics/stk_mesh.hpp"
#include "config/user_config.hpp"
#include "central_settings.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/camera.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp"
#include "graphics/shaders.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/helpers.hpp"
#include "graphics/texture_manager.hpp"
#include <ISceneManager.h>
#include <IMaterialRenderer.h>

View File

@ -92,6 +92,7 @@ public:
virtual bool isImmediateDraw() const { return false; }
}; // STKMeshCommon
// ----------------------------------------------------------------------------
template<typename T, typename... Args>
class MeshList : public Singleton<T>
@ -107,67 +108,33 @@ public:
}
}; // MeshList
// ----------------------------------------------------------------------------
template<typename T>
class InstancedMeshList : public Singleton<T>
{
public:
std::vector<GLMesh *> SolidPass, Shadows[4], RSM;
void clear()
{
SolidPass.clear();
RSM.clear();
for (unsigned i = 0; i < 4; i++)
Shadows[i].clear();
}
}; // InstancedMeshList
// ----------------------------------------------------------------------------
class ListMatDefault : public MeshList<ListMatDefault, GLMesh *, core::matrix4,
core::matrix4, core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatDefault : public InstancedMeshList<ListInstancedMatDefault>
{};
// ----------------------------------------------------------------------------
class ListMatAlphaRef : public MeshList<ListMatAlphaRef, GLMesh *, core::matrix4,
core::matrix4, core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatAlphaRef : public InstancedMeshList<ListInstancedMatAlphaRef>
{};
// ----------------------------------------------------------------------------
class ListMatNormalMap : public MeshList<ListMatNormalMap, GLMesh *, core::matrix4,
core::matrix4, core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatNormalMap : public InstancedMeshList<ListInstancedMatNormalMap>
{};
// ----------------------------------------------------------------------------
class ListMatGrass : public MeshList<ListMatGrass, GLMesh *, core::matrix4,
core::matrix4, core::vector3df>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatGrass : public InstancedMeshList<ListInstancedMatGrass>
{};
// ----------------------------------------------------------------------------
class ListMatSphereMap : public MeshList<ListMatSphereMap, GLMesh *,
core::matrix4, core::matrix4,
core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatSphereMap : public InstancedMeshList<ListInstancedMatSphereMap>
{};
// ----------------------------------------------------------------------------
class ListMatSplatting : public MeshList<ListMatSplatting, GLMesh *,
core::matrix4, core::matrix4>
@ -178,19 +145,11 @@ class ListMatUnlit : public MeshList<ListMatUnlit, GLMesh *, core::matrix4,
core::matrix4, core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatUnlit : public InstancedMeshList<ListInstancedMatUnlit>
{};
// ----------------------------------------------------------------------------
class ListMatDetails : public MeshList<ListMatDetails, GLMesh *, core::matrix4,
core::matrix4, core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedMatDetails : public InstancedMeshList<ListInstancedMatDetails>
{};
// ----------------------------------------------------------------------------
// Transparent
template <typename T, typename ...Args>
@ -242,11 +201,6 @@ class ListDisplacement : public MiscList<ListDisplacement, GLMesh *,
core::matrix4>
{};
// ----------------------------------------------------------------------------
class ListInstancedGlow : public Singleton<ListInstancedGlow>
, public std::vector<GLMesh *>
{};
// ----------------------------------------------------------------------------
Material::ShaderType getMeshMaterialFromType(video::E_MATERIAL_TYPE MaterialType,
video::E_VERTEX_TYPE tp,

View File

@ -17,20 +17,16 @@
#include "graphics/stk_mesh_scene_node.hpp"
#include "config/user_config.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/camera.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp"
#include "graphics/rtts.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/texture_manager.hpp"
#include "graphics/vao_manager.hpp"
#include "tracks/track.hpp"
#include "modes/world.hpp"
#include "utils/cpp2011.hpp"
#include "utils/helpers.hpp"
#include "utils/tuple.hpp"
#include <IMaterialRenderer.h>
#include <ISceneManager.h>
@ -408,20 +404,14 @@ void STKMeshSceneNode::render()
glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_DIFFUSE),
Shaders::ObjectPass2Shader
::getInstance()->m_sampler_ids[0]);
if (!glIsTextureHandleResidentARB(DiffuseHandle))
glMakeTextureHandleResidentARB(DiffuseHandle);
GLuint64 SpecularHandle =
glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_SPECULAR),
Shaders::ObjectPass2Shader::getInstance()->m_sampler_ids[1]);
if (!glIsTextureHandleResidentARB(SpecularHandle))
glMakeTextureHandleResidentARB(SpecularHandle);
GLuint64 SSAOHandle =
glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_HALF1_R),
Shaders::ObjectPass2Shader::getInstance()->m_sampler_ids[2]);
if (!glIsTextureHandleResidentARB(SSAOHandle))
glMakeTextureHandleResidentARB(SSAOHandle);
if (!mesh.TextureHandles[0])
mesh.TextureHandles[0] =

View File

@ -16,179 +16,10 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/stk_scene_manager.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/render_info.hpp"
#include "graphics/shadow_matrices.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "graphics/stk_mesh.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/cpp2011.hpp"
#include "utils/profiler.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/time.hpp"
#include <ICameraSceneNode.h>
#include <ISceneManager.h>
#include <ISceneNode.h>
#include <SViewFrustum.h>
#include <vector>
#include <unordered_map>
#include <SViewFrustum.h>
template<typename T>
struct InstanceFiller
{
static void add(GLMesh *, scene::ISceneNode *, T &);
};
template<>
void InstanceFiller<InstanceDataSingleTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataSingleTex &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;
Instance.Texture = mesh->TextureHandles[0];
}
template<>
void InstanceFiller<InstanceDataDualTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataDualTex &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;
Instance.Texture = mesh->TextureHandles[0];
Instance.SecondTexture = mesh->TextureHandles[1];
}
template<>
void InstanceFiller<InstanceDataThreeTex>::add(GLMesh *mesh, scene::ISceneNode *node, InstanceDataThreeTex &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;
Instance.Texture = mesh->TextureHandles[0];
Instance.SecondTexture = mesh->TextureHandles[1];
Instance.ThirdTexture = mesh->TextureHandles[2];
}
template<>
void InstanceFiller<GlowInstanceData>::add(GLMesh *mesh, scene::ISceneNode *node, GlowInstanceData &Instance)
{
STKMeshSceneNode *nd = dynamic_cast<STKMeshSceneNode*>(node);
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.Color = nd->getGlowColor().color;
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 T>
static void
FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > InstanceList, T * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer,
size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount)
{
// Should never be empty
GLMesh *mesh = InstanceList.front().first;
size_t InitialOffset = InstanceBufferOffset;
for (unsigned i = 0; i < InstanceList.size(); i++)
{
auto &Tp = InstanceList[i];
scene::ISceneNode *node = Tp.second;
InstanceFiller<T>::add(mesh, node, InstanceBuffer[InstanceBufferOffset++]);
assert(InstanceBufferOffset * sizeof(T) < 10000 * sizeof(InstanceDataDualTex));
}
DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++];
CurrentCommand.baseVertex = mesh->vaoBaseVertex;
CurrentCommand.count = mesh->IndexCount;
CurrentCommand.firstIndex = mesh->vaoOffset / 2;
CurrentCommand.baseInstance = InitialOffset;
CurrentCommand.instanceCount = InstanceBufferOffset - InitialOffset;
PolyCount += (InstanceBufferOffset - InitialOffset) * mesh->IndexCount / 3;
}
template<typename T>
static
void FillInstances(const std::unordered_map<std::pair<scene::IMeshBuffer*, RenderInfo*>, std::vector<std::pair<GLMesh *, scene::ISceneNode*> >, MeshRenderInfoHash, MeshRenderInfoEquals> &GatheredGLMesh, std::vector<GLMesh *> &InstancedList,
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount)
{
auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end();
for (; It != E; ++It)
{
FillInstances_impl<T>(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount);
if (!CVS->isAZDOEnabled())
InstancedList.push_back(It->second.front().first);
}
}
template<typename T>
static
void FillInstances(const std::unordered_map<scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > &GatheredGLMesh, std::vector<GLMesh *> &InstancedList,
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount)
{
auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end();
for (; It != E; ++It)
{
FillInstances_impl<T>(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount);
if (!CVS->isAZDOEnabled())
InstancedList.push_back(It->second.front().first);
}
}
static std::unordered_map <std::pair<scene::IMeshBuffer*, RenderInfo*>, std::vector<std::pair<GLMesh *, scene::ISceneNode*> >, MeshRenderInfoHash, MeshRenderInfoEquals> MeshForSolidPass[Material::SHADERTYPE_COUNT];
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForShadowPass[Material::SHADERTYPE_COUNT][4], MeshForRSM[Material::SHADERTYPE_COUNT];
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForGlowPass;
static std::vector <STKMeshCommon *> DeferredUpdate;
static core::vector3df windDir;
using namespace irr;
// From irrlicht code
static
@ -202,7 +33,7 @@ bool isBoxInFrontOfPlane(const core::plane3df &plane, const core::vector3df edge
std::vector<float> BoundingBoxes;
static void addEdge(const core::vector3df &P0, const core::vector3df &P1)
void addEdge(const core::vector3df &P0, const core::vector3df &P1)
{
BoundingBoxes.push_back(P0.X);
BoundingBoxes.push_back(P0.Y);
@ -212,7 +43,6 @@ static void addEdge(const core::vector3df &P0, const core::vector3df &P1)
BoundingBoxes.push_back(P1.Z);
}
static
bool isCulledPrecise(const scene::ICameraSceneNode *cam, const scene::ISceneNode *node)
{
if (!node->getAutomaticCulling())
@ -231,671 +61,3 @@ bool isCulledPrecise(const scene::ICameraSceneNode *cam, const scene::ISceneNode
return true;
return false;
}
static void
handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode *cam, scene::ICameraSceneNode *shadowcam[4], const scene::ICameraSceneNode *rsmcam,
bool &culledforcam, bool culledforshadowcam[4], bool &culledforrsm, bool drawRSM)
{
STKMeshCommon *node = dynamic_cast<STKMeshCommon*>(Node);
if (!node)
return;
node->updateNoGL();
DeferredUpdate.push_back(node);
const core::matrix4 &trans = Node->getAbsoluteTransformation();
core::vector3df edges[8];
Node->getBoundingBox().getEdges(edges);
for (unsigned i = 0; i < 8; i++)
trans.transformVect(edges[i]);
/* From irrlicht
/3--------/7
/ | / |
/ | / |
1---------5 |
| /2- - -|- -6
| / | /
|/ | /
0---------4/
*/
if (irr_driver->getBoundingBoxesViz())
{
addEdge(edges[0], edges[1]);
addEdge(edges[1], edges[5]);
addEdge(edges[5], edges[4]);
addEdge(edges[4], edges[0]);
addEdge(edges[2], edges[3]);
addEdge(edges[3], edges[7]);
addEdge(edges[7], edges[6]);
addEdge(edges[6], edges[2]);
addEdge(edges[0], edges[2]);
addEdge(edges[1], edges[3]);
addEdge(edges[5], edges[7]);
addEdge(edges[4], edges[6]);
}
if (node->isImmediateDraw())
{
ImmediateDraw->push_back(Node);
return;
}
culledforcam = culledforcam || isCulledPrecise(cam, Node);
culledforrsm = culledforrsm || isCulledPrecise(rsmcam, Node);
for (unsigned i = 0; i < 4; i++)
culledforshadowcam[i] = culledforshadowcam[i] || isCulledPrecise(shadowcam[i], Node);
// Transparent
if (World::getWorld() && World::getWorld()->isFogEnabled())
{
const Track * const track = World::getWorld()->getTrack();
// Todo : put everything in a ubo
const float fogmax = track->getFogMax();
const float startH = track->getFogStartHeight();
const float endH = track->getFogEndHeight();
const float start = track->getFogStart();
const float end = track->getFogEnd();
const video::SColor tmpcol = track->getFogColor();
video::SColorf col(tmpcol.getRed() / 255.0f,
tmpcol.getGreen() / 255.0f,
tmpcol.getBlue() / 255.0f);
for (GLMesh *mesh : node->TransparentMesh[TM_DEFAULT])
pushVector(ListBlendTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix,
fogmax, startH, endH, start, end, col);
for (GLMesh *mesh : node->TransparentMesh[TM_ADDITIVE])
pushVector(ListAdditiveTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix,
fogmax, startH, endH, start, end, col);
}
else
{
for (GLMesh *mesh : node->TransparentMesh[TM_DEFAULT])
pushVector(ListBlendTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, 1.0f);
for (GLMesh *mesh : node->TransparentMesh[TM_ADDITIVE])
pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, 1.0f);
}
// Use sun color to determine custom alpha for ghost karts
float custom_alpha = 1.0f;
if (World::getWorld())
{
const video::SColor& c = World::getWorld()->getTrack()->getSunColor();
float y = 0.2126f * c.getRed() + 0.7152f * c.getGreen() + 0.0722f * c.getBlue();
custom_alpha = y > 128.0f ? 0.5f : 0.35f;
}
for (GLMesh *mesh : node->TransparentMesh[TM_GHOST_KART])
pushVector(ListGhostKart::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, custom_alpha);
for (GLMesh *mesh : node->TransparentMesh[TM_GHOST_KART_TANGENTS])
pushVector(ListGhostKartTangents::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, custom_alpha);
for (GLMesh *mesh : node->TransparentMesh[TM_DISPLACEMENT])
pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation());
if (!culledforcam)
{
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
if (node->glow())
MeshForGlowPass[mesh->mb].emplace_back(mesh, Node);
if (Mat != Material::SHADERTYPE_SPLATTING && mesh->TextureMatrix.isIdentity())
MeshForSolidPass[Mat][std::pair<scene::IMeshBuffer*, RenderInfo*>(mesh->mb, mesh->m_render_info)].emplace_back(mesh, Node);
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
}
}
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
}
}
}
}
}
if (!CVS->isShadowEnabled())
return;
for (unsigned cascade = 0; cascade < 4; ++cascade)
{
if (culledforshadowcam[cascade])
continue;
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
if (Mat != Material::SHADERTYPE_SPLATTING)
MeshForShadowPass[Mat][cascade][mesh->mb].emplace_back(mesh, Node);
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix);
}
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
}
}
}
}
}
if (!UserConfigParams::m_gi || !drawRSM)
return;
if (!culledforrsm)
{
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (CVS->supportsIndirectInstancingRendering())
{
if (Mat == Material::SHADERTYPE_SPLATTING)
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
}
else
{
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
MeshForRSM[Mat][mesh->mb].emplace_back(mesh, Node);
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for (GLMesh *mesh : node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
}
}
}
}
}
}
static void
parseSceneManager(core::list<scene::ISceneNode*> &List, std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode* cam, scene::ICameraSceneNode *shadow_cam[4], const scene::ICameraSceneNode *rsmcam,
bool culledforcam, bool culledforshadowcam[4], bool culledforrsm, bool drawRSM)
{
core::list<scene::ISceneNode*>::Iterator I = List.begin(), E = List.end();
for (; I != E; ++I)
{
if (LODNode *node = dynamic_cast<LODNode *>(*I))
node->updateVisibility();
(*I)->updateAbsolutePosition();
if (!(*I)->isVisible())
continue;
if (ParticleSystemProxy *node = dynamic_cast<ParticleSystemProxy *>(*I))
{
if (!isCulledPrecise(cam, *I))
ParticlesList::getInstance()->push_back(node);
continue;
}
if (STKBillboard *node = dynamic_cast<STKBillboard *>(*I))
{
if (!isCulledPrecise(cam, *I))
BillBoardList::getInstance()->push_back(node);
continue;
}
bool newculledforcam = culledforcam;
bool newculledforrsm = culledforrsm;
bool newculledforshadowcam[4] = { culledforshadowcam[0], culledforshadowcam[1], culledforshadowcam[2], culledforshadowcam[3] };
handleSTKCommon(*I, ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm, drawRSM);
parseSceneManager(const_cast<core::list<scene::ISceneNode*>& >((*I)->getChildren()), ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm, drawRSM);
}
}
template<Material::ShaderType Mat, typename T> static void
GenDrawCalls(unsigned cascade, std::vector<GLMesh *> &InstancedList,
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount)
{
if (CVS->supportsIndirectInstancingRendering())
ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset
FillInstances<T>(MeshForShadowPass[Mat][cascade], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount);
if (CVS->isAZDOEnabled())
ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat];
}
int enableOpenMP;
static void FixBoundingBoxes(scene::ISceneNode* node)
{
for (scene::ISceneNode *child : node->getChildren())
{
FixBoundingBoxes(child);
const_cast<core::aabbox3df&>(node->getBoundingBox()).addInternalBox(child->getBoundingBox());
}
}
void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
{
windDir = getWindDir();
ListBlendTransparent::getInstance()->clear();
ListAdditiveTransparent::getInstance()->clear();
ListGhostKart::getInstance()->clear();
ListGhostKartTangents::getInstance()->clear();
ListBlendTransparentFog::getInstance()->clear();
ListAdditiveTransparentFog::getInstance()->clear();
ListDisplacement::getInstance()->clear();
ListMatDefault::getInstance()->clear();
ListMatAlphaRef::getInstance()->clear();
ListMatSphereMap::getInstance()->clear();
ListMatDetails::getInstance()->clear();
ListMatUnlit::getInstance()->clear();
ListMatNormalMap::getInstance()->clear();
ListMatGrass::getInstance()->clear();
ListMatSplatting::getInstance()->clear();
ImmediateDrawList::getInstance()->clear();
BillBoardList::getInstance()->clear();
ParticlesList::getInstance()->clear();
ListInstancedGlow::getInstance()->clear();
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
MeshForSolidPass[Mat].clear();
MeshForRSM[Mat].clear();
for (unsigned i = 0; i < 4; i++)
MeshForShadowPass[Mat][i].clear();
}
MeshForGlowPass.clear();
DeferredUpdate.clear();
core::list<scene::ISceneNode*> List = m_scene_manager->getRootSceneNode()->getChildren();
PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
for (scene::ISceneNode *child : List)
FixBoundingBoxes(child);
bool cam = false, rsmcam = false;
bool shadowcam[4] = { false, false, false, false };
parseSceneManager(List, ImmediateDrawList::getInstance(), camnode,
getShadowMatrices()->getShadowCamNodes(),
getShadowMatrices()->getSunCam(), cam,
shadowcam, rsmcam,
!getShadowMatrices()->isRSMMapAvail());
PROFILER_POP_CPU_MARKER();
// Add a 1 s timeout
if (!m_sync)
m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
PROFILER_PUSH_CPU_MARKER("- Sync Stall", 0xFF, 0x0, 0x0);
GLenum reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
if (reason != GL_ALREADY_SIGNALED)
{
do
{
reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000);
}
while (reason == GL_TIMEOUT_EXPIRED);
}
glDeleteSync(m_sync);
PROFILER_POP_CPU_MARKER();
/* switch (reason)
{
case GL_ALREADY_SIGNALED:
printf("Already Signaled\n");
break;
case GL_TIMEOUT_EXPIRED:
printf("Timeout Expired\n");
break;
case GL_CONDITION_SATISFIED:
printf("Condition Satisfied\n");
break;
case GL_WAIT_FAILED:
printf("Wait Failed\n");
break;
}*/
PROFILER_PUSH_CPU_MARKER("- Animations/Buffer upload", 0x0, 0x0, 0x0);
for (unsigned i = 0; i < DeferredUpdate.size(); i++)
DeferredUpdate[i]->updateGL();
PROFILER_POP_CPU_MARKER();
if (!CVS->supportsIndirectInstancingRendering())
return;
#if !defined(USE_GLES2)
InstanceDataDualTex *InstanceBufferDualTex;
InstanceDataThreeTex *InstanceBufferThreeTex;
InstanceDataSingleTex *ShadowInstanceBuffer;
InstanceDataSingleTex *RSMInstanceBuffer;
GlowInstanceData *GlowInstanceBuffer;
DrawElementsIndirectCommand *CmdBuffer;
DrawElementsIndirectCommand *ShadowCmdBuffer;
DrawElementsIndirectCommand *RSMCmdBuffer;
DrawElementsIndirectCommand *GlowCmdBuffer;
if (CVS->supportsAsyncInstanceUpload())
{
InstanceBufferDualTex = (InstanceDataDualTex*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeDualTex);
InstanceBufferThreeTex = (InstanceDataThreeTex*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeThreeTex);
ShadowInstanceBuffer = (InstanceDataSingleTex*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeShadow);
RSMInstanceBuffer = (InstanceDataSingleTex*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeRSM);
GlowInstanceBuffer = (GlowInstanceData*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeGlow);
CmdBuffer = SolidPassCmd::getInstance()->Ptr;
ShadowCmdBuffer = ShadowPassCmd::getInstance()->Ptr;
GlowCmdBuffer = GlowPassCmd::getInstance()->Ptr;
RSMCmdBuffer = RSMPassCmd::getInstance()->Ptr;
enableOpenMP = 1;
}
else
enableOpenMP = 0;
ListInstancedMatDefault::getInstance()->clear();
ListInstancedMatAlphaRef::getInstance()->clear();
ListInstancedMatGrass::getInstance()->clear();
ListInstancedMatNormalMap::getInstance()->clear();
ListInstancedMatSphereMap::getInstance()->clear();
ListInstancedMatDetails::getInstance()->clear();
ListInstancedMatUnlit::getInstance()->clear();
size_t SolidPoly = 0, ShadowPoly = 0;
PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF);
#pragma omp parallel sections if(enableOpenMP)
{
#pragma omp section
{
size_t offset = 0, current_cmd = 0;
if (!CVS->supportsAsyncInstanceUpload())
{
glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeDualTex));
InstanceBufferDualTex = (InstanceDataDualTex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceDataDualTex), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, SolidPassCmd::getInstance()->drawindirectcmd);
CmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
// Default Material
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID];
// Alpha Ref
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_ALPHA_TEST] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST];
// Unlit
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT];
// Spheremap
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SPHERE_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SPHERE_MAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SPHERE_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SPHERE_MAP];
// Grass
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_VEGETATION] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_VEGETATION], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_VEGETATION] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_VEGETATION];
if (!CVS->supportsAsyncInstanceUpload())
{
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeThreeTex));
InstanceBufferThreeTex = (InstanceDataThreeTex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceDataSingleTex), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
// Detail
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_DETAIL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP];
// Normal Map
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_NORMAL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP];
if (!CVS->supportsAsyncInstanceUpload())
{
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
}
#pragma omp section
{
size_t offset = 0, current_cmd = 0;
if (!CVS->supportsAsyncInstanceUpload())
{
glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeGlow));
GlowInstanceBuffer = (GlowInstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceDataDualTex), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, GlowPassCmd::getInstance()->drawindirectcmd);
GlowCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
// Glow
if (CVS->supportsIndirectInstancingRendering())
GlowPassCmd::getInstance()->Offset = offset; // Store command buffer offset
auto It = MeshForGlowPass.begin(), E = MeshForGlowPass.end();
for (; It != E; ++It)
{
size_t Polycnt = 0;
FillInstances_impl<GlowInstanceData>(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd, Polycnt);
if (!CVS->isAZDOEnabled())
ListInstancedGlow::getInstance()->push_back(It->second.front().first);
}
if (CVS->isAZDOEnabled())
GlowPassCmd::getInstance()->Size = current_cmd - GlowPassCmd::getInstance()->Offset;
if (!CVS->supportsAsyncInstanceUpload())
{
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
}
#pragma omp section
{
irr_driver->setPhase(SHADOW_PASS);
size_t offset = 0, current_cmd = 0;
if (!CVS->supportsAsyncInstanceUpload())
{
glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeShadow));
ShadowInstanceBuffer = (InstanceDataSingleTex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceDataDualTex), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ShadowPassCmd::getInstance()->drawindirectcmd);
ShadowCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
for (unsigned i = 0; i < 4; i++)
{
// Mat default
GenDrawCalls<Material::SHADERTYPE_SOLID>(i, ListInstancedMatDefault::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat AlphaRef
GenDrawCalls<Material::SHADERTYPE_ALPHA_TEST>(i, ListInstancedMatAlphaRef::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat Unlit
GenDrawCalls<Material::SHADERTYPE_SOLID_UNLIT>(i, ListInstancedMatUnlit::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat NormalMap
GenDrawCalls<Material::SHADERTYPE_NORMAL_MAP>(i, ListInstancedMatNormalMap::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat Spheremap
GenDrawCalls<Material::SHADERTYPE_SPHERE_MAP>(i, ListInstancedMatSphereMap::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat Detail
GenDrawCalls<Material::SHADERTYPE_DETAIL_MAP>(i, ListInstancedMatDetails::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
// Mat Grass
GenDrawCalls<Material::SHADERTYPE_VEGETATION>(i, ListInstancedMatGrass::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly);
}
if (!CVS->supportsAsyncInstanceUpload())
{
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
}
#pragma omp section
if (!getShadowMatrices()->isRSMMapAvail())
{
size_t offset = 0, current_cmd = 0;
if (!CVS->supportsAsyncInstanceUpload())
{
glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeRSM));
RSMInstanceBuffer = (InstanceDataSingleTex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceDataDualTex), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, RSMPassCmd::getInstance()->drawindirectcmd);
RSMCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
size_t MiscPoly = 0;
// Default Material
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID] = current_cmd;
FillInstances(MeshForRSM[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID];
// Alpha Ref
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST] = current_cmd;
FillInstances(MeshForRSM[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_ALPHA_TEST] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST];
// Unlit
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd;
FillInstances(MeshForRSM[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT];
// Detail
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP] = current_cmd;
FillInstances(MeshForRSM[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_DETAIL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP];
// Normal Map
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP] = current_cmd;
FillInstances(MeshForRSM[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_NORMAL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP];
if (!CVS->supportsAsyncInstanceUpload())
{
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
}
}
PROFILER_POP_CPU_MARKER();
m_poly_count[SOLID_NORMAL_AND_DEPTH_PASS] += SolidPoly;
m_poly_count[SHADOW_PASS] += ShadowPoly;
if (CVS->supportsAsyncInstanceUpload())
glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
#endif
}

View File

@ -22,70 +22,12 @@
#ifndef HEADER_STKSCENEMANAGER_HPP
#define HEADER_STKSCENEMANAGER_HPP
#include "graphics/central_settings.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/gpu_particles.hpp"
#include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh.hpp"
#include "utils/singleton.hpp"
#include <ICameraSceneNode.h>
#include <ISceneNode.h>
#include <vector3d.h>
template<typename T>
class CommandBuffer : public Singleton<T>
{
public:
GLuint drawindirectcmd;
DrawElementsIndirectCommand *Ptr;
CommandBuffer()
{
#if !defined(USE_GLES2)
glGenBuffers(1, &drawindirectcmd);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawindirectcmd);
if (CVS->supportsAsyncInstanceUpload())
{
glBufferStorage(GL_DRAW_INDIRECT_BUFFER, 10000 * sizeof(DrawElementsIndirectCommand), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
Ptr = (DrawElementsIndirectCommand *)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
}
else
{
glBufferData(GL_DRAW_INDIRECT_BUFFER, 10000 * sizeof(DrawElementsIndirectCommand), 0, GL_STREAM_DRAW);
}
#endif
}
};
class ImmediateDrawList : public Singleton<ImmediateDrawList>, public std::vector<scene::ISceneNode *>
{};
class BillBoardList : public Singleton<BillBoardList>, public std::vector<STKBillboard *>
{};
class ParticlesList : public Singleton<ParticlesList>, public std::vector<ParticleSystemProxy *>
{};
class SolidPassCmd : public CommandBuffer<SolidPassCmd>
{
public:
size_t Offset[Material::SHADERTYPE_COUNT], Size[Material::SHADERTYPE_COUNT];
};
class ShadowPassCmd : public CommandBuffer<ShadowPassCmd>
{
public:
size_t Offset[4][Material::SHADERTYPE_COUNT], Size[4][Material::SHADERTYPE_COUNT];
};
class RSMPassCmd : public CommandBuffer<RSMPassCmd>
{
public:
size_t Offset[Material::SHADERTYPE_COUNT], Size[Material::SHADERTYPE_COUNT];
};
class GlowPassCmd : public CommandBuffer<GlowPassCmd>
{
public:
size_t Offset, Size;
};
void addEdge(const irr::core::vector3df &P0, const irr::core::vector3df &P1);
bool isCulledPrecise(const irr::scene::ICameraSceneNode *cam, const irr::scene::ISceneNode *node);
#endif

View File

@ -16,13 +16,11 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/stk_text_billboard.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/shaders.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "guiengine/engine.hpp"
#include "glwrap.hpp"
#include "graphics/texture_manager.hpp"
#include <SMesh.h>
#include <SMeshBuffer.h>
#include <ISceneManager.h>

View File

@ -18,21 +18,7 @@
#include "graphics/sun.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/material.hpp"
#include "graphics/rtts.hpp"
#include "graphics/screen_quad.hpp"
#include "graphics/shaders.hpp"
#include "io/file_manager.hpp"
#include "modes/world.hpp"
#include "tracks/track.hpp"
using namespace video;
using namespace scene;
using namespace core;
SunNode::SunNode(scene::ISceneManager* mgr, scene::ISceneNode* parent,
float r, float g, float b)

View File

@ -16,11 +16,13 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef MEMORYMANAGER_HPP
#define MEMORYMANAGER_HPP
#ifndef HEADER_TEXTURE_MANAGER_HPP
#define HEADER_TEXTURE_MANAGER_HPP
#include "graphics/gl_headers.hpp"
#include "gl_headers.hpp"
#include <ITexture.h>
#include <SColor.h>
#include <string>
GLuint getTextureGLuint(irr::video::ITexture *tex);
@ -30,5 +32,6 @@ void cleanUnicolorTextures();
void compressTexture(irr::video::ITexture *tex, bool srgb, bool premul_alpha = false);
bool loadCompressedTexture(const std::string& compressed_tex);
void saveCompressedTexture(const std::string& compressed_tex);
irr::video::ITexture* getUnicolorTexture(const irr::video::SColor &c);
#endif

View File

@ -19,11 +19,7 @@
#include "graphics/water.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/material.hpp"
#include "graphics/rtts.hpp"
#include "graphics/shaders.hpp"
using namespace video;

View File

@ -665,6 +665,7 @@ namespace GUIEngine
#include "input/input_manager.hpp"
#include "io/file_manager.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/event_handler.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/message_queue.hpp"
@ -681,7 +682,6 @@ namespace GUIEngine
#include <iostream>
#include <assert.h>
#include <irrlicht.h>
#include "graphics/glwrap.hpp"
using namespace irr::gui;
using namespace irr::video;

View File

@ -144,6 +144,35 @@ bool EventHandler::OnEvent (const SEvent &event)
DemoWorld::resetIdleTime();
}
// Simulate mouse event for first finger on multitouch device.
// This allows to click on GUI elements.
if (event.EventType == EET_TOUCH_INPUT_EVENT)
{
if (event.TouchInput.ID == 0)
{
if (event.TouchInput.Event == ETIE_PRESSED_DOWN)
{
SEvent irrevent;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = event.TouchInput.X;
irrevent.MouseInput.Y = event.TouchInput.Y;
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
irr_driver->getDevice()->postEventFromUser(irrevent);
}
else if (event.TouchInput.Event == ETIE_LEFT_UP)
{
SEvent irrevent;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = event.TouchInput.X;
irrevent.MouseInput.Y = event.TouchInput.Y;
irrevent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
irr_driver->getDevice()->postEventFromUser(irrevent);
}
}
}
if (event.EventType == EET_GUI_EVENT)
{
return onGUIEvent(event) == EVENT_BLOCK;
@ -155,6 +184,7 @@ bool EventHandler::OnEvent (const SEvent &event)
return false; // EVENT_LET
}
else if (event.EventType == EET_MOUSE_INPUT_EVENT ||
event.EventType == EET_TOUCH_INPUT_EVENT ||
event.EventType == EET_KEY_INPUT_EVENT ||
event.EventType == EET_JOYSTICK_INPUT_EVENT)
{

View File

@ -33,7 +33,6 @@
#include "io/file_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/log.hpp"
#include "graphics/glwrap.hpp"
using namespace GUIEngine;
using namespace irr;
@ -1959,29 +1958,7 @@ void Skin::process3DPane(IGUIElement *element, const core::recti &rect,
else if (type == WTYPE_MODEL_VIEW)
{
ModelViewWidget* mvw = dynamic_cast<ModelViewWidget*>(widget);
if (CVS->isGLSL())
{
FrameBuffer* fb = mvw->getFrameBuffer();
if (fb != NULL && fb->getRTT().size() > 0)
{
glEnable(GL_FRAMEBUFFER_SRGB);
draw2DImageFromRTT(fb->getRTT()[0], 512, 512,
rect, core::rect<s32>(0, 0, 512, 512), NULL,
SColor(255, 255, 255, 255), true);
glDisable(GL_FRAMEBUFFER_SRGB);
}
}
else
{
video::ITexture* texture = mvw->getTexture();
if (texture != NULL && texture->getSize().Width > 0
&& texture->getSize().Height > 0)
{
draw2DImage(texture, rect, core::rect<s32>(0, 0, 512, 512),
NULL, NULL, true);
}
}
mvw->drawRTTScene(rect);
}
else if (type == WTYPE_ICON_BUTTON)
{

View File

@ -21,8 +21,7 @@
#include "guiengine/engine.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/post_processing.hpp"
#include "graphics/rtts.hpp"
#include "graphics/render_target.hpp"
#include <IAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h>
@ -40,14 +39,11 @@ using namespace irr::gui;
ModelViewWidget::ModelViewWidget() :
IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false, false)
{
m_frame_buffer = NULL;
m_texture = NULL;
m_rtt_main_node = NULL;
m_camera = NULL;
m_light = NULL;
m_type = WTYPE_MODEL_VIEW;
m_rtt_provider = NULL;
m_old_rtt_provider = NULL;
m_render_target = NULL;
m_rotation_mode = ROTATE_OFF;
m_render_info = new RenderInfo();
m_angle = 0;
@ -61,14 +57,6 @@ IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false,
ModelViewWidget::~ModelViewWidget()
{
GUIEngine::needsUpdate.remove(this);
delete m_rtt_provider;
m_rtt_provider = NULL;
delete m_old_rtt_provider;
m_old_rtt_provider = NULL;
m_texture = NULL;
delete m_render_info;
}
// -----------------------------------------------------------------------------
@ -120,9 +108,8 @@ void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location,
m_model_frames.push_back(frame);
m_model_render_info_affected.push_back(all_parts_colorized);
delete m_old_rtt_provider;
m_old_rtt_provider = NULL;
m_texture = NULL;
if (!CVS->isGLSL())
m_render_target = NULL;
}
// -----------------------------------------------------------------------------
@ -175,11 +162,11 @@ void ModelViewWidget::update(float delta)
if (fabsf(m_angle - m_rotation_target) < 2.0f) m_rotation_mode = ROTATE_OFF;
}
if (CVS->isGLSL())
if (m_render_target == NULL)
{
if (m_rtt_provider == NULL)
{
m_rtt_provider = new RTT(512, 512);
std::string name = "model view ";
name += m_properties[PROP_ID].c_str();
m_render_target = irr_driver->createRenderTarget(irr::core::dimension2du(512,512), name);
}
if (m_rtt_main_node == NULL)
@ -191,27 +178,9 @@ void ModelViewWidget::update(float delta)
m_rtt_main_node->setVisible(true);
m_frame_buffer = m_rtt_provider->render(m_camera, GUIEngine::getLatestDt());
m_render_target->renderToTexture(m_camera, GUIEngine::getLatestDt());
m_rtt_main_node->setVisible(false);
}
else
{
if (m_old_rtt_provider == NULL)
{
std::string name = "model view ";
name += m_properties[PROP_ID].c_str();
m_old_rtt_provider = new IrrDriver::RTTProvider(core::dimension2d<u32>(512, 512), name, false);
m_old_rtt_provider->setupRTTScene(m_models, m_model_location, m_model_scale, m_model_frames);
}
m_texture = m_old_rtt_provider->renderToTexture(m_angle);
if (m_texture == NULL)
{
m_rtt_unsupported = true;
}
}
}
void ModelViewWidget::setupRTTScene()
@ -286,7 +255,21 @@ void ModelViewWidget::setupRTTScene()
irr_driver->setAmbientLight(video::SColor(255, 35, 35, 35));
const core::vector3df &spot_pos = core::vector3df(0, 30, 40);
if (!CVS->isGLSL())
{
scene::ILightSceneNode* light = irr_driver->getSceneManager()
->addLightSceneNode(NULL, spot_pos, video::SColorf(1.0f,1.0f,1.0f),
1600 /* radius */);
light->setLightType(video::ELT_SPOT);
light->setRotation((core::vector3df(0, 10, 0) - spot_pos).getHorizontalAngle());
light->updateAbsolutePosition();
m_light = light;
}
else
{
m_light = irr_driver->addLight(spot_pos, 0.3f /* energy */, 10 /* distance */, 1.0f /* r */, 1.0f /* g */, 1.0f /* g*/, true, NULL);
}
m_rtt_main_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true);
m_rtt_main_node->setMaterialFlag(video::EMF_LIGHTING, true);
@ -314,7 +297,6 @@ void ModelViewWidget::setupRTTScene()
m_camera->setFOV(DEGREE_TO_RAD*50.0f);
m_camera->updateAbsolutePosition();
m_rtt_provider->prepareRender(m_camera);
}
void ModelViewWidget::setRotateOff()
@ -340,22 +322,17 @@ bool ModelViewWidget::isRotating()
void ModelViewWidget::elementRemoved()
{
delete m_rtt_provider;
m_rtt_provider = NULL;
delete m_old_rtt_provider;
m_old_rtt_provider = NULL;
m_texture = NULL;
m_render_target = NULL;
IconButtonWidget::elementRemoved();
}
void ModelViewWidget::clearRttProvider()
{
delete m_rtt_provider;
m_rtt_provider = NULL;
delete m_old_rtt_provider;
m_old_rtt_provider = NULL;
m_texture = NULL;
m_render_target = NULL;
}
void ModelViewWidget::drawRTTScene(const irr::core::rect<s32>& dest_rect) const
{
if(m_render_target != NULL)
m_render_target->draw2DImage(dest_rect, NULL, video::SColor(255, 255, 255, 255), true);
}

View File

@ -52,10 +52,7 @@ namespace GUIEngine
AlignedArray<Vec3> m_model_scale;
std::vector<int> m_model_frames;
std::vector<bool> m_model_render_info_affected;
RTT* m_rtt_provider;
IrrDriver::RTTProvider* m_old_rtt_provider;
std::unique_ptr<RenderTarget> m_render_target;
float m_angle;
bool m_rtt_unsupported;
@ -66,9 +63,6 @@ namespace GUIEngine
scene::ISceneNode *m_light;
FrameBuffer *m_frame_buffer;
video::ITexture *m_texture;
RenderInfo *m_render_info;
public:
@ -106,8 +100,8 @@ namespace GUIEngine
void setupRTTScene();
FrameBuffer* getFrameBuffer() { return m_frame_buffer; }
video::ITexture* getTexture() { return m_texture; }
void drawRTTScene(const irr::core::rect<s32>& dest_rect) const;
RenderInfo* getModelViewRenderInfo() { return m_render_info; }
};

View File

@ -25,6 +25,7 @@
#include "graphics/irr_driver.hpp"
#include "input/gamepad_device.hpp"
#include "input/keyboard_device.hpp"
#include "input/multitouch_device.hpp"
#include "input/wiimote_manager.hpp"
#include "io/file_manager.hpp"
#include "states_screens/kart_selection.hpp"
@ -43,6 +44,7 @@ DeviceManager::DeviceManager()
m_latest_used_device = NULL;
m_assign_mode = NO_ASSIGN;
m_single_player = NULL;
m_multitouch_device = NULL;
} // DeviceManager
// -----------------------------------------------------------------------------
@ -138,6 +140,11 @@ bool DeviceManager::initialize()
addGamepad(gamepadDevice);
} // end for
if (UserConfigParams::m_multitouch_enabled)
{
m_multitouch_device = new MultitouchDevice();
}
if (created) save();
return created;
@ -154,6 +161,12 @@ void DeviceManager::clearGamepads()
{
m_gamepads.clearAndDeleteAll();
} // clearGamepads
// -----------------------------------------------------------------------------
void DeviceManager::clearMultitouchDevices()
{
delete m_multitouch_device;
m_multitouch_device = NULL;
} // clearMultitouchDevices
// -----------------------------------------------------------------------------
void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
@ -177,6 +190,9 @@ void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
{
m_keyboards[i].setPlayer(NULL);
}
if (m_multitouch_device != NULL)
m_multitouch_device->setPlayer(NULL);
}
} // setAssignMode
@ -391,6 +407,25 @@ InputDevice *DeviceManager::mapGamepadInput(Input::InputType type,
//-----------------------------------------------------------------------------
void DeviceManager::updateMultitouchDevice()
{
if (m_multitouch_device == NULL)
return;
if (m_single_player != NULL)
{
// in single-player mode, assign the gamepad as needed
if (m_multitouch_device->getPlayer() != m_single_player)
m_multitouch_device->setPlayer(m_single_player);
}
else if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
{
m_multitouch_device->setPlayer(NULL);
}
} // updateMultitouchDevice
//-----------------------------------------------------------------------------
bool DeviceManager::translateInput( Input::InputType type,
int device_id,
int button_id,
@ -604,5 +639,7 @@ void DeviceManager::shutdown()
m_keyboards.clearAndDeleteAll();
m_gamepad_configs.clearAndDeleteAll();
m_keyboard_configs.clearAndDeleteAll();
delete m_multitouch_device;
m_multitouch_device = NULL;
m_latest_used_device = NULL;
} // shutdown

View File

@ -34,6 +34,7 @@ class DeviceConfig;
class InputDevice;
class GamePadDevice;
class KeyboardDevice;
class MultitouchDevice;
enum PlayerAssignMode
@ -66,6 +67,7 @@ private:
PtrVector<GamePadDevice, HOLD> m_gamepads;
PtrVector<KeyboardConfig, HOLD> m_keyboard_configs;
PtrVector<GamepadConfig, HOLD> m_gamepad_configs;
MultitouchDevice* m_multitouch_device;
/** The list of all joysticks that were found and activated. */
core::array<SJoystickInfo> m_irrlicht_gamepads;
@ -129,6 +131,11 @@ public:
KeyboardConfig* getKeyboardConfig(const int i) { return m_keyboard_configs.get(i); }
KeyboardDevice* getKeyboardFromBtnID(const int btnID);
// ---- Multitouch device ----
MultitouchDevice* getMultitouchDevice() { return m_multitouch_device; }
void clearMultitouchDevices();
void updateMultitouchDevice();
/**
* \brief Delete the given config and removes DeviceManager references to it.

View File

@ -36,7 +36,8 @@ class DeviceConfig;
enum DeviceType
{
DT_KEYBOARD,
DT_GAMEPAD
DT_GAMEPAD,
DT_MULTITOUCH
};
/**

View File

@ -28,6 +28,7 @@
#include "input/device_manager.hpp"
#include "input/gamepad_device.hpp"
#include "input/keyboard_device.hpp"
#include "input/multitouch_device.hpp"
#include "input/input.hpp"
#include "karts/controller/controller.hpp"
#include "karts/abstract_kart.hpp"
@ -1014,6 +1015,30 @@ EventPropagation InputManager::input(const SEvent& event)
return EVENT_BLOCK; // Don't propagate key up events
}
}
else if (event.EventType == EET_TOUCH_INPUT_EVENT)
{
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
unsigned int id = event.TouchInput.ID;
if (device != NULL && id < device->m_events.size())
{
device->m_events[id].id = id;
device->m_events[id].x = event.TouchInput.X;
device->m_events[id].y = event.TouchInput.Y;
if (event.TouchInput.Event == ETIE_PRESSED_DOWN)
{
device->m_events[id].touched = true;
}
else if (event.TouchInput.Event == ETIE_LEFT_UP)
{
device->m_events[id].touched = false;
}
m_device_manager->updateMultitouchDevice();
device->updateDeviceState(id);
}
}
// Use the mouse to change the looking direction when first person view is activated
else if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
@ -1096,6 +1121,35 @@ EventPropagation InputManager::input(const SEvent& event)
}
}
// Simulate touch event on non-android devices
#if !defined(ANDROID)
if (UserConfigParams::m_multitouch_enabled == true &&
(type == EMIE_LMOUSE_PRESSED_DOWN || type == EMIE_LMOUSE_LEFT_UP ||
type == EMIE_MOUSE_MOVED))
{
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
if (device != NULL)
{
device->m_events[0].id = 0;
device->m_events[0].x = event.MouseInput.X;
device->m_events[0].y = event.MouseInput.Y;
if (type == EMIE_LMOUSE_PRESSED_DOWN)
{
device->m_events[0].touched = true;
}
else if (type == EMIE_LMOUSE_LEFT_UP)
{
device->m_events[0].touched = false;
}
m_device_manager->updateMultitouchDevice();
device->updateDeviceState(0);
}
}
#endif
/*
EMIE_LMOUSE_PRESSED_DOWN Left mouse button was pressed down.
EMIE_RMOUSE_PRESSED_DOWN Right mouse button was pressed down.

View File

@ -0,0 +1,306 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-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.
#include <cassert>
#include <algorithm>
#include "config/user_config.hpp"
#include "input/multitouch_device.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/modaldialog.hpp"
// ----------------------------------------------------------------------------
/** The multitouch device constructor
*/
MultitouchDevice::MultitouchDevice()
{
m_configuration = NULL;
m_type = DT_MULTITOUCH;
m_name = "Multitouch";
m_player = NULL;
for (MultitouchEvent& event : m_events)
{
event.id = 0;
event.touched = false;
event.x = 0;
event.y = 0;
}
m_deadzone_center = UserConfigParams::m_multitouch_deadzone_center;
m_deadzone_center = std::min(std::max(m_deadzone_center, 0.0f), 0.5f);
m_deadzone_edge = UserConfigParams::m_multitouch_deadzone_edge;
m_deadzone_edge = std::min(std::max(m_deadzone_edge, 0.0f), 0.5f);
} // MultitouchDevice
// ----------------------------------------------------------------------------
/** The multitouch device destructor
*/
MultitouchDevice::~MultitouchDevice()
{
clearButtons();
}
// ----------------------------------------------------------------------------
/** Returns a number of fingers that are currently in use
*/
unsigned int MultitouchDevice::getActiveTouchesCount()
{
unsigned int count = 0;
for (MultitouchEvent event : m_events)
{
if (event.touched)
count++;
}
return count;
} // getActiveTouchesCount
// ----------------------------------------------------------------------------
/** Creates a button of specified type and position. The button is then updated
* when touch event occurs and proper action is sent to player controller.
* Note that it just determines the screen area that is considered as button
* and it doesn't draw the GUI element on a screen.
* \param type The button type that determines its behaviour.
* \param x Vertical position of the button.
* \param y Horizontal position of the button.
* \param width Width of the button.
* \param height Height of the button.
*/
void MultitouchDevice::addButton(MultitouchButtonType type, int x, int y,
int width, int height)
{
assert(width > 0 && height > 0);
MultitouchButton* button = new MultitouchButton();
button->type = type;
button->event_id = 0;
button->pressed = false;
button->x = x;
button->y = y;
button->width = width;
button->height = height;
button->axis_x = 0.0f;
button->axis_y = 0.0f;
switch (button->type)
{
case MultitouchButtonType::BUTTON_FIRE:
button->action = PA_FIRE;
break;
case MultitouchButtonType::BUTTON_NITRO:
button->action = PA_NITRO;
break;
case MultitouchButtonType::BUTTON_SKIDDING:
button->action = PA_DRIFT;
break;
case MultitouchButtonType::BUTTON_LOOK_BACKWARDS:
button->action = PA_LOOK_BACK;
break;
case MultitouchButtonType::BUTTON_RESCUE:
button->action = PA_RESCUE;
break;
case MultitouchButtonType::BUTTON_ESCAPE:
button->action = PA_PAUSE_RACE;
break;
case MultitouchButtonType::BUTTON_UP:
button->action = PA_ACCEL;
break;
case MultitouchButtonType::BUTTON_DOWN:
button->action = PA_BRAKE;
break;
case MultitouchButtonType::BUTTON_LEFT:
button->action = PA_STEER_LEFT;
break;
case MultitouchButtonType::BUTTON_RIGHT:
button->action = PA_STEER_RIGHT;
break;
default:
button->action = PA_BEFORE_FIRST;
break;
}
m_buttons.push_back(button);
} // addButton
// ----------------------------------------------------------------------------
/** Deletes all previously created buttons
*/
void MultitouchDevice::clearButtons()
{
for (MultitouchButton* button : m_buttons)
{
delete button;
}
m_buttons.clear();
} // clearButtons
// ----------------------------------------------------------------------------
/** The function that is executed when touch event occurs. It updates the
* buttons state when it's needed.
* \param event_id The id of touch event that should be processed.
*/
void MultitouchDevice::updateDeviceState(unsigned int event_id)
{
assert(event_id < m_events.size());
MultitouchEvent event = m_events[event_id];
for (MultitouchButton* button : m_buttons)
{
bool update_controls = false;
bool prev_button_state = button->pressed;
float prev_axis_x = button->axis_x;
float prev_axis_y = button->axis_y;
if (event.x < button->x || event.x > button->x + button->width ||
event.y < button->y || event.y > button->y + button->height)
{
if (button->event_id == event_id)
{
button->pressed = false;
button->event_id = 0;
button->axis_x = 0.0f;
button->axis_y = 0.0f;
update_controls = true;
}
}
else
{
button->pressed = event.touched;
button->event_id = event_id;
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
if (button->pressed == true)
{
button->axis_x = (float)(event.x - button->x) /
(button->width/2) - 1;
button->axis_y = (float)(event.y - button->y) /
(button->height/2) - 1;
}
else
{
button->axis_x = 0.0f;
button->axis_y = 0.0f;
}
if (prev_axis_x != button->axis_x ||
prev_axis_y != button->axis_y)
{
update_controls = true;
}
}
else if (prev_button_state != button->pressed)
{
update_controls = true;
}
}
if (update_controls)
{
handleControls(button);
}
}
} // updateDeviceState
// ----------------------------------------------------------------------------
/** Sends proper action for player controller depending on the button type
* and state.
* \param button The button that should be handled.
*/
void MultitouchDevice::handleControls(MultitouchButton* button)
{
if (m_player == NULL)
return;
// Handle multitouch events only when race is running. It avoids to process
// it when pause dialog is active during the race. And there is no reason
// to use it for GUI navigation.
if (StateManager::get()->getGameState() != GUIEngine::GAME ||
GUIEngine::ModalDialog::isADialogActive() ||
race_manager->isWatchingReplay())
return;
AbstractKart* pk = m_player->getKart();
if (pk == NULL)
return;
Controller* controller = pk->getController();
if (controller == NULL)
return;
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
assert(m_deadzone_edge != 1.0f);
if (button->axis_y < -m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_y) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_ACCEL, factor * Input::MAX_VALUE);
}
else if (button->axis_y > m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_y) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_BRAKE, factor * Input::MAX_VALUE);
}
else
{
controller->action(PA_BRAKE, 0);
controller->action(PA_ACCEL, 0);
}
if (button->axis_x < -m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_x) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_STEER_LEFT, factor * Input::MAX_VALUE);
}
else if (button->axis_x > m_deadzone_center)
{
float factor = std::min(std::abs(button->axis_x) / (1 -
m_deadzone_edge), 1.0f);
controller->action(PA_STEER_RIGHT, factor * Input::MAX_VALUE);
}
else
{
controller->action(PA_STEER_LEFT, 0);
controller->action(PA_STEER_RIGHT, 0);
}
}
else
{
if (button->action != PA_BEFORE_FIRST)
{
int value = button->pressed ? Input::MAX_VALUE : 0;
controller->action(button->action, value);
}
}
} // handleControls
// ----------------------------------------------------------------------------

View File

@ -0,0 +1,111 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-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_MULTITOUCH_DEVICE_HPP
#define HEADER_MULTITOUCH_DEVICE_HPP
#include <array>
#include <vector>
#include "input/input_device.hpp"
#include "IEventReceiver.h"
#define NUMBER_OF_MULTI_TOUCHES 10
enum MultitouchButtonType
{
BUTTON_STEERING,
BUTTON_FIRE,
BUTTON_NITRO,
BUTTON_SKIDDING,
BUTTON_LOOK_BACKWARDS,
BUTTON_RESCUE,
BUTTON_ESCAPE,
BUTTON_UP,
BUTTON_DOWN,
BUTTON_LEFT,
BUTTON_RIGHT
};
struct MultitouchEvent
{
int id;
bool touched;
int x;
int y;
};
struct MultitouchButton
{
MultitouchButtonType type;
PlayerAction action;
bool pressed;
unsigned int event_id;
int x;
int y;
int width;
int height;
float axis_x;
float axis_y;
};
class MultitouchDevice : public InputDevice
{
private:
/** The list of pointers to all created buttons */
std::vector<MultitouchButton*> m_buttons;
/** The parameter that is used for steering button and determines dead area
* in a center of button */
float m_deadzone_center;
/** The parameter that is used for steering button and determines dead area
* at the edge of button */
float m_deadzone_edge;
public:
/** The array that contains data for all multitouch input events */
std::array<MultitouchEvent, NUMBER_OF_MULTI_TOUCHES> m_events;
MultitouchDevice();
virtual ~MultitouchDevice();
/** Unused function */
bool processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction *action, int* value = NULL)
{return true;}
unsigned int getActiveTouchesCount();
void addButton(MultitouchButtonType type, int x, int y, int width,
int height);
void clearButtons();
/** Returns the number of created buttons */
unsigned int getButtonsCount() {return m_buttons.size();}
/** Returns pointer to the selected button */
MultitouchButton* getButton(unsigned int i) {return m_buttons.at(i);}
void updateDeviceState(unsigned int event_id);
void handleControls(MultitouchButton* button);
}; // MultitouchDevice
#endif

View File

@ -43,7 +43,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
m_distance_2 = 1.2f;
initItem(type, xyz);
m_original_rotation = Track::createRotationFromNormal(normal);
m_original_rotation = shortestArcQuat(Vec3(0, 1, 0), normal);
m_rotation_angle = 0.0f;
m_original_mesh = mesh;
m_original_lowmesh = lowres_mesh;

View File

@ -20,10 +20,10 @@
#include <IMeshSceneNode.h>
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/texture_manager.hpp"
#include "items/plunger.hpp"
#include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp"

View File

@ -25,7 +25,6 @@
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/post_processing.hpp"
#include "input/input_manager.hpp"
#include "items/attachment.hpp"
#include "items/item.hpp"
@ -265,8 +264,7 @@ void LocalPlayerController::handleZipper(bool play_sound)
}
// Apply the motion blur according to the speed of the kart
irr_driver->getPostProcessing()->giveBoost(m_camera_index);
irr_driver->giveBoost(m_camera_index);
} // handleZipper
//-----------------------------------------------------------------------------

View File

@ -20,8 +20,6 @@
#include "karts/controller/player_controller.hpp"
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/post_processing.hpp"
#include "input/input_manager.hpp"
#include "items/attachment.hpp"
#include "items/item.hpp"

View File

@ -22,8 +22,8 @@
#include "karts/controller/skidding_ai.hpp"
#ifdef AI_DEBUG
# include "graphics/glwrap.hpp"
# include "graphics/irr_driver.hpp"
# include "graphics/texture_manager.hpp"
#endif
#include "graphics/show_curve.hpp"
#include "graphics/slip_stream.hpp"

View File

@ -22,8 +22,8 @@
#include "karts/controller/test_ai.hpp"
#ifdef AI_DEBUG
# include "graphics/glwrap.hpp"
# include "graphics/irr_driver.hpp"
# include "graphics/texture_manager.hpp"
#endif
#include "graphics/show_curve.hpp"
#include "graphics/slip_stream.hpp"

View File

@ -21,9 +21,9 @@
#include "addons/addon.hpp"
#include "config/stk_config.hpp"
#include "config/player_manager.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/texture_manager.hpp"
#include "io/file_manager.hpp"
#include "karts/cached_characteristic.hpp"
#include "karts/combined_characteristic.hpp"

View File

@ -578,6 +578,7 @@ void cmdLineHelp()
" --password=s Automatically log in (set the password).\n"
" --port=n Port number to use.\n"
" --my-address=1.1.1.1:1 Own IP address (can replace stun protocol)\n"
" --disable-lan Disable LAN detection (connect using WAN).\n"
" --max-players=n Maximum number of clients (server only).\n"
" --no-console Does not write messages in the console but to\n"
" stdout.log.\n"
@ -1016,6 +1017,11 @@ int handleCmdLine()
if (CommandLine::has("--my-address", &s))
GetPublicAddress::setMyIPAddress(s);
/** Disable detection of LAN connection when connecting via WAN. This is
* mostly a debugging feature to force using WAN connection. */
if (CommandLine::has("--disable-lan"))
NetworkConfig::m_disable_lan = true;
// Race parameters
if(CommandLine::has("--kartsize-debug"))
{

View File

@ -104,10 +104,15 @@ float MainLoop::getLimitedDt()
}
// don't allow the game to run slower than a certain amount.
// Don't allow the game to run slower than a certain amount.
// when the computer can't keep it up, slow down the shown time instead
static const float max_elapsed_time = 3.0f*1.0f/60.0f*1000.0f; /* time 3 internal substeps take */
if(dt > max_elapsed_time) dt=max_elapsed_time;
// But this can not be done in networking, otherwise the game time on
// client and server will not be in synch anymore
if(!NetworkConfig::get()->isNetworking())
{
static const float max_elapsed_time = 3.0f*1.0f / 60.0f*1000.0f; /* time 3 internal substeps take */
if (dt > max_elapsed_time) dt = max_elapsed_time;
}
// Throttle fps if more than maximum, which can reduce
// the noise the fan on a graphics card makes.

View File

@ -711,7 +711,7 @@ void ThreeStrikesBattle::loadCustomModels()
const ArenaNode* n = ag->getNode(node);
btTransform t;
t.setOrigin(n->getCenter());
t.setRotation(Track::createRotationFromNormal(n->getNormal()));
t.setRotation(shortestArcQuat(Vec3(0, 1, 0), n->getNormal()));
pos.push_back(t);
pos_created++;
used.push_back(node);

View File

@ -19,6 +19,7 @@
#include "network/network_config.hpp"
NetworkConfig *NetworkConfig::m_network_config = NULL;
bool NetworkConfig::m_disable_lan = false;
/** \class NetworkConfig
* This class is the interface between STK and the online code, particularly

View File

@ -72,6 +72,10 @@ private:
NetworkConfig();
public:
/** Stores the command line flag to disable lan detection (i.e. force
* WAN code to be used when connection client and server). */
static bool m_disable_lan;
/** Singleton get, which creates this object if necessary. */
static NetworkConfig *get()
{

View File

@ -43,8 +43,10 @@ NetworkConsole::NetworkConsole()
// ----------------------------------------------------------------------------
NetworkConsole::~NetworkConsole()
{
#ifndef ANDROID
if (m_thread_keyboard)
pthread_cancel(*m_thread_keyboard);//, SIGKILL);
#endif
}
// ----------------------------------------------------------------------------

View File

@ -125,9 +125,10 @@ void ConnectToPeer::asynchronousUpdate()
// the Ping protocol to keep the port available. We can't rely on
// STKHost::isLAN(), since we might get a LAN connection even if
// the server itself accepts connections from anywhere.
if (!m_is_lan &&
m_peer_address.getIP() != NetworkConfig::get()
->getMyAddress().getIP())
if ( (!m_is_lan &&
m_peer_address.getIP() !=
NetworkConfig::get()->getMyAddress().getIP() ) ||
NetworkConfig::m_disable_lan )
{
m_current_protocol = new PingProtocol(m_peer_address,
/*time-between-ping*/2.0);

View File

@ -175,9 +175,10 @@ void ConnectToServer::asynchronousUpdate()
m_current_protocol->requestStart();
return;
}
if (m_server_address.getIP()
== NetworkConfig::get()->getMyAddress().getIP() ||
NetworkConfig::get()->isLAN())
if( ( !NetworkConfig::m_disable_lan &&
m_server_address.getIP()
== NetworkConfig::get()->getMyAddress().getIP() ) ||
NetworkConfig::get()->isLAN() )
{
// We're in the same lan (same public ip address).
// The state will change to CONNECTING

View File

@ -66,7 +66,7 @@ void GetPeerAddress::asynchronousUpdate()
uint16_t port;
uint32_t my_ip = NetworkConfig::get()->getMyAddress().getIP();
if (m_address.getIP() == my_ip)
if (m_address.getIP() == my_ip && !NetworkConfig::m_disable_lan)
result->get("private_port", &port);
else
result->get("port", &port);

View File

@ -136,6 +136,12 @@ bool StartGameProtocol::notifyEventAsynchronous(Event* event)
if (NetworkConfig::get()->isServer() && ready) // on server, player is ready
{
Log::info("StartGameProtocol", "One of the players is ready.");
if (m_player_states[player_id] != LOADING)
{
Log::error("StartGameProtocol",
"Player %d send more than one ready message.",
player_id);
}
m_player_states[player_id] = READY;
m_ready_count++;
if (m_ready_count == m_game_setup->getPlayerCount())
@ -159,7 +165,7 @@ void StartGameProtocol::startRace()
Protocol *p = ProtocolManager::getInstance()
->getProtocol(PROTOCOL_SYNCHRONIZATION);
SynchronizationProtocol* protocol =
static_cast<SynchronizationProtocol*>(p);
dynamic_cast<SynchronizationProtocol*>(p);
if (protocol)
{
protocol->startCountdown(5.0f); // 5 seconds countdown
@ -185,7 +191,7 @@ void StartGameProtocol::update(float dt)
Protocol *p = ProtocolManager::getInstance()
->getProtocol(PROTOCOL_SYNCHRONIZATION);
SynchronizationProtocol* protocol =
static_cast<SynchronizationProtocol*>(p);
dynamic_cast<SynchronizationProtocol*>(p);
if (protocol)
{
// Now the synchronization protocol exists.

View File

@ -47,7 +47,7 @@
#include <signal.h>
STKHost *STKHost::m_stk_host = NULL;
bool STKHost::m_enable_console = true;
bool STKHost::m_enable_console = false;
void STKHost::create()
{
@ -184,7 +184,7 @@ void STKHost::create()
* This triggers the creation of the kart selection screen in
* CLR::startSelection / CLR::update for all clients. The clients create
* the ActivePlayer object (which stores which device is used by which
* plauyer). The kart selection in a client calls
* player). The kart selection in a client calls
* (NetworkKartSelection::playerConfirm) which calls CLR::requestKartSelection.
* This sends a message to SLR::kartSelectionRequested, which verifies the
* selected kart and sends this information to all clients (including the
@ -219,7 +219,7 @@ void STKHost::create()
* NULL ActivePlayer (the ActivePlayer is only used for assigning the input
* device to each kart, achievements and highscores, so it's not needed for
* remote players). It will also start the SynchronizationProtocol.
* The StartGameProtocol has a callback ready which is called from world
* The StartGameProtocol has a callback ready() which is called from world
* when the world is loaded (i.e. track and all karts are ready). When
* this callback is invoked, each client will send a 'ready' message to
* the server's StartGameProtocol. Once the server has received all
@ -228,7 +228,7 @@ void STKHost::create()
* sending regular (once per second) pings to the clients and measure
* the averate latency. Upon starting the countdown this information
* is included in the ping request, so the clients can start the countdown
* at that stage as wellk.
* at that stage as well.
*
* Once the countdown is 0 (or below), the Synchronization Protocol will
* start the protocols: KartUpdateProtocol, ControllerEventsProtocol,
@ -323,6 +323,7 @@ void STKHost::init()
ProtocolManager::getInstance<ProtocolManager>();
// Optional: start the network console
m_network_console = NULL;
if(m_enable_console)
{
m_network_console = new NetworkConsole();

View File

@ -104,10 +104,6 @@ namespace Online
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Should be the default, but just in case:
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
m_thread_id.setAtomic(new pthread_t());
int error = pthread_create(m_thread_id.getData(), &attr,
&RequestManager::mainLoop, this);
@ -189,8 +185,6 @@ namespace Online
VS::setThreadName("RequestManager");
RequestManager *me = (RequestManager*) obj;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
me->m_current_request = NULL;
me->m_request_queue.lock();
while (me->m_request_queue.getData().empty() ||

View File

@ -199,10 +199,11 @@ void NetworkingLobby::tearDown()
bool NetworkingLobby::onEscapePressed()
{
// notify the server that we left
ClientLobbyRoomProtocol* protocol = static_cast<ClientLobbyRoomProtocol*>(
ClientLobbyRoomProtocol* protocol = dynamic_cast<ClientLobbyRoomProtocol*>(
ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM));
if (protocol)
protocol->leave();
STKHost::get()->shutdown();
return true; // close the screen
} // onEscapePressed

View File

@ -27,7 +27,7 @@ using namespace irr;
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/modaldialog.hpp"
@ -35,10 +35,13 @@ using namespace irr;
#include "io/file_manager.hpp"
#include "input/input.hpp"
#include "input/input_manager.hpp"
#include "input/device_manager.hpp"
#include "input/multitouch_device.hpp"
#include "items/attachment.hpp"
#include "items/attachment_manager.hpp"
#include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/controller/spare_tire_ai.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
@ -83,6 +86,11 @@ RaceGUI::RaceGUI()
{
m_map_left = irr_driver->getActualScreenSize().Width - m_map_width;
}
else if (UserConfigParams::m_multitouch_enabled)
{
m_map_left = irr_driver->getActualScreenSize().Width - m_map_width;
m_map_bottom = irr_driver->getActualScreenSize().Height * 0.55f;
}
m_is_tutorial = (race_manager->getTrackName() == "tutorial");
@ -104,11 +112,22 @@ RaceGUI::RaceGUI()
else
m_lap_width = font->getDimension(L"9/9").Width;
if (UserConfigParams::m_multitouch_enabled)
{
initMultitouchSteering();
}
} // RaceGUI
//-----------------------------------------------------------------------------
RaceGUI::~RaceGUI()
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device != NULL)
{
device->clearButtons();
}
} // ~Racegui
@ -216,10 +235,19 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt)
scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size
drawAllMessages(kart, viewport, scaling);
if (UserConfigParams::m_multitouch_enabled)
{
drawMultitouchSteering(kart, viewport, scaling);
}
if(!World::getWorld()->isRacePhase()) return;
drawPowerupIcons (kart, viewport, scaling);
drawPowerupIcons(kart, viewport, scaling);
if (!UserConfigParams::m_multitouch_enabled)
{
drawSpeedEnergyRank(kart, viewport, scaling, dt);
}
if (!m_is_tutorial)
drawLap(kart, viewport, scaling);
@ -348,30 +376,13 @@ void RaceGUI::drawGlobalMiniMap()
!(world->getTrack()->hasNavMesh()))
return;
const video::ITexture *old_rtt_mini_map = world->getTrack()->getOldRttMiniMap();
const FrameBuffer* new_rtt_mini_map = world->getTrack()->getNewRttMiniMap();
int upper_y = irr_driver->getActualScreenSize().Height - m_map_bottom - m_map_height;
int lower_y = irr_driver->getActualScreenSize().Height - m_map_bottom;
core::rect<s32> dest(m_map_left, upper_y,
m_map_left + m_map_width, lower_y);
if (old_rtt_mini_map != NULL)
{
core::rect<s32> source(core::position2di(0, 0),
old_rtt_mini_map->getSize());
draw2DImage(old_rtt_mini_map, dest, source,
NULL, NULL, true);
}
else if (new_rtt_mini_map != NULL)
{
core::rect<s32> source(0, 0, (int)new_rtt_mini_map->getWidth(),
(int)new_rtt_mini_map->getHeight());
draw2DImageFromRTT(new_rtt_mini_map->getRTT()[0],
new_rtt_mini_map->getWidth(), new_rtt_mini_map->getHeight(),
dest, source, NULL, video::SColor(127, 255, 255, 255), true);
}
world->getTrack()->drawMiniMap(dest);
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
@ -878,3 +889,157 @@ void RaceGUI::drawLap(const AbstractKart* kart,
font->setScale(1.0f);
} // drawLap
//-----------------------------------------------------------------------------
/** Makes some initializations and determines the look of multitouch steering
* interface
*/
void RaceGUI::initMultitouchSteering()
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device == NULL)
return;
const int w = irr_driver->getActualScreenSize().Width;
const int h = irr_driver->getActualScreenSize().Height;
const float btn_size = 0.1f * h;
const float btn2_size = 0.35f * h;
const float margin = 0.1f * h;
const float top_margin = 0.3f * h;
const float col_size = btn_size + margin;
const float small_ratio = 0.6f;
device->addButton(BUTTON_STEERING,
0.5f * margin, h - 0.5f * margin - btn2_size,
btn2_size, btn2_size);
device->addButton(BUTTON_ESCAPE,
top_margin, small_ratio * margin,
small_ratio * btn_size, small_ratio * btn_size);
device->addButton(BUTTON_RESCUE,
top_margin + small_ratio * col_size, small_ratio * margin,
small_ratio * btn_size, small_ratio * btn_size);
device->addButton(BUTTON_NITRO,
w - 1 * col_size, h - 2 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_SKIDDING,
w - 1 * col_size, h - 1 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_FIRE,
w - 2 * col_size, h - 2 * col_size,
btn_size, btn_size);
device->addButton(BUTTON_LOOK_BACKWARDS,
w - 2 * col_size, h - 1 * col_size,
btn_size, btn_size);
} // initMultitouchSteering
//-----------------------------------------------------------------------------
/** Draws the buttons for multitouch steering.
* \param kart The kart for which to show the data.
* \param viewport The viewport to use.
* \param scaling Which scaling to apply to the buttons.
*/
void RaceGUI::drawMultitouchSteering(const AbstractKart* kart,
const core::recti &viewport,
const core::vector2df &scaling)
{
MultitouchDevice* device = input_manager->getDeviceManager()->
getMultitouchDevice();
if (device == NULL)
return;
for (unsigned int i = 0; i < device->getButtonsCount(); i++)
{
MultitouchButton* button = device->getButton(i);
core::rect<s32> pos(button->x, button->y, button->x + button->width,
button->y + button->height);
if (button->type == MultitouchButtonType::BUTTON_STEERING)
{
video::ITexture* tex = irr_driver->getTexture(FileManager::GUI,
"blue_plus.png");
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos, coords, NULL, NULL, true);
float x = (float)(button->x) + (float)(button->width) / 2.0f *
(button->axis_x + 1.0f);
float y = (float)(button->y) + (float)(button->height) / 2.0f *
(button->axis_y + 1.0f);
float w = (float)(button->width) / 20.0f;
float h = (float)(button->height) / 20.0f;
core::rect<s32> pos2(round(x - w), round(y - h),
round(x + w), round(y + h));
draw2DImage(tex, pos2, coords, NULL, NULL, true);
}
else
{
if (button->pressed)
{
core::rect<s32> pos2(button->x - button->width * 0.2f,
button->y - button->height * 0.2f,
button->x + button->width * 1.2f,
button->y + button->height * 1.2f);
video::ITexture* tex = irr_driver->getTexture(FileManager::GUI,
"icons-frame.png");
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos2, coords, NULL, NULL, true);
}
video::ITexture* tex;
if (button->type == MultitouchButtonType::BUTTON_SKIDDING)
{
tex = irr_driver->getTexture(FileManager::TEXTURE,
"skid-particle1.png");
}
else
{
std::string name = "gui_lock.png";
switch (button->type)
{
case MultitouchButtonType::BUTTON_ESCAPE:
name = "back.png";
break;
case MultitouchButtonType::BUTTON_FIRE:
name = "banana.png";
break;
case MultitouchButtonType::BUTTON_NITRO:
name = "nitro.png";
break;
case MultitouchButtonType::BUTTON_LOOK_BACKWARDS:
name = "down.png";
break;
case MultitouchButtonType::BUTTON_RESCUE:
name = "restart.png";
break;
default:
break;
}
tex = irr_driver->getTexture(FileManager::GUI, name);
}
core::rect<s32> coords(core::position2d<s32>(0,0), tex->getSize());
draw2DImage(tex, pos, coords, NULL, NULL, true);
if (button->type == MultitouchButtonType::BUTTON_NITRO)
{
float scale = (float)(irr_driver->
getActualScreenSize().Height) / 1600.0f;
drawEnergyMeter(button->x + button->width,
button->y + button->height,
kart, viewport, core::vector2df(scale, scale));
}
}
}
} // drawMultitouchSteering

View File

@ -94,6 +94,8 @@ private:
bool m_is_tutorial;
void initMultitouchSteering();
/* Display informat for one player on the screen. */
void drawEnergyMeter (int x, int y, const AbstractKart *kart,
const core::recti &viewport,
@ -108,6 +110,9 @@ private:
const core::vector2df &offset,
float min_ratio, int meter_width,
int meter_height, float dt);
void drawMultitouchSteering (const AbstractKart* kart,
const core::recti &viewport,
const core::vector2df &scaling);
/** Display items that are shown once only (for all karts). */
void drawGlobalMiniMap ();

Some files were not shown because too many files have changed in this diff Show More