1// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Adapted from the javascript implementation upon WebGL by kwaters@.
6
7#include "shader.h"
8
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "shadersrc.h"
13
14#undef IMPORTGL_API
15#undef IMPORTGL_FNPTRINIT
16#include "importgl.h"
17
18
19SHADERLIT sShaderLit;
20SHADERFLAT sShaderFlat;
21SHADERFADE sShaderFade;
22
23Matrix4x4 sModelView;
24Matrix4x4 sProjection;
25
26
27static void printShaderLog(GLuint shader)
28{
29    int infoLogSize, infoWritten;
30    char *infoLog;
31    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogSize);
32    infoLog = malloc(infoLogSize);
33    glGetShaderInfoLog(shader, infoLogSize, &infoWritten, infoLog);
34    fprintf(stderr, "Error: glCompileShader failed: %s\n", infoLog);
35    free(infoLog);
36}
37
38
39static GLuint createShader(const char *src, GLenum shaderType)
40{
41    GLint bShaderCompiled;
42    GLuint shader = glCreateShader(shaderType);
43    if (shader == 0)
44        return 0;
45    glShaderSource(shader, 1, &src, NULL);
46    glCompileShader(shader);
47    glGetShaderiv(shader, GL_COMPILE_STATUS, &bShaderCompiled);
48    if (!bShaderCompiled)
49    {
50        printShaderLog(shader);
51        glDeleteShader(shader);
52        return 0;
53    }
54    return shader;
55}
56
57
58static GLuint createProgram(const char *srcVertex, const char * srcFragment)
59{
60    GLuint program = glCreateProgram();
61    if (program == 0)
62        return 0;
63
64    GLuint shaderVertex = createShader(srcVertex, GL_VERTEX_SHADER);
65    if (shaderVertex == 0)
66    {
67        glDeleteProgram(program);
68        return 0;
69    }
70    glAttachShader(program, shaderVertex);
71    glDeleteShader(shaderVertex);
72
73    GLuint shaderFragment = createShader(srcFragment, GL_FRAGMENT_SHADER);
74    if (shaderFragment == 0)
75    {
76        glDeleteProgram(program);
77        return 0;
78    }
79    glAttachShader(program, shaderFragment);
80    glDeleteShader(shaderFragment);
81
82    glLinkProgram(program);
83    return program;
84}
85
86
87static void computeNormalMatrix(Matrix4x4 m, Matrix3x3 normal)
88{
89    float det = m[0*4+0] * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]) -
90                m[0*4+1] * (m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]) +
91                m[0*4+2] * (m[1*4+0] * m[2*4+1] - m[1*4+1] * m[2*4+0]);
92    float invDet = 1.f / det;
93    normal[0*3+0] = invDet * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]);
94    normal[1*3+0] = invDet * -(m[0*4+1] * m[2*4+2] - m[0*4+2] * m[2*4+1]);
95    normal[2*3+0] = invDet * (m[0*4+1] * m[1*4+2] - m[0*4+2] * m[1*4+1]);
96    normal[0*3+1] = invDet * -(m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]);
97    normal[1*3+1] = invDet * (m[0*4+0] * m[2*4+2] - m[0*4+2] * m[2*4+0]);
98    normal[2*3+1] = invDet * -(m[0*4+0] * m[1*4+2] - m[1*4+0] * m[0*4+2]);
99    normal[0*3+2] = invDet * (m[1*4+0] * m[2*4+1] - m[2*4+0] * m[1*4+1]);
100    normal[1*3+2] = invDet * -(m[0*4+0] * m[2*4+1] - m[2*4+0] * m[0*4+1]);
101    normal[2*3+2] = invDet * (m[0*4+0] * m[1*4+1] - m[1*4+0] * m[0*4+1]);
102}
103
104
105static int getLocations()
106{
107    int rt = 1;
108#define GET_ATTRIBUTE_LOC(programName, varName) \
109        sShader##programName.varName = \
110        glGetAttribLocation(sShader##programName.program, #varName); \
111        if (sShader##programName.varName == -1) rt = 0
112#define GET_UNIFORM_LOC(programName, varName) \
113        sShader##programName.varName = \
114        glGetUniformLocation(sShader##programName.program, #varName); \
115        if (sShader##programName.varName == -1) rt = 0
116    GET_ATTRIBUTE_LOC(Lit, pos);
117    GET_ATTRIBUTE_LOC(Lit, normal);
118    GET_ATTRIBUTE_LOC(Lit, colorIn);
119    GET_UNIFORM_LOC(Lit, mvp);
120    GET_UNIFORM_LOC(Lit, normalMatrix);
121    GET_UNIFORM_LOC(Lit, ambient);
122    GET_UNIFORM_LOC(Lit, shininess);
123    GET_UNIFORM_LOC(Lit, light_0_direction);
124    GET_UNIFORM_LOC(Lit, light_0_diffuse);
125    GET_UNIFORM_LOC(Lit, light_0_specular);
126    GET_UNIFORM_LOC(Lit, light_1_direction);
127    GET_UNIFORM_LOC(Lit, light_1_diffuse);
128    GET_UNIFORM_LOC(Lit, light_2_direction);
129    GET_UNIFORM_LOC(Lit, light_2_diffuse);
130
131    GET_ATTRIBUTE_LOC(Flat, pos);
132    GET_ATTRIBUTE_LOC(Flat, colorIn);
133    GET_UNIFORM_LOC(Flat, mvp);
134
135    GET_ATTRIBUTE_LOC(Fade, pos);
136    GET_UNIFORM_LOC(Fade, minFade);
137#undef GET_ATTRIBUTE_LOC
138#undef GET_UNIFORM_LOC
139    return rt;
140}
141
142
143int initShaderPrograms()
144{
145    Matrix4x4_LoadIdentity(sModelView);
146    Matrix4x4_LoadIdentity(sProjection);
147
148    sShaderFlat.program = createProgram(sFlatVertexSource,
149                                        sFlatFragmentSource);
150    sShaderLit.program = createProgram(sLitVertexSource,
151                                       sFlatFragmentSource);
152    sShaderFade.program = createProgram(sFadeVertexSource,
153                                        sFlatFragmentSource);
154    if (sShaderFlat.program == 0 || sShaderLit.program == 0 ||
155        sShaderFade.program == 0)
156        return 0;
157
158    return getLocations();
159}
160
161
162void deInitShaderPrograms()
163{
164    glDeleteProgram(sShaderFlat.program);
165    glDeleteProgram(sShaderLit.program);
166    glDeleteProgram(sShaderFade.program);
167}
168
169
170void bindShaderProgram(GLuint program)
171{
172    int loc_mvp = -1;
173    int loc_normalMatrix = -1;
174
175    glUseProgram(program);
176
177    if (program == sShaderLit.program)
178    {
179        loc_mvp = sShaderLit.mvp;
180        loc_normalMatrix = sShaderLit.normalMatrix;
181    }
182    else if (program == sShaderFlat.program)
183    {
184        loc_mvp = sShaderFlat.mvp;
185    }
186
187    if (loc_mvp != -1)
188    {
189        Matrix4x4 mvp;
190        Matrix4x4_Multiply(mvp, sModelView, sProjection);
191        glUniformMatrix4fv(loc_mvp, 1, GL_FALSE, (GLfloat *)mvp);
192    }
193    if (loc_normalMatrix != -1)
194    {
195        Matrix3x3 normalMatrix;
196        computeNormalMatrix(sModelView, normalMatrix);
197        glUniformMatrix3fv(loc_normalMatrix, 1, GL_FALSE,
198                           (GLfloat *)normalMatrix);
199    }
200}
201
202