Merge branch 'master' of https://github.com/supertuxkart/stk-code
This commit is contained in:
31
TODO.md
31
TODO.md
@@ -4,30 +4,27 @@ SuperTuxKart is looking for additional man power to make this
|
||||
one of the best free linux games out there :) We need (in
|
||||
no particular order):
|
||||
|
||||
1. Musicians/sound engineers
|
||||
- Create additional background soundtrack
|
||||
- Musicians/sound engineers
|
||||
- Create additional background soundtracks
|
||||
- Create sound effects
|
||||
2. Artists and track designer
|
||||
- Artists and track designer
|
||||
- Create additional tracks
|
||||
- Create additional art work for tracks,
|
||||
background images
|
||||
3. Developers
|
||||
- Create additional artwork for tracks and background images
|
||||
- Developers
|
||||
- Work on network play support
|
||||
- Check our bug and enhancement request tracker on
|
||||
https://github.com/supertuxkart/stk-code/issues
|
||||
- Extend the current web page, keep it up to date
|
||||
4. Tester
|
||||
- For just about everything
|
||||
- Esp. different platforms and graphics cards
|
||||
5. Writers
|
||||
- Write documentation, ranging from man page, to
|
||||
a description for the web, to a design document, ...
|
||||
- Extend the current web page and keep it up to date
|
||||
- Testers
|
||||
- For just about everything, especially different platforms and graphics cards
|
||||
- Writers
|
||||
- Write documentation, ranging from man page, to a description for the web, to a design document, etc...
|
||||
|
||||
If you want to help the SuperTuxKart - Project, please
|
||||
contact us on the email list: [supertuxkart-devel@lists.sourceforge.net](mailto:supertuxkart-devel@lists.sourceforge.net)
|
||||
If you want to help the SuperTuxKart Project, please contact us on the email list: [supertuxkart-devel@lists.sourceforge.net](mailto:supertuxkart-devel@lists.sourceforge.net)
|
||||
|
||||
Thanks in advance!
|
||||
|
||||
-- The SuperTuxKart-Team
|
||||
-- The SuperTuxKart Team
|
||||
|
||||
|
||||
For details, see <http://supertuxkart.sourceforge.net/Get_involved>
|
||||
For details, see <http://supertuxkart.net/Community>
|
||||
|
||||
@@ -7,11 +7,16 @@ uniform sampler2D SpecMap;
|
||||
flat in sampler2D handle;
|
||||
flat in sampler2D secondhandle;
|
||||
#endif
|
||||
|
||||
uniform vec2 color_change;
|
||||
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
out vec4 FragColor;
|
||||
|
||||
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue, float emitMapValue);
|
||||
vec3 rgbToHsv(vec3 c);
|
||||
vec3 hsvToRgb(vec3 c);
|
||||
|
||||
void main(void)
|
||||
{
|
||||
@@ -27,7 +32,16 @@ void main(void)
|
||||
float specmap = texture(SpecMap, uv).g;
|
||||
float emitmap = texture(SpecMap, uv).b;
|
||||
#endif
|
||||
|
||||
if (color_change.x > 0.0)
|
||||
{
|
||||
vec3 old_hsv = rgbToHsv(col.rgb);
|
||||
old_hsv.y = max(old_hsv.y, color_change.y);
|
||||
vec3 new_color = hsvToRgb(vec3(color_change.x, old_hsv.y, old_hsv.z));
|
||||
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
|
||||
}
|
||||
|
||||
col.xyz *= pow(color.xyz, vec3(2.2));
|
||||
|
||||
|
||||
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap, emitmap) , 1.);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,15 @@ uniform sampler2D Albedo;
|
||||
uniform sampler2D SpecMap;
|
||||
#endif
|
||||
|
||||
uniform vec2 color_change;
|
||||
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
out vec4 FragColor;
|
||||
|
||||
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue, float emitMapValue);
|
||||
vec3 rgbToHsv(vec3 c);
|
||||
vec3 hsvToRgb(vec3 c);
|
||||
|
||||
void main(void)
|
||||
{
|
||||
@@ -22,6 +26,15 @@ void main(void)
|
||||
#else
|
||||
vec4 col = texture(Albedo, uv);
|
||||
#endif
|
||||
|
||||
if (color_change.x > 0.0)
|
||||
{
|
||||
vec3 old_hsv = rgbToHsv(col.rgb);
|
||||
old_hsv.y = max(old_hsv.y, color_change.y);
|
||||
vec3 new_color = hsvToRgb(vec3(color_change.x, old_hsv.y, old_hsv.z));
|
||||
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
|
||||
}
|
||||
|
||||
col.xyz *= pow(color.xyz, vec3(2.2));
|
||||
float specmap = texture(SpecMap, uv).g;
|
||||
float emitmap = texture(SpecMap, uv).b;
|
||||
|
||||
17
data/shaders/utils/rgb_conversion.frag
Normal file
17
data/shaders/utils/rgb_conversion.frag
Normal file
@@ -0,0 +1,17 @@
|
||||
vec3 rgbToHsv(vec3 c)
|
||||
{
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
vec3 hsvToRgb(vec3 c)
|
||||
{
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
@@ -11,6 +11,11 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||
find_package(OpenGL REQUIRED)
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(X11 REQUIRED)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/MacOSX" "${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64")
|
||||
@@ -25,8 +30,8 @@ elseif(MINGW)
|
||||
add_definitions(-D_IRR_STATIC_LIB_)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Shut up about unsafe stuff
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing -I/usr/X11R6/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing -I/usr/X11R6/include")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing")
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexpensive-optimizations")
|
||||
endif()
|
||||
|
||||
@@ -10,15 +10,6 @@ namespace irr
|
||||
namespace video
|
||||
{
|
||||
|
||||
//! Flag for mesh (mainly karts in STK) to use specific render type
|
||||
enum E_RENDER_TYPE
|
||||
{
|
||||
ERT_DEFAULT = 0,
|
||||
ERT_TRANSPARENT,
|
||||
ERT_RED,
|
||||
ERT_BLUE
|
||||
};
|
||||
|
||||
//! Abstracted and easy to use fixed function/programmable pipeline material modes.
|
||||
enum E_MATERIAL_TYPE
|
||||
{
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace scene
|
||||
class IMesh : public virtual IReferenceCounted
|
||||
{
|
||||
public:
|
||||
IMesh() : m_rt(video::ERT_DEFAULT) {}
|
||||
|
||||
virtual ~IMesh() {}
|
||||
|
||||
//! Get the amount of mesh buffers.
|
||||
/** \return Amount of mesh buffers (IMeshBuffer) in this mesh. */
|
||||
@@ -69,15 +66,6 @@ namespace scene
|
||||
indices have changed. Otherwise, changes won't be updated
|
||||
on the GPU in the next render cycle. */
|
||||
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0;
|
||||
|
||||
//! Set the mesh to use a specific render type (mainly karts in STK)
|
||||
/** \param t New render type for the mesh. */
|
||||
void setRenderType(video::E_RENDER_TYPE t) { m_rt = t; }
|
||||
|
||||
//! Get the specific render type for the mesh (mainly karts in STK)
|
||||
video::E_RENDER_TYPE getRenderType() const { return m_rt; }
|
||||
private:
|
||||
video::E_RENDER_TYPE m_rt;
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
||||
@@ -66,7 +66,7 @@ void CImageLoaderJPG::init_source (j_decompress_ptr cinfo)
|
||||
boolean CImageLoaderJPG::fill_input_buffer (j_decompress_ptr cinfo)
|
||||
{
|
||||
// DO NOTHING
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
# 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")
|
||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "graphics/per_camera_node.hpp"
|
||||
#include "graphics/post_processing.hpp"
|
||||
#include "graphics/referee.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/shadow_matrices.hpp"
|
||||
#include "graphics/stk_animated_mesh.hpp"
|
||||
@@ -1013,8 +1014,7 @@ scene::IMesh *IrrDriver::getMesh(const std::string &filename)
|
||||
* \return Newly created skinned mesh. You should call drop() when you don't
|
||||
* need it anymore.
|
||||
*/
|
||||
scene::IAnimatedMesh *IrrDriver::copyAnimatedMesh(scene::IAnimatedMesh *orig,
|
||||
video::E_RENDER_TYPE rt)
|
||||
scene::IAnimatedMesh *IrrDriver::copyAnimatedMesh(scene::IAnimatedMesh *orig)
|
||||
{
|
||||
using namespace scene;
|
||||
CSkinnedMesh *mesh = dynamic_cast<CSkinnedMesh*>(orig);
|
||||
@@ -1025,7 +1025,6 @@ scene::IAnimatedMesh *IrrDriver::copyAnimatedMesh(scene::IAnimatedMesh *orig,
|
||||
}
|
||||
|
||||
scene::IAnimatedMesh* out = mesh->clone();
|
||||
out->setRenderType(rt);
|
||||
return out;
|
||||
} // copyAnimatedMesh
|
||||
|
||||
@@ -1171,7 +1170,9 @@ scene::IParticleSystemSceneNode *IrrDriver::addParticleNode(bool default_emitter
|
||||
*/
|
||||
scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh,
|
||||
const std::string& debug_name,
|
||||
scene::ISceneNode *parent)
|
||||
scene::ISceneNode *parent,
|
||||
RenderInfo* render_info,
|
||||
bool all_parts_colorized)
|
||||
{
|
||||
if (!CVS->isGLSL())
|
||||
return m_scene_manager->addMeshSceneNode(mesh, parent);
|
||||
@@ -1181,7 +1182,12 @@ scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh,
|
||||
|
||||
scene::IMeshSceneNode* node = new STKMeshSceneNode(mesh, parent,
|
||||
m_scene_manager, -1,
|
||||
debug_name);
|
||||
debug_name,
|
||||
core::vector3df(0, 0, 0),
|
||||
core::vector3df(0, 0, 0),
|
||||
core::vector3df(1.0f, 1.0f, 1.0f),
|
||||
true, render_info,
|
||||
all_parts_colorized);
|
||||
node->drop();
|
||||
|
||||
return node;
|
||||
@@ -1363,7 +1369,8 @@ void IrrDriver::removeTexture(video::ITexture *t)
|
||||
* \param mesh The animated mesh to add.
|
||||
*/
|
||||
scene::IAnimatedMeshSceneNode *IrrDriver::addAnimatedMesh(scene::IAnimatedMesh *mesh,
|
||||
const std::string& debug_name, scene::ISceneNode* parent)
|
||||
const std::string& debug_name, scene::ISceneNode* parent,
|
||||
RenderInfo* render_info, bool all_parts_colorized)
|
||||
{
|
||||
if (!CVS->isGLSL())
|
||||
{
|
||||
@@ -1378,7 +1385,8 @@ scene::IAnimatedMeshSceneNode *IrrDriver::addAnimatedMesh(scene::IAnimatedMesh *
|
||||
parent = m_scene_manager->getRootSceneNode();
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
new STKAnimatedMesh(mesh, parent, m_scene_manager, -1, debug_name,
|
||||
core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), core::vector3df(1, 1, 1));
|
||||
core::vector3df(0, 0, 0), core::vector3df(0, 0, 0),
|
||||
core::vector3df(1, 1, 1), render_info, all_parts_colorized);
|
||||
node->drop();
|
||||
return node;
|
||||
} // addAnimatedMesh
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace irr
|
||||
using namespace irr;
|
||||
|
||||
class RTT;
|
||||
class RenderInfo;
|
||||
class FrameBuffer;
|
||||
class ShadowImportanceProvider;
|
||||
class AbstractKart;
|
||||
@@ -353,8 +354,7 @@ public:
|
||||
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::E_RENDER_TYPE rt);
|
||||
scene::IAnimatedMesh *copyAnimatedMesh(scene::IAnimatedMesh *orig);
|
||||
video::ITexture *applyMask(video::ITexture* texture,
|
||||
const std::string& mask_path);
|
||||
void displayFPS();
|
||||
@@ -387,7 +387,9 @@ public:
|
||||
const video::SColor &color=video::SColor(128, 255, 255, 255));
|
||||
scene::IMeshSceneNode*addMesh(scene::IMesh *mesh,
|
||||
const std::string& debug_name,
|
||||
scene::ISceneNode *parent=NULL);
|
||||
scene::ISceneNode *parent = NULL,
|
||||
RenderInfo* render_info = NULL,
|
||||
bool all_parts_colorized = false);
|
||||
PerCameraNode *addPerCameraNode(scene::ISceneNode* node,
|
||||
scene::ICameraSceneNode* cam,
|
||||
scene::ISceneNode *parent = NULL);
|
||||
@@ -407,7 +409,11 @@ public:
|
||||
void removeMeshFromCache(scene::IMesh *mesh);
|
||||
void removeTexture(video::ITexture *t);
|
||||
scene::IAnimatedMeshSceneNode
|
||||
*addAnimatedMesh(scene::IAnimatedMesh *mesh, const std::string& debug_name, scene::ISceneNode* parent = NULL);
|
||||
*addAnimatedMesh(scene::IAnimatedMesh *mesh,
|
||||
const std::string& debug_name,
|
||||
scene::ISceneNode* parent = NULL,
|
||||
RenderInfo* render_info = NULL,
|
||||
bool all_parts_colorized = false);
|
||||
scene::ICameraSceneNode
|
||||
*addCameraSceneNode();
|
||||
Camera *addCamera(unsigned int index, AbstractKart *kart);
|
||||
|
||||
@@ -133,20 +133,22 @@ Material::Material(const XMLNode *node, bool deprecated)
|
||||
// force the reset flag in this case.
|
||||
if(m_falling_effect)
|
||||
m_drive_reset=true;
|
||||
node->get("surface", &m_surface );
|
||||
node->get("ignore", &m_ignore );
|
||||
node->get("surface", &m_surface );
|
||||
node->get("ignore", &m_ignore );
|
||||
|
||||
node->get("max-speed", &m_max_speed_fraction);
|
||||
node->get("slowdown-time", &m_slowdown_time );
|
||||
node->get("backface-culling", &m_backface_culling );
|
||||
node->get("disable-z-write", &m_disable_z_write );
|
||||
node->get("fog", &m_fog );
|
||||
node->get("max-speed", &m_max_speed_fraction );
|
||||
node->get("slowdown-time", &m_slowdown_time );
|
||||
node->get("backface-culling", &m_backface_culling );
|
||||
node->get("disable-z-write", &m_disable_z_write );
|
||||
node->get("colorizable", &m_colorizable );
|
||||
node->get("colorization-factor", &m_colorization_factor);
|
||||
node->get("fog", &m_fog );
|
||||
|
||||
node->get("mask", &m_mask );
|
||||
node->get("gloss-map", &m_gloss_map );
|
||||
node->get("water-splash", &m_water_splash );
|
||||
node->get("jump", &m_is_jump_texture );
|
||||
node->get("has-gravity", &m_has_gravity );
|
||||
node->get("mask", &m_mask );
|
||||
node->get("gloss-map", &m_gloss_map );
|
||||
node->get("water-splash", &m_water_splash );
|
||||
node->get("jump", &m_is_jump_texture );
|
||||
node->get("has-gravity", &m_has_gravity );
|
||||
|
||||
if (m_collision_reaction != NORMAL)
|
||||
{
|
||||
@@ -434,6 +436,8 @@ void Material::init()
|
||||
m_mirror_axis_when_reverse = ' ';
|
||||
m_collision_reaction = NORMAL;
|
||||
m_disable_z_write = false;
|
||||
m_colorizable = false;
|
||||
m_colorization_factor = 0.0f;
|
||||
m_water_shader_speed_1 = 6.6667f;
|
||||
m_water_shader_speed_2 = 4.0f;
|
||||
m_fog = true;
|
||||
|
||||
@@ -175,6 +175,12 @@ private:
|
||||
/** Set to true to disable writing to the Z buffer. Usually to be used with alpha blending */
|
||||
bool m_disable_z_write;
|
||||
|
||||
/** True if this material can be colorized (like red/blue in team game). */
|
||||
bool m_colorizable;
|
||||
|
||||
/** Minimum resulting saturation when colorized (from 0 to 1) */
|
||||
float m_colorization_factor;
|
||||
|
||||
/** Some textures need to be pre-multiplied, some divided to give
|
||||
* the intended effect. */
|
||||
//enum {ADJ_NONE, ADJ_PREMUL, ADJ_DIV}
|
||||
@@ -283,6 +289,14 @@ public:
|
||||
* is driving on it. */
|
||||
bool isDriveReset () const { return m_drive_reset; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this material can be colorized (like red/blue in team game).
|
||||
*/
|
||||
bool isColorizable () const { return m_colorizable; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the minimum resulting saturation when colorized.
|
||||
*/
|
||||
float getColorizationFactor () const { return m_colorization_factor; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this material should trigger a rescue if a kart
|
||||
* crashes against it. */
|
||||
CollisionReaction getCollisionReaction() const { return m_collision_reaction; }
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/post_processing.hpp"
|
||||
#include "graphics/rtts.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/shadow_matrices.hpp"
|
||||
#include "graphics/stk_scene_manager.hpp"
|
||||
@@ -133,13 +134,18 @@ public:
|
||||
// ============================================================================
|
||||
class InstancedObjectPass2Shader : public TextureShader<InstancedObjectPass2Shader, 5>
|
||||
{
|
||||
private:
|
||||
GLint m_color_change_location;
|
||||
|
||||
public:
|
||||
InstancedObjectPass2Shader()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "utils/getworldmatrix.vert",
|
||||
GL_VERTEX_SHADER, "instanced_object_pass.vert",
|
||||
GL_FRAGMENT_SHADER, "utils/getLightFactor.frag",
|
||||
GL_FRAGMENT_SHADER, "utils/rgb_conversion.frag",
|
||||
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,
|
||||
@@ -147,6 +153,12 @@ public:
|
||||
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
|
||||
4, "SpecMap", 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
|
||||
|
||||
// ============================================================================
|
||||
@@ -987,10 +999,27 @@ void draw(const T *Shader, const GLMesh *mesh, uniforms... Args)
|
||||
GLenum itype = mesh->IndexType;
|
||||
size_t count = mesh->IndexCount;
|
||||
|
||||
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)
|
||||
{
|
||||
Shader->changeableColor(mesh->m_render_info->getHue(),
|
||||
mesh->m_material->getColorizationFactor());
|
||||
}
|
||||
|
||||
Shader->setUniforms(Args...);
|
||||
glDrawElementsBaseVertex(ptype, (int)count, itype,
|
||||
(GLvoid *)mesh->vaoOffset,
|
||||
(int)mesh->vaoBaseVertex);
|
||||
|
||||
if (need_change_hue)
|
||||
{
|
||||
// Reset after changing
|
||||
Shader->changeableColor();
|
||||
}
|
||||
|
||||
} // draw
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1272,10 +1301,28 @@ void renderInstancedMeshes2ndPass(const std::vector<GLuint> &Prefilled_tex, Args
|
||||
TexExpander<typename T::InstancedSecondPassShader>::template
|
||||
ExpandTex(*mesh, T::SecondPassTextures, Prefilled_tex[0],
|
||||
Prefilled_tex[1], Prefilled_tex[2]);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
T::InstancedSecondPassShader::getInstance()->setUniforms(args...);
|
||||
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT,
|
||||
(const void*)((SolidPassCmd::getInstance()->Offset[T::MaterialType] + i)
|
||||
* sizeof(DrawElementsIndirectCommand)));
|
||||
|
||||
if (need_change_hue)
|
||||
{
|
||||
// Reset after changing
|
||||
T::InstancedSecondPassShader::getInstance()->changeableColor();
|
||||
}
|
||||
}
|
||||
} // renderInstancedMeshes2ndPass
|
||||
|
||||
|
||||
44
src/graphics/render_info.cpp
Normal file
44
src/graphics/render_info.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 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_info.hpp"
|
||||
|
||||
#include "graphics/material.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
|
||||
#include <ISceneManager.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
RenderInfo::RenderInfo(float hue, bool transparent)
|
||||
{
|
||||
m_hue = hue;
|
||||
m_transparent = transparent;
|
||||
} // RenderInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RenderInfo::setColorizableParts(irr::scene::IMesh* m)
|
||||
{
|
||||
for (int i = 0; i < int(m->getMeshBufferCount()); i++)
|
||||
{
|
||||
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
|
||||
Material* material = material_manager->getMaterialFor(mb
|
||||
->getMaterial().getTexture(0), mb);
|
||||
if (material->isColorizable())
|
||||
m_colorizable_parts.push_back(i);
|
||||
}
|
||||
} // setColorizableParts
|
||||
87
src/graphics/render_info.hpp
Normal file
87
src/graphics/render_info.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 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_INFO_HPP
|
||||
#define HEADER_RENDER_INFO_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; }
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup graphics
|
||||
*/
|
||||
class RenderInfo
|
||||
{
|
||||
public:
|
||||
enum KartRenderType
|
||||
{
|
||||
KRT_DEFAULT,
|
||||
KRT_RED,
|
||||
KRT_BLUE,
|
||||
KRT_TRANSPARENT,
|
||||
};
|
||||
|
||||
private:
|
||||
float m_hue;
|
||||
|
||||
bool m_transparent;
|
||||
|
||||
std::vector<int> m_colorizable_parts;
|
||||
|
||||
public:
|
||||
RenderInfo(float hue = 0.0f, bool transparent = false);
|
||||
// ------------------------------------------------------------------------
|
||||
~RenderInfo() {}
|
||||
// ------------------------------------------------------------------------
|
||||
void setColorizableParts(irr::scene::IMesh* m);
|
||||
// ------------------------------------------------------------------------
|
||||
void setHue(float hue) { m_hue = hue; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setTransparent(bool transparent) { m_transparent = transparent; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getHue() const { return m_hue; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isTransparent() const { return m_transparent; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isColorizable(int mesh_buffer_index) const
|
||||
{
|
||||
return m_colorizable_parts.empty() ||
|
||||
std::find(m_colorizable_parts.begin(), m_colorizable_parts.end(),
|
||||
mesh_buffer_index) != m_colorizable_parts.end();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setKartModelRenderInfo(KartRenderType krt)
|
||||
{
|
||||
setHue(krt == RenderInfo::KRT_BLUE ? 0.66f :
|
||||
krt == RenderInfo::KRT_RED ? 1.0f : 0.0f);
|
||||
|
||||
setTransparent(krt == RenderInfo::KRT_TRANSPARENT ? true : false);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setRenderInfo(const RenderInfo* other) { *this = *other; }
|
||||
|
||||
}; // RenderInfo
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -340,7 +340,9 @@ Shaders::ObjectPass2Shader::ObjectPass2Shader()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "object_pass.vert",
|
||||
GL_FRAGMENT_SHADER, "utils/getLightFactor.frag",
|
||||
GL_FRAGMENT_SHADER, "utils/rgb_conversion.frag",
|
||||
GL_FRAGMENT_SHADER, "object_pass2.frag");
|
||||
m_color_change_location = glGetUniformLocation(m_program, "color_change");
|
||||
assignUniforms("ModelMatrix", "TextureMatrix");
|
||||
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
|
||||
1, "SpecularMap", ST_NEAREST_FILTERED,
|
||||
|
||||
@@ -146,8 +146,15 @@ public:
|
||||
class ObjectPass2Shader : public TextureShader < ObjectPass2Shader, 5,
|
||||
core::matrix4, core::matrix4 >
|
||||
{
|
||||
private:
|
||||
GLint m_color_change_location;
|
||||
public:
|
||||
ObjectPass2Shader();
|
||||
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
|
||||
}; // ObjectPass2Shader
|
||||
|
||||
// ========================================================================
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
#include "central_settings.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/stk_animated_mesh.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"
|
||||
@@ -38,11 +39,13 @@ STKAnimatedMesh::STKAnimatedMesh(irr::scene::IAnimatedMesh* mesh, irr::scene::IS
|
||||
irr::scene::ISceneManager* mgr, s32 id, const std::string& debug_name,
|
||||
const core::vector3df& position,
|
||||
const core::vector3df& rotation,
|
||||
const core::vector3df& scale) :
|
||||
const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized) :
|
||||
CAnimatedMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale)
|
||||
{
|
||||
isGLInitialized = false;
|
||||
isMaterialInitialized = false;
|
||||
m_mesh_render_info = render_info;
|
||||
m_all_parts_colorized = all_parts_colorized;
|
||||
#ifdef DEBUG
|
||||
m_debug_name = debug_name;
|
||||
#endif
|
||||
@@ -100,7 +103,16 @@ void STKAnimatedMesh::updateNoGL()
|
||||
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
|
||||
{
|
||||
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
|
||||
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name));
|
||||
bool affected = false;
|
||||
if (!m_all_parts_colorized && mb && m_mesh_render_info)
|
||||
{
|
||||
// Test if material is affected by hue change
|
||||
affected = m_mesh_render_info->isColorizable(i);
|
||||
}
|
||||
|
||||
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name,
|
||||
affected || m_all_parts_colorized || (m_mesh_render_info
|
||||
&& m_mesh_render_info->isTransparent()) ? m_mesh_render_info : NULL));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
|
||||
@@ -126,10 +138,17 @@ void STKAnimatedMesh::updateNoGL()
|
||||
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material);
|
||||
TransparentMesh[TranspMat].push_back(&mesh);
|
||||
}
|
||||
else if (m->getRenderType() == video::ERT_TRANSPARENT)
|
||||
else if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent())
|
||||
{
|
||||
TransparentMesh[TM_ADDITIVE].push_back(&mesh);
|
||||
}
|
||||
else if (mesh.m_render_info != NULL)
|
||||
{
|
||||
// For now, put all meshes that support custom render info into
|
||||
// solid (default) material first, this allowing changing fewer
|
||||
// shaders
|
||||
MeshSolidMaterial[Material::SHADERTYPE_SOLID].push_back(&mesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
Material::ShaderType MatType = material->getShaderType();// getMeshMaterialFromType(type, mb->getVertexType(), material);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <IAnimatedMesh.h>
|
||||
#include <irrTypes.h>
|
||||
|
||||
class RenderInfo;
|
||||
|
||||
class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon
|
||||
{
|
||||
protected:
|
||||
@@ -40,12 +42,16 @@ public:
|
||||
irr::scene::ISceneManager* mgr, irr::s32 id, const std::string& debug_name,
|
||||
const irr::core::vector3df& position = irr::core::vector3df(0,0,0),
|
||||
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));
|
||||
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f),
|
||||
RenderInfo* render_info = NULL, bool all_parts_colorized = false);
|
||||
~STKAnimatedMesh();
|
||||
|
||||
virtual void render();
|
||||
virtual void setMesh(irr::scene::IAnimatedMesh* mesh);
|
||||
virtual bool glow() const { return false; }
|
||||
private:
|
||||
RenderInfo* m_mesh_render_info;
|
||||
bool m_all_parts_colorized;
|
||||
};
|
||||
|
||||
#endif // STKANIMATEDMESH_HPP
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#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/shaders.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
@@ -163,13 +165,21 @@ GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type)
|
||||
} // createVAO
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb, const std::string& debug_name)
|
||||
GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb, const std::string& debug_name,
|
||||
RenderInfo* render_info)
|
||||
{
|
||||
GLMesh result = {};
|
||||
result.m_material = NULL;
|
||||
result.m_render_info = NULL;
|
||||
if (!mb)
|
||||
return result;
|
||||
result.mb = mb;
|
||||
|
||||
if (render_info != NULL)
|
||||
{
|
||||
result.m_render_info = render_info;
|
||||
result.m_material = material_manager->getMaterialFor(mb
|
||||
->getMaterial().getTexture(0), mb);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
result.debug_name = debug_name;
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Material;
|
||||
class RenderInfo;
|
||||
|
||||
enum TransparentMaterial
|
||||
{
|
||||
@@ -56,6 +56,8 @@ struct GLMesh
|
||||
video::E_VERTEX_TYPE VAOType;
|
||||
uint64_t TextureHandles[6];
|
||||
scene::IMeshBuffer *mb;
|
||||
RenderInfo* m_render_info;
|
||||
Material* m_material;
|
||||
#ifdef DEBUG
|
||||
std::string debug_name;
|
||||
#endif
|
||||
@@ -63,7 +65,8 @@ struct GLMesh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb,
|
||||
const std::string& debug_name);
|
||||
const std::string& debug_name,
|
||||
RenderInfo* render_info);
|
||||
void fillLocalBuffer(GLMesh &, scene::IMeshBuffer* mb);
|
||||
video::E_VERTEX_TYPE getVTXTYPEFromStride(size_t stride);
|
||||
GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "graphics/stk_mesh.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "modes/world.hpp"
|
||||
@@ -34,7 +35,6 @@
|
||||
#include <ISceneManager.h>
|
||||
#include <IMaterialRenderer.h>
|
||||
|
||||
|
||||
// ============================================================================
|
||||
class ColorizeShader : public Shader<ColorizeShader, core::matrix4,
|
||||
video::SColorf>
|
||||
@@ -54,7 +54,7 @@ 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) :
|
||||
const irr::core::vector3df& scale, bool createGLMeshes, RenderInfo* render_info, bool all_parts_colorized) :
|
||||
CMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale)
|
||||
{
|
||||
isDisplacement = false;
|
||||
@@ -65,7 +65,7 @@ STKMeshSceneNode::STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent,
|
||||
m_debug_name = debug_name;
|
||||
|
||||
if (createGLMeshes)
|
||||
this->createGLMeshes();
|
||||
this->createGLMeshes(render_info, all_parts_colorized);
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::setReloadEachFrame(bool val)
|
||||
@@ -75,12 +75,21 @@ void STKMeshSceneNode::setReloadEachFrame(bool val)
|
||||
immediate_draw = true;
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::createGLMeshes()
|
||||
void STKMeshSceneNode::createGLMeshes(RenderInfo* render_info, bool all_parts_colorized)
|
||||
{
|
||||
for (u32 i = 0; i<Mesh->getMeshBufferCount(); ++i)
|
||||
{
|
||||
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
|
||||
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name));
|
||||
bool affected = false;
|
||||
if (!all_parts_colorized && mb && render_info)
|
||||
{
|
||||
// Test if material is affected by hue change
|
||||
affected = render_info->isColorizable(i);
|
||||
}
|
||||
|
||||
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name,
|
||||
affected || all_parts_colorized || (render_info &&
|
||||
render_info->isTransparent()) ? render_info : NULL));
|
||||
}
|
||||
isMaterialInitialized = false;
|
||||
isGLInitialized = false;
|
||||
@@ -173,7 +182,7 @@ void STKMeshSceneNode::updateNoGL()
|
||||
|
||||
GLMesh &mesh = GLmeshes[i];
|
||||
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
|
||||
if (Mesh->getRenderType() == video::ERT_TRANSPARENT)
|
||||
if (mesh.m_render_info != NULL && mesh.m_render_info->isTransparent())
|
||||
{
|
||||
if (!immediate_draw)
|
||||
TransparentMesh[TM_ADDITIVE].push_back(&mesh);
|
||||
@@ -188,6 +197,14 @@ void STKMeshSceneNode::updateNoGL()
|
||||
else
|
||||
additive = (TranspMat == TM_ADDITIVE);
|
||||
}
|
||||
else if (mesh.m_render_info != NULL)
|
||||
{
|
||||
// For now, put all meshes that support custom render info into
|
||||
// solid (default) material first, this allowing changing fewer
|
||||
// shaders
|
||||
if (!immediate_draw)
|
||||
MeshSolidMaterial[Material::SHADERTYPE_SOLID].push_back(&mesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!isDisplacement);
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
class RenderInfo;
|
||||
|
||||
class STKMeshSceneNode : public irr::scene::CMeshSceneNode, public STKMeshCommon
|
||||
{
|
||||
protected:
|
||||
@@ -33,7 +35,7 @@ protected:
|
||||
|
||||
// Misc passes shaders (glow, displace...)
|
||||
void drawGlow(const GLMesh &mesh);
|
||||
void createGLMeshes();
|
||||
void createGLMeshes(RenderInfo* render_info = NULL, bool all_parts_colorized = false);
|
||||
void cleanGLMeshes();
|
||||
void setFirstTimeMaterial();
|
||||
void updatevbo();
|
||||
@@ -54,7 +56,8 @@ public:
|
||||
const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0),
|
||||
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);
|
||||
bool createGLMeshes = true,
|
||||
RenderInfo* render_info = NULL, bool all_parts_colorized = false);
|
||||
virtual void render();
|
||||
virtual void setMesh(irr::scene::IMesh* mesh);
|
||||
virtual void OnRegisterSceneNode();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#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"
|
||||
@@ -155,6 +156,42 @@ FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > Instan
|
||||
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,
|
||||
@@ -169,7 +206,8 @@ void FillInstances(const std::unordered_map<scene::IMeshBuffer *, std::vector<st
|
||||
}
|
||||
}
|
||||
|
||||
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForSolidPass[Material::SHADERTYPE_COUNT], MeshForShadowPass[Material::SHADERTYPE_COUNT][4], MeshForRSM[Material::SHADERTYPE_COUNT];
|
||||
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;
|
||||
|
||||
@@ -321,7 +359,7 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
|
||||
MeshForGlowPass[mesh->mb].emplace_back(mesh, Node);
|
||||
|
||||
if (Mat != Material::SHADERTYPE_SPLATTING && mesh->TextureMatrix.isIdentity())
|
||||
MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node);
|
||||
MeshForSolidPass[Mat][std::pair<scene::IMeshBuffer*, RenderInfo*>(mesh->mb, mesh->m_render_info)].emplace_back(mesh, Node);
|
||||
else
|
||||
{
|
||||
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/gl_headers.hpp"
|
||||
#include "graphics/shader.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <functional>
|
||||
@@ -241,6 +242,12 @@ public:
|
||||
glDeleteSamplers(1, &m_sampler_ids[i]);
|
||||
} // ~TextureShader
|
||||
|
||||
/** Override this class and return true if a shader has changeable color.
|
||||
*/
|
||||
virtual bool changeableColor(float hue = 0.0f, float min_sat = 0.0f) const
|
||||
{
|
||||
return false;
|
||||
} // changeableColor
|
||||
|
||||
}; // class TextureShader
|
||||
|
||||
|
||||
@@ -48,20 +48,20 @@ IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false,
|
||||
m_rtt_provider = NULL;
|
||||
m_old_rtt_provider = NULL;
|
||||
m_rotation_mode = ROTATE_OFF;
|
||||
|
||||
|
||||
// so that the base class doesn't complain there is no icon defined
|
||||
m_properties[PROP_ICON]="gui/main_help.png";
|
||||
|
||||
|
||||
m_rtt_unsupported = false;
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
ModelViewWidget::~ModelViewWidget()
|
||||
{
|
||||
GUIEngine::needsUpdate.remove(this);
|
||||
|
||||
|
||||
delete m_rtt_provider;
|
||||
m_rtt_provider = NULL;
|
||||
|
||||
|
||||
delete m_old_rtt_provider;
|
||||
m_old_rtt_provider = NULL;
|
||||
m_texture = NULL;
|
||||
@@ -71,18 +71,18 @@ void ModelViewWidget::add()
|
||||
{
|
||||
// so that the base class doesn't complain there is no icon defined
|
||||
m_properties[PROP_ICON]="gui/main_help.png";
|
||||
|
||||
|
||||
IconButtonWidget::add();
|
||||
|
||||
|
||||
/*
|
||||
FIXME: remove this unclean thing, I think irrlicht provides this feature:
|
||||
virtual void IGUIElement::OnPostRender (u32 timeMs)
|
||||
\brief animate the element and its children.
|
||||
*/
|
||||
GUIEngine::needsUpdate.push_back(this);
|
||||
|
||||
|
||||
angle = 0;
|
||||
|
||||
|
||||
} // add
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -92,11 +92,12 @@ void ModelViewWidget::clearModels()
|
||||
m_model_location.clear();
|
||||
m_model_scale.clear();
|
||||
m_model_frames.clear();
|
||||
|
||||
m_model_render_info_affected.clear();
|
||||
|
||||
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;
|
||||
@@ -105,15 +106,17 @@ void ModelViewWidget::clearModels()
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location,
|
||||
const Vec3& scale, const int frame)
|
||||
const Vec3& scale, const int frame,
|
||||
bool all_parts_colorized)
|
||||
{
|
||||
if(!mesh) return;
|
||||
|
||||
|
||||
m_models.push_back(mesh);
|
||||
m_model_location.push_back(location);
|
||||
m_model_scale.push_back(scale);
|
||||
m_model_frames.push_back(frame);
|
||||
|
||||
m_model_render_info_affected.push_back(all_parts_colorized);
|
||||
|
||||
delete m_old_rtt_provider;
|
||||
m_old_rtt_provider = NULL;
|
||||
m_texture = NULL;
|
||||
@@ -123,7 +126,7 @@ void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location,
|
||||
void ModelViewWidget::update(float delta)
|
||||
{
|
||||
if (m_rtt_unsupported) return;
|
||||
|
||||
|
||||
if (m_rotation_mode == ROTATE_CONTINUOUSLY)
|
||||
{
|
||||
angle += delta*m_rotation_speed;
|
||||
@@ -135,10 +138,10 @@ void ModelViewWidget::update(float delta)
|
||||
// (taking wrap-arounds into account)
|
||||
const int angle_distance_from_end = (int)(360 - angle);
|
||||
const int target_distance_from_end = (int)(360 - angle);
|
||||
|
||||
|
||||
int distance_with_positive_rotation;
|
||||
int distance_with_negative_rotation;
|
||||
|
||||
|
||||
if (angle < m_rotation_target)
|
||||
{
|
||||
distance_with_positive_rotation = (int)(m_rotation_target - angle);
|
||||
@@ -149,11 +152,11 @@ void ModelViewWidget::update(float delta)
|
||||
distance_with_positive_rotation = (int)(angle_distance_from_end + m_rotation_target);
|
||||
distance_with_negative_rotation = (int)(angle - m_rotation_target);
|
||||
}
|
||||
|
||||
|
||||
//Log::info("ModelViewWidget", "distance_with_positive_rotation = %d; "
|
||||
// "distance_with_negative_rotation = %d; angle = %f", distance_with_positive_rotation,
|
||||
// distance_with_negative_rotation, angle);
|
||||
|
||||
|
||||
if (distance_with_positive_rotation < distance_with_negative_rotation)
|
||||
{
|
||||
angle += m_rotation_speed * delta*(3.0f + std::min(distance_with_positive_rotation, distance_with_negative_rotation)*2.0f);
|
||||
@@ -164,29 +167,29 @@ void ModelViewWidget::update(float delta)
|
||||
}
|
||||
if (angle > 360) angle -= 360;
|
||||
if (angle < 0) angle += 360;
|
||||
|
||||
|
||||
// stop rotating when target reached
|
||||
if (fabsf(angle - m_rotation_target) < 2.0f) m_rotation_mode = ROTATE_OFF;
|
||||
}
|
||||
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
if (m_rtt_provider == NULL)
|
||||
{
|
||||
m_rtt_provider = new RTT(512, 512);
|
||||
}
|
||||
|
||||
|
||||
if (m_rtt_main_node == NULL)
|
||||
{
|
||||
setupRTTScene(m_models, m_model_location, m_model_scale, m_model_frames);
|
||||
setupRTTScene();
|
||||
}
|
||||
|
||||
|
||||
m_rtt_main_node->setRotation(core::vector3df(0.0f, angle, 0.0f));
|
||||
|
||||
|
||||
m_rtt_main_node->setVisible(true);
|
||||
|
||||
|
||||
m_frame_buffer = m_rtt_provider->render(m_camera, GUIEngine::getLatestDt());
|
||||
|
||||
|
||||
m_rtt_main_node->setVisible(false);
|
||||
}
|
||||
else
|
||||
@@ -198,9 +201,9 @@ void ModelViewWidget::update(float delta)
|
||||
m_old_rtt_provider = new IrrDriver::RTTProvider(core::dimension2d<u32>(512, 512), name, false);
|
||||
m_old_rtt_provider->setupRTTScene(m_models, m_model_location, m_model_scale, m_model_frames);
|
||||
}
|
||||
|
||||
|
||||
m_texture = m_old_rtt_provider->renderToTexture(angle);
|
||||
|
||||
|
||||
if (m_texture == NULL)
|
||||
{
|
||||
m_rtt_unsupported = true;
|
||||
@@ -208,98 +211,100 @@ void ModelViewWidget::update(float delta)
|
||||
}
|
||||
}
|
||||
|
||||
void ModelViewWidget::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
|
||||
AlignedArray<Vec3>& mesh_location,
|
||||
AlignedArray<Vec3>& mesh_scale,
|
||||
const std::vector<int>& model_frames)
|
||||
void ModelViewWidget::setupRTTScene()
|
||||
{
|
||||
irr_driver->suppressSkyBox();
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
irr_driver->clearLights();
|
||||
|
||||
if (model_frames[0] == -1)
|
||||
|
||||
if (m_model_frames[0] == -1)
|
||||
{
|
||||
scene::ISceneNode* node = irr_driver->addMesh(mesh.get(0), "rtt_mesh", NULL);
|
||||
node->setPosition(mesh_location[0].toIrrVector());
|
||||
node->setScale(mesh_scale[0].toIrrVector());
|
||||
scene::ISceneNode* node = irr_driver->addMesh(m_models.get(0), "rtt_mesh",
|
||||
NULL, &m_render_info, m_model_render_info_affected[0]);
|
||||
node->setPosition(m_model_location[0].toIrrVector());
|
||||
node->setScale(m_model_scale[0].toIrrVector());
|
||||
node->setMaterialFlag(video::EMF_FOG_ENABLE, false);
|
||||
m_rtt_main_node = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(0), "rtt_mesh", NULL);
|
||||
node->setPosition(mesh_location[0].toIrrVector());
|
||||
node->setFrameLoop(model_frames[0], model_frames[0]);
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_models.get(0), "rtt_mesh",
|
||||
NULL, &m_render_info, m_model_render_info_affected[0]);
|
||||
node->setPosition(m_model_location[0].toIrrVector());
|
||||
node->setFrameLoop(m_model_frames[0], m_model_frames[0]);
|
||||
node->setAnimationSpeed(0);
|
||||
node->setScale(mesh_scale[0].toIrrVector());
|
||||
node->setScale(m_model_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();
|
||||
assert(m_models.size() == m_model_location.size());
|
||||
assert(m_models.size() == m_model_frames.size());
|
||||
assert(m_models.size() == m_model_scale.size());
|
||||
assert(m_models.size() == m_model_render_info_affected.size());
|
||||
|
||||
const int mesh_amount = m_models.size();
|
||||
for (int n = 1; n<mesh_amount; n++)
|
||||
{
|
||||
if (model_frames[n] == -1)
|
||||
if (m_model_frames[n] == -1)
|
||||
{
|
||||
scene::ISceneNode* node =
|
||||
irr_driver->addMesh(mesh.get(n), "rtt_node", m_rtt_main_node);
|
||||
node->setPosition(mesh_location[n].toIrrVector());
|
||||
irr_driver->addMesh(m_models.get(n), "rtt_node", m_rtt_main_node,
|
||||
&m_render_info, m_model_render_info_affected[n]);
|
||||
node->setPosition(m_model_location[n].toIrrVector());
|
||||
node->updateAbsolutePosition();
|
||||
node->setScale(mesh_scale[n].toIrrVector());
|
||||
node->setScale(m_model_scale[n].toIrrVector());
|
||||
}
|
||||
else
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode* node =
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)mesh.get(n),
|
||||
"modelviewrtt", m_rtt_main_node);
|
||||
node->setPosition(mesh_location[n].toIrrVector());
|
||||
node->setFrameLoop(model_frames[n], model_frames[n]);
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_models.get(n),
|
||||
"modelviewrtt", m_rtt_main_node, &m_render_info,
|
||||
m_model_render_info_affected[n]);
|
||||
node->setPosition(m_model_location[n].toIrrVector());
|
||||
node->setFrameLoop(m_model_frames[n], m_model_frames[n]);
|
||||
node->setAnimationSpeed(0);
|
||||
node->updateAbsolutePosition();
|
||||
node->setScale(mesh_scale[n].toIrrVector());
|
||||
//Log::info("ModelViewWidget", "Set frame %d", model_frames[n]);
|
||||
node->setScale(m_model_scale[n].toIrrVector());
|
||||
//Log::info("ModelViewWidget", "Set frame %d", m_model_frames[n]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
irr_driver->setAmbientLight(video::SColor(255, 35, 35, 35));
|
||||
|
||||
|
||||
const core::vector3df &spot_pos = core::vector3df(0, 30, 40);
|
||||
m_light = irr_driver->addLight(spot_pos, 0.3f /* energy */, 10 /* distance */, 1.0f /* r */, 1.0f /* g */, 1.0f /* g*/, true, NULL);
|
||||
|
||||
|
||||
m_rtt_main_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true);
|
||||
m_rtt_main_node->setMaterialFlag(video::EMF_LIGHTING, true);
|
||||
|
||||
|
||||
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->setAspectRatio(1.0f);
|
||||
|
||||
|
||||
m_camera->setPosition(core::vector3df(0.0, 20.0f, 70.0f));
|
||||
m_camera->setUpVector(core::vector3df(0.0, 1.0, 0.0));
|
||||
m_camera->setTarget(core::vector3df(0, 10, 0.0f));
|
||||
@@ -334,11 +339,11 @@ void ModelViewWidget::elementRemoved()
|
||||
{
|
||||
delete m_rtt_provider;
|
||||
m_rtt_provider = NULL;
|
||||
|
||||
|
||||
delete m_old_rtt_provider;
|
||||
m_old_rtt_provider = NULL;
|
||||
m_texture = NULL;
|
||||
|
||||
|
||||
IconButtonWidget::elementRemoved();
|
||||
}
|
||||
|
||||
@@ -346,7 +351,7 @@ void ModelViewWidget::clearRttProvider()
|
||||
{
|
||||
delete m_rtt_provider;
|
||||
m_rtt_provider = NULL;
|
||||
|
||||
|
||||
delete m_old_rtt_provider;
|
||||
m_old_rtt_provider = NULL;
|
||||
m_texture = NULL;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <IMesh.h>
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "utils/aligned_array.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
@@ -44,19 +45,20 @@ namespace GUIEngine
|
||||
RotationMode m_rotation_mode;
|
||||
float m_rotation_speed;
|
||||
float m_rotation_target;
|
||||
|
||||
|
||||
PtrVector<scene::IMesh, REF> m_models;
|
||||
AlignedArray<Vec3> m_model_location;
|
||||
AlignedArray<Vec3> m_model_scale;
|
||||
std::vector<int> m_model_frames;
|
||||
|
||||
std::vector<bool> m_model_render_info_affected;
|
||||
|
||||
RTT* m_rtt_provider;
|
||||
IrrDriver::RTTProvider* m_old_rtt_provider;
|
||||
|
||||
|
||||
float angle;
|
||||
|
||||
|
||||
bool m_rtt_unsupported;
|
||||
|
||||
|
||||
scene::ISceneNode *m_rtt_main_node;
|
||||
|
||||
scene::ICameraSceneNode *m_camera;
|
||||
@@ -66,47 +68,48 @@ namespace GUIEngine
|
||||
FrameBuffer *m_frame_buffer;
|
||||
video::ITexture *m_texture;
|
||||
|
||||
RenderInfo m_render_info;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
LEAK_CHECK()
|
||||
|
||||
|
||||
ModelViewWidget();
|
||||
virtual ~ModelViewWidget();
|
||||
|
||||
|
||||
void add();
|
||||
void clearModels();
|
||||
void addModel(irr::scene::IMesh* mesh,
|
||||
const Vec3& location = Vec3(0,0,0),
|
||||
const Vec3& scale = Vec3(1,1,1),
|
||||
const int frame=-1);
|
||||
|
||||
const int frame=-1,
|
||||
bool all_parts_colorized = false);
|
||||
|
||||
void update(float delta);
|
||||
|
||||
|
||||
virtual void elementRemoved();
|
||||
|
||||
|
||||
/** Disables any model rotation */
|
||||
void setRotateOff();
|
||||
|
||||
|
||||
/** Makes the model rotate at given speed (in degrees per second) */
|
||||
void setRotateContinuously(float speed);
|
||||
|
||||
|
||||
/** Rotate to 'targetAngle' in degrees at given speed (in degrees per second) */
|
||||
void setRotateTo(float targetAngle, float speed);
|
||||
|
||||
|
||||
/** Returns information if currently kart is rotating */
|
||||
bool isRotating();
|
||||
|
||||
|
||||
void clearRttProvider();
|
||||
|
||||
void setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
|
||||
AlignedArray<Vec3>& mesh_location,
|
||||
AlignedArray<Vec3>& mesh_scale,
|
||||
const std::vector<int>& model_frames);
|
||||
void setupRTTScene();
|
||||
|
||||
FrameBuffer* getFrameBuffer() { return m_frame_buffer; }
|
||||
video::ITexture* getTexture() { return m_texture; }
|
||||
FrameBuffer* getFrameBuffer() { return m_frame_buffer; }
|
||||
video::ITexture* getTexture() { return m_texture; }
|
||||
RenderInfo& getModelViewRenderInfo() { return m_render_info; }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/abstract_kart_animation.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
@@ -36,7 +35,7 @@ AbstractKart::AbstractKart(const std::string& ident,
|
||||
int world_kart_id, int position,
|
||||
const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
video::E_RENDER_TYPE rt)
|
||||
RenderInfo::KartRenderType krt)
|
||||
: Moveable()
|
||||
{
|
||||
m_world_kart_id = world_kart_id;
|
||||
@@ -60,7 +59,7 @@ AbstractKart::AbstractKart(const std::string& ident,
|
||||
// released when the kart is deleted, but since the original
|
||||
// kart_model is stored in the kart_properties all the time,
|
||||
// there is no risk of a mesh being deleted to early.
|
||||
m_kart_model = m_kart_properties->getKartModelCopy(rt);
|
||||
m_kart_model = m_kart_properties->getKartModelCopy(krt);
|
||||
m_kart_width = m_kart_model->getWidth();
|
||||
m_kart_height = m_kart_model->getHeight();
|
||||
m_kart_length = m_kart_model->getLength();
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
#ifndef HEADER_ABSTRACT_KART_HPP
|
||||
#define HEADER_ABSTRACT_KART_HPP
|
||||
|
||||
#include <EMaterialTypes.h>
|
||||
#include <memory>
|
||||
|
||||
#include "items/powerup_manager.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "karts/moveable.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
video::E_RENDER_TYPE rt);
|
||||
RenderInfo::KartRenderType krt);
|
||||
virtual ~AbstractKart();
|
||||
virtual core::stringw getName() const;
|
||||
virtual void reset();
|
||||
|
||||
@@ -28,7 +28,7 @@ GhostKart::GhostKart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position)
|
||||
: Kart(ident, world_kart_id,
|
||||
position, btTransform(btQuaternion(0, 0, 0, 1)),
|
||||
PLAYER_DIFFICULTY_NORMAL, video::ERT_TRANSPARENT)
|
||||
PLAYER_DIFFICULTY_NORMAL, RenderInfo::KRT_TRANSPARENT)
|
||||
{
|
||||
} // GhostKart
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@
|
||||
Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
video::E_RENDER_TYPE rt)
|
||||
RenderInfo::KartRenderType krt)
|
||||
: AbstractKart(ident, world_kart_id, position, init_transform,
|
||||
difficulty, rt)
|
||||
difficulty, krt)
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
# pragma warning(1:4355)
|
||||
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
Kart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
video::E_RENDER_TYPE rt = video::ERT_DEFAULT);
|
||||
RenderInfo::KartRenderType krt = RenderInfo::KRT_DEFAULT);
|
||||
virtual ~Kart();
|
||||
virtual void init(RaceManager::KartType type);
|
||||
virtual void kartIsInRestNow();
|
||||
|
||||
@@ -134,12 +134,13 @@ KartModel::KartModel(bool is_master)
|
||||
m_wheel_filename[3] = "";
|
||||
m_speed_weighted_objects.clear();
|
||||
m_animated_node = NULL;
|
||||
m_mesh = NULL;
|
||||
for(unsigned int i=AF_BEGIN; i<=AF_END; i++)
|
||||
m_animation_frame[i]=-1;
|
||||
m_animation_speed = 25;
|
||||
m_current_animation = AF_DEFAULT;
|
||||
m_play_non_loop = false;
|
||||
m_krt = RenderInfo::KRT_DEFAULT;
|
||||
m_render_info = RenderInfo();
|
||||
} // KartModel
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -226,17 +227,6 @@ KartModel::~KartModel()
|
||||
{
|
||||
// Master KartModels should never have a wheel attached.
|
||||
assert(!m_is_master);
|
||||
|
||||
// Drop the cloned transparent mesh wheel if created
|
||||
if (m_wheel_model[i])
|
||||
{
|
||||
// m_wheel_model[i] can be NULL
|
||||
if (m_wheel_model[i]
|
||||
->getRenderType() == video::ERT_TRANSPARENT)
|
||||
{
|
||||
m_wheel_model[i]->drop();
|
||||
}
|
||||
}
|
||||
m_wheel_node[i]->drop();
|
||||
}
|
||||
if(m_is_master && m_wheel_model[i])
|
||||
@@ -253,9 +243,8 @@ KartModel::~KartModel()
|
||||
// Master KartModels should never have a speed weighted object attached.
|
||||
assert(!m_is_master);
|
||||
|
||||
// Drop the cloned model if created
|
||||
if (m_speed_weighted_objects[i].m_model
|
||||
->getRenderType() != video::ERT_DEFAULT)
|
||||
// Drop the cloned transparent model if created
|
||||
if (m_krt == RenderInfo::KRT_TRANSPARENT)
|
||||
{
|
||||
m_speed_weighted_objects[i].m_model->drop();
|
||||
}
|
||||
@@ -298,7 +287,7 @@ KartModel::~KartModel()
|
||||
* It is also marked not to be a master copy, so attachModel can be called
|
||||
* for this instance.
|
||||
*/
|
||||
KartModel* KartModel::makeCopy(video::E_RENDER_TYPE rt)
|
||||
KartModel* KartModel::makeCopy(RenderInfo::KartRenderType krt)
|
||||
{
|
||||
// Make sure that we are copying from a master objects, and
|
||||
// that there is indeed no animated node defined here ...
|
||||
@@ -311,34 +300,25 @@ KartModel* KartModel::makeCopy(video::E_RENDER_TYPE rt)
|
||||
km->m_kart_height = m_kart_height;
|
||||
km->m_kart_highest_point= m_kart_highest_point;
|
||||
km->m_kart_lowest_point = m_kart_lowest_point;
|
||||
km->m_mesh = irr_driver->copyAnimatedMesh(m_mesh, rt);
|
||||
km->m_mesh = irr_driver->copyAnimatedMesh(m_mesh);
|
||||
km->m_model_filename = m_model_filename;
|
||||
km->m_animation_speed = m_animation_speed;
|
||||
km->m_current_animation = AF_DEFAULT;
|
||||
km->m_animated_node = NULL;
|
||||
km->m_hat_offset = m_hat_offset;
|
||||
km->m_hat_name = m_hat_name;
|
||||
|
||||
km->m_krt = krt;
|
||||
km->m_render_info = m_render_info;
|
||||
|
||||
km->m_nitro_emitter_position[0] = m_nitro_emitter_position[0];
|
||||
km->m_nitro_emitter_position[1] = m_nitro_emitter_position[1];
|
||||
km->m_has_nitro_emitter = m_has_nitro_emitter;
|
||||
|
||||
scene::IMeshManipulator *mani =
|
||||
irr_driver->getVideoDriver()->getMeshManipulator();
|
||||
for(unsigned int i=0; i<4; i++)
|
||||
{
|
||||
// Master should not have any wheel nodes.
|
||||
assert(!m_wheel_node[i]);
|
||||
if (m_wheel_model[i] && rt == video::ERT_TRANSPARENT)
|
||||
{
|
||||
// Only clone the mesh if transparence is used
|
||||
scene::SMesh* clone = mani->createMeshCopy(m_wheel_model[i]);
|
||||
clone->setRenderType(rt);
|
||||
km->m_wheel_model[i] = dynamic_cast<scene::IMesh*>(clone);
|
||||
}
|
||||
else
|
||||
km->m_wheel_model[i] = m_wheel_model[i];
|
||||
|
||||
km->m_wheel_model[i] = m_wheel_model[i];
|
||||
km->m_wheel_filename[i] = m_wheel_filename[i];
|
||||
km->m_wheel_graphics_position[i] = m_wheel_graphics_position[i];
|
||||
km->m_wheel_graphics_radius[i] = m_wheel_graphics_radius[i];
|
||||
@@ -346,18 +326,18 @@ KartModel* KartModel::makeCopy(video::E_RENDER_TYPE rt)
|
||||
km->m_max_suspension[i] = m_max_suspension[i];
|
||||
km->m_dampen_suspension_amplitude[i]= m_dampen_suspension_amplitude[i];
|
||||
}
|
||||
|
||||
|
||||
km->m_speed_weighted_objects.resize(m_speed_weighted_objects.size());
|
||||
for(size_t i=0; i<m_speed_weighted_objects.size(); i++)
|
||||
{
|
||||
// Master should not have any speed weighted nodes.
|
||||
assert(!m_speed_weighted_objects[i].m_node);
|
||||
km->m_speed_weighted_objects[i] = m_speed_weighted_objects[i];
|
||||
if (rt != video::ERT_DEFAULT)
|
||||
if (krt == RenderInfo::KRT_TRANSPARENT)
|
||||
{
|
||||
// Only clone the mesh if default type is not used
|
||||
// Only clone the mesh if transparent type is used, see #2445
|
||||
km->m_speed_weighted_objects[i].m_model = irr_driver
|
||||
->copyAnimatedMesh(m_speed_weighted_objects[i].m_model, rt);
|
||||
->copyAnimatedMesh(m_speed_weighted_objects[i].m_model);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +356,8 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
|
||||
{
|
||||
assert(!m_is_master);
|
||||
|
||||
scene::ISceneNode* node;
|
||||
scene::ISceneNode* node = NULL;
|
||||
m_render_info.setKartModelRenderInfo(m_krt);
|
||||
|
||||
if (animated_models)
|
||||
{
|
||||
@@ -385,7 +366,8 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
|
||||
irr_driver->getSceneManager() );
|
||||
|
||||
|
||||
node = irr_driver->addAnimatedMesh(m_mesh, "kartmesh");
|
||||
node = irr_driver->addAnimatedMesh(m_mesh, "kartmesh",
|
||||
NULL/*parent*/, getRenderInfo());
|
||||
// as animated mesh are not cheap to render use frustum box culling
|
||||
if (CVS->isGLSL())
|
||||
node->setAutomaticCulling(scene::EAC_OFF);
|
||||
@@ -462,7 +444,8 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
|
||||
debug_name = m_model_filename + " (kart-model)";
|
||||
#endif
|
||||
|
||||
node = irr_driver->addMesh(main_frame, debug_name);
|
||||
node = irr_driver->addMesh(main_frame, debug_name,
|
||||
NULL /*parent*/, getRenderInfo());
|
||||
|
||||
#ifdef DEBUG
|
||||
node->setName(debug_name.c_str());
|
||||
@@ -473,7 +456,8 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
|
||||
for(unsigned int i=0; i<4; i++)
|
||||
{
|
||||
if(!m_wheel_model[i]) continue;
|
||||
m_wheel_node[i] = irr_driver->addMesh(m_wheel_model[i], "wheel", node);
|
||||
m_wheel_node[i] = irr_driver->addMesh(m_wheel_model[i], "wheel",
|
||||
node, getRenderInfo(), true/*all_parts_colorized*/);
|
||||
Vec3 wheel_min, wheel_max;
|
||||
MeshTools::minMax3D(m_wheel_model[i], &wheel_min, &wheel_max);
|
||||
m_wheel_graphics_radius[i] = 0.5f*(wheel_max.getY() - wheel_min.getY());
|
||||
@@ -495,7 +479,8 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
|
||||
if(obj.m_model)
|
||||
{
|
||||
obj.m_node = irr_driver->addAnimatedMesh(obj.m_model,
|
||||
"speedweighted", node);
|
||||
"speedweighted", node, getRenderInfo(),
|
||||
true/*all_parts_colorized*/);
|
||||
obj.m_node->grab();
|
||||
|
||||
obj.m_node->setFrameLoop(m_animation_frame[AF_SPEED_WEIGHTED_START],
|
||||
@@ -535,6 +520,9 @@ bool KartModel::loadModels(const KartProperties &kart_properties)
|
||||
MeshTools::minMax3D(m_mesh->getMesh(m_animation_frame[AF_STRAIGHT]),
|
||||
&kart_min, &kart_max);
|
||||
|
||||
// Enable colorization for karts later when attachModel
|
||||
m_render_info.setColorizableParts(m_mesh);
|
||||
|
||||
#undef MOVE_KART_MESHES
|
||||
#ifdef MOVE_KART_MESHES
|
||||
// Kart models are not exactly centered. The following code would
|
||||
@@ -984,6 +972,7 @@ void KartModel::update(float dt, float distance, float steer, float speed,
|
||||
|
||||
m_animated_node->setCurrentFrame(frame);
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void KartModel::attachHat()
|
||||
{
|
||||
@@ -1018,4 +1007,4 @@ void KartModel::attachHat()
|
||||
m_hat_node->setRotation(inv.getRotationDegrees());
|
||||
} // if bone
|
||||
} // if(m_hat_name)
|
||||
}
|
||||
} // attachHat
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace irr
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
@@ -115,6 +116,7 @@ public:
|
||||
AF_SPEED_WEIGHTED_END, // End of speed-weighted animation
|
||||
AF_END=AF_SPEED_WEIGHTED_END, // Last animation frame
|
||||
AF_COUNT}; // Number of entries here
|
||||
|
||||
private:
|
||||
/** Which frame number starts/end which animation. */
|
||||
int m_animation_frame[AF_COUNT];
|
||||
@@ -229,10 +231,14 @@ private:
|
||||
/** Pointer to the kart object belonging to this kart model. */
|
||||
AbstractKart* m_kart;
|
||||
|
||||
RenderInfo::KartRenderType m_krt;
|
||||
|
||||
RenderInfo m_render_info;
|
||||
|
||||
public:
|
||||
KartModel(bool is_master);
|
||||
~KartModel();
|
||||
KartModel* makeCopy(video::E_RENDER_TYPE rt);
|
||||
KartModel* makeCopy(RenderInfo::KartRenderType krt);
|
||||
void reset();
|
||||
void loadInfo(const XMLNode &node);
|
||||
bool loadModels(const KartProperties &kart_properties);
|
||||
@@ -328,6 +334,10 @@ public:
|
||||
scene::IAnimatedMeshSceneNode* getAnimatedNode(){ return m_animated_node; }
|
||||
// ------------------------------------------------------------------------
|
||||
core::vector3df getHatOffset() { return m_hat_offset; }
|
||||
// ------------------------------------------------------------------------
|
||||
RenderInfo* getRenderInfo() { return &m_render_info; }
|
||||
// ------------------------------------------------------------------------
|
||||
const RenderInfo* getRenderInfo() const { return &m_render_info; }
|
||||
|
||||
}; // KartModel
|
||||
#endif
|
||||
|
||||
@@ -244,8 +244,8 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the KartModel object. */
|
||||
KartModel* getKartModelCopy
|
||||
(video::E_RENDER_TYPE rt = video::ERT_DEFAULT) const
|
||||
{return m_kart_model->makeCopy(rt); }
|
||||
(RenderInfo::KartRenderType krt = RenderInfo::KRT_DEFAULT) const
|
||||
{return m_kart_model->makeCopy(krt); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the main KartModel object. This copy
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
@@ -303,6 +305,9 @@ void SoccerWorld::countdownReachedZero()
|
||||
//-----------------------------------------------------------------------------
|
||||
void SoccerWorld::initKartList()
|
||||
{
|
||||
// Color of karts can be changed using shaders
|
||||
if (CVS->isGLSL()) return;
|
||||
|
||||
const unsigned int kart_amount = (unsigned int)m_karts.size();
|
||||
|
||||
//Loading the indicator textures
|
||||
@@ -388,9 +393,8 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
||||
m_kart_position_map[index] = (unsigned)(pos_index - 1);
|
||||
|
||||
AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
|
||||
difficulty);
|
||||
//difficulty, team == SOCCER_TEAM_BLUE ?
|
||||
//video::ERT_BLUE : video::ERT_RED);
|
||||
difficulty, team == SOCCER_TEAM_BLUE ?
|
||||
RenderInfo::KRT_BLUE : RenderInfo::KRT_RED);
|
||||
new_kart->init(race_manager->getKartType(index));
|
||||
Controller *controller = NULL;
|
||||
|
||||
|
||||
@@ -131,37 +131,72 @@ void SoccerSetupScreen::beforeAddingWidget()
|
||||
|
||||
// Add the view
|
||||
ModelViewWidget* kart_view = new ModelViewWidget();
|
||||
// These values will be overriden by updateKartViewsLayout() anyway
|
||||
kart_view->m_x = 0;
|
||||
kart_view->m_y = 0;
|
||||
kart_view->m_w = 200;
|
||||
kart_view->m_h = 200; // these values will be overriden by updateKartViewsLayout() anyway
|
||||
kart_view->m_h = 200;
|
||||
kart_view->clearModels();
|
||||
|
||||
// Add the kart model
|
||||
// Record info about it for further update
|
||||
KartViewInfo info;
|
||||
|
||||
int single_team = UserConfigParams::m_soccer_default_team;
|
||||
info.team = (nb_players == 1 ? (SoccerTeam)single_team :
|
||||
(i&1 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED));
|
||||
|
||||
// addModel requires loading the RenderInfo first
|
||||
kart_view->getModelViewRenderInfo().setRenderInfo
|
||||
(kart_model.getRenderInfo());
|
||||
|
||||
kart_view->getModelViewRenderInfo().setKartModelRenderInfo
|
||||
(info.team == SOCCER_TEAM_BLUE ?
|
||||
RenderInfo::KRT_BLUE : RenderInfo::KRT_RED);
|
||||
|
||||
// Add the kart model (including wheels and speed weight objects)
|
||||
kart_view->addModel( kart_model.getModel(), Vec3(0,0,0),
|
||||
Vec3(35.0f, 35.0f, 35.0f),
|
||||
kart_model.getBaseFrame() );
|
||||
kart_view->addModel( kart_model.getWheelModel(0),
|
||||
kart_model.getWheelGraphicsPosition(0) );
|
||||
kart_view->addModel( kart_model.getWheelModel(1),
|
||||
kart_model.getWheelGraphicsPosition(1) );
|
||||
kart_view->addModel( kart_model.getWheelModel(2),
|
||||
kart_model.getWheelGraphicsPosition(2) );
|
||||
kart_view->addModel( kart_model.getWheelModel(3),
|
||||
kart_model.getWheelGraphicsPosition(3) );
|
||||
kart_view->setRotateContinuously( KART_CONTINUOUS_ROTATION_SPEED );
|
||||
|
||||
kart_view->addModel( kart_model.getWheelModel(0),
|
||||
kart_model.getWheelGraphicsPosition(0),
|
||||
Vec3(1, 1, 1), /*scale*/
|
||||
-1, /*frame*/
|
||||
true /*all_parts_colorized*/);
|
||||
|
||||
kart_view->addModel( kart_model.getWheelModel(1),
|
||||
kart_model.getWheelGraphicsPosition(1),
|
||||
Vec3(1, 1, 1), /*scale*/
|
||||
-1, /*frame*/
|
||||
true /*all_parts_colorized*/);
|
||||
kart_view->addModel( kart_model.getWheelModel(2),
|
||||
kart_model.getWheelGraphicsPosition(2),
|
||||
Vec3(1, 1, 1), /*scale*/
|
||||
-1, /*frame*/
|
||||
true /*all_parts_colorized*/);
|
||||
|
||||
kart_view->addModel( kart_model.getWheelModel(3),
|
||||
kart_model.getWheelGraphicsPosition(3),
|
||||
Vec3(1, 1, 1), /*scale*/
|
||||
-1, /*frame*/
|
||||
true /*all_parts_colorized*/);
|
||||
|
||||
for (size_t i = 0; i < kart_model.getSpeedWeightedObjectsCount(); i++)
|
||||
{
|
||||
const SpeedWeightedObject& obj = kart_model.getSpeedWeightedObject((int)i);
|
||||
kart_view->addModel(obj.m_model, obj.m_position,
|
||||
Vec3(1, 1, 1), /*scale*/
|
||||
-1, /*frame*/
|
||||
true /*all_parts_colorized*/);
|
||||
}
|
||||
|
||||
kart_view->setRotateContinuously( KART_CONTINUOUS_ROTATION_SPEED );
|
||||
kart_view->update(0);
|
||||
|
||||
central_div->getChildren().push_back(kart_view);
|
||||
|
||||
// Record info about it for further update
|
||||
KartViewInfo info;
|
||||
info.view = kart_view;
|
||||
info.confirmed = false;
|
||||
int single_team = UserConfigParams::m_soccer_default_team;
|
||||
info.team = nb_players == 1 ? (SoccerTeam)single_team :
|
||||
(i&1 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
|
||||
info.view = kart_view;
|
||||
info.confirmed = false;
|
||||
m_kart_view_info.push_back(info);
|
||||
race_manager->setKartSoccerTeam(i, info.team);
|
||||
}
|
||||
@@ -255,6 +290,10 @@ GUIEngine::EventPropagation SoccerSetupScreen::filterActions(PlayerAction action
|
||||
{
|
||||
team_switch = SOCCER_TEAM_RED;
|
||||
|
||||
// Change the kart color
|
||||
m_kart_view_info[playerId].view->getModelViewRenderInfo()
|
||||
.setKartModelRenderInfo(RenderInfo::KRT_RED);
|
||||
|
||||
for(int i=0 ; i < nb_players ; i++)
|
||||
{
|
||||
m_kart_view_info[i].view->unsetBadge(BAD_BADGE);
|
||||
@@ -268,6 +307,10 @@ GUIEngine::EventPropagation SoccerSetupScreen::filterActions(PlayerAction action
|
||||
{
|
||||
team_switch = SOCCER_TEAM_BLUE;
|
||||
|
||||
// Change the kart color
|
||||
m_kart_view_info[playerId].view->getModelViewRenderInfo()
|
||||
.setKartModelRenderInfo(RenderInfo::KRT_BLUE);
|
||||
|
||||
for(int i=0 ; i < nb_players ; i++)
|
||||
{
|
||||
m_kart_view_info[i].view->unsetBadge(BAD_BADGE);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef HEADER_SOCCER_SETUP_SCREEN_HPP
|
||||
#define HEADER_SOCCER_SETUP_SCREEN_HPP
|
||||
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "network/remote_kart_info.hpp"
|
||||
|
||||
@@ -38,8 +39,9 @@ class SoccerSetupScreen : public GUIEngine::Screen, public GUIEngine::ScreenSing
|
||||
GUIEngine::ModelViewWidget* view;
|
||||
bool confirmed;
|
||||
SoccerTeam team;
|
||||
RenderInfo render_info;
|
||||
|
||||
KartViewInfo() : view(NULL), confirmed(false), team(SOCCER_TEAM_NONE) {}
|
||||
KartViewInfo() : view(), confirmed(false), team(SOCCER_TEAM_NONE) {}
|
||||
};
|
||||
|
||||
AlignedArray<KartViewInfo> m_kart_view_info;
|
||||
|
||||
Reference in New Issue
Block a user