1/**
2 * Implement glRasterPos + glBitmap with textures + shaders.
3 * Brian Paul
4 * 14 May 2007
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
17static GLuint FragShader;
18static GLuint VertShader;
19static GLuint Program;
20
21static GLint Win = 0;
22static GLint WinWidth = 500, WinHeight = 500;
23static GLboolean Anim = GL_TRUE;
24static GLboolean Bitmap = GL_FALSE;
25static GLfloat Xrot = 20.0f, Yrot = 70.0f;
26static GLint uTex, uScale;
27static GLuint Textures[2];
28
29#define TEX_WIDTH 16
30#define TEX_HEIGHT 8
31
32
33static void
34BitmapText(const char *s)
35{
36   while (*s) {
37      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
38      s++;
39   }
40}
41
42
43static void
44Redisplay(void)
45{
46   static const GLfloat px[3] = { 1.2, 0, 0};
47   static const GLfloat nx[3] = {-1.2, 0, 0};
48
49   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
50
51   glPushMatrix();
52   glRotatef(Xrot, 1.0f, 0.0f, 0.0f);
53   glRotatef(Yrot, 0.0f, 1.0f, 0.0f);
54
55   glEnable(GL_LIGHTING);
56
57   glPushMatrix();
58   glScalef(0.5, 0.5, 0.5);
59   glutSolidDodecahedron();
60   glPopMatrix();
61
62   glDisable(GL_LIGHTING);
63
64   glColor3f(0, 1, 0);
65   glBegin(GL_LINES);
66   glVertex3f(-1, 0, 0);
67   glVertex3f( 1, 0, 0);
68   glEnd();
69
70   glColor3f(1, 1, 0);
71
72   if (Bitmap) {
73      glRasterPos3fv(px);
74      BitmapText("+X");
75      glRasterPos3fv(nx);
76      BitmapText("-X");
77   }
78   else {
79      glUseProgram(Program);
80
81      /* vertex positions (deltas) depend on texture size and window size */
82      if (uScale != -1) {
83         glUniform2f(uScale,
84                          2.0 * TEX_WIDTH / WinWidth,
85                          2.0 * TEX_HEIGHT / WinHeight);
86      }
87
88      /* draw +X */
89      glBindTexture(GL_TEXTURE_2D, Textures[0]);
90      glBegin(GL_QUADS);
91      glTexCoord2f(0, 0);  glVertex3fv(px);
92      glTexCoord2f(1, 0);  glVertex3fv(px);
93      glTexCoord2f(1, 1);  glVertex3fv(px);
94      glTexCoord2f(0, 1);  glVertex3fv(px);
95      glEnd();
96
97      /* draw -X */
98      glBindTexture(GL_TEXTURE_2D, Textures[1]);
99      glBegin(GL_QUADS);
100      glTexCoord2f(0, 0);  glVertex3fv(nx);
101      glTexCoord2f(1, 0);  glVertex3fv(nx);
102      glTexCoord2f(1, 1);  glVertex3fv(nx);
103      glTexCoord2f(0, 1);  glVertex3fv(nx);
104      glEnd();
105
106      glUseProgram(0);
107   }
108
109   glPopMatrix();
110
111   glutSwapBuffers();
112}
113
114
115static void
116Idle(void)
117{
118   Yrot = glutGet(GLUT_ELAPSED_TIME) * 0.01;
119   glutPostRedisplay();
120}
121
122
123static void
124Reshape(int width, int height)
125{
126   WinWidth = width;
127   WinHeight = height;
128   glViewport(0, 0, width, height);
129   glMatrixMode(GL_PROJECTION);
130   glLoadIdentity();
131   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
132   glMatrixMode(GL_MODELVIEW);
133   glLoadIdentity();
134   glTranslatef(0.0f, 0.0f, -10.0f);
135}
136
137
138static void
139Key(unsigned char key, int x, int y)
140{
141  (void) x;
142  (void) y;
143
144   switch(key) {
145   case ' ':
146   case 'a':
147      Anim = !Anim;
148      if (Anim)
149         glutIdleFunc(Idle);
150      else
151         glutIdleFunc(NULL);
152      break;
153   case 'b':
154      Bitmap = !Bitmap;
155      if (Bitmap)
156         printf("Using glBitmap\n");
157      else
158         printf("Using billboard texture\n");
159      break;
160   case 27:
161      glDeleteShader(FragShader);
162      glDeleteShader(VertShader);
163      glDeleteProgram(Program);
164      glutDestroyWindow(Win);
165      exit(0);
166   }
167   glutPostRedisplay();
168}
169
170
171static void
172SpecialKey(int key, int x, int y)
173{
174   const GLfloat step = 0.125f;
175   switch(key) {
176   case GLUT_KEY_UP:
177      Xrot -= step;
178      break;
179   case GLUT_KEY_DOWN:
180      Xrot += step;
181      break;
182   case GLUT_KEY_LEFT:
183      Yrot -= step;
184      break;
185   case GLUT_KEY_RIGHT:
186      Yrot += step;
187      break;
188   }
189   /*printf("Xrot: %f  Yrot: %f\n", Xrot, Yrot);*/
190   glutPostRedisplay();
191}
192
193
194static void
195MakeTexImage(const char *p, GLuint texobj)
196{
197   GLubyte image[TEX_HEIGHT][TEX_WIDTH];
198   GLuint i, j, k;
199
200   for (i = 0; i < TEX_HEIGHT; i++) {
201      for (j = 0; j < TEX_WIDTH; j++) {
202         k = i * TEX_WIDTH + j;
203         if (p[k] == ' ') {
204            image[i][j] = 0;
205         }
206         else {
207            image[i][j] = 255;
208         }
209      }
210   }
211
212   glBindTexture(GL_TEXTURE_2D, texobj);
213   glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, TEX_WIDTH, TEX_HEIGHT, 0,
214                GL_RED, GL_UNSIGNED_BYTE, image);
215   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
216   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
217   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
218}
219
220
221static void
222MakeBitmapTextures(void)
223{
224   const char *px =
225      "        X     X "
226      "   X     X   X  "
227      "   X      X X   "
228      " XXXXX     X    "
229      "   X      X X   "
230      "   X     X   X  "
231      "        X     X "
232      "        X     X ";
233   const char *nx =
234      "        X     X "
235      "         X   X  "
236      "          X X   "
237      " XXXXX     X    "
238      "          X X   "
239      "         X   X  "
240      "        X     X "
241      "        X     X ";
242   glGenTextures(2, Textures);
243   MakeTexImage(px, Textures[0]);
244   MakeTexImage(nx, Textures[1]);
245}
246
247
248static void
249Init(void)
250{
251   /* Fragment shader: modulate raster color by texture, discard fragments
252    * with alpha < 1.0
253    */
254   static const char *fragShaderText =
255      "uniform sampler2D tex2d; \n"
256      "void main() {\n"
257      "   vec4 c = texture2D(tex2d, gl_TexCoord[0].xy); \n"
258      "   if (c.w < 1.0) \n"
259      "      discard; \n"
260      "   gl_FragColor = c * gl_Color; \n"
261      "}\n";
262   /* Vertex shader: compute new vertex position based on incoming vertex pos,
263    * texcoords and special scale factor.
264    */
265   static const char *vertShaderText =
266      "uniform vec2 scale; \n"
267      "void main() {\n"
268      "   vec4 p = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
269      "   gl_Position.xy = p.xy + gl_MultiTexCoord0.xy * scale * p.w; \n"
270      "   gl_Position.zw = p.zw; \n"
271      "   gl_TexCoord[0] = gl_MultiTexCoord0; \n"
272      "   gl_FrontColor = gl_Color; \n"
273      "}\n";
274
275   if (!ShadersSupported())
276      exit(1);
277
278   VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
279   FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
280   Program = LinkShaders(VertShader, FragShader);
281
282   glUseProgram(Program);
283
284   uScale = glGetUniformLocation(Program, "scale");
285   uTex = glGetUniformLocation(Program, "tex2d");
286   if (uTex != -1) {
287      glUniform1i(uTex, 0);  /* tex unit 0 */
288   }
289
290   glUseProgram(0);
291
292   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
293   glEnable(GL_DEPTH_TEST);
294   glEnable(GL_NORMALIZE);
295   glEnable(GL_LIGHT0);
296
297   MakeBitmapTextures();
298}
299
300
301int
302main(int argc, char *argv[])
303{
304   glutInit(&argc, argv);
305   glutInitWindowSize(WinWidth, WinHeight);
306   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
307   Win = glutCreateWindow(argv[0]);
308   glewInit();
309   glutReshapeFunc(Reshape);
310   glutKeyboardFunc(Key);
311   glutSpecialFunc(SpecialKey);
312   glutDisplayFunc(Redisplay);
313   if (Anim)
314      glutIdleFunc(Idle);
315   Init();
316   glutMainLoop();
317   return 0;
318}
319
320
321