added SDL tests
[glpixels] / glpixels.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include <GL/glut.h>
7
8 #if defined(unix) || defined(__unix__)
9 #include <GL/glx.h>
10
11 #define BUILD_X11
12 #define get_proc_addr(s)        (void (*)())glXGetProcAddress((unsigned char*)(s))
13 #endif
14
15 enum {
16         MODE_POINTS,
17         MODE_DRAWPIX,
18         MODE_TEXQUAD,
19         MODE_TEXTRI,
20
21         NUM_MODES
22 };
23
24 static const char *modestr[] = { "GL_POINTS", "glDrawPixels", "textured quad",
25         "textured triangle"};
26
27 int init(void);
28 void display(void);
29 void idle(void);
30 void reshape(int x, int y);
31 void keyb(unsigned char key, int x, int y);
32 void change_mode(int m);
33
34 int win_width, win_height;
35 int max_xscroll, max_yscroll;
36
37 #define IMG_W   1400
38 #define IMG_H   1200
39 unsigned int img[IMG_W * IMG_H];
40 float *varr, *carr;
41 unsigned int vbo_pos, vbo_col;
42 int varr_sz, carr_sz;
43 unsigned int tex, quad, tri;
44
45 int mode = MODE_POINTS;
46
47 int have_vbo;
48
49 unsigned int start_tm;
50 unsigned int num_frames;
51
52 void (*gl_gen_buffers)(GLsizei, GLuint*);
53 void (*gl_bind_buffer)(GLenum, GLuint);
54 void (*gl_buffer_data)(GLenum, GLsizeiptr, const void*, GLenum);
55 void (*gl_buffer_sub_data)(GLenum, GLintptr, GLsizeiptr, const void *data);
56
57 #ifdef BUILD_X11
58 static Display *dpy;
59 static Window win;
60
61 static void (*glx_swap_interval_ext)(Display*, Window, int);
62 static void (*glx_swap_interval_mesa)(int);
63 static void (*glx_swap_interval_sgi)(int);
64 #endif
65
66
67 int main(int argc, char **argv)
68 {
69         glutInit(&argc, argv);
70         glutInitWindowSize(800, 600);
71         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
72         glutCreateWindow("GL pixel drawing methods");
73
74         change_mode(mode);
75
76         glutDisplayFunc(display);
77         glutReshapeFunc(reshape);
78         glutKeyboardFunc(keyb);
79         glutIdleFunc(idle);
80
81         if(init() == -1) {
82                 return 1;
83         }
84
85         start_tm = glutGet(GLUT_ELAPSED_TIME);
86         glutMainLoop();
87         return 0;
88 }
89
90
91 int init(void)
92 {
93         int i, j, xor, r, g, b;
94         unsigned int *ptr;
95         float *vptr;
96         const char *extstr;
97
98         extstr = (char*)glGetString(GL_EXTENSIONS);
99
100         if(strstr(extstr, "ARB_vertex_buffer_object")) {
101                 if(!(gl_gen_buffers = get_proc_addr("glGenBuffers"))) {
102                         gl_gen_buffers = get_proc_addr("glGenBuffersARB");
103                 }
104                 if(!(gl_bind_buffer = get_proc_addr("glBindBuffer"))) {
105                         gl_bind_buffer = get_proc_addr("glBindBufferARB");
106                 }
107                 if(!(gl_buffer_data = get_proc_addr("glBufferData"))) {
108                         gl_buffer_data = get_proc_addr("glBufferDataARB");
109                 }
110                 if(!(gl_buffer_sub_data = get_proc_addr("glBufferSubData"))) {
111                         gl_buffer_sub_data = get_proc_addr("glBufferSubDataARB");
112                 }
113                 if(gl_gen_buffers && gl_bind_buffer && gl_buffer_data && gl_buffer_sub_data) {
114                         have_vbo = 1;
115                 }
116         }
117         if(have_vbo) {
118                 printf("Using vertex buffer objects for the GL_POINTS test\n");
119         } else {
120                 printf("No VBO extension, using client-side vertex arrays for the GL_POINTS test\n");
121         }
122
123 #ifdef BUILD_X11
124         {
125                 int scr;
126                 XWindowAttributes wattr;
127
128                 dpy = glXGetCurrentDisplay();
129                 win = glXGetCurrentDrawable();
130
131                 XGetWindowAttributes(dpy, win, &wattr);
132                 scr = XScreenNumberOfScreen(wattr.screen);
133
134                 if(!(extstr = glXQueryExtensionsString(dpy, scr))) {
135                         return -1;
136                 }
137         }
138
139         if(strstr(extstr, "GLX_EXT_swap_control") && (glx_swap_interval_ext = get_proc_addr("glXSwapIntervalEXT"))) {
140                 printf("using GLX_EXT_swap_control to disable vsync\n");
141                 glx_swap_interval_ext(dpy, win, 0);
142         } else if(strstr(extstr, "GLX_MESA_swap_control") && (glx_swap_interval_mesa = get_proc_addr("glXSwapIntervalMESA"))) {
143                 printf("using GLX_MESA_swap_control to disable vsync\n");
144                 glx_swap_interval_mesa(0);
145         } else if(strstr(extstr, "GLX_SGI_swap_control") && (glx_swap_interval_sgi = get_proc_addr("glXSwapIntervalSGI"))) {
146                 printf("using GLX_SGI_swap_control to disable vsync\n");
147                 glx_swap_interval_sgi(0);
148         } else {
149                 fprintf(stderr, "No vsync extension found, you might need to disable vsync externally\n");
150         }
151 #endif
152
153
154         ptr = img;
155         for(i=0; i<IMG_H; i++) {
156                 for(j=0; j<IMG_W; j++) {
157                         xor = i ^ j;
158                         r = (xor >> 1) & 0xff;
159                         g = xor & 0xff;
160                         b = (xor << 1) & 0xff;
161                         *ptr++ = r | (g << 8) | (b << 16);
162                 }
163         }
164
165         glPixelStorei(GL_UNPACK_ROW_LENGTH, IMG_W);
166
167         win_width = glutGet(GLUT_WINDOW_WIDTH);
168         win_height = glutGet(GLUT_WINDOW_HEIGHT);
169
170         glGenTextures(1, &tex);
171         glBindTexture(GL_TEXTURE_2D, tex);
172         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
173         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
174         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
175
176         varr_sz = win_width * win_height * sizeof *varr * 2;
177         if(!(varr = malloc(varr_sz))) {
178                 fprintf(stderr, "failed to allocate vertex array\n");
179                 return -1;
180         }
181         carr_sz = win_width * win_height * sizeof *carr * 3;
182         if(!(carr = malloc(carr_sz))) {
183                 fprintf(stderr, "failed to allocate color array\n");
184                 return -1;
185         }
186
187         vptr = varr;
188         for(i=0; i<win_height; i++) {
189                 for(j=0; j<win_width; j++) {
190                         vptr[0] = j;
191                         vptr[1] = i;
192                         vptr += 2;
193                 }
194         }
195
196         if(have_vbo) {
197                 gl_gen_buffers(1, &vbo_pos);
198                 gl_bind_buffer(GL_ARRAY_BUFFER, vbo_pos);
199                 gl_buffer_data(GL_ARRAY_BUFFER, varr_sz, varr, GL_STATIC_DRAW);
200
201                 gl_gen_buffers(1, &vbo_col);
202                 gl_bind_buffer(GL_ARRAY_BUFFER, vbo_col);
203                 gl_buffer_data(GL_ARRAY_BUFFER, carr_sz, 0, GL_STREAM_DRAW);
204         }
205
206         quad = glGenLists(1);
207         glNewList(quad, GL_COMPILE);
208         glBegin(GL_QUADS);
209         glTexCoord2f(0, 0); glVertex2f(0, 0);
210         glTexCoord2f(1, 0); glVertex2f(1, 0);
211         glTexCoord2f(1, 1); glVertex2f(1, 1);
212         glTexCoord2f(0, 1); glVertex2f(0, 1);
213         glEnd();
214         glEndList();
215
216         tri = glGenLists(1);
217         glNewList(tri, GL_COMPILE);
218         glBegin(GL_TRIANGLES);
219         glTexCoord2f(0, 0); glVertex2f(0, 0);
220         glTexCoord2f(2, 0); glVertex2f(2, 0);
221         glTexCoord2f(0, 2); glVertex2f(0, 2);
222         glEnd();
223         glEndList();
224
225         return 0;
226 }
227
228 void display(void)
229 {
230         int i, j;
231         unsigned int tm = glutGet(GLUT_ELAPSED_TIME);
232         unsigned int interv;
233         float t = tm / 256.0f;
234         int xoffs = (int)((sin(t) * 0.5f + 0.5f) * max_xscroll);
235         int yoffs = (int)((cos(t) * 0.5f + 0.5f) * max_yscroll);
236         unsigned int *start = img + yoffs * IMG_W + xoffs;
237         float *vptr = varr;
238
239         glMatrixMode(GL_MODELVIEW);
240         glLoadIdentity();
241
242         switch(mode) {
243         case MODE_POINTS:
244                 /* draw with points */
245                 vptr = carr;
246                 for(i=0; i<win_height; i++) {
247                         for(j=0; j<win_width; j++) {
248                                 int r = start[j] & 0xff;
249                                 int g = (start[j] >> 8) & 0xff;
250                                 int b = (start[j] >> 16) & 0xff;
251                                 vptr[0] = r / 255.0f;
252                                 vptr[1] = g / 255.0f;
253                                 vptr[2] = b / 255.0f;
254                                 vptr += 3;
255                         }
256                         start += IMG_W;
257                 }
258
259                 if(have_vbo) {
260                         gl_bind_buffer(GL_ARRAY_BUFFER, vbo_pos);
261                         glVertexPointer(2, GL_FLOAT, 0, 0);
262                         gl_bind_buffer(GL_ARRAY_BUFFER, vbo_col);
263                         gl_buffer_sub_data(GL_ARRAY_BUFFER, 0, carr_sz, carr);
264                         glColorPointer(3, GL_FLOAT, 0, 0);
265                         gl_bind_buffer(GL_ARRAY_BUFFER, 0);
266                 } else {
267                         glVertexPointer(2, GL_FLOAT, 0, varr);
268                         glColorPointer(3, GL_FLOAT, 0, carr);
269                 }
270
271                 glEnableClientState(GL_VERTEX_ARRAY);
272                 glEnableClientState(GL_COLOR_ARRAY);
273
274                 glDrawArrays(GL_POINTS, 0, win_width * win_height);
275
276                 glDisableClientState(GL_VERTEX_ARRAY);
277                 glDisableClientState(GL_COLOR_ARRAY);
278                 break;
279
280         case MODE_DRAWPIX:
281                 /* draw with glDrawPixels */
282                 glDrawPixels(win_width, win_height, GL_RGBA, GL_UNSIGNED_BYTE, start);
283                 break;
284
285         case MODE_TEXQUAD:
286         case MODE_TEXTRI:
287                 /* draw with textured quad or triangle */
288                 glBindTexture(GL_TEXTURE_2D, tex);
289                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, win_width, win_height, GL_RGBA,
290                                 GL_UNSIGNED_BYTE, start);
291                 glEnable(GL_TEXTURE_2D);
292                 glScalef(win_width, win_height, 1);
293                 glCallList(mode == MODE_TEXQUAD ? quad : tri);
294                 glDisable(GL_TEXTURE_2D);
295                 break;
296         }
297
298         glutSwapBuffers();
299         assert(glGetError() == GL_NO_ERROR);
300
301         num_frames++;
302         tm = glutGet(GLUT_ELAPSED_TIME);
303         interv = tm - start_tm;
304         if(interv >= 4000) {
305                 unsigned int fps = 100000 * num_frames / interv;
306                 printf("%s: %.2f fps\n", modestr[mode], fps / 100.0f);
307                 num_frames = 0;
308                 start_tm = tm;
309
310                 if(mode < NUM_MODES - 1) {
311                         change_mode(mode + 1);
312                 } else {
313                         exit(0);
314                 }
315         }
316 }
317
318 void idle(void)
319 {
320         glutPostRedisplay();
321 }
322
323 void reshape(int x, int y)
324 {
325         glViewport(0, 0, x, y);
326
327         glMatrixMode(GL_PROJECTION);
328         glLoadIdentity();
329         glOrtho(0, x, 0, y, -1, 1);
330
331         win_width = x;
332         win_height = y;
333         max_xscroll = IMG_W - win_width;
334         max_yscroll = IMG_H - win_height;
335         if(max_xscroll < 0) max_xscroll = 0;
336         if(max_yscroll < 0) max_yscroll = 0;
337 }
338
339 void keyb(unsigned char key, int x, int y)
340 {
341         switch(key) {
342         case 27:
343                 exit(0);
344
345         case ' ':
346                 change_mode((mode + 1) % NUM_MODES);
347                 break;
348
349         default:
350                 break;
351         }
352 }
353
354 void change_mode(int m)
355 {
356         char title[128];
357         mode = m;
358         sprintf(title, "GL pixel drawing test: %s\n", modestr[mode]);
359         glutSetWindowTitle(title);
360 }