Example #1
0
ShaderGLES2::Version* ShaderGLES2::get_current_version() {

	Version *_v=version_map.getptr(conditional_version);

	if (_v) {

		if (conditional_version.code_version!=0) {
			CustomCode *cc=custom_code_map.getptr(conditional_version.code_version);
			ERR_FAIL_COND_V(!cc,_v);
			if (cc->version==_v->code_version)
				return _v;
		} else {
			return _v;
		}

	}



	if (!_v)
		version_map[conditional_version]=Version();


	Version &v = version_map[conditional_version];

	if (!_v) {

		v.uniform_location = memnew_arr( GLint, uniform_count );

	} else {
		if (v.ok) {
			//bye bye shaders
			glDeleteShader( v.vert_id );
			glDeleteShader( v.frag_id );
			glDeleteProgram( v.id );
			v.id=0;
		}

	}

	v.ok=false;
	/* SETUP CONDITIONALS */
	
	Vector<const char*> strings;
#ifdef GLEW_ENABLED
	strings.push_back("#version 120\n"); //ATI requieres this before anything
#endif
	int define_line_ofs=1;

	for(int j=0;j<conditional_count;j++) {
		
		bool enable=((1<<j)&conditional_version.version);
		strings.push_back(enable?conditional_defines[j]:"");
		if (enable)
			define_line_ofs++;

		if (enable) {
			DEBUG_PRINT(conditional_defines[j]);
		}

	}
	
	//keep them around during the function
	CharString code_string;
	CharString code_string2;
	CharString code_globals;


	//print_line("code version? "+itos(conditional_version.code_version));

	CustomCode *cc=NULL;

	if ( conditional_version.code_version>0 ) {
		//do custom code related stuff

		ERR_FAIL_COND_V( !custom_code_map.has( conditional_version.code_version ), NULL );
		cc=&custom_code_map[conditional_version.code_version];
		v.code_version=cc->version;
		define_line_ofs+=2;
	}


	/* CREATE PROGRAM */
	
	v.id = glCreateProgram();
	
	ERR_FAIL_COND_V(v.id==0, NULL);
	
	/* VERTEX SHADER */


	if (cc) {
		for(int i=0;i<cc->custom_defines.size();i++) {

			strings.push_back(cc->custom_defines[i]);
			DEBUG_PRINT("CD #"+itos(i)+": "+String(cc->custom_defines[i]));
		}
	}

	int strings_base_size=strings.size();
#if 0
	if (cc) {

		String _code_string = "#define VERTEX_SHADER_CODE "+cc->vertex+"\n";
		String _code_globals = "#define VERTEX_SHADER_GLOBALS "+cc->vertex_globals+"\n";

		code_string=_code_string.ascii();
		code_globals=_code_globals.ascii();
		DEBUG_PRINT( code_globals.get_data() );
		DEBUG_PRINT( code_string.get_data() );
		strings.push_back(code_globals);
		strings.push_back(code_string);
	}
#endif


	strings.push_back(vertex_code0.get_data());
	if (cc) {
		code_globals=cc->vertex_globals.ascii();
		strings.push_back(code_globals.get_data());
	}
	strings.push_back(vertex_code1.get_data());

	if (cc) {
		code_string=cc->vertex.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(vertex_code2.get_data());
#ifdef DEBUG_SHADER

	DEBUG_PRINT("\nVertex Code:\n\n"+String(code_string.get_data()));
	for(int i=0;i<strings.size();i++) {

		//print_line("vert strings "+itos(i)+":"+String(strings[i]));
	}
#endif


	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(v.vert_id,strings.size(),&strings[0],NULL);
	glCompileShader(v.vert_id);
	
	GLint status;
	
	glGetShaderiv(v.vert_id,GL_COMPILE_STATUS,&status);			
	if (status==GL_FALSE) {
	// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.vert_id,GL_INFO_LOG_LENGTH,&iloglen);
		
		if (iloglen<0) {
			
			glDeleteShader(v.vert_id);
			glDeleteProgram( v.id );
			v.id=0;
			
			ERR_PRINT("NO LOG, WTF");
		} else {

			if (iloglen==0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			
			char *ilogmem = (char*)Memory::alloc_static(iloglen+1);
			ilogmem[iloglen]=0;
			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); 	
			
			String err_string=get_shader_name()+": Vertex Program Compilation Failed:\n";
			
			err_string+=ilogmem;
			err_string=_fix_error_code_line(err_string,vertex_code_start,define_line_ofs);
			ERR_PRINT(err_string.ascii().get_data());
			Memory::free_static(ilogmem);
			glDeleteShader(v.vert_id);
			glDeleteProgram( v.id );
			v.id=0;
			
		}
		
		ERR_FAIL_V(NULL);
	}	
	
	/* FRAGMENT SHADER */

	strings.resize(strings_base_size);
#if 0
	if (cc) {

		String _code_string = "#define FRAGMENT_SHADER_CODE "+cc->fragment+"\n";
		String _code_globals = "#define FRAGMENT_SHADER_GLOBALS "+cc->fragment_globals+"\n";

		code_string=_code_string.ascii();
		code_globals=_code_globals.ascii();
		DEBUG_PRINT( code_globals.get_data() );
		DEBUG_PRINT( code_string.get_data() );
		strings.push_back(code_globals);
		strings.push_back(code_string);
	}
#endif


	strings.push_back(fragment_code0.get_data());
	if (cc) {
		code_globals=cc->fragment_globals.ascii();
		strings.push_back(code_globals.get_data());
	}
	strings.push_back(fragment_code1.get_data());

	if (cc) {
		code_string=cc->fragment.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(fragment_code2.get_data());

	if (cc) {
		code_string2=cc->light.ascii();
		strings.push_back(code_string2.get_data());
	}

	strings.push_back(fragment_code3.get_data());

#ifdef DEBUG_SHADER
	DEBUG_PRINT("\nFragment Code:\n\n"+String(code_string.get_data()));
	for(int i=0;i<strings.size();i++) {

		//print_line("frag strings "+itos(i)+":"+String(strings[i]));
	}
#endif

	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(v.frag_id,strings.size(),&strings[0],NULL);
	glCompileShader(v.frag_id);
	
	glGetShaderiv(v.frag_id,GL_COMPILE_STATUS,&status);			
	if (status==GL_FALSE) {
	// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.frag_id,GL_INFO_LOG_LENGTH,&iloglen);
		
		if (iloglen<0) {

			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram( v.id );
			v.id=0;
			ERR_PRINT("NO LOG, WTF");
		} else {
			
			if (iloglen==0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			char *ilogmem = (char*)Memory::alloc_static(iloglen+1);
			ilogmem[iloglen]=0;
			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); 	
			
			String err_string=get_shader_name()+": Fragment Program Compilation Failed:\n";
			
			err_string+=ilogmem;
			err_string=_fix_error_code_line(err_string,fragment_code_start,define_line_ofs);
			ERR_PRINT(err_string.ascii().get_data());
			Memory::free_static(ilogmem);
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram( v.id );
			v.id=0;
			
		}
		
		ERR_FAIL_V( NULL );
	}		
	
	glAttachShader(v.id,v.frag_id);
	glAttachShader(v.id,v.vert_id);

	// bind attributes before linking
	for (int i=0;i<attribute_pair_count;i++) {

		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name );
	}

	glLinkProgram(v.id);
	
	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
	
	if (status==GL_FALSE) {
	// error linking
		GLsizei iloglen;
		glGetProgramiv(v.id,GL_INFO_LOG_LENGTH,&iloglen);
		
		if (iloglen<0) {
			
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram( v.id );
			v.id=0;
			ERR_FAIL_COND_V(iloglen<=0, NULL);		
		}

		if (iloglen==0) {

			iloglen = 4096; //buggy driver (Adreno 220+....)
		}

		
		char *ilogmem = (char*)Memory::alloc_static(iloglen+1);
		ilogmem[iloglen]=0;
		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); 	
		
		String err_string=get_shader_name()+": Program LINK FAILED:\n";
		
		err_string+=ilogmem;
		err_string=_fix_error_code_line(err_string,fragment_code_start,define_line_ofs);
		ERR_PRINT(err_string.ascii().get_data());
		Memory::free_static(ilogmem);
		glDeleteShader(v.frag_id);
		glDeleteShader(v.vert_id);
		glDeleteProgram( v.id );
		v.id=0;
		
		ERR_FAIL_V(NULL);
	}
	
	/* UNIFORMS */		
	
	glUseProgram(v.id);


	//print_line("uniforms:  ");
	for(int j=0;j<uniform_count;j++) {
		
		
		v.uniform_location[j]=glGetUniformLocation(v.id,uniform_names[j]);
		//print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j]));
	}
	
	// set texture uniforms
	for (int i=0;i<texunit_pair_count;i++) {

		GLint loc = glGetUniformLocation(v.id,texunit_pairs[i].name);
		if (loc>=0)
			glUniform1i(loc,texunit_pairs[i].index);
	}

	if ( cc ) {

		v.custom_uniform_locations.resize(cc->custom_uniforms.size());
		for(int i=0;i<cc->custom_uniforms.size();i++) {

			v.custom_uniform_locations[i]=glGetUniformLocation(v.id,String(cc->custom_uniforms[i]).ascii().get_data());
		}
	}

	glUseProgram(0);
	

	v.ok=true;

	return &v;
}
Example #2
0
ShaderGLES2::Version *ShaderGLES2::get_current_version() {

	Version *_v = version_map.getptr(conditional_version);

	if (_v) {
		if (conditional_version.code_version != 0) {
			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
			ERR_FAIL_COND_V(!cc, _v);
			if (cc->version == _v->code_version)
				return _v;
		} else {
			return _v;
		}
	}

	if (!_v)
		version_map[conditional_version] = Version();

	Version &v = version_map[conditional_version];

	if (!_v) {
		v.uniform_location = memnew_arr(GLint, uniform_count);
	} else {
		if (v.ok) {
			glDeleteShader(v.vert_id);
			glDeleteShader(v.frag_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}
	}

	v.ok = false;

	Vector<const char *> strings;

#ifdef GLES_OVER_GL
	strings.push_back("#version 120\n");
	strings.push_back("#define USE_GLES_OVER_GL\n");
#else
	strings.push_back("#version 100\n");
//angle does not like
#ifdef JAVASCRIPT_ENABLED
	strings.push_back("#define USE_HIGHP_PRECISION\n");
#endif

#endif

	int define_line_ofs = 1;

	for (int j = 0; j < conditional_count; j++) {
		bool enable = (conditional_version.version & (1 << j)) > 0;

		if (enable) {
			strings.push_back(conditional_defines[j]);
			define_line_ofs++;
			DEBUG_PRINT(conditional_defines[j]);
		}
	}

	// keep them around during the function
	CharString code_string;
	CharString code_string2;
	CharString code_globals;

	CustomCode *cc = NULL;

	if (conditional_version.code_version > 0) {
		cc = custom_code_map.getptr(conditional_version.code_version);

		ERR_FAIL_COND_V(!cc, NULL);
		v.code_version = cc->version;
		define_line_ofs += 2;
	}

	// program

	v.id = glCreateProgram();
	ERR_FAIL_COND_V(v.id == 0, NULL);

	if (cc) {
		for (int i = 0; i < cc->custom_defines.size(); i++) {
			strings.push_back(cc->custom_defines.write[i]);
			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data()));
		}
	}

	// vertex shader

	int string_base_size = strings.size();

	strings.push_back(vertex_code0.get_data());

	if (cc) {
		code_globals = cc->vertex_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(vertex_code1.get_data());

	if (cc) {
		code_string = cc->vertex.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(vertex_code2.get_data());

#ifdef DEBUG_SHADER

	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));

#endif

	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.vert_id);

	GLint status;

	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
		} else {
			if (iloglen == 0) {
				iloglen = 4096; // buggy driver (Adreno 220+)
			}

			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
			ilogmem[iloglen] = '\0';
			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Vertex shader compilation failed:\n";

			err_string += ilogmem;

			_display_error_with_code(err_string, strings);

			Memory::free_static(ilogmem);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	strings.resize(string_base_size);

	// fragment shader

	strings.push_back(fragment_code0.get_data());

	if (cc) {
		code_globals = cc->fragment_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(fragment_code1.get_data());

	if (cc) {
		code_string = cc->light.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(fragment_code2.get_data());

	if (cc) {
		code_string2 = cc->fragment.ascii();
		strings.push_back(code_string2.get_data());
	}

	strings.push_back(fragment_code3.get_data());

#ifdef DEBUG_SHADER

	if (cc) {
		DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals));
	}
	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
#endif

	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.frag_id);

	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?");
		} else {
			if (iloglen == 0) {
				iloglen = 4096; // buggy driver (Adreno 220+)
			}

			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
			ilogmem[iloglen] = '\0';
			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Fragment shader compilation failed:\n";

			err_string += ilogmem;

			_display_error_with_code(err_string, strings);

			Memory::free_static(ilogmem);
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	glAttachShader(v.id, v.frag_id);
	glAttachShader(v.id, v.vert_id);

	// bind the attribute locations. This has to be done before linking so that the
	// linker doesn't assign some random indices

	for (int i = 0; i < attribute_pair_count; i++) {
		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
	}

	glLinkProgram(v.id);

	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL program link log. What the frick?");
			ERR_FAIL_V(NULL);
		}

		if (iloglen == 0) {
			iloglen = 4096; // buggy driver (Adreno 220+)
		}

		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
		ilogmem[iloglen] = '\0';
		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);

		String err_string = get_shader_name() + ": Program linking failed:\n";

		err_string += ilogmem;

		_display_error_with_code(err_string, strings);

		Memory::free_static(ilogmem);
		glDeleteShader(v.frag_id);
		glDeleteShader(v.vert_id);
		glDeleteProgram(v.id);
		v.id = 0;

		ERR_FAIL_V(NULL);
	}

	// get uniform locations

	glUseProgram(v.id);

	for (int i = 0; i < uniform_count; i++) {
		v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]);
	}

	for (int i = 0; i < texunit_pair_count; i++) {
		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
		if (loc >= 0) {
			if (texunit_pairs[i].index < 0) {
				glUniform1i(loc, max_image_units + texunit_pairs[i].index);
			} else {
				glUniform1i(loc, texunit_pairs[i].index);
			}
		}
	}

	if (cc) {
		// uniforms
		for (int i = 0; i < cc->custom_uniforms.size(); i++) {
			String native_uniform_name = _mkid(cc->custom_uniforms[i]);
			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
			v.custom_uniform_locations[cc->custom_uniforms[i]] = location;
		}

		// textures
		for (int i = 0; i < cc->texture_uniforms.size(); i++) {
			String native_uniform_name = _mkid(cc->texture_uniforms[i]);
			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
			v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
		}
	}

	glUseProgram(0);
	v.ok = true;

	if (cc) {
		cc->versions.insert(conditional_version.version);
	}

	return &v;
}
Example #3
0
ShaderGLES3::Version *ShaderGLES3::get_current_version() {

	Version *_v = version_map.getptr(conditional_version);

	if (_v) {

		if (conditional_version.code_version != 0) {
			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
			ERR_FAIL_COND_V(!cc, _v);
			if (cc->version == _v->code_version)
				return _v;
		} else {
			return _v;
		}
	}

	if (!_v)
		version_map[conditional_version] = Version();

	Version &v = version_map[conditional_version];

	if (!_v) {

		v.uniform_location = memnew_arr(GLint, uniform_count);

	} else {
		if (v.ok) {
			//bye bye shaders
			glDeleteShader(v.vert_id);
			glDeleteShader(v.frag_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}
	}

	v.ok = false;
	/* SETUP CONDITIONALS */

	Vector<const char *> strings;
#ifdef GLES_OVER_GL
	strings.push_back("#version 330\n");
	strings.push_back("#define GLES_OVER_GL\n");
#else
	strings.push_back("#version 300 es\n");
#endif

	int define_line_ofs = 1;

	for (int i = 0; i < custom_defines.size(); i++) {

		strings.push_back(custom_defines[i].get_data());
		define_line_ofs++;
	}

	for (int j = 0; j < conditional_count; j++) {

		bool enable = ((1 << j) & conditional_version.version);
		strings.push_back(enable ? conditional_defines[j] : "");
		if (enable)
			define_line_ofs++;

		if (enable) {
			DEBUG_PRINT(conditional_defines[j]);
		}
	}

	//keep them around during the function
	CharString code_string;
	CharString code_string2;
	CharString code_globals;
	CharString material_string;

	CustomCode *cc = NULL;

	if (conditional_version.code_version > 0) {
		//do custom code related stuff

		ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL);
		cc = &custom_code_map[conditional_version.code_version];
		v.code_version = cc->version;
		define_line_ofs += 2;
	}

	/* CREATE PROGRAM */

	v.id = glCreateProgram();

	ERR_FAIL_COND_V(v.id == 0, NULL);

	/* VERTEX SHADER */

	if (cc) {
		for (int i = 0; i < cc->custom_defines.size(); i++) {

			strings.push_back(cc->custom_defines[i].get_data());
			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i]));
		}
	}

	int strings_base_size = strings.size();

	//vertex precision is high
	strings.push_back("precision highp float;\n");
	strings.push_back("precision highp int;\n");
#ifndef GLES_OVER_GL
	strings.push_back("precision highp sampler2D;\n");
	strings.push_back("precision highp samplerCube;\n");
	strings.push_back("precision highp sampler2DArray;\n");
#endif

	strings.push_back(vertex_code0.get_data());

	if (cc) {
		material_string = cc->uniforms.ascii();
		strings.push_back(material_string.get_data());
	}

	strings.push_back(vertex_code1.get_data());

	if (cc) {
		code_globals = cc->vertex_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(vertex_code2.get_data());

	if (cc) {
		code_string = cc->vertex.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(vertex_code3.get_data());
#ifdef DEBUG_SHADER

	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));
	for (int i = 0; i < strings.size(); i++) {

		//print_line("vert strings "+itos(i)+":"+String(strings[i]));
	}
#endif

	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.vert_id);

	GLint status;

	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("Vertex shader compilation failed with empty log");
		} else {

			if (iloglen == 0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			char *ilogmem = (char *)memalloc(iloglen + 1);
			ilogmem[iloglen] = 0;
			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Vertex Program Compilation Failed:\n";

			err_string += ilogmem;
			_display_error_with_code(err_string, strings);
			memfree(ilogmem);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	//_display_error_with_code("pepo", strings);

	/* FRAGMENT SHADER */

	strings.resize(strings_base_size);
	//fragment precision is medium
	strings.push_back("precision highp float;\n");
	strings.push_back("precision highp int;\n");
#ifndef GLES_OVER_GL
	strings.push_back("precision highp sampler2D;\n");
	strings.push_back("precision highp samplerCube;\n");
	strings.push_back("precision highp sampler2DArray;\n");
#endif

	strings.push_back(fragment_code0.get_data());
	if (cc) {
		material_string = cc->uniforms.ascii();
		strings.push_back(material_string.get_data());
	}

	strings.push_back(fragment_code1.get_data());

	if (cc) {
		code_globals = cc->fragment_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(fragment_code2.get_data());

	if (cc) {
		code_string = cc->light.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(fragment_code3.get_data());

	if (cc) {
		code_string2 = cc->fragment.ascii();
		strings.push_back(code_string2.get_data());
	}

	strings.push_back(fragment_code4.get_data());

#ifdef DEBUG_SHADER
	DEBUG_PRINT("\nFragment Globals:\n\n" + String(code_globals.get_data()));
	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string2.get_data()));
	for (int i = 0; i < strings.size(); i++) {

		//print_line("frag strings "+itos(i)+":"+String(strings[i]));
	}
#endif

	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.frag_id);

	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
			ERR_PRINT("Fragment shader compilation failed with empty log");
		} else {

			if (iloglen == 0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			char *ilogmem = (char *)memalloc(iloglen + 1);
			ilogmem[iloglen] = 0;
			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Fragment Program Compilation Failed:\n";

			err_string += ilogmem;
			_display_error_with_code(err_string, strings);
			ERR_PRINT(err_string.ascii().get_data());
			memfree(ilogmem);
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	glAttachShader(v.id, v.frag_id);
	glAttachShader(v.id, v.vert_id);

	// bind attributes before linking
	for (int i = 0; i < attribute_pair_count; i++) {

		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
	}

	//if feedback exists, set it up

	if (feedback_count) {
		Vector<const char *> feedback;
		for (int i = 0; i < feedback_count; i++) {

			if (feedbacks[i].conditional == -1 || (1 << feedbacks[i].conditional) & conditional_version.version) {
				//conditional for this feedback is enabled
				feedback.push_back(feedbacks[i].name);
			}
		}

		if (feedback.size()) {
			glTransformFeedbackVaryings(v.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS);
		}
	}

	glLinkProgram(v.id);

	glGetProgramiv(v.id, GL_LINK_STATUS, &status);

	if (status == GL_FALSE) {
		// error linking
		GLsizei iloglen;
		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
			ERR_FAIL_COND_V(iloglen <= 0, NULL);
		}

		if (iloglen == 0) {

			iloglen = 4096; //buggy driver (Adreno 220+....)
		}

		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
		ilogmem[iloglen] = 0;
		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);

		String err_string = get_shader_name() + ": Program LINK FAILED:\n";

		err_string += ilogmem;
		_display_error_with_code(err_string, strings);
		ERR_PRINT(err_string.ascii().get_data());
		Memory::free_static(ilogmem);
		glDeleteShader(v.frag_id);
		glDeleteShader(v.vert_id);
		glDeleteProgram(v.id);
		v.id = 0;

		ERR_FAIL_V(NULL);
	}

	/* UNIFORMS */

	glUseProgram(v.id);

	//print_line("uniforms:  ");
	for (int j = 0; j < uniform_count; j++) {

		v.uniform_location[j] = glGetUniformLocation(v.id, uniform_names[j]);
		//print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j]));
	}

	// set texture uniforms
	for (int i = 0; i < texunit_pair_count; i++) {

		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
		if (loc >= 0) {
			if (texunit_pairs[i].index < 0) {
				glUniform1i(loc, max_image_units + texunit_pairs[i].index); //negative, goes down
			} else {

				glUniform1i(loc, texunit_pairs[i].index);
			}
		}
	}

	// assign uniform block bind points
	for (int i = 0; i < ubo_count; i++) {

		GLint loc = glGetUniformBlockIndex(v.id, ubo_pairs[i].name);
		if (loc >= 0)
			glUniformBlockBinding(v.id, loc, ubo_pairs[i].index);
	}

	if (cc) {

		v.texture_uniform_locations.resize(cc->texture_uniforms.size());
		for (int i = 0; i < cc->texture_uniforms.size(); i++) {

			v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data());
			glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index);
		}
	}

	glUseProgram(0);

	v.ok = true;

	return &v;
}