Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (revision 12643) @@ -0,0 +1,74 @@ +#if USE_GPU_SKINNING +// Skinning requires GLSL 1.30 for ivec4 vertex attributes +#version 130 +#else +#version 120 +#endif + +uniform mat4 transform; +uniform vec3 cameraPos; +uniform vec3 sunDir; +uniform vec3 sunColor; +uniform vec2 losTransform; +uniform mat4 shadowTransform; +uniform mat4 instancingTransform; + +uniform float sim_time; +uniform vec2 translation; + +#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + uniform vec4 shadowScale; +#endif + + +attribute vec3 a_vertex; +attribute vec3 a_normal; +#if USE_INSTANCING + attribute vec4 a_tangent; +#endif +attribute vec2 a_uv0; +attribute vec2 a_uv1; + +#if USE_GPU_SKINNING + const int MAX_INFLUENCES = 4; + const int MAX_BONES = 64; + uniform mat4 skinBlendMatrices[MAX_BONES]; + attribute ivec4 a_skinJoints; + attribute vec4 a_skinWeights; +#endif + + +varying vec4 worldPos; +varying vec4 v_tex; +varying vec4 v_shadow; +varying vec2 v_los; + + +vec4 fakeCos(vec4 x) +{ + vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); + return tri * tri *(3.0 - 2.0 * tri); +} + + + +void main() +{ + worldPos = instancingTransform * vec4(a_vertex, 1.0); + + v_tex.xy = (a_uv0 + worldPos.xz) / 5.0 + sim_time * translation; + + v_tex.zw = a_uv0; + + #if USE_SHADOW + v_shadow = shadowTransform * worldPos; + #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + v_shadow.xy *= shadowScale.xy; + #endif + #endif + + v_los = worldPos.xz * losTransform.x + losTransform.y; + + gl_Position = transform * worldPos; +} + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.xml (revision 12643) @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + Index: ps/trunk/source/graphics/ShaderDefines.cpp =================================================================== --- ps/trunk/source/graphics/ShaderDefines.cpp (revision 12642) +++ ps/trunk/source/graphics/ShaderDefines.cpp (revision 12643) @@ -1,283 +1,291 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "ShaderDefines.h" #include "maths/Vector4D.h" #include "ps/ThreadUtil.h" #include size_t hash_value(const CStrIntern& v) { return v.GetHash(); } size_t hash_value(const CVector4D& v) { size_t hash = 0; boost::hash_combine(hash, v.X); boost::hash_combine(hash, v.Y); boost::hash_combine(hash, v.Z); boost::hash_combine(hash, v.W); return hash; } size_t hash_value(const CShaderParams::SItems& items) { return items.hash; } size_t hash_value(const CShaderParams::SItems& items) { return items.hash; } bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b) { return a.items == b.items; } bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b) { return a.items == b.items; } template struct ItemNameCmp { typedef typename CShaderParams::SItems::Item Item; typedef Item first_argument_type; typedef Item second_argument_type; bool operator()(const Item& a, const Item& b) const { return a.first < b.first; } }; template struct ItemNameGeq { typedef typename CShaderParams::SItems::Item Item; bool operator()(const Item& a, const Item& b) const { return !(b.first < a.first); } }; template typename CShaderParams::SItems* CShaderParams::GetInterned(const SItems& items) { ENSURE(ThreadUtil::IsMainThread()); // s_InternedItems is not thread-safe typename InternedItems_t::iterator it = s_InternedItems.find(items); if (it != s_InternedItems.end()) return it->second.get(); // Sanity test: the items list is meant to be sorted by name. // This is a reasonable place to verify that, since this will be called once per distinct SItems. typedef ItemNameCmp Cmp; ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate(Cmp())) == items.items.end()); shared_ptr ptr(new SItems(items)); s_InternedItems.insert(std::make_pair(items, ptr)); return ptr.get(); } template CShaderParams::CShaderParams() { SItems items; items.RecalcHash(); m_Items = GetInterned(items); } template void CShaderParams::Set(CStrIntern name, const value_t& value) { SItems items = *m_Items; typename SItems::Item addedItem = std::make_pair(name, value); // Add the new item in a way that preserves the sortedness and uniqueness of item names for (typename std::vector::iterator it = items.items.begin(); ; ++it) { if (it == items.items.end() || addedItem.first < it->first) { items.items.insert(it, addedItem); break; } else if (addedItem.first == it->first) { it->second = addedItem.second; break; } } items.RecalcHash(); m_Items = GetInterned(items); } template void CShaderParams::SetMany(const CShaderParams& params) { SItems items; // set_union merges the two sorted lists into a new sorted list; // if two items are equivalent (i.e. equal names, possibly different values) // then the one from the first list is kept std::set_union( params.m_Items->items.begin(), params.m_Items->items.end(), m_Items->items.begin(), m_Items->items.end(), std::inserter(items.items, items.items.begin()), ItemNameCmp()); items.RecalcHash(); m_Items = GetInterned(items); } template std::map CShaderParams::GetMap() const { std::map ret; for (size_t i = 0; i < m_Items->items.size(); ++i) ret[m_Items->items[i].first] = m_Items->items[i].second; return ret; } template size_t CShaderParams::GetHash() const { return m_Items->hash; } template void CShaderParams::SItems::RecalcHash() { size_t h = 0; for (size_t i = 0; i < items.size(); ++i) { boost::hash_combine(h, items[i].first); boost::hash_combine(h, items[i].second); } hash = h; } void CShaderDefines::Add(const char* name, const char* value) { Set(CStrIntern(name), CStrIntern(value)); } int CShaderDefines::GetInt(const char* name) const { CStrIntern nameIntern(name); for (size_t i = 0; i < m_Items->items.size(); ++i) { if (m_Items->items[i].first == nameIntern) { int ret; std::stringstream str(m_Items->items[i].second.c_str()); str >> ret; return ret; } } return 0; } void CShaderUniforms::Add(const char* name, const CVector4D& value) { Set(CStrIntern(name), value); } CVector4D CShaderUniforms::GetVector(const char* name) const { CStrIntern nameIntern(name); for (size_t i = 0; i < m_Items->items.size(); ++i) { if (m_Items->items[i].first == nameIntern) { return m_Items->items[i].second; } } return CVector4D(); } void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const { const std::vector& items = m_Items->items; for (size_t i = 0; i < items.size(); ++i) { CShaderProgram::Binding binding = shader->GetUniformBinding(items[i].first); if (binding.Active()) { CVector4D v = items[i].second; shader->Uniform(binding, v.X, v.Y, v.Z, v.W); } } } void CShaderRenderQueries::Add(const char* name) { - if (name == std::string("time")) + if (name == CStr("sim_time")) { m_Items.push_back(std::make_pair(RQUERY_TIME, CStrIntern(name))); } + else if (name == CStr("water_tex")) + { + m_Items.push_back(std::make_pair(RQUERY_WATER_TEX, CStrIntern(name))); + } + else if (name == CStr("sky_cube")) + { + m_Items.push_back(std::make_pair(RQUERY_SKY_CUBE, CStrIntern(name))); + } } size_t CShaderRenderQueries::GetSize() { return m_Items.size(); } CShaderRenderQueries::RenderQuery CShaderRenderQueries::GetItem(size_t i) { return m_Items[i]; } void CShaderConditionalDefines::Add(const char* defname, const char* defvalue, int type, std::vector &args) { CondDefine cd; cd.m_DefName = CStrIntern(defname); cd.m_DefValue = CStrIntern(defvalue); cd.m_CondArgs = args; cd.m_CondType = type; m_Defines.push_back(cd); } size_t CShaderConditionalDefines::GetSize() { return m_Defines.size(); } CShaderConditionalDefines::CondDefine& CShaderConditionalDefines::GetItem(size_t i) { return m_Defines[i]; } // Explicit instantiations: template<> CShaderParams::InternedItems_t CShaderParams::s_InternedItems = CShaderParams::InternedItems_t(); template<> CShaderParams::InternedItems_t CShaderParams::s_InternedItems = CShaderParams::InternedItems_t(); template class CShaderParams; template class CShaderParams; Index: ps/trunk/source/graphics/ShaderDefines.h =================================================================== --- ps/trunk/source/graphics/ShaderDefines.h (revision 12642) +++ ps/trunk/source/graphics/ShaderDefines.h (revision 12643) @@ -1,218 +1,220 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #ifndef INCLUDED_SHADERDEFINES #define INCLUDED_SHADERDEFINES #include "graphics/ShaderProgram.h" #include "ps/CStr.h" #include "ps/CStrIntern.h" #include class CVector4D; /** * Represents a mapping of name strings to value, for use with * CShaderDefines (values are strings) and CShaderUniforms (values are vec4s). * * Stored as interned vectors of name-value pairs, to support high performance * comparison operators. * * Not thread-safe - must only be used from the main thread. */ template class CShaderParams { public: /** * Create an empty map of defines. */ CShaderParams(); /** * Add a name and associated value to the map of parameters. * If the name is already defined, its value will be replaced. */ void Set(CStrIntern name, const value_t& value); /** * Add all the names and values from another set of parameters. * If any name is already defined in this object, its value will be replaced. */ void SetMany(const CShaderParams& params); /** * Return a copy of the current name/value mapping. */ std::map GetMap() const; /** * Return a hash of the current mapping. */ size_t GetHash() const; /** * Compare with some arbitrary total order. * The order may be different each time the application is run * (it is based on interned memory addresses). */ bool operator<(const CShaderParams& b) const { return m_Items < b.m_Items; } /** * Fast equality comparison. */ bool operator==(const CShaderParams& b) const { return m_Items == b.m_Items; } /** * Fast inequality comparison. */ bool operator!=(const CShaderParams& b) const { return m_Items != b.m_Items; } struct SItems { // Name/value pair typedef std::pair Item; // Sorted by name; no duplicated names std::vector items; size_t hash; void RecalcHash(); }; protected: SItems* m_Items; // interned value private: typedef boost::unordered_map > InternedItems_t; static InternedItems_t s_InternedItems; /** * Returns a pointer to an SItems equal to @p items. * The pointer will be valid forever, and the same pointer will be returned * for any subsequent requests for an equal items list. */ static SItems* GetInterned(const SItems& items); }; /** * Represents a mapping of name strings to value strings, for use with * \#if and \#ifdef and similar conditionals in shaders. * * Not thread-safe - must only be used from the main thread. */ class CShaderDefines : public CShaderParams { public: /** * Add a name and associated value to the map of defines. * If the name is already defined, its value will be replaced. */ void Add(const char* name, const char* value); /** * Return the value for the given name as an integer, or 0 if not defined. */ int GetInt(const char* name) const; }; /** * Represents a mapping of name strings to value CVector4Ds, for use with * uniforms in shaders. * * Not thread-safe - must only be used from the main thread. */ class CShaderUniforms : public CShaderParams { public: /** * Add a name and associated value to the map of uniforms. * If the name is already defined, its value will be replaced. */ void Add(const char* name, const CVector4D& value); /** * Return the value for the given name, or (0,0,0,0) if not defined. */ CVector4D GetVector(const char* name) const; /** * Bind the collection of uniforms onto the given shader. */ void BindUniforms(const CShaderProgramPtr& shader) const; }; // Add here the types of queries we can make in the renderer enum RENDER_QUERIES { - RQUERY_TIME + RQUERY_TIME, + RQUERY_WATER_TEX, + RQUERY_SKY_CUBE }; /** * Uniform values that need to be evaluated in the renderer. * * Not thread-safe - must only be used from the main thread. */ class CShaderRenderQueries { public: typedef std::pair RenderQuery; void Add(const char* name); size_t GetSize(); RenderQuery GetItem(size_t i); private: std::vector m_Items; }; enum DEFINE_CONDITION_TYPES { DCOND_DISTANCE }; class CShaderConditionalDefines { public: struct CondDefine { CStrIntern m_DefName; CStrIntern m_DefValue; int m_CondType; std::vector m_CondArgs; }; void Add(const char* defname, const char* defvalue, int type, std::vector &args); size_t GetSize(); CondDefine& GetItem(size_t i); private: std::vector m_Defines; }; #endif // INCLUDED_SHADERDEFINES Index: ps/trunk/source/renderer/SkyManager.cpp =================================================================== --- ps/trunk/source/renderer/SkyManager.cpp (revision 12642) +++ ps/trunk/source/renderer/SkyManager.cpp (revision 12643) @@ -1,266 +1,346 @@ /* Copyright (C) 2009 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ /* * Sky settings, texture management and rendering. */ #include "precompiled.h" #include #include "lib/timer.h" #include "lib/tex/tex.h" #include "lib/res/graphics/ogl_tex.h" #include "maths/MathUtil.h" #include "ps/CStr.h" #include "ps/CLogger.h" #include "ps/Loader.h" #include "ps/Filesystem.h" #include "renderer/SkyManager.h" #include "renderer/Renderer.h" #include "graphics/Camera.h" #include "graphics/LightEnv.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" /////////////////////////////////////////////////////////////////////////////////////////////// // SkyManager implementation /////////////////////////////////////////////////////////////////// // String names for each image, in order of the IMG_ constants const wchar_t* SkyManager::s_imageNames[numTextures] = { L"front", L"back", L"right", L"left", L"top" }; /////////////////////////////////////////////////////////////////// // Construction/Destruction SkyManager::SkyManager() { m_RenderSky = true; m_SkySet = L""; m_HorizonHeight = -150.0f; + + m_SkyCubeMap = 0; } /////////////////////////////////////////////////////////////////// // Load all sky textures void SkyManager::LoadSkyTextures() { for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i) { VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds"); CTextureProperties textureProps(path); textureProps.SetWrap(GL_CLAMP_TO_EDGE); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_SkyTexture[i] = texture; } + + glGenTextures(1, &m_SkyCubeMap); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap); + + int types[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + }; + + const wchar_t* images[numTextures+1] = { + L"front", + L"back", + L"right", + L"left", + L"top", + L"top" + }; + + for (size_t i = 0; i < numTextures+1; ++i) + { + VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds"); + + shared_ptr file; + size_t fileSize; + g_VFS->LoadFile(path, file, fileSize); + + Tex tex; + tex_decode(file, fileSize, &tex); + + tex_transform_to(&tex, (tex.flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)); + + u8* data = tex_get_data(&tex); + + if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y) + { + std::vector rotated(tex.dataSize); + + for (size_t y = 0; y < tex.h; ++y) + { + for (size_t x = 0; x < tex.w; ++x) + { + size_t invx = y, invy = tex.w-x-1; + + rotated[(y*tex.w + x) * 4 + 0] = data[(invy*tex.w + invx) * 4 + 0]; + rotated[(y*tex.w + x) * 4 + 1] = data[(invy*tex.w + invx) * 4 + 1]; + rotated[(y*tex.w + x) * 4 + 2] = data[(invy*tex.w + invx) * 4 + 2]; + rotated[(y*tex.w + x) * 4 + 3] = data[(invy*tex.w + invx) * 4 + 3]; + } + } + + glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]); + } + else + { + glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } + + tex_free(&tex); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, 0); } /////////////////////////////////////////////////////////////////// // Switch to a different sky set (while the game is running) void SkyManager::SetSkySet( const CStrW& newSet ) { if(newSet == m_SkySet) return; + + if (m_SkyCubeMap) + { + glDeleteTextures(1, &m_SkyCubeMap); + m_SkyCubeMap = 0; + } + m_SkySet = newSet; LoadSkyTextures(); } /////////////////////////////////////////////////////////////////// // Generate list of available skies std::vector SkyManager::GetSkySets() const { std::vector skies; // Find all subdirectories in art/textures/skies const VfsPath path(L"art/textures/skies/"); DirectoryNames subdirectories; if(g_VFS->GetDirectoryEntries(path, 0, &subdirectories) < 0) { LOGERROR(L"Error opening directory '%ls'", path.string().c_str()); return std::vector(1, GetSkySet()); // just return what we currently have } for(size_t i = 0; i < subdirectories.size(); i++) skies.push_back(subdirectories[i].string()); sort(skies.begin(), skies.end()); return skies; } /////////////////////////////////////////////////////////////////// // Render sky void SkyManager::RenderSky() { #if CONFIG2_GLES #warning TODO: implement SkyManager::RenderSky for GLES #else // Draw the sky as a small box around the camera position, with depth write enabled. // This will be done before anything else is drawn so we'll be overlapped by everything else. // Note: The coordinates for this were set up through a rather cumbersome trial-and-error // process - there might be a smarter way to do it, but this seems to work. // Do nothing unless SetSkySet was called if (m_SkySet.empty()) return; glDepthMask( GL_FALSE ); pglActiveTextureARB(GL_TEXTURE0_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Translate so we are at the camera in the X and Z directions, but // put the horizon at a fixed height regardless of camera Y const CCamera& camera = g_Renderer.GetViewCamera(); CVector3D pos = camera.m_Orientation.GetTranslation(); glTranslatef( pos.X, m_HorizonHeight, pos.Z ); // Rotate so that the "left" face, which contains the brightest part of each // skymap, is in the direction of the sun from our light environment glRotatef( 90.0f + RADTODEG(g_Renderer.GetLightEnv().GetRotation()), 0.0f, 1.0f, 0.0f ); // Distance to draw the faces at const float D = 2000.0; CShaderProgramPtr shader; CShaderTechniquePtr skytech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { skytech = g_Renderer.GetShaderManager().LoadEffect("sky_simple"); skytech->BeginPass(); shader = skytech->GetShader(); } // Front face (positive Z) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[FRONT]); else m_SkyTexture[FRONT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 0, 1 ); glVertex3f( -D, -D, +D ); glTexCoord2f( 1, 1 ); glVertex3f( +D, -D, +D ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, +D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, +D ); glEnd(); // Back face (negative Z) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[BACK]); else m_SkyTexture[BACK]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 1 ); glVertex3f( -D, -D, -D ); glTexCoord2f( 1, 0 ); glVertex3f( -D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 1 ); glVertex3f( +D, -D, -D ); glEnd(); // Right face (negative X) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[RIGHT]); else m_SkyTexture[RIGHT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 0, 1 ); glVertex3f( -D, -D, -D ); glTexCoord2f( 1, 1 ); glVertex3f( -D, -D, +D ); glTexCoord2f( 1, 0 ); glVertex3f( -D, +D, +D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, -D ); glEnd(); // Left face (positive X) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[LEFT]); else m_SkyTexture[LEFT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 1 ); glVertex3f( +D, -D, -D ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( +D, +D, +D ); glTexCoord2f( 0, 1 ); glVertex3f( +D, -D, +D ); glEnd(); // Top face (positive Y) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[TOP]); else m_SkyTexture[TOP]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, -D ); glTexCoord2f( 0, 1 ); glVertex3f( -D, +D, +D ); glTexCoord2f( 1, 1 ); glVertex3f( +D, +D, +D ); glEnd(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) skytech->EndPass(); glPopMatrix(); glDepthMask( GL_TRUE ); #endif } Index: ps/trunk/source/renderer/ModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/ModelRenderer.cpp (revision 12642) +++ ps/trunk/source/renderer/ModelRenderer.cpp (revision 12643) @@ -1,743 +1,758 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "lib/ogl.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" #include "ps/Profile.h" #include "graphics/Color.h" #include "graphics/LightEnv.h" #include "graphics/Material.h" #include "graphics/Model.h" #include "graphics/ModelDef.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "renderer/MikktspaceWrap.h" #include "renderer/ModelRenderer.h" #include "renderer/ModelVertexRenderer.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" +#include "renderer/SkyManager.h" +#include "renderer/WaterManager.h" #include #if ARCH_X86_X64 # include "lib/sysdep/arch/x86_x64/x86_x64.h" #endif /////////////////////////////////////////////////////////////////////////////////////////////// // ModelRenderer implementation #if ARCH_X86_X64 static bool g_EnableSSE = false; #endif void ModelRenderer::Init() { #if ARCH_X86_X64 if (x86_x64::Cap(x86_x64::CAP_SSE)) g_EnableSSE = true; #endif } // Helper function to copy object-space position and normal vectors into arrays. void ModelRenderer::CopyPositionAndNormals( const CModelDefPtr& mdef, const VertexArrayIterator& Position, const VertexArrayIterator& Normal) { size_t numVertices = mdef->GetNumVertices(); SModelVertex* vertices = mdef->GetVertices(); for(size_t j = 0; j < numVertices; ++j) { Position[j] = vertices[j].m_Coords; Normal[j] = vertices[j].m_Norm; } } // Helper function to transform position and normal vectors into world-space. void ModelRenderer::BuildPositionAndNormals( CModel* model, const VertexArrayIterator& Position, const VertexArrayIterator& Normal) { CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); SModelVertex* vertices=mdef->GetVertices(); if (model->IsSkinned()) { // boned model - calculate skinned vertex positions/normals // Avoid the noisy warnings that occur inside SkinPoint/SkinNormal in // some broken situations if (numVertices && vertices[0].m_Blend.m_Bone[0] == 0xff) { LOGERROR(L"Model %ls is boned with unboned animation", mdef->GetName().string().c_str()); return; } #if ARCH_X86_X64 if (g_EnableSSE) { CModelDef::SkinPointsAndNormals_SSE(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices()); } else #endif { CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices()); } } else { PROFILE( "software transform" ); // just copy regular positions, transform normals to world space const CMatrix3D& transform = model->GetTransform(); const CMatrix3D& invtransform = model->GetInvTransform(); for (size_t j=0; j& Normal, const VertexArrayIterator& Color) { PROFILE( "lighting vertices" ); CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); CColor shadingColor = model->GetShadingColor(); for (size_t j=0; j& newVertices) { MikkTSpace ms(mdef, newVertices); ms.generate(); } // Copy UV coordinates void ModelRenderer::BuildUV( const CModelDefPtr& mdef, const VertexArrayIterator& UV, int UVset) { size_t numVertices = mdef->GetNumVertices(); SModelVertex* vertices = mdef->GetVertices(); for (size_t j=0; j < numVertices; ++j) { UV[j][0] = vertices[j].m_UVs[UVset * 2]; UV[j][1] = 1.0-vertices[j].m_UVs[UVset * 2 + 1]; } } // Build default indices array. void ModelRenderer::BuildIndices( const CModelDefPtr& mdef, const VertexArrayIterator& Indices) { size_t idxidx = 0; SModelFace* faces = mdef->GetFaces(); for (size_t j = 0; j < mdef->GetNumFaces(); ++j) { SModelFace& face=faces[j]; Indices[idxidx++]=face.m_Verts[0]; Indices[idxidx++]=face.m_Verts[1]; Indices[idxidx++]=face.m_Verts[2]; } } /////////////////////////////////////////////////////////////////////////////////////////////// // ShaderModelRenderer implementation /** * Internal data of the ShaderModelRenderer. * * Separated into the source file to increase implementation hiding (and to * avoid some causes of recompiles). */ struct ShaderModelRendererInternals { ShaderModelRendererInternals(ShaderModelRenderer* r) : m_Renderer(r) { } /// Back-link to "our" renderer ShaderModelRenderer* m_Renderer; /// ModelVertexRenderer used for vertex transformations ModelVertexRendererPtr vertexRenderer; /// List of submitted models for rendering in this frame std::vector submissions; }; // Construction/Destruction ShaderModelRenderer::ShaderModelRenderer(ModelVertexRendererPtr vertexrenderer) { m = new ShaderModelRendererInternals(this); m->vertexRenderer = vertexrenderer; } ShaderModelRenderer::~ShaderModelRenderer() { delete m; } // Submit one model. void ShaderModelRenderer::Submit(CModel* model) { CModelDefPtr mdef = model->GetModelDef(); CModelRData* rdata = (CModelRData*)model->GetRenderData(); // Ensure model data is valid const void* key = m->vertexRenderer.get(); if (!rdata || rdata->GetKey() != key) { rdata = m->vertexRenderer->CreateModelData(key, model); model->SetRenderData(rdata); model->SetDirty(~0u); } m->submissions.push_back(model); } // Call update for all submitted models and enter the rendering phase void ShaderModelRenderer::PrepareModels() { for (size_t i = 0; i < m->submissions.size(); ++i) { CModel* model = m->submissions[i]; CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); m->vertexRenderer->UpdateModelData(model, rdata, rdata->m_UpdateFlags); rdata->m_UpdateFlags = 0; } } // Clear the submissions list void ShaderModelRenderer::EndFrame() { m->submissions.clear(); } // Helper structs for ShaderModelRenderer::Render(): struct SMRSortByDistItem { size_t techIdx; CModel* model; float dist; }; struct SMRBatchModel { bool operator()(CModel* a, CModel* b) { if (a->GetModelDef() < b->GetModelDef()) return true; if (b->GetModelDef() < a->GetModelDef()) return false; if (a->GetMaterial().GetDiffuseTexture() < b->GetMaterial().GetDiffuseTexture()) return true; if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture()) return false; return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms(); } }; struct SMRCompareSortByDistItem { bool operator()(const SMRSortByDistItem& a, const SMRSortByDistItem& b) { // Prefer items with greater distance, so we draw back-to-front return (a.dist > b.dist); // (Distances will almost always be distinct, so we don't need to bother // tie-breaking on modeldef/texture/etc) } }; struct SMRMaterialBucketKey { SMRMaterialBucketKey(CStrIntern effect, const CShaderDefines& defines) : effect(effect), defines(defines) { } CStrIntern effect; CShaderDefines defines; bool operator==(const SMRMaterialBucketKey& b) const { return (effect == b.effect && defines == b.defines); } private: SMRMaterialBucketKey& operator=(const SMRMaterialBucketKey&); }; struct SMRMaterialBucketKeyHash { size_t operator()(const SMRMaterialBucketKey& key) const { size_t hash = 0; boost::hash_combine(hash, key.effect.GetHash()); boost::hash_combine(hash, key.defines.GetHash()); return hash; } }; struct SMRTechBucket { CShaderTechniquePtr tech; CModel** models; size_t numModels; // Model list is stored as pointers, not as a std::vector, // so that sorting lists of this struct is fast }; struct SMRCompareTechBucket { bool operator()(const SMRTechBucket& a, const SMRTechBucket& b) { return a.tech < b.tech; } }; void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int flags) { if (m->submissions.empty()) return; CMatrix3D worldToCam; g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam); /* * Rendering approach: * * m->submissions contains the list of CModels to render. * * The data we need to render a model is: * - CShaderTechnique * - CTexture * - CShaderUniforms * - CModelDef (mesh data) * - CModel (model instance data) * * For efficient rendering, we need to batch the draw calls to minimise state changes. * (Uniform and texture changes are assumed to be cheaper than binding new mesh data, * and shader changes are assumed to be most expensive.) * First, group all models that share a technique to render them together. * Within those groups, sub-group by CModelDef. * Within those sub-groups, sub-sub-group by CTexture. * Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms. * * Alpha-blended models have to be sorted by distance from camera, * then we can batch as long as the order is preserved. * Non-alpha-blended models can be arbitrarily reordered to maximise batching. * * For each model, the CShaderTechnique is derived from: * - The current global 'context' defines * - The CModel's material's defines * - The CModel's material's shader effect name * * There are a smallish number of materials, and a smaller number of techniques. * * To minimise technique lookups, we first group models by material, * in 'materialBuckets' (a hash table). * * For each material bucket we then look up the appropriate shader technique. * If the technique requires sort-by-distance, the model is added to the * 'sortByDistItems' list with its computed distance. * Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms, * then the technique and model list is added to 'techBuckets'. * * 'techBuckets' is then sorted by technique, to improve batching when multiple * materials map onto the same technique. * * (Note that this isn't perfect batching: we don't sort across models in * multiple buckets that share a technique. In practice that shouldn't reduce * batching much (we rarely have one mesh used with multiple materials), * and it saves on copying and lets us sort smaller lists.) * * Extra tech buckets are added for the sorted-by-distance models without reordering. * Finally we render by looping over each tech bucket, then looping over the model * list in each, rebinding the GL state whenever it changes. */ typedef boost::unordered_map, SMRMaterialBucketKeyHash> MaterialBuckets_t; MaterialBuckets_t materialBuckets; { PROFILE3("bucketing by material"); for (size_t i = 0; i < m->submissions.size(); ++i) { CModel* model = m->submissions[i]; CShaderDefines defs = model->GetMaterial().GetShaderDefines(); CShaderConditionalDefines condefs = model->GetMaterial().GetConditionalDefines(); for (size_t j = 0; j < condefs.GetSize(); ++j) { CShaderConditionalDefines::CondDefine &item = condefs.GetItem(j); int type = item.m_CondType; switch (type) { case DCOND_DISTANCE: { CVector3D modelpos = model->GetTransform().GetTranslation(); float dist = worldToCam.Transform(modelpos).Z; float dmin = item.m_CondArgs[0]; float dmax = item.m_CondArgs[1]; if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax)) defs.Add(item.m_DefName.c_str(), item.m_DefValue.c_str()); break; } } } SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs); std::vector& bucketItems = materialBuckets[key]; bucketItems.push_back(model); } } std::vector sortByDistItems; std::vector sortByDistTechs; // indexed by sortByDistItems[i].techIdx // (which stores indexes instead of CShaderTechniquePtr directly // to avoid the shared_ptr copy cost when sorting; maybe it'd be better // if we just stored raw CShaderTechnique* and assumed the shader manager // will keep it alive long enough) std::vector techBuckets; { PROFILE3("processing material buckets"); for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it) { CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines); // Skip invalid techniques (e.g. from data file errors) if (!tech) continue; if (tech->GetSortByDistance()) { // Add the tech into a vector so we can index it // (There might be duplicates in this list, but that doesn't really matter) if (sortByDistTechs.empty() || sortByDistTechs.back() != tech) sortByDistTechs.push_back(tech); size_t techIdx = sortByDistTechs.size()-1; // Add each model into sortByDistItems for (size_t i = 0; i < it->second.size(); ++i) { SMRSortByDistItem itemWithDist; itemWithDist.techIdx = techIdx; CModel* model = it->second[i]; itemWithDist.model = model; CVector3D modelpos = model->GetTransform().GetTranslation(); itemWithDist.dist = worldToCam.Transform(modelpos).Z; sortByDistItems.push_back(itemWithDist); } } else { // Sort model list by modeldef+texture, for batching // TODO: This only sorts by base texture. While this is an OK approximation // for most cases (as related samplers are usually used together), it would be better // to take all the samplers into account when sorting here. std::sort(it->second.begin(), it->second.end(), SMRBatchModel()); // Add a tech bucket pointing at this model list SMRTechBucket techBucket = { tech, &it->second[0], it->second.size() }; techBuckets.push_back(techBucket); } } } { PROFILE3("sorting tech buckets"); // Sort by technique, for better batching std::sort(techBuckets.begin(), techBuckets.end(), SMRCompareTechBucket()); } // List of models corresponding to sortByDistItems[i].model // (This exists primarily because techBuckets wants a CModel**; // we could avoid the cost of copying into this list by adding // a stride length into techBuckets and not requiring contiguous CModel*s) std::vector sortByDistModels; if (!sortByDistItems.empty()) { { PROFILE3("sorting items by dist"); std::sort(sortByDistItems.begin(), sortByDistItems.end(), SMRCompareSortByDistItem()); } { PROFILE3("batching dist-sorted items"); sortByDistModels.reserve(sortByDistItems.size()); // Find runs of distance-sorted models that share a technique, // and create a new tech bucket for each run size_t start = 0; // start of current run size_t currentTechIdx = sortByDistItems[start].techIdx; for (size_t end = 0; end < sortByDistItems.size(); ++end) { sortByDistModels.push_back(sortByDistItems[end].model); size_t techIdx = sortByDistItems[end].techIdx; if (techIdx != currentTechIdx) { // Start of a new run - push the old run into a new tech bucket SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], end-start }; techBuckets.push_back(techBucket); start = end; currentTechIdx = techIdx; } } // Add the tech bucket for the final run SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size()-start }; techBuckets.push_back(techBucket); } } { PROFILE3("rendering bucketed submissions"); size_t idxTechStart = 0; // This vector keeps track of texture changes during rendering. It is kept outside the // loops to avoid excessive reallocations. The token allocation of 64 elements // should be plenty, though it is reallocated below (at a cost) if necessary. std::vector currentTexs; currentTexs.reserve(64); // texBindings holds the identifier bindings in the shader, which can no longer be defined // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to // keep track of when bindings need to be reevaluated. std::vector texBindings; texBindings.reserve(64); std::vector texBindingNames; texBindingNames.reserve(64); while (idxTechStart < techBuckets.size()) { CShaderTechniquePtr currentTech = techBuckets[idxTechStart].tech; // Find runs [idxTechStart, idxTechEnd) in techBuckets of the same technique size_t idxTechEnd; for (idxTechEnd = idxTechStart + 1; idxTechEnd < techBuckets.size(); ++idxTechEnd) { if (techBuckets[idxTechEnd].tech != currentTech) break; } // For each of the technique's passes, render all the models in this run for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) { currentTech->BeginPass(pass); const CShaderProgramPtr& shader = currentTech->GetShader(pass); int streamflags = shader->GetStreamFlags(); modifier->BeginPass(shader); m->vertexRenderer->BeginPass(streamflags); // When the shader technique changes, textures need to be // rebound, so ensure there are no remnants from the last pass. // (the vector size is set to 0, but memory is not freed) currentTexs.clear(); texBindings.clear(); texBindingNames.clear(); CModelDef* currentModeldef = NULL; CShaderUniforms currentStaticUniforms; for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) { CModel** models = techBuckets[idx].models; size_t numModels = techBuckets[idx].numModels; for (size_t i = 0; i < numModels; ++i) { CModel* model = models[i]; if (flags && !(model->GetFlags() & flags)) continue; CMaterial::SamplersVector samplers = model->GetMaterial().GetSamplers(); size_t samplersNum = samplers.size(); // make sure the vectors are the right virtual sizes, and also // reallocate if there are more samplers than expected. if (currentTexs.size() != samplersNum) { currentTexs.resize(samplersNum, NULL); texBindings.resize(samplersNum, CShaderProgram::Binding()); texBindingNames.resize(samplersNum, CStrIntern()); // ensure they are definitely empty std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding()); std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); } // bind the samplers to the shader for (size_t s = 0; s < samplersNum; ++s) { CMaterial::TextureSampler &samp = samplers[s]; CShaderProgram::Binding bind = texBindings[s]; // check that the handles are current // and reevaluate them if necessary if (texBindingNames[s] == samp.Name && bind.Active()) { bind = texBindings[s]; } else { bind = shader->GetTextureBinding(samp.Name.c_str()); texBindings[s] = bind; texBindingNames[s] = samp.Name; } // same with the actual sampler bindings CTexture* newTex = samp.Sampler.get(); if (bind.Active() && newTex != currentTexs[s]) { shader->BindTexture(bind, samp.Sampler->GetHandle()); currentTexs[s] = newTex; } } // Bind modeldef when it changes CModelDef* newModeldef = model->GetModelDef().get(); if (newModeldef != currentModeldef) { currentModeldef = newModeldef; m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); } // Bind all uniforms when any change CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); if (newStaticUniforms != currentStaticUniforms) { currentStaticUniforms = newStaticUniforms; currentStaticUniforms.BindUniforms(shader); } CShaderRenderQueries renderQueries = model->GetMaterial().GetRenderQueries(); for (size_t q = 0; q < renderQueries.GetSize(); q++) { CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); if (rq.first == RQUERY_TIME) { CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); if (binding.Active()) { double time = g_Renderer.GetTimeManager().GetGlobalTime(); shader->Uniform(binding, time, 0,0,0); } } + else if (rq.first == RQUERY_WATER_TEX) + { + WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + double time = WaterMgr->m_WaterTexTimer; + double period = 1.6; + int curTex = (int)(time*60/period) % 60; + + shader->BindTexture("waterTex", WaterMgr->m_NormalMap[curTex]); + } + else if (rq.first == RQUERY_SKY_CUBE) + { + shader->BindTexture("skyCube", g_Renderer.GetSkyManager()->GetSkyCube()); + } } modifier->PrepareModel(shader, model); CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); } } m->vertexRenderer->EndPass(streamflags); currentTech->EndPass(pass); } idxTechStart = idxTechEnd; } } } void ShaderModelRenderer::Filter(CModelFilter& filter, int passed, int flags) { for (size_t i = 0; i < m->submissions.size(); ++i) { CModel* model = m->submissions[i]; if (flags && !(model->GetFlags() & flags)) continue; if (filter.Filter(model)) model->SetFlags(model->GetFlags() | passed); else model->SetFlags(model->GetFlags() & ~passed); } } Index: ps/trunk/source/renderer/SkyManager.h =================================================================== --- ps/trunk/source/renderer/SkyManager.h (revision 12642) +++ ps/trunk/source/renderer/SkyManager.h (revision 12643) @@ -1,87 +1,93 @@ /* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ /* * Sky settings and texture management */ #ifndef INCLUDED_SKYMANAGER #define INCLUDED_SKYMANAGER #include "graphics/Texture.h" /** * Class SkyManager: Maintain sky settings and textures, and render the sky. */ class SkyManager { public: bool m_RenderSky; float m_HorizonHeight; public: SkyManager(); /** * RenderSky: Render the sky. */ void RenderSky(); /** * GetSkySet(): Return the currently selected sky set name. */ inline const CStrW& GetSkySet() const { return m_SkySet; } + + GLuint GetSkyCube() { + return m_SkyCubeMap; + } /** * GetSkySet(): Set the sky set name, potentially loading the textures. */ void SetSkySet(const CStrW& name); /** * Return a sorted list of available sky sets, in a form suitable * for passing to SetSkySet. */ std::vector GetSkySets() const; private: void LoadSkyTextures(); /// Name of current skyset (a directory within art/textures/skies) CStrW m_SkySet; // Indices into m_SkyTexture enum { FRONT, BACK, RIGHT, LEFT, TOP, numTextures }; // Sky textures CTexturePtr m_SkyTexture[numTextures]; + + GLuint m_SkyCubeMap; // Array of image names (defined in SkyManager.cpp), in the order of the IMG_ id's static const wchar_t* s_imageNames[numTextures]; }; #endif // INCLUDED_SKYMANAGER Index: ps/trunk/binaries/data/mods/public/maps/scenarios/reservoir.xml =================================================================== --- ps/trunk/binaries/data/mods/public/maps/scenarios/reservoir.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/scenarios/reservoir.xml (revision 12643) @@ -0,0 +1,416 @@ + + + + + standard + default + + + + + + + + default + + 20.459 + 150 + 8 + 0.45 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: ps/trunk/binaries/data/mods/public/art/materials/player_water.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/player_water.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/materials/player_water.xml (revision 12643) @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/art/materials/basic_trans_wind.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/basic_trans_wind.xml (revision 12642) +++ ps/trunk/binaries/data/mods/public/art/materials/basic_trans_wind.xml (revision 12643) @@ -1,9 +1,9 @@ - + Index: ps/trunk/binaries/data/mods/public/art/materials/waterfall.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/waterfall.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/materials/waterfall.xml (revision 12643) @@ -0,0 +1,10 @@ + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/art/materials/trans_wind.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/materials/trans_wind.xml (revision 12642) +++ ps/trunk/binaries/data/mods/public/art/materials/trans_wind.xml (revision 12643) @@ -1,6 +1,7 @@ - + + Index: ps/trunk/binaries/data/mods/public/art/textures/skins/temp/waterfall.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/skins/temp/waterfall.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/skins/temp/waterfall.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/skins/temp/waterfall.png (revision 12643) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/skins/temp/waterfall.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir.dae =================================================================== --- ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir.dae (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir.dae (revision 12643) @@ -0,0 +1,81 @@ + + + + + Blender User + Blender 2.62.0 r44136 + + 2012-07-16T20:19:23 + 2012-07-16T20:19:23 + + Z_UP + + + + + + 2.787381 2.816133 -1 2.78738 -1 -1 -1 -0.9999998 -1 -0.9999997 2.816134 -1 2.787381 2.816133 1 2.78738 -1.000001 1 -1 -0.9999997 1 -1 2.816133 1 2.78738 -0.8579376 -1 -1 -0.8579375 -1 2.78738 -0.8579383 1 -1 -0.8579374 1 2.787381 2.668627 -1 -0.9999997 2.668627 -1 2.787381 2.668626 1 -1 2.668627 1 2.636765 -1 -1 2.636765 2.816133 -1 2.636765 -1 1 2.636766 2.816133 1 2.636765 -0.8579376 -1 2.636765 -0.8579382 1 2.636765 2.668627 -1 2.636765 2.668626 1 -0.8408575 -0.9999999 -1 -0.840857 2.816134 -1 -0.8408578 -0.9999997 1 -0.8408572 2.816133 1 -0.8408575 -0.8579375 -1 -0.8408577 -0.8579375 1 -0.840857 2.668627 -1 -0.8408572 2.668627 1 -0.8408572 2.668627 -0.8500642 -0.8408577 -0.8579375 -0.8500642 2.636765 2.668626 -0.8500642 2.636765 -0.8579382 -0.8500642 + + + + + + + + + + 1 -8.39134e-7 2.98023e-7 -1 0 -1.19209e-7 1 -8.08163e-7 -1.78814e-7 1 -1.69016e-7 0 -1 0 0 -1 2.02041e-7 -1.3411e-7 -3.95741e-7 -1 -2.98023e-7 7.91481e-7 1 1.78814e-7 0 0 -1 0 0 1 0 0 -1 0 0 -1 0 0 1 0 0 1 -1.19976e-7 -1 0 -3.74536e-7 -1 0 0 1 1.78814e-7 7.49072e-7 1 1.78814e-7 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 1 -1.35213e-7 0 -1.37116e-7 -1 0 2.22813e-7 1 0 -1 2.02819e-7 0 0 0 1 + + + + + + + + + + 0.7059123 0.421577 0.6954652 0.421577 0.6954653 0.3278181 0.7059125 0.3278181 0.6954653 0.421577 0.7059125 0.421577 0.7059125 0.3278181 0.6954653 0.3278181 0.8181747 0.421577 0.8290222 0.421577 0.8290222 0.5153358 0.8181747 0.5153358 0.8181747 0.421577 0.558834 0.421577 0.558834 0.3278181 0.8181747 0.3278181 0.7059125 0.421577 0.9652531 0.421577 0.9652531 0.3278181 0.7059125 0.3278181 0.8181747 0.421577 0.8290222 0.421577 0.8290222 0.3278181 0.8181747 0.3278181 0.8269076 0.421577 0.8158317 0.421577 0.8158317 0.3278181 0.8269078 0.3278181 0.8269078 0.421577 0.8158317 0.421577 0.8158317 0.5153358 0.8269078 0.5153358 0.8269078 0.421577 0.8158317 0.421577 0.8158317 0.4282368 0.8269078 0.4282368 0.8158317 0.5153358 0.8269076 0.5153358 0.8269076 0.5219956 0.8158317 0.5219956 0.8158317 0.5067163 0.8269078 0.5067163 0.8269078 0.4998013 0.8158317 0.4998013 0.8269078 0.4282368 0.8158317 0.4282368 0.8158317 0.59356 0.8269078 0.59356 0.8158317 0.4998012 0.8269078 0.4998012 0.8269078 0.5067163 0.8158317 0.5067163 0.8158317 0.4282368 0.8269076 0.4282368 0.8269078 0.59356 0.8158317 0.59356 0.8158317 0.421577 0.5600902 0.421577 0.5600902 0.3278181 0.8158317 0.3278181 0.7071685 0.421577 0.6954652 0.421577 0.6954652 0.3278181 0.7071685 0.3278181 0.8158317 0.421577 0.5600902 0.421577 0.5600902 0.5153358 0.8158317 0.5153358 0.7071685 0.421577 0.6954653 0.421577 0.6954653 0.5153358 0.7071685 0.5153358 0.8158317 0.421577 0.5600902 0.421577 0.5600902 0.4282369 0.8158317 0.4282368 0.7071685 0.421577 0.6954652 0.421577 0.6954652 0.4282369 0.7071685 0.4282369 0.8425436 0.421577 0.8542467 0.421577 0.8542467 0.4282369 0.8425436 0.4282369 0.7071685 0.421577 0.9629101 0.421577 0.9629099 0.4282368 0.7071685 0.4282369 0.8158317 0.4998013 0.5600902 0.4998013 0.5600902 0.5067163 0.8158317 0.5067163 0.7071685 0.4998013 0.6954653 0.4998013 0.6954653 0.5067163 0.7071685 0.5067163 0.8158317 0.4282368 0.5600902 0.4282369 0.5600902 0.5935602 0.8158317 0.59356 0.7071685 0.4282369 0.6954652 0.4282369 0.6954653 0.5935602 0.7071685 0.5935602 0.6954653 0.4998013 0.7071685 0.4998013 0.7071685 0.5067163 0.6954653 0.5067163 0.7071685 0.4998013 0.9629101 0.4998012 0.9629101 0.5067163 0.7071685 0.5067163 0.8425436 0.4282369 0.8542467 0.4282369 0.8542469 0.59356 0.8425436 0.59356 0.8181747 0.421577 0.558834 0.421577 0.558834 0.334847 0.8181747 0.334847 0.8158317 0.421577 0.5600902 0.421577 0.5600902 0.334847 0.8158317 0.334847 0.7071685 0.421577 0.9629099 0.421577 0.9629099 0.334847 0.7071685 0.334847 0.7059123 0.421577 0.965253 0.421577 0.965253 0.334847 0.7059123 0.334847 0.7071685 0.4282369 0.9629099 0.4282368 0.9629101 0.59356 0.7071685 0.59356 + + + + + + + + + + + + + + + 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 +

10 0 0 5 0 1 1 0 2 8 0 3 6 1 4 11 1 5 9 1 6 2 1 7 12 2 8 0 2 9 4 2 10 14 2 11 14 3 12 10 3 13 8 3 14 12 3 15 11 4 16 15 4 17 13 4 18 9 4 19 15 5 20 7 5 21 3 5 22 13 5 23 5 6 24 18 6 25 16 6 26 1 6 27 0 7 28 17 7 29 19 7 30 4 7 31 1 8 32 16 8 33 20 8 34 8 8 35 18 9 36 5 9 37 10 9 38 21 9 39 17 10 40 0 10 41 12 10 42 22 10 43 8 11 44 20 11 45 22 11 46 12 11 47 23 12 48 14 12 49 4 12 50 19 12 51 21 13 52 10 13 53 14 13 54 23 13 55 18 14 56 26 14 57 24 14 58 16 14 59 26 15 60 6 15 61 2 15 62 24 15 63 17 16 64 25 16 65 27 16 66 19 16 67 25 17 68 3 17 69 7 17 70 27 17 71 16 18 72 24 18 73 28 18 74 20 18 75 24 19 76 2 19 77 9 19 78 28 19 79 6 20 80 26 20 81 29 20 82 11 20 83 26 21 84 18 21 85 21 21 86 29 21 87 22 22 88 30 22 89 25 22 90 17 22 91 30 23 92 13 23 93 3 23 94 25 23 95 20 24 96 28 24 97 30 24 98 22 24 99 28 25 100 9 25 101 13 25 102 30 25 103 15 26 104 31 26 105 27 26 106 7 26 107 31 27 108 23 27 109 19 27 110 27 27 111 11 28 112 29 28 113 31 28 114 15 28 115 31 29 116 29 29 117 33 29 118 32 29 119 23 30 120 31 30 121 32 30 122 34 30 123 29 31 124 21 31 125 35 31 126 33 31 127 21 32 128 23 32 129 34 32 130 35 32 131 33 33 132 35 33 133 34 33 134 32 33 135

+
+
+ 1 +
+
+ + + + 0 0 0.9679919 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 1 1 1 + + + 0.8951757 0.8192524 0.6654637 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 1 1 1 + + + + + + + +
\ No newline at end of file Index: ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir-water.dae =================================================================== --- ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir-water.dae (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/meshes/test/reservoir-water.dae (revision 12643) @@ -0,0 +1,74 @@ + + + + + Blender User + Blender 2.62.0 r44136 + + 2012-07-16T20:25:29 + 2012-07-16T20:25:29 + + Z_UP + + + + + + 1 1 0 1 -1 0 -1 -0.9999998 0 -0.9999997 1 0 + + + + + + + + + + 0 0 1 + + + + + + + + + + 0 0 1 0 1 1 0 1 + + + + + + + + + + + + + + + 4 +

0 0 0 3 0 1 2 0 2 1 0 3

+
+
+ 1 +
+
+ + + + 0.9108683 0.8981681 1.596016 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 1.783521 1.783521 1.783521 + + + + + + + +
\ No newline at end of file Index: ps/trunk/binaries/data/mods/public/art/meshes/test/waterfall.dae =================================================================== --- ps/trunk/binaries/data/mods/public/art/meshes/test/waterfall.dae (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/meshes/test/waterfall.dae (revision 12643) @@ -0,0 +1,74 @@ + + + + + Blender User + Blender 2.63.0 r46461 + + 2012-09-08T19:28:50 + 2012-09-08T19:28:50 + + Z_UP + + + + + + 0.8558017 -0.4922109 4.890604 -0.9705614 -0.4922109 4.890604 0.5212568 1.536574 4.452951 -0.6775384 1.536574 4.452951 0.6019558 2.421539 3.47628 -0.6749517 2.421539 3.47628 0.5327125 2.841524 2.204052 -0.6443323 2.841524 2.204052 0.4924808 3.132735 0.8966158 -0.6753391 3.132735 0.8966158 0.4360746 3.211275 -0.04431569 -0.6425524 3.211275 -0.04431569 + + + + + + + + + + 0 0.2108523 0.9775078 0 0.2108523 0.9775078 0 0.4917448 0.8707236 0 0.4878079 0.8729209 0 0.8643758 0.5027924 0 0.8631855 0.5048372 0 0.963683 0.2670064 0 0.9640187 0.2657552 0 0.9882809 0.152562 0 0.988525 0.1508835 0 0.9965209 0.0831629 0 0.9965209 0.0831629 + + + + + + + + + + 0.9776521 0.9974767 0.0151689 1 0.004231333 0.7716285 0.926613 0.7650349 0.00573486 0.520321 0.9632181 0.5156414 0.926613 0.7650349 0.004231333 0.7716285 0.02666038 0.3325256 0.9900883 0.3299684 0.9632181 0.5156414 0.00573486 0.520321 0.01693361 0.16259 0.9619107 0.1552892 0.9900883 0.3299684 0.02666038 0.3325256 0.0151689 0.005099952 0.9552896 0.001907348 0.9619107 0.1552892 0.01693361 0.16259 + + + + + + + + + + + + + + + 4 4 4 4 4 +

1 0 0 0 1 1 2 2 2 3 3 3 4 4 4 5 5 5 3 3 6 2 2 7 6 6 8 7 7 9 5 5 10 4 4 11 8 8 12 9 9 13 7 7 14 6 6 15 10 10 16 11 11 17 9 9 18 8 8 19

+
+
+ 1 +
+
+ + + + 0 0 0 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 2 2 2 + + + + + + + +
\ No newline at end of file Index: ps/trunk/binaries/data/mods/public/art/meshes/test/waterplane.dae =================================================================== --- ps/trunk/binaries/data/mods/public/art/meshes/test/waterplane.dae (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/meshes/test/waterplane.dae (revision 12643) @@ -0,0 +1,74 @@ + + + + + Blender User + Blender 2.62.0 r44136 + + 2012-09-01T16:37:35 + 2012-09-01T16:37:35 + + Z_UP + + + + + + 1 1 0 1 -1 0 -1 -2.325905 0 -0.9999997 1 0 2.686735 -2.324057 0 2.686735 8.651491 0 + + + + + + + + + + 0 0 1 0 0 1 + + + + + + + + + + 0.4590111 2.071086 1 2.072745 0.9972401 2.972384 0.4573514 2.612075 0.4590111 2.071086 0.4573514 2.612075 0 2.968825 0.009108066 0 + + + + + + + + + + + + + + + 4 4 +

0 0 0 3 0 1 2 0 2 1 0 3 0 1 4 1 1 5 4 1 6 5 1 7

+
+
+ 1 +
+
+ + + + 0.9108683 0.8981681 1.596016 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 1.783521 1.783521 1.783521 + + + + + + + +
\ No newline at end of file Index: ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir_water.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir_water.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir_water.xml (revision 12643) @@ -0,0 +1,16 @@ + + + + + + + test/reservoir-water.dae + + + + + + + player_water.xml + + Index: ps/trunk/binaries/data/mods/public/art/actors/temp/water_plane.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/actors/temp/water_plane.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/actors/temp/water_plane.xml (revision 12643) @@ -0,0 +1,16 @@ + + + + + + + test/waterplane.dae + + + + + + + player_water.xml + + Index: ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/actors/temp/reservoir.xml (revision 12643) @@ -0,0 +1,19 @@ + + + + + + + + + test/reservoir.dae + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/art/actors/temp/waterfall.xml =================================================================== --- ps/trunk/binaries/data/mods/public/art/actors/temp/waterfall.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/actors/temp/waterfall.xml (revision 12643) @@ -0,0 +1,16 @@ + + + + + + + test/waterfall.dae + + + + + + + waterfall.xml + + Index: ps/trunk/binaries/data/mods/public/shaders/effects/model_waterfall.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/model_waterfall.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/effects/model_waterfall.xml (revision 12643) @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/shaders/effects/model_water.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/model_water.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/effects/model_water.xml (revision 12643) @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.xml (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.xml (revision 12643) @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 12643) @@ -0,0 +1,82 @@ +#version 120 + +uniform sampler2D baseTex; +uniform sampler2D losTex; + + +#if USE_SHADOW + #if USE_SHADOW_SAMPLER + uniform sampler2DShadow shadowTex; + #if USE_SHADOW_PCF + uniform vec4 shadowScale; + #endif + #else + uniform sampler2D shadowTex; + #endif +#endif + +uniform vec3 shadingColor; +uniform vec3 ambient; +uniform vec3 sunColor; +uniform vec3 sunDir; +uniform vec3 cameraPos; + + +uniform float specularPower; +uniform vec3 specularColor; + + +varying vec4 v_tex; +varying vec4 v_shadow; +varying vec2 v_los; +varying vec3 v_half; +varying vec3 v_normal; + +varying vec3 v_lighting; + +float get_shadow() +{ + #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS + #if USE_SHADOW_SAMPLER + #if USE_SHADOW_PCF + vec2 offset = fract(v_shadow.xy - 0.5); + vec4 size = vec4(offset + 1.0, 2.0 - offset); + vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw; + return (1.0/9.0)*dot(size.zxzx*size.wwyy, + vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r, + shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r, + shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r, + shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r)); + #else + return shadow2D(shadowTex, v_shadow.xyz).r; + #endif + #else + if (v_shadow.z >= 1.0) + return 1.0; + return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); + #endif + #else + return 1.0; + #endif +} + + +void main() +{ + vec4 texdiffuse = textureGrad(baseTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); + + vec3 specular = sunColor * specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower); + + vec3 color = (texdiffuse.rgb * v_lighting + specular) * get_shadow(); + color += texdiffuse.rgb * ambient; + + #if !IGNORE_LOS + float los = texture2D(losTex, v_los).a; + los = los < 0.03 ? 0.0 : los; + color *= los; + #endif + + gl_FragColor.rgb = color; + gl_FragColor.a = texdiffuse.a; +} + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 12643) @@ -0,0 +1,151 @@ +#version 120 + +uniform sampler2D baseTex; +uniform sampler2D losTex; +uniform sampler2D aoTex; +uniform sampler2D normTex; +uniform sampler2D specTex; + +uniform sampler2D waterTex; +uniform samplerCube skyCube; + +#if USE_SHADOW + #if USE_SHADOW_SAMPLER + uniform sampler2DShadow shadowTex; + #if USE_SHADOW_PCF + uniform vec4 shadowScale; + #endif + #else + uniform sampler2D shadowTex; + #endif +#endif + +#if USE_OBJECTCOLOR + uniform vec3 objectColor; +#else +#if USE_PLAYERCOLOR + uniform vec3 playerColor; +#endif +#endif + +uniform vec3 shadingColor; +uniform vec3 ambient; +uniform vec3 sunColor; +uniform vec3 sunDir; +uniform vec3 cameraPos; + + +uniform float shininess; +uniform float specularStrength; +uniform float waviness; +uniform vec3 waterTint; +uniform float murkiness; +uniform vec3 reflectionTint; +uniform float reflectionTintStrength; + + +float waterDepth = 4.0; +float fullDepth = 5.0; // Depth at which to use full murkiness (shallower water will be clearer) + + +varying vec4 worldPos; +varying vec4 v_tex; +varying vec4 v_shadow; +varying vec2 v_los; + + +float get_shadow(vec4 coords) +{ + #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS + #if USE_SHADOW_SAMPLER + #if USE_SHADOW_PCF + vec2 offset = fract(coords.xy - 0.5); + vec4 size = vec4(offset + 1.0, 2.0 - offset); + vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (coords.xy - offset).xyxy) * shadowScale.zwzw; + return (1.0/9.0)*dot(size.zxzx*size.wwyy, + vec4(shadow2D(shadowTex, vec3(weight.zw, coords.z)).r, + shadow2D(shadowTex, vec3(weight.xw, coords.z)).r, + shadow2D(shadowTex, vec3(weight.zy, coords.z)).r, + shadow2D(shadowTex, vec3(weight.xy, coords.z)).r)); + #else + return shadow2D(shadowTex, coords.xyz).r; + #endif + #else + if (coords.z >= 1.0) + return 1.0; + return (coords.z <= texture2D(shadowTex, coords.xy).x ? 1.0 : 0.0); + #endif + #else + return 1.0; + #endif +} + + +void main() +{ + vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye) + float ndotl, ndoth, ndotv; + float fresnel; + float t; // Temporary variable + vec2 reflCoords, refrCoords; + vec3 reflColor, refrColor, specular; + float losMod; + + vec4 wtex = textureGrad(waterTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); + + n = normalize(wtex.xzy - vec3(0.5, 0.5, 0.5)); + l = -sunDir; + v = normalize(cameraPos - worldPos.xyz); + h = normalize(l + v); + + ndotl = dot(n, l); + ndoth = dot(n, h); + ndotv = dot(n, v); + + fresnel = pow(1.0 - ndotv, 0.8); // A rather random Fresnel approximation + + //refrCoords = (0.5*gl_TexCoord[2].xy - 0.8*waviness*n.xz) / gl_TexCoord[2].w + 0.5; // Unbias texture coords + //reflCoords = (0.5*gl_TexCoord[1].xy + waviness*n.xz) / gl_TexCoord[1].w + 0.5; // Unbias texture coords + + //vec3 dir = normalize(v + vec3(waviness*n.x, 0.0, waviness*n.z)); + + vec3 eye = reflect(v, n); + + vec3 tex = textureCube(skyCube, eye).rgb; + + reflColor = mix(tex, sunColor * reflectionTint, + reflectionTintStrength); + + //waterDepth = 4.0 + 2.0 * dot(abs(v_tex.zw - 0.5), vec2(0.5)); + waterDepth = 4.0; + + //refrColor = (0.5 + 0.5*ndotl) * mix(texture2D(refractionMap, refrCoords).rgb, sunColor * tint, + refrColor = (0.5 + 0.5*ndotl) * mix(vec3(0.3), sunColor * waterTint, + murkiness * clamp(waterDepth / fullDepth, 0.0, 1.0)); // Murkiness and tint at this pixel (tweaked based on lighting and depth) + + specular = pow(max(0.0, ndoth), shininess) * sunColor * specularStrength; + + losMod = texture2D(losTex, v_los).a; + + //losMod = texture2D(losMap, gl_TexCoord[3].st).a; + +#if USE_SHADOW + float shadow = get_shadow(vec4(v_shadow.xy - 8*waviness*n.xz, v_shadow.zw)); + float fresShadow = mix(fresnel, fresnel*shadow, dot(sunColor, vec3(0.16666))); +#else + float fresShadow = fresnel; +#endif + + vec3 colour = mix(refrColor + 0.3*specular, reflColor + specular, fresShadow); + + gl_FragColor.rgb = colour * losMod; + + + //gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod; + + // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it + // become opaque faster at lower view angles so we can't look "underneath" the water plane) + t = 18.0 * max(0.0, 0.7 - v.y); + gl_FragColor.a = 0.15 * waterDepth * (1.2 + t + fresnel); +} + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (revision 12643) @@ -0,0 +1,64 @@ +#if USE_GPU_SKINNING +// Skinning requires GLSL 1.30 for ivec4 vertex attributes +#version 130 +#else +#version 120 +#endif + +uniform mat4 transform; +uniform vec3 cameraPos; +uniform vec3 sunDir; +uniform vec3 sunColor; +uniform vec2 losTransform; +uniform mat4 shadowTransform; +uniform mat4 instancingTransform; + +uniform float sim_time; +uniform vec2 translation; + +#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + uniform vec4 shadowScale; +#endif + + +attribute vec3 a_vertex; +attribute vec3 a_normal; +attribute vec2 a_uv0; + + +varying vec4 worldPos; +varying vec4 v_tex; +varying vec4 v_shadow; +varying vec2 v_los; +varying vec3 v_half; +varying vec3 v_normal; + +varying vec3 v_lighting; + + +void main() +{ + worldPos = instancingTransform * vec4(a_vertex, 1.0); + + v_tex.xy = a_uv0 + sim_time * translation; + + #if USE_SHADOW + v_shadow = shadowTransform * worldPos; + #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + v_shadow.xy *= shadowScale.xy; + #endif + #endif + + v_los = worldPos.xz * losTransform.x + losTransform.y; + + vec3 eyeVec = cameraPos.xyz - worldPos.xyz; + vec3 sunVec = -sunDir; + v_half = normalize(sunVec + normalize(eyeVec)); + + mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); + v_normal = normalMatrix * a_normal; + v_lighting = max(0.0, dot(v_normal, -sunDir)) * sunColor; + + gl_Position = transform * worldPos; +} + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 12642) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 12643) @@ -1,179 +1,179 @@ #if USE_GPU_SKINNING // Skinning requires GLSL 1.30 for ivec4 vertex attributes #version 130 #else #version 120 #endif uniform mat4 transform; uniform vec3 cameraPos; uniform vec3 sunDir; uniform vec3 sunColor; uniform vec2 losTransform; uniform mat4 shadowTransform; uniform mat4 instancingTransform; #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF uniform vec4 shadowScale; #endif #if USE_WIND - uniform vec4 time; + uniform vec4 sim_time; uniform vec4 windData; #endif varying vec4 v_lighting; varying vec2 v_tex; varying vec2 v_los; #if USE_SHADOW varying vec4 v_shadow; #endif #if USE_INSTANCING && USE_AO varying vec2 v_tex2; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP varying vec4 v_normal; #if USE_INSTANCING && (USE_NORMAL_MAP || USE_PARALLAX_MAP) varying vec4 v_tangent; //varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #if USE_INSTANCING && USE_PARALLAX_MAP varying vec3 v_eyeVec; #endif #endif attribute vec3 a_vertex; attribute vec3 a_normal; #if USE_INSTANCING attribute vec4 a_tangent; #endif attribute vec2 a_uv0; attribute vec2 a_uv1; #if USE_GPU_SKINNING const int MAX_INFLUENCES = 4; const int MAX_BONES = 64; uniform mat4 skinBlendMatrices[MAX_BONES]; attribute ivec4 a_skinJoints; attribute vec4 a_skinWeights; #endif vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); return tri * tri *(3.0 - 2.0 * tri); } void main() { #if USE_GPU_SKINNING vec3 p = vec3(0.0); vec3 n = vec3(0.0); for (int i = 0; i < MAX_INFLUENCES; ++i) { int joint = a_skinJoints[i]; if (joint != 0xff) { mat4 m = skinBlendMatrices[joint]; p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i]; n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; } } vec4 position = instancingTransform * vec4(p, 1.0); vec3 normal = mat3(instancingTransform) * normalize(n); #else #if USE_INSTANCING vec4 position = instancingTransform * vec4(a_vertex, 1.0); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); vec3 normal = normalMatrix * a_normal; #if (USE_NORMAL_MAP || USE_PARALLAX_MAP) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else vec4 position = vec4(a_vertex, 1.0); vec3 normal = a_normal; #endif #endif #if USE_WIND vec2 wind = windData.xy; // fractional part of model position, clamped to >.4 vec4 modelPos = instancingTransform[3]; modelPos = fract(modelPos); modelPos = clamp(modelPos, 0.4, 1); // crude measure of wind intensity float abswind = abs(wind.x) + abs(wind.y); vec4 cosVec; // these determine the speed of the wind's "cosine" waves. - cosVec.x = time.x * modelPos[0] + position.x; - cosVec.y = time.x * modelPos[2] / 3 + instancingTransform[3][0]; - cosVec.z = time.x * abswind / 4 + position.z; + cosVec.x = sim_time.x * modelPos[0] + position.x; + cosVec.y = sim_time.x * modelPos[2] / 3 + instancingTransform[3][0]; + cosVec.z = sim_time.x * abswind / 4 + position.z; // calculate "cosines" in parallel, using a smoothed triangle wave cosVec = fakeCos(cosVec); float limit = clamp((a_vertex.x * a_vertex.z * a_vertex.y) / 3000, 0, 0.2); float diff = cosVec.x * limit; float diff2 = cosVec.y * clamp(a_vertex.y / 60, 0, 0.25); // fluttering of model parts based on distance from model center (ie longer branches) position.xyz += cosVec.z * limit * clamp(abswind, 1.2, 1.7); // swaying of trunk based on distance from ground (higher parts sway more) position.xz += diff + diff2 * wind; #endif gl_Position = transform * position; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP v_normal.xyz = normal; #if USE_INSTANCING && (USE_NORMAL_MAP || USE_PARALLAX_MAP) v_tangent.xyz = tangent; vec3 bitangent = cross(v_normal.xyz, v_tangent.xyz) * a_tangent.w; v_normal.w = bitangent.x; v_tangent.w = bitangent.y; v_lighting.w = bitangent.z; #endif #if USE_SPECULAR || USE_SPECULAR_MAP || USE_PARALLAX_MAP vec3 eyeVec = cameraPos.xyz - position.xyz; #if USE_SPECULAR || USE_SPECULAR_MAP vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); #endif #if USE_INSTANCING && USE_PARALLAX_MAP v_eyeVec = eyeVec; #endif #endif #endif v_lighting.xyz = max(0.0, dot(normal, -sunDir)) * sunColor; v_tex = a_uv0; #if USE_INSTANCING && USE_AO v_tex2 = a_uv1; #endif #if USE_SHADOW v_shadow = shadowTransform * position; #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF v_shadow.xy *= shadowScale.xy; #endif #endif v_los = position.xz * losTransform.x + losTransform.y; }