summaryrefslogtreecommitdiffstats
path: root/progs/util/shaderutil.c
blob: 4f17dd7efa15ae8fefdaac1b90338a56956b5ab0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
 * Utilities for OpenGL shading language
 *
 * Brian Paul
 * 9 April 2008
 */


#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include "extfuncs.h"
#include "shaderutil.h"


static void
Init(void)
{
   static GLboolean firstCall = GL_TRUE;
   if (firstCall) {
      GetExtensionFuncs();
      firstCall = GL_FALSE;
   }
}


GLboolean
ShadersSupported(void)
{
   const char *version = (const char *) glGetString(GL_VERSION);
   if (version[0] == '2' && version[1] == '.') {
      return GL_TRUE;
   }
   else if (glutExtensionSupported("GL_ARB_vertex_shader")
            && glutExtensionSupported("GL_ARB_fragment_shader")
            && glutExtensionSupported("GL_ARB_shader_objects")) {
      fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x.  This may not work.\n");
      return GL_TRUE;
   }
   return GL_TRUE;
}


GLuint
CompileShaderText(GLenum shaderType, const char *text)
{
   GLuint shader;
   GLint stat;

   Init();

   shader = glCreateShader_func(shaderType);
   glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
   glCompileShader_func(shader);
   glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
   if (!stat) {
      GLchar log[1000];
      GLsizei len;
      glGetShaderInfoLog_func(shader, 1000, &len, log);
      fprintf(stderr, "Error: problem compiling shader: %s\n", log);
      exit(1);
   }
   else {
      /*printf("Shader compiled OK\n");*/
   }
   return shader;
}


/**
 * Read a shader from a file.
 */
GLuint
CompileShaderFile(GLenum shaderType, const char *filename)
{
   const int max = 100*1000;
   int n;
   char *buffer = (char*) malloc(max);
   GLuint shader;

   FILE *f = fopen(filename, "r");
   if (!f) {
      return 0;
   }

   n = fread(buffer, 1, max, f);
   /*printf("read %d bytes from shader file %s\n", n, filename);*/
   if (n > 0) {
      buffer[n] = 0;
      shader = CompileShaderText(shaderType, buffer);
   }
   else {
      return 0;
   }

   fclose(f);
   free(buffer);

   return shader;
}


GLuint
LinkShaders(GLuint vertShader, GLuint fragShader)
{
   GLuint program = glCreateProgram_func();

   glAttachShader_func(program, fragShader);
   glAttachShader_func(program, vertShader);
   glLinkProgram_func(program);

   /* check link */
   {
      GLint stat;
      glGetProgramiv_func(program, GL_LINK_STATUS, &stat);
      if (!stat) {
         GLchar log[1000];
         GLsizei len;
         glGetProgramInfoLog_func(program, 1000, &len, log);
         fprintf(stderr, "Shader link error:\n%s\n", log);
         return 0;
      }
   }

   return program;
}


void
InitUniforms(GLuint program, struct uniform_info uniforms[])
{
   GLuint i;

   for (i = 0; uniforms[i].name; i++) {
      uniforms[i].location
         = glGetUniformLocation_func(program, uniforms[i].name);

      printf("Uniform %s location: %d\n", uniforms[i].name,
             uniforms[i].location);

      switch (uniforms[i].size) {
      case 1:
         if (uniforms[i].type == GL_INT)
            glUniform1i_func(uniforms[i].location,
                             (GLint) uniforms[i].value[0]);
         else
            glUniform1fv_func(uniforms[i].location, 1, uniforms[i].value);
         break;
      case 2:
         glUniform2fv_func(uniforms[i].location, 1, uniforms[i].value);
         break;
      case 3:
         glUniform3fv_func(uniforms[i].location, 1, uniforms[i].value);
         break;
      case 4:
         glUniform4fv_func(uniforms[i].location, 1, uniforms[i].value);
         break;
      default:
         abort();
      }
   }
}