/* ** shader.cpp ** ** This file is part of mkxp. ** ** Copyright (C) 2013 Jonas Kulla ** ** mkxp 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. ** ** mkxp 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 mkxp. If not, see . */ #include "shader.h" #include "globalstate.h" #include "glstate.h" #include "GL/glew.h" #include #include "../sprite.frag.xxd" #include "../hue.frag.xxd" #include "../trans.frag.xxd" #include "../transSimple.frag.xxd" #include "../bitmapBlit.frag.xxd" #include "../plane.frag.xxd" #include "../simple.frag.xxd" #include "../simpleColor.frag.xxd" #include "../simpleAlpha.frag.xxd" #include "../simple.vert.xxd" #include "../simpleColor.vert.xxd" #include "../sprite.vert.xxd" #define INIT_SHADER(vert, frag) \ Shader::init(shader_##vert##_vert, shader_##vert##_vert_len, shader_##frag##_frag, shader_##frag##_frag_len) #define GET_U(name) u_##name = glGetUniformLocation(program, #name) Shader::Shader() { vertShader = glCreateShader(GL_VERTEX_SHADER); fragShader = glCreateShader(GL_FRAGMENT_SHADER); program = glCreateProgram(); } Shader::~Shader() { glUseProgram(0); glDeleteProgram(program); glDeleteShader(vertShader); glDeleteShader(fragShader); } void Shader::bind() { glUseProgram(program); } void Shader::unbind() { glActiveTexture(GL_TEXTURE0); glUseProgram(0); } void Shader::init(const unsigned char *vert, int vertSize, const unsigned char *frag, int fragSize) { GLint success; /* Compile vertex shader */ glShaderSource(vertShader, 1, (const GLchar**) &vert, (const GLint*) &vertSize); glCompileShader(vertShader); glGetObjectParameterivARB(vertShader, GL_COMPILE_STATUS, &success); Q_ASSERT(success); /* Compile fragment shader */ glShaderSource(fragShader, 1, (const GLchar**) &frag, (const GLint*) &fragSize); glCompileShader(fragShader); glGetObjectParameterivARB(fragShader, GL_COMPILE_STATUS, &success); Q_ASSERT(success); /* Link shader program */ glAttachShader(program, vertShader); glAttachShader(program, fragShader); glBindAttribLocation(program, Position, "position"); glBindAttribLocation(program, TexCoord, "texCoord"); glBindAttribLocation(program, Color, "color"); glLinkProgram(program); glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); Q_ASSERT(success); } void Shader::initFromFile(const char *_vertFile, const char *_fragFile) { QFile vertFile(_vertFile); vertFile.open(QFile::ReadOnly); QByteArray vertContents = vertFile.readAll(); vertFile.close(); QFile fragFile(_fragFile); fragFile.open(QFile::ReadOnly); QByteArray fragContents = fragFile.readAll(); fragFile.close(); init((const unsigned char*) vertContents.constData(), vertContents.size(), (const unsigned char*) fragContents.constData(), fragContents.size()); } void Shader::setVec4Uniform(GLint location, const Vec4 &vec) { glUniform4f(location, vec.x, vec.y, vec.z, vec.w); } void Shader::setTexUniform(GLint location, unsigned unitIndex, TEX::ID texture) { GLenum texUnit = GL_TEXTURE0 + unitIndex; glActiveTexture(texUnit); glBindTexture(GL_TEXTURE_2D, texture.gl); glUniform1i(location, unitIndex); glActiveTexture(GL_TEXTURE0); } void ShaderBase::GLProjMat::apply(const Vec2i &value) { /* glOrtho replacement */ const float a = 2.f / value.x; const float b = 2.f / value.y; const float c = -2.f; GLfloat mat[16] = { a, 0, 0, 0, 0, b, 0, 0, 0, 0, c, 0, -1, -1, -1, 1 }; glUniformMatrix4fv(u_mat, 1, GL_FALSE, mat); } void ShaderBase::init() { GET_U(texSizeInv); GET_U(translation); projMat.u_mat = glGetUniformLocation(program, "projMat"); } void ShaderBase::applyViewportProj() { const IntRect &vp = glState.viewport.get(); projMat.set(Vec2i(vp.w, vp.h)); } void ShaderBase::setTexSize(const Vec2i &value) { glUniform2f(u_texSizeInv, 1.f / value.x, 1.f / value.y); } void ShaderBase::setTranslation(const Vec2i &value) { glUniform2f(u_translation, value.x, value.y); } SimpleShader::SimpleShader() { INIT_SHADER(simple, simple); ShaderBase::init(); GET_U(texOffsetX); } void SimpleShader::setTexOffsetX(int value) { glUniform1f(u_texOffsetX, value); } SimpleColorShader::SimpleColorShader() { INIT_SHADER(simpleColor, simpleColor); ShaderBase::init(); } SimpleAlphaShader::SimpleAlphaShader() { INIT_SHADER(simpleColor, simpleAlpha); ShaderBase::init(); } SimpleSpriteShader::SimpleSpriteShader() { INIT_SHADER(sprite, simple); ShaderBase::init(); GET_U(spriteMat); } void SimpleSpriteShader::setSpriteMat(const float value[16]) { glUniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value); } TransShader::TransShader() { INIT_SHADER(simple, trans); ShaderBase::init(); GET_U(currentScene); GET_U(frozenScene); GET_U(transMap); GET_U(prog); GET_U(vague); } void TransShader::setCurrentScene(TEX::ID tex) { setTexUniform(u_currentScene, 0, tex); } void TransShader::setFrozenScene(TEX::ID tex) { setTexUniform(u_frozenScene, 1, tex); } void TransShader::setTransMap(TEX::ID tex) { setTexUniform(u_transMap, 2, tex); } void TransShader::setProg(float value) { glUniform1f(u_prog, value); } void TransShader::setVague(float value) { glUniform1f(u_vague, value); } SimpleTransShader::SimpleTransShader() { INIT_SHADER(simple, transSimple); ShaderBase::init(); GET_U(currentScene); GET_U(frozenScene); GET_U(prog); } void SimpleTransShader::setCurrentScene(TEX::ID tex) { setTexUniform(u_currentScene, 0, tex); } void SimpleTransShader::setFrozenScene(TEX::ID tex) { setTexUniform(u_frozenScene, 1, tex); } void SimpleTransShader::setProg(float value) { glUniform1f(u_prog, value); } SpriteShader::SpriteShader() { INIT_SHADER(sprite, sprite); ShaderBase::init(); GET_U(spriteMat); GET_U(tone); GET_U(color); GET_U(opacity); GET_U(bushDepth); GET_U(bushOpacity); } void SpriteShader::setSpriteMat(const float value[16]) { glUniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value); } void SpriteShader::setTone(const Vec4 &tone) { setVec4Uniform(u_tone, tone); } void SpriteShader::setColor(const Vec4 &color) { setVec4Uniform(u_color, color); } void SpriteShader::setOpacity(float value) { glUniform1f(u_opacity, value); } void SpriteShader::setBushDepth(float value) { glUniform1f(u_bushDepth, value); } void SpriteShader::setBushOpacity(float value) { glUniform1f(u_bushOpacity, value); } PlaneShader::PlaneShader() { INIT_SHADER(simple, plane); ShaderBase::init(); GET_U(tone); GET_U(color); GET_U(flash); GET_U(opacity); } void PlaneShader::setTone(const Vec4 &tone) { setVec4Uniform(u_tone, tone); } void PlaneShader::setColor(const Vec4 &color) { setVec4Uniform(u_color, color); } void PlaneShader::setFlash(const Vec4 &flash) { setVec4Uniform(u_flash, flash); } void PlaneShader::setOpacity(float value) { glUniform1f(u_opacity, value); } HueShader::HueShader() { INIT_SHADER(simple, hue); ShaderBase::init(); GET_U(hueAdjust); GET_U(inputTexture); } void HueShader::setHueAdjust(float value) { glUniform1f(u_hueAdjust, value); } void HueShader::setInputTexture(TEX::ID tex) { setTexUniform(u_inputTexture, 0, tex); } BltShader::BltShader() { INIT_SHADER(simple, bitmapBlit); ShaderBase::init(); GET_U(source); GET_U(destination); GET_U(subRect); GET_U(opacity); } void BltShader::setSource() { glUniform1i(u_source, 0); } void BltShader::setDestination(const TEX::ID value) { setTexUniform(u_destination, 1, value); } void BltShader::setSubRect(const FloatRect &value) { glUniform4f(u_subRect, value.x, value.y, value.w, value.h); } void BltShader::setOpacity(float value) { glUniform1f(u_opacity, value); }