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;
							 | 
						||
| 
								 | 
							
								}
							 |