| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Adapted from the javascript implementation upon WebGL by kwaters@. |
| |
| #include "shader.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include "shadersrc.h" |
| |
| #undef IMPORTGL_API |
| #undef IMPORTGL_FNPTRINIT |
| #include "importgl.h" |
| |
| |
| SHADERLIT sShaderLit; |
| SHADERFLAT sShaderFlat; |
| SHADERFADE sShaderFade; |
| |
| Matrix4x4 sModelView; |
| Matrix4x4 sProjection; |
| |
| |
| static void printShaderLog(GLuint shader) |
| { |
| int infoLogSize, infoWritten; |
| char *infoLog; |
| glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogSize); |
| infoLog = malloc(infoLogSize); |
| glGetShaderInfoLog(shader, infoLogSize, &infoWritten, infoLog); |
| fprintf(stderr, "Error: glCompileShader failed: %s\n", infoLog); |
| free(infoLog); |
| } |
| |
| |
| static GLuint createShader(const char *src, GLenum shaderType) |
| { |
| GLint bShaderCompiled; |
| GLuint shader = glCreateShader(shaderType); |
| if (shader == 0) |
| return 0; |
| glShaderSource(shader, 1, &src, NULL); |
| glCompileShader(shader); |
| glGetShaderiv(shader, GL_COMPILE_STATUS, &bShaderCompiled); |
| if (!bShaderCompiled) |
| { |
| printShaderLog(shader); |
| glDeleteShader(shader); |
| return 0; |
| } |
| return shader; |
| } |
| |
| |
| static GLuint createProgram(const char *srcVertex, const char * srcFragment) |
| { |
| GLuint program = glCreateProgram(); |
| if (program == 0) |
| return 0; |
| |
| GLuint shaderVertex = createShader(srcVertex, GL_VERTEX_SHADER); |
| if (shaderVertex == 0) |
| { |
| glDeleteProgram(program); |
| return 0; |
| } |
| glAttachShader(program, shaderVertex); |
| glDeleteShader(shaderVertex); |
| |
| GLuint shaderFragment = createShader(srcFragment, GL_FRAGMENT_SHADER); |
| if (shaderFragment == 0) |
| { |
| glDeleteProgram(program); |
| return 0; |
| } |
| glAttachShader(program, shaderFragment); |
| glDeleteShader(shaderFragment); |
| |
| glLinkProgram(program); |
| return program; |
| } |
| |
| |
| static void computeNormalMatrix(Matrix4x4 m, Matrix3x3 normal) |
| { |
| float det = m[0*4+0] * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]) - |
| m[0*4+1] * (m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]) + |
| m[0*4+2] * (m[1*4+0] * m[2*4+1] - m[1*4+1] * m[2*4+0]); |
| float invDet = 1.f / det; |
| normal[0*3+0] = invDet * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]); |
| normal[1*3+0] = invDet * -(m[0*4+1] * m[2*4+2] - m[0*4+2] * m[2*4+1]); |
| normal[2*3+0] = invDet * (m[0*4+1] * m[1*4+2] - m[0*4+2] * m[1*4+1]); |
| normal[0*3+1] = invDet * -(m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]); |
| normal[1*3+1] = invDet * (m[0*4+0] * m[2*4+2] - m[0*4+2] * m[2*4+0]); |
| normal[2*3+1] = invDet * -(m[0*4+0] * m[1*4+2] - m[1*4+0] * m[0*4+2]); |
| normal[0*3+2] = invDet * (m[1*4+0] * m[2*4+1] - m[2*4+0] * m[1*4+1]); |
| normal[1*3+2] = invDet * -(m[0*4+0] * m[2*4+1] - m[2*4+0] * m[0*4+1]); |
| normal[2*3+2] = invDet * (m[0*4+0] * m[1*4+1] - m[1*4+0] * m[0*4+1]); |
| } |
| |
| |
| static int getLocations() |
| { |
| int rt = 1; |
| #define GET_ATTRIBUTE_LOC(programName, varName) \ |
| sShader##programName.varName = \ |
| glGetAttribLocation(sShader##programName.program, #varName); \ |
| if (sShader##programName.varName == -1) rt = 0 |
| #define GET_UNIFORM_LOC(programName, varName) \ |
| sShader##programName.varName = \ |
| glGetUniformLocation(sShader##programName.program, #varName); \ |
| if (sShader##programName.varName == -1) rt = 0 |
| GET_ATTRIBUTE_LOC(Lit, pos); |
| GET_ATTRIBUTE_LOC(Lit, normal); |
| GET_ATTRIBUTE_LOC(Lit, colorIn); |
| GET_UNIFORM_LOC(Lit, mvp); |
| GET_UNIFORM_LOC(Lit, normalMatrix); |
| GET_UNIFORM_LOC(Lit, ambient); |
| GET_UNIFORM_LOC(Lit, shininess); |
| GET_UNIFORM_LOC(Lit, light_0_direction); |
| GET_UNIFORM_LOC(Lit, light_0_diffuse); |
| GET_UNIFORM_LOC(Lit, light_0_specular); |
| GET_UNIFORM_LOC(Lit, light_1_direction); |
| GET_UNIFORM_LOC(Lit, light_1_diffuse); |
| GET_UNIFORM_LOC(Lit, light_2_direction); |
| GET_UNIFORM_LOC(Lit, light_2_diffuse); |
| |
| GET_ATTRIBUTE_LOC(Flat, pos); |
| GET_ATTRIBUTE_LOC(Flat, colorIn); |
| GET_UNIFORM_LOC(Flat, mvp); |
| |
| GET_ATTRIBUTE_LOC(Fade, pos); |
| GET_UNIFORM_LOC(Fade, minFade); |
| #undef GET_ATTRIBUTE_LOC |
| #undef GET_UNIFORM_LOC |
| return rt; |
| } |
| |
| |
| int initShaderPrograms() |
| { |
| Matrix4x4_LoadIdentity(sModelView); |
| Matrix4x4_LoadIdentity(sProjection); |
| |
| sShaderFlat.program = createProgram(sFlatVertexSource, |
| sFlatFragmentSource); |
| sShaderLit.program = createProgram(sLitVertexSource, |
| sFlatFragmentSource); |
| sShaderFade.program = createProgram(sFadeVertexSource, |
| sFlatFragmentSource); |
| if (sShaderFlat.program == 0 || sShaderLit.program == 0 || |
| sShaderFade.program == 0) |
| return 0; |
| |
| return getLocations(); |
| } |
| |
| |
| void deInitShaderPrograms() |
| { |
| glDeleteProgram(sShaderFlat.program); |
| glDeleteProgram(sShaderLit.program); |
| glDeleteProgram(sShaderFade.program); |
| } |
| |
| |
| void bindShaderProgram(GLuint program) |
| { |
| int loc_mvp = -1; |
| int loc_normalMatrix = -1; |
| |
| glUseProgram(program); |
| |
| if (program == sShaderLit.program) |
| { |
| loc_mvp = sShaderLit.mvp; |
| loc_normalMatrix = sShaderLit.normalMatrix; |
| } |
| else if (program == sShaderFlat.program) |
| { |
| loc_mvp = sShaderFlat.mvp; |
| } |
| |
| if (loc_mvp != -1) |
| { |
| Matrix4x4 mvp; |
| Matrix4x4_Multiply(mvp, sModelView, sProjection); |
| glUniformMatrix4fv(loc_mvp, 1, GL_FALSE, (GLfloat *)mvp); |
| } |
| if (loc_normalMatrix != -1) |
| { |
| Matrix3x3 normalMatrix; |
| computeNormalMatrix(sModelView, normalMatrix); |
| glUniformMatrix3fv(loc_normalMatrix, 1, GL_FALSE, |
| (GLfloat *)normalMatrix); |
| } |
| } |
| |