Merge branch 'master' of github.com:supertuxkart/stk-code
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,7 @@
|
||||
bld*/
|
||||
build*/
|
||||
cmake_build/
|
||||
cmake_build*/
|
||||
dependencies/
|
||||
dependencies*/
|
||||
CMakeFiles/
|
||||
stk-editor/
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ addons:
|
||||
- zlib1g-dev
|
||||
|
||||
before_script:
|
||||
- export THREADS=$((`nproc` + 1))
|
||||
#- export THREADS=$((`nproc` + 1))
|
||||
# Unfortunately using all threads crashes g++: "g++: internal compiler error: Killed (program cc1plus)"
|
||||
- export THREADS=4
|
||||
- echo "THREADS = $THREADS"
|
||||
- free -mt
|
||||
|
||||
|
||||
BIN
data/gui/heart.png
Normal file
BIN
data/gui/heart.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
@@ -13,6 +13,8 @@
|
||||
I18N="Tab in help menu" text="Game Modes"/>
|
||||
<icon-button id="page4" width="128" height="128" icon="gui/options_input.png"
|
||||
I18N="Tab in help menu" text="Multi-player"/>
|
||||
<icon-button id="page5" width="128" height="128" icon="gui/banana.png"
|
||||
I18N="Tab in help menu" text="Bananas"/>
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
I18N="Tab in help menu" text="Game Modes"/>
|
||||
<icon-button id="page4" width="128" height="128" icon="gui/options_input.png"
|
||||
I18N="Tab in help menu" text="Multi-player"/>
|
||||
<icon-button id="page5" width="128" height="128" icon="gui/banana.png"
|
||||
I18N="Tab in help menu" text="Bananas"/>
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
I18N="Tab in help menu" text="Game Modes"/>
|
||||
<icon-button id="page4" width="128" height="128" icon="gui/options_input.png"
|
||||
I18N="Tab in help menu" text="Multi-player"/>
|
||||
<icon-button id="page5" width="128" height="128" icon="gui/banana.png"
|
||||
I18N="Tab in help menu" text="Bananas"/>
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
I18N="Tab in help menu" text="Game Modes"/>
|
||||
<icon-button id="page4" width="128" height="128" icon="gui/options_input.png"
|
||||
I18N="Tab in help menu" text="Multi-player"/>
|
||||
<icon-button id="page5" width="128" height="128" icon="gui/banana.png"
|
||||
I18N="Tab in help menu" text="Bananas"/>
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
|
||||
49
data/gui/help5.stkgui
Normal file
49
data/gui/help5.stkgui
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
|
||||
<header align="center" width="80%" text="SuperTuxKart Help" text_align="center"/>
|
||||
<spacer height="15" width="10"/>
|
||||
|
||||
<tabs id="category" height="10%" max_height="110" x="2%" width="98%" align="center">
|
||||
<icon-button id="page1" width="100" height="128" icon="gui/track_random.png"
|
||||
I18N="Tab in help menu" text="General"/>
|
||||
<icon-button id="page2" width="100" height="128" icon="gui/weapons.png"
|
||||
I18N="Tab in help menu" text="Weapons"/>
|
||||
<icon-button id="page3" width="100" height="128" icon="gui/mode_ftl.png"
|
||||
I18N="Tab in help menu" text="Game Modes"/>
|
||||
<icon-button id="page4" width="100" height="128" icon="gui/options_input.png"
|
||||
I18N="Tab in help menu" text="Multi-player"/>
|
||||
<icon-button id="page5" width="100" height="128" icon="gui/banana.png"
|
||||
I18N="Tab in help menu" text="Bananas"/>
|
||||
</tabs>
|
||||
|
||||
<box proportion="1" width="100%" layout="vertical-row">
|
||||
<label align="center" text="Hitting a banana can result in one of the following being attached to the kart:"/>
|
||||
|
||||
<div width="100%" proportion="2" layout="horizontal-row">
|
||||
<icon align="center" width="64" height="64" icon="models/anchor-icon.png"/>
|
||||
<spacer width="64" height="64"/>
|
||||
<bubble proportion="1" height="100%"
|
||||
I18N="In the help menu"
|
||||
text="Anchor - slows down the kart."/>
|
||||
</div>
|
||||
|
||||
<div width="100%" proportion="2" layout="horizontal-row">
|
||||
<icon align="center" width="64" height="64" icon="models/parachute-icon.png"/>
|
||||
<spacer width="64" height="64"/>
|
||||
<bubble proportion="1" height="100%"
|
||||
I18N="In the help menu"
|
||||
text="Parachute - slows down the kart less than the anchor."/>
|
||||
</div>
|
||||
|
||||
<div width="100%" proportion="2" layout="horizontal-row">
|
||||
<icon align="center" width="128" height="128" icon="models/bomb-attach-icon.png"/>
|
||||
<bubble proportion="1" height="100%"
|
||||
I18N="In the help menu"
|
||||
text="Bomb - detonates after a short amount of time to throw the kart up in the air. Bump into another kart to transfer the bomb to another player."/>
|
||||
</div>
|
||||
</box>
|
||||
</div>
|
||||
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||
</stkgui>
|
||||
@@ -4,5 +4,5 @@ out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(glowColor.rgb, 1.0);
|
||||
FragColor = vec4(glowColor.bgr, 1.0);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ layout(bindless_sampler) uniform sampler2D tex;
|
||||
#else
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
uniform float custom_alpha;
|
||||
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
@@ -18,5 +19,5 @@ void main()
|
||||
Color.xyz *= pow(color.xyz, vec3(2.2));
|
||||
Color.a *= color.a;
|
||||
// Premultiply alpha
|
||||
FragColor = vec4(Color.rgb * Color.a, Color.a);
|
||||
FragColor = vec4(Color.rgb * (Color.a * custom_alpha), Color.a * custom_alpha);
|
||||
}
|
||||
|
||||
@@ -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,54 +381,22 @@ 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];
|
||||
|
||||
// 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;
|
||||
s32 Y;
|
||||
|
||||
//! 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;
|
||||
|
||||
@@ -899,7 +899,7 @@ bool CIrrDeviceLinux::createWindow()
|
||||
WMCheck, 0L, 1L, False, XA_WINDOW,
|
||||
&type, &form, &len, &remain,
|
||||
(unsigned char **)&list);
|
||||
|
||||
XFree(list);
|
||||
bool netWM = (s == Success) && len;
|
||||
attributes.override_redirect = !netWM && CreationParams.Fullscreen;
|
||||
|
||||
|
||||
@@ -1474,77 +1474,6 @@ void CSkinnedMesh::calculateTangents(
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Copies a mesh.
|
||||
*/
|
||||
CSkinnedMesh *CSkinnedMesh::clone()
|
||||
{
|
||||
|
||||
CSkinnedMesh* skinned_mesh = new CSkinnedMesh();
|
||||
|
||||
for (u32 i = 0; i < getMeshBuffers().size(); i++)
|
||||
{
|
||||
SSkinMeshBuffer * buffer = skinned_mesh->addMeshBuffer();
|
||||
*buffer = *(getMeshBuffers()[i]);
|
||||
}
|
||||
|
||||
for (u32 j = 0; j < getAllJoints().size(); ++j)
|
||||
{
|
||||
ISkinnedMesh::SJoint *joint = skinned_mesh->addJoint();
|
||||
*joint = *(getAllJoints()[j]);
|
||||
}
|
||||
|
||||
// fix children pointers (they still have old pointers)
|
||||
core::array<ISkinnedMesh::SJoint*> & new_joints = skinned_mesh->getAllJoints();
|
||||
for (u32 i = 0; i < new_joints.size(); ++i)
|
||||
{
|
||||
ISkinnedMesh::SJoint * joint = new_joints[i];
|
||||
for (u32 c = 0; c < joint->Children.size(); ++c)
|
||||
{
|
||||
// the child is one of the oldJoints and must be replaced by the newjoint on the same index
|
||||
bool found = false;
|
||||
for (u32 k = 0; k < AllJoints.size(); ++k)
|
||||
{
|
||||
if (joint->Children[c] == AllJoints[k])
|
||||
{
|
||||
joint->Children[c] = new_joints[k];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
} // k < old_joints.size
|
||||
|
||||
if (!found)
|
||||
found = true;
|
||||
} // c < joint->Children.size()
|
||||
} // i < new_joints.size()
|
||||
|
||||
// In finalize the values from LocalBuffers are copied into
|
||||
// Weights[].StaticPos. Since skinned_mesh already has the correct
|
||||
// values in Weights, we have to copy the values from Weights
|
||||
// into LocalBuffer (so that in the copy from LocalBuffer to weights
|
||||
// no values are overwritten).
|
||||
// FIXME: Not ideal, better would be not to copy the values in
|
||||
// finalize().
|
||||
for (unsigned int i = 0; i<AllJoints.size(); ++i)
|
||||
{
|
||||
SJoint *joint = AllJoints[i];
|
||||
for (unsigned int j = 0; j<joint->Weights.size(); ++j)
|
||||
{
|
||||
const u16 buffer_id = joint->Weights[j].buffer_id;
|
||||
const u32 vertex_id = joint->Weights[j].vertex_id;
|
||||
|
||||
skinned_mesh->LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
|
||||
skinned_mesh->LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
|
||||
}
|
||||
}
|
||||
skinned_mesh->finalize();
|
||||
|
||||
|
||||
|
||||
return skinned_mesh;
|
||||
|
||||
} // clone
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
@@ -159,7 +159,6 @@ namespace scene
|
||||
void addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
|
||||
IAnimatedMeshSceneNode* node,
|
||||
ISceneManager* smgr);
|
||||
CSkinnedMesh *clone();
|
||||
private:
|
||||
void checkForAnimation();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
|
||||
@@ -424,7 +424,7 @@ void SFXOpenAL::setPosition(const Vec3 &position)
|
||||
{
|
||||
// Don't send a position command to the thread if the sound is not playing
|
||||
// (or sfx disabled or the sound was not initialised correctly)
|
||||
// if (m_status != SFX_PLAYING|| !SFXManager::get()->sfxAllowed()) return;
|
||||
if (!SFXManager::get()->sfxAllowed()) return;
|
||||
SFXManager::get()->queue(SFXManager::SFX_POSITION, this, position);
|
||||
|
||||
} // setPosition
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
#include "font/bold_face.hpp"
|
||||
|
||||
#include "font/face_ttf.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor of BoldFace.
|
||||
* \param ttf \ref FaceTTF for BoldFace to use.
|
||||
*/
|
||||
BoldFace::BoldFace(FaceTTF* ttf) : FontWithFace("BoldFace", ttf)
|
||||
{
|
||||
} // BoldFace
|
||||
@@ -53,3 +54,12 @@ void BoldFace::reset()
|
||||
insertCharacters(preload_chars.c_str());
|
||||
updateCharactersList();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Embolden the glyph to make bold font using FT_Outline_Embolden.
|
||||
* \return A FT_Error value.
|
||||
*/
|
||||
int BoldFace::shapeOutline(FT_Outline* outline) const
|
||||
{
|
||||
return FT_Outline_Embolden(outline, getDPI() * 2);
|
||||
} // shapeOutline
|
||||
|
||||
@@ -23,24 +23,28 @@
|
||||
|
||||
class FaceTTF;
|
||||
|
||||
/** A font which uses regular TTFs to render title or important message in STK
|
||||
* with a bold outline, it shares the same \ref FaceTTF with \ref RegularFace.
|
||||
* \ingroup font
|
||||
*/
|
||||
class BoldFace : public FontWithFace
|
||||
{
|
||||
private:
|
||||
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 1024; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual float getScalingFactorOne() const OVERRIDE { return 0.2f; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual unsigned int getScalingFactorTwo() const OVERRIDE { return 120; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isBold() const OVERRIDE { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual int shapeOutline(FT_Outline* outline) const OVERRIDE;
|
||||
|
||||
public:
|
||||
LEAK_CHECK()
|
||||
// ------------------------------------------------------------------------
|
||||
BoldFace(FaceTTF* ttf);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~BoldFace() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void init() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
#include "font/digit_face.hpp"
|
||||
|
||||
#include "font/face_ttf.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor of DigitFace.
|
||||
* \param ttf \ref FaceTTF for DigitFace to use.
|
||||
*/
|
||||
DigitFace::DigitFace(FaceTTF* ttf) : FontWithFace("DigitFace", ttf)
|
||||
{
|
||||
} // DigitFace
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
class FaceTTF;
|
||||
|
||||
/** A font which uses a more cartonish style TTF to render big numbers in STK.
|
||||
* \ingroup font
|
||||
*/
|
||||
class DigitFace : public FontWithFace
|
||||
{
|
||||
private:
|
||||
@@ -39,8 +42,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
DigitFace(FaceTTF* ttf);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~DigitFace() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void init() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
@@ -18,22 +18,29 @@
|
||||
|
||||
#include "font/face_ttf.hpp"
|
||||
|
||||
#include "font/font_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor. Load all TTFs from a list.
|
||||
* \param ttf_list List of TTFs to be loaded.
|
||||
*/
|
||||
FaceTTF::FaceTTF(const std::vector<std::string>& ttf_list)
|
||||
{
|
||||
for (const std::string& font : ttf_list)
|
||||
{
|
||||
FT_Face face = NULL;
|
||||
const std::string loc = file_manager
|
||||
->getAssetChecked(FileManager::TTF, font.c_str(), true);
|
||||
font_manager->checkFTError(FT_New_Face(font_manager->getFTLibrary(),
|
||||
(file_manager->getAssetChecked(FileManager::TTF,
|
||||
font.c_str(), true)).c_str(), 0, &face), "loading fonts");
|
||||
loc.c_str(), 0, &face), loc + " is loaded");
|
||||
m_faces.push_back(face);
|
||||
}
|
||||
} // FaceTTF
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor. Clears all TTFs.
|
||||
*/
|
||||
FaceTTF::~FaceTTF()
|
||||
{
|
||||
for (unsigned int i = 0; i < m_faces.size(); i++)
|
||||
@@ -42,6 +49,9 @@ FaceTTF::~FaceTTF()
|
||||
}
|
||||
} // ~FaceTTF
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Return a TTF in \ref m_faces.
|
||||
* \param i index of TTF file in \ref m_faces.
|
||||
*/
|
||||
FT_Face FaceTTF::getFace(unsigned int i) const
|
||||
{
|
||||
assert(i < m_faces.size());
|
||||
|
||||
@@ -19,15 +19,30 @@
|
||||
#ifndef HEADER_FACE_TTF_HPP
|
||||
#define HEADER_FACE_TTF_HPP
|
||||
|
||||
#include "font/font_manager.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
/** This class will load a list of TTF files from \ref STKConfig, and save
|
||||
* them inside \ref m_faces for \ref FontWithFace to load glyph.
|
||||
* Each FaceTTF can be used more than once in each instantiation of \ref
|
||||
* FontWithFace, so it can render characters differently using the same TTF
|
||||
* file to save memory, for example different outline size.
|
||||
* \ingroup font
|
||||
*/
|
||||
class FaceTTF : public NoCopy
|
||||
{
|
||||
private:
|
||||
/** Contains all TTF files loaded. */
|
||||
std::vector<FT_Face> m_faces;
|
||||
|
||||
public:
|
||||
LEAK_CHECK();
|
||||
LEAK_CHECK()
|
||||
// ------------------------------------------------------------------------
|
||||
FaceTTF(const std::vector<std::string>& ttf_list);
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -35,6 +50,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
FT_Face getFace(unsigned int i) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the total TTF files loaded. */
|
||||
unsigned int getTotalFaces() const { return m_faces.size(); }
|
||||
|
||||
}; // FaceTTF
|
||||
|
||||
@@ -28,15 +28,22 @@
|
||||
|
||||
FontManager *font_manager = NULL;
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor. It will initialize the \ref m_ft_library.
|
||||
*/
|
||||
FontManager::FontManager()
|
||||
{
|
||||
checkFTError(FT_Init_FreeType(&m_ft_library), "loading freetype library");
|
||||
} // FontManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor. Clears all fonts and related stuff.
|
||||
*/
|
||||
FontManager::~FontManager()
|
||||
{
|
||||
m_fonts.clearAndDeleteAll();
|
||||
for (unsigned int i = 0; i < m_fonts.size(); i++)
|
||||
delete m_fonts[i];
|
||||
m_fonts.clear();
|
||||
|
||||
delete m_normal_ttf;
|
||||
m_normal_ttf = NULL;
|
||||
delete m_digit_ttf;
|
||||
@@ -47,6 +54,8 @@ FontManager::~FontManager()
|
||||
} // ~FontManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Initialize all \ref FaceTTF and \ref FontWithFace members.
|
||||
*/
|
||||
void FontManager::loadFonts()
|
||||
{
|
||||
// First load the TTF files required by each font
|
||||
@@ -72,15 +81,10 @@ void FontManager::loadFonts()
|
||||
} // loadFonts
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void FontManager::checkFTError(FT_Error err, const std::string& desc) const
|
||||
{
|
||||
if (err > 0)
|
||||
{
|
||||
Log::error("FontManager", "Something wrong when %s!", desc.c_str());
|
||||
}
|
||||
} // checkFTError
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Unit testing that will try to load all translations in STK, and discover if
|
||||
* there is any characters required by it are not supported in \ref
|
||||
* m_normal_ttf.
|
||||
*/
|
||||
void FontManager::unitTesting()
|
||||
{
|
||||
std::vector<std::string> list = *(translations->getLanguageList());
|
||||
|
||||
@@ -19,14 +19,18 @@
|
||||
#ifndef HEADER_FONT_MANAGER_HPP
|
||||
#define HEADER_FONT_MANAGER_HPP
|
||||
|
||||
/** \defgroup font Font
|
||||
* This module stores font files and tools used to draw characters in STK.
|
||||
*/
|
||||
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
@@ -34,17 +38,26 @@
|
||||
class FaceTTF;
|
||||
class FontWithFace;
|
||||
|
||||
/** This class stores all font files required in STK.
|
||||
* \ingroup font
|
||||
*/
|
||||
class FontManager : public NoCopy
|
||||
{
|
||||
private:
|
||||
PtrVector<FontWithFace> m_fonts;
|
||||
/** Stores all \ref FontWithFace used in STK. */
|
||||
std::vector<FontWithFace*> m_fonts;
|
||||
|
||||
/** A FreeType library, it holds the FT_Face internally inside freetype. */
|
||||
FT_Library m_ft_library;
|
||||
|
||||
/** TTF files used in \ref BoldFace and \ref RegularFace. */
|
||||
FaceTTF* m_normal_ttf;
|
||||
|
||||
/** TTF files used in \ref DigitFace. */
|
||||
FaceTTF* m_digit_ttf;
|
||||
|
||||
/** Map type for each \ref FontWithFace with a index, save getting time in
|
||||
* \ref getFont. */
|
||||
std::unordered_map<std::type_index, int> m_font_type_map;
|
||||
|
||||
public:
|
||||
@@ -54,11 +67,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
~FontManager();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return a specfic type of \ref FontWithFace found in \ref m_fonts. */
|
||||
template <typename T> T* getFont()
|
||||
{
|
||||
T* out = NULL;
|
||||
const unsigned int n = m_font_type_map[std::type_index(typeid(T))];
|
||||
out = dynamic_cast<T*>(m_fonts.get(n));
|
||||
out = dynamic_cast<T*>(m_fonts[n]);
|
||||
if (out != NULL)
|
||||
{
|
||||
return out;
|
||||
@@ -68,16 +82,23 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Check for any error discovered in a freetype function that will return
|
||||
* a FT_Error value.
|
||||
* a FT_Error value, and log into the terminal.
|
||||
* \param err The Freetype function.
|
||||
* \param desc The description of what is the function doing.
|
||||
*/
|
||||
void checkFTError(FT_Error err, const std::string& desc) const;
|
||||
* \param desc The description of what is the function doing. */
|
||||
void checkFTError(FT_Error err, const std::string& desc) const
|
||||
{
|
||||
if (err > 0)
|
||||
{
|
||||
Log::error("FontManager", "Something wrong when %s! The error "
|
||||
"code was %d.", desc.c_str(), err);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void loadFonts();
|
||||
// ------------------------------------------------------------------------
|
||||
void unitTesting();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the \ref m_ft_library. */
|
||||
FT_Library getFTLibrary() const { return m_ft_library; }
|
||||
|
||||
}; // FontManager
|
||||
|
||||
@@ -25,21 +25,34 @@
|
||||
|
||||
using namespace irr;
|
||||
|
||||
/** This class stores settings when rendering fonts, used when instantiating
|
||||
* \ref irr::gui::ScalableFont.
|
||||
* \ingroup font
|
||||
*/
|
||||
class FontSettings
|
||||
{
|
||||
private:
|
||||
/** True if black border will be drawn when rendering. */
|
||||
bool m_black_border;
|
||||
|
||||
/** If true, characters will have right alignment when rendering, for RTL
|
||||
* language. */
|
||||
bool m_rtl;
|
||||
|
||||
/** Scaling when rendering. */
|
||||
float m_scale;
|
||||
|
||||
/** True if shadow will be drawn when rendering. */
|
||||
bool m_shadow;
|
||||
|
||||
/** Save the color of shadow when rendering. */
|
||||
video::SColor m_shadow_color;
|
||||
|
||||
public:
|
||||
LEAK_CHECK()
|
||||
// ------------------------------------------------------------------------
|
||||
/** Constructor. It will initialize all members with default values if no
|
||||
* parameter is given. */
|
||||
FontSettings(bool black_border = false, bool rtl = false,
|
||||
float scale = 1.0f, bool shadow = false,
|
||||
const video::SColor& color = video::SColor(0, 0, 0, 0))
|
||||
@@ -51,26 +64,39 @@ public:
|
||||
m_shadow_color = color;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
~FontSettings() {}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set the scaling.
|
||||
* \param scale Scaling to be set. */
|
||||
void setScale(float scale) { m_scale = scale; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the scaling. */
|
||||
float getScale() const { return m_scale; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set the color of shadow.
|
||||
* \param col The color of shadow to be set. */
|
||||
void setShadowColor(const video::SColor &col) { m_shadow_color = col; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the color of shadow. */
|
||||
const video::SColor& getShadowColor() const { return m_shadow_color; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return if shadow is enabled. */
|
||||
bool useShadow() const { return m_shadow; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set whether shadow is enabled.
|
||||
* \param shadow If it's enabled. */
|
||||
void setShadow(bool shadow) { m_shadow = shadow; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set whether black border is enabled.
|
||||
* \param border If it's enabled. */
|
||||
void setBlackBorder(bool border) { m_black_border = border; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return if black border is enabled. */
|
||||
bool useBlackBorder() const { return m_black_border; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set right text alignment for RTL language.
|
||||
* \param rtl If it's enabled. */
|
||||
void setRTL(bool rtl) { m_rtl = rtl; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return if right text alignment for RTL language is enabled. */
|
||||
bool isRTL() const { return m_rtl; }
|
||||
|
||||
}; // FontSettings
|
||||
|
||||
@@ -18,17 +18,20 @@
|
||||
|
||||
#include "font/font_with_face.hpp"
|
||||
|
||||
#include "font/bold_face.hpp"
|
||||
#include "font/face_ttf.hpp"
|
||||
#include "font/font_manager.hpp"
|
||||
#include "font/font_settings.hpp"
|
||||
#include "graphics/2dutils.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/skin.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor. It will initialize the \ref m_spritebank and TTF files to use.
|
||||
* \param name The name of face, used by irrlicht to distinguish spritebank.
|
||||
* \param ttf \ref FaceTTF for this face to use.
|
||||
*/
|
||||
FontWithFace::FontWithFace(const std::string& name, FaceTTF* ttf)
|
||||
{
|
||||
m_spritebank = irr_driver->getGUI()->addEmptySpriteBank(name.c_str());
|
||||
@@ -43,6 +46,8 @@ FontWithFace::FontWithFace(const std::string& name, FaceTTF* ttf)
|
||||
|
||||
} // FontWithFace
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor. Clears the glyph page and sprite bank.
|
||||
*/
|
||||
FontWithFace::~FontWithFace()
|
||||
{
|
||||
m_page->drop();
|
||||
@@ -56,6 +61,8 @@ FontWithFace::~FontWithFace()
|
||||
} // ~FontWithFace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Initialize the font structure, but don't load glyph here.
|
||||
*/
|
||||
void FontWithFace::init()
|
||||
{
|
||||
setDPI();
|
||||
@@ -83,7 +90,11 @@ void FontWithFace::init()
|
||||
|
||||
reset();
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Clear all the loaded characters, sub-class can do pre-loading of characters
|
||||
* after this.
|
||||
*/
|
||||
void FontWithFace::reset()
|
||||
{
|
||||
m_new_char_holder.clear();
|
||||
@@ -94,6 +105,12 @@ void FontWithFace::reset()
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Convert a character to a glyph index in one of the font in \ref m_face_ttf,
|
||||
* it will find the first TTF that supports this character, if the final
|
||||
* glyph_index is 0, this means such character is not supported by all TTFs in
|
||||
* \ref m_face_ttf.
|
||||
* \param c The character to be loaded.
|
||||
*/
|
||||
void FontWithFace::loadGlyphInfo(wchar_t c)
|
||||
{
|
||||
unsigned int font_number = 0;
|
||||
@@ -108,11 +125,12 @@ void FontWithFace::loadGlyphInfo(wchar_t c)
|
||||
} // loadGlyphInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Create a new glyph page by filling it with transparent content.
|
||||
*/
|
||||
void FontWithFace::createNewGlyphPage()
|
||||
{
|
||||
// Clean the current glyph page by filling it with transparent content
|
||||
m_page->fill(video::SColor(0, 255, 255, 255));
|
||||
m_temp_height = 0;
|
||||
m_current_height = 0;
|
||||
m_used_width = 0;
|
||||
m_used_height = 0;
|
||||
|
||||
@@ -140,6 +158,10 @@ void FontWithFace::createNewGlyphPage()
|
||||
} // createNewGlyphPage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Render a glyph for a character into bitmap and save it into the glyph page.
|
||||
* \param c The character to be loaded.
|
||||
* \param c \ref GlyphInfo for the character.
|
||||
*/
|
||||
void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
{
|
||||
assert(gi.glyph_index > 0);
|
||||
@@ -147,7 +169,7 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
FT_Face cur_face = m_face_ttf->getFace(gi.font_number);
|
||||
FT_GlyphSlot slot = cur_face->glyph;
|
||||
|
||||
// Faces may be shared across regular and bold,
|
||||
// Same face may be shared across the different FontWithFace,
|
||||
// so reset dpi each time
|
||||
font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
|
||||
"setting DPI");
|
||||
@@ -155,15 +177,11 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
font_manager->checkFTError(FT_Load_Glyph(cur_face, gi.glyph_index,
|
||||
FT_LOAD_DEFAULT), "loading a glyph");
|
||||
|
||||
if (dynamic_cast<BoldFace*>(this) != NULL)
|
||||
{
|
||||
// Embolden the outline of the glyph
|
||||
font_manager->checkFTError(FT_Outline_Embolden(&(slot->outline),
|
||||
getDPI() * 2), "embolden a glyph");
|
||||
}
|
||||
font_manager->checkFTError(shapeOutline(&(slot->outline)),
|
||||
"shaping outline");
|
||||
|
||||
font_manager->checkFTError(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL),
|
||||
"render a glyph to bitmap");
|
||||
"rendering a glyph to bitmap");
|
||||
|
||||
// Convert to an anti-aliased bitmap
|
||||
FT_Bitmap bits = slot->bitmap;
|
||||
@@ -176,7 +194,7 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
true, 0);
|
||||
|
||||
if ((m_used_width + texture_size.Width > getGlyphPageSize() &&
|
||||
m_used_height + m_temp_height + texture_size.Height >
|
||||
m_used_height + m_current_height + texture_size.Height >
|
||||
getGlyphPageSize()) ||
|
||||
m_used_height + texture_size.Height > getGlyphPageSize())
|
||||
{
|
||||
@@ -244,8 +262,8 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
if (m_used_width + texture_size.Width > getGlyphPageSize())
|
||||
{
|
||||
m_used_width = 0;
|
||||
m_used_height += m_temp_height;
|
||||
m_temp_height = 0;
|
||||
m_used_height += m_current_height;
|
||||
m_current_height = 0;
|
||||
}
|
||||
|
||||
// Copy to the full glyph page
|
||||
@@ -283,11 +301,13 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
|
||||
// Store used area
|
||||
m_used_width += texture_size.Width;
|
||||
if (m_temp_height < texture_size.Height)
|
||||
m_temp_height = texture_size.Height;
|
||||
if (m_current_height < texture_size.Height)
|
||||
m_current_height = texture_size.Height;
|
||||
} // insertGlyph
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Update the supported characters for this font if required.
|
||||
*/
|
||||
void FontWithFace::updateCharactersList()
|
||||
{
|
||||
if (m_fallback_font != NULL)
|
||||
@@ -321,6 +341,10 @@ void FontWithFace::updateCharactersList()
|
||||
} // updateCharactersList
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Write the current glyph page in png inside current running directory.
|
||||
* Mainly for debug use.
|
||||
* \param name The file name.
|
||||
*/
|
||||
void FontWithFace::dumpGlyphPage(const std::string& name)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_spritebank->getTextureCount(); i++)
|
||||
@@ -341,20 +365,23 @@ void FontWithFace::dumpGlyphPage(const std::string& name)
|
||||
} // dumpGlyphPage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Write the current glyph page in png inside current running directory.
|
||||
* Useful in gdb without parameter.
|
||||
*/
|
||||
void FontWithFace::dumpGlyphPage()
|
||||
{
|
||||
dumpGlyphPage("face");
|
||||
} // dumpGlyphPage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Set the face dpi which is resolution-dependent.
|
||||
* Normal text will range from 0.8, in 640x* resolutions (won't scale below
|
||||
* that) to 1.0, in 1024x* resolutions, and linearly up.
|
||||
* Bold text will range from 0.2, in 640x* resolutions (won't scale below
|
||||
* that) to 0.4, in 1024x* resolutions, and linearly up.
|
||||
*/
|
||||
void FontWithFace::setDPI()
|
||||
{
|
||||
// Set face dpi:
|
||||
// Font size is resolution-dependent.
|
||||
// Normal text will range from 0.8, in 640x* resolutions (won't scale
|
||||
// below that) to 1.0, in 1024x* resolutions, and linearly up
|
||||
// Bold text will range from 0.2, in 640x* resolutions (won't scale
|
||||
// below that) to 0.4, in 1024x* resolutions, and linearly up
|
||||
const int screen_width = irr_driver->getFrameSize().Width;
|
||||
const int screen_height = irr_driver->getFrameSize().Height;
|
||||
float scale = std::max(0, screen_width - 640) / 564.0f;
|
||||
@@ -371,6 +398,10 @@ void FontWithFace::setDPI()
|
||||
} // setDPI
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Return the \ref FontArea about a character.
|
||||
* \param c The character to get.
|
||||
* \param[out] fallback_font Whether fallback font is used.
|
||||
*/
|
||||
const FontWithFace::FontArea&
|
||||
FontWithFace::getAreaFromCharacter(const wchar_t c,
|
||||
bool* fallback_font) const
|
||||
@@ -397,6 +428,12 @@ const FontWithFace::FontArea&
|
||||
} // getAreaFromCharacter
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Get the dimension of text with support to different \ref FontSettings,
|
||||
* it will also do checking for missing characters in font and lazy load them.
|
||||
* \param text The text to be calculated.
|
||||
* \param font_settings \ref FontSettings to use.
|
||||
* \return The dimension of text
|
||||
*/
|
||||
core::dimension2d<u32> FontWithFace::getDimension(const wchar_t* text,
|
||||
FontSettings* font_settings)
|
||||
{
|
||||
@@ -441,6 +478,12 @@ core::dimension2d<u32> FontWithFace::getDimension(const wchar_t* text,
|
||||
} // getDimension
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Calculate the index of the character in the text on a specific position.
|
||||
* \param text The text to be calculated.
|
||||
* \param pixel_x The specific position.
|
||||
* \param font_settings \ref FontSettings to use.
|
||||
* \return The index of the character, -1 means no character in such position.
|
||||
*/
|
||||
int FontWithFace::getCharacterFromPos(const wchar_t* text, int pixel_x,
|
||||
FontSettings* font_settings) const
|
||||
{
|
||||
@@ -466,6 +509,17 @@ int FontWithFace::getCharacterFromPos(const wchar_t* text, int pixel_x,
|
||||
} // getCharacterFromPos
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Render text and clip it to the specified rectangle if wanted, it will also
|
||||
* do checking for missing characters in font and lazy load them.
|
||||
* \param text The text to be rendering.
|
||||
* \param position The position to be rendering.
|
||||
* \param color The color used when rendering.
|
||||
* \param hcenter If rendered horizontally center.
|
||||
* \param vcenter If rendered vertically center.
|
||||
* \param clip If clipping is needed.
|
||||
* \param font_settings \ref FontSettings to use.
|
||||
* \param char_collector \ref FontCharCollector to render billboard text.
|
||||
*/
|
||||
void FontWithFace::render(const core::stringw& text,
|
||||
const core::rect<s32>& position,
|
||||
const video::SColor& color, bool hcenter,
|
||||
@@ -473,7 +527,6 @@ void FontWithFace::render(const core::stringw& text,
|
||||
FontSettings* font_settings,
|
||||
FontCharCollector* char_collector)
|
||||
{
|
||||
const bool is_bold_face = (dynamic_cast<BoldFace*>(this) != NULL);
|
||||
const bool black_border = font_settings ?
|
||||
font_settings->useBlackBorder() : false;
|
||||
const bool rtl = font_settings ? font_settings->isRTL() : false;
|
||||
@@ -621,7 +674,7 @@ void FontWithFace::render(const core::stringw& text,
|
||||
|
||||
const int sprite_amount = sprites.size();
|
||||
|
||||
if ((black_border || is_bold_face) && char_collector == NULL)
|
||||
if ((black_border || isBold()) && char_collector == NULL)
|
||||
{
|
||||
// Draw black border first, to make it behind the real character
|
||||
// which make script language display better
|
||||
@@ -693,7 +746,7 @@ void FontWithFace::render(const core::stringw& text,
|
||||
m_fallback_font->m_spritebank->getTexture(tex_id) :
|
||||
m_spritebank->getTexture(tex_id));
|
||||
|
||||
if (fallback[n] || is_bold_face)
|
||||
if (fallback[n] || isBold())
|
||||
{
|
||||
video::SColor top = GUIEngine::getSkin()->getColor("font::top");
|
||||
video::SColor bottom = GUIEngine::getSkin()
|
||||
|
||||
@@ -19,47 +19,85 @@
|
||||
#ifndef HEADER_FONT_WITH_FACE_HPP
|
||||
#define HEADER_FONT_WITH_FACE_HPP
|
||||
|
||||
#include "font/font_manager.hpp"
|
||||
#include "font/font_settings.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
#include <irrlicht.h>
|
||||
|
||||
using namespace irr;
|
||||
|
||||
const int BEARING = 64;
|
||||
|
||||
class FaceTTF;
|
||||
class FontSettings;
|
||||
|
||||
/** An abstract class which contains functions which convert vector fonts into
|
||||
* bitmap and render them in STK. To make STK draw characters with different
|
||||
* render option (like scaling, shadow) using a same FontWithFace, you need
|
||||
* to wrap this with \ref irr::gui::ScalableFont and configure the
|
||||
* \ref FontSettings for it.
|
||||
* \ingroup font
|
||||
*/
|
||||
class FontWithFace : public NoCopy
|
||||
{
|
||||
public:
|
||||
/** A class for \ref STKTextBillboard to get font info to render billboard
|
||||
* text. */
|
||||
class FontCharCollector
|
||||
{
|
||||
public:
|
||||
/** Collect the character info for billboard text.
|
||||
* \param texture The texture of the character.
|
||||
* \param destRect The destination rectangle
|
||||
* \param sourceRect The source rectangle in the glyph page
|
||||
* \param colors The color to render it. */
|
||||
virtual void collectChar(video::ITexture* texture,
|
||||
const core::rect<float>& destRect,
|
||||
const core::rect<s32>& sourceRect,
|
||||
const video::SColor* const colors) = 0;
|
||||
};
|
||||
|
||||
/** Glyph metrics for each glyph loaded. */
|
||||
struct FontArea
|
||||
{
|
||||
FontArea() : advance_x(0), bearing_x(0) ,offset_y(0), offset_y_bt(0),
|
||||
spriteno(0) {}
|
||||
/** Advance width for horizontal layout. */
|
||||
int advance_x;
|
||||
/** Left side bearing for horizontal layout. */
|
||||
int bearing_x;
|
||||
/** Top side bearing for horizontal layout. */
|
||||
int offset_y;
|
||||
/** Top side bearing for horizontal layout used in billboard text. */
|
||||
int offset_y_bt;
|
||||
/** Index number in sprite bank. */
|
||||
int spriteno;
|
||||
};
|
||||
|
||||
protected:
|
||||
int m_font_max_height;
|
||||
/** Used in vertical dimension calculation. */
|
||||
int m_font_max_height;
|
||||
|
||||
int m_glyph_max_height;
|
||||
/** Used in top side bearing calculation. */
|
||||
int m_glyph_max_height;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Check characters to see if they are loaded in font, if not load them.
|
||||
* For font that doesn't need lazy loading, nothing will be done.
|
||||
* \param in_ptr Characters to check.
|
||||
* \param first_load If true, it will ignore \ref supportLazyLoadChar,
|
||||
* which is called in \ref reset. */
|
||||
void insertCharacters(const wchar_t* in_ptr, bool first_load = false)
|
||||
{
|
||||
if (!supportLazyLoadChar() && !first_load) return;
|
||||
@@ -88,44 +126,69 @@ protected:
|
||||
// ------------------------------------------------------------------------
|
||||
void updateCharactersList();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set the fallback font for this font, so if some character is missing in
|
||||
* this font, it will use that fallback font to try rendering it.
|
||||
* \param face A \ref FontWithFace font. */
|
||||
void setFallbackFont(FontWithFace* face) { m_fallback_font = face; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set the scaling of fallback font.
|
||||
* \param scale The scaling to set. */
|
||||
void setFallbackFontScale(float scale) { m_fallback_font_scale = scale; }
|
||||
|
||||
private:
|
||||
/** Mapping of glyph index to a TTF in \ref FaceTTF. */
|
||||
struct GlyphInfo
|
||||
{
|
||||
GlyphInfo(unsigned int font_num = 0, unsigned int glyph_idx = 0) :
|
||||
font_number(font_num), glyph_index(glyph_idx) {}
|
||||
/** Index to a TTF in \ref FaceTTF. */
|
||||
unsigned int font_number;
|
||||
/** Glyph index in the TTF, 0 means no such glyph. */
|
||||
unsigned int glyph_index;
|
||||
GlyphInfo(unsigned int first = 0, unsigned int second = 0)
|
||||
{
|
||||
font_number = first;
|
||||
glyph_index = second;
|
||||
}
|
||||
};
|
||||
|
||||
/** \ref FaceTTF to load glyph from. */
|
||||
FaceTTF* m_face_ttf;
|
||||
|
||||
/** Fallback font to use if some character isn't supported by this font. */
|
||||
FontWithFace* m_fallback_font;
|
||||
|
||||
/** Scaling for fallback font. */
|
||||
float m_fallback_font_scale;
|
||||
|
||||
/** A temporary holder stored new char to be inserted. */
|
||||
/** A temporary holder to store new characters to be inserted. */
|
||||
std::set<wchar_t> m_new_char_holder;
|
||||
|
||||
/** Sprite bank to store each glyph. */
|
||||
gui::IGUISpriteBank* m_spritebank;
|
||||
|
||||
/** A full glyph page for this font. */
|
||||
video::IImage* m_page;
|
||||
|
||||
unsigned int m_temp_height;
|
||||
/** The current max height at current drawing line in glyph page. */
|
||||
unsigned int m_current_height;
|
||||
|
||||
/** The used width in glyph page. */
|
||||
unsigned int m_used_width;
|
||||
|
||||
/** The used height in glyph page. */
|
||||
unsigned int m_used_height;
|
||||
|
||||
/** The dpi of this font. */
|
||||
unsigned int m_face_dpi;
|
||||
|
||||
/** Store a list of supported character to a \ref FontArea. */
|
||||
std::map<wchar_t, FontArea> m_character_area_map;
|
||||
|
||||
/** Store a list of loaded and tested character to a \ref GlyphInfo. */
|
||||
std::map<wchar_t, GlyphInfo> m_character_glyph_info_map;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return a character width.
|
||||
* \param area \ref FontArea to get glyph metrics.
|
||||
* \param fallback If fallback font is used.
|
||||
* \param scale The scaling of the character.
|
||||
* \return The calculated width with suitable scaling. */
|
||||
float getCharWidth(const FontArea& area, bool fallback, float scale) const
|
||||
{
|
||||
if (fallback)
|
||||
@@ -134,6 +197,9 @@ private:
|
||||
return area.advance_x * scale;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Test if a character has already been tried to be loaded.
|
||||
* \param c Character to test.
|
||||
* \return True if tested. */
|
||||
bool loadedChar(wchar_t c) const
|
||||
{
|
||||
std::map<wchar_t, GlyphInfo>::const_iterator n =
|
||||
@@ -143,6 +209,10 @@ private:
|
||||
return false;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get the \ref GlyphInfo from \ref m_character_glyph_info_map about a
|
||||
* character.
|
||||
* \param c Character to get.
|
||||
* \return \ref GlyphInfo of this character. */
|
||||
const GlyphInfo& getGlyphInfo(wchar_t c) const
|
||||
{
|
||||
std::map<wchar_t, GlyphInfo>::const_iterator n =
|
||||
@@ -152,6 +222,10 @@ private:
|
||||
return n->second;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Tells whether a character is supported by all TTFs in \ref m_face_ttf
|
||||
* which is determined by \ref GlyphInfo of this character.
|
||||
* \param c Character to test.
|
||||
* \return True if it's supported. */
|
||||
bool supportChar(wchar_t c)
|
||||
{
|
||||
std::map<wchar_t, GlyphInfo>::const_iterator n =
|
||||
@@ -167,22 +241,36 @@ private:
|
||||
// ------------------------------------------------------------------------
|
||||
void createNewGlyphPage();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Add a character into \ref m_new_char_holder for lazy loading later. */
|
||||
void addLazyLoadChar(wchar_t c) { m_new_char_holder.insert(c); }
|
||||
// ------------------------------------------------------------------------
|
||||
void insertGlyph(wchar_t c, const GlyphInfo& gi);
|
||||
// ------------------------------------------------------------------------
|
||||
void setDPI();
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool supportLazyLoadChar() const = 0;
|
||||
/** Override it if sub-class should not do lazy loading characters. */
|
||||
virtual bool supportLazyLoadChar() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Defined by sub-class about the texture size of glyph page, it should be
|
||||
* a power of two. */
|
||||
virtual unsigned int getGlyphPageSize() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Defined by sub-class about the scaling factor 1. */
|
||||
virtual float getScalingFactorOne() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Defined by sub-class about the scaling factor 2. */
|
||||
virtual unsigned int getScalingFactorTwo() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override it if sub-class has bold outline. */
|
||||
virtual bool isBold() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override it if any outline shaping is needed to be done before
|
||||
* rendering the glyph into bitmap.
|
||||
* \return A FT_Error value if needed. */
|
||||
virtual int shapeOutline(FT_Outline* outline) const { return 0; }
|
||||
|
||||
public:
|
||||
LEAK_CHECK();
|
||||
LEAK_CHECK()
|
||||
// ------------------------------------------------------------------------
|
||||
FontWithFace(const std::string& name, FaceTTF* ttf);
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -204,22 +292,17 @@ public:
|
||||
FontSettings* font_settings,
|
||||
FontCharCollector* char_collector = NULL);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Write the current glyph page in png inside current running directory.
|
||||
* Mainly for debug use.
|
||||
* \param name The file name.
|
||||
*/
|
||||
void dumpGlyphPage(const std::string& name);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Write the current glyph page in png inside current running directory.
|
||||
* Useful in gdb without parameter.
|
||||
*/
|
||||
void dumpGlyphPage();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the sprite bank. */
|
||||
gui::IGUISpriteBank* getSpriteBank() const { return m_spritebank; }
|
||||
// ------------------------------------------------------------------------
|
||||
const FontArea& getAreaFromCharacter(const wchar_t c,
|
||||
bool* fallback_font) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the dpi of this face. */
|
||||
unsigned int getDPI() const { return m_face_dpi; }
|
||||
|
||||
}; // FontWithFace
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "font/face_ttf.hpp"
|
||||
|
||||
#include "font/regular_face.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor of RegularFace.
|
||||
* \param ttf \ref FaceTTF for RegularFace to use.
|
||||
*/
|
||||
RegularFace::RegularFace(FaceTTF* ttf) : FontWithFace("RegularFace", ttf)
|
||||
{
|
||||
} // RegularFace
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
|
||||
class FaceTTF;
|
||||
|
||||
/** A font which uses regular TTFs to render most text in STK.
|
||||
* \ingroup font
|
||||
*/
|
||||
class RegularFace : public FontWithFace
|
||||
{
|
||||
private:
|
||||
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 512; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual float getScalingFactorOne() const OVERRIDE { return 0.7f; }
|
||||
@@ -39,8 +40,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
RegularFace(FaceTTF* ttf);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RegularFace() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void init() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
@@ -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)
|
||||
@@ -34,14 +36,14 @@
|
||||
|
||||
|
||||
// ============================================================================
|
||||
class Primitive2DList : public TextureShader<Primitive2DList, 1>
|
||||
class Primitive2DList : public TextureShader<Primitive2DList, 1, float>
|
||||
{
|
||||
public:
|
||||
Primitive2DList()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "primitive2dlist.vert",
|
||||
GL_FRAGMENT_SHADER, "transparent.frag");
|
||||
assignUniforms();
|
||||
assignUniforms("custom_alpha");
|
||||
assignSamplerNames(0, "tex", ST_BILINEAR_FILTERED);
|
||||
} // Primitive2DList
|
||||
}; //Primitive2DList
|
||||
@@ -703,7 +705,7 @@ void draw2DVertexPrimitiveList(video::ITexture *tex, const void* vertices,
|
||||
VertexUtils::bindVertexArrayAttrib(vType);
|
||||
|
||||
Primitive2DList::getInstance()->use();
|
||||
Primitive2DList::getInstance()->setUniforms();
|
||||
Primitive2DList::getInstance()->setUniforms(1.0f);
|
||||
compressTexture(tex, false);
|
||||
Primitive2DList::getInstance()->setTextureUnits(getTextureGLuint(tex));
|
||||
glDrawElements(GL_TRIANGLE_FAN, primitiveCount, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
204
src/graphics/abstract_renderer.cpp
Normal file
204
src/graphics/abstract_renderer.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
127
src/graphics/abstract_renderer.hpp
Normal file
127
src/graphics/abstract_renderer.hpp
Normal 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
|
||||
@@ -245,8 +245,11 @@ void Camera::setMode(Mode mode)
|
||||
{
|
||||
Vec3 start_offset(0, 1.6f, -3);
|
||||
Vec3 current_position = m_kart->getTrans()(start_offset);
|
||||
Vec3 target_position = m_kart->getTrans()(Vec3(0, 0, 1));
|
||||
// Don't set position and target the same, otherwise
|
||||
// nan values will be calculated in ViewArea of camera
|
||||
m_camera->setPosition(current_position.toIrrVector());
|
||||
m_camera->setTarget(m_camera->getPosition());
|
||||
m_camera->setTarget(target_position.toIrrVector());
|
||||
}
|
||||
|
||||
m_mode = mode;
|
||||
@@ -291,9 +294,9 @@ void Camera::setInitialTransform()
|
||||
// direction till smoothMoveCamera has corrected this. Setting target
|
||||
// to position doesn't make sense, but smoothMoves will adjust the
|
||||
// value before the first frame is rendered
|
||||
m_camera->setTarget(m_camera->getPosition());
|
||||
Vec3 target_position = m_kart->getTrans()(Vec3(0, 0, 1));
|
||||
m_camera->setTarget(target_position.toIrrVector());
|
||||
m_camera->setRotation(core::vector3df(0, 0, 0));
|
||||
m_camera->setRotation( core::vector3df( 0.0f, 0.0f, 0.0f ) );
|
||||
m_camera->setFOV(m_fov);
|
||||
} // setInitialTransform
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -28,7 +28,7 @@ private:
|
||||
bool hasVSLayer;
|
||||
bool hasBaseInstance;
|
||||
bool hasDrawIndirect;
|
||||
bool hasBuffserStorage;
|
||||
bool hasBufferStorage;
|
||||
bool hasComputeShaders;
|
||||
bool hasArraysOfArrays;
|
||||
bool hasTextureStorage;
|
||||
|
||||
255
src/graphics/command_buffer.cpp
Normal file
255
src/graphics/command_buffer.cpp
Normal 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)
|
||||
669
src/graphics/command_buffer.hpp
Normal file
669
src/graphics/command_buffer.hpp
Normal 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
847
src/graphics/draw_calls.cpp
Normal 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
109
src/graphics/draw_calls.hpp
Normal 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
|
||||
338
src/graphics/draw_policies.cpp
Normal file
338
src/graphics/draw_policies.cpp
Normal 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)
|
||||
}
|
||||
95
src/graphics/draw_policies.hpp
Normal file
95
src/graphics/draw_policies.hpp
Normal 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
210
src/graphics/draw_tools.hpp
Normal 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
|
||||
114
src/graphics/fixed_pipeline_renderer.cpp
Normal file
114
src/graphics/fixed_pipeline_renderer.cpp
Normal 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));
|
||||
}
|
||||
40
src/graphics/fixed_pipeline_renderer.hpp
Normal file
40
src/graphics/fixed_pipeline_renderer.hpp
Normal 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
|
||||
389
src/graphics/geometry_passes.cpp
Normal file
389
src/graphics/geometry_passes.cpp
Normal 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
|
||||
|
||||
|
||||
|
||||
173
src/graphics/geometry_passes.hpp
Normal file
173
src/graphics/geometry_passes.hpp
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,33 +135,19 @@ 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();
|
||||
m_device->drop();
|
||||
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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -179,7 +155,7 @@ IrrDriver::~IrrDriver()
|
||||
*/
|
||||
void IrrDriver::reset()
|
||||
{
|
||||
if (CVS->isGLSL()) m_post_processing->reset();
|
||||
m_renderer->resetPostProcessing();
|
||||
} // reset
|
||||
|
||||
void IrrDriver::setPhase(STKRenderingPass p)
|
||||
@@ -194,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()
|
||||
@@ -212,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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -579,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 ||
|
||||
@@ -682,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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -869,11 +836,11 @@ void IrrDriver::applyResolutionSettings()
|
||||
UserConfigParams::m_prev_height) );
|
||||
m_video_driver->endScene();
|
||||
track_manager->removeAllCachedData();
|
||||
attachment_manager->removeTextures();
|
||||
delete attachment_manager;
|
||||
projectile_manager->removeTextures();
|
||||
ItemManager::removeTextures();
|
||||
kart_properties_manager->unloadAllKarts();
|
||||
powerup_manager->unloadPowerups();
|
||||
delete powerup_manager;
|
||||
Referee::cleanup();
|
||||
ParticleKindManager::get()->cleanup();
|
||||
delete input_manager;
|
||||
@@ -895,16 +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();
|
||||
cleanUnicolorTextures();
|
||||
// initDevice will drop the current device.
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
Shaders::destroy();
|
||||
}
|
||||
delete m_renderer;
|
||||
initDevice();
|
||||
|
||||
font_manager = new FontManager();
|
||||
@@ -917,6 +882,8 @@ void IrrDriver::applyResolutionSettings()
|
||||
material_manager->loadMaterial();
|
||||
input_manager = new InputManager ();
|
||||
input_manager->setMode(InputManager::MENU);
|
||||
powerup_manager = new PowerupManager();
|
||||
attachment_manager = new AttachmentManager();
|
||||
|
||||
GUIEngine::addLoadingIcon(
|
||||
irr_driver->getTexture(file_manager
|
||||
@@ -1054,28 +1021,6 @@ scene::IMesh *IrrDriver::getMesh(const std::string &filename)
|
||||
return am->getMesh(0);
|
||||
} // getMesh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Create a skinned mesh which has copied all meshbuffers and joints of the
|
||||
* original mesh. Note, that this will not copy any other information like
|
||||
* joints data.
|
||||
* \param mesh Original mesh
|
||||
* \return Newly created skinned mesh. You should call drop() when you don't
|
||||
* need it anymore.
|
||||
*/
|
||||
scene::IAnimatedMesh *IrrDriver::copyAnimatedMesh(scene::IAnimatedMesh *orig)
|
||||
{
|
||||
using namespace scene;
|
||||
CSkinnedMesh *mesh = dynamic_cast<CSkinnedMesh*>(orig);
|
||||
if (!mesh)
|
||||
{
|
||||
Log::error("copyAnimatedMesh", "Given mesh was not a skinned mesh.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::IAnimatedMesh* out = mesh->clone();
|
||||
return out;
|
||||
} // copyAnimatedMesh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the material flags in this mesh depending on the settings in
|
||||
* material_manager.
|
||||
@@ -1221,7 +1166,8 @@ scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh,
|
||||
const std::string& debug_name,
|
||||
scene::ISceneNode *parent,
|
||||
RenderInfo* render_info,
|
||||
bool all_parts_colorized)
|
||||
bool all_parts_colorized,
|
||||
int frame_for_mesh)
|
||||
{
|
||||
if (!CVS->isGLSL())
|
||||
return m_scene_manager->addMeshSceneNode(mesh, parent);
|
||||
@@ -1236,7 +1182,8 @@ scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh,
|
||||
core::vector3df(0, 0, 0),
|
||||
core::vector3df(1.0f, 1.0f, 1.0f),
|
||||
true, render_info,
|
||||
all_parts_colorized);
|
||||
all_parts_colorized,
|
||||
frame_for_mesh);
|
||||
node->drop();
|
||||
|
||||
return node;
|
||||
@@ -1480,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],
|
||||
@@ -1497,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();;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1846,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
|
||||
@@ -1946,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.
|
||||
*/
|
||||
@@ -2247,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())
|
||||
@@ -2333,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())
|
||||
@@ -2649,8 +2169,6 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos,
|
||||
else
|
||||
light = new SunNode(m_scene_manager, parent, r, g, b);
|
||||
|
||||
light->grab();
|
||||
|
||||
light->setPosition(pos);
|
||||
light->updateAbsolutePosition();
|
||||
|
||||
@@ -2660,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);
|
||||
@@ -2680,9 +2198,7 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos,
|
||||
|
||||
void IrrDriver::clearLights()
|
||||
{
|
||||
u32 i;
|
||||
const u32 max = (int)m_lights.size();
|
||||
for (i = 0; i < max; i++)
|
||||
for (unsigned int i = 0; i < m_lights.size(); i++)
|
||||
{
|
||||
m_lights[i]->drop();
|
||||
}
|
||||
@@ -2691,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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -188,9 +73,8 @@ enum TypeRTT
|
||||
* \ingroup graphics
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -311,34 +184,14 @@ private:
|
||||
float m_ssao_radius;
|
||||
float m_ssao_k;
|
||||
float m_ssao_sigma;
|
||||
|
||||
|
||||
#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();
|
||||
void doScreenShot();
|
||||
void PrepareDrawCalls(scene::ICameraSceneNode *camnode);
|
||||
public:
|
||||
void doScreenShot();
|
||||
public:
|
||||
IrrDriver();
|
||||
~IrrDriver();
|
||||
@@ -348,22 +201,20 @@ 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;
|
||||
scene::IAnimatedMesh *getAnimatedMesh(const std::string &name);
|
||||
scene::IMesh *getMesh(const std::string &name);
|
||||
scene::IAnimatedMesh *copyAnimatedMesh(scene::IAnimatedMesh *orig);
|
||||
video::ITexture *applyMask(video::ITexture* texture,
|
||||
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,
|
||||
@@ -393,7 +244,8 @@ public:
|
||||
const std::string& debug_name,
|
||||
scene::ISceneNode *parent = NULL,
|
||||
RenderInfo* render_info = NULL,
|
||||
bool all_parts_colorized = false);
|
||||
bool all_parts_colorized = false,
|
||||
int frame_for_mesh = -1);
|
||||
PerCameraNode *addPerCameraNode(scene::ISceneNode* node,
|
||||
scene::ICameraSceneNode* cam,
|
||||
scene::ISceneNode *parent = NULL);
|
||||
@@ -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()
|
||||
@@ -574,45 +414,49 @@ public:
|
||||
m_boundingboxesviz = false;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleWireframe() { m_wireframe = !m_wireframe; }
|
||||
void toggleWireframe() { m_wireframe = !m_wireframe; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleMipVisualization() { m_mipviz = !m_mipviz; }
|
||||
bool getWireframe() { return m_wireframe; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleNormals() { m_normals = !m_normals; }
|
||||
void toggleMipVisualization() { m_mipviz = !m_mipviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getNormals() { return m_normals; }
|
||||
bool getMipViz() { return m_mipviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleNormals() { m_normals = !m_normals; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleSSAOViz() { m_ssaoviz = !m_ssaoviz; }
|
||||
bool getNormals() { return m_normals; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleLightViz() { m_lightviz = !m_lightviz; }
|
||||
void toggleSSAOViz() { m_ssaoviz = !m_ssaoviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getLightViz() { return m_lightviz; }
|
||||
void toggleLightViz() { m_lightviz = !m_lightviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getSSAOViz() { return m_ssaoviz; }
|
||||
bool getLightViz() { return m_lightviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleRSM() { m_rsm = !m_rsm; }
|
||||
bool getSSAOViz() { return m_ssaoviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getRSM() { return m_rsm; }
|
||||
void toggleRSM() { m_rsm = !m_rsm; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleRH() { m_rh = !m_rh; }
|
||||
bool getRSM() { return m_rsm; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getRH() { return m_rh; }
|
||||
void toggleRH() { m_rh = !m_rh; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleGI() { m_gi = !m_gi; }
|
||||
bool getRH() { return m_rh; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getGI() { return m_gi; }
|
||||
void toggleGI() { m_gi = !m_gi; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleShadowViz() { m_shadowviz = !m_shadowviz; }
|
||||
bool getGI() { return m_gi; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getShadowViz() { return m_shadowviz; }
|
||||
void toggleShadowViz() { m_shadowviz = !m_shadowviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleDistortViz() { m_distortviz = !m_distortviz; }
|
||||
bool getShadowViz() { return m_shadowviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getDistortViz() { return m_distortviz; }
|
||||
void toggleDistortViz() { m_distortviz = !m_distortviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getDistortViz() { return m_distortviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
void toggleBoundingBoxesViz() { m_boundingboxesviz = !m_boundingboxesviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool getBoundingBoxesViz() { return m_boundingboxesviz; }
|
||||
bool getBoundingBoxesViz() { return m_boundingboxesviz; }
|
||||
// ------------------------------------------------------------------------
|
||||
u32 getRenderPass() { return m_renderpass; }
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,10 +15,9 @@
|
||||
// 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/central_settings.hpp"
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/light.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,
|
||||
float dt)
|
||||
void LightingPasses::renderEnvMap(GLuint normal_depth_texture,
|
||||
GLuint depth_stencil_texture,
|
||||
GLuint specular_probe)
|
||||
{
|
||||
const u32 lightcount = (u32)m_lights.size();
|
||||
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)
|
||||
{
|
||||
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,184 +520,156 @@ 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);
|
||||
radiance_hint_framebuffer.bind();
|
||||
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
|
||||
if (CVS->needRHWorkaround())
|
||||
{
|
||||
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_RH));
|
||||
glDisable(GL_BLEND);
|
||||
m_rtts->getRH().bind();
|
||||
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
|
||||
if (CVS->needRHWorkaround())
|
||||
NVWorkaroundRadianceHintsConstructionShader::getInstance()->use();
|
||||
NVWorkaroundRadianceHintsConstructionShader::getInstance()
|
||||
->setTextureUnits(
|
||||
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()->use();
|
||||
NVWorkaroundRadianceHintsConstructionShader::getInstance()
|
||||
->setTextureUnits(
|
||||
m_rtts->getRSM().getRTT()[0],
|
||||
m_rtts->getRSM().getRTT()[1],
|
||||
m_rtts->getRSM().getDepthTexture());
|
||||
for (unsigned i = 0; i < 32; i++)
|
||||
{
|
||||
NVWorkaroundRadianceHintsConstructionShader::getInstance()
|
||||
->setUniforms(getShadowMatrices()->getRSMMatrix(),
|
||||
getShadowMatrices()->getRHMatrix(),
|
||||
getShadowMatrices()->getRHExtend(), i,
|
||||
irr_driver->getSunColor());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RadianceHintsConstructionShader::getInstance()->use();
|
||||
RadianceHintsConstructionShader::getInstance()
|
||||
->setTextureUnits(
|
||||
m_rtts->getRSM().getRTT()[0],
|
||||
m_rtts->getRSM().getRTT()[1],
|
||||
m_rtts->getRSM().getDepthTexture()
|
||||
);
|
||||
RadianceHintsConstructionShader::getInstance()
|
||||
->setUniforms(getShadowMatrices()->getRSMMatrix(),
|
||||
getShadowMatrices()->getRHMatrix(),
|
||||
getShadowMatrices()->getRHExtend(),
|
||||
->setUniforms(shadow_matrices.getRSMMatrix(),
|
||||
shadow_matrices.getRHMatrix(),
|
||||
shadow_matrices.getRHExtend(), i,
|
||||
irr_driver->getSunColor());
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
getShadowMatrices()->updateSunOrthoMatrices();
|
||||
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
else
|
||||
{
|
||||
RadianceHintsConstructionShader::getInstance()->use();
|
||||
RadianceHintsConstructionShader::getInstance()
|
||||
->setTextureUnits(
|
||||
reflective_shadow_map_framebuffer.getRTT()[0],
|
||||
reflective_shadow_map_framebuffer.getRTT()[1],
|
||||
reflective_shadow_map_framebuffer.getDepthTexture()
|
||||
);
|
||||
RadianceHintsConstructionShader::getInstance()
|
||||
->setUniforms(shadow_matrices.getRSMMatrix(),
|
||||
shadow_matrices.getRHMatrix(),
|
||||
shadow_matrices.getRHExtend(),
|
||||
irr_driver->getSunColor());
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32);
|
||||
}
|
||||
#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
|
||||
} // 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
|
||||
|
||||
74
src/graphics/lighting_passes.hpp
Normal file
74
src/graphics/lighting_passes.hpp
Normal 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
|
||||
@@ -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"
|
||||
@@ -740,6 +740,26 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
|
||||
m->setTexture(7, colorization_mask_tex);
|
||||
}
|
||||
|
||||
|
||||
if (race_manager->getReverseTrack() &&
|
||||
m_mirror_axis_when_reverse != ' ')
|
||||
{
|
||||
if (m_mirrorred_mesh_buffers.find((void*)mb) == m_mirrorred_mesh_buffers.end())
|
||||
{
|
||||
m_mirrorred_mesh_buffers[(void*)mb] = true;
|
||||
//irr::video::S3DVertex* mbVertices = (video::S3DVertex*)mb->getVertices();
|
||||
for (unsigned int i = 0; i < mb->getVertexCount(); i++)
|
||||
{
|
||||
core::vector2df &tc = mb->getTCoords(i);
|
||||
if (m_mirror_axis_when_reverse == 'V')
|
||||
tc.Y = 1 - tc.Y;
|
||||
else
|
||||
tc.X = 1 - tc.X;
|
||||
}
|
||||
}
|
||||
} // reverse track and texture needs mirroring
|
||||
|
||||
|
||||
switch (m_shader_type)
|
||||
{
|
||||
case SHADERTYPE_SOLID_UNLIT:
|
||||
@@ -986,21 +1006,6 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (race_manager->getReverseTrack() &&
|
||||
m_mirror_axis_when_reverse != ' ')
|
||||
{
|
||||
//irr::video::S3DVertex* mbVertices = (video::S3DVertex*)mb->getVertices();
|
||||
for (unsigned int i = 0; i < mb->getVertexCount(); i++)
|
||||
{
|
||||
core::vector2df &tc = mb->getTCoords(i);
|
||||
if (m_mirror_axis_when_reverse == 'V')
|
||||
tc.Y = 1 - tc.Y;
|
||||
else
|
||||
tc.X = 1 - tc.X;
|
||||
}
|
||||
} // reverse track and texture needs mirroring
|
||||
|
||||
} // setMaterialProperties
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -47,7 +47,7 @@ class Material : public NoCopy
|
||||
public:
|
||||
enum ShaderType
|
||||
{
|
||||
SHADERTYPE_SOLID,
|
||||
SHADERTYPE_SOLID = 0,
|
||||
SHADERTYPE_ALPHA_TEST,
|
||||
SHADERTYPE_ALPHA_BLEND,
|
||||
SHADERTYPE_ADDITIVE,
|
||||
@@ -162,6 +162,12 @@ private:
|
||||
* the direction. */
|
||||
char m_mirror_axis_when_reverse;
|
||||
|
||||
/**
|
||||
* Associated with m_mirror_axis_when_reverse, to avoid mirroring the same material twice
|
||||
* (setAllMaterialFlags can be called multiple times on the same mesh buffer)
|
||||
*/
|
||||
std::map<void*, bool> m_mirrorred_mesh_buffers;
|
||||
|
||||
ParticleKind* m_particles_effects[EMIT_KINDS_COUNT];
|
||||
|
||||
/** For normal maps */
|
||||
|
||||
78
src/graphics/materials.cpp
Normal file
78
src/graphics/materials.cpp
Normal 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
799
src/graphics/materials.hpp
Normal 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
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <irrlicht.h>
|
||||
#include <IMesh.h>
|
||||
#include <IMeshBuffer.h>
|
||||
#include <SSkinMeshBuffer.h>
|
||||
|
||||
void MeshTools::minMax3D(scene::IMesh* mesh, Vec3 *min, Vec3 *max) {
|
||||
|
||||
@@ -444,29 +445,86 @@ scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh,
|
||||
clone->recalculateBoundingBox();
|
||||
if (calculate_tangents)
|
||||
recalculateTangents(clone, recalculate_normals, smooth, angle_weighted);
|
||||
|
||||
int mbcount = clone->getMeshBufferCount();
|
||||
for (int i = 0; i < mbcount; i++)
|
||||
{
|
||||
scene::IMeshBuffer* mb = clone->getMeshBuffer(i);
|
||||
|
||||
for (u32 t = 0; t < video::MATERIAL_MAX_TEXTURES; t++)
|
||||
{
|
||||
video::ITexture* texture = mb->getMaterial().TextureLayer[t].Texture;
|
||||
if (texture != NULL)
|
||||
texture->grab();
|
||||
}
|
||||
}
|
||||
|
||||
scene::IMeshCache* meshCache = irr_driver->getSceneManager()->getMeshCache();
|
||||
io::SNamedPath path = meshCache->getMeshName(mesh);
|
||||
irr_driver->removeMeshFromCache(mesh);
|
||||
if (path.getPath() == "")
|
||||
{
|
||||
// This mesh is not in irrlicht cache, drop it directly
|
||||
assert(mesh->getReferenceCount() == 1);
|
||||
mesh->drop();
|
||||
return clone;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cache the calcuated tangent mesh with path
|
||||
irr_driver->removeMeshFromCache(mesh);
|
||||
scene::SAnimatedMesh* amesh = new scene::SAnimatedMesh(clone);
|
||||
clone->drop();
|
||||
meshCache->addMesh(path, amesh);
|
||||
if (World::getWorld())
|
||||
{
|
||||
irr_driver->grabAllTextures(amesh);
|
||||
World::getWorld()->getTrack()->addCachedMesh(amesh);
|
||||
return amesh;
|
||||
}
|
||||
amesh->drop();
|
||||
return amesh;
|
||||
}
|
||||
|
||||
scene::SAnimatedMesh* amesh = new scene::SAnimatedMesh(clone);
|
||||
meshCache->addMesh(path, amesh);
|
||||
|
||||
World::getWorld()->getTrack()->addCachedMesh(amesh);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
void MeshTools::createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh,
|
||||
bool(*predicate)(scene::IMeshBuffer*))
|
||||
{
|
||||
core::array<scene::SSkinMeshBuffer*>& all_mb = mesh->getMeshBuffers();
|
||||
const int all_mb_size = all_mb.size();
|
||||
for (int i = 0; i < all_mb_size; i++)
|
||||
{
|
||||
scene::SSkinMeshBuffer* mb = all_mb[i];
|
||||
if (mb && predicate(mb))
|
||||
{
|
||||
mb->convertToTangents();
|
||||
const int index_count = mb->getIndexCount();
|
||||
uint16_t* idx = mb->getIndices();
|
||||
video::S3DVertexTangents* v =
|
||||
(video::S3DVertexTangents*)mb->getVertices();
|
||||
|
||||
for (int i = 0; i < index_count; i += 3)
|
||||
{
|
||||
calculateTangents(
|
||||
v[idx[i+0]].Normal,
|
||||
v[idx[i+0]].Tangent,
|
||||
v[idx[i+0]].Binormal,
|
||||
v[idx[i+0]].Pos,
|
||||
v[idx[i+1]].Pos,
|
||||
v[idx[i+2]].Pos,
|
||||
v[idx[i+0]].TCoords,
|
||||
v[idx[i+1]].TCoords,
|
||||
v[idx[i+2]].TCoords);
|
||||
|
||||
calculateTangents(
|
||||
v[idx[i+1]].Normal,
|
||||
v[idx[i+1]].Tangent,
|
||||
v[idx[i+1]].Binormal,
|
||||
v[idx[i+1]].Pos,
|
||||
v[idx[i+2]].Pos,
|
||||
v[idx[i+0]].Pos,
|
||||
v[idx[i+1]].TCoords,
|
||||
v[idx[i+2]].TCoords,
|
||||
v[idx[i+0]].TCoords);
|
||||
|
||||
calculateTangents(
|
||||
v[idx[i+2]].Normal,
|
||||
v[idx[i+2]].Tangent,
|
||||
v[idx[i+2]].Binormal,
|
||||
v[idx[i+2]].Pos,
|
||||
v[idx[i+0]].Pos,
|
||||
v[idx[i+1]].Pos,
|
||||
v[idx[i+2]].TCoords,
|
||||
v[idx[i+0]].TCoords,
|
||||
v[idx[i+1]].TCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; class IMeshBuffer; }
|
||||
namespace scene { class IMesh; class IMeshBuffer; class ISkinnedMesh; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
@@ -37,8 +37,14 @@ namespace MeshTools
|
||||
bool isNormalMap(scene::IMeshBuffer* mb);
|
||||
|
||||
// Copied from irrlicht
|
||||
scene::IMesh* createMeshWithTangents(scene::IMesh* mesh, bool(*predicate)(scene::IMeshBuffer*),
|
||||
bool recalculateNormals = false, bool smooth = false, bool angleWeighted = false, bool calculateTangents = true);
|
||||
scene::IMesh* createMeshWithTangents(scene::IMesh* mesh,
|
||||
bool(*predicate)(scene::IMeshBuffer*), bool recalculateNormals = false,
|
||||
bool smooth = false, bool angleWeighted = false,
|
||||
bool calculateTangents = true);
|
||||
|
||||
void createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh,
|
||||
bool(*predicate)(scene::IMeshBuffer*));
|
||||
|
||||
} // MeshTools
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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,46 +724,20 @@ 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,
|
||||
class LightningShader : public TextureShader<LightningShader, 1,
|
||||
core::vector3df>
|
||||
{
|
||||
public:
|
||||
@@ -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)
|
||||
{
|
||||
@@ -1101,8 +972,8 @@ static std::vector<float> getGaussianWeight(float sigma, size_t count)
|
||||
} // getGaussianWeight
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void PostProcessing::renderGaussian3Blur(const FrameBuffer &in_fbo,
|
||||
const FrameBuffer &auxiliary)
|
||||
void PostProcessing::renderGaussian3Blur(const FrameBuffer &in_fbo,
|
||||
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,15 +1005,15 @@ 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),
|
||||
UserConfigParams::m_shadows_resolution,
|
||||
->render(scalar_fbo,
|
||||
UserConfigParams::m_shadows_resolution,
|
||||
UserConfigParams::m_shadows_resolution, sigma_h);
|
||||
}
|
||||
else
|
||||
@@ -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,13 +1171,15 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo,
|
||||
{
|
||||
in_fbo.bind();
|
||||
Gaussian17TapVShader::getInstance()->render(auxiliary,
|
||||
linear_depth,
|
||||
in_fbo.getWidth(),
|
||||
in_fbo.getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
ComputeGaussian17TapVShader::getInstance()->render(auxiliary,
|
||||
in_fbo,
|
||||
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();
|
||||
}
|
||||
|
||||
bool hasgodrays = false;
|
||||
if (World::getWorld() != NULL)
|
||||
hasgodrays = World::getWorld()->getTrack()->hasGodRays();
|
||||
|
||||
if (isRace && UserConfigParams::m_light_shaft && hasgodrays)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
153
src/graphics/render_target.cpp
Normal file
153
src/graphics/render_target.cpp
Normal 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
|
||||
90
src/graphics/render_target.hpp
Normal file
90
src/graphics/render_target.hpp
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,32 +35,135 @@ 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
|
||||
{
|
||||
public:
|
||||
RTT(size_t width, size_t height);
|
||||
~RTT();
|
||||
|
||||
size_t getWidth () const { return m_width ; }
|
||||
size_t getHeight() const { return m_height; }
|
||||
|
||||
FrameBuffer &getShadowFBO() { return *m_shadow_FBO; }
|
||||
FrameBuffer &getRH() { return *m_RH_FBO; }
|
||||
FrameBuffer &getRSM() { return *m_RSM; }
|
||||
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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
975
src/graphics/shader_based_renderer.cpp
Normal file
975
src/graphics/shader_based_renderer.cpp
Normal 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
|
||||
129
src/graphics/shader_based_renderer.hpp
Normal file
129
src/graphics/shader_based_renderer.hpp
Normal 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
|
||||
@@ -365,7 +365,7 @@ Shaders::TransparentShader::TransparentShader()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
|
||||
GL_FRAGMENT_SHADER, "transparent.frag");
|
||||
assignUniforms("ModelMatrix", "TextureMatrix");
|
||||
assignUniforms("ModelMatrix", "TextureMatrix", "custom_alpha");
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
|
||||
} // TransparentShader
|
||||
|
||||
|
||||
@@ -120,7 +120,8 @@ public:
|
||||
|
||||
// ========================================================================
|
||||
class TransparentShader : public TextureShader<TransparentShader, 1,
|
||||
core::matrix4, core::matrix4 >
|
||||
core::matrix4, core::matrix4,
|
||||
float >
|
||||
{
|
||||
public:
|
||||
TransparentShader();
|
||||
|
||||
@@ -126,15 +126,34 @@ ShadowMatrices::ShadowMatrices()
|
||||
m_shadow_cam_nodes[1] = NULL;
|
||||
m_shadow_cam_nodes[2] = NULL;
|
||||
m_shadow_cam_nodes[3] = NULL;
|
||||
m_rsm_map_available = false;
|
||||
m_rsm_matrix_initialized = false;
|
||||
} // ShadowMatrices
|
||||
// ----------------------------------------------------------------------------
|
||||
ShadowMatrices::~ShadowMatrices()
|
||||
{
|
||||
resetShadowCamNodes();
|
||||
m_sun_cam->drop();
|
||||
} // ~ShadowMatrices
|
||||
// ----------------------------------------------------------------------------
|
||||
void ShadowMatrices::resetShadowCamNodes()
|
||||
{
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_shadow_cam_nodes[i])
|
||||
{
|
||||
m_shadow_cam_nodes[i]->drop();
|
||||
m_shadow_cam_nodes[i] = NULL;
|
||||
}
|
||||
}
|
||||
} // resetShadowCamNodes
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ShadowMatrices::addLight(const core::vector3df &pos)
|
||||
{
|
||||
m_sun_cam->setPosition(pos);
|
||||
m_sun_cam->updateAbsolutePosition();
|
||||
|
||||
m_rsm_matrix_initialized = false;
|
||||
|
||||
} // addLight
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -221,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
|
||||
@@ -259,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],
|
||||
@@ -298,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();
|
||||
@@ -334,17 +355,6 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca
|
||||
|
||||
if (World::getWorld() && World::getWorld()->getTrack())
|
||||
{
|
||||
// Compute track extent
|
||||
btVector3 btmin, btmax;
|
||||
if (World::getWorld()->getTrack()->getPtrTriangleMesh())
|
||||
{
|
||||
World::getWorld()->getTrack()->getTriangleMesh().getCollisionShape()
|
||||
.getAabb(btTransform::getIdentity(), btmin, btmax);
|
||||
}
|
||||
const Vec3 vmin = btmin, vmax = btmax;
|
||||
core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() -
|
||||
core::vector3df(0, 30, 0));
|
||||
|
||||
float FarValues[] =
|
||||
{
|
||||
ShadowMatrices::m_shadow_split[1],
|
||||
@@ -411,8 +421,16 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca
|
||||
}
|
||||
|
||||
// Rsm Matrix and camera
|
||||
if (!m_rsm_matrix_initialized)
|
||||
if (!m_rsm_matrix_initialized &&
|
||||
World::getWorld()->getTrack()->getPtrTriangleMesh())
|
||||
{
|
||||
// Compute track extent
|
||||
Vec3 vmin, vmax;
|
||||
World::getWorld()->getTrack()->getTriangleMesh().getCollisionShape()
|
||||
.getAabb(btTransform::getIdentity(), vmin, vmax);
|
||||
core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() -
|
||||
core::vector3df(0, 30, 0));
|
||||
|
||||
if (trackbox.MinEdge.X != trackbox.MaxEdge.X &&
|
||||
trackbox.MinEdge.Y != trackbox.MaxEdge.Y &&
|
||||
// Cover the case where sun_cam_view_matrix is null
|
||||
@@ -454,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,
|
||||
@@ -481,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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -61,18 +64,18 @@ private:
|
||||
public:
|
||||
|
||||
ShadowMatrices();
|
||||
~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()
|
||||
{
|
||||
memset(m_shadow_cam_nodes, 0, 4 * sizeof(void*));
|
||||
} // resetShadowCamNodes
|
||||
void resetShadowCamNodes();
|
||||
// ------------------------------------------------------------------------
|
||||
scene::ICameraSceneNode** getShadowCamNodes()
|
||||
{
|
||||
@@ -81,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()
|
||||
{
|
||||
@@ -101,7 +104,6 @@ public:
|
||||
return m_shadow_scales;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
}; // class ShadowMatrices
|
||||
|
||||
|
||||
@@ -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();
|
||||
initShadowVPMUBO();
|
||||
initLightingDataUBO();
|
||||
initParticleQuadVBO();
|
||||
|
||||
if(CVS->isARBUniformBufferObjectUsable())
|
||||
{
|
||||
initShadowVPMUBO();
|
||||
initLightingDataUBO();
|
||||
}
|
||||
|
||||
m_has_been_initialised = true;
|
||||
} // SharedGPUObjects
|
||||
@@ -205,4 +212,4 @@ void SharedGPUObjects::init()
|
||||
void SharedGPUObjects::reset()
|
||||
{
|
||||
m_has_been_initialised = false;
|
||||
} // reset
|
||||
} // reset
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -342,7 +342,8 @@ Skybox::Skybox(const std::vector<video::ITexture *> &skybox_textures)
|
||||
if (!skybox_textures.empty())
|
||||
{
|
||||
generateCubeMapFromTextures();
|
||||
generateSpecularCubemap();
|
||||
if(CVS->isGLSL())
|
||||
generateSpecularCubemap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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]);
|
||||
@@ -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;}
|
||||
|
||||
@@ -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>
|
||||
@@ -99,6 +93,16 @@ void STKAnimatedMesh::updateNoGL()
|
||||
|
||||
if (!isMaterialInitialized)
|
||||
{
|
||||
// Use a default render info to distinguish same mesh buffer created by
|
||||
// different animated mesh node in vao manager when using instanced
|
||||
// rendering
|
||||
RenderInfo* default_ri = NULL;
|
||||
if (CVS->isARBBaseInstanceUsable())
|
||||
{
|
||||
default_ri = new RenderInfo();
|
||||
m_static_render_info.push_back(default_ri);
|
||||
}
|
||||
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
const u32 mb_count = m->getMeshBufferCount();
|
||||
for (u32 i = 0; i < mb_count; ++i)
|
||||
@@ -121,7 +125,7 @@ void STKAnimatedMesh::updateNoGL()
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_ri = NULL;
|
||||
cur_ri = default_ri;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -137,7 +141,7 @@ void STKAnimatedMesh::updateNoGL()
|
||||
assert(cur_ri ? cur_ri->isStatic() : true);
|
||||
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name,
|
||||
affected || m_all_parts_colorized || (cur_ri
|
||||
&& cur_ri->isTransparent()) ? cur_ri : NULL));
|
||||
&& cur_ri->isTransparent()) ? cur_ri : default_ri));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
|
||||
@@ -165,11 +169,14 @@ void STKAnimatedMesh::updateNoGL()
|
||||
}
|
||||
else if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent())
|
||||
{
|
||||
TransparentMesh[TM_ADDITIVE].push_back(&mesh);
|
||||
if (mesh.VAOType == video::EVT_TANGENTS)
|
||||
TransparentMesh[TM_GHOST_KART_TANGENTS].push_back(&mesh);
|
||||
else
|
||||
TransparentMesh[TM_GHOST_KART].push_back(&mesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
Material::ShaderType MatType = material->getShaderType();// getMeshMaterialFromType(type, mb->getVertexType(), material);
|
||||
Material::ShaderType MatType = getMeshMaterialFromType(type, mb->getVertexType(), material, NULL);
|
||||
MeshSolidMaterial[MatType].push_back(&mesh);
|
||||
}
|
||||
}
|
||||
@@ -218,7 +225,7 @@ void STKAnimatedMesh::updateGL()
|
||||
|
||||
if (CVS->isARBBaseInstanceUsable())
|
||||
{
|
||||
std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb);
|
||||
std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb, GLmeshes[i].m_render_info);
|
||||
mesh.vaoBaseVertex = p.first;
|
||||
mesh.vaoOffset = p.second;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -37,6 +37,8 @@ enum TransparentMaterial
|
||||
TM_DEFAULT,
|
||||
TM_ADDITIVE,
|
||||
TM_DISPLACEMENT,
|
||||
TM_GHOST_KART,
|
||||
TM_GHOST_KART_TANGENTS,
|
||||
TM_COUNT
|
||||
}; // TransparentMaterial
|
||||
|
||||
@@ -90,6 +92,7 @@ public:
|
||||
virtual bool isImmediateDraw() const { return false; }
|
||||
}; // STKMeshCommon
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
template<typename T, typename... Args>
|
||||
class MeshList : public Singleton<T>
|
||||
@@ -105,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>
|
||||
@@ -176,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>
|
||||
@@ -197,13 +158,26 @@ class MiscList : public Singleton<T>, public std::vector<STK::Tuple<Args...> >
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class ListBlendTransparent : public MiscList<ListBlendTransparent, GLMesh *,
|
||||
core::matrix4, core::matrix4>
|
||||
core::matrix4, core::matrix4,
|
||||
float>
|
||||
{};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class ListAdditiveTransparent : public MiscList<ListAdditiveTransparent,
|
||||
GLMesh *, core::matrix4,
|
||||
core::matrix4>
|
||||
core::matrix4, float>
|
||||
{};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class ListGhostKart : public MiscList<ListGhostKart,
|
||||
GLMesh *, core::matrix4,
|
||||
core::matrix4, float>
|
||||
{};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class ListGhostKartTangents : public MiscList<ListGhostKartTangents,
|
||||
GLMesh *, core::matrix4,
|
||||
core::matrix4, float>
|
||||
{};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -227,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,
|
||||
|
||||
@@ -17,23 +17,19 @@
|
||||
|
||||
#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 <ISceneManager.h>
|
||||
#include <IMaterialRenderer.h>
|
||||
#include <ISceneManager.h>
|
||||
|
||||
// ============================================================================
|
||||
class ColorizeShader : public Shader<ColorizeShader, core::matrix4,
|
||||
@@ -54,12 +50,14 @@ STKMeshSceneNode::STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent,
|
||||
irr::s32 id, const std::string& debug_name,
|
||||
const irr::core::vector3df& position,
|
||||
const irr::core::vector3df& rotation,
|
||||
const irr::core::vector3df& scale, bool createGLMeshes, RenderInfo* render_info, bool all_parts_colorized) :
|
||||
const irr::core::vector3df& scale, bool createGLMeshes, RenderInfo* render_info, bool all_parts_colorized,
|
||||
int frame_for_mesh) :
|
||||
CMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale)
|
||||
{
|
||||
isDisplacement = false;
|
||||
immediate_draw = false;
|
||||
update_each_frame = false;
|
||||
m_frame_for_mesh = frame_for_mesh;
|
||||
isGlow = false;
|
||||
|
||||
m_debug_name = debug_name;
|
||||
@@ -207,12 +205,13 @@ void STKMeshSceneNode::updateNoGL()
|
||||
|
||||
GLMesh &mesh = GLmeshes[i];
|
||||
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
|
||||
if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent())
|
||||
if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent() && !rnd->isTransparent())
|
||||
{
|
||||
if (!immediate_draw)
|
||||
TransparentMesh[TM_ADDITIVE].push_back(&mesh);
|
||||
assert(!immediate_draw);
|
||||
if (mesh.VAOType == video::EVT_TANGENTS)
|
||||
TransparentMesh[TM_GHOST_KART_TANGENTS].push_back(&mesh);
|
||||
else
|
||||
additive = true;
|
||||
TransparentMesh[TM_GHOST_KART].push_back(&mesh);
|
||||
}
|
||||
else if (rnd->isTransparent())
|
||||
{
|
||||
@@ -249,9 +248,18 @@ void STKMeshSceneNode::updateGL()
|
||||
{
|
||||
if (isGLInitialized)
|
||||
return;
|
||||
for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i)
|
||||
|
||||
scene::IAnimatedMesh* am = dynamic_cast<scene::IAnimatedMesh*>(Mesh);
|
||||
scene::IMesh* m = Mesh;
|
||||
if (am && m_frame_for_mesh > -1)
|
||||
{
|
||||
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
|
||||
// Get the correct frame of animation for animated mesh
|
||||
m = am->getMesh(m_frame_for_mesh);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
|
||||
{
|
||||
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
|
||||
if (!mb)
|
||||
continue;
|
||||
GLMesh &mesh = GLmeshes[i];
|
||||
@@ -396,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] =
|
||||
@@ -567,7 +569,7 @@ void STKMeshSceneNode::render()
|
||||
#endif
|
||||
Shaders::TransparentShader::getInstance()->setTextureUnits(getTextureGLuint(mesh.textures[0]));
|
||||
|
||||
Shaders::TransparentShader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix);
|
||||
Shaders::TransparentShader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix, 1.0f);
|
||||
assert(mesh.vao);
|
||||
glBindVertexArray(mesh.vao);
|
||||
glDrawElements(ptype, count, itype, 0);
|
||||
|
||||
@@ -29,6 +29,7 @@ class STKMeshSceneNode : public irr::scene::CMeshSceneNode, public STKMeshCommon
|
||||
{
|
||||
protected:
|
||||
PtrVector<RenderInfo> m_static_render_info;
|
||||
int m_frame_for_mesh;
|
||||
std::vector<GLMesh> GLmeshes;
|
||||
core::matrix4 ModelViewProjectionMatrix;
|
||||
core::vector3df windDir;
|
||||
@@ -58,7 +59,8 @@ public:
|
||||
const irr::core::vector3df& rotation = irr::core::vector3df(0, 0, 0),
|
||||
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f),
|
||||
bool createGLMeshes = true,
|
||||
RenderInfo* render_info = NULL, bool all_parts_colorized = false);
|
||||
RenderInfo* render_info = NULL, bool all_parts_colorized = false,
|
||||
int frame_for_mesh = -1);
|
||||
virtual void render();
|
||||
virtual void setMesh(irr::scene::IMesh* mesh);
|
||||
virtual void OnRegisterSceneNode();
|
||||
|
||||
@@ -16,202 +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>
|
||||
#include <functional>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
class MeshRenderInfoHash
|
||||
{
|
||||
public:
|
||||
size_t operator() (const std::pair<scene::IMeshBuffer*, RenderInfo*> &p) const
|
||||
{
|
||||
return (std::hash<scene::IMeshBuffer*>()(p.first) ^
|
||||
(std::hash<RenderInfo*>()(p.second) << 1));
|
||||
}
|
||||
};
|
||||
|
||||
struct MeshRenderInfoEquals : std::binary_function
|
||||
<const std::pair<scene::IMeshBuffer*, RenderInfo*>&,
|
||||
const std::pair<scene::IMeshBuffer*, RenderInfo*>&, bool>
|
||||
{
|
||||
result_type operator() (first_argument_type lhs,
|
||||
second_argument_type rhs) const
|
||||
{
|
||||
return (lhs.first == rhs.first) &&
|
||||
(lhs.second == rhs.second);
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
@@ -225,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);
|
||||
@@ -235,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())
|
||||
@@ -254,655 +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);
|
||||
for (GLMesh *mesh : node->TransparentMesh[TM_ADDITIVE])
|
||||
pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix);
|
||||
}
|
||||
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();
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -50,14 +48,28 @@ STKTextBillboard::STKTextBillboard(core::stringw text, FontWithFace* font,
|
||||
|
||||
void STKTextBillboard::updateAbsolutePosition()
|
||||
{
|
||||
// Make billboard always face the camera
|
||||
scene::ICameraSceneNode* curr_cam =
|
||||
irr_driver->getSceneManager()->getActiveCamera();
|
||||
if (!curr_cam) return;
|
||||
core::quaternion q(curr_cam->getViewMatrix());
|
||||
q.W = -q.W;
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
// Override to not use the parent's rotation
|
||||
AbsoluteTransformation = getRelativeTransformation();
|
||||
AbsoluteTransformation.setTranslation(AbsoluteTransformation.getTranslation() + Parent->getAbsolutePosition());
|
||||
core::vector3df wc = RelativeTranslation;
|
||||
Parent->getAbsoluteTransformation().transformVect(wc);
|
||||
AbsoluteTransformation.setTranslation(wc);
|
||||
q.getMatrix(AbsoluteTransformation, wc);
|
||||
}
|
||||
else
|
||||
AbsoluteTransformation = getRelativeTransformation();
|
||||
{
|
||||
q.getMatrix(AbsoluteTransformation, RelativeTranslation);
|
||||
}
|
||||
core::matrix4 m;
|
||||
m.setScale(RelativeScale);
|
||||
AbsoluteTransformation *= m;
|
||||
}
|
||||
|
||||
scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, FontWithFace* font)
|
||||
@@ -171,18 +183,6 @@ scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, FontWithFace* fo
|
||||
return Mesh;
|
||||
}
|
||||
|
||||
void STKTextBillboard::updateNoGL()
|
||||
{
|
||||
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()->getActiveCamera();
|
||||
core::vector3df cam_pos = curr_cam->getPosition();
|
||||
core::vector3df text_pos = this->getAbsolutePosition();
|
||||
float angle = atan2(text_pos.X - cam_pos.X, text_pos.Z - cam_pos.Z);
|
||||
this->setRotation(core::vector3df(0.0f, angle * 180.0f / M_PI, 0.0f));
|
||||
updateAbsolutePosition();
|
||||
|
||||
STKMeshSceneNode::updateNoGL();
|
||||
}
|
||||
|
||||
void STKTextBillboard::collectChar(video::ITexture* texture,
|
||||
const core::rect<float>& destRect,
|
||||
const core::rect<s32>& sourceRect,
|
||||
|
||||
@@ -74,8 +74,6 @@ public:
|
||||
const irr::core::vector3df& position,
|
||||
const irr::core::vector3df& size);
|
||||
|
||||
virtual void updateNoGL() OVERRIDE;
|
||||
|
||||
virtual scene::ESCENE_NODE_TYPE getType() const OVERRIDE
|
||||
{
|
||||
return scene::ESNT_TEXT;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -59,6 +59,14 @@ static std::map<int, video::ITexture*> unicolor_cache;
|
||||
void resetTextureTable()
|
||||
{
|
||||
AlreadyTransformedTexture.clear();
|
||||
}
|
||||
|
||||
void cleanUnicolorTextures()
|
||||
{
|
||||
for (std::pair<const int, video::ITexture*>& uc : unicolor_cache)
|
||||
{
|
||||
uc.second->drop();
|
||||
}
|
||||
unicolor_cache.clear();
|
||||
}
|
||||
|
||||
@@ -228,7 +236,6 @@ video::ITexture* getUnicolorTexture(const video::SColor &c)
|
||||
std::map<int, video::ITexture*>::iterator it = unicolor_cache.find(c.color);
|
||||
if (it != unicolor_cache.end())
|
||||
{
|
||||
it->second->grab();
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
@@ -240,10 +247,12 @@ video::ITexture* getUnicolorTexture(const video::SColor &c)
|
||||
c.color
|
||||
};
|
||||
video::IImage *img = irr_driver->getVideoDriver()->createImageFromData(video::ECF_A8R8G8B8, core::dimension2d<u32>(2, 2), tmp);
|
||||
img->grab();
|
||||
std::stringstream name;
|
||||
name << "color" << c.color;
|
||||
video::ITexture* tex = irr_driver->getVideoDriver()->addTexture(name.str().c_str(), img);
|
||||
tex->grab();
|
||||
// Only let our map hold the unicolor texture
|
||||
irr_driver->getVideoDriver()->removeTexture(tex);
|
||||
unicolor_cache[c.color] = tex;
|
||||
img->drop();
|
||||
return tex;
|
||||
|
||||
@@ -16,18 +16,22 @@
|
||||
// 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);
|
||||
GLuint getDepthTexture(irr::video::ITexture *tex);
|
||||
void resetTextureTable();
|
||||
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
|
||||
|
||||
@@ -287,7 +287,7 @@ irr::video::E_VERTEX_TYPE VAOManager::getVertexType(enum VTXTYPE tp)
|
||||
}
|
||||
}
|
||||
|
||||
void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp)
|
||||
void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp, RenderInfo* ri)
|
||||
{
|
||||
size_t old_vtx_cnt = last_vertex[tp];
|
||||
size_t old_idx_cnt = last_index[tp];
|
||||
@@ -318,26 +318,28 @@ void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp)
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, old_idx_cnt * sizeof(u16), mb->getIndexCount() * sizeof(u16), mb->getIndices());
|
||||
}
|
||||
|
||||
mappedBaseVertex[tp][mb] = old_vtx_cnt;
|
||||
mappedBaseIndex[tp][mb] = old_idx_cnt * sizeof(u16);
|
||||
std::pair<scene::IMeshBuffer*, RenderInfo*> key(mb, ri);
|
||||
mappedBaseVertex[tp][key] = old_vtx_cnt;
|
||||
mappedBaseIndex[tp][key] = old_idx_cnt * sizeof(u16);
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb)
|
||||
std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb, RenderInfo* ri)
|
||||
{
|
||||
VTXTYPE tp = getVTXTYPE(mb->getVertexType());
|
||||
if (mappedBaseVertex[tp].find(mb) == mappedBaseVertex[tp].end())
|
||||
std::pair<scene::IMeshBuffer*, RenderInfo*> key(mb, ri);
|
||||
if (mappedBaseVertex[tp].find(key) == mappedBaseVertex[tp].end())
|
||||
{
|
||||
assert(mappedBaseIndex[tp].find(mb) == mappedBaseIndex[tp].end());
|
||||
append(mb, tp);
|
||||
assert(mappedBaseIndex[tp].find(key) == mappedBaseIndex[tp].end());
|
||||
append(mb, tp, ri);
|
||||
regenerateVAO(tp);
|
||||
regenerateInstancedVAO();
|
||||
}
|
||||
|
||||
std::unordered_map<scene::IMeshBuffer*, unsigned>::iterator It;
|
||||
It = mappedBaseVertex[tp].find(mb);
|
||||
std::unordered_map<std::pair<scene::IMeshBuffer*, RenderInfo*>, unsigned, MeshRenderInfoHash, MeshRenderInfoEquals>::iterator It;
|
||||
It = mappedBaseVertex[tp].find(key);
|
||||
assert(It != mappedBaseVertex[tp].end());
|
||||
unsigned vtx = It->second;
|
||||
It = mappedBaseIndex[tp].find(mb);
|
||||
It = mappedBaseIndex[tp].find(key);
|
||||
assert(It != mappedBaseIndex[tp].end());
|
||||
return std::pair<unsigned, unsigned>(vtx, It->second);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
class RenderInfo;
|
||||
|
||||
enum InstanceType
|
||||
{
|
||||
InstanceTypeDualTex,
|
||||
@@ -153,6 +155,30 @@ struct GlowInstanceData
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
|
||||
class MeshRenderInfoHash
|
||||
{
|
||||
public:
|
||||
size_t operator() (const std::pair<irr::scene::IMeshBuffer*, RenderInfo*> &p) const
|
||||
{
|
||||
return (std::hash<irr::scene::IMeshBuffer*>()(p.first) ^
|
||||
(std::hash<RenderInfo*>()(p.second) << 1));
|
||||
}
|
||||
};
|
||||
|
||||
struct MeshRenderInfoEquals : std::binary_function
|
||||
<const std::pair<irr::scene::IMeshBuffer*, RenderInfo*>&,
|
||||
const std::pair<irr::scene::IMeshBuffer*, RenderInfo*>&, bool>
|
||||
{
|
||||
result_type operator() (first_argument_type lhs,
|
||||
second_argument_type rhs) const
|
||||
{
|
||||
return (lhs.first == rhs.first) &&
|
||||
(lhs.second == rhs.second);
|
||||
}
|
||||
};
|
||||
|
||||
class VAOManager : public Singleton<VAOManager>
|
||||
{
|
||||
enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT };
|
||||
@@ -162,7 +188,7 @@ class VAOManager : public Singleton<VAOManager>
|
||||
void *VBOPtr[VTXTYPE_COUNT], *IBOPtr[VTXTYPE_COUNT];
|
||||
size_t RealVBOSize[VTXTYPE_COUNT], RealIBOSize[VTXTYPE_COUNT];
|
||||
size_t last_vertex[VTXTYPE_COUNT], last_index[VTXTYPE_COUNT];
|
||||
std::unordered_map<irr::scene::IMeshBuffer*, unsigned> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT];
|
||||
std::unordered_map <std::pair<irr::scene::IMeshBuffer*, RenderInfo*>, unsigned, MeshRenderInfoHash, MeshRenderInfoEquals> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT];
|
||||
std::map<std::pair<irr::video::E_VERTEX_TYPE, InstanceType>, GLuint> InstanceVAO;
|
||||
|
||||
void cleanInstanceVAOs();
|
||||
@@ -172,10 +198,10 @@ class VAOManager : public Singleton<VAOManager>
|
||||
size_t getVertexPitch(enum VTXTYPE) const;
|
||||
VTXTYPE getVTXTYPE(irr::video::E_VERTEX_TYPE type);
|
||||
irr::video::E_VERTEX_TYPE getVertexType(enum VTXTYPE tp);
|
||||
void append(irr::scene::IMeshBuffer *, VTXTYPE tp);
|
||||
void append(irr::scene::IMeshBuffer *, VTXTYPE tp, RenderInfo* ri = NULL);
|
||||
public:
|
||||
VAOManager();
|
||||
std::pair<unsigned, unsigned> getBase(irr::scene::IMeshBuffer *);
|
||||
std::pair<unsigned, unsigned> getBase(irr::scene::IMeshBuffer *, RenderInfo* ri = NULL);
|
||||
GLuint getInstanceBuffer(InstanceType it) { return instance_vbo[it]; }
|
||||
void *getInstanceBufferPtr(InstanceType it) { return Ptr[it]; }
|
||||
unsigned getVBO(irr::video::E_VERTEX_TYPE type) { return vbo[getVTXTYPE(type)]; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -659,10 +659,13 @@ namespace GUIEngine
|
||||
#include "config/user_config.hpp"
|
||||
#include "font/bold_face.hpp"
|
||||
#include "font/digit_face.hpp"
|
||||
#include "font/font_manager.hpp"
|
||||
#include "font/font_settings.hpp"
|
||||
#include "font/regular_face.hpp"
|
||||
#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"
|
||||
@@ -679,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;
|
||||
|
||||
@@ -143,6 +143,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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user