Newer
Older
/**
* @file llshadermgr.cpp
* @brief Shader manager implementation.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llshadermgr.h"
#include "llrender.h"
// Lots of STL stuff in here, using namespace std to keep things more readable
using std::vector;
using std::pair;
using std::make_pair;
using std::string;
LLShaderMgr * LLShaderMgr::sInstance = NULL;
LLShaderMgr::LLShaderMgr()
{
}
LLShaderMgr::~LLShaderMgr()
{
}
// static
LLShaderMgr * LLShaderMgr::instance()
{
if(NULL == sInstance)
{
LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL;
}
}
BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
llassert_always(shader != NULL);
LLShaderFeatures *features = & shader->mFeatures;
if (features->attachNothing)
{
return TRUE;
}
//////////////////////////////////////
// Attach Vertex Shader Features First
//////////////////////////////////////
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->calculatesAtmospherics)
{
if (features->hasWaterFog)
{
if (!shader->attachVertexObject("windlight/atmosphericsVarsWaterV.glsl"))
else if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl"))
{
return FALSE;
}
}
if (features->calculatesLighting || features->calculatesAtmospherics)
{
if (!shader->attachVertexObject("windlight/atmosphericsHelpersV.glsl"))
{
return FALSE;
}
}
if (features->calculatesLighting)
{
if (features->isSpecular)
{
if (!shader->attachVertexObject("lighting/lightFuncSpecularV.glsl"))
{
return FALSE;
}
if (!features->isAlphaLighting)
{
if (!shader->attachVertexObject("lighting/sumLightsSpecularV.glsl"))
if (!shader->attachVertexObject("lighting/lightSpecularV.glsl"))
if (!shader->attachVertexObject("lighting/lightFuncV.glsl"))
{
return FALSE;
}
if (!features->isAlphaLighting)
{
if (!shader->attachVertexObject("lighting/sumLightsV.glsl"))
if (!shader->attachVertexObject("lighting/lightV.glsl"))
{
return FALSE;
}
}
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->calculatesAtmospherics)
{
if (!shader->attachVertexObject("windlight/atmosphericsFuncs.glsl")) {
return FALSE;
}
if (!shader->attachVertexObject("windlight/atmosphericsV.glsl"))
{
return FALSE;
}
}
if (features->hasSkinning)
{
if (!shader->attachVertexObject("avatar/avatarSkinV.glsl"))
{
return FALSE;
}
}
if (features->hasObjectSkinning)
{
if (!shader->attachVertexObject("avatar/objectSkinV.glsl"))
{
return FALSE;
}
}
///////////////////////////////////////
// Attach Fragment Shader Features Next
///////////////////////////////////////
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if(features->calculatesAtmospherics)
{
if (features->hasWaterFog)
{
if (!shader->attachFragmentObject("windlight/atmosphericsVarsWaterF.glsl"))
else if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl"))
if (features->calculatesLighting || features->calculatesAtmospherics)
if (!shader->attachFragmentObject("windlight/atmosphericsHelpersF.glsl"))
Graham Linden graham@lindenlab.com
committed
// we want this BEFORE shadows and AO because those facilities use pos/norm access
Graham Linden
committed
if (features->isDeferred)
if (!shader->attachFragmentObject("deferred/deferredUtil.glsl"))
if (features->hasShadows)
if (!shader->attachFragmentObject("deferred/shadowUtil.glsl"))
if (features->hasAmbientOcclusion)
if (!shader->attachFragmentObject("deferred/aoUtil.glsl"))
if (!shader->attachFragmentObject("deferred/indirect.glsl"))
{
return FALSE;
}
}
if (features->hasGamma)
{
if (!shader->attachFragmentObject("windlight/gammaF.glsl"))
{
return FALSE;
}
}
if (features->hasSrgb)
{
if (!shader->attachFragmentObject("environment/srgbF.glsl"))
Graham Linden graham@lindenlab.com
committed
if (features->encodesNormal)
if (!shader->attachFragmentObject("environment/encodeNormF.glsl"))
{
return FALSE;
}
}
if (features->hasAtmospherics)
{
if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) {
return FALSE;
}
if (!shader->attachFragmentObject("windlight/atmosphericsF.glsl"))
{
return FALSE;
}
}
if (features->hasTransport)
{
if (!shader->attachFragmentObject("windlight/transportF.glsl"))
{
return FALSE;
}
// Test hasFullbright and hasShiny and attach fullbright and
// fullbright shiny atmos transport if we split them out.
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->hasWaterFog)
{
if (!shader->attachFragmentObject("environment/waterFogF.glsl"))
{
return FALSE;
}
}
if (features->hasLighting)
{
if (features->hasWaterFog)
{
if (features->disableTextureIndex)
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskF.glsl"))
if (!shader->attachFragmentObject("lighting/lightWaterF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else
{
if (features->disableTextureIndex)
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl"))
if (!shader->attachFragmentObject("lighting/lightF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
else if (features->isFullbright)
{
if (features->isShiny && features->hasWaterFog)
{
if (features->disableTextureIndex)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightFullbrightShinyWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else if (features->hasWaterFog)
{
if (features->disableTextureIndex)
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl"))
else if (!shader->attachFragmentObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightWaterAlphaMaskF.glsl"))
else if (!shader->attachFragmentObject("lighting/lightFullbrightWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else if (features->isShiny)
{
if (features->disableTextureIndex)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightShinyNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightFullbrightShinyF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else
{
if (features->disableTextureIndex)
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl"))
if (!shader->attachFragmentObject("lighting/lightFullbrightNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachFragmentObject("lighting/lightFullbrightAlphaMaskF.glsl"))
if (!shader->attachFragmentObject("lighting/lightFullbrightF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
else if (features->isShiny)
{
if (features->hasWaterFog)
{
if (features->disableTextureIndex)
{
if (!shader->attachFragmentObject("lighting/lightShinyWaterNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightShinyWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else
{
if (features->disableTextureIndex)
{
if (!shader->attachFragmentObject("lighting/lightShinyNonIndexedF.glsl"))
if (!shader->attachFragmentObject("lighting/lightShinyF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
if (features->mIndexedTextureChannels <= 1)
{
if (!shader->attachVertexObject("objects/nonindexedTextureV.glsl"))
if (!shader->attachVertexObject("objects/indexedTextureV.glsl"))
{
return FALSE;
}
}
return TRUE;
}
//============================================================================
// Load Shader
std::string res;
//get log length
GLint length;
glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &length);
if (length > 0)
{
//the log could be any size, so allocate appropriately
GLchar* log = new GLchar[length];
glGetShaderInfoLog(ret, length, &length, log);
res = std::string((char *)log);
delete[] log;
}
return res;
static std::string get_program_log(GLuint ret)
{
std::string res;
//get log length
GLint length;
glGetProgramiv(ret, GL_INFO_LOG_LENGTH, &length);
if (length > 0)
{
//the log could be any size, so allocate appropriately
GLchar* log = new GLchar[length];
glGetProgramInfoLog(ret, length, &length, log);
res = std::string((char*)log);
delete[] log;
}
return res;
}
void LLShaderMgr::dumpShaderSource(U32 shader_code_count, GLchar** shader_code_text)
char num_str[16]; // U32 = max 10 digits
LL_SHADER_LOADING_WARNS() << "\n";
Michael Pohoreski (Ptolemy Linden)
committed
for (U32 i = 0; i < shader_code_count; i++)
snprintf(num_str, sizeof(num_str), "%4d: ", i+1);
std::string line_number(num_str);
LL_CONT << line_number << shader_code_text[i];
void LLShaderMgr::dumpObjectLog(bool is_program, GLuint ret, BOOL warns, const std::string& filename)
std::string log = is_program ? get_program_log(ret) : get_shader_log(ret);
std::string fname = filename;
if (filename.empty())
{
fname = "unknown shader file";
}
LL_SHADER_LOADING_WARNS() << "Shader loading from " << fname << LL_ENDL;
LL_SHADER_LOADING_WARNS() << "\n" << log << LL_ENDL;
}
GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
// endsure work-around for missing GLSL funcs gets propogated to feature shader files (e.g. srgbF.glsl)
#if LL_DARWIN
if (defines)
{
(*defines)["OLD_SELECT"] = "1";
}
#endif
GLenum error = GL_NO_ERROR;
if (gDebugGL)
{
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_SHADER_LOADING_WARNS() << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
}
}
if (filename.empty())
{
return 0;
}
S32 try_gpu_class = shader_level;
S32 gpu_class;
//find the most relevant file
for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--)
{ //search from the current gpu class down to class 1 to find the most relevant shader
std::stringstream fname;
fname << getShaderDirPrefix();
fname << gpu_class << "/" << filename;
open_file_name = fname.str();
/*
Would be awesome, if we didn't have shaders that re-use files
with different environments to say, add skinning, etc
can't depend on cached version to have evaluate ifdefs identically...
if we can define a deterministic hash for the shader based on
all the inputs, maybe we can save some time here.
if (mShaderObjects.count(filename) > 0)
{
return mShaderObjects[filename];
}
*/
LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL;
file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */
if (file)
{
LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL;
break; // done
}
}
if (file == NULL)
{
LL_SHADER_LOADING_WARNS() << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
return 0;
}
//we can't have any lines longer than 1024 characters
//or any shaders longer than 4096 lines... deal - DaveP
GLchar buff[1024];
GLchar*extra_code_text[1024];
GLchar*shader_code_text[4096 + LL_ARRAY_SIZE(extra_code_text)] = { NULL };
ruslantproductengine
committed
GLuint extra_code_count = 0, shader_code_count = 0;
BOOST_STATIC_ASSERT(LL_ARRAY_SIZE(extra_code_text) < LL_ARRAY_SIZE(shader_code_text));
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
S32 major_version = gGLManager.mGLSLVersionMajor;
S32 minor_version = gGLManager.mGLSLVersionMinor;
if (major_version == 1 && minor_version < 30)
{
if (minor_version < 10)
{
//should NEVER get here -- if major version is 1 and minor version is less than 10,
// viewer should never attempt to use shaders, continuing will result in undefined behavior
LL_ERRS() << "Unsupported GLSL Version." << LL_ENDL;
}
if (minor_version <= 19)
{
shader_code_text[shader_code_count++] = strdup("#version 110\n");
extra_code_text[extra_code_count++] = strdup("#define ATTRIBUTE attribute\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING varying\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING_FLAT varying\n");
}
else if (minor_version <= 29)
{
//set version to 1.20
shader_code_text[shader_code_count++] = strdup("#version 120\n");
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_120 1\n");
extra_code_text[extra_code_count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
extra_code_text[extra_code_count++] = strdup("#define ATTRIBUTE attribute\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING varying\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING_FLAT varying\n");
}
}
else
{
if (major_version >= 4)
{
//set version to 400
shader_code_text[shader_code_count++] = strdup("#version 400\n");
}
else if (major_version == 3)
{
if (minor_version < 10)
{
shader_code_text[shader_code_count++] = strdup("#version 300\n");
}
else if (minor_version <= 19)
{
shader_code_text[shader_code_count++] = strdup("#version 310\n");
}
else if (minor_version <= 29)
{
shader_code_text[shader_code_count++] = strdup("#version 320\n");
}
else
{
shader_code_text[shader_code_count++] = strdup("#version 330\n");
}
}
else
{
//set version to 1.30
shader_code_text[shader_code_count++] = strdup("#version 130\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
extra_code_text[extra_code_count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
extra_code_text[extra_code_count++] = strdup("#define ATTRIBUTE in\n");
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
{ //"varying" state is "out" in a vertex program, "in" in a fragment program
// ("varying" is deprecated after version 1.20)
extra_code_text[extra_code_count++] = strdup("#define VARYING out\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING_FLAT flat out\n");
}
else
{
extra_code_text[extra_code_count++] = strdup("#define VARYING in\n");
extra_code_text[extra_code_count++] = strdup("#define VARYING_FLAT flat in\n");
}
//backwards compatibility with legacy texture lookup syntax
extra_code_text[extra_code_count++] = strdup("#define texture2D texture\n");
extra_code_text[extra_code_count++] = strdup("#define textureCube texture\n");
extra_code_text[extra_code_count++] = strdup("#define texture2DLod textureLod\n");
extra_code_text[extra_code_count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n");
if (major_version > 1 || minor_version >= 40)
{ //GLSL 1.40 replaces texture2DRect et al with texture
extra_code_text[extra_code_count++] = strdup("#define texture2DRect texture\n");
extra_code_text[extra_code_count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
}
}
if (defines)
{
for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
{
std::string define = "#define " + iter->first + " " + iter->second + "\n";
extra_code_text[extra_code_count++] = (GLchar*) strdup(define.c_str());
}
}
if( gGLManager.mIsATI )
{
extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" );
}
if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER)
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
{
//use specified number of texture channels for indexed texture rendering
/* prepend shader code that looks like this:
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
.
.
.
uniform sampler2D texN;
VARYING_FLAT ivec4 vary_texture_index;
vec4 ret = vec4(1,0,1,1);
vec4 diffuseLookup(vec2 texcoord)
{
switch (vary_texture_index.r))
{
case 0: ret = texture2D(tex0, texcoord); break;
case 1: ret = texture2D(tex1, texcoord); break;
case 2: ret = texture2D(tex2, texcoord); break;
.
.
.
case N: return texture2D(texN, texcoord); break;
}
return ret;
}
*/
extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP\n");
//uniform declartion
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string decl = llformat("uniform sampler2D tex%d;\n", i);
extra_code_text[extra_code_count++] = strdup(decl.c_str());
}
if (texture_index_channels > 1)
{
extra_code_text[extra_code_count++] = strdup("VARYING_FLAT int vary_texture_index;\n");
}
extra_code_text[extra_code_count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
extra_code_text[extra_code_count++] = strdup("{\n");
if (texture_index_channels == 1)
{ //don't use flow control, that's silly
extra_code_text[extra_code_count++] = strdup("return texture2D(tex0, texcoord);\n");
extra_code_text[extra_code_count++] = strdup("}\n");
}
else if (major_version > 1 || minor_version >= 30)
{ //switches are supported in GLSL 1.30 and later
if (gGLManager.mIsNVIDIA)
{ //switches are unreliable on some NVIDIA drivers
for (U32 i = 0; i < texture_index_channels; ++i)
{
std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
extra_code_text[extra_code_count++] = strdup(if_string.c_str());
}
extra_code_text[extra_code_count++] = strdup("\treturn vec4(1,0,1,1);\n");
extra_code_text[extra_code_count++] = strdup("}\n");
}
else
{
extra_code_text[extra_code_count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
extra_code_text[extra_code_count++] = strdup("\tswitch (vary_texture_index)\n");
extra_code_text[extra_code_count++] = strdup("\t{\n");
//switch body
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
extra_code_text[extra_code_count++] = strdup(case_str.c_str());
}
extra_code_text[extra_code_count++] = strdup("\t}\n");
extra_code_text[extra_code_count++] = strdup("\treturn ret;\n");
extra_code_text[extra_code_count++] = strdup("}\n");
}
}
else
{ //should never get here. Indexed texture rendering requires GLSL 1.30 or later
// (for passing integers between vertex and fragment shaders)
LL_ERRS() << "Indexed texture rendering requires GLSL 1.30 or later." << LL_ENDL;
}
}
ruslantproductengine
committed
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
//copy file into memory
enum {
flag_write_to_out_of_extra_block_area = 0x01
, flag_extra_block_marker_was_found = 0x02
};
unsigned char flags = flag_write_to_out_of_extra_block_area;
GLuint out_of_extra_block_counter = 0, start_shader_code = shader_code_count, file_lines_count = 0;
while(NULL != fgets((char *)buff, 1024, file)
&& shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text)))
{
file_lines_count++;
bool extra_block_area_found = NULL != strstr((const char*)buff, "[EXTRA_CODE_HERE]");
if(extra_block_area_found && !(flag_extra_block_marker_was_found & flags))
{
if(!(flag_write_to_out_of_extra_block_area & flags))
{
//shift
for(GLuint to = start_shader_code, from = extra_code_count + start_shader_code;
from < shader_code_count; ++to, ++from)
{
shader_code_text[to] = shader_code_text[from];
}
shader_code_count -= extra_code_count;
}
//copy extra code
for(GLuint n = 0; n < extra_code_count
&& shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text)); ++n)
{
shader_code_text[shader_code_count++] = extra_code_text[n];
}
extra_code_count = 0;
flags &= ~flag_write_to_out_of_extra_block_area;
flags |= flag_extra_block_marker_was_found;
}
shader_code_text[shader_code_count] = (GLchar*)strdup((char *)buff);
if(flag_write_to_out_of_extra_block_area & flags)
{
shader_code_text[extra_code_count + start_shader_code + out_of_extra_block_counter]
= shader_code_text[shader_code_count];
out_of_extra_block_counter++;
if(out_of_extra_block_counter == extra_code_count)
{
shader_code_count += extra_code_count;
flags &= ~flag_write_to_out_of_extra_block_area;
}
}
}
} //while
if(!(flag_extra_block_marker_was_found & flags))
{
for(GLuint n = start_shader_code; n < extra_code_count + start_shader_code; ++n)
{
shader_code_text[n] = extra_code_text[n - start_shader_code];
}
if (file_lines_count < extra_code_count)
{
shader_code_count += extra_code_count;
}
extra_code_count = 0;
}
fclose(file);
//create shader object
if (gDebugGL)
{
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShader: " << error << LL_ENDL;
glShaderSource(ret, shader_code_count, (const GLchar**) shader_code_text, NULL);
if (gDebugGL)
{
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSource: " << error << LL_ENDL;