blob: 1db92b5512a811600d92124fa335d7625144cd95 [file] [log] [blame]
Brian87002ab2007-12-18 16:21:49 -07001/**
2 * Test two-sided lighting with shaders.
3 * Both GL_VERTEX_PROGRAM_TWO_SIDE and gl_FrontFacing can be tested
4 * (see keys below).
5 *
6 * Brian Paul
7 * 18 Dec 2007
8 */
9
10#include <assert.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <math.h>
15#include <GL/gl.h>
16#include <GL/glut.h>
17#include <GL/glext.h>
18#include "extfuncs.h"
19
20
21static const char *Prog = "twoside";
22static GLint WinWidth = 300, WinHeight = 300;
23static char *FragProgFile = NULL;
24static char *VertProgFile = NULL;
25static GLuint fragShader;
26static GLuint vertShader;
27static GLuint program;
28static GLint win = 0;
29static GLboolean anim = 0*GL_TRUE;
30static GLboolean DetermineInFragProg = GL_TRUE;
31static GLfloat Yrot = 0.0f;
32static GLint u_fragface;
33static GLenum FrontWinding = GL_CCW;
34static int prevTime = 0;
35
36
37static const GLfloat Red[4] = {1, 0, 0, 0};
38static const GLfloat Green[4] = {0, 1, 0, 0};
39
40
41static void
42Redisplay(void)
43{
44 float xmin = -1, xmax = 1, ymin = -1, ymax = 1;
45
46 glFrontFace(FrontWinding);
47
48 if (DetermineInFragProg) {
49 glUniform1i_func(u_fragface, 1);
50 glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
51 }
52 else {
53 glUniform1i_func(u_fragface, 0);
54 glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
55 }
56
57 glClear(GL_COLOR_BUFFER_BIT);
58
59 glPushMatrix();
60 glRotatef(Yrot, 0, 1, 0);
61
62 glBegin(GL_POLYGON);
63 glColor4fv(Red);
64 glSecondaryColor3fv_func(Green);
65 glVertex2f(xmin, ymin);
66 glVertex2f(xmax, ymin);
67 glVertex2f(xmax, ymax);
68 glVertex2f(xmin, ymax);
69 glEnd();
70
71 glPopMatrix();
72
73 glutSwapBuffers();
74}
75
76
77static void
78Idle(void)
79{
80 int curTime = glutGet(GLUT_ELAPSED_TIME);
81 int dt = curTime - prevTime;
82
83 if (prevTime == 0) {
84 prevTime = curTime;
85 return;
86 }
87 prevTime = curTime;
88
89 Yrot += dt * 0.1;
90 glutPostRedisplay();
91}
92
93
94static void
95Reshape(int width, int height)
96{
97 float ar = (float) width / height;
98 glViewport(0, 0, width, height);
99 glMatrixMode(GL_PROJECTION);
100 glLoadIdentity();
101 glFrustum(-ar, ar, -1, 1, 5, 15);
102 glMatrixMode(GL_MODELVIEW);
103 glLoadIdentity();
104 glTranslatef(0, 0, -10);
105}
106
107
108static void
109CleanUp(void)
110{
111 glDeleteShader_func(fragShader);
112 glDeleteShader_func(vertShader);
113 glDeleteProgram_func(program);
114 glutDestroyWindow(win);
115}
116
117
118static void
119Key(unsigned char key, int x, int y)
120{
121 (void) x;
122 (void) y;
123
124 switch(key) {
125 case ' ':
126 case 'a':
127 anim = !anim;
128 if (anim) {
129 prevTime = glutGet(GLUT_ELAPSED_TIME);
130 glutIdleFunc(Idle);
131 }
132 else
133 glutIdleFunc(NULL);
134 break;
135 case 'f':
136 printf("Using frag shader gl_FrontFacing\n");
137 DetermineInFragProg = GL_TRUE;
138 break;
139 case 'v':
140 printf("Using vert shader Two-sided lighting\n");
141 DetermineInFragProg = GL_FALSE;
142 break;
143 case 'r':
144 Yrot = 0;
145 anim = 0;
146 glutIdleFunc(NULL);
147 break;
148 case 's':
149 Yrot += 5;
150 break;
151 case 'w':
152 if (FrontWinding == GL_CCW) {
153 FrontWinding = GL_CW;
154 printf("FrontFace = GL_CW\n");
155 }
156 else {
157 FrontWinding = GL_CCW;
158 printf("FrontFace = GL_CCW\n");
159 }
160 break;
161 case 27:
162 CleanUp();
163 exit(0);
164 break;
165 }
166 glutPostRedisplay();
167}
168
169
170static void
171LoadAndCompileShader(GLuint shader, const char *text)
172{
173 GLint stat;
174
175 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
176
177 glCompileShader_func(shader);
178
179 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
180 if (!stat) {
181 GLchar log[1000];
182 GLsizei len;
183 glGetShaderInfoLog_func(shader, 1000, &len, log);
184 fprintf(stderr, "%s: problem compiling shader:\n%s\n", Prog, log);
185 exit(1);
186 }
187}
188
189
190/**
191 * Read a shader from a file.
192 */
193static void
194ReadShader(GLuint shader, const char *filename)
195{
196 const int max = 100*1000;
197 int n;
198 char *buffer = (char*) malloc(max);
199 FILE *f = fopen(filename, "r");
200 if (!f) {
201 fprintf(stderr, "%s: Unable to open shader file %s\n", Prog, filename);
202 exit(1);
203 }
204
205 n = fread(buffer, 1, max, f);
206 printf("%s: read %d bytes from shader file %s\n", Prog, n, filename);
207 if (n > 0) {
208 buffer[n] = 0;
209 LoadAndCompileShader(shader, buffer);
210 }
211
212 fclose(f);
213 free(buffer);
214}
215
216
217static void
218CheckLink(GLuint prog)
219{
220 GLint stat;
221 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
222 if (!stat) {
223 GLchar log[1000];
224 GLsizei len;
225 glGetProgramInfoLog_func(prog, 1000, &len, log);
226 fprintf(stderr, "Linker error:\n%s\n", log);
227 }
228}
229
230
231static void
232Init(void)
233{
234 static const char *fragShaderText =
235 "uniform bool fragface; \n"
236 "void main() { \n"
237 " if (!fragface || gl_FrontFacing) { \n"
238 " gl_FragColor = gl_Color; \n"
239 " } \n"
240 " else { \n"
241 " gl_FragColor = 0.8 * gl_SecondaryColor; \n"
242 " } \n"
243 "} \n";
244 static const char *vertShaderText =
245 "uniform bool fragface; \n"
246 "void main() { \n"
247 " gl_FrontColor = gl_Color; \n"
248 " if (fragface) { \n"
249 " // front/back chosen in frag prog \n"
250 " gl_FrontSecondaryColor = gl_SecondaryColor; \n"
251 " } \n"
252 " else { \n"
253 " // front/back chosen in prim setup \n"
254 " gl_BackColor = gl_SecondaryColor; \n"
255 " } \n"
256 " gl_Position = ftransform(); \n"
257 "} \n";
258 const char *version;
259
260 version = (const char *) glGetString(GL_VERSION);
261 if (version[0] != '2' || version[1] != '.') {
262 printf("This program requires OpenGL 2.x, found %s\n", version);
263 exit(1);
264 }
265
266 GetExtensionFuncs();
267
268 fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
269 if (FragProgFile)
270 ReadShader(fragShader, FragProgFile);
271 else
272 LoadAndCompileShader(fragShader, fragShaderText);
273
274 vertShader = glCreateShader_func(GL_VERTEX_SHADER);
275 if (VertProgFile)
276 ReadShader(vertShader, VertProgFile);
277 else
278 LoadAndCompileShader(vertShader, vertShaderText);
279
280 program = glCreateProgram_func();
281 glAttachShader_func(program, fragShader);
282 glAttachShader_func(program, vertShader);
283 glLinkProgram_func(program);
284 CheckLink(program);
285 glUseProgram_func(program);
286
287 u_fragface = glGetUniformLocation_func(program, "fragface");
288 printf("Uniforms: %d\n", u_fragface);
289
290 /*assert(glGetError() == 0);*/
291
292 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
293
294 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
295
296 assert(glIsProgram_func(program));
297 assert(glIsShader_func(fragShader));
298 assert(glIsShader_func(vertShader));
299}
300
301
302static void
303ParseOptions(int argc, char *argv[])
304{
305 int i;
306 for (i = 1; i < argc; i++) {
307 if (strcmp(argv[i], "-fs") == 0) {
308 FragProgFile = argv[i+1];
309 }
310 else if (strcmp(argv[i], "-vs") == 0) {
311 VertProgFile = argv[i+1];
312 }
313 }
314}
315
316
317static void
318Usage(void)
319{
320 printf("Keys:\n");
321 printf(" f - do front/back determination in fragment shader\n");
322 printf(" v - do front/back determination in vertex shader\n");
323 printf(" r - reset, show front\n");
324 printf(" a - toggle animation\n");
325 printf(" s - step rotation\n");
326 printf(" w - toggle CW, CCW front-face winding\n");
327}
328
329
330int
331main(int argc, char *argv[])
332{
333 glutInit(&argc, argv);
334 glutInitWindowPosition( 0, 0);
335 glutInitWindowSize(WinWidth, WinHeight);
336 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
337 win = glutCreateWindow(argv[0]);
338 glutReshapeFunc(Reshape);
339 glutKeyboardFunc(Key);
340 glutDisplayFunc(Redisplay);
341 if (anim)
342 glutIdleFunc(Idle);
343 ParseOptions(argc, argv);
344 Init();
345 Usage();
346 glutMainLoop();
347 return 0;
348}