1/*
2 * (C) Copyright IBM Corporation 2007
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19 * IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25/**
26 * \file arraytexture.c
27 *
28 *
29 * \author Ian Romanick <idr@us.ibm.com>
30 */
31
32#include <assert.h>
33#include <stdlib.h>
34#include <stdio.h>
35#include <string.h>
36#include <math.h>
37#include <GL/glew.h>
38#include "glut_wrap.h"
39
40#if !defined(GL_EXT_texture_array) && !defined(GL_MESA_texture_array)
41# error "This demo requires enums for either GL_EXT_texture_array or GL_MESA_texture_array to build."
42#endif
43
44#include "readtex.h"
45
46#define GL_CHECK_ERROR() \
47    do { \
48       GLenum err = glGetError(); \
49       if (err) { \
50          printf("%s:%u: %s (0x%04x)\n", __FILE__, __LINE__, \
51                    gluErrorString(err), err); \
52       } \
53    } while (0)
54
55static const char *const textures[] = {
56   DEMOS_DATA_DIR "girl.rgb",
57   DEMOS_DATA_DIR "girl2.rgb",
58   DEMOS_DATA_DIR "arch.rgb",
59   DEMOS_DATA_DIR "s128.rgb",
60
61   DEMOS_DATA_DIR "tree3.rgb",
62   DEMOS_DATA_DIR "bw.rgb",
63   DEMOS_DATA_DIR "reflect.rgb",
64   DEMOS_DATA_DIR "wrs_logo.rgb",
65   NULL
66};
67
68static const char frag_prog[] =
69  "!!ARBfp1.0\n"
70  "OPTION MESA_texture_array;\n"
71  "TEX    result.color, fragment.texcoord[0], texture[0], ARRAY2D;\n"
72  "END\n";
73
74static GLfloat Xrot = 0, Yrot = -30, Zrot = 0;
75static GLfloat texZ = 0.0;
76static GLfloat texZ_dir = 0.01;
77static GLint num_layers;
78
79
80static void
81PrintString(const char *s)
82{
83   while (*s) {
84      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
85      s++;
86   }
87}
88
89
90static void Idle(void)
91{
92   static int lastTime = 0;
93   int t = glutGet(GLUT_ELAPSED_TIME);
94
95   if (lastTime == 0)
96      lastTime = t;
97   else if (t - lastTime < 10)
98      return;
99
100   lastTime = t;
101
102   texZ += texZ_dir;
103   if ((texZ < 0.0) || ((GLint) texZ > num_layers)) {
104      texZ_dir = -texZ_dir;
105   }
106
107   glutPostRedisplay();
108}
109
110
111static void Display(void)
112{
113   char str[100];
114
115   glClear(GL_COLOR_BUFFER_BIT);
116
117   glMatrixMode(GL_PROJECTION);
118   glLoadIdentity();
119   glOrtho(-1, 1, -1, 1, -1, 1);
120   glMatrixMode(GL_MODELVIEW);
121   glLoadIdentity();
122
123   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
124   glColor3f(1,1,1);
125   glRasterPos3f(-0.9, -0.9, 0.0);
126   sprintf(str, "Texture Z coordinate = %4.1f", texZ);
127   PrintString(str);
128
129   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 1);
130   GL_CHECK_ERROR();
131   glEnable(GL_TEXTURE_2D_ARRAY_EXT);
132   GL_CHECK_ERROR();
133
134   glMatrixMode(GL_PROJECTION);
135   glLoadIdentity();
136   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
137   glMatrixMode(GL_MODELVIEW);
138   glLoadIdentity();
139   glTranslatef(0.0, 0.0, -8.0);
140
141   glPushMatrix();
142   glRotatef(Xrot, 1, 0, 0);
143   glRotatef(Yrot, 0, 1, 0);
144   glRotatef(Zrot, 0, 0, 1);
145
146   glBegin(GL_QUADS);
147   glTexCoord3f(0.0, 0.0, texZ);  glVertex2f(-1.0, -1.0);
148   glTexCoord3f(2.0, 0.0, texZ);  glVertex2f(1.0, -1.0);
149   glTexCoord3f(2.0, 2.0, texZ);  glVertex2f(1.0,  1.0);
150   glTexCoord3f(0.0, 2.0, texZ);  glVertex2f(-1.0,  1.0);
151   glEnd();
152
153   glPopMatrix();
154
155   glDisable(GL_TEXTURE_2D_ARRAY_EXT);
156   GL_CHECK_ERROR();
157   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
158   GL_CHECK_ERROR();
159
160   glutSwapBuffers();
161}
162
163
164static void Reshape(int width, int height)
165{
166   glViewport(0, 0, width, height);
167}
168
169
170static void Key(unsigned char key, int x, int y)
171{
172   (void) x;
173   (void) y;
174   switch (key) {
175      case 27:
176         exit(0);
177         break;
178   }
179   glutPostRedisplay();
180}
181
182
183static void SpecialKey(int key, int x, int y)
184{
185   const GLfloat step = 3.0;
186   (void) x;
187   (void) y;
188   switch (key) {
189      case GLUT_KEY_UP:
190         Xrot -= step;
191         break;
192      case GLUT_KEY_DOWN:
193         Xrot += step;
194         break;
195      case GLUT_KEY_LEFT:
196         Yrot -= step;
197         break;
198      case GLUT_KEY_RIGHT:
199         Yrot += step;
200         break;
201   }
202   glutPostRedisplay();
203}
204
205
206static int FindLine(const char *program, int position)
207{
208   int i, line = 1;
209   for (i = 0; i < position; i++) {
210      if (program[i] == '\n')
211          line++;
212   }
213   return line;
214}
215
216
217static void
218compile_fragment_program(GLuint id, const char *prog)
219{
220   int errorPos;
221   int err;
222
223   err = glGetError();
224   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, id);
225   glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
226                     strlen(prog), (const GLubyte *) prog);
227
228   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
229   err = glGetError();
230   if (err != GL_NO_ERROR || errorPos != -1) {
231      int l = FindLine(prog, errorPos);
232
233      printf("Fragment Program Error (err=%d, pos=%d line=%d): %s\n",
234             err, errorPos, l,
235             (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
236      exit(0);
237   }
238}
239
240
241static void require_extension(const char *ext)
242{
243   if (!glutExtensionSupported(ext)) {
244      printf("Sorry, %s not supported by this renderer.\n", ext);
245      exit(1);
246   }
247}
248
249
250static void Init(void)
251{
252   const char *const ver_string = (const char *) glGetString(GL_VERSION);
253   unsigned i;
254
255   printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
256   printf("GL_VERSION = %s\n", ver_string);
257
258   require_extension("GL_ARB_fragment_program");
259   require_extension("GL_MESA_texture_array");
260   require_extension("GL_SGIS_generate_mipmap");
261
262   for (num_layers = 0; textures[num_layers] != NULL; num_layers++)
263      /* empty */ ;
264
265   glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 1);
266   glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGB8,
267                256, 256, num_layers, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
268   GL_CHECK_ERROR();
269
270   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_GENERATE_MIPMAP_SGIS,
271                   GL_TRUE);
272
273   for (i = 0; textures[i] != NULL; i++) {
274      GLint width, height;
275      GLenum format;
276
277      GLubyte *image = LoadRGBImage(textures[i], &width, &height, &format);
278      if (!image) {
279         printf("Error: could not load texture image %s\n", textures[i]);
280         exit(1);
281      }
282
283      /* resize to 256 x 256 */
284      if (width != 256 || height != 256) {
285         GLubyte *newImage = malloc(256 * 256 * 4);
286         gluScaleImage(format, width, height, GL_UNSIGNED_BYTE, image,
287                       256, 256, GL_UNSIGNED_BYTE, newImage);
288         free(image);
289         image = newImage;
290      }
291
292      glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0,
293                      0, 0, i, 256, 256, 1,
294                      format, GL_UNSIGNED_BYTE, image);
295      free(image);
296   }
297   GL_CHECK_ERROR();
298
299   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_REPEAT);
300   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_REPEAT);
301   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
302
303   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
304   GL_CHECK_ERROR();
305   glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
306   GL_CHECK_ERROR();
307
308   compile_fragment_program(1, frag_prog);
309   GL_CHECK_ERROR();
310}
311
312
313int main(int argc, char *argv[])
314{
315   glutInit(&argc, argv);
316   glutInitWindowPosition(0, 0);
317   glutInitWindowSize(350, 350);
318   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
319   glutCreateWindow("Array texture test");
320   glewInit();
321   glutReshapeFunc(Reshape);
322   glutKeyboardFunc(Key);
323   glutSpecialFunc(SpecialKey);
324   glutDisplayFunc(Display);
325   glutIdleFunc(Idle);
326   Init();
327   glutMainLoop();
328   return 0;
329}
330