added stb, more binaryout changes"
[henge/apc.git] / stb / tests / caveview / stb_gl.h
1 // stbgl - v0.04 - Sean Barrett 2008 - public domain
2 //
3 // Note that the gl extensions support requires glext.h. In fact, it works
4 // if you just concatenate glext.h onto the end of this file. In that case,
5 // this file is covered by the SGI FreeB license, and is not public domain.
6 //
7 // Extension usage:
8 //
9 // 1. Make a file called something like "extlist.txt" which contains stuff like:
10 // GLE(ShaderSourceARB,SHADERSOURCEARB)
11 // GLE(Uniform1iARB,UNIFORM1IARB)
12 // GLARB(ActiveTexture,ACTIVETEXTURE) // same as GLE(ActiveTextureARB,ACTIVETEXTUREARB)
13 // GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE)
14 // GLE(MultiTexCoord2f,MULTITEXCOORD2F)
15 //
16 // 2. To declare functions (to make a header file), do this:
17 // #define STB_GLEXT_DECLARE "extlist.txt"
18 // #include "stb_gl.h"
19 //
20 // A good way to do this is to define STB_GLEXT_DECLARE project-wide.
21 //
22 // 3. To define functions (implement), do this in some C file:
23 // #define STB_GLEXT_DEFINE "extlist.txt"
24 // #include "stb_gl.h"
25 //
26 // If you've already defined STB_GLEXT_DECLARE, you can just do:
27 // #define STB_GLEXT_DEFINE_DECLARE
28 // #include "stb_gl.h"
29 //
30 // 4. Now you need to initialize:
31 //
32 // stbgl_initExtensions();
33
34
35 #ifndef INCLUDE_STB_GL_H
36 #define INCLUDE_STB_GL_H
37
38 #define STB_GL
39
40 #ifdef _WIN32
41 #ifndef WINGDIAPI
42 #define CALLBACK __stdcall
43 #define WINGDIAPI __declspec(dllimport)
44 #define APIENTRY __stdcall
45 #endif
46 #endif //_WIN32
47
48 #include <stddef.h>
49
50 #include <gl/gl.h>
51 #include <gl/glu.h>
52
53 #ifndef M_PI
54 #define M_PI 3.14159265358979323846f
55 #endif
56
57 #ifdef __cplusplus
58 extern "C" {
59 #endif
60
61 // like gluPerspective, but:
62 // fov is chosen to satisfy both hfov <= max_hfov & vfov <= max_vfov;
63 // set one to 179 or 0 to ignore it
64 // zoom is applied separately, so you can do linear zoom without
65 // mucking with trig with fov; 1 -> use exact fov
66 // 'aspect' is inferred from the current viewport, and ignores the
67 // possibility of non-square pixels
68 extern void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar);
69 extern void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float max_hfov, float max_vfov, float znear, float zfar);
70 extern void stbgl_initCamera_zup_facing_x(void);
71 extern void stbgl_initCamera_zup_facing_y(void);
72 extern void stbgl_positionCameraWithEulerAngles(float *loc, float *ang);
73 extern void stbgl_drawRect(float x0, float y0, float x1, float y1);
74 extern void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1);
75 extern void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw);
76
77 extern int stbgl_hasExtension(char *ext);
78 extern void stbgl_SimpleLight(int index, float bright, float x, float y, float z);
79 extern void stbgl_GlobalAmbient(float r, float g, float b);
80
81 extern int stbgl_LoadTexture(char *filename, char *props); // only if stb_image is available
82
83 extern int stbgl_TestTexture(int w);
84 extern int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2);
85 extern unsigned int stbgl_rand(void); // internal, but exposed just in case; LCG, so use middle bits
86
87 extern int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props);
88 extern int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data);
89 // "props" is a series of characters (and blocks of characters), a la fopen()'s mode,
90 // e.g.:
91 // GLuint texid = stbgl_LoadTexture("myfile.jpg", "mbc")
92 // means: load the image "myfile.jpg", and do the following:
93 // generate mipmaps
94 // use bilinear filtering (not trilinear)
95 // use clamp-to-edge on both channels
96 //
97 // input descriptor: AT MOST ONE
98 // TEXT MEANING
99 // 1 1 channel of input (intensity/alpha)
100 // 2 2 channels of input (luminance, alpha)
101 // 3 3 channels of input (RGB)
102 // 4 4 channels of input (RGBA)
103 // l 1 channel of input (luminance)
104 // a 1 channel of input (alpha)
105 // la 2 channels of input (lum/alpha)
106 // rgb 3 channels of input (RGB)
107 // ycocg 3 channels of input (YCoCg - forces YCoCg output)
108 // ycocgj 4 channels of input (YCoCgJunk - forces YCoCg output)
109 // rgba 4 channels of input (RGBA)
110 //
111 // output descriptor: AT MOST ONE
112 // TEXT MEANING
113 // A 1 channel of output (alpha)
114 // I 1 channel of output (intensity)
115 // LA 2 channels of output (lum/alpha)
116 // RGB 3 channels of output (RGB)
117 // RGBA 4 channels of output (RGBA)
118 // DXT1 encode as a DXT1 texture (RGB unless input has RGBA)
119 // DXT3 encode as a DXT3 texture
120 // DXT5 encode as a DXT5 texture
121 // YCoCg encode as a DXT5 texture with Y in alpha, CoCg in RG
122 // D GL_DEPTH_COMPONENT
123 // NONE no input/output, don't call TexImage2D at all
124 //
125 // when reading from a file or using another interface with an explicit
126 // channel count, the input descriptor is ignored and instead the channel
127 // count is used as the input descriptor. if the file read is a DXT DDS,
128 // then it is passed directly to OpenGL in the file format.
129 //
130 // if an input descriptor is supplied but no output descriptor, the output
131 // is assumed to be the same as the input. if an output descriptor is supplied
132 // but no input descriptor, the input is assumed to be the same as the
133 // output. if neither is supplied, the input is assumed to be 4-channel.
134 // If DXT1 or YCoCG output is requested with no input, the input is assumed
135 // to be 4-channel but the alpha channel is ignored.
136 //
137 // filtering descriptor (default is no mipmaps)
138 // TEXT MEANING
139 // m generate mipmaps
140 // M mipmaps are provided, concatenated at end of data (from largest to smallest)
141 // t use trilinear filtering (default if mipmapped)
142 // b use bilinear filtering (default if not-mipmapped)
143 // n use nearest-neighbor sampling
144 //
145 // wrapping descriptor
146 // TEXT MEANING
147 // w wrap (default)
148 // c clamp-to-edge
149 // C GL_CLAMP (uses border color)
150 //
151 // If only one wrapping descriptor is supplied, it is applied to both channels.
152 //
153 // special:
154 // TEXT MEANING
155 // f input data is floats (default unsigned bytes)
156 // F input&output data is floats (default unsigned bytes)
157 // p explicitly pre-multiply the alpha
158 // P pad to power-of-two (default stretches)
159 // NP2 non-power-of-two
160 // + can overwrite the texture data with temp data
161 // ! free the texture data with "free"
162 //
163 // the properties string can also include spaces
164
165 #ifdef __cplusplus
166 }
167 #endif
168
169
170 #ifdef STB_GL_IMPLEMENTATION
171 #include <math.h>
172 #include <stdlib.h>
173 #include <assert.h>
174 #include <memory.h>
175
176 int stbgl_hasExtension(char *ext)
177 {
178 const char *s = glGetString(GL_EXTENSIONS);
179 for(;;) {
180 char *e = ext;
181 for (;;) {
182 if (*e == 0) {
183 if (*s == 0 || *s == ' ') return 1;
184 break;
185 }
186 if (*s != *e)
187 break;
188 ++s, ++e;
189 }
190 while (*s && *s != ' ') ++s;
191 if (!*s) return 0;
192 ++s; // skip space
193 }
194 }
195
196 void stbgl_drawRect(float x0, float y0, float x1, float y1)
197 {
198 glBegin(GL_POLYGON);
199 glTexCoord2f(0,0); glVertex2f(x0,y0);
200 glTexCoord2f(1,0); glVertex2f(x1,y0);
201 glTexCoord2f(1,1); glVertex2f(x1,y1);
202 glTexCoord2f(0,1); glVertex2f(x0,y1);
203 glEnd();
204 }
205
206 void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1)
207 {
208 glBegin(GL_POLYGON);
209 glTexCoord2f(s0,t0); glVertex2f(x0,y0);
210 glTexCoord2f(s1,t0); glVertex2f(x1,y0);
211 glTexCoord2f(s1,t1); glVertex2f(x1,y1);
212 glTexCoord2f(s0,t1); glVertex2f(x0,y1);
213 glEnd();
214 }
215
216 void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw)
217 {
218 float x0,y0,z0,x1,y1,z1;
219 sx /=2, sy/=2, sz/=2;
220 x0 = x-sx; y0 = y-sy; z0 = z-sz;
221 x1 = x+sx; y1 = y+sy; z1 = z+sz;
222
223 glBegin(GL_QUADS);
224 if (cw) {
225 glNormal3f(0,0,-1);
226 glTexCoord2f(0,0); glVertex3f(x0,y0,z0);
227 glTexCoord2f(1,0); glVertex3f(x1,y0,z0);
228 glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
229 glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
230
231 glNormal3f(0,0,1);
232 glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
233 glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
234 glTexCoord2f(1,1); glVertex3f(x0,y1,z1);
235 glTexCoord2f(0,1); glVertex3f(x1,y1,z1);
236
237 glNormal3f(-1,0,0);
238 glTexCoord2f(0,0); glVertex3f(x0,y1,z1);
239 glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
240 glTexCoord2f(1,1); glVertex3f(x0,y0,z0);
241 glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
242
243 glNormal3f(1,0,0);
244 glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
245 glTexCoord2f(1,0); glVertex3f(x1,y1,z1);
246 glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
247 glTexCoord2f(0,1); glVertex3f(x1,y0,z0);
248
249 glNormal3f(0,-1,0);
250 glTexCoord2f(0,0); glVertex3f(x0,y0,z1);
251 glTexCoord2f(1,0); glVertex3f(x1,y0,z1);
252 glTexCoord2f(1,1); glVertex3f(x1,y0,z0);
253 glTexCoord2f(0,1); glVertex3f(x0,y0,z0);
254
255 glNormal3f(0,1,0);
256 glTexCoord2f(0,0); glVertex3f(x1,y1,z1);
257 glTexCoord2f(1,0); glVertex3f(x0,y1,z1);
258 glTexCoord2f(1,1); glVertex3f(x0,y1,z0);
259 glTexCoord2f(0,1); glVertex3f(x1,y1,z0);
260 } else {
261 glNormal3f(0,0,-1);
262 glTexCoord2f(0,0); glVertex3f(x0,y0,z0);
263 glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
264 glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
265 glTexCoord2f(1,0); glVertex3f(x1,y0,z0);
266
267 glNormal3f(0,0,1);
268 glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
269 glTexCoord2f(0,1); glVertex3f(x1,y1,z1);
270 glTexCoord2f(1,1); glVertex3f(x0,y1,z1);
271 glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
272
273 glNormal3f(-1,0,0);
274 glTexCoord2f(0,0); glVertex3f(x0,y1,z1);
275 glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
276 glTexCoord2f(1,1); glVertex3f(x0,y0,z0);
277 glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
278
279 glNormal3f(1,0,0);
280 glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
281 glTexCoord2f(0,1); glVertex3f(x1,y0,z0);
282 glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
283 glTexCoord2f(1,0); glVertex3f(x1,y1,z1);
284
285 glNormal3f(0,-1,0);
286 glTexCoord2f(0,0); glVertex3f(x0,y0,z1);
287 glTexCoord2f(0,1); glVertex3f(x0,y0,z0);
288 glTexCoord2f(1,1); glVertex3f(x1,y0,z0);
289 glTexCoord2f(1,0); glVertex3f(x1,y0,z1);
290
291 glNormal3f(0,1,0);
292 glTexCoord2f(0,0); glVertex3f(x1,y1,z1);
293 glTexCoord2f(0,1); glVertex3f(x1,y1,z0);
294 glTexCoord2f(1,1); glVertex3f(x0,y1,z0);
295 glTexCoord2f(1,0); glVertex3f(x0,y1,z1);
296 }
297 glEnd();
298 }
299
300 void stbgl_SimpleLight(int index, float bright, float x, float y, float z)
301 {
302 float d = (float) (1.0f/sqrt(x*x+y*y+z*z));
303 float dir[4] = { x*d,y*d,z*d,0 }, zero[4] = { 0,0,0,0 };
304 float c[4] = { bright,bright,bright,0 };
305 GLuint light = GL_LIGHT0 + index;
306 glLightfv(light, GL_POSITION, dir);
307 glLightfv(light, GL_DIFFUSE, c);
308 glLightfv(light, GL_AMBIENT, zero);
309 glLightfv(light, GL_SPECULAR, zero);
310 glEnable(light);
311 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
312 glEnable(GL_COLOR_MATERIAL);
313 }
314
315 void stbgl_GlobalAmbient(float r, float g, float b)
316 {
317 float v[4] = { r,g,b,0 };
318 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v);
319 }
320
321
322 #define stbgl_rad2deg(r) ((r)*180.0f / M_PI)
323 #define stbgl_deg2rad(r) ((r)/180.0f * M_PI)
324
325 void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar)
326 {
327 float unit_width, unit_height, aspect, vfov;
328 int data[4],w,h;
329 glGetIntegerv(GL_VIEWPORT, data);
330 w = data[2];
331 h = data[3];
332 aspect = (float) w / h;
333
334 if (max_hfov <= 0) max_hfov = 179;
335 if (max_vfov <= 0) max_vfov = 179;
336
337 // convert max_hfov, max_vfov to worldspace width at depth=1
338 unit_width = (float) tan(stbgl_deg2rad(max_hfov/2)) * 2;
339 unit_height = (float) tan(stbgl_deg2rad(max_vfov/2)) * 2;
340 // check if hfov = max_hfov is enough to satisfy it
341 if (unit_width <= aspect * unit_height) {
342 float height = unit_width / aspect;
343 vfov = (float) atan(( height/2) / zoom);
344 } else {
345 vfov = (float) atan((unit_height/2) / zoom);
346 }
347 vfov = (float) stbgl_rad2deg(vfov * 2);
348 gluPerspective(vfov, aspect, znear, zfar);
349 }
350
351 void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float min_hfov, float min_vfov, float znear, float zfar)
352 {
353 if (znear <= 0.0001f) znear = 0.0001f;
354 glViewport(x,y,w,h);
355 glScissor(x,y,w,h);
356 glMatrixMode(GL_PROJECTION);
357 glLoadIdentity();
358 stbgl_Perspective(zoom, min_hfov, min_vfov, znear, zfar);
359 glMatrixMode(GL_MODELVIEW);
360 }
361
362 // point the camera along the positive X axis, Z-up
363 void stbgl_initCamera_zup_facing_x(void)
364 {
365 glRotatef(-90, 1,0,0);
366 glRotatef( 90, 0,0,1);
367 }
368
369 // point the camera along the positive Y axis, Z-up
370 void stbgl_initCamera_zup_facing_y(void)
371 {
372 glRotatef(-90, 1,0,0);
373 }
374
375 // setup a camera using Euler angles
376 void stbgl_positionCameraWithEulerAngles(float *loc, float *ang)
377 {
378 glRotatef(-ang[1], 0,1,0);
379 glRotatef(-ang[0], 1,0,0);
380 glRotatef(-ang[2], 0,0,1);
381 glTranslatef(-loc[0], -loc[1], -loc[2]);
382 }
383
384 static int stbgl_m(char *a, char *b)
385 {
386 // skip first character
387 do { ++a,++b; } while (*b && *a == *b);
388 return *b == 0;
389 }
390
391 #ifdef STBI_VERSION
392 #ifndef STBI_NO_STDIO
393 int stbgl_LoadTexture(char *filename, char *props)
394 {
395 // @TODO: handle DDS files directly
396 int res;
397 void *data;
398 int w,h,c;
399 #ifndef STBI_NO_HDR
400 if (stbi_is_hdr(filename)) {
401 data = stbi_loadf(filename, &w, &h, &c, 0);
402 if (!data) return 0;
403 res = stbgl_TexImage2D_Extra(0, w,h,data, -c, props, 0);
404 free(data);
405 return res;
406 }
407 #endif
408
409 data = stbi_load(filename, &w, &h, &c, 0);
410 if (!data) return 0;
411 res = stbgl_TexImage2D_Extra(0, w,h,data, c, props, 0);
412 free(data);
413 return res;
414 }
415 #endif
416 #endif // STBI_VERSION
417
418 int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props)
419 {
420 return stbgl_TexImage2D_Extra(texid, w, h, data, 0, props,1);
421 }
422
423 int stbgl_TestTexture(int w)
424 {
425 char scale_table[] = { 10,20,30,30,35,40,5,18,25,13,7,5,3,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0 };
426 return stbgl_TestTextureEx(w, scale_table, 2, 140,130,200, 180,200,170);
427 }
428
429 unsigned int stbgl_rand(void)
430 {
431 static unsigned int stbgl__rand_seed = 3248980923; // random typing
432 return stbgl__rand_seed = stbgl__rand_seed * 2147001325 + 715136305; // BCPL generator
433 }
434
435 // wish this could be smaller, since it's so frivolous
436 int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2)
437 {
438 int rt[2] = {r1,r2}, gt[2] = {g1,g2}, bt[2] = {b1,b2};
439 signed char modded[256];
440 int i,j, m = w-1, s,k,scale;
441 unsigned char *data = (unsigned char *) malloc(w*w*3);
442 assert((m & w) == 0);
443 data[0] = 128;
444 for (s=0; s < 16; ++s) if ((1 << s) == w) break;
445 assert(w == (1 << s));
446 // plasma fractal noise
447 for (k=s-1; k >= 0; --k) {
448 int step = 1 << k;
449 // interpolate from "parents"
450 for (j=0; j < w; j += step*2) {
451 for (i=0; i < w; i += step*2) {
452 int i1 = i+step, j1=j+step;
453 int i2 = (i+step*2)&m, j2 = (j+step*2)&m;
454 int p00 = data[(j*w+i )*3], p01 = data[(j2*w+i )*3];
455 int p10 = data[(j*w+i2)*3], p11 = data[(j2*w+i2)*3];
456 data[(j*w+i1)*3] = (p00+p10)>>1;
457 data[(j1*w+i)*3] = (p00+p01)>>1;
458 data[(j1*w+i1)*3]= (p00+p01+p10+p11)>>2;
459 }
460 }
461 scale = scale_table[s-k+1];
462 if (!scale) continue; // just interpolate down the remaining data
463 for (j=0,i=0; i < 256; i += 2, j == scale ? j=0 : ++j)
464 modded[i] = j, modded[i+1] = -j; // precompute i%scale (plus sign)
465 for (j=0; j < w; j += step)
466 for (i=0; i < w; i += step) {
467 int x = data[(j*w+i)*3] + modded[(stbgl_rand() >> 12) & 255];
468 data[(j*w+i)*3] = x < 0 ? 0 : x > 255 ? 255 : x;
469 }
470 }
471 for (j=0; j < w; ++j)
472 for (i=0; i < w; ++i) {
473 int check = ((i^j) & (1 << (s-checks_log2))) == 0;
474 int v = data[(j*w+i)*3] >> 2;
475 data[(j*w+i)*3+0] = rt[check]-v;
476 data[(j*w+i)*3+1] = gt[check]-v;
477 data[(j*w+i)*3+2] = bt[check]-v;
478 }
479 return stbgl_TexImage2D(0, w, w, data, "3m!"); // 3 channels, mipmap, free
480 }
481
482 #ifdef _WIN32
483 #ifndef WINGDIAPI
484 typedef int (__stdcall *stbgl__voidfunc)(void);
485 __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
486 #endif
487 #define STB__HAS_WGLPROC
488 static void (__stdcall *stbgl__CompressedTexImage2DARB)(int target, int level,
489 int internalformat, int width,
490 int height, int border,
491 int imageSize, void *data);
492 static void stbgl__initCompTex(void)
493 {
494 *((void **) &stbgl__CompressedTexImage2DARB) = (void *) wglGetProcAddress("glCompressedTexImage2DARB");
495 }
496 #else
497 static void (*stbgl__CompressedTexImage2DARB)(int target, int level,
498 int internalformat, int width,
499 int height, int border,
500 int imageSize, void *data);
501 static void stbgl__initCompTex(void)
502 {
503 }
504 #endif // _WIN32
505
506 #define STBGL_COMPRESSED_RGB_S3TC_DXT1 0x83F0
507 #define STBGL_COMPRESSED_RGBA_S3TC_DXT1 0x83F1
508 #define STBGL_COMPRESSED_RGBA_S3TC_DXT3 0x83F2
509 #define STBGL_COMPRESSED_RGBA_S3TC_DXT5 0x83F3
510
511 #ifdef STB_COMPRESS_DXT_BLOCK
512 static void stbgl__convert(uint8 *p, uint8 *q, int n, int input_desc, uint8 *end)
513 {
514 int i;
515 switch (input_desc) {
516 case GL_RED:
517 case GL_LUMINANCE: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=255, q+=1; break;
518 case GL_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = 0, p[3] = q[0], q+=1; break;
519 case GL_LUMINANCE_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=q[1], q+=2; break;
520 case GL_RGB: for (i=0; i < n; ++i,p+=4) p[0]=q[0],p[1]=q[1],p[2]=q[2],p[3]=255,q+=3; break;
521 case GL_RGBA: memcpy(p, q, n*4); break;
522 case GL_INTENSITY: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = p[3] = q[0], q+=1; break;
523 }
524 assert(p <= end);
525 }
526
527 static void stbgl__compress(uint8 *p, uint8 *rgba, int w, int h, int output_desc, uint8 *end)
528 {
529 int i,j,y,y2;
530 int alpha = (output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT5);
531 for (j=0; j < w; j += 4) {
532 int x=4;
533 for (i=0; i < h; i += 4) {
534 uint8 block[16*4];
535 if (i+3 >= w) x = w-i;
536 for (y=0; y < 4; ++y) {
537 if (j+y >= h) break;
538 memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4);
539 }
540 if (x < 4) {
541 switch (x) {
542 case 0: assert(0);
543 case 1:
544 for (y2=0; y2 < y; ++y2) {
545 memcpy(block+y2*16+1*4, block+y2*16+0*4, 4);
546 memcpy(block+y2*16+2*4, block+y2*16+0*4, 8);
547 }
548 break;
549 case 2:
550 for (y2=0; y2 < y; ++y2)
551 memcpy(block+y2*16+2*4, block+y2*16+0*4, 8);
552 break;
553 case 3:
554 for (y2=0; y2 < y; ++y2)
555 memcpy(block+y2*16+3*4, block+y2*16+1*4, 4);
556 break;
557 }
558 }
559 y2 = 0;
560 for(; y<4; ++y,++y2)
561 memcpy(block+y*16, block+y2*16, 4*4);
562 stb_compress_dxt_block(p, block, alpha, 10);
563 p += alpha ? 16 : 8;
564 }
565 }
566 assert(p <= end);
567 }
568 #endif // STB_COMPRESS_DXT_BLOCK
569
570 // use the reserved temporary-use enumerant range, since no
571 // OpenGL enumerants should fall in that range
572 enum
573 {
574 STBGL_UNDEFINED = 0x6000,
575 STBGL_YCOCG,
576 STBGL_YCOCGJ,
577 STBGL_GEN_MIPMAPS,
578 STBGL_MIPMAPS,
579 STBGL_NO_DOWNLOAD,
580 };
581
582 #define STBGL_CLAMP_TO_EDGE 0x812F
583 #define STBGL_CLAMP_TO_BORDER 0x812D
584
585 #define STBGL_DEPTH_COMPONENT16 0x81A5
586 #define STBGL_DEPTH_COMPONENT24 0x81A6
587 #define STBGL_DEPTH_COMPONENT32 0x81A7
588
589 int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data)
590 {
591 static int has_s3tc = -1; // haven't checked yet
592 int free_data = 0, is_compressed = 0;
593 int pad_to_power_of_two = 0, non_power_of_two = 0;
594 int premultiply_alpha = 0; // @TODO
595 int float_tex = 0; // @TODO
596 int input_type = GL_UNSIGNED_BYTE;
597 int input_desc = STBGL_UNDEFINED;
598 int output_desc = STBGL_UNDEFINED;
599 int mipmaps = STBGL_UNDEFINED;
600 int filter = STBGL_UNDEFINED, mag_filter;
601 int wrap_s = STBGL_UNDEFINED, wrap_t = STBGL_UNDEFINED;
602
603 // parse out the properties
604 if (props == NULL) props = "";
605 while (*props) {
606 switch (*props) {
607 case '1' : input_desc = GL_LUMINANCE; break;
608 case '2' : input_desc = GL_LUMINANCE_ALPHA; break;
609 case '3' : input_desc = GL_RGB; break;
610 case '4' : input_desc = GL_RGBA; break;
611 case 'l' : if (props[1] == 'a') { input_desc = GL_LUMINANCE_ALPHA; ++props; }
612 else input_desc = GL_LUMINANCE;
613 break;
614 case 'a' : input_desc = GL_ALPHA; break;
615 case 'r' : if (stbgl_m(props, "rgba")) { input_desc = GL_RGBA; props += 3; break; }
616 if (stbgl_m(props, "rgb")) { input_desc = GL_RGB; props += 2; break; }
617 input_desc = GL_RED;
618 break;
619 case 'y' : if (stbgl_m(props, "ycocg")) {
620 if (props[5] == 'j') { props += 5; input_desc = STBGL_YCOCGJ; }
621 else { props += 4; input_desc = STBGL_YCOCG; }
622 break;
623 }
624 return 0;
625 case 'L' : if (props[1] == 'A') { output_desc = GL_LUMINANCE_ALPHA; ++props; }
626 else output_desc = GL_LUMINANCE;
627 break;
628 case 'I' : output_desc = GL_INTENSITY; break;
629 case 'A' : output_desc = GL_ALPHA; break;
630 case 'R' : if (stbgl_m(props, "RGBA")) { output_desc = GL_RGBA; props += 3; break; }
631 if (stbgl_m(props, "RGB")) { output_desc = GL_RGB; props += 2; break; }
632 output_desc = GL_RED;
633 break;
634 case 'Y' : if (stbgl_m(props, "YCoCg") || stbgl_m(props, "YCOCG")) {
635 props += 4;
636 output_desc = STBGL_YCOCG;
637 break;
638 }
639 return 0;
640 case 'D' : if (stbgl_m(props, "DXT")) {
641 switch (props[3]) {
642 case '1': output_desc = STBGL_COMPRESSED_RGB_S3TC_DXT1; break;
643 case '3': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT3; break;
644 case '5': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; break;
645 default: return 0;
646 }
647 props += 3;
648 } else if (stbgl_m(props, "D16")) {
649 output_desc = STBGL_DEPTH_COMPONENT16;
650 input_desc = GL_DEPTH_COMPONENT;
651 props += 2;
652 } else if (stbgl_m(props, "D24")) {
653 output_desc = STBGL_DEPTH_COMPONENT24;
654 input_desc = GL_DEPTH_COMPONENT;
655 props += 2;
656 } else if (stbgl_m(props, "D32")) {
657 output_desc = STBGL_DEPTH_COMPONENT32;
658 input_desc = GL_DEPTH_COMPONENT;
659 props += 2;
660 } else {
661 output_desc = GL_DEPTH_COMPONENT;
662 input_desc = GL_DEPTH_COMPONENT;
663 }
664 break;
665 case 'N' : if (stbgl_m(props, "NONE")) {
666 props += 3;
667 input_desc = STBGL_NO_DOWNLOAD;
668 output_desc = STBGL_NO_DOWNLOAD;
669 break;
670 }
671 if (stbgl_m(props, "NP2")) {
672 non_power_of_two = 1;
673 props += 2;
674 break;
675 }
676 return 0;
677 case 'm' : mipmaps = STBGL_GEN_MIPMAPS; break;
678 case 'M' : mipmaps = STBGL_MIPMAPS; break;
679 case 't' : filter = GL_LINEAR_MIPMAP_LINEAR; break;
680 case 'b' : filter = GL_LINEAR; break;
681 case 'n' : filter = GL_NEAREST; break;
682 case 'w' : if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; else wrap_t = GL_REPEAT; break;
683 case 'C' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_BORDER; else wrap_t = STBGL_CLAMP_TO_BORDER; break;
684 case 'c' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_EDGE; else wrap_t = STBGL_CLAMP_TO_EDGE; break;
685 case 'f' : input_type = GL_FLOAT; break;
686 case 'F' : input_type = GL_FLOAT; float_tex = 1; break;
687 case 'p' : premultiply_alpha = 1; break;
688 case 'P' : pad_to_power_of_two = 1; break;
689 case '+' : preserve_data = 0; break;
690 case '!' : preserve_data = 0; free_data = 1; break;
691 case ' ' : break;
692 case '-' : break;
693 default : if (free_data) free(data);
694 return 0;
695 }
696 ++props;
697 }
698
699 // override input_desc based on channel count
700 if (output_desc != STBGL_NO_DOWNLOAD) {
701 switch (abs(chan)) {
702 case 1: input_desc = GL_LUMINANCE; break;
703 case 2: input_desc = GL_LUMINANCE_ALPHA; break;
704 case 3: input_desc = GL_RGB; break;
705 case 4: input_desc = GL_RGBA; break;
706 case 0: break;
707 default: return 0;
708 }
709 }
710
711 // override input_desc based on channel info
712 if (chan > 0) { input_type = GL_UNSIGNED_BYTE; }
713 if (chan < 0) { input_type = GL_FLOAT; }
714
715 if (output_desc == GL_ALPHA) {
716 if (input_desc == GL_LUMINANCE)
717 input_desc = GL_ALPHA;
718 if (input_desc == GL_RGB) {
719 // force a presumably-mono image to alpha
720 // @TODO handle 'preserve_data' case?
721 if (data && !preserve_data && input_type == GL_UNSIGNED_BYTE) {
722 int i;
723 unsigned char *p = (unsigned char *) data, *q = p;
724 for (i=0; i < w*h; ++i) {
725 *q = (p[0] + 2*p[1] + p[2]) >> 2;
726 p += 3;
727 q += 1;
728 }
729 input_desc = GL_ALPHA;
730 }
731 }
732 }
733
734 // set undefined input/output based on the other
735 if (input_desc == STBGL_UNDEFINED && output_desc == STBGL_UNDEFINED) {
736 input_desc = output_desc = GL_RGBA;
737 } else if (output_desc == STBGL_UNDEFINED) {
738 switch (input_desc) {
739 case GL_LUMINANCE:
740 case GL_ALPHA:
741 case GL_LUMINANCE_ALPHA:
742 case GL_RGB:
743 case GL_RGBA:
744 output_desc = input_desc;
745 break;
746 case GL_RED:
747 output_desc = GL_INTENSITY;
748 break;
749 case STBGL_YCOCG:
750 case STBGL_YCOCGJ:
751 output_desc = STBGL_YCOCG;
752 break;
753 default: assert(0); return 0;
754 }
755 } else if (input_desc == STBGL_UNDEFINED) {
756 switch (output_desc) {
757 case GL_LUMINANCE:
758 case GL_ALPHA:
759 case GL_LUMINANCE_ALPHA:
760 case GL_RGB:
761 case GL_RGBA:
762 input_desc = output_desc;
763 break;
764 case GL_INTENSITY:
765 input_desc = GL_RED;
766 break;
767 case STBGL_YCOCG:
768 case STBGL_COMPRESSED_RGB_S3TC_DXT1:
769 case STBGL_COMPRESSED_RGBA_S3TC_DXT3:
770 case STBGL_COMPRESSED_RGBA_S3TC_DXT5:
771 input_desc = GL_RGBA;
772 break;
773 }
774 } else {
775 if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) {
776 // if input has alpha, force output alpha
777 switch (input_desc) {
778 case GL_ALPHA:
779 case GL_LUMINANCE_ALPHA:
780 case GL_RGBA:
781 output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5;
782 break;
783 }
784 }
785 }
786
787 switch(input_desc) {
788 case GL_LUMINANCE:
789 case GL_RED:
790 case GL_ALPHA:
791 chan = 1;
792 break;
793 case GL_LUMINANCE_ALPHA:
794 chan = 2;
795 break;
796 case GL_RGB:
797 chan = 3;
798 break;
799 case GL_RGBA:
800 chan = 4;
801 break;
802 }
803
804 if (pad_to_power_of_two && ((w & (w-1)) || (h & (h-1)))) {
805 if (output_desc != STBGL_NO_DOWNLOAD && input_type == GL_UNSIGNED_BYTE && chan > 0) {
806 unsigned char *new_data;
807 int w2 = w, h2 = h, j;
808 while (w & (w-1))
809 w = (w | (w>>1))+1;
810 while (h & (h-1))
811 h = (h | (h>>1))+1;
812 new_data = malloc(w * h * chan);
813 for (j=0; j < h2; ++j) {
814 memcpy(new_data + j * w * chan, (char *) data+j*w2*chan, w2*chan);
815 memset(new_data + (j * w+w2) * chan, 0, (w-w2)*chan);
816 }
817 for (; j < h; ++j)
818 memset(new_data + j*w*chan, 0, w*chan);
819 if (free_data)
820 free(data);
821 data = new_data;
822 free_data = 1;
823 }
824 }
825
826 switch (output_desc) {
827 case STBGL_COMPRESSED_RGB_S3TC_DXT1:
828 case STBGL_COMPRESSED_RGBA_S3TC_DXT1:
829 case STBGL_COMPRESSED_RGBA_S3TC_DXT3:
830 case STBGL_COMPRESSED_RGBA_S3TC_DXT5:
831 is_compressed = 1;
832 if (has_s3tc == -1) {
833 has_s3tc = stbgl_hasExtension("GL_EXT_texture_compression_s3tc");
834 if (has_s3tc) stbgl__initCompTex();
835 }
836 if (!has_s3tc) {
837 is_compressed = 0;
838 if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1)
839 output_desc = GL_RGB;
840 else
841 output_desc = GL_RGBA;
842 }
843 }
844
845 if (output_desc == STBGL_YCOCG) {
846 assert(0);
847 output_desc = GL_RGB; // @TODO!
848 if (free_data) free(data);
849 return 0;
850 }
851
852 mag_filter = 0;
853 if (mipmaps != STBGL_UNDEFINED) {
854 switch (filter) {
855 case STBGL_UNDEFINED: filter = GL_LINEAR_MIPMAP_LINEAR; break;
856 case GL_NEAREST : mag_filter = GL_NEAREST; filter = GL_LINEAR_MIPMAP_LINEAR; break;
857 case GL_LINEAR : filter = GL_LINEAR_MIPMAP_NEAREST; break;
858 }
859 } else {
860 if (filter == STBGL_UNDEFINED)
861 filter = GL_LINEAR;
862 }
863
864 // update filtering
865 if (!mag_filter) {
866 if (filter == GL_NEAREST)
867 mag_filter = GL_NEAREST;
868 else
869 mag_filter = GL_LINEAR;
870 }
871
872 // update wrap/clamp
873 if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT;
874 if (wrap_t == STBGL_UNDEFINED) wrap_t = wrap_s;
875
876 // if no texture id, generate one
877 if (texid == 0) {
878 GLuint tex;
879 glGenTextures(1, &tex);
880 if (tex == 0) { if (free_data) free(data); return 0; }
881 texid = tex;
882 }
883
884 if (data == NULL && mipmaps == STBGL_GEN_MIPMAPS)
885 mipmaps = STBGL_MIPMAPS;
886
887 if (output_desc == STBGL_NO_DOWNLOAD)
888 mipmaps = STBGL_NO_DOWNLOAD;
889
890 glBindTexture(GL_TEXTURE_2D, texid);
891
892 #ifdef STB_COMPRESS_DXT_BLOCK
893 if (!is_compressed || !stbgl__CompressedTexImage2DARB || output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT3 || data == NULL)
894 #endif
895 {
896 switch (mipmaps) {
897 case STBGL_NO_DOWNLOAD:
898 break;
899
900 case STBGL_UNDEFINED:
901 // check if actually power-of-two
902 if (non_power_of_two || ((w & (w-1)) == 0 && (h & (h-1)) == 0))
903 glTexImage2D(GL_TEXTURE_2D, 0, output_desc, w, h, 0, input_desc, input_type, data);
904 else
905 gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data);
906 // not power of two, so use glu to resize (generates mipmaps needlessly)
907 break;
908
909 case STBGL_MIPMAPS: {
910 int level = 0;
911 int size = input_type == GL_FLOAT ? sizeof(float) : 1;
912 if (data == NULL) size = 0; // reuse same block of memory for all mipmaps
913 assert((w & (w-1)) == 0 && (h & (h-1)) == 0); // verify power-of-two
914 while (w > 1 && h > 1) {
915 glTexImage2D(GL_TEXTURE_2D, level, output_desc, w, h, 0, input_desc, input_type, data);
916 data = (void *) ((char *) data + w * h * size * chan);
917 if (w > 1) w >>= 1;
918 if (h > 1) h >>= 1;
919 ++level;
920 }
921 break;
922 }
923 case STBGL_GEN_MIPMAPS:
924 gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data);
925 break;
926
927 default:
928 assert(0);
929 if (free_data) free(data);
930 return 0;
931 }
932 #ifdef STB_COMPRESS_DXT_BLOCK
933 } else {
934 uint8 *out, *rgba=0, *end_out, *end_rgba;
935 int level = 0, alpha = (output_desc != STBGL_COMPRESSED_RGB_S3TC_DXT1);
936 int size = input_type == GL_FLOAT ? sizeof(float) : 1;
937 int osize = alpha ? 16 : 8;
938 if (!free_data && mipmaps == STBGL_GEN_MIPMAPS) {
939 uint8 *temp = malloc(w*h*chan);
940 if (!temp) { if (free_data) free(data); return 0; }
941 memcpy(temp, data, w*h*chan);
942 if (free_data) free(data);
943 free_data = 1;
944 data = temp;
945 }
946 if (chan != 4 || size != 1) {
947 rgba = malloc(w*h*4);
948 if (!rgba) return 0;
949 end_rgba = rgba+w*h*4;
950 }
951 out = malloc((w+3)*(h+3)/16*osize); // enough storage for the s3tc data
952 if (!out) return 0;
953 end_out = out + ((w+3)*(h+3))/16*osize;
954
955 for(;;) {
956 if (chan != 4)
957 stbgl__convert(rgba, data, w*h, input_desc, end_rgba);
958 stbgl__compress(out, rgba ? rgba : data, w, h, output_desc, end_out);
959 stbgl__CompressedTexImage2DARB(GL_TEXTURE_2D, level, output_desc, w, h, 0, ((w+3)&~3)*((h+3)&~3)/16*osize, out);
960 //glTexImage2D(GL_TEXTURE_2D, level, alpha?GL_RGBA:GL_RGB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba ? rgba : data);
961
962 if (mipmaps == STBGL_UNDEFINED) break;
963 if (w <= 1 && h <= 1) break;
964 if (mipmaps == STBGL_MIPMAPS) data = (void *) ((char *) data + w * h * size * chan);
965 if (mipmaps == STBGL_GEN_MIPMAPS) {
966 int w2 = w>>1, h2=h>>1, i,j,k, s=w*chan;
967 uint8 *p = data, *q=data;
968 if (w == 1) {
969 for (j=0; j < h2; ++j) {
970 for (k=0; k < chan; ++k)
971 *p++ = (q[k] + q[s+k] + 1) >> 1;
972 q += s*2;
973 }
974 } else if (h == 1) {
975 for (i=0; i < w2; ++i) {
976 for (k=0; k < chan; ++k)
977 *p++ = (q[k] + q[k+chan] + 1) >> 1;
978 q += chan*2;
979 }
980 } else {
981 for (j=0; j < h2; ++j) {
982 for (i=0; i < w2; ++i) {
983 for (k=0; k < chan; ++k)
984 *p++ = (q[k] + q[k+chan] + q[s+k] + q[s+k+chan] + 2) >> 2;
985 q += chan*2;
986 }
987 q += s;
988 }
989 }
990 }
991 if (w > 1) w >>= 1;
992 if (h > 1) h >>= 1;
993 ++level;
994 }
995 if (out) free(out);
996 if (rgba) free(rgba);
997 #endif // STB_COMPRESS_DXT_BLOCK
998 }
999
1000 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
1001 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
1002 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
1003 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
1004
1005 if (free_data) free(data);
1006 return texid;
1007 }
1008
1009 #endif // STB_DEFINE
1010 #undef STB_EXTERN
1011
1012 #endif //INCLUDE_STB_GL_H
1013
1014 // Extension handling... must be outside the INCLUDE_ brackets
1015
1016 #if defined(STB_GLEXT_DEFINE) || defined(STB_GLEXT_DECLARE)
1017
1018 #ifndef STB_GLEXT_SKIP_DURING_RECURSION
1019
1020 #ifndef GL_GLEXT_VERSION
1021
1022 // First check if glext.h is concatenated on the end of this file
1023 // (if it's concatenated on the beginning, we'll have GL_GLEXT_VERSION)
1024
1025 #define STB_GLEXT_SKIP_DURING_RECURSION
1026 #include __FILE__
1027 #undef STB_GLEXT_SKIP_DURING_RECURSION
1028
1029 // now check if it's still undefined; if so, try going for it by name;
1030 // if this errors, that's fine, since we can't compile without it
1031
1032 #ifndef GL_GLEXT_VERSION
1033 #include "glext.h"
1034 #endif
1035 #endif
1036
1037 #define GLARB(a,b) GLE(a##ARB,b##ARB)
1038 #define GLEXT(a,b) GLE(a##EXT,b##EXT)
1039 #define GLNV(a,b) GLE(a##NV ,b##NV)
1040 #define GLATI(a,b) GLE(a##ATI,b##ATI)
1041 #define GLCORE(a,b) GLE(a,b)
1042
1043 #ifdef STB_GLEXT_DEFINE_DECLARE
1044 #define STB_GLEXT_DEFINE STB_GLEXT_DECLARE
1045 #endif
1046
1047 #if defined(STB_GLEXT_DECLARE) && defined(STB_GLEXT_DEFINE)
1048 #undef STB_GLEXT_DECLARE
1049 #endif
1050
1051 #if defined(STB_GLEXT_DECLARE) && !defined(STB_GLEXT_DEFINE)
1052 #define GLE(a,b) extern PFNGL##b##PROC gl##a;
1053
1054 #ifdef __cplusplus
1055 extern "C" {
1056 #endif
1057
1058 extern void stbgl_initExtensions(void);
1059
1060 #include STB_GLEXT_DECLARE
1061
1062 #ifdef __cplusplus
1063 };
1064 #endif
1065
1066 #else
1067
1068 #ifndef STB_GLEXT_DEFINE
1069 #error "Header file is screwed up somehow"
1070 #endif
1071
1072 #ifdef _WIN32
1073 #ifndef WINGDIAPI
1074 #ifndef STB__HAS_WGLPROC
1075 typedef int (__stdcall *stbgl__voidfunc)(void);
1076 __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
1077 #endif
1078 #endif
1079 #define STBGL__GET_FUNC(x) wglGetProcAddress(x)
1080 #endif
1081
1082 #ifdef GLE
1083 #undef GLE
1084 #endif
1085
1086 #define GLE(a,b) PFNGL##b##PROC gl##a;
1087 #include STB_GLEXT_DEFINE
1088
1089 #undef GLE
1090 #define GLE(a,b) gl##a = (PFNGL##b##PROC) STBGL__GET_FUNC("gl" #a );
1091
1092 void stbgl_initExtensions(void)
1093 {
1094 #include STB_GLEXT_DEFINE
1095 }
1096
1097 #undef GLE
1098
1099 #endif // STB_GLEXT_DECLARE
1100
1101 #endif // STB_GLEXT_SKIP
1102
1103 #endif // STB_GLEXT_DEFINE || STB_GLEXT_DECLARE