| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103 |
- // stbgl - v0.04 - Sean Barrett 2008 - public domain
- //
- // Note that the gl extensions support requires glext.h. In fact, it works
- // if you just concatenate glext.h onto the end of this file. In that case,
- // this file is covered by the SGI FreeB license, and is not public domain.
- //
- // Extension usage:
- //
- // 1. Make a file called something like "extlist.txt" which contains stuff like:
- // GLE(ShaderSourceARB,SHADERSOURCEARB)
- // GLE(Uniform1iARB,UNIFORM1IARB)
- // GLARB(ActiveTexture,ACTIVETEXTURE) // same as GLE(ActiveTextureARB,ACTIVETEXTUREARB)
- // GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE)
- // GLE(MultiTexCoord2f,MULTITEXCOORD2F)
- //
- // 2. To declare functions (to make a header file), do this:
- // #define STB_GLEXT_DECLARE "extlist.txt"
- // #include "stb_gl.h"
- //
- // A good way to do this is to define STB_GLEXT_DECLARE project-wide.
- //
- // 3. To define functions (implement), do this in some C file:
- // #define STB_GLEXT_DEFINE "extlist.txt"
- // #include "stb_gl.h"
- //
- // If you've already defined STB_GLEXT_DECLARE, you can just do:
- // #define STB_GLEXT_DEFINE_DECLARE
- // #include "stb_gl.h"
- //
- // 4. Now you need to initialize:
- //
- // stbgl_initExtensions();
- #ifndef INCLUDE_STB_GL_H
- #define INCLUDE_STB_GL_H
- #define STB_GL
- #ifdef _WIN32
- #ifndef WINGDIAPI
- #define CALLBACK __stdcall
- #define WINGDIAPI __declspec(dllimport)
- #define APIENTRY __stdcall
- #endif
- #endif //_WIN32
- #include <stddef.h>
- #include <gl/gl.h>
- #include <gl/glu.h>
- #ifndef M_PI
- #define M_PI 3.14159265358979323846f
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- // like gluPerspective, but:
- // fov is chosen to satisfy both hfov <= max_hfov & vfov <= max_vfov;
- // set one to 179 or 0 to ignore it
- // zoom is applied separately, so you can do linear zoom without
- // mucking with trig with fov; 1 -> use exact fov
- // 'aspect' is inferred from the current viewport, and ignores the
- // possibility of non-square pixels
- extern void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar);
- extern void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float max_hfov, float max_vfov, float znear, float zfar);
- extern void stbgl_initCamera_zup_facing_x(void);
- extern void stbgl_initCamera_zup_facing_y(void);
- extern void stbgl_positionCameraWithEulerAngles(float *loc, float *ang);
- extern void stbgl_drawRect(float x0, float y0, float x1, float y1);
- extern void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1);
- extern void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw);
- extern int stbgl_hasExtension(char *ext);
- extern void stbgl_SimpleLight(int index, float bright, float x, float y, float z);
- extern void stbgl_GlobalAmbient(float r, float g, float b);
- extern int stbgl_LoadTexture(char *filename, char *props); // only if stb_image is available
- extern int stbgl_TestTexture(int w);
- extern int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2);
- extern unsigned int stbgl_rand(void); // internal, but exposed just in case; LCG, so use middle bits
- extern int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props);
- extern int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data);
- // "props" is a series of characters (and blocks of characters), a la fopen()'s mode,
- // e.g.:
- // GLuint texid = stbgl_LoadTexture("myfile.jpg", "mbc")
- // means: load the image "myfile.jpg", and do the following:
- // generate mipmaps
- // use bilinear filtering (not trilinear)
- // use clamp-to-edge on both channels
- //
- // input descriptor: AT MOST ONE
- // TEXT MEANING
- // 1 1 channel of input (intensity/alpha)
- // 2 2 channels of input (luminance, alpha)
- // 3 3 channels of input (RGB)
- // 4 4 channels of input (RGBA)
- // l 1 channel of input (luminance)
- // a 1 channel of input (alpha)
- // la 2 channels of input (lum/alpha)
- // rgb 3 channels of input (RGB)
- // ycocg 3 channels of input (YCoCg - forces YCoCg output)
- // ycocgj 4 channels of input (YCoCgJunk - forces YCoCg output)
- // rgba 4 channels of input (RGBA)
- //
- // output descriptor: AT MOST ONE
- // TEXT MEANING
- // A 1 channel of output (alpha)
- // I 1 channel of output (intensity)
- // LA 2 channels of output (lum/alpha)
- // RGB 3 channels of output (RGB)
- // RGBA 4 channels of output (RGBA)
- // DXT1 encode as a DXT1 texture (RGB unless input has RGBA)
- // DXT3 encode as a DXT3 texture
- // DXT5 encode as a DXT5 texture
- // YCoCg encode as a DXT5 texture with Y in alpha, CoCg in RG
- // D GL_DEPTH_COMPONENT
- // NONE no input/output, don't call TexImage2D at all
- //
- // when reading from a file or using another interface with an explicit
- // channel count, the input descriptor is ignored and instead the channel
- // count is used as the input descriptor. if the file read is a DXT DDS,
- // then it is passed directly to OpenGL in the file format.
- //
- // if an input descriptor is supplied but no output descriptor, the output
- // is assumed to be the same as the input. if an output descriptor is supplied
- // but no input descriptor, the input is assumed to be the same as the
- // output. if neither is supplied, the input is assumed to be 4-channel.
- // If DXT1 or YCoCG output is requested with no input, the input is assumed
- // to be 4-channel but the alpha channel is ignored.
- //
- // filtering descriptor (default is no mipmaps)
- // TEXT MEANING
- // m generate mipmaps
- // M mipmaps are provided, concatenated at end of data (from largest to smallest)
- // t use trilinear filtering (default if mipmapped)
- // b use bilinear filtering (default if not-mipmapped)
- // n use nearest-neighbor sampling
- //
- // wrapping descriptor
- // TEXT MEANING
- // w wrap (default)
- // c clamp-to-edge
- // C GL_CLAMP (uses border color)
- //
- // If only one wrapping descriptor is supplied, it is applied to both channels.
- //
- // special:
- // TEXT MEANING
- // f input data is floats (default unsigned bytes)
- // F input&output data is floats (default unsigned bytes)
- // p explicitly pre-multiply the alpha
- // P pad to power-of-two (default stretches)
- // NP2 non-power-of-two
- // + can overwrite the texture data with temp data
- // ! free the texture data with "free"
- //
- // the properties string can also include spaces
- #ifdef __cplusplus
- }
- #endif
- #ifdef STB_GL_IMPLEMENTATION
- #include <math.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <memory.h>
- int stbgl_hasExtension(char *ext)
- {
- const char *s = glGetString(GL_EXTENSIONS);
- for(;;) {
- char *e = ext;
- for (;;) {
- if (*e == 0) {
- if (*s == 0 || *s == ' ') return 1;
- break;
- }
- if (*s != *e)
- break;
- ++s, ++e;
- }
- while (*s && *s != ' ') ++s;
- if (!*s) return 0;
- ++s; // skip space
- }
- }
- void stbgl_drawRect(float x0, float y0, float x1, float y1)
- {
- glBegin(GL_POLYGON);
- glTexCoord2f(0,0); glVertex2f(x0,y0);
- glTexCoord2f(1,0); glVertex2f(x1,y0);
- glTexCoord2f(1,1); glVertex2f(x1,y1);
- glTexCoord2f(0,1); glVertex2f(x0,y1);
- glEnd();
- }
- void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1)
- {
- glBegin(GL_POLYGON);
- glTexCoord2f(s0,t0); glVertex2f(x0,y0);
- glTexCoord2f(s1,t0); glVertex2f(x1,y0);
- glTexCoord2f(s1,t1); glVertex2f(x1,y1);
- glTexCoord2f(s0,t1); glVertex2f(x0,y1);
- glEnd();
- }
- void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw)
- {
- float x0,y0,z0,x1,y1,z1;
- sx /=2, sy/=2, sz/=2;
- x0 = x-sx; y0 = y-sy; z0 = z-sz;
- x1 = x+sx; y1 = y+sy; z1 = z+sz;
- glBegin(GL_QUADS);
- if (cw) {
- glNormal3f(0,0,-1);
- glTexCoord2f(0,0); glVertex3f(x0,y0,z0);
- glTexCoord2f(1,0); glVertex3f(x1,y0,z0);
- glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
- glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
- glNormal3f(0,0,1);
- glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
- glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
- glTexCoord2f(1,1); glVertex3f(x0,y1,z1);
- glTexCoord2f(0,1); glVertex3f(x1,y1,z1);
- glNormal3f(-1,0,0);
- glTexCoord2f(0,0); glVertex3f(x0,y1,z1);
- glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
- glTexCoord2f(1,1); glVertex3f(x0,y0,z0);
- glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
- glNormal3f(1,0,0);
- glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
- glTexCoord2f(1,0); glVertex3f(x1,y1,z1);
- glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
- glTexCoord2f(0,1); glVertex3f(x1,y0,z0);
- glNormal3f(0,-1,0);
- glTexCoord2f(0,0); glVertex3f(x0,y0,z1);
- glTexCoord2f(1,0); glVertex3f(x1,y0,z1);
- glTexCoord2f(1,1); glVertex3f(x1,y0,z0);
- glTexCoord2f(0,1); glVertex3f(x0,y0,z0);
- glNormal3f(0,1,0);
- glTexCoord2f(0,0); glVertex3f(x1,y1,z1);
- glTexCoord2f(1,0); glVertex3f(x0,y1,z1);
- glTexCoord2f(1,1); glVertex3f(x0,y1,z0);
- glTexCoord2f(0,1); glVertex3f(x1,y1,z0);
- } else {
- glNormal3f(0,0,-1);
- glTexCoord2f(0,0); glVertex3f(x0,y0,z0);
- glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
- glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
- glTexCoord2f(1,0); glVertex3f(x1,y0,z0);
- glNormal3f(0,0,1);
- glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
- glTexCoord2f(0,1); glVertex3f(x1,y1,z1);
- glTexCoord2f(1,1); glVertex3f(x0,y1,z1);
- glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
- glNormal3f(-1,0,0);
- glTexCoord2f(0,0); glVertex3f(x0,y1,z1);
- glTexCoord2f(0,1); glVertex3f(x0,y1,z0);
- glTexCoord2f(1,1); glVertex3f(x0,y0,z0);
- glTexCoord2f(1,0); glVertex3f(x0,y0,z1);
- glNormal3f(1,0,0);
- glTexCoord2f(0,0); glVertex3f(x1,y0,z1);
- glTexCoord2f(0,1); glVertex3f(x1,y0,z0);
- glTexCoord2f(1,1); glVertex3f(x1,y1,z0);
- glTexCoord2f(1,0); glVertex3f(x1,y1,z1);
- glNormal3f(0,-1,0);
- glTexCoord2f(0,0); glVertex3f(x0,y0,z1);
- glTexCoord2f(0,1); glVertex3f(x0,y0,z0);
- glTexCoord2f(1,1); glVertex3f(x1,y0,z0);
- glTexCoord2f(1,0); glVertex3f(x1,y0,z1);
- glNormal3f(0,1,0);
- glTexCoord2f(0,0); glVertex3f(x1,y1,z1);
- glTexCoord2f(0,1); glVertex3f(x1,y1,z0);
- glTexCoord2f(1,1); glVertex3f(x0,y1,z0);
- glTexCoord2f(1,0); glVertex3f(x0,y1,z1);
- }
- glEnd();
- }
- void stbgl_SimpleLight(int index, float bright, float x, float y, float z)
- {
- float d = (float) (1.0f/sqrt(x*x+y*y+z*z));
- float dir[4] = { x*d,y*d,z*d,0 }, zero[4] = { 0,0,0,0 };
- float c[4] = { bright,bright,bright,0 };
- GLuint light = GL_LIGHT0 + index;
- glLightfv(light, GL_POSITION, dir);
- glLightfv(light, GL_DIFFUSE, c);
- glLightfv(light, GL_AMBIENT, zero);
- glLightfv(light, GL_SPECULAR, zero);
- glEnable(light);
- glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
- }
- void stbgl_GlobalAmbient(float r, float g, float b)
- {
- float v[4] = { r,g,b,0 };
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v);
- }
- #define stbgl_rad2deg(r) ((r)*180.0f / M_PI)
- #define stbgl_deg2rad(r) ((r)/180.0f * M_PI)
- void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar)
- {
- float unit_width, unit_height, aspect, vfov;
- int data[4],w,h;
- glGetIntegerv(GL_VIEWPORT, data);
- w = data[2];
- h = data[3];
- aspect = (float) w / h;
- if (max_hfov <= 0) max_hfov = 179;
- if (max_vfov <= 0) max_vfov = 179;
- // convert max_hfov, max_vfov to worldspace width at depth=1
- unit_width = (float) tan(stbgl_deg2rad(max_hfov/2)) * 2;
- unit_height = (float) tan(stbgl_deg2rad(max_vfov/2)) * 2;
- // check if hfov = max_hfov is enough to satisfy it
- if (unit_width <= aspect * unit_height) {
- float height = unit_width / aspect;
- vfov = (float) atan(( height/2) / zoom);
- } else {
- vfov = (float) atan((unit_height/2) / zoom);
- }
- vfov = (float) stbgl_rad2deg(vfov * 2);
- gluPerspective(vfov, aspect, znear, zfar);
- }
- void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float min_hfov, float min_vfov, float znear, float zfar)
- {
- if (znear <= 0.0001f) znear = 0.0001f;
- glViewport(x,y,w,h);
- glScissor(x,y,w,h);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- stbgl_Perspective(zoom, min_hfov, min_vfov, znear, zfar);
- glMatrixMode(GL_MODELVIEW);
- }
- // point the camera along the positive X axis, Z-up
- void stbgl_initCamera_zup_facing_x(void)
- {
- glRotatef(-90, 1,0,0);
- glRotatef( 90, 0,0,1);
- }
- // point the camera along the positive Y axis, Z-up
- void stbgl_initCamera_zup_facing_y(void)
- {
- glRotatef(-90, 1,0,0);
- }
- // setup a camera using Euler angles
- void stbgl_positionCameraWithEulerAngles(float *loc, float *ang)
- {
- glRotatef(-ang[1], 0,1,0);
- glRotatef(-ang[0], 1,0,0);
- glRotatef(-ang[2], 0,0,1);
- glTranslatef(-loc[0], -loc[1], -loc[2]);
- }
- static int stbgl_m(char *a, char *b)
- {
- // skip first character
- do { ++a,++b; } while (*b && *a == *b);
- return *b == 0;
- }
- #ifdef STBI_VERSION
- #ifndef STBI_NO_STDIO
- int stbgl_LoadTexture(char *filename, char *props)
- {
- // @TODO: handle DDS files directly
- int res;
- void *data;
- int w,h,c;
- #ifndef STBI_NO_HDR
- if (stbi_is_hdr(filename)) {
- data = stbi_loadf(filename, &w, &h, &c, 0);
- if (!data) return 0;
- res = stbgl_TexImage2D_Extra(0, w,h,data, -c, props, 0);
- free(data);
- return res;
- }
- #endif
- data = stbi_load(filename, &w, &h, &c, 0);
- if (!data) return 0;
- res = stbgl_TexImage2D_Extra(0, w,h,data, c, props, 0);
- free(data);
- return res;
- }
- #endif
- #endif // STBI_VERSION
- int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props)
- {
- return stbgl_TexImage2D_Extra(texid, w, h, data, 0, props,1);
- }
- int stbgl_TestTexture(int w)
- {
- 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 };
- return stbgl_TestTextureEx(w, scale_table, 2, 140,130,200, 180,200,170);
- }
- unsigned int stbgl_rand(void)
- {
- static unsigned int stbgl__rand_seed = 3248980923; // random typing
- return stbgl__rand_seed = stbgl__rand_seed * 2147001325 + 715136305; // BCPL generator
- }
- // wish this could be smaller, since it's so frivolous
- int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2)
- {
- int rt[2] = {r1,r2}, gt[2] = {g1,g2}, bt[2] = {b1,b2};
- signed char modded[256];
- int i,j, m = w-1, s,k,scale;
- unsigned char *data = (unsigned char *) malloc(w*w*3);
- assert((m & w) == 0);
- data[0] = 128;
- for (s=0; s < 16; ++s) if ((1 << s) == w) break;
- assert(w == (1 << s));
- // plasma fractal noise
- for (k=s-1; k >= 0; --k) {
- int step = 1 << k;
- // interpolate from "parents"
- for (j=0; j < w; j += step*2) {
- for (i=0; i < w; i += step*2) {
- int i1 = i+step, j1=j+step;
- int i2 = (i+step*2)&m, j2 = (j+step*2)&m;
- int p00 = data[(j*w+i )*3], p01 = data[(j2*w+i )*3];
- int p10 = data[(j*w+i2)*3], p11 = data[(j2*w+i2)*3];
- data[(j*w+i1)*3] = (p00+p10)>>1;
- data[(j1*w+i)*3] = (p00+p01)>>1;
- data[(j1*w+i1)*3]= (p00+p01+p10+p11)>>2;
- }
- }
- scale = scale_table[s-k+1];
- if (!scale) continue; // just interpolate down the remaining data
- for (j=0,i=0; i < 256; i += 2, j == scale ? j=0 : ++j)
- modded[i] = j, modded[i+1] = -j; // precompute i%scale (plus sign)
- for (j=0; j < w; j += step)
- for (i=0; i < w; i += step) {
- int x = data[(j*w+i)*3] + modded[(stbgl_rand() >> 12) & 255];
- data[(j*w+i)*3] = x < 0 ? 0 : x > 255 ? 255 : x;
- }
- }
- for (j=0; j < w; ++j)
- for (i=0; i < w; ++i) {
- int check = ((i^j) & (1 << (s-checks_log2))) == 0;
- int v = data[(j*w+i)*3] >> 2;
- data[(j*w+i)*3+0] = rt[check]-v;
- data[(j*w+i)*3+1] = gt[check]-v;
- data[(j*w+i)*3+2] = bt[check]-v;
- }
- return stbgl_TexImage2D(0, w, w, data, "3m!"); // 3 channels, mipmap, free
- }
- #ifdef _WIN32
- #ifndef WINGDIAPI
- typedef int (__stdcall *stbgl__voidfunc)(void);
- __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
- #endif
- #define STB__HAS_WGLPROC
- static void (__stdcall *stbgl__CompressedTexImage2DARB)(int target, int level,
- int internalformat, int width,
- int height, int border,
- int imageSize, void *data);
- static void stbgl__initCompTex(void)
- {
- *((void **) &stbgl__CompressedTexImage2DARB) = (void *) wglGetProcAddress("glCompressedTexImage2DARB");
- }
- #else
- static void (*stbgl__CompressedTexImage2DARB)(int target, int level,
- int internalformat, int width,
- int height, int border,
- int imageSize, void *data);
- static void stbgl__initCompTex(void)
- {
- }
- #endif // _WIN32
- #define STBGL_COMPRESSED_RGB_S3TC_DXT1 0x83F0
- #define STBGL_COMPRESSED_RGBA_S3TC_DXT1 0x83F1
- #define STBGL_COMPRESSED_RGBA_S3TC_DXT3 0x83F2
- #define STBGL_COMPRESSED_RGBA_S3TC_DXT5 0x83F3
- #ifdef STB_COMPRESS_DXT_BLOCK
- static void stbgl__convert(uint8 *p, uint8 *q, int n, int input_desc, uint8 *end)
- {
- int i;
- switch (input_desc) {
- case GL_RED:
- 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;
- 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;
- 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;
- 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;
- case GL_RGBA: memcpy(p, q, n*4); break;
- case GL_INTENSITY: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = p[3] = q[0], q+=1; break;
- }
- assert(p <= end);
- }
- static void stbgl__compress(uint8 *p, uint8 *rgba, int w, int h, int output_desc, uint8 *end)
- {
- int i,j,y,y2;
- int alpha = (output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT5);
- for (j=0; j < w; j += 4) {
- int x=4;
- for (i=0; i < h; i += 4) {
- uint8 block[16*4];
- if (i+3 >= w) x = w-i;
- for (y=0; y < 4; ++y) {
- if (j+y >= h) break;
- memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4);
- }
- if (x < 4) {
- switch (x) {
- case 0: assert(0);
- case 1:
- for (y2=0; y2 < y; ++y2) {
- memcpy(block+y2*16+1*4, block+y2*16+0*4, 4);
- memcpy(block+y2*16+2*4, block+y2*16+0*4, 8);
- }
- break;
- case 2:
- for (y2=0; y2 < y; ++y2)
- memcpy(block+y2*16+2*4, block+y2*16+0*4, 8);
- break;
- case 3:
- for (y2=0; y2 < y; ++y2)
- memcpy(block+y2*16+3*4, block+y2*16+1*4, 4);
- break;
- }
- }
- y2 = 0;
- for(; y<4; ++y,++y2)
- memcpy(block+y*16, block+y2*16, 4*4);
- stb_compress_dxt_block(p, block, alpha, 10);
- p += alpha ? 16 : 8;
- }
- }
- assert(p <= end);
- }
- #endif // STB_COMPRESS_DXT_BLOCK
- // use the reserved temporary-use enumerant range, since no
- // OpenGL enumerants should fall in that range
- enum
- {
- STBGL_UNDEFINED = 0x6000,
- STBGL_YCOCG,
- STBGL_YCOCGJ,
- STBGL_GEN_MIPMAPS,
- STBGL_MIPMAPS,
- STBGL_NO_DOWNLOAD,
- };
- #define STBGL_CLAMP_TO_EDGE 0x812F
- #define STBGL_CLAMP_TO_BORDER 0x812D
- #define STBGL_DEPTH_COMPONENT16 0x81A5
- #define STBGL_DEPTH_COMPONENT24 0x81A6
- #define STBGL_DEPTH_COMPONENT32 0x81A7
- int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data)
- {
- static int has_s3tc = -1; // haven't checked yet
- int free_data = 0, is_compressed = 0;
- int pad_to_power_of_two = 0, non_power_of_two = 0;
- int premultiply_alpha = 0; // @TODO
- int float_tex = 0; // @TODO
- int input_type = GL_UNSIGNED_BYTE;
- int input_desc = STBGL_UNDEFINED;
- int output_desc = STBGL_UNDEFINED;
- int mipmaps = STBGL_UNDEFINED;
- int filter = STBGL_UNDEFINED, mag_filter;
- int wrap_s = STBGL_UNDEFINED, wrap_t = STBGL_UNDEFINED;
- // parse out the properties
- if (props == NULL) props = "";
- while (*props) {
- switch (*props) {
- case '1' : input_desc = GL_LUMINANCE; break;
- case '2' : input_desc = GL_LUMINANCE_ALPHA; break;
- case '3' : input_desc = GL_RGB; break;
- case '4' : input_desc = GL_RGBA; break;
- case 'l' : if (props[1] == 'a') { input_desc = GL_LUMINANCE_ALPHA; ++props; }
- else input_desc = GL_LUMINANCE;
- break;
- case 'a' : input_desc = GL_ALPHA; break;
- case 'r' : if (stbgl_m(props, "rgba")) { input_desc = GL_RGBA; props += 3; break; }
- if (stbgl_m(props, "rgb")) { input_desc = GL_RGB; props += 2; break; }
- input_desc = GL_RED;
- break;
- case 'y' : if (stbgl_m(props, "ycocg")) {
- if (props[5] == 'j') { props += 5; input_desc = STBGL_YCOCGJ; }
- else { props += 4; input_desc = STBGL_YCOCG; }
- break;
- }
- return 0;
- case 'L' : if (props[1] == 'A') { output_desc = GL_LUMINANCE_ALPHA; ++props; }
- else output_desc = GL_LUMINANCE;
- break;
- case 'I' : output_desc = GL_INTENSITY; break;
- case 'A' : output_desc = GL_ALPHA; break;
- case 'R' : if (stbgl_m(props, "RGBA")) { output_desc = GL_RGBA; props += 3; break; }
- if (stbgl_m(props, "RGB")) { output_desc = GL_RGB; props += 2; break; }
- output_desc = GL_RED;
- break;
- case 'Y' : if (stbgl_m(props, "YCoCg") || stbgl_m(props, "YCOCG")) {
- props += 4;
- output_desc = STBGL_YCOCG;
- break;
- }
- return 0;
- case 'D' : if (stbgl_m(props, "DXT")) {
- switch (props[3]) {
- case '1': output_desc = STBGL_COMPRESSED_RGB_S3TC_DXT1; break;
- case '3': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT3; break;
- case '5': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; break;
- default: return 0;
- }
- props += 3;
- } else if (stbgl_m(props, "D16")) {
- output_desc = STBGL_DEPTH_COMPONENT16;
- input_desc = GL_DEPTH_COMPONENT;
- props += 2;
- } else if (stbgl_m(props, "D24")) {
- output_desc = STBGL_DEPTH_COMPONENT24;
- input_desc = GL_DEPTH_COMPONENT;
- props += 2;
- } else if (stbgl_m(props, "D32")) {
- output_desc = STBGL_DEPTH_COMPONENT32;
- input_desc = GL_DEPTH_COMPONENT;
- props += 2;
- } else {
- output_desc = GL_DEPTH_COMPONENT;
- input_desc = GL_DEPTH_COMPONENT;
- }
- break;
- case 'N' : if (stbgl_m(props, "NONE")) {
- props += 3;
- input_desc = STBGL_NO_DOWNLOAD;
- output_desc = STBGL_NO_DOWNLOAD;
- break;
- }
- if (stbgl_m(props, "NP2")) {
- non_power_of_two = 1;
- props += 2;
- break;
- }
- return 0;
- case 'm' : mipmaps = STBGL_GEN_MIPMAPS; break;
- case 'M' : mipmaps = STBGL_MIPMAPS; break;
- case 't' : filter = GL_LINEAR_MIPMAP_LINEAR; break;
- case 'b' : filter = GL_LINEAR; break;
- case 'n' : filter = GL_NEAREST; break;
- case 'w' : if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; else wrap_t = GL_REPEAT; break;
- case 'C' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_BORDER; else wrap_t = STBGL_CLAMP_TO_BORDER; break;
- case 'c' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_EDGE; else wrap_t = STBGL_CLAMP_TO_EDGE; break;
- case 'f' : input_type = GL_FLOAT; break;
- case 'F' : input_type = GL_FLOAT; float_tex = 1; break;
- case 'p' : premultiply_alpha = 1; break;
- case 'P' : pad_to_power_of_two = 1; break;
- case '+' : preserve_data = 0; break;
- case '!' : preserve_data = 0; free_data = 1; break;
- case ' ' : break;
- case '-' : break;
- default : if (free_data) free(data);
- return 0;
- }
- ++props;
- }
-
- // override input_desc based on channel count
- if (output_desc != STBGL_NO_DOWNLOAD) {
- switch (abs(chan)) {
- case 1: input_desc = GL_LUMINANCE; break;
- case 2: input_desc = GL_LUMINANCE_ALPHA; break;
- case 3: input_desc = GL_RGB; break;
- case 4: input_desc = GL_RGBA; break;
- case 0: break;
- default: return 0;
- }
- }
- // override input_desc based on channel info
- if (chan > 0) { input_type = GL_UNSIGNED_BYTE; }
- if (chan < 0) { input_type = GL_FLOAT; }
- if (output_desc == GL_ALPHA) {
- if (input_desc == GL_LUMINANCE)
- input_desc = GL_ALPHA;
- if (input_desc == GL_RGB) {
- // force a presumably-mono image to alpha
- // @TODO handle 'preserve_data' case?
- if (data && !preserve_data && input_type == GL_UNSIGNED_BYTE) {
- int i;
- unsigned char *p = (unsigned char *) data, *q = p;
- for (i=0; i < w*h; ++i) {
- *q = (p[0] + 2*p[1] + p[2]) >> 2;
- p += 3;
- q += 1;
- }
- input_desc = GL_ALPHA;
- }
- }
- }
- // set undefined input/output based on the other
- if (input_desc == STBGL_UNDEFINED && output_desc == STBGL_UNDEFINED) {
- input_desc = output_desc = GL_RGBA;
- } else if (output_desc == STBGL_UNDEFINED) {
- switch (input_desc) {
- case GL_LUMINANCE:
- case GL_ALPHA:
- case GL_LUMINANCE_ALPHA:
- case GL_RGB:
- case GL_RGBA:
- output_desc = input_desc;
- break;
- case GL_RED:
- output_desc = GL_INTENSITY;
- break;
- case STBGL_YCOCG:
- case STBGL_YCOCGJ:
- output_desc = STBGL_YCOCG;
- break;
- default: assert(0); return 0;
- }
- } else if (input_desc == STBGL_UNDEFINED) {
- switch (output_desc) {
- case GL_LUMINANCE:
- case GL_ALPHA:
- case GL_LUMINANCE_ALPHA:
- case GL_RGB:
- case GL_RGBA:
- input_desc = output_desc;
- break;
- case GL_INTENSITY:
- input_desc = GL_RED;
- break;
- case STBGL_YCOCG:
- case STBGL_COMPRESSED_RGB_S3TC_DXT1:
- case STBGL_COMPRESSED_RGBA_S3TC_DXT3:
- case STBGL_COMPRESSED_RGBA_S3TC_DXT5:
- input_desc = GL_RGBA;
- break;
- }
- } else {
- if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) {
- // if input has alpha, force output alpha
- switch (input_desc) {
- case GL_ALPHA:
- case GL_LUMINANCE_ALPHA:
- case GL_RGBA:
- output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5;
- break;
- }
- }
- }
- switch(input_desc) {
- case GL_LUMINANCE:
- case GL_RED:
- case GL_ALPHA:
- chan = 1;
- break;
- case GL_LUMINANCE_ALPHA:
- chan = 2;
- break;
- case GL_RGB:
- chan = 3;
- break;
- case GL_RGBA:
- chan = 4;
- break;
- }
- if (pad_to_power_of_two && ((w & (w-1)) || (h & (h-1)))) {
- if (output_desc != STBGL_NO_DOWNLOAD && input_type == GL_UNSIGNED_BYTE && chan > 0) {
- unsigned char *new_data;
- int w2 = w, h2 = h, j;
- while (w & (w-1))
- w = (w | (w>>1))+1;
- while (h & (h-1))
- h = (h | (h>>1))+1;
- new_data = malloc(w * h * chan);
- for (j=0; j < h2; ++j) {
- memcpy(new_data + j * w * chan, (char *) data+j*w2*chan, w2*chan);
- memset(new_data + (j * w+w2) * chan, 0, (w-w2)*chan);
- }
- for (; j < h; ++j)
- memset(new_data + j*w*chan, 0, w*chan);
- if (free_data)
- free(data);
- data = new_data;
- free_data = 1;
- }
- }
- switch (output_desc) {
- case STBGL_COMPRESSED_RGB_S3TC_DXT1:
- case STBGL_COMPRESSED_RGBA_S3TC_DXT1:
- case STBGL_COMPRESSED_RGBA_S3TC_DXT3:
- case STBGL_COMPRESSED_RGBA_S3TC_DXT5:
- is_compressed = 1;
- if (has_s3tc == -1) {
- has_s3tc = stbgl_hasExtension("GL_EXT_texture_compression_s3tc");
- if (has_s3tc) stbgl__initCompTex();
- }
- if (!has_s3tc) {
- is_compressed = 0;
- if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1)
- output_desc = GL_RGB;
- else
- output_desc = GL_RGBA;
- }
- }
- if (output_desc == STBGL_YCOCG) {
- assert(0);
- output_desc = GL_RGB; // @TODO!
- if (free_data) free(data);
- return 0;
- }
- mag_filter = 0;
- if (mipmaps != STBGL_UNDEFINED) {
- switch (filter) {
- case STBGL_UNDEFINED: filter = GL_LINEAR_MIPMAP_LINEAR; break;
- case GL_NEAREST : mag_filter = GL_NEAREST; filter = GL_LINEAR_MIPMAP_LINEAR; break;
- case GL_LINEAR : filter = GL_LINEAR_MIPMAP_NEAREST; break;
- }
- } else {
- if (filter == STBGL_UNDEFINED)
- filter = GL_LINEAR;
- }
- // update filtering
- if (!mag_filter) {
- if (filter == GL_NEAREST)
- mag_filter = GL_NEAREST;
- else
- mag_filter = GL_LINEAR;
- }
- // update wrap/clamp
- if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT;
- if (wrap_t == STBGL_UNDEFINED) wrap_t = wrap_s;
- // if no texture id, generate one
- if (texid == 0) {
- GLuint tex;
- glGenTextures(1, &tex);
- if (tex == 0) { if (free_data) free(data); return 0; }
- texid = tex;
- }
- if (data == NULL && mipmaps == STBGL_GEN_MIPMAPS)
- mipmaps = STBGL_MIPMAPS;
- if (output_desc == STBGL_NO_DOWNLOAD)
- mipmaps = STBGL_NO_DOWNLOAD;
- glBindTexture(GL_TEXTURE_2D, texid);
- #ifdef STB_COMPRESS_DXT_BLOCK
- if (!is_compressed || !stbgl__CompressedTexImage2DARB || output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT3 || data == NULL)
- #endif
- {
- switch (mipmaps) {
- case STBGL_NO_DOWNLOAD:
- break;
- case STBGL_UNDEFINED:
- // check if actually power-of-two
- if (non_power_of_two || ((w & (w-1)) == 0 && (h & (h-1)) == 0))
- glTexImage2D(GL_TEXTURE_2D, 0, output_desc, w, h, 0, input_desc, input_type, data);
- else
- gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data);
- // not power of two, so use glu to resize (generates mipmaps needlessly)
- break;
- case STBGL_MIPMAPS: {
- int level = 0;
- int size = input_type == GL_FLOAT ? sizeof(float) : 1;
- if (data == NULL) size = 0; // reuse same block of memory for all mipmaps
- assert((w & (w-1)) == 0 && (h & (h-1)) == 0); // verify power-of-two
- while (w > 1 && h > 1) {
- glTexImage2D(GL_TEXTURE_2D, level, output_desc, w, h, 0, input_desc, input_type, data);
- data = (void *) ((char *) data + w * h * size * chan);
- if (w > 1) w >>= 1;
- if (h > 1) h >>= 1;
- ++level;
- }
- break;
- }
- case STBGL_GEN_MIPMAPS:
- gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data);
- break;
- default:
- assert(0);
- if (free_data) free(data);
- return 0;
- }
- #ifdef STB_COMPRESS_DXT_BLOCK
- } else {
- uint8 *out, *rgba=0, *end_out, *end_rgba;
- int level = 0, alpha = (output_desc != STBGL_COMPRESSED_RGB_S3TC_DXT1);
- int size = input_type == GL_FLOAT ? sizeof(float) : 1;
- int osize = alpha ? 16 : 8;
- if (!free_data && mipmaps == STBGL_GEN_MIPMAPS) {
- uint8 *temp = malloc(w*h*chan);
- if (!temp) { if (free_data) free(data); return 0; }
- memcpy(temp, data, w*h*chan);
- if (free_data) free(data);
- free_data = 1;
- data = temp;
- }
- if (chan != 4 || size != 1) {
- rgba = malloc(w*h*4);
- if (!rgba) return 0;
- end_rgba = rgba+w*h*4;
- }
- out = malloc((w+3)*(h+3)/16*osize); // enough storage for the s3tc data
- if (!out) return 0;
- end_out = out + ((w+3)*(h+3))/16*osize;
- for(;;) {
- if (chan != 4)
- stbgl__convert(rgba, data, w*h, input_desc, end_rgba);
- stbgl__compress(out, rgba ? rgba : data, w, h, output_desc, end_out);
- stbgl__CompressedTexImage2DARB(GL_TEXTURE_2D, level, output_desc, w, h, 0, ((w+3)&~3)*((h+3)&~3)/16*osize, out);
- //glTexImage2D(GL_TEXTURE_2D, level, alpha?GL_RGBA:GL_RGB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba ? rgba : data);
- if (mipmaps == STBGL_UNDEFINED) break;
- if (w <= 1 && h <= 1) break;
- if (mipmaps == STBGL_MIPMAPS) data = (void *) ((char *) data + w * h * size * chan);
- if (mipmaps == STBGL_GEN_MIPMAPS) {
- int w2 = w>>1, h2=h>>1, i,j,k, s=w*chan;
- uint8 *p = data, *q=data;
- if (w == 1) {
- for (j=0; j < h2; ++j) {
- for (k=0; k < chan; ++k)
- *p++ = (q[k] + q[s+k] + 1) >> 1;
- q += s*2;
- }
- } else if (h == 1) {
- for (i=0; i < w2; ++i) {
- for (k=0; k < chan; ++k)
- *p++ = (q[k] + q[k+chan] + 1) >> 1;
- q += chan*2;
- }
- } else {
- for (j=0; j < h2; ++j) {
- for (i=0; i < w2; ++i) {
- for (k=0; k < chan; ++k)
- *p++ = (q[k] + q[k+chan] + q[s+k] + q[s+k+chan] + 2) >> 2;
- q += chan*2;
- }
- q += s;
- }
- }
- }
- if (w > 1) w >>= 1;
- if (h > 1) h >>= 1;
- ++level;
- }
- if (out) free(out);
- if (rgba) free(rgba);
- #endif // STB_COMPRESS_DXT_BLOCK
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
- if (free_data) free(data);
- return texid;
- }
- #endif // STB_DEFINE
- #undef STB_EXTERN
- #endif //INCLUDE_STB_GL_H
- // Extension handling... must be outside the INCLUDE_ brackets
- #if defined(STB_GLEXT_DEFINE) || defined(STB_GLEXT_DECLARE)
- #ifndef STB_GLEXT_SKIP_DURING_RECURSION
- #ifndef GL_GLEXT_VERSION
- // First check if glext.h is concatenated on the end of this file
- // (if it's concatenated on the beginning, we'll have GL_GLEXT_VERSION)
- #define STB_GLEXT_SKIP_DURING_RECURSION
- #include __FILE__
- #undef STB_GLEXT_SKIP_DURING_RECURSION
- // now check if it's still undefined; if so, try going for it by name;
- // if this errors, that's fine, since we can't compile without it
- #ifndef GL_GLEXT_VERSION
- #include "glext.h"
- #endif
- #endif
- #define GLARB(a,b) GLE(a##ARB,b##ARB)
- #define GLEXT(a,b) GLE(a##EXT,b##EXT)
- #define GLNV(a,b) GLE(a##NV ,b##NV)
- #define GLATI(a,b) GLE(a##ATI,b##ATI)
- #define GLCORE(a,b) GLE(a,b)
- #ifdef STB_GLEXT_DEFINE_DECLARE
- #define STB_GLEXT_DEFINE STB_GLEXT_DECLARE
- #endif
- #if defined(STB_GLEXT_DECLARE) && defined(STB_GLEXT_DEFINE)
- #undef STB_GLEXT_DECLARE
- #endif
- #if defined(STB_GLEXT_DECLARE) && !defined(STB_GLEXT_DEFINE)
- #define GLE(a,b) extern PFNGL##b##PROC gl##a;
- #ifdef __cplusplus
- extern "C" {
- #endif
- extern void stbgl_initExtensions(void);
- #include STB_GLEXT_DECLARE
- #ifdef __cplusplus
- };
- #endif
- #else
- #ifndef STB_GLEXT_DEFINE
- #error "Header file is screwed up somehow"
- #endif
- #ifdef _WIN32
- #ifndef WINGDIAPI
- #ifndef STB__HAS_WGLPROC
- typedef int (__stdcall *stbgl__voidfunc)(void);
- __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
- #endif
- #endif
- #define STBGL__GET_FUNC(x) wglGetProcAddress(x)
- #endif
- #ifdef GLE
- #undef GLE
- #endif
- #define GLE(a,b) PFNGL##b##PROC gl##a;
- #include STB_GLEXT_DEFINE
- #undef GLE
- #define GLE(a,b) gl##a = (PFNGL##b##PROC) STBGL__GET_FUNC("gl" #a );
- void stbgl_initExtensions(void)
- {
- #include STB_GLEXT_DEFINE
- }
- #undef GLE
- #endif // STB_GLEXT_DECLARE
- #endif // STB_GLEXT_SKIP
- #endif // STB_GLEXT_DEFINE || STB_GLEXT_DECLARE
|