From a0b376f04d0dd8f5a8ae2343118f0773af212cb1 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Fri, 22 Aug 2014 22:21:46 +0200
Subject: [PATCH 01/11] Fix some warnings

---
 src/utils/debug.cpp | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp
index 62bbc8dd3..a6bfc6fcc 100644
--- a/src/utils/debug.cpp
+++ b/src/utils/debug.cpp
@@ -439,32 +439,32 @@ bool onEvent(const SEvent &event)
                 {
 #if !defined(__APPLE__)
                     DebugSliderDialog *dsd = new DebugSliderDialog();
-                    dsd->setSliderHook( "red_slider", 0, 255, [](){ return irr_driver->getAmbientLight().r * 255.; },
+                    dsd->setSliderHook( "red_slider", 0, 255, [](){ return irr_driver->getAmbientLight().r * 255.f; },
                         [](int v){
                             video::SColorf ambient = irr_driver->getAmbientLight();
-                            ambient.setColorComponentValue(0, v / 255.);
+                            ambient.setColorComponentValue(0, v / 255.f);
                             irr_driver->setAmbientLight(ambient); }
                     );
-                    dsd->setSliderHook("green_slider", 0, 255, [](){ return irr_driver->getAmbientLight().g * 255.; },
+                    dsd->setSliderHook("green_slider", 0, 255, [](){ return irr_driver->getAmbientLight().g * 255.f; },
                         [](int v){
                         video::SColorf ambient = irr_driver->getAmbientLight();
-                        ambient.setColorComponentValue(1, v / 255.);
+                        ambient.setColorComponentValue(1, v / 255.f);
                         irr_driver->setAmbientLight(ambient); }
                     );
-                    dsd->setSliderHook("blue_slider", 0, 255, [](){ return irr_driver->getAmbientLight().b * 255.; },
+                    dsd->setSliderHook("blue_slider", 0, 255, [](){ return irr_driver->getAmbientLight().b * 255.f; },
                         [](int v){
                         video::SColorf ambient = irr_driver->getAmbientLight();
-                        ambient.setColorComponentValue(2, v / 255.);
+                        ambient.setColorComponentValue(2, v / 255.f);
                         irr_driver->setAmbientLight(ambient); }
                     );
-                    dsd->setSliderHook("ssao_radius", 0, 100, [](){ return irr_driver->getSSAORadius() * 10; },
-                        [](int v){irr_driver->setSSAORadius(v / 10.); }
+                    dsd->setSliderHook("ssao_radius", 0, 100, [](){ return irr_driver->getSSAORadius() * 10.f; },
+                        [](int v){irr_driver->setSSAORadius(v / 10.f); }
                     );
-                    dsd->setSliderHook("ssao_k", 0, 100, [](){ return irr_driver->getSSAOK() * 10; },
-                        [](int v){irr_driver->setSSAOK(v / 10.); }
+                    dsd->setSliderHook("ssao_k", 0, 100, [](){ return irr_driver->getSSAOK() * 10.f; },
+                        [](int v){irr_driver->setSSAOK(v / 10.f); }
                     );
-                    dsd->setSliderHook("ssao_sigma", 0, 100, [](){ return irr_driver->getSSAOSigma() * 10; },
-                        [](int v){irr_driver->setSSAOSigma(v / 10.); }
+                    dsd->setSliderHook("ssao_sigma", 0, 100, [](){ return irr_driver->getSSAOSigma() * 10.f; },
+                        [](int v){irr_driver->setSSAOSigma(v / 10.f); }
                     );
 #endif
                 }

From 4a62fd7968d46db28428dc0bb408ec9a9d62d84f Mon Sep 17 00:00:00 2001
From: vlj <vljn@ovi.com>
Date: Fri, 22 Aug 2014 18:49:30 +0200
Subject: [PATCH 02/11] Use an instance manager

---
 src/graphics/gl_headers.hpp            |   1 +
 src/graphics/glwrap.cpp                |  83 ++++++++++++++++-
 src/graphics/glwrap.hpp                |  37 ++++++++
 src/graphics/irr_driver.cpp            |   8 ++
 src/graphics/irr_driver.hpp            |   6 ++
 src/graphics/render_geometry.cpp       |  47 +++++++++-
 src/graphics/stkinstancedscenenode.cpp | 122 +++++++++++++++----------
 src/graphics/stkinstancedscenenode.hpp |   4 +-
 src/graphics/stkmesh.hpp               |   1 +
 9 files changed, 252 insertions(+), 57 deletions(-)

diff --git a/src/graphics/gl_headers.hpp b/src/graphics/gl_headers.hpp
index 81789ddf2..91c314ef2 100644
--- a/src/graphics/gl_headers.hpp
+++ b/src/graphics/gl_headers.hpp
@@ -128,6 +128,7 @@ extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
 
 #ifdef WIN32
 #define Bindless_Texture_Support
+#define Base_Instance_Support
 #endif
 
 #endif
\ No newline at end of file
diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp
index c8b44bd5c..3baa27d22 100644
--- a/src/graphics/glwrap.cpp
+++ b/src/graphics/glwrap.cpp
@@ -4,6 +4,7 @@
 #include "config/user_config.hpp"
 #include "utils/profiler.hpp"
 #include "utils/cpp2011.hpp"
+#include "graphics/stkmesh.hpp"
 
 #ifdef _IRR_WINDOWS_API_
 #define IRR_OGL_LOAD_EXTENSION(X) wglGetProcAddress(reinterpret_cast<const char*>(X))
@@ -592,10 +593,33 @@ VAOManager::VAOManager()
     idx_cnt[0] = idx_cnt[1] = idx_cnt[2] = 0;
     vtx_mirror[0] = vtx_mirror[1] = vtx_mirror[2] = NULL;
     idx_mirror[0] = idx_mirror[1] = idx_mirror[2] = NULL;
+    instance_count[0] = 0;
+
+    glGenBuffers(1, &instance_vbo[0]);
+    glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[0]);
+    glBufferData(GL_ARRAY_BUFFER, 10000 * sizeof(float)* 9, 0, GL_STATIC_DRAW);
+}
+
+static void cleanVAOMap(std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint> Map)
+{
+    std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint>::iterator It = Map.begin(), E = Map.end();
+    for (; It != E; It++)
+    {
+        glDeleteVertexArrays(1, &(It->second));
+    }
+}
+
+void VAOManager::cleanInstanceVAOs()
+{
+    cleanVAOMap(InstanceVAO);
+    cleanVAOMap(ShadowInstanceVAO);
+    InstanceVAO.clear();
+    ShadowInstanceVAO.clear();
 }
 
 VAOManager::~VAOManager()
 {
+    cleanInstanceVAOs();
     for (unsigned i = 0; i < 3; i++)
     {
         if (vtx_mirror[i])
@@ -609,7 +633,7 @@ VAOManager::~VAOManager()
         if (vao[i])
             glDeleteVertexArrays(1, &vao[i]);
     }
-
+    glDeleteBuffers(1, &instance_vbo[0]);
 }
 
 void VAOManager::regenerateBuffer(enum VTXTYPE tp)
@@ -697,6 +721,53 @@ void VAOManager::regenerateVAO(enum VTXTYPE tp)
     glBindVertexArray(0);
 }
 
+void VAOManager::regenerateInstancedVAO()
+{
+    cleanInstanceVAOs();
+
+    enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS };
+    for (unsigned i = 0; i < VTXTYPE_COUNT; i++)
+    {
+        for (unsigned j = 0; j < InstanceTypeCount; j++)
+        {
+            video::E_VERTEX_TYPE tp = IrrVT[i];
+            if (!vbo[tp] || !ibo[tp])
+                continue;
+            GLuint vao = createVAO(vbo[tp], ibo[tp], tp);
+            glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[j]);
+
+            glEnableVertexAttribArray(7);
+            glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);
+            glVertexAttribDivisor(7, 1);
+            glEnableVertexAttribArray(8);
+            glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float)));
+            glVertexAttribDivisor(8, 1);
+            glEnableVertexAttribArray(9);
+            glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
+            glVertexAttribDivisor(9, 1);
+            InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, (InstanceType) j)] = vao;
+
+            GLuint shadow_vao = createVAO(vbo[tp], ibo[tp], tp);
+            glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[j]);
+
+            glEnableVertexAttribArray(7);
+            glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);
+            glVertexAttribDivisor(7, 4);
+            glEnableVertexAttribArray(8);
+            glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float)));
+            glVertexAttribDivisor(8, 4);
+            glEnableVertexAttribArray(9);
+            glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
+            glVertexAttribDivisor(9, 4);
+            ShadowInstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, (InstanceType)j)] = shadow_vao;
+            glBindVertexArray(0);
+        }
+    }
+
+
+
+}
+
 size_t VAOManager::getVertexPitch(enum VTXTYPE tp) const
 {
     switch (tp)
@@ -756,6 +827,7 @@ std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb)
         append(mb, tp);
         regenerateBuffer(tp);
         regenerateVAO(tp);
+        regenerateInstancedVAO();
     }
 
     std::map<scene::IMeshBuffer*, unsigned>::iterator It;
@@ -767,6 +839,15 @@ std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb)
     return std::pair<unsigned, unsigned>(vtx, It->second);
 }
 
+size_t VAOManager::appendInstance(enum InstanceType, const std::vector<InstanceData> &instance_data)
+{
+    glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[0]);
+    glBufferSubData(GL_ARRAY_BUFFER, instance_count[0] * sizeof(InstanceData), instance_data.size() * sizeof(InstanceData), instance_data.data());
+    size_t result = instance_count[0];
+    instance_count[0] += instance_data.size();
+    return result;
+}
+
 ScopedGPUTimer::ScopedGPUTimer(GPUTimer &timer)
 {
     if (!UserConfigParams::m_profiler_enabled) return;
diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp
index 034af4090..c775bcebe 100644
--- a/src/graphics/glwrap.hpp
+++ b/src/graphics/glwrap.hpp
@@ -139,25 +139,62 @@ void compressTexture(irr::video::ITexture *tex, bool srgb, bool premul_alpha = f
 bool loadCompressedTexture(const std::string& compressed_tex);
 void saveCompressedTexture(const std::string& compressed_tex);
 
+enum InstanceType
+{
+    InstanceTypeDefault,
+    InstanceTypeCount,
+};
+
+struct InstanceData
+{
+    struct
+    {
+        float X;
+        float Y;
+        float Z;
+    } Origin;
+    struct
+    {
+        float X;
+        float Y;
+        float Z;
+    } Orientation;
+    struct
+    {
+        float X;
+        float Y;
+        float Z;
+    } Scale;
+    uint64_t Texture;
+};
+
 class VAOManager : public Singleton<VAOManager>
 {
     enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT };
     GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT];
+    GLuint instance_vbo[1];
+    size_t instance_count[1];
     std::vector<scene::IMeshBuffer *> storedCPUBuffer[VTXTYPE_COUNT];
     void *vtx_mirror[VTXTYPE_COUNT], *idx_mirror[VTXTYPE_COUNT];
     size_t vtx_cnt[VTXTYPE_COUNT], idx_cnt[VTXTYPE_COUNT];
     std::map<scene::IMeshBuffer*, unsigned> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT];
+    std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint> InstanceVAO, ShadowInstanceVAO;
 
+    void cleanInstanceVAOs();
     void regenerateBuffer(enum VTXTYPE);
     void regenerateVAO(enum VTXTYPE);
+    void regenerateInstancedVAO();
     size_t getVertexPitch(enum VTXTYPE) const;
     VTXTYPE getVTXTYPE(video::E_VERTEX_TYPE type);
     void append(scene::IMeshBuffer *, VTXTYPE tp);
 public:
     VAOManager();
     std::pair<unsigned, unsigned> getBase(scene::IMeshBuffer *);
+    size_t appendInstance(enum InstanceType, const std::vector<InstanceData> &instance_data);
     unsigned getVBO(video::E_VERTEX_TYPE type) { return vbo[getVTXTYPE(type)]; }
     unsigned getVAO(video::E_VERTEX_TYPE type) { return vao[getVTXTYPE(type)]; }
+    unsigned getInstanceVAO(video::E_VERTEX_TYPE vt, enum InstanceType it) { return InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(vt, it)]; }
+    unsigned getShadowInstanceVAO(video::E_VERTEX_TYPE vt, enum InstanceType it) { return ShadowInstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(vt, it)]; }
     ~VAOManager();
 };
 
diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp
index 66eaabe21..b40d279d5 100644
--- a/src/graphics/irr_driver.cpp
+++ b/src/graphics/irr_driver.cpp
@@ -483,12 +483,20 @@ void IrrDriver::initDevice()
 
     // Parse extensions
     hasVSLayer = false;
+    hasBaseInstance = false;
     // Default false value for hasVSLayer if --no-graphics argument is used
     if (!ProfileWorld::isNoGraphics())
     {
         if (hasGLExtension("GL_AMD_vertex_shader_layer")) {
             hasVSLayer = true;
+            Log::info("GLDriver", "AMD Vertex Shader Layer enabled");
         }
+#ifdef Base_Instance_Support
+        if (hasGLExtension("GL_ARB_base_instance")) {
+            hasBaseInstance = true;
+            Log::info("GLDriver", "ARB Instance enabled");
+        }
+#endif
     }
 
 
diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp
index 86ca6490e..dec484903 100644
--- a/src/graphics/irr_driver.hpp
+++ b/src/graphics/irr_driver.hpp
@@ -199,6 +199,7 @@ class IrrDriver : public IEventReceiver, public NoCopy
 private:
     int GLMajorVersion, GLMinorVersion;
     bool hasVSLayer;
+    bool hasBaseInstance;
     bool m_need_ubo_workaround;
     bool m_need_rh_workaround;
     /** The irrlicht device. */
@@ -293,6 +294,11 @@ public:
         return m_need_rh_workaround;
     }
 
+    bool hasARB_base_instance() const
+    {
+        return hasBaseInstance;
+    }
+
     bool hasVSLayerExtension() const
     {
         return hasVSLayer;
diff --git a/src/graphics/render_geometry.cpp b/src/graphics/render_geometry.cpp
index ae9d00c1d..1b3d01acb 100644
--- a/src/graphics/render_geometry.cpp
+++ b/src/graphics/render_geometry.cpp
@@ -176,7 +176,12 @@ struct instanced_custom_unroll_args<>
         size_t count = mesh->IndexCount;
 
         Shader->setUniforms(args...);
-        glDrawElementsInstanced(ptype, count, itype, 0, instance_count);
+#ifdef Base_Instance_Support
+        if (irr_driver->hasARB_base_instance())
+            glDrawElementsInstancedBaseVertexBaseInstance(ptype, count, itype, (const void*)mesh->vaoOffset, instance_count, mesh->vaoBaseVertex, mesh->vaoBaseInstance);
+        else
+#endif
+            glDrawElementsInstanced(ptype, count, itype, 0, instance_count);
     }
 };
 
@@ -203,7 +208,8 @@ void renderInstancedMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vec
         if (mesh.VAOType != VertexType)
             Log::error("RenderGeometry", "Wrong instanced vertex format");
 #endif
-        glBindVertexArray(mesh.vao);
+        if (!irr_driver->hasARB_base_instance())
+            glBindVertexArray(mesh.vao);
         for (unsigned j = 0; j < TexUnits.size(); j++)
         {
             if (!mesh.textures[TexUnits[j].m_id])
@@ -306,15 +312,23 @@ void IrrDriver::renderSolidFirstPass()
         renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_2TCOORDS, 2, 1>(TexUnits(TexUnit(0, true)), AnimatedListMatDetails::getInstance());
         renderMeshes1stPass<MeshShader::ObjectRefPass1Shader, video::EVT_STANDARD, 3, 2, 1>(TexUnits(TexUnit(0, true)), AnimatedListMatUnlit::getInstance());
 
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, video::EVT_STANDARD>(
                     TexUnits(TexUnit(0, true)),
                     ListInstancedMatDefault::getInstance());
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         renderInstancedMeshes1stPass<MeshShader::InstancedObjectRefPass1Shader, video::EVT_STANDARD>(
                     TexUnits(TexUnit(0, true)),
                     ListInstancedMatAlphaRef::getInstance());
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         renderInstancedMeshes1stPass<MeshShader::InstancedGrassPass1Shader, video::EVT_STANDARD, 2>(
                     TexUnits(TexUnit(0, true)),
                     ListInstancedMatGrass::getInstance());
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_TANGENTS, InstanceTypeDefault));
         renderInstancedMeshes1stPass<MeshShader::InstancedNormalMapShader, video::EVT_TANGENTS>(
             TexUnits(TexUnit(1, false), TexUnit(0, true)),
             ListInstancedMatNormalMap::getInstance());
@@ -385,7 +399,8 @@ void renderInstancedMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vec
     for (unsigned i = 0; i < meshes->size(); i++)
     {
         GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i)));
-        glBindVertexArray(mesh.vao);
+        if (!irr_driver->hasARB_base_instance())
+            glBindVertexArray(mesh.vao);
 
         std::vector<GLuint> Textures(Prefilled_tex);
         std::vector<uint64_t> Handles(Prefilled_Handles);
@@ -529,15 +544,23 @@ void IrrDriver::renderSolidSecondPass()
             TexUnit(0, true)
             ), ListMatNormalMap::getInstance(), createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex);
 
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader>(
             TexUnits(TexUnit(0, true)),
             ListInstancedMatDefault::getInstance(), createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex);
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_TANGENTS, InstanceTypeDefault));
         renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader>(
             TexUnits(TexUnit(0, true)),
             ListInstancedMatNormalMap::getInstance(), createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex);
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         renderInstancedMeshes2ndPass<MeshShader::InstancedObjectRefPass2Shader>(
             TexUnits(TexUnit(0, true)),
             ListInstancedMatAlphaRef::getInstance(), createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex);
+        if (irr_driver->hasARB_base_instance())
+            glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
         DiffSpecSSAOTex.push_back(irr_driver->getDepthStencilTexture());
         renderInstancedMeshes2ndPass<MeshShader::InstancedGrassPass2Shader, 3, 2>(
             TexUnits(TexUnit(0, true)),
@@ -788,7 +811,12 @@ struct instanced_shadow_custom_unroll_args<>
         size_t count = mesh->IndexCount;
 
         Shader->setUniforms(args...);
-        glDrawElementsInstanced(ptype, count, itype, 0, 4 * instance_count);
+#ifdef Base_Instance_Support
+        if (irr_driver->hasARB_base_instance())
+            glDrawElementsInstancedBaseVertexBaseInstance(ptype, count, itype, (const void*) mesh->vaoOffset, 4 * instance_count, mesh->vaoBaseVertex, mesh->vaoBaseInstance);
+        else
+#endif
+            glDrawElementsInstanced(ptype, count, itype, 0, 4 * instance_count);
     }
 };
 
@@ -811,7 +839,8 @@ void renderInstancedShadow(const std::vector<GLuint> TextureUnits, const std::ve
         std::vector<uint64_t> Handles;
         std::vector<GLuint> Textures;
         GLMesh *mesh = STK::tuple_get<0>(t->at(i));
-        glBindVertexArray(mesh->vao_shadow_pass);
+        if (!irr_driver->hasARB_base_instance())
+            glBindVertexArray(mesh->vao_shadow_pass);
         for (unsigned j = 0; j < TextureUnits.size(); j++)
         {
             compressTexture(mesh->textures[TextureUnits[j]], true);
@@ -883,9 +912,17 @@ void IrrDriver::renderShadows()
     renderShadow<MeshShader::RefShadowShader, EVT_STANDARD, 1>(std::vector<GLuint>{ 0 }, AnimatedListMatUnlit::getInstance());
     renderShadow<MeshShader::ShadowShader, EVT_2TCOORDS, 1>(noTexUnits, AnimatedListMatDetails::getInstance());
 
+    if (irr_driver->hasARB_base_instance())
+        glBindVertexArray(VAOManager::getInstance()->getShadowInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
     renderInstancedShadow<MeshShader::InstancedShadowShader>(noTexUnits, ListInstancedMatDefault::getInstance());
+    if (irr_driver->hasARB_base_instance())
+        glBindVertexArray(VAOManager::getInstance()->getShadowInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
     renderInstancedShadow<MeshShader::InstancedRefShadowShader>(std::vector<GLuint>{ 0 }, ListInstancedMatAlphaRef::getInstance());
+    if (irr_driver->hasARB_base_instance())
+        glBindVertexArray(VAOManager::getInstance()->getShadowInstanceVAO(video::EVT_STANDARD, InstanceTypeDefault));
     renderInstancedShadow<MeshShader::InstancedGrassShadowShader, 2>(std::vector<GLuint>{ 0 }, ListInstancedMatGrass::getInstance());
+    if (irr_driver->hasARB_base_instance())
+        glBindVertexArray(VAOManager::getInstance()->getShadowInstanceVAO(video::EVT_TANGENTS, InstanceTypeDefault));
     renderInstancedShadow<MeshShader::InstancedShadowShader>(noTexUnits, ListInstancedMatNormalMap::getInstance());
 
     glDisable(GL_POLYGON_OFFSET_FILL);
diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp
index 64c28206f..f12e27be7 100644
--- a/src/graphics/stkinstancedscenenode.cpp
+++ b/src/graphics/stkinstancedscenenode.cpp
@@ -50,41 +50,55 @@ void STKInstancedSceneNode::createGLMeshes()
     {
         scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
         GLmeshes.push_back(allocateMeshBuffer(mb));
-        fillLocalBuffer(GLmeshes.back(), mb);
+        GLMesh &mesh = GLmeshes.back();
+        if (irr_driver->hasARB_base_instance())
+        {
+            std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb);
+            mesh.vaoBaseVertex = p.first;
+            mesh.vaoOffset = p.second;
+            mesh.VAOType = mb->getVertexType();
+        }
+        else
+            fillLocalBuffer(mesh, mb);
     }
     isMaterialInitialized = false;
 }
 
 void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh)
 {
-    mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
-    glGenBuffers(1, &instances_vbo);
-    glBindBuffer(GL_ARRAY_BUFFER, instances_vbo);
-    glBufferData(GL_ARRAY_BUFFER, instance_pos.size() * sizeof(float), instance_pos.data(), GL_STATIC_DRAW);
+    if (irr_driver->hasARB_base_instance())
+        mesh.vaoBaseInstance = VAOManager::getInstance()->appendInstance(InstanceTypeDefault, instanceData);
+    else
+    {
+        mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
+        glGenBuffers(1, &instances_vbo);
+        glBindBuffer(GL_ARRAY_BUFFER, instances_vbo);
+        glBufferData(GL_ARRAY_BUFFER, instanceData.size() * sizeof(InstanceData), instanceData.data(), GL_STATIC_DRAW);
 
-    glEnableVertexAttribArray(7);
-    glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0);
-    glVertexAttribDivisor(7, 1);
-    glEnableVertexAttribArray(8);
-    glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(3 * sizeof(float)));
-    glVertexAttribDivisor(8, 1);
-    glEnableVertexAttribArray(9);
-    glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(6 * sizeof(float)));
-    glVertexAttribDivisor(9, 1);
+        glEnableVertexAttribArray(7);
+        glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);
+        glVertexAttribDivisor(7, 1);
+        glEnableVertexAttribArray(8);
+        glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float)));
+        glVertexAttribDivisor(8, 1);
+        glEnableVertexAttribArray(9);
+        glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
+        glVertexAttribDivisor(9, 1);
 
-    mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
-    glBindBuffer(GL_ARRAY_BUFFER, instances_vbo);
-    glEnableVertexAttribArray(7);
-    glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0);
-    glVertexAttribDivisor(7, 4);
-    glEnableVertexAttribArray(8);
-    glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(3 * sizeof(float)));
-    glVertexAttribDivisor(8, 4);
-    glEnableVertexAttribArray(9);
-    glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(6 * sizeof(float)));
-    glVertexAttribDivisor(9, 4);
+        mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
+        glBindBuffer(GL_ARRAY_BUFFER, instances_vbo);
+        glEnableVertexAttribArray(7);
+        glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);
+        glVertexAttribDivisor(7, 4);
+        glEnableVertexAttribArray(8);
+        glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float)));
+        glVertexAttribDivisor(8, 4);
+        glEnableVertexAttribArray(9);
+        glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
+        glVertexAttribDivisor(9, 4);
 
-    glBindVertexArray(0);
+        glBindVertexArray(0);
+    }
 }
 
 void STKInstancedSceneNode::setFirstTimeMaterial()
@@ -108,34 +122,44 @@ void STKInstancedSceneNode::setFirstTimeMaterial()
 
 void STKInstancedSceneNode::addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale)
 {
-    instance_pos.push_back(origin.X);
-    instance_pos.push_back(origin.Y);
-    instance_pos.push_back(origin.Z);
-    instance_pos.push_back(orientation.X);
-    instance_pos.push_back(orientation.Y);
-    instance_pos.push_back(orientation.Z);
-    instance_pos.push_back(scale.X);
-    instance_pos.push_back(scale.Y);
-    instance_pos.push_back(scale.Z);
+    InstanceData instance = {
+        {
+            origin.X,
+            origin.Y,
+            origin.Z
+        },
+        {
+            orientation.X,
+            orientation.Y,
+            orientation.Z
+        },
+        {
+            scale.X,
+            scale.Y,
+            scale.Z
+        },
+        0
+    };
+    instanceData.push_back(instance);
 }
 
 core::matrix4 STKInstancedSceneNode::getInstanceTransform(int id)
 {
     core::matrix4 mat;
 
-    int offset = id * 9;
+    const InstanceData &instance = instanceData[id];
     mat.setTranslation(core::vector3df(
-        instance_pos[offset],
-        instance_pos[offset + 1],
-        instance_pos[offset + 2]));
+        instance.Origin.X,
+        instance.Origin.Y,
+        instance.Origin.Z));
     mat.setRotationDegrees(core::vector3df(
-        instance_pos[offset + 3],
-        instance_pos[offset + 4],
-        instance_pos[offset + 5]));
+        instance.Orientation.X,
+        instance.Orientation.Y,
+        instance.Orientation.Z));
     mat.setScale(core::vector3df(
-        instance_pos[offset + 6],
-        instance_pos[offset + 7],
-        instance_pos[offset + 8]));
+        instance.Scale.X,
+        instance.Scale.Y,
+        instance.Scale.Z));
 
     return mat;
 }
@@ -154,13 +178,13 @@ void STKInstancedSceneNode::render()
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_DEFAULT].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_DEFAULT][i];
-        ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9));
+        ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
     }
 
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_ALPHA_REF].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_ALPHA_REF][i];
-        ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9));
+        ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
     }
 
     windDir = getWind();
@@ -168,12 +192,12 @@ void STKInstancedSceneNode::render()
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_GRASS].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_GRASS][i];
-        ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9, windDir, cb->getPosition()));
+        ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size(), windDir, cb->getPosition()));
     }
 
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_NORMAL_MAP].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_NORMAL_MAP][i];
-        ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9));
+        ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
     }
 }
diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp
index d1063ca6d..35a38d8b1 100644
--- a/src/graphics/stkinstancedscenenode.hpp
+++ b/src/graphics/stkinstancedscenenode.hpp
@@ -22,7 +22,7 @@ protected:
     int m_ref_count;
     std::vector<GLMesh *> MeshSolidMaterial[MAT_COUNT];
     std::vector<GLMesh> GLmeshes;
-    std::vector<float> instance_pos;
+    std::vector<InstanceData> instanceData;
     core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView;
     GLuint instances_vbo;
     void createGLMeshes();
@@ -40,7 +40,7 @@ public:
     virtual void render();
     void addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale);
 
-    int getInstanceCount() const { return instance_pos.size() / 9; }
+    int getInstanceCount() const { return instanceData.size(); }
 
     core::matrix4 getInstanceTransform(int id);
 
diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp
index dd21eb6c6..beaee62cb 100644
--- a/src/graphics/stkmesh.hpp
+++ b/src/graphics/stkmesh.hpp
@@ -46,6 +46,7 @@ struct GLMesh {
     core::matrix4 TextureMatrix;
     size_t vaoBaseVertex;
     size_t vaoOffset;
+    size_t vaoBaseInstance;
     video::E_VERTEX_TYPE VAOType;
     uint64_t TextureHandles[6];
 };

From db53dd6767e51bb962d54f7e56f2ccf1ea4f7587 Mon Sep 17 00:00:00 2001
From: Deve <deveee@gmail.com>
Date: Sun, 24 Aug 2014 17:18:06 +0200
Subject: [PATCH 03/11] xrandr: Simplify code a bit.

Fixed some memory leaks.
---
 .../source/Irrlicht/CIrrDeviceLinux.cpp       | 123 ++++++++----------
 .../source/Irrlicht/CIrrDeviceLinux.h         |   2 +-
 2 files changed, 58 insertions(+), 67 deletions(-)

diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp
index 096309f15..b5423ca57 100644
--- a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp
+++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp
@@ -251,12 +251,10 @@ bool CIrrDeviceLinux::restoreResolution()
 	if (UseXRandR && CreationParams.Fullscreen && old_mode != BadRRMode)
 	{
 		XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display));
-		
 		if (!res)
 			return false;
 
 		XRROutputInfo* output = XRRGetOutputInfo(display, res, output_id);
-		
 		if (!output || !output->crtc || output->connection == RR_Disconnected) 
 		{
 			XRRFreeOutputInfo(output);
@@ -264,10 +262,8 @@ bool CIrrDeviceLinux::restoreResolution()
 		}
 
 		XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, res, output->crtc);
-
 		if (!crtc) 
 		{
-			XRRFreeCrtcInfo(crtc);
 			XRRFreeOutputInfo(output);
 			return false;
 		}
@@ -288,7 +284,7 @@ bool CIrrDeviceLinux::restoreResolution()
 }
 
 
-bool CIrrDeviceLinux::switchToFullscreen()
+bool CIrrDeviceLinux::changeResolution()
 {
 	if (!CreationParams.Fullscreen)
 		return true;
@@ -356,22 +352,33 @@ bool CIrrDeviceLinux::switchToFullscreen()
 
 		XFree(modes);
 	}
-	else
 	#endif
 	#ifdef _IRR_LINUX_X11_RANDR_
-	if (XRRQueryExtension(display, &eventbase, &errorbase))
+	while (XRRQueryExtension(display, &eventbase, &errorbase))
 	{
-		XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display));
+		if (output_id == BadRROutput)
+			break;
 
-		if (!res || output_id == BadRROutput)
-		{
-			os::Printer::log("Could not get video output. Try to run in windowed mode.", ELL_WARNING);
-			CreationParams.Fullscreen = false;
-			return CreationParams.Fullscreen;
-		}
+		XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display));
+		if (!res)
+			break;
 
 		XRROutputInfo* output = XRRGetOutputInfo(display, res, output_id);
+		if (!output || !output->crtc || output->connection == RR_Disconnected)
+		{
+			XRRFreeOutputInfo(output);
+			XRRFreeScreenResources(res);
+			break;
+		}
+		
 		XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, res, output->crtc);
+		if (!crtc)
+		{
+			XRRFreeOutputInfo(output);
+			XRRFreeScreenResources(res);
+			break;
+		}
+
 		float refresh_rate, refresh_rate_new;
 		core::dimension2d<u32> mode0_size = core::dimension2d<u32>(0, 0);
 
@@ -436,26 +443,22 @@ bool CIrrDeviceLinux::switchToFullscreen()
 		Status s = XRRSetCrtcConfig(display, res, output->crtc, CurrentTime,
 									crtc->x, crtc->y, output->modes[bestMode],
 									crtc->rotation, &output_id, 1);
+		
+		if (s == Success)
+			UseXRandR = true;
 
 		XRRFreeCrtcInfo(crtc);
 		XRRFreeOutputInfo(output);
 		XRRFreeScreenResources(res);
-
-		if (s != Success)
-		{
-			CreationParams.Fullscreen = false;
-			return CreationParams.Fullscreen;
-		}
-
-		UseXRandR=true;
+		break;
 	}
-	else
-	#endif
+	
+	if (UseXRandR == false)
 	{
-		os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht "
-		"to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING);
+		os::Printer::log("Could not get video output. Try to run in windowed mode.", ELL_WARNING);
 		CreationParams.Fullscreen = false;
 	}
+	#endif
 
 	return CreationParams.Fullscreen;
 }
@@ -570,7 +573,7 @@ bool CIrrDeviceLinux::createWindow()
 
 	screennr = DefaultScreen(display);
 
-	switchToFullscreen();
+	changeResolution();
 
 #ifdef _IRR_COMPILE_WITH_OPENGL_
 
@@ -1625,7 +1628,6 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
 				crtc_x = crtc_y = -1;
 
 				XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display));
-
 				if (!res)
 					break;
 				
@@ -1633,49 +1635,39 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
 		
 				for (int i = 0; i < res->noutput; i++) 
 				{
-					output = XRRGetOutputInfo(display, res, res->outputs[i]);
-					
-					if (!output || !output->crtc || output->connection == RR_Disconnected) 
+					XRROutputInfo* output_tmp = XRRGetOutputInfo(display, res, res->outputs[i]);
+					if (!output_tmp || !output_tmp->crtc || output_tmp->connection == RR_Disconnected) 
 					{
-						XRRFreeOutputInfo(output);
+						XRRFreeOutputInfo(output_tmp);
 						continue;
 					}
 		
-					crtc = XRRGetCrtcInfo(display, res, output->crtc);
-		
-					if (!crtc) 
+					XRRCrtcInfo* crtc_tmp = XRRGetCrtcInfo(display, res, output_tmp->crtc);
+					if (!crtc_tmp) 
+					{
+						XRRFreeOutputInfo(output_tmp);
+						continue;
+					}
+					
+					if (res->outputs[i] == primary_id ||
+						output_id == BadRROutput || crtc_tmp->x < crtc->x ||
+						(crtc_tmp->x == crtc->x && crtc_tmp->y < crtc->y))
 					{
 						XRRFreeCrtcInfo(crtc);
-						XRRFreeOutputInfo(output);
-						continue;
+						XRRFreeOutputInfo(output);		
+						
+						output = output_tmp;
+						crtc = crtc_tmp;					
+						output_id = res->outputs[i];
+					}
+					else
+					{
+						XRRFreeCrtcInfo(crtc_tmp);
+						XRRFreeOutputInfo(output_tmp);			
 					}
 					
 					if (res->outputs[i] == primary_id)
-					{
-						crtc_x = crtc->x;
-						crtc_y = crtc->y;	
-						output_id = res->outputs[i];
-						
-						XRRFreeCrtcInfo(crtc);
-						XRRFreeOutputInfo(output);
 						break;
-					}
-					
-					if (crtc_x == -1 || crtc->x < crtc_x)
-					{
-						crtc_x = crtc->x;
-						crtc_y = crtc->y;						
-						output_id = res->outputs[i];
-					}
-					else if (crtc_x == crtc->x && crtc->y < crtc_y)
-					{
-						crtc_x = crtc->x;
-						crtc_y = crtc->y;
-						output_id = res->outputs[i];			
-					}
-					
-					XRRFreeCrtcInfo(crtc);
-					XRRFreeOutputInfo(output);
 				}
 				
 				if (output_id == BadRROutput)
@@ -1683,9 +1675,9 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
 					os::Printer::log("Could not get video output.", ELL_WARNING);
 					break;
 				}
-
-				output = XRRGetOutputInfo(display, res, output_id);
-				crtc = XRRGetCrtcInfo(display, res, output->crtc);
+				
+				crtc_x = crtc->x;
+				crtc_y = crtc->y;
 
 				for (int i = 0; i < res->nmode; i++)
 				{
@@ -1719,8 +1711,7 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
 				
 				XRRFreeCrtcInfo(crtc);
 				XRRFreeOutputInfo(output);
-				XRRFreeScreenResources(res);	
-							
+				XRRFreeScreenResources(res);						
 				break;
 			}
 			#endif
diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h
index d2fd06899..c808b8ebd 100644
--- a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h
+++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h
@@ -151,7 +151,7 @@ namespace irr
 		void initXAtoms();
 
 		bool restoreResolution();
-		bool switchToFullscreen();
+		bool changeResolution();
 
 		//! Implementation of the linux cursor control
 		class CCursorControl : public gui::ICursorControl

From 7bff68870c0ef2ed236a95b799bc72b5486651b5 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Sat, 23 Aug 2014 00:18:14 +0200
Subject: [PATCH 04/11] Read sampler from attributes.

---
 data/shaders/instanced_grass.vert           |  10 ++
 data/shaders/instanced_grass_pass2.frag     |  45 +++++++++
 data/shaders/instanced_normalmap.frag       |  35 +++++++
 data/shaders/instanced_object_pass.vert     |  13 +++
 data/shaders/instanced_object_pass1.frag    |  23 +++++
 data/shaders/instanced_object_pass2.frag    |  24 +++++
 data/shaders/instanced_objectref_pass1.frag |  25 +++++
 data/shaders/instanced_objectref_pass2.frag |  26 +++++
 data/shaders/instanced_shadow.geom          |  28 ++++++
 data/shaders/instanced_shadowref.frag       |  21 ++++
 data/shaders/instanciedgrassshadow.vert     |  16 +++
 data/shaders/instanciedshadow.vert          |  16 +++
 src/graphics/glwrap.cpp                     |  12 +++
 src/graphics/glwrap.hpp                     |   1 +
 src/graphics/render_geometry.cpp            | 104 ++++++--------------
 src/graphics/shaders.cpp                    |  28 +++---
 src/graphics/shaders.hpp                    |   4 +-
 src/graphics/stkinstancedscenenode.cpp      |  74 +++++++++-----
 src/graphics/stkinstancedscenenode.hpp      |   2 +-
 19 files changed, 388 insertions(+), 119 deletions(-)
 create mode 100644 data/shaders/instanced_grass_pass2.frag
 create mode 100644 data/shaders/instanced_normalmap.frag
 create mode 100644 data/shaders/instanced_object_pass1.frag
 create mode 100644 data/shaders/instanced_object_pass2.frag
 create mode 100644 data/shaders/instanced_objectref_pass1.frag
 create mode 100644 data/shaders/instanced_objectref_pass2.frag
 create mode 100644 data/shaders/instanced_shadow.geom
 create mode 100644 data/shaders/instanced_shadowref.frag

diff --git a/data/shaders/instanced_grass.vert b/data/shaders/instanced_grass.vert
index 803fa7f92..b65a08d1f 100644
--- a/data/shaders/instanced_grass.vert
+++ b/data/shaders/instanced_grass.vert
@@ -9,6 +9,10 @@ layout(location = 3) in vec2 Texcoord;
 layout(location = 7) in vec3 Origin;
 layout(location = 8) in vec3 Orientation;
 layout(location = 9) in vec3 Scale;
+#ifdef GL_ARB_bindless_texture
+layout(location = 10) in sampler2D Handle;
+#endif
+
 #else
 in vec3 Position;
 in vec3 Normal;
@@ -22,6 +26,9 @@ in vec3 Scale;
 
 out vec3 nor;
 out vec2 uv;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D handle;
+#endif
 
 mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
 mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
@@ -33,4 +40,7 @@ void main()
     gl_Position = ProjectionMatrix * ViewMatrix *  ModelMatrix * vec4(Position, 1.);
     nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz;
     uv = Texcoord;
+#ifdef GL_ARB_bindless_texture
+    handle = Handle;
+#endif
 }
diff --git a/data/shaders/instanced_grass_pass2.frag b/data/shaders/instanced_grass_pass2.frag
new file mode 100644
index 000000000..f3134047d
--- /dev/null
+++ b/data/shaders/instanced_grass_pass2.frag
@@ -0,0 +1,45 @@
+#ifdef GL_ARB_bindless_texture
+layout(bindless_sampler) uniform sampler2D dtex;
+#else
+uniform sampler2D Albedo;
+uniform sampler2D dtex;
+#endif
+
+uniform vec3 SunDir;
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec3 nor;
+in vec2 uv;
+out vec4 FragColor;
+
+vec3 getLightFactor(float specMapValue);
+
+void main(void)
+{
+    vec2 texc = gl_FragCoord.xy / screen;
+    float z = texture(dtex, texc).x;
+
+    vec4 xpos = 2.0 * vec4(texc, z, 1.0) - 1.0f;
+    xpos = InverseProjectionMatrix * xpos;
+    xpos /= xpos.w;
+    vec3 eyedir = normalize(xpos.xyz);
+
+    // Inspired from http://http.developer.nvidia.com/GPUGems3/gpugems3_ch16.html
+    float fEdotL = max(0., dot(SunDir, eyedir));
+    float fPowEdotL = pow(fEdotL, 4.);
+
+    float fLdotNBack  = max(0., - dot(nor, SunDir) * 0.6 + 0.4);
+    float scattering = mix(fPowEdotL, fLdotNBack, .5);
+
+#ifdef GL_ARB_bindless_texture
+    vec4 color = texture(handle, uv);
+    color.xyz = pow(color.xyz, vec3(2.2));
+#else
+    vec4 color = texture(Albedo, uv);
+#endif
+    if (color.a < 0.5) discard;
+    vec3 LightFactor = (scattering * 0.3) + getLightFactor(1.);
+    FragColor = vec4(color.xyz * LightFactor, 1.);
+}
diff --git a/data/shaders/instanced_normalmap.frag b/data/shaders/instanced_normalmap.frag
new file mode 100644
index 000000000..4b4ecadcd
--- /dev/null
+++ b/data/shaders/instanced_normalmap.frag
@@ -0,0 +1,35 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D normalMap;
+uniform sampler2D DiffuseForAlpha;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+flat in sampler2D secondhandle;
+#endif
+in vec3 tangent;
+in vec3 bitangent;
+in vec2 uv;
+out vec3 EncodedNormal;
+
+vec2 EncodeNormal(vec3 n);
+
+void main()
+{
+    // normal in Tangent Space
+#ifdef GL_ARB_bindless_texture
+    vec3 TS_normal = 2.0 * texture(secondhandle, uv).rgb - 1.0;
+    float alpha = texture(handle, uv).a;
+#else
+    vec3 TS_normal = 2.0 * texture(normalMap, uv).rgb - 1.0;
+    float alpha = texture(DiffuseForAlpha, uv).a;
+#endif
+    // Because of interpolation, we need to renormalize
+    vec3 Frag_tangent = normalize(tangent);
+    vec3 Frag_normal = normalize(cross(Frag_tangent, bitangent));
+    vec3 Frag_bitangent = cross(Frag_normal, Frag_tangent);
+
+    vec3 FragmentNormal = TS_normal.x * Frag_tangent + TS_normal.y * Frag_bitangent - TS_normal.z * Frag_normal;
+    EncodedNormal.xy = 0.5 * EncodeNormal(normalize(FragmentNormal)) + 0.5;
+    EncodedNormal.z = exp2(10. * (1. - alpha) + 1.);
+}
diff --git a/data/shaders/instanced_object_pass.vert b/data/shaders/instanced_object_pass.vert
index f83c7f7b5..eb8a9e018 100644
--- a/data/shaders/instanced_object_pass.vert
+++ b/data/shaders/instanced_object_pass.vert
@@ -9,6 +9,11 @@ layout(location = 6) in vec3 Bitangent;
 layout(location = 7) in vec3 Origin;
 layout(location = 8) in vec3 Orientation;
 layout(location = 9) in vec3 Scale;
+#ifdef GL_ARB_bindless_texture
+layout(location = 10) in sampler2D Handle;
+layout(location = 11) in sampler2D SecondHandle;
+#endif
+
 #else
 in vec3 Position;
 in vec3 Normal;
@@ -27,6 +32,10 @@ out vec3 tangent;
 out vec3 bitangent;
 out vec2 uv;
 out vec4 color;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D handle;
+flat out sampler2D secondhandle;
+#endif
 
 mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
 mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
@@ -41,4 +50,8 @@ void main(void)
     bitangent = (TransposeInverseModelView * vec4(Bitangent, 1.)).xyz;
     uv = Texcoord;
     color = Color.zyxw;
+#ifdef GL_ARB_bindless_texture
+    handle = Handle;
+    secondhandle = SecondHandle;
+#endif
 }
diff --git a/data/shaders/instanced_object_pass1.frag b/data/shaders/instanced_object_pass1.frag
new file mode 100644
index 000000000..fc04aa63f
--- /dev/null
+++ b/data/shaders/instanced_object_pass1.frag
@@ -0,0 +1,23 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D tex;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec3 nor;
+in vec2 uv;
+out vec3 EncodedNormal;
+
+vec2 EncodeNormal(vec3 n);
+
+void main(void)
+{
+#ifdef GL_ARB_bindless_texture
+    vec4 col = texture(handle, uv);
+#else
+    vec4 col = texture(tex, uv);
+#endif
+    EncodedNormal.xy = 0.5 * EncodeNormal(normalize(nor)) + 0.5;
+    EncodedNormal.z = exp2(10. * (1. - col.a) + 1.);
+}
diff --git a/data/shaders/instanced_object_pass2.frag b/data/shaders/instanced_object_pass2.frag
new file mode 100644
index 000000000..6cb4296a8
--- /dev/null
+++ b/data/shaders/instanced_object_pass2.frag
@@ -0,0 +1,24 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D Albedo;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec2 uv;
+in vec4 color;
+out vec4 FragColor;
+
+vec3 getLightFactor(float specMapValue);
+
+void main(void)
+{
+#ifdef GL_ARB_bindless_texture
+    vec4 col = pow(texture(handle, uv), vec4(2.2));
+#else
+    vec4 col = texture(Albedo, uv);
+#endif
+    col.xyz *= pow(color.xyz, vec3(2.2));
+    vec3 LightFactor = getLightFactor(1.);
+    FragColor = vec4(col.xyz * LightFactor, 1.);
+}
diff --git a/data/shaders/instanced_objectref_pass1.frag b/data/shaders/instanced_objectref_pass1.frag
new file mode 100644
index 000000000..c24fcddf7
--- /dev/null
+++ b/data/shaders/instanced_objectref_pass1.frag
@@ -0,0 +1,25 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D tex;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec3 nor;
+in vec2 uv;
+out vec3 EncodedNormal;
+
+vec2 EncodeNormal(vec3 n);
+
+void main() {
+#ifdef GL_ARB_bindless_texture
+    vec4 col = texture(handle, uv);
+#else
+    vec4 col = texture(tex, uv);
+#endif
+    if (col.a < 0.5)
+        discard;
+    EncodedNormal.xy = 0.5 * EncodeNormal(normalize(nor)) + 0.5;
+    EncodedNormal.z = 1.;
+}
+
diff --git a/data/shaders/instanced_objectref_pass2.frag b/data/shaders/instanced_objectref_pass2.frag
new file mode 100644
index 000000000..27d1bd03d
--- /dev/null
+++ b/data/shaders/instanced_objectref_pass2.frag
@@ -0,0 +1,26 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D Albedo;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec2 uv;
+in vec4 color;
+out vec4 FragColor;
+
+vec3 getLightFactor(float specMapValue);
+
+void main(void)
+{
+#ifdef GL_ARB_bindless_texture
+    vec4 col = texture(handle, uv);
+    col.xyz = pow(col.xyz, vec3(2.2));
+#else
+    vec4 col = texture(Albedo, uv);
+#endif
+    col.xyz *= pow(color.xyz, vec3(2.2));
+    if (col.a * color.a < 0.5) discard;
+    vec3 LightFactor = getLightFactor(1.);
+    FragColor = vec4(col.xyz * LightFactor, 1.);
+}
diff --git a/data/shaders/instanced_shadow.geom b/data/shaders/instanced_shadow.geom
new file mode 100644
index 000000000..1ecc55a46
--- /dev/null
+++ b/data/shaders/instanced_shadow.geom
@@ -0,0 +1,28 @@
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D hdle[3];
+#endif
+in vec2 tc[3];
+in int layerId[3];
+
+out vec2 uv;
+#ifdef GL_ARB_bindless_texture
+out flat sampler2D handle;
+#endif
+
+void main(void)
+{
+  gl_Layer = layerId[0];
+#ifdef GL_ARB_bindless_texture
+  handle = hdle[0];
+#endif
+  for(int i=0; i<3; i++)
+  {
+    uv = tc[i];
+    gl_Position = gl_in[i].gl_Position;
+    EmitVertex();
+  }
+  EndPrimitive();
+}
diff --git a/data/shaders/instanced_shadowref.frag b/data/shaders/instanced_shadowref.frag
new file mode 100644
index 000000000..7ed4ab3ae
--- /dev/null
+++ b/data/shaders/instanced_shadowref.frag
@@ -0,0 +1,21 @@
+#ifndef GL_ARB_bindless_texture
+uniform sampler2D tex;
+#endif
+
+#ifdef GL_ARB_bindless_texture
+flat in sampler2D handle;
+#endif
+in vec2 uv;
+in vec4 color;
+out vec4 FragColor;
+
+void main(void)
+{
+#ifdef GL_ARB_bindless_texture
+    vec4 col = texture(handle, uv);
+#else
+    vec4 col = texture(tex, uv);
+#endif
+    if (col.a < 0.5) discard;
+    FragColor = vec4(1.);
+}
diff --git a/data/shaders/instanciedgrassshadow.vert b/data/shaders/instanciedgrassshadow.vert
index d27f2e808..1a88fbf6a 100644
--- a/data/shaders/instanciedgrassshadow.vert
+++ b/data/shaders/instanciedgrassshadow.vert
@@ -7,6 +7,10 @@ layout(location = 3) in vec2 Texcoord;
 layout(location = 7) in vec3 Origin;
 layout(location = 8) in vec3 Orientation;
 layout(location = 9) in vec3 Scale;
+#ifdef GL_ARB_bindless_texture
+layout(location = 10) in sampler2D Handle;
+#endif
+
 #else
 in vec3 Position;
 in vec4 Color;
@@ -19,9 +23,15 @@ in vec3 Scale;
 
 #ifdef VSLayer
 out vec2 uv;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D handle;
+#endif
 #else
 out vec2 tc;
 out int layerId;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D hdle;
+#endif
 #endif
 
 mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
@@ -34,9 +44,15 @@ void main(void)
     gl_Layer = gl_InstanceID & 3;
     gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
     uv = Texcoord;
+#ifdef GL_ARB_bindless_texture
+    handle = Handle;
+#endif
 #else
     layerId = gl_InstanceID & 3;
     gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
     tc = Texcoord;
+#ifdef GL_ARB_bindless_texture
+    hdle = Handle;
+#endif
 #endif
 }
\ No newline at end of file
diff --git a/data/shaders/instanciedshadow.vert b/data/shaders/instanciedshadow.vert
index a9f5fc34d..0bfc9426b 100644
--- a/data/shaders/instanciedshadow.vert
+++ b/data/shaders/instanciedshadow.vert
@@ -5,6 +5,10 @@ layout(location = 3) in vec2 Texcoord;
 layout(location = 7) in vec3 Origin;
 layout(location = 8) in vec3 Orientation;
 layout(location = 9) in vec3 Scale;
+#ifdef GL_ARB_bindless_texture
+layout(location = 10) in sampler2D Handle;
+#endif
+
 #else
 in vec3 Position;
 in vec2 Texcoord;
@@ -16,9 +20,15 @@ in vec3 Scale;
 
 #ifdef VSLayer
 out vec2 uv;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D handle;
+#endif
 #else
 out vec2 tc;
 out int layerId;
+#ifdef GL_ARB_bindless_texture
+flat out sampler2D hdle;
+#endif
 #endif
 
 mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
@@ -31,9 +41,15 @@ void main(void)
     gl_Layer = gl_InstanceID & 3;
     gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position, 1.);
     uv = Texcoord;
+#ifdef GL_ARB_bindless_texture
+    handle = Handle;
+#endif
 #else
     layerId = gl_InstanceID & 3;
     gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position, 1.);
     tc = Texcoord;
+#ifdef GL_ARB_bindless_texture
+    hdle = Handle;
+#endif
 #endif
 }
\ No newline at end of file
diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp
index 3baa27d22..219e2f558 100644
--- a/src/graphics/glwrap.cpp
+++ b/src/graphics/glwrap.cpp
@@ -745,6 +745,12 @@ void VAOManager::regenerateInstancedVAO()
             glEnableVertexAttribArray(9);
             glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
             glVertexAttribDivisor(9, 1);
+            glEnableVertexAttribArray(10);
+            glVertexAttribIPointer(10, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float)));
+            glVertexAttribDivisor(10, 1);
+            glEnableVertexAttribArray(11);
+            glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float) + 2 * sizeof(unsigned)));
+            glVertexAttribDivisor(11, 1);
             InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, (InstanceType) j)] = vao;
 
             GLuint shadow_vao = createVAO(vbo[tp], ibo[tp], tp);
@@ -759,6 +765,12 @@ void VAOManager::regenerateInstancedVAO()
             glEnableVertexAttribArray(9);
             glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float)));
             glVertexAttribDivisor(9, 4);
+            glEnableVertexAttribArray(10);
+            glVertexAttribIPointer(10, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float)));
+            glVertexAttribDivisor(10, 4);
+            glEnableVertexAttribArray(11);
+            glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float)+2 * sizeof(unsigned)));
+            glVertexAttribDivisor(11, 1);
             ShadowInstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, (InstanceType)j)] = shadow_vao;
             glBindVertexArray(0);
         }
diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp
index c775bcebe..6d45bbba5 100644
--- a/src/graphics/glwrap.hpp
+++ b/src/graphics/glwrap.hpp
@@ -166,6 +166,7 @@ struct InstanceData
         float Z;
     } Scale;
     uint64_t Texture;
+    uint64_t SecondTexture;
 };
 
 class VAOManager : public Singleton<VAOManager>
diff --git a/src/graphics/render_geometry.cpp b/src/graphics/render_geometry.cpp
index 1b3d01acb..20e6e4620 100644
--- a/src/graphics/render_geometry.cpp
+++ b/src/graphics/render_geometry.cpp
@@ -201,7 +201,6 @@ void renderInstancedMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vec
     glUseProgram(Shader::getInstance()->Program);
     for (unsigned i = 0; i < meshes->size(); i++)
     {
-        std::vector<uint64_t> Handles;
         std::vector<GLuint> Textures;
         GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i)));
 #ifdef DEBUG
@@ -210,28 +209,17 @@ void renderInstancedMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vec
 #endif
         if (!irr_driver->hasARB_base_instance())
             glBindVertexArray(mesh.vao);
-        for (unsigned j = 0; j < TexUnits.size(); j++)
+        if (!UserConfigParams::m_bindless_textures)
         {
-            if (!mesh.textures[TexUnits[j].m_id])
-                mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
-            compressTexture(mesh.textures[TexUnits[j].m_id], TexUnits[j].m_premul_alpha);
-            if (UserConfigParams::m_bindless_textures)
+            for (unsigned j = 0; j < TexUnits.size(); j++)
             {
-#ifdef Bindless_Texture_Support
-                if (!mesh.TextureHandles[TexUnits[j].m_id])
-                    mesh.TextureHandles[TexUnits[j].m_id] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[TexUnits[j].m_id]), Shader::getInstance()->SamplersId[j]);
-                if (!glIsTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id]))
-                    glMakeTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id]);
-#endif
-                Handles.push_back(mesh.TextureHandles[TexUnits[j].m_id]);
-            }
-            else
+                if (!mesh.textures[TexUnits[j].m_id])
+                    mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
+                compressTexture(mesh.textures[TexUnits[j].m_id], TexUnits[j].m_premul_alpha);
                 Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id]));
-        }
-        if (UserConfigParams::m_bindless_textures)
-            Shader::getInstance()->SetTextureHandles(Handles);
-        else
+            }
             Shader::getInstance()->SetTextureUnits(Textures);
+        }
         instanced_custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i));
     }
 }
@@ -363,16 +351,6 @@ void renderMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::
             }
             else
                 Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id]));
-/*            if (irr_driver->getLightViz())
-            {
-                GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA };
-                glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
-            }
-            else
-            {
-                GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
-                glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
-            }*/
         }
 
         if (mesh.VAOType != VertexType)
@@ -402,40 +380,25 @@ void renderInstancedMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vec
         if (!irr_driver->hasARB_base_instance())
             glBindVertexArray(mesh.vao);
 
-        std::vector<GLuint> Textures(Prefilled_tex);
-        std::vector<uint64_t> Handles(Prefilled_Handles);
-
-        for (unsigned j = 0; j < TexUnits.size(); j++)
-        {
-            if (!mesh.textures[TexUnits[j].m_id])
-                mesh.textures[TexUnits[j].m_id] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
-            compressTexture(mesh.textures[TexUnits[j].m_id], TexUnits[j].m_premul_alpha);
-#ifdef Bindless_Texture_Support
-            if (!mesh.TextureHandles[TexUnits[j].m_id])
-                mesh.TextureHandles[TexUnits[j].m_id] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[TexUnits[j].m_id]), Shader::getInstance()->SamplersId[Handles.size()]);
-            if (!glIsTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id]))
-                glMakeTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id]);
-#endif
-            if (UserConfigParams::m_bindless_textures)
-                Handles.push_back(mesh.TextureHandles[TexUnits[j].m_id]);
-            else
-                Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id]));
-/*            if (irr_driver->getLightViz())
-            {
-                GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA };
-                glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
-            }
-            else
-            {
-                GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
-                glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
-            }*/
-        }
-
         if (UserConfigParams::m_bindless_textures)
+        {
+            std::vector<uint64_t> Handles(Prefilled_Handles);
+            for (unsigned i = 0; i < TexUnits.size(); i++)
+                Handles.push_back(0);
             Shader::getInstance()->SetTextureHandles(Handles);
+        }
         else
-            Shader::getInstance()->SetTextureUnits(Textures);
+        {
+            std::vector<GLuint> Textures(Prefilled_tex);
+            for (unsigned j = 0; j < TexUnits.size(); j++)
+            {
+                if (!mesh.textures[TexUnits[j].m_id])
+                    mesh.textures[TexUnits[j].m_id] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
+                compressTexture(mesh.textures[TexUnits[j].m_id], TexUnits[j].m_premul_alpha);
+                Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id]));
+                Shader::getInstance()->SetTextureUnits(Textures);
+            }
+        }
 
         instanced_custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i));
     }
@@ -841,26 +804,15 @@ void renderInstancedShadow(const std::vector<GLuint> TextureUnits, const std::ve
         GLMesh *mesh = STK::tuple_get<0>(t->at(i));
         if (!irr_driver->hasARB_base_instance())
             glBindVertexArray(mesh->vao_shadow_pass);
-        for (unsigned j = 0; j < TextureUnits.size(); j++)
+        if (!UserConfigParams::m_bindless_textures)
         {
-            compressTexture(mesh->textures[TextureUnits[j]], true);
-            if (UserConfigParams::m_bindless_textures)
+            for (unsigned j = 0; j < TextureUnits.size(); j++)
             {
-#ifdef Bindless_Texture_Support
-                if (!mesh->TextureHandles[TextureUnits[j]])
-                    mesh->TextureHandles[TextureUnits[j]] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh->textures[TextureUnits[j]]), T::getInstance()->SamplersId[j]);
-                if (!glIsTextureHandleResidentARB(mesh->TextureHandles[TextureUnits[j]]))
-                    glMakeTextureHandleResidentARB(mesh->TextureHandles[TextureUnits[j]]);
-#endif
-                Handles.push_back(mesh->TextureHandles[TextureUnits[j]]);
-            }
-            else
+                compressTexture(mesh->textures[TextureUnits[j]], true);
                 Textures.push_back(getTextureGLuint(mesh->textures[TextureUnits[j]]));
+                T::getInstance()->SetTextureUnits(Textures);
+            }
         }
-        if (UserConfigParams::m_bindless_textures)
-            T::getInstance()->SetTextureHandles(Handles);
-        else
-            T::getInstance()->SetTextureUnits(Textures);
         instanced_shadow_custom_unroll_args<List...>::template exec<T>(T::getInstance(), t->at(i));
     }
 }
diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp
index dc357c07f..968642db9 100644
--- a/src/graphics/shaders.cpp
+++ b/src/graphics/shaders.cpp
@@ -818,7 +818,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_pass1.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_pass1.frag").c_str());
 
         AssignUniforms();
         AssignSamplerNames(Program, 0, "tex");
@@ -833,7 +833,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass1.frag").c_str());
 
         AssignUniforms();
         AssignSamplerNames(Program, 0, "tex");
@@ -848,7 +848,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass1.frag").c_str());
         AssignUniforms("windDir");
 
         AssignSamplerNames(Program, 0, "tex");
@@ -863,7 +863,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/normalmap.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_normalmap.frag").c_str());
         AssignUniforms();
 
         GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData");
@@ -893,7 +893,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_pass2.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_pass2.frag").c_str());
         AssignUniforms();
 
         AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
@@ -909,7 +909,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass2.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass2.frag").c_str());
         AssignUniforms();
 
         AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
@@ -975,7 +975,7 @@ namespace MeshShader
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
             GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(),
             GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
-            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/grass_pass2.frag").c_str());
+            GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_grass_pass2.frag").c_str());
         AssignUniforms("windDir", "SunDir");
 
         AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "dtex", 4, "Albedo");
@@ -1158,7 +1158,7 @@ namespace MeshShader
             Program = LoadProgram(
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(),
-                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(),
+                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(),
                 GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str());
         }
         GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData");
@@ -1200,15 +1200,15 @@ namespace MeshShader
             Program = LoadProgram(
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(),
-                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
+                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str());
         }
         else
         {
             Program = LoadProgram(
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(),
-                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(),
-                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
+                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(),
+                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str());
         }
 
         AssignSamplerNames(Program, 0, "tex");
@@ -1251,15 +1251,15 @@ namespace MeshShader
             Program = LoadProgram(
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedgrassshadow.vert").c_str(),
-                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
+                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str());
         }
         else
         {
             Program = LoadProgram(
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
                 GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedgrassshadow.vert").c_str(),
-                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(),
-                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
+                GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(),
+                GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str());
         }
 
         AssignSamplerNames(Program, 0, "tex");
diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp
index 33ae728f9..ce4481cb9 100644
--- a/src/graphics/shaders.hpp
+++ b/src/graphics/shaders.hpp
@@ -439,10 +439,12 @@ public:
 
     void SetTextureHandles(const std::vector<uint64_t> &args)
     {
+        assert(args.size() == TextureLocation.size() && "Wrong Handle count");
         for (unsigned i = 0; i < args.size(); i++)
         {
 #ifdef Bindless_Texture_Support
-            glUniformHandleui64ARB(TextureLocation[i], args[i]);
+            if (args[i])
+                glUniformHandleui64ARB(TextureLocation[i], args[i]);
 #endif
         }
     }
diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp
index f12e27be7..ff0c7384a 100644
--- a/src/graphics/stkinstancedscenenode.cpp
+++ b/src/graphics/stkinstancedscenenode.cpp
@@ -57,6 +57,7 @@ void STKInstancedSceneNode::createGLMeshes()
             mesh.vaoBaseVertex = p.first;
             mesh.vaoOffset = p.second;
             mesh.VAOType = mb->getVertexType();
+            instanceData.push_back(std::vector<InstanceData>());
         }
         else
             fillLocalBuffer(mesh, mb);
@@ -66,9 +67,7 @@ void STKInstancedSceneNode::createGLMeshes()
 
 void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh)
 {
-    if (irr_driver->hasARB_base_instance())
-        mesh.vaoBaseInstance = VAOManager::getInstance()->appendInstance(InstanceTypeDefault, instanceData);
-    else
+    if (!irr_driver->hasARB_base_instance())
     {
         mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
         glGenBuffers(1, &instances_vbo);
@@ -115,6 +114,7 @@ void STKInstancedSceneNode::setFirstTimeMaterial()
         GLMesh &mesh = GLmeshes[i];
         MeshMaterial MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType());
         initinstancedvaostate(mesh);
+        mesh.vaoBaseInstance = VAOManager::getInstance()->appendInstance(InstanceTypeDefault, instanceData[i]);
         MeshSolidMaterial[MatType].push_back(&mesh);
     }
     isMaterialInitialized = true;
@@ -122,32 +122,53 @@ void STKInstancedSceneNode::setFirstTimeMaterial()
 
 void STKInstancedSceneNode::addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale)
 {
-    InstanceData instance = {
+    for (unsigned i = 0; i < GLmeshes.size(); i++)
+    {
+        GLMesh &mesh = GLmeshes[i];
+#ifdef Bindless_Texture_Support
+        if (UserConfigParams::m_bindless_textures)
         {
-            origin.X,
-            origin.Y,
-            origin.Z
-        },
-        {
-            orientation.X,
-            orientation.Y,
-            orientation.Z
-        },
-        {
-            scale.X,
-            scale.Y,
-            scale.Z
-        },
-        0
-    };
-    instanceData.push_back(instance);
+            for (unsigned j = 0; j < 2; j++)
+            {
+                if (!mesh.textures[j])
+                    mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255));
+                compressTexture(mesh.textures[j], true);
+
+                if (!mesh.TextureHandles[j])
+                    mesh.TextureHandles[j] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[j]), MeshShader::InstancedNormalMapShader::getInstance()->SamplersId[j]);
+                if (!glIsTextureHandleResidentARB(mesh.TextureHandles[j]))
+                    glMakeTextureHandleResidentARB(mesh.TextureHandles[j]);
+            }
+        }
+#endif
+        InstanceData instance = {
+            {
+                origin.X,
+                origin.Y,
+                origin.Z
+            },
+            {
+                orientation.X,
+                orientation.Y,
+                orientation.Z
+            },
+            {
+                scale.X,
+                scale.Y,
+                scale.Z
+            },
+            mesh.TextureHandles[0],
+            mesh.TextureHandles[1]
+        };
+        instanceData[i].push_back(instance);
+    }
 }
 
 core::matrix4 STKInstancedSceneNode::getInstanceTransform(int id)
 {
     core::matrix4 mat;
 
-    const InstanceData &instance = instanceData[id];
+    const InstanceData &instance = instanceData[0][id];
     mat.setTranslation(core::vector3df(
         instance.Origin.X,
         instance.Origin.Y,
@@ -174,17 +195,16 @@ void STKInstancedSceneNode::render()
 
     setFirstTimeMaterial();
 
-    
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_DEFAULT].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_DEFAULT][i];
-        ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
+        ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
     }
 
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_ALPHA_REF].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_ALPHA_REF][i];
-        ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
+        ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
     }
 
     windDir = getWind();
@@ -192,12 +212,12 @@ void STKInstancedSceneNode::render()
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_GRASS].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_GRASS][i];
-        ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size(), windDir, cb->getPosition()));
+        ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size(), windDir, cb->getPosition()));
     }
 
     for(unsigned i = 0; i < MeshSolidMaterial[MAT_NORMAL_MAP].size(); i++)
     {
         GLMesh *mesh = MeshSolidMaterial[MAT_NORMAL_MAP][i];
-        ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instanceData.size()));
+        ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
     }
 }
diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp
index 35a38d8b1..c6787a02f 100644
--- a/src/graphics/stkinstancedscenenode.hpp
+++ b/src/graphics/stkinstancedscenenode.hpp
@@ -22,7 +22,7 @@ protected:
     int m_ref_count;
     std::vector<GLMesh *> MeshSolidMaterial[MAT_COUNT];
     std::vector<GLMesh> GLmeshes;
-    std::vector<InstanceData> instanceData;
+    std::vector<std::vector<InstanceData> > instanceData;
     core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView;
     GLuint instances_vbo;
     void createGLMeshes();

From 0fa38161b54cc0b8d614590654fadfb790491dba Mon Sep 17 00:00:00 2001
From: Deve <deveee@gmail.com>
Date: Sun, 24 Aug 2014 21:57:56 +0200
Subject: [PATCH 05/11] Install icons in $PREFIX/share/icons/hicolor path.

Don't use static paths in .desktop file. Actually I don't know about any application which uses it :P
---
 CMakeLists.txt                                            | 8 +++-----
 ...supertuxkart_desktop.template => supertuxkart.desktop} | 5 ++---
 2 files changed, 5 insertions(+), 8 deletions(-)
 rename data/{supertuxkart_desktop.template => supertuxkart.desktop} (66%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 16759b88f..0c447a46d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -368,10 +368,8 @@ install(DIRECTORY ${STK_DATA_DIR} DESTINATION ${STK_INSTALL_DATA_DIR} PATTERN ".
 if(STK_ASSETS_DIR AND CHECK_ASSETS)
   install(DIRECTORY ${STK_ASSETS_DIR} DESTINATION ${STK_INSTALL_DATA_DIR}/data PATTERN ".svn" EXCLUDE PATTERN ".git" EXCLUDE)
 endif()
-install(FILES ${PROJECT_BINARY_DIR}/supertuxkart.desktop DESTINATION share/applications)
+install(FILES ${STK_DATA_DIR}/supertuxkart.desktop DESTINATION share/applications)
+install(FILES data/supertuxkart_32.png DESTINATION share/icons/hicolor/32x32 RENAME supertuxkart.png)
+install(FILES data/supertuxkart_128.png DESTINATION share/icons/hicolor/128x128 RENAME supertuxkart.png)
 install(FILES data/supertuxkart_32.png data/supertuxkart_128.png DESTINATION share/pixmaps)
 install(FILES data/supertuxkart.appdata DESTINATION share/appdata)
-
-set(PREFIX ${CMAKE_INSTALL_PREFIX})
-configure_file(data/supertuxkart_desktop.template supertuxkart.desktop)
-add_dependencies(supertuxkart supertuxkart.desktop)
diff --git a/data/supertuxkart_desktop.template b/data/supertuxkart.desktop
similarity index 66%
rename from data/supertuxkart_desktop.template
rename to data/supertuxkart.desktop
index 789b21442..034f20da6 100644
--- a/data/supertuxkart_desktop.template
+++ b/data/supertuxkart.desktop
@@ -1,15 +1,14 @@
 [Desktop Entry]
 Name=SuperTuxKart
-Icon=@PREFIX@/share/pixmaps/supertuxkart_128.png
+Icon=supertuxkart
 GenericName=A kart racing game
 GenericName[de]=Ein Kart-Rennspiel
 GenericName[fr]=Un jeu de karting
 GenericName[gl]=Xogo de carreiras con karts
 GenericName[pl]=Wyścigi gokartów
 GenericName[ro]=Un joc de curse cu carturi
-Exec=@PREFIX@/@STK_INSTALL_BINARY_DIR@/supertuxkart --no-console
+Exec=supertuxkart
 Terminal=false
 StartupNotify=false
 Type=Application
-TryExec=@PREFIX@/@STK_INSTALL_BINARY_DIR@/supertuxkart
 Categories=Game;ArcadeGame;

From aa6e3570dfcc4f10430855664b7e56dff4660f28 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Mon, 25 Aug 2014 00:37:36 +0200
Subject: [PATCH 06/11] Fix attempt for crash.

---
 src/graphics/stkinstancedscenenode.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp
index c6787a02f..d3fe05b32 100644
--- a/src/graphics/stkinstancedscenenode.hpp
+++ b/src/graphics/stkinstancedscenenode.hpp
@@ -40,7 +40,7 @@ public:
     virtual void render();
     void addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale);
 
-    int getInstanceCount() const { return instanceData.size(); }
+    int getInstanceCount() const { return instanceData[0].size(); }
 
     core::matrix4 getInstanceTransform(int id);
 

From b401d1e082e0b1f330633b61d4018805e573bd82 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Mon, 25 Aug 2014 01:09:52 +0200
Subject: [PATCH 07/11] Push empty InstanceData independently of gl level

---
 src/graphics/stkinstancedscenenode.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp
index ff0c7384a..f286e229c 100644
--- a/src/graphics/stkinstancedscenenode.cpp
+++ b/src/graphics/stkinstancedscenenode.cpp
@@ -57,10 +57,10 @@ void STKInstancedSceneNode::createGLMeshes()
             mesh.vaoBaseVertex = p.first;
             mesh.vaoOffset = p.second;
             mesh.VAOType = mb->getVertexType();
-            instanceData.push_back(std::vector<InstanceData>());
         }
         else
             fillLocalBuffer(mesh, mb);
+        instanceData.push_back(std::vector<InstanceData>());
     }
     isMaterialInitialized = false;
 }

From 44de38bf107a1392934ea98ebf3962f6560099b1 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Sat, 23 Aug 2014 21:35:50 +0200
Subject: [PATCH 08/11] Pack instanceData

---
 src/graphics/glwrap.hpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp
index 6d45bbba5..62f192864 100644
--- a/src/graphics/glwrap.hpp
+++ b/src/graphics/glwrap.hpp
@@ -145,6 +145,9 @@ enum InstanceType
     InstanceTypeCount,
 };
 
+#ifdef WIN32
+#pragma pack(push, 1)
+#endif
 struct InstanceData
 {
     struct
@@ -167,7 +170,12 @@ struct InstanceData
     } Scale;
     uint64_t Texture;
     uint64_t SecondTexture;
+#ifdef WIN32
 };
+#pragma pack(pop)
+#else
+} __attribute__((packed));
+#endif
 
 class VAOManager : public Singleton<VAOManager>
 {

From f3752a03f0745c86442722b75ba3365e4be1c126 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Mon, 25 Aug 2014 01:53:05 +0200
Subject: [PATCH 09/11] Enable arb debug output on all non apple platform

---
 src/graphics/glwrap.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp
index 219e2f558..031b08ef4 100644
--- a/src/graphics/glwrap.cpp
+++ b/src/graphics/glwrap.cpp
@@ -108,7 +108,7 @@ PFNGLVERTEXATTRIBLPOINTERPROC glVertexAttribLPointer;
 static bool is_gl_init = false;
 
 #ifdef DEBUG
-#ifdef WIN32
+#if !defined(__APPLE__)
 #define ARB_DEBUG_OUTPUT
 #endif
 #endif

From 55346185d7ffaaeed5b803b301baa8cbf2d69ca1 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Mon, 25 Aug 2014 02:13:01 +0200
Subject: [PATCH 10/11] Fix instancing without base instance support

---
 src/graphics/stkinstancedscenenode.cpp | 9 +++++----
 src/graphics/stkinstancedscenenode.hpp | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp
index f286e229c..bfec20701 100644
--- a/src/graphics/stkinstancedscenenode.cpp
+++ b/src/graphics/stkinstancedscenenode.cpp
@@ -65,14 +65,14 @@ void STKInstancedSceneNode::createGLMeshes()
     isMaterialInitialized = false;
 }
 
-void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh)
+void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh, const std::vector<InstanceData> &instances)
 {
     if (!irr_driver->hasARB_base_instance())
     {
         mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride));
         glGenBuffers(1, &instances_vbo);
         glBindBuffer(GL_ARRAY_BUFFER, instances_vbo);
-        glBufferData(GL_ARRAY_BUFFER, instanceData.size() * sizeof(InstanceData), instanceData.data(), GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, instances.size() * sizeof(InstanceData), instances.data(), GL_STATIC_DRAW);
 
         glEnableVertexAttribArray(7);
         glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);
@@ -113,8 +113,9 @@ void STKInstancedSceneNode::setFirstTimeMaterial()
 
         GLMesh &mesh = GLmeshes[i];
         MeshMaterial MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType());
-        initinstancedvaostate(mesh);
-        mesh.vaoBaseInstance = VAOManager::getInstance()->appendInstance(InstanceTypeDefault, instanceData[i]);
+        initinstancedvaostate(mesh, instanceData[i]);
+        if (irr_driver->hasARB_base_instance())
+            mesh.vaoBaseInstance = VAOManager::getInstance()->appendInstance(InstanceTypeDefault, instanceData[i]);
         MeshSolidMaterial[MatType].push_back(&mesh);
     }
     isMaterialInitialized = true;
diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp
index d3fe05b32..74dbc719d 100644
--- a/src/graphics/stkinstancedscenenode.hpp
+++ b/src/graphics/stkinstancedscenenode.hpp
@@ -28,7 +28,7 @@ protected:
     void createGLMeshes();
     bool isMaterialInitialized;
     void setFirstTimeMaterial();
-    void initinstancedvaostate(GLMesh &mesh);
+    void initinstancedvaostate(GLMesh &mesh, const std::vector<InstanceData> &);
     void cleanGL();
     core::vector3df windDir;
 public:

From 805d35a5e6d9f0b12fb1a810c44d9d34d83ddca3 Mon Sep 17 00:00:00 2001
From: Vincent Lejeune <vljn@ovi.com>
Date: Mon, 25 Aug 2014 02:17:23 +0200
Subject: [PATCH 11/11] Do not draw twice the second pass instanced mesh

---
 src/graphics/stkinstancedscenenode.cpp | 43 ++++++++++++++------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp
index bfec20701..3b7b8e225 100644
--- a/src/graphics/stkinstancedscenenode.cpp
+++ b/src/graphics/stkinstancedscenenode.cpp
@@ -196,29 +196,32 @@ void STKInstancedSceneNode::render()
 
     setFirstTimeMaterial();
 
-    for(unsigned i = 0; i < MeshSolidMaterial[MAT_DEFAULT].size(); i++)
+    if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS || irr_driver->getPhase() == SHADOW_PASS)
     {
-        GLMesh *mesh = MeshSolidMaterial[MAT_DEFAULT][i];
-        ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
-    }
+        for (unsigned i = 0; i < MeshSolidMaterial[MAT_DEFAULT].size(); i++)
+        {
+            GLMesh *mesh = MeshSolidMaterial[MAT_DEFAULT][i];
+            ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
+        }
 
-    for(unsigned i = 0; i < MeshSolidMaterial[MAT_ALPHA_REF].size(); i++)
-    {
-        GLMesh *mesh = MeshSolidMaterial[MAT_ALPHA_REF][i];
-        ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
-    }
+        for (unsigned i = 0; i < MeshSolidMaterial[MAT_ALPHA_REF].size(); i++)
+        {
+            GLMesh *mesh = MeshSolidMaterial[MAT_ALPHA_REF][i];
+            ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
+        }
 
-    windDir = getWind();
-    SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT);
-    for(unsigned i = 0; i < MeshSolidMaterial[MAT_GRASS].size(); i++)
-    {
-        GLMesh *mesh = MeshSolidMaterial[MAT_GRASS][i];
-        ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size(), windDir, cb->getPosition()));
-    }
+        windDir = getWind();
+        SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT);
+        for (unsigned i = 0; i < MeshSolidMaterial[MAT_GRASS].size(); i++)
+        {
+            GLMesh *mesh = MeshSolidMaterial[MAT_GRASS][i];
+            ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size(), windDir, cb->getPosition()));
+        }
 
-    for(unsigned i = 0; i < MeshSolidMaterial[MAT_NORMAL_MAP].size(); i++)
-    {
-        GLMesh *mesh = MeshSolidMaterial[MAT_NORMAL_MAP][i];
-        ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
+        for (unsigned i = 0; i < MeshSolidMaterial[MAT_NORMAL_MAP].size(); i++)
+        {
+            GLMesh *mesh = MeshSolidMaterial[MAT_NORMAL_MAP][i];
+            ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instanceData[0].size()));
+        }
     }
 }