1/**
2 * Test variable array indexing in a vertex shader.
3 * Brian Paul
4 * 17 April 2009
5 */
6
7#include <assert.h>
8#include <string.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <math.h>
12#include <GL/glew.h>
13#include "glut_wrap.h"
14#include "shaderutil.h"
15
16
17/**
18 * The vertex position.z is used as a (variable) index into an
19 * array which returns a new Z value.
20 */
21static const char *VertShaderText =
22   "uniform sampler2D tex1; \n"
23   "uniform float HeightArray[20]; \n"
24   "void main() \n"
25   "{ \n"
26   "   vec4 pos = gl_Vertex; \n"
27   "   int i = int(pos.z * 9.5); \n"
28   "   pos.z = HeightArray[i]; \n"
29   "   gl_Position = gl_ModelViewProjectionMatrix * pos; \n"
30   "   gl_FrontColor = pos; \n"
31   "} \n";
32
33static const char *FragShaderText =
34   "void main() \n"
35   "{ \n"
36   "   gl_FragColor = gl_Color; \n"
37   "} \n";
38
39
40static GLuint fragShader;
41static GLuint vertShader;
42static GLuint program;
43
44static GLint win = 0;
45static GLboolean Anim = GL_TRUE;
46static GLboolean WireFrame = GL_TRUE;
47static GLfloat xRot = -70.0f, yRot = 0.0f, zRot = 0.0f;
48
49
50static void
51Idle(void)
52{
53   zRot = 90 + glutGet(GLUT_ELAPSED_TIME) * 0.05;
54   glutPostRedisplay();
55}
56
57
58/** z=f(x,y) */
59static float
60fz(float x, float y)
61{
62   return fabs(cos(1.5*x) + cos(1.5*y));
63}
64
65
66static void
67DrawMesh(void)
68{
69   GLfloat xmin = -2.0, xmax = 2.0;
70   GLfloat ymin = -2.0, ymax = 2.0;
71   GLuint xdivs = 20, ydivs = 20;
72   GLfloat dx = (xmax - xmin) / xdivs;
73   GLfloat dy = (ymax - ymin) / ydivs;
74   GLfloat ds = 1.0 / xdivs, dt = 1.0 / ydivs;
75   GLfloat x, y, s, t;
76   GLuint i, j;
77
78   y = ymin;
79   t = 0.0;
80   for (i = 0; i < ydivs; i++) {
81      x = xmin;
82      s = 0.0;
83      glBegin(GL_QUAD_STRIP);
84      for (j = 0; j < xdivs; j++) {
85         float z0 = fz(x, y), z1 = fz(x, y + dy);
86
87         glTexCoord2f(s, t);
88         glVertex3f(x, y, z0);
89
90         glTexCoord2f(s, t + dt);
91         glVertex3f(x, y + dy, z1);
92         x += dx;
93         s += ds;
94      }
95      glEnd();
96      y += dy;
97      t += dt;
98   }
99}
100
101
102static void
103Redisplay(void)
104{
105   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
106
107   if (WireFrame)
108      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
109   else
110      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
111
112   glPushMatrix();
113   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
114   glRotatef(yRot, 0.0f, 1.0f, 0.0f);
115   glRotatef(zRot, 0.0f, 0.0f, 1.0f);
116
117   glPushMatrix();
118   DrawMesh();
119   glPopMatrix();
120
121   glPopMatrix();
122
123   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
124
125   glutSwapBuffers();
126}
127
128
129static void
130Reshape(int width, int height)
131{
132   glViewport(0, 0, width, height);
133   glMatrixMode(GL_PROJECTION);
134   glLoadIdentity();
135   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
136   glMatrixMode(GL_MODELVIEW);
137   glLoadIdentity();
138   glTranslatef(0.0f, 0.0f, -15.0f);
139}
140
141
142static void
143CleanUp(void)
144{
145   glDeleteShader(fragShader);
146   glDeleteShader(vertShader);
147   glDeleteProgram(program);
148   glutDestroyWindow(win);
149}
150
151
152static void
153Key(unsigned char key, int x, int y)
154{
155   const GLfloat step = 2.0;
156   (void) x;
157   (void) y;
158
159   switch(key) {
160   case 'a':
161      Anim = !Anim;
162      if (Anim)
163         glutIdleFunc(Idle);
164      else
165         glutIdleFunc(NULL);
166      break;
167   case 'w':
168      WireFrame = !WireFrame;
169      break;
170   case 'z':
171      zRot += step;
172      break;
173   case 'Z':
174      zRot -= step;
175      break;
176   case 27:
177      CleanUp();
178      exit(0);
179      break;
180   }
181   glutPostRedisplay();
182}
183
184
185static void
186SpecialKey(int key, int x, int y)
187{
188   const GLfloat step = 2.0;
189
190   (void) x;
191   (void) y;
192
193   switch(key) {
194   case GLUT_KEY_UP:
195      xRot += step;
196      break;
197   case GLUT_KEY_DOWN:
198      xRot -= step;
199      break;
200   case GLUT_KEY_LEFT:
201      yRot -= step;
202      break;
203   case GLUT_KEY_RIGHT:
204      yRot += step;
205      break;
206   }
207   glutPostRedisplay();
208}
209
210
211static void
212Init(void)
213{
214   GLfloat HeightArray[20];
215   GLint u, i;
216
217   if (!ShadersSupported())
218      exit(1);
219
220   vertShader = CompileShaderText(GL_VERTEX_SHADER, VertShaderText);
221   fragShader = CompileShaderText(GL_FRAGMENT_SHADER, FragShaderText);
222   program = LinkShaders(vertShader, fragShader);
223
224   glUseProgram(program);
225
226   /* Setup the HeightArray[] uniform */
227   for (i = 0; i < 20; i++)
228      HeightArray[i] = i / 20.0;
229   u = glGetUniformLocation(program, "HeightArray");
230   glUniform1fv(u, 20, HeightArray);
231
232   assert(glGetError() == 0);
233
234   glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
235   glEnable(GL_DEPTH_TEST);
236   glColor3f(1, 1, 1);
237}
238
239
240int
241main(int argc, char *argv[])
242{
243   glutInit(&argc, argv);
244   glutInitWindowSize(500, 500);
245   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
246   win = glutCreateWindow(argv[0]);
247   glewInit();
248   glutReshapeFunc(Reshape);
249   glutKeyboardFunc(Key);
250   glutSpecialFunc(SpecialKey);
251   glutDisplayFunc(Redisplay);
252   Init();
253   if (Anim)
254      glutIdleFunc(Idle);
255   glutMainLoop();
256   return 0;
257}
258
259