205 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "ogl.h"
 | |
| 
 | |
| #include <Kore/Graphics3/Graphics.h>
 | |
| #include <Kore/Graphics4/Shader.h>
 | |
| #include <Kore/Log.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <string>
 | |
| 
 | |
| using namespace Kore;
 | |
| 
 | |
| namespace Kore {
 | |
| #ifndef OPENGLES
 | |
| 	bool programUsesTessellation = false;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| ProgramImpl::ProgramImpl()
 | |
|     : textureCount(0), vertexShader(nullptr), fragmentShader(nullptr), geometryShader(nullptr), tessellationEvaluationShader(nullptr),
 | |
|       tessellationControlShader(nullptr) {
 | |
| 	textures = new const char *[16];
 | |
| 	textureValues = new int[16];
 | |
| }
 | |
| 
 | |
| Graphics4::Program::Program() {
 | |
| 	programId = glCreateProgram();
 | |
| 	glCheckErrors();
 | |
| }
 | |
| 
 | |
| ProgramImpl::~ProgramImpl() {
 | |
| 	glDeleteProgram(programId);
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::setVertexShader(Shader *shader) {
 | |
| 	vertexShader = shader;
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::setFragmentShader(Shader *shader) {
 | |
| 	fragmentShader = shader;
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::setGeometryShader(Shader *shader) {
 | |
| #ifndef OPENGLES
 | |
| 	geometryShader = shader;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::setTessellationControlShader(Shader *shader) {
 | |
| #ifndef OPENGLES
 | |
| 	tessellationControlShader = shader;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::setTessellationEvaluationShader(Shader *shader) {
 | |
| #ifndef OPENGLES
 | |
| 	tessellationEvaluationShader = shader;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 	int toGlShader(Graphics4::ShaderType type) {
 | |
| 		switch (type) {
 | |
| 		case Graphics4::VertexShader:
 | |
| 		default:
 | |
| 			return GL_VERTEX_SHADER;
 | |
| 		case Graphics4::FragmentShader:
 | |
| 			return GL_FRAGMENT_SHADER;
 | |
| 			/*#ifndef OPENGLES
 | |
| 			        case GeometryShader:
 | |
| 			            return GL_GEOMETRY_SHADER;
 | |
| 			        case TessellationControlShader:
 | |
| 			            return GL_TESS_CONTROL_SHADER;
 | |
| 			        case TessellationEvaluationShader:
 | |
| 			            return GL_TESS_EVALUATION_SHADER;
 | |
| 			#endif*/
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	void compileShader(uint &id, char *source, int length, Graphics4::ShaderType type) {
 | |
| 		id = glCreateShader(toGlShader(type));
 | |
| 		glCheckErrors();
 | |
| 		glShaderSource(id, 1, (const GLchar **)&source, 0);
 | |
| 		glCompileShader(id);
 | |
| 
 | |
| 		int result;
 | |
| 		glGetShaderiv(id, GL_COMPILE_STATUS, &result);
 | |
| 		if (result != GL_TRUE) {
 | |
| 			int length;
 | |
| 			glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
 | |
| 			char *errormessage = new char[length];
 | |
| 			glGetShaderInfoLog(id, length, nullptr, errormessage);
 | |
| 			printf("GLSL compiler error: %s\n", errormessage);
 | |
| 			delete[] errormessage;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::link(VertexStructure **structures, int count) {
 | |
| 	compileShader(vertexShader->id, vertexShader->source, vertexShader->length, VertexShader);
 | |
| 	compileShader(fragmentShader->id, fragmentShader->source, fragmentShader->length, FragmentShader);
 | |
| #ifndef OPENGLES
 | |
| 	if (geometryShader != nullptr)
 | |
| 		compileShader(geometryShader->id, geometryShader->source, geometryShader->length, GeometryShader);
 | |
| 	if (tessellationControlShader != nullptr)
 | |
| 		compileShader(tessellationControlShader->id, tessellationControlShader->source, tessellationControlShader->length, TessellationControlShader);
 | |
| 	if (tessellationEvaluationShader != nullptr)
 | |
| 		compileShader(tessellationEvaluationShader->id, tessellationEvaluationShader->source, tessellationEvaluationShader->length,
 | |
| 		              TessellationEvaluationShader);
 | |
| #endif
 | |
| 	glAttachShader(programId, vertexShader->id);
 | |
| 	glAttachShader(programId, fragmentShader->id);
 | |
| #ifndef OPENGLES
 | |
| 	if (geometryShader != nullptr)
 | |
| 		glAttachShader(programId, geometryShader->id);
 | |
| 	if (tessellationControlShader != nullptr)
 | |
| 		glAttachShader(programId, tessellationControlShader->id);
 | |
| 	if (tessellationEvaluationShader != nullptr)
 | |
| 		glAttachShader(programId, tessellationEvaluationShader->id);
 | |
| #endif
 | |
| 	glCheckErrors();
 | |
| 
 | |
| 	int index = 0;
 | |
| 	for (int i1 = 0; i1 < count; ++i1) {
 | |
| 		for (int i2 = 0; i2 < structures[i1]->size; ++i2) {
 | |
| 			VertexElement element = structures[i1]->elements[i2];
 | |
| 			glBindAttribLocation(programId, index, element.name);
 | |
| 			glCheckErrors();
 | |
| 			if (element.data == Float4x4VertexData) {
 | |
| 				index += 4;
 | |
| 			}
 | |
| 			else {
 | |
| 				++index;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	glLinkProgram(programId);
 | |
| 
 | |
| 	int result;
 | |
| 	glGetProgramiv(programId, GL_LINK_STATUS, &result);
 | |
| 	if (result != GL_TRUE) {
 | |
| 		int length;
 | |
| 		glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &length);
 | |
| 		char *errormessage = new char[length];
 | |
| 		glGetProgramInfoLog(programId, length, nullptr, errormessage);
 | |
| 		printf("GLSL linker error: %s\n", errormessage);
 | |
| 		delete[] errormessage;
 | |
| 	}
 | |
| 
 | |
| #ifndef KINC_OPENGL_ES
 | |
| #ifndef KINC_LINUX
 | |
| /*	if (tessellationControlShader != nullptr) {
 | |
| 	    glPatchParameteri(GL_PATCH_VERTICES, 3);
 | |
| 	    glCheckErrors();
 | |
| 	}*/
 | |
| #endif
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void Graphics4::Program::set() {
 | |
| #ifndef KINC_OPENGL_ES
 | |
| 	programUsesTessellation = tessellationControlShader != nullptr;
 | |
| #endif
 | |
| 	glUseProgram(programId);
 | |
| 	glCheckErrors();
 | |
| 	for (int index = 0; index < textureCount; ++index) {
 | |
| 		glUniform1i(textureValues[index], index);
 | |
| 		glCheckErrors();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| Graphics4::ConstantLocation Graphics4::Program::getConstantLocation(const char *name) {
 | |
| 	ConstantLocation location;
 | |
| 	location.location = glGetUniformLocation(programId, name);
 | |
| 	glCheckErrors();
 | |
| 	if (location.location < 0) {
 | |
| 		log(Warning, "Uniform %s not found.", name);
 | |
| 	}
 | |
| 	return location;
 | |
| }
 | |
| 
 | |
| int ProgramImpl::findTexture(const char *name) {
 | |
| 	for (int index = 0; index < textureCount; ++index) {
 | |
| 		if (strcmp(textures[index], name) == 0)
 | |
| 			return index;
 | |
| 	}
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| Graphics4::TextureUnit Graphics4::Program::getTextureUnit(const char *name) {
 | |
| 	int index = findTexture(name);
 | |
| 	if (index < 0) {
 | |
| 		int location = glGetUniformLocation(programId, name);
 | |
| 		glCheckErrors();
 | |
| 		index = textureCount;
 | |
| 		textureValues[index] = location;
 | |
| 		textures[index] = name;
 | |
| 		++textureCount;
 | |
| 	}
 | |
| 	TextureUnit unit;
 | |
| 	unit.unit = index;
 | |
| 	return unit;
 | |
| }
 |