testing compressed cubemaps
[cubetest] / src / main.cc
1 #include <GL/glut.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 static bool init();
8 static void cleanup();
9 static unsigned int load_cubemap();
10
11 static void display();
12 static void reshape(int x, int y);
13 static void keyboard(unsigned char key, int x, int y);
14 static void mouse(int bn, int state, int x, int y);
15 static void motion(int x, int y);
16
17 struct Texture {
18         unsigned int id;
19         int width;
20         int height;
21         unsigned int format;
22         unsigned int size;
23         unsigned char *data;
24 };
25
26 struct Header {
27         char magic[8];
28         uint32_t glfmt;
29         uint16_t flags;
30         uint16_t levels;
31         uint32_t width, height;
32         struct {
33                 uint32_t offset, size;
34         } datadesc[20];
35         char unused[8];
36 };
37
38 static unsigned int cubemap;
39 static float cam_phi, cam_theta;
40
41 int main(int argc, char **argv)
42 {
43         glutInit(&argc, argv);
44         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
45         glutInitWindowSize(1024, 768);
46         glutCreateWindow("cubetest");
47
48         glutDisplayFunc(display);
49         glutReshapeFunc(reshape);
50         glutKeyboardFunc(keyboard);
51         glutMouseFunc(mouse);
52         glutMotionFunc(motion);
53
54         if(!init())
55                 return 1;
56
57         atexit(cleanup);
58
59         glutMainLoop();
60         return 0;
61 }
62
63 static bool load_teximage(const char *fname, Texture *tex)
64 {
65         FILE *fp;
66         if(!(fp = fopen(fname, "rb"))) {
67                 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
68                 return false;
69         }
70
71         Header hdr;
72         if(fread(&hdr, 1, sizeof hdr, fp) != sizeof hdr) {
73                 fprintf(stderr, "failed to read image file header: %s: %s\n", fname, strerror(errno));
74                 fclose(fp);
75                 return false;
76         }
77         if(memcmp(hdr.magic, "COMPTEX0", sizeof hdr.magic) != 0 || hdr.levels < 0 ||
78                         hdr.levels > 20 || !hdr.datadesc[0].size) {
79                 fprintf(stderr, "%s is not a compressed texture file, or is corrupted\n", fname);
80                 fclose(fp);
81                 return false;
82         }
83
84         tex->data = new unsigned char[hdr.datadesc[0].size];
85
86         if(fread(tex->data, 1, hdr.datadesc[0].size, fp) != hdr.datadesc[0].size) {
87                 fprintf(stderr, "unexpected EOF while reading texture: %s\n", fname);
88                 fclose(fp);
89                 delete [] tex->data;
90                 return false;
91         }
92
93         tex->width = hdr.width;
94         tex->height = hdr.height;
95         tex->format = hdr.glfmt;
96         tex->size = hdr.datadesc[0].size;
97
98         fclose(fp);
99
100         return true;
101 }
102
103 static unsigned int load_cubemap()
104 {
105         static const char *names[6] = {"data/right.tex", "data/left.tex", "data/up.tex",
106                                                                    "data/down.tex", "data/back.tex", "data/front.tex"};
107
108         Texture tex;
109         glGenTextures(1, &tex.id);
110         glBindTexture(GL_TEXTURE_CUBE_MAP, tex.id);
111         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
112         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
113         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
114         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
115
116         for(int i=0; i<6; i++) {
117                 if(!load_teximage(names[i], &tex)) {
118                         glDeleteTextures(1, &tex.id);
119                         return 0;
120                 }
121                 unsigned int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
122                 glCompressedTexImage2D(face, 0, tex.format, tex.width, tex.height, 0, tex.size, tex.data); 
123                 delete [] tex.data;
124         }
125
126         return tex.id;
127 }
128
129 static bool init()
130 {
131         if(!(cubemap = load_cubemap())) {
132                 return false;
133         }
134         glEnable(GL_TEXTURE_CUBE_MAP);
135
136         glEnable(GL_TEXTURE_GEN_S);
137         glEnable(GL_TEXTURE_GEN_T);
138         glEnable(GL_TEXTURE_GEN_R);
139
140         float planes[][4] = {{1, 0, 0, 0}, {0,1, 0, 0}, {0, 0, 1, 0}};
141
142         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
143         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
144         glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
145
146         glTexGenfv(GL_S, GL_OBJECT_PLANE, planes[0]);
147         glTexGenfv(GL_T, GL_OBJECT_PLANE, planes[1]);
148         glTexGenfv(GL_R, GL_OBJECT_PLANE, planes[2]);
149
150         return true;
151 }
152
153 static void cleanup()
154 {
155         glDeleteTextures(1, &cubemap);
156 }
157
158 static void display()
159 {
160         glClear(GL_COLOR_BUFFER_BIT);
161
162         glMatrixMode(GL_MODELVIEW);
163         glLoadIdentity();
164         glRotatef(cam_phi, 1, 0, 0);
165         glRotatef(cam_theta, 0, 1, 0);
166
167         glutSolidSphere(10, 10, 5);
168
169         glutSwapBuffers();
170 }
171
172 static void reshape(int x, int y)
173 {
174         glViewport(0, 0, x, y);
175         glMatrixMode(GL_PROJECTION);
176         glLoadIdentity();
177         gluPerspective(45, (float)x / (float)y, 0.5, 100);
178 }
179
180 static void keyboard(unsigned char key, int x, int y)
181 {
182         switch(key) {
183         case 27:
184                 exit(0);
185         default:
186                 break;
187         }
188 }
189
190 static int prev_x, prev_y;
191 static bool bnstate[6];
192
193 static void mouse(int bn, int state, int x, int y)
194 {
195         prev_x = x;
196         prev_y = y;
197         bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN;
198 }
199
200 static void motion(int x, int y)
201 {
202         if(bnstate[0]) {
203                 cam_phi += (y - prev_y) * 0.5;
204                 cam_theta += (x - prev_x) * 0.5;
205
206                 if(cam_phi < -90) cam_phi = -90;
207                 if(cam_phi > 90) cam_phi = 90;
208
209                 glutPostRedisplay();
210         }
211
212         prev_y = y;
213         prev_x = x;
214 }