Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1103 lines
37 KiB

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